@wonderwhy-er/desktop-commander 0.2.15 → 0.2.16

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.
package/README.md CHANGED
@@ -954,7 +954,7 @@ External telemetry (sent to analytics services) is enabled by default but can be
954
954
 
955
955
  **Note:** This only disables external telemetry. Local usage analytics remain active for tool functionality but is not share externally
956
956
 
957
- For complete details about data collection, please see our [Privacy Policy](PRIVACY.md).
957
+ For complete details about data collection, please see our [Privacy Policy](https://legal.desktopcommander.app/privacy_desktop_commander_mcp).
958
958
 
959
959
  ## Verifications
960
960
  [![Verified on MseeP](https://mseep.ai/badge.svg)](https://mseep.ai/app/25ff7a06-58bc-40b8-bd79-ebb715140f1a)
@@ -132,6 +132,10 @@ export async function handleGetMoreSearchResults(args) {
132
132
  }
133
133
  if (results.isComplete) {
134
134
  output += `\n✅ Search completed.`;
135
+ // Warn users if search was incomplete due to permission issues
136
+ if (results.wasIncomplete) {
137
+ output += `\n⚠️ Warning: Some files were inaccessible due to permissions. Results may be incomplete.`;
138
+ }
135
139
  }
136
140
  return {
137
141
  content: [{ type: "text", text: output }],
@@ -18,6 +18,7 @@ export interface SearchSession {
18
18
  buffer: string;
19
19
  totalMatches: number;
20
20
  totalContextLines: number;
21
+ wasIncomplete?: boolean;
21
22
  }
22
23
  export interface SearchSessionOptions {
23
24
  rootPath: string;
@@ -64,6 +65,7 @@ export interface SearchSessionOptions {
64
65
  error?: string;
65
66
  hasMoreResults: boolean;
66
67
  runtime: number;
68
+ wasIncomplete?: boolean;
67
69
  };
68
70
  /**
69
71
  * Terminate a search session (like force_terminate)
@@ -105,4 +107,3 @@ export interface SearchSessionOptions {
105
107
  private parseLine;
106
108
  }
107
109
  export declare const searchManager: SearchManager;
108
- export declare function stopSearchManagerCleanup(): void;
@@ -120,7 +120,8 @@ import { capture } from './utils/capture.js';
120
120
  isError: session.isError && !!session.error?.trim(), // Only error if we have actual errors
121
121
  error: session.error?.trim() || undefined,
122
122
  hasMoreResults: false, // Tail always returns what's available
123
- runtime: Date.now() - session.startTime
123
+ runtime: Date.now() - session.startTime,
124
+ wasIncomplete: session.wasIncomplete
124
125
  };
125
126
  }
126
127
  // Handle positive offsets (range behavior) - like file reading
@@ -136,7 +137,8 @@ import { capture } from './utils/capture.js';
136
137
  isError: session.isError && !!session.error?.trim(), // Only error if we have actual errors
137
138
  error: session.error?.trim() || undefined,
138
139
  hasMoreResults,
139
- runtime: Date.now() - session.startTime
140
+ runtime: Date.now() - session.startTime,
141
+ wasIncomplete: session.wasIncomplete
140
142
  };
141
143
  }
142
144
  /**
@@ -149,7 +151,6 @@ import { capture } from './utils/capture.js';
149
151
  }
150
152
  if (!session.process.killed) {
151
153
  session.process.kill('SIGTERM');
152
- capture('search_session_terminated', { sessionId });
153
154
  }
154
155
  // Don't delete session immediately - let user read final results
155
156
  // It will be cleaned up by cleanup process
@@ -178,7 +179,6 @@ import { capture } from './utils/capture.js';
178
179
  for (const [sessionId, session] of this.sessions) {
179
180
  if (session.isComplete && session.lastReadTime < cutoffTime) {
180
181
  this.sessions.delete(sessionId);
181
- capture('search_session_cleaned_up', { sessionId });
182
182
  }
183
183
  }
184
184
  }
@@ -289,6 +289,9 @@ import { capture } from './utils/capture.js';
289
289
  });
290
290
  process.stderr?.on('data', (data) => {
291
291
  const errorText = data.toString();
292
+ // Store error text for potential user display, but don't capture individual errors
293
+ // We'll capture incomplete search status in the completion event instead
294
+ session.error = (session.error || '') + errorText;
292
295
  // Filter meaningful errors
293
296
  const filteredErrors = errorText
294
297
  .split('\n')
@@ -320,6 +323,11 @@ import { capture } from './utils/capture.js';
320
323
  this.processBufferedOutput(session, true);
321
324
  }
322
325
  session.isComplete = true;
326
+ // Track if search was incomplete due to access issues
327
+ // Ripgrep exit code 2 means "some files couldn't be searched"
328
+ if (code === 2) {
329
+ session.wasIncomplete = true;
330
+ }
323
331
  // Only treat as error if:
324
332
  // 1. Unexpected exit code (not 0, 1, or 2) AND
325
333
  // 2. We have meaningful errors after filtering AND
@@ -340,7 +348,8 @@ import { capture } from './utils/capture.js';
340
348
  exitCode: code,
341
349
  totalResults: session.totalMatches + session.totalContextLines,
342
350
  totalMatches: session.totalMatches,
343
- runtime: Date.now() - session.startTime
351
+ runtime: Date.now() - session.startTime,
352
+ wasIncomplete: session.wasIncomplete || false // NEW: Track incomplete searches
344
353
  });
345
354
  // Rely on cleanupSessions(maxAge) only; no per-session timer
346
355
  });
@@ -348,10 +357,6 @@ import { capture } from './utils/capture.js';
348
357
  session.isComplete = true;
349
358
  session.isError = true;
350
359
  session.error = `Process error: ${error.message}`;
351
- capture('search_session_process_error', {
352
- sessionId: session.id,
353
- error: error.message
354
- });
355
360
  // Rely on cleanupSessions(maxAge) only; no per-session timer
356
361
  });
357
362
  }
@@ -462,10 +467,3 @@ function startCleanupIfNeeded() {
462
467
  }, 1000);
463
468
  }
464
469
  }
465
- // Export cleanup function for graceful shutdown
466
- export function stopSearchManagerCleanup() {
467
- if (cleanupInterval) {
468
- clearInterval(cleanupInterval);
469
- cleanupInterval = null;
470
- }
471
- }
package/dist/server.js CHANGED
@@ -117,6 +117,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
117
117
  - systemInfo (operating system and environment details)
118
118
  ${CMD_PREFIX_DESCRIPTION}`,
119
119
  inputSchema: zodToJsonSchema(GetConfigArgsSchema),
120
+ annotations: {
121
+ title: "Get Configuration",
122
+ readOnlyHint: true,
123
+ },
120
124
  },
121
125
  {
122
126
  name: "set_config_value",
@@ -139,6 +143,12 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
139
143
 
140
144
  ${CMD_PREFIX_DESCRIPTION}`,
141
145
  inputSchema: zodToJsonSchema(SetConfigValueArgsSchema),
146
+ annotations: {
147
+ title: "Set Configuration Value",
148
+ readOnlyHint: false,
149
+ destructiveHint: true,
150
+ openWorldHint: false,
151
+ },
142
152
  },
143
153
  // Filesystem tools
144
154
  {
@@ -177,6 +187,11 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
177
187
  ${PATH_GUIDANCE}
178
188
  ${CMD_PREFIX_DESCRIPTION}`,
179
189
  inputSchema: zodToJsonSchema(ReadFileArgsSchema),
190
+ annotations: {
191
+ title: "Read File or URL",
192
+ readOnlyHint: true,
193
+ openWorldHint: true,
194
+ },
180
195
  },
181
196
  {
182
197
  name: "read_multiple_files",
@@ -193,6 +208,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
193
208
  ${PATH_GUIDANCE}
194
209
  ${CMD_PREFIX_DESCRIPTION}`,
195
210
  inputSchema: zodToJsonSchema(ReadMultipleFilesArgsSchema),
211
+ annotations: {
212
+ title: "Read Multiple Files",
213
+ readOnlyHint: true,
214
+ },
196
215
  },
197
216
  {
198
217
  name: "write_file",
@@ -226,6 +245,12 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
226
245
  ${PATH_GUIDANCE}
227
246
  ${CMD_PREFIX_DESCRIPTION}`,
228
247
  inputSchema: zodToJsonSchema(WriteFileArgsSchema),
248
+ annotations: {
249
+ title: "Write File",
250
+ readOnlyHint: false,
251
+ destructiveHint: true,
252
+ openWorldHint: false,
253
+ },
229
254
  },
230
255
  {
231
256
  name: "create_directory",
@@ -251,6 +276,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
251
276
  ${PATH_GUIDANCE}
252
277
  ${CMD_PREFIX_DESCRIPTION}`,
253
278
  inputSchema: zodToJsonSchema(ListDirectoryArgsSchema),
279
+ annotations: {
280
+ title: "List Directory Contents",
281
+ readOnlyHint: true,
282
+ },
254
283
  },
255
284
  {
256
285
  name: "move_file",
@@ -263,6 +292,12 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
263
292
  ${PATH_GUIDANCE}
264
293
  ${CMD_PREFIX_DESCRIPTION}`,
265
294
  inputSchema: zodToJsonSchema(MoveFileArgsSchema),
295
+ annotations: {
296
+ title: "Move/Rename File",
297
+ readOnlyHint: false,
298
+ destructiveHint: true,
299
+ openWorldHint: false,
300
+ },
266
301
  },
267
302
  {
268
303
  name: "start_search",
@@ -372,6 +407,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
372
407
 
373
408
  ${CMD_PREFIX_DESCRIPTION}`,
374
409
  inputSchema: zodToJsonSchema(GetMoreSearchResultsArgsSchema),
410
+ annotations: {
411
+ title: "Get Search Results",
412
+ readOnlyHint: true,
413
+ },
375
414
  },
376
415
  {
377
416
  name: "stop_search",
@@ -399,6 +438,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
399
438
 
400
439
  ${CMD_PREFIX_DESCRIPTION}`,
401
440
  inputSchema: zodToJsonSchema(ListSearchesArgsSchema),
441
+ annotations: {
442
+ title: "List Active Searches",
443
+ readOnlyHint: true,
444
+ },
402
445
  },
403
446
  {
404
447
  name: "get_file_info",
@@ -418,6 +461,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
418
461
  ${PATH_GUIDANCE}
419
462
  ${CMD_PREFIX_DESCRIPTION}`,
420
463
  inputSchema: zodToJsonSchema(GetFileInfoArgsSchema),
464
+ annotations: {
465
+ title: "Get File Information",
466
+ readOnlyHint: true,
467
+ },
421
468
  },
422
469
  // Note: list_allowed_directories removed - use get_config to check allowedDirectories
423
470
  // Text editing tools
@@ -457,6 +504,12 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
457
504
  ${PATH_GUIDANCE}
458
505
  ${CMD_PREFIX_DESCRIPTION}`,
459
506
  inputSchema: zodToJsonSchema(EditBlockArgsSchema),
507
+ annotations: {
508
+ title: "Edit Text Block",
509
+ readOnlyHint: false,
510
+ destructiveHint: true,
511
+ openWorldHint: false,
512
+ },
460
513
  },
461
514
  // Terminal tools
462
515
  {
@@ -513,6 +566,12 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
513
566
  ${PATH_GUIDANCE}
514
567
  ${CMD_PREFIX_DESCRIPTION}`,
515
568
  inputSchema: zodToJsonSchema(StartProcessArgsSchema),
569
+ annotations: {
570
+ title: "Start Terminal Process",
571
+ readOnlyHint: false,
572
+ destructiveHint: true,
573
+ openWorldHint: true,
574
+ },
516
575
  },
517
576
  {
518
577
  name: "read_process_output",
@@ -540,6 +599,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
540
599
 
541
600
  ${CMD_PREFIX_DESCRIPTION}`,
542
601
  inputSchema: zodToJsonSchema(ReadProcessOutputArgsSchema),
602
+ annotations: {
603
+ title: "Read Process Output",
604
+ readOnlyHint: true,
605
+ },
543
606
  },
544
607
  {
545
608
  name: "interact_with_process",
@@ -592,6 +655,12 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
592
655
 
593
656
  ${CMD_PREFIX_DESCRIPTION}`,
594
657
  inputSchema: zodToJsonSchema(InteractWithProcessArgsSchema),
658
+ annotations: {
659
+ title: "Send Input to Process",
660
+ readOnlyHint: false,
661
+ destructiveHint: true,
662
+ openWorldHint: true,
663
+ },
595
664
  },
596
665
  {
597
666
  name: "force_terminate",
@@ -600,6 +669,12 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
600
669
 
601
670
  ${CMD_PREFIX_DESCRIPTION}`,
602
671
  inputSchema: zodToJsonSchema(ForceTerminateArgsSchema),
672
+ annotations: {
673
+ title: "Force Terminate Process",
674
+ readOnlyHint: false,
675
+ destructiveHint: true,
676
+ openWorldHint: false,
677
+ },
603
678
  },
604
679
  {
605
680
  name: "list_sessions",
@@ -618,6 +693,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
618
693
 
619
694
  ${CMD_PREFIX_DESCRIPTION}`,
620
695
  inputSchema: zodToJsonSchema(ListSessionsArgsSchema),
696
+ annotations: {
697
+ title: "List Terminal Sessions",
698
+ readOnlyHint: true,
699
+ },
621
700
  },
622
701
  {
623
702
  name: "list_processes",
@@ -628,6 +707,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
628
707
 
629
708
  ${CMD_PREFIX_DESCRIPTION}`,
630
709
  inputSchema: zodToJsonSchema(ListProcessesArgsSchema),
710
+ annotations: {
711
+ title: "List Running Processes",
712
+ readOnlyHint: true,
713
+ },
631
714
  },
632
715
  {
633
716
  name: "kill_process",
@@ -638,6 +721,12 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
638
721
 
639
722
  ${CMD_PREFIX_DESCRIPTION}`,
640
723
  inputSchema: zodToJsonSchema(KillProcessArgsSchema),
724
+ annotations: {
725
+ title: "Kill Process",
726
+ readOnlyHint: false,
727
+ destructiveHint: true,
728
+ openWorldHint: false,
729
+ },
641
730
  },
642
731
  {
643
732
  name: "get_usage_stats",
@@ -648,6 +737,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
648
737
 
649
738
  ${CMD_PREFIX_DESCRIPTION}`,
650
739
  inputSchema: zodToJsonSchema(GetUsageStatsArgsSchema),
740
+ annotations: {
741
+ title: "Get Usage Statistics",
742
+ readOnlyHint: true,
743
+ },
651
744
  },
652
745
  {
653
746
  name: "give_feedback_to_desktop_commander",
@@ -14,17 +14,7 @@ export async function getConfig() {
14
14
  const configWithSystemInfo = {
15
15
  ...config,
16
16
  currentClient,
17
- systemInfo: {
18
- platform: systemInfo.platform,
19
- platformName: systemInfo.platformName,
20
- defaultShell: systemInfo.defaultShell,
21
- pathSeparator: systemInfo.pathSeparator,
22
- isWindows: systemInfo.isWindows,
23
- isMacOS: systemInfo.isMacOS,
24
- isLinux: systemInfo.isLinux,
25
- docker: systemInfo.docker,
26
- examplePaths: systemInfo.examplePaths
27
- }
17
+ systemInfo
28
18
  };
29
19
  console.error(`getConfig result: ${JSON.stringify(configWithSystemInfo, null, 2)}`);
30
20
  return {
@@ -29,6 +29,18 @@ export interface SystemInfo {
29
29
  isMacOS: boolean;
30
30
  isLinux: boolean;
31
31
  docker: ContainerInfo;
32
+ isDXT: boolean;
33
+ nodeInfo?: {
34
+ version: string;
35
+ path: string;
36
+ npmVersion?: string;
37
+ };
38
+ processInfo: {
39
+ pid: number;
40
+ arch: string;
41
+ platform: string;
42
+ versions: NodeJS.ProcessVersions;
43
+ };
32
44
  examplePaths: {
33
45
  home: string;
34
46
  temp: string;
@@ -305,6 +305,27 @@ function getContainerEnvironment(containerType) {
305
305
  }
306
306
  return Object.keys(env).length > 0 ? env : undefined;
307
307
  }
308
+ /**
309
+ * Detect Node.js installation and version from current process
310
+ */
311
+ function detectNodeInfo() {
312
+ try {
313
+ // Get Node.js version from current process
314
+ const version = process.version.replace('v', ''); // Remove 'v' prefix
315
+ // Get Node.js executable path from current process
316
+ const path = process.execPath;
317
+ // Get npm version from environment if available
318
+ const npmVersion = process.env.npm_version;
319
+ return {
320
+ version,
321
+ path,
322
+ ...(npmVersion && { npmVersion })
323
+ };
324
+ }
325
+ catch (error) {
326
+ return undefined;
327
+ }
328
+ }
308
329
  /**
309
330
  * Get comprehensive system information for tool prompts
310
331
  */
@@ -397,6 +418,15 @@ export function getSystemInfo() {
397
418
  examplePaths.accessible = mountPoints.map(mount => mount.containerPath);
398
419
  }
399
420
  }
421
+ // Detect Node.js installation from current process
422
+ const nodeInfo = detectNodeInfo();
423
+ // Get process information
424
+ const processInfo = {
425
+ pid: process.pid,
426
+ arch: process.arch,
427
+ platform: process.platform,
428
+ versions: process.versions
429
+ };
400
430
  return {
401
431
  platform,
402
432
  platformName,
@@ -415,6 +445,9 @@ export function getSystemInfo() {
415
445
  mountPoints,
416
446
  containerEnvironment: getContainerEnvironment(containerDetection.containerType)
417
447
  },
448
+ isDXT: !!process.env.MCP_DXT,
449
+ nodeInfo,
450
+ processInfo,
418
451
  examplePaths
419
452
  };
420
453
  }
@@ -545,33 +578,51 @@ LINUX-SPECIFIC NOTES:
545
578
  * Get common development tool guidance based on OS
546
579
  */
547
580
  export function getDevelopmentToolGuidance(systemInfo) {
548
- const { isWindows, isMacOS, isLinux, platformName } = systemInfo;
581
+ const { isWindows, isMacOS, isLinux, platformName, nodeInfo, processInfo } = systemInfo;
582
+ // Add detected Node.js info to guidance
583
+ const nodeGuidance = nodeInfo
584
+ ? `Node.js: v${nodeInfo.version} (${nodeInfo.path})${nodeInfo.npmVersion ? ` | npm: v${nodeInfo.npmVersion}` : ''}`
585
+ : 'Node.js: Not detected';
586
+ // Add process environment info
587
+ const envInfo = `
588
+ Current Process Environment:
589
+ - Node: v${processInfo.versions.node}
590
+ - V8: v${processInfo.versions.v8}
591
+ - Architecture: ${processInfo.arch}
592
+ - Platform: ${processInfo.platform}
593
+ - Process ID: ${processInfo.pid}`;
549
594
  if (isWindows) {
550
595
  return `
551
596
  COMMON WINDOWS DEVELOPMENT TOOLS:
552
- - Node.js: Usually installed globally, accessible from any shell
597
+ - ${nodeGuidance}
553
598
  - Python: May be 'python' or 'py' command, check both
554
599
  - Git: Git Bash provides Unix-like environment
555
600
  - WSL: Windows Subsystem for Linux available for Unix tools
556
- - Visual Studio tools: cl, msbuild for C++ compilation`;
601
+ - Visual Studio tools: cl, msbuild for C++ compilation
602
+
603
+ ${envInfo}`;
557
604
  }
558
605
  else if (isMacOS) {
559
606
  return `
560
607
  COMMON MACOS DEVELOPMENT TOOLS:
561
608
  - Xcode Command Line Tools: Required for many development tools
562
609
  - Homebrew: Primary package manager for development tools
610
+ - ${nodeGuidance}
563
611
  - Python: Usually python3, check if python points to Python 2
564
- - Node.js: Available via brew or direct installer
565
- - Ruby: System Ruby available, rbenv/rvm for version management`;
612
+ - Ruby: System Ruby available, rbenv/rvm for version management
613
+
614
+ ${envInfo}`;
566
615
  }
567
616
  else {
568
617
  return `
569
618
  COMMON LINUX DEVELOPMENT TOOLS:
570
619
  - Package managers: Install tools via distribution package manager
571
620
  - Python: Usually python3, python may point to Python 2
572
- - Node.js: Available via package manager or NodeSource repository
621
+ - ${nodeGuidance}
573
622
  - Build tools: gcc, make typically available or easily installed
574
- - Container tools: docker, podman common for development`;
623
+ - Container tools: docker, podman common for development
624
+
625
+ ${envInfo}`;
575
626
  }
576
627
  }
577
628
  /**
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const VERSION = "0.2.15";
1
+ export declare const VERSION = "0.2.16";
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const VERSION = '0.2.15';
1
+ export const VERSION = '0.2.16';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wonderwhy-er/desktop-commander",
3
- "version": "0.2.15",
3
+ "version": "0.2.16",
4
4
  "description": "MCP server for terminal operations and file editing",
5
5
  "mcpName": "io.github.wonderwhy-er/desktop-commander",
6
6
  "license": "MIT",
@@ -42,6 +42,7 @@
42
42
  "link:local": "npm run build && npm link",
43
43
  "unlink:local": "npm unlink",
44
44
  "inspector": "npx @modelcontextprotocol/inspector dist/index.js",
45
+ "build:mcpb": "node scripts/build-mcpb.cjs",
45
46
  "logs:view": "npm run build && node scripts/view-fuzzy-logs.js",
46
47
  "logs:analyze": "npm run build && node scripts/analyze-fuzzy-logs.js",
47
48
  "logs:clear": "npm run build && node scripts/clear-fuzzy-logs.js",