@clarvis/agent-tools 0.1.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 (116) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/CODE_OF_CONDUCT.md +117 -0
  3. package/CONTRIBUTING.md +78 -0
  4. package/LICENSE +21 -0
  5. package/README.md +203 -0
  6. package/SECURITY.md +58 -0
  7. package/SPEC.md +266 -0
  8. package/dist/config.d.ts +29 -0
  9. package/dist/config.d.ts.map +1 -0
  10. package/dist/config.js +145 -0
  11. package/dist/config.js.map +1 -0
  12. package/dist/core.d.ts +13 -0
  13. package/dist/core.d.ts.map +1 -0
  14. package/dist/core.js +43 -0
  15. package/dist/core.js.map +1 -0
  16. package/dist/errors.d.ts +9 -0
  17. package/dist/errors.d.ts.map +1 -0
  18. package/dist/errors.js +29 -0
  19. package/dist/errors.js.map +1 -0
  20. package/dist/index.d.ts +20 -0
  21. package/dist/index.d.ts.map +1 -0
  22. package/dist/index.js +17 -0
  23. package/dist/index.js.map +1 -0
  24. package/dist/lib/atomic.d.ts +11 -0
  25. package/dist/lib/atomic.d.ts.map +1 -0
  26. package/dist/lib/atomic.js +307 -0
  27. package/dist/lib/atomic.js.map +1 -0
  28. package/dist/lib/binary.d.ts +3 -0
  29. package/dist/lib/binary.d.ts.map +1 -0
  30. package/dist/lib/binary.js +20 -0
  31. package/dist/lib/binary.js.map +1 -0
  32. package/dist/lib/files.d.ts +9 -0
  33. package/dist/lib/files.d.ts.map +1 -0
  34. package/dist/lib/files.js +49 -0
  35. package/dist/lib/files.js.map +1 -0
  36. package/dist/lib/ignore.d.ts +5 -0
  37. package/dist/lib/ignore.d.ts.map +1 -0
  38. package/dist/lib/ignore.js +106 -0
  39. package/dist/lib/ignore.js.map +1 -0
  40. package/dist/lib/log.d.ts +4 -0
  41. package/dist/lib/log.d.ts.map +1 -0
  42. package/dist/lib/log.js +11 -0
  43. package/dist/lib/log.js.map +1 -0
  44. package/dist/lib/match-cascade.d.ts +10 -0
  45. package/dist/lib/match-cascade.d.ts.map +1 -0
  46. package/dist/lib/match-cascade.js +153 -0
  47. package/dist/lib/match-cascade.js.map +1 -0
  48. package/dist/lib/output.d.ts +8 -0
  49. package/dist/lib/output.d.ts.map +1 -0
  50. package/dist/lib/output.js +77 -0
  51. package/dist/lib/output.js.map +1 -0
  52. package/dist/lib/paths.d.ts +3 -0
  53. package/dist/lib/paths.d.ts.map +1 -0
  54. package/dist/lib/paths.js +46 -0
  55. package/dist/lib/paths.js.map +1 -0
  56. package/dist/lib/rg.d.ts +22 -0
  57. package/dist/lib/rg.d.ts.map +1 -0
  58. package/dist/lib/rg.js +285 -0
  59. package/dist/lib/rg.js.map +1 -0
  60. package/dist/lib/text.d.ts +18 -0
  61. package/dist/lib/text.d.ts.map +1 -0
  62. package/dist/lib/text.js +129 -0
  63. package/dist/lib/text.js.map +1 -0
  64. package/dist/lib/textfile.d.ts +4 -0
  65. package/dist/lib/textfile.d.ts.map +1 -0
  66. package/dist/lib/textfile.js +55 -0
  67. package/dist/lib/textfile.js.map +1 -0
  68. package/dist/lib/token.d.ts +2 -0
  69. package/dist/lib/token.d.ts.map +1 -0
  70. package/dist/lib/token.js +6 -0
  71. package/dist/lib/token.js.map +1 -0
  72. package/dist/tools/apply-patch.d.ts +3 -0
  73. package/dist/tools/apply-patch.d.ts.map +1 -0
  74. package/dist/tools/apply-patch.js +221 -0
  75. package/dist/tools/apply-patch.js.map +1 -0
  76. package/dist/tools/bash.d.ts +3 -0
  77. package/dist/tools/bash.d.ts.map +1 -0
  78. package/dist/tools/bash.js +179 -0
  79. package/dist/tools/bash.js.map +1 -0
  80. package/dist/tools/edit-file.d.ts +15 -0
  81. package/dist/tools/edit-file.d.ts.map +1 -0
  82. package/dist/tools/edit-file.js +163 -0
  83. package/dist/tools/edit-file.js.map +1 -0
  84. package/dist/tools/glob.d.ts +3 -0
  85. package/dist/tools/glob.d.ts.map +1 -0
  86. package/dist/tools/glob.js +64 -0
  87. package/dist/tools/glob.js.map +1 -0
  88. package/dist/tools/grep.d.ts +3 -0
  89. package/dist/tools/grep.d.ts.map +1 -0
  90. package/dist/tools/grep.js +201 -0
  91. package/dist/tools/grep.js.map +1 -0
  92. package/dist/tools/list-dir.d.ts +3 -0
  93. package/dist/tools/list-dir.d.ts.map +1 -0
  94. package/dist/tools/list-dir.js +59 -0
  95. package/dist/tools/list-dir.js.map +1 -0
  96. package/dist/tools/multi-edit.d.ts +3 -0
  97. package/dist/tools/multi-edit.d.ts.map +1 -0
  98. package/dist/tools/multi-edit.js +86 -0
  99. package/dist/tools/multi-edit.js.map +1 -0
  100. package/dist/tools/read-file.d.ts +3 -0
  101. package/dist/tools/read-file.d.ts.map +1 -0
  102. package/dist/tools/read-file.js +102 -0
  103. package/dist/tools/read-file.js.map +1 -0
  104. package/dist/tools/registry.d.ts +6 -0
  105. package/dist/tools/registry.d.ts.map +1 -0
  106. package/dist/tools/registry.js +28 -0
  107. package/dist/tools/registry.js.map +1 -0
  108. package/dist/tools/types.d.ts +9 -0
  109. package/dist/tools/types.d.ts.map +1 -0
  110. package/dist/tools/types.js +2 -0
  111. package/dist/tools/types.js.map +1 -0
  112. package/dist/tools/write-file.d.ts +3 -0
  113. package/dist/tools/write-file.d.ts.map +1 -0
  114. package/dist/tools/write-file.js +61 -0
  115. package/dist/tools/write-file.js.map +1 -0
  116. package/package.json +70 -0
