@nervekit/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 (267) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +5 -0
  3. package/dist/catalog/core/filesystem.tools.d.ts +140 -0
  4. package/dist/catalog/core/filesystem.tools.d.ts.map +1 -0
  5. package/dist/catalog/core/filesystem.tools.js +221 -0
  6. package/dist/catalog/core/filesystem.tools.js.map +1 -0
  7. package/dist/catalog/core/interaction.tools.d.ts +37 -0
  8. package/dist/catalog/core/interaction.tools.d.ts.map +1 -0
  9. package/dist/catalog/core/interaction.tools.js +55 -0
  10. package/dist/catalog/core/interaction.tools.js.map +1 -0
  11. package/dist/catalog/core/python.tools.d.ts +17 -0
  12. package/dist/catalog/core/python.tools.d.ts.map +1 -0
  13. package/dist/catalog/core/python.tools.js +32 -0
  14. package/dist/catalog/core/python.tools.js.map +1 -0
  15. package/dist/catalog/core/shell.tools.d.ts +14 -0
  16. package/dist/catalog/core/shell.tools.d.ts.map +1 -0
  17. package/dist/catalog/core/shell.tools.js +22 -0
  18. package/dist/catalog/core/shell.tools.js.map +1 -0
  19. package/dist/catalog/core/web.tools.d.ts +23 -0
  20. package/dist/catalog/core/web.tools.d.ts.map +1 -0
  21. package/dist/catalog/core/web.tools.js +34 -0
  22. package/dist/catalog/core/web.tools.js.map +1 -0
  23. package/dist/catalog/descriptors.d.ts +4 -0
  24. package/dist/catalog/descriptors.d.ts.map +1 -0
  25. package/dist/catalog/descriptors.js +17 -0
  26. package/dist/catalog/descriptors.js.map +1 -0
  27. package/dist/catalog/index.d.ts +18 -0
  28. package/dist/catalog/index.d.ts.map +1 -0
  29. package/dist/catalog/index.js +44 -0
  30. package/dist/catalog/index.js.map +1 -0
  31. package/dist/catalog/orchestration/explore.tools.d.ts +20 -0
  32. package/dist/catalog/orchestration/explore.tools.d.ts.map +1 -0
  33. package/dist/catalog/orchestration/explore.tools.js +42 -0
  34. package/dist/catalog/orchestration/explore.tools.js.map +1 -0
  35. package/dist/catalog/orchestration/plan-mode.tools.d.ts +32 -0
  36. package/dist/catalog/orchestration/plan-mode.tools.d.ts.map +1 -0
  37. package/dist/catalog/orchestration/plan-mode.tools.js +43 -0
  38. package/dist/catalog/orchestration/plan-mode.tools.js.map +1 -0
  39. package/dist/catalog/orchestration/process.tools.d.ts +68 -0
  40. package/dist/catalog/orchestration/process.tools.d.ts.map +1 -0
  41. package/dist/catalog/orchestration/process.tools.js +96 -0
  42. package/dist/catalog/orchestration/process.tools.js.map +1 -0
  43. package/dist/catalog/orchestration/subagent.tools.d.ts +16 -0
  44. package/dist/catalog/orchestration/subagent.tools.d.ts.map +1 -0
  45. package/dist/catalog/orchestration/subagent.tools.js +25 -0
  46. package/dist/catalog/orchestration/subagent.tools.js.map +1 -0
  47. package/dist/catalog/orchestration/task.tools.d.ts +107 -0
  48. package/dist/catalog/orchestration/task.tools.d.ts.map +1 -0
  49. package/dist/catalog/orchestration/task.tools.js +170 -0
  50. package/dist/catalog/orchestration/task.tools.js.map +1 -0
  51. package/dist/catalog/risk.d.ts +3 -0
  52. package/dist/catalog/risk.d.ts.map +1 -0
  53. package/dist/catalog/risk.js +29 -0
  54. package/dist/catalog/risk.js.map +1 -0
  55. package/dist/catalog/types.d.ts +14 -0
  56. package/dist/catalog/types.d.ts.map +1 -0
  57. package/dist/catalog/types.js +2 -0
  58. package/dist/catalog/types.js.map +1 -0
  59. package/dist/definitions.d.ts +2 -0
  60. package/dist/definitions.d.ts.map +1 -0
  61. package/dist/definitions.js +2 -0
  62. package/dist/definitions.js.map +1 -0
  63. package/dist/execution/atomic-write.d.ts +2 -0
  64. package/dist/execution/atomic-write.d.ts.map +1 -0
  65. package/dist/execution/atomic-write.js +7 -0
  66. package/dist/execution/atomic-write.js.map +1 -0
  67. package/dist/execution/bash.d.ts +3 -0
  68. package/dist/execution/bash.d.ts.map +1 -0
  69. package/dist/execution/bash.js +133 -0
  70. package/dist/execution/bash.js.map +1 -0
  71. package/dist/execution/common/args.d.ts +2 -0
  72. package/dist/execution/common/args.d.ts.map +1 -0
  73. package/dist/execution/common/args.js +6 -0
  74. package/dist/execution/common/args.js.map +1 -0
  75. package/dist/execution/common/output-budget.d.ts +61 -0
  76. package/dist/execution/common/output-budget.d.ts.map +1 -0
  77. package/dist/execution/common/output-budget.js +140 -0
  78. package/dist/execution/common/output-budget.js.map +1 -0
  79. package/dist/execution/common/process-result.d.ts +44 -0
  80. package/dist/execution/common/process-result.d.ts.map +1 -0
  81. package/dist/execution/common/process-result.js +322 -0
  82. package/dist/execution/common/process-result.js.map +1 -0
  83. package/dist/execution/common/search-utils.d.ts +8 -0
  84. package/dist/execution/common/search-utils.d.ts.map +1 -0
  85. package/dist/execution/common/search-utils.js +110 -0
  86. package/dist/execution/common/search-utils.js.map +1 -0
  87. package/dist/execution/common/tool-error.d.ts +8 -0
  88. package/dist/execution/common/tool-error.d.ts.map +1 -0
  89. package/dist/execution/common/tool-error.js +14 -0
  90. package/dist/execution/common/tool-error.js.map +1 -0
  91. package/dist/execution/common/truncate.d.ts +27 -0
  92. package/dist/execution/common/truncate.d.ts.map +1 -0
  93. package/dist/execution/common/truncate.js +108 -0
  94. package/dist/execution/common/truncate.js.map +1 -0
  95. package/dist/execution/common.d.ts +2 -0
  96. package/dist/execution/common.d.ts.map +1 -0
  97. package/dist/execution/common.js +6 -0
  98. package/dist/execution/common.js.map +1 -0
  99. package/dist/execution/core-dispatch.d.ts +4 -0
  100. package/dist/execution/core-dispatch.d.ts.map +1 -0
  101. package/dist/execution/core-dispatch.js +58 -0
  102. package/dist/execution/core-dispatch.js.map +1 -0
  103. package/dist/execution/dispatch.d.ts +4 -0
  104. package/dist/execution/dispatch.d.ts.map +1 -0
  105. package/dist/execution/dispatch.js +54 -0
  106. package/dist/execution/dispatch.js.map +1 -0
  107. package/dist/execution/edit.d.ts +9 -0
  108. package/dist/execution/edit.d.ts.map +1 -0
  109. package/dist/execution/edit.js +175 -0
  110. package/dist/execution/edit.js.map +1 -0
  111. package/dist/execution/file-mutation-queue.d.ts +2 -0
  112. package/dist/execution/file-mutation-queue.d.ts.map +1 -0
  113. package/dist/execution/file-mutation-queue.js +19 -0
  114. package/dist/execution/file-mutation-queue.js.map +1 -0
  115. package/dist/execution/filesystem/atomic-write.d.ts +2 -0
  116. package/dist/execution/filesystem/atomic-write.d.ts.map +1 -0
  117. package/dist/execution/filesystem/atomic-write.js +7 -0
  118. package/dist/execution/filesystem/atomic-write.js.map +1 -0
  119. package/dist/execution/filesystem/edit-args.d.ts +46 -0
  120. package/dist/execution/filesystem/edit-args.d.ts.map +1 -0
  121. package/dist/execution/filesystem/edit-args.js +212 -0
  122. package/dist/execution/filesystem/edit-args.js.map +1 -0
  123. package/dist/execution/filesystem/edit-errors.d.ts +4 -0
  124. package/dist/execution/filesystem/edit-errors.d.ts.map +1 -0
  125. package/dist/execution/filesystem/edit-errors.js +8 -0
  126. package/dist/execution/filesystem/edit-errors.js.map +1 -0
  127. package/dist/execution/filesystem/edit.d.ts +4 -0
  128. package/dist/execution/filesystem/edit.d.ts.map +1 -0
  129. package/dist/execution/filesystem/edit.js +330 -0
  130. package/dist/execution/filesystem/edit.js.map +1 -0
  131. package/dist/execution/filesystem/file-mutation-queue.d.ts +2 -0
  132. package/dist/execution/filesystem/file-mutation-queue.d.ts.map +1 -0
  133. package/dist/execution/filesystem/file-mutation-queue.js +19 -0
  134. package/dist/execution/filesystem/file-mutation-queue.js.map +1 -0
  135. package/dist/execution/filesystem/find.d.ts +3 -0
  136. package/dist/execution/filesystem/find.d.ts.map +1 -0
  137. package/dist/execution/filesystem/find.js +93 -0
  138. package/dist/execution/filesystem/find.js.map +1 -0
  139. package/dist/execution/filesystem/legacy-edit.d.ts +9 -0
  140. package/dist/execution/filesystem/legacy-edit.d.ts.map +1 -0
  141. package/dist/execution/filesystem/legacy-edit.js +122 -0
  142. package/dist/execution/filesystem/legacy-edit.js.map +1 -0
  143. package/dist/execution/filesystem/list.d.ts +3 -0
  144. package/dist/execution/filesystem/list.d.ts.map +1 -0
  145. package/dist/execution/filesystem/list.js +49 -0
  146. package/dist/execution/filesystem/list.js.map +1 -0
  147. package/dist/execution/filesystem/path.d.ts +7 -0
  148. package/dist/execution/filesystem/path.d.ts.map +1 -0
  149. package/dist/execution/filesystem/path.js +69 -0
  150. package/dist/execution/filesystem/path.js.map +1 -0
  151. package/dist/execution/filesystem/read.d.ts +3 -0
  152. package/dist/execution/filesystem/read.d.ts.map +1 -0
  153. package/dist/execution/filesystem/read.js +225 -0
  154. package/dist/execution/filesystem/read.js.map +1 -0
  155. package/dist/execution/filesystem/search.d.ts +3 -0
  156. package/dist/execution/filesystem/search.d.ts.map +1 -0
  157. package/dist/execution/filesystem/search.js +149 -0
  158. package/dist/execution/filesystem/search.js.map +1 -0
  159. package/dist/execution/filesystem/smart-match.d.ts +31 -0
  160. package/dist/execution/filesystem/smart-match.d.ts.map +1 -0
  161. package/dist/execution/filesystem/smart-match.js +309 -0
  162. package/dist/execution/filesystem/smart-match.js.map +1 -0
  163. package/dist/execution/filesystem/text-editing.d.ts +9 -0
  164. package/dist/execution/filesystem/text-editing.d.ts.map +1 -0
  165. package/dist/execution/filesystem/text-editing.js +43 -0
  166. package/dist/execution/filesystem/text-editing.js.map +1 -0
  167. package/dist/execution/filesystem/write.d.ts +3 -0
  168. package/dist/execution/filesystem/write.d.ts.map +1 -0
  169. package/dist/execution/filesystem/write.js +21 -0
  170. package/dist/execution/filesystem/write.js.map +1 -0
  171. package/dist/execution/find.d.ts +3 -0
  172. package/dist/execution/find.d.ts.map +1 -0
  173. package/dist/execution/find.js +90 -0
  174. package/dist/execution/find.js.map +1 -0
  175. package/dist/execution/index.d.ts +18 -0
  176. package/dist/execution/index.d.ts.map +1 -0
  177. package/dist/execution/index.js +17 -0
  178. package/dist/execution/index.js.map +1 -0
  179. package/dist/execution/list.d.ts +3 -0
  180. package/dist/execution/list.d.ts.map +1 -0
  181. package/dist/execution/list.js +46 -0
  182. package/dist/execution/list.js.map +1 -0
  183. package/dist/execution/path.d.ts +7 -0
  184. package/dist/execution/path.d.ts.map +1 -0
  185. package/dist/execution/path.js +69 -0
  186. package/dist/execution/path.js.map +1 -0
  187. package/dist/execution/python/python.d.ts +3 -0
  188. package/dist/execution/python/python.d.ts.map +1 -0
  189. package/dist/execution/python/python.js +566 -0
  190. package/dist/execution/python/python.js.map +1 -0
  191. package/dist/execution/python/runtime.d.ts +22 -0
  192. package/dist/execution/python/runtime.d.ts.map +1 -0
  193. package/dist/execution/python/runtime.js +178 -0
  194. package/dist/execution/python/runtime.js.map +1 -0
  195. package/dist/execution/read.d.ts +3 -0
  196. package/dist/execution/read.d.ts.map +1 -0
  197. package/dist/execution/read.js +97 -0
  198. package/dist/execution/read.js.map +1 -0
  199. package/dist/execution/search-utils.d.ts +8 -0
  200. package/dist/execution/search-utils.d.ts.map +1 -0
  201. package/dist/execution/search-utils.js +110 -0
  202. package/dist/execution/search-utils.js.map +1 -0
  203. package/dist/execution/search.d.ts +3 -0
  204. package/dist/execution/search.d.ts.map +1 -0
  205. package/dist/execution/search.js +131 -0
  206. package/dist/execution/search.js.map +1 -0
  207. package/dist/execution/shell/bash.d.ts +3 -0
  208. package/dist/execution/shell/bash.d.ts.map +1 -0
  209. package/dist/execution/shell/bash.js +134 -0
  210. package/dist/execution/shell/bash.js.map +1 -0
  211. package/dist/execution/truncate.d.ts +21 -0
  212. package/dist/execution/truncate.d.ts.map +1 -0
  213. package/dist/execution/truncate.js +94 -0
  214. package/dist/execution/truncate.js.map +1 -0
  215. package/dist/execution/web/web-fetch.d.ts +3 -0
  216. package/dist/execution/web/web-fetch.d.ts.map +1 -0
  217. package/dist/execution/web/web-fetch.js +132 -0
  218. package/dist/execution/web/web-fetch.js.map +1 -0
  219. package/dist/execution/web/web-search.d.ts +3 -0
  220. package/dist/execution/web/web-search.d.ts.map +1 -0
  221. package/dist/execution/web/web-search.js +59 -0
  222. package/dist/execution/web/web-search.js.map +1 -0
  223. package/dist/execution/web-fetch.d.ts +3 -0
  224. package/dist/execution/web-fetch.d.ts.map +1 -0
  225. package/dist/execution/web-fetch.js +132 -0
  226. package/dist/execution/web-fetch.js.map +1 -0
  227. package/dist/execution/web-search.d.ts +3 -0
  228. package/dist/execution/web-search.d.ts.map +1 -0
  229. package/dist/execution/web-search.js +59 -0
  230. package/dist/execution/web-search.js.map +1 -0
  231. package/dist/execution/write.d.ts +3 -0
  232. package/dist/execution/write.d.ts.map +1 -0
  233. package/dist/execution/write.js +21 -0
  234. package/dist/execution/write.js.map +1 -0
  235. package/dist/index.d.ts +9 -0
  236. package/dist/index.d.ts.map +1 -0
  237. package/dist/index.js +11 -0
  238. package/dist/index.js.map +1 -0
  239. package/dist/safety/command-policy-git.d.ts +2 -0
  240. package/dist/safety/command-policy-git.d.ts.map +1 -0
  241. package/dist/safety/command-policy-git.js +88 -0
  242. package/dist/safety/command-policy-git.js.map +1 -0
  243. package/dist/safety/command-policy-options.d.ts +6 -0
  244. package/dist/safety/command-policy-options.d.ts.map +1 -0
  245. package/dist/safety/command-policy-options.js +112 -0
  246. package/dist/safety/command-policy-options.js.map +1 -0
  247. package/dist/safety/command-policy-packages.d.ts +4 -0
  248. package/dist/safety/command-policy-packages.d.ts.map +1 -0
  249. package/dist/safety/command-policy-packages.js +161 -0
  250. package/dist/safety/command-policy-packages.js.map +1 -0
  251. package/dist/safety/command-policy-parser.d.ts +11 -0
  252. package/dist/safety/command-policy-parser.d.ts.map +1 -0
  253. package/dist/safety/command-policy-parser.js +121 -0
  254. package/dist/safety/command-policy-parser.js.map +1 -0
  255. package/dist/safety/command-policy-wrappers.d.ts +6 -0
  256. package/dist/safety/command-policy-wrappers.d.ts.map +1 -0
  257. package/dist/safety/command-policy-wrappers.js +95 -0
  258. package/dist/safety/command-policy-wrappers.js.map +1 -0
  259. package/dist/safety/command-policy.d.ts +6 -0
  260. package/dist/safety/command-policy.d.ts.map +1 -0
  261. package/dist/safety/command-policy.js +118 -0
  262. package/dist/safety/command-policy.js.map +1 -0
  263. package/dist/types.d.ts +78 -0
  264. package/dist/types.d.ts.map +1 -0
  265. package/dist/types.js +2 -0
  266. package/dist/types.js.map +1 -0
  267. package/package.json +48 -0
