@datename/fastcode-termux 0.1.6 → 0.1.8-beta.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 (303) hide show
  1. package/LICENSE +4 -0
  2. package/README.md +67 -16
  3. package/dist/agent/approval-json.d.ts +43 -0
  4. package/dist/agent/approval-json.js +69 -0
  5. package/dist/agent/approval-native.d.ts +3 -0
  6. package/dist/agent/approval-native.js +165 -0
  7. package/dist/agent/approval-store.d.ts +16 -0
  8. package/dist/agent/approval-store.js +21 -0
  9. package/dist/agent/approval.d.ts +83 -0
  10. package/dist/agent/approval.js +42 -0
  11. package/dist/agent/compaction.d.ts +41 -0
  12. package/dist/agent/compaction.js +270 -0
  13. package/dist/agent/context.d.ts +29 -0
  14. package/dist/agent/context.js +62 -0
  15. package/dist/agent/guards.d.ts +24 -16
  16. package/dist/agent/guards.js +1167 -18
  17. package/dist/agent/ignore.d.ts +11 -0
  18. package/dist/agent/ignore.js +129 -0
  19. package/dist/agent/policy/defaults.d.ts +16 -0
  20. package/dist/agent/policy/defaults.js +17 -0
  21. package/dist/agent/policy/egress.d.ts +32 -0
  22. package/dist/agent/policy/egress.js +280 -0
  23. package/dist/agent/process-tree.d.ts +22 -0
  24. package/dist/agent/process-tree.js +102 -0
  25. package/dist/agent/protocol-mode.d.ts +6 -0
  26. package/dist/agent/protocol-mode.js +51 -0
  27. package/dist/agent/protocol.d.ts +20 -1
  28. package/dist/agent/protocol.js +169 -39
  29. package/dist/agent/registry.d.ts +19 -0
  30. package/dist/agent/registry.js +247 -0
  31. package/dist/agent/runner.d.ts +127 -0
  32. package/dist/agent/runner.js +391 -0
  33. package/dist/agent/shell-ast.d.ts +11 -0
  34. package/dist/agent/shell-ast.js +204 -0
  35. package/dist/agent/shell-session.d.ts +51 -0
  36. package/dist/agent/shell-session.js +611 -0
  37. package/dist/agent/stream.d.ts +29 -0
  38. package/dist/agent/stream.js +103 -0
  39. package/dist/agent/tool-schemas.d.ts +2 -0
  40. package/dist/agent/tool-schemas.js +82 -0
  41. package/dist/agent/tools/append_file.d.ts +2 -0
  42. package/dist/agent/tools/append_file.js +28 -0
  43. package/dist/agent/tools/apply_patch.d.ts +10 -0
  44. package/dist/agent/tools/apply_patch.js +92 -0
  45. package/dist/agent/tools/copy_file.d.ts +2 -0
  46. package/dist/agent/tools/copy_file.js +53 -0
  47. package/dist/agent/tools/delete_file.d.ts +2 -0
  48. package/dist/agent/tools/delete_file.js +43 -0
  49. package/dist/agent/tools/grep.d.ts +2 -0
  50. package/dist/agent/tools/grep.js +54 -0
  51. package/dist/agent/tools/index.d.ts +2 -0
  52. package/dist/agent/tools/index.js +32 -0
  53. package/dist/agent/tools/list_files.d.ts +2 -0
  54. package/dist/agent/tools/list_files.js +17 -0
  55. package/dist/agent/tools/make_dir.d.ts +2 -0
  56. package/dist/agent/tools/make_dir.js +26 -0
  57. package/dist/agent/tools/move_path.d.ts +9 -0
  58. package/dist/agent/tools/move_path.js +73 -0
  59. package/dist/agent/tools/paths.d.ts +7 -0
  60. package/dist/agent/tools/paths.js +84 -0
  61. package/dist/agent/tools/pwd.d.ts +2 -0
  62. package/dist/agent/tools/pwd.js +10 -0
  63. package/dist/agent/tools/read_file.d.ts +2 -0
  64. package/dist/agent/tools/read_file.js +81 -0
  65. package/dist/agent/tools/read_many.d.ts +2 -0
  66. package/dist/agent/tools/read_many.js +43 -0
  67. package/dist/agent/tools/readers.d.ts +58 -0
  68. package/dist/agent/tools/readers.js +426 -0
  69. package/dist/agent/tools/replace_in_file.d.ts +2 -0
  70. package/dist/agent/tools/replace_in_file.js +63 -0
  71. package/dist/agent/tools/shell.d.ts +2 -0
  72. package/dist/agent/tools/shell.js +48 -0
  73. package/dist/agent/tools/stat_path.d.ts +2 -0
  74. package/dist/agent/tools/stat_path.js +31 -0
  75. package/dist/agent/tools/types.d.ts +65 -0
  76. package/dist/agent/tools/types.js +1 -0
  77. package/dist/agent/tools/validate.d.ts +19 -0
  78. package/dist/agent/tools/validate.js +92 -0
  79. package/dist/agent/tools/write_file.d.ts +2 -0
  80. package/dist/agent/tools/write_file.js +28 -0
  81. package/dist/agent/tools.d.ts +3 -1
  82. package/dist/agent/tools.js +2 -377
  83. package/dist/app.d.ts +2 -1
  84. package/dist/app.js +846 -173
  85. package/dist/cli-main.js +363 -0
  86. package/dist/cli.js +444 -333
  87. package/dist/commands/about.js +1 -1
  88. package/dist/commands/attach.d.ts +9 -0
  89. package/dist/commands/attach.js +15 -0
  90. package/dist/commands/bg.d.ts +7 -0
  91. package/dist/commands/bg.js +9 -0
  92. package/dist/commands/cancel.d.ts +10 -0
  93. package/dist/commands/cancel.js +10 -0
  94. package/dist/commands/clear.d.ts +1 -0
  95. package/dist/commands/clear.js +1 -1
  96. package/dist/commands/compact.d.ts +22 -0
  97. package/dist/commands/compact.js +34 -0
  98. package/dist/commands/context.d.ts +7 -0
  99. package/dist/commands/context.js +25 -0
  100. package/dist/commands/edit.d.ts +10 -0
  101. package/dist/commands/edit.js +36 -0
  102. package/dist/commands/effort.d.ts +25 -0
  103. package/dist/commands/effort.js +48 -0
  104. package/dist/commands/expand.d.ts +10 -0
  105. package/dist/commands/expand.js +8 -0
  106. package/dist/commands/index.js +24 -0
  107. package/dist/commands/jobs.d.ts +7 -0
  108. package/dist/commands/jobs.js +17 -0
  109. package/dist/commands/kill.d.ts +7 -0
  110. package/dist/commands/kill.js +13 -0
  111. package/dist/commands/login.d.ts +6 -4
  112. package/dist/commands/login.js +24 -22
  113. package/dist/commands/logout.js +8 -16
  114. package/dist/commands/model.d.ts +1 -0
  115. package/dist/commands/model.js +10 -22
  116. package/dist/commands/provider.d.ts +1 -2
  117. package/dist/commands/provider.js +4 -11
  118. package/dist/commands/skills.js +34 -4
  119. package/dist/commands/steer.d.ts +11 -0
  120. package/dist/commands/steer.js +13 -0
  121. package/dist/commands/threads.d.ts +9 -0
  122. package/dist/commands/threads.js +26 -0
  123. package/dist/commands/whoami.js +6 -5
  124. package/dist/config/store.d.ts +53 -12
  125. package/dist/config/store.js +163 -73
  126. package/dist/config/trust.d.ts +30 -8
  127. package/dist/config/trust.js +139 -14
  128. package/dist/headless.d.ts +7 -0
  129. package/dist/headless.js +213 -0
  130. package/dist/index.js +19 -3
  131. package/dist/lib/debug.d.ts +2 -0
  132. package/dist/lib/debug.js +22 -0
  133. package/dist/lib/diagnostics.d.ts +48 -4
  134. package/dist/lib/diagnostics.js +90 -8
  135. package/dist/lib/highlight-subset.d.ts +21 -0
  136. package/dist/lib/highlight-subset.js +88 -0
  137. package/dist/lib/http.d.ts +11 -1
  138. package/dist/lib/http.js +62 -4
  139. package/dist/lib/lifecycle.d.ts +5 -0
  140. package/dist/lib/lifecycle.js +62 -0
  141. package/dist/lib/markdown.js +22 -4
  142. package/dist/lib/model-meta.d.ts +19 -0
  143. package/dist/lib/model-meta.js +113 -0
  144. package/dist/lib/native-tools.d.ts +12 -0
  145. package/dist/lib/native-tools.js +21 -0
  146. package/dist/lib/net.d.ts +33 -0
  147. package/dist/lib/net.js +168 -0
  148. package/dist/patch/apply.d.ts +15 -0
  149. package/dist/patch/apply.js +172 -0
  150. package/dist/patch/parse.d.ts +29 -0
  151. package/dist/patch/parse.js +112 -0
  152. package/dist/patch/plan.d.ts +49 -0
  153. package/dist/patch/plan.js +273 -0
  154. package/dist/providers/anthropic.d.ts +1 -0
  155. package/dist/providers/anthropic.js +12 -0
  156. package/dist/providers/custom.d.ts +9 -0
  157. package/dist/providers/deepseek.d.ts +10 -0
  158. package/dist/providers/deepseek.js +3 -2
  159. package/dist/providers/google.d.ts +9 -0
  160. package/dist/providers/groq.d.ts +10 -0
  161. package/dist/providers/groq.js +2 -1
  162. package/dist/providers/index.d.ts +10 -201
  163. package/dist/providers/index.js +30 -0
  164. package/dist/providers/mistral.d.ts +10 -0
  165. package/dist/providers/mistral.js +2 -1
  166. package/dist/providers/moonshot.d.ts +10 -0
  167. package/dist/providers/moonshot.js +2 -1
  168. package/dist/providers/ollama.d.ts +9 -0
  169. package/dist/providers/openai.d.ts +10 -0
  170. package/dist/providers/openai.js +2 -1
  171. package/dist/providers/openaiCompatible.d.ts +33 -2
  172. package/dist/providers/openaiCompatible.js +78 -16
  173. package/dist/providers/openrouter.d.ts +10 -0
  174. package/dist/providers/openrouter.js +2 -1
  175. package/dist/providers/qwen.d.ts +10 -0
  176. package/dist/providers/qwen.js +2 -1
  177. package/dist/providers/spec.d.ts +12 -0
  178. package/dist/providers/spec.js +29 -0
  179. package/dist/providers/xai.d.ts +10 -0
  180. package/dist/providers/xai.js +2 -1
  181. package/dist/providers/zhipu.d.ts +10 -0
  182. package/dist/providers/zhipu.js +2 -1
  183. package/dist/session/log.d.ts +49 -14
  184. package/dist/session/log.js +236 -11
  185. package/dist/session/projection.d.ts +76 -0
  186. package/dist/session/projection.js +526 -0
  187. package/dist/skills/manager.d.ts +15 -0
  188. package/dist/skills/manager.js +135 -18
  189. package/dist/types.d.ts +75 -1
  190. package/dist/ui/Message.d.ts +1 -7
  191. package/dist/ui/Message.js +13 -2
  192. package/dist/ui/Picker.d.ts +8 -0
  193. package/dist/ui/Picker.js +24 -0
  194. package/dist/ui/Prompt.d.ts +1 -2
  195. package/dist/ui/Prompt.js +2 -2
  196. package/dist/ui/Spinner.js +11 -5
  197. package/dist/ui/StatusBar.d.ts +2 -1
  198. package/dist/ui/StatusBar.js +6 -5
  199. package/package.json +3 -2
  200. package/src/agent/approval-json.ts +103 -0
  201. package/src/agent/approval-native.ts +168 -0
  202. package/src/agent/approval-store.ts +38 -0
  203. package/src/agent/approval.ts +94 -0
  204. package/src/agent/compaction.ts +321 -0
  205. package/src/agent/context.ts +97 -0
  206. package/src/agent/guards.ts +1239 -19
  207. package/src/agent/ignore.ts +147 -0
  208. package/src/agent/policy/defaults.ts +34 -0
  209. package/src/agent/policy/egress.ts +335 -0
  210. package/src/agent/process-tree.ts +114 -0
  211. package/src/agent/protocol-mode.ts +59 -0
  212. package/src/agent/protocol.ts +191 -40
  213. package/src/agent/registry.ts +270 -0
  214. package/src/agent/runner.ts +486 -0
  215. package/src/agent/shell-ast.ts +227 -0
  216. package/src/agent/shell-session.ts +673 -0
  217. package/src/agent/stream.ts +143 -0
  218. package/src/agent/tool-schemas.ts +86 -0
  219. package/src/agent/tools/append_file.ts +30 -0
  220. package/src/agent/tools/apply_patch.ts +95 -0
  221. package/src/agent/tools/copy_file.ts +56 -0
  222. package/src/agent/tools/delete_file.ts +45 -0
  223. package/src/agent/tools/grep.ts +57 -0
  224. package/src/agent/tools/index.ts +34 -0
  225. package/src/agent/tools/list_files.ts +19 -0
  226. package/src/agent/tools/make_dir.ts +28 -0
  227. package/src/agent/tools/move_path.ts +83 -0
  228. package/src/agent/tools/paths.ts +92 -0
  229. package/src/agent/tools/pwd.ts +12 -0
  230. package/src/agent/tools/read_file.ts +84 -0
  231. package/src/agent/tools/read_many.ts +45 -0
  232. package/src/agent/tools/readers.ts +491 -0
  233. package/src/agent/tools/replace_in_file.ts +66 -0
  234. package/src/agent/tools/shell.ts +53 -0
  235. package/src/agent/tools/stat_path.ts +33 -0
  236. package/src/agent/tools/types.ts +84 -0
  237. package/src/agent/tools/validate.ts +104 -0
  238. package/src/agent/tools/write_file.ts +30 -0
  239. package/src/agent/tools.ts +3 -377
  240. package/src/app.ts +853 -170
  241. package/src/{cli.ts → cli-main.ts} +64 -9
  242. package/src/commands/about.ts +1 -1
  243. package/src/commands/attach.ts +16 -0
  244. package/src/commands/bg.ts +9 -0
  245. package/src/commands/cancel.ts +10 -0
  246. package/src/commands/clear.ts +1 -1
  247. package/src/commands/compact.ts +35 -0
  248. package/src/commands/context.ts +26 -0
  249. package/src/commands/edit.ts +37 -0
  250. package/src/commands/effort.ts +49 -0
  251. package/src/commands/expand.ts +8 -0
  252. package/src/commands/index.ts +24 -0
  253. package/src/commands/jobs.ts +18 -0
  254. package/src/commands/kill.ts +14 -0
  255. package/src/commands/login.ts +24 -22
  256. package/src/commands/logout.ts +8 -16
  257. package/src/commands/model.ts +10 -22
  258. package/src/commands/provider.ts +4 -11
  259. package/src/commands/skills.ts +34 -4
  260. package/src/commands/steer.ts +13 -0
  261. package/src/commands/threads.ts +28 -0
  262. package/src/commands/whoami.ts +6 -5
  263. package/src/config/store.ts +168 -77
  264. package/src/config/trust.ts +181 -22
  265. package/src/headless.ts +225 -0
  266. package/src/index.ts +19 -3
  267. package/src/lib/debug.ts +24 -0
  268. package/src/lib/diagnostics.ts +90 -8
  269. package/src/lib/highlight-subset.ts +93 -0
  270. package/src/lib/http.ts +66 -4
  271. package/src/lib/lifecycle.ts +69 -0
  272. package/src/lib/markdown.ts +22 -4
  273. package/src/lib/model-meta.ts +138 -0
  274. package/src/lib/native-tools.ts +32 -0
  275. package/src/lib/net.ts +204 -0
  276. package/src/patch/apply.ts +194 -0
  277. package/src/patch/parse.ts +131 -0
  278. package/src/patch/plan.ts +317 -0
  279. package/src/providers/anthropic.ts +13 -1
  280. package/src/providers/deepseek.ts +3 -2
  281. package/src/providers/groq.ts +2 -1
  282. package/src/providers/index.ts +32 -1
  283. package/src/providers/mistral.ts +2 -1
  284. package/src/providers/moonshot.ts +2 -1
  285. package/src/providers/openai.ts +2 -1
  286. package/src/providers/openaiCompatible.ts +104 -19
  287. package/src/providers/openrouter.ts +2 -1
  288. package/src/providers/qwen.ts +2 -1
  289. package/src/providers/spec.ts +42 -0
  290. package/src/providers/xai.ts +2 -1
  291. package/src/providers/zhipu.ts +2 -1
  292. package/src/session/log.ts +311 -29
  293. package/src/session/projection.ts +621 -0
  294. package/src/skills/manager.ts +140 -18
  295. package/src/types/highlight-shims.d.ts +14 -0
  296. package/src/types.ts +79 -2
  297. package/src/ui/Message.ts +13 -2
  298. package/src/ui/Picker.ts +24 -0
  299. package/src/ui/Prompt.ts +2 -2
  300. package/src/ui/Spinner.ts +11 -5
  301. package/src/ui/StatusBar.ts +6 -5
  302. package/tsconfig.json +1 -0
  303. /package/dist/{cli.d.ts → cli-main.d.ts} +0 -0
