@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,101 @@
1
+ import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync, } from "node:fs";
2
+ import { basename, join, resolve } from "node:path";
3
+ import { getPaths } from "../config/paths.js";
4
+ export function listInstalledPlugins() {
5
+ const { plugins } = getPaths();
6
+ if (!existsSync(plugins))
7
+ return [];
8
+ return readdirSync(plugins, { withFileTypes: true })
9
+ .filter((entry) => entry.isDirectory())
10
+ .map((entry) => loadPlugin(join(plugins, entry.name), entry.name))
11
+ .filter((plugin) => plugin !== undefined)
12
+ .sort((a, b) => a.name.localeCompare(b.name));
13
+ }
14
+ export function getPlugin(name) {
15
+ return listInstalledPlugins().find((p) => p.name === name || basename(p.path) === name);
16
+ }
17
+ export function importPlugin(source, name) {
18
+ const { plugins } = getPaths();
19
+ const src = resolve(source);
20
+ if (!existsSync(src))
21
+ throw new Error(`Plugin source does not exist: ${source}`);
22
+ if (!statSync(src).isDirectory())
23
+ throw new Error("Plugin source must be a directory");
24
+ const folder = slugify(name ?? basename(src));
25
+ const target = join(plugins, folder);
26
+ if (existsSync(target))
27
+ rmSync(target, { recursive: true, force: true });
28
+ mkdirSync(target, { recursive: true });
29
+ cpSync(src, target, { recursive: true });
30
+ writeFileSync(join(target, ".fastcode-source"), src);
31
+ const loaded = loadPlugin(target, folder);
32
+ if (!loaded)
33
+ throw new Error("Plugin must include PLUGIN.md, README.md, or at least one SKILL.md");
34
+ return loaded;
35
+ }
36
+ export function removePlugin(name) {
37
+ const plugin = getPlugin(name);
38
+ if (!plugin)
39
+ return false;
40
+ rmSync(plugin.path, { recursive: true, force: true });
41
+ return true;
42
+ }
43
+ export function buildPluginsPrompt(enabled) {
44
+ if (enabled.length === 0)
45
+ return "";
46
+ const plugins = enabled.map(getPlugin).filter((p) => p !== undefined);
47
+ if (plugins.length === 0)
48
+ return "";
49
+ const chunks = plugins.map((plugin) => {
50
+ const skills = plugin.skills
51
+ .map((skill) => `<plugin-skill name="${skill.name}">\n${skill.body.trim()}\n</plugin-skill>`)
52
+ .join("\n\n");
53
+ return `<plugin name="${plugin.name}">\n${plugin.body.trim()}\n${skills ? `\n\n${skills}` : ""}\n</plugin>`;
54
+ });
55
+ return [
56
+ "",
57
+ "## Active plugins",
58
+ "The following plugins are always-active behavior packs. Follow them when relevant:",
59
+ "",
60
+ chunks.join("\n\n"),
61
+ ].join("\n");
62
+ }
63
+ function loadPlugin(path, fallbackName) {
64
+ const pluginMd = firstExisting([join(path, "PLUGIN.md"), join(path, "README.md")]);
65
+ const skillsDir = join(path, "skills");
66
+ const rootSkill = join(path, "SKILL.md");
67
+ const skills = [];
68
+ if (existsSync(rootSkill))
69
+ skills.push({ name: "root", body: readFileSync(rootSkill, "utf8") });
70
+ if (existsSync(skillsDir)) {
71
+ for (const entry of readdirSync(skillsDir, { withFileTypes: true })) {
72
+ if (!entry.isDirectory())
73
+ continue;
74
+ const skillPath = join(skillsDir, entry.name, "SKILL.md");
75
+ if (existsSync(skillPath))
76
+ skills.push({ name: entry.name, body: readFileSync(skillPath, "utf8") });
77
+ }
78
+ }
79
+ if (!pluginMd && skills.length === 0)
80
+ return undefined;
81
+ const body = pluginMd ? readFileSync(pluginMd, "utf8") : `Plugin ${fallbackName}`;
82
+ return {
83
+ name: fallbackName,
84
+ description: firstParagraph(body) || `${fallbackName} plugin`,
85
+ path,
86
+ body,
87
+ skills,
88
+ };
89
+ }
90
+ function firstExisting(paths) {
91
+ return paths.find((path) => existsSync(path));
92
+ }
93
+ function firstParagraph(markdown) {
94
+ return markdown
95
+ .split(/\n\s*\n/)
96
+ .map((part) => part.replace(/^#+\s*/, "").trim())
97
+ .find(Boolean);
98
+ }
99
+ function slugify(value) {
100
+ return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "plugin";
101
+ }
@@ -0,0 +1,22 @@
1
+ export declare const anthropicProvider: {
2
+ id: string;
3
+ label: string;
4
+ authEnv: string[];
5
+ baseUrl: string;
6
+ defaultModel: string;
7
+ supportsReasoning(): boolean;
8
+ listModels(apiKey: any): Promise<any>;
9
+ stream(req: any, apiKey: any): AsyncGenerator<{
10
+ delta: any;
11
+ done: boolean;
12
+ usage?: undefined;
13
+ } | {
14
+ delta: string;
15
+ done: boolean;
16
+ usage: {
17
+ inputTokens: number;
18
+ outputTokens: number;
19
+ costUsd: number;
20
+ };
21
+ }, void, unknown>;
22
+ };
@@ -0,0 +1,119 @@
1
+ import { streamSSE } from "../lib/http.js";
2
+ const STATIC_MODELS = [
3
+ { id: "claude-sonnet-5.5", label: "Claude Sonnet 5.5", contextWindow: 1000000, pricing: { inputUsdPerM: 3, outputUsdPerM: 15 } },
4
+ { id: "claude-opus-5.5", label: "Claude Opus 5.5", contextWindow: 1000000, pricing: { inputUsdPerM: 15, outputUsdPerM: 75 } },
5
+ { id: "claude-haiku-5.5", label: "Claude Haiku 5.5", contextWindow: 200000, pricing: { inputUsdPerM: 0.8, outputUsdPerM: 4 } },
6
+ { id: "claude-sonnet-5", label: "Claude Sonnet 5" },
7
+ { id: "claude-opus-5", label: "Claude Opus 5" },
8
+ { id: "claude-sonnet-4.6", label: "Claude Sonnet 4.6" },
9
+ { id: "claude-opus-4.6", label: "Claude Opus 4.6" },
10
+ { id: "claude-haiku-4.5", label: "Claude Haiku 4.5" },
11
+ ];
12
+ const BASE = "https://api.anthropic.com/v1";
13
+ const THINKING_BUDGETS = { low: 1024, medium: 4096, high: 8192, max: 16000 };
14
+ export const anthropicProvider = {
15
+ id: "anthropic",
16
+ label: "Anthropic (Claude)",
17
+ authEnv: ["ANTHROPIC_API_KEY", "CLAUDE_API_KEY"],
18
+ baseUrl: BASE,
19
+ defaultModel: "claude-sonnet-5.5",
20
+ supportsReasoning() {
21
+ return true;
22
+ },
23
+ async listModels(apiKey) {
24
+ // Query the live model list; fall back to the built-in list offline.
25
+ if (apiKey) {
26
+ try {
27
+ const res = await fetch(BASE + "/models", {
28
+ headers: { "x-api-key": apiKey, "anthropic-version": "2023-06-01" },
29
+ });
30
+ if (res.ok) {
31
+ const json = await res.json();
32
+ const ids = (json.data ?? [])
33
+ .map((m) => m.id)
34
+ .filter((id) => typeof id === "string" && id.length > 0);
35
+ if (ids.length > 0) {
36
+ const known = new Map(STATIC_MODELS.map((m) => [m.id, m]));
37
+ return ids.map((id) => known.get(id) ?? { id });
38
+ }
39
+ }
40
+ }
41
+ catch {
42
+ // network/auth issue → fall through to the static list
43
+ }
44
+ }
45
+ return STATIC_MODELS;
46
+ },
47
+ async *stream(req, apiKey) {
48
+ if (!apiKey) {
49
+ throw new Error("Missing ANTHROPIC_API_KEY. Bind one with /login anthropic <model> <key>, or set the env var.");
50
+ }
51
+ const messages = req.messages.map((m) => ({ role: m.role, content: m.content }));
52
+ const body = {
53
+ model: req.model,
54
+ messages,
55
+ ...(req.system ? { system: req.system } : {}),
56
+ stream: true,
57
+ max_tokens: req.maxOutputTokens ?? 4096,
58
+ ...(req.temperature !== undefined ? { temperature: req.temperature } : {}),
59
+ };
60
+ if (req.reasoningEffort && req.reasoningEffort !== "auto") {
61
+ const budget = THINKING_BUDGETS[req.reasoningEffort] ?? THINKING_BUDGETS.medium;
62
+ body.thinking = { type: "enabled", budget_tokens: budget };
63
+ // max_tokens must exceed the thinking budget.
64
+ body.max_tokens = Math.max(body.max_tokens, budget + 1024);
65
+ // Extended thinking is incompatible with a custom temperature.
66
+ delete body.temperature;
67
+ }
68
+ const res = await fetch(BASE + "/messages", {
69
+ method: "POST",
70
+ headers: {
71
+ "content-type": "application/json",
72
+ "x-api-key": apiKey,
73
+ "anthropic-version": "2023-06-01",
74
+ accept: "text/event-stream",
75
+ },
76
+ body: JSON.stringify(body),
77
+ signal: req.signal,
78
+ });
79
+ let usageInput = 0;
80
+ let usageOutput = 0;
81
+ for await (const ev of streamSSE(res)) {
82
+ let data;
83
+ try {
84
+ data = JSON.parse(ev.data);
85
+ }
86
+ catch {
87
+ continue;
88
+ }
89
+ const t = data.type;
90
+ if (t === "content_block_delta") {
91
+ const delta = data.delta?.text;
92
+ if (delta)
93
+ yield { delta, done: false };
94
+ }
95
+ else if (t === "message_start") {
96
+ const u = data.message?.usage;
97
+ if (u?.input_tokens)
98
+ usageInput = u.input_tokens;
99
+ }
100
+ else if (t === "message_delta") {
101
+ const u = data.usage;
102
+ if (u?.output_tokens)
103
+ usageOutput = u.output_tokens;
104
+ }
105
+ else if (t === "message_stop") {
106
+ break;
107
+ }
108
+ }
109
+ const cost = priceFor(req.model, usageInput, usageOutput);
110
+ yield { delta: "", done: true, usage: { inputTokens: usageInput, outputTokens: usageOutput, costUsd: cost } };
111
+ },
112
+ };
113
+ function priceFor(modelId, input, output) {
114
+ const m = STATIC_MODELS.find((x) => x.id === modelId);
115
+ const p = m?.pricing;
116
+ if (!p?.inputUsdPerM || !p.outputUsdPerM)
117
+ return undefined;
118
+ return (input / 1000000) * p.inputUsdPerM + (output / 1000000) * p.outputUsdPerM;
119
+ }
@@ -0,0 +1,33 @@
1
+ export declare const customProvider: {
2
+ id: string;
3
+ label: string;
4
+ authEnv: any[];
5
+ readonly baseUrl: string;
6
+ defaultModel: string;
7
+ listModels: () => Promise<any>;
8
+ stream: (req: any) => AsyncGenerator<{
9
+ delta: string;
10
+ done: boolean;
11
+ reasoning?: undefined;
12
+ usage?: undefined;
13
+ toolCalls?: undefined;
14
+ } | {
15
+ delta: string;
16
+ done: boolean;
17
+ reasoning: string;
18
+ usage?: undefined;
19
+ toolCalls?: undefined;
20
+ } | {
21
+ delta: string;
22
+ done: boolean;
23
+ usage: any;
24
+ toolCalls: import("../types.js").NativeToolCall[];
25
+ reasoning?: undefined;
26
+ } | {
27
+ delta: string;
28
+ done: boolean;
29
+ usage: any;
30
+ reasoning?: undefined;
31
+ toolCalls?: undefined;
32
+ }, void, unknown>;
33
+ };
@@ -0,0 +1,25 @@
1
+ import { listModelsHttp, streamChatCompletion } from "./openaiCompatible.js";
2
+ function baseUrl() {
3
+ return (process.env["FASTCODE_BASE_URL"] ?? "").trim().replace(/[/]+$/, "");
4
+ }
5
+ function defaultModel() {
6
+ return (process.env["FASTCODE_MODEL"] ?? "").trim() || "gpt-4o-mini";
7
+ }
8
+ function requireBaseUrl() {
9
+ const base = baseUrl();
10
+ if (!base) {
11
+ throw new Error("FASTCODE_BASE_URL is not set. Example: export FASTCODE_BASE_URL=https://api.example.com/v1");
12
+ }
13
+ return base;
14
+ }
15
+ export const customProvider = {
16
+ id: "custom",
17
+ label: "Custom (OpenAI-compatible)",
18
+ authEnv: [],
19
+ get baseUrl() {
20
+ return baseUrl();
21
+ },
22
+ defaultModel: defaultModel(),
23
+ listModels: () => listModelsHttp({ baseUrl: requireBaseUrl(), apiKey: process.env["FASTCODE_API_KEY"], staticModels: [] }),
24
+ stream: (req) => streamChatCompletion(req, { baseUrl: requireBaseUrl(), apiKey: process.env["FASTCODE_API_KEY"], staticModels: [] }),
25
+ };
@@ -0,0 +1,34 @@
1
+ export declare const deepseekProvider: {
2
+ id: string;
3
+ label: string;
4
+ authEnv: string[];
5
+ baseUrl: string;
6
+ defaultModel: string;
7
+ listModels: (apiKey: any) => Promise<any>;
8
+ stream: (req: any, apiKey: any) => AsyncGenerator<{
9
+ delta: string;
10
+ done: boolean;
11
+ reasoning?: undefined;
12
+ usage?: undefined;
13
+ toolCalls?: undefined;
14
+ } | {
15
+ delta: string;
16
+ done: boolean;
17
+ reasoning: string;
18
+ usage?: undefined;
19
+ toolCalls?: undefined;
20
+ } | {
21
+ delta: string;
22
+ done: boolean;
23
+ usage: any;
24
+ toolCalls: import("../types.js").NativeToolCall[];
25
+ reasoning?: undefined;
26
+ } | {
27
+ delta: string;
28
+ done: boolean;
29
+ usage: any;
30
+ reasoning?: undefined;
31
+ toolCalls?: undefined;
32
+ }, void, unknown>;
33
+ supportsReasoning: () => boolean;
34
+ };
@@ -0,0 +1,16 @@
1
+ import { listModelsHttp, streamChatCompletion } from "./openaiCompatible.js";
2
+ const BASE = "https://api.deepseek.com/v1";
3
+ const STATIC = [
4
+ { id: "deepseek-v4-pro", label: "DeepSeek V4 Pro" },
5
+ { id: "deepseek-flash", label: "DeepSeek Flash" },
6
+ ];
7
+ export const deepseekProvider = {
8
+ id: "deepseek",
9
+ label: "DeepSeek",
10
+ authEnv: ["DEEPSEEK_API_KEY"],
11
+ baseUrl: BASE,
12
+ defaultModel: "deepseek-v4-pro",
13
+ listModels: (apiKey) => listModelsHttp({ baseUrl: BASE, apiKey, staticModels: STATIC }),
14
+ stream: (req, apiKey) => streamChatCompletion(req, { baseUrl: BASE, apiKey, staticModels: STATIC, reasoning: "openai" }),
15
+ supportsReasoning: () => true,
16
+ };
@@ -0,0 +1,33 @@
1
+ export declare const googleProvider: {
2
+ id: string;
3
+ label: string;
4
+ authEnv: string[];
5
+ baseUrl: string;
6
+ defaultModel: string;
7
+ listModels: (apiKey: any) => Promise<any>;
8
+ stream: (req: any, apiKey: any) => AsyncGenerator<{
9
+ delta: string;
10
+ done: boolean;
11
+ reasoning?: undefined;
12
+ usage?: undefined;
13
+ toolCalls?: undefined;
14
+ } | {
15
+ delta: string;
16
+ done: boolean;
17
+ reasoning: string;
18
+ usage?: undefined;
19
+ toolCalls?: undefined;
20
+ } | {
21
+ delta: string;
22
+ done: boolean;
23
+ usage: any;
24
+ toolCalls: import("../types.js").NativeToolCall[];
25
+ reasoning?: undefined;
26
+ } | {
27
+ delta: string;
28
+ done: boolean;
29
+ usage: any;
30
+ reasoning?: undefined;
31
+ toolCalls?: undefined;
32
+ }, void, unknown>;
33
+ };
@@ -0,0 +1,19 @@
1
+ import { listModelsHttp, streamChatCompletion } from "./openaiCompatible.js";
2
+ const BASE = "https://generativelanguage.googleapis.com/v1beta/openai";
3
+ const STATIC = [
4
+ { id: "gemini-3.8-flash", label: "Gemini 3.8 Flash" },
5
+ { id: "gemini-3.7-flash", label: "Gemini 3.7 Flash" },
6
+ { id: "gemini-3.5-flash", label: "Gemini 3.5 Flash" },
7
+ { id: "gemini-3.5-flash-lite", label: "Gemini 3.5 Flash Lite" },
8
+ { id: "gemini-3.1-flash-lite", label: "Gemini 3.1 Flash Lite" },
9
+ { id: "gemini-4-argon", label: "Gemini 4 Argon" },
10
+ ];
11
+ export const googleProvider = {
12
+ id: "google",
13
+ label: "Google Gemini",
14
+ authEnv: ["GEMINI_API_KEY", "GOOGLE_API_KEY"],
15
+ baseUrl: BASE,
16
+ defaultModel: "gemini-3.8-flash",
17
+ listModels: (apiKey) => listModelsHttp({ baseUrl: BASE, apiKey, staticModels: STATIC }),
18
+ stream: (req, apiKey) => streamChatCompletion(req, { baseUrl: BASE, apiKey, staticModels: STATIC }),
19
+ };
@@ -0,0 +1,34 @@
1
+ export declare const groqProvider: {
2
+ id: string;
3
+ label: string;
4
+ authEnv: string[];
5
+ baseUrl: string;
6
+ defaultModel: string;
7
+ listModels: (apiKey: any) => Promise<any>;
8
+ stream: (req: any, apiKey: any) => AsyncGenerator<{
9
+ delta: string;
10
+ done: boolean;
11
+ reasoning?: undefined;
12
+ usage?: undefined;
13
+ toolCalls?: undefined;
14
+ } | {
15
+ delta: string;
16
+ done: boolean;
17
+ reasoning: string;
18
+ usage?: undefined;
19
+ toolCalls?: undefined;
20
+ } | {
21
+ delta: string;
22
+ done: boolean;
23
+ usage: any;
24
+ toolCalls: import("../types.js").NativeToolCall[];
25
+ reasoning?: undefined;
26
+ } | {
27
+ delta: string;
28
+ done: boolean;
29
+ usage: any;
30
+ reasoning?: undefined;
31
+ toolCalls?: undefined;
32
+ }, void, unknown>;
33
+ supportsReasoning: () => boolean;
34
+ };
@@ -0,0 +1,21 @@
1
+ import { listModelsHttp, streamChatCompletion } from "./openaiCompatible.js";
2
+ const BASE = "https://api.groq.com/openai/v1";
3
+ const STATIC = [
4
+ { id: "llama-3.3-70b-versatile", label: "Llama 3.3 70B" },
5
+ { id: "meta-llama/llama-4-maverick-17b-128e-instruct", label: "Llama 4 Maverick" },
6
+ { id: "meta-llama/llama-4-scout-17b-16e-instruct", label: "Llama 4 Scout" },
7
+ { id: "moonshotai/kimi-k2-instruct", label: "Kimi K2" },
8
+ { id: "openai/gpt-oss-120b", label: "GPT-OSS 120B" },
9
+ { id: "qwen/qwen3-32b", label: "Qwen3 32B" },
10
+ { id: "llama-3.1-8b-instant", label: "Llama 3.1 8B instant" },
11
+ ];
12
+ export const groqProvider = {
13
+ id: "groq",
14
+ label: "Groq",
15
+ authEnv: ["GROQ_API_KEY"],
16
+ baseUrl: BASE,
17
+ defaultModel: "llama-3.3-70b-versatile",
18
+ listModels: (apiKey) => listModelsHttp({ baseUrl: BASE, apiKey, staticModels: STATIC }),
19
+ stream: (req, apiKey) => streamChatCompletion(req, { baseUrl: BASE, apiKey, staticModels: STATIC, reasoning: "openai" }),
20
+ supportsReasoning: () => true,
21
+ };
@@ -0,0 +1,10 @@
1
+ import type { Provider } from "../types.js";
2
+ export declare const PROVIDERS: Provider[];
3
+ export declare function getProvider(id: any): Provider;
4
+ export declare function getProviderOrThrow(id: any): Provider;
5
+ /**
6
+ * Cheap connectivity check used by the model picker to label a list "offline".
7
+ * `listModels()` silently falls back to the static list, so without this probe
8
+ * the UI cannot tell a live catalog from a cached one.
9
+ */
10
+ export declare function probeProvider(provider: any, apiKey: any, timeoutMs?: number): Promise<boolean>;
@@ -0,0 +1,67 @@
1
+ import { anthropicProvider } from "./anthropic.js";
2
+ import { openaiProvider } from "./openai.js";
3
+ import { googleProvider } from "./google.js";
4
+ import { openrouterProvider } from "./openrouter.js";
5
+ import { groqProvider } from "./groq.js";
6
+ import { deepseekProvider } from "./deepseek.js";
7
+ import { mistralProvider } from "./mistral.js";
8
+ import { ollamaProvider } from "./ollama.js";
9
+ import { xaiProvider } from "./xai.js";
10
+ import { moonshotProvider } from "./moonshot.js";
11
+ import { zhipuProvider } from "./zhipu.js";
12
+ import { qwenProvider } from "./qwen.js";
13
+ import { customProvider } from "./custom.js";
14
+ export const PROVIDERS = [
15
+ anthropicProvider,
16
+ openaiProvider,
17
+ googleProvider,
18
+ deepseekProvider,
19
+ openrouterProvider,
20
+ groqProvider,
21
+ mistralProvider,
22
+ xaiProvider,
23
+ moonshotProvider,
24
+ zhipuProvider,
25
+ qwenProvider,
26
+ ollamaProvider,
27
+ customProvider,
28
+ ];
29
+ export function getProvider(id) {
30
+ return PROVIDERS.find((p) => p.id === id);
31
+ }
32
+ export function getProviderOrThrow(id) {
33
+ const p = getProvider(id);
34
+ if (!p)
35
+ throw new Error("Unknown provider: " + id);
36
+ return p;
37
+ }
38
+ /**
39
+ * Cheap connectivity check used by the model picker to label a list "offline".
40
+ * `listModels()` silently falls back to the static list, so without this probe
41
+ * the UI cannot tell a live catalog from a cached one.
42
+ */
43
+ export async function probeProvider(provider, apiKey, timeoutMs = 4000) {
44
+ const controller = new AbortController();
45
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
46
+ try {
47
+ const base = String(provider.baseUrl).replace(/[/]+$/, "");
48
+ const headers = { accept: "application/json" };
49
+ if (apiKey) {
50
+ if (provider.id === "anthropic") {
51
+ headers["x-api-key"] = apiKey;
52
+ headers["anthropic-version"] = "2023-06-01";
53
+ }
54
+ else {
55
+ headers["authorization"] = "Bearer " + apiKey;
56
+ }
57
+ }
58
+ const res = await fetch(base + "/models", { headers, signal: controller.signal });
59
+ return res.ok;
60
+ }
61
+ catch {
62
+ return false;
63
+ }
64
+ finally {
65
+ clearTimeout(timer);
66
+ }
67
+ }
@@ -0,0 +1,34 @@
1
+ export declare const mistralProvider: {
2
+ id: string;
3
+ label: string;
4
+ authEnv: string[];
5
+ baseUrl: string;
6
+ defaultModel: string;
7
+ listModels: (apiKey: any) => Promise<any>;
8
+ stream: (req: any, apiKey: any) => AsyncGenerator<{
9
+ delta: string;
10
+ done: boolean;
11
+ reasoning?: undefined;
12
+ usage?: undefined;
13
+ toolCalls?: undefined;
14
+ } | {
15
+ delta: string;
16
+ done: boolean;
17
+ reasoning: string;
18
+ usage?: undefined;
19
+ toolCalls?: undefined;
20
+ } | {
21
+ delta: string;
22
+ done: boolean;
23
+ usage: any;
24
+ toolCalls: import("../types.js").NativeToolCall[];
25
+ reasoning?: undefined;
26
+ } | {
27
+ delta: string;
28
+ done: boolean;
29
+ usage: any;
30
+ reasoning?: undefined;
31
+ toolCalls?: undefined;
32
+ }, void, unknown>;
33
+ supportsReasoning: () => boolean;
34
+ };
@@ -0,0 +1,20 @@
1
+ import { listModelsHttp, streamChatCompletion } from "./openaiCompatible.js";
2
+ const BASE = "https://api.mistral.ai/v1";
3
+ const STATIC = [
4
+ { id: "mistral-large-latest", label: "Mistral Large" },
5
+ { id: "mistral-medium-latest", label: "Mistral Medium" },
6
+ { id: "mistral-small-latest", label: "Mistral Small" },
7
+ { id: "codestral-latest", label: "Codestral" },
8
+ { id: "devstral-medium-latest", label: "Devstral" },
9
+ { id: "magistral-medium-latest", label: "Magistral" },
10
+ ];
11
+ export const mistralProvider = {
12
+ id: "mistral",
13
+ label: "Mistral",
14
+ authEnv: ["MISTRAL_API_KEY"],
15
+ baseUrl: BASE,
16
+ defaultModel: "mistral-small-latest",
17
+ listModels: (apiKey) => listModelsHttp({ baseUrl: BASE, apiKey, staticModels: STATIC }),
18
+ stream: (req, apiKey) => streamChatCompletion(req, { baseUrl: BASE, apiKey, staticModels: STATIC, reasoning: "openai" }),
19
+ supportsReasoning: () => true,
20
+ };
@@ -0,0 +1,34 @@
1
+ export declare const moonshotProvider: {
2
+ id: string;
3
+ label: string;
4
+ authEnv: string[];
5
+ readonly baseUrl: string;
6
+ defaultModel: string;
7
+ listModels: (apiKey: any) => Promise<any>;
8
+ stream: (req: any, apiKey: any) => AsyncGenerator<{
9
+ delta: string;
10
+ done: boolean;
11
+ reasoning?: undefined;
12
+ usage?: undefined;
13
+ toolCalls?: undefined;
14
+ } | {
15
+ delta: string;
16
+ done: boolean;
17
+ reasoning: string;
18
+ usage?: undefined;
19
+ toolCalls?: undefined;
20
+ } | {
21
+ delta: string;
22
+ done: boolean;
23
+ usage: any;
24
+ toolCalls: import("../types.js").NativeToolCall[];
25
+ reasoning?: undefined;
26
+ } | {
27
+ delta: string;
28
+ done: boolean;
29
+ usage: any;
30
+ reasoning?: undefined;
31
+ toolCalls?: undefined;
32
+ }, void, unknown>;
33
+ supportsReasoning: () => boolean;
34
+ };
@@ -0,0 +1,23 @@
1
+ import { listModelsHttp, streamChatCompletion } from "./openaiCompatible.js";
2
+ function baseUrl() {
3
+ return (process.env["MOONSHOT_BASE_URL"] ?? "").trim() || "https://api.moonshot.cn/v1";
4
+ }
5
+ const STATIC = [
6
+ { id: "kimi-k3", label: "Kimi K3" },
7
+ { id: "kimi-k2.7-code", label: "Kimi K2.7 Code" },
8
+ { id: "kimi-k2.6", label: "Kimi K2.6" },
9
+ { id: "kimi-k2-thinking", label: "Kimi K2 Thinking" },
10
+ { id: "kimi-k2-0905", label: "Kimi K2 0905" },
11
+ ];
12
+ export const moonshotProvider = {
13
+ id: "moonshot",
14
+ label: "Moonshot (Kimi)",
15
+ authEnv: ["MOONSHOT_API_KEY"],
16
+ get baseUrl() {
17
+ return baseUrl();
18
+ },
19
+ defaultModel: "kimi-k3",
20
+ listModels: (apiKey) => listModelsHttp({ baseUrl: baseUrl(), apiKey, staticModels: STATIC }),
21
+ stream: (req, apiKey) => streamChatCompletion(req, { baseUrl: baseUrl(), apiKey, staticModels: STATIC, reasoning: "openai" }),
22
+ supportsReasoning: () => true,
23
+ };