UNPKG

@wonderwhy-er/desktop-commander

Version:

MCP server for terminal operations and file editing

218 lines (217 loc) 7.48 kB
/** * Client-side utility for interacting with the REPL functionality */ export class REPLClient { constructor(apiClient) { this.apiClient = apiClient; this.sessions = {}; } /** * Create a new REPL session for a specific language * @param language - Language for the REPL (python, node, bash) * @param options - Optional configuration * @returns Session information */ async createSession(language, options = {}) { try { const response = await this.apiClient.executeCommand('repl.create', { language, options }); if (response.success && response.pid) { this.sessions[response.pid] = { language, pid: response.pid, createdAt: new Date() }; } return response; } catch (error) { console.error('Failed to create REPL session:', error); return { success: false, error: error.message || 'Failed to create REPL session' }; } } /** * Execute code in an existing REPL session * @param pid - Process ID of the session * @param code - Code to execute * @param options - Optional execution options * @returns Execution results */ async executeCode(pid, code, options = {}) { try { return await this.apiClient.executeCommand('repl.execute', { pid, code, options }); } catch (error) { console.error('Failed to execute code:', error); return { success: false, error: error.message || 'Failed to execute code' }; } } /** * List all active REPL sessions * @returns List of active sessions */ async listSessions() { try { return await this.apiClient.executeCommand('repl.list'); } catch (error) { console.error('Failed to list REPL sessions:', error); return { success: false, error: error.message || 'Failed to list REPL sessions' }; } } /** * Close a specific REPL session * @param pid - Process ID to close * @returns Result indicating success */ async closeSession(pid) { try { const response = await this.apiClient.executeCommand('repl.close', { pid }); if (response.success) { delete this.sessions[pid]; } return response; } catch (error) { console.error('Failed to close REPL session:', error); return { success: false, error: error.message || 'Failed to close REPL session' }; } } /** * Close all idle REPL sessions * @param maxIdleMs - Maximum idle time in milliseconds * @returns Result with number of closed sessions */ async closeIdleSessions(maxIdleMs) { try { const response = await this.apiClient.executeCommand('repl.closeIdle', { maxIdleMs }); // If successful, refresh our local session cache if (response.success && response.closedCount > 0) { const activeSessionsResponse = await this.listSessions(); if (activeSessionsResponse.success) { // Reset our session tracking this.sessions = {}; // Add back active sessions activeSessionsResponse.sessions.forEach((session) => { this.sessions[session.pid] = { language: session.language, pid: session.pid, createdAt: new Date(session.startTime) }; }); } } return response; } catch (error) { console.error('Failed to close idle REPL sessions:', error); return { success: false, error: error.message || 'Failed to close idle REPL sessions' }; } } /** * Execute a multi-line code block in the appropriate REPL session * @param codeBlock - Code block with language marker * @param options - Optional execution options * @returns Execution results */ async executeCodeBlock(codeBlock, options = {}) { try { // Parse code block format with language marker // Example: ```python // print("Hello") // ``` const match = codeBlock.match(/```(\w+)\s*\n([\s\S]+?)```/); if (!match) { return { success: false, error: 'Invalid code block format. Use ```language\\ncode```' }; } const language = match[1].toLowerCase(); const code = match[2].trim(); // Find or create session for this language let pid = null; // Look for existing session for (const sessionPid in this.sessions) { if (this.sessions[sessionPid].language === language) { pid = parseInt(sessionPid); break; } } // Create new session if needed if (!pid) { const createResult = await this.createSession(language, options); if (!createResult.success) { return createResult; } pid = createResult.pid; } // Execute the code return await this.executeCode(pid, code, options); } catch (error) { console.error('Failed to execute code block:', error); return { success: false, error: error.message || 'Failed to execute code block' }; } } /** * Run a simple one-liner code snippet * @param language - The programming language * @param code - Code to execute (single line) * @param options - Optional execution options * @returns Execution results */ async runSnippet(language, code, options = {}) { try { // Look for existing session let pid = null; for (const sessionPid in this.sessions) { if (this.sessions[sessionPid].language === language.toLowerCase()) { pid = parseInt(sessionPid); break; } } // Create new session if needed if (!pid) { const createResult = await this.createSession(language, options); if (!createResult.success) { return createResult; } pid = createResult.pid; } // Execute the code return await this.executeCode(pid, code, options); } catch (error) { console.error('Failed to run snippet:', error); return { success: false, error: error.message || 'Failed to run snippet' }; } } }