@@ -0,0 +1,83 @@
1
+ import { cp, mkdir, rename, rm } from "node:fs/promises";
2
+ import { lstatSync } from "node:fs";
3
+ import { dirname } from "node:path";
4
+ import { sandboxPath } from "./paths.js";
5
+ import type { Tool } from "./types.js";
6
+ import { invalid, preparePath, requiredString } from "./validate.js";
7
+
8
+ function exists(path: string): boolean {
9
+ try {
10
+ lstatSync(path);
11
+ return true;
12
+ }
13
+ catch {
14
+ return false;
15
+ }
16
+ }
17
+
18
+ export interface MoveOps {
19
+ rename: typeof rename;
20
+ cp: typeof cp;
21
+ rm: typeof rm;
22
+ }
23
+
24
+ export async function moveWithFallback(from: string, to: string, ops: MoveOps = { rename, cp, rm }): Promise<"rename" | "copy"> {
25
+ try {
26
+ await ops.rename(from, to);
27
+ return "rename";
28
+ }
29
+ catch (err: any) {
30
+ if (err?.code !== "EXDEV")
31
+ throw err;
32
+ await ops.cp(from, to, { recursive: true, force: false, errorOnExist: true });
33
+ try {
34
+ await ops.rm(from, { recursive: true, force: false });
35
+ }
36
+ catch (cleanup: any) {
37
+ throw Object.assign(new Error(`copied ${from} to ${to}, but could not remove the source: ${cleanup?.message ?? String(cleanup)}`), {
38
+ code: "UNKNOWN",
39
+ });
40
+ }
41
+ return "copy";
42
+ }
43
+ }
44
+
45
+ export const movePathTool: Tool = {
46
+ name: "move_path",
47
+ requiresTrust: true,
48
+ stateScope: "turn",
49
+ revalidate: ["trust", "sandboxRoots"],
50
+ prepare(call, ctx) {
51
+ try {
52
+ const from = requiredString(call, "from");
53
+ const to = requiredString(call, "to");
54
+ const checkedFrom = preparePath(ctx.cwd, from);
55
+ if (!checkedFrom.ok)
56
+ return checkedFrom;
57
+ const checkedTo = preparePath(ctx.cwd, to);
58
+ if (!checkedTo.ok)
59
+ return checkedTo;
60
+ if (exists(to))
61
+ return invalid(`move target exists: ${to}`, "EEXIST", "Choose a target that does not exist.");
62
+ return { ok: true };
63
+ }
64
+ catch (err: any) {
65
+ return invalid(err.message);
66
+ }
67
+ },
68
+ async execute(call, ctx) {
69
+ const from = sandboxPath(ctx.cwd, requiredString(call, "from"));
70
+ const to = sandboxPath(ctx.cwd, requiredString(call, "to"));
71
+ if (exists(to))
72
+ return { ok: false, output: `move target exists: ${to}`, code: "EEXIST", hint: "Choose a target that does not exist." };
73
+ await mkdir(dirname(to), { recursive: true });
74
+ const method = await moveWithFallback(from, to);
75
+ return {
76
+ ok: true,
77
+ output: method === "copy"
78
+ ? `moved ${from} to ${to} (cross-device copy + remove)`
79
+ : `moved ${from} to ${to}`,
80
+ sideEffects: { removed: [from], touched: [to] },
81
+ };
82
+ },
83
+ };
@@ -0,0 +1,92 @@
1
+ import { existsSync, realpathSync } from "node:fs";
2
+ import { basename, delimiter, dirname, isAbsolute, join, relative, resolve } from "node:path";
3
+ import { detectPlatform, safeHome } from "../../lib/platform.js";
4
+ import { loadConfig } from "../../config/store.js";
5
+ import type { ToolCall } from "./types.js";
6
+
7
+ export function allowedRoots(cwd: string): string[] {
8
+ const roots = [resolve(cwd)];
9
+ const configured = (process.env["FASTCODE_ALLOW_PATHS"] ?? "")
10
+ .split(delimiter)
11
+ .map((entry) => entry.trim())
12
+ .filter(Boolean);
13
+ for (const entry of configured)
14
+ roots.push(resolve(entry));
15
+ const sharedDirs = loadConfig().sharedDirs;
16
+ if (Array.isArray(sharedDirs)) {
17
+ for (const entry of sharedDirs) {
18
+ if (typeof entry !== "string" || !entry.trim())
19
+ continue;
20
+ roots.push(resolveSharedDir(cwd, entry.trim()));
21
+ }
22
+ }
23
+ if (detectPlatform() === "termux" && !isDisabled(process.env["FASTCODE_ALLOW_SHARED_STORAGE"])) {
24
+ const home = process.env["HOME"];
25
+ if (home) {
26
+ const shared = join(home, "storage", "shared");
27
+ if (existsSync(shared))
28
+ roots.push(shared);
29
+ }
30
+ }
31
+ return roots;
32
+ }
33
+
34
+ export function resolveSharedDir(cwd: string, entry: string): string {
35
+ const expanded = entry === "~" || entry.startsWith("~/") || entry.startsWith("~\\")
36
+ ? join(safeHome(), entry.slice(1))
37
+ : entry;
38
+ return isAbsolute(expanded) ? resolve(expanded) : resolve(cwd, expanded);
39
+ }
40
+
41
+ function isDisabled(value: string | undefined): boolean {
42
+ if (value === undefined)
43
+ return false;
44
+ return ["0", "false", "no", "off"].includes(value.trim().toLowerCase());
45
+ }
46
+
47
+ export function isInsideAny(child: string, roots: string[]): boolean {
48
+ return roots.some((root) => {
49
+ const rel = relative(root, child);
50
+ return rel === "" || (!rel.startsWith("..") && !isAbsolute(rel));
51
+ });
52
+ }
53
+
54
+ export function resolvePath(cwd: string, call: ToolCall, fallback = ""): string {
55
+ const raw = typeof call.path === "string" ? call.path : fallback;
56
+ return sandboxPath(cwd, raw);
57
+ }
58
+
59
+ export function sandboxPath(cwd: string, raw: string): string {
60
+ const target = resolve(cwd, raw);
61
+ const roots = allowedRoots(cwd);
62
+ const realRoots = roots.map((root) => realpathOf(root)).filter(Boolean) as string[];
63
+ const realTarget = realpathOf(target);
64
+ if (realTarget) {
65
+ if (isInsideAny(realTarget, realRoots))
66
+ return target;
67
+ throw new Error("path outside sandbox: " + raw);
68
+ }
69
+ if (isInsideAny(target, roots))
70
+ return target;
71
+ throw new Error("path outside sandbox: " + raw);
72
+ }
73
+
74
+ export function realpathOf(input: string): string | undefined {
75
+ let current = resolve(input);
76
+ const missing: string[] = [];
77
+ for (;;) {
78
+ if (existsSync(current)) {
79
+ try {
80
+ return join(realpathSync(current), ...missing.slice().reverse());
81
+ }
82
+ catch {
83
+ return undefined;
84
+ }
85
+ }
86
+ const parent = dirname(current);
87
+ if (parent === current)
88
+ return undefined;
89
+ missing.push(basename(current));
90
+ current = parent;
91
+ }
92
+ }
@@ -0,0 +1,12 @@
1
+ import type { Tool } from "./types.js";
2
+
3
+ export const pwdTool: Tool = {
4
+ name: "pwd",
5
+ stateScope: "call",
6
+ prepare() {
7
+ return { ok: true };
8
+ },
9
+ async execute(_call, ctx) {
10
+ return { ok: true, output: ctx.cwd };
11
+ },
12
+ };
@@ -0,0 +1,84 @@
1
+ import { readFileRange, readTextFileResult } from "./readers.js";
2
+ import { resolvePath } from "./paths.js";
3
+ import type { Tool } from "./types.js";
4
+ import { clampInt, invalid, optionalNumber, preparePath, requiredString } from "./validate.js";
5
+
6
+ const MAX_READ_LINES = 2000;
7
+
8
+ export const readFileTool: Tool = {
9
+ name: "read_file",
10
+ stateScope: "call",
11
+ revalidate: ["sandboxRoots"],
12
+ prepare(call, ctx) {
13
+ let path: string;
14
+ try {
15
+ path = requiredString(call, "path");
16
+ const offset = optionalNumber(call, "offset");
17
+ const limit = optionalNumber(call, "limit");
18
+ if (offset !== undefined && offset < 1)
19
+ return invalid("offset must be >= 1");
20
+ if (limit !== undefined && limit < 1)
21
+ return invalid("limit must be >= 1");
22
+ }
23
+ catch (err: any) {
24
+ return invalid(err.message);
25
+ }
26
+ return preparePath(ctx.cwd, path);
27
+ },
28
+ async execute(call, ctx) {
29
+ const file = resolvePath(ctx.cwd, call);
30
+ const offset = optionalNumber(call, "offset");
31
+ const limit = optionalNumber(call, "limit");
32
+ if (offset === undefined && limit === undefined) {
33
+ const result = await readTextFileResult(file);
34
+ const output = result.truncated
35
+ ? `${result.text}\n[... truncated at ${result.returnedBytes} of ${result.totalBytes} bytes; use offset/limit, grep, or a narrower file ...]`
36
+ : result.text;
37
+ return {
38
+ ok: true,
39
+ output,
40
+ truncated: result.truncated,
41
+ totalLines: result.totalLines,
42
+ returnedLines: result.returnedLines,
43
+ totalBytes: result.totalBytes,
44
+ returnedBytes: result.returnedBytes,
45
+ };
46
+ }
47
+ const start = clampInt(offset, 1, 1, 1_000_000);
48
+ const count = clampInt(limit, MAX_READ_LINES, 1, MAX_READ_LINES);
49
+ const result = await readFileRange(file, start, count, { signal: ctx.signal });
50
+ if (result.binary) {
51
+ return {
52
+ ok: true,
53
+ output: result.text,
54
+ truncated: false,
55
+ totalLines: 0,
56
+ returnedLines: 0,
57
+ totalBytes: result.totalBytes,
58
+ returnedBytes: 0,
59
+ };
60
+ }
61
+ if (result.returnedLines === 0 && start > result.totalLines) {
62
+ return {
63
+ ok: false,
64
+ output: `offset ${start} is beyond the end of ${file} (${result.totalLines} lines)`,
65
+ code: "NOT_FOUND",
66
+ hint: "Use a smaller offset or read without offset.",
67
+ totalLines: result.totalLines,
68
+ returnedLines: 0,
69
+ };
70
+ }
71
+ const end = start + result.returnedLines - 1;
72
+ const header = `[lines ${start}-${end} of ${result.totalLines}${result.scannedAll ? "" : "+"}]\n`;
73
+ return {
74
+ ok: true,
75
+ output: header + result.text,
76
+ truncated: result.truncated,
77
+ hint: result.scannedAll ? undefined : "totalLines is a lower bound; the file scan hit FASTCODE_READ_SCAN_MAX_BYTES.",
78
+ totalLines: result.totalLines,
79
+ returnedLines: result.returnedLines,
80
+ totalBytes: result.totalBytes,
81
+ returnedBytes: result.returnedBytes,
82
+ };
83
+ },
84
+ };
@@ -0,0 +1,45 @@
1
+ import { readManyResult } from "./readers.js";
2
+ import type { Tool } from "./types.js";
3
+ import { invalid, optionalNumber, preparePath, stringArray } from "./validate.js";
4
+
5
+ export const readManyTool: Tool = {
6
+ name: "read_many",
7
+ stateScope: "call",
8
+ revalidate: ["sandboxRoots"],
9
+ prepare(call, ctx) {
10
+ let paths: string[];
11
+ try {
12
+ paths = stringArray(call, "paths");
13
+ if (paths.length === 0)
14
+ return invalid("paths must contain at least one path");
15
+ const maxBytes = optionalNumber(call, "maxBytes");
16
+ if (maxBytes !== undefined && maxBytes < 1)
17
+ return invalid("maxBytes must be >= 1");
18
+ }
19
+ catch (err: any) {
20
+ return invalid(err.message);
21
+ }
22
+ for (const path of paths) {
23
+ const checked = preparePath(ctx.cwd, path);
24
+ if (!checked.ok)
25
+ return checked;
26
+ }
27
+ return { ok: true };
28
+ },
29
+ async execute(call, ctx) {
30
+ const paths = stringArray(call, "paths");
31
+ const requested = optionalNumber(call, "maxBytes");
32
+ const maxBytes = requested === undefined ? undefined : Math.max(1, Math.floor(requested));
33
+ const result = await readManyResult(ctx.cwd, paths, maxBytes);
34
+ return {
35
+ ok: true,
36
+ output: result.text,
37
+ truncated: result.truncated,
38
+ totalBytes: result.totalBytes,
39
+ returnedBytes: result.returnedBytes,
40
+ filesRead: result.filesRead,
41
+ filesSkipped: result.filesSkipped,
42
+ hint: result.filesSkipped > 0 ? `${result.filesSkipped} file(s) skipped by the read_many byte budget.` : undefined,
43
+ };
44
+ },
45
+ };