flanders 0.0.2 → 0.2.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 (60) hide show
  1. package/lib/ai/AiRunner.d.ts +24 -0
  2. package/lib/ai/AiRunner.js +100 -0
  3. package/lib/ai/AiSession.d.ts +32 -0
  4. package/lib/ai/AiSession.js +143 -0
  5. package/lib/ai/ClaudeAdapter.d.ts +12 -0
  6. package/lib/ai/ClaudeAdapter.js +345 -0
  7. package/lib/ai/CodexAdapter.d.ts +13 -0
  8. package/lib/ai/CodexAdapter.js +354 -0
  9. package/lib/ai/ToolAdapter.d.ts +52 -0
  10. package/lib/ai/ToolAdapter.js +2 -0
  11. package/lib/cli.js +56 -35
  12. package/lib/commands/Implement.d.ts +22 -8
  13. package/lib/commands/Implement.js +296 -171
  14. package/lib/commands/Install.d.ts +31 -3
  15. package/lib/commands/Install.js +649 -49
  16. package/lib/commands/InstallAvailabilityCheck.d.ts +8 -0
  17. package/lib/commands/InstallAvailabilityCheck.js +45 -0
  18. package/lib/commands/InstallModelProbe.d.ts +2 -0
  19. package/lib/commands/InstallModelProbe.js +74 -0
  20. package/lib/contexts.d.ts +5 -4
  21. package/lib/index.d.ts +5 -3
  22. package/lib/{PlanFile.d.ts → plan/PlanFile.d.ts} +8 -1
  23. package/lib/{PlanFile.js → plan/PlanFile.js} +44 -5
  24. package/lib/prompts/prompts.d.ts +48 -0
  25. package/lib/prompts/prompts.js +328 -0
  26. package/lib/prompts/skills.d.ts +3 -0
  27. package/lib/prompts/skills.js +463 -0
  28. package/lib/{Git.d.ts → system/Git.d.ts} +4 -2
  29. package/lib/{Git.js → system/Git.js} +63 -3
  30. package/lib/{ScriptRunner.d.ts → system/ScriptRunner.d.ts} +1 -1
  31. package/lib/system/ShellScriptContext.d.ts +36 -0
  32. package/lib/system/ShellScriptContext.js +70 -0
  33. package/lib/{fsUtils.d.ts → system/fsUtils.d.ts} +1 -1
  34. package/lib/{wait.d.ts → system/wait.d.ts} +1 -1
  35. package/lib/ui/BottomBlock.d.ts +9 -1
  36. package/lib/ui/BottomBlock.js +30 -14
  37. package/lib/ui/PromptHelper.d.ts +12 -0
  38. package/lib/ui/PromptHelper.js +32 -0
  39. package/lib/ui/TerminalSizeSource.d.ts +19 -0
  40. package/lib/ui/TerminalSizeSource.js +77 -0
  41. package/lib/ui/formatters.d.ts +14 -0
  42. package/lib/ui/formatters.js +65 -2
  43. package/lib/workspace/FlandersConfig.d.ts +23 -0
  44. package/lib/workspace/FlandersConfig.js +90 -0
  45. package/lib/workspace/SpecDiscovery.d.ts +12 -0
  46. package/lib/workspace/SpecDiscovery.js +40 -0
  47. package/lib/{Workspace.d.ts → workspace/Workspace.d.ts} +10 -2
  48. package/lib/{Workspace.js → workspace/Workspace.js} +52 -6
  49. package/package.json +3 -2
  50. package/lib/Claude.d.ts +0 -129
  51. package/lib/Claude.js +0 -387
  52. package/lib/ClaudeSession.d.ts +0 -34
  53. package/lib/ClaudeSession.js +0 -292
  54. package/lib/prompts.d.ts +0 -18
  55. package/lib/prompts.js +0 -221
  56. package/lib/skills.d.ts +0 -3
  57. package/lib/skills.js +0 -256
  58. /package/lib/{ScriptRunner.js → system/ScriptRunner.js} +0 -0
  59. /package/lib/{fsUtils.js → system/fsUtils.js} +0 -0
  60. /package/lib/{wait.js → system/wait.js} +0 -0
