@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,201 @@
1
+ import { resolvePath, displayPath } from "../lib/paths.js";
2
+ import { bound } from "../lib/output.js";
3
+ import { countNewlines } from "../lib/text.js";
4
+ import { grepSearch } from "../lib/rg.js";
5
+ export const grep = {
6
+ name: "grep",
7
+ description: "Search file CONTENTS by regular expression, recursively (ripgrep-backed when available, else " +
8
+ "an equivalent JS fallback). Use this to find where text or a symbol appears — do NOT read " +
9
+ "whole files with read_file to look for a string. .gitignore and binary files are skipped. No " +
10
+ "matches returns `(no matches)` — a success, not an error.",
11
+ bounded: true,
12
+ inputSchema: {
13
+ type: "object",
14
+ properties: {
15
+ pattern: {
16
+ type: "string",
17
+ description: "Regular expression (ripgrep / Rust regex syntax). Escape regex metacharacters to match " +
18
+ "them literally.",
19
+ },
20
+ path: {
21
+ type: "string",
22
+ description: "File or directory to search. Relative to workspace root or absolute. Default: " +
23
+ "workspace root.",
24
+ },
25
+ glob: {
26
+ type: "string",
27
+ description: 'Restrict the search to files matching this glob, e.g. "*.ts".',
28
+ },
29
+ output_mode: {
30
+ type: "string",
31
+ enum: ["content", "files_with_matches", "count"],
32
+ default: "files_with_matches",
33
+ description: 'What to return: "files_with_matches" (default) lists matching file paths; "content" ' +
34
+ 'lists matching lines as path:line:text; "count" lists path:match_count per file.',
35
+ },
36
+ ignore_case: {
37
+ type: "boolean",
38
+ default: false,
39
+ description: "Case-insensitive matching. Default false.",
40
+ },
41
+ multiline: {
42
+ type: "boolean",
43
+ default: false,
44
+ description: "Match across line boundaries (ripgrep --multiline --multiline-dotall). When true, `.` " +
45
+ "also matches newlines and `^`/`$` anchor at line boundaries, so one match may span " +
46
+ "multiple lines. Applies in all output modes. Default false.",
47
+ },
48
+ context: {
49
+ type: "integer",
50
+ minimum: 0,
51
+ default: 0,
52
+ description: "Lines of context on BOTH sides of each match (shorthand for before_context and " +
53
+ "after_context). Applies to content mode only. Default 0.",
54
+ },
55
+ before_context: {
56
+ type: "integer",
57
+ minimum: 0,
58
+ description: "Lines of context BEFORE each match (ripgrep -B); overrides `context` for the before " +
59
+ "side. Content mode only.",
60
+ },
61
+ after_context: {
62
+ type: "integer",
63
+ minimum: 0,
64
+ description: "Lines of context AFTER each match (ripgrep -A); overrides `context` for the after " +
65
+ "side. Content mode only.",
66
+ },
67
+ head_limit: {
68
+ type: "integer",
69
+ minimum: 1,
70
+ description: "Max number of results to return — files in files_with_matches/count modes, matches in " +
71
+ "content mode. Omit for unlimited (output is still byte-bounded). Page by re-running " +
72
+ "with offset advanced per the footer.",
73
+ },
74
+ offset: {
75
+ type: "integer",
76
+ minimum: 0,
77
+ default: 0,
78
+ description: "Number of leading results to skip (0-based). Re-run with a higher offset to page. " +
79
+ "Note: this is a result offset, not read_file's 1-based line offset.",
80
+ },
81
+ },
82
+ required: ["pattern"],
83
+ additionalProperties: false,
84
+ },
85
+ async handler(args, config) {
86
+ const mode = args.output_mode;
87
+ const ctx = mode === "content" ? args.context : 0;
88
+ const before = mode === "content" ? (args.before_context ?? ctx) : 0;
89
+ const after = mode === "content" ? (args.after_context ?? ctx) : 0;
90
+ const offset = args.offset;
91
+ const headLimit = args.head_limit;
92
+ const multiline = args.multiline;
93
+ const searchRoot = resolvePath(args.path ?? ".", config.workspaceRoot, config.confineToWorkspace);
94
+ const { matches, truncated } = await grepSearch({
95
+ pattern: args.pattern,
96
+ searchRoot,
97
+ glob: args.glob,
98
+ ignoreCase: args.ignore_case,
99
+ before,
100
+ after,
101
+ multiline,
102
+ }, config);
103
+ const { rendered, unitTotal, shownUnits } = format(matches, mode, config, {
104
+ before,
105
+ after,
106
+ offset,
107
+ headLimit,
108
+ });
109
+ return composeResult(rendered, config, { truncated, unitTotal, shownUnits, offset });
110
+ },
111
+ };
112
+ function paginate(items, offset, headLimit) {
113
+ const end = headLimit === undefined ? items.length : offset + headLimit;
114
+ return items.slice(offset, end);
115
+ }
116
+ function format(matches, mode, config, opts) {
117
+ if (matches.length === 0)
118
+ return { rendered: "(no matches)", unitTotal: 0, shownUnits: 0 };
119
+ if (mode === "files_with_matches") {
120
+ const files = [
121
+ ...new Set(matches
122
+ .filter((m) => m.kind === "match")
123
+ .map((m) => displayPath(m.file, config.workspaceRoot))),
124
+ ].sort();
125
+ const page = paginate(files, opts.offset, opts.headLimit);
126
+ return { rendered: page.join("\n"), unitTotal: files.length, shownUnits: page.length };
127
+ }
128
+ if (mode === "count") {
129
+ const counts = new Map();
130
+ for (const m of matches) {
131
+ if (m.kind !== "match")
132
+ continue;
133
+ const f = displayPath(m.file, config.workspaceRoot);
134
+ counts.set(f, (counts.get(f) ?? 0) + 1);
135
+ }
136
+ const entries = [...counts.entries()]
137
+ .sort((a, b) => (a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0))
138
+ .map(([f, c]) => `${f}:${c}`);
139
+ const page = paginate(entries, opts.offset, opts.headLimit);
140
+ return { rendered: page.join("\n"), unitTotal: entries.length, shownUnits: page.length };
141
+ }
142
+ return formatContent(matches, config, opts);
143
+ }
144
+ function formatContent(matches, config, opts) {
145
+ const rows = matches
146
+ .map((m) => ({ ...m, f: displayPath(m.file, config.workspaceRoot) }))
147
+ .sort((a, b) => (a.f < b.f ? -1 : a.f > b.f ? 1 : a.lineNumber - b.lineNumber));
148
+ const anchors = rows.filter((r) => r.kind === "match");
149
+ const pageAnchors = paginate(anchors, opts.offset, opts.headLimit);
150
+ const keep = new Set();
151
+ for (const a of pageAnchors) {
152
+ const endLine = a.lineNumber + countNewlines(a.text);
153
+ keep.add(`${a.f}\0${a.lineNumber}`);
154
+ for (let d = 1; d <= opts.before; d++)
155
+ keep.add(`${a.f}\0${a.lineNumber - d}`);
156
+ for (let d = 1; d <= opts.after; d++)
157
+ keep.add(`${a.f}\0${endLine + d}`);
158
+ }
159
+ const hasContext = opts.before > 0 || opts.after > 0;
160
+ const out = [];
161
+ let prevFile = null;
162
+ let prevLine = -2;
163
+ for (const r of rows) {
164
+ if (!keep.has(`${r.f}\0${r.lineNumber}`))
165
+ continue;
166
+ if (hasContext && prevFile !== null && (r.f !== prevFile || r.lineNumber > prevLine + 1)) {
167
+ if (out.length > 0)
168
+ out.push("--");
169
+ }
170
+ const sep = r.kind === "match" ? ":" : "-";
171
+ out.push(`${r.f}${sep}${r.lineNumber}${sep}${r.text}`);
172
+ prevFile = r.f;
173
+ prevLine = r.lineNumber + countNewlines(r.text);
174
+ }
175
+ return { rendered: out.join("\n"), unitTotal: anchors.length, shownUnits: pageAnchors.length };
176
+ }
177
+ function composeResult(rendered, config, state) {
178
+ const { truncated, unitTotal, shownUnits, offset } = state;
179
+ const bounded = bound(rendered, config.maxOutputBytes);
180
+ if (truncated) {
181
+ const warning = "[... search incomplete: the scan hit its output cap; some matching files were not scanned. " +
182
+ "Narrow the pattern, path, or glob for complete results. ...]";
183
+ if (unitTotal === 0)
184
+ return warning;
185
+ return `${bounded}\n${warning}`;
186
+ }
187
+ if (unitTotal === 0)
188
+ return bounded;
189
+ if (offset >= unitTotal) {
190
+ return `(no results at offset ${offset}; ${unitTotal} total)`;
191
+ }
192
+ if (Buffer.byteLength(rendered, "utf8") > config.maxOutputBytes) {
193
+ return `${bounded}\n[... page exceeded ${config.maxOutputBytes} bytes and was cut; set or reduce head_limit to page in smaller chunks ...]`;
194
+ }
195
+ const nextOffset = offset + shownUnits;
196
+ if (nextOffset < unitTotal) {
197
+ return `${bounded}\n[... showing ${offset}..${nextOffset} of ${unitTotal}; call again with offset=${nextOffset} for more ...]`;
198
+ }
199
+ return bounded;
200
+ }
201
+ //# sourceMappingURL=grep.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grep.js","sourceRoot":"","sources":["../../src/tools/grep.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { ToolDef } from "./types.js";
2
+ export declare const listDir: ToolDef;
3
+ //# sourceMappingURL=list-dir.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-dir.d.ts","sourceRoot":"","sources":["../../src/tools/list-dir.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,eAAO,MAAM,OAAO,EAAE,OAuDrB,CAAC"}
@@ -0,0 +1,59 @@
1
+ import { promises as fs } from "node:fs";
2
+ import path from "node:path";
3
+ import { fsError } from "../errors.js";
4
+ import { resolvePath } from "../lib/paths.js";
5
+ import { mapLimit, statDirectory, STAT_CONCURRENCY } from "../lib/files.js";
6
+ export const listDir = {
7
+ name: "list_dir",
8
+ description: "List the immediate entries of one directory (non-recursive). Directories first, then files; " +
9
+ "directories end with `/` and files show a byte size. Includes dotfiles; does NOT apply " +
10
+ ".gitignore. To match files by pattern across subdirectories use glob; to search file contents " +
11
+ "use grep.",
12
+ inputSchema: {
13
+ type: "object",
14
+ properties: {
15
+ path: {
16
+ type: "string",
17
+ description: "Directory to list. Relative to workspace root or absolute. Default: workspace root.",
18
+ },
19
+ },
20
+ required: [],
21
+ additionalProperties: false,
22
+ },
23
+ async handler(args, config) {
24
+ const rel = args.path ?? ".";
25
+ const target = resolvePath(rel, config.workspaceRoot, config.confineToWorkspace);
26
+ await statDirectory(target, rel);
27
+ let entries;
28
+ try {
29
+ entries = await fs.readdir(target, { withFileTypes: true });
30
+ }
31
+ catch (err) {
32
+ throw fsError(err, rel);
33
+ }
34
+ const items = await mapLimit(entries, STAT_CONCURRENCY, async (e) => {
35
+ let isDir = e.isDirectory();
36
+ let size = 0;
37
+ if (!isDir || e.isSymbolicLink()) {
38
+ try {
39
+ const st = await fs.stat(path.join(target, e.name));
40
+ isDir = st.isDirectory();
41
+ size = st.size;
42
+ }
43
+ catch {
44
+ isDir = false;
45
+ }
46
+ }
47
+ return { name: e.name, isDir, size };
48
+ });
49
+ items.sort((a, b) => {
50
+ if (a.isDir !== b.isDir)
51
+ return a.isDir ? -1 : 1;
52
+ return a.name < b.name ? -1 : a.name > b.name ? 1 : 0;
53
+ });
54
+ if (items.length === 0)
55
+ return "(empty directory)";
56
+ return items.map((it) => (it.isDir ? `${it.name}/` : `${it.name}\t${it.size}`)).join("\n");
57
+ },
58
+ };
59
+ //# sourceMappingURL=list-dir.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-dir.js","sourceRoot":"","sources":["../../src/tools/list-dir.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { ToolDef } from "./types.js";
2
+ export declare const multiEdit: ToolDef;
3
+ //# sourceMappingURL=multi-edit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"multi-edit.d.ts","sourceRoot":"","sources":["../../src/tools/multi-edit.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,eAAO,MAAM,SAAS,EAAE,OA8FvB,CAAC"}
@@ -0,0 +1,86 @@
1
+ import { ToolError } from "../errors.js";
2
+ import { resolvePath } from "../lib/paths.js";
3
+ import { applyEdit, editFileLocked } from "./edit-file.js";
4
+ export const multiEdit = {
5
+ name: "multi_edit",
6
+ description: "Apply several edit_file-style replacements to ONE file in a single atomic call. Edits run in " +
7
+ "order; each operates on the text produced by the previous one. Every edit follows edit_file's " +
8
+ "rules (literal match, unique unless replace_all). If any edit fails, NOTHING is written and " +
9
+ "the error names the failing edit index. Use this instead of repeated edit_file calls to the " +
10
+ "same file; to change MANY files use apply_patch.",
11
+ inputSchema: {
12
+ type: "object",
13
+ properties: {
14
+ path: {
15
+ type: "string",
16
+ description: "File to edit. Relative to workspace root or absolute. Must already exist and be text.",
17
+ },
18
+ edits: {
19
+ type: "array",
20
+ minItems: 1,
21
+ description: "Ordered list of replacements, applied in sequence to this one file. At least one.",
22
+ items: {
23
+ type: "object",
24
+ properties: {
25
+ old_string: {
26
+ type: "string",
27
+ minLength: 1,
28
+ description: "Exact text to find, verbatim and without read_file's line-number prefixes. " +
29
+ "Matched against the result of the previous edit. Not a regex.",
30
+ },
31
+ new_string: {
32
+ type: "string",
33
+ description: "Replacement text. May be empty to delete. Must differ from old_string.",
34
+ },
35
+ replace_all: {
36
+ type: "boolean",
37
+ default: false,
38
+ description: "Replace every occurrence of this edit's old_string instead of requiring a " +
39
+ "unique match. Default false.",
40
+ },
41
+ },
42
+ required: ["old_string", "new_string"],
43
+ additionalProperties: false,
44
+ },
45
+ },
46
+ },
47
+ required: ["path", "edits"],
48
+ additionalProperties: false,
49
+ },
50
+ async handler(args, config) {
51
+ const target = resolvePath(args.path, config.workspaceRoot, config.confineToWorkspace);
52
+ const edits = args.edits;
53
+ let fuzzyCount = 0;
54
+ return editFileLocked(target, args.path, config, (content) => {
55
+ let text = content;
56
+ for (let i = 0; i < edits.length; i++) {
57
+ const spec = edits[i];
58
+ if (spec === undefined)
59
+ continue;
60
+ try {
61
+ const r = applyEdit(text, spec);
62
+ text = r.text;
63
+ if (r.fuzzy)
64
+ fuzzyCount++;
65
+ }
66
+ catch (err) {
67
+ if (err instanceof ToolError) {
68
+ throw new ToolError(err.code, `edit[${i}]: ${err.message}`, {
69
+ ...err.fields,
70
+ index: i,
71
+ });
72
+ }
73
+ throw err;
74
+ }
75
+ }
76
+ return text;
77
+ }, (rel) => {
78
+ const base = `Applied ${edits.length} ${edits.length === 1 ? "edit" : "edits"} to ${rel}.`;
79
+ return fuzzyCount > 0
80
+ ? `${base} (${fuzzyCount} matched after a whitespace-tolerant search; each such region ` +
81
+ "— including its leading indentation — was replaced verbatim, so re-read to verify.)"
82
+ : base;
83
+ });
84
+ },
85
+ };
86
+ //# sourceMappingURL=multi-edit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"multi-edit.js","sourceRoot":"","sources":["../../src/tools/multi-edit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { ToolDef } from "./types.js";
2
+ export declare const readFile: ToolDef;
3
+ //# sourceMappingURL=read-file.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read-file.d.ts","sourceRoot":"","sources":["../../src/tools/read-file.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAe1C,eAAO,MAAM,QAAQ,EAAE,OA+FtB,CAAC"}
@@ -0,0 +1,102 @@
1
+ import { ToolError } from "../errors.js";
2
+ import { resolvePath } from "../lib/paths.js";
3
+ import { splitLines } from "../lib/text.js";
4
+ import { readTextFile } from "../lib/textfile.js";
5
+ const MAX_LINE = 2000;
6
+ const DEFAULT_LIMIT = 2000;
7
+ const LINE_TRUNC = " [... line truncated ...]";
8
+ function capBytes(content, maxBytes) {
9
+ if (Buffer.byteLength(content, "utf8") <= maxBytes)
10
+ return content;
11
+ const room = Math.max(0, maxBytes - Buffer.byteLength(LINE_TRUNC, "utf8"));
12
+ const buf = Buffer.from(content, "utf8");
13
+ let end = Math.min(room, buf.length);
14
+ while (end > 0 && ((buf[end] ?? 0) & 0xc0) === 0x80)
15
+ end--;
16
+ return buf.subarray(0, end).toString("utf8") + LINE_TRUNC;
17
+ }
18
+ export const readFile = {
19
+ name: "read_file",
20
+ description: "Read a UTF-8 text file, returned with 1-indexed line-number prefixes (like `cat -n`). Reads " +
21
+ "up to 2000 lines from `offset`; if more remain, a footer gives the next `offset` to continue " +
22
+ "from. NEVER use to search large files for a string — use grep. If you do not know the path, " +
23
+ "use glob or list_dir first. Binary files are rejected.",
24
+ bounded: true,
25
+ inputSchema: {
26
+ type: "object",
27
+ properties: {
28
+ path: {
29
+ type: "string",
30
+ description: "File to read. Relative to workspace root or absolute (~ is not expanded).",
31
+ },
32
+ offset: {
33
+ type: "integer",
34
+ description: "1-indexed first line to read. Default 1. A negative value counts from the end (e.g. " +
35
+ "-10 reads the last 10 lines); 0 is invalid. A positive offset must be <= the file's " +
36
+ "line count.",
37
+ },
38
+ limit: {
39
+ type: "integer",
40
+ minimum: 1,
41
+ description: "Max number of lines to return. Default 2000. Page through a long file by repeating " +
42
+ "with offset advanced per the footer.",
43
+ },
44
+ },
45
+ required: ["path"],
46
+ additionalProperties: false,
47
+ },
48
+ async handler(args, config) {
49
+ const relPath = args.path;
50
+ const target = resolvePath(relPath, config.workspaceRoot, config.confineToWorkspace);
51
+ const offset = args.offset ?? 1;
52
+ const limit = args.limit ?? DEFAULT_LIMIT;
53
+ const text = (await readTextFile(target, relPath, config.maxFileBytes)).content;
54
+ if (text === "")
55
+ return "(empty file)";
56
+ const lines = splitLines(text);
57
+ const total = lines.length;
58
+ if (offset === 0) {
59
+ throw new ToolError("invalid_input", "offset must be non-zero: use a positive 1-indexed line, or a negative tail offset.", { path: relPath });
60
+ }
61
+ let start1;
62
+ if (offset < 0) {
63
+ start1 = Math.max(1, total + offset + 1);
64
+ }
65
+ else {
66
+ if (total > 0 && offset > total) {
67
+ throw new ToolError("invalid_input", `offset ${offset} exceeds file line count ${total}; read from offset 1..${total}`, { path: relPath, line_count: total });
68
+ }
69
+ start1 = offset;
70
+ }
71
+ const start = start1 - 1;
72
+ const hardEnd = Math.min(total, start + limit);
73
+ const out = [];
74
+ let used = 0;
75
+ let end = start;
76
+ for (let i = start; i < hardEnd; i++) {
77
+ let content = lines[i] ?? "";
78
+ if (content.length > MAX_LINE) {
79
+ let cut = MAX_LINE;
80
+ const code = content.charCodeAt(cut - 1);
81
+ if (code >= 0xd800 && code <= 0xdbff)
82
+ cut -= 1;
83
+ content = content.slice(0, cut) + LINE_TRUNC;
84
+ }
85
+ const prefix = `${String(i + 1).padStart(6)}\t`;
86
+ content = capBytes(content, config.maxOutputBytes - Buffer.byteLength(prefix, "utf8") - 1);
87
+ const row = prefix + content;
88
+ const rowBytes = Buffer.byteLength(row, "utf8") + 1;
89
+ if (i > start && used + rowBytes > config.maxOutputBytes)
90
+ break;
91
+ out.push(row);
92
+ used += rowBytes;
93
+ end = i + 1;
94
+ }
95
+ if (end < total) {
96
+ const shown = end - start;
97
+ out.push(`[... ${shown} of ${total} lines shown; continue with offset=${end + 1} ...]`);
98
+ }
99
+ return out.join("\n");
100
+ },
101
+ };
102
+ //# sourceMappingURL=read-file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read-file.js","sourceRoot":"","sources":["../../src/tools/read-file.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { ToolDef } from "./types.js";
2
+ export declare const tools: ToolDef[];
3
+ export declare const readOnlyTools: ToolDef[];
4
+ export declare function selectSurface(readOnly: boolean): ToolDef[];
5
+ export declare function getTool(name: string, surface?: ToolDef[]): ToolDef | undefined;
6
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/tools/registry.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,eAAO,MAAM,KAAK,EAAE,OAAO,EAU1B,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,OAAO,EAAwC,CAAC;AAE5E,wBAAgB,aAAa,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,EAAE,CAE1D;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,OAAO,EAAU,GAAG,OAAO,GAAG,SAAS,CAErF"}
@@ -0,0 +1,28 @@
1
+ import { readFile } from "./read-file.js";
2
+ import { writeFile } from "./write-file.js";
3
+ import { editFile } from "./edit-file.js";
4
+ import { multiEdit } from "./multi-edit.js";
5
+ import { applyPatchTool } from "./apply-patch.js";
6
+ import { listDir } from "./list-dir.js";
7
+ import { globTool } from "./glob.js";
8
+ import { grep } from "./grep.js";
9
+ import { bash } from "./bash.js";
10
+ export const tools = [
11
+ readFile,
12
+ writeFile,
13
+ editFile,
14
+ multiEdit,
15
+ applyPatchTool,
16
+ listDir,
17
+ globTool,
18
+ grep,
19
+ bash,
20
+ ];
21
+ export const readOnlyTools = [readFile, listDir, globTool, grep];
22
+ export function selectSurface(readOnly) {
23
+ return readOnly ? readOnlyTools : tools;
24
+ }
25
+ export function getTool(name, surface = tools) {
26
+ return surface.find((t) => t.name === name);
27
+ }
28
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/tools/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC,MAAM,CAAC,MAAM,KAAK,GAAc;IAC9B,QAAQ;IACR,SAAS;IACT,QAAQ;IACR,SAAS;IACT,cAAc;IACd,OAAO;IACP,QAAQ;IACR,IAAI;IACJ,IAAI;CACL,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAc,CAAC,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;AAE5E,MAAM,UAAU,aAAa,CAAC,QAAiB;IAC7C,OAAO,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC;AAC1C,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,IAAY,EAAE,UAAqB,KAAK;IAC9D,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;AAC9C,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { ServerConfig } from "../config.js";
2
+ export interface ToolDef {
3
+ name: string;
4
+ description: string;
5
+ inputSchema: Record<string, unknown>;
6
+ bounded?: boolean;
7
+ handler: (args: Record<string, unknown>, config: ServerConfig) => Promise<string>;
8
+ }
9
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/tools/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IAEpB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAErC,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,YAAY,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CACnF"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/tools/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ import type { ToolDef } from "./types.js";
2
+ export declare const writeFile: ToolDef;
3
+ //# sourceMappingURL=write-file.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write-file.d.ts","sourceRoot":"","sources":["../../src/tools/write-file.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,eAAO,MAAM,SAAS,EAAE,OAuDvB,CAAC"}