@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
|
@@ -1,113 +1,74 @@
|
|
|
1
|
-
import { distance } from 'fastest-levenshtein';
|
|
2
1
|
import { capture } from '../utils/capture.js';
|
|
2
|
+
import { Worker } from 'worker_threads';
|
|
3
|
+
// Re-export so existing callers keep importing from this module.
|
|
4
|
+
export { recursiveFuzzyIndexOf, getSimilarityRatio } from './fuzzySearchCore.js';
|
|
5
|
+
/** Abort fuzzy search in the worker after this many ms to avoid unbounded CPU burn. */
|
|
6
|
+
export const FUZZY_SEARCH_TIMEOUT_MS = 30000;
|
|
3
7
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* @param parentDistance Best distance found so far (default: Infinity)
|
|
10
|
-
* @returns Object with start and end indices, matched value, and Levenshtein distance
|
|
8
|
+
* Inline worker entry: imports the dependency-free core module (passed as
|
|
9
|
+
* moduleUrl) and runs the search off the main thread. The core module is
|
|
10
|
+
* deliberately a leaf — importing this module (or anything app-level) from the
|
|
11
|
+
* worker would boot the whole server per search. Kept as an eval'd snippet so
|
|
12
|
+
* the worker needs no separate file to ship alongside the compiled output.
|
|
11
13
|
*/
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
result_distance: result.distance
|
|
24
|
-
});
|
|
25
|
-
return result;
|
|
26
|
-
}
|
|
27
|
-
if (end === null)
|
|
28
|
-
end = text.length;
|
|
29
|
-
// For small text segments, use iterative approach
|
|
30
|
-
if (end - start <= 2 * query.length) {
|
|
31
|
-
return iterativeReduction(text, query, start, end, parentDistance);
|
|
32
|
-
}
|
|
33
|
-
let midPoint = start + Math.floor((end - start) / 2);
|
|
34
|
-
let leftEnd = Math.min(end, midPoint + query.length); // Include query length to cover overlaps
|
|
35
|
-
let rightStart = Math.max(start, midPoint - query.length); // Include query length to cover overlaps
|
|
36
|
-
// Calculate distance for current segments
|
|
37
|
-
let leftDistance = distance(text.substring(start, leftEnd), query);
|
|
38
|
-
let rightDistance = distance(text.substring(rightStart, end), query);
|
|
39
|
-
let bestDistance = Math.min(leftDistance, parentDistance, rightDistance);
|
|
40
|
-
// If parent distance is already the best, use iterative approach
|
|
41
|
-
if (parentDistance === bestDistance) {
|
|
42
|
-
return iterativeReduction(text, query, start, end, parentDistance);
|
|
43
|
-
}
|
|
44
|
-
// Recursively search the better half
|
|
45
|
-
if (leftDistance < rightDistance) {
|
|
46
|
-
return recursiveFuzzyIndexOf(text, query, start, leftEnd, bestDistance, depth + 1);
|
|
47
|
-
}
|
|
48
|
-
else {
|
|
49
|
-
return recursiveFuzzyIndexOf(text, query, rightStart, end, bestDistance, depth + 1);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
14
|
+
const WORKER_CODE = `
|
|
15
|
+
const { workerData, parentPort } = require('worker_threads');
|
|
16
|
+
import(workerData.moduleUrl)
|
|
17
|
+
.then((m) => {
|
|
18
|
+
parentPort.postMessage({ ok: true, ...m.runFuzzySearch(workerData.text, workerData.query) });
|
|
19
|
+
})
|
|
20
|
+
.catch((err) => {
|
|
21
|
+
parentPort.postMessage({ ok: false, error: String(err && err.stack || err) });
|
|
22
|
+
});
|
|
23
|
+
`;
|
|
24
|
+
const CORE_MODULE_URL = new URL('./fuzzySearchCore.js', import.meta.url).href;
|
|
52
25
|
/**
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
* @param parentDistance Best distance found so far
|
|
59
|
-
* @returns Object with start and end indices, matched value, and Levenshtein distance
|
|
26
|
+
* Runs the fuzzy search in a Worker thread so the main MCP event loop stays
|
|
27
|
+
* responsive to pings and other tool calls during heavy scans. Rejects if the
|
|
28
|
+
* scan exceeds timeoutMs, terminating the worker so it doesn't linger in the
|
|
29
|
+
* background. Search metrics come back with the result and are captured here,
|
|
30
|
+
* on the main thread, where the client identity is initialized.
|
|
60
31
|
*/
|
|
61
|
-
function
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
32
|
+
export function runFuzzySearchInWorker(text, query, timeoutMs = FUZZY_SEARCH_TIMEOUT_MS) {
|
|
33
|
+
return new Promise((resolve, reject) => {
|
|
34
|
+
const worker = new Worker(WORKER_CODE, { eval: true, workerData: { moduleUrl: CORE_MODULE_URL, text, query } });
|
|
35
|
+
// Never let a scan keep the server process alive during shutdown.
|
|
36
|
+
worker.unref();
|
|
37
|
+
const timer = setTimeout(() => {
|
|
38
|
+
worker.terminate();
|
|
39
|
+
reject(new Error(`Fuzzy search timed out after ${timeoutMs}ms`));
|
|
40
|
+
}, timeoutMs);
|
|
41
|
+
timer.unref();
|
|
42
|
+
worker.on('message', (msg) => {
|
|
43
|
+
clearTimeout(timer);
|
|
44
|
+
if (msg.ok) {
|
|
45
|
+
captureFuzzySearchMetrics(msg.metrics);
|
|
46
|
+
resolve(msg.result);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
reject(new Error(`Fuzzy search worker failed: ${msg.error}`));
|
|
50
|
+
}
|
|
51
|
+
// Don't let the worker wind down on its own; the answer is already
|
|
52
|
+
// here, and a lingering worker holds its copy of the file text.
|
|
53
|
+
// The promise is settled, so the exit-code rejection below is a no-op.
|
|
54
|
+
worker.terminate();
|
|
55
|
+
});
|
|
56
|
+
worker.on('error', (err) => {
|
|
57
|
+
clearTimeout(timer);
|
|
58
|
+
reject(err);
|
|
59
|
+
});
|
|
60
|
+
worker.on('exit', (code) => {
|
|
61
|
+
clearTimeout(timer);
|
|
62
|
+
if (code !== 0) {
|
|
63
|
+
reject(new Error(`Fuzzy search worker exited with code ${code}`));
|
|
64
|
+
}
|
|
65
|
+
});
|
|
93
66
|
});
|
|
94
|
-
return {
|
|
95
|
-
start: bestStart,
|
|
96
|
-
end: bestEnd,
|
|
97
|
-
value: text.substring(bestStart, bestEnd),
|
|
98
|
-
distance: bestDistance
|
|
99
|
-
};
|
|
100
67
|
}
|
|
101
|
-
/**
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
export function getSimilarityRatio(a, b) {
|
|
108
|
-
const maxLength = Math.max(a.length, b.length);
|
|
109
|
-
if (maxLength === 0)
|
|
110
|
-
return 1; // Both strings are empty
|
|
111
|
-
const levenshteinDistance = distance(a, b);
|
|
112
|
-
return 1 - (levenshteinDistance / maxLength);
|
|
68
|
+
/** Same telemetry events the search used to emit inline, now sent from the main thread. */
|
|
69
|
+
function captureFuzzySearchMetrics(metrics) {
|
|
70
|
+
capture('fuzzy_search_recursive_metrics', metrics.recursive);
|
|
71
|
+
if (metrics.iterative) {
|
|
72
|
+
capture('fuzzy_search_iterative_metrics', metrics.iterative);
|
|
73
|
+
}
|
|
113
74
|
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure fuzzy-search core, kept free of app imports on purpose: it runs inside
|
|
3
|
+
* the worker thread spawned by runFuzzySearchInWorker (fuzzySearch.ts), and
|
|
4
|
+
* anything imported here is loaded per worker. Telemetry is returned as data
|
|
5
|
+
* and captured on the main thread, which has the real client identity.
|
|
6
|
+
*/
|
|
7
|
+
export interface FuzzyMatch {
|
|
8
|
+
start: number;
|
|
9
|
+
end: number;
|
|
10
|
+
value: string;
|
|
11
|
+
distance: number;
|
|
12
|
+
}
|
|
13
|
+
export interface FuzzySearchMetrics {
|
|
14
|
+
recursive: {
|
|
15
|
+
execution_time_ms: number;
|
|
16
|
+
text_length: number;
|
|
17
|
+
query_length: number;
|
|
18
|
+
result_distance: number;
|
|
19
|
+
};
|
|
20
|
+
iterative: {
|
|
21
|
+
execution_time_ms: number;
|
|
22
|
+
iterations: number;
|
|
23
|
+
segment_length: number;
|
|
24
|
+
query_length: number;
|
|
25
|
+
final_distance: number;
|
|
26
|
+
} | null;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Runs a full fuzzy search and returns the match together with the timing
|
|
30
|
+
* metrics that used to be captured inline.
|
|
31
|
+
*/
|
|
32
|
+
export declare function runFuzzySearch(text: string, query: string): {
|
|
33
|
+
result: FuzzyMatch;
|
|
34
|
+
metrics: FuzzySearchMetrics;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Recursively finds the closest match to a query string within text using fuzzy matching
|
|
38
|
+
* @param text The text to search within
|
|
39
|
+
* @param query The query string to find
|
|
40
|
+
* @param start Start index in the text (default: 0)
|
|
41
|
+
* @param end End index in the text (default: text.length)
|
|
42
|
+
* @param parentDistance Best distance found so far (default: Infinity)
|
|
43
|
+
* @returns Object with start and end indices, matched value, and Levenshtein distance
|
|
44
|
+
*/
|
|
45
|
+
export declare function recursiveFuzzyIndexOf(text: string, query: string, start?: number, end?: number | null, parentDistance?: number): FuzzyMatch;
|
|
46
|
+
/**
|
|
47
|
+
* Calculates the similarity ratio between two strings
|
|
48
|
+
* @param a First string
|
|
49
|
+
* @param b Second string
|
|
50
|
+
* @returns Similarity ratio (0-1)
|
|
51
|
+
*/
|
|
52
|
+
export declare function getSimilarityRatio(a: string, b: string): number;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { distance } from 'fastest-levenshtein';
|
|
2
|
+
// Set by iterativeReduction during a search (exactly one terminal call per
|
|
3
|
+
// search) and collected by runFuzzySearch. Single-threaded per context, so a
|
|
4
|
+
// module-level slot is safe.
|
|
5
|
+
let lastIterativeMetrics = null;
|
|
6
|
+
/**
|
|
7
|
+
* Runs a full fuzzy search and returns the match together with the timing
|
|
8
|
+
* metrics that used to be captured inline.
|
|
9
|
+
*/
|
|
10
|
+
export function runFuzzySearch(text, query) {
|
|
11
|
+
const startTime = performance.now();
|
|
12
|
+
lastIterativeMetrics = null;
|
|
13
|
+
const result = recursiveFuzzyIndexOf(text, query);
|
|
14
|
+
return {
|
|
15
|
+
result,
|
|
16
|
+
metrics: {
|
|
17
|
+
recursive: {
|
|
18
|
+
execution_time_ms: performance.now() - startTime,
|
|
19
|
+
text_length: text.length,
|
|
20
|
+
query_length: query.length,
|
|
21
|
+
result_distance: result.distance
|
|
22
|
+
},
|
|
23
|
+
iterative: lastIterativeMetrics
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Recursively finds the closest match to a query string within text using fuzzy matching
|
|
29
|
+
* @param text The text to search within
|
|
30
|
+
* @param query The query string to find
|
|
31
|
+
* @param start Start index in the text (default: 0)
|
|
32
|
+
* @param end End index in the text (default: text.length)
|
|
33
|
+
* @param parentDistance Best distance found so far (default: Infinity)
|
|
34
|
+
* @returns Object with start and end indices, matched value, and Levenshtein distance
|
|
35
|
+
*/
|
|
36
|
+
export function recursiveFuzzyIndexOf(text, query, start = 0, end = null, parentDistance = Infinity) {
|
|
37
|
+
if (end === null)
|
|
38
|
+
end = text.length;
|
|
39
|
+
// For small text segments, use iterative approach
|
|
40
|
+
if (end - start <= 2 * query.length) {
|
|
41
|
+
return iterativeReduction(text, query, start, end, parentDistance);
|
|
42
|
+
}
|
|
43
|
+
let midPoint = start + Math.floor((end - start) / 2);
|
|
44
|
+
let leftEnd = Math.min(end, midPoint + query.length); // Include query length to cover overlaps
|
|
45
|
+
let rightStart = Math.max(start, midPoint - query.length); // Include query length to cover overlaps
|
|
46
|
+
// Calculate distance for current segments
|
|
47
|
+
let leftDistance = distance(text.substring(start, leftEnd), query);
|
|
48
|
+
let rightDistance = distance(text.substring(rightStart, end), query);
|
|
49
|
+
let bestDistance = Math.min(leftDistance, parentDistance, rightDistance);
|
|
50
|
+
// If parent distance is already the best, use iterative approach
|
|
51
|
+
if (parentDistance === bestDistance) {
|
|
52
|
+
return iterativeReduction(text, query, start, end, parentDistance);
|
|
53
|
+
}
|
|
54
|
+
// Recursively search the better half
|
|
55
|
+
if (leftDistance < rightDistance) {
|
|
56
|
+
return recursiveFuzzyIndexOf(text, query, start, leftEnd, bestDistance);
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
return recursiveFuzzyIndexOf(text, query, rightStart, end, bestDistance);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Iteratively refines the best match by reducing the search area
|
|
64
|
+
* @param text The text to search within
|
|
65
|
+
* @param query The query string to find
|
|
66
|
+
* @param start Start index in the text
|
|
67
|
+
* @param end End index in the text
|
|
68
|
+
* @param parentDistance Best distance found so far
|
|
69
|
+
* @returns Object with start and end indices, matched value, and Levenshtein distance
|
|
70
|
+
*/
|
|
71
|
+
function iterativeReduction(text, query, start, end, parentDistance) {
|
|
72
|
+
const startTime = performance.now();
|
|
73
|
+
let iterations = 0;
|
|
74
|
+
// Seed with the measured distance of this slice. For recursive callers
|
|
75
|
+
// this equals parentDistance (the parent measured exactly this slice), but
|
|
76
|
+
// a top-level call on text <= 2x query length arrives with Infinity, which
|
|
77
|
+
// made the first shrink unconditional and a position-0 match unreachable.
|
|
78
|
+
let bestDistance = distance(text.substring(start, end), query);
|
|
79
|
+
let bestStart = start;
|
|
80
|
+
let bestEnd = end;
|
|
81
|
+
// Improve start position
|
|
82
|
+
let nextDistance = distance(text.substring(bestStart + 1, bestEnd), query);
|
|
83
|
+
while (nextDistance < bestDistance) {
|
|
84
|
+
bestDistance = nextDistance;
|
|
85
|
+
bestStart++;
|
|
86
|
+
const smallerString = text.substring(bestStart + 1, bestEnd);
|
|
87
|
+
nextDistance = distance(smallerString, query);
|
|
88
|
+
iterations++;
|
|
89
|
+
}
|
|
90
|
+
// Improve end position
|
|
91
|
+
nextDistance = distance(text.substring(bestStart, bestEnd - 1), query);
|
|
92
|
+
while (nextDistance < bestDistance) {
|
|
93
|
+
bestDistance = nextDistance;
|
|
94
|
+
bestEnd--;
|
|
95
|
+
const smallerString = text.substring(bestStart, bestEnd - 1);
|
|
96
|
+
nextDistance = distance(smallerString, query);
|
|
97
|
+
iterations++;
|
|
98
|
+
}
|
|
99
|
+
lastIterativeMetrics = {
|
|
100
|
+
execution_time_ms: performance.now() - startTime,
|
|
101
|
+
iterations: iterations,
|
|
102
|
+
segment_length: end - start,
|
|
103
|
+
query_length: query.length,
|
|
104
|
+
final_distance: bestDistance
|
|
105
|
+
};
|
|
106
|
+
return {
|
|
107
|
+
start: bestStart,
|
|
108
|
+
end: bestEnd,
|
|
109
|
+
value: text.substring(bestStart, bestEnd),
|
|
110
|
+
distance: bestDistance
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Calculates the similarity ratio between two strings
|
|
115
|
+
* @param a First string
|
|
116
|
+
* @param b Second string
|
|
117
|
+
* @returns Similarity ratio (0-1)
|
|
118
|
+
*/
|
|
119
|
+
export function getSimilarityRatio(a, b) {
|
|
120
|
+
const maxLength = Math.max(a.length, b.length);
|
|
121
|
+
if (maxLength === 0)
|
|
122
|
+
return 1; // Both strings are empty
|
|
123
|
+
const levenshteinDistance = distance(a, b);
|
|
124
|
+
return 1 - (levenshteinDistance / maxLength);
|
|
125
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { terminalManager } from '../terminal-manager.js';
|
|
1
|
+
import { terminalManager, MAX_BUFFERED_OUTPUT_CHARS } from '../terminal-manager.js';
|
|
2
2
|
import { commandManager } from '../command-manager.js';
|
|
3
3
|
import { StartProcessArgsSchema, ReadProcessOutputArgsSchema, InteractWithProcessArgsSchema, ForceTerminateArgsSchema } from './schemas.js';
|
|
4
4
|
import { capture } from "../utils/capture.js";
|
|
@@ -293,6 +293,13 @@ export async function readProcessOutput(args) {
|
|
|
293
293
|
// Absolute position read
|
|
294
294
|
statusMessage = `[Reading ${result.readCount} lines from line ${result.readFrom} (total: ${result.totalLines} lines, ${result.remaining} remaining)]`;
|
|
295
295
|
}
|
|
296
|
+
// Surface buffer-cap eviction so the model knows the retained output is not
|
|
297
|
+
// the full output and that line numbers shifted (matches the truncation
|
|
298
|
+
// markers used by other tools).
|
|
299
|
+
if (result.evictedLines && result.evictedLines > 0) {
|
|
300
|
+
const capMB = Math.round(MAX_BUFFERED_OUTPUT_CHARS / 1024 / 1024);
|
|
301
|
+
statusMessage += `\n[WARNING: output exceeded the ${capMB}MB buffer cap; the ${result.evictedLines} earliest lines were evicted and cannot be read. Line numbers and totals refer to the retained buffer only]`;
|
|
302
|
+
}
|
|
296
303
|
// Add process state info
|
|
297
304
|
let processStateMessage = '';
|
|
298
305
|
if (result.isComplete) {
|
package/dist/tools/schemas.d.ts
CHANGED
|
@@ -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>;
|
package/dist/tools/schemas.js
CHANGED
|
@@ -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
|
+
};
|
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;
|
|
@@ -69,7 +72,6 @@ export interface FilePreviewStructuredContent {
|
|
|
69
72
|
defaultEditorName?: string;
|
|
70
73
|
defaultEditorPath?: string;
|
|
71
74
|
content?: string;
|
|
72
|
-
imageData?: string;
|
|
73
75
|
mimeType?: string;
|
|
74
76
|
}
|
|
75
77
|
export interface ServerResult {
|