@datename/fastcode-termux 0.1.6 → 0.1.8-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (303) hide show
  1. package/LICENSE +4 -0
  2. package/README.md +67 -16
  3. package/dist/agent/approval-json.d.ts +43 -0
  4. package/dist/agent/approval-json.js +69 -0
  5. package/dist/agent/approval-native.d.ts +3 -0
  6. package/dist/agent/approval-native.js +165 -0
  7. package/dist/agent/approval-store.d.ts +16 -0
  8. package/dist/agent/approval-store.js +21 -0
  9. package/dist/agent/approval.d.ts +83 -0
  10. package/dist/agent/approval.js +42 -0
  11. package/dist/agent/compaction.d.ts +41 -0
  12. package/dist/agent/compaction.js +270 -0
  13. package/dist/agent/context.d.ts +29 -0
  14. package/dist/agent/context.js +62 -0
  15. package/dist/agent/guards.d.ts +24 -16
  16. package/dist/agent/guards.js +1167 -18
  17. package/dist/agent/ignore.d.ts +11 -0
  18. package/dist/agent/ignore.js +129 -0
  19. package/dist/agent/policy/defaults.d.ts +16 -0
  20. package/dist/agent/policy/defaults.js +17 -0
  21. package/dist/agent/policy/egress.d.ts +32 -0
  22. package/dist/agent/policy/egress.js +280 -0
  23. package/dist/agent/process-tree.d.ts +22 -0
  24. package/dist/agent/process-tree.js +102 -0
  25. package/dist/agent/protocol-mode.d.ts +6 -0
  26. package/dist/agent/protocol-mode.js +51 -0
  27. package/dist/agent/protocol.d.ts +20 -1
  28. package/dist/agent/protocol.js +169 -39
  29. package/dist/agent/registry.d.ts +19 -0
  30. package/dist/agent/registry.js +247 -0
  31. package/dist/agent/runner.d.ts +127 -0
  32. package/dist/agent/runner.js +391 -0
  33. package/dist/agent/shell-ast.d.ts +11 -0
  34. package/dist/agent/shell-ast.js +204 -0
  35. package/dist/agent/shell-session.d.ts +51 -0
  36. package/dist/agent/shell-session.js +611 -0
  37. package/dist/agent/stream.d.ts +29 -0
  38. package/dist/agent/stream.js +103 -0
  39. package/dist/agent/tool-schemas.d.ts +2 -0
  40. package/dist/agent/tool-schemas.js +82 -0
  41. package/dist/agent/tools/append_file.d.ts +2 -0
  42. package/dist/agent/tools/append_file.js +28 -0
  43. package/dist/agent/tools/apply_patch.d.ts +10 -0
  44. package/dist/agent/tools/apply_patch.js +92 -0
  45. package/dist/agent/tools/copy_file.d.ts +2 -0
  46. package/dist/agent/tools/copy_file.js +53 -0
  47. package/dist/agent/tools/delete_file.d.ts +2 -0
  48. package/dist/agent/tools/delete_file.js +43 -0
  49. package/dist/agent/tools/grep.d.ts +2 -0
  50. package/dist/agent/tools/grep.js +54 -0
  51. package/dist/agent/tools/index.d.ts +2 -0
  52. package/dist/agent/tools/index.js +32 -0
  53. package/dist/agent/tools/list_files.d.ts +2 -0
  54. package/dist/agent/tools/list_files.js +17 -0
  55. package/dist/agent/tools/make_dir.d.ts +2 -0
  56. package/dist/agent/tools/make_dir.js +26 -0
  57. package/dist/agent/tools/move_path.d.ts +9 -0
  58. package/dist/agent/tools/move_path.js +73 -0
  59. package/dist/agent/tools/paths.d.ts +7 -0
  60. package/dist/agent/tools/paths.js +84 -0
  61. package/dist/agent/tools/pwd.d.ts +2 -0
  62. package/dist/agent/tools/pwd.js +10 -0
  63. package/dist/agent/tools/read_file.d.ts +2 -0
  64. package/dist/agent/tools/read_file.js +81 -0
  65. package/dist/agent/tools/read_many.d.ts +2 -0
  66. package/dist/agent/tools/read_many.js +43 -0
  67. package/dist/agent/tools/readers.d.ts +58 -0
  68. package/dist/agent/tools/readers.js +426 -0
  69. package/dist/agent/tools/replace_in_file.d.ts +2 -0
  70. package/dist/agent/tools/replace_in_file.js +63 -0
  71. package/dist/agent/tools/shell.d.ts +2 -0
  72. package/dist/agent/tools/shell.js +48 -0
  73. package/dist/agent/tools/stat_path.d.ts +2 -0
  74. package/dist/agent/tools/stat_path.js +31 -0
  75. package/dist/agent/tools/types.d.ts +65 -0
  76. package/dist/agent/tools/types.js +1 -0
  77. package/dist/agent/tools/validate.d.ts +19 -0
  78. package/dist/agent/tools/validate.js +92 -0
  79. package/dist/agent/tools/write_file.d.ts +2 -0
  80. package/dist/agent/tools/write_file.js +28 -0
  81. package/dist/agent/tools.d.ts +3 -1
  82. package/dist/agent/tools.js +2 -377
  83. package/dist/app.d.ts +2 -1
  84. package/dist/app.js +846 -173
  85. package/dist/cli-main.js +363 -0
  86. package/dist/cli.js +444 -333
  87. package/dist/commands/about.js +1 -1
  88. package/dist/commands/attach.d.ts +9 -0
  89. package/dist/commands/attach.js +15 -0
  90. package/dist/commands/bg.d.ts +7 -0
  91. package/dist/commands/bg.js +9 -0
  92. package/dist/commands/cancel.d.ts +10 -0
  93. package/dist/commands/cancel.js +10 -0
  94. package/dist/commands/clear.d.ts +1 -0
  95. package/dist/commands/clear.js +1 -1
  96. package/dist/commands/compact.d.ts +22 -0
  97. package/dist/commands/compact.js +34 -0
  98. package/dist/commands/context.d.ts +7 -0
  99. package/dist/commands/context.js +25 -0
  100. package/dist/commands/edit.d.ts +10 -0
  101. package/dist/commands/edit.js +36 -0
  102. package/dist/commands/effort.d.ts +25 -0
  103. package/dist/commands/effort.js +48 -0
  104. package/dist/commands/expand.d.ts +10 -0
  105. package/dist/commands/expand.js +8 -0
  106. package/dist/commands/index.js +24 -0
  107. package/dist/commands/jobs.d.ts +7 -0
  108. package/dist/commands/jobs.js +17 -0
  109. package/dist/commands/kill.d.ts +7 -0
  110. package/dist/commands/kill.js +13 -0
  111. package/dist/commands/login.d.ts +6 -4
  112. package/dist/commands/login.js +24 -22
  113. package/dist/commands/logout.js +8 -16
  114. package/dist/commands/model.d.ts +1 -0
  115. package/dist/commands/model.js +10 -22
  116. package/dist/commands/provider.d.ts +1 -2
  117. package/dist/commands/provider.js +4 -11
  118. package/dist/commands/skills.js +34 -4
  119. package/dist/commands/steer.d.ts +11 -0
  120. package/dist/commands/steer.js +13 -0
  121. package/dist/commands/threads.d.ts +9 -0
  122. package/dist/commands/threads.js +26 -0
  123. package/dist/commands/whoami.js +6 -5
  124. package/dist/config/store.d.ts +53 -12
  125. package/dist/config/store.js +163 -73
  126. package/dist/config/trust.d.ts +30 -8
  127. package/dist/config/trust.js +139 -14
  128. package/dist/headless.d.ts +7 -0
  129. package/dist/headless.js +213 -0
  130. package/dist/index.js +19 -3
  131. package/dist/lib/debug.d.ts +2 -0
  132. package/dist/lib/debug.js +22 -0
  133. package/dist/lib/diagnostics.d.ts +48 -4
  134. package/dist/lib/diagnostics.js +90 -8
  135. package/dist/lib/highlight-subset.d.ts +21 -0
  136. package/dist/lib/highlight-subset.js +88 -0
  137. package/dist/lib/http.d.ts +11 -1
  138. package/dist/lib/http.js +62 -4
  139. package/dist/lib/lifecycle.d.ts +5 -0
  140. package/dist/lib/lifecycle.js +62 -0
  141. package/dist/lib/markdown.js +22 -4
  142. package/dist/lib/model-meta.d.ts +19 -0
  143. package/dist/lib/model-meta.js +113 -0
  144. package/dist/lib/native-tools.d.ts +12 -0
  145. package/dist/lib/native-tools.js +21 -0
  146. package/dist/lib/net.d.ts +33 -0
  147. package/dist/lib/net.js +168 -0
  148. package/dist/patch/apply.d.ts +15 -0
  149. package/dist/patch/apply.js +172 -0
  150. package/dist/patch/parse.d.ts +29 -0
  151. package/dist/patch/parse.js +112 -0
  152. package/dist/patch/plan.d.ts +49 -0
  153. package/dist/patch/plan.js +273 -0
  154. package/dist/providers/anthropic.d.ts +1 -0
  155. package/dist/providers/anthropic.js +12 -0
  156. package/dist/providers/custom.d.ts +9 -0
  157. package/dist/providers/deepseek.d.ts +10 -0
  158. package/dist/providers/deepseek.js +3 -2
  159. package/dist/providers/google.d.ts +9 -0
  160. package/dist/providers/groq.d.ts +10 -0
  161. package/dist/providers/groq.js +2 -1
  162. package/dist/providers/index.d.ts +10 -201
  163. package/dist/providers/index.js +30 -0
  164. package/dist/providers/mistral.d.ts +10 -0
  165. package/dist/providers/mistral.js +2 -1
  166. package/dist/providers/moonshot.d.ts +10 -0
  167. package/dist/providers/moonshot.js +2 -1
  168. package/dist/providers/ollama.d.ts +9 -0
  169. package/dist/providers/openai.d.ts +10 -0
  170. package/dist/providers/openai.js +2 -1
  171. package/dist/providers/openaiCompatible.d.ts +33 -2
  172. package/dist/providers/openaiCompatible.js +78 -16
  173. package/dist/providers/openrouter.d.ts +10 -0
  174. package/dist/providers/openrouter.js +2 -1
  175. package/dist/providers/qwen.d.ts +10 -0
  176. package/dist/providers/qwen.js +2 -1
  177. package/dist/providers/spec.d.ts +12 -0
  178. package/dist/providers/spec.js +29 -0
  179. package/dist/providers/xai.d.ts +10 -0
  180. package/dist/providers/xai.js +2 -1
  181. package/dist/providers/zhipu.d.ts +10 -0
  182. package/dist/providers/zhipu.js +2 -1
  183. package/dist/session/log.d.ts +49 -14
  184. package/dist/session/log.js +236 -11
  185. package/dist/session/projection.d.ts +76 -0
  186. package/dist/session/projection.js +526 -0
  187. package/dist/skills/manager.d.ts +15 -0
  188. package/dist/skills/manager.js +135 -18
  189. package/dist/types.d.ts +75 -1
  190. package/dist/ui/Message.d.ts +1 -7
  191. package/dist/ui/Message.js +13 -2
  192. package/dist/ui/Picker.d.ts +8 -0
  193. package/dist/ui/Picker.js +24 -0
  194. package/dist/ui/Prompt.d.ts +1 -2
  195. package/dist/ui/Prompt.js +2 -2
  196. package/dist/ui/Spinner.js +11 -5
  197. package/dist/ui/StatusBar.d.ts +2 -1
  198. package/dist/ui/StatusBar.js +6 -5
  199. package/package.json +3 -2
  200. package/src/agent/approval-json.ts +103 -0
  201. package/src/agent/approval-native.ts +168 -0
  202. package/src/agent/approval-store.ts +38 -0
  203. package/src/agent/approval.ts +94 -0
  204. package/src/agent/compaction.ts +321 -0
  205. package/src/agent/context.ts +97 -0
  206. package/src/agent/guards.ts +1239 -19
  207. package/src/agent/ignore.ts +147 -0
  208. package/src/agent/policy/defaults.ts +34 -0
  209. package/src/agent/policy/egress.ts +335 -0
  210. package/src/agent/process-tree.ts +114 -0
  211. package/src/agent/protocol-mode.ts +59 -0
  212. package/src/agent/protocol.ts +191 -40
  213. package/src/agent/registry.ts +270 -0
  214. package/src/agent/runner.ts +486 -0
  215. package/src/agent/shell-ast.ts +227 -0
  216. package/src/agent/shell-session.ts +673 -0
  217. package/src/agent/stream.ts +143 -0
  218. package/src/agent/tool-schemas.ts +86 -0
  219. package/src/agent/tools/append_file.ts +30 -0
  220. package/src/agent/tools/apply_patch.ts +95 -0
  221. package/src/agent/tools/copy_file.ts +56 -0
  222. package/src/agent/tools/delete_file.ts +45 -0
  223. package/src/agent/tools/grep.ts +57 -0
  224. package/src/agent/tools/index.ts +34 -0
  225. package/src/agent/tools/list_files.ts +19 -0
  226. package/src/agent/tools/make_dir.ts +28 -0
  227. package/src/agent/tools/move_path.ts +83 -0
  228. package/src/agent/tools/paths.ts +92 -0
  229. package/src/agent/tools/pwd.ts +12 -0
  230. package/src/agent/tools/read_file.ts +84 -0
  231. package/src/agent/tools/read_many.ts +45 -0
  232. package/src/agent/tools/readers.ts +491 -0
  233. package/src/agent/tools/replace_in_file.ts +66 -0
  234. package/src/agent/tools/shell.ts +53 -0
  235. package/src/agent/tools/stat_path.ts +33 -0
  236. package/src/agent/tools/types.ts +84 -0
  237. package/src/agent/tools/validate.ts +104 -0
  238. package/src/agent/tools/write_file.ts +30 -0
  239. package/src/agent/tools.ts +3 -377
  240. package/src/app.ts +853 -170
  241. package/src/{cli.ts → cli-main.ts} +64 -9
  242. package/src/commands/about.ts +1 -1
  243. package/src/commands/attach.ts +16 -0
  244. package/src/commands/bg.ts +9 -0
  245. package/src/commands/cancel.ts +10 -0
  246. package/src/commands/clear.ts +1 -1
  247. package/src/commands/compact.ts +35 -0
  248. package/src/commands/context.ts +26 -0
  249. package/src/commands/edit.ts +37 -0
  250. package/src/commands/effort.ts +49 -0
  251. package/src/commands/expand.ts +8 -0
  252. package/src/commands/index.ts +24 -0
  253. package/src/commands/jobs.ts +18 -0
  254. package/src/commands/kill.ts +14 -0
  255. package/src/commands/login.ts +24 -22
  256. package/src/commands/logout.ts +8 -16
  257. package/src/commands/model.ts +10 -22
  258. package/src/commands/provider.ts +4 -11
  259. package/src/commands/skills.ts +34 -4
  260. package/src/commands/steer.ts +13 -0
  261. package/src/commands/threads.ts +28 -0
  262. package/src/commands/whoami.ts +6 -5
  263. package/src/config/store.ts +168 -77
  264. package/src/config/trust.ts +181 -22
  265. package/src/headless.ts +225 -0
  266. package/src/index.ts +19 -3
  267. package/src/lib/debug.ts +24 -0
  268. package/src/lib/diagnostics.ts +90 -8
  269. package/src/lib/highlight-subset.ts +93 -0
  270. package/src/lib/http.ts +66 -4
  271. package/src/lib/lifecycle.ts +69 -0
  272. package/src/lib/markdown.ts +22 -4
  273. package/src/lib/model-meta.ts +138 -0
  274. package/src/lib/native-tools.ts +32 -0
  275. package/src/lib/net.ts +204 -0
  276. package/src/patch/apply.ts +194 -0
  277. package/src/patch/parse.ts +131 -0
  278. package/src/patch/plan.ts +317 -0
  279. package/src/providers/anthropic.ts +13 -1
  280. package/src/providers/deepseek.ts +3 -2
  281. package/src/providers/groq.ts +2 -1
  282. package/src/providers/index.ts +32 -1
  283. package/src/providers/mistral.ts +2 -1
  284. package/src/providers/moonshot.ts +2 -1
  285. package/src/providers/openai.ts +2 -1
  286. package/src/providers/openaiCompatible.ts +104 -19
  287. package/src/providers/openrouter.ts +2 -1
  288. package/src/providers/qwen.ts +2 -1
  289. package/src/providers/spec.ts +42 -0
  290. package/src/providers/xai.ts +2 -1
  291. package/src/providers/zhipu.ts +2 -1
  292. package/src/session/log.ts +311 -29
  293. package/src/session/projection.ts +621 -0
  294. package/src/skills/manager.ts +140 -18
  295. package/src/types/highlight-shims.d.ts +14 -0
  296. package/src/types.ts +79 -2
  297. package/src/ui/Message.ts +13 -2
  298. package/src/ui/Picker.ts +24 -0
  299. package/src/ui/Prompt.ts +2 -2
  300. package/src/ui/Spinner.ts +11 -5
  301. package/src/ui/StatusBar.ts +6 -5
  302. package/tsconfig.json +1 -0
  303. /package/dist/{cli.d.ts → cli-main.d.ts} +0 -0
