maestro-agent-sdk 0.1.7 → 0.1.9

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.
@@ -41,34 +41,42 @@ export const globTool = {
41
41
  schema: {
42
42
  name: "Glob",
43
43
  description: "Fast file pattern matching. Supports `*` (within-segment wildcard), " +
44
- "`**` (cross-segment wildcard), `?` (one char). Returns absolute paths " +
45
- "sorted by modification time descending recently-touched files first. " +
46
- "Does NOT skip dotfiles or build dirs; the model's pattern is authoritative. " +
47
- "Caps results at 10,000 entries (truncates with a note when exceeded).",
44
+ "`**` (cross-segment wildcard), `?` (one char), `[abc]` / `[a-z]` / `[!abc]` " +
45
+ "character classes, and `{a,b}` brace expansion (nestable). Returns " +
46
+ "absolute paths sorted by modification time descending recently-touched " +
47
+ "files first. Does NOT skip dotfiles or build dirs; the model's pattern is " +
48
+ "authoritative. Caps results at 10,000 entries (truncates with a note when exceeded).",
48
49
  input_schema: {
49
50
  type: "object",
50
51
  properties: {
51
52
  pattern: {
52
53
  type: "string",
53
- description: "Glob pattern. Examples: `**/*.ts`, `src/**/*.tsx`, `README.md`, " +
54
- "`config/*.json`. Matched against paths relative to `path`.",
54
+ description: "Glob pattern. Examples: `**/*.ts`, `src/**/*.{js,ts,tsx}`, " +
55
+ "`file[0-9].log`, `README.md`, `config/*.json`. May also embed " +
56
+ "the absolute root (e.g. `/abs/path/**/*.ts`) — in that case " +
57
+ "`path` is auto-derived from the fixed prefix and the trailing " +
58
+ "portion becomes the matcher.",
55
59
  },
56
60
  path: {
57
61
  type: "string",
58
62
  description: "Optional absolute directory to search in. Defaults to the SDK's process cwd. " +
59
- "Relative paths are rejected.",
63
+ "If omitted and `pattern` is absolute, the walk root is auto-extracted " +
64
+ "from `pattern`. Relative paths are rejected.",
60
65
  },
61
66
  },
62
67
  required: ["pattern"],
63
68
  },
64
69
  },
65
70
  async execute(input) {
66
- const pattern = typeof input.pattern === "string" ? input.pattern : "";
67
- if (!pattern) {
71
+ const rawPattern = typeof input.pattern === "string" ? input.pattern : "";
72
+ if (!rawPattern) {
68
73
  return JSON.stringify({ error: "Glob: missing 'pattern' argument" });
69
74
  }
70
75
  const rawPath = typeof input.path === "string" ? input.path : undefined;
71
76
  let root;
77
+ // `pattern` is what compileGlob() consumes. We may rewrite it below when
78
+ // the caller passed an absolute path inside `pattern` (claude SDK parity).
79
+ let pattern = rawPattern;
72
80
  if (rawPath !== undefined) {
73
81
  if (!isAbsolute(rawPath)) {
74
82
  return JSON.stringify({
@@ -77,6 +85,17 @@ export const globTool = {
77
85
  }
78
86
  root = rawPath;
79
87
  }
88
+ else if (isAbsolute(rawPattern)) {
89
+ // claude-SDK parity: when the caller embeds the absolute root inside
90
+ // `pattern` (e.g. `/Users/foo/proj/**/*.ts`) and omits `path`, we split
91
+ // off the longest fixed prefix and use that as the walk root. Without
92
+ // this the regex compiled from the absolute pattern matches against
93
+ // *relative* paths and returns zero — a footgun we hit often when the
94
+ // model copy-pastes absolute paths it just got from Read/Grep.
95
+ const split = splitAbsolutePattern(rawPattern);
96
+ root = split.root;
97
+ pattern = split.pattern;
98
+ }
80
99
  else {
81
100
  root = process.cwd();
82
101
  }
@@ -186,15 +205,23 @@ export const globTool = {
186
205
  * path (anchored at both ends).
187
206
  *
188
207
  * Handled tokens:
189
- * `**\/` → `(?:.*\/)?` — zero or more path segments (greedy across `/`)
190
- * `**` → `.*` — anything including `/`
191
- * `*` → `[^/]*` — anything except `/` within one segment
192
- * `?` → `[^/]` — single char within one segment
208
+ * `**\/` → `(?:.*\/)?` — zero or more path segments (greedy across `/`)
209
+ * `**` → `.*` — anything including `/`
210
+ * `*` → `[^/]*` — anything except `/` within one segment
211
+ * `?` → `[^/]` — single char within one segment
212
+ * `[abc]` → `[abc]` — character class (POSIX `[!abc]` → `[^abc]`)
213
+ * `{a,b}` → `(?:a|b)` — brace expansion (nestable, body recursively
214
+ * compiled so wildcards / classes inside each
215
+ * alternative still work)
193
216
  *
194
217
  * Other regex metacharacters are escaped so literals like `.` in `foo.ts`
195
218
  * don't accidentally turn into "any char".
196
219
  */
197
220
  export function compileGlob(pattern) {
221
+ return new RegExp(`^${compileGlobBody(pattern)}$`);
222
+ }
223
+ /** Build the regex body (no anchors) so brace alternatives can recurse. */
224
+ function compileGlobBody(pattern) {
198
225
  let s = "";
199
226
  let i = 0;
200
227
  while (i < pattern.length) {
@@ -220,6 +247,41 @@ export function compileGlob(pattern) {
220
247
  s += "[^/]";
221
248
  i += 1;
222
249
  }
250
+ else if (c === "[") {
251
+ // Character class `[abc]`, `[a-z]`, `[!abc]`. Find the closing `]`;
252
+ // if missing, treat the `[` as a literal (matches bash defensively).
253
+ const end = pattern.indexOf("]", i + 1);
254
+ if (end === -1) {
255
+ s += "\\[";
256
+ i += 1;
257
+ }
258
+ else {
259
+ let cls = pattern.slice(i + 1, end);
260
+ if (cls.startsWith("!"))
261
+ cls = `^${cls.slice(1)}`; // POSIX negation
262
+ s += `[${cls}]`;
263
+ i = end + 1;
264
+ }
265
+ }
266
+ else if (c === "{") {
267
+ // Brace expansion `{a,b,c}`. Find the matching `}` accounting for
268
+ // nesting (`{a,{b,c}}`). On unbalanced braces we treat the `{` as a
269
+ // literal — bash does the same.
270
+ const close = matchingBraceClose(pattern, i);
271
+ if (close === -1) {
272
+ s += "\\{";
273
+ i += 1;
274
+ }
275
+ else {
276
+ const body = pattern.slice(i + 1, close);
277
+ const parts = splitTopLevel(body, ",");
278
+ // Recursively compile each alternative so a brace can carry full
279
+ // glob syntax inside (`{*.ts,src/**/*.tsx}` works).
280
+ const alts = parts.map((p) => compileGlobBody(p));
281
+ s += `(?:${alts.join("|")})`;
282
+ i = close + 1;
283
+ }
284
+ }
223
285
  else if (REGEX_META.includes(c)) {
224
286
  s += `\\${c}`;
225
287
  i += 1;
@@ -229,7 +291,92 @@ export function compileGlob(pattern) {
229
291
  i += 1;
230
292
  }
231
293
  }
232
- return new RegExp(`^${s}$`);
294
+ return s;
295
+ }
296
+ /**
297
+ * Locate the `}` that closes the `{` at `openIdx`, respecting nesting.
298
+ * Returns -1 if the brace is unbalanced (caller falls back to literal).
299
+ */
300
+ function matchingBraceClose(pattern, openIdx) {
301
+ let depth = 1;
302
+ for (let j = openIdx + 1; j < pattern.length; j++) {
303
+ const ch = pattern[j];
304
+ if (ch === "{")
305
+ depth++;
306
+ else if (ch === "}") {
307
+ depth--;
308
+ if (depth === 0)
309
+ return j;
310
+ }
311
+ }
312
+ return -1;
313
+ }
314
+ /**
315
+ * Split `body` by `sep` only when the separator appears at the top level
316
+ * (depth-0 with respect to `{}` nesting). `{a,{b,c}}` splits into
317
+ * `["a", "{b,c}"]` — not `["a", "{b", "c}"]`.
318
+ */
319
+ function splitTopLevel(body, sep) {
320
+ const parts = [];
321
+ let depth = 0;
322
+ let start = 0;
323
+ for (let k = 0; k < body.length; k++) {
324
+ const ch = body[k];
325
+ if (ch === "{")
326
+ depth++;
327
+ else if (ch === "}")
328
+ depth--;
329
+ else if (ch === sep && depth === 0) {
330
+ parts.push(body.slice(start, k));
331
+ start = k + 1;
332
+ }
333
+ }
334
+ parts.push(body.slice(start));
335
+ return parts;
336
+ }
337
+ const REGEX_META = ".+^$()|\\";
338
+ /**
339
+ * Split an absolute glob pattern into (root, relativePattern).
340
+ *
341
+ * claude-SDK accepts patterns like `/Users/foo/proj/**\/*.ts` directly —
342
+ * its implementation pulls out the longest fixed-segment prefix as the
343
+ * walk root and uses the rest as the matcher. We mirror that here so the
344
+ * model's pretrained instinct works without forcing the caller to split
345
+ * `path` and `pattern` manually.
346
+ *
347
+ * Algorithm:
348
+ * - Split the pattern by `/`. The leading `/` produces an empty first
349
+ * segment.
350
+ * - Find the first segment that contains a wildcard meta (`*` or `?`).
351
+ * - Everything strictly before it forms the root (rejoined with `/`).
352
+ * Everything from that segment onward is the new pattern (relative
353
+ * to root).
354
+ * - If no segment contains a wildcard the pattern is a literal absolute
355
+ * path; treat dirname as the root and basename as the pattern so
356
+ * `Glob({pattern: "/etc/hosts"})` still matches the single file.
357
+ * - Empty root collapses to "/" (POSIX absolute root).
358
+ */
359
+ export function splitAbsolutePattern(p) {
360
+ const segs = p.split("/");
361
+ let wildAt = -1;
362
+ for (let i = 0; i < segs.length; i++) {
363
+ if (segs[i].includes("*") || segs[i].includes("?")) {
364
+ wildAt = i;
365
+ break;
366
+ }
367
+ }
368
+ if (wildAt === -1) {
369
+ // No wildcard — split dirname/basename so literal absolute paths still
370
+ // match. `Glob({pattern: "/etc/hosts"})` → root "/etc", pattern "hosts".
371
+ const parts = segs.slice();
372
+ const last = parts.pop() ?? "";
373
+ const root = parts.join("/") || "/";
374
+ return { root, pattern: last };
375
+ }
376
+ const rootJoined = segs.slice(0, wildAt).join("/");
377
+ return {
378
+ root: rootJoined || "/",
379
+ pattern: segs.slice(wildAt).join("/"),
380
+ };
233
381
  }
234
- const REGEX_META = ".+^$()[]{}|\\";
235
382
  //# sourceMappingURL=glob.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"glob.js","sourceRoot":"","sources":["../../../src/tools/builtin/glob.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAc,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAG5D;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,8EAA8E;AAC9E,MAAM,WAAW,GAAG,MAAM,CAAC;AAE3B;+BAC+B;AAC/B,MAAM,eAAe,GAAG,MAAM,CAAC;AAE/B,MAAM,CAAC,MAAM,QAAQ,GAAgB;IACnC,sEAAsE;IACtE,oCAAoC;IACpC,YAAY,EAAE,IAAI;IAClB,MAAM,EAAE;QACN,IAAI,EAAE,MAAM;QACZ,WAAW,EACT,sEAAsE;YACtE,wEAAwE;YACxE,yEAAyE;YACzE,8EAA8E;YAC9E,uEAAuE;QACzE,YAAY,EAAE;YACZ,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,OAAO,EAAE;oBACP,IAAI,EAAE,QAAQ;oBACd,WAAW,EACT,kEAAkE;wBAClE,4DAA4D;iBAC/D;gBACD,IAAI,EAAE;oBACJ,IAAI,EAAE,QAAQ;oBACd,WAAW,EACT,+EAA+E;wBAC/E,8BAA8B;iBACjC;aACF;YACD,QAAQ,EAAE,CAAC,SAAS,CAAC;SACtB;KACF;IACD,KAAK,CAAC,OAAO,CAAC,KAAK;QACjB,MAAM,OAAO,GAAG,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;QACvE,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,kCAAkC,EAAE,CAAC,CAAC;QACvE,CAAC;QAED,MAAM,OAAO,GAAG,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;QACxE,IAAI,IAAY,CAAC;QACjB,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;gBACzB,OAAO,IAAI,CAAC,SAAS,CAAC;oBACpB,KAAK,EAAE,uCAAuC,OAAO,GAAG;iBACzD,CAAC,CAAC;YACL,CAAC;YACD,IAAI,GAAG,OAAO,CAAC;QACjB,CAAC;aAAM,CAAC;YACN,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;QACvB,CAAC;QAED,IAAI,QAAe,CAAC;QACpB,IAAI,CAAC;YACH,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC5B,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,IAAI,CAAC,SAAS,CAAC;gBACpB,KAAK,EAAE,2BAA2B,IAAI,MAAM,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;aACzF,CAAC,CAAC;QACL,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,EAAE,CAAC;YAC5B,OAAO,IAAI,CAAC,SAAS,CAAC;gBACpB,KAAK,EAAE,gDAAgD,IAAI,GAAG;aAC/D,CAAC,CAAC;QACL,CAAC;QAED,IAAI,KAAa,CAAC;QAClB,IAAI,CAAC;YACH,KAAK,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;QAC/B,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,IAAI,CAAC,SAAS,CAAC;gBACpB,KAAK,EAAE,oCAAoC,OAAO,MAAM,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;aACrG,CAAC,CAAC;QACL,CAAC;QAED,MAAM,OAAO,GAA0C,EAAE,CAAC;QAC1D,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,IAAI,SAAS,GAAG,KAAK,CAAC;QACtB,IAAI,QAAQ,GAAG,KAAK,CAAC;QAErB,SAAS,UAAU;YACjB,IAAI,OAAO,CAAC,MAAM,IAAI,WAAW,EAAE,CAAC;gBAClC,SAAS,GAAG,IAAI,CAAC;gBACjB,OAAO,IAAI,CAAC;YACd,CAAC;YACD,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,GAAG,eAAe,EAAE,CAAC;gBAC7C,QAAQ,GAAG,IAAI,CAAC;gBAChB,OAAO,IAAI,CAAC;YACd,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC;QAED,SAAS,IAAI,CAAC,GAAW;YACvB,IAAI,UAAU,EAAE;gBAAE,OAAO;YACzB,IAAI,KAAe,CAAC;YACpB,IAAI,CAAC;gBACH,qEAAqE;gBACrE,sEAAsE;gBACtE,4DAA4D;gBAC5D,uEAAuE;gBACvE,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;YAC3B,CAAC;YAAC,MAAM,CAAC;gBACP,gEAAgE;gBAChE,OAAO;YACT,CAAC;YACD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,IAAI,UAAU,EAAE;oBAAE,OAAO;gBACzB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;gBAC5B,IAAI,IAAW,CAAC;gBAChB,IAAI,CAAC;oBACH,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;gBACvB,CAAC;gBAAC,MAAM,CAAC;oBACP,SAAS;gBACX,CAAC;gBACD,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;oBACvB,IAAI,CAAC,GAAG,CAAC,CAAC;oBACV,SAAS;gBACX,CAAC;gBACD,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;oBAAE,SAAS;gBAC7B,oEAAoE;gBACpE,oCAAoC;gBACpC,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBACrD,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC;oBAAE,SAAS;gBAC/B,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;YAC7C,CAAC;QACH,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,CAAC;QACX,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;QAC1C,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAExC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,OAAO,IAAI,CAAC,SAAS,CAAC;gBACpB,EAAE,EAAE,IAAI;gBACR,KAAK,EAAE,CAAC;gBACR,KAAK,EAAE,EAAE;gBACT,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,2CAA2C,CAAC,CAAC,CAAC,aAAa;aAC7E,CAAC,CAAC;QACL,CAAC;QAED,MAAM,OAAO,GAA4B;YACvC,EAAE,EAAE,IAAI;YACR,KAAK,EAAE,KAAK,CAAC,MAAM;YACnB,KAAK;SACN,CAAC;QACF,IAAI,SAAS;YAAE,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;QACxC,IAAI,QAAQ;YAAE,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;QACtC,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IACjC,CAAC;CACF,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,WAAW,CAAC,OAAe;IACzC,IAAI,CAAC,GAAG,EAAE,CAAC;IACX,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;QAC1B,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QACrB,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;YACd,8CAA8C;YAC9C,IAAI,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;gBAC3B,IAAI,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;oBAC3B,CAAC,IAAI,YAAY,CAAC;oBAClB,CAAC,IAAI,CAAC,CAAC;gBACT,CAAC;qBAAM,CAAC;oBACN,CAAC,IAAI,IAAI,CAAC;oBACV,CAAC,IAAI,CAAC,CAAC;gBACT,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,CAAC,IAAI,OAAO,CAAC;gBACb,CAAC,IAAI,CAAC,CAAC;YACT,CAAC;QACH,CAAC;aAAM,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;YACrB,CAAC,IAAI,MAAM,CAAC;YACZ,CAAC,IAAI,CAAC,CAAC;QACT,CAAC;aAAM,IAAI,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;YAClC,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YACd,CAAC,IAAI,CAAC,CAAC;QACT,CAAC;aAAM,CAAC;YACN,CAAC,IAAI,CAAC,CAAC;YACP,CAAC,IAAI,CAAC,CAAC;QACT,CAAC;IACH,CAAC;IACD,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,GAAG,eAAe,CAAC"}
1
+ {"version":3,"file":"glob.js","sourceRoot":"","sources":["../../../src/tools/builtin/glob.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAc,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAG5D;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,8EAA8E;AAC9E,MAAM,WAAW,GAAG,MAAM,CAAC;AAE3B;+BAC+B;AAC/B,MAAM,eAAe,GAAG,MAAM,CAAC;AAE/B,MAAM,CAAC,MAAM,QAAQ,GAAgB;IACnC,sEAAsE;IACtE,oCAAoC;IACpC,YAAY,EAAE,IAAI;IAClB,MAAM,EAAE;QACN,IAAI,EAAE,MAAM;QACZ,WAAW,EACT,sEAAsE;YACtE,8EAA8E;YAC9E,qEAAqE;YACrE,2EAA2E;YAC3E,4EAA4E;YAC5E,sFAAsF;QACxF,YAAY,EAAE;YACZ,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,OAAO,EAAE;oBACP,IAAI,EAAE,QAAQ;oBACd,WAAW,EACT,6DAA6D;wBAC7D,gEAAgE;wBAChE,8DAA8D;wBAC9D,gEAAgE;wBAChE,8BAA8B;iBACjC;gBACD,IAAI,EAAE;oBACJ,IAAI,EAAE,QAAQ;oBACd,WAAW,EACT,+EAA+E;wBAC/E,wEAAwE;wBACxE,8CAA8C;iBACjD;aACF;YACD,QAAQ,EAAE,CAAC,SAAS,CAAC;SACtB;KACF;IACD,KAAK,CAAC,OAAO,CAAC,KAAK;QACjB,MAAM,UAAU,GAAG,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1E,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,kCAAkC,EAAE,CAAC,CAAC;QACvE,CAAC;QAED,MAAM,OAAO,GAAG,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;QACxE,IAAI,IAAY,CAAC;QACjB,yEAAyE;QACzE,2EAA2E;QAC3E,IAAI,OAAO,GAAG,UAAU,CAAC;QAEzB,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;gBACzB,OAAO,IAAI,CAAC,SAAS,CAAC;oBACpB,KAAK,EAAE,uCAAuC,OAAO,GAAG;iBACzD,CAAC,CAAC;YACL,CAAC;YACD,IAAI,GAAG,OAAO,CAAC;QACjB,CAAC;aAAM,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAClC,qEAAqE;YACrE,wEAAwE;YACxE,sEAAsE;YACtE,oEAAoE;YACpE,sEAAsE;YACtE,+DAA+D;YAC/D,MAAM,KAAK,GAAG,oBAAoB,CAAC,UAAU,CAAC,CAAC;YAC/C,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;YAClB,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;QAC1B,CAAC;aAAM,CAAC;YACN,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;QACvB,CAAC;QAED,IAAI,QAAe,CAAC;QACpB,IAAI,CAAC;YACH,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC5B,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,IAAI,CAAC,SAAS,CAAC;gBACpB,KAAK,EAAE,2BAA2B,IAAI,MAAM,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;aACzF,CAAC,CAAC;QACL,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,EAAE,CAAC;YAC5B,OAAO,IAAI,CAAC,SAAS,CAAC;gBACpB,KAAK,EAAE,gDAAgD,IAAI,GAAG;aAC/D,CAAC,CAAC;QACL,CAAC;QAED,IAAI,KAAa,CAAC;QAClB,IAAI,CAAC;YACH,KAAK,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;QAC/B,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,IAAI,CAAC,SAAS,CAAC;gBACpB,KAAK,EAAE,oCAAoC,OAAO,MAAM,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;aACrG,CAAC,CAAC;QACL,CAAC;QAED,MAAM,OAAO,GAA0C,EAAE,CAAC;QAC1D,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,IAAI,SAAS,GAAG,KAAK,CAAC;QACtB,IAAI,QAAQ,GAAG,KAAK,CAAC;QAErB,SAAS,UAAU;YACjB,IAAI,OAAO,CAAC,MAAM,IAAI,WAAW,EAAE,CAAC;gBAClC,SAAS,GAAG,IAAI,CAAC;gBACjB,OAAO,IAAI,CAAC;YACd,CAAC;YACD,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,GAAG,eAAe,EAAE,CAAC;gBAC7C,QAAQ,GAAG,IAAI,CAAC;gBAChB,OAAO,IAAI,CAAC;YACd,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC;QAED,SAAS,IAAI,CAAC,GAAW;YACvB,IAAI,UAAU,EAAE;gBAAE,OAAO;YACzB,IAAI,KAAe,CAAC;YACpB,IAAI,CAAC;gBACH,qEAAqE;gBACrE,sEAAsE;gBACtE,4DAA4D;gBAC5D,uEAAuE;gBACvE,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;YAC3B,CAAC;YAAC,MAAM,CAAC;gBACP,gEAAgE;gBAChE,OAAO;YACT,CAAC;YACD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,IAAI,UAAU,EAAE;oBAAE,OAAO;gBACzB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;gBAC5B,IAAI,IAAW,CAAC;gBAChB,IAAI,CAAC;oBACH,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;gBACvB,CAAC;gBAAC,MAAM,CAAC;oBACP,SAAS;gBACX,CAAC;gBACD,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;oBACvB,IAAI,CAAC,GAAG,CAAC,CAAC;oBACV,SAAS;gBACX,CAAC;gBACD,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;oBAAE,SAAS;gBAC7B,oEAAoE;gBACpE,oCAAoC;gBACpC,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBACrD,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC;oBAAE,SAAS;gBAC/B,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;YAC7C,CAAC;QACH,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,CAAC;QACX,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;QAC1C,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAExC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,OAAO,IAAI,CAAC,SAAS,CAAC;gBACpB,EAAE,EAAE,IAAI;gBACR,KAAK,EAAE,CAAC;gBACR,KAAK,EAAE,EAAE;gBACT,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,2CAA2C,CAAC,CAAC,CAAC,aAAa;aAC7E,CAAC,CAAC;QACL,CAAC;QAED,MAAM,OAAO,GAA4B;YACvC,EAAE,EAAE,IAAI;YACR,KAAK,EAAE,KAAK,CAAC,MAAM;YACnB,KAAK;SACN,CAAC;QACF,IAAI,SAAS;YAAE,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;QACxC,IAAI,QAAQ;YAAE,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;QACtC,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IACjC,CAAC;CACF,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,WAAW,CAAC,OAAe;IACzC,OAAO,IAAI,MAAM,CAAC,IAAI,eAAe,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;AACrD,CAAC;AAED,2EAA2E;AAC3E,SAAS,eAAe,CAAC,OAAe;IACtC,IAAI,CAAC,GAAG,EAAE,CAAC;IACX,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;QAC1B,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QACrB,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;YACd,8CAA8C;YAC9C,IAAI,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;gBAC3B,IAAI,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;oBAC3B,CAAC,IAAI,YAAY,CAAC;oBAClB,CAAC,IAAI,CAAC,CAAC;gBACT,CAAC;qBAAM,CAAC;oBACN,CAAC,IAAI,IAAI,CAAC;oBACV,CAAC,IAAI,CAAC,CAAC;gBACT,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,CAAC,IAAI,OAAO,CAAC;gBACb,CAAC,IAAI,CAAC,CAAC;YACT,CAAC;QACH,CAAC;aAAM,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;YACrB,CAAC,IAAI,MAAM,CAAC;YACZ,CAAC,IAAI,CAAC,CAAC;QACT,CAAC;aAAM,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;YACrB,oEAAoE;YACpE,qEAAqE;YACrE,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;YACxC,IAAI,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC;gBACf,CAAC,IAAI,KAAK,CAAC;gBACX,CAAC,IAAI,CAAC,CAAC;YACT,CAAC;iBAAM,CAAC;gBACN,IAAI,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC;gBACpC,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC;oBAAE,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,iBAAiB;gBACpE,CAAC,IAAI,IAAI,GAAG,GAAG,CAAC;gBAChB,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC;YACd,CAAC;QACH,CAAC;aAAM,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;YACrB,kEAAkE;YAClE,oEAAoE;YACpE,gCAAgC;YAChC,MAAM,KAAK,GAAG,kBAAkB,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;YAC7C,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;gBACjB,CAAC,IAAI,KAAK,CAAC;gBACX,CAAC,IAAI,CAAC,CAAC;YACT,CAAC;iBAAM,CAAC;gBACN,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;gBACzC,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;gBACvC,iEAAiE;gBACjE,oDAAoD;gBACpD,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC;gBAClD,CAAC,IAAI,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;gBAC7B,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC;YAChB,CAAC;QACH,CAAC;aAAM,IAAI,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;YAClC,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YACd,CAAC,IAAI,CAAC,CAAC;QACT,CAAC;aAAM,CAAC;YACN,CAAC,IAAI,CAAC,CAAC;YACP,CAAC,IAAI,CAAC,CAAC;QACT,CAAC;IACH,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED;;;GAGG;AACH,SAAS,kBAAkB,CAAC,OAAe,EAAE,OAAe;IAC1D,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,IAAI,CAAC,GAAG,OAAO,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAClD,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QACtB,IAAI,EAAE,KAAK,GAAG;YAAE,KAAK,EAAE,CAAC;aACnB,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACpB,KAAK,EAAE,CAAC;YACR,IAAI,KAAK,KAAK,CAAC;gBAAE,OAAO,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;IACD,OAAO,CAAC,CAAC,CAAC;AACZ,CAAC;AAED;;;;GAIG;AACH,SAAS,aAAa,CAAC,IAAY,EAAE,GAAW;IAC9C,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACnB,IAAI,EAAE,KAAK,GAAG;YAAE,KAAK,EAAE,CAAC;aACnB,IAAI,EAAE,KAAK,GAAG;YAAE,KAAK,EAAE,CAAC;aACxB,IAAI,EAAE,KAAK,GAAG,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;YACnC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;YACjC,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC;QAChB,CAAC;IACH,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;IAC9B,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,GAAG,WAAW,CAAC;AAE/B;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,oBAAoB,CAAC,CAAS;IAC5C,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC1B,IAAI,MAAM,GAAG,CAAC,CAAC,CAAC;IAChB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACnD,MAAM,GAAG,CAAC,CAAC;YACX,MAAM;QACR,CAAC;IACH,CAAC;IACD,IAAI,MAAM,KAAK,CAAC,CAAC,EAAE,CAAC;QAClB,uEAAuE;QACvE,yEAAyE;QACzE,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;QAC3B,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC;QACpC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACjC,CAAC;IACD,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACnD,OAAO;QACL,IAAI,EAAE,UAAU,IAAI,GAAG;QACvB,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;KACtC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { FileStateTracker } from "../../tools/file-state.js";
2
+ import type { ToolHandler } from "../../tools/registry.js";
3
+ export interface MultiEditToolOptions {
4
+ /**
5
+ * Per-session file-state tracker. When provided, MultiEdit enforces the
6
+ * Read-before-Edit invariant: the path must have been Read in this session
7
+ * AND its mtime/size must still match the recorded values.
8
+ */
9
+ tracker?: FileStateTracker;
10
+ }
11
+ export declare function createMultiEditTool(opts?: MultiEditToolOptions): ToolHandler;
12
+ /** Backwards-compatible singleton (no tracker — Read-before-Edit gate off). */
13
+ export declare const multiEditTool: ToolHandler;
14
+ export declare const __MAX_FILE_BYTES: number;
15
+ export declare const __MAX_EDITS = 64;
16
+ //# sourceMappingURL=multi_edit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"multi_edit.d.ts","sourceRoot":"","sources":["../../../src/tools/builtin/multi_edit.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAqDpD,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,OAAO,CAAC,EAAE,gBAAgB,CAAC;CAC5B;AAED,wBAAgB,mBAAmB,CAAC,IAAI,GAAE,oBAAyB,GAAG,WAAW,CAsNhF;AAED,+EAA+E;AAC/E,eAAO,MAAM,aAAa,EAAE,WAAmC,CAAC;AA8BhE,eAAO,MAAM,gBAAgB,QAAiB,CAAC;AAC/C,eAAO,MAAM,WAAW,KAAY,CAAC"}
@@ -0,0 +1,286 @@
1
+ import { existsSync, readFileSync, statSync, writeFileSync } from "node:fs";
2
+ import { isAbsolute } from "node:path";
3
+ import { countOccurrences } from "../../tools/builtin/edit.js";
4
+ /**
5
+ * MultiEdit builtin — claude SDK `MultiEdit` tool parity for maestro.
6
+ *
7
+ * Applies an ordered list of (old_string, new_string) replacements to a
8
+ * single file **atomically**. The contract that makes this tool valuable:
9
+ *
10
+ * 1. Read the file once.
11
+ * 2. Apply edits sequentially to the in-memory buffer — each edit sees
12
+ * the state left by the previous one (so a follow-up edit can target
13
+ * text inserted by the previous step).
14
+ * 3. If ANY edit fails (`old_string` not found, ambiguous match without
15
+ * `replace_all`, no-op replacement) we abort BEFORE writing. The
16
+ * file on disk is left untouched. The model then sees a structured
17
+ * `failedAt: <index>` payload it can react to without having to
18
+ * reason about which earlier edits did or didn't land.
19
+ * 4. Only after all edits succeed do we write once.
20
+ *
21
+ * Why a separate tool (rather than have the model call `Edit` in a loop):
22
+ *
23
+ * - Halves API round-trips for the common "fix N spots in one file"
24
+ * refactor — the model emits one tool call instead of N.
25
+ * - Atomic-by-default eliminates a real class of bug where edit #3 of
26
+ * 5 fails and the file is left with edits 1–2 applied but the model
27
+ * thinks the whole batch is done.
28
+ * - The Read-before-Edit gate fires once for the whole batch instead
29
+ * of forcing a re-Read between each step.
30
+ *
31
+ * Same constraints as Edit:
32
+ * - file_path must be absolute.
33
+ * - File must exist (MultiEdit never creates — use Write for that).
34
+ * - Each edit's `old_string` must occur exactly once in the current
35
+ * buffer unless `replace_all: true` is passed for that edit.
36
+ * - `old_string === new_string` is rejected as a no-op.
37
+ * - 10MB cap on file size (matches Edit / Read).
38
+ *
39
+ * Returns a short summary (`File edited: <path> (N edits, M total replacements)`)
40
+ * followed by a line-numbered preview of the region around the first edit's
41
+ * new_string — same shape Edit returns post-edit, kept consistent so the
42
+ * model's verification instinct transfers.
43
+ */
44
+ const MAX_FILE_BYTES = 10 * 1024 * 1024; // 10MB — same cap as Read / Edit
45
+ const MAX_EDITS = 64; // ceiling on edits per call; prevents pathological batches
46
+ const PREVIEW_LINES_AROUND = 3;
47
+ export function createMultiEditTool(opts = {}) {
48
+ const { tracker } = opts;
49
+ return {
50
+ schema: {
51
+ name: "MultiEdit",
52
+ description: "Apply multiple find-and-replace edits to a single file atomically. " +
53
+ "Each `edits[i].old_string` is matched against the buffer state left " +
54
+ "by the previous edit, so chained edits can target inserted text. " +
55
+ "If any edit fails (not found, ambiguous, or no-op) the file is left " +
56
+ "untouched and a `failedAt` index is returned. file_path must be " +
57
+ "absolute and the file must already exist (use Write for new files).",
58
+ input_schema: {
59
+ type: "object",
60
+ properties: {
61
+ file_path: {
62
+ type: "string",
63
+ description: "Absolute path to the file. MultiEdit never creates new files.",
64
+ },
65
+ edits: {
66
+ type: "array",
67
+ description: "Ordered list of edits to apply. Capped at 64 entries per call. " +
68
+ "Each edit obeys the same uniqueness contract as the single-Edit tool " +
69
+ "unless its own `replace_all: true` is set.",
70
+ items: {
71
+ type: "object",
72
+ properties: {
73
+ old_string: {
74
+ type: "string",
75
+ description: "Exact text to find in the current buffer. Must be non-empty.",
76
+ },
77
+ new_string: {
78
+ type: "string",
79
+ description: "Replacement text. Must differ from old_string.",
80
+ },
81
+ replace_all: {
82
+ type: "boolean",
83
+ description: "When true, replace every occurrence in the current buffer. " +
84
+ "Default false (unique-match required).",
85
+ },
86
+ },
87
+ required: ["old_string", "new_string"],
88
+ },
89
+ },
90
+ },
91
+ required: ["file_path", "edits"],
92
+ },
93
+ },
94
+ async execute(input) {
95
+ const filePath = typeof input.file_path === "string" ? input.file_path : "";
96
+ if (!filePath) {
97
+ return JSON.stringify({ error: "MultiEdit: missing 'file_path' argument" });
98
+ }
99
+ if (!isAbsolute(filePath)) {
100
+ return JSON.stringify({
101
+ error: `MultiEdit: file_path must be absolute, got '${filePath}'`,
102
+ });
103
+ }
104
+ // Read-before-Edit gate. Fires once for the whole batch.
105
+ if (tracker) {
106
+ const gateErr = tracker.checkBeforeMutate(filePath, "MultiEdit");
107
+ if (gateErr) {
108
+ return JSON.stringify({ error: gateErr });
109
+ }
110
+ }
111
+ const rawEdits = input.edits;
112
+ if (!Array.isArray(rawEdits) || rawEdits.length === 0) {
113
+ return JSON.stringify({
114
+ error: "MultiEdit: 'edits' must be a non-empty array",
115
+ });
116
+ }
117
+ if (rawEdits.length > MAX_EDITS) {
118
+ return JSON.stringify({
119
+ error: `MultiEdit: 'edits' length ${rawEdits.length} exceeds cap of ${MAX_EDITS}. Split into multiple calls.`,
120
+ });
121
+ }
122
+ // Validate every edit up-front so we don't perform a partial dry-run
123
+ // before realising one edit is malformed. The validation block only
124
+ // checks shape — the per-edit `old_string` existence check happens
125
+ // during the apply loop because it depends on prior edits.
126
+ const edits = [];
127
+ for (let i = 0; i < rawEdits.length; i++) {
128
+ const e = rawEdits[i];
129
+ if (e === null || typeof e !== "object" || Array.isArray(e)) {
130
+ return JSON.stringify({
131
+ error: `MultiEdit: edit[${i}] must be an object`,
132
+ });
133
+ }
134
+ const rec = e;
135
+ if (typeof rec.old_string !== "string") {
136
+ return JSON.stringify({
137
+ error: `MultiEdit: edit[${i}].old_string must be a string, got ${typeof rec.old_string}`,
138
+ });
139
+ }
140
+ if (typeof rec.new_string !== "string") {
141
+ return JSON.stringify({
142
+ error: `MultiEdit: edit[${i}].new_string must be a string, got ${typeof rec.new_string}`,
143
+ });
144
+ }
145
+ if (rec.old_string.length === 0) {
146
+ return JSON.stringify({
147
+ error: `MultiEdit: edit[${i}].old_string must be non-empty`,
148
+ });
149
+ }
150
+ if (rec.old_string === rec.new_string) {
151
+ return JSON.stringify({
152
+ error: `MultiEdit: edit[${i}] is a no-op (old_string === new_string)`,
153
+ });
154
+ }
155
+ edits.push({
156
+ old_string: rec.old_string,
157
+ new_string: rec.new_string,
158
+ replace_all: Boolean(rec.replace_all),
159
+ });
160
+ }
161
+ if (!existsSync(filePath)) {
162
+ return JSON.stringify({
163
+ error: `MultiEdit: file does not exist: ${filePath}. Use Write to create new files.`,
164
+ });
165
+ }
166
+ let stat;
167
+ try {
168
+ stat = statSync(filePath);
169
+ }
170
+ catch (e) {
171
+ return JSON.stringify({
172
+ error: `MultiEdit: stat failed: ${e instanceof Error ? e.message : String(e)}`,
173
+ });
174
+ }
175
+ if (stat.isDirectory()) {
176
+ return JSON.stringify({
177
+ error: `MultiEdit: '${filePath}' is a directory, not a file.`,
178
+ });
179
+ }
180
+ if (stat.size > MAX_FILE_BYTES) {
181
+ return JSON.stringify({
182
+ error: `MultiEdit: file size ${stat.size} exceeds 10MB cap. Use bash sed/awk for large files.`,
183
+ });
184
+ }
185
+ let raw;
186
+ try {
187
+ raw = readFileSync(filePath, "utf-8");
188
+ }
189
+ catch (e) {
190
+ return JSON.stringify({
191
+ error: `MultiEdit: read failed: ${e instanceof Error ? e.message : String(e)}`,
192
+ });
193
+ }
194
+ // Apply edits sequentially to an in-memory buffer. Each edit sees the
195
+ // state left by the previous one. Any failure aborts the whole batch —
196
+ // the file on disk is untouched and we return `failedAt: <index>` so
197
+ // the model can pinpoint where the cascade broke.
198
+ let buffer = raw;
199
+ let totalReplacements = 0;
200
+ let firstEditNewString = null;
201
+ for (let i = 0; i < edits.length; i++) {
202
+ const { old_string, new_string, replace_all } = edits[i];
203
+ const occurrences = countOccurrences(buffer, old_string);
204
+ if (occurrences === 0) {
205
+ return JSON.stringify({
206
+ error: `MultiEdit: edit[${i}].old_string not found in current buffer ` +
207
+ "(may have been consumed by an earlier edit, or never present).",
208
+ failedAt: i,
209
+ });
210
+ }
211
+ if (!replace_all && occurrences > 1) {
212
+ return JSON.stringify({
213
+ error: `MultiEdit: edit[${i}].old_string appears ${occurrences} times. ` +
214
+ "Enlarge old_string for uniqueness, or set replace_all=true on this edit.",
215
+ failedAt: i,
216
+ occurrences,
217
+ });
218
+ }
219
+ if (replace_all) {
220
+ buffer = buffer.split(old_string).join(new_string);
221
+ totalReplacements += occurrences;
222
+ }
223
+ else {
224
+ const idx = buffer.indexOf(old_string);
225
+ buffer = buffer.slice(0, idx) + new_string + buffer.slice(idx + old_string.length);
226
+ totalReplacements += 1;
227
+ }
228
+ if (firstEditNewString === null && new_string.length > 0) {
229
+ firstEditNewString = new_string;
230
+ }
231
+ }
232
+ try {
233
+ writeFileSync(filePath, buffer, "utf-8");
234
+ }
235
+ catch (e) {
236
+ return JSON.stringify({
237
+ error: `MultiEdit: write failed: ${e instanceof Error ? e.message : String(e)}`,
238
+ });
239
+ }
240
+ tracker?.forget(filePath);
241
+ const preview = firstEditNewString
242
+ ? buildPreview(buffer, firstEditNewString)
243
+ : "[change preview unavailable]";
244
+ const editCount = edits.length;
245
+ return [
246
+ `File edited: ${filePath} (${editCount} edit${editCount === 1 ? "" : "s"}, ` +
247
+ `${totalReplacements} total replacement${totalReplacements === 1 ? "" : "s"})`,
248
+ "",
249
+ preview,
250
+ ].join("\n");
251
+ },
252
+ };
253
+ }
254
+ /** Backwards-compatible singleton (no tracker — Read-before-Edit gate off). */
255
+ export const multiEditTool = createMultiEditTool();
256
+ /**
257
+ * Build a line-numbered preview of the buffer around the first occurrence
258
+ * of `marker`. Same shape as Edit's post-edit preview so the model's
259
+ * verification habit transfers.
260
+ */
261
+ function buildPreview(buffer, marker) {
262
+ const idx = buffer.indexOf(marker);
263
+ if (idx < 0)
264
+ return "";
265
+ const allLines = buffer.split("\n");
266
+ let acc = 0;
267
+ let changedLine = 0;
268
+ for (let i = 0; i < allLines.length; i++) {
269
+ const next = acc + allLines[i].length + 1; // +1 for the dropped \n
270
+ if (next > idx) {
271
+ changedLine = i;
272
+ break;
273
+ }
274
+ acc = next;
275
+ }
276
+ const start = Math.max(0, changedLine - PREVIEW_LINES_AROUND);
277
+ const end = Math.min(allLines.length, changedLine + PREVIEW_LINES_AROUND + 1);
278
+ return allLines
279
+ .slice(start, end)
280
+ .map((line, i) => `${String(start + i + 1).padStart(6, " ")}\t${line}`)
281
+ .join("\n");
282
+ }
283
+ // Internal exports for tests.
284
+ export const __MAX_FILE_BYTES = MAX_FILE_BYTES;
285
+ export const __MAX_EDITS = MAX_EDITS;
286
+ //# sourceMappingURL=multi_edit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"multi_edit.js","sourceRoot":"","sources":["../../../src/tools/builtin/multi_edit.ts"],"names":[],"mappings":"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"}
@@ -5,6 +5,22 @@ export declare const webFetchTool: ToolHandler;
5
5
  * decoding and comment removal built into cheerio's .text(). Collapses
6
6
  * whitespace and preserves paragraph breaks — clean prose, no markup noise. */
7
7
  export declare function htmlToText(html: string): string;
8
+ /**
9
+ * Convert HTML to markdown using cheerio. Walks the DOM emitting markdown
10
+ * for the structural elements the model uses for navigation and citation
11
+ * (headings, links, lists, code, emphasis, blockquotes, tables).
12
+ *
13
+ * Unknown / unhandled tags fall through to their text content, so any tag
14
+ * we forget still contributes the inner text rather than vanishing. This
15
+ * is the same defensive-default claude-SDK's WebFetch markdown converter
16
+ * adopts.
17
+ *
18
+ * Why this lives next to `htmlToText`: hosts may want plain text for
19
+ * downstream NLP (still exported), but the model gets a much better
20
+ * picture from markdown — headings preserve outline, link anchors stay
21
+ * resolvable, and code blocks aren't flattened into prose.
22
+ */
23
+ export declare function htmlToMarkdown(html: string): string;
8
24
  export declare const __FETCH_TIMEOUT_MS = 30000;
9
25
  export declare const __MAX_RESPONSE_BYTES: number;
10
26
  //# sourceMappingURL=web_fetch.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"web_fetch.d.ts","sourceRoot":"","sources":["../../../src/tools/builtin/web_fetch.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AA4BpD,eAAO,MAAM,YAAY,EAAE,WAuG1B,CAAC;AAWF;;;gFAGgF;AAChF,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAa/C;AAGD,eAAO,MAAM,kBAAkB,QAAmB,CAAC;AACnD,eAAO,MAAM,oBAAoB,QAAqB,CAAC"}
1
+ {"version":3,"file":"web_fetch.d.ts","sourceRoot":"","sources":["../../../src/tools/builtin/web_fetch.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AA4BpD,eAAO,MAAM,YAAY,EAAE,WA8G1B,CAAC;AAWF;;;gFAGgF;AAChF,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAa/C;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAmBnD;AAoKD,eAAO,MAAM,kBAAkB,QAAmB,CAAC;AACnD,eAAO,MAAM,oBAAoB,QAAqB,CAAC"}