@@ -0,0 +1,93 @@
1
+ import { execFile } from "node:child_process";
2
+ import { stat } from "node:fs/promises";
3
+ import { relative } from "node:path";
4
+ import { promisify } from "node:util";
5
+ import { numberArg } from "../common/args.js";
6
+ import { boundText, FILE_OUTPUT_MAX_LINE_CHARS, textBoundaryDetails, } from "../common/output-budget.js";
7
+ import { globToRegExp, walkFiles } from "../common/search-utils.js";
8
+ import { isErrnoException, pathNotFoundMessage, resolveToolPath, } from "./path.js";
9
+ const execFileAsync = promisify(execFile);
10
+ export async function executeFind(args, context) {
11
+ if (typeof args.pattern !== "string" || args.pattern.length === 0) {
12
+ throw new Error("Tool argument 'pattern' must be a non-empty string.");
13
+ }
14
+ const input = args.path ?? ".";
15
+ const root = resolveToolPath(context.cwd, input);
16
+ await stat(root).catch((error) => {
17
+ if (isErrnoException(error) && error.code === "ENOENT") {
18
+ throw new Error(pathNotFoundMessage("find", input, root));
19
+ }
20
+ throw error;
21
+ });
22
+ const limit = Math.min(numberArg(args.limit, 1000), 5000);
23
+ const fd = await runFd(args.pattern, root, limit).catch(() => undefined);
24
+ const paths = fd ?? (await fallbackFind(root, args.pattern, limit));
25
+ const entries = paths
26
+ .slice(0, limit)
27
+ .map((path) => ({ path, kind: "file" }));
28
+ const formatted = formatFind(paths, limit);
29
+ return {
30
+ path: root,
31
+ entries,
32
+ content: formatted.content,
33
+ contentBlocks: [{ type: "text", text: formatted.content }],
34
+ details: formatted.details,
35
+ };
36
+ }
37
+ async function runFd(pattern, root, limit) {
38
+ const fdArgs = [
39
+ "--hidden",
40
+ "--glob",
41
+ "--type",
42
+ "file",
43
+ "--color=never",
44
+ "--no-require-git",
45
+ "--max-results",
46
+ String(limit),
47
+ ];
48
+ let effectivePattern = pattern;
49
+ if (pattern.includes("/")) {
50
+ fdArgs.push("--full-path");
51
+ if (!pattern.startsWith("/") && !pattern.startsWith("**/")) {
52
+ effectivePattern = `**/${pattern}`;
53
+ }
54
+ }
55
+ fdArgs.push("--", effectivePattern, root);
56
+ const { stdout } = await execFileAsync("fd", fdArgs, {
57
+ timeout: 30_000,
58
+ maxBuffer: 1024 * 1024,
59
+ });
60
+ return stdout
61
+ .split(/\r?\n/)
62
+ .map((line) => line.trim())
63
+ .filter(Boolean)
64
+ .map((path) => (relative(root, path) || path).replaceAll("\\", "/"));
65
+ }
66
+ async function fallbackFind(root, pattern, limit) {
67
+ const results = [];
68
+ const regex = globToRegExp(pattern);
69
+ await walkFiles(root, root, limit, async (_absolutePath, relativePath) => {
70
+ if (regex.test(relativePath))
71
+ results.push(relativePath.replaceAll("\\", "/"));
72
+ }, () => results.length >= limit);
73
+ return results;
74
+ }
75
+ function formatFind(paths, limit) {
76
+ const lines = paths.slice(0, limit);
77
+ if (lines.length === 0)
78
+ lines.push("No files found.");
79
+ if (paths.length >= limit) {
80
+ lines.push("", `[Result limit ${limit} reached. Increase limit or refine the pattern for more results.]`);
81
+ }
82
+ const bounded = boundText(lines.join("\n"), {
83
+ maxLines: Number.MAX_SAFE_INTEGER,
84
+ maxLineChars: FILE_OUTPUT_MAX_LINE_CHARS,
85
+ });
86
+ return {
87
+ content: bounded.text,
88
+ details: bounded.truncated
89
+ ? { truncation: textBoundaryDetails(bounded) }
90
+ : undefined,
91
+ };
92
+ }
93
+ //# sourceMappingURL=find.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"find.js","sourceRoot":"","sources":["../../../src/execution/filesystem/find.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { ToolExecutionContext, ToolExecutionResult } from "../../types.js";
2
+ type NormalizedLegacyEdit = {
3
+ oldText: string;
4
+ newText: string;
5
+ };
6
+ export declare function executeLegacyEdit(args: Record<string, unknown>, context: ToolExecutionContext): Promise<ToolExecutionResult>;
7
+ export declare function normalizeLegacyEditOperations(args: Record<string, unknown>): NormalizedLegacyEdit[];
8
+ export {};
9
+ //# sourceMappingURL=legacy-edit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"legacy-edit.d.ts","sourceRoot":"","sources":["../../../src/execution/filesystem/legacy-edit.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAahF,KAAK,oBAAoB,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAOjE,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,mBAAmB,CAAC,CAoD9B;AA2DD,wBAAgB,6BAA6B,CAC3C,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,oBAAoB,EAAE,CA2BxB"}
@@ -0,0 +1,122 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { writeTextFileAtomically } from "./atomic-write.js";
3
+ import { withFileMutationQueue } from "./file-mutation-queue.js";
4
+ import { resolveToolPath } from "./path.js";
5
+ import { detectLineEnding, firstChangedLine, generateDiffString, normalizeForTrimmedMatch, normalizeLineEndings, restoreLineEndings, } from "./text-editing.js";
6
+ export async function executeLegacyEdit(args, context) {
7
+ const path = resolveToolPath(context.cwd, args.path);
8
+ const edits = normalizeLegacyEditOperations(args);
9
+ return withFileMutationQueue(path, async () => {
10
+ const raw = await readFile(path, "utf8");
11
+ const bom = raw.startsWith("\uFEFF") ? "\uFEFF" : "";
12
+ const withoutBom = bom ? raw.slice(1) : raw;
13
+ const lineEnding = detectLineEnding(withoutBom);
14
+ const content = normalizeLineEndings(withoutBom);
15
+ const normalizedEdits = edits.map((edit) => ({
16
+ oldText: normalizeLineEndings(edit.oldText),
17
+ newText: normalizeLineEndings(edit.newText),
18
+ }));
19
+ const matches = normalizedEdits.map((edit, index) => findUniqueMatch(content, edit, index));
20
+ const ordered = [...matches].sort((a, b) => a.start - b.start);
21
+ for (let i = 1; i < ordered.length; i++) {
22
+ const previous = ordered[i - 1];
23
+ const current = ordered[i];
24
+ if (!previous || !current)
25
+ continue;
26
+ if (current.start < previous.end) {
27
+ throw new Error(`edits[${current.index}] overlaps edits[${previous.index}]; merge overlapping changes.`);
28
+ }
29
+ }
30
+ let updated = content;
31
+ for (const edit of [...ordered].reverse()) {
32
+ updated = `${updated.slice(0, edit.start)}${edit.newText}${updated.slice(edit.end)}`;
33
+ }
34
+ if (updated === content) {
35
+ throw new Error("Legacy edit would not change the file.");
36
+ }
37
+ const restored = bom + restoreLineEndings(updated, lineEnding);
38
+ await writeTextFileAtomically(path, restored);
39
+ const contentMessage = `Edited file with ${edits.length} replacement(s).`;
40
+ return {
41
+ path,
42
+ content: contentMessage,
43
+ contentBlocks: [{ type: "text", text: contentMessage }],
44
+ details: {
45
+ diff: generateDiffString(content, updated),
46
+ firstChangedLine: firstChangedLine(content, updated),
47
+ lineEnding,
48
+ bom: Boolean(bom),
49
+ },
50
+ };
51
+ });
52
+ }
53
+ function findUniqueMatch(content, edit, index) {
54
+ const first = content.indexOf(edit.oldText);
55
+ if (first >= 0) {
56
+ if (content.indexOf(edit.oldText, first + edit.oldText.length) >= 0) {
57
+ throw new Error(`edits[${index}].oldText matched more than once; provide a unique region.`);
58
+ }
59
+ return { ...edit, index, start: first, end: first + edit.oldText.length };
60
+ }
61
+ const fuzzy = fuzzyFind(content, edit.oldText);
62
+ if (!fuzzy)
63
+ throw new Error(`edits[${index}].oldText was not found.`);
64
+ if (fuzzy.duplicate) {
65
+ throw new Error(`edits[${index}].oldText matched more than once; provide a unique region.`);
66
+ }
67
+ return { ...edit, index, start: fuzzy.start, end: fuzzy.end };
68
+ }
69
+ function fuzzyFind(content, needle) {
70
+ const normalizedNeedle = normalizeForTrimmedMatch(needle);
71
+ const lines = content.split("\n");
72
+ const needleLineCount = needle.split("\n").length;
73
+ const matches = [];
74
+ const offsets = [];
75
+ let offset = 0;
76
+ for (const line of lines) {
77
+ offsets.push(offset);
78
+ offset += line.length + 1;
79
+ }
80
+ for (let line = 0; line < lines.length; line += 1) {
81
+ for (let count = Math.max(1, needleLineCount - 1); count <= needleLineCount + 1; count += 1) {
82
+ const chunk = lines.slice(line, line + count).join("\n");
83
+ if (normalizeForTrimmedMatch(chunk) !== normalizedNeedle)
84
+ continue;
85
+ const start = offsets[line] ?? 0;
86
+ const end = start + chunk.length;
87
+ matches.push({ start, end });
88
+ }
89
+ }
90
+ const first = matches[0];
91
+ if (!first)
92
+ return undefined;
93
+ return { ...first, duplicate: matches.length > 1 };
94
+ }
95
+ export function normalizeLegacyEditOperations(args) {
96
+ if (Array.isArray(args.edits)) {
97
+ if (args.edits.length === 0) {
98
+ throw new Error("Tool argument 'edits' must contain at least one edit.");
99
+ }
100
+ return args.edits.map((entry, index) => {
101
+ if (!entry || typeof entry !== "object") {
102
+ throw new Error(`edits[${index}] must be an object.`);
103
+ }
104
+ const edit = entry;
105
+ if (typeof edit.oldText !== "string" || edit.oldText.length === 0) {
106
+ throw new Error(`edits[${index}].oldText must be a non-empty string.`);
107
+ }
108
+ if (typeof edit.newText !== "string") {
109
+ throw new Error(`edits[${index}].newText must be a string.`);
110
+ }
111
+ return { oldText: edit.oldText, newText: edit.newText };
112
+ });
113
+ }
114
+ if (typeof args.oldText !== "string" || args.oldText.length === 0) {
115
+ throw new Error("Tool argument 'oldText' must be a non-empty string.");
116
+ }
117
+ if (typeof args.newText !== "string") {
118
+ throw new Error("Tool argument 'newText' must be a string.");
119
+ }
120
+ return [{ oldText: args.oldText, newText: args.newText }];
121
+ }
122
+ //# sourceMappingURL=legacy-edit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"legacy-edit.js","sourceRoot":"","sources":["../../../src/execution/filesystem/legacy-edit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,kBAAkB,EAClB,wBAAwB,EACxB,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,mBAAmB,CAAC;AAS3B,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,IAA6B,EAC7B,OAA6B;IAE7B,MAAM,IAAI,GAAG,eAAe,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IACrD,MAAM,KAAK,GAAG,6BAA6B,CAAC,IAAI,CAAC,CAAC;IAClD,OAAO,qBAAqB,CAAC,IAAI,EAAE,KAAK,IAAI,EAAE;QAC5C,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACzC,MAAM,GAAG,GAAG,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;QACrD,MAAM,UAAU,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;QAC5C,MAAM,UAAU,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAC;QAChD,MAAM,OAAO,GAAG,oBAAoB,CAAC,UAAU,CAAC,CAAC;QACjD,MAAM,eAAe,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAC3C,OAAO,EAAE,oBAAoB,CAAC,IAAI,CAAC,OAAO,CAAC;YAC3C,OAAO,EAAE,oBAAoB,CAAC,IAAI,CAAC,OAAO,CAAC;SAC5C,CAAC,CAAC,CAAC;QAEJ,MAAM,OAAO,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAClD,eAAe,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,CACtC,CAAC;QACF,MAAM,OAAO,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;QAC/D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACxC,MAAM,QAAQ,GAAG,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAChC,MAAM,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;YAC3B,IAAI,CAAC,QAAQ,IAAI,CAAC,OAAO;gBAAE,SAAS;YACpC,IAAI,OAAO,CAAC,KAAK,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC;gBACjC,MAAM,IAAI,KAAK,CACb,SAAS,OAAO,CAAC,KAAK,oBAAoB,QAAQ,CAAC,KAAK,+BAA+B,CACxF,CAAC;YACJ,CAAC;QACH,CAAC;QAED,IAAI,OAAO,GAAG,OAAO,CAAC;QACtB,KAAK,MAAM,IAAI,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC;YAC1C,OAAO,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACvF,CAAC;QACD,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;QAC5D,CAAC;QAED,MAAM,QAAQ,GAAG,GAAG,GAAG,kBAAkB,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;QAC/D,MAAM,uBAAuB,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QAC9C,MAAM,cAAc,GAAG,oBAAoB,KAAK,CAAC,MAAM,kBAAkB,CAAC;QAC1E,OAAO;YACL,IAAI;YACJ,OAAO,EAAE,cAAc;YACvB,aAAa,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC;YACvD,OAAO,EAAE;gBACP,IAAI,EAAE,kBAAkB,CAAC,OAAO,EAAE,OAAO,CAAC;gBAC1C,gBAAgB,EAAE,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC;gBACpD,UAAU;gBACV,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC;aAClB;SACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,eAAe,CACtB,OAAe,EACf,IAA0B,EAC1B,KAAa;IAEb,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC5C,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;QACf,IAAI,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;YACpE,MAAM,IAAI,KAAK,CACb,SAAS,KAAK,4DAA4D,CAC3E,CAAC;QACJ,CAAC;QACD,OAAO,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;IAC5E,CAAC;IAED,MAAM,KAAK,GAAG,SAAS,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IAC/C,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,SAAS,KAAK,0BAA0B,CAAC,CAAC;IACtE,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CACb,SAAS,KAAK,4DAA4D,CAC3E,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC;AAChE,CAAC;AAED,SAAS,SAAS,CAChB,OAAe,EACf,MAAc;IAEd,MAAM,gBAAgB,GAAG,wBAAwB,CAAC,MAAM,CAAC,CAAC;IAC1D,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,eAAe,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;IAClD,MAAM,OAAO,GAA0C,EAAE,CAAC;IAC1D,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACrB,MAAM,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;IAC5B,CAAC;IACD,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,KAAK,CAAC,MAAM,EAAE,IAAI,IAAI,CAAC,EAAE,CAAC;QAClD,KACE,IAAI,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,eAAe,GAAG,CAAC,CAAC,EAC5C,KAAK,IAAI,eAAe,GAAG,CAAC,EAC5B,KAAK,IAAI,CAAC,EACV,CAAC;YACD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACzD,IAAI,wBAAwB,CAAC,KAAK,CAAC,KAAK,gBAAgB;gBAAE,SAAS;YACnE,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACjC,MAAM,GAAG,GAAG,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC;YACjC,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;IACD,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACzB,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAC7B,OAAO,EAAE,GAAG,KAAK,EAAE,SAAS,EAAE,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;AACrD,CAAC;AAED,MAAM,UAAU,6BAA6B,CAC3C,IAA6B;IAE7B,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9B,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC5B,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;QAC3E,CAAC;QACD,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;YACrC,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;gBACxC,MAAM,IAAI,KAAK,CAAC,SAAS,KAAK,sBAAsB,CAAC,CAAC;YACxD,CAAC;YACD,MAAM,IAAI,GAAG,KAAgC,CAAC;YAC9C,IAAI,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAClE,MAAM,IAAI,KAAK,CAAC,SAAS,KAAK,uCAAuC,CAAC,CAAC;YACzE,CAAC;YACD,IAAI,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;gBACrC,MAAM,IAAI,KAAK,CAAC,SAAS,KAAK,6BAA6B,CAAC,CAAC;YAC/D,CAAC;YACD,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC;QAC1D,CAAC,CAAC,CAAC;IACL,CAAC;IAED,IAAI,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAClE,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;IACzE,CAAC;IACD,IAAI,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;QACrC,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;AAC5D,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { ToolExecutionContext, ToolExecutionResult } from "../../types.js";
2
+ export declare function executeLs(args: Record<string, unknown>, context: ToolExecutionContext): Promise<ToolExecutionResult>;
3
+ //# sourceMappingURL=list.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../src/execution/filesystem/list.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAahF,wBAAsB,SAAS,CAC7B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,mBAAmB,CAAC,CA8C9B"}
@@ -0,0 +1,49 @@
1
+ import { readdir, stat } from "node:fs/promises";
2
+ import { numberArg } from "../common/args.js";
3
+ import { boundText, FILE_OUTPUT_MAX_LINE_CHARS, textBoundaryDetails, } from "../common/output-budget.js";
4
+ import { isErrnoException, pathNotFoundMessage, resolveToolPath, } from "./path.js";
5
+ export async function executeLs(args, context) {
6
+ const input = args.path ?? ".";
7
+ const root = resolveToolPath(context.cwd, input);
8
+ const info = await stat(root).catch((error) => {
9
+ if (isErrnoException(error) && error.code === "ENOENT") {
10
+ throw new Error(pathNotFoundMessage("ls", input, root));
11
+ }
12
+ throw error;
13
+ });
14
+ if (!info.isDirectory())
15
+ throw new Error("ls path is not a directory.");
16
+ const limit = Math.min(numberArg(args.limit, 500), 5000);
17
+ const dirEntries = await readdir(root, { withFileTypes: true });
18
+ dirEntries.sort((a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase()));
19
+ const entries = [];
20
+ for (const entry of dirEntries.slice(0, limit)) {
21
+ entries.push({
22
+ path: `${entry.name}${entry.isDirectory() ? "/" : ""}`,
23
+ kind: entry.isDirectory()
24
+ ? "directory"
25
+ : entry.isFile()
26
+ ? "file"
27
+ : "other",
28
+ });
29
+ }
30
+ let content = entries.map((entry) => entry.path).join("\n");
31
+ if (dirEntries.length > entries.length) {
32
+ content += `${content ? "\n\n" : ""}[...${dirEntries.length - entries.length} more entries. Increase limit to see more.]`;
33
+ }
34
+ const bounded = boundText(content, {
35
+ maxLines: Number.MAX_SAFE_INTEGER,
36
+ maxLineChars: FILE_OUTPUT_MAX_LINE_CHARS,
37
+ });
38
+ content = bounded.text;
39
+ return {
40
+ path: root,
41
+ entries,
42
+ content,
43
+ contentBlocks: [{ type: "text", text: content }],
44
+ details: bounded.truncated
45
+ ? { truncation: textBoundaryDetails(bounded) }
46
+ : undefined,
47
+ };
48
+ }
49
+ //# sourceMappingURL=list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.js","sourceRoot":"","sources":["../../../src/execution/filesystem/list.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export declare function expandToolPathInput(input: string): string;
2
+ export declare function resolveToCwd(cwd: string, input: string): string;
3
+ export declare function resolveToolPath(cwd: string, input: unknown): string;
4
+ export declare function isErrnoException(error: unknown): error is NodeJS.ErrnoException;
5
+ export declare function pathNotFoundMessage(toolName: string, input: unknown, resolvedPath: string): string;
6
+ export declare function resolveReadPath(cwd: string, input: unknown): Promise<string>;
7
+ //# sourceMappingURL=path.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../../../src/execution/filesystem/path.ts"],"names":[],"mappings":"AAMA,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAQzD;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAG/D;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,CAKnE;AAED,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,MAAM,CAAC,cAAc,CAEhC;AAED,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,OAAO,EACd,YAAY,EAAE,MAAM,GACnB,MAAM,CAGR;AAED,wBAAsB,eAAe,CACnC,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,OAAO,GACb,OAAO,CAAC,MAAM,CAAC,CAOjB"}
@@ -0,0 +1,69 @@
1
+ import { access } from "node:fs/promises";
2
+ import { homedir } from "node:os";
3
+ import { isAbsolute, resolve } from "node:path";
4
+ const UNICODE_SPACES = /[\u00a0\u2007\u202f]/g;
5
+ export function expandToolPathInput(input) {
6
+ let path = input.trim().replace(UNICODE_SPACES, " ").normalize("NFC");
7
+ if (path.startsWith("@"))
8
+ path = path.slice(1);
9
+ if (path === "~")
10
+ return homedir();
11
+ if (path.startsWith("~/") || path.startsWith("~\\")) {
12
+ return resolve(homedir(), path.slice(2));
13
+ }
14
+ return path;
15
+ }
16
+ export function resolveToCwd(cwd, input) {
17
+ const expanded = expandToolPathInput(input);
18
+ return isAbsolute(expanded) ? resolve(expanded) : resolve(cwd, expanded);
19
+ }
20
+ export function resolveToolPath(cwd, input) {
21
+ if (typeof input !== "string" || input.trim().length === 0) {
22
+ throw new Error("Tool argument 'path' must be a non-empty string.");
23
+ }
24
+ return resolveToCwd(cwd, input);
25
+ }
26
+ export function isErrnoException(error) {
27
+ return error instanceof Error && "code" in error;
28
+ }
29
+ export function pathNotFoundMessage(toolName, input, resolvedPath) {
30
+ const label = typeof input === "string" ? JSON.stringify(input) : "path";
31
+ return `${toolName} path not found: ${label} (resolved to ${resolvedPath}).`;
32
+ }
33
+ export async function resolveReadPath(cwd, input) {
34
+ const initial = resolveToolPath(cwd, input);
35
+ const candidates = readPathCandidates(initial);
36
+ for (const candidate of candidates) {
37
+ if (await exists(candidate))
38
+ return candidate;
39
+ }
40
+ return initial;
41
+ }
42
+ function readPathCandidates(path) {
43
+ const variants = new Set([
44
+ path,
45
+ path.normalize("NFC"),
46
+ path.normalize("NFD"),
47
+ ]);
48
+ for (const value of [...variants]) {
49
+ variants.add(value.replace(UNICODE_SPACES, " "));
50
+ }
51
+ // macOS screenshots sometimes use narrow no-break spaces before AM/PM.
52
+ for (const value of [...variants]) {
53
+ variants.add(value.replace(/ ([AP]M)(\.[^./]+)?$/u, "\u202f$1$2"));
54
+ variants.add(value.replace(/\u202f([AP]M)(\.[^./]+)?$/u, " $1$2"));
55
+ variants.add(value.replace(/[’‘]/g, "'"));
56
+ variants.add(value.replace(/'/g, "’"));
57
+ }
58
+ return [...variants].filter((candidate) => candidate.length > 0);
59
+ }
60
+ async function exists(path) {
61
+ try {
62
+ await access(path);
63
+ return true;
64
+ }
65
+ catch {
66
+ return false;
67
+ }
68
+ }
69
+ //# sourceMappingURL=path.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path.js","sourceRoot":"","sources":["../../../src/execution/filesystem/path.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { ToolExecutionContext, ToolExecutionResult } from "../../types.js";
2
+ export declare function executeRead(args: Record<string, unknown>, context: ToolExecutionContext): Promise<ToolExecutionResult>;
3
+ //# sourceMappingURL=read.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read.d.ts","sourceRoot":"","sources":["../../../src/execution/filesystem/read.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAqDhF,wBAAsB,WAAW,CAC/B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,mBAAmB,CAAC,CA8F9B"}
@@ -0,0 +1,225 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { numberArg } from "../common/args.js";
3
+ import { boundText, FILE_OUTPUT_MAX_LINE_CHARS, textBoundaryDetails, } from "../common/output-budget.js";
4
+ import { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize, } from "../common/truncate.js";
5
+ import { isErrnoException, pathNotFoundMessage, resolveReadPath, } from "./path.js";
6
+ const PNG_SIGNATURE = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a];
7
+ const READ_BYTE_DEFAULT_LIMIT = FILE_OUTPUT_MAX_LINE_CHARS;
8
+ const READ_BYTE_MAX_LIMIT = FILE_OUTPUT_MAX_LINE_CHARS;
9
+ function startsWith(buffer, bytes) {
10
+ if (buffer.length < bytes.length)
11
+ return false;
12
+ return bytes.every((byte, index) => buffer[index] === byte);
13
+ }
14
+ function startsWithAscii(buffer, offset, text) {
15
+ if (buffer.length < offset + text.length)
16
+ return false;
17
+ for (let index = 0; index < text.length; index += 1) {
18
+ if (buffer[offset + index] !== text.charCodeAt(index))
19
+ return false;
20
+ }
21
+ return true;
22
+ }
23
+ function detectSupportedImageMimeType(buffer) {
24
+ if (startsWith(buffer, [0xff, 0xd8, 0xff]))
25
+ return "image/jpeg";
26
+ if (startsWith(buffer, PNG_SIGNATURE))
27
+ return "image/png";
28
+ if (startsWithAscii(buffer, 0, "GIF"))
29
+ return "image/gif";
30
+ if (startsWithAscii(buffer, 0, "RIFF") &&
31
+ startsWithAscii(buffer, 8, "WEBP")) {
32
+ return "image/webp";
33
+ }
34
+ return null;
35
+ }
36
+ export async function executeRead(args, context) {
37
+ const path = await resolveReadPath(context.cwd, args.path);
38
+ const buffer = await readFile(path).catch((error) => {
39
+ if (isErrnoException(error) && error.code === "ENOENT") {
40
+ throw new Error(pathNotFoundMessage("read", args.path, path));
41
+ }
42
+ throw error;
43
+ });
44
+ const hasByteOffset = typeof args.byteOffset === "number";
45
+ const hasByteLimit = typeof args.byteLimit === "number";
46
+ const hasByteRange = hasByteOffset || hasByteLimit;
47
+ const hasExplicitLimit = typeof args.limit === "number";
48
+ const hasExplicitOffset = typeof args.offset === "number";
49
+ if (hasByteRange && (hasExplicitLimit || hasExplicitOffset)) {
50
+ throw new Error("Use either line arguments ('offset'/'limit') or byte arguments ('byteOffset'/'byteLimit'), not both.");
51
+ }
52
+ const mimeType = detectSupportedImageMimeType(buffer);
53
+ if (mimeType && !hasByteRange) {
54
+ const content = `Read image file [${mimeType}]`;
55
+ return {
56
+ path,
57
+ content,
58
+ contentBlocks: [
59
+ { type: "text", text: content },
60
+ { type: "image", data: buffer.toString("base64"), mimeType },
61
+ ],
62
+ };
63
+ }
64
+ if (hasByteRange)
65
+ return readByteRange(path, buffer, args);
66
+ const content = buffer.toString("utf8");
67
+ const lines = content.split(/\r?\n/);
68
+ const offset = numberArg(args.offset, 1);
69
+ if (hasExplicitLimit || hasExplicitOffset) {
70
+ const limit = Math.min(numberArg(args.limit, 1000), 5000);
71
+ const start = Math.max(0, offset - 1);
72
+ const selected = lines.slice(start, start + limit).join("\n");
73
+ const remaining = Math.max(0, lines.length - (start + limit));
74
+ const bounded = boundFileText(selected, { maxLines: limit });
75
+ const messages = [];
76
+ if (bounded.truncated) {
77
+ messages.push(formatSelectedRangeTruncation(bounded));
78
+ }
79
+ if (remaining > 0) {
80
+ messages.push(bounded.truncated
81
+ ? `[...${remaining} more lines remain after the requested range. Narrow this read range before continuing past it.]`
82
+ : `[...${remaining} more lines. Continue with offset ${offset + limit}.]`);
83
+ }
84
+ const output = [bounded.text, ...messages]
85
+ .filter((part) => part.length > 0)
86
+ .join("\n\n");
87
+ const wasTruncated = bounded.truncated || remaining > 0;
88
+ return {
89
+ path,
90
+ content: output,
91
+ contentBlocks: [{ type: "text", text: output }],
92
+ details: wasTruncated
93
+ ? {
94
+ truncation: {
95
+ ...textBoundaryDetails(bounded),
96
+ truncated: true,
97
+ omittedLines: bounded.omittedLines + remaining,
98
+ nextOffset: !bounded.truncated && remaining > 0
99
+ ? offset + limit
100
+ : undefined,
101
+ },
102
+ }
103
+ : undefined,
104
+ };
105
+ }
106
+ const bounded = boundFileText(content, { maxLines: DEFAULT_MAX_LINES });
107
+ let output = bounded.text;
108
+ if (bounded.truncated) {
109
+ output += `\n\n[...output truncated to ${DEFAULT_MAX_LINES} lines, ${formatSize(DEFAULT_MAX_BYTES)}, or ${FILE_OUTPUT_MAX_LINE_CHARS} characters per line.${formatContinuationGuidance(bounded)}]`;
110
+ }
111
+ return {
112
+ path,
113
+ content: output,
114
+ contentBlocks: [{ type: "text", text: output }],
115
+ details: bounded.truncated
116
+ ? { truncation: textBoundaryDetails(bounded) }
117
+ : undefined,
118
+ };
119
+ }
120
+ function readByteRange(path, buffer, args) {
121
+ const requestedOffset = Math.min(numberArg(args.byteOffset, 0), buffer.length);
122
+ const requestedLimit = positiveIntegerArg(args.byteLimit, READ_BYTE_DEFAULT_LIMIT, READ_BYTE_MAX_LIMIT);
123
+ const requestedEnd = Math.min(buffer.length, requestedOffset + requestedLimit);
124
+ const slice = safeUtf8Slice(buffer, requestedOffset, requestedEnd);
125
+ const bounded = boundText(slice.text, {
126
+ maxBytes: requestedLimit,
127
+ maxLines: Number.MAX_SAFE_INTEGER,
128
+ maxLineChars: requestedLimit,
129
+ });
130
+ const nextByteOffset = requestedEnd < buffer.length ? requestedEnd : undefined;
131
+ const messages = [];
132
+ if (bounded.truncated) {
133
+ messages.push(formatByteRangeTruncation(bounded));
134
+ }
135
+ if (nextByteOffset !== undefined) {
136
+ messages.push(`[...${formatSize(buffer.length - requestedEnd)} remain after this byte range. Continue with byteOffset ${nextByteOffset}.]`);
137
+ }
138
+ const output = [bounded.text, ...messages]
139
+ .filter((part) => part.length > 0)
140
+ .join("\n\n");
141
+ return {
142
+ path,
143
+ content: output,
144
+ contentBlocks: [{ type: "text", text: output }],
145
+ details: {
146
+ byteOffset: requestedOffset,
147
+ byteLimit: requestedLimit,
148
+ actualByteOffset: slice.start,
149
+ actualByteEnd: slice.end,
150
+ size: buffer.length,
151
+ nextByteOffset,
152
+ truncation: bounded.truncated ? textBoundaryDetails(bounded) : undefined,
153
+ },
154
+ };
155
+ }
156
+ function boundFileText(text, options) {
157
+ return boundText(text, {
158
+ maxLines: options.maxLines,
159
+ maxBytes: DEFAULT_MAX_BYTES,
160
+ maxLineChars: FILE_OUTPUT_MAX_LINE_CHARS,
161
+ });
162
+ }
163
+ function countLines(text) {
164
+ if (text.length === 0)
165
+ return 0;
166
+ return text.split("\n").length;
167
+ }
168
+ function formatSelectedRangeTruncation(truncation) {
169
+ const omissions = formatOmissions(truncation);
170
+ const guidance = truncation.partialLine || truncation.truncatedLines > 0
171
+ ? " Use byteOffset/byteLimit to inspect overlong lines exactly."
172
+ : "";
173
+ return `[...selected output truncated to ${formatSize(DEFAULT_MAX_BYTES)} or ${FILE_OUTPUT_MAX_LINE_CHARS} characters per line${omissions}.${guidance}]`;
174
+ }
175
+ function formatByteRangeTruncation(truncation) {
176
+ const omissions = formatOmissions(truncation);
177
+ return `[...byte range output truncated${omissions}. Use a smaller byteLimit to inspect this range.]`;
178
+ }
179
+ function formatContinuationGuidance(truncation) {
180
+ if (truncation.partialLine || truncation.truncatedLines > 0) {
181
+ return " Use byteOffset/byteLimit to inspect overlong lines exactly.";
182
+ }
183
+ return ` Continue reading with offset ${countLines(truncation.text) + 1}.`;
184
+ }
185
+ function formatOmissions(truncation) {
186
+ const parts = [];
187
+ if (truncation.truncatedLines > 0) {
188
+ parts.push(`${truncation.truncatedLines} overlong line${truncation.truncatedLines === 1 ? "" : "s"}`);
189
+ }
190
+ if (truncation.omittedLines > 0) {
191
+ parts.push(`${truncation.omittedLines} omitted line${truncation.omittedLines === 1 ? "" : "s"}`);
192
+ }
193
+ if (truncation.omittedBytes > 0) {
194
+ parts.push(`${formatSize(truncation.omittedBytes)} omitted`);
195
+ }
196
+ return parts.length > 0 ? ` (${parts.join(", ")})` : "";
197
+ }
198
+ function positiveIntegerArg(value, fallback, max) {
199
+ const number = numberArg(value, fallback);
200
+ if (number <= 0)
201
+ return fallback;
202
+ return Math.min(number, max);
203
+ }
204
+ function safeUtf8Slice(buffer, start, end) {
205
+ let safeStart = Math.max(0, Math.min(start, buffer.length));
206
+ let safeEnd = Math.max(safeStart, Math.min(end, buffer.length));
207
+ while (safeStart < safeEnd &&
208
+ isUtf8ContinuationByte(buffer[safeStart] ?? 0)) {
209
+ safeStart += 1;
210
+ }
211
+ while (safeEnd > safeStart &&
212
+ safeEnd < buffer.length &&
213
+ isUtf8ContinuationByte(buffer[safeEnd] ?? 0)) {
214
+ safeEnd -= 1;
215
+ }
216
+ return {
217
+ text: buffer.subarray(safeStart, safeEnd).toString("utf8"),
218
+ start: safeStart,
219
+ end: safeEnd,
220
+ };
221
+ }
222
+ function isUtf8ContinuationByte(byte) {
223
+ return (byte & 0xc0) === 0x80;
224
+ }
225
+ //# sourceMappingURL=read.js.map