@datename/fastcode-termux 0.0.0-stage → 0.1.6-beta

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 (347) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +418 -2
  3. package/bin/fastcode.mjs +59 -0
  4. package/dist/agent/approval.d.ts +50 -0
  5. package/dist/agent/approval.js +7 -0
  6. package/dist/agent/compaction.d.ts +39 -0
  7. package/dist/agent/compaction.js +227 -0
  8. package/dist/agent/context.d.ts +29 -0
  9. package/dist/agent/context.js +62 -0
  10. package/dist/agent/guards.d.ts +43 -0
  11. package/dist/agent/guards.js +269 -0
  12. package/dist/agent/ignore.d.ts +11 -0
  13. package/dist/agent/ignore.js +129 -0
  14. package/dist/agent/limits.d.ts +24 -0
  15. package/dist/agent/limits.js +71 -0
  16. package/dist/agent/process-tree.d.ts +2 -0
  17. package/dist/agent/process-tree.js +31 -0
  18. package/dist/agent/protocol-mode.d.ts +6 -0
  19. package/dist/agent/protocol-mode.js +51 -0
  20. package/dist/agent/protocol.d.ts +4 -0
  21. package/dist/agent/protocol.js +129 -0
  22. package/dist/agent/registry.d.ts +17 -0
  23. package/dist/agent/registry.js +90 -0
  24. package/dist/agent/runner.d.ts +106 -0
  25. package/dist/agent/runner.js +352 -0
  26. package/dist/agent/shell-session.d.ts +37 -0
  27. package/dist/agent/shell-session.js +400 -0
  28. package/dist/agent/stream.d.ts +29 -0
  29. package/dist/agent/stream.js +103 -0
  30. package/dist/agent/tool-schemas.d.ts +2 -0
  31. package/dist/agent/tool-schemas.js +63 -0
  32. package/dist/agent/tools/append_file.d.ts +2 -0
  33. package/dist/agent/tools/append_file.js +26 -0
  34. package/dist/agent/tools/apply_patch.d.ts +10 -0
  35. package/dist/agent/tools/apply_patch.js +52 -0
  36. package/dist/agent/tools/copy_file.d.ts +2 -0
  37. package/dist/agent/tools/copy_file.js +30 -0
  38. package/dist/agent/tools/delete_file.d.ts +2 -0
  39. package/dist/agent/tools/delete_file.js +24 -0
  40. package/dist/agent/tools/grep.d.ts +2 -0
  41. package/dist/agent/tools/grep.js +23 -0
  42. package/dist/agent/tools/index.d.ts +2 -0
  43. package/dist/agent/tools/index.js +32 -0
  44. package/dist/agent/tools/list_files.d.ts +2 -0
  45. package/dist/agent/tools/list_files.js +17 -0
  46. package/dist/agent/tools/make_dir.d.ts +2 -0
  47. package/dist/agent/tools/make_dir.js +24 -0
  48. package/dist/agent/tools/move_path.d.ts +2 -0
  49. package/dist/agent/tools/move_path.js +47 -0
  50. package/dist/agent/tools/paths.d.ts +7 -0
  51. package/dist/agent/tools/paths.js +84 -0
  52. package/dist/agent/tools/pwd.d.ts +2 -0
  53. package/dist/agent/tools/pwd.js +10 -0
  54. package/dist/agent/tools/read_file.d.ts +2 -0
  55. package/dist/agent/tools/read_file.js +21 -0
  56. package/dist/agent/tools/read_many.d.ts +2 -0
  57. package/dist/agent/tools/read_many.js +25 -0
  58. package/dist/agent/tools/readers.d.ts +6 -0
  59. package/dist/agent/tools/readers.js +216 -0
  60. package/dist/agent/tools/replace_in_file.d.ts +2 -0
  61. package/dist/agent/tools/replace_in_file.js +30 -0
  62. package/dist/agent/tools/shell.d.ts +2 -0
  63. package/dist/agent/tools/shell.js +48 -0
  64. package/dist/agent/tools/stat_path.d.ts +2 -0
  65. package/dist/agent/tools/stat_path.js +31 -0
  66. package/dist/agent/tools/types.d.ts +39 -0
  67. package/dist/agent/tools/types.js +1 -0
  68. package/dist/agent/tools/validate.d.ts +6 -0
  69. package/dist/agent/tools/validate.js +29 -0
  70. package/dist/agent/tools/write_file.d.ts +2 -0
  71. package/dist/agent/tools/write_file.js +26 -0
  72. package/dist/agent/tools.d.ts +3 -0
  73. package/dist/agent/tools.js +2 -0
  74. package/dist/app.d.ts +4 -0
  75. package/dist/app.js +708 -0
  76. package/dist/cli.d.ts +1 -0
  77. package/dist/cli.js +569 -0
  78. package/dist/commands/about.d.ts +8 -0
  79. package/dist/commands/about.js +16 -0
  80. package/dist/commands/agent.d.ts +11 -0
  81. package/dist/commands/agent.js +18 -0
  82. package/dist/commands/attach.d.ts +9 -0
  83. package/dist/commands/attach.js +15 -0
  84. package/dist/commands/bg.d.ts +7 -0
  85. package/dist/commands/bg.js +9 -0
  86. package/dist/commands/cancel.d.ts +10 -0
  87. package/dist/commands/cancel.js +10 -0
  88. package/dist/commands/clear.d.ts +11 -0
  89. package/dist/commands/clear.js +9 -0
  90. package/dist/commands/compact.d.ts +10 -0
  91. package/dist/commands/compact.js +22 -0
  92. package/dist/commands/config.d.ts +7 -0
  93. package/dist/commands/config.js +24 -0
  94. package/dist/commands/context.d.ts +7 -0
  95. package/dist/commands/context.js +24 -0
  96. package/dist/commands/cost.d.ts +9 -0
  97. package/dist/commands/cost.js +13 -0
  98. package/dist/commands/cwd.d.ts +7 -0
  99. package/dist/commands/cwd.js +7 -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/exit.d.ts +9 -0
  105. package/dist/commands/exit.js +8 -0
  106. package/dist/commands/expand.d.ts +10 -0
  107. package/dist/commands/expand.js +8 -0
  108. package/dist/commands/help.d.ts +6 -0
  109. package/dist/commands/help.js +18 -0
  110. package/dist/commands/index.d.ts +9 -0
  111. package/dist/commands/index.js +80 -0
  112. package/dist/commands/jobs.d.ts +7 -0
  113. package/dist/commands/jobs.js +16 -0
  114. package/dist/commands/kill.d.ts +7 -0
  115. package/dist/commands/kill.js +11 -0
  116. package/dist/commands/login.d.ts +18 -0
  117. package/dist/commands/login.js +63 -0
  118. package/dist/commands/logout.d.ts +9 -0
  119. package/dist/commands/logout.js +45 -0
  120. package/dist/commands/model.d.ts +24 -0
  121. package/dist/commands/model.js +50 -0
  122. package/dist/commands/plugin.d.ts +11 -0
  123. package/dist/commands/plugin.js +74 -0
  124. package/dist/commands/provider.d.ts +24 -0
  125. package/dist/commands/provider.js +39 -0
  126. package/dist/commands/reset.d.ts +9 -0
  127. package/dist/commands/reset.js +13 -0
  128. package/dist/commands/skills.d.ts +11 -0
  129. package/dist/commands/skills.js +106 -0
  130. package/dist/commands/steer.d.ts +11 -0
  131. package/dist/commands/steer.js +13 -0
  132. package/dist/commands/system.d.ts +11 -0
  133. package/dist/commands/system.js +20 -0
  134. package/dist/commands/theme.d.ts +11 -0
  135. package/dist/commands/theme.js +22 -0
  136. package/dist/commands/tools.d.ts +7 -0
  137. package/dist/commands/tools.js +29 -0
  138. package/dist/commands/whoami.d.ts +9 -0
  139. package/dist/commands/whoami.js +52 -0
  140. package/dist/config/paths.d.ts +4 -0
  141. package/dist/config/paths.js +59 -0
  142. package/dist/config/store.d.ts +89 -0
  143. package/dist/config/store.js +260 -0
  144. package/dist/config/themes.d.ts +73 -0
  145. package/dist/config/themes.js +77 -0
  146. package/dist/config/trust.d.ts +22 -0
  147. package/dist/config/trust.js +153 -0
  148. package/dist/index.d.ts +1 -0
  149. package/dist/index.js +31 -0
  150. package/dist/lib/diagnostics.d.ts +66 -0
  151. package/dist/lib/diagnostics.js +195 -0
  152. package/dist/lib/http.d.ts +23 -0
  153. package/dist/lib/http.js +128 -0
  154. package/dist/lib/markdown.d.ts +1 -0
  155. package/dist/lib/markdown.js +32 -0
  156. package/dist/lib/model-meta.d.ts +19 -0
  157. package/dist/lib/model-meta.js +113 -0
  158. package/dist/lib/native-tools.d.ts +12 -0
  159. package/dist/lib/native-tools.js +21 -0
  160. package/dist/lib/net.d.ts +33 -0
  161. package/dist/lib/net.js +168 -0
  162. package/dist/lib/pkg.d.ts +5 -0
  163. package/dist/lib/pkg.js +27 -0
  164. package/dist/lib/platform.d.ts +7 -0
  165. package/dist/lib/platform.js +57 -0
  166. package/dist/lib/startup.d.ts +6 -0
  167. package/dist/lib/startup.js +25 -0
  168. package/dist/lib/uiMode.d.ts +2 -0
  169. package/dist/lib/uiMode.js +7 -0
  170. package/dist/patch/apply.d.ts +15 -0
  171. package/dist/patch/apply.js +172 -0
  172. package/dist/patch/parse.d.ts +29 -0
  173. package/dist/patch/parse.js +112 -0
  174. package/dist/patch/plan.d.ts +49 -0
  175. package/dist/patch/plan.js +273 -0
  176. package/dist/plugins/manager.d.ts +23 -0
  177. package/dist/plugins/manager.js +101 -0
  178. package/dist/providers/anthropic.d.ts +22 -0
  179. package/dist/providers/anthropic.js +119 -0
  180. package/dist/providers/custom.d.ts +33 -0
  181. package/dist/providers/custom.js +25 -0
  182. package/dist/providers/deepseek.d.ts +34 -0
  183. package/dist/providers/deepseek.js +16 -0
  184. package/dist/providers/google.d.ts +33 -0
  185. package/dist/providers/google.js +19 -0
  186. package/dist/providers/groq.d.ts +34 -0
  187. package/dist/providers/groq.js +21 -0
  188. package/dist/providers/index.d.ts +10 -0
  189. package/dist/providers/index.js +67 -0
  190. package/dist/providers/mistral.d.ts +34 -0
  191. package/dist/providers/mistral.js +20 -0
  192. package/dist/providers/moonshot.d.ts +34 -0
  193. package/dist/providers/moonshot.js +23 -0
  194. package/dist/providers/ollama.d.ts +33 -0
  195. package/dist/providers/ollama.js +22 -0
  196. package/dist/providers/openai.d.ts +34 -0
  197. package/dist/providers/openai.js +26 -0
  198. package/dist/providers/openaiCompatible.d.ts +26 -0
  199. package/dist/providers/openaiCompatible.js +158 -0
  200. package/dist/providers/openrouter.d.ts +34 -0
  201. package/dist/providers/openrouter.js +27 -0
  202. package/dist/providers/qwen.d.ts +34 -0
  203. package/dist/providers/qwen.js +24 -0
  204. package/dist/providers/xai.d.ts +34 -0
  205. package/dist/providers/xai.js +19 -0
  206. package/dist/providers/zhipu.d.ts +34 -0
  207. package/dist/providers/zhipu.js +24 -0
  208. package/dist/session/log.d.ts +52 -0
  209. package/dist/session/log.js +331 -0
  210. package/dist/session/projection.d.ts +43 -0
  211. package/dist/session/projection.js +257 -0
  212. package/dist/skills/manager.d.ts +18 -0
  213. package/dist/skills/manager.js +201 -0
  214. package/dist/skills/parser.d.ts +18 -0
  215. package/dist/skills/parser.js +65 -0
  216. package/dist/types.d.ts +205 -0
  217. package/dist/types.js +1 -0
  218. package/dist/ui/Banner.d.ts +5 -0
  219. package/dist/ui/Banner.js +65 -0
  220. package/dist/ui/Message.d.ts +1 -0
  221. package/dist/ui/Message.js +24 -0
  222. package/dist/ui/Picker.d.ts +8 -0
  223. package/dist/ui/Picker.js +24 -0
  224. package/dist/ui/Prompt.d.ts +9 -0
  225. package/dist/ui/Prompt.js +38 -0
  226. package/dist/ui/Spinner.d.ts +5 -0
  227. package/dist/ui/Spinner.js +39 -0
  228. package/dist/ui/StatusBar.d.ts +11 -0
  229. package/dist/ui/StatusBar.js +20 -0
  230. package/dist/ui/TrustGate.d.ts +5 -0
  231. package/dist/ui/TrustGate.js +26 -0
  232. package/package.json +96 -4
  233. package/src/agent/approval.ts +47 -0
  234. package/src/agent/compaction.ts +276 -0
  235. package/src/agent/context.ts +97 -0
  236. package/src/agent/guards.ts +270 -0
  237. package/src/agent/ignore.ts +147 -0
  238. package/src/agent/limits.ts +71 -0
  239. package/src/agent/process-tree.ts +32 -0
  240. package/src/agent/protocol-mode.ts +59 -0
  241. package/src/agent/protocol.ts +129 -0
  242. package/src/agent/registry.ts +98 -0
  243. package/src/agent/runner.ts +443 -0
  244. package/src/agent/shell-session.ts +449 -0
  245. package/src/agent/stream.ts +143 -0
  246. package/src/agent/tool-schemas.ts +67 -0
  247. package/src/agent/tools/append_file.ts +28 -0
  248. package/src/agent/tools/apply_patch.ts +54 -0
  249. package/src/agent/tools/copy_file.ts +32 -0
  250. package/src/agent/tools/delete_file.ts +26 -0
  251. package/src/agent/tools/grep.ts +25 -0
  252. package/src/agent/tools/index.ts +34 -0
  253. package/src/agent/tools/list_files.ts +19 -0
  254. package/src/agent/tools/make_dir.ts +26 -0
  255. package/src/agent/tools/move_path.ts +50 -0
  256. package/src/agent/tools/paths.ts +92 -0
  257. package/src/agent/tools/pwd.ts +12 -0
  258. package/src/agent/tools/read_file.ts +23 -0
  259. package/src/agent/tools/read_many.ts +27 -0
  260. package/src/agent/tools/readers.ts +228 -0
  261. package/src/agent/tools/replace_in_file.ts +32 -0
  262. package/src/agent/tools/shell.ts +53 -0
  263. package/src/agent/tools/stat_path.ts +33 -0
  264. package/src/agent/tools/types.ts +42 -0
  265. package/src/agent/tools/validate.ts +35 -0
  266. package/src/agent/tools/write_file.ts +28 -0
  267. package/src/agent/tools.ts +3 -0
  268. package/src/app.ts +708 -0
  269. package/src/cli.ts +335 -0
  270. package/src/commands/about.ts +16 -0
  271. package/src/commands/agent.ts +18 -0
  272. package/src/commands/attach.ts +16 -0
  273. package/src/commands/bg.ts +9 -0
  274. package/src/commands/cancel.ts +10 -0
  275. package/src/commands/clear.ts +9 -0
  276. package/src/commands/compact.ts +23 -0
  277. package/src/commands/config.ts +24 -0
  278. package/src/commands/context.ts +25 -0
  279. package/src/commands/cost.ts +13 -0
  280. package/src/commands/cwd.ts +7 -0
  281. package/src/commands/edit.ts +37 -0
  282. package/src/commands/effort.ts +49 -0
  283. package/src/commands/exit.ts +8 -0
  284. package/src/commands/expand.ts +8 -0
  285. package/src/commands/help.ts +18 -0
  286. package/src/commands/index.ts +80 -0
  287. package/src/commands/jobs.ts +17 -0
  288. package/src/commands/kill.ts +12 -0
  289. package/src/commands/login.ts +63 -0
  290. package/src/commands/logout.ts +45 -0
  291. package/src/commands/model.ts +50 -0
  292. package/src/commands/plugin.ts +74 -0
  293. package/src/commands/provider.ts +39 -0
  294. package/src/commands/reset.ts +13 -0
  295. package/src/commands/skills.ts +106 -0
  296. package/src/commands/steer.ts +13 -0
  297. package/src/commands/system.ts +20 -0
  298. package/src/commands/theme.ts +22 -0
  299. package/src/commands/tools.ts +29 -0
  300. package/src/commands/whoami.ts +52 -0
  301. package/src/config/paths.ts +59 -0
  302. package/src/config/store.ts +293 -0
  303. package/src/config/themes.ts +77 -0
  304. package/src/config/trust.ts +183 -0
  305. package/src/index.ts +31 -0
  306. package/src/lib/diagnostics.ts +195 -0
  307. package/src/lib/http.ts +132 -0
  308. package/src/lib/markdown.ts +32 -0
  309. package/src/lib/model-meta.ts +138 -0
  310. package/src/lib/native-tools.ts +32 -0
  311. package/src/lib/net.ts +204 -0
  312. package/src/lib/pkg.ts +35 -0
  313. package/src/lib/platform.ts +57 -0
  314. package/src/lib/startup.ts +25 -0
  315. package/src/lib/uiMode.ts +7 -0
  316. package/src/patch/apply.ts +194 -0
  317. package/src/patch/parse.ts +131 -0
  318. package/src/patch/plan.ts +317 -0
  319. package/src/plugins/manager.ts +101 -0
  320. package/src/providers/anthropic.ts +119 -0
  321. package/src/providers/custom.ts +25 -0
  322. package/src/providers/deepseek.ts +16 -0
  323. package/src/providers/google.ts +19 -0
  324. package/src/providers/groq.ts +21 -0
  325. package/src/providers/index.ts +68 -0
  326. package/src/providers/mistral.ts +20 -0
  327. package/src/providers/moonshot.ts +23 -0
  328. package/src/providers/ollama.ts +22 -0
  329. package/src/providers/openai.ts +26 -0
  330. package/src/providers/openaiCompatible.ts +158 -0
  331. package/src/providers/openrouter.ts +27 -0
  332. package/src/providers/qwen.ts +24 -0
  333. package/src/providers/xai.ts +19 -0
  334. package/src/providers/zhipu.ts +24 -0
  335. package/src/session/log.ts +374 -0
  336. package/src/session/projection.ts +308 -0
  337. package/src/skills/manager.ts +201 -0
  338. package/src/skills/parser.ts +65 -0
  339. package/src/types.ts +205 -0
  340. package/src/ui/Banner.ts +68 -0
  341. package/src/ui/Message.ts +24 -0
  342. package/src/ui/Picker.ts +24 -0
  343. package/src/ui/Prompt.ts +38 -0
  344. package/src/ui/Spinner.ts +39 -0
  345. package/src/ui/StatusBar.ts +20 -0
  346. package/src/ui/TrustGate.ts +26 -0
  347. package/tsconfig.json +22 -0
