@wonderwhy-er/desktop-commander 0.2.5 → 0.2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. package/dist/index-dxt.js +10 -47
  2. package/dist/server.js +6 -0
  3. package/dist/tools/filesystem.js +37 -4
  4. package/dist/utils/usageTracker.js +8 -5
  5. package/dist/version.d.ts +1 -1
  6. package/dist/version.js +1 -1
  7. package/package.json +2 -1
  8. package/dist/REPLSessionManager.d.ts +0 -109
  9. package/dist/REPLSessionManager.js +0 -364
  10. package/dist/REPLSessionManager.test.d.ts +0 -1
  11. package/dist/REPLSessionManager.test.js +0 -75
  12. package/dist/client/replClient.d.ts +0 -63
  13. package/dist/client/replClient.js +0 -217
  14. package/dist/client/sshClient.d.ts +0 -82
  15. package/dist/client/sshClient.js +0 -200
  16. package/dist/command-manager.js.map +0 -1
  17. package/dist/config-manager.js.map +0 -1
  18. package/dist/config.js.map +0 -1
  19. package/dist/custom-stdio.js.map +0 -1
  20. package/dist/error-handlers.js.map +0 -1
  21. package/dist/handlers/command-handlers.d.ts +0 -13
  22. package/dist/handlers/command-handlers.js +0 -43
  23. package/dist/handlers/edit-search-handlers.js.map +0 -1
  24. package/dist/handlers/filesystem-handlers.js.map +0 -1
  25. package/dist/handlers/fuzzy-search-log-handlers.d.ts +0 -13
  26. package/dist/handlers/fuzzy-search-log-handlers.js +0 -179
  27. package/dist/handlers/index.js.map +0 -1
  28. package/dist/handlers/process-handlers.js.map +0 -1
  29. package/dist/handlers/repl-handlers.d.ts +0 -21
  30. package/dist/handlers/repl-handlers.js +0 -37
  31. package/dist/handlers/replCommandHandler.d.ts +0 -125
  32. package/dist/handlers/replCommandHandler.js +0 -255
  33. package/dist/handlers/replCommandHandler.test.d.ts +0 -1
  34. package/dist/handlers/replCommandHandler.test.js +0 -103
  35. package/dist/handlers/terminal-handlers.js.map +0 -1
  36. package/dist/index-with-startup-detection.d.ts +0 -5
  37. package/dist/index-with-startup-detection.js +0 -180
  38. package/dist/index.js.map +0 -1
  39. package/dist/logging.d.ts +0 -2
  40. package/dist/logging.js +0 -28
  41. package/dist/polyform-license-src/edit/edit.d.ts +0 -15
  42. package/dist/polyform-license-src/edit/edit.js +0 -163
  43. package/dist/polyform-license-src/edit/fuzzySearch.d.ts +0 -30
  44. package/dist/polyform-license-src/edit/fuzzySearch.js +0 -121
  45. package/dist/polyform-license-src/edit/handlers.d.ts +0 -16
  46. package/dist/polyform-license-src/edit/handlers.js +0 -24
  47. package/dist/polyform-license-src/edit/index.d.ts +0 -12
  48. package/dist/polyform-license-src/edit/index.js +0 -13
  49. package/dist/polyform-license-src/edit/schemas.d.ts +0 -25
  50. package/dist/polyform-license-src/edit/schemas.js +0 -16
  51. package/dist/polyform-license-src/index.d.ts +0 -9
  52. package/dist/polyform-license-src/index.js +0 -10
  53. package/dist/repl-manager.d.ts +0 -73
  54. package/dist/repl-manager.js +0 -407
  55. package/dist/replIntegration.d.ts +0 -14
  56. package/dist/replIntegration.js +0 -27
  57. package/dist/sandbox/index.d.ts +0 -9
  58. package/dist/sandbox/index.js +0 -50
  59. package/dist/sandbox/mac-sandbox.d.ts +0 -19
  60. package/dist/sandbox/mac-sandbox.js +0 -174
  61. package/dist/server.js.map +0 -1
  62. package/dist/setup.log +0 -32
  63. package/dist/terminal-manager.js.map +0 -1
  64. package/dist/tools/client.d.ts +0 -10
  65. package/dist/tools/client.js +0 -13
  66. package/dist/tools/command-block.d.ts +0 -18
  67. package/dist/tools/command-block.js +0 -62
  68. package/dist/tools/config.js.map +0 -1
  69. package/dist/tools/debug-path.d.ts +0 -1
  70. package/dist/tools/debug-path.js +0 -44
  71. package/dist/tools/edit.js.map +0 -1
  72. package/dist/tools/enhanced-read-output.js +0 -69
  73. package/dist/tools/enhanced-send-input.js +0 -111
  74. package/dist/tools/environment.d.ts +0 -55
  75. package/dist/tools/environment.js +0 -65
  76. package/dist/tools/execute.d.ts +0 -10
  77. package/dist/tools/execute.js +0 -158
  78. package/dist/tools/execute.js.map +0 -1
  79. package/dist/tools/filesystem-fixed.d.ts +0 -22
  80. package/dist/tools/filesystem-fixed.js +0 -176
  81. package/dist/tools/filesystem.js.map +0 -1
  82. package/dist/tools/fuzzySearch.js.map +0 -1
  83. package/dist/tools/mime-types.js.map +0 -1
  84. package/dist/tools/pdf-reader.d.ts +0 -13
  85. package/dist/tools/pdf-reader.js +0 -214
  86. package/dist/tools/process.js.map +0 -1
  87. package/dist/tools/progress.d.ts +0 -20
  88. package/dist/tools/progress.js +0 -59
  89. package/dist/tools/repl.d.ts +0 -21
  90. package/dist/tools/repl.js +0 -217
  91. package/dist/tools/schemas.js.map +0 -1
  92. package/dist/tools/search.js.map +0 -1
  93. package/dist/tools/send-input.d.ts +0 -2
  94. package/dist/tools/send-input.js +0 -45
  95. package/dist/types.js.map +0 -1
  96. package/dist/utils/capture.js.map +0 -1
  97. package/dist/utils/early-logger.d.ts +0 -4
  98. package/dist/utils/early-logger.js +0 -35
  99. package/dist/utils/fuzzySearchLogger.js.map +0 -1
  100. package/dist/utils/lineEndingHandler.js.map +0 -1
  101. package/dist/utils/lineEndingHandler_optimized.d.ts +0 -21
  102. package/dist/utils/lineEndingHandler_optimized.js +0 -77
  103. package/dist/utils/mcp-logger.d.ts +0 -30
  104. package/dist/utils/mcp-logger.js +0 -59
  105. package/dist/utils/smithery-detector.d.ts +0 -94
  106. package/dist/utils/smithery-detector.js +0 -292
  107. package/dist/utils/startup-detector.d.ts +0 -65
  108. package/dist/utils/startup-detector.js +0 -390
  109. package/dist/utils/trackTools.js.map +0 -1
  110. package/dist/utils/withTimeout.js.map +0 -1
  111. package/dist/utils.d.ts +0 -26
  112. package/dist/utils.js +0 -227
  113. package/dist/version.js.map +0 -1
