@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,52 @@
1
+ import { PROVIDERS, getProvider } from "../providers/index.js";
2
+ import { listCredentials, listLegacy, maskKey, resolveApiKey } from "../config/store.js";
3
+ export const whoamiCommand = {
4
+ name: "whoami",
5
+ description: "Show which provider/model keys are configured.",
6
+ run({ state }) {
7
+ const lines = ["Authentication status:", ` current scope: ${state.providerId} · ${state.model}`];
8
+ const current = getProvider(state.providerId);
9
+ if (current)
10
+ lines.push(" " + describeLookup(current, resolveApiKey(current.id, state.model, current.authEnv)));
11
+ const credentials = listCredentials();
12
+ lines.push("");
13
+ lines.push(`Stored keys (${credentials.length}, provider-wide):`);
14
+ if (credentials.length === 0)
15
+ lines.push(" (none) — add one with /login");
16
+ for (const c of credentials) {
17
+ const marker = c.provider === state.providerId ? "● " : " ";
18
+ const origin = c.model ? ` (originally saved for ${c.model})` : "";
19
+ lines.push(`${marker}${c.provider} ${maskKey(c.key)}${origin}`);
20
+ }
21
+ const legacy = listLegacy();
22
+ if (legacy.length > 0) {
23
+ lines.push("");
24
+ lines.push("Legacy keys (could not be migrated — re-save with /login):");
25
+ for (const l of legacy)
26
+ lines.push(` ${l.provider} ${maskKey(l.key)}`);
27
+ }
28
+ const envLines = [];
29
+ for (const p of PROVIDERS) {
30
+ const envVar = p.authEnv.find((v) => process.env[v]);
31
+ if (envVar)
32
+ envLines.push(` ${envVar} (${p.id}, any model)`);
33
+ }
34
+ if (envLines.length > 0) {
35
+ lines.push("");
36
+ lines.push("Environment keys:");
37
+ lines.push(...envLines);
38
+ }
39
+ return { message: lines.join("\n") };
40
+ },
41
+ };
42
+ function describeLookup(provider, lookup) {
43
+ if (provider.authEnv.length === 0)
44
+ return `${provider.id}: no key needed`;
45
+ if (lookup.status === "ok")
46
+ return lookup.source === "env"
47
+ ? `${provider.id}: env ${lookup.envVar}`
48
+ : `${provider.id}: stored ${maskKey(lookup.key)}`;
49
+ if (lookup.status === "unbound")
50
+ return `${provider.id}: NO bound key (a stored legacy key needs re-binding)`;
51
+ return `${provider.id}: no key — /login ${provider.id} <model> <key>`;
52
+ }
@@ -0,0 +1,4 @@
1
+ export declare function getPaths(): any;
2
+ export declare function ensureDir(dir: any): void;
3
+ /** Tighten permissions on a file storing secrets where the OS supports it. */
4
+ export declare function lockdown(file: any): void;
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Filesystem layout for FastCode user data.
3
+ *
4
+ * ~/.fastcode/
5
+ * config.json global preferences (provider, model, theme, …)
6
+ * auth.json per-provider API keys (mode 0600)
7
+ * skills/ installed SKILL.md folders
8
+ * plugins/ installed plugin folders
9
+ * cache/ transient downloads & registry caches
10
+ * sessions/ conversation transcripts (future)
11
+ * logs/ debug logs (future)
12
+ *
13
+ * On Windows we keep using `~/.fastcode` rather than %APPDATA% to match the
14
+ * dotfile convention most TUIs use; users can override via $FASTCODE_HOME.
15
+ */
16
+ import { join } from "node:path";
17
+ import { mkdirSync, existsSync, chmodSync } from "node:fs";
18
+ import { safeHome, isWindows } from "../lib/platform.js";
19
+ let cached;
20
+ export function getPaths() {
21
+ if (cached)
22
+ return cached;
23
+ const root = process.env["FASTCODE_HOME"] ?? join(safeHome(), ".fastcode");
24
+ const paths = {
25
+ root,
26
+ config: join(root, "config.json"),
27
+ auth: join(root, "auth.json"),
28
+ trust: join(root, "trusted.json"),
29
+ skills: join(root, "skills"),
30
+ plugins: join(root, "plugins"),
31
+ cache: join(root, "cache"),
32
+ sessions: join(root, "sessions"),
33
+ logs: join(root, "logs"),
34
+ };
35
+ ensureDir(paths.root);
36
+ ensureDir(paths.skills);
37
+ ensureDir(paths.plugins);
38
+ ensureDir(paths.cache);
39
+ ensureDir(paths.sessions);
40
+ ensureDir(paths.logs);
41
+ cached = paths;
42
+ return paths;
43
+ }
44
+ export function ensureDir(dir) {
45
+ if (!existsSync(dir))
46
+ mkdirSync(dir, { recursive: true });
47
+ }
48
+ /** Tighten permissions on a file storing secrets where the OS supports it. */
49
+ export function lockdown(file) {
50
+ if (isWindows())
51
+ return;
52
+ try {
53
+ chmodSync(file, 0o600);
54
+ }
55
+ catch {
56
+ // best effort; some filesystems (FAT, Termux on internal storage) don't
57
+ // honor chmod and that's fine.
58
+ }
59
+ }
@@ -0,0 +1,89 @@
1
+ export declare const DEFAULT_CONFIG: {
2
+ providerId: string;
3
+ model: string;
4
+ theme: string;
5
+ agentMode: boolean;
6
+ systemPrompt: string;
7
+ enabledSkills: any[];
8
+ enabledPlugins: any[];
9
+ skillsRegistry: string;
10
+ lifetimeCostUsd: number;
11
+ /**
12
+ * Extra directories the file tools may read and write outside the project
13
+ * root. Relative entries are resolved against the project root; `~/` is
14
+ * expanded against the user's home directory.
15
+ */
16
+ sharedDirs: any[];
17
+ /** Maximum agent tool turns before the loop asks the user to continue. */
18
+ maxAgentTurns: number;
19
+ /** Abort a stream that receives no data for this long (ms). */
20
+ requestIdleTimeoutMs: number;
21
+ /** Approximate character budget before history compaction kicks in. */
22
+ contextBudgetChars: number;
23
+ /** Thinking depth: auto = send nothing, provider default. */
24
+ reasoningEffort: string;
25
+ /** Cached per-provider/model capabilities (native vs pseudo tool calling). */
26
+ capabilities: {
27
+ toolCalling: {};
28
+ };
29
+ };
30
+ export interface StoredCredential {
31
+ provider: string;
32
+ /** Model the key was originally saved for (display only; keys are provider-wide). */
33
+ model?: string;
34
+ key: string;
35
+ addedAt: string;
36
+ }
37
+ export interface AuthStore {
38
+ version: number;
39
+ /** Provider-scoped credentials, keyed by provider id. */
40
+ keys: Record<string, StoredCredential>;
41
+ /** Old provider-only keys that could not be migrated (kept for diagnostics). */
42
+ legacy: Record<string, string>;
43
+ }
44
+ export declare const AUTH_VERSION = 3;
45
+ export type KeyLookup = {
46
+ status: "ok";
47
+ key: string;
48
+ source: "file" | "env";
49
+ envVar?: string;
50
+ } | {
51
+ status: "unbound";
52
+ provider: string;
53
+ legacyKey: string;
54
+ } | {
55
+ status: "missing";
56
+ };
57
+ export declare function loadConfig(): any;
58
+ export declare function saveConfig(cfg: any): void;
59
+ /** Composite id used by the legacy v2 format; kept for API compatibility. */
60
+ export declare function scopeId(providerId: any, model: any): string;
61
+ export declare function loadAuth(): AuthStore;
62
+ export declare function saveAuth(store: AuthStore): void;
63
+ export declare function getCredential(providerId: any, _model?: any): StoredCredential | undefined;
64
+ export declare function listCredentials(): StoredCredential[];
65
+ export declare function listLegacy(): Array<{
66
+ provider: string;
67
+ key: string;
68
+ }>;
69
+ export declare function getLegacy(providerId: any): string | undefined;
70
+ /** Save/replace the provider-wide credential (drops any legacy key). */
71
+ export declare function setCredential(providerId: any, model: any, key: any): StoredCredential;
72
+ export declare function removeCredential(providerId: any, _model?: any): boolean;
73
+ /** Remove the provider-wide credential plus any legacy leftovers. */
74
+ export declare function removeCredentialsForProvider(providerId: any): number;
75
+ /** Turn a key into a safe terminal echo: `sk-****abcd`. */
76
+ export declare function maskKey(key: any): string;
77
+ /**
78
+ * Resolve the key to use for a provider:
79
+ * 1. the provider-wide credential in auth.json,
80
+ * 2. the provider's environment variable (provider-scoped, any model), and
81
+ * 3. a legacy provider-only key that somehow escaped migration.
82
+ */
83
+ export declare function resolveApiKey(providerId: any, _model: any, envVars: any): KeyLookup;
84
+ /** Best-effort key for a provider regardless of model (used to list models). */
85
+ export declare function resolveProviderKey(providerId: any, envVars: any): {
86
+ key?: string;
87
+ source?: "file" | "env";
88
+ envVar?: string;
89
+ };
@@ -0,0 +1,260 @@
1
+ /**
2
+ * Persistent config & auth store.
3
+ *
4
+ * We deliberately keep the format human-readable JSON so users on Termux can
5
+ * edit it from `nano ~/.fastcode/config.json` if needed. Atomic writes prevent
6
+ * partial files on Ctrl+C.
7
+ *
8
+ * API keys are scoped to a provider, not to a model. auth.json stores one
9
+ * credential per provider id, so switching between models of the same provider
10
+ * reuses the same key. The old "provider::model" (v2) and provider-only (v1)
11
+ * formats are read and migrated to the provider-scoped v3 layout on first load.
12
+ */
13
+ import { readFileSync, writeFileSync, existsSync, renameSync, copyFileSync } from "node:fs";
14
+ import { join, dirname } from "node:path";
15
+ import { getPaths, lockdown, ensureDir } from "./paths.js";
16
+ import { DEFAULT_THEME } from "./themes.js";
17
+ export const DEFAULT_CONFIG = {
18
+ providerId: "anthropic",
19
+ model: "claude-sonnet-5.5",
20
+ theme: DEFAULT_THEME,
21
+ agentMode: true,
22
+ systemPrompt: "You are FastCode, a fast, friendly coding assistant in a terminal UI. " +
23
+ "Prefer concise responses. Use markdown when helpful (especially fenced " +
24
+ "code blocks). When the user asks for code changes, output complete files " +
25
+ "or unified diffs the user can apply.",
26
+ enabledSkills: [],
27
+ enabledPlugins: [],
28
+ skillsRegistry: "https://skillshub.wtf",
29
+ lifetimeCostUsd: 0,
30
+ /**
31
+ * Extra directories the file tools may read and write outside the project
32
+ * root. Relative entries are resolved against the project root; `~/` is
33
+ * expanded against the user's home directory.
34
+ */
35
+ sharedDirs: [],
36
+ /** Maximum agent tool turns before the loop asks the user to continue. */
37
+ maxAgentTurns: 24,
38
+ /** Abort a stream that receives no data for this long (ms). */
39
+ requestIdleTimeoutMs: 60_000,
40
+ /** Approximate character budget before history compaction kicks in. */
41
+ contextBudgetChars: 400_000,
42
+ /** Thinking depth: auto = send nothing, provider default. */
43
+ reasoningEffort: "auto",
44
+ /** Cached per-provider/model capabilities (native vs pseudo tool calling). */
45
+ capabilities: {
46
+ toolCalling: {},
47
+ },
48
+ };
49
+ export const AUTH_VERSION = 3;
50
+ export function loadConfig() {
51
+ const { config } = getPaths();
52
+ if (!existsSync(config))
53
+ return { ...DEFAULT_CONFIG };
54
+ try {
55
+ const raw = JSON.parse(readFileSync(config, "utf8"));
56
+ return { ...DEFAULT_CONFIG, ...raw };
57
+ }
58
+ catch {
59
+ return { ...DEFAULT_CONFIG };
60
+ }
61
+ }
62
+ export function saveConfig(cfg) {
63
+ const { config } = getPaths();
64
+ atomicWrite(config, JSON.stringify(cfg, null, 2));
65
+ }
66
+ /** Composite id used by the legacy v2 format; kept for API compatibility. */
67
+ export function scopeId(providerId, model) {
68
+ return `${providerId}::${model}`;
69
+ }
70
+ /** Pick the most recently saved credential when several legacy scopes map to one provider. */
71
+ function keepNewest(keys, credential) {
72
+ const existing = keys[credential.provider];
73
+ if (!existing) {
74
+ keys[credential.provider] = credential;
75
+ return;
76
+ }
77
+ const previous = Date.parse(existing.addedAt || "") || 0;
78
+ const next = Date.parse(credential.addedAt || "") || 0;
79
+ if (next > previous)
80
+ keys[credential.provider] = credential;
81
+ }
82
+ let migrationChecked = false;
83
+ export function loadAuth() {
84
+ const { auth } = getPaths();
85
+ const empty = { version: AUTH_VERSION, keys: {}, legacy: {} };
86
+ if (!existsSync(auth))
87
+ return empty;
88
+ let raw;
89
+ try {
90
+ raw = JSON.parse(readFileSync(auth, "utf8"));
91
+ }
92
+ catch {
93
+ return empty;
94
+ }
95
+ if (!raw || typeof raw !== "object")
96
+ return empty;
97
+ const keys = {};
98
+ const legacy = {};
99
+ let migrated = false;
100
+ const source = raw.keys && typeof raw.keys === "object" ? raw.keys : {};
101
+ for (const [id, value] of Object.entries(source)) {
102
+ if (value && typeof value === "object" && typeof value.key === "string" && value.key.trim()) {
103
+ const [idProvider, idModel] = id.split("::");
104
+ const provider = typeof value.provider === "string" && value.provider ? value.provider : idProvider || id;
105
+ const model = typeof value.model === "string" ? value.model : idModel || "";
106
+ if (id.includes("::") || raw.version !== AUTH_VERSION)
107
+ migrated = true;
108
+ keepNewest(keys, {
109
+ provider,
110
+ model,
111
+ key: value.key,
112
+ addedAt: typeof value.addedAt === "string" ? value.addedAt : "",
113
+ });
114
+ }
115
+ else if (typeof value === "string" && value.trim()) {
116
+ // v1: keys were plain provider -> key strings.
117
+ keepNewest(keys, { provider: id, key: value, addedAt: "" });
118
+ migrated = true;
119
+ }
120
+ }
121
+ if (raw.legacy && typeof raw.legacy === "object") {
122
+ for (const [provider, value] of Object.entries(raw.legacy)) {
123
+ if (typeof value === "string" && value.trim()) {
124
+ // Provider-only keys are exactly what v3 wants: migrate instead
125
+ // of leaving them unusable.
126
+ keepNewest(keys, { provider, key: value, addedAt: "" });
127
+ migrated = true;
128
+ }
129
+ }
130
+ }
131
+ if (migrated && !migrationChecked) {
132
+ try {
133
+ // Keep the pre-migration file so a user with several old model
134
+ // keys can recover a credential we had to collapse.
135
+ const backup = auth + ".v2.bak";
136
+ if (!existsSync(backup))
137
+ copyFileSync(auth, backup);
138
+ writeAuth({ version: AUTH_VERSION, keys, legacy });
139
+ }
140
+ catch {
141
+ // Read-only home (or locked file): keep the migrated view in memory.
142
+ }
143
+ }
144
+ migrationChecked = true;
145
+ return { version: AUTH_VERSION, keys, legacy };
146
+ }
147
+ function writeAuth(store) {
148
+ const { auth } = getPaths();
149
+ atomicWrite(auth, JSON.stringify({ version: AUTH_VERSION, keys: store.keys }, null, 2));
150
+ lockdown(auth);
151
+ }
152
+ export function saveAuth(store) {
153
+ writeAuth(store);
154
+ }
155
+ export function getCredential(providerId, _model) {
156
+ return loadAuth().keys[providerId];
157
+ }
158
+ export function listCredentials() {
159
+ return Object.values(loadAuth().keys);
160
+ }
161
+ export function listLegacy() {
162
+ return Object.entries(loadAuth().legacy).map(([provider, key]) => ({ provider, key }));
163
+ }
164
+ export function getLegacy(providerId) {
165
+ return loadAuth().legacy[providerId];
166
+ }
167
+ /** Save/replace the provider-wide credential (drops any legacy key). */
168
+ export function setCredential(providerId, model, key) {
169
+ const store = loadAuth();
170
+ const credential = {
171
+ provider: providerId,
172
+ model,
173
+ key: key.trim(),
174
+ addedAt: new Date().toISOString(),
175
+ };
176
+ store.keys[providerId] = credential;
177
+ delete store.legacy[providerId];
178
+ saveAuth(store);
179
+ return credential;
180
+ }
181
+ export function removeCredential(providerId, _model) {
182
+ const store = loadAuth();
183
+ if (!store.keys[providerId])
184
+ return false;
185
+ delete store.keys[providerId];
186
+ saveAuth(store);
187
+ return true;
188
+ }
189
+ /** Remove the provider-wide credential plus any legacy leftovers. */
190
+ export function removeCredentialsForProvider(providerId) {
191
+ const store = loadAuth();
192
+ let removed = 0;
193
+ if (store.keys[providerId]) {
194
+ delete store.keys[providerId];
195
+ removed += 1;
196
+ }
197
+ if (store.legacy[providerId]) {
198
+ delete store.legacy[providerId];
199
+ removed += 1;
200
+ }
201
+ if (removed > 0)
202
+ saveAuth(store);
203
+ return removed;
204
+ }
205
+ /** Turn a key into a safe terminal echo: `sk-****abcd`. */
206
+ export function maskKey(key) {
207
+ const value = (key ?? "").trim();
208
+ if (!value)
209
+ return "";
210
+ if (value.length <= 8)
211
+ return "*".repeat(value.length);
212
+ return value.slice(0, 3) + "****" + value.slice(-4);
213
+ }
214
+ /**
215
+ * Resolve the key to use for a provider:
216
+ * 1. the provider-wide credential in auth.json,
217
+ * 2. the provider's environment variable (provider-scoped, any model), and
218
+ * 3. a legacy provider-only key that somehow escaped migration.
219
+ */
220
+ export function resolveApiKey(providerId, _model, envVars) {
221
+ const store = loadAuth();
222
+ const credential = store.keys[providerId];
223
+ if (credential && credential.key)
224
+ return { status: "ok", key: credential.key, source: "file" };
225
+ for (const envVar of envVars ?? []) {
226
+ const value = process.env[envVar];
227
+ if (value && value.trim())
228
+ return { status: "ok", key: value.trim(), source: "env", envVar };
229
+ }
230
+ if (store.legacy[providerId])
231
+ return { status: "unbound", provider: providerId, legacyKey: store.legacy[providerId] };
232
+ return { status: "missing" };
233
+ }
234
+ /** Best-effort key for a provider regardless of model (used to list models). */
235
+ export function resolveProviderKey(providerId, envVars) {
236
+ const store = loadAuth();
237
+ const credential = store.keys[providerId];
238
+ if (credential && credential.key)
239
+ return { key: credential.key, source: "file" };
240
+ for (const envVar of envVars ?? []) {
241
+ const value = process.env[envVar];
242
+ if (value && value.trim())
243
+ return { key: value.trim(), source: "env", envVar };
244
+ }
245
+ return {};
246
+ }
247
+ /**
248
+ * Write-then-rename so a Ctrl+C mid-write never leaves a corrupt file.
249
+ *
250
+ * The temp file MUST live in the same directory as the target so the rename
251
+ * is a same-filesystem operation. On many Linux distros `/tmp` is a tmpfs
252
+ * mount, which would make `renameSync` throw EXDEV across filesystems.
253
+ */
254
+ function atomicWrite(target, contents) {
255
+ const dir = dirname(target);
256
+ ensureDir(dir);
257
+ const tmp = join(dir, `.fastcode-${Date.now()}-${Math.random().toString(36).slice(2)}.tmp`);
258
+ writeFileSync(tmp, contents, { encoding: "utf8" });
259
+ renameSync(tmp, target);
260
+ }
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Built-in color themes. The `banner` triple is fed to gradient-string
3
+ * (start → mid → end) so each theme produces a recognizable big-text logo.
4
+ */
5
+ export declare const THEMES: {
6
+ fastcode: {
7
+ id: string;
8
+ label: string;
9
+ banner: string[];
10
+ user: string;
11
+ assistant: string;
12
+ system: string;
13
+ border: string;
14
+ accent: string;
15
+ muted: string;
16
+ error: string;
17
+ success: string;
18
+ };
19
+ neon: {
20
+ id: string;
21
+ label: string;
22
+ banner: string[];
23
+ user: string;
24
+ assistant: string;
25
+ system: string;
26
+ border: string;
27
+ accent: string;
28
+ muted: string;
29
+ error: string;
30
+ success: string;
31
+ };
32
+ sunset: {
33
+ id: string;
34
+ label: string;
35
+ banner: string[];
36
+ user: string;
37
+ assistant: string;
38
+ system: string;
39
+ border: string;
40
+ accent: string;
41
+ muted: string;
42
+ error: string;
43
+ success: string;
44
+ };
45
+ matrix: {
46
+ id: string;
47
+ label: string;
48
+ banner: string[];
49
+ user: string;
50
+ assistant: string;
51
+ system: string;
52
+ border: string;
53
+ accent: string;
54
+ muted: string;
55
+ error: string;
56
+ success: string;
57
+ };
58
+ mono: {
59
+ id: string;
60
+ label: string;
61
+ banner: string[];
62
+ user: string;
63
+ assistant: string;
64
+ system: string;
65
+ border: string;
66
+ accent: string;
67
+ muted: string;
68
+ error: string;
69
+ success: string;
70
+ };
71
+ };
72
+ export declare const DEFAULT_THEME = "fastcode";
73
+ export declare function getTheme(id: any): any;
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Built-in color themes. The `banner` triple is fed to gradient-string
3
+ * (start → mid → end) so each theme produces a recognizable big-text logo.
4
+ */
5
+ export const THEMES = {
6
+ fastcode: {
7
+ id: "fastcode",
8
+ label: "FastCode (default)",
9
+ banner: ["#ff7a00", "#ff2d95", "#7c4dff"],
10
+ user: "cyan",
11
+ assistant: "white",
12
+ system: "gray",
13
+ border: "magenta",
14
+ accent: "magenta",
15
+ muted: "gray",
16
+ error: "red",
17
+ success: "green",
18
+ },
19
+ neon: {
20
+ id: "neon",
21
+ label: "Neon",
22
+ banner: ["#00ffd0", "#00b3ff", "#7c4dff"],
23
+ user: "cyanBright",
24
+ assistant: "whiteBright",
25
+ system: "gray",
26
+ border: "cyan",
27
+ accent: "cyan",
28
+ muted: "gray",
29
+ error: "red",
30
+ success: "greenBright",
31
+ },
32
+ sunset: {
33
+ id: "sunset",
34
+ label: "Sunset",
35
+ banner: ["#ff5f6d", "#ffc371", "#ff9966"],
36
+ user: "yellow",
37
+ assistant: "whiteBright",
38
+ system: "gray",
39
+ border: "yellow",
40
+ accent: "yellow",
41
+ muted: "gray",
42
+ error: "redBright",
43
+ success: "green",
44
+ },
45
+ matrix: {
46
+ id: "matrix",
47
+ label: "Matrix",
48
+ banner: ["#00ff41", "#008f11", "#003b00"],
49
+ user: "greenBright",
50
+ assistant: "green",
51
+ system: "gray",
52
+ border: "green",
53
+ accent: "green",
54
+ muted: "gray",
55
+ error: "redBright",
56
+ success: "greenBright",
57
+ },
58
+ mono: {
59
+ id: "mono",
60
+ label: "Monochrome",
61
+ banner: ["#ffffff", "#cccccc", "#888888"],
62
+ user: "white",
63
+ assistant: "whiteBright",
64
+ system: "gray",
65
+ border: "white",
66
+ accent: "white",
67
+ muted: "gray",
68
+ error: "red",
69
+ success: "white",
70
+ },
71
+ };
72
+ export const DEFAULT_THEME = "fastcode";
73
+ export function getTheme(id) {
74
+ if (id && THEMES[id])
75
+ return THEMES[id];
76
+ return THEMES[DEFAULT_THEME];
77
+ }
@@ -0,0 +1,22 @@
1
+ export interface TrustPathEntry {
2
+ grantedAt: string;
3
+ lastUsed: string;
4
+ }
5
+ export interface TrustToolEntry extends TrustPathEntry {
6
+ catalogHash: string;
7
+ }
8
+ export interface TrustStore {
9
+ version: 1;
10
+ tools: Record<string, TrustToolEntry>;
11
+ paths: Record<string, TrustPathEntry>;
12
+ }
13
+ export declare function normalizeProjectPath(dir: string): string;
14
+ export declare function loadTrust(): TrustStore;
15
+ export declare function trustAllEnabled(): boolean;
16
+ export declare function isTrusted(dir: string): boolean;
17
+ export declare function trustProject(dir: string): string;
18
+ export declare function untrustProject(dir: string): boolean;
19
+ export declare function listTrusted(): Array<{
20
+ path: string;
21
+ addedAt: string;
22
+ }>;