@wonderwhy-er/desktop-commander 0.2.41 → 0.2.43

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 (45) hide show
  1. package/README.md +0 -2
  2. package/dist/handlers/filesystem-handlers.js +24 -4
  3. package/dist/remote-device/remote-channel.d.ts +14 -0
  4. package/dist/remote-device/remote-channel.js +107 -28
  5. package/dist/server.d.ts +6 -1
  6. package/dist/server.js +112 -25
  7. package/dist/setup-claude-server.js +56 -50
  8. package/dist/terminal-manager.d.ts +18 -0
  9. package/dist/terminal-manager.js +130 -18
  10. package/dist/tools/edit.js +11 -4
  11. package/dist/tools/filesystem.d.ts +5 -0
  12. package/dist/tools/filesystem.js +43 -0
  13. package/dist/tools/fuzzySearch.d.ts +10 -20
  14. package/dist/tools/fuzzySearch.js +66 -105
  15. package/dist/tools/fuzzySearchCore.d.ts +52 -0
  16. package/dist/tools/fuzzySearchCore.js +125 -0
  17. package/dist/tools/improved-process-tools.js +8 -1
  18. package/dist/tools/pdf/markdown.d.ts +13 -0
  19. package/dist/tools/pdf/markdown.js +93 -29
  20. package/dist/tools/schemas.d.ts +20 -0
  21. package/dist/tools/schemas.js +45 -2
  22. package/dist/track-installation.js +57 -38
  23. package/dist/types.d.ts +6 -1
  24. package/dist/ui/contracts.d.ts +1 -1
  25. package/dist/ui/contracts.js +4 -1
  26. package/dist/ui/file-preview/preview-runtime.js +111 -113
  27. package/dist/ui/file-preview/src/app.js +19 -17
  28. package/dist/ui/file-preview/src/directory-controller.js +3 -3
  29. package/dist/ui/file-preview/src/file-type-handlers.js +2 -2
  30. package/dist/ui/file-preview/src/host/external-actions.d.ts +0 -11
  31. package/dist/ui/file-preview/src/host/external-actions.js +0 -39
  32. package/dist/ui/file-preview/src/markdown/controller.js +3 -1
  33. package/dist/ui/file-preview/src/panel-actions.js +2 -2
  34. package/dist/uninstall-claude-server.js +54 -47
  35. package/dist/utils/ab-test.d.ts +4 -0
  36. package/dist/utils/ab-test.js +6 -0
  37. package/dist/utils/capture.d.ts +10 -2
  38. package/dist/utils/capture.js +92 -60
  39. package/dist/utils/mcp-ui-ab-test.d.ts +13 -0
  40. package/dist/utils/mcp-ui-ab-test.js +62 -0
  41. package/dist/utils/unsupportedParams.d.ts +24 -0
  42. package/dist/utils/unsupportedParams.js +66 -0
  43. package/dist/version.d.ts +1 -1
  44. package/dist/version.js +1 -1
  45. package/package.json +6 -1