@@ -0,0 +1,273 @@
1
+ import { closeSync, constants as fsConstants, lstatSync, openSync, readFileSync } from "node:fs";
2
+ import { basename } from "node:path";
3
+ import { sandboxPath } from "../agent/tools/paths.js";
4
+ import { parsePatch } from "./parse.js";
5
+ export function planPatch(patch, cwd) {
6
+ const parsed = parsePatch(patch);
7
+ if (parsed.ok === false)
8
+ return { ok: false, output: parsed.output };
9
+ const files = [];
10
+ const warnings = [];
11
+ for (const op of parsed.ops) {
12
+ const planned = planOp(op, cwd, warnings);
13
+ if (planned.ok === false)
14
+ return { ok: false, output: planned.output };
15
+ files.push(planned.file);
16
+ }
17
+ return { ok: true, plan: { files, warnings } };
18
+ }
19
+ function planOp(op, cwd, warnings) {
20
+ try {
21
+ const path = sandboxPath(cwd, op.path);
22
+ if (op.kind === "add") {
23
+ if (lexists(path))
24
+ return { ok: false, output: `Add File target already exists: ${op.path}` };
25
+ const newContent = op.lines.length > 0 ? op.lines.join("\n") + "\n" : "";
26
+ return {
27
+ ok: true,
28
+ file: {
29
+ kind: "add",
30
+ relPath: op.path,
31
+ path,
32
+ existed: false,
33
+ origMode: 0o644,
34
+ eol: "\n",
35
+ newContent,
36
+ diff: makeDiff(null, op.path, "", newContent, "add"),
37
+ changedLines: newContent.split("\n").filter(Boolean).length,
38
+ },
39
+ };
40
+ }
41
+ if (!lexists(path))
42
+ return { ok: false, output: `file not found: ${op.path}` };
43
+ const info = lstatSync(path);
44
+ if (info.isSymbolicLink())
45
+ return { ok: false, output: `refusing to patch a symbolic link: ${op.path}` };
46
+ if (!info.isFile())
47
+ return { ok: false, output: `not a regular file: ${op.path}` };
48
+ const oldContent = readNoFollow(path);
49
+ if (op.kind === "delete") {
50
+ return {
51
+ ok: true,
52
+ file: {
53
+ kind: "delete",
54
+ relPath: op.path,
55
+ path,
56
+ existed: true,
57
+ origMode: info.mode & 0o777,
58
+ eol: detectEol(oldContent),
59
+ oldContent,
60
+ diff: makeDiff(op.path, null, oldContent, "", "delete"),
61
+ changedLines: oldContent.split(/\r?\n/).length,
62
+ },
63
+ };
64
+ }
65
+ const eol = detectEol(oldContent);
66
+ if (eol === "\n" && /\r\n/.test(oldContent))
67
+ warnings.push(`mixed line endings in ${op.path}; writing LF`);
68
+ let newContent = oldContent;
69
+ if (op.hunks.length > 0) {
70
+ const applied = applyHunks(oldContent, op.hunks);
71
+ if (applied.ok === false)
72
+ return applied;
73
+ newContent = applied.content;
74
+ if (eol === "\r\n")
75
+ newContent = newContent.replace(/\n/g, "\r\n");
76
+ }
77
+ let moveTo;
78
+ let moveRel;
79
+ if (op.moveTo) {
80
+ moveTo = sandboxPath(cwd, op.moveTo);
81
+ if (lexists(moveTo))
82
+ return { ok: false, output: `Move target already exists: ${op.moveTo}` };
83
+ moveRel = op.moveTo;
84
+ }
85
+ const diff = makeDiff(op.path, op.moveTo ?? op.path, oldContent, newContent, "update");
86
+ return {
87
+ ok: true,
88
+ file: {
89
+ kind: "update",
90
+ relPath: op.path,
91
+ path,
92
+ moveRel,
93
+ moveTo,
94
+ existed: true,
95
+ origMode: info.mode & 0o777,
96
+ eol,
97
+ oldContent,
98
+ newContent,
99
+ diff,
100
+ changedLines: countChangedLines(oldContent, newContent),
101
+ },
102
+ };
103
+ }
104
+ catch (err) {
105
+ return { ok: false, output: err?.message ?? String(err) };
106
+ }
107
+ }
108
+ export function reviewPatchPlan(plan) {
109
+ let changed = 0;
110
+ for (const file of plan.files) {
111
+ changed += file.changedLines;
112
+ if (isHardDenied(file.path))
113
+ return { kind: "deny", reason: `patch targets a protected path: ${file.relPath}` };
114
+ if (isSensitivePath(file.path))
115
+ return { kind: "pending", reason: `patch targets a sensitive path: ${file.relPath}`, changedLines: changed };
116
+ }
117
+ if (changed > 200)
118
+ return { kind: "pending", reason: `patch changes ${changed} lines (limit 200)`, changedLines: changed };
119
+ return { kind: "allow" };
120
+ }
121
+ function isHardDenied(path) {
122
+ const normalized = path.replace(/\\/g, "/").toLowerCase();
123
+ const segments = normalized.split("/");
124
+ if (segments.includes(".ssh") || segments.includes(".gnupg"))
125
+ return true;
126
+ if (normalized.includes("/.git/hooks/"))
127
+ return true;
128
+ if (normalized.includes("/android/data/"))
129
+ return true;
130
+ const name = basename(normalized);
131
+ return name === "auth.json" || name === "trust.json";
132
+ }
133
+ function isSensitivePath(path) {
134
+ const normalized = path.replace(/\\/g, "/").toLowerCase();
135
+ const name = basename(normalized);
136
+ return name === ".env" || name.startsWith(".env.") || /[.](pem|key|p12|pfx)$/.test(name) || normalized.includes("/.git/hooks/");
137
+ }
138
+ function lexists(path) {
139
+ try {
140
+ lstatSync(path);
141
+ return true;
142
+ }
143
+ catch {
144
+ return false;
145
+ }
146
+ }
147
+ function readNoFollow(path) {
148
+ const flags = fsConstants.O_RDONLY | (fsConstants.O_NOFOLLOW ?? 0);
149
+ const fd = openSync(path, flags);
150
+ try {
151
+ return readFileSync(fd, "utf8");
152
+ }
153
+ finally {
154
+ closeSync(fd);
155
+ }
156
+ }
157
+ export function detectEol(content) {
158
+ const crlf = (content.match(/\r\n/g) ?? []).length;
159
+ const lf = (content.match(/\n/g) ?? []).length;
160
+ return crlf > 0 && crlf === lf ? "\r\n" : "\n";
161
+ }
162
+ export function applyHunks(oldContent, hunks) {
163
+ const lines = oldContent.split(/\r?\n/);
164
+ let changed = false;
165
+ for (const hunk of hunks) {
166
+ const needle = hunk.lines.filter((line) => line.type !== "+").map((line) => line.text);
167
+ const replacement = hunk.lines.filter((line) => line.type !== "-").map((line) => line.text);
168
+ if (needle.length === 0) {
169
+ const at = lines.length > 0 && lines[lines.length - 1] === "" ? lines.length - 1 : lines.length;
170
+ lines.splice(at, 0, ...replacement);
171
+ changed = true;
172
+ continue;
173
+ }
174
+ const verdict = findHunk(lines, needle);
175
+ if (verdict.ok === false)
176
+ return verdict;
177
+ lines.splice(verdict.index, needle.length, ...replacement);
178
+ changed = true;
179
+ }
180
+ if (!changed)
181
+ return { ok: false, output: "patch made no changes" };
182
+ return { ok: true, content: lines.join("\n") };
183
+ }
184
+ function findHunk(lines, needle) {
185
+ for (let level = 0; level < 3; level += 1) {
186
+ const matches = matchAll(lines, needle, level);
187
+ if (matches.length === 0)
188
+ continue;
189
+ if (matches.length > 1) {
190
+ return {
191
+ ok: false,
192
+ output: `ambiguous patch context (${matches.length} candidates at lines ${matches.map((index) => index + 1).join(", ")}); add surrounding context`,
193
+ };
194
+ }
195
+ return { ok: true, index: matches[0] };
196
+ }
197
+ return { ok: false, output: `patch context not found: ${JSON.stringify(needle.slice(0, 4))}` };
198
+ }
199
+ function matchAll(lines, needle, level) {
200
+ const found = [];
201
+ const wanted = needle.map((line) => normalizeLine(line, level));
202
+ for (let i = 0; i + needle.length <= lines.length; i += 1) {
203
+ let match = true;
204
+ for (let j = 0; j < needle.length; j += 1) {
205
+ if (normalizeLine(lines[i + j], level) !== wanted[j]) {
206
+ match = false;
207
+ break;
208
+ }
209
+ }
210
+ if (match)
211
+ found.push(i);
212
+ }
213
+ return found;
214
+ }
215
+ function normalizeLine(line, level) {
216
+ if (level === 0)
217
+ return line;
218
+ if (level === 1)
219
+ return line.replace(/\s+$/, "");
220
+ return line.replace(/\s+/g, " ").trim();
221
+ }
222
+ export function makeDiff(oldPath, newPath, oldContent, newContent, kind) {
223
+ const oldLines = splitDiffLines(oldContent);
224
+ const newLines = splitDiffLines(newContent);
225
+ let prefix = 0;
226
+ while (prefix < oldLines.length && prefix < newLines.length && oldLines[prefix] === newLines[prefix])
227
+ prefix += 1;
228
+ let suffix = 0;
229
+ while (suffix < oldLines.length - prefix && suffix < newLines.length - prefix &&
230
+ oldLines[oldLines.length - 1 - suffix] === newLines[newLines.length - 1 - suffix])
231
+ suffix += 1;
232
+ const oldMiddle = oldLines.slice(prefix, oldLines.length - suffix);
233
+ const newMiddle = newLines.slice(prefix, newLines.length - suffix);
234
+ const oldStart = prefix + 1;
235
+ const newStart = prefix + 1;
236
+ const header = kind === "add"
237
+ ? `--- /dev/null\n+++ b/${newPath ?? ""}`
238
+ : kind === "delete"
239
+ ? `--- a/${oldPath ?? ""}\n+++ /dev/null`
240
+ : `--- a/${oldPath ?? ""}\n+++ b/${newPath ?? oldPath ?? ""}`;
241
+ const body = [
242
+ `@@ -${oldStart},${oldMiddle.length} +${newStart},${newMiddle.length} @@`,
243
+ ...oldMiddle.map((line) => "-" + line),
244
+ ...newMiddle.map((line) => "+" + line),
245
+ ];
246
+ return [header, ...body].join("\n");
247
+ }
248
+ function splitDiffLines(content) {
249
+ if (content === "")
250
+ return [];
251
+ const lines = content.split(/\r?\n/);
252
+ if (lines.length > 0 && lines[lines.length - 1] === "")
253
+ lines.pop();
254
+ return lines;
255
+ }
256
+ function countChangedLines(oldContent, newContent) {
257
+ const oldLines = oldContent.split(/\r?\n/);
258
+ const newLines = newContent.split(/\r?\n/);
259
+ let changed = 0;
260
+ let i = 0;
261
+ let j = 0;
262
+ while (i < oldLines.length && j < newLines.length) {
263
+ if (oldLines[i] === newLines[j]) {
264
+ i += 1;
265
+ j += 1;
266
+ continue;
267
+ }
268
+ changed += 1;
269
+ i += 1;
270
+ j += 1;
271
+ }
272
+ return changed + Math.abs(oldLines.length - newLines.length);
273
+ }
@@ -4,6 +4,7 @@ export declare const anthropicProvider: {
4
4
  authEnv: string[];
5
5
  baseUrl: string;
6
6
  defaultModel: string;
7
+ supportsReasoning(): boolean;
7
8
  listModels(apiKey: any): Promise<any>;
8
9
  stream(req: any, apiKey: any): AsyncGenerator<{
9
10
  delta: any;
@@ -10,12 +10,16 @@ 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 };
13
14
  export const anthropicProvider = {
14
15
  id: "anthropic",
15
16
  label: "Anthropic (Claude)",
16
17
  authEnv: ["ANTHROPIC_API_KEY", "CLAUDE_API_KEY"],
17
18
  baseUrl: BASE,
18
19
  defaultModel: "claude-sonnet-5.5",
20
+ supportsReasoning() {
21
+ return true;
22
+ },
19
23
  async listModels(apiKey) {
20
24
  // Query the live model list; fall back to the built-in list offline.
21
25
  if (apiKey) {
@@ -53,6 +57,14 @@ export const anthropicProvider = {
53
57
  max_tokens: req.maxOutputTokens ?? 4096,
54
58
  ...(req.temperature !== undefined ? { temperature: req.temperature } : {}),
55
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
+ }
56
68
  const res = await fetch(BASE + "/messages", {
57
69
  method: "POST",
58
70
  headers: {
@@ -10,15 +10,24 @@ export declare const customProvider: {
10
10
  done: boolean;
11
11
  reasoning?: undefined;
12
12
  usage?: undefined;
13
+ toolCalls?: undefined;
13
14
  } | {
14
15
  delta: string;
15
16
  done: boolean;
16
17
  reasoning: string;
17
18
  usage?: undefined;
19
+ toolCalls?: undefined;
18
20
  } | {
19
21
  delta: string;
20
22
  done: boolean;
21
23
  usage: any;
24
+ toolCalls: import("../types.js").NativeToolCall[];
22
25
  reasoning?: undefined;
26
+ } | {
27
+ delta: string;
28
+ done: boolean;
29
+ usage: any;
30
+ reasoning?: undefined;
31
+ toolCalls?: undefined;
23
32
  }, void, unknown>;
24
33
  };
@@ -10,15 +10,25 @@ export declare const deepseekProvider: {
10
10
  done: boolean;
11
11
  reasoning?: undefined;
12
12
  usage?: undefined;
13
+ toolCalls?: undefined;
13
14
  } | {
14
15
  delta: string;
15
16
  done: boolean;
16
17
  reasoning: string;
17
18
  usage?: undefined;
19
+ toolCalls?: undefined;
18
20
  } | {
19
21
  delta: string;
20
22
  done: boolean;
21
23
  usage: any;
24
+ toolCalls: import("../types.js").NativeToolCall[];
22
25
  reasoning?: undefined;
26
+ } | {
27
+ delta: string;
28
+ done: boolean;
29
+ usage: any;
30
+ reasoning?: undefined;
31
+ toolCalls?: undefined;
23
32
  }, void, unknown>;
33
+ supportsReasoning: () => boolean;
24
34
  };
@@ -9,7 +9,8 @@ export const deepseekProvider = {
9
9
  label: "DeepSeek",
10
10
  authEnv: ["DEEPSEEK_API_KEY"],
11
11
  baseUrl: BASE,
12
- defaultModel: "deepseek-v4-pro",
12
+ defaultModel: "deepseek-flash",
13
13
  listModels: (apiKey) => listModelsHttp({ baseUrl: BASE, apiKey, staticModels: STATIC }),
14
- stream: (req, apiKey) => streamChatCompletion(req, { baseUrl: BASE, apiKey, staticModels: STATIC }),
14
+ stream: (req, apiKey) => streamChatCompletion(req, { baseUrl: BASE, apiKey, staticModels: STATIC, reasoning: "openai" }),
15
+ supportsReasoning: () => true,
15
16
  };
@@ -10,15 +10,24 @@ export declare const googleProvider: {
10
10
  done: boolean;
11
11
  reasoning?: undefined;
12
12
  usage?: undefined;
13
+ toolCalls?: undefined;
13
14
  } | {
14
15
  delta: string;
15
16
  done: boolean;
16
17
  reasoning: string;
17
18
  usage?: undefined;
19
+ toolCalls?: undefined;
18
20
  } | {
19
21
  delta: string;
20
22
  done: boolean;
21
23
  usage: any;
24
+ toolCalls: import("../types.js").NativeToolCall[];
22
25
  reasoning?: undefined;
26
+ } | {
27
+ delta: string;
28
+ done: boolean;
29
+ usage: any;
30
+ reasoning?: undefined;
31
+ toolCalls?: undefined;
23
32
  }, void, unknown>;
24
33
  };
@@ -10,15 +10,25 @@ export declare const groqProvider: {
10
10
  done: boolean;
11
11
  reasoning?: undefined;
12
12
  usage?: undefined;
13
+ toolCalls?: undefined;
13
14
  } | {
14
15
  delta: string;
15
16
  done: boolean;
16
17
  reasoning: string;
17
18
  usage?: undefined;
19
+ toolCalls?: undefined;
18
20
  } | {
19
21
  delta: string;
20
22
  done: boolean;
21
23
  usage: any;
24
+ toolCalls: import("../types.js").NativeToolCall[];
22
25
  reasoning?: undefined;
26
+ } | {
27
+ delta: string;
28
+ done: boolean;
29
+ usage: any;
30
+ reasoning?: undefined;
31
+ toolCalls?: undefined;
23
32
  }, void, unknown>;
33
+ supportsReasoning: () => boolean;
24
34
  };
@@ -16,5 +16,6 @@ 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 }),
19
+ stream: (req, apiKey) => streamChatCompletion(req, { baseUrl: BASE, apiKey, staticModels: STATIC, reasoning: "openai" }),
20
+ supportsReasoning: () => true,
20
21
  };