@@ -0,0 +1,179 @@
1
+ import { spawn } from "node:child_process";
2
+ import { constants as osConstants } from "node:os";
3
+ import path from "node:path";
4
+ import { ToolError } from "../errors.js";
5
+ import { resolvePath, displayPath } from "../lib/paths.js";
6
+ import { statDirectory } from "../lib/files.js";
7
+ import { boundOrSpill, allocateBudget } from "../lib/output.js";
8
+ import { uniqueToken } from "../lib/token.js";
9
+ const MAX_CAPTURE_FLOOR = 8 * 1024 * 1024;
10
+ const STDIO_DRAIN_MS = 100;
11
+ const MAX_TIMER_DELAY_MS = 2_147_483_647;
12
+ function spillTarget(config, stream) {
13
+ const name = `bash-${uniqueToken()}.${stream}.log`;
14
+ const absPath = path.join(config.workspaceRoot, ".clarvis", name);
15
+ return { absPath, displayPath: displayPath(absPath, config.workspaceRoot) };
16
+ }
17
+ function computeExit(code, signal) {
18
+ if (code !== null)
19
+ return code;
20
+ const sigNum = signal ? (osConstants.signals[signal] ?? 0) : 0;
21
+ return signal ? 128 + sigNum : 0;
22
+ }
23
+ async function finalizeOutput(config, outText, errText) {
24
+ const [outBudget, errBudget] = allocateBudget(Buffer.byteLength(outText, "utf8"), Buffer.byteLength(errText, "utf8"), config.maxOutputBytes);
25
+ const [stdout, stderr] = await Promise.all([
26
+ boundOrSpill(outText, outBudget, spillTarget(config, "stdout")),
27
+ boundOrSpill(errText, errBudget, spillTarget(config, "stderr")),
28
+ ]);
29
+ return { stdout, stderr };
30
+ }
31
+ export const bash = {
32
+ name: "bash",
33
+ description: "Run a shell command (sh -c) and return stdout, stderr, and exit code. The command runs to " +
34
+ "completion and BLOCKS until it exits, so a long-lived process (a dev server, file watcher, " +
35
+ "`npm run dev`, `npm start`) MUST be started in the BACKGROUND with its output redirected — e.g. " +
36
+ "`npm start > /tmp/server.log 2>&1 &` — and then verified separately (sleep + curl the port, or " +
37
+ "read the log). A server left in the foreground will block until the timeout and waste the call.",
38
+ bounded: true,
39
+ inputSchema: {
40
+ type: "object",
41
+ properties: {
42
+ command: {
43
+ type: "string",
44
+ description: "Shell command, run via the system shell (sh -c). stdin is closed (no interactive " +
45
+ "prompts). A long-lived process MUST be backgrounded with output redirected (e.g. " +
46
+ "cmd > /tmp/out.log 2>&1 &) or it blocks until timeout.",
47
+ },
48
+ cwd: { type: "string", description: "Working directory. Default: workspace root." },
49
+ timeout_ms: {
50
+ type: "integer",
51
+ minimum: 1,
52
+ description: "Max run time in ms. Default: BASH_TIMEOUT_MS (120000); may be raised up to " +
53
+ "BASH_TIMEOUT_MAX_MS (600000) for a long build/test/install. On timeout the process " +
54
+ "group is killed and a timeout error is returned.",
55
+ },
56
+ },
57
+ required: ["command"],
58
+ additionalProperties: false,
59
+ },
60
+ async handler(args, config) {
61
+ const command = args.command;
62
+ const cwdArg = args.cwd;
63
+ const cwd = cwdArg
64
+ ? resolvePath(cwdArg, config.workspaceRoot, config.confineToWorkspace)
65
+ : config.workspaceRoot;
66
+ const requestedTimeoutMs = args.timeout_ms ?? config.bashTimeoutMs;
67
+ const timeoutMs = Math.min(requestedTimeoutMs, config.bashTimeoutMaxMs, MAX_TIMER_DELAY_MS);
68
+ await statDirectory(cwd, cwdArg ?? cwd);
69
+ return runCommand(command, cwd, timeoutMs, config);
70
+ },
71
+ };
72
+ function runCommand(command, cwd, timeoutMs, config) {
73
+ return new Promise((resolve, reject) => {
74
+ let child;
75
+ try {
76
+ child = spawn("sh", ["-c", command], {
77
+ cwd,
78
+ stdio: ["ignore", "pipe", "pipe"],
79
+ detached: true,
80
+ });
81
+ }
82
+ catch (err) {
83
+ reject(new ToolError("io_error", `Failed to spawn command: ${err.message}`));
84
+ return;
85
+ }
86
+ const captureCap = Math.max(config.maxOutputBytes, MAX_CAPTURE_FLOOR);
87
+ const stdoutSink = { text: "", bytes: 0, capped: false };
88
+ const stderrSink = { text: "", bytes: 0, capped: false };
89
+ let timedOut = false;
90
+ let outputLimited = false;
91
+ let settled = false;
92
+ let drainTimer;
93
+ const killGroup = () => {
94
+ try {
95
+ if (child.pid !== undefined)
96
+ process.kill(-child.pid, "SIGKILL");
97
+ }
98
+ catch {
99
+ child.kill("SIGKILL");
100
+ }
101
+ };
102
+ const onData = (sink) => (d) => {
103
+ if (sink.capped)
104
+ return;
105
+ sink.text += d;
106
+ sink.bytes += Buffer.byteLength(d, "utf8");
107
+ if (sink.bytes > captureCap) {
108
+ sink.capped = true;
109
+ if (!outputLimited) {
110
+ outputLimited = true;
111
+ killGroup();
112
+ }
113
+ }
114
+ };
115
+ child.stdout.setEncoding("utf8");
116
+ child.stderr.setEncoding("utf8");
117
+ child.stdout.on("data", onData(stdoutSink));
118
+ child.stderr.on("data", onData(stderrSink));
119
+ const timer = setTimeout(() => {
120
+ timedOut = true;
121
+ killGroup();
122
+ }, timeoutMs);
123
+ const teardown = () => {
124
+ child.stdout?.removeAllListeners("data");
125
+ child.stderr?.removeAllListeners("data");
126
+ child.stdout?.destroy();
127
+ child.stderr?.destroy();
128
+ child.unref();
129
+ };
130
+ const beginSettle = () => {
131
+ if (settled)
132
+ return false;
133
+ settled = true;
134
+ clearTimeout(timer);
135
+ if (drainTimer)
136
+ clearTimeout(drainTimer);
137
+ teardown();
138
+ return true;
139
+ };
140
+ const finish = (code, signal) => {
141
+ if (!beginSettle())
142
+ return;
143
+ void finalizeOutput(config, stdoutSink.text, stderrSink.text).then(({ stdout, stderr }) => {
144
+ if (timedOut) {
145
+ reject(new ToolError("timeout", `Command exceeded ${timeoutMs}ms`, {
146
+ timeout_ms: timeoutMs,
147
+ stdout,
148
+ stderr,
149
+ }));
150
+ return;
151
+ }
152
+ if (outputLimited) {
153
+ reject(new ToolError("output_limit", `Command output exceeded ${captureCap} bytes on a single stream and was killed`, { max_capture_bytes: captureCap, stdout, stderr }));
154
+ return;
155
+ }
156
+ resolve(JSON.stringify({
157
+ exit_code: computeExit(code, signal),
158
+ stdout,
159
+ stderr,
160
+ signal: signal ?? null,
161
+ timed_out: false,
162
+ }));
163
+ }, (err) => reject(new ToolError("io_error", `Failed to finalize output: ${err.message}`)));
164
+ };
165
+ child.on("error", (err) => {
166
+ if (!beginSettle())
167
+ return;
168
+ reject(new ToolError("io_error", `Failed to run command: ${err.message}`));
169
+ });
170
+ child.on("exit", (code, signal) => {
171
+ clearTimeout(timer);
172
+ if (drainTimer)
173
+ clearTimeout(drainTimer);
174
+ drainTimer = setTimeout(() => finish(code, signal), STDIO_DRAIN_MS);
175
+ });
176
+ child.on("close", (code, signal) => finish(code, signal));
177
+ });
178
+ }
179
+ //# sourceMappingURL=bash.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bash.js","sourceRoot":"","sources":["../../src/tools/bash.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { ServerConfig } from "../config.js";
2
+ import type { ToolDef } from "./types.js";
3
+ export declare function editFileLocked(target: string, relPath: string, config: ServerConfig, transform: (content: string) => string, message: (rel: string) => string): Promise<string>;
4
+ export interface EditSpec {
5
+ old_string: string;
6
+ new_string: string;
7
+ replace_all?: boolean;
8
+ }
9
+ export declare function applyEdit(text: string, spec: EditSpec): {
10
+ text: string;
11
+ count: number;
12
+ fuzzy: boolean;
13
+ };
14
+ export declare const editFile: ToolDef;
15
+ //# sourceMappingURL=edit-file.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edit-file.d.ts","sourceRoot":"","sources":["../../src/tools/edit-file.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,YAAY,EACpB,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,EACtC,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,GAC/B,OAAO,CAAC,MAAM,CAAC,CAejB;AAED,MAAM,WAAW,QAAQ;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAmDD,wBAAgB,SAAS,CACvB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,QAAQ,GACb;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CA2DjD;AAED,eAAO,MAAM,QAAQ,EAAE,OAuEtB,CAAC"}
@@ -0,0 +1,163 @@
1
+ import { ToolError } from "../errors.js";
2
+ import { resolvePath, displayPath } from "../lib/paths.js";
3
+ import { writeAtomic, withFileLock } from "../lib/atomic.js";
4
+ import { reencode } from "../lib/text.js";
5
+ import { readTextFile } from "../lib/textfile.js";
6
+ import { findCascadeMatch, scanLineBlocks, trimEnds } from "../lib/match-cascade.js";
7
+ export async function editFileLocked(target, relPath, config, transform, message) {
8
+ return withFileLock(target, async () => {
9
+ const decoded = await readTextFile(target, relPath, config.maxFileBytes);
10
+ if (decoded.encoding !== "utf8") {
11
+ throw new ToolError("is_binary", `Editing ${decoded.encoding} files is not supported (the file would be rewritten as ` +
12
+ `UTF-8): ${relPath}`, { path: relPath, encoding: decoded.encoding });
13
+ }
14
+ const newText = transform(decoded.content);
15
+ await writeAtomic(target, reencode(newText, decoded));
16
+ return message(displayPath(target, config.workspaceRoot));
17
+ });
18
+ }
19
+ function countOccurrences(haystack, needle) {
20
+ if (needle === "")
21
+ return 0;
22
+ let count = 0;
23
+ let idx = haystack.indexOf(needle);
24
+ while (idx !== -1) {
25
+ count++;
26
+ idx = haystack.indexOf(needle, idx + needle.length);
27
+ }
28
+ return count;
29
+ }
30
+ function occurrenceLines(text, needle, cap = 20) {
31
+ const lines = [];
32
+ let idx = text.indexOf(needle);
33
+ while (idx !== -1 && lines.length < cap) {
34
+ lines.push(text.slice(0, idx).split("\n").length);
35
+ idx = text.indexOf(needle, idx + needle.length);
36
+ }
37
+ return lines;
38
+ }
39
+ function diagnoseNoMatch(text, needle) {
40
+ if (needle === "")
41
+ return "";
42
+ const destripped = needle
43
+ .split("\n")
44
+ .map((l) => l.replace(/^\s*\d+\t/, ""))
45
+ .join("\n");
46
+ if (destripped !== needle && destripped !== "" && text.includes(destripped)) {
47
+ return (" It looks like old_string still contains read_file's line-number prefixes " +
48
+ '(e.g. " 12\\t"): drop them so old_string is only the file\'s own text.');
49
+ }
50
+ const hay = text.split("\n");
51
+ const need = needle.split("\n").map(trimEnds);
52
+ const hits = scanLineBlocks(hay, need, (a, b) => trimEnds(a) === b, 6).map((i) => i + 1);
53
+ if (hits.length > 0) {
54
+ const shown = hits.slice(0, 5).join(", ");
55
+ const where = hits.length === 1 ? `line ${shown}` : `lines ${shown}${hits.length > 5 ? ", …" : ""}`;
56
+ return (` The text is present at ${where} but its leading/trailing whitespace differs from ` +
57
+ "old_string. Re-read that region with read_file and copy the indentation verbatim.");
58
+ }
59
+ return "";
60
+ }
61
+ export function applyEdit(text, spec) {
62
+ if (spec.old_string === spec.new_string) {
63
+ throw new ToolError("invalid_input", "old_string and new_string are identical — nothing to change.");
64
+ }
65
+ const count = countOccurrences(text, spec.old_string);
66
+ if (count === 0) {
67
+ if (!spec.replace_all) {
68
+ const m = findCascadeMatch(text, spec.old_string);
69
+ if (m && m.spans.length === 1) {
70
+ const { start, end } = m.spans[0];
71
+ return {
72
+ text: text.slice(0, start) + spec.new_string + text.slice(end),
73
+ count: 1,
74
+ fuzzy: true,
75
+ };
76
+ }
77
+ if (m) {
78
+ const lines = m.spans.map((s) => text.slice(0, s.start).split("\n").length);
79
+ throw new ToolError("ambiguous_match", `old_string was not found exactly; after whitespace-tolerant matching it matched ` +
80
+ `${m.spans.length} regions (at lines ${lines.join(", ")}); it must be unique. Add ` +
81
+ "surrounding lines, or correct the whitespace so it matches one region exactly.", { lines });
82
+ }
83
+ }
84
+ throw new ToolError("no_match", "old_string not found. It must match the file byte-for-byte (whitespace, " +
85
+ "indentation, and line breaks included) and must NOT include the line-number " +
86
+ "prefixes shown by read_file. Re-read the exact region and copy the text verbatim." +
87
+ diagnoseNoMatch(text, spec.old_string));
88
+ }
89
+ if (count > 1 && !spec.replace_all) {
90
+ const lines = occurrenceLines(text, spec.old_string);
91
+ const at = lines.length > 0
92
+ ? ` (at line${lines.length === 1 ? "" : "s"} ${lines.join(", ")}${count > lines.length ? ", …" : ""})`
93
+ : "";
94
+ throw new ToolError("ambiguous_match", `old_string matched ${count} times${at}; it must be unique. Add surrounding lines to ` +
95
+ "make the match unique, or pass replace_all: true to replace every occurrence.");
96
+ }
97
+ if (spec.replace_all) {
98
+ return { text: text.split(spec.old_string).join(spec.new_string), count, fuzzy: false };
99
+ }
100
+ const idx = text.indexOf(spec.old_string);
101
+ return {
102
+ text: text.slice(0, idx) + spec.new_string + text.slice(idx + spec.old_string.length),
103
+ count: 1,
104
+ fuzzy: false,
105
+ };
106
+ }
107
+ export const editFile = {
108
+ name: "edit_file",
109
+ description: "Replace one exact occurrence of `old_string` with `new_string` in a file. `old_string` is " +
110
+ "matched LITERALLY (not a regex), exactly as read_file shows the text — including whitespace, " +
111
+ "indentation, and line breaks — but WITHOUT read_file's line-number/tab prefixes. The match " +
112
+ "MUST be unique: if it appears more than once the call fails (`ambiguous_match`) unless " +
113
+ "`replace_all` is set; if not found it fails (`no_match`). On failure, re-read the region and " +
114
+ "copy more surrounding lines verbatim, or set replace_all. For several edits to ONE file use " +
115
+ "multi_edit; to change MANY files use apply_patch.",
116
+ inputSchema: {
117
+ type: "object",
118
+ properties: {
119
+ path: {
120
+ type: "string",
121
+ description: "File to edit. Relative to workspace root or absolute. Must already exist and be text " +
122
+ "(binary is rejected).",
123
+ },
124
+ old_string: {
125
+ type: "string",
126
+ minLength: 1,
127
+ description: "Exact text to find. Copy it verbatim from read_file output with the line-number/tab " +
128
+ "prefix removed; whitespace, indentation, and newlines must match. Not a regex.",
129
+ },
130
+ new_string: {
131
+ type: "string",
132
+ description: "Replacement text. May be empty to delete the matched text. Must differ from old_string.",
133
+ },
134
+ replace_all: {
135
+ type: "boolean",
136
+ default: false,
137
+ description: "Replace every occurrence instead of requiring a single unique match. Default false.",
138
+ },
139
+ },
140
+ required: ["path", "old_string", "new_string"],
141
+ additionalProperties: false,
142
+ },
143
+ async handler(args, config) {
144
+ const target = resolvePath(args.path, config.workspaceRoot, config.confineToWorkspace);
145
+ let count = 0;
146
+ let fuzzy = false;
147
+ return editFileLocked(target, args.path, config, (content) => {
148
+ const r = applyEdit(content, {
149
+ old_string: args.old_string,
150
+ new_string: args.new_string,
151
+ replace_all: args.replace_all,
152
+ });
153
+ count = r.count;
154
+ fuzzy = r.fuzzy;
155
+ return r.text;
156
+ }, (rel) => fuzzy
157
+ ? `Replaced 1 occurrence in ${rel} (matched after a whitespace-tolerant search; the ` +
158
+ "matched region — including its leading indentation — was replaced by new_string " +
159
+ "verbatim, so re-read the file to verify the indentation is correct)."
160
+ : `Replaced ${count} ${count === 1 ? "occurrence" : "occurrences"} in ${rel}.`);
161
+ },
162
+ };
163
+ //# sourceMappingURL=edit-file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edit-file.js","sourceRoot":"","sources":["../../src/tools/edit-file.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { ToolDef } from "./types.js";
2
+ export declare const globTool: ToolDef;
3
+ //# sourceMappingURL=glob.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"glob.d.ts","sourceRoot":"","sources":["../../src/tools/glob.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,eAAO,MAAM,QAAQ,EAAE,OAgEtB,CAAC"}
@@ -0,0 +1,64 @@
1
+ import { promises as fs } from "node:fs";
2
+ import { ToolError } from "../errors.js";
3
+ import { resolvePath, displayPath } from "../lib/paths.js";
4
+ import { listFiles, mapLimit, statDirectory, STAT_CONCURRENCY } from "../lib/files.js";
5
+ export const globTool = {
6
+ name: "glob",
7
+ description: "Find files (not directories) by glob pattern, returned one path per line, " +
8
+ "most-recently-modified first. Use when you know part of a name or extension but not the full " +
9
+ "path. To search file CONTENTS use grep instead. No matches returns the line `(no matches)` — " +
10
+ "a success, not an error.",
11
+ inputSchema: {
12
+ type: "object",
13
+ properties: {
14
+ pattern: {
15
+ type: "string",
16
+ description: 'Glob pattern, e.g. "**/*.ts" or "src/**/test_*.py". ** matches across directories.',
17
+ },
18
+ path: {
19
+ type: "string",
20
+ description: "Base directory for the search. Relative to workspace root or absolute. Default: " +
21
+ "workspace root.",
22
+ },
23
+ respect_gitignore: {
24
+ type: "boolean",
25
+ default: true,
26
+ description: "When true (default), skip files ignored by .gitignore and the .git/ directory.",
27
+ },
28
+ },
29
+ required: ["pattern"],
30
+ additionalProperties: false,
31
+ },
32
+ async handler(args, config) {
33
+ const pattern = args.pattern;
34
+ const baseRel = args.path ?? ".";
35
+ const base = resolvePath(baseRel, config.workspaceRoot, config.confineToWorkspace);
36
+ const respectGitignore = args.respect_gitignore;
37
+ await statDirectory(base, baseRel);
38
+ let files;
39
+ try {
40
+ files = await listFiles(base, config.workspaceRoot, { pattern, respectGitignore });
41
+ }
42
+ catch (err) {
43
+ throw new ToolError("invalid_input", `Invalid glob pattern: ${err.message}`, {
44
+ pattern,
45
+ });
46
+ }
47
+ const stats = await mapLimit(files, STAT_CONCURRENCY, async (abs) => {
48
+ try {
49
+ return { abs, mtime: (await fs.stat(abs)).mtimeMs };
50
+ }
51
+ catch {
52
+ return null;
53
+ }
54
+ });
55
+ const withMtime = stats
56
+ .filter((s) => s !== null)
57
+ .map((s) => ({ rel: displayPath(s.abs, config.workspaceRoot), mtime: s.mtime }));
58
+ if (withMtime.length === 0)
59
+ return "(no matches)";
60
+ withMtime.sort((a, b) => b.mtime - a.mtime || (a.rel < b.rel ? -1 : 1));
61
+ return withMtime.map((e) => e.rel).join("\n");
62
+ },
63
+ };
64
+ //# sourceMappingURL=glob.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"glob.js","sourceRoot":"","sources":["../../src/tools/glob.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { ToolDef } from "./types.js";
2
+ export declare const grep: ToolDef;
3
+ //# sourceMappingURL=grep.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grep.d.ts","sourceRoot":"","sources":["../../src/tools/grep.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAiB1C,eAAO,MAAM,IAAI,EAAE,OA+HlB,CAAC"}