@@ -0,0 +1,24 @@
1
+ import type { TimeContext } from "../contexts";
2
+ import type { ToolAdapter, ToolAdapterUsageCallback, ToolEventOutput } from "./ToolAdapter";
3
+ export type RunCallbacks = Readonly<{
4
+ onOutput(event: ToolEventOutput): void;
5
+ onSessionId(id: string): void;
6
+ onUsage?: ToolAdapterUsageCallback;
7
+ onWaitStart?(kind: "rate-limit", endTimeMs: number): void;
8
+ onWaitEnd?(): void;
9
+ }>;
10
+ export type RunArgs = Readonly<{
11
+ adapter: ToolAdapter;
12
+ prompt: string;
13
+ model: string;
14
+ effort: string;
15
+ resumeSessionId?: string;
16
+ forkParentSessionId?: string;
17
+ abortSignal: AbortSignal;
18
+ callbacks: RunCallbacks;
19
+ time: TimeContext;
20
+ }>;
21
+ export type RunResult = Readonly<{
22
+ sessionId: string | null;
23
+ }>;
24
+ export declare function run(args: RunArgs): Promise<RunResult>;
@@ -0,0 +1,100 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.run = run;
4
+ const wait_1 = require("../system/wait");
5
+ const RATE_LIMIT_CHUNK_MS = 60 * 60 * 1000;
6
+ const INITIAL_TRANSIENT_WAIT_MS = 1000;
7
+ const TRANSIENT_WAIT_CAP_MS = 60000;
8
+ async function run(args) {
9
+ var _a, _b;
10
+ const { adapter, prompt, model, effort, abortSignal, callbacks, time } = args;
11
+ if (abortSignal.aborted) {
12
+ throw abortError();
13
+ }
14
+ let capturedSessionId = null;
15
+ let transientAttempt = 0;
16
+ let firstInvocation = true;
17
+ for (;;) {
18
+ const base = { prompt, model, effort, abortSignal, onUsage: callbacks.onUsage };
19
+ let invokeArgs;
20
+ if (firstInvocation) {
21
+ if (args.forkParentSessionId) {
22
+ invokeArgs = { ...base, forkParentSessionId: args.forkParentSessionId };
23
+ }
24
+ else if (args.resumeSessionId) {
25
+ invokeArgs = { ...base, resumeSessionId: args.resumeSessionId };
26
+ }
27
+ else {
28
+ invokeArgs = base;
29
+ }
30
+ firstInvocation = false;
31
+ }
32
+ else {
33
+ const retrySessionId = capturedSessionId !== null && capturedSessionId !== void 0 ? capturedSessionId : args.resumeSessionId;
34
+ if (retrySessionId) {
35
+ invokeArgs = { ...base, resumeSessionId: retrySessionId };
36
+ }
37
+ else {
38
+ invokeArgs = base;
39
+ }
40
+ }
41
+ let terminal = null;
42
+ const iterable = adapter.invoke(invokeArgs);
43
+ for await (const event of iterable) {
44
+ switch (event.type) {
45
+ case "output":
46
+ callbacks.onOutput(event);
47
+ break;
48
+ case "session":
49
+ capturedSessionId = event.id;
50
+ callbacks.onSessionId(event.id);
51
+ break;
52
+ case "error":
53
+ case "rate_limit":
54
+ case "done":
55
+ terminal = event;
56
+ break;
57
+ }
58
+ if (terminal)
59
+ break;
60
+ }
61
+ if (!terminal && abortSignal.aborted) {
62
+ throw abortError();
63
+ }
64
+ if (!terminal) {
65
+ throw new Error("adapter closed without terminal event");
66
+ }
67
+ if (terminal.type === "done") {
68
+ transientAttempt = 0;
69
+ return { sessionId: capturedSessionId };
70
+ }
71
+ if (terminal.type === "error" && !terminal.retryable) {
72
+ throw new Error(terminal.message);
73
+ }
74
+ if (terminal.type === "rate_limit") {
75
+ const waitMs = Math.max(0, terminal.waitUntilMs - time.now());
76
+ (_a = callbacks.onWaitStart) === null || _a === void 0 ? void 0 : _a.call(callbacks, "rate-limit", terminal.waitUntilMs);
77
+ try {
78
+ await (0, wait_1.wait)(waitMs, RATE_LIMIT_CHUNK_MS, time, abortSignal);
79
+ }
80
+ finally {
81
+ (_b = callbacks.onWaitEnd) === null || _b === void 0 ? void 0 : _b.call(callbacks);
82
+ }
83
+ if (abortSignal.aborted) {
84
+ throw abortError();
85
+ }
86
+ continue;
87
+ }
88
+ transientAttempt++;
89
+ const waitMs = Math.min(TRANSIENT_WAIT_CAP_MS, INITIAL_TRANSIENT_WAIT_MS * 2 ** (transientAttempt - 1));
90
+ await (0, wait_1.wait)(waitMs, waitMs, time, abortSignal);
91
+ if (abortSignal.aborted) {
92
+ throw abortError();
93
+ }
94
+ }
95
+ }
96
+ function abortError() {
97
+ const err = new Error("aborted");
98
+ err.name = "AbortError";
99
+ return err;
100
+ }
@@ -0,0 +1,32 @@
1
+ import type { OutputContext, TimeContext } from "../contexts";
2
+ import type { ToolAdapter } from "./ToolAdapter";
3
+ export type AiSessionResult = Readonly<{
4
+ text: string;
5
+ sessionId: string | null;
6
+ inputTokens: number;
7
+ outputTokens: number;
8
+ }>;
9
+ export type AiSessionOptions = Readonly<{
10
+ adapter: ToolAdapter;
11
+ prompt: string;
12
+ model: string;
13
+ effort: string;
14
+ resumeSessionId?: string | null;
15
+ forkParentSessionId?: string | null;
16
+ onLongWaitStart?(kind: "rate-limit", endTimeMs: number): void;
17
+ onLongWaitEnd?(): void;
18
+ }>;
19
+ export type AiSessionContexts = Readonly<{
20
+ time: TimeContext;
21
+ output: OutputContext;
22
+ }>;
23
+ export declare class AiSession {
24
+ private _options;
25
+ private _contexts;
26
+ private _disposed;
27
+ private _abortController;
28
+ private _runPromise;
29
+ constructor(_options: AiSessionOptions, _contexts: AiSessionContexts);
30
+ run(): Promise<AiSessionResult>;
31
+ dispose(): Promise<void>;
32
+ }
@@ -0,0 +1,143 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AiSession = void 0;
4
+ const AiRunner_1 = require("./AiRunner");
5
+ const formatters_1 = require("../ui/formatters");
6
+ const TOOL_RESULT_MAX_LINES = 5;
7
+ class AiSession {
8
+ constructor(_options, _contexts) {
9
+ this._options = _options;
10
+ this._contexts = _contexts;
11
+ this._disposed = false;
12
+ this._abortController = null;
13
+ this._runPromise = null;
14
+ }
15
+ async run() {
16
+ if (this._disposed) {
17
+ throw new Error("AiSession disposed");
18
+ }
19
+ const controller = new AbortController();
20
+ this._abortController = controller;
21
+ let inputTokens = 0;
22
+ let outputTokens = 0;
23
+ let capturedText = "";
24
+ let textOpen = false;
25
+ let inAssistantBlock = false;
26
+ const onUsage = (usage) => {
27
+ inputTokens += usage.inputTokens;
28
+ outputTokens += usage.outputTokens;
29
+ };
30
+ const closeOpenTextLine = () => {
31
+ if (textOpen) {
32
+ this._contexts.output.write("\n");
33
+ textOpen = false;
34
+ }
35
+ };
36
+ const emitText = (text) => {
37
+ this._contexts.output.write(text);
38
+ textOpen = !text.endsWith("\n");
39
+ };
40
+ const onOutput = (event) => {
41
+ if (event.title === "Assistant") {
42
+ if (!inAssistantBlock) {
43
+ this._contexts.output.write((0, formatters_1.colorize)("Assistant", formatters_1.GREEN) + "\n");
44
+ inAssistantBlock = true;
45
+ }
46
+ emitText(event.details);
47
+ capturedText += event.details;
48
+ return;
49
+ }
50
+ inAssistantBlock = false;
51
+ closeOpenTextLine();
52
+ if (event.title === "Result") {
53
+ const formatted = formatToolResultLines(event.details);
54
+ this._contexts.output.write(formatted);
55
+ return;
56
+ }
57
+ if (event.title === "stderr") {
58
+ this._contexts.output.writeError(event.details);
59
+ return;
60
+ }
61
+ if (event.title === "Thinking") {
62
+ this._contexts.output.write((0, formatters_1.colorize)("● Thinking(" + event.subtitle + ")", formatters_1.DIM) + "\n");
63
+ return;
64
+ }
65
+ this._contexts.output.write("● " + (0, formatters_1.colorize)(event.title, formatters_1.CYAN) + "(" + (0, formatters_1.colorize)(event.subtitle, formatters_1.YELLOW) + ")\n");
66
+ };
67
+ const promise = (async () => {
68
+ try {
69
+ const result = await (0, AiRunner_1.run)({
70
+ adapter: this._options.adapter,
71
+ prompt: this._options.prompt,
72
+ model: this._options.model,
73
+ effort: this._options.effort,
74
+ ...(this._options.resumeSessionId != null ? { resumeSessionId: this._options.resumeSessionId } : null),
75
+ ...(this._options.forkParentSessionId != null ? { forkParentSessionId: this._options.forkParentSessionId } : null),
76
+ abortSignal: controller.signal,
77
+ callbacks: {
78
+ onOutput,
79
+ onSessionId: () => { },
80
+ onUsage,
81
+ onWaitStart: this._options.onLongWaitStart,
82
+ onWaitEnd: this._options.onLongWaitEnd
83
+ },
84
+ time: this._contexts.time
85
+ });
86
+ closeOpenTextLine();
87
+ return {
88
+ text: capturedText,
89
+ sessionId: result.sessionId,
90
+ inputTokens,
91
+ outputTokens
92
+ };
93
+ }
94
+ finally {
95
+ if (this._abortController === controller) {
96
+ this._abortController = null;
97
+ }
98
+ }
99
+ })();
100
+ this._runPromise = promise;
101
+ try {
102
+ return await promise;
103
+ }
104
+ finally {
105
+ if (this._runPromise === promise) {
106
+ this._runPromise = null;
107
+ }
108
+ }
109
+ }
110
+ async dispose() {
111
+ var _a;
112
+ if (this._disposed) {
113
+ return;
114
+ }
115
+ this._disposed = true;
116
+ (_a = this._abortController) === null || _a === void 0 ? void 0 : _a.abort();
117
+ if (this._runPromise) {
118
+ try {
119
+ await this._runPromise;
120
+ }
121
+ catch {
122
+ }
123
+ }
124
+ }
125
+ }
126
+ exports.AiSession = AiSession;
127
+ function formatToolResultLines(text) {
128
+ const prefix = (0, formatters_1.colorize)(" ⎿ ", formatters_1.MAGENTA);
129
+ const trimmed = text.replace(/\s+$/, "");
130
+ const lines = trimmed.split("\n");
131
+ if (lines.length === 0 || (lines.length === 1 && lines[0] === "")) {
132
+ return `${prefix}(empty)\n`;
133
+ }
134
+ const visible = lines.slice(0, TOOL_RESULT_MAX_LINES);
135
+ let out = "";
136
+ for (let i = 0; i < visible.length; i++) {
137
+ out += (i === 0 ? prefix : " ") + visible[i] + "\n";
138
+ }
139
+ if (lines.length > TOOL_RESULT_MAX_LINES) {
140
+ out += ` … +${lines.length - TOOL_RESULT_MAX_LINES} more lines\n`;
141
+ }
142
+ return out;
143
+ }
@@ -0,0 +1,12 @@
1
+ import type { ScriptContext, TimeContext } from "../contexts";
2
+ import type { ToolAdapter, ToolAdapterInvokeArgs, ToolEvent } from "./ToolAdapter";
3
+ export type ClaudeAdapterContexts = Readonly<{
4
+ claude: ScriptContext;
5
+ time: TimeContext;
6
+ }>;
7
+ export declare function formatToolInput(input: Readonly<Record<string, unknown>> | undefined): string;
8
+ export declare class ClaudeAdapter implements ToolAdapter {
9
+ private _contexts;
10
+ constructor(_contexts: ClaudeAdapterContexts);
11
+ invoke(args: ToolAdapterInvokeArgs): AsyncIterable<ToolEvent>;
12
+ }
@@ -0,0 +1,345 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ClaudeAdapter = void 0;
4
+ exports.formatToolInput = formatToolInput;
5
+ const TOOL_INPUT_INLINE_MAX = 120;
6
+ function formatToolInput(input) {
7
+ if (!input || typeof input !== "object") {
8
+ return "";
9
+ }
10
+ const i = input;
11
+ if (typeof i["command"] === "string") {
12
+ return i["command"];
13
+ }
14
+ if (typeof i["file_path"] === "string") {
15
+ return i["file_path"];
16
+ }
17
+ if (typeof i["path"] === "string") {
18
+ return i["path"];
19
+ }
20
+ if (typeof i["pattern"] === "string") {
21
+ return i["pattern"];
22
+ }
23
+ if (typeof i["url"] === "string") {
24
+ return i["url"];
25
+ }
26
+ if (typeof i["query"] === "string") {
27
+ return i["query"];
28
+ }
29
+ const json = JSON.stringify(input);
30
+ if (json.length > TOOL_INPUT_INLINE_MAX) {
31
+ return json.slice(0, TOOL_INPUT_INLINE_MAX - 3) + "...";
32
+ }
33
+ return json;
34
+ }
35
+ function renderToolResultContent(content) {
36
+ if (typeof content === "string") {
37
+ return content;
38
+ }
39
+ if (Array.isArray(content)) {
40
+ let out = "";
41
+ for (const block of content) {
42
+ if (block && typeof block === "object") {
43
+ const b = block;
44
+ if (b.type === "text" && typeof b.text === "string") {
45
+ out += b.text;
46
+ }
47
+ }
48
+ }
49
+ return out;
50
+ }
51
+ return "";
52
+ }
53
+ function toolResultSummary(content) {
54
+ var _a;
55
+ const text = renderToolResultContent(content);
56
+ if (!text) {
57
+ return "";
58
+ }
59
+ const firstLine = (_a = text.split("\n")[0]) !== null && _a !== void 0 ? _a : "";
60
+ return firstLine;
61
+ }
62
+ class ClaudeAdapter {
63
+ constructor(_contexts) {
64
+ this._contexts = _contexts;
65
+ }
66
+ invoke(args) {
67
+ const iter = new ClaudeAdapterIterator(args, this._contexts);
68
+ return {
69
+ [Symbol.asyncIterator]() {
70
+ return iter;
71
+ }
72
+ };
73
+ }
74
+ }
75
+ exports.ClaudeAdapter = ClaudeAdapter;
76
+ class ClaudeAdapterIterator {
77
+ constructor(_args, _contexts) {
78
+ this._args = _args;
79
+ this._contexts = _contexts;
80
+ this._proc = null;
81
+ this._capturedSessionId = null;
82
+ this._queue = [];
83
+ this._done = false;
84
+ this._error = null;
85
+ this._waitResolve = null;
86
+ this._abortListener = null;
87
+ this._pendingTerminal = null;
88
+ this._exitPromise = null;
89
+ this._start();
90
+ }
91
+ _start() {
92
+ var _a, _b, _c, _d;
93
+ const argv = this._buildArgv();
94
+ const spawnOptions = { stdio: "pipe" };
95
+ const proc = this._contexts.claude.spawn("claude", argv, spawnOptions);
96
+ this._proc = proc;
97
+ const initialMessage = {
98
+ type: "user",
99
+ message: { role: "user", content: this._args.prompt }
100
+ };
101
+ (_a = proc.stdin) === null || _a === void 0 ? void 0 : _a.write(JSON.stringify(initialMessage) + "\n");
102
+ (_b = proc.stdin) === null || _b === void 0 ? void 0 : _b.end();
103
+ let exitResolve = null;
104
+ this._exitPromise = new Promise(resolve => { exitResolve = resolve; });
105
+ let buffer = "";
106
+ (_c = proc.stdout) === null || _c === void 0 ? void 0 : _c.on("data", (chunk) => {
107
+ buffer += String(chunk);
108
+ for (;;) {
109
+ const nl = buffer.indexOf("\n");
110
+ if (nl < 0)
111
+ break;
112
+ const line = buffer.slice(0, nl).replace(/\r$/, "");
113
+ buffer = buffer.slice(nl + 1);
114
+ if (line) {
115
+ this._handleLine(line);
116
+ }
117
+ }
118
+ });
119
+ let stderrBuf = "";
120
+ (_d = proc.stderr) === null || _d === void 0 ? void 0 : _d.on("data", (chunk) => {
121
+ stderrBuf += String(chunk);
122
+ });
123
+ proc.on("error", (e) => {
124
+ if (!this._done) {
125
+ this._done = true;
126
+ this._error = e instanceof Error ? e : new Error(String(e));
127
+ this._wake();
128
+ }
129
+ exitResolve === null || exitResolve === void 0 ? void 0 : exitResolve();
130
+ });
131
+ proc.on("exit", () => {
132
+ if (stderrBuf) {
133
+ this._queue.push({
134
+ type: "output",
135
+ title: "stderr",
136
+ subtitle: "",
137
+ details: stderrBuf
138
+ });
139
+ stderrBuf = "";
140
+ }
141
+ if (this._pendingTerminal) {
142
+ this._queue.push(this._pendingTerminal);
143
+ this._pendingTerminal = null;
144
+ }
145
+ if (!this._done) {
146
+ this._done = true;
147
+ }
148
+ this._wake();
149
+ exitResolve === null || exitResolve === void 0 ? void 0 : exitResolve();
150
+ });
151
+ this._abortListener = () => {
152
+ if (this._proc) {
153
+ this._proc.kill("SIGINT");
154
+ }
155
+ this._done = true;
156
+ this._wake();
157
+ };
158
+ if (this._args.abortSignal.aborted) {
159
+ this._abortListener();
160
+ }
161
+ else {
162
+ this._args.abortSignal.addEventListener("abort", this._abortListener, { once: true });
163
+ }
164
+ }
165
+ _buildArgv() {
166
+ const argv = [];
167
+ if (this._args.resumeSessionId) {
168
+ argv.push("--resume", this._args.resumeSessionId);
169
+ }
170
+ else if (this._args.forkParentSessionId) {
171
+ argv.push("--resume", this._args.forkParentSessionId, "--fork-session");
172
+ }
173
+ if (this._args.model) {
174
+ argv.push("--model", this._args.model);
175
+ }
176
+ if (this._args.effort) {
177
+ argv.push("--effort", this._args.effort);
178
+ }
179
+ argv.push("--input-format", "stream-json", "--output-format", "stream-json", "--include-partial-messages", "--verbose", "--print");
180
+ return argv;
181
+ }
182
+ _handleLine(line) {
183
+ var _a, _b, _c, _d, _e, _f;
184
+ let parsed = null;
185
+ try {
186
+ parsed = JSON.parse(line);
187
+ }
188
+ catch {
189
+ return;
190
+ }
191
+ if (!parsed)
192
+ return;
193
+ if (parsed.session_id) {
194
+ if (this._capturedSessionId === null) {
195
+ this._capturedSessionId = parsed.session_id;
196
+ this._queue.push({ type: "session", id: parsed.session_id });
197
+ }
198
+ else if (this._capturedSessionId !== parsed.session_id) {
199
+ this._capturedSessionId = parsed.session_id;
200
+ this._queue.push({ type: "session", id: parsed.session_id });
201
+ }
202
+ }
203
+ if (parsed.type === "assistant" && ((_a = parsed.message) === null || _a === void 0 ? void 0 : _a.content)) {
204
+ for (const block of parsed.message.content) {
205
+ if (block.type === "tool_use" && typeof block.name === "string") {
206
+ this._queue.push({
207
+ type: "output",
208
+ title: block.name,
209
+ subtitle: formatToolInput(block.input),
210
+ details: ""
211
+ });
212
+ }
213
+ else if (block.type === "text" && typeof block.text === "string") {
214
+ this._queue.push({
215
+ type: "output",
216
+ title: "Assistant",
217
+ subtitle: "",
218
+ details: block.text
219
+ });
220
+ }
221
+ else if (block.type === "thinking" && typeof block.thinking === "string") {
222
+ this._queue.push({
223
+ type: "output",
224
+ title: "Thinking",
225
+ subtitle: "",
226
+ details: block.thinking
227
+ });
228
+ }
229
+ }
230
+ }
231
+ if (parsed.type === "user" && ((_b = parsed.message) === null || _b === void 0 ? void 0 : _b.content)) {
232
+ for (const block of parsed.message.content) {
233
+ if (block.type === "tool_result") {
234
+ const text = renderToolResultContent(block.content);
235
+ this._queue.push({
236
+ type: "output",
237
+ title: "Result",
238
+ subtitle: toolResultSummary(block.content),
239
+ details: text
240
+ });
241
+ }
242
+ }
243
+ }
244
+ if (parsed.type === "result") {
245
+ const u = parsed.usage;
246
+ if (u && this._args.onUsage) {
247
+ const inputTokens = ((_c = u.input_tokens) !== null && _c !== void 0 ? _c : 0) + ((_d = u.cache_creation_input_tokens) !== null && _d !== void 0 ? _d : 0) + ((_e = u.cache_read_input_tokens) !== null && _e !== void 0 ? _e : 0);
248
+ const outputTokens = (_f = u.output_tokens) !== null && _f !== void 0 ? _f : 0;
249
+ this._args.onUsage({ inputTokens, outputTokens });
250
+ }
251
+ if (parsed.session_id && !this._capturedSessionId) {
252
+ this._capturedSessionId = parsed.session_id;
253
+ this._queue.push({ type: "session", id: parsed.session_id });
254
+ }
255
+ if (!parsed.is_error) {
256
+ this._pendingTerminal = { type: "done" };
257
+ }
258
+ else {
259
+ this._pendingTerminal = this._classifyError(parsed);
260
+ }
261
+ }
262
+ this._wake();
263
+ }
264
+ _classifyError(parsed) {
265
+ var _a, _b;
266
+ const status = parsed.api_error_status;
267
+ const subtype = parsed.subtype;
268
+ const message = (_b = (_a = parsed.error) === null || _a === void 0 ? void 0 : _a.message) !== null && _b !== void 0 ? _b : "unknown error";
269
+ if (status === 429) {
270
+ const info = parsed.rate_limit_info;
271
+ if (info) {
272
+ const target = info.isUsingOverage && typeof info.overageResetsAt === "number"
273
+ ? info.overageResetsAt
274
+ : info.resetsAt;
275
+ if (typeof target === "number") {
276
+ return { type: "rate_limit", waitUntilMs: target * 1000 };
277
+ }
278
+ }
279
+ return { type: "error", retryable: true, message };
280
+ }
281
+ if (typeof status === "number" && status >= 500) {
282
+ return { type: "error", retryable: true, message };
283
+ }
284
+ if (status === 408 || status === 425) {
285
+ return { type: "error", retryable: true, message };
286
+ }
287
+ if (status === null) {
288
+ return { type: "error", retryable: true, message };
289
+ }
290
+ if (subtype === "error_during_execution") {
291
+ return { type: "error", retryable: true, message };
292
+ }
293
+ if (subtype === "error_max_turns" || subtype === "error_max_budget_usd" || subtype === "error_max_structured_output_retries") {
294
+ return { type: "error", retryable: false, message };
295
+ }
296
+ return { type: "error", retryable: false, message };
297
+ }
298
+ _wake() {
299
+ if (this._waitResolve) {
300
+ const resolve = this._waitResolve;
301
+ this._waitResolve = null;
302
+ resolve();
303
+ }
304
+ }
305
+ _wait() {
306
+ return new Promise(resolve => {
307
+ this._waitResolve = resolve;
308
+ });
309
+ }
310
+ async next() {
311
+ for (;;) {
312
+ if (this._queue.length > 0) {
313
+ return { value: this._queue.shift(), done: false };
314
+ }
315
+ if (this._error) {
316
+ throw this._error;
317
+ }
318
+ if (this._done && this._queue.length === 0) {
319
+ this._cleanup();
320
+ if (this._exitPromise) {
321
+ await this._exitPromise;
322
+ }
323
+ return { value: undefined, done: true };
324
+ }
325
+ await this._wait();
326
+ }
327
+ }
328
+ async return() {
329
+ this._done = true;
330
+ this._cleanup();
331
+ if (this._proc) {
332
+ this._proc.kill("SIGINT");
333
+ if (this._exitPromise) {
334
+ await this._exitPromise;
335
+ }
336
+ }
337
+ return { value: undefined, done: true };
338
+ }
339
+ _cleanup() {
340
+ if (this._abortListener) {
341
+ this._args.abortSignal.removeEventListener("abort", this._abortListener);
342
+ this._abortListener = null;
343
+ }
344
+ }
345
+ }
@@ -0,0 +1,13 @@
1
+ import type { RandomContext, ScriptContext, TimeContext } from "../contexts";
2
+ import type { ToolAdapter, ToolAdapterInvokeArgs, ToolEvent } from "./ToolAdapter";
3
+ export type CodexAdapterContexts = Readonly<{
4
+ script: ScriptContext;
5
+ time: TimeContext;
6
+ random: RandomContext;
7
+ }>;
8
+ export declare function formatCodexCommand(command: string | undefined): string;
9
+ export declare class CodexAdapter implements ToolAdapter {
10
+ private _contexts;
11
+ constructor(_contexts: CodexAdapterContexts);
12
+ invoke(args: ToolAdapterInvokeArgs): AsyncIterable<ToolEvent>;
13
+ }