UNPKG

@mseep/desktop-commander

Version:

MCP server for terminal operations and file editing

76 lines (75 loc) 2.88 kB
import { parseEditBlock, performSearchReplace } from '../tools/edit.js'; import { searchTextInFiles } from '../tools/search.js'; import { EditBlockArgsSchema, SearchCodeArgsSchema } from '../tools/schemas.js'; import { capture, withTimeout } from '../utils.js'; import { createErrorResponse } from '../error-handlers.js'; /** * Handle edit_block command */ export async function handleEditBlock(args) { const parsed = EditBlockArgsSchema.parse(args); const { filePath, searchReplace, error } = await parseEditBlock(parsed.blockContent); if (error) { return createErrorResponse(error); } return performSearchReplace(filePath, searchReplace); } /** * Handle search_code command */ export async function handleSearchCode(args) { const parsed = SearchCodeArgsSchema.parse(args); const timeoutMs = parsed.timeoutMs || 30000; // 30 seconds default // Apply timeout at the handler level const searchOperation = async () => { return await searchTextInFiles({ rootPath: parsed.path, pattern: parsed.pattern, filePattern: parsed.filePattern, ignoreCase: parsed.ignoreCase, maxResults: parsed.maxResults, includeHidden: parsed.includeHidden, contextLines: parsed.contextLines, // Don't pass timeoutMs down to the implementation }); }; // Use withTimeout at the handler level const results = await withTimeout(searchOperation(), timeoutMs, 'Code search operation', [] // Empty array as default on timeout ); // If timeout occurred, try to terminate the ripgrep process if (results.length === 0 && globalThis.currentSearchProcess) { try { console.log(`Terminating timed out search process (PID: ${globalThis.currentSearchProcess.pid})`); globalThis.currentSearchProcess.kill(); delete globalThis.currentSearchProcess; } catch (error) { capture('server_request_error', { error: 'Error terminating search process' }); } } if (results.length === 0) { if (timeoutMs > 0) { return { content: [{ type: "text", text: `No matches found or search timed out after ${timeoutMs}ms.` }], }; } return { content: [{ type: "text", text: "No matches found" }], }; } // Format the results in a VS Code-like format let currentFile = ""; let formattedResults = ""; results.forEach(result => { if (result.file !== currentFile) { formattedResults += `\n${result.file}:\n`; currentFile = result.file; } formattedResults += ` ${result.line}: ${result.match}\n`; }); return { content: [{ type: "text", text: formattedResults.trim() }], }; }