@@ -72,18 +72,21 @@ export declare const ReadFileArgsSchema: z.ZodObject<{
72
72
  sheet: z.ZodOptional<z.ZodString>;
73
73
  range: z.ZodOptional<z.ZodString>;
74
74
  options: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
75
+ origin: z.ZodOptional<z.ZodEnum<["ui", "llm"]>>;
75
76
  }, "strip", z.ZodTypeAny, {
76
77
  length: number;
77
78
  path: string;
78
79
  offset: number;
79
80
  isUrl: boolean;
80
81
  options?: Record<string, any> | undefined;
82
+ origin?: "ui" | "llm" | undefined;
81
83
  sheet?: string | undefined;
82
84
  range?: string | undefined;
83
85
  }, {
84
86
  path: string;
85
87
  length?: number | undefined;
86
88
  options?: Record<string, any> | undefined;
89
+ origin?: "ui" | "llm" | undefined;
87
90
  offset?: number | undefined;
88
91
  isUrl?: boolean | undefined;
89
92
  sheet?: string | undefined;
@@ -100,13 +103,16 @@ export declare const WriteFileArgsSchema: z.ZodObject<{
100
103
  path: z.ZodString;
101
104
  content: z.ZodString;
102
105
  mode: z.ZodDefault<z.ZodEnum<["rewrite", "append"]>>;
106
+ origin: z.ZodOptional<z.ZodEnum<["ui", "llm"]>>;
103
107
  }, "strip", z.ZodTypeAny, {
104
108
  path: string;
105
109
  content: string;
106
110
  mode: "rewrite" | "append";
111
+ origin?: "ui" | "llm" | undefined;
107
112
  }, {
108
113
  path: string;
109
114
  content: string;
115
+ origin?: "ui" | "llm" | undefined;
110
116
  mode?: "rewrite" | "append" | undefined;
111
117
  }>;
112
118
  export declare const PdfInsertOperationSchema: z.ZodObject<{
@@ -237,11 +243,14 @@ export declare const CreateDirectoryArgsSchema: z.ZodObject<{
237
243
  export declare const ListDirectoryArgsSchema: z.ZodObject<{
238
244
  path: z.ZodString;
239
245
  depth: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
246
+ origin: z.ZodOptional<z.ZodEnum<["ui", "llm"]>>;
240
247
  }, "strip", z.ZodTypeAny, {
241
248
  path: string;
242
249
  depth: number;
250
+ origin?: "ui" | "llm" | undefined;
243
251
  }, {
244
252
  path: string;
253
+ origin?: "ui" | "llm" | undefined;
245
254
  depth?: number | undefined;
246
255
  }>;
247
256
  export declare const MoveFileArgsSchema: z.ZodObject<{
@@ -269,10 +278,12 @@ export declare const EditBlockArgsSchema: z.ZodEffects<z.ZodObject<{
269
278
  range: z.ZodOptional<z.ZodString>;
270
279
  content: z.ZodOptional<z.ZodAny>;
271
280
  options: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
281
+ origin: z.ZodOptional<z.ZodEnum<["ui", "llm"]>>;
272
282
  }, "strip", z.ZodTypeAny, {
273
283
  file_path: string;
274
284
  expected_replacements: number;
275
285
  options?: Record<string, any> | undefined;
286
+ origin?: "ui" | "llm" | undefined;
276
287
  range?: string | undefined;
277
288
  content?: any;
278
289
  old_string?: string | undefined;
@@ -280,6 +291,7 @@ export declare const EditBlockArgsSchema: z.ZodEffects<z.ZodObject<{
280
291
  }, {
281
292
  file_path: string;
282
293
  options?: Record<string, any> | undefined;
294
+ origin?: "ui" | "llm" | undefined;
283
295
  range?: string | undefined;
284
296
  content?: any;
285
297
  old_string?: string | undefined;
@@ -289,6 +301,7 @@ export declare const EditBlockArgsSchema: z.ZodEffects<z.ZodObject<{
289
301
  file_path: string;
290
302
  expected_replacements: number;
291
303
  options?: Record<string, any> | undefined;
304
+ origin?: "ui" | "llm" | undefined;
292
305
  range?: string | undefined;
293
306
  content?: any;
294
307
  old_string?: string | undefined;
@@ -296,6 +309,7 @@ export declare const EditBlockArgsSchema: z.ZodEffects<z.ZodObject<{
296
309
  }, {
297
310
  file_path: string;
298
311
  options?: Record<string, any> | undefined;
312
+ origin?: "ui" | "llm" | undefined;
299
313
  range?: string | undefined;
300
314
  content?: any;
301
315
  old_string?: string | undefined;
@@ -417,3 +431,9 @@ export declare const TrackUiEventArgsSchema: z.ZodObject<{
417
431
  params?: Record<string, string | number | boolean | null> | undefined;
418
432
  component?: string | undefined;
419
433
  }>;
434
+ /**
435
+ * Map of tool name -> argument schema, used by the dispatcher to detect and warn
436
+ * about parameters a caller sent that the tool does not support. Keep in sync
437
+ * with the tool definitions in server.ts.
438
+ */
439
+ export declare const toolArgSchemas: Record<string, z.ZodTypeAny>;
@@ -43,7 +43,10 @@ export const ReadFileArgsSchema = z.object({
43
43
  length: z.number().optional().default(1000),
44
44
  sheet: z.string().optional(), // String only for MCP client compatibility (Cursor doesn't support union types in JSON Schema)
45
45
  range: z.string().optional(),
46
- options: z.record(z.any()).optional()
46
+ options: z.record(z.any()).optional(),
47
+ // Whether the call came from the file-preview UI (refresh/navigation) or the
48
+ // LLM. Used only for telemetry attribution; see call_origin in server.ts.
49
+ origin: z.enum(['ui', 'llm']).optional(),
47
50
  });
48
51
  export const ReadMultipleFilesArgsSchema = z.object({
49
52
  paths: z.array(z.string()),
@@ -52,6 +55,8 @@ export const WriteFileArgsSchema = z.object({
52
55
  path: z.string(),
53
56
  content: z.string(),
54
57
  mode: z.enum(['rewrite', 'append']).default('rewrite'),
58
+ // Telemetry attribution: 'ui' when fired by the file-preview UI, else 'llm'.
59
+ origin: z.enum(['ui', 'llm']).optional(),
55
60
  });
56
61
  // PDF modification schemas - exported for reuse
57
62
  export const PdfInsertOperationSchema = z.object({
@@ -92,6 +97,8 @@ export const CreateDirectoryArgsSchema = z.object({
92
97
  export const ListDirectoryArgsSchema = z.object({
93
98
  path: z.string(),
94
99
  depth: z.number().optional().default(2),
100
+ // Telemetry attribution: 'ui' when fired by the file-preview UI, else 'llm'.
101
+ origin: z.enum(['ui', 'llm']).optional(),
95
102
  });
96
103
  export const MoveFileArgsSchema = z.object({
97
104
  source: z.string(),
@@ -114,7 +121,9 @@ export const EditBlockArgsSchema = z.object({
114
121
  // Structured file range rewrite (Excel, etc.)
115
122
  range: z.string().optional(),
116
123
  content: z.any().optional(),
117
- options: z.record(z.any()).optional()
124
+ options: z.record(z.any()).optional(),
125
+ // Telemetry attribution: 'ui' when fired by the file-preview UI, else 'llm'.
126
+ origin: z.enum(['ui', 'llm']).optional(),
118
127
  }).refine(data => {
119
128
  // Helper to check if value is actually provided (not undefined, not empty string)
120
129
  const hasValue = (v) => v !== undefined && v !== '';
@@ -181,3 +190,37 @@ export const TrackUiEventArgsSchema = z.object({
181
190
  component: z.string().optional().default('file_preview'),
182
191
  params: z.record(z.union([z.string(), z.number(), z.boolean(), z.null()])).optional().default({}),
183
192
  });
193
+ /**
194
+ * Map of tool name -> argument schema, used by the dispatcher to detect and warn
195
+ * about parameters a caller sent that the tool does not support. Keep in sync
196
+ * with the tool definitions in server.ts.
197
+ */
198
+ export const toolArgSchemas = {
199
+ get_config: GetConfigArgsSchema,
200
+ set_config_value: SetConfigValueArgsSchema,
201
+ read_file: ReadFileArgsSchema,
202
+ read_multiple_files: ReadMultipleFilesArgsSchema,
203
+ write_file: WriteFileArgsSchema,
204
+ write_pdf: WritePdfArgsSchema,
205
+ create_directory: CreateDirectoryArgsSchema,
206
+ list_directory: ListDirectoryArgsSchema,
207
+ move_file: MoveFileArgsSchema,
208
+ start_search: StartSearchArgsSchema,
209
+ get_more_search_results: GetMoreSearchResultsArgsSchema,
210
+ stop_search: StopSearchArgsSchema,
211
+ list_searches: ListSearchesArgsSchema,
212
+ get_file_info: GetFileInfoArgsSchema,
213
+ edit_block: EditBlockArgsSchema,
214
+ start_process: StartProcessArgsSchema,
215
+ read_process_output: ReadProcessOutputArgsSchema,
216
+ interact_with_process: InteractWithProcessArgsSchema,
217
+ force_terminate: ForceTerminateArgsSchema,
218
+ list_sessions: ListSessionsArgsSchema,
219
+ list_processes: ListProcessesArgsSchema,
220
+ kill_process: KillProcessArgsSchema,
221
+ get_usage_stats: GetUsageStatsArgsSchema,
222
+ get_recent_tool_calls: GetRecentToolCallsArgsSchema,
223
+ give_feedback_to_desktop_commander: GiveFeedbackArgsSchema,
224
+ get_prompts: GetPromptsArgsSchema,
225
+ track_ui_event: TrackUiEventArgsSchema,
226
+ };
@@ -73,10 +73,9 @@ async function getClientId() {
73
73
  }
74
74
  }
75
75
 
76
- // Google Analytics configuration (same as setup script)
77
- const GA_MEASUREMENT_ID = 'G-NGGDNL0K4L';
78
- const GA_API_SECRET = '5M0mC--2S_6t94m8WrI60A';
79
- const GA_BASE_URL = `https://www.google-analytics.com/mp/collect?measurement_id=${GA_MEASUREMENT_ID}&api_secret=${GA_API_SECRET}`;
76
+ // Telemetry proxy configuration (same as setup script)
77
+ const TELEMETRY_PROXY_URL = 'https://telemetry.desktopcommander.app/mp/collect';
78
+ const TELEMETRY_PROXY_FALLBACK_URL = 'https://dc-telemetry-proxy-83847352264.europe-west1.run.app/mp/collect';
80
79
 
81
80
  /**
82
81
  * Detect installation source from environment and process context
@@ -267,18 +266,13 @@ async function detectInstallationSource() {
267
266
  }
268
267
 
269
268
  /**
270
- * Send installation tracking to analytics
269
+ * Send installation tracking to telemetry proxy
271
270
  */
272
271
  async function trackInstallation(installationData) {
273
- if (!GA_MEASUREMENT_ID || !GA_API_SECRET) {
274
- debug('Analytics not configured, skipping tracking');
275
- return;
276
- }
277
-
278
272
  try {
279
273
  const uniqueUserId = await getClientId();
280
274
  log("user id", uniqueUserId)
281
- // Prepare GA4 payload
275
+ // Prepare telemetry payload
282
276
  const payload = {
283
277
  client_id: uniqueUserId,
284
278
  non_personalized_ads: false,
@@ -308,33 +302,11 @@ async function trackInstallation(installationData) {
308
302
  }
309
303
  };
310
304
 
311
- await new Promise((resolve, reject) => {
312
- const req = https.request(GA_BASE_URL, options);
313
-
314
- const timeoutId = setTimeout(() => {
315
- req.destroy();
316
- reject(new Error('Request timeout'));
317
- }, 5000);
318
-
319
- req.on('error', (error) => {
320
- clearTimeout(timeoutId);
321
- debug(`Analytics error: ${error.message}`);
322
- resolve(); // Don't fail installation on analytics error
323
- });
324
-
325
- req.on('response', (res) => {
326
- clearTimeout(timeoutId);
327
- // Consume the response data to complete the request
328
- res.on('data', () => {}); // Ignore response data
329
- res.on('end', () => {
330
- log(`Installation tracked: ${installationData.source}`);
331
- resolve();
332
- });
333
- });
334
-
335
- req.write(postData);
336
- req.end();
337
- });
305
+ const sent = await postTelemetryPayload(TELEMETRY_PROXY_URL, postData, options);
306
+ if (!sent) {
307
+ await postTelemetryPayload(TELEMETRY_PROXY_FALLBACK_URL, postData, options);
308
+ }
309
+ log(`Installation tracked: ${installationData.source}`);
338
310
 
339
311
  } catch (error) {
340
312
  debug(`Failed to track installation: ${error.message}`);
@@ -342,6 +314,53 @@ async function trackInstallation(installationData) {
342
314
  }
343
315
  }
344
316
 
317
+ // TODO(dedup): postTelemetryPayload is copy-pasted across setup/uninstall/track
318
+ // scripts + a variant in src/utils/capture.ts. Consolidate into one shared module.
319
+ // TODO(timeout): per-endpoint timeout here is 5s, but ensureTrackingCompleted caps
320
+ // the whole flow at 6s — so if the primary times out, the fallback gets ~1s and
321
+ // almost never completes. Lower per-endpoint timeout (capture.ts uses 3s) or raise
322
+ // the overall budget so the fallback is actually usable.
323
+ async function postTelemetryPayload(endpoint, postData, options) {
324
+ return await new Promise((resolve) => {
325
+ let settled = false;
326
+ let timeoutId;
327
+ const finish = (result) => {
328
+ if (settled) return;
329
+ settled = true;
330
+ clearTimeout(timeoutId);
331
+ resolve(result);
332
+ };
333
+ const req = https.request(endpoint, options);
334
+
335
+ timeoutId = setTimeout(() => {
336
+ req.destroy();
337
+ finish(false);
338
+ }, 5000);
339
+
340
+ req.on('error', (error) => {
341
+ debug(`Telemetry error: ${error.message}`);
342
+ finish(false);
343
+ });
344
+
345
+ req.on('response', (res) => {
346
+ res.on('data', () => {});
347
+ res.on('error', (error) => {
348
+ debug(`Telemetry response error: ${error.message}`);
349
+ finish(false);
350
+ });
351
+ res.on('end', () => {
352
+ finish(res.statusCode >= 200 && res.statusCode < 300);
353
+ });
354
+ res.on('close', () => {
355
+ finish(false);
356
+ });
357
+ });
358
+
359
+ req.write(postData);
360
+ req.end();
361
+ });
362
+ }
363
+
345
364
  /**
346
365
  * Main execution
347
366
  */
package/dist/types.d.ts CHANGED
@@ -18,6 +18,9 @@ export interface TerminalSession {
18
18
  lastReadIndex: number;
19
19
  isBlocked: boolean;
20
20
  startTime: Date;
21
+ bufferedChars: number;
22
+ evictedLines: number;
23
+ evictedChars: number;
21
24
  }
22
25
  export interface CommandExecutionResult {
23
26
  pid: number;
@@ -65,8 +68,10 @@ export interface FilePreviewStructuredContent {
65
68
  fileName: string;
66
69
  filePath: string;
67
70
  fileType: PreviewFileType;
71
+ sourceTool?: 'read_file' | 'write_file' | 'edit_block';
72
+ defaultEditorName?: string;
73
+ defaultEditorPath?: string;
68
74
  content?: string;
69
- imageData?: string;
70
75
  mimeType?: string;
71
76
  }
72
77
  export interface ServerResult {
@@ -11,4 +11,4 @@ export interface UiToolMeta extends Record<string, unknown> {
11
11
  };
12
12
  'openai/widgetAccessible'?: boolean;
13
13
  }
14
- export declare function buildUiToolMeta(resourceUri: string, widgetAccessible?: boolean): UiToolMeta;
14
+ export declare function buildUiToolMeta(resourceUri: string, widgetAccessible?: boolean, showMcpUiPreviews?: boolean): UiToolMeta | undefined;
@@ -3,7 +3,10 @@
3
3
  */
4
4
  export const FILE_PREVIEW_RESOURCE_URI = 'ui://desktop-commander/file-preview';
5
5
  export const CONFIG_EDITOR_RESOURCE_URI = 'ui://desktop-commander/config-editor';
6
- export function buildUiToolMeta(resourceUri, widgetAccessible = false) {
6
+ export function buildUiToolMeta(resourceUri, widgetAccessible = false, showMcpUiPreviews = true) {
7
+ if (!showMcpUiPreviews) {
8
+ return undefined;
9
+ }
7
10
  const meta = {
8
11
  'ui/resourceUri': resourceUri,
9
12
  'openai/outputTemplate': resourceUri,