@j0hanz/filesystem-mcp 1.13.2 → 1.14.0
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 +117 -100
- package/dist/config.d.ts +0 -1
- package/dist/lib/errors.js +5 -2
- package/dist/lib/file-operations/metadata.js +9 -3
- package/dist/lib/file-operations/search.d.ts +0 -1
- package/dist/lib/file-operations/search.js +5 -12
- package/dist/lib/fs-helpers.js +10 -11
- package/dist/lib/globs.d.ts +2 -0
- package/dist/lib/globs.js +19 -0
- package/dist/lib/zod-codecs.d.ts +2 -0
- package/dist/lib/zod-codecs.js +18 -0
- package/dist/pkg-info.d.ts +1 -0
- package/dist/pkg-info.js +2 -2
- package/dist/prompts.js +3 -3
- package/dist/resources/generated-instructions.js +3 -12
- package/dist/resources/tool-catalog.js +10 -41
- package/dist/resources/tool-info.d.ts +0 -1
- package/dist/resources/tool-info.js +11 -39
- package/dist/resources/workflows.js +8 -1
- package/dist/schemas.d.ts +179 -459
- package/dist/schemas.js +156 -165
- package/dist/server/roots-manager.js +1 -1
- package/dist/tools/apply-patch.js +19 -8
- package/dist/tools/calculate-hash.js +3 -5
- package/dist/tools/create-directory.js +1 -1
- package/dist/tools/delete-file.js +2 -4
- package/dist/tools/diff-files.js +1 -3
- package/dist/tools/edit-file.js +5 -2
- package/dist/tools/list-directory.js +10 -15
- package/dist/tools/move-file.js +14 -26
- package/dist/tools/read-multiple.js +12 -7
- package/dist/tools/read.js +1 -2
- package/dist/tools/replace-in-files.js +58 -94
- package/dist/tools/roots.js +2 -6
- package/dist/tools/search-content.js +150 -186
- package/dist/tools/search-files.js +5 -9
- package/dist/tools/shared.d.ts +7 -0
- package/dist/tools/shared.js +38 -11
- package/dist/tools/stat-many.js +6 -4
- package/dist/tools/stat.js +2 -2
- package/dist/tools/tree.js +1 -1
- package/dist/tools/write-file.js +1 -5
- package/package.json +2 -1
package/dist/schemas.js
CHANGED
|
@@ -1,26 +1,20 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { DEFAULT_LIST_MAX_ENTRIES, DEFAULT_SEARCH_CONTENT_RESULTS, DEFAULT_SEARCH_RESULTS, DEFAULT_TREE_DEPTH, DEFAULT_TREE_ENTRIES, MAX_LIST_ENTRIES, MAX_SEARCH_DEPTH, MAX_SEARCH_RESULTS, MAX_TREE_DEPTH, MAX_TREE_ENTRIES, } from './lib/constants.js';
|
|
3
3
|
import { ErrorCode } from './lib/errors.js';
|
|
4
|
-
|
|
5
|
-
if (value.length === 0)
|
|
6
|
-
return false;
|
|
7
|
-
if (value.includes('**/**/**'))
|
|
8
|
-
return false;
|
|
9
|
-
const absolutePattern = /^([/\\]|[A-Za-z]:[/\\]|\\\\)/u;
|
|
10
|
-
if (absolutePattern.test(value)) {
|
|
11
|
-
return false;
|
|
12
|
-
}
|
|
13
|
-
if (/[\\/]\.\.(?:[/\\]|$)/u.test(value) || value.startsWith('..')) {
|
|
14
|
-
return false;
|
|
15
|
-
}
|
|
16
|
-
return true;
|
|
17
|
-
}
|
|
4
|
+
import { isSafeGlobPattern } from './lib/globs.js';
|
|
18
5
|
const MAX_PATH_LENGTH = 4096;
|
|
19
6
|
const DESC_PATH_ROOT = 'Base directory (default: root). Absolute path required if multiple roots.';
|
|
20
7
|
const DESC_PATH_REQUIRED = 'Absolute path to file or directory.';
|
|
21
8
|
function defaultFalseBoolean(description) {
|
|
22
9
|
return z.boolean().optional().default(false).describe(description);
|
|
23
10
|
}
|
|
11
|
+
const SuccessFlagSchema = z.literal(true);
|
|
12
|
+
const NonNegativeIntegerSchema = z.int().min(0, 'Min: 0');
|
|
13
|
+
const PositiveIntegerSchema = z.int().min(1, 'Min: 1');
|
|
14
|
+
const IsoDateTimeSchema = z.iso.datetime();
|
|
15
|
+
const Sha256HexSchema = z
|
|
16
|
+
.string()
|
|
17
|
+
.regex(/^[a-f0-9]{64}$/u, 'Expected SHA-256 hex digest');
|
|
24
18
|
const PathSchemaBase = z
|
|
25
19
|
.string()
|
|
26
20
|
.max(MAX_PATH_LENGTH, `Path too long (max ${MAX_PATH_LENGTH} chars)`);
|
|
@@ -61,11 +55,12 @@ const TailLinesSchema = z
|
|
|
61
55
|
.optional()
|
|
62
56
|
.describe('Read last N lines');
|
|
63
57
|
const LineNumberSchema = z.int({ error: 'Must be integer' }).min(1, 'Min: 1');
|
|
64
|
-
function addReadRangeIssue(ctx, path, message) {
|
|
58
|
+
function addReadRangeIssue(ctx, input, path, message) {
|
|
65
59
|
ctx.addIssue({
|
|
66
60
|
code: 'custom',
|
|
67
61
|
path: [path],
|
|
68
62
|
message,
|
|
63
|
+
input,
|
|
69
64
|
});
|
|
70
65
|
}
|
|
71
66
|
const validateReadRange = (value, ctx) => {
|
|
@@ -74,18 +69,14 @@ const validateReadRange = (value, ctx) => {
|
|
|
74
69
|
const hasStart = value.startLine !== undefined;
|
|
75
70
|
const hasEnd = value.endLine !== undefined;
|
|
76
71
|
if (hasHead && (hasStart || hasEnd)) {
|
|
77
|
-
addReadRangeIssue(ctx, 'head', "Cannot use 'head' with 'startLine'/'endLine'");
|
|
72
|
+
addReadRangeIssue(ctx, value, 'head', "Cannot use 'head' with 'startLine'/'endLine'");
|
|
78
73
|
}
|
|
79
74
|
if (hasTail && (hasHead || hasStart || hasEnd)) {
|
|
80
|
-
addReadRangeIssue(ctx, 'tail', "Cannot use 'tail' with 'head'/'startLine'/'endLine'");
|
|
81
|
-
}
|
|
82
|
-
if (hasEnd && !hasStart) {
|
|
83
|
-
addReadRangeIssue(ctx, 'endLine', "'endLine' requires 'startLine'");
|
|
75
|
+
addReadRangeIssue(ctx, value, 'tail', "Cannot use 'tail' with 'head'/'startLine'/'endLine'");
|
|
84
76
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
value
|
|
88
|
-
addReadRangeIssue(ctx, 'endLine', "'endLine' must be >= 'startLine'");
|
|
77
|
+
const effectiveStart = value.startLine ?? 1;
|
|
78
|
+
if (value.endLine !== undefined && value.endLine < effectiveStart) {
|
|
79
|
+
addReadRangeIssue(ctx, value, 'endLine', "'endLine' must be >= 'startLine'");
|
|
89
80
|
}
|
|
90
81
|
};
|
|
91
82
|
function createReadRangeInputFields(descriptions) {
|
|
@@ -100,20 +91,20 @@ const FileInfoSchema = z.strictObject({
|
|
|
100
91
|
name: z.string().describe('Name'),
|
|
101
92
|
path: z.string().describe('Absolute path'),
|
|
102
93
|
type: FileTypeSchema.describe('Type'),
|
|
103
|
-
size:
|
|
104
|
-
tokenEstimate:
|
|
105
|
-
created:
|
|
106
|
-
modified:
|
|
107
|
-
accessed:
|
|
94
|
+
size: NonNegativeIntegerSchema.describe('Size (bytes)'),
|
|
95
|
+
tokenEstimate: NonNegativeIntegerSchema.optional().describe('Est. tokens (size/4)'),
|
|
96
|
+
created: IsoDateTimeSchema.describe('Created'),
|
|
97
|
+
modified: IsoDateTimeSchema.describe('Modified'),
|
|
98
|
+
accessed: IsoDateTimeSchema.describe('Accessed'),
|
|
108
99
|
permissions: z.string().describe('Permissions'),
|
|
109
100
|
isHidden: z.boolean().describe('Hidden?'),
|
|
110
101
|
mimeType: z.string().optional().describe('MIME type'),
|
|
111
102
|
symlinkTarget: z.string().optional().describe('Target (symlink)'),
|
|
112
103
|
});
|
|
113
104
|
const OperationSummarySchema = z.strictObject({
|
|
114
|
-
total:
|
|
115
|
-
succeeded:
|
|
116
|
-
failed:
|
|
105
|
+
total: NonNegativeIntegerSchema.describe('Total'),
|
|
106
|
+
succeeded: NonNegativeIntegerSchema.describe('Succeeded'),
|
|
107
|
+
failed: NonNegativeIntegerSchema.describe('Failed'),
|
|
117
108
|
});
|
|
118
109
|
export const ListDirectoryInputSchema = z.strictObject({
|
|
119
110
|
path: OptionalPathSchema.describe(DESC_PATH_ROOT),
|
|
@@ -139,6 +130,9 @@ export const ListDirectoryInputSchema = z.strictObject({
|
|
|
139
130
|
.string()
|
|
140
131
|
.min(1, 'Pattern required')
|
|
141
132
|
.max(1000, 'Max 1000 chars')
|
|
133
|
+
.refine((val) => isSafeGlobPattern(val), {
|
|
134
|
+
error: 'Invalid glob or unsafe path (absolute/.. forbidden)',
|
|
135
|
+
})
|
|
142
136
|
.optional()
|
|
143
137
|
.describe('Optional glob pattern filter (e.g. "**/*.ts")'),
|
|
144
138
|
includeSymlinkTargets: defaultFalseBoolean('Resolve and include symlink targets in results'),
|
|
@@ -236,7 +230,6 @@ export const SearchContentInputSchema = z.strictObject({
|
|
|
236
230
|
.describe('Glob for candidate files (e.g. "**/*.ts")'),
|
|
237
231
|
includeHidden: defaultFalseBoolean('Include hidden items (starting with .)'),
|
|
238
232
|
includeIgnored: defaultFalseBoolean('Include ignored items (node_modules, etc).'),
|
|
239
|
-
multiline: defaultFalseBoolean('Multi-line mode. ^ and $ match line boundaries when isRegex=true.'),
|
|
240
233
|
});
|
|
241
234
|
export const ReadFileInputSchema = z
|
|
242
235
|
.strictObject({
|
|
@@ -244,13 +237,13 @@ export const ReadFileInputSchema = z
|
|
|
244
237
|
...createReadRangeInputFields({
|
|
245
238
|
head: 'Read first N lines (preview)',
|
|
246
239
|
tail: 'Read last N lines',
|
|
247
|
-
startLine: 'Start line (1-based, inclusive)',
|
|
248
|
-
endLine: 'End line (1-based, inclusive).
|
|
240
|
+
startLine: 'Start line (1-based, inclusive). Defaults to 1 when endLine is set.',
|
|
241
|
+
endLine: 'End line (1-based, inclusive). Defaults to last line when startLine is set.',
|
|
249
242
|
}),
|
|
250
243
|
includeHash: defaultFalseBoolean('Include SHA-256 hash of full file content'),
|
|
251
244
|
})
|
|
252
245
|
.superRefine(validateReadRange)
|
|
253
|
-
.describe("Use one read mode only: 'head', 'tail', or 'startLine'/'endLine'.
|
|
246
|
+
.describe("Use one read mode only: 'head', 'tail', or 'startLine'/'endLine'.");
|
|
254
247
|
export const ReadMultipleFilesInputSchema = z
|
|
255
248
|
.strictObject({
|
|
256
249
|
paths: z
|
|
@@ -261,12 +254,12 @@ export const ReadMultipleFilesInputSchema = z
|
|
|
261
254
|
...createReadRangeInputFields({
|
|
262
255
|
head: 'Read first N lines of each file',
|
|
263
256
|
tail: 'Read last N lines of each file',
|
|
264
|
-
startLine: 'Start line (1-based, inclusive) per file',
|
|
265
|
-
endLine: 'End line (1-based, inclusive) per file.
|
|
257
|
+
startLine: 'Start line (1-based, inclusive) per file. Defaults to 1 when endLine is set.',
|
|
258
|
+
endLine: 'End line (1-based, inclusive) per file. Defaults to last line when startLine is set.',
|
|
266
259
|
}),
|
|
267
260
|
})
|
|
268
261
|
.superRefine(validateReadRange)
|
|
269
|
-
.describe("Use one read mode only: 'head', 'tail', or 'startLine'/'endLine'.
|
|
262
|
+
.describe("Use one read mode only: 'head', 'tail', or 'startLine'/'endLine'.");
|
|
270
263
|
export const GetFileInfoInputSchema = z.strictObject({
|
|
271
264
|
path: RequiredPathSchema.describe(DESC_PATH_REQUIRED),
|
|
272
265
|
});
|
|
@@ -278,62 +271,49 @@ export const GetMultipleFileInfoInputSchema = z.strictObject({
|
|
|
278
271
|
.describe('File/directory paths. e.g. ["src", "lib"]'),
|
|
279
272
|
});
|
|
280
273
|
export const ListAllowedDirectoriesOutputSchema = z.strictObject({
|
|
281
|
-
ok:
|
|
274
|
+
ok: SuccessFlagSchema,
|
|
282
275
|
directories: z.array(z.string()).optional().describe('Allowed directories'),
|
|
283
|
-
rootsCount: z.number().optional().describe('Number of roots'),
|
|
284
|
-
hasMultipleRoots: z
|
|
285
|
-
.boolean()
|
|
286
|
-
.optional()
|
|
287
|
-
.describe('Multiple roots configured'),
|
|
288
|
-
error: ErrorSchema.optional(),
|
|
289
276
|
});
|
|
290
277
|
export const ListDirectoryOutputSchema = z.strictObject({
|
|
291
|
-
ok:
|
|
278
|
+
ok: SuccessFlagSchema,
|
|
292
279
|
path: z.string().optional(),
|
|
293
280
|
entries: z
|
|
294
281
|
.array(z.strictObject({
|
|
295
282
|
name: z.string().describe('Entry name'),
|
|
296
283
|
relativePath: z.string().optional(),
|
|
297
284
|
type: FileTypeSchema,
|
|
298
|
-
size:
|
|
299
|
-
modified:
|
|
285
|
+
size: NonNegativeIntegerSchema.optional(),
|
|
286
|
+
modified: IsoDateTimeSchema.optional(),
|
|
300
287
|
}))
|
|
301
288
|
.optional(),
|
|
302
|
-
totalEntries:
|
|
289
|
+
totalEntries: NonNegativeIntegerSchema.optional(),
|
|
303
290
|
truncated: z.boolean().optional(),
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
totalFiles: z.number().optional(),
|
|
307
|
-
totalDirectories: z.number().optional(),
|
|
308
|
-
maxDepthReached: z.number().optional(),
|
|
291
|
+
totalFiles: NonNegativeIntegerSchema.optional(),
|
|
292
|
+
totalDirectories: NonNegativeIntegerSchema.optional(),
|
|
309
293
|
stoppedReason: ListDirectoryStopReasonSchema.optional(),
|
|
310
|
-
skippedInaccessible:
|
|
311
|
-
symlinksNotFollowed: z.number().optional(),
|
|
294
|
+
skippedInaccessible: NonNegativeIntegerSchema.optional(),
|
|
312
295
|
nextCursor: z
|
|
313
296
|
.string()
|
|
314
297
|
.optional()
|
|
315
298
|
.describe('Cursor for the next page; absent on the final page'),
|
|
316
|
-
error: ErrorSchema.optional(),
|
|
317
299
|
});
|
|
318
300
|
const SearchSummarySchema = z.strictObject({
|
|
319
|
-
totalMatches:
|
|
301
|
+
totalMatches: NonNegativeIntegerSchema.optional().describe('Total matches found'),
|
|
320
302
|
truncated: z.boolean().optional().describe('Results truncated?'),
|
|
321
303
|
resourceUri: z.string().optional().describe('Full results URI'),
|
|
322
|
-
error: ErrorSchema.optional(),
|
|
323
304
|
});
|
|
324
305
|
export const SearchFilesOutputSchema = SearchSummarySchema.extend({
|
|
325
|
-
ok:
|
|
306
|
+
ok: SuccessFlagSchema,
|
|
326
307
|
root: z.string().optional().describe('Search root'),
|
|
327
|
-
pattern: z.string().optional().describe('Glob pattern used'),
|
|
328
308
|
results: z
|
|
329
309
|
.array(z.strictObject({
|
|
330
310
|
path: z.string().describe('Relative path'),
|
|
331
|
-
size:
|
|
332
|
-
modified:
|
|
311
|
+
size: NonNegativeIntegerSchema.optional(),
|
|
312
|
+
modified: IsoDateTimeSchema.optional(),
|
|
333
313
|
}))
|
|
334
314
|
.optional(),
|
|
335
|
-
filesScanned:
|
|
336
|
-
skippedInaccessible:
|
|
315
|
+
filesScanned: NonNegativeIntegerSchema.optional().describe('Files scanned'),
|
|
316
|
+
skippedInaccessible: NonNegativeIntegerSchema.optional().describe('Inaccessible files'),
|
|
337
317
|
stoppedReason: SearchStopReasonSchema.optional().describe('Why search stopped'),
|
|
338
318
|
nextCursor: z
|
|
339
319
|
.string()
|
|
@@ -341,70 +321,49 @@ export const SearchFilesOutputSchema = SearchSummarySchema.extend({
|
|
|
341
321
|
.describe('Cursor for the next page; absent on the final page'),
|
|
342
322
|
});
|
|
343
323
|
export const SearchContentOutputSchema = SearchSummarySchema.extend({
|
|
344
|
-
ok:
|
|
345
|
-
patternType: z
|
|
346
|
-
.enum(['literal', 'regex'])
|
|
347
|
-
.optional()
|
|
348
|
-
.describe('Pattern interpretation'),
|
|
349
|
-
caseSensitive: z.boolean().optional().describe('Case-sensitive matching'),
|
|
324
|
+
ok: SuccessFlagSchema,
|
|
350
325
|
matches: z
|
|
351
326
|
.array(z.strictObject({
|
|
352
327
|
file: z.string().describe('Relative path'),
|
|
353
|
-
line:
|
|
354
|
-
column:
|
|
355
|
-
.number()
|
|
356
|
-
.optional()
|
|
357
|
-
.describe('Column of first match (0-based)'),
|
|
328
|
+
line: PositiveIntegerSchema,
|
|
329
|
+
column: NonNegativeIntegerSchema.optional().describe('Column of first match (0-based)'),
|
|
358
330
|
content: z.string(),
|
|
359
|
-
matchCount:
|
|
331
|
+
matchCount: PositiveIntegerSchema,
|
|
360
332
|
contextBefore: z.array(z.string()).optional(),
|
|
361
333
|
contextAfter: z.array(z.string()).optional(),
|
|
362
334
|
}))
|
|
363
335
|
.optional(),
|
|
364
|
-
filesScanned:
|
|
365
|
-
filesMatched:
|
|
366
|
-
skippedTooLarge:
|
|
367
|
-
skippedBinary:
|
|
368
|
-
skippedInaccessible:
|
|
369
|
-
.number()
|
|
370
|
-
.optional()
|
|
371
|
-
.describe('Files skipped: inaccessible'),
|
|
372
|
-
linesSkippedDueToRegexTimeout: z
|
|
373
|
-
.number()
|
|
374
|
-
.optional()
|
|
375
|
-
.describe('Lines skipped due to regex timeout'),
|
|
336
|
+
filesScanned: NonNegativeIntegerSchema.optional().describe('Files scanned'),
|
|
337
|
+
filesMatched: NonNegativeIntegerSchema.optional().describe('Files with matches'),
|
|
338
|
+
skippedTooLarge: NonNegativeIntegerSchema.optional().describe('Files skipped: too large'),
|
|
339
|
+
skippedBinary: NonNegativeIntegerSchema.optional().describe('Files skipped: binary'),
|
|
340
|
+
skippedInaccessible: NonNegativeIntegerSchema.optional().describe('Files skipped: inaccessible'),
|
|
376
341
|
stoppedReason: SearchStopReasonSchema.optional().describe('Why search stopped'),
|
|
377
342
|
});
|
|
378
343
|
export const TreeOutputSchema = z.strictObject({
|
|
379
|
-
ok:
|
|
344
|
+
ok: SuccessFlagSchema,
|
|
380
345
|
root: z.string().optional(),
|
|
381
346
|
tree: TreeEntrySchema.optional(),
|
|
382
347
|
ascii: z.string().optional(),
|
|
383
348
|
truncated: z.boolean().optional(),
|
|
384
|
-
totalEntries:
|
|
385
|
-
error: ErrorSchema.optional(),
|
|
349
|
+
totalEntries: NonNegativeIntegerSchema.optional(),
|
|
386
350
|
});
|
|
387
351
|
const ReadResultSchema = z.strictObject({
|
|
388
352
|
content: z.string().optional().describe('Content'),
|
|
389
353
|
truncated: z.boolean().optional().describe('Truncated?'),
|
|
390
354
|
resourceUri: z.string().optional().describe('Full content URI'),
|
|
391
|
-
totalLines:
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
tail: z.number().optional().describe('Tail lines'),
|
|
398
|
-
startLine: z.number().optional().describe('Start line'),
|
|
399
|
-
endLine: z.number().optional().describe('End line'),
|
|
400
|
-
linesRead: z.number().optional().describe('Lines read'),
|
|
355
|
+
totalLines: NonNegativeIntegerSchema.optional().describe('Total lines'),
|
|
356
|
+
head: PositiveIntegerSchema.optional().describe('Head lines'),
|
|
357
|
+
tail: PositiveIntegerSchema.optional().describe('Tail lines'),
|
|
358
|
+
startLine: PositiveIntegerSchema.optional().describe('Start line'),
|
|
359
|
+
endLine: PositiveIntegerSchema.optional().describe('End line'),
|
|
360
|
+
linesRead: NonNegativeIntegerSchema.optional().describe('Lines read'),
|
|
401
361
|
hasMoreLines: z.boolean().optional().describe('More lines?'),
|
|
402
362
|
});
|
|
403
363
|
export const ReadFileOutputSchema = ReadResultSchema.extend({
|
|
404
|
-
ok:
|
|
364
|
+
ok: SuccessFlagSchema,
|
|
405
365
|
path: z.string().optional(),
|
|
406
|
-
contentHash:
|
|
407
|
-
error: ErrorSchema.optional(),
|
|
366
|
+
contentHash: Sha256HexSchema.optional().describe('SHA-256 of full file content'),
|
|
408
367
|
});
|
|
409
368
|
const ReadMultipleFileResultSchema = ReadResultSchema.extend({
|
|
410
369
|
path: z.string().describe('File path'),
|
|
@@ -412,60 +371,77 @@ const ReadMultipleFileResultSchema = ReadResultSchema.extend({
|
|
|
412
371
|
.enum(['head', 'tail', 'range', 'externalized'])
|
|
413
372
|
.optional()
|
|
414
373
|
.describe('Why content was truncated'),
|
|
415
|
-
|
|
416
|
-
error: z.string().optional().describe('Error message'),
|
|
374
|
+
error: ErrorSchema.optional().describe('Structured error details'),
|
|
417
375
|
});
|
|
418
376
|
export const ReadMultipleFilesOutputSchema = z.strictObject({
|
|
419
|
-
ok:
|
|
377
|
+
ok: SuccessFlagSchema,
|
|
420
378
|
results: z.array(ReadMultipleFileResultSchema).optional(),
|
|
421
379
|
summary: OperationSummarySchema.optional(),
|
|
422
|
-
error: ErrorSchema.optional(),
|
|
423
380
|
});
|
|
424
381
|
export const GetFileInfoOutputSchema = z.strictObject({
|
|
425
|
-
ok:
|
|
382
|
+
ok: SuccessFlagSchema,
|
|
426
383
|
info: FileInfoSchema.optional(),
|
|
427
|
-
error: ErrorSchema.optional(),
|
|
428
384
|
});
|
|
429
385
|
export const GetMultipleFileInfoOutputSchema = z.strictObject({
|
|
430
|
-
ok:
|
|
386
|
+
ok: SuccessFlagSchema,
|
|
431
387
|
results: z
|
|
432
388
|
.array(z.strictObject({
|
|
433
389
|
path: z.string(),
|
|
434
390
|
info: FileInfoSchema.optional(),
|
|
435
|
-
error:
|
|
391
|
+
error: ErrorSchema.optional(),
|
|
436
392
|
}))
|
|
437
393
|
.optional(),
|
|
438
394
|
summary: OperationSummarySchema.optional(),
|
|
439
|
-
error: ErrorSchema.optional(),
|
|
440
395
|
});
|
|
441
396
|
export const CreateDirectoryInputSchema = z
|
|
442
397
|
.strictObject({
|
|
443
398
|
path: RequiredPathSchema.optional().describe(DESC_PATH_REQUIRED),
|
|
444
399
|
paths: z
|
|
445
400
|
.array(RequiredPathSchema)
|
|
401
|
+
.min(1, 'Min 1 path required')
|
|
446
402
|
.optional()
|
|
447
403
|
.describe('Absolute paths to directories to create'),
|
|
448
404
|
})
|
|
449
|
-
.
|
|
450
|
-
|
|
451
|
-
|
|
405
|
+
.superRefine((data, ctx) => {
|
|
406
|
+
const hasPath = data.path !== undefined;
|
|
407
|
+
const hasPaths = data.paths !== undefined;
|
|
408
|
+
if (!hasPath && !hasPaths) {
|
|
409
|
+
ctx.addIssue({
|
|
410
|
+
code: 'custom',
|
|
411
|
+
path: ['path'],
|
|
412
|
+
message: "Either 'path' or 'paths' must be provided",
|
|
413
|
+
input: data,
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
if (hasPath && hasPaths) {
|
|
417
|
+
ctx.addIssue({
|
|
418
|
+
code: 'custom',
|
|
419
|
+
path: ['path'],
|
|
420
|
+
message: "Provide either 'path' or 'paths', not both",
|
|
421
|
+
input: data,
|
|
422
|
+
});
|
|
423
|
+
ctx.addIssue({
|
|
424
|
+
code: 'custom',
|
|
425
|
+
path: ['paths'],
|
|
426
|
+
message: "Provide either 'path' or 'paths', not both",
|
|
427
|
+
input: data,
|
|
428
|
+
});
|
|
429
|
+
}
|
|
452
430
|
})
|
|
453
431
|
.describe("Provide either 'path' or 'paths'.");
|
|
454
432
|
export const CreateDirectoryOutputSchema = z.strictObject({
|
|
455
|
-
ok:
|
|
433
|
+
ok: SuccessFlagSchema,
|
|
456
434
|
path: z.string().optional(),
|
|
457
435
|
paths: z.array(z.string()).optional(),
|
|
458
|
-
error: ErrorSchema.optional(),
|
|
459
436
|
});
|
|
460
437
|
export const WriteFileInputSchema = z.strictObject({
|
|
461
438
|
path: RequiredPathSchema.describe(DESC_PATH_REQUIRED),
|
|
462
439
|
content: z.string().describe('Content to write'),
|
|
463
440
|
});
|
|
464
441
|
export const WriteFileOutputSchema = z.strictObject({
|
|
465
|
-
ok:
|
|
442
|
+
ok: SuccessFlagSchema,
|
|
466
443
|
path: z.string().optional(),
|
|
467
|
-
bytesWritten:
|
|
468
|
-
error: ErrorSchema.optional(),
|
|
444
|
+
bytesWritten: NonNegativeIntegerSchema.optional(),
|
|
469
445
|
});
|
|
470
446
|
export const EditFileInputSchema = z.strictObject({
|
|
471
447
|
path: RequiredPathSchema.describe(DESC_PATH_REQUIRED),
|
|
@@ -486,11 +462,11 @@ export const EditFileInputSchema = z.strictObject({
|
|
|
486
462
|
export const EditFileOutputSchema = z.strictObject({
|
|
487
463
|
ok: z.boolean(),
|
|
488
464
|
path: z.string().optional(),
|
|
489
|
-
appliedEdits:
|
|
490
|
-
linesAdded:
|
|
491
|
-
linesRemoved:
|
|
465
|
+
appliedEdits: NonNegativeIntegerSchema.optional(),
|
|
466
|
+
linesAdded: NonNegativeIntegerSchema.optional().describe('Lines added'),
|
|
467
|
+
linesRemoved: NonNegativeIntegerSchema.optional().describe('Lines removed'),
|
|
492
468
|
lineRange: z
|
|
493
|
-
.tuple([
|
|
469
|
+
.tuple([PositiveIntegerSchema, PositiveIntegerSchema])
|
|
494
470
|
.optional()
|
|
495
471
|
.describe('Line range modified [start, end] (1-based)'),
|
|
496
472
|
unmatchedEdits: z
|
|
@@ -498,17 +474,42 @@ export const EditFileOutputSchema = z.strictObject({
|
|
|
498
474
|
.optional()
|
|
499
475
|
.describe('Edits that could not be applied'),
|
|
500
476
|
diff: z.string().optional().describe('Unified diff of changes (dryRun)'),
|
|
501
|
-
error: ErrorSchema.optional(),
|
|
502
477
|
});
|
|
503
478
|
export const MoveFileInputSchema = z
|
|
504
479
|
.strictObject({
|
|
505
480
|
source: RequiredPathSchema.optional().describe('Path to move (deprecated: use sources)'),
|
|
506
|
-
sources: z
|
|
481
|
+
sources: z
|
|
482
|
+
.array(RequiredPathSchema)
|
|
483
|
+
.min(1, 'Min 1 source required')
|
|
484
|
+
.optional()
|
|
485
|
+
.describe('Paths to move'),
|
|
507
486
|
destination: RequiredPathSchema.describe('New path'),
|
|
508
487
|
})
|
|
509
|
-
.
|
|
510
|
-
|
|
511
|
-
|
|
488
|
+
.superRefine((data, ctx) => {
|
|
489
|
+
const hasSource = data.source !== undefined;
|
|
490
|
+
const hasSources = data.sources !== undefined;
|
|
491
|
+
if (!hasSource && !hasSources) {
|
|
492
|
+
ctx.addIssue({
|
|
493
|
+
code: 'custom',
|
|
494
|
+
path: ['source'],
|
|
495
|
+
message: "Either 'source' or 'sources' must be provided",
|
|
496
|
+
input: data,
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
if (hasSource && hasSources) {
|
|
500
|
+
ctx.addIssue({
|
|
501
|
+
code: 'custom',
|
|
502
|
+
path: ['source'],
|
|
503
|
+
message: "Provide either 'source' or 'sources', not both",
|
|
504
|
+
input: data,
|
|
505
|
+
});
|
|
506
|
+
ctx.addIssue({
|
|
507
|
+
code: 'custom',
|
|
508
|
+
path: ['sources'],
|
|
509
|
+
message: "Provide either 'source' or 'sources', not both",
|
|
510
|
+
input: data,
|
|
511
|
+
});
|
|
512
|
+
}
|
|
512
513
|
})
|
|
513
514
|
.describe("Provide either 'source' or 'sources'.");
|
|
514
515
|
export const MoveFileOutputSchema = z.strictObject({
|
|
@@ -519,11 +520,10 @@ export const MoveFileOutputSchema = z.strictObject({
|
|
|
519
520
|
failed: z
|
|
520
521
|
.array(z.strictObject({
|
|
521
522
|
source: z.string().describe('Source path'),
|
|
522
|
-
error:
|
|
523
|
+
error: ErrorSchema.describe('Structured error details'),
|
|
523
524
|
}))
|
|
524
525
|
.optional()
|
|
525
526
|
.describe('List of files that failed to move'),
|
|
526
|
-
error: ErrorSchema.optional(),
|
|
527
527
|
});
|
|
528
528
|
export const DeleteFileInputSchema = z.strictObject({
|
|
529
529
|
path: RequiredPathSchema.describe(DESC_PATH_REQUIRED),
|
|
@@ -531,23 +531,18 @@ export const DeleteFileInputSchema = z.strictObject({
|
|
|
531
531
|
ignoreIfNotExists: defaultFalseBoolean('No error if missing'),
|
|
532
532
|
});
|
|
533
533
|
export const DeleteFileOutputSchema = z.strictObject({
|
|
534
|
-
ok:
|
|
534
|
+
ok: SuccessFlagSchema,
|
|
535
535
|
path: z.string().optional(),
|
|
536
|
-
error: ErrorSchema.optional(),
|
|
537
536
|
});
|
|
538
537
|
export const CalculateHashInputSchema = z.strictObject({
|
|
539
538
|
path: RequiredPathSchema.describe(DESC_PATH_REQUIRED),
|
|
540
539
|
});
|
|
541
540
|
export const CalculateHashOutputSchema = z.strictObject({
|
|
542
|
-
ok:
|
|
541
|
+
ok: SuccessFlagSchema,
|
|
543
542
|
path: z.string().optional(),
|
|
544
|
-
hash:
|
|
543
|
+
hash: Sha256HexSchema.optional().describe('SHA-256 hash'),
|
|
545
544
|
isDirectory: z.boolean().optional().describe('True if path is a directory'),
|
|
546
|
-
fileCount:
|
|
547
|
-
.number()
|
|
548
|
-
.optional()
|
|
549
|
-
.describe('Number of files hashed (directories only)'),
|
|
550
|
-
error: ErrorSchema.optional(),
|
|
545
|
+
fileCount: NonNegativeIntegerSchema.optional().describe('Number of files hashed (directories only)'),
|
|
551
546
|
});
|
|
552
547
|
export const DiffFilesInputSchema = z.strictObject({
|
|
553
548
|
original: RequiredPathSchema.describe('Path to original file'),
|
|
@@ -570,15 +565,14 @@ export const DiffFilesInputSchema = z.strictObject({
|
|
|
570
565
|
.describe('Strip trailing carriage returns before diffing'),
|
|
571
566
|
});
|
|
572
567
|
export const DiffFilesOutputSchema = z.strictObject({
|
|
573
|
-
ok:
|
|
568
|
+
ok: SuccessFlagSchema,
|
|
574
569
|
diff: z.string().optional().describe('Unified diff content'),
|
|
575
570
|
isIdentical: z.boolean().optional().describe('True if files are identical'),
|
|
576
|
-
linesAdded:
|
|
577
|
-
linesRemoved:
|
|
578
|
-
hunksCount:
|
|
571
|
+
linesAdded: NonNegativeIntegerSchema.optional().describe('Lines added'),
|
|
572
|
+
linesRemoved: NonNegativeIntegerSchema.optional().describe('Lines removed'),
|
|
573
|
+
hunksCount: NonNegativeIntegerSchema.optional().describe('Number of diff hunks'),
|
|
579
574
|
truncated: z.boolean().optional().describe('Diff content truncated?'),
|
|
580
575
|
resourceUri: z.string().optional().describe('Full diff content URI'),
|
|
581
|
-
error: ErrorSchema.optional(),
|
|
582
576
|
});
|
|
583
577
|
export const ApplyPatchInputSchema = z.strictObject({
|
|
584
578
|
path: RequiredPathSchema.describe('Path to file to patch'),
|
|
@@ -610,21 +604,20 @@ export const ApplyPatchOutputSchema = z.strictObject({
|
|
|
610
604
|
ok: z.boolean(),
|
|
611
605
|
path: z.string().optional(),
|
|
612
606
|
applied: z.boolean().optional(),
|
|
613
|
-
hunksApplied:
|
|
614
|
-
linesAdded:
|
|
615
|
-
linesRemoved:
|
|
607
|
+
hunksApplied: NonNegativeIntegerSchema.optional().describe('Hunks applied'),
|
|
608
|
+
linesAdded: NonNegativeIntegerSchema.optional().describe('Lines added'),
|
|
609
|
+
linesRemoved: NonNegativeIntegerSchema.optional().describe('Lines removed'),
|
|
616
610
|
results: z
|
|
617
611
|
.array(z.strictObject({
|
|
618
612
|
path: z.string().describe('File path'),
|
|
619
613
|
applied: z.boolean().describe('Patch applied successfully'),
|
|
620
|
-
hunksApplied:
|
|
621
|
-
linesAdded:
|
|
622
|
-
linesRemoved:
|
|
623
|
-
error:
|
|
614
|
+
hunksApplied: NonNegativeIntegerSchema.optional().describe('Hunks applied'),
|
|
615
|
+
linesAdded: NonNegativeIntegerSchema.optional().describe('Lines added'),
|
|
616
|
+
linesRemoved: NonNegativeIntegerSchema.optional().describe('Lines removed'),
|
|
617
|
+
error: ErrorSchema.optional().describe('Structured error details'),
|
|
624
618
|
}))
|
|
625
619
|
.optional()
|
|
626
620
|
.describe('Per-file results for multi-file patches'),
|
|
627
|
-
error: ErrorSchema.optional(),
|
|
628
621
|
});
|
|
629
622
|
export const SearchAndReplaceInputSchema = z.strictObject({
|
|
630
623
|
path: OptionalPathSchema.describe(DESC_PATH_ROOT),
|
|
@@ -671,22 +664,22 @@ export const SearchAndReplaceInputSchema = z.strictObject({
|
|
|
671
664
|
.describe('Max files to process before stopping'),
|
|
672
665
|
});
|
|
673
666
|
export const SearchAndReplaceOutputSchema = z.strictObject({
|
|
674
|
-
ok:
|
|
675
|
-
matches:
|
|
676
|
-
filesChanged:
|
|
677
|
-
processedFiles:
|
|
678
|
-
failedFiles:
|
|
667
|
+
ok: SuccessFlagSchema,
|
|
668
|
+
matches: NonNegativeIntegerSchema.optional().describe('Total matches found'),
|
|
669
|
+
filesChanged: NonNegativeIntegerSchema.optional().describe('Files modified'),
|
|
670
|
+
processedFiles: NonNegativeIntegerSchema.optional().describe('Files processed'),
|
|
671
|
+
failedFiles: NonNegativeIntegerSchema.optional().describe('Files skipped due to errors'),
|
|
679
672
|
failures: z
|
|
680
673
|
.array(z.strictObject({
|
|
681
674
|
path: z.string().describe('File path'),
|
|
682
|
-
error:
|
|
675
|
+
error: ErrorSchema.describe('Structured error details'),
|
|
683
676
|
}))
|
|
684
677
|
.optional()
|
|
685
678
|
.describe('Sample of per-file errors'),
|
|
686
679
|
changedFiles: z
|
|
687
680
|
.array(z.strictObject({
|
|
688
681
|
path: z.string().describe('File path'),
|
|
689
|
-
matches:
|
|
682
|
+
matches: PositiveIntegerSchema.describe('Matches in file'),
|
|
690
683
|
}))
|
|
691
684
|
.optional()
|
|
692
685
|
.describe('Sample of changed files'),
|
|
@@ -703,6 +696,4 @@ export const SearchAndReplaceOutputSchema = z.strictObject({
|
|
|
703
696
|
.enum(['maxFiles'])
|
|
704
697
|
.optional()
|
|
705
698
|
.describe('Why processing stopped early'),
|
|
706
|
-
dryRun: z.boolean().optional(),
|
|
707
|
-
error: ErrorSchema.optional(),
|
|
708
699
|
});
|
|
@@ -22,7 +22,7 @@ const RootSchema = z.strictObject({
|
|
|
22
22
|
uri: z.string(),
|
|
23
23
|
name: z.string().optional(),
|
|
24
24
|
});
|
|
25
|
-
const RootsResponseSchema = z.
|
|
25
|
+
const RootsResponseSchema = z.strictObject({
|
|
26
26
|
roots: z.array(RootSchema).optional(),
|
|
27
27
|
});
|
|
28
28
|
function isRoot(value) {
|