@@ -1,201 +1,10 @@
1
- export declare const PROVIDERS: ({
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: any;
10
- done: boolean;
11
- usage?: undefined;
12
- } | {
13
- delta: string;
14
- done: boolean;
15
- usage: {
16
- inputTokens: number;
17
- outputTokens: number;
18
- costUsd: number;
19
- };
20
- }, void, unknown>;
21
- } | {
22
- id: string;
23
- label: string;
24
- authEnv: string[];
25
- readonly baseUrl: string;
26
- defaultModel: string;
27
- listModels: (apiKey: any) => Promise<any>;
28
- stream: (req: any, apiKey: any) => AsyncGenerator<{
29
- delta: string;
30
- done: boolean;
31
- reasoning?: undefined;
32
- usage?: undefined;
33
- } | {
34
- delta: string;
35
- done: boolean;
36
- reasoning: string;
37
- usage?: undefined;
38
- } | {
39
- delta: string;
40
- done: boolean;
41
- usage: any;
42
- reasoning?: undefined;
43
- }, void, unknown>;
44
- } | {
45
- id: string;
46
- label: string;
47
- authEnv: any[];
48
- readonly baseUrl: string;
49
- defaultModel: string;
50
- listModels: () => Promise<any>;
51
- stream: (req: any) => AsyncGenerator<{
52
- delta: string;
53
- done: boolean;
54
- reasoning?: undefined;
55
- usage?: undefined;
56
- } | {
57
- delta: string;
58
- done: boolean;
59
- reasoning: string;
60
- usage?: undefined;
61
- } | {
62
- delta: string;
63
- done: boolean;
64
- usage: any;
65
- reasoning?: undefined;
66
- }, void, unknown>;
67
- })[];
68
- export declare function getProvider(id: any): {
69
- id: string;
70
- label: string;
71
- authEnv: string[];
72
- baseUrl: string;
73
- defaultModel: string;
74
- listModels(apiKey: any): Promise<any>;
75
- stream(req: any, apiKey: any): AsyncGenerator<{
76
- delta: any;
77
- done: boolean;
78
- usage?: undefined;
79
- } | {
80
- delta: string;
81
- done: boolean;
82
- usage: {
83
- inputTokens: number;
84
- outputTokens: number;
85
- costUsd: number;
86
- };
87
- }, void, unknown>;
88
- } | {
89
- id: string;
90
- label: string;
91
- authEnv: string[];
92
- readonly baseUrl: string;
93
- defaultModel: string;
94
- listModels: (apiKey: any) => Promise<any>;
95
- stream: (req: any, apiKey: any) => AsyncGenerator<{
96
- delta: string;
97
- done: boolean;
98
- reasoning?: undefined;
99
- usage?: undefined;
100
- } | {
101
- delta: string;
102
- done: boolean;
103
- reasoning: string;
104
- usage?: undefined;
105
- } | {
106
- delta: string;
107
- done: boolean;
108
- usage: any;
109
- reasoning?: undefined;
110
- }, void, unknown>;
111
- } | {
112
- id: string;
113
- label: string;
114
- authEnv: any[];
115
- readonly baseUrl: string;
116
- defaultModel: string;
117
- listModels: () => Promise<any>;
118
- stream: (req: any) => AsyncGenerator<{
119
- delta: string;
120
- done: boolean;
121
- reasoning?: undefined;
122
- usage?: undefined;
123
- } | {
124
- delta: string;
125
- done: boolean;
126
- reasoning: string;
127
- usage?: undefined;
128
- } | {
129
- delta: string;
130
- done: boolean;
131
- usage: any;
132
- reasoning?: undefined;
133
- }, void, unknown>;
134
- };
135
- export declare function getProviderOrThrow(id: any): {
136
- id: string;
137
- label: string;
138
- authEnv: string[];
139
- baseUrl: string;
140
- defaultModel: string;
141
- listModels(apiKey: any): Promise<any>;
142
- stream(req: any, apiKey: any): AsyncGenerator<{
143
- delta: any;
144
- done: boolean;
145
- usage?: undefined;
146
- } | {
147
- delta: string;
148
- done: boolean;
149
- usage: {
150
- inputTokens: number;
151
- outputTokens: number;
152
- costUsd: number;
153
- };
154
- }, void, unknown>;
155
- } | {
156
- id: string;
157
- label: string;
158
- authEnv: string[];
159
- readonly baseUrl: string;
160
- defaultModel: string;
161
- listModels: (apiKey: any) => Promise<any>;
162
- stream: (req: any, apiKey: any) => AsyncGenerator<{
163
- delta: string;
164
- done: boolean;
165
- reasoning?: undefined;
166
- usage?: undefined;
167
- } | {
168
- delta: string;
169
- done: boolean;
170
- reasoning: string;
171
- usage?: undefined;
172
- } | {
173
- delta: string;
174
- done: boolean;
175
- usage: any;
176
- reasoning?: undefined;
177
- }, void, unknown>;
178
- } | {
179
- id: string;
180
- label: string;
181
- authEnv: any[];
182
- readonly baseUrl: string;
183
- defaultModel: string;
184
- listModels: () => Promise<any>;
185
- stream: (req: any) => AsyncGenerator<{
186
- delta: string;
187
- done: boolean;
188
- reasoning?: undefined;
189
- usage?: undefined;
190
- } | {
191
- delta: string;
192
- done: boolean;
193
- reasoning: string;
194
- usage?: undefined;
195
- } | {
196
- delta: string;
197
- done: boolean;
198
- usage: any;
199
- reasoning?: undefined;
200
- }, void, unknown>;
201
- };
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>;
@@ -35,3 +35,33 @@ export function getProviderOrThrow(id) {
35
35
  throw new Error("Unknown provider: " + id);
36
36
  return p;
37
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
+ }