@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
@@ -1,113 +0,0 @@
1
- import { existsSync, readFileSync } from "node:fs";
2
- import { homedir } from "node:os";
3
- import { join } from "node:path";
4
- export const UNKNOWN_MODEL_META = {
5
- contextWindow: 32_768,
6
- supportsTools: false,
7
- charsPerToken: 2.5,
8
- };
9
- const PROVIDER_META = {
10
- anthropic: { contextWindow: 1_000_000, supportsTools: true, charsPerToken: 3.8, maxOutputTokens: 64_000 },
11
- openai: { contextWindow: 400_000, supportsTools: true, charsPerToken: 3.8, maxOutputTokens: 32_000 },
12
- google: { contextWindow: 1_048_576, supportsTools: true, charsPerToken: 3.6, maxOutputTokens: 65_536 },
13
- deepseek: { contextWindow: 128_000, supportsTools: true, charsPerToken: 1.7, maxOutputTokens: 8_192 },
14
- openrouter: { contextWindow: 128_000, supportsTools: true, charsPerToken: 2.5, maxOutputTokens: 16_384 },
15
- groq: { contextWindow: 128_000, supportsTools: true, charsPerToken: 3.8, maxOutputTokens: 8_192 },
16
- mistral: { contextWindow: 128_000, supportsTools: true, charsPerToken: 3.8, maxOutputTokens: 8_192 },
17
- xai: { contextWindow: 256_000, supportsTools: true, charsPerToken: 3.8, maxOutputTokens: 16_384 },
18
- moonshot: { contextWindow: 256_000, supportsTools: true, charsPerToken: 2.0, maxOutputTokens: 16_384 },
19
- zhipu: { contextWindow: 128_000, supportsTools: true, charsPerToken: 1.7, maxOutputTokens: 8_192 },
20
- qwen: { contextWindow: 128_000, supportsTools: true, charsPerToken: 1.7, maxOutputTokens: 8_192 },
21
- ollama: { contextWindow: 32_768, supportsTools: true, charsPerToken: 2.5, maxOutputTokens: 4_096 },
22
- custom: { contextWindow: 32_768, supportsTools: false, charsPerToken: 2.5 },
23
- };
24
- const MODEL_OVERRIDES = {
25
- "claude-haiku-5.5": { contextWindow: 200_000 },
26
- "claude-haiku-4.5": { contextWindow: 200_000 },
27
- "claude-sonnet-5": { contextWindow: 1_000_000 },
28
- "claude-opus-5": { contextWindow: 1_000_000 },
29
- "claude-sonnet-4.6": { contextWindow: 1_000_000 },
30
- "claude-opus-4.6": { contextWindow: 1_000_000 },
31
- "gpt-4o": { contextWindow: 128_000 },
32
- "gpt-4o-mini": { contextWindow: 128_000 },
33
- "gpt-4.1": { contextWindow: 1_000_000 },
34
- o3: { contextWindow: 200_000 },
35
- "o4-mini": { contextWindow: 200_000 },
36
- "gemini-3.5-flash-lite": { contextWindow: 1_048_576 },
37
- "gemini-3.1-flash-lite": { contextWindow: 1_048_576 },
38
- "deepseek-v4-pro": { contextWindow: 128_000, charsPerToken: 1.7 },
39
- "deepseek-flash": { contextWindow: 128_000, charsPerToken: 1.7 },
40
- "glm-5.3": { contextWindow: 128_000, charsPerToken: 1.7 },
41
- "glm-5.2": { contextWindow: 128_000, charsPerToken: 1.7 },
42
- "qwen3.8-max": { contextWindow: 128_000, charsPerToken: 1.7 },
43
- "qwen3.8-flash": { contextWindow: 128_000, charsPerToken: 1.7 },
44
- "kimi-k3": { contextWindow: 256_000, charsPerToken: 2.0 },
45
- "grok-4.7": { contextWindow: 256_000, charsPerToken: 3.8 },
46
- "mistral-large-latest": { contextWindow: 128_000, charsPerToken: 3.8 },
47
- };
48
- let overrideCache;
49
- export function modelMetaOverridePath() {
50
- const root = process.env["FASTCODE_HOME"] ?? join(homedir(), ".fastcode");
51
- return join(root, "model-meta.json");
52
- }
53
- export function clearModelMetaCache() {
54
- overrideCache = undefined;
55
- }
56
- function loadOverrides() {
57
- if (overrideCache)
58
- return overrideCache;
59
- const file = modelMetaOverridePath();
60
- if (!existsSync(file)) {
61
- overrideCache = {};
62
- return overrideCache;
63
- }
64
- try {
65
- const raw = JSON.parse(readFileSync(file, "utf8"));
66
- overrideCache = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
67
- }
68
- catch {
69
- overrideCache = {};
70
- }
71
- return overrideCache;
72
- }
73
- function usable(meta) {
74
- return Boolean(meta) && typeof meta === "object";
75
- }
76
- function apply(base, ...layers) {
77
- const next = { ...base };
78
- for (const layer of layers) {
79
- if (!usable(layer))
80
- continue;
81
- if (typeof layer.contextWindow === "number" && layer.contextWindow > 0)
82
- next.contextWindow = Math.floor(layer.contextWindow);
83
- if (typeof layer.charsPerToken === "number" && layer.charsPerToken > 0)
84
- next.charsPerToken = layer.charsPerToken;
85
- if (typeof layer.supportsTools === "boolean")
86
- next.supportsTools = layer.supportsTools;
87
- if (typeof layer.maxOutputTokens === "number" && layer.maxOutputTokens > 0)
88
- next.maxOutputTokens = Math.floor(layer.maxOutputTokens);
89
- }
90
- return next;
91
- }
92
- export function getModelMeta(providerId, model) {
93
- const provider = providerId && PROVIDER_META[providerId] ? PROVIDER_META[providerId] : UNKNOWN_MODEL_META;
94
- const overrides = loadOverrides();
95
- const keys = [
96
- providerId && model ? `${providerId}/${model}` : undefined,
97
- providerId && model ? `${providerId}::${model}` : undefined,
98
- model,
99
- ].filter((key) => Boolean(key));
100
- const layers = keys.map((key) => overrides[key]);
101
- return apply(provider, model ? MODEL_OVERRIDES[model] : undefined, ...layers);
102
- }
103
- export function estTokens(text, options = {}) {
104
- if (!text)
105
- return 0;
106
- const ratio = typeof options === "number"
107
- ? options
108
- : options.charsPerToken ?? getModelMeta(options.providerId, options.model).charsPerToken;
109
- return Math.ceil(text.length / Math.max(0.1, ratio));
110
- }
111
- export function estMessagesTokens(messages, options = {}) {
112
- return messages.reduce((sum, message) => sum + estTokens(message.content ?? "", options), 0);
113
- }
@@ -1,12 +0,0 @@
1
- import type { NativeToolCall } from "../types.js";
2
- export type ToolCallAccumulator = Map<number, NativeToolCall>;
3
- export interface ToolCallDelta {
4
- index?: number;
5
- id?: string;
6
- function?: {
7
- name?: string;
8
- arguments?: string;
9
- };
10
- }
11
- export declare function mergeToolCallDelta(accumulator: ToolCallAccumulator, delta: ToolCallDelta): void;
12
- export declare function finalizeToolCalls(accumulator: ToolCallAccumulator): NativeToolCall[];
@@ -1,21 +0,0 @@
1
- export function mergeToolCallDelta(accumulator, delta) {
2
- const index = typeof delta.index === "number" && Number.isFinite(delta.index) ? delta.index : accumulator.size;
3
- const entry = accumulator.get(index) ?? { id: "", name: "", arguments: "" };
4
- if (typeof delta.id === "string" && delta.id)
5
- entry.id = delta.id;
6
- if (typeof delta.function?.name === "string" && delta.function.name)
7
- entry.name = delta.function.name;
8
- if (typeof delta.function?.arguments === "string")
9
- entry.arguments += delta.function.arguments;
10
- accumulator.set(index, entry);
11
- }
12
- export function finalizeToolCalls(accumulator) {
13
- return Array.from(accumulator.entries())
14
- .sort((a, b) => a[0] - b[0])
15
- .filter(([, call]) => Boolean(call.name))
16
- .map(([index, call]) => ({
17
- id: call.id || `call_${index}`,
18
- name: call.name,
19
- arguments: call.arguments || "{}",
20
- }));
21
- }
package/dist/lib/net.d.ts DELETED
@@ -1,33 +0,0 @@
1
- import type { ChatChunk } from "../types.js";
2
- export declare class QuotaError extends Error {
3
- readonly code = "QUOTA";
4
- constructor(message: string);
5
- }
6
- export declare class IncompleteStreamError extends Error {
7
- readonly partialText: string;
8
- constructor(message: string, partialText: string);
9
- }
10
- export interface RetryRequestOptions {
11
- retries?: number;
12
- backoffMs?: number[];
13
- retryOn?: (error: Error) => boolean;
14
- signal?: AbortSignal;
15
- }
16
- export interface RetryStreamOptions {
17
- clientRequestId?: string;
18
- lastAcc?: string;
19
- retries?: number;
20
- backoffMs?: number[];
21
- retryOn?: (error: Error) => boolean;
22
- signal?: AbortSignal;
23
- onRetry?: (error: Error, attempt: number) => void;
24
- onReset?: () => void;
25
- }
26
- export interface StreamChunk extends ChatChunk {
27
- reset?: boolean;
28
- }
29
- export declare function isRetryableError(error: Error): boolean;
30
- export declare function retryRequest<T>(fn: (attempt: number) => Promise<T>, options?: RetryRequestOptions): Promise<T>;
31
- export declare function retryStream(send: (options: {
32
- clientRequestId: string;
33
- }) => AsyncGenerator<ChatChunk>, options?: RetryStreamOptions): AsyncGenerator<StreamChunk>;
package/dist/lib/net.js DELETED
@@ -1,168 +0,0 @@
1
- import { randomUUID } from "node:crypto";
2
- export class QuotaError extends Error {
3
- code = "QUOTA";
4
- constructor(message) {
5
- super(message);
6
- this.name = "QuotaError";
7
- }
8
- }
9
- export class IncompleteStreamError extends Error {
10
- partialText;
11
- constructor(message, partialText) {
12
- super(message);
13
- this.name = "IncompleteStreamError";
14
- this.partialText = partialText;
15
- }
16
- }
17
- const DEFAULT_BACKOFF = [1000, 2000, 4000];
18
- const STREAM_BACKOFF = [400, 800, 1600];
19
- export function isRetryableError(error) {
20
- const message = String(error?.message ?? error);
21
- if (/\b(401|402|403|404)\b/.test(message))
22
- return false;
23
- if (/timeout|timed? ?out|ECONNRESET|ECONNREFUSED|ENOTFOUND|ETIMEDOUT|EPIPE|fetch failed|network|socket hang up|terminated|other side closed|stream ended before done/i.test(message))
24
- return true;
25
- return /\b(429|5\d\d)\b/.test(message);
26
- }
27
- function isQuotaError(error) {
28
- return /\b429\b|quota|insufficient|rate limit|billing|balance/i.test(String(error?.message ?? error));
29
- }
30
- export async function retryRequest(fn, options = {}) {
31
- const attempts = Math.max(1, Math.floor(options.retries ?? 3));
32
- const backoff = options.backoffMs ?? DEFAULT_BACKOFF;
33
- const retryOn = options.retryOn ?? isRetryableError;
34
- let lastError;
35
- for (let attempt = 0; attempt < attempts; attempt += 1) {
36
- if (options.signal?.aborted)
37
- throw abortError();
38
- try {
39
- return await fn(attempt);
40
- }
41
- catch (err) {
42
- lastError = toError(err);
43
- if (attempt >= attempts - 1 || !retryOn(lastError))
44
- break;
45
- await delay(backoff[Math.min(attempt, backoff.length - 1)], options.signal);
46
- }
47
- }
48
- if (lastError && isQuotaError(lastError))
49
- throw new QuotaError(lastError.message);
50
- throw lastError ?? new Error("retryRequest failed");
51
- }
52
- export async function* retryStream(send, options = {}) {
53
- const clientRequestId = options.clientRequestId ?? randomUUID();
54
- const attempts = Math.max(1, Math.floor(options.retries ?? 1) + 1);
55
- const backoff = options.backoffMs ?? STREAM_BACKOFF;
56
- const retryOn = options.retryOn ?? isRetryableError;
57
- let delivered = options.lastAcc ?? "";
58
- let lastError;
59
- for (let attempt = 0; attempt < attempts; attempt += 1) {
60
- if (options.signal?.aborted)
61
- throw abortError();
62
- let buffering = delivered.length > 0;
63
- let pending = "";
64
- let doneSeen = false;
65
- let usage;
66
- let toolCalls;
67
- try {
68
- for await (const chunk of send({ clientRequestId })) {
69
- if (options.signal?.aborted)
70
- throw abortError();
71
- if (chunk.usage)
72
- usage = chunk.usage;
73
- if (chunk.toolCalls)
74
- toolCalls = chunk.toolCalls;
75
- const delta = chunk.delta ?? "";
76
- if (!delta) {
77
- if (!buffering && !chunk.done)
78
- yield chunk;
79
- if (chunk.done)
80
- doneSeen = true;
81
- continue;
82
- }
83
- if (buffering) {
84
- pending += delta;
85
- const matchedPrefix = delivered.startsWith(pending) || pending.startsWith(delivered);
86
- if (delivered.startsWith(pending)) {
87
- if (pending.length === delivered.length) {
88
- buffering = false;
89
- pending = "";
90
- }
91
- if (chunk.done)
92
- doneSeen = true;
93
- continue;
94
- }
95
- if (matchedPrefix) {
96
- const extra = pending.slice(delivered.length);
97
- buffering = false;
98
- pending = "";
99
- if (extra) {
100
- delivered += extra;
101
- yield { ...chunk, delta: extra, done: false };
102
- }
103
- }
104
- else {
105
- buffering = false;
106
- delivered = pending;
107
- pending = "";
108
- options.onReset?.();
109
- yield { ...chunk, delta: delivered, reset: true, done: false };
110
- }
111
- if (chunk.done)
112
- doneSeen = true;
113
- continue;
114
- }
115
- delivered += delta;
116
- yield { ...chunk, done: false };
117
- if (chunk.done)
118
- doneSeen = true;
119
- }
120
- if (!doneSeen)
121
- throw new IncompleteStreamError("stream ended before done", delivered);
122
- yield {
123
- delta: "",
124
- done: true,
125
- ...(usage ? { usage } : {}),
126
- ...(toolCalls ? { toolCalls } : {}),
127
- };
128
- return;
129
- }
130
- catch (err) {
131
- lastError = toError(err);
132
- if (options.signal?.aborted)
133
- throw abortError();
134
- if (attempt >= attempts - 1 || !retryOn(lastError)) {
135
- lastError.partialText = delivered;
136
- throw lastError;
137
- }
138
- options.onRetry?.(lastError, attempt + 1);
139
- await delay(backoff[Math.min(attempt, backoff.length - 1)], options.signal);
140
- }
141
- }
142
- throw lastError ?? new Error("retryStream failed");
143
- }
144
- function delay(ms, signal) {
145
- return new Promise((resolve, reject) => {
146
- if (signal?.aborted) {
147
- reject(abortError());
148
- return;
149
- }
150
- const timer = setTimeout(() => {
151
- signal?.removeEventListener("abort", onAbort);
152
- resolve();
153
- }, ms);
154
- const onAbort = () => {
155
- clearTimeout(timer);
156
- reject(abortError());
157
- };
158
- signal?.addEventListener("abort", onAbort, { once: true });
159
- });
160
- }
161
- function abortError() {
162
- const error = new Error("Aborted");
163
- error.name = "AbortError";
164
- return error;
165
- }
166
- function toError(value) {
167
- return value instanceof Error ? value : new Error(String(value));
168
- }
@@ -1,15 +0,0 @@
1
- import type { PatchPlan, PlannedFile } from "./plan.js";
2
- export interface AppliedFile {
3
- path: string;
4
- kind: PlannedFile["kind"];
5
- diff: string;
6
- }
7
- export interface ApplyResult {
8
- ok: boolean;
9
- output: string;
10
- files: AppliedFile[];
11
- touched: string[];
12
- removed: string[];
13
- warnings: string[];
14
- }
15
- export declare function applyPatchPlan(plan: PatchPlan): ApplyResult;
@@ -1,172 +0,0 @@
1
- import { closeSync, constants as fsConstants, fchmodSync, lstatSync, mkdirSync, openSync, renameSync, rmSync, unlinkSync, writeSync } from "node:fs";
2
- import { dirname } from "node:path";
3
- export function applyPatchPlan(plan) {
4
- const warnings = [...plan.warnings];
5
- const applied = [];
6
- const touched = [];
7
- const removed = [];
8
- const temps = [];
9
- try {
10
- for (const file of plan.files) {
11
- commit(file, warnings, temps);
12
- applied.push(file);
13
- if (file.kind === "delete") {
14
- removed.push(file.path);
15
- }
16
- else if (file.kind === "add") {
17
- touched.push(file.path);
18
- }
19
- else if (file.moveTo) {
20
- removed.push(file.path);
21
- touched.push(file.moveTo);
22
- }
23
- else {
24
- touched.push(file.path);
25
- }
26
- }
27
- }
28
- catch (err) {
29
- for (const tmp of temps) {
30
- try {
31
- rmSync(tmp, { force: true });
32
- }
33
- catch {
34
- // best effort
35
- }
36
- }
37
- rollback(applied, warnings);
38
- return {
39
- ok: false,
40
- output: `patch failed: ${err?.message ?? String(err)}; rolled back ${applied.length} file(s)`,
41
- files: [],
42
- touched: [],
43
- removed: [],
44
- warnings,
45
- };
46
- }
47
- const files = plan.files.map((file) => ({
48
- path: file.moveTo ?? file.path,
49
- kind: file.kind,
50
- diff: file.diff,
51
- }));
52
- return {
53
- ok: true,
54
- output: [`applied ${plan.files.length} file(s)`, ...files.map((file) => file.diff)].join("\n\n"),
55
- files,
56
- touched,
57
- removed,
58
- warnings,
59
- };
60
- }
61
- function commit(file, warnings, temps) {
62
- if (file.kind === "delete") {
63
- rejectSymlink(file.path);
64
- unlinkSync(file.path);
65
- return;
66
- }
67
- const target = file.moveTo ?? file.path;
68
- if (file.kind === "add" || file.moveTo) {
69
- if (lexists(target))
70
- throw new Error(`target already exists: ${target}`);
71
- }
72
- rejectSymlink(target, true);
73
- mkdirSync(dirname(target), { recursive: true });
74
- const tmp = `${target}.fastcode-patch-${process.pid}-${Math.random().toString(36).slice(2, 8)}.tmp`;
75
- temps.push(tmp);
76
- const flags = fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_EXCL | (fsConstants.O_NOFOLLOW ?? 0);
77
- const fd = openSync(tmp, flags, 0o600);
78
- try {
79
- writeSync(fd, file.newContent ?? "");
80
- try {
81
- fchmodSync(fd, file.origMode & 0o777);
82
- }
83
- catch {
84
- warnings.push(`could not restore mode ${(file.origMode & 0o777).toString(8)} on ${target}; check permissions`);
85
- }
86
- }
87
- finally {
88
- closeSync(fd);
89
- }
90
- rejectSymlink(target, true);
91
- renameSync(tmp, target);
92
- const index = temps.indexOf(tmp);
93
- if (index >= 0)
94
- temps.splice(index, 1);
95
- if (file.moveTo) {
96
- try {
97
- unlinkSync(file.path);
98
- }
99
- catch (err) {
100
- try {
101
- rmSync(target, { force: true });
102
- }
103
- catch {
104
- // best effort
105
- }
106
- throw err;
107
- }
108
- }
109
- }
110
- function rejectSymlink(path, allowMissing = false) {
111
- try {
112
- if (lstatSync(path).isSymbolicLink())
113
- throw new Error(`refusing to write through a symbolic link: ${path}`);
114
- }
115
- catch (err) {
116
- if (err?.code === "ENOENT" && allowMissing)
117
- return;
118
- throw err;
119
- }
120
- }
121
- function lexists(path) {
122
- try {
123
- lstatSync(path);
124
- return true;
125
- }
126
- catch {
127
- return false;
128
- }
129
- }
130
- function rollback(applied, warnings) {
131
- for (let i = applied.length - 1; i >= 0; i -= 1) {
132
- const file = applied[i];
133
- try {
134
- if (file.kind === "add") {
135
- rmSync(file.path, { force: true });
136
- continue;
137
- }
138
- if (file.kind === "delete") {
139
- restore(file.path, file.oldContent ?? "", file.origMode);
140
- continue;
141
- }
142
- if (file.moveTo) {
143
- rmSync(file.moveTo, { force: true });
144
- restore(file.path, file.oldContent ?? "", file.origMode);
145
- continue;
146
- }
147
- restore(file.path, file.oldContent ?? "", file.origMode);
148
- }
149
- catch (err) {
150
- warnings.push(`rollback failed for ${file.path}: ${err?.message ?? String(err)}`);
151
- }
152
- }
153
- }
154
- function restore(path, content, mode) {
155
- mkdirSync(dirname(path), { recursive: true });
156
- const tmp = `${path}.fastcode-restore-${process.pid}-${Math.random().toString(36).slice(2, 8)}.tmp`;
157
- const flags = fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_EXCL | (fsConstants.O_NOFOLLOW ?? 0);
158
- const fd = openSync(tmp, flags, 0o600);
159
- try {
160
- writeSync(fd, content);
161
- try {
162
- fchmodSync(fd, mode & 0o777);
163
- }
164
- catch {
165
- // best effort during rollback
166
- }
167
- }
168
- finally {
169
- closeSync(fd);
170
- }
171
- renameSync(tmp, path);
172
- }
@@ -1,29 +0,0 @@
1
- export type PatchLineType = " " | "-" | "+";
2
- export interface PatchLine {
3
- type: PatchLineType;
4
- text: string;
5
- }
6
- export interface PatchHunk {
7
- lines: PatchLine[];
8
- }
9
- export type PatchOp = {
10
- kind: "add";
11
- path: string;
12
- lines: string[];
13
- } | {
14
- kind: "delete";
15
- path: string;
16
- } | {
17
- kind: "update";
18
- path: string;
19
- hunks: PatchHunk[];
20
- moveTo?: string;
21
- };
22
- export type ParseResult = {
23
- ok: true;
24
- ops: PatchOp[];
25
- } | {
26
- ok: false;
27
- output: string;
28
- };
29
- export declare function parsePatch(patch: string): ParseResult;
@@ -1,112 +0,0 @@
1
- export function parsePatch(patch) {
2
- const lines = String(patch ?? "").split(/\r?\n/);
3
- if (lines[0] !== "*** Begin Patch")
4
- return fail("patch must start with *** Begin Patch");
5
- const ops = [];
6
- const seen = new Set();
7
- const claim = (path) => {
8
- if (!path)
9
- return "empty file path in patch";
10
- if (seen.has(path))
11
- return `duplicate file in patch: ${path}`;
12
- seen.add(path);
13
- return undefined;
14
- };
15
- let i = 1;
16
- let foundEnd = false;
17
- while (i < lines.length) {
18
- const line = lines[i];
19
- if (line === "*** End Patch") {
20
- foundEnd = true;
21
- i += 1;
22
- break;
23
- }
24
- if (line === "" || line === undefined) {
25
- i += 1;
26
- continue;
27
- }
28
- if (line.startsWith("*** Add File: ")) {
29
- const path = line.slice("*** Add File: ".length).trim();
30
- const duplicate = claim(path);
31
- if (duplicate)
32
- return fail(duplicate);
33
- i += 1;
34
- const content = [];
35
- while (i < lines.length && !lines[i].startsWith("*** ")) {
36
- const row = lines[i];
37
- if (row === "") {
38
- content.push("");
39
- i += 1;
40
- continue;
41
- }
42
- if (!row.startsWith("+"))
43
- return fail(`Add File body must start with '+': ${row}`);
44
- content.push(row.slice(1));
45
- i += 1;
46
- }
47
- ops.push({ kind: "add", path, lines: content });
48
- continue;
49
- }
50
- if (line.startsWith("*** Delete File: ")) {
51
- const path = line.slice("*** Delete File: ".length).trim();
52
- const duplicate = claim(path);
53
- if (duplicate)
54
- return fail(duplicate);
55
- ops.push({ kind: "delete", path });
56
- i += 1;
57
- continue;
58
- }
59
- if (line.startsWith("*** Update File: ")) {
60
- const path = line.slice("*** Update File: ".length).trim();
61
- const duplicate = claim(path);
62
- if (duplicate)
63
- return fail(duplicate);
64
- i += 1;
65
- let moveTo;
66
- if (i < lines.length && lines[i].startsWith("*** Move to: ")) {
67
- moveTo = lines[i].slice("*** Move to: ".length).trim();
68
- const movedDuplicate = claim(moveTo);
69
- if (movedDuplicate)
70
- return fail(movedDuplicate);
71
- i += 1;
72
- }
73
- const hunks = [];
74
- let current;
75
- while (i < lines.length && !lines[i].startsWith("*** ")) {
76
- const row = lines[i];
77
- if (row === "") {
78
- i += 1;
79
- continue;
80
- }
81
- if (row.startsWith("@@")) {
82
- current = { lines: [] };
83
- hunks.push(current);
84
- i += 1;
85
- continue;
86
- }
87
- const type = row[0];
88
- if (type !== " " && type !== "-" && type !== "+")
89
- return fail(`invalid hunk line (must start with ' ', '-', or '+'): ${row}`);
90
- if (!current) {
91
- current = { lines: [] };
92
- hunks.push(current);
93
- }
94
- current.lines.push({ type: type, text: row.slice(1) });
95
- i += 1;
96
- }
97
- if (hunks.length === 0 && !moveTo)
98
- return fail(`Update File has no hunks: ${path}`);
99
- ops.push({ kind: "update", path, hunks, moveTo });
100
- continue;
101
- }
102
- return fail(`unsupported patch directive: ${line}`);
103
- }
104
- if (!foundEnd)
105
- return fail("patch must end with *** End Patch");
106
- if (ops.length === 0)
107
- return fail("patch contains no file operations");
108
- return { ok: true, ops };
109
- }
110
- function fail(output) {
111
- return { ok: false, output };
112
- }