@datename/fastcode-termux 0.1.6-beta → 0.1.6

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 (246) hide show
  1. package/README.md +6 -24
  2. package/dist/agent/guards.d.ts +0 -8
  3. package/dist/agent/guards.js +0 -195
  4. package/dist/agent/protocol.js +1 -4
  5. package/dist/agent/tools.d.ts +1 -3
  6. package/dist/agent/tools.js +377 -2
  7. package/dist/app.js +103 -335
  8. package/dist/cli.js +311 -362
  9. package/dist/commands/index.js +0 -22
  10. package/dist/commands/login.d.ts +2 -4
  11. package/dist/commands/login.js +10 -12
  12. package/dist/commands/logout.js +16 -8
  13. package/dist/commands/model.d.ts +0 -13
  14. package/dist/commands/model.js +22 -42
  15. package/dist/commands/provider.d.ts +0 -13
  16. package/dist/commands/provider.js +9 -20
  17. package/dist/commands/whoami.js +5 -6
  18. package/dist/config/store.d.ts +12 -32
  19. package/dist/config/store.js +65 -117
  20. package/dist/config/trust.d.ts +8 -21
  21. package/dist/config/trust.js +13 -99
  22. package/dist/lib/diagnostics.d.ts +4 -29
  23. package/dist/lib/diagnostics.js +4 -60
  24. package/dist/lib/http.d.ts +1 -11
  25. package/dist/lib/http.js +4 -62
  26. package/dist/providers/anthropic.d.ts +0 -1
  27. package/dist/providers/anthropic.js +0 -12
  28. package/dist/providers/custom.d.ts +0 -9
  29. package/dist/providers/deepseek.d.ts +0 -10
  30. package/dist/providers/deepseek.js +1 -2
  31. package/dist/providers/google.d.ts +0 -9
  32. package/dist/providers/groq.d.ts +0 -10
  33. package/dist/providers/groq.js +1 -2
  34. package/dist/providers/index.d.ts +201 -10
  35. package/dist/providers/index.js +0 -30
  36. package/dist/providers/mistral.d.ts +0 -10
  37. package/dist/providers/mistral.js +1 -2
  38. package/dist/providers/moonshot.d.ts +0 -10
  39. package/dist/providers/moonshot.js +1 -2
  40. package/dist/providers/ollama.d.ts +0 -9
  41. package/dist/providers/openai.d.ts +0 -10
  42. package/dist/providers/openai.js +1 -2
  43. package/dist/providers/openaiCompatible.d.ts +0 -9
  44. package/dist/providers/openaiCompatible.js +10 -58
  45. package/dist/providers/openrouter.d.ts +0 -10
  46. package/dist/providers/openrouter.js +1 -2
  47. package/dist/providers/qwen.d.ts +0 -10
  48. package/dist/providers/qwen.js +1 -2
  49. package/dist/providers/xai.d.ts +0 -10
  50. package/dist/providers/xai.js +1 -2
  51. package/dist/providers/zhipu.d.ts +0 -10
  52. package/dist/providers/zhipu.js +1 -2
  53. package/dist/session/log.d.ts +12 -35
  54. package/dist/session/log.js +10 -206
  55. package/dist/types.d.ts +1 -60
  56. package/dist/ui/Message.d.ts +7 -1
  57. package/dist/ui/Message.js +2 -13
  58. package/dist/ui/Prompt.d.ts +2 -1
  59. package/dist/ui/Prompt.js +2 -2
  60. package/dist/ui/Spinner.js +5 -11
  61. package/dist/ui/StatusBar.d.ts +1 -2
  62. package/dist/ui/StatusBar.js +5 -6
  63. package/package.json +1 -1
  64. package/src/agent/guards.ts +0 -196
  65. package/src/agent/protocol.ts +1 -4
  66. package/src/agent/tools.ts +377 -3
  67. package/src/app.ts +103 -335
  68. package/src/cli.ts +3 -30
  69. package/src/commands/index.ts +0 -22
  70. package/src/commands/login.ts +10 -12
  71. package/src/commands/logout.ts +16 -8
  72. package/src/commands/model.ts +22 -42
  73. package/src/commands/provider.ts +9 -20
  74. package/src/commands/whoami.ts +5 -6
  75. package/src/config/store.ts +69 -122
  76. package/src/config/trust.ts +21 -137
  77. package/src/lib/diagnostics.ts +4 -60
  78. package/src/lib/http.ts +4 -66
  79. package/src/providers/anthropic.ts +1 -13
  80. package/src/providers/deepseek.ts +1 -2
  81. package/src/providers/groq.ts +1 -2
  82. package/src/providers/index.ts +1 -32
  83. package/src/providers/mistral.ts +1 -2
  84. package/src/providers/moonshot.ts +1 -2
  85. package/src/providers/openai.ts +1 -2
  86. package/src/providers/openaiCompatible.ts +10 -58
  87. package/src/providers/openrouter.ts +1 -2
  88. package/src/providers/qwen.ts +1 -2
  89. package/src/providers/xai.ts +1 -2
  90. package/src/providers/zhipu.ts +1 -2
  91. package/src/session/log.ts +28 -267
  92. package/src/types.ts +1 -63
  93. package/src/ui/Message.ts +2 -13
  94. package/src/ui/Prompt.ts +2 -2
  95. package/src/ui/Spinner.ts +5 -11
  96. package/src/ui/StatusBar.ts +5 -6
  97. package/dist/agent/approval.d.ts +0 -50
  98. package/dist/agent/approval.js +0 -7
  99. package/dist/agent/compaction.d.ts +0 -39
  100. package/dist/agent/compaction.js +0 -227
  101. package/dist/agent/context.d.ts +0 -29
  102. package/dist/agent/context.js +0 -62
  103. package/dist/agent/ignore.d.ts +0 -11
  104. package/dist/agent/ignore.js +0 -129
  105. package/dist/agent/process-tree.d.ts +0 -2
  106. package/dist/agent/process-tree.js +0 -31
  107. package/dist/agent/protocol-mode.d.ts +0 -6
  108. package/dist/agent/protocol-mode.js +0 -51
  109. package/dist/agent/registry.d.ts +0 -17
  110. package/dist/agent/registry.js +0 -90
  111. package/dist/agent/runner.d.ts +0 -106
  112. package/dist/agent/runner.js +0 -352
  113. package/dist/agent/shell-session.d.ts +0 -37
  114. package/dist/agent/shell-session.js +0 -400
  115. package/dist/agent/stream.d.ts +0 -29
  116. package/dist/agent/stream.js +0 -103
  117. package/dist/agent/tool-schemas.d.ts +0 -2
  118. package/dist/agent/tool-schemas.js +0 -63
  119. package/dist/agent/tools/append_file.d.ts +0 -2
  120. package/dist/agent/tools/append_file.js +0 -26
  121. package/dist/agent/tools/apply_patch.d.ts +0 -10
  122. package/dist/agent/tools/apply_patch.js +0 -52
  123. package/dist/agent/tools/copy_file.d.ts +0 -2
  124. package/dist/agent/tools/copy_file.js +0 -30
  125. package/dist/agent/tools/delete_file.d.ts +0 -2
  126. package/dist/agent/tools/delete_file.js +0 -24
  127. package/dist/agent/tools/grep.d.ts +0 -2
  128. package/dist/agent/tools/grep.js +0 -23
  129. package/dist/agent/tools/index.d.ts +0 -2
  130. package/dist/agent/tools/index.js +0 -32
  131. package/dist/agent/tools/list_files.d.ts +0 -2
  132. package/dist/agent/tools/list_files.js +0 -17
  133. package/dist/agent/tools/make_dir.d.ts +0 -2
  134. package/dist/agent/tools/make_dir.js +0 -24
  135. package/dist/agent/tools/move_path.d.ts +0 -2
  136. package/dist/agent/tools/move_path.js +0 -47
  137. package/dist/agent/tools/paths.d.ts +0 -7
  138. package/dist/agent/tools/paths.js +0 -84
  139. package/dist/agent/tools/pwd.d.ts +0 -2
  140. package/dist/agent/tools/pwd.js +0 -10
  141. package/dist/agent/tools/read_file.d.ts +0 -2
  142. package/dist/agent/tools/read_file.js +0 -21
  143. package/dist/agent/tools/read_many.d.ts +0 -2
  144. package/dist/agent/tools/read_many.js +0 -25
  145. package/dist/agent/tools/readers.d.ts +0 -6
  146. package/dist/agent/tools/readers.js +0 -216
  147. package/dist/agent/tools/replace_in_file.d.ts +0 -2
  148. package/dist/agent/tools/replace_in_file.js +0 -30
  149. package/dist/agent/tools/shell.d.ts +0 -2
  150. package/dist/agent/tools/shell.js +0 -48
  151. package/dist/agent/tools/stat_path.d.ts +0 -2
  152. package/dist/agent/tools/stat_path.js +0 -31
  153. package/dist/agent/tools/types.d.ts +0 -39
  154. package/dist/agent/tools/types.js +0 -1
  155. package/dist/agent/tools/validate.d.ts +0 -6
  156. package/dist/agent/tools/validate.js +0 -29
  157. package/dist/agent/tools/write_file.d.ts +0 -2
  158. package/dist/agent/tools/write_file.js +0 -26
  159. package/dist/commands/attach.d.ts +0 -9
  160. package/dist/commands/attach.js +0 -15
  161. package/dist/commands/bg.d.ts +0 -7
  162. package/dist/commands/bg.js +0 -9
  163. package/dist/commands/cancel.d.ts +0 -10
  164. package/dist/commands/cancel.js +0 -10
  165. package/dist/commands/compact.d.ts +0 -10
  166. package/dist/commands/compact.js +0 -22
  167. package/dist/commands/context.d.ts +0 -7
  168. package/dist/commands/context.js +0 -24
  169. package/dist/commands/edit.d.ts +0 -10
  170. package/dist/commands/edit.js +0 -36
  171. package/dist/commands/effort.d.ts +0 -25
  172. package/dist/commands/effort.js +0 -48
  173. package/dist/commands/expand.d.ts +0 -10
  174. package/dist/commands/expand.js +0 -8
  175. package/dist/commands/jobs.d.ts +0 -7
  176. package/dist/commands/jobs.js +0 -16
  177. package/dist/commands/kill.d.ts +0 -7
  178. package/dist/commands/kill.js +0 -11
  179. package/dist/commands/steer.d.ts +0 -11
  180. package/dist/commands/steer.js +0 -13
  181. package/dist/lib/model-meta.d.ts +0 -19
  182. package/dist/lib/model-meta.js +0 -113
  183. package/dist/lib/native-tools.d.ts +0 -12
  184. package/dist/lib/native-tools.js +0 -21
  185. package/dist/lib/net.d.ts +0 -33
  186. package/dist/lib/net.js +0 -168
  187. package/dist/patch/apply.d.ts +0 -15
  188. package/dist/patch/apply.js +0 -172
  189. package/dist/patch/parse.d.ts +0 -29
  190. package/dist/patch/parse.js +0 -112
  191. package/dist/patch/plan.d.ts +0 -49
  192. package/dist/patch/plan.js +0 -273
  193. package/dist/session/projection.d.ts +0 -43
  194. package/dist/session/projection.js +0 -257
  195. package/dist/ui/Picker.d.ts +0 -8
  196. package/dist/ui/Picker.js +0 -24
  197. package/src/agent/approval.ts +0 -47
  198. package/src/agent/compaction.ts +0 -276
  199. package/src/agent/context.ts +0 -97
  200. package/src/agent/ignore.ts +0 -147
  201. package/src/agent/process-tree.ts +0 -32
  202. package/src/agent/protocol-mode.ts +0 -59
  203. package/src/agent/registry.ts +0 -98
  204. package/src/agent/runner.ts +0 -443
  205. package/src/agent/shell-session.ts +0 -449
  206. package/src/agent/stream.ts +0 -143
  207. package/src/agent/tool-schemas.ts +0 -67
  208. package/src/agent/tools/append_file.ts +0 -28
  209. package/src/agent/tools/apply_patch.ts +0 -54
  210. package/src/agent/tools/copy_file.ts +0 -32
  211. package/src/agent/tools/delete_file.ts +0 -26
  212. package/src/agent/tools/grep.ts +0 -25
  213. package/src/agent/tools/index.ts +0 -34
  214. package/src/agent/tools/list_files.ts +0 -19
  215. package/src/agent/tools/make_dir.ts +0 -26
  216. package/src/agent/tools/move_path.ts +0 -50
  217. package/src/agent/tools/paths.ts +0 -92
  218. package/src/agent/tools/pwd.ts +0 -12
  219. package/src/agent/tools/read_file.ts +0 -23
  220. package/src/agent/tools/read_many.ts +0 -27
  221. package/src/agent/tools/readers.ts +0 -228
  222. package/src/agent/tools/replace_in_file.ts +0 -32
  223. package/src/agent/tools/shell.ts +0 -53
  224. package/src/agent/tools/stat_path.ts +0 -33
  225. package/src/agent/tools/types.ts +0 -42
  226. package/src/agent/tools/validate.ts +0 -35
  227. package/src/agent/tools/write_file.ts +0 -28
  228. package/src/commands/attach.ts +0 -16
  229. package/src/commands/bg.ts +0 -9
  230. package/src/commands/cancel.ts +0 -10
  231. package/src/commands/compact.ts +0 -23
  232. package/src/commands/context.ts +0 -25
  233. package/src/commands/edit.ts +0 -37
  234. package/src/commands/effort.ts +0 -49
  235. package/src/commands/expand.ts +0 -8
  236. package/src/commands/jobs.ts +0 -17
  237. package/src/commands/kill.ts +0 -12
  238. package/src/commands/steer.ts +0 -13
  239. package/src/lib/model-meta.ts +0 -138
  240. package/src/lib/native-tools.ts +0 -32
  241. package/src/lib/net.ts +0 -204
  242. package/src/patch/apply.ts +0 -194
  243. package/src/patch/parse.ts +0 -131
  244. package/src/patch/plan.ts +0 -317
  245. package/src/session/projection.ts +0 -308
  246. package/src/ui/Picker.ts +0 -24