@@ -0,0 +1,129 @@
1
+ /**
2
+ * Ignore rules for directory walks and reads.
3
+ *
4
+ * Defaults cover the usual dependency/build folders. Users can add more with
5
+ * `.fastcodeignore` in the project root, using a gitignore-like syntax:
6
+ *
7
+ * node_modules/ # trailing slash = directories only
8
+ * *.log # basename at any depth
9
+ * /secrets.txt # anchored to the project root
10
+ * !important.log # re-include (last matching rule wins)
11
+ */
12
+ import { readFileSync, statSync } from "node:fs";
13
+ import { join, relative, sep } from "node:path";
14
+ const DEFAULT_NAMES = new Set([
15
+ "node_modules",
16
+ ".git",
17
+ ".hg",
18
+ ".svn",
19
+ "dist",
20
+ "build",
21
+ "out",
22
+ ".next",
23
+ ".nuxt",
24
+ ".output",
25
+ ".turbo",
26
+ ".parcel-cache",
27
+ ".cache",
28
+ "coverage",
29
+ ".nyc_output",
30
+ "__pycache__",
31
+ ".venv",
32
+ "venv",
33
+ "target",
34
+ ".gradle",
35
+ ".idea",
36
+ ]);
37
+ const BINARY_EXT = /\.(png|jpe?g|gif|webp|ico|bmp|tiff?|pdf|zip|gz|tgz|bz2|xz|7z|rar|exe|dll|so|dylib|bin|wasm|mp3|mp4|mov|avi|mkv|wav|flac|ttf|otf|woff2?|eot|class|jar|apk|ipa|sqlite|db|lock)$/i;
38
+ export function isBinaryName(name) {
39
+ return BINARY_EXT.test(name);
40
+ }
41
+ export function createIgnore(root) {
42
+ const rules = loadRules(root);
43
+ return {
44
+ ignored(name, fullPath, isDir) {
45
+ if (DEFAULT_NAMES.has(name))
46
+ return true;
47
+ if (rules.length === 0)
48
+ return false;
49
+ const rel = relative(root, fullPath).split(sep).join("/");
50
+ let ignored = false;
51
+ for (const rule of rules) {
52
+ if (rule.dirOnly && !isDir)
53
+ continue;
54
+ if (rule.regex.test(rel) || rule.regex.test(name))
55
+ ignored = !rule.negate;
56
+ }
57
+ return ignored;
58
+ },
59
+ isBinary(name) {
60
+ return BINARY_EXT.test(name);
61
+ },
62
+ };
63
+ }
64
+ function loadRules(root) {
65
+ const file = join(root, ".fastcodeignore");
66
+ let text = "";
67
+ try {
68
+ const info = statSync(file);
69
+ if (!info.isFile())
70
+ return [];
71
+ text = readFileSync(file, "utf8");
72
+ }
73
+ catch {
74
+ return [];
75
+ }
76
+ const rules = [];
77
+ for (const raw of text.split(/\r?\n/)) {
78
+ const line = raw.trim();
79
+ if (!line || line.startsWith("#"))
80
+ continue;
81
+ const negate = line.startsWith("!");
82
+ const body = negate ? line.slice(1).trim() : line;
83
+ if (!body)
84
+ continue;
85
+ const dirOnly = body.endsWith("/");
86
+ const pattern = dirOnly ? body.slice(0, -1) : body;
87
+ const anchored = pattern.startsWith("/");
88
+ const glob = anchored ? pattern.slice(1) : pattern;
89
+ try {
90
+ rules.push({
91
+ regex: globToRegExp(glob, anchored),
92
+ negate,
93
+ dirOnly,
94
+ });
95
+ }
96
+ catch {
97
+ // A bad pattern must not disable the whole ignore file.
98
+ }
99
+ }
100
+ return rules;
101
+ }
102
+ function globToRegExp(glob, anchored) {
103
+ let source = "";
104
+ for (let i = 0; i < glob.length; i += 1) {
105
+ const char = glob[i];
106
+ if (char === "*") {
107
+ if (glob[i + 1] === "*") {
108
+ source += ".*";
109
+ i += 1;
110
+ if (glob[i + 1] === "/")
111
+ i += 1;
112
+ }
113
+ else {
114
+ source += "[^/]*";
115
+ }
116
+ }
117
+ else if (char === "?") {
118
+ source += "[^/]";
119
+ }
120
+ else {
121
+ source += escapeRegExp(char);
122
+ }
123
+ }
124
+ // Unanchored patterns match a basename at any depth.
125
+ return new RegExp("^" + (anchored ? "" : "(?:.*/)?") + source + "$");
126
+ }
127
+ function escapeRegExp(value) {
128
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
129
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Single source of truth for how much tool output reaches the model.
3
+ *
4
+ * Output is bounded while it is produced, not by slicing a finished string
5
+ * afterwards, so a runaway command or a huge directory listing cannot grow
6
+ * without limit. Override the cap with FASTCODE_TOOL_OUTPUT_LIMIT (characters).
7
+ */
8
+ export declare const DEFAULT_TOOL_OUTPUT_LIMIT = 30000;
9
+ export declare function toolOutputLimit(): number;
10
+ /**
11
+ * Bounded text accumulator.
12
+ *
13
+ * mode "head" keeps the first N characters (listings, search hits);
14
+ * mode "tail" keeps the last N (command logs, where the error is last).
15
+ * trimEnd()/toString() mimic a plain string so callers stay simple.
16
+ */
17
+ export declare function createOutputBuffer(limit?: number, mode?: string): {
18
+ readonly full: boolean;
19
+ push(chunk: any): void;
20
+ line(value: any): void;
21
+ value(): string;
22
+ trimEnd(): string;
23
+ toString(): string;
24
+ };
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Single source of truth for how much tool output reaches the model.
3
+ *
4
+ * Output is bounded while it is produced, not by slicing a finished string
5
+ * afterwards, so a runaway command or a huge directory listing cannot grow
6
+ * without limit. Override the cap with FASTCODE_TOOL_OUTPUT_LIMIT (characters).
7
+ */
8
+ export const DEFAULT_TOOL_OUTPUT_LIMIT = 30000;
9
+ export function toolOutputLimit() {
10
+ const raw = Number(process.env["FASTCODE_TOOL_OUTPUT_LIMIT"]);
11
+ return Number.isFinite(raw) && raw > 0 ? Math.floor(raw) : DEFAULT_TOOL_OUTPUT_LIMIT;
12
+ }
13
+ /**
14
+ * Bounded text accumulator.
15
+ *
16
+ * mode "head" keeps the first N characters (listings, search hits);
17
+ * mode "tail" keeps the last N (command logs, where the error is last).
18
+ * trimEnd()/toString() mimic a plain string so callers stay simple.
19
+ */
20
+ export function createOutputBuffer(limit = toolOutputLimit(), mode = "head") {
21
+ const NL = String.fromCharCode(10);
22
+ let text = "";
23
+ let dropped = 0;
24
+ const buffer = {
25
+ get full() {
26
+ return text.length >= limit;
27
+ },
28
+ push(chunk) {
29
+ const value = String(chunk);
30
+ if (mode === "tail") {
31
+ text += value;
32
+ if (text.length > limit) {
33
+ const over = text.length - limit;
34
+ dropped += over;
35
+ text = text.slice(over);
36
+ }
37
+ return;
38
+ }
39
+ if (text.length >= limit) {
40
+ dropped += value.length;
41
+ return;
42
+ }
43
+ const room = limit - text.length;
44
+ if (value.length <= room) {
45
+ text += value;
46
+ }
47
+ else {
48
+ text += value.slice(0, room);
49
+ dropped += value.length - room;
50
+ }
51
+ },
52
+ line(value) {
53
+ if (text.length > 0)
54
+ buffer.push(NL);
55
+ buffer.push(value);
56
+ },
57
+ value() {
58
+ if (dropped <= 0)
59
+ return text;
60
+ const note = "[" + dropped + " more characters omitted]";
61
+ return mode === "tail" ? note + NL + text : text + NL + note;
62
+ },
63
+ trimEnd() {
64
+ return buffer.value().trimEnd();
65
+ },
66
+ toString() {
67
+ return buffer.value();
68
+ },
69
+ };
70
+ return buffer;
71
+ }
@@ -0,0 +1,2 @@
1
+ import { type ChildProcess } from "node:child_process";
2
+ export declare function killProcessTree(child: ChildProcess | undefined, signal?: NodeJS.Signals): void;
@@ -0,0 +1,31 @@
1
+ import { spawn } from "node:child_process";
2
+ export function killProcessTree(child, signal = "SIGTERM") {
3
+ if (!child || typeof child.pid !== "number")
4
+ return;
5
+ if (process.platform === "win32") {
6
+ try {
7
+ const killer = spawn("taskkill", ["/pid", String(child.pid), "/T", "/F"], { windowsHide: true, stdio: "ignore" });
8
+ killer.unref();
9
+ }
10
+ catch {
11
+ try {
12
+ child.kill();
13
+ }
14
+ catch {
15
+ // The process may already be gone.
16
+ }
17
+ }
18
+ return;
19
+ }
20
+ try {
21
+ process.kill(-child.pid, signal);
22
+ }
23
+ catch {
24
+ try {
25
+ child.kill(signal);
26
+ }
27
+ catch {
28
+ // Same as above.
29
+ }
30
+ }
31
+ }
@@ -0,0 +1,6 @@
1
+ export type ToolProtocol = "legacy" | "native";
2
+ export type ToolCapability = "native" | "pseudo";
3
+ export declare function toolCapabilityKey(providerId: string, model: string): string;
4
+ export declare function resolveToolProtocol(config: any, providerId: string, model: string, env?: NodeJS.ProcessEnv): ToolProtocol;
5
+ export declare function withToolCapability(config: any, providerId: string, model: string, capability: ToolCapability): any;
6
+ export declare function isNativeUnsupportedError(message: string): boolean;
@@ -0,0 +1,51 @@
1
+ import { getModelMeta } from "../lib/model-meta.js";
2
+ const NATIVE_PROVIDERS = new Set([
3
+ "openai",
4
+ "openrouter",
5
+ "deepseek",
6
+ "groq",
7
+ "mistral",
8
+ "xai",
9
+ "moonshot",
10
+ "zhipu",
11
+ "qwen",
12
+ "ollama",
13
+ ]);
14
+ export function toolCapabilityKey(providerId, model) {
15
+ return `${providerId}::${model}`;
16
+ }
17
+ export function resolveToolProtocol(config, providerId, model, env = process.env) {
18
+ const mode = String(env["FASTCODE_TOOL_PROTOCOL"] ?? "legacy").trim().toLowerCase();
19
+ if (mode === "legacy")
20
+ return "legacy";
21
+ if (mode === "native")
22
+ return "native";
23
+ if (mode !== "auto")
24
+ return "legacy";
25
+ const cached = config?.capabilities?.toolCalling?.[toolCapabilityKey(providerId, model)];
26
+ if (cached === "pseudo")
27
+ return "legacy";
28
+ if (cached === "native")
29
+ return "native";
30
+ if (!NATIVE_PROVIDERS.has(providerId))
31
+ return "legacy";
32
+ return getModelMeta(providerId, model).supportsTools ? "native" : "legacy";
33
+ }
34
+ export function withToolCapability(config, providerId, model, capability) {
35
+ const key = toolCapabilityKey(providerId, model);
36
+ return {
37
+ ...config,
38
+ capabilities: {
39
+ ...(config?.capabilities ?? {}),
40
+ toolCalling: {
41
+ ...(config?.capabilities?.toolCalling ?? {}),
42
+ [key]: capability,
43
+ },
44
+ },
45
+ };
46
+ }
47
+ export function isNativeUnsupportedError(message) {
48
+ return /\b400\b/.test(message)
49
+ && /tool|function/i.test(message)
50
+ && /not supported|unsupported|unrecognized|unknown|invalid|does not support/i.test(message);
51
+ }
@@ -0,0 +1,4 @@
1
+ export declare function parseToolCalls(text: any): any[];
2
+ export declare function stripToolCalls(text: any): any;
3
+ export declare function formatToolResults(results: any): string;
4
+ export declare const AGENT_SYSTEM_PROMPT: string;
@@ -0,0 +1,129 @@
1
+ const TOOL_RE = /<fastcode_tool>([\s\S]*?)<\/fastcode_tool>/g;
2
+ // Some models (notably DeepSeek) emit their native "DSML" tool-call markup
3
+ // instead of <fastcode_tool>. The markers look like `<|DSML|invoke ...>`
4
+ // (U+FF5C fullwidth bar, sometimes doubled or spaced). We canonicalize those
5
+ // markers back to plain angle-bracket tags and then parse the
6
+ // calls -> invoke -> parameter structure as a second dialect.
7
+ const DSML_OPEN_RE = /<\s*(?:[||]\s*)+DSML\s*(?:[||]\s*)+/gi;
8
+ const DSML_CLOSE_RE = /<\/\s*(?:[||]\s*)+DSML\s*(?:[||]\s*)+/gi;
9
+ const DSML_BLOCK_RE = /<([a-z_]*calls?)>([\s\S]*?)<\/\1>/gi;
10
+ const DSML_INVOKE_RE = /<invoke\s+name="([^"]+)"\s*>([\s\S]*?)<\/invoke>/gi;
11
+ const DSML_PARAM_RE = /<parameter\s+name="([^"]+)"([^>]*)>([\s\S]*?)<\/parameter>/gi;
12
+ /** Turn the DSML glyph markers into ordinary `<tag>` / `</tag>` tags. */
13
+ function canonicalizeDsml(text) {
14
+ return text.replace(DSML_CLOSE_RE, "</").replace(DSML_OPEN_RE, "<");
15
+ }
16
+ function coerceDsmlValue(attrs, raw) {
17
+ const value = raw.replace(/^\n/, "").replace(/\n$/, "");
18
+ if (/\bstring\s*=\s*"true"/i.test(attrs))
19
+ return value;
20
+ const trimmed = value.trim();
21
+ if (trimmed === "")
22
+ return "";
23
+ try {
24
+ return JSON.parse(trimmed);
25
+ }
26
+ catch {
27
+ if (trimmed === "true")
28
+ return true;
29
+ if (trimmed === "false")
30
+ return false;
31
+ const n = Number(trimmed);
32
+ return Number.isNaN(n) ? value : n;
33
+ }
34
+ }
35
+ function parseDsmlCalls(text) {
36
+ const canonical = canonicalizeDsml(text);
37
+ const bodies = [];
38
+ for (const block of canonical.matchAll(DSML_BLOCK_RE))
39
+ bodies.push(block[2] ?? "");
40
+ if (bodies.length === 0)
41
+ bodies.push(canonical);
42
+ const calls = [];
43
+ for (const body of bodies) {
44
+ for (const invoke of body.matchAll(DSML_INVOKE_RE)) {
45
+ const call = { tool: invoke[1] };
46
+ for (const param of (invoke[2] ?? "").matchAll(DSML_PARAM_RE))
47
+ call[param[1]] = coerceDsmlValue(param[2] ?? "", param[3] ?? "");
48
+ calls.push(call);
49
+ }
50
+ }
51
+ return calls;
52
+ }
53
+ export function parseToolCalls(text) {
54
+ const calls = [];
55
+ for (const match of text.matchAll(TOOL_RE)) {
56
+ const raw = match[1]?.trim();
57
+ if (!raw)
58
+ continue;
59
+ try {
60
+ const parsed = JSON.parse(raw);
61
+ if (typeof parsed.tool === "string")
62
+ calls.push(parsed);
63
+ }
64
+ catch {
65
+ // Ignore malformed tool blocks; the model can correct itself next turn.
66
+ }
67
+ }
68
+ calls.push(...parseDsmlCalls(text));
69
+ return calls;
70
+ }
71
+ export function stripToolCalls(text) {
72
+ return canonicalizeDsml(text).replace(TOOL_RE, "").replace(DSML_BLOCK_RE, "").trim();
73
+ }
74
+ export function formatToolResults(results) {
75
+ const blocks = results.map((r, index) => {
76
+ const status = r.ok ? "ok" : "error";
77
+ return [
78
+ `Tool result ${index + 1} (${status})`,
79
+ `call: ${JSON.stringify(r.call)}`,
80
+ "output:",
81
+ fence(r.output),
82
+ ].join("\n");
83
+ });
84
+ return [
85
+ "FastCode executed the requested local tools. Use these results to continue.",
86
+ ...blocks,
87
+ ].join("\n\n");
88
+ }
89
+ export const AGENT_SYSTEM_PROMPT = `
90
+ You are FastCode Agent, a local coding agent running inside the user's terminal.
91
+ Tools run inside a filesystem sandbox rooted at the current working directory.
92
+ File tools cannot access paths outside that root. Shell commands run with FASTCODE_SANDBOX=1 and FASTCODE_SANDBOX_ROOT set.
93
+
94
+ You can inspect and change the user's machine by emitting exactly one or more tool calls in this format:
95
+ <fastcode_tool>{"tool":"shell","command":"npm test"}</fastcode_tool>
96
+
97
+ Available tools:
98
+ - shell: {"tool":"shell","command":"command to run"}
99
+ - shell with timeout: {"tool":"shell","command":"npm test","timeoutMs":120000}
100
+ - shell poll (long commands return a session id): {"tool":"shell","session_id":"sh_..."}
101
+ Polling returns only new output; use waitMs to wait briefly for more.
102
+ - pwd: {"tool":"pwd"}
103
+ - read_file: {"tool":"read_file","path":"path/to/file"}
104
+ - read_many: {"tool":"read_many","paths":["file1","file2"]}
105
+ - write_file: {"tool":"write_file","path":"path/to/file","content":"full file contents"}
106
+ - append_file: {"tool":"append_file","path":"path/to/file","content":"text to append"}
107
+ - apply_patch: {"tool":"apply_patch","patch":"*** Begin Patch\\n*** Update File: path\\n@@\\n-old\\n+new\\n*** End Patch\\n"}
108
+ - list_files: {"tool":"list_files","path":"optional/path","maxDepth":2,"detail":false}
109
+ - read_file is capped (default 200KB); grep skips files over 1MB. .fastcodeignore is honored.
110
+ - grep: {"tool":"grep","pattern":"text or regex","path":"optional/path"}
111
+ - replace_in_file: {"tool":"replace_in_file","path":"path/to/file","find":"exact text","replace":"replacement"}
112
+ - stat_path: {"tool":"stat_path","path":"path/to/file"}
113
+ - make_dir: {"tool":"make_dir","path":"path/to/dir"}
114
+ - copy_file: {"tool":"copy_file","from":"src","to":"dest"}
115
+ - move_path: {"tool":"move_path","from":"src","to":"dest"}
116
+ - delete_file: {"tool":"delete_file","path":"path/to/file"}
117
+
118
+ Rules:
119
+ - Prefer inspecting files before editing.
120
+ - Use shell for tests, builds, package scripts, git inspection, and OS commands.
121
+ - Use apply_patch or replace_in_file for focused edits.
122
+ - Use write_file only when replacing the whole file is appropriate.
123
+ - Run verification commands after code changes.
124
+ - After tool results come back, continue working until the user's request is done.
125
+ - When done, answer normally without tool calls.
126
+ `.trim();
127
+ function fence(text) {
128
+ return `\`\`\`\n${text}\n\`\`\``;
129
+ }
@@ -0,0 +1,17 @@
1
+ import type { ApprovalDecision } from "./approval.js";
2
+ import type { Tool, ToolCall, ToolCtx, ToolResult } from "./tools/types.js";
3
+ export declare function assertToolContract(tools?: Tool[]): void;
4
+ export declare function toolCatalogHash(tools?: Tool[]): string;
5
+ export declare class ToolRegistry {
6
+ private readonly tools;
7
+ constructor(tools?: Tool[]);
8
+ get(name: string): Tool | undefined;
9
+ list(): Tool[];
10
+ approve(call: ToolCall, ctx: ToolCtx): ApprovalDecision;
11
+ execute(call: ToolCall, ctx: ToolCtx): Promise<ToolResult>;
12
+ }
13
+ export declare const registry: ToolRegistry;
14
+ export declare function runAgentTool(call: ToolCall, cwd?: string, options?: {
15
+ signal?: AbortSignal;
16
+ turn?: number;
17
+ }): Promise<ToolResult>;
@@ -0,0 +1,90 @@
1
+ import { createHash } from "node:crypto";
2
+ import { isTrusted } from "../config/trust.js";
3
+ import { evaluateShellCommand } from "./guards.js";
4
+ import { TOOLS } from "./tools/index.js";
5
+ const STATE_SCOPES = new Set(["call", "turn", "session"]);
6
+ const REVALIDATE_KEYS = new Set(["trust", "sandboxRoots", "schema", "modelCaps"]);
7
+ export function assertToolContract(tools = TOOLS) {
8
+ const names = new Set();
9
+ for (const tool of tools) {
10
+ if (!tool.name || typeof tool.name !== "string")
11
+ throw new Error("tool contract: every tool needs a name");
12
+ if (names.has(tool.name))
13
+ throw new Error(`tool contract: duplicate tool name ${tool.name}`);
14
+ names.add(tool.name);
15
+ if (!STATE_SCOPES.has(tool.stateScope))
16
+ throw new Error(`tool contract: ${tool.name} has an invalid stateScope`);
17
+ for (const key of tool.revalidate ?? []) {
18
+ if (!REVALIDATE_KEYS.has(key))
19
+ throw new Error(`tool contract: ${tool.name} has an invalid revalidate key ${String(key)}`);
20
+ }
21
+ if (tool.requiresTrust && !(tool.revalidate ?? []).includes("trust")) {
22
+ throw new Error(`tool contract: ${tool.name} requiresTrust but does not revalidate "trust"`);
23
+ }
24
+ }
25
+ }
26
+ export function toolCatalogHash(tools = TOOLS) {
27
+ const catalog = tools
28
+ .map((tool) => ({
29
+ name: tool.name,
30
+ trust: Boolean(tool.requiresTrust),
31
+ scope: tool.stateScope,
32
+ revalidate: [...(tool.revalidate ?? [])].sort(),
33
+ }))
34
+ .sort((a, b) => a.name.localeCompare(b.name));
35
+ return createHash("sha1").update(JSON.stringify(catalog)).digest("hex").slice(0, 8);
36
+ }
37
+ export class ToolRegistry {
38
+ tools = new Map();
39
+ constructor(tools = TOOLS) {
40
+ assertToolContract(tools);
41
+ for (const tool of tools)
42
+ this.tools.set(tool.name, tool);
43
+ }
44
+ get(name) {
45
+ return this.tools.get(name);
46
+ }
47
+ list() {
48
+ return Array.from(this.tools.values());
49
+ }
50
+ approve(call, ctx) {
51
+ const tool = this.get(call.tool);
52
+ if (!tool)
53
+ return { kind: "deny", reason: `unknown tool: ${String(call.tool)}` };
54
+ if (tool.name === "shell") {
55
+ const verdict = evaluateShellCommand(call.command);
56
+ if (!verdict.allow)
57
+ return { kind: "deny", reason: verdict.output };
58
+ }
59
+ if ((tool.revalidate ?? []).includes("trust") && !isTrusted(ctx.cwd)) {
60
+ return {
61
+ kind: "deny",
62
+ reason: `project is not trusted: ${ctx.cwd}. Run \`fastcode trust ${ctx.cwd}\` or accept the trust prompt.`,
63
+ };
64
+ }
65
+ return { kind: "allow", scope: "once" };
66
+ }
67
+ async execute(call, ctx) {
68
+ const tool = this.get(call.tool);
69
+ if (!tool)
70
+ return { ok: false, output: `unknown tool: ${String(call.tool)}` };
71
+ const prepared = tool.prepare(call, ctx);
72
+ if (prepared.ok === false)
73
+ return { ok: false, output: prepared.output };
74
+ const decision = this.approve(call, ctx);
75
+ if (decision.kind === "deny")
76
+ return { ok: false, output: decision.reason ?? "denied by approval policy" };
77
+ if (decision.kind === "pending")
78
+ return { ok: false, output: "approval required, but no approval resolver is registered (fail closed)" };
79
+ try {
80
+ return await tool.execute(call, ctx);
81
+ }
82
+ catch (err) {
83
+ return { ok: false, output: err?.message ?? String(err) };
84
+ }
85
+ }
86
+ }
87
+ export const registry = new ToolRegistry();
88
+ export async function runAgentTool(call, cwd = process.cwd(), options = {}) {
89
+ return registry.execute(call, { cwd, signal: options.signal, turn: options.turn });
90
+ }
@@ -0,0 +1,106 @@
1
+ import type { ChatChunk, ChatMessage, NativeToolCall, Provider, ReasoningEffort, ToolSchema } from "../types.js";
2
+ import type { ActiveFile } from "../session/log.js";
3
+ import type { SideEffects } from "./tools/types.js";
4
+ import { type CompactionConfig } from "./compaction.js";
5
+ import { type ToolProtocol } from "./protocol-mode.js";
6
+ export interface ToolCall {
7
+ tool: string;
8
+ [key: string]: any;
9
+ }
10
+ export interface LoopDetectionOptions {
11
+ readOnlyThreshold?: number;
12
+ sideEffectThreshold?: number;
13
+ window?: number;
14
+ exemptReadOnly?: boolean;
15
+ }
16
+ export interface RunOptions {
17
+ provider: Provider;
18
+ apiKey?: string;
19
+ model: string;
20
+ messages?: ChatMessage[];
21
+ prompt: string;
22
+ system?: string;
23
+ maxTurns?: number;
24
+ allowTools?: boolean;
25
+ tokenBudget?: number;
26
+ costBudgetUsd?: number;
27
+ signal?: AbortSignal;
28
+ cwd?: string;
29
+ idleTimeoutMs?: number;
30
+ contextBudgetChars?: number;
31
+ compaction?: CompactionConfig;
32
+ contextWindow?: number;
33
+ serverOpaqueState?: string;
34
+ loopDetection?: LoopDetectionOptions;
35
+ reasoningEffort?: ReasoningEffort;
36
+ protocol?: ToolProtocol;
37
+ tools?: ToolSchema[];
38
+ onProtocolFallback?: (message: string) => void;
39
+ onNativeOk?: () => void;
40
+ takeSteering?: () => string[];
41
+ onDelta?: (delta: string, text: string) => void;
42
+ }
43
+ export type AgentStopReason = "complete" | "max_turns" | "token_budget" | "cost_budget" | "loop_detected" | "aborted" | "incomplete" | "stream_error";
44
+ export type AgentErrorKind = "token_budget" | "cost_budget" | "loop_detected" | "aborted" | "stream_error";
45
+ export type AgentEvent = {
46
+ type: "compaction";
47
+ beforeChars: number;
48
+ afterChars: number;
49
+ beforeTokens: number;
50
+ afterTokens: number;
51
+ droppedMessages: number;
52
+ keptMessages: number;
53
+ reason: "threshold" | "heap";
54
+ source: "local" | "server";
55
+ summaryFile?: string;
56
+ } | {
57
+ type: "assistant_raw";
58
+ text: string;
59
+ toolCalls?: NativeToolCall[];
60
+ } | {
61
+ type: "assistant_text";
62
+ text: string;
63
+ } | {
64
+ type: "tool_call";
65
+ id: string;
66
+ call: ToolCall;
67
+ native?: boolean;
68
+ } | {
69
+ type: "tool_result";
70
+ id: string;
71
+ call: ToolCall;
72
+ ok: boolean;
73
+ output: string;
74
+ sideEffects?: SideEffects;
75
+ } | {
76
+ type: "usage";
77
+ usage: NonNullable<ChatChunk["usage"]>;
78
+ } | {
79
+ type: "loop_detected";
80
+ fingerprint: string;
81
+ occurrences: number;
82
+ warned: boolean;
83
+ } | {
84
+ type: "notice";
85
+ text: string;
86
+ } | {
87
+ type: "error";
88
+ kind: AgentErrorKind;
89
+ message: string;
90
+ text?: string;
91
+ used?: number;
92
+ } | {
93
+ type: "checkpoint";
94
+ turn: number;
95
+ cwd: string;
96
+ providerId: string;
97
+ model: string;
98
+ activeFiles: ActiveFile[];
99
+ } | {
100
+ type: "done";
101
+ history: ChatMessage[];
102
+ finalText: string;
103
+ stopReason: AgentStopReason;
104
+ };
105
+ export declare const LOOP_WARNING: string;
106
+ export declare function runAgent(options: RunOptions): AsyncGenerator<AgentEvent, void, void>;