-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathedit.ts
More file actions
60 lines (57 loc) · 2.03 KB
/
Copy pathedit.ts
File metadata and controls
60 lines (57 loc) · 2.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import { capsOf } from "../capabilities/index.js";
import type { ToolDefinition } from "../types.js";
interface EditInput {
path: string;
old_string: string;
new_string: string;
replace_all?: boolean;
}
export const editTool: ToolDefinition<EditInput, string> = {
name: "edit",
description:
"Replace exact text in an existing file. `old_string` must match the file content verbatim (whitespace included). " +
"By default it must match exactly once; pass `replace_all: true` to replace every occurrence (useful for renames). " +
"Use `read` first to see the exact text to match.",
inputSchema: {
type: "object",
properties: {
path: { type: "string" },
old_string: { type: "string" },
new_string: { type: "string" },
replace_all: { type: "boolean", default: false },
},
required: ["path", "old_string", "new_string"],
},
async execute(input, ctx) {
if (input.old_string === input.new_string) {
throw new Error("old_string and new_string are identical");
}
const { fs } = capsOf(ctx);
const abs = fs.resolvePath(ctx.cwd, input.path);
const original = await fs.readFile(abs);
const occurrences = countOccurrences(original, input.old_string);
if (occurrences === 0) {
throw new Error(`old_string not found in ${abs}`);
}
if (occurrences > 1 && !input.replace_all) {
throw new Error(
`old_string matches ${occurrences} places. Pass replace_all:true or add more context to match exactly once.`,
);
}
const updated = input.replace_all
? original.split(input.old_string).join(input.new_string)
: original.replace(input.old_string, input.new_string);
await fs.writeFile(abs, updated);
return `Edited ${abs}: ${input.replace_all ? occurrences : 1} replacement(s).`;
},
};
function countOccurrences(haystack: string, needle: string): number {
if (!needle) return 0;
let count = 0;
let idx = 0;
while ((idx = haystack.indexOf(needle, idx)) !== -1) {
count++;
idx += needle.length;
}
return count;
}