package/dist/index-dxt.js CHANGED
@@ -1,76 +1,39 @@
1
1
  #!/usr/bin/env node
2
- // Add immediate logging before any imports
3
- console.error("[DXT] === ENTRY POINT START ===");
4
- console.error(`[DXT] Node version: ${process.version}`);
5
- console.error(`[DXT] Platform: ${process.platform}`);
6
- console.error(`[DXT] Working directory: ${process.cwd()}`);
7
- console.error(`[DXT] __dirname: ${__dirname}`);
8
- console.error(`[DXT] Args: ${JSON.stringify(process.argv)}`);
9
- // Add error handlers immediately
10
- process.on('uncaughtException', (error) => {
11
- console.error(`[DXT] UNCAUGHT EXCEPTION: ${error.message}`);
12
- console.error(`[DXT] Stack: ${error.stack}`);
13
- });
14
- process.on('unhandledRejection', (reason) => {
15
- console.error(`[DXT] UNHANDLED REJECTION: ${String(reason)}`);
16
- });
17
- process.on('exit', (code) => {
18
- console.error(`[DXT] PROCESS EXITING with code: ${code}`);
19
- });
20
- console.error("[DXT] About to import modules...");
21
2
  // Simplified entry point for DXT that avoids configuration loading issues
22
3
  import { FilteredStdioServerTransport } from './custom-stdio.js';
23
- console.error("[DXT] FilteredStdioServerTransport imported");
24
4
  import { server } from './server.js';
