@steipete/terminator-mcp
Version:
MCP plugin to manage macOS terminal sessions.
126 lines • 5.67 kB
JavaScript
import * as fs from 'node:fs'; // Import fs for file operations
// --- Utility Functions ---
// Use a known writable directory, like the one TERMINATOR_LOG_DIR points to.
const nodejsDebugLogFilePath = '/Users/steipete/Library/Logs/terminator-mcp/terminator_nodejs_debug.log';
export function debugLog(message, ...args) {
// Basic debug logging, now appends to a file.
try {
const timestamp = new Date().toISOString();
const logMessage = `${timestamp} [TerminatorMCP NodeJS DEBUG] ${message} ${args.map(arg => {
try {
return JSON.stringify(arg, null, 2);
}
catch (e) {
return '[UnserializableArg]'; // Handle potential circular structures or other errors
}
}).join(' ')}\\n`;
// Ensure the directory exists (optional, but good practice for robustness if it might not)
// For now, assuming /Users/steipete/Library/Logs/terminator-mcp/ exists as per Swift config.
fs.appendFileSync(nodejsDebugLogFilePath, logMessage);
}
catch (e) {
console.error(`Failed to write to NodeJS debug log file '${nodejsDebugLogFilePath}':`, e);
console.debug(`Original NodeJS debug message: ${message}`, ...args);
}
}
// --- Configuration Loading (as per SDD 3.1.2 for dynamic description) ---
export function getEnvVar(key, defaultValue) {
return process.env[key] || defaultValue;
}
export function getEnvVarInt(key, defaultValue) {
const valStr = process.env[key];
if (valStr === undefined || valStr === null || valStr.trim() === '')
return defaultValue;
const parsed = parseInt(valStr, 10);
return isNaN(parsed) ? defaultValue : parsed;
}
export function getEnvVarBool(key, defaultValue) {
const val = process.env[key]?.toLowerCase();
if (val === undefined)
return defaultValue;
return ['true', '1', 't', 'yes', 'on'].includes(val);
}
export const CURRENT_TERMINAL_APP = getEnvVar('TERMINATOR_APP', 'iTerm');
export const DEFAULT_BACKGROUND_STARTUP_SECONDS = getEnvVarInt('TERMINATOR_BACKGROUND_STARTUP_SECONDS', 5);
export const DEFAULT_FOREGROUND_COMPLETION_SECONDS = getEnvVarInt('TERMINATOR_FOREGROUND_COMPLETION_SECONDS', 60);
export const DEFAULT_LINES = getEnvVarInt('TERMINATOR_DEFAULT_LINES', 100);
export const DEFAULT_FOCUS_ON_ACTION = getEnvVarBool('TERMINATOR_DEFAULT_FOCUS_ON_ACTION', true);
export const DEFAULT_BACKGROUND_EXECUTION = getEnvVarBool('TERMINATOR_DEFAULT_BACKGROUND_EXECUTION', false); // Added from SDD 3.2.3
// Defines mappings from various raw option keys (case-insensitive) to canonical TerminatorOptions keys.
export const PARAM_ALIASES = {
timeout: 'timeout',
timeoutseconds: 'timeout',
timeout_seconds: 'timeout',
customtimeout: 'timeout',
lines: 'lines',
outputlines: 'lines',
maxlines: 'lines',
projectpath: 'project_path',
project_path: 'project_path',
dir: 'project_path',
directory: 'project_path',
background: 'background',
bg: 'background',
isbackground: 'background',
focus: 'focus',
bringtofront: 'focus',
setfocus: 'focus',
tag: 'tag',
sessiontag: 'tag',
session_tag: 'tag',
command: 'command',
cmd: 'command',
execute: 'command',
};
// Defines the order of preference for aliases mapping to the same canonical key.
// For each canonical key, lists its recognized aliases in preferred order.
export const ALIAS_PRIORITY_MAP = {
timeout: ['timeout', 'timeoutseconds', 'timeout_seconds', 'customtimeout'],
lines: ['lines', 'outputlines', 'maxlines'],
project_path: ['project_path', 'projectpath', 'dir', 'directory'],
background: ['background', 'bg', 'isbackground'],
focus: ['focus', 'bringtofront', 'setfocus'],
tag: ['tag', 'sessiontag', 'session_tag'],
command: ['command', 'cmd', 'execute'],
};
export function getCanonicalOptions(rawOptions) {
const canonical = {};
if (!rawOptions)
return {};
const rawKeys = Object.keys(rawOptions);
for (const key of Object.keys(ALIAS_PRIORITY_MAP)) {
const canonicalKey = key;
const preferredAliases = ALIAS_PRIORITY_MAP[canonicalKey];
if (!preferredAliases)
continue;
for (const alias of preferredAliases) {
const matchingRawKey = rawKeys.find(rk => rk.toLowerCase() === alias.toLowerCase());
if (matchingRawKey) {
if (canonical[canonicalKey] === undefined) { // Only take the first matched alias based on priority
canonical[canonicalKey] = rawOptions[matchingRawKey];
debugLog(`Lenient mapping: used raw key '${matchingRawKey}' for canonical '${canonicalKey}' with value:`, rawOptions[matchingRawKey]);
}
else {
debugLog(`Lenient mapping: ignored additional raw key '${matchingRawKey}' for canonical '${canonicalKey}' as it was already set.`);
}
}
}
}
// Log any unrecognized parameters
for (const rawKey of rawKeys) {
let recognized = false;
for (const key of Object.keys(ALIAS_PRIORITY_MAP)) {
const canonicalKey = key;
const preferredAliases = ALIAS_PRIORITY_MAP[canonicalKey];
if (preferredAliases && preferredAliases.some(alias => alias.toLowerCase() === rawKey.toLowerCase())) {
recognized = true;
break;
}
}
if (!recognized) {
debugLog(`Ignoring unknown parameter: '${rawKey}' with value:`, rawOptions[rawKey]);
}
}
return canonical;
}
//# sourceMappingURL=config.js.map