@j0hanz/filesystem-mcp 2.2.0 → 2.3.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.
Files changed (94) hide show
  1. package/README.md +40 -27
  2. package/dist/cli-help.d.ts.map +1 -1
  3. package/dist/cli-help.js +10 -2
  4. package/dist/cli-help.js.map +1 -1
  5. package/dist/cli.d.ts.map +1 -1
  6. package/dist/cli.js +10 -5
  7. package/dist/cli.js.map +1 -1
  8. package/dist/core/concurrency.d.ts.map +1 -1
  9. package/dist/core/concurrency.js +21 -6
  10. package/dist/core/concurrency.js.map +1 -1
  11. package/dist/core/config.d.ts +2 -0
  12. package/dist/core/config.d.ts.map +1 -1
  13. package/dist/core/config.js.map +1 -1
  14. package/dist/core/errors.d.ts +6 -9
  15. package/dist/core/errors.d.ts.map +1 -1
  16. package/dist/core/errors.js +58 -102
  17. package/dist/core/errors.js.map +1 -1
  18. package/dist/core/file-uri.d.ts +5 -1
  19. package/dist/core/file-uri.d.ts.map +1 -1
  20. package/dist/core/file-uri.js +6 -2
  21. package/dist/core/file-uri.js.map +1 -1
  22. package/dist/core/fmt.d.ts +0 -1
  23. package/dist/core/fmt.d.ts.map +1 -1
  24. package/dist/core/fmt.js +0 -1
  25. package/dist/core/fmt.js.map +1 -1
  26. package/dist/core/fs.d.ts +31 -1
  27. package/dist/core/fs.d.ts.map +1 -1
  28. package/dist/core/fs.js +142 -2
  29. package/dist/core/fs.js.map +1 -1
  30. package/dist/core/glob.d.ts.map +1 -1
  31. package/dist/core/glob.js +3 -8
  32. package/dist/core/glob.js.map +1 -1
  33. package/dist/core/input-required.d.ts +8 -17
  34. package/dist/core/input-required.d.ts.map +1 -1
  35. package/dist/core/input-required.js +32 -47
  36. package/dist/core/input-required.js.map +1 -1
  37. package/dist/core/observability.d.ts +9 -0
  38. package/dist/core/observability.d.ts.map +1 -1
  39. package/dist/core/observability.js +11 -0
  40. package/dist/core/observability.js.map +1 -1
  41. package/dist/core/page-store.d.ts +4 -3
  42. package/dist/core/page-store.d.ts.map +1 -1
  43. package/dist/core/page-store.js +4 -3
  44. package/dist/core/page-store.js.map +1 -1
  45. package/dist/core/search.d.ts +5 -0
  46. package/dist/core/search.d.ts.map +1 -1
  47. package/dist/core/search.js +18 -19
  48. package/dist/core/search.js.map +1 -1
  49. package/dist/core/sensitive.d.ts +4 -2
  50. package/dist/core/sensitive.d.ts.map +1 -1
  51. package/dist/core/sensitive.js +261 -43
  52. package/dist/core/sensitive.js.map +1 -1
  53. package/dist/core/watcher-registry.d.ts.map +1 -1
  54. package/dist/core/watcher-registry.js +5 -1
  55. package/dist/core/watcher-registry.js.map +1 -1
  56. package/dist/resources.d.ts.map +1 -1
  57. package/dist/resources.js +13 -4
  58. package/dist/resources.js.map +1 -1
  59. package/dist/server.d.ts.map +1 -1
  60. package/dist/server.js +7 -2
  61. package/dist/server.js.map +1 -1
  62. package/dist/tools/create.d.ts.map +1 -1
  63. package/dist/tools/create.js +163 -14
  64. package/dist/tools/create.js.map +1 -1
  65. package/dist/tools/define.d.ts +6 -1
  66. package/dist/tools/define.d.ts.map +1 -1
  67. package/dist/tools/define.js +25 -5
  68. package/dist/tools/define.js.map +1 -1
  69. package/dist/tools/delete.d.ts.map +1 -1
  70. package/dist/tools/delete.js +8 -11
  71. package/dist/tools/delete.js.map +1 -1
  72. package/dist/tools/edit.d.ts.map +1 -1
  73. package/dist/tools/edit.js +77 -69
  74. package/dist/tools/edit.js.map +1 -1
  75. package/dist/tools/index.d.ts +1 -0
  76. package/dist/tools/index.d.ts.map +1 -1
  77. package/dist/tools/index.js +1 -0
  78. package/dist/tools/index.js.map +1 -1
  79. package/dist/tools/move.d.ts.map +1 -1
  80. package/dist/tools/move.js +14 -33
  81. package/dist/tools/move.js.map +1 -1
  82. package/dist/tools/patch.js +3 -3
  83. package/dist/tools/patch.js.map +1 -1
  84. package/dist/tools/search-text.d.ts.map +1 -1
  85. package/dist/tools/search-text.js +64 -1
  86. package/dist/tools/search-text.js.map +1 -1
  87. package/dist/transport/http.d.ts.map +1 -1
  88. package/dist/transport/http.js +5 -1
  89. package/dist/transport/http.js.map +1 -1
  90. package/dist/transport/stdio.d.ts +1 -0
  91. package/dist/transport/stdio.d.ts.map +1 -1
  92. package/dist/transport/stdio.js +1 -0
  93. package/dist/transport/stdio.js.map +1 -1
  94. package/package.json +6 -9
@@ -4,7 +4,7 @@ import { computeDiffStats, unifiedPatch } from '../core/diff.js';
4
4
  import { ErrorCode, FsError } from '../core/errors.js';
5
5
  import { buildWrittenFileMeta } from '../core/file-uri.js';
6
6
  import { escapeRegexLiteral } from '../core/primitives.js';
7
- import { defaultFalseBoolean, FileKind, isBlank, IsoDateTime, NonNegInt, OperationSummarySchema, PerFileErrorSchema, PositiveInt, RequiredPath, singleOrBatchAccessPaths, } from '../core/schema.js';
7
+ import { defaultFalseBoolean, FileKind, isBlank, IsoDateTime, NonNegInt, OperationSummarySchema, PerFileErrorSchema, RequiredPath, singleOrBatchAccessPaths, } from '../core/schema.js';
8
8
  import { compileRegex, execMatches, freeRegex } from '../core/search.js';
9
9
  import { isTotalFailure, runOverPaths } from './batch.js';
10
10
  import { defineTool } from './define.js';
@@ -16,7 +16,7 @@ const EditSpecSchema = z
16
16
  .refine((val) => !isBlank(val), {
17
17
  message: 'oldText cannot be empty or whitespace-only',
18
18
  })
19
- .describe('Exact literal text to locate in the file. Must include 3-5 lines of context to ensure uniqueness and avoid matching the wrong block.')
19
+ .describe('Exact literal text to locate in the file; it must match exactly once. Include 3-5 lines of context so it does — an oldText found in several places fails with their line numbers.')
20
20
  .meta({ examples: ['const x = 1;', 'function oldName('] }),
21
21
  newText: z
22
22
  .string()
@@ -107,10 +107,6 @@ const PerFileResultSchema = z.strictObject({
107
107
  .array(z.string())
108
108
  .optional()
109
109
  .describe('oldText values that did not match any content in the file'),
110
- lineRange: z
111
- .tuple([PositiveInt, PositiveInt])
112
- .optional()
113
- .describe('Line range [firstLine, lastLine] covering all applied edits'),
114
110
  });
