@wonderwhy-er/desktop-commander
Version:
MCP server for terminal operations and file editing
218 lines (217 loc) • 7.48 kB
JavaScript
/**
* 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'
};
}
}
}