25
- console.error("[DXT] Server imported");
26
5
  async function runDXTServer() {
27
6
  try {
28
- console.error("[DXT] === runDXTServer() START ===");
29
- console.error("=== DXT DEBUG START ===");
30
- console.error(`Node version: ${process.version}`);
31
- console.error(`Platform: ${process.platform}`);
32
- console.error(`Working directory: ${process.cwd()}`);
33
- console.error(`__dirname: ${__dirname}`);
34
- console.error(`Args: ${JSON.stringify(process.argv)}`);
35
- console.error("=== DXT DEBUG END ===");
36
- console.error("[DXT] About to create transport...");
7
+ console.error("Starting Desktop Commander MCP for DXT...");
37
8
  // Create transport
38
9
  const transport = new FilteredStdioServerTransport();
39
- console.error("[DXT] Transport created successfully");
40
- // Send structured debug info
41
- transport.sendLog("info", "DXT Server Starting", {
42
- nodeVersion: process.version,
43
- platform: process.platform,
44
- cwd: process.cwd(),
45
- dirname: __dirname,
46
- argv: process.argv
10
+ // Handle process errors gracefully
11
+ process.on('uncaughtException', (error) => {
12
+ console.error(`[DXT] Uncaught exception: ${error.message}`);
13
+ // Don't exit immediately - let the server handle it
14
+ });
15
+ process.on('unhandledRejection', (reason) => {
16
+ console.error(`[DXT] Unhandled rejection: ${reason}`);
17
+ // Don't exit immediately - let the server handle it
47
18
  });
48
- console.error("[DXT] Debug info sent via transport");
49
19
  // Connect server
50
- console.error("[DXT] About to connect server...");
51
20
  console.error("Connecting MCP server...");
52
21
  await server.connect(transport);
53
- console.error("[DXT] Server connected successfully!");
54
22
  console.error("MCP server connected successfully");
55
- transport.sendLog("info", "MCP server connected successfully in DXT mode");
56
- console.error("[DXT] === runDXTServer() END ===");
57
23
  }
58
24
  catch (error) {
59
25
  const errorMessage = error instanceof Error ? error.message : String(error);
60
26
  const errorStack = error instanceof Error ? error.stack : undefined;
61
- console.error(`[DXT] FATAL ERROR in runDXTServer: ${errorMessage}`);
27
+ console.error(`[DXT] FATAL ERROR: ${errorMessage}`);
62
28
  if (errorStack) {
63
29
  console.error(`[DXT] Stack: ${errorStack}`);
64
30
  }
65
31
  process.exit(1);
66
32
  }
67
33
  }
68
- console.error("[DXT] About to call runDXTServer...");
69
34
  // Run the server
70
35
  runDXTServer().catch((error) => {
71
36
  const errorMessage = error instanceof Error ? error.message : String(error);
72
- console.error(`[DXT] Failed to start in catch block: ${errorMessage}`);
73
37
  console.error(`[DXT] Failed to start: ${errorMessage}`);
74
38
  process.exit(1);
75
39
  });
76
- console.error("[DXT] === ENTRY POINT END ===");
package/dist/server.js CHANGED
@@ -365,6 +365,9 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
365
365
  • start_process("wc -l /path/file.csv") → Line counting
366
366
  • start_process("head -10 /path/file.csv") → File preview
367
367
 
368
+ BINARY FILE SUPPORT:
369
+ For PDF, Excel, Word, archives, databases, and other binary formats, use process tools with appropriate libraries or command-line utilities.
370
+
368
371
  INTERACTIVE PROCESSES FOR DATA ANALYSIS:
369
372
  1. start_process("python3 -i") - Start Python REPL for data work
370
373
  2. start_process("node -i") - Start Node.js REPL for JSON/JS
@@ -438,6 +441,9 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
438
441
  4. Analyze: interact_with_process(pid, "print(df.describe())")
439
442
  5. Continue: interact_with_process(pid, "df.groupby('column').size()")
440
443
 
444
+ BINARY FILE PROCESSING WORKFLOWS:
445
+ Use appropriate Python libraries (PyPDF2, pandas, docx2txt, etc.) or command-line tools for binary file analysis.
446
+
441
447
  SMART DETECTION:
442
448
  - Automatically waits for REPL prompt (>>>, >, etc.)
443
449
  - Detects errors and completion states
@@ -4,6 +4,7 @@ import os from 'os';
4
4
  import fetch from 'cross-fetch';
5
5
  import { createReadStream } from 'fs';
6
6
  import { createInterface } from 'readline';
7
+ import { isBinaryFile } from 'isbinaryfile';
7
8
  import { capture } from '../utils/capture.js';
8
9
  import { withTimeout } from '../utils/withTimeout.js';
9
10
  import { configManager } from '../config-manager.js';
@@ -78,6 +79,20 @@ async function getDefaultReadLength() {
78
79
  const config = await configManager.getConfig();
79
80
  return config.fileReadLineLimit ?? 1000; // Default to 1000 lines if not set
80
81
  }
82
+ /**
83
+ * Generate instructions for handling binary files
84
+ * @param filePath Path to the binary file
85
+ * @param mimeType MIME type of the file
86
+ * @returns Instruction message for the LLM
87
+ */
88
+ function getBinaryFileInstructions(filePath, mimeType) {
89
+ const fileName = path.basename(filePath);
90
+ return `Cannot read binary file as text: ${fileName} (${mimeType})
91
+
92
+ Use start_process + interact_with_process to analyze binary files with appropriate tools (Node.js or Python libraries, command-line utilities, etc.).
93
+
94
+ The read_file tool only handles text files and images.`;
95
+ }
81
96
  // Initialize allowed directories from configuration
82
97
  async function getAllowedDirs() {
83
98
  try {
@@ -329,6 +344,16 @@ function generateEnhancedStatusMessage(readLines, offset, totalLines, isNegative
329
344
  async function readFileWithSmartPositioning(filePath, offset, length, mimeType, includeStatusMessage = true) {
330
345
  const stats = await fs.stat(filePath);
331
346
  const fileSize = stats.size;
347
+ // Check if the file is binary (but allow images to pass through)
348
+ const { isImage } = await getMimeTypeInfo(filePath);
349
+ if (!isImage) {
350
+ const isBinary = await isBinaryFile(filePath);
351
+ if (isBinary) {
352
+ // Return instructions instead of trying to read binary content
353
+ const instructions = getBinaryFileInstructions(filePath, mimeType);
354
+ throw new Error(instructions);
355
+ }
356
+ }
332
357
  // Get total line count for enhanced status messages (only for smaller files)
333
358
  const totalLines = await getFileLineCount(filePath);
334
359
  // For negative offsets (tail behavior), use reverse reading
@@ -574,10 +599,18 @@ export async function readFileFromDisk(filePath, offset = 0, length) {
574
599
  return await readFileWithSmartPositioning(validPath, offset, length, mimeType, true);
575
600
  }
576
601
  catch (error) {
577
- // If UTF-8 reading fails, treat as binary and return base64 but still as text
578
- const buffer = await fs.readFile(validPath);
579
- const content = `Binary file content (base64 encoded):\n${buffer.toString('base64')}`;
580
- return { content, mimeType: 'text/plain', isImage: false };
602
+ // If it's our binary file instruction error, return it as content
603
+ if (error instanceof Error && error.message.includes('Cannot read binary file as text:')) {
604
+ return { content: error.message, mimeType: 'text/plain', isImage: false };
605
+ }
606
+ // If UTF-8 reading fails for other reasons, also check if it's binary
607
+ const isBinary = await isBinaryFile(validPath);
608
+ if (isBinary) {
609
+ const instructions = getBinaryFileInstructions(validPath, mimeType);
610
+ return { content: instructions, mimeType: 'text/plain', isImage: false };
611
+ }
612
+ // Only if it's truly not binary, then we have a real UTF-8 reading error
613
+ throw error;
581
614
  }
582
615
  }
583
616
  };
@@ -149,18 +149,21 @@ class UsageTracker {
149
149
  * Check if user should be prompted for feedback based on usage patterns
150
150
  */
151
151
  async shouldPromptForFeedback() {
152
+ return false;
153
+ /* TODO Turn off feedback requests until further issue investigation
152
154
  const stats = await this.getStats();
155
+
153
156
  // Don't prompt if feedback already given (check top-level config)
154
157
  const feedbackGiven = await configManager.getValue('feedbackGiven');
155
- if (feedbackGiven === true)
156
- return false;
158
+ if (feedbackGiven === true) return false;
159
+
157
160
  // Check if enough time has passed since last prompt (2 hours minimum)
158
161
  const now = Date.now();
159
162
  const hoursSinceLastPrompt = (now - stats.lastFeedbackPrompt) / (1000 * 60 * 60);
160
- if (stats.lastFeedbackPrompt > 0 && hoursSinceLastPrompt < 2)
161
- return false;
163
+ if (stats.lastFeedbackPrompt > 0 && hoursSinceLastPrompt < 2) return false;
164
+
162
165
  // MAIN TRIGGER: 25+ total tool calls (earlier trigger for faster feedback)
163
- return stats.totalToolCalls >= 25;
166
+ return stats.totalToolCalls >= 25;*/
164
167
  }
165
168
  /**
166
169
  * Get a random feedback prompt message with strong CTAs and clear actions
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const VERSION = "0.2.5";
1
+ export declare const VERSION = "0.2.7";
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const VERSION = '0.2.5';
1
+ export const VERSION = '0.2.7';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wonderwhy-er/desktop-commander",
3
- "version": "0.2.5",
3
+ "version": "0.2.7",
4
4
  "description": "MCP server for terminal operations and file editing",
5
5
  "license": "MIT",
6
6
  "author": "Eduards Ruzga",
@@ -71,6 +71,7 @@
71
71
  "cross-fetch": "^4.1.0",
72
72
  "fastest-levenshtein": "^1.0.16",
73
73
  "glob": "^10.3.10",
74
+ "isbinaryfile": "^5.0.4",
74
75
  "zod": "^3.24.1",
75
76
  "zod-to-json-schema": "^3.23.5"
76
77
  },
@@ -1,109 +0,0 @@
1
- interface TerminalManager {
2
- executeCommand: (command: string, options?: any) => Promise<any>;
3
- sendInputToProcess: (pid: number, input: string) => boolean;
4
- getNewOutput: (pid: number) => string;
5
- terminateProcess: (pid: number) => Promise<boolean>;
6
- }
7
- interface SSHOptions {
8
- username?: string;
9
- port?: number;
10
- identity?: string;
11
- password?: string;
12
- timeout?: number;
13
- }
14
- interface ExecuteOptions {
15
- timeout?: number;
16
- stopOnError?: boolean;
17
- }
18
- export declare class REPLSessionManager {
19
- private sessions;
20
- private terminalManager;
21
- private defaultPromptPatterns;
22
- constructor(terminalManager: TerminalManager);
23
- /**
24
- * Create a new SSH session
25
- * @param host - SSH host to connect to
26
- * @param options - SSH connection options
27
- * @returns PID of the created SSH session
28
- */
29
- createSSHSession(host: string, options?: SSHOptions): Promise<number>;
30
- /**
31
- * Create a new REPL session for a specific language
32
- * @param language - Language for the REPL (python, node, bash)
33
- * @param options - Configuration options
34
- * @returns PID of the created session
35
- */
36
- createSession(language: string, options?: any): Promise<number>;
37
- /**
38
- * Execute code in an existing REPL session
39
- * @param pid - Process ID of the REPL session
40
- * @param code - Code to execute
41
- * @param options - Execution options
42
- * @returns Results including output and status
43
- */
44
- executeCode(pid: number, code: string, options?: ExecuteOptions): Promise<any>;
45
- /**
46
- * Send input to a REPL process and wait for output with timeout
47
- * @param pid - Process ID
48
- * @param input - Input to send
49
- * @param language - REPL language
50
- * @param timeoutMs - Timeout in milliseconds
51
- * @returns Result object with output and status
52
- */
53
- sendAndReadREPL(pid: number, input: string, language: string, timeoutMs?: number): Promise<any>;
54
- /**
55
- * Handle multi-line code input for different languages
56
- * @param pid - Process ID
57
- * @param code - Multi-line code
58
- * @param language - REPL language
59
- * @param timeout - Timeout in milliseconds
60
- * @returns Result object
61
- */
62
- handleMultilineCode(pid: number, code: string, language: string, timeout: number): Promise<any>;
63
- /**
64
- * Detect if the REPL output is complete and ready for next input
65
- * @param output - Current output
66
- * @param language - REPL language or session type
67
- * @returns Whether output is complete
68
- */
69
- isOutputComplete(output: string, language: string): boolean;
70
- /**
71
- * Calculate appropriate timeout based on code complexity
72
- * @param code - Code to analyze
73
- * @returns Timeout in milliseconds
74
- */
75
- calculateTimeout(code: string): number;
76
- /**
77
- * Detect errors in REPL output
78
- * @param output - REPL output
79
- * @param language - REPL language
80
- * @returns Detected error or null
81
- */
82
- detectErrors(output: string, language: string): string | null;
83
- /**
84
- * Clean and format REPL output
85
- * @param output - Raw output
86
- * @param input - Input that was sent
87
- * @param language - REPL language
88
- * @returns Cleaned output
89
- */
90
- cleanOutput(output: string, input: string, language: string): string;
91
- /**
92
- * List all active REPL sessions
93
- * @returns List of session objects
94
- */
95
- listSessions(): Array<any>;
96
- /**
97
- * Close a specific REPL session
98
- * @param pid - Process ID to close
99
- * @returns Success status
100
- */
101
- closeSession(pid: number): Promise<boolean>;
102
- /**
103
- * Close all idle sessions older than specified time
104
- * @param maxIdleMs - Maximum idle time in milliseconds
105
- * @returns Number of closed sessions
106
- */
107
- closeIdleSessions(maxIdleMs?: number): Promise<number>;
108
- }
109
- export {};