@@ -7,30 +7,11 @@
7
7
  *
8
8
  * FASTCODE_TRUST_ALL=1 marks every directory trusted (scripts, CI).
9
9
  */
10
- import { existsSync, readFileSync, realpathSync, statSync, writeFileSync } from "node:fs";
10
+ import { existsSync, readFileSync, realpathSync, writeFileSync } from "node:fs";
11
11
  import { resolve } from "node:path";
12
12
  import { ensureDir, getPaths } from "./paths.js";
13
-
14
13
  const TRUTHY = ["1", "true", "yes", "on"];
15
-
16
- export interface TrustPathEntry {
17
- grantedAt: string;
18
- lastUsed: string;
19
- }
20
-
21
- export interface TrustToolEntry extends TrustPathEntry {
22
- catalogHash: string;
23
- }
24
-
25
- export interface TrustStore {
26
- version: 1;
27
- tools: Record<string, TrustToolEntry>;
28
- paths: Record<string, TrustPathEntry>;
29
- }
30
-
31
- let cache: { file: string; key: string; state: TrustStore } | undefined;
32
-
33
- export function normalizeProjectPath(dir: string): string {
14
+ export function normalizeProjectPath(dir) {
34
15
  const absolute = resolve(dir);
35
16
  try {
36
17
  return realpathSync(absolute);
@@ -39,145 +20,48 @@ export function normalizeProjectPath(dir: string): string {
39
20
  return absolute;
40
21
  }
41
22
  }
42
-
43
- function emptyStore(): TrustStore {
44
- return { version: 1, tools: {}, paths: {} };
45
- }
46
-
47
- function normalizePaths(raw: any): Record<string, TrustPathEntry> {
48
- const paths: Record<string, TrustPathEntry> = {};
49
- if (!raw || typeof raw !== "object")
50
- return paths;
51
- for (const [key, value] of Object.entries<any>(raw)) {
52
- if (!key || !value || typeof value !== "object")
53
- continue;
54
- paths[key] = {
55
- grantedAt: typeof value.grantedAt === "string" ? value.grantedAt : "",
56
- lastUsed: typeof value.lastUsed === "string" ? value.lastUsed : "",
57
- };
58
- }
59
- return paths;
60
- }
61
-
62
- function normalizeTools(raw: any): Record<string, TrustToolEntry> {
63
- const tools: Record<string, TrustToolEntry> = {};
64
- if (!raw || typeof raw !== "object")
65
- return tools;
66
- for (const [key, value] of Object.entries<any>(raw)) {
67
- if (!key || !value || typeof value !== "object" || typeof value.catalogHash !== "string")
68
- continue;
69
- tools[key] = {
70
- grantedAt: typeof value.grantedAt === "string" ? value.grantedAt : "",
71
- lastUsed: typeof value.lastUsed === "string" ? value.lastUsed : "",
72
- catalogHash: value.catalogHash,
73
- };
74
- }
75
- return tools;
76
- }
77
-
78
- function migrateLegacy(raw: any): TrustStore | undefined {
79
- if (!raw || typeof raw !== "object" || !Array.isArray(raw.trusted))
80
- return undefined;
81
- const store = emptyStore();
82
- for (const entry of raw.trusted) {
83
- if (!entry || typeof entry.path !== "string" || !entry.path)
84
- continue;
85
- const at = typeof entry.addedAt === "string" ? entry.addedAt : new Date().toISOString();
86
- store.paths[entry.path] = { grantedAt: at, lastUsed: at };
87
- }
88
- return store;
89
- }
90
-
91
- function readStore(file: string): TrustStore {
92
- if (!existsSync(file))
93
- return emptyStore();
94
- try {
95
- const raw = JSON.parse(readFileSync(file, "utf8"));
96
- if (raw && raw.version === 1) {
97
- return {
98
- version: 1,
99
- tools: normalizeTools(raw.tools),
100
- paths: normalizePaths(raw.paths),
101
- };
102
- }
103
- const migrated = migrateLegacy(raw);
104
- if (!migrated)
105
- return emptyStore();
106
- try {
107
- writeFileSync(file, JSON.stringify(migrated, null, 2), "utf8");
108
- }
109
- catch {
110
- // A read-only home still gets the migrated view in memory.
111
- }
112
- return migrated;
113
- }
114
- catch {
115
- return emptyStore();
116
- }
117
- }
118
-
119
- export function loadTrust(): TrustStore {
23
+ export function loadTrust() {
120
24
  const { trust } = getPaths();
121
- let key = "missing";
25
+ if (!existsSync(trust))
26
+ return { trusted: [] };
122
27
  try {
123
- const info = statSync(trust);
124
- key = `${info.mtimeMs}:${info.size}`;
28
+ const raw = JSON.parse(readFileSync(trust, "utf8"));
29
+ return { trusted: Array.isArray(raw.trusted) ? raw.trusted.filter((entry) => entry && typeof entry.path === "string") : [] };
125
30
  }
126
31
  catch {
127
- // Missing file: cache the empty store until it appears.
32
+ return { trusted: [] };
128
33
  }
129
- if (cache && cache.file === trust && cache.key === key)
130
- return cache.state;
131
- const state = readStore(trust);
132
- cache = { file: trust, key, state };
133
- return state;
134
34
  }
135
-
136
- function saveTrust(state: TrustStore): void {
35
+ function saveTrust(state) {
137
36
  const paths = getPaths();
138
37
  ensureDir(paths.root);
139
38
  writeFileSync(paths.trust, JSON.stringify(state, null, 2), "utf8");
140
- try {
141
- const info = statSync(paths.trust);
142
- cache = { file: paths.trust, key: `${info.mtimeMs}:${info.size}`, state };
143
- }
144
- catch {
145
- cache = undefined;
146
- }
147
39
  }
148
-
149
- export function trustAllEnabled(): boolean {
40
+ export function trustAllEnabled() {
150
41
  return TRUTHY.includes((process.env["FASTCODE_TRUST_ALL"] ?? "").trim().toLowerCase());
151
42
  }
152
-
153
- export function isTrusted(dir: string): boolean {
43
+ export function isTrusted(dir) {
154
44
  if (trustAllEnabled())
155
45
  return true;
156
46
  const target = normalizeProjectPath(dir);
157
- return Boolean(loadTrust().paths[target]);
47
+ return loadTrust().trusted.some((entry) => entry.path === target);
158
48
  }
159
-
160
- export function trustProject(dir: string): string {
49
+ export function trustProject(dir) {
161
50
  const target = normalizeProjectPath(dir);
162
51
  const state = loadTrust();
163
- if (!state.paths[target]) {
164
- const at = new Date().toISOString();
165
- state.paths[target] = { grantedAt: at, lastUsed: at };
52
+ if (!state.trusted.some((entry) => entry.path === target)) {
53
+ state.trusted.push({ path: target, addedAt: new Date().toISOString() });
166
54
  saveTrust(state);
167
55
  }
168
56
  return target;
169
57
  }
170
-
171
- export function untrustProject(dir: string): boolean {
58
+ export function untrustProject(dir) {
172
59
  const target = normalizeProjectPath(dir);
173
60
  const state = loadTrust();
174
- if (!state.paths[target])
175
- return false;
176
- delete state.paths[target];
177
- saveTrust(state);
178
- return true;
61
+ const next = state.trusted.filter((entry) => entry.path !== target);
62
+ saveTrust({ trusted: next });
63
+ return state.trusted.length !== next.length;
179
64
  }
180
-
181
- export function listTrusted(): Array<{ path: string; addedAt: string }> {
182
- return Object.entries(loadTrust().paths).map(([path, entry]) => ({ path, addedAt: entry.grantedAt }));
65
+ export function listTrusted() {
66
+ return loadTrust().trusted;
183
67
  }
@@ -5,8 +5,6 @@
5
5
  * diagnosed without opening the TUI: Node version, Termux detection, whether
6
6
  * stdout is a real terminal, the config root, and which provider keys exist.
7
7
  */
8
- import { existsSync, statSync } from "node:fs";
9
- import { totalmem, freemem, tmpdir as osTmpdir } from "node:os";
10
8
  import { detectPlatform, platformLabel } from "./platform.js";
11
9
  import { readPackageMeta } from "./pkg.js";
12
10
  import { shouldUseStableTerminalUi } from "./uiMode.js";
@@ -15,14 +13,10 @@ import { loadConfig, resolveApiKey, resolveProviderKey } from "../config/store.j
15
13
  import { PROVIDERS } from "../providers/index.js";
16
14
  import { listInstalledSkills } from "../skills/manager.js";
17
15
  import { listInstalledPlugins } from "../plugins/manager.js";
18
- import { findUnclosedSessions, fsyncMode, loggingEnabled, listSessions, sessionCacheLimitBytes } from "../session/log.js";
16
+ import { loggingEnabled, listSessions, sessionCacheLimitBytes } from "../session/log.js";
19
17
  import { isTrusted } from "../config/trust.js";
20
- import { DEFAULT_DENY_PATTERNS, loopExemptTools } from "../agent/guards.js";
18
+ import { DEFAULT_DENY_PATTERNS } from "../agent/guards.js";
21
19
  import { toolOutputLimit } from "../agent/limits.js";
22
- import { compactionConfigFromEnv, heapExceeded } from "../agent/compaction.js";
23
- import { shellPoolStats } from "../agent/shell-session.js";
24
- import { resolveToolProtocol, toolCapabilityKey } from "../agent/protocol-mode.js";
25
- import { getModelMeta, modelMetaOverridePath } from "./model-meta.js";
26
20
  const NODE_REQUIRED = "18.17";
27
21
  function readVersion() {
28
22
  return readPackageMeta().version;
@@ -61,16 +55,6 @@ export function collectDiagnostics() {
61
55
  // Same for plugins.
62
56
  }
63
57
  const platform = detectPlatform();
64
- const compaction = compactionConfigFromEnv();
65
- const shells = shellPoolStats();
66
- let authMode = "missing";
67
- try {
68
- if (paths?.auth && existsSync(paths.auth))
69
- authMode = (statSync(paths.auth).mode & 0o777).toString(8).padStart(4, "0");
70
- }
71
- catch {
72
- authMode = "unreadable";
73
- }
74
58
  return {
75
59
  version: readVersion(),
76
60
  node: process.version,
@@ -85,10 +69,6 @@ export function collectDiagnostics() {
85
69
  configRoot: paths?.root,
86
70
  configFile: paths?.config,
87
71
  authFile: paths?.auth,
88
- authMode,
89
- tmpdir: process.env["TMPDIR"] || osTmpdir(),
90
- memTotalMb: totalmem() / 1024 / 1024,
91
- memFreeMb: freemem() / 1024 / 1024,
92
72
  providerId: config.providerId,
93
73
  model: config.model,
94
74
  keyPresent,
@@ -100,8 +80,6 @@ export function collectDiagnostics() {
100
80
  enabledPlugins: (config.enabledPlugins ?? []).length,
101
81
  sessionLogEnabled: loggingEnabled(),
102
82
  sessionCacheMb: Math.round(sessionCacheLimitBytes() / (1024 * 1024)),
103
- sessionFsync: fsyncMode(),
104
- unclosedSessions: findUnclosedSessions().length,
105
83
  sessionsDir: paths?.sessions,
106
84
  sessionsCount: listSessions().length,
107
85
  sessionsBytes: listSessions().reduce((sum, entry) => sum + entry.bytes, 0),
@@ -110,25 +88,6 @@ export function collectDiagnostics() {
110
88
  shellDenyPatterns: DEFAULT_DENY_PATTERNS.length,
111
89
  allowDangerous: ["1", "true", "yes", "on"].includes((process.env["FASTCODE_ALLOW_DANGEROUS"] ?? "").trim().toLowerCase()),
112
90
  toolOutputLimit: toolOutputLimit(),
113
- tokenBudget: positiveEnv("FASTCODE_TOKEN_BUDGET"),
114
- costBudgetUsd: positiveEnv("FASTCODE_COST_BUDGET_USD"),
115
- compactionEnabled: compaction.enabled,
116
- compactionRatio: compaction.localThresholdRatio,
117
- compactionHeapMb: compaction.heapLimitMb,
118
- compactionHeapUsedMb: process.memoryUsage().heapUsed / 1024 / 1024,
119
- compactionForced: heapExceeded(compaction),
120
- serverCompactionAware: compaction.serverCompactionAware,
121
- shellActive: shells.active,
122
- shellPool: shells.pool,
123
- shellSpawns: shells.spawns,
124
- shellMaxSpawn: shells.maxSpawnPerTurn,
125
- sseIdleMs: positiveEnv("FASTCODE_SSE_IDLE_MS") || 25_000,
126
- toolProtocol: resolveToolProtocol(config, config.providerId, config.model),
127
- toolProtocolMode: (process.env["FASTCODE_TOOL_PROTOCOL"] ?? "legacy").trim().toLowerCase(),
128
- toolCapability: config.capabilities?.toolCalling?.[toolCapabilityKey(config.providerId, config.model)] ?? "unknown",
129
- loopExempt: Array.from(loopExemptTools()),
130
- modelMetaFile: modelMetaOverridePath(),
131
- modelMeta: getModelMeta(config.providerId, config.model),
132
91
  providers: PROVIDERS.map((p) => ({
133
92
  id: p.id,
134
93
  label: p.label,
@@ -137,10 +96,6 @@ export function collectDiagnostics() {
137
96
  })),
138
97
  };
139
98
  }
140
- function positiveEnv(name) {
141
- const value = Number(process.env[name]);
142
- return Number.isFinite(value) && value > 0 ? value : 0;
143
- }
144
99
  export function formatDiagnostics(info) {
145
100
  const lines = [];
146
101
  lines.push(`FastCode ${info.version} — environment check`);
@@ -151,21 +106,12 @@ export function formatDiagnostics(info) {
151
106
  lines.push(` stable UI ${info.stableUi ? "on (anti-flicker)" : "off"}`);
152
107
  lines.push(" config root " + (info.configRoot ?? "(unavailable)"));
153
108
  lines.push(" config file " + (info.configFile ?? "(unavailable)"));
154
- lines.push(" keys file " + (info.authFile ?? "(unavailable)") + " mode " + info.authMode + (info.authMode !== "missing" && info.authMode !== "0600" ? " [WARN: expected 0600]" : ""));
155
- lines.push(" tmpdir " + info.tmpdir + (info.termux && !String(info.tmpdir).startsWith("/data/data/com.termux") ? " [WARN: use $PREFIX/tmp]" : ""));
156
- lines.push(" memory " + info.memFreeMb.toFixed(0) + "MB free / " + info.memTotalMb.toFixed(0) + "MB total");
109
+ lines.push(" keys file " + (info.authFile ?? "(unavailable)") + " (separate, chmod 0600)");
157
110
  lines.push(" trusted cwd " + (info.trusted ? "yes" : "NO - agent tools ask first or stay off") + " (" + (info.trustFile ?? "?") + ")");
158
111
  lines.push(" session log " + (info.sessionLogEnabled ? "on" : "off") + " cache cap " + info.sessionCacheMb + "MB, " + info.sessionsCount + " file(s), " + (info.sessionsBytes / 1024 / 1024).toFixed(2) + "MB used");
159
- lines.push(" session fsync " + info.sessionFsync + " unclosed " + info.unclosedSessions + " " + (info.sessionsDir ?? "(unavailable)"));
112
+ lines.push(" session dir " + (info.sessionsDir ?? "(unavailable)"));
160
113
  lines.push(" shell guard " + info.shellDenyPatterns + " deny patterns" + (info.allowDangerous ? " [FASTCODE_ALLOW_DANGEROUS is ON]" : ""));
161
114
  lines.push(" tool output " + info.toolOutputLimit + " chars max (streaming cap)");
162
- lines.push(` budgets ${info.tokenBudget > 0 ? "tokens ≤ " + info.tokenBudget : "token budget off"} · ${info.costBudgetUsd > 0 ? "$" + info.costBudgetUsd : "cost budget off"}`);
163
- lines.push(` compaction ${info.compactionEnabled ? "on" : "off"} · ${Math.round(info.compactionRatio * 100)}% · heap ${info.compactionHeapUsedMb.toFixed(1)}/${info.compactionHeapMb}MB${info.compactionForced ? " [FORCED]" : ""}${info.serverCompactionAware ? " · server-aware" : ""}`);
164
- lines.push(` shell pool ${info.shellActive} active · ${info.shellPool} resident · ${info.shellSpawns} spawns · cap ${info.shellMaxSpawn}/turn`);
165
- lines.push(` loop exempt ${info.loopExempt.length > 0 ? info.loopExempt.join(", ") : "(none)"}`);
166
- lines.push(` model meta ctx ${info.modelMeta.contextWindow} · ~${info.modelMeta.charsPerToken} chars/token · ${info.modelMeta.supportsTools ? "tools" : "no tools"} · ${info.modelMetaFile}`);
167
- lines.push(` sse timeout ${info.sseIdleMs}ms idle`);
168
- lines.push(` tool protocol ${info.toolProtocol} (${info.toolProtocolMode}) · cached ${info.toolCapability}`);
169
115
  lines.push(` provider ${info.providerId} · model ${info.model}`);
170
116
  let apiKeyStatus;
171
117
  if (info.keyPresent)
@@ -188,8 +134,6 @@ export function formatDiagnostics(info) {
188
134
  lines.push(" - pkg install nodejs git");
189
135
  lines.push(" - keep the session alive with: termux-wake-lock");
190
136
  lines.push(" - add an extra-keys row for Esc/Ctrl in ~/.termux/termux.properties");
191
- lines.push(" - long tasks: export TMPDIR=$PREFIX/tmp and use termux-wake-lock");
192
- lines.push(` - Android 12+ caps phantom processes (~32); background shells are pooled (${info.shellPool} resident, cap ${info.shellMaxSpawn}/turn)`);
193
137
  }
194
138
  return lines.join("\n");
195
139
  }
package/src/lib/http.ts CHANGED
@@ -16,21 +16,8 @@ export async function fetchJson(url: string, init: any = {}): Promise<any> {
16
16
  }
17
17
  return (await res.json());
18
18
  }
19
- export class NetworkStallError extends Error {
20
- readonly code = "NETWORK_STALL";
21
- readonly bytesReceived: number;
22
- constructor(message: string, bytesReceived = 0) {
23
- super(message);
24
- this.name = "NetworkStallError";
25
- this.bytesReceived = bytesReceived;
26
- }
27
- }
28
- export interface StreamSseOptions {
29
- idleTimeoutMs?: number;
30
- totalTimeoutMs?: number;
31
- }
32
19
  /** Async iterator over SSE events from a streaming HTTP response. */
33
- export async function* streamSSE(res, options: StreamSseOptions = {}) {
20
+ export async function* streamSSE(res) {
34
21
  if (!res.ok) {
35
22
  const body = await res.text().catch(() => "");
36
23
  throw new Error(`${res.status} ${res.statusText}: ${body.slice(0, 500)}`);
@@ -39,50 +26,19 @@ export async function* streamSSE(res, options: StreamSseOptions = {}) {
39
26
  throw new Error("Empty response body");
40
27
  const reader = res.body.getReader();
41
28
  const decoder = new TextDecoder("utf-8");
42
- const envIdle = Number(process.env["FASTCODE_SSE_IDLE_MS"]);
43
- const idleMs = positive(options.idleTimeoutMs, positive(envIdle, 25_000));
44
- const totalMs = positive(options.totalTimeoutMs, 0);
45
- const startedAt = Date.now();
46
- let bytesReceived = 0;
47
29
  let buffer = "";
48
30
  while (true) {
49
- const remaining = totalMs > 0 ? totalMs - (Date.now() - startedAt) : Number.POSITIVE_INFINITY;
50
- if (remaining <= 0)
51
- throw new NetworkStallError(`SSE total timeout after ${totalMs}ms`, bytesReceived);
52
- const boundedByTotal = remaining <= idleMs;
53
- const waitMs = boundedByTotal ? Math.max(1, remaining) : idleMs;
54
- let timer: ReturnType<typeof setTimeout> | undefined;
55
- const timeout = new Promise<never>((_resolve, reject) => {
56
- timer = setTimeout(() => {
57
- reject(new NetworkStallError(boundedByTotal
58
- ? `SSE total timeout after ${totalMs}ms`
59
- : `SSE idle timeout after ${idleMs}ms (no data received; set FASTCODE_SSE_IDLE_MS to wait longer)`, bytesReceived));
60
- }, waitMs);
61
- });
62
- let chunk;
63
- try {
64
- chunk = await Promise.race([reader.read(), timeout]);
65
- }
66
- catch (err) {
67
- await reader.cancel().catch(() => undefined);
68
- throw err;
69
- }
70
- finally {
71
- if (timer)
72
- clearTimeout(timer);
73
- }
74
- const { value, done } = chunk;
31
+ const { value, done } = await reader.read();
75
32
  if (done)
76
33
  break;
77
- bytesReceived += value?.byteLength ?? 0;
78
34
  // Normalize CR/LF so both "\n\n" and "\r\n\r\n" frame separators
79
35
  // are detected, including a CR/LF split across two chunks.
80
36
  buffer = (buffer + decoder.decode(value, { stream: true })).replace(/\r\n?/g, "\n");
81
37
  let sep = buffer.indexOf("\n\n");
82
38
  while (sep !== -1) {
83
- const chunkText = buffer.slice(0, sep);
39
+ const chunk = buffer.slice(0, sep);
84
40
  buffer = buffer.slice(sep + 2);
85
- const ev = parseSseChunk(chunkText);
41
+ const ev = parseSseChunk(chunk);
86
42
  if (ev)
87
43
  yield ev;
88
44
  sep = buffer.indexOf("\n\n");
@@ -96,24 +52,6 @@ export async function* streamSSE(res, options: StreamSseOptions = {}) {
96
52
  yield ev;
97
53
  }
98
54
  }
99
- export async function probeConnectivity(url: string, timeoutMs = 3000): Promise<boolean> {
100
- const controller = new AbortController();
101
- const timer = setTimeout(() => controller.abort(), positive(timeoutMs, 3000));
102
- try {
103
- const res = await fetch(url, { signal: controller.signal });
104
- await res.body?.cancel().catch(() => undefined);
105
- return res.ok;
106
- }
107
- catch {
108
- return false;
109
- }
110
- finally {
111
- clearTimeout(timer);
112
- }
113
- }
114
- function positive(value, fallback) {
115
- return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : fallback;
116
- }
117
55
  function parseSseChunk(chunk) {
118
56
  let event;
119
57
  const dataLines = [];
@@ -10,16 +10,12 @@ const STATIC_MODELS = [
10
10
  { id: "claude-haiku-4.5", label: "Claude Haiku 4.5" },
11
11
  ];
12
12
  const BASE = "https://api.anthropic.com/v1";
13
- const THINKING_BUDGETS = { low: 1024, medium: 4096, high: 8192, max: 16000 };
14
13
  export const anthropicProvider = {
15
14
  id: "anthropic",
16
15
  label: "Anthropic (Claude)",
17
16
  authEnv: ["ANTHROPIC_API_KEY", "CLAUDE_API_KEY"],
18
17
  baseUrl: BASE,
19
18
  defaultModel: "claude-sonnet-5.5",
20
- supportsReasoning() {
21
- return true;
22
- },
23
19
  async listModels(apiKey) {
24
20
  // Query the live model list; fall back to the built-in list offline.
25
21
  if (apiKey) {
@@ -49,7 +45,7 @@ export const anthropicProvider = {
49
45
  throw new Error("Missing ANTHROPIC_API_KEY. Bind one with /login anthropic <model> <key>, or set the env var.");
50
46
  }
51
47
  const messages = req.messages.map((m) => ({ role: m.role, content: m.content }));
52
- const body: any = {
48
+ const body = {
53
49
  model: req.model,
54
50
  messages,
55
51
  ...(req.system ? { system: req.system } : {}),
@@ -57,14 +53,6 @@ export const anthropicProvider = {
57
53
  max_tokens: req.maxOutputTokens ?? 4096,
58
54
  ...(req.temperature !== undefined ? { temperature: req.temperature } : {}),
59
55
  };
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
56
  const res = await fetch(BASE + "/messages", {
69
57
  method: "POST",
70
58
  headers: {
@@ -11,6 +11,5 @@ export const deepseekProvider = {
11
11
  baseUrl: BASE,
12
12
  defaultModel: "deepseek-v4-pro",
13
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,
14
+ stream: (req, apiKey) => streamChatCompletion(req, { baseUrl: BASE, apiKey, staticModels: STATIC }),
16
15
  };
@@ -16,6 +16,5 @@ export const groqProvider = {
16
16
  baseUrl: BASE,
17
17
  defaultModel: "llama-3.3-70b-versatile",
18
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,
19
+ stream: (req, apiKey) => streamChatCompletion(req, { baseUrl: BASE, apiKey, staticModels: STATIC }),
21
20
  };
@@ -11,8 +11,7 @@ import { moonshotProvider } from "./moonshot.js";
11
11
  import { zhipuProvider } from "./zhipu.js";
12
12
  import { qwenProvider } from "./qwen.js";
13
13
  import { customProvider } from "./custom.js";
14
- import type { Provider } from "../types.js";
15
- export const PROVIDERS: Provider[] = [
14
+ export const PROVIDERS = [
16
15
  anthropicProvider,
17
16
  openaiProvider,
18
17
  googleProvider,
@@ -36,33 +35,3 @@ export function getProviderOrThrow(id) {
36
35
  throw new Error("Unknown provider: " + id);
37
36
  return p;
38
37
  }
39
- /**
40
- * Cheap connectivity check used by the model picker to label a list "offline".
41
- * `listModels()` silently falls back to the static list, so without this probe
42
- * the UI cannot tell a live catalog from a cached one.
43
- */
44
- export async function probeProvider(provider, apiKey, timeoutMs = 4000) {
45
- const controller = new AbortController();
46
- const timer = setTimeout(() => controller.abort(), timeoutMs);
47
- try {
48
- const base = String(provider.baseUrl).replace(/[/]+$/, "");
49
- const headers = { accept: "application/json" };
50
- if (apiKey) {
51
- if (provider.id === "anthropic") {
52
- headers["x-api-key"] = apiKey;
53
- headers["anthropic-version"] = "2023-06-01";
54
- }
55
- else {
56
- headers["authorization"] = "Bearer " + apiKey;
57
- }
58
- }
59
- const res = await fetch(base + "/models", { headers, signal: controller.signal });
60
- return res.ok;
61
- }
62
- catch {
63
- return false;
64
- }
65
- finally {
66
- clearTimeout(timer);
67
- }
68
- }
@@ -15,6 +15,5 @@ export const mistralProvider = {
15
15
  baseUrl: BASE,
16
16
  defaultModel: "mistral-small-latest",
17
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,
18
+ stream: (req, apiKey) => streamChatCompletion(req, { baseUrl: BASE, apiKey, staticModels: STATIC }),
20
19
  };
@@ -18,6 +18,5 @@ export const moonshotProvider = {
18
18
  },
19
19
  defaultModel: "kimi-k3",
20
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,
21
+ stream: (req, apiKey) => streamChatCompletion(req, { baseUrl: baseUrl(), apiKey, staticModels: STATIC }),
23
22
  };
@@ -21,6 +21,5 @@ export const openaiProvider = {
21
21
  baseUrl: BASE,
22
22
  defaultModel: "gpt-6-luna",
23
23
  listModels: (apiKey) => listModelsHttp({ baseUrl: BASE, apiKey, staticModels: STATIC }),
24
- stream: (req, apiKey) => streamChatCompletion(req, { baseUrl: BASE, apiKey, staticModels: STATIC, reasoning: "openai" }),
25
- supportsReasoning: (model) => /^(o\d|gpt-5|gpt-6)/i.test(model),
24
+ stream: (req, apiKey) => streamChatCompletion(req, { baseUrl: BASE, apiKey, staticModels: STATIC }),
26
25
  };