MCPcopy Create free account
hub / github.com/QodeXcli/QodeX / execute

Method execute

src/tools/filesystem/multi-edit.ts:25–81  ·  view source on GitHub ↗
(args: z.infer<typeof ArgsSchema>, ctx: ToolContext)

Source from the content-addressed store, hash-verified

23 argsSchema = ArgsSchema;
24
25 async execute(args: z.infer<typeof ArgsSchema>, ctx: ToolContext): Promise<ToolResult> {
26 const abs = path.isAbsolute(args.path) ? args.path : path.resolve(ctx.cwd, args.path);
27 const rel = path.relative(ctx.cwd, abs);
28
29 let content: string;
30 try {
31 content = await fs.readFile(abs, 'utf-8');
32 } catch (e: any) {
33 return { content: `[ERROR] Cannot read ${args.path}: ${e.message}`, isError: true };
34 }
35
36 const original = content;
37 let applied = 0;
38 for (let i = 0; i < args.edits.length; i++) {
39 const edit = args.edits[i]!;
40 if (!content.includes(edit.old_string)) {
41 return {
42 content: `[MULTI_EDIT_FAILED] Edit #${i + 1} failed: old_string not found. ` +
43 `${applied} previous edits would have been applied — rolling back. Re-read the file and provide accurate old_strings.`,
44 isError: true,
45 };
46 }
47 const occ = content.split(edit.old_string).length - 1;
48 if (occ > 1 && !edit.replace_all) {
49 return {
50 content: `[MULTI_EDIT_FAILED] Edit #${i + 1}: old_string appears ${occ} times. Make it unique or set replace_all=true. Rolled back.`,
51 isError: true,
52 };
53 }
54 content = edit.replace_all
55 ? content.split(edit.old_string).join(edit.new_string)
56 : content.replace(edit.old_string, edit.new_string);
57 applied++;
58 }
59
60 if (content === original) {
61 return { content: `[NO_OP] All edits resulted in no change to ${rel}.`, isError: true };
62 }
63
64 // Permission check
65 const permReq = { tool: 'multi_edit', operation: rel, description: `Multi-edit ${rel} (${args.edits.length} changes)` };
66 const decision = ctx.permissions.evaluate(permReq);
67 if (decision === 'deny') return { content: `[PERMISSION_DENIED]`, isError: true };
68 if (decision === 'ask') {
69 const dec = await confirmEdit(ctx, {
70 rel, before: original, after: content, absPath: abs, permReq,
71 label: `Apply ${args.edits.length} edits to ${rel}?`,
72 });
73 if (dec.kind === 'reject') return { content: `[USER_REJECTED]`, isError: true };
74 if (dec.kind === 'revise') return reviseResult(rel);
75 content = dec.content; // may be the user-edited version from [E] Edit
76 } else {
77 emitEditDiff(ctx, rel, original, content);
78 }
79
80 await ctx.transaction.write(abs, content, { base: original, label: rel });
81
82 return { content: `Applied ${args.edits.length} edits to ${rel}` };

Callers

nothing calls this directly

Calls 5

confirmEditFunction · 0.85
reviseResultFunction · 0.85
resolveMethod · 0.80
evaluateMethod · 0.80
writeMethod · 0.45

Tested by

no test coverage detected