@wonderwhy-er/desktop-commander 0.2.42 → 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.
- package/dist/handlers/filesystem-handlers.js +2 -1
- package/dist/remote-device/remote-channel.d.ts +14 -0
- package/dist/remote-device/remote-channel.js +107 -28
- package/dist/server.d.ts +5 -1
- package/dist/server.js +65 -14
- package/dist/terminal-manager.d.ts +18 -0
- package/dist/terminal-manager.js +84 -18
- package/dist/tools/edit.js +4 -3
- package/dist/tools/fuzzySearch.d.ts +10 -20
- package/dist/tools/fuzzySearch.js +66 -105
- package/dist/tools/fuzzySearchCore.d.ts +52 -0
- package/dist/tools/fuzzySearchCore.js +125 -0
- package/dist/tools/improved-process-tools.js +8 -1
- package/dist/tools/schemas.d.ts +20 -0
- package/dist/tools/schemas.js +45 -2
- package/dist/types.d.ts +3 -1
- package/dist/ui/file-preview/preview-runtime.js +5 -5
- package/dist/ui/file-preview/src/directory-controller.js +3 -3
- package/dist/ui/file-preview/src/file-type-handlers.js +2 -2
- package/dist/ui/file-preview/src/markdown/controller.js +3 -1
- package/dist/ui/file-preview/src/panel-actions.js +2 -2
- package/dist/utils/capture.js +13 -7
- package/dist/utils/unsupportedParams.d.ts +24 -0
- package/dist/utils/unsupportedParams.js +66 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +5 -1
|
@@ -146,7 +146,7 @@ export function attachDirectoryHandlers(options) {
|
|
|
146
146
|
loadMoreBtn.querySelector('.dir-warning-text').textContent = 'Loading…';
|
|
147
147
|
loadMoreBtn.disabled = true;
|
|
148
148
|
try {
|
|
149
|
-
const result = await options.callTool?.('list_directory', { path: loadPath, depth: 1 });
|
|
149
|
+
const result = await options.callTool?.('list_directory', { path: loadPath, depth: 1, origin: 'ui' });
|
|
150
150
|
const text = extractToolText(result) ?? '';
|
|
151
151
|
if (text) {
|
|
152
152
|
const parsed = parseDirectoryEntries(text);
|
|
@@ -194,7 +194,7 @@ export function attachDirectoryHandlers(options) {
|
|
|
194
194
|
if (chevron)
|
|
195
195
|
chevron.textContent = '⏳';
|
|
196
196
|
try {
|
|
197
|
-
const result = await options.callTool?.('list_directory', { path: fullPath, depth: 2 });
|
|
197
|
+
const result = await options.callTool?.('list_directory', { path: fullPath, depth: 2, origin: 'ui' });
|
|
198
198
|
const text = extractToolText(result) ?? '';
|
|
199
199
|
if (text) {
|
|
200
200
|
target.dataset.loaded = 'true';
|
|
@@ -222,7 +222,7 @@ export function attachDirectoryHandlers(options) {
|
|
|
222
222
|
if (target.classList.contains('dir-row-file')) {
|
|
223
223
|
target.classList.add('dir-loading');
|
|
224
224
|
try {
|
|
225
|
-
const result = await options.callTool?.('read_file', { path: fullPath });
|
|
225
|
+
const result = await options.callTool?.('read_file', { path: fullPath, origin: 'ui' });
|
|
226
226
|
if (!result || typeof result !== 'object' || result === null) {
|
|
227
227
|
return;
|
|
228
228
|
}
|
|
@@ -16,13 +16,13 @@ function renderImageBody(payload) {
|
|
|
16
16
|
html: '<div class="panel-content source-content"></div>',
|
|
17
17
|
};
|
|
18
18
|
}
|
|
19
|
-
if (!payload.
|
|
19
|
+
if (!payload.content || payload.content.trim().length === 0) {
|
|
20
20
|
return {
|
|
21
21
|
notice: 'Preview is unavailable because image data is missing.',
|
|
22
22
|
html: '<div class="panel-content source-content"></div>',
|
|
23
23
|
};
|
|
24
24
|
}
|
|
25
|
-
const src = `data:${mimeType};base64,${payload.
|
|
25
|
+
const src = `data:${mimeType};base64,${payload.content}`;
|
|
26
26
|
return {
|
|
27
27
|
html: `<div class="panel-content image-content"><div class="image-preview"><img src="${escapeHtml(src)}" alt="${escapeHtml(payload.fileName)}" loading="eager" decoding="async"></div></div>`,
|
|
28
28
|
};
|
|
@@ -281,6 +281,7 @@ export function createMarkdownController(dependencies) {
|
|
|
281
281
|
const rawResult = await dependencies.callTool?.('read_file', {
|
|
282
282
|
path: filePath,
|
|
283
283
|
...(typeof length === 'number' ? { offset: offset ?? 0, length } : {}),
|
|
284
|
+
origin: 'ui',
|
|
284
285
|
});
|
|
285
286
|
return { rawResult, payload: extractRenderPayload(rawResult) ?? null };
|
|
286
287
|
}
|
|
@@ -360,7 +361,7 @@ export function createMarkdownController(dependencies) {
|
|
|
360
361
|
const markers = new Set(['[DIR] .git', '[DIR] .obsidian', '[FILE] package.json', '[FILE] pnpm-workspace.yaml', '[FILE] turbo.json']);
|
|
361
362
|
for (const ancestor of ancestors) {
|
|
362
363
|
try {
|
|
363
|
-
const result = await dependencies.callTool?.('list_directory', { path: ancestor, depth: 1 });
|
|
364
|
+
const result = await dependencies.callTool?.('list_directory', { path: ancestor, depth: 1, origin: 'ui' });
|
|
364
365
|
const text = extractToolText(result) ?? '';
|
|
365
366
|
const entries = splitListingLines(text);
|
|
366
367
|
if (entries.some((entry) => markers.has(entry))) {
|
|
@@ -681,6 +682,7 @@ export function createMarkdownController(dependencies) {
|
|
|
681
682
|
old_string: block.old_string,
|
|
682
683
|
new_string: block.new_string,
|
|
683
684
|
expected_replacements: 1,
|
|
685
|
+
origin: 'ui',
|
|
684
686
|
});
|
|
685
687
|
assertSuccessfulEditBlockResult(editResult);
|
|
686
688
|
appliedCount++;
|
|
@@ -144,8 +144,8 @@ export function attachPanelActions(options) {
|
|
|
144
144
|
});
|
|
145
145
|
try {
|
|
146
146
|
const readArgs = direction === 'before'
|
|
147
|
-
? { path: options.payload.filePath, offset: 0, length: range.fromLine - 1 }
|
|
148
|
-
: { path: options.payload.filePath, offset: range.toLine };
|
|
147
|
+
? { path: options.payload.filePath, offset: 0, length: range.fromLine - 1, origin: 'ui' }
|
|
148
|
+
: { path: options.payload.filePath, offset: range.toLine, origin: 'ui' };
|
|
149
149
|
const result = await options.callTool?.('read_file', readArgs);
|
|
150
150
|
const newText = extractToolText(result);
|
|
151
151
|
if (newText && typeof newText === 'string') {
|
package/dist/utils/capture.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { platform } from 'os';
|
|
2
2
|
import * as https from 'https';
|
|
3
3
|
import { configManager, isTelemetryDisabledValue } from '../config-manager.js';
|
|
4
|
-
import { currentClient, currentCallIsRemote } from '../server.js';
|
|
4
|
+
import { currentClient, currentCallIsRemote, currentRemoteClient } from '../server.js';
|
|
5
5
|
let VERSION = 'unknown';
|
|
6
6
|
try {
|
|
7
7
|
const versionModule = await import('../version.js');
|
|
@@ -89,11 +89,14 @@ export const captureBase = async (captureURL, event, properties) => {
|
|
|
89
89
|
uniqueUserId = await configManager.getOrCreateClientId();
|
|
90
90
|
}
|
|
91
91
|
// Get current client information for all events
|
|
92
|
+
// For remote calls, attribute to the originating remote client (carried on
|
|
93
|
+
// the tool call) instead of the device's local currentClient.
|
|
94
|
+
const effectiveClient = currentCallIsRemote && currentRemoteClient ? currentRemoteClient : currentClient;
|
|
92
95
|
let clientContext = {};
|
|
93
|
-
if (
|
|
96
|
+
if (effectiveClient) {
|
|
94
97
|
clientContext = {
|
|
95
|
-
client_name:
|
|
96
|
-
client_version:
|
|
98
|
+
client_name: effectiveClient.name,
|
|
99
|
+
client_version: effectiveClient.version,
|
|
97
100
|
};
|
|
98
101
|
}
|
|
99
102
|
// Track if user saw onboarding page
|
|
@@ -265,11 +268,14 @@ const buildEventProperties = async (properties) => {
|
|
|
265
268
|
if (uniqueUserId === 'unknown') {
|
|
266
269
|
uniqueUserId = await configManager.getOrCreateClientId();
|
|
267
270
|
}
|
|
271
|
+
// For remote calls, attribute to the originating remote client (carried on
|
|
272
|
+
// the tool call) instead of the device's local currentClient.
|
|
273
|
+
const effectiveClient = currentCallIsRemote && currentRemoteClient ? currentRemoteClient : currentClient;
|
|
268
274
|
let clientContext = {};
|
|
269
|
-
if (
|
|
275
|
+
if (effectiveClient) {
|
|
270
276
|
clientContext = {
|
|
271
|
-
client_name:
|
|
272
|
-
client_version:
|
|
277
|
+
client_name: effectiveClient.name,
|
|
278
|
+
client_version: effectiveClient.version,
|
|
273
279
|
};
|
|
274
280
|
}
|
|
275
281
|
const sawOnboardingPage = await configManager.getValue('sawOnboardingPage');
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility for detecting parameters a caller sent that a tool's Zod schema does
|
|
3
|
+
* not accept.
|
|
4
|
+
*
|
|
5
|
+
* Zod's default `z.object()` silently strips unknown keys, so a model that
|
|
6
|
+
* invents a parameter (e.g. `view_range`) gets a normal-looking response with no
|
|
7
|
+
* signal that its input was ignored. These helpers let the dispatcher surface a
|
|
8
|
+
* corrective warning instead.
|
|
9
|
+
*
|
|
10
|
+
* Detection is top-level only. That is sufficient here because none of the tool
|
|
11
|
+
* arg schemas use a top-level `.passthrough()`/catchall — free-form fields
|
|
12
|
+
* (`options`, `params`, `pdfOptions`) are named keys whose contents are
|
|
13
|
+
* intentionally unvalidated.
|
|
14
|
+
*/
|
|
15
|
+
/** List the parameter names a tool schema accepts (empty array if it takes none). */
|
|
16
|
+
export declare function getSupportedParams(schema: unknown): string[];
|
|
17
|
+
/**
|
|
18
|
+
* Return the names of top-level keys in `args` that the schema does not accept.
|
|
19
|
+
* Returns [] when args is not a plain object or the schema's params can't be
|
|
20
|
+
* determined (so we never warn on something we can't reason about).
|
|
21
|
+
*/
|
|
22
|
+
export declare function detectUnsupportedParams(args: unknown, schema: unknown): string[];
|
|
23
|
+
/** Build the corrective warning string shown to the model. */
|
|
24
|
+
export declare function buildUnsupportedParamsWarning(toolName: string, unsupported: string[], supported: string[]): string;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility for detecting parameters a caller sent that a tool's Zod schema does
|
|
3
|
+
* not accept.
|
|
4
|
+
*
|
|
5
|
+
* Zod's default `z.object()` silently strips unknown keys, so a model that
|
|
6
|
+
* invents a parameter (e.g. `view_range`) gets a normal-looking response with no
|
|
7
|
+
* signal that its input was ignored. These helpers let the dispatcher surface a
|
|
8
|
+
* corrective warning instead.
|
|
9
|
+
*
|
|
10
|
+
* Detection is top-level only. That is sufficient here because none of the tool
|
|
11
|
+
* arg schemas use a top-level `.passthrough()`/catchall — free-form fields
|
|
12
|
+
* (`options`, `params`, `pdfOptions`) are named keys whose contents are
|
|
13
|
+
* intentionally unvalidated.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Resolve a Zod schema down to the field map of its underlying object schema,
|
|
17
|
+
* unwrapping wrappers (effects/optional/default/nullable/branded) defensively.
|
|
18
|
+
* Returns null when the schema is not (and does not wrap) a plain object schema,
|
|
19
|
+
* in which case we cannot determine the supported parameters and must not warn.
|
|
20
|
+
*/
|
|
21
|
+
function getObjectShape(schema) {
|
|
22
|
+
let current = schema;
|
|
23
|
+
for (let i = 0; current && current._def && i < 10; i++) {
|
|
24
|
+
const typeName = current._def.typeName;
|
|
25
|
+
if (typeName === 'ZodObject') {
|
|
26
|
+
const shape = typeof current.shape === 'function' ? current.shape() : current.shape;
|
|
27
|
+
return shape ?? null;
|
|
28
|
+
}
|
|
29
|
+
if (typeName === 'ZodEffects')
|
|
30
|
+
current = current._def.schema;
|
|
31
|
+
else if (typeName === 'ZodOptional' || typeName === 'ZodNullable' || typeName === 'ZodDefault') {
|
|
32
|
+
current = typeof current._def.innerType === 'function' ? current._def.innerType() : current._def.innerType;
|
|
33
|
+
}
|
|
34
|
+
else if (typeName === 'ZodBranded')
|
|
35
|
+
current = current._def.type;
|
|
36
|
+
else
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
/** List the parameter names a tool schema accepts (empty array if it takes none). */
|
|
42
|
+
export function getSupportedParams(schema) {
|
|
43
|
+
const shape = getObjectShape(schema);
|
|
44
|
+
return shape ? Object.keys(shape) : [];
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Return the names of top-level keys in `args` that the schema does not accept.
|
|
48
|
+
* Returns [] when args is not a plain object or the schema's params can't be
|
|
49
|
+
* determined (so we never warn on something we can't reason about).
|
|
50
|
+
*/
|
|
51
|
+
export function detectUnsupportedParams(args, schema) {
|
|
52
|
+
if (!args || typeof args !== 'object' || Array.isArray(args))
|
|
53
|
+
return [];
|
|
54
|
+
const shape = getObjectShape(schema);
|
|
55
|
+
if (shape === null)
|
|
56
|
+
return [];
|
|
57
|
+
const supported = new Set(Object.keys(shape));
|
|
58
|
+
return Object.keys(args).filter((k) => !supported.has(k));
|
|
59
|
+
}
|
|
60
|
+
/** Build the corrective warning string shown to the model. */
|
|
61
|
+
export function buildUnsupportedParamsWarning(toolName, unsupported, supported) {
|
|
62
|
+
const ignored = unsupported.join(', ');
|
|
63
|
+
const supportedList = supported.length > 0 ? supported.join(', ') : '(none)';
|
|
64
|
+
return `You sent parameters not supported by this tool, which were ignored: ${ignored}. `
|
|
65
|
+
+ `Supported parameters for ${toolName}: ${supportedList}.`;
|
|
66
|
+
}
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const VERSION = "0.2.
|
|
1
|
+
export declare const VERSION = "0.2.43";
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const VERSION = '0.2.
|
|
1
|
+
export const VERSION = '0.2.43';
|
package/package.json
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wonderwhy-er/desktop-commander",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.43",
|
|
4
4
|
"description": "MCP server for terminal operations and file editing",
|
|
5
5
|
"mcpName": "io.github.wonderwhy-er/desktop-commander",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "Eduards Ruzga",
|
|
8
8
|
"homepage": "https://github.com/wonderwhy-er/DesktopCommanderMCP",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://github.com/wonderwhy-er/DesktopCommanderMCP.git"
|
|
12
|
+
},
|
|
9
13
|
"bugs": "https://github.com/wonderwhy-er/DesktopCommanderMCP/issues",
|
|
10
14
|
"type": "module",
|
|
11
15
|
"engines": {
|