UNPKG

vscode-mcp-comprehensive

Version:

Comprehensive MCP server exposing all VSCode features to AI agents with 101 tools including advanced debugging and console access

282 lines 11.9 kB
import * as vscode from 'vscode'; export class TerminalTools { constructor(server) { this.server = server; this.terminals = new Map(); this.registerTools(); this.setupTerminalTracking(); } setupTerminalTracking() { // Track terminal creation and disposal vscode.window.onDidOpenTerminal(terminal => { this.terminals.set(terminal.name, terminal); }); vscode.window.onDidCloseTerminal(terminal => { // Find and remove the terminal from our map for (const [name, term] of this.terminals.entries()) { if (term === terminal) { this.terminals.delete(name); break; } } }); // Initialize with existing terminals vscode.window.terminals.forEach(terminal => { this.terminals.set(terminal.name, terminal); }); } registerTools() { // Create terminal this.server.registerTool('terminal_create', 'Create new terminal', { type: 'object', properties: { name: { type: 'string', description: 'Terminal name' }, shellPath: { type: 'string', description: 'Shell executable path' }, shellArgs: { type: 'array', items: { type: 'string' }, description: 'Shell arguments' }, cwd: { type: 'string', description: 'Working directory' }, env: { type: 'object', description: 'Environment variables', additionalProperties: { type: 'string' } }, hideFromUser: { type: 'boolean', description: 'Hide from user', default: false }, message: { type: 'string', description: 'Welcome message' }, }, }, this.createTerminal.bind(this)); // Get all terminals this.server.registerTool('terminal_get_all', 'Get all terminals', { type: 'object', properties: {}, }, this.getAllTerminals.bind(this)); // Send text to terminal this.server.registerTool('terminal_send_text', 'Send command to terminal', { type: 'object', properties: { terminalName: { type: 'string', description: 'Terminal name (optional, uses active if not provided)' }, text: { type: 'string', description: 'Text to send' }, addNewLine: { type: 'boolean', description: 'Add newline after text', default: true }, }, required: ['text'], }, this.sendText.bind(this)); // Show terminal this.server.registerTool('terminal_show', 'Show terminal panel', { type: 'object', properties: { terminalName: { type: 'string', description: 'Terminal name (optional, shows active if not provided)' }, preserveFocus: { type: 'boolean', description: 'Preserve editor focus', default: false }, }, }, this.showTerminal.bind(this)); // Hide terminal this.server.registerTool('terminal_hide', 'Hide terminal panel', { type: 'object', properties: {}, }, this.hideTerminal.bind(this)); // Dispose terminal this.server.registerTool('terminal_dispose', 'Close terminal', { type: 'object', properties: { terminalName: { type: 'string', description: 'Terminal name to close' }, }, required: ['terminalName'], }, this.disposeTerminal.bind(this)); // Get terminal info this.server.registerTool('terminal_get_info', 'Get terminal information', { type: 'object', properties: { terminalName: { type: 'string', description: 'Terminal name (optional, uses active if not provided)' }, }, }, this.getTerminalInfo.bind(this)); // Execute command and wait this.server.registerTool('terminal_execute_command', 'Execute command and optionally wait for completion', { type: 'object', properties: { command: { type: 'string', description: 'Command to execute' }, terminalName: { type: 'string', description: 'Terminal name (optional, uses active if not provided)' }, waitForCompletion: { type: 'boolean', description: 'Wait for command completion', default: false }, timeout: { type: 'number', description: 'Timeout in milliseconds for waiting', default: 30000 }, }, required: ['command'], }, this.executeCommand.bind(this)); // Clear terminal this.server.registerTool('terminal_clear', 'Clear terminal content', { type: 'object', properties: { terminalName: { type: 'string', description: 'Terminal name (optional, uses active if not provided)' }, }, }, this.clearTerminal.bind(this)); } getTerminal(name) { if (name) { return this.terminals.get(name) || vscode.window.terminals.find(t => t.name === name); } return vscode.window.activeTerminal; } async createTerminal(args) { try { const options = {}; if (args.name) options.name = args.name; if (args.shellPath) options.shellPath = args.shellPath; if (args.shellArgs) options.shellArgs = args.shellArgs; if (args.cwd) options.cwd = args.cwd; if (args.env) options.env = args.env; if (args.hideFromUser) options.hideFromUser = args.hideFromUser; if (args.message) options.message = args.message; const terminal = vscode.window.createTerminal(options); const terminalName = terminal.name; this.terminals.set(terminalName, terminal); return this.server.createSuccessResponse({ name: terminalName, processId: await terminal.processId, }, `Terminal '${terminalName}' created`); } catch (error) { return this.server.createErrorResponse(error); } } async getAllTerminals() { try { const terminals = await Promise.all(vscode.window.terminals.map(async (terminal) => ({ name: terminal.name, processId: await terminal.processId, creationOptions: terminal.creationOptions, }))); return this.server.createSuccessResponse(terminals); } catch (error) { return this.server.createErrorResponse(error); } } async sendText(args) { try { this.server.validateRequiredParams(args, ['text']); const terminal = this.getTerminal(args.terminalName); if (!terminal) { return this.server.createErrorResponse('No terminal found'); } terminal.sendText(args.text, args.addNewLine !== false); return this.server.createSuccessResponse({ success: true }, `Text sent to terminal '${terminal.name}'`); } catch (error) { return this.server.createErrorResponse(error); } } async showTerminal(args) { try { const terminal = this.getTerminal(args.terminalName); if (!terminal) { return this.server.createErrorResponse('No terminal found'); } terminal.show(args.preserveFocus || false); return this.server.createSuccessResponse({ success: true }, `Terminal '${terminal.name}' shown`); } catch (error) { return this.server.createErrorResponse(error); } } async hideTerminal() { try { await vscode.commands.executeCommand('workbench.action.terminal.toggleTerminal'); return this.server.createSuccessResponse({ success: true }, 'Terminal panel hidden'); } catch (error) { return this.server.createErrorResponse(error); } } async disposeTerminal(args) { try { this.server.validateRequiredParams(args, ['terminalName']); const terminal = this.getTerminal(args.terminalName); if (!terminal) { return this.server.createErrorResponse(`Terminal '${args.terminalName}' not found`); } terminal.dispose(); this.terminals.delete(args.terminalName); return this.server.createSuccessResponse({ success: true }, `Terminal '${args.terminalName}' closed`); } catch (error) { return this.server.createErrorResponse(error); } } async getTerminalInfo(args) { try { const terminal = this.getTerminal(args.terminalName); if (!terminal) { return this.server.createErrorResponse('No terminal found'); } const terminalInfo = { name: terminal.name, processId: await terminal.processId, creationOptions: terminal.creationOptions, }; return this.server.createSuccessResponse(terminalInfo); } catch (error) { return this.server.createErrorResponse(error); } } async executeCommand(args) { try { this.server.validateRequiredParams(args, ['command']); const terminal = this.getTerminal(args.terminalName); if (!terminal) { return this.server.createErrorResponse('No terminal found'); } terminal.sendText(args.command, true); if (args.waitForCompletion) { // Note: VSCode doesn't provide direct access to terminal output // This would need to be implemented through custom shell integration // For now, we'll simulate waiting with a timeout await new Promise(resolve => setTimeout(resolve, Math.min(args.timeout || 30000, 1000))); return this.server.createSuccessResponse({ success: true, command: args.command, waited: true, note: 'Command executed. Note: Output capture requires custom shell integration.' }, `Command executed in terminal '${terminal.name}'`); } else { return this.server.createSuccessResponse({ success: true, command: args.command, waited: false }, `Command sent to terminal '${terminal.name}'`); } } catch (error) { return this.server.createErrorResponse(error); } } async clearTerminal(args) { try { const terminal = this.getTerminal(args.terminalName); if (!terminal) { return this.server.createErrorResponse('No terminal found'); } // Send clear command (works on most shells) terminal.sendText('clear', true); return this.server.createSuccessResponse({ success: true }, `Terminal '${terminal.name}' cleared`); } catch (error) { return this.server.createErrorResponse(error); } } dispose() { // Dispose all tracked terminals for (const terminal of this.terminals.values()) { terminal.dispose(); } this.terminals.clear(); } } //# sourceMappingURL=terminalTools.js.map