115
111
  const EditPerPathSchema = z.strictObject({
116
112
  path: z.string().describe('Requested file path'),
@@ -123,7 +119,22 @@ const EditFileOutputSchema = z.strictObject({
123
119
  .describe('Per-path edit results ordered to match the input paths'),
124
120
  summary: OperationSummarySchema,
125
121
  });
126
- function findEditMatch(content, oldText, ignoreWhitespace) {
122
+ const MAX_REPORTED_MATCH_LINES = 5;
123
+ /**
124
+ * Where `oldText` matches. `count` is non-overlapping occurrences, except that a
125
+ * lone match with a second one overlapping it counts two (`abab` in `ababab`),
126
+ * since either is a span the caller could have meant — the count is exact only
127
+ * when it answers "once or not". Only the count and the first few starts are
128
+ * kept: a short oldText in a large file can match millions of times.
129
+ */
130
+ function findEditMatches(content, oldText, ignoreWhitespace) {
131
+ const found = { first: undefined, count: 0, starts: [] };
132
+ const add = (startIndex, length) => {
133
+ found.first ??= { startIndex, length };
134
+ found.count += 1;
135
+ if (found.starts.length < MAX_REPORTED_MATCH_LINES)
136
+ found.starts.push(startIndex);
137
+ };
127
138
  if (ignoreWhitespace) {
128
139
  // Make whitespace flexible (tolerate indentation/spacing differences)
129
140
  // without letting it cross line boundaries: a whitespace run that contains
@@ -139,68 +150,65 @@ function findEditMatch(content, oldText, ignoreWhitespace) {
139
150
  try {
140
151
  // execMatches resets lastIndex and reports UTF-16 offsets; the raw RE2
141
152
  // index counts code points and would splice off-by-one per emoji.
142
- const { value: match } = execMatches(regex, content).next();
143
- // A zero-length match names an empty span, which cannot be replaced.
144
- if (match === undefined || match.text.length === 0)
145
- return undefined;
146
- return {
147
- startIndex: match.start,
148
- length: match.text.length,
153
+ const scan = (from) => {
154
+ for (const match of execMatches(regex, from === 0 ? content : content.slice(from))) {
155
+ // A zero-length match names an empty span, which cannot be replaced.
156
+ if (match.text.length > 0)
157
+ add(from + match.start, match.text.length);
158
+ if (from > 0)
159
+ return;
160
+ }
149
161
  };
162
+ scan(0);
163
+ // execMatches resumes past each match, so a second match overlapping the
164
+ // first is never reported; look once more from just past its first
165
+ // non-whitespace character. Starting inside the leading whitespace would
166
+ // re-find the same occurrence, since the pattern's leading run is `*`. The
167
+ // pattern carries no anchors, so matching a suffix finds the same spans.
168
+ if (found.count === 1 && found.first) {
169
+ const { startIndex, length } = found.first;
170
+ const lead = content.slice(startIndex, startIndex + length).search(/\S/u);
171
+ scan(afterCodePoint(content, startIndex + lead));
172
+ }
150
173
  }
151
174
  finally {
152
175
  // The compiled pattern owns wasm memory re2-wasm never reclaims on its
153
- // own; its lifetime is this one match.
176
+ // own; its lifetime is this one search.
154
177
  freeRegex(regex);
155
178
  }
179
+ return found;
156
180
  }
157
- const index = content.indexOf(oldText);
158
- if (index === -1) {
159
- return undefined;
181
+ // Non-overlapping, so the scan stays linear on repetitive content; the one
182
+ // overlap that matters — a second match inside the only one — is checked after.
183
+ for (let i = content.indexOf(oldText); i !== -1; i = content.indexOf(oldText, i + oldText.length)) {
184
+ add(i, oldText.length);
160
185
  }
161
- return {
162
- startIndex: index,
163
- length: oldText.length,
164
- };
186
+ if (found.count === 1 && found.first) {
187
+ const overlap = content.indexOf(oldText, afterCodePoint(content, found.first.startIndex));
188
+ if (overlap !== -1)
189
+ add(overlap, oldText.length);
190
+ }
191
+ return found;
192
+ }
193
+ /** The UTF-16 offset just past the code point at `index`, so a surrogate pair is never split. */
194
+ function afterCodePoint(content, index) {
195
+ return index + ((content.codePointAt(index) ?? 0) > 0xffff ? 2 : 1);
196
+ }
197
+ function ambiguousEditError(content, found, editIndex, shifted) {
198
+ const lines = [
199
+ ...new Set(found.starts.map((start) => content.slice(0, start).split('\n').length)),
200
+ ];
201
+ const label = lines.length === 1 ? 'line' : 'lines';
202
+ const more = found.count > found.starts.length ? ', ...' : '';
203
+ // Offsets come from the content as earlier edits in this call left it, which
204
+ // is not the file the caller read once one of them has applied.
205
+ const where = shifted ? ' after earlier edits' : '';
206
+ return new FsError(ErrorCode.INVALID_INPUT, `edits[${String(editIndex)}]: oldText matches ${String(found.count)} places${where} ` +
207
+ `(${label} ${lines.join(', ')}${more}). Add surrounding lines so it matches once.`);
165
208
  }
166
209
  function replaceEditMatch(content, match, newText) {
167
210
  return (content.slice(0, match.startIndex) + newText + content.slice(match.startIndex + match.length));
168
211
  }
169
- /**
170
- * Compute the 1-indexed line range of changed lines in `modified` relative to
171
- * `original`, using a common-prefix/suffix line scan. This is a conservative
172
- * bound (it widens to cover independent changes between matching bookends), but
173
- * it is computed against the FINAL content so it is not skewed by earlier edits
174
- * inserting or removing lines — which the per-edit merge could not account for.
175
- */
176
- function computeChangedLineRange(original, modified) {
177
- const origLines = original.split('\n');
178
- const modLines = modified.split('\n');
179
- const minLen = Math.min(origLines.length, modLines.length);
180
- let firstChanged = -1;
181
- for (let i = 0; i < minLen; i++) {
182
- if (origLines[i] !== modLines[i]) {
183
- firstChanged = i;
184
- break;
185
- }
186
- }
187
- if (firstChanged === -1 && origLines.length === modLines.length)
188
- return undefined;
189
- if (firstChanged === -1)
190
- firstChanged = minLen; // pure append/trim at the tail
191
- let lastChangedMod = modLines.length - 1;
192
- let lastChangedOrig = origLines.length - 1;
193
- while (lastChangedMod > firstChanged &&
194
- lastChangedOrig >= 0 &&
195
- modLines[lastChangedMod] === origLines[lastChangedOrig]) {
196
- lastChangedMod--;
197
- lastChangedOrig--;
198
- }
199
- // When the modified content is a strict prefix of the original (a tail trim on
200
- // a file with no final newline), the loop above never runs and lastChangedMod
201
- // lands one below firstChanged. Clamp so the range is never inverted.
202
- return [firstChanged + 1, Math.max(firstChanged, lastChangedMod) + 1];
203
- }
204
212
  function buildEditFileValue(validPath, meta, modified, result) {
205
213
  return {
206
214
  path: validPath,
@@ -216,10 +224,9 @@ function buildEditFileValue(validPath, meta, modified, result) {
216
224
  : {}),
217
225
  ...(result.unmatchedEdits.length > 0 ? { unmatchedEdits: result.unmatchedEdits } : {}),
218
226
  ...(result.diff ? { diff: result.diff } : {}),
219
- ...(result.lineRange ? { lineRange: result.lineRange } : {}),
220
227
  };
221
228
  }
222
- function finalizeEditResult(originalContent, updatedContent, appliedEdits, unmatchedEdits, lineRange) {
229
+ function finalizeEditResult(originalContent, updatedContent, appliedEdits, unmatchedEdits) {
223
230
  const { linesAdded, linesRemoved } = appliedEdits > 0
224
231
  ? computeDiffStats(originalContent, updatedContent)
225
232
  : { linesAdded: 0, linesRemoved: 0 };
@@ -229,7 +236,6 @@ function finalizeEditResult(originalContent, updatedContent, appliedEdits, unmat
229
236
  unmatchedEdits,
230
237
  linesAdded,
231
238
  linesRemoved,
232
- ...(lineRange ? { lineRange } : {}),
233
239
  };
234
240
  }
235
241
  function buildEditFileMetadata(content, validPath, appliedEdits, resourceStore) {
@@ -247,19 +253,20 @@ function applyEdits(content, edits, ignoreWhitespace) {
247
253
  let newContent = content;
248
254
  let appliedEdits = 0;
249
255
  const unmatchedEdits = [];
250
- for (const edit of edits) {
251
- const match = findEditMatch(newContent, edit.oldText, ignoreWhitespace);
252
- if (!match) {
256
+ for (const [index, edit] of edits.entries()) {
257
+ const found = findEditMatches(newContent, edit.oldText, ignoreWhitespace);
258
+ // A second match is an error rather than a pick: splicing the first would
259
+ // edit a block the caller may not have meant and still report success.
260
+ if (found.count > 1)
261
+ throw ambiguousEditError(newContent, found, index, appliedEdits > 0);
262
+ if (!found.first) {
253
263
  unmatchedEdits.push(edit.oldText);
254
264
  continue;
255
265
  }
256
- newContent = replaceEditMatch(newContent, match, edit.newText);
266
+ newContent = replaceEditMatch(newContent, found.first, edit.newText);
257
267
  appliedEdits += 1;
258
268
  }
259
- // Compute the line range against the final content so earlier edits whose
260
- // lines were shifted by later edits are still covered.
261
- const lineRange = appliedEdits > 0 ? computeChangedLineRange(content, newContent) : undefined;
262
- return finalizeEditResult(content, newContent, appliedEdits, unmatchedEdits, lineRange);
269
+ return finalizeEditResult(content, newContent, appliedEdits, unmatchedEdits);
263
270
  }
264
271
  async function handleEditFile(filePath, edits, options, ctx) {
265
272
  const { validPath, content } = await ctx.fs.readEditableText(filePath, {
@@ -332,7 +339,8 @@ export const EDIT = defineTool({
332
339
  title: 'Edit Files',
333
340
  description: 'Apply sequential literal string replacements to one or more files (max 5 files per call). ' +
334
341
  'Modes: single-file { path, edits } or per-file { files: [{ path, edits }] }. ' +
335
- 'oldText must match file content exactly; include 3-5 lines of surrounding context to ensure uniqueness. ' +
342
+ 'oldText must match file content exactly and only once; include 3-5 lines of surrounding context, ' +
343
+ 'or the edit fails listing the lines it matched. ' +
336
344
  'Set dryRun=true to preview diffs without writing. ' +
337
345
  'For glob-based bulk regex replacement across many files, use replace_text instead.',
338
346
  input: EditFileInputSchema,
@@ -1 +1 @@
1
- {"version":3,"file":"edit.js","sourceRoot":"","sources":["../../src/tools/edit.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ContentBlock } from '@modelcontextprotocol/server';\n\nimport { basename } from 'node:path';\n\nimport * as z from 'zod/v4';\n\nimport { computeDiffStats, unifiedPatch } from '../core/diff.js';\nimport { ErrorCode, FsError } from '../core/errors.js';\nimport { buildWrittenFileMeta, type WrittenFileMeta } from '../core/file-uri.js';\nimport { escapeRegexLiteral } from '../core/primitives.js';\nimport {\n defaultFalseBoolean,\n FileKind,\n isBlank,\n IsoDateTime,\n NonNegInt,\n OperationSummarySchema,\n PerFileErrorSchema,\n PositiveInt,\n RequiredPath,\n singleOrBatchAccessPaths,\n} from '../core/schema.js';\nimport { compileRegex, execMatches, freeRegex } from '../core/search.js';\nimport type { ResourceStore } from '../core/store.js';\nimport { isTotalFailure, runOverPaths } from './batch.js';\nimport { defineTool, type ToolCtx } from './define.js';\n\nconst EditSpecSchema = z\n .strictObject({\n oldText: z\n .string()\n .min(1, 'oldText required')\n .refine((val) => !isBlank(val), {\n message: 'oldText cannot be empty or whitespace-only',\n })\n .describe(\n 'Exact literal text to locate in the file. Must include 3-5 lines of context to ensure uniqueness and avoid matching the wrong block.',\n )\n .meta({ examples: ['const x = 1;', 'function oldName('] }),\n newText: z\n .string()\n .describe('Replacement text. Use an empty string to delete the matched oldText.')\n .meta({ examples: ['const x = 2;', 'function newName(', ''] }),\n })\n // The one document in this server where a `$ref` pays: this subschema is used\n // at both `edits` and `files[].edits`, so an `id` hoists it into `$defs` once\n // instead of inlining ~1.3 kB twice. Shared schemas used once per document\n // deliberately carry no `id` — there a `$ref` costs more than it saves.\n .meta({ id: 'EditSpec' });\n\nconst MAX_MULTI_FILES = 5;\nconst MAX_EDITS_PER_FILE = 100;\n\nconst EditFileInputSchema = z\n .strictObject({\n path: RequiredPath.optional().describe('Single file path; mutually exclusive with files'),\n edits: z\n .array(EditSpecSchema)\n .min(1)\n .max(MAX_EDITS_PER_FILE)\n .optional()\n .describe('Replacements applied to path; not allowed when using files'),\n files: z\n .array(\n z.strictObject({\n path: RequiredPath,\n edits: z\n .array(EditSpecSchema)\n .min(1)\n .max(MAX_EDITS_PER_FILE)\n .describe('Replacements to apply to this specific file'),\n }),\n )\n .min(1)\n .max(MAX_MULTI_FILES)\n .optional()\n .describe('Per-file entries (batch mode)'),\n dryRun: defaultFalseBoolean(\n 'Preview diffs without writing to disk (default: false = apply edits)',\n ),\n ignoreWhitespace: defaultFalseBoolean(\n 'Ignore leading/trailing whitespace differences when matching oldText',\n ),\n })\n .superRefine((value, ctx) => {\n const hasPath = value.path !== undefined;\n const hasFiles = value.files !== undefined;\n if (hasPath === hasFiles) {\n ctx.addIssue({\n code: 'custom',\n path: ['path'],\n message: \"Provide exactly one of 'path' or 'files'\",\n input: value,\n });\n }\n if (hasPath && value.edits === undefined) {\n ctx.addIssue({\n code: 'custom',\n path: ['edits'],\n message: \"'edits' required when using 'path'\",\n input: value,\n });\n }\n if (hasFiles && value.edits !== undefined) {\n ctx.addIssue({\n code: 'custom',\n path: ['edits'],\n message: \"'edits' not allowed with 'files'; each file carries its own edits\",\n input: value,\n });\n }\n })\n // Mirror the superRefine on the wire: exactly one input mode, and single-file\n // mode carries its own `edits`. Without `edits` in the first branch, `{ path }`\n // alone validated against the published schema and was then rejected at\n // runtime — the model had no way to see that coming.\n .meta({ oneOf: [{ required: ['path', 'edits'] }, { required: ['files'] }] });\n\nconst PerFileResultSchema = z.strictObject({\n path: z.string().describe('Resolved absolute path of the edited file'),\n size: NonNegInt.describe('File size in bytes after edits'),\n lineCount: NonNegInt.describe('Number of lines in the file after edits'),\n mimeType: z.string().describe('Detected MIME type of the file'),\n kind: FileKind.describe('Broad file kind: text, binary, image, audio, or pdf'),\n resourceUri: z\n .string()\n .optional()\n .describe(\n 'Resource URI pointing to the updated file content; omitted when no edit matched (appliedEdits is 0) and the file was left untouched',\n ),\n modified: IsoDateTime.describe('Last modification timestamp after edits (ISO 8601 UTC)'),\n appliedEdits: NonNegInt.describe('Number of edits successfully applied'),\n linesAdded: NonNegInt.optional().describe('Net lines added by all applied edits'),\n linesRemoved: NonNegInt.optional().describe('Net lines removed by all applied edits'),\n diff: z.string().optional().describe('Unified diff of all changes (present only in dryRun mode)'),\n unmatchedEdits: z\n .array(z.string())\n .optional()\n .describe('oldText values that did not match any content in the file'),\n lineRange: z\n .tuple([PositiveInt, PositiveInt])\n .optional()\n .describe('Line range [firstLine, lastLine] covering all applied edits'),\n});\n\nconst EditPerPathSchema = z.strictObject({\n path: z.string().describe('Requested file path'),\n value: PerFileResultSchema.optional().describe('Edit result; present on success'),\n error: PerFileErrorSchema.optional().describe('Error details; present on failure'),\n});\n\nconst EditFileOutputSchema = z.strictObject({\n results: z\n .array(EditPerPathSchema)\n .describe('Per-path edit results ordered to match the input paths'),\n summary: OperationSummarySchema,\n});\n\ntype EditFileValue = z.infer<typeof PerFileResultSchema>;\n\ninterface TextRange {\n startIndex: number;\n length: number;\n}\n\ninterface EditResult {\n content: string;\n appliedEdits: number;\n unmatchedEdits: string[];\n linesAdded: number;\n linesRemoved: number;\n diff?: string;\n lineRange?: [number, number];\n}\n\nfunction findEditMatch(\n content: string,\n oldText: string,\n ignoreWhitespace: boolean,\n): TextRange | undefined {\n if (ignoreWhitespace) {\n // Make whitespace flexible (tolerate indentation/spacing differences)\n // without letting it cross line boundaries: a whitespace run that contains\n // a newline keeps at least one newline, so a single-line oldText cannot\n // match across a newline and a multi-line oldText cannot collapse onto one\n // line. Horizontal whitespace stays mandatory between word characters so\n // adjacent identifiers are not merged.\n const pattern = escapeRegexLiteral(oldText)\n .replace(/[^\\S\\n]*\\n\\s*/g, '[^\\\\S\\\\n]*\\\\n+[^\\\\S\\\\n]*')\n .replace(/(\\w)[^\\S\\n]+(\\w)/g, '$1[^\\\\S\\\\n]+$2')\n .replace(/[^\\S\\n]+/g, '[^\\\\S\\\\n]*');\n const regex = compileRegex(pattern, { caseSensitive: true });\n try {\n // execMatches resets lastIndex and reports UTF-16 offsets; the raw RE2\n // index counts code points and would splice off-by-one per emoji.\n const { value: match } = execMatches(regex, content).next();\n // A zero-length match names an empty span, which cannot be replaced.\n if (match === undefined || match.text.length === 0) return undefined;\n\n return {\n startIndex: match.start,\n length: match.text.length,\n };\n } finally {\n // The compiled pattern owns wasm memory re2-wasm never reclaims on its\n // own; its lifetime is this one match.\n freeRegex(regex);\n }\n }\n\n const index = content.indexOf(oldText);\n if (index === -1) {\n return undefined;\n }\n\n return {\n startIndex: index,\n length: oldText.length,\n };\n}\n\nfunction replaceEditMatch(content: string, match: TextRange, newText: string): string {\n return (\n content.slice(0, match.startIndex) + newText + content.slice(match.startIndex + match.length)\n );\n}\n\n/**\n * Compute the 1-indexed line range of changed lines in `modified` relative to\n * `original`, using a common-prefix/suffix line scan. This is a conservative\n * bound (it widens to cover independent changes between matching bookends), but\n * it is computed against the FINAL content so it is not skewed by earlier edits\n * inserting or removing lines — which the per-edit merge could not account for.\n */\nfunction computeChangedLineRange(original: string, modified: string): [number, number] | undefined {\n const origLines = original.split('\\n');\n const modLines = modified.split('\\n');\n const minLen = Math.min(origLines.length, modLines.length);\n\n let firstChanged = -1;\n for (let i = 0; i < minLen; i++) {\n if (origLines[i] !== modLines[i]) {\n firstChanged = i;\n break;\n }\n }\n if (firstChanged === -1 && origLines.length === modLines.length) return undefined;\n if (firstChanged === -1) firstChanged = minLen; // pure append/trim at the tail\n\n let lastChangedMod = modLines.length - 1;\n let lastChangedOrig = origLines.length - 1;\n while (\n lastChangedMod > firstChanged &&\n lastChangedOrig >= 0 &&\n modLines[lastChangedMod] === origLines[lastChangedOrig]\n ) {\n lastChangedMod--;\n lastChangedOrig--;\n }\n\n // When the modified content is a strict prefix of the original (a tail trim on\n // a file with no final newline), the loop above never runs and lastChangedMod\n // lands one below firstChanged. Clamp so the range is never inverted.\n return [firstChanged + 1, Math.max(firstChanged, lastChangedMod) + 1];\n}\n\nfunction buildEditFileValue(\n validPath: string,\n meta: EditFileMetadata,\n modified: string,\n result: EditResult,\n): EditFileValue {\n return {\n path: validPath,\n size: meta.size,\n lineCount: meta.lineCount,\n mimeType: meta.mimeType,\n kind: meta.kind,\n ...(meta.resourceUri !== undefined ? { resourceUri: meta.resourceUri } : {}),\n modified,\n appliedEdits: result.appliedEdits,\n ...(result.appliedEdits > 0\n ? { linesAdded: result.linesAdded, linesRemoved: result.linesRemoved }\n : {}),\n ...(result.unmatchedEdits.length > 0 ? { unmatchedEdits: result.unmatchedEdits } : {}),\n ...(result.diff ? { diff: result.diff } : {}),\n ...(result.lineRange ? { lineRange: result.lineRange } : {}),\n };\n}\n\nfunction finalizeEditResult(\n originalContent: string,\n updatedContent: string,\n appliedEdits: number,\n unmatchedEdits: string[],\n lineRange: EditResult['lineRange'],\n): EditResult {\n const { linesAdded, linesRemoved } =\n appliedEdits > 0\n ? computeDiffStats(originalContent, updatedContent)\n : { linesAdded: 0, linesRemoved: 0 };\n\n return {\n content: updatedContent,\n appliedEdits,\n unmatchedEdits,\n linesAdded,\n linesRemoved,\n ...(lineRange ? { lineRange } : {}),\n };\n}\n\n/** {@link WrittenFileMeta}, with `resourceUri` widened: an edit that matched\n * nothing has no updated content to point at. */\ntype EditFileMetadata = Omit<WrittenFileMeta, 'resourceUri'> & {\n resourceUri: string | undefined;\n};\n\nfunction buildEditFileMetadata(\n content: string,\n validPath: string,\n appliedEdits: number,\n resourceStore: ResourceStore | undefined,\n): EditFileMetadata {\n const meta = buildWrittenFileMeta(validPath, content, resourceStore);\n // Omitted rather than empty-stringed when nothing matched: `\"\"` satisfied the\n // schema's `string` and then failed every resources/read a client tried it on.\n const written = appliedEdits > 0;\n return {\n ...meta,\n resourceUri: written ? meta.resourceUri : undefined,\n resourceLink: written ? meta.resourceLink : undefined,\n };\n}\n\nfunction applyEdits(\n content: string,\n edits: z.infer<typeof EditSpecSchema>[],\n ignoreWhitespace: boolean,\n): EditResult {\n let newContent = content;\n let appliedEdits = 0;\n const unmatchedEdits: string[] = [];\n\n for (const edit of edits) {\n const match = findEditMatch(newContent, edit.oldText, ignoreWhitespace);\n\n if (!match) {\n unmatchedEdits.push(edit.oldText);\n continue;\n }\n\n newContent = replaceEditMatch(newContent, match, edit.newText);\n appliedEdits += 1;\n }\n\n // Compute the line range against the final content so earlier edits whose\n // lines were shifted by later edits are still covered.\n const lineRange = appliedEdits > 0 ? computeChangedLineRange(content, newContent) : undefined;\n\n return finalizeEditResult(content, newContent, appliedEdits, unmatchedEdits, lineRange);\n}\n\ninterface EditFileOptions {\n dryRun: boolean;\n ignoreWhitespace: boolean;\n}\n\nasync function handleEditFile(\n filePath: string,\n edits: z.infer<typeof EditSpecSchema>[],\n options: EditFileOptions,\n ctx: ToolCtx,\n): Promise<{ file: EditFileValue; resourceLink?: ContentBlock }> {\n const { validPath, content } = await ctx.fs.readEditableText(filePath, {\n signal: ctx.signal,\n });\n const editResult = applyEdits(content, edits, options.ignoreWhitespace);\n\n if (options.dryRun) {\n if (editResult.appliedEdits > 0) {\n editResult.diff = unifiedPatch(basename(validPath), content, editResult.content);\n }\n\n // Nothing was written, so there is no updated content to point a\n // resourceUri or a resource_link at — the file on disk is still the one the\n // caller already has. Same rule the appliedEdits-is-0 case follows: no\n // write, no link.\n const meta = buildEditFileMetadata(editResult.content, validPath, 0, ctx.resourceStore);\n return {\n file: buildEditFileValue(validPath, meta, new Date().toISOString(), editResult),\n ...(meta.resourceLink ? { resourceLink: meta.resourceLink } : {}),\n };\n }\n\n if (editResult.unmatchedEdits.length > 0) {\n throw new FsError(\n ErrorCode.INVALID_INPUT,\n `${editResult.unmatchedEdits.length} edit(s) failed to match. Verify oldText matches exact file content.`,\n filePath,\n );\n }\n\n if (editResult.appliedEdits > 0) {\n await ctx.fs.writeFile(filePath, editResult.content, {\n encoding: 'utf-8',\n signal: ctx.signal,\n });\n ctx.log?.(\n 'info',\n `edit: ${filePath} (${editResult.appliedEdits} edits, +${editResult.linesAdded}/-${editResult.linesRemoved})`,\n 'edit',\n );\n }\n\n // `modified` is read from a post-write stat and is advisory: under a concurrent\n // writer it may reflect that writer's mtime while `size`/content below come from\n // this edit's atomic write. The file content itself is always consistent.\n const { stats: fileStats } = await ctx.fs.stat(filePath, { signal: ctx.signal });\n const meta = buildEditFileMetadata(\n editResult.content,\n validPath,\n editResult.appliedEdits,\n ctx.resourceStore,\n );\n return {\n file: buildEditFileValue(validPath, meta, fileStats.mtime.toISOString(), editResult),\n ...(meta.resourceLink ? { resourceLink: meta.resourceLink } : {}),\n };\n}\n\nfunction formatEditSummary(\n results: readonly z.infer<typeof EditPerPathSchema>[],\n dryRun: boolean,\n): string {\n const tag = dryRun ? ' [dry run]' : '';\n // Single-file failure: say why here rather than making the caller read\n // structuredContent for the one message that can apply.\n const [only] = results;\n if (results.length === 1 && only?.error) {\n return `edit: ${only.path} FAILED — ${only.error.message}${tag}`;\n }\n const tokens = results.map((r) => {\n if (r.error) return `${basename(r.path)} FAILED`;\n const v = r.value;\n if (!v) return `${basename(r.path)} (no result)`;\n if (v.unmatchedEdits && v.unmatchedEdits.length > 0) return `${basename(v.path)} NO MATCH`;\n const added = v.linesAdded ?? 0;\n const removed = v.linesRemoved ?? 0;\n if (added === 0 && removed === 0) return `${basename(v.path)} (no change)`;\n return `${basename(v.path)} +${String(added)} -${String(removed)}`;\n });\n\n const failed = results.filter((r) => r.error !== undefined).length;\n const ok = results.length - failed;\n const ratio = failed > 0 ? ` (${String(ok)}/${String(results.length)} ok)` : '';\n return `edit: ${tokens.join(' · ')}${ratio}${tag}`;\n}\n\nexport const EDIT = defineTool({\n name: 'edit',\n title: 'Edit Files',\n description:\n 'Apply sequential literal string replacements to one or more files (max 5 files per call). ' +\n 'Modes: single-file { path, edits } or per-file { files: [{ path, edits }] }. ' +\n 'oldText must match file content exactly; include 3-5 lines of surrounding context to ensure uniqueness. ' +\n 'Set dryRun=true to preview diffs without writing. ' +\n 'For glob-based bulk regex replacement across many files, use replace_text instead.',\n input: EditFileInputSchema,\n output: EditFileOutputSchema,\n annotations: {\n readOnlyHint: false,\n idempotentHint: false,\n destructiveHint: true,\n openWorldHint: false,\n },\n progress: (args) => {\n const dryLabel = args.dryRun ? ' [dry run]' : '';\n let subject: string;\n if (args.path !== undefined) {\n subject = basename(args.path);\n } else if (args.files !== undefined) {\n subject = `${args.files.length} files`;\n } else {\n subject = 'files';\n }\n return { label: `Edit${dryLabel}`, subject };\n },\n accessPaths: singleOrBatchAccessPaths,\n run: async (args, ctx) => {\n const sharedEdits = args.edits ?? [];\n const batchInput = args.path !== undefined ? { path: args.path } : { files: args.files ?? [] };\n\n const options: EditFileOptions = {\n dryRun: args.dryRun,\n ignoreWhitespace: args.ignoreWhitespace,\n };\n\n const batch = await runOverPaths<\n { edits: z.infer<typeof EditSpecSchema>[] },\n { file: EditFileValue; resourceLink?: ContentBlock }\n >(\n batchInput,\n ctx,\n ({ path, override }) => handleEditFile(path, override?.edits ?? sharedEdits, options, ctx),\n { defaultErrorCode: ErrorCode.UNKNOWN },\n );\n\n const perPathResults: z.infer<typeof EditPerPathSchema>[] = [];\n const resourceLinks: ContentBlock[] = [];\n for (const r of batch.results) {\n if ('error' in r) {\n perPathResults.push({ path: r.path, error: r.error });\n continue;\n }\n perPathResults.push({ path: r.path, value: r.value.file });\n if (r.value.resourceLink) resourceLinks.push(r.value.resourceLink);\n }\n\n const summaryText = formatEditSummary(perPathResults, args.dryRun);\n\n return {\n structured: {\n results: perPathResults,\n summary: batch.summary,\n },\n text: summaryText,\n isError: isTotalFailure(batch.summary),\n ...(resourceLinks.length > 0 ? { resources: resourceLinks } : {}),\n };\n },\n});\n"]}
1
+ {"version":3,"file":"edit.js","sourceRoot":"","sources":["../../src/tools/edit.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ContentBlock } from '@modelcontextprotocol/server';\n\nimport { basename } from 'node:path';\n\nimport * as z from 'zod/v4';\n\nimport { computeDiffStats, unifiedPatch } from '../core/diff.js';\nimport { ErrorCode, FsError } from '../core/errors.js';\nimport { buildWrittenFileMeta, type WrittenFileMeta } from '../core/file-uri.js';\nimport { escapeRegexLiteral } from '../core/primitives.js';\nimport {\n defaultFalseBoolean,\n FileKind,\n isBlank,\n IsoDateTime,\n NonNegInt,\n OperationSummarySchema,\n PerFileErrorSchema,\n RequiredPath,\n singleOrBatchAccessPaths,\n} from '../core/schema.js';\nimport { compileRegex, execMatches, freeRegex } from '../core/search.js';\nimport type { ResourceStore } from '../core/store.js';\nimport { isTotalFailure, runOverPaths } from './batch.js';\nimport { defineTool, type ToolCtx } from './define.js';\n\nconst EditSpecSchema = z\n .strictObject({\n oldText: z\n .string()\n .min(1, 'oldText required')\n .refine((val) => !isBlank(val), {\n message: 'oldText cannot be empty or whitespace-only',\n })\n .describe(\n 'Exact literal text to locate in the file; it must match exactly once. Include 3-5 lines of context so it does — an oldText found in several places fails with their line numbers.',\n )\n .meta({ examples: ['const x = 1;', 'function oldName('] }),\n newText: z\n .string()\n .describe('Replacement text. Use an empty string to delete the matched oldText.')\n .meta({ examples: ['const x = 2;', 'function newName(', ''] }),\n })\n // The one document in this server where a `$ref` pays: this subschema is used\n // at both `edits` and `files[].edits`, so an `id` hoists it into `$defs` once\n // instead of inlining ~1.3 kB twice. Shared schemas used once per document\n // deliberately carry no `id` — there a `$ref` costs more than it saves.\n .meta({ id: 'EditSpec' });\n\nconst MAX_MULTI_FILES = 5;\nconst MAX_EDITS_PER_FILE = 100;\n\nconst EditFileInputSchema = z\n .strictObject({\n path: RequiredPath.optional().describe('Single file path; mutually exclusive with files'),\n edits: z\n .array(EditSpecSchema)\n .min(1)\n .max(MAX_EDITS_PER_FILE)\n .optional()\n .describe('Replacements applied to path; not allowed when using files'),\n files: z\n .array(\n z.strictObject({\n path: RequiredPath,\n edits: z\n .array(EditSpecSchema)\n .min(1)\n .max(MAX_EDITS_PER_FILE)\n .describe('Replacements to apply to this specific file'),\n }),\n )\n .min(1)\n .max(MAX_MULTI_FILES)\n .optional()\n .describe('Per-file entries (batch mode)'),\n dryRun: defaultFalseBoolean(\n 'Preview diffs without writing to disk (default: false = apply edits)',\n ),\n ignoreWhitespace: defaultFalseBoolean(\n 'Ignore leading/trailing whitespace differences when matching oldText',\n ),\n })\n .superRefine((value, ctx) => {\n const hasPath = value.path !== undefined;\n const hasFiles = value.files !== undefined;\n if (hasPath === hasFiles) {\n ctx.addIssue({\n code: 'custom',\n path: ['path'],\n message: \"Provide exactly one of 'path' or 'files'\",\n input: value,\n });\n }\n if (hasPath && value.edits === undefined) {\n ctx.addIssue({\n code: 'custom',\n path: ['edits'],\n message: \"'edits' required when using 'path'\",\n input: value,\n });\n }\n if (hasFiles && value.edits !== undefined) {\n ctx.addIssue({\n code: 'custom',\n path: ['edits'],\n message: \"'edits' not allowed with 'files'; each file carries its own edits\",\n input: value,\n });\n }\n })\n // Mirror the superRefine on the wire: exactly one input mode, and single-file\n // mode carries its own `edits`. Without `edits` in the first branch, `{ path }`\n // alone validated against the published schema and was then rejected at\n // runtime — the model had no way to see that coming.\n .meta({ oneOf: [{ required: ['path', 'edits'] }, { required: ['files'] }] });\n\nconst PerFileResultSchema = z.strictObject({\n path: z.string().describe('Resolved absolute path of the edited file'),\n size: NonNegInt.describe('File size in bytes after edits'),\n lineCount: NonNegInt.describe('Number of lines in the file after edits'),\n mimeType: z.string().describe('Detected MIME type of the file'),\n kind: FileKind.describe('Broad file kind: text, binary, image, audio, or pdf'),\n resourceUri: z\n .string()\n .optional()\n .describe(\n 'Resource URI pointing to the updated file content; omitted when no edit matched (appliedEdits is 0) and the file was left untouched',\n ),\n modified: IsoDateTime.describe('Last modification timestamp after edits (ISO 8601 UTC)'),\n appliedEdits: NonNegInt.describe('Number of edits successfully applied'),\n linesAdded: NonNegInt.optional().describe('Net lines added by all applied edits'),\n linesRemoved: NonNegInt.optional().describe('Net lines removed by all applied edits'),\n diff: z.string().optional().describe('Unified diff of all changes (present only in dryRun mode)'),\n unmatchedEdits: z\n .array(z.string())\n .optional()\n .describe('oldText values that did not match any content in the file'),\n});\n\nconst EditPerPathSchema = z.strictObject({\n path: z.string().describe('Requested file path'),\n value: PerFileResultSchema.optional().describe('Edit result; present on success'),\n error: PerFileErrorSchema.optional().describe('Error details; present on failure'),\n});\n\nconst EditFileOutputSchema = z.strictObject({\n results: z\n .array(EditPerPathSchema)\n .describe('Per-path edit results ordered to match the input paths'),\n summary: OperationSummarySchema,\n});\n\ntype EditFileValue = z.infer<typeof PerFileResultSchema>;\n\ninterface TextRange {\n startIndex: number;\n length: number;\n}\n\ninterface EditResult {\n content: string;\n appliedEdits: number;\n unmatchedEdits: string[];\n linesAdded: number;\n linesRemoved: number;\n diff?: string;\n}\n\nconst MAX_REPORTED_MATCH_LINES = 5;\n\ninterface EditMatches {\n /** The first match; undefined when oldText matches nothing. */\n first: TextRange | undefined;\n count: number;\n /** UTF-16 start offsets of the first {@link MAX_REPORTED_MATCH_LINES} matches. */\n starts: number[];\n}\n\n/**\n * Where `oldText` matches. `count` is non-overlapping occurrences, except that a\n * lone match with a second one overlapping it counts two (`abab` in `ababab`),\n * since either is a span the caller could have meant — the count is exact only\n * when it answers \"once or not\". Only the count and the first few starts are\n * kept: a short oldText in a large file can match millions of times.\n */\nfunction findEditMatches(content: string, oldText: string, ignoreWhitespace: boolean): EditMatches {\n const found: EditMatches = { first: undefined, count: 0, starts: [] };\n const add = (startIndex: number, length: number): void => {\n found.first ??= { startIndex, length };\n found.count += 1;\n if (found.starts.length < MAX_REPORTED_MATCH_LINES) found.starts.push(startIndex);\n };\n\n if (ignoreWhitespace) {\n // Make whitespace flexible (tolerate indentation/spacing differences)\n // without letting it cross line boundaries: a whitespace run that contains\n // a newline keeps at least one newline, so a single-line oldText cannot\n // match across a newline and a multi-line oldText cannot collapse onto one\n // line. Horizontal whitespace stays mandatory between word characters so\n // adjacent identifiers are not merged.\n const pattern = escapeRegexLiteral(oldText)\n .replace(/[^\\S\\n]*\\n\\s*/g, '[^\\\\S\\\\n]*\\\\n+[^\\\\S\\\\n]*')\n .replace(/(\\w)[^\\S\\n]+(\\w)/g, '$1[^\\\\S\\\\n]+$2')\n .replace(/[^\\S\\n]+/g, '[^\\\\S\\\\n]*');\n const regex = compileRegex(pattern, { caseSensitive: true });\n try {\n // execMatches resets lastIndex and reports UTF-16 offsets; the raw RE2\n // index counts code points and would splice off-by-one per emoji.\n const scan = (from: number): void => {\n for (const match of execMatches(regex, from === 0 ? content : content.slice(from))) {\n // A zero-length match names an empty span, which cannot be replaced.\n if (match.text.length > 0) add(from + match.start, match.text.length);\n if (from > 0) return;\n }\n };\n scan(0);\n // execMatches resumes past each match, so a second match overlapping the\n // first is never reported; look once more from just past its first\n // non-whitespace character. Starting inside the leading whitespace would\n // re-find the same occurrence, since the pattern's leading run is `*`. The\n // pattern carries no anchors, so matching a suffix finds the same spans.\n if (found.count === 1 && found.first) {\n const { startIndex, length } = found.first;\n const lead = content.slice(startIndex, startIndex + length).search(/\\S/u);\n scan(afterCodePoint(content, startIndex + lead));\n }\n } finally {\n // The compiled pattern owns wasm memory re2-wasm never reclaims on its\n // own; its lifetime is this one search.\n freeRegex(regex);\n }\n return found;\n }\n\n // Non-overlapping, so the scan stays linear on repetitive content; the one\n // overlap that matters — a second match inside the only one — is checked after.\n for (\n let i = content.indexOf(oldText);\n i !== -1;\n i = content.indexOf(oldText, i + oldText.length)\n ) {\n add(i, oldText.length);\n }\n if (found.count === 1 && found.first) {\n const overlap = content.indexOf(oldText, afterCodePoint(content, found.first.startIndex));\n if (overlap !== -1) add(overlap, oldText.length);\n }\n return found;\n}\n\n/** The UTF-16 offset just past the code point at `index`, so a surrogate pair is never split. */\nfunction afterCodePoint(content: string, index: number): number {\n return index + ((content.codePointAt(index) ?? 0) > 0xffff ? 2 : 1);\n}\n\nfunction ambiguousEditError(\n content: string,\n found: EditMatches,\n editIndex: number,\n shifted: boolean,\n): FsError {\n const lines = [\n ...new Set(found.starts.map((start) => content.slice(0, start).split('\\n').length)),\n ];\n const label = lines.length === 1 ? 'line' : 'lines';\n const more = found.count > found.starts.length ? ', ...' : '';\n // Offsets come from the content as earlier edits in this call left it, which\n // is not the file the caller read once one of them has applied.\n const where = shifted ? ' after earlier edits' : '';\n return new FsError(\n ErrorCode.INVALID_INPUT,\n `edits[${String(editIndex)}]: oldText matches ${String(found.count)} places${where} ` +\n `(${label} ${lines.join(', ')}${more}). Add surrounding lines so it matches once.`,\n );\n}\n\nfunction replaceEditMatch(content: string, match: TextRange, newText: string): string {\n return (\n content.slice(0, match.startIndex) + newText + content.slice(match.startIndex + match.length)\n );\n}\n\nfunction buildEditFileValue(\n validPath: string,\n meta: EditFileMetadata,\n modified: string,\n result: EditResult,\n): EditFileValue {\n return {\n path: validPath,\n size: meta.size,\n lineCount: meta.lineCount,\n mimeType: meta.mimeType,\n kind: meta.kind,\n ...(meta.resourceUri !== undefined ? { resourceUri: meta.resourceUri } : {}),\n modified,\n appliedEdits: result.appliedEdits,\n ...(result.appliedEdits > 0\n ? { linesAdded: result.linesAdded, linesRemoved: result.linesRemoved }\n : {}),\n ...(result.unmatchedEdits.length > 0 ? { unmatchedEdits: result.unmatchedEdits } : {}),\n ...(result.diff ? { diff: result.diff } : {}),\n };\n}\n\nfunction finalizeEditResult(\n originalContent: string,\n updatedContent: string,\n appliedEdits: number,\n unmatchedEdits: string[],\n): EditResult {\n const { linesAdded, linesRemoved } =\n appliedEdits > 0\n ? computeDiffStats(originalContent, updatedContent)\n : { linesAdded: 0, linesRemoved: 0 };\n\n return {\n content: updatedContent,\n appliedEdits,\n unmatchedEdits,\n linesAdded,\n linesRemoved,\n };\n}\n\n/** {@link WrittenFileMeta}, with `resourceUri` widened: an edit that matched\n * nothing has no updated content to point at. */\ntype EditFileMetadata = Omit<WrittenFileMeta, 'resourceUri'> & {\n resourceUri: string | undefined;\n};\n\nfunction buildEditFileMetadata(\n content: string,\n validPath: string,\n appliedEdits: number,\n resourceStore: ResourceStore | undefined,\n): EditFileMetadata {\n const meta = buildWrittenFileMeta(validPath, content, resourceStore);\n // Omitted rather than empty-stringed when nothing matched: `\"\"` satisfied the\n // schema's `string` and then failed every resources/read a client tried it on.\n const written = appliedEdits > 0;\n return {\n ...meta,\n resourceUri: written ? meta.resourceUri : undefined,\n resourceLink: written ? meta.resourceLink : undefined,\n };\n}\n\nfunction applyEdits(\n content: string,\n edits: z.infer<typeof EditSpecSchema>[],\n ignoreWhitespace: boolean,\n): EditResult {\n let newContent = content;\n let appliedEdits = 0;\n const unmatchedEdits: string[] = [];\n\n for (const [index, edit] of edits.entries()) {\n const found = findEditMatches(newContent, edit.oldText, ignoreWhitespace);\n\n // A second match is an error rather than a pick: splicing the first would\n // edit a block the caller may not have meant and still report success.\n if (found.count > 1) throw ambiguousEditError(newContent, found, index, appliedEdits > 0);\n\n if (!found.first) {\n unmatchedEdits.push(edit.oldText);\n continue;\n }\n\n newContent = replaceEditMatch(newContent, found.first, edit.newText);\n appliedEdits += 1;\n }\n\n return finalizeEditResult(content, newContent, appliedEdits, unmatchedEdits);\n}\n\ninterface EditFileOptions {\n dryRun: boolean;\n ignoreWhitespace: boolean;\n}\n\nasync function handleEditFile(\n filePath: string,\n edits: z.infer<typeof EditSpecSchema>[],\n options: EditFileOptions,\n ctx: ToolCtx,\n): Promise<{ file: EditFileValue; resourceLink?: ContentBlock }> {\n const { validPath, content } = await ctx.fs.readEditableText(filePath, {\n signal: ctx.signal,\n });\n const editResult = applyEdits(content, edits, options.ignoreWhitespace);\n\n if (options.dryRun) {\n if (editResult.appliedEdits > 0) {\n editResult.diff = unifiedPatch(basename(validPath), content, editResult.content);\n }\n\n // Nothing was written, so there is no updated content to point a\n // resourceUri or a resource_link at — the file on disk is still the one the\n // caller already has. Same rule the appliedEdits-is-0 case follows: no\n // write, no link.\n const meta = buildEditFileMetadata(editResult.content, validPath, 0, ctx.resourceStore);\n return {\n file: buildEditFileValue(validPath, meta, new Date().toISOString(), editResult),\n ...(meta.resourceLink ? { resourceLink: meta.resourceLink } : {}),\n };\n }\n\n if (editResult.unmatchedEdits.length > 0) {\n throw new FsError(\n ErrorCode.INVALID_INPUT,\n `${editResult.unmatchedEdits.length} edit(s) failed to match. Verify oldText matches exact file content.`,\n filePath,\n );\n }\n\n if (editResult.appliedEdits > 0) {\n await ctx.fs.writeFile(filePath, editResult.content, {\n encoding: 'utf-8',\n signal: ctx.signal,\n });\n ctx.log?.(\n 'info',\n `edit: ${filePath} (${editResult.appliedEdits} edits, +${editResult.linesAdded}/-${editResult.linesRemoved})`,\n 'edit',\n );\n }\n\n // `modified` is read from a post-write stat and is advisory: under a concurrent\n // writer it may reflect that writer's mtime while `size`/content below come from\n // this edit's atomic write. The file content itself is always consistent.\n const { stats: fileStats } = await ctx.fs.stat(filePath, { signal: ctx.signal });\n const meta = buildEditFileMetadata(\n editResult.content,\n validPath,\n editResult.appliedEdits,\n ctx.resourceStore,\n );\n return {\n file: buildEditFileValue(validPath, meta, fileStats.mtime.toISOString(), editResult),\n ...(meta.resourceLink ? { resourceLink: meta.resourceLink } : {}),\n };\n}\n\nfunction formatEditSummary(\n results: readonly z.infer<typeof EditPerPathSchema>[],\n dryRun: boolean,\n): string {\n const tag = dryRun ? ' [dry run]' : '';\n // Single-file failure: say why here rather than making the caller read\n // structuredContent for the one message that can apply.\n const [only] = results;\n if (results.length === 1 && only?.error) {\n return `edit: ${only.path} FAILED — ${only.error.message}${tag}`;\n }\n const tokens = results.map((r) => {\n if (r.error) return `${basename(r.path)} FAILED`;\n const v = r.value;\n if (!v) return `${basename(r.path)} (no result)`;\n if (v.unmatchedEdits && v.unmatchedEdits.length > 0) return `${basename(v.path)} NO MATCH`;\n const added = v.linesAdded ?? 0;\n const removed = v.linesRemoved ?? 0;\n if (added === 0 && removed === 0) return `${basename(v.path)} (no change)`;\n return `${basename(v.path)} +${String(added)} -${String(removed)}`;\n });\n\n const failed = results.filter((r) => r.error !== undefined).length;\n const ok = results.length - failed;\n const ratio = failed > 0 ? ` (${String(ok)}/${String(results.length)} ok)` : '';\n return `edit: ${tokens.join(' · ')}${ratio}${tag}`;\n}\n\nexport const EDIT = defineTool({\n name: 'edit',\n title: 'Edit Files',\n description:\n 'Apply sequential literal string replacements to one or more files (max 5 files per call). ' +\n 'Modes: single-file { path, edits } or per-file { files: [{ path, edits }] }. ' +\n 'oldText must match file content exactly and only once; include 3-5 lines of surrounding context, ' +\n 'or the edit fails listing the lines it matched. ' +\n 'Set dryRun=true to preview diffs without writing. ' +\n 'For glob-based bulk regex replacement across many files, use replace_text instead.',\n input: EditFileInputSchema,\n output: EditFileOutputSchema,\n annotations: {\n readOnlyHint: false,\n idempotentHint: false,\n destructiveHint: true,\n openWorldHint: false,\n },\n progress: (args) => {\n const dryLabel = args.dryRun ? ' [dry run]' : '';\n let subject: string;\n if (args.path !== undefined) {\n subject = basename(args.path);\n } else if (args.files !== undefined) {\n subject = `${args.files.length} files`;\n } else {\n subject = 'files';\n }\n return { label: `Edit${dryLabel}`, subject };\n },\n accessPaths: singleOrBatchAccessPaths,\n run: async (args, ctx) => {\n const sharedEdits = args.edits ?? [];\n const batchInput = args.path !== undefined ? { path: args.path } : { files: args.files ?? [] };\n\n const options: EditFileOptions = {\n dryRun: args.dryRun,\n ignoreWhitespace: args.ignoreWhitespace,\n };\n\n const batch = await runOverPaths<\n { edits: z.infer<typeof EditSpecSchema>[] },\n { file: EditFileValue; resourceLink?: ContentBlock }\n >(\n batchInput,\n ctx,\n ({ path, override }) => handleEditFile(path, override?.edits ?? sharedEdits, options, ctx),\n { defaultErrorCode: ErrorCode.UNKNOWN },\n );\n\n const perPathResults: z.infer<typeof EditPerPathSchema>[] = [];\n const resourceLinks: ContentBlock[] = [];\n for (const r of batch.results) {\n if ('error' in r) {\n perPathResults.push({ path: r.path, error: r.error });\n continue;\n }\n perPathResults.push({ path: r.path, value: r.value.file });\n if (r.value.resourceLink) resourceLinks.push(r.value.resourceLink);\n }\n\n const summaryText = formatEditSummary(perPathResults, args.dryRun);\n\n return {\n structured: {\n results: perPathResults,\n summary: batch.summary,\n },\n text: summaryText,\n isError: isTotalFailure(batch.summary),\n ...(resourceLinks.length > 0 ? { resources: resourceLinks } : {}),\n };\n },\n});\n"]}
@@ -20,6 +20,7 @@ interface ToolRegistrarDeps {
20
20
  readonly pageStore: PageSnapshotStore;
21
21
  readonly resourceStore: ResourceStore;
22
22
  readonly readOnly?: boolean;
23
+ readonly era?: 'legacy' | 'modern';
23
24
  }
24
25
  export declare function registerTools(deps: ToolRegistrarDeps): void;
25
26
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAE9D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAI/C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,eAAO,MAAM,SAAS,oLAcZ,CAAC;AAEX,eAAO,MAAM,mBAAmB,aAE/B,CAAC;AAEF,8FAA8F;AAC9F,wBAAgB,eAAe,CAAC,QAAQ,EAAE,OAAO,GAAG,SAAS,WAAW,EAAE,CAEzE;AAOD,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;AAEjE,UAAU,iBAAiB;IACzB,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAC;IACtC,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC;IACtC,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,iBAAiB,GAAG,IAAI,CAU3D"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAE9D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAI/C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,eAAO,MAAM,SAAS,oLAcZ,CAAC;AAEX,eAAO,MAAM,mBAAmB,aAE/B,CAAC;AAEF,8FAA8F;AAC9F,wBAAgB,eAAe,CAAC,QAAQ,EAAE,OAAO,GAAG,SAAS,WAAW,EAAE,CAEzE;AAOD,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;AAEjE,UAAU,iBAAiB;IACzB,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAC;IACtC,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC;IACtC,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,GAAG,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;CACpC;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,iBAAiB,GAAG,IAAI,CAW3D"}
@@ -43,6 +43,7 @@ export function registerTools(deps) {
43
43
  pathGuard: deps.pathGuard,
44
44
  pageStore: deps.pageStore,
45
45
  resourceStore: deps.resourceStore,
46
+ ...(deps.era ? { era: deps.era } : {}),
46
47
  };
47
48
  for (const tool of registeredTools(deps.readOnly ?? false)) {
48
49
  tool.register(toolDeps);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,MAAM;IACN,MAAM;IACN,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,KAAK;IACL,IAAI;IACJ,YAAY;IACZ,UAAU;IACV,WAAW;IACX,UAAU;IACV,IAAI;CACI,CAAC;AAEX,MAAM,CAAC,MAAM,mBAAmB,GAAG,IAAI,GAAG,CACxC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CACxE,CAAC;AAEF,8FAA8F;AAC9F,MAAM,UAAU,eAAe,CAAC,QAAiB;IAC/C,OAAO,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAC1F,CAAC;AAED,gFAAgF;AAChF,6EAA6E;AAC7E,2EAA2E;AAC3E,uEAAuE;AACvE,6CAA6C;AAC7C,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;AAUjE,MAAM,UAAU,aAAa,CAAC,IAAuB;IACnD,MAAM,QAAQ,GAAG;QACf,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,aAAa,EAAE,IAAI,CAAC,aAAa;KAClC,CAAC;IACF,KAAK,MAAM,IAAI,IAAI,eAAe,CAAC,IAAI,CAAC,QAAQ,IAAI,KAAK,CAAC,EAAE,CAAC;QAC3D,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC1B,CAAC;AACH,CAAC","sourcesContent":["import type { McpServer } from '@modelcontextprotocol/server';\n\nimport type { PageSnapshotStore } from '../core/page-store.js';\nimport type { PathGuard } from '../core/path.js';\nimport type { ResourceStore } from '../core/store.js';\nimport { CREATE } from './create.js';\nimport type { DefinedTool } from './define.js';\nimport { DELETE } from './delete.js';\nimport { DIFF } from './diff.js';\nimport { EDIT } from './edit.js';\nimport { FIND_FILES } from './find-files.js';\nimport { LIST_ROOTS } from './list-roots.js';\nimport { LIST } from './list.js';\nimport { MOVE } from './move.js';\nimport { PATCH } from './patch.js';\nimport { READ } from './read.js';\nimport { REPLACE_TEXT } from './replace-text.js';\nimport { SEARCH_TEXT } from './search-text.js';\nimport { STAT } from './stat.js';\n\nexport const ALL_TOOLS = [\n CREATE,\n DELETE,\n DIFF,\n EDIT,\n LIST,\n MOVE,\n PATCH,\n READ,\n REPLACE_TEXT,\n LIST_ROOTS,\n SEARCH_TEXT,\n FIND_FILES,\n STAT,\n] as const;\n\nexport const MUTATING_TOOL_NAMES = new Set(\n ALL_TOOLS.filter((t) => !t.annotations.readOnlyHint).map((t) => t.name),\n);\n\n/** The tools a server registers at this setting — the one owner of the `--read-only` gate. */\nexport function registeredTools(readOnly: boolean): readonly DefinedTool[] {\n return readOnly ? ALL_TOOLS.filter((t) => !MUTATING_TOOL_NAMES.has(t.name)) : ALL_TOOLS;\n}\n\n// Re-exported so documentation surfaces quote `.name` off the definition rather\n// than repeating the string. This module is the only owner of the inventory.\n// Only the read-only tools are named individually: the mutating six are no\n// longer listed by hand anywhere, so their names reach callers through\n// MUTATING_TOOL_NAMES and ALL_TOOLS instead.\nexport { LIST, LIST_ROOTS, READ, SEARCH_TEXT, FIND_FILES, STAT };\n\ninterface ToolRegistrarDeps {\n readonly server: McpServer;\n readonly pathGuard: PathGuard;\n readonly pageStore: PageSnapshotStore;\n readonly resourceStore: ResourceStore;\n readonly readOnly?: boolean;\n}\n\nexport function registerTools(deps: ToolRegistrarDeps): void {\n const toolDeps = {\n server: deps.server,\n pathGuard: deps.pathGuard,\n pageStore: deps.pageStore,\n resourceStore: deps.resourceStore,\n };\n for (const tool of registeredTools(deps.readOnly ?? false)) {\n tool.register(toolDeps);\n }\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,MAAM;IACN,MAAM;IACN,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,KAAK;IACL,IAAI;IACJ,YAAY;IACZ,UAAU;IACV,WAAW;IACX,UAAU;IACV,IAAI;CACI,CAAC;AAEX,MAAM,CAAC,MAAM,mBAAmB,GAAG,IAAI,GAAG,CACxC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CACxE,CAAC;AAEF,8FAA8F;AAC9F,MAAM,UAAU,eAAe,CAAC,QAAiB;IAC/C,OAAO,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAC1F,CAAC;AAED,gFAAgF;AAChF,6EAA6E;AAC7E,2EAA2E;AAC3E,uEAAuE;AACvE,6CAA6C;AAC7C,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;AAWjE,MAAM,UAAU,aAAa,CAAC,IAAuB;IACnD,MAAM,QAAQ,GAAG;QACf,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,aAAa,EAAE,IAAI,CAAC,aAAa;QACjC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACvC,CAAC;IACF,KAAK,MAAM,IAAI,IAAI,eAAe,CAAC,IAAI,CAAC,QAAQ,IAAI,KAAK,CAAC,EAAE,CAAC;QAC3D,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC1B,CAAC;AACH,CAAC","sourcesContent":["import type { McpServer } from '@modelcontextprotocol/server';\n\nimport type { PageSnapshotStore } from '../core/page-store.js';\nimport type { PathGuard } from '../core/path.js';\nimport type { ResourceStore } from '../core/store.js';\nimport { CREATE } from './create.js';\nimport type { DefinedTool } from './define.js';\nimport { DELETE } from './delete.js';\nimport { DIFF } from './diff.js';\nimport { EDIT } from './edit.js';\nimport { FIND_FILES } from './find-files.js';\nimport { LIST_ROOTS } from './list-roots.js';\nimport { LIST } from './list.js';\nimport { MOVE } from './move.js';\nimport { PATCH } from './patch.js';\nimport { READ } from './read.js';\nimport { REPLACE_TEXT } from './replace-text.js';\nimport { SEARCH_TEXT } from './search-text.js';\nimport { STAT } from './stat.js';\n\nexport const ALL_TOOLS = [\n CREATE,\n DELETE,\n DIFF,\n EDIT,\n LIST,\n MOVE,\n PATCH,\n READ,\n REPLACE_TEXT,\n LIST_ROOTS,\n SEARCH_TEXT,\n FIND_FILES,\n STAT,\n] as const;\n\nexport const MUTATING_TOOL_NAMES = new Set(\n ALL_TOOLS.filter((t) => !t.annotations.readOnlyHint).map((t) => t.name),\n);\n\n/** The tools a server registers at this setting — the one owner of the `--read-only` gate. */\nexport function registeredTools(readOnly: boolean): readonly DefinedTool[] {\n return readOnly ? ALL_TOOLS.filter((t) => !MUTATING_TOOL_NAMES.has(t.name)) : ALL_TOOLS;\n}\n\n// Re-exported so documentation surfaces quote `.name` off the definition rather\n// than repeating the string. This module is the only owner of the inventory.\n// Only the read-only tools are named individually: the mutating six are no\n// longer listed by hand anywhere, so their names reach callers through\n// MUTATING_TOOL_NAMES and ALL_TOOLS instead.\nexport { LIST, LIST_ROOTS, READ, SEARCH_TEXT, FIND_FILES, STAT };\n\ninterface ToolRegistrarDeps {\n readonly server: McpServer;\n readonly pathGuard: PathGuard;\n readonly pageStore: PageSnapshotStore;\n readonly resourceStore: ResourceStore;\n readonly readOnly?: boolean;\n readonly era?: 'legacy' | 'modern';\n}\n\nexport function registerTools(deps: ToolRegistrarDeps): void {\n const toolDeps = {\n server: deps.server,\n pathGuard: deps.pathGuard,\n pageStore: deps.pageStore,\n resourceStore: deps.resourceStore,\n ...(deps.era ? { era: deps.era } : {}),\n };\n for (const tool of registeredTools(deps.readOnly ?? false)) {\n tool.register(toolDeps);\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"move.d.ts","sourceRoot":"","sources":["../../src/tools/move.ts"],"names":[],"mappings":"AAqfA,eAAO,MAAM,IAAI,mCA8Cf,CAAC"}
1
+ {"version":3,"file":"move.d.ts","sourceRoot":"","sources":["../../src/tools/move.ts"],"names":[],"mappings":"AAwdA,eAAO,MAAM,IAAI,mCAmDf,CAAC"}
@@ -186,10 +186,7 @@ async function runTransfers(items, ctx, op, overwrite) {
186
186
  clientCapabilities: ctx.clientCapabilities,
187
187
  buildInputs: (dests) => dests.map((dest, i) => choiceInput(confirmKey(i), op === 'move'
188
188
  ? `"${dest}" already exists. Overwrite it?`
189
- : `Destination "${dest}" already exists. Overwrite it?`, [
190
- { value: 'overwrite', title: 'Overwrite' },
191
- { value: 'skip', title: 'Skip' },
192
- ])),
189
+ : `Destination "${dest}" already exists. Overwrite it?`, ['overwrite', 'skip'])),
193
190
  });
194
191
  if (round !== undefined)
195
192
  return round;
@@ -224,27 +221,6 @@ async function runTransfers(items, ctx, op, overwrite) {
224
221
  }
225
222
  return { results, skipped, failures };
226
223
  }
227
- /**
228
- * Two-phase move: pre-check every move (no mutation) to build the overwrite
229
- * pending set; if any move is pending and the round carries no verified
230
- * `requestState`, return `input_required` moving nothing (R14). On retry, R9
231
- * checks the state binds this move set, then each pending move proceeds only on
232
- * an accepted overwrite. Non-pending moves proceed alongside them.
233
- */
234
- async function handleMove(args, ctx) {
235
- const op = args.copy ? 'copy' : 'move';
236
- // `overwrite` is copy-only; move has no confirmation bypass.
237
- const overwrite = args.copy && args.overwrite;
238
- const outcome = await runTransfers(args.moves, ctx, op, overwrite);
239
- if (isInputRequiredResult(outcome))
240
- return outcome;
241
- const { results, skipped, failures } = outcome;
242
- return {
243
- moves: results,
244
- ...(failures.length > 0 ? { failures } : {}),
245
- ...(skipped.length > 0 ? { skipped } : {}),
246
- };
247
- }
248
224
  function buildSummary(verb, results, failures, skipped) {
249
225
  const successCount = results.length;
250
226
  const failCount = failures.length;
@@ -353,19 +329,24 @@ export const MOVE = defineTool({
353
329
  defaultErrorCode: ErrorCode.UNKNOWN,
354
330
  accessPaths: (args) => args.moves.flatMap((m) => [m.source, m.destination]),
355
331
  run: async (args, ctx) => {
356
- const output = await handleMove(args, ctx);
332
+ const op = args.copy ? 'copy' : 'move';
333
+ // `overwrite` is copy-only; move has no confirmation bypass.
334
+ const outcome = await runTransfers(args.moves, ctx, op, args.copy && args.overwrite);
357
335
  // input_required is a return value, not a completed call: surface it
358
336
  // verbatim so the executor short-circuits before building a CallToolResult.
359
- if (isInputRequiredResult(output))
360
- return output;
361
- const failures = output.failures ?? [];
362
- const skipped = output.skipped ?? [];
337
+ if (isInputRequiredResult(outcome))
338
+ return outcome;
339
+ const { results, skipped, failures } = outcome;
363
340
  return {
364
- structured: output,
365
- text: buildSummary(args.copy ? 'copy' : 'move', output.moves, failures, skipped),
341
+ structured: {
342
+ moves: results,
343
+ ...(failures.length > 0 ? { failures } : {}),
344
+ ...(skipped.length > 0 ? { skipped } : {}),
345
+ },
346
+ text: buildSummary(op, results, failures, skipped),
366
347
  // Every requested pair failed: no move, no copy, no user-chosen skip - the
367
348
  // call did nothing. A skip is work the caller asked for, so it counts.
368
- isError: failures.length > 0 && output.moves.length + skipped.length === 0,
349
+ isError: failures.length > 0 && results.length + skipped.length === 0,
369
350
  };
370
351
  },
371
352
  });