@loops-adk/core 0.1.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.
- package/LICENSE +21 -0
- package/README.md +486 -0
- package/bin/loops.mjs +16 -0
- package/dist/App-3YQS6DXA.js +461 -0
- package/dist/App-3YQS6DXA.js.map +1 -0
- package/dist/agent-sdk-RF5VJZAT.js +95 -0
- package/dist/agent-sdk-RF5VJZAT.js.map +1 -0
- package/dist/anthropic-api-XJY6Y4T2.js +131 -0
- package/dist/anthropic-api-XJY6Y4T2.js.map +1 -0
- package/dist/api.d.ts +949 -0
- package/dist/api.js +898 -0
- package/dist/api.js.map +1 -0
- package/dist/chunk-33YIGWNU.js +63 -0
- package/dist/chunk-33YIGWNU.js.map +1 -0
- package/dist/chunk-3BPU34DE.js +2163 -0
- package/dist/chunk-3BPU34DE.js.map +1 -0
- package/dist/chunk-CXEPZHSR.js +86 -0
- package/dist/chunk-CXEPZHSR.js.map +1 -0
- package/dist/chunk-I3STY7U6.js +61 -0
- package/dist/chunk-I3STY7U6.js.map +1 -0
- package/dist/chunk-JFTXJ7I2.js +18 -0
- package/dist/chunk-JFTXJ7I2.js.map +1 -0
- package/dist/chunk-XC46B4FD.js +9 -0
- package/dist/chunk-XC46B4FD.js.map +1 -0
- package/dist/chunk-Y2SD7GBL.js +30 -0
- package/dist/chunk-Y2SD7GBL.js.map +1 -0
- package/dist/claude-cli-U7WEVAOL.js +124 -0
- package/dist/claude-cli-U7WEVAOL.js.map +1 -0
- package/dist/codex-6I5UZ2HM.js +60 -0
- package/dist/codex-6I5UZ2HM.js.map +1 -0
- package/dist/env/command.d.ts +53 -0
- package/dist/env/command.js +3 -0
- package/dist/env/command.js.map +1 -0
- package/dist/env/docker.d.ts +38 -0
- package/dist/env/docker.js +33 -0
- package/dist/env/docker.js.map +1 -0
- package/dist/env/sst.d.ts +39 -0
- package/dist/env/sst.js +20 -0
- package/dist/env/sst.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +620 -0
- package/dist/index.js.map +1 -0
- package/dist/types-B4wGVpqo.d.ts +898 -0
- package/package.json +100 -0
- package/skills/author-loop/SKILL.md +121 -0
|
@@ -0,0 +1,461 @@
|
|
|
1
|
+
import { useRef, useReducer, useEffect } from 'react';
|
|
2
|
+
import { useInput, Box, Text } from 'ink';
|
|
3
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
4
|
+
|
|
5
|
+
// src/tui/App.tsx
|
|
6
|
+
|
|
7
|
+
// src/tui/theme.ts
|
|
8
|
+
var glyph = {
|
|
9
|
+
loop: "\u21BB",
|
|
10
|
+
dag: "\u25A4",
|
|
11
|
+
pass: "\u2714",
|
|
12
|
+
fail: "\u2718",
|
|
13
|
+
aborted: "\u25FC",
|
|
14
|
+
exhausted: "\u2298",
|
|
15
|
+
paused: "\u23F8",
|
|
16
|
+
running: "\u25D0"
|
|
17
|
+
};
|
|
18
|
+
function statusColor(status) {
|
|
19
|
+
switch (status) {
|
|
20
|
+
case "pass":
|
|
21
|
+
return "green";
|
|
22
|
+
case "fail":
|
|
23
|
+
return "red";
|
|
24
|
+
case "exhausted":
|
|
25
|
+
return "yellow";
|
|
26
|
+
case "aborted":
|
|
27
|
+
return "gray";
|
|
28
|
+
case "paused":
|
|
29
|
+
return "cyan";
|
|
30
|
+
default:
|
|
31
|
+
return "cyan";
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function statusGlyph(status) {
|
|
35
|
+
switch (status) {
|
|
36
|
+
case "pass":
|
|
37
|
+
return glyph.pass;
|
|
38
|
+
case "fail":
|
|
39
|
+
return glyph.fail;
|
|
40
|
+
case "exhausted":
|
|
41
|
+
return glyph.exhausted;
|
|
42
|
+
case "aborted":
|
|
43
|
+
return glyph.aborted;
|
|
44
|
+
case "paused":
|
|
45
|
+
return glyph.paused;
|
|
46
|
+
default:
|
|
47
|
+
return glyph.running;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function emptyVM() {
|
|
51
|
+
return {
|
|
52
|
+
nodes: /* @__PURE__ */ new Map(),
|
|
53
|
+
order: [],
|
|
54
|
+
stream: "",
|
|
55
|
+
tokensIn: 0,
|
|
56
|
+
tokensOut: 0,
|
|
57
|
+
calls: 0,
|
|
58
|
+
errors: [],
|
|
59
|
+
startedAt: Date.now()
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function currentIteration(node) {
|
|
63
|
+
return node.iterations[node.iterations.length - 1];
|
|
64
|
+
}
|
|
65
|
+
function reduce(vm, e) {
|
|
66
|
+
const key = e.path.join(" / ");
|
|
67
|
+
const ensure = (type) => {
|
|
68
|
+
let n = vm.nodes.get(key);
|
|
69
|
+
if (!n) {
|
|
70
|
+
n = {
|
|
71
|
+
key,
|
|
72
|
+
name: e.path[e.path.length - 1] ?? "(root)",
|
|
73
|
+
depth: e.path.length,
|
|
74
|
+
type,
|
|
75
|
+
iteration: 0,
|
|
76
|
+
reviewPass: 0,
|
|
77
|
+
reviewFail: 0,
|
|
78
|
+
iterations: []
|
|
79
|
+
};
|
|
80
|
+
vm.nodes.set(key, n);
|
|
81
|
+
vm.order.push(key);
|
|
82
|
+
}
|
|
83
|
+
return n;
|
|
84
|
+
};
|
|
85
|
+
const loopAt = () => {
|
|
86
|
+
const n = vm.nodes.get(key);
|
|
87
|
+
return n?.type === "loop" ? n : void 0;
|
|
88
|
+
};
|
|
89
|
+
switch (e.kind) {
|
|
90
|
+
case "loop:start":
|
|
91
|
+
ensure("loop").max = e.max;
|
|
92
|
+
break;
|
|
93
|
+
case "loop:iteration": {
|
|
94
|
+
const n = ensure("loop");
|
|
95
|
+
n.iteration = e.iteration;
|
|
96
|
+
const prev = currentIteration(n);
|
|
97
|
+
if (prev && prev.status === "running") {
|
|
98
|
+
prev.status = prev.bodyStatus ?? "pass";
|
|
99
|
+
prev.endedAt = e.ts;
|
|
100
|
+
}
|
|
101
|
+
n.iterations.push({
|
|
102
|
+
iteration: e.iteration,
|
|
103
|
+
status: "running",
|
|
104
|
+
tokensIn: 0,
|
|
105
|
+
tokensOut: 0,
|
|
106
|
+
calls: 0,
|
|
107
|
+
transcript: "",
|
|
108
|
+
startedAt: e.ts
|
|
109
|
+
});
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
case "loop:condition": {
|
|
113
|
+
const cur = loopAt() && currentIteration(loopAt());
|
|
114
|
+
if (cur) {
|
|
115
|
+
if (e.which === "until")
|
|
116
|
+
cur.until = {
|
|
117
|
+
met: e.result.met,
|
|
118
|
+
reason: e.result.reason,
|
|
119
|
+
confidence: e.result.confidence
|
|
120
|
+
};
|
|
121
|
+
else if (e.which === "stopOn")
|
|
122
|
+
cur.stopOn = { met: e.result.met, reason: e.result.reason };
|
|
123
|
+
}
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
case "loop:review": {
|
|
127
|
+
const n = ensure("loop");
|
|
128
|
+
if (e.outcome.status === "pass") n.reviewPass += 1;
|
|
129
|
+
else n.reviewFail += 1;
|
|
130
|
+
const cur = currentIteration(n);
|
|
131
|
+
if (cur) {
|
|
132
|
+
cur.review = { status: e.outcome.status, summary: e.outcome.summary };
|
|
133
|
+
if (e.outcome.status !== "pass") cur.status = "fail";
|
|
134
|
+
}
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
case "loop:end": {
|
|
138
|
+
const n = ensure("loop");
|
|
139
|
+
n.status = e.outcome.status;
|
|
140
|
+
const cur = currentIteration(n);
|
|
141
|
+
if (cur && cur.status === "running") {
|
|
142
|
+
cur.status = e.outcome.status;
|
|
143
|
+
cur.endedAt = e.ts;
|
|
144
|
+
} else if (cur && cur.endedAt == null) {
|
|
145
|
+
cur.endedAt = e.ts;
|
|
146
|
+
}
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
case "dag:start":
|
|
150
|
+
ensure("dag");
|
|
151
|
+
break;
|
|
152
|
+
case "dag:end":
|
|
153
|
+
ensure("dag").status = e.outcome.status;
|
|
154
|
+
break;
|
|
155
|
+
case "job:start":
|
|
156
|
+
vm.activeLabel = e.label;
|
|
157
|
+
vm.stream = "";
|
|
158
|
+
break;
|
|
159
|
+
case "job:end": {
|
|
160
|
+
const cur = loopAt() && currentIteration(loopAt());
|
|
161
|
+
if (cur) {
|
|
162
|
+
cur.bodyStatus = e.outcome.status;
|
|
163
|
+
cur.bodySummary = e.outcome.summary;
|
|
164
|
+
}
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
case "engine:text": {
|
|
168
|
+
vm.stream = (vm.stream + e.delta).slice(-1600);
|
|
169
|
+
const cur = loopAt() && currentIteration(loopAt());
|
|
170
|
+
if (cur)
|
|
171
|
+
cur.transcript = (cur.transcript + e.delta).slice(-2e3);
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
174
|
+
case "engine:usage": {
|
|
175
|
+
vm.calls += 1;
|
|
176
|
+
vm.tokensIn += e.usage.inputTokens;
|
|
177
|
+
vm.tokensOut += e.usage.outputTokens;
|
|
178
|
+
const cur = loopAt() && currentIteration(loopAt());
|
|
179
|
+
if (cur) {
|
|
180
|
+
cur.calls += 1;
|
|
181
|
+
cur.tokensIn += e.usage.inputTokens;
|
|
182
|
+
cur.tokensOut += e.usage.outputTokens;
|
|
183
|
+
}
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
186
|
+
case "error":
|
|
187
|
+
vm.errors.push(`[${e.code}] ${e.message}`);
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
function loopKeys(m) {
|
|
192
|
+
return m.order.filter((k) => m.nodes.get(k)?.type === "loop");
|
|
193
|
+
}
|
|
194
|
+
function newestLoopKey(m) {
|
|
195
|
+
const keys = loopKeys(m);
|
|
196
|
+
for (let i = keys.length - 1; i >= 0; i--) {
|
|
197
|
+
const n = m.nodes.get(keys[i]);
|
|
198
|
+
if (n.iterations.length > 0) return keys[i];
|
|
199
|
+
}
|
|
200
|
+
return keys[keys.length - 1];
|
|
201
|
+
}
|
|
202
|
+
function resolveSelection(m, sel) {
|
|
203
|
+
loopKeys(m);
|
|
204
|
+
let key = sel.loopKey;
|
|
205
|
+
if (sel.followLive || !key || !m.nodes.has(key)) key = newestLoopKey(m);
|
|
206
|
+
const node = key ? m.nodes.get(key) : void 0;
|
|
207
|
+
if (!node) return { index: 0 };
|
|
208
|
+
const count = node.iterations.length;
|
|
209
|
+
let index = sel.followLive ? count - 1 : sel.iterationIndex;
|
|
210
|
+
if (index >= count) index = count - 1;
|
|
211
|
+
if (index < 0) index = 0;
|
|
212
|
+
return { node, index };
|
|
213
|
+
}
|
|
214
|
+
function App({ hub, title, onAbort }) {
|
|
215
|
+
const vm = useRef(emptyVM());
|
|
216
|
+
const sel = useRef({ iterationIndex: 0, followLive: true });
|
|
217
|
+
const [, repaint] = useReducer((n) => n + 1, 0);
|
|
218
|
+
useEffect(() => {
|
|
219
|
+
const unsubscribe = hub.subscribe((event) => reduce(vm.current, event));
|
|
220
|
+
const timer = setInterval(repaint, 90);
|
|
221
|
+
return () => {
|
|
222
|
+
unsubscribe();
|
|
223
|
+
clearInterval(timer);
|
|
224
|
+
};
|
|
225
|
+
}, [hub]);
|
|
226
|
+
useInput((input, k) => {
|
|
227
|
+
if (input === "q" || k.escape || k.ctrl && input === "c") {
|
|
228
|
+
onAbort();
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
const m2 = vm.current;
|
|
232
|
+
const s = sel.current;
|
|
233
|
+
const keys = loopKeys(m2);
|
|
234
|
+
if (input === "f" || input === " ") {
|
|
235
|
+
s.followLive = !s.followLive;
|
|
236
|
+
if (!s.followLive) {
|
|
237
|
+
const { node, index } = resolveSelection(m2, s);
|
|
238
|
+
s.loopKey = node?.key;
|
|
239
|
+
s.iterationIndex = index;
|
|
240
|
+
}
|
|
241
|
+
repaint();
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
const moveLoop = (delta) => {
|
|
245
|
+
if (keys.length === 0) return;
|
|
246
|
+
s.followLive = false;
|
|
247
|
+
const { node } = resolveSelection(m2, s);
|
|
248
|
+
const cur = node ? keys.indexOf(node.key) : -1;
|
|
249
|
+
let next = (cur < 0 ? 0 : cur) + delta;
|
|
250
|
+
if (next < 0) next = 0;
|
|
251
|
+
if (next >= keys.length) next = keys.length - 1;
|
|
252
|
+
s.loopKey = keys[next];
|
|
253
|
+
const n = m2.nodes.get(s.loopKey);
|
|
254
|
+
s.iterationIndex = n ? Math.max(0, n.iterations.length - 1) : 0;
|
|
255
|
+
repaint();
|
|
256
|
+
};
|
|
257
|
+
const moveIteration = (delta) => {
|
|
258
|
+
s.followLive = false;
|
|
259
|
+
const { node, index } = resolveSelection(m2, s);
|
|
260
|
+
if (!node) return;
|
|
261
|
+
s.loopKey = node.key;
|
|
262
|
+
let next = index + delta;
|
|
263
|
+
if (next < 0) next = 0;
|
|
264
|
+
if (next >= node.iterations.length) next = node.iterations.length - 1;
|
|
265
|
+
s.iterationIndex = next;
|
|
266
|
+
repaint();
|
|
267
|
+
};
|
|
268
|
+
if (k.upArrow || input === "k") moveLoop(-1);
|
|
269
|
+
else if (k.downArrow || input === "j") moveLoop(1);
|
|
270
|
+
else if (k.leftArrow || input === "h") moveIteration(-1);
|
|
271
|
+
else if (k.rightArrow || input === "l") moveIteration(1);
|
|
272
|
+
});
|
|
273
|
+
const m = vm.current;
|
|
274
|
+
const elapsed = ((Date.now() - m.startedAt) / 1e3).toFixed(1);
|
|
275
|
+
const { node: selectedNode, index: selectedIndex } = resolveSelection(
|
|
276
|
+
m,
|
|
277
|
+
sel.current
|
|
278
|
+
);
|
|
279
|
+
const selectedRecord = selectedNode?.iterations[selectedIndex];
|
|
280
|
+
const following = sel.current.followLive;
|
|
281
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 1, children: [
|
|
282
|
+
/* @__PURE__ */ jsxs(Box, { justifyContent: "space-between", children: [
|
|
283
|
+
/* @__PURE__ */ jsxs(Text, { bold: true, color: "cyan", children: [
|
|
284
|
+
glyph.loop,
|
|
285
|
+
" ",
|
|
286
|
+
title
|
|
287
|
+
] }),
|
|
288
|
+
/* @__PURE__ */ jsxs(Text, { color: "gray", children: [
|
|
289
|
+
elapsed,
|
|
290
|
+
"s \xB7 q to stop"
|
|
291
|
+
] })
|
|
292
|
+
] }),
|
|
293
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
294
|
+
m.order.length === 0 && /* @__PURE__ */ jsx(Text, { color: "gray", children: "starting\u2026" }),
|
|
295
|
+
m.order.map((key) => {
|
|
296
|
+
const n = m.nodes.get(key);
|
|
297
|
+
const g = n.type === "dag" ? glyph.dag : glyph.loop;
|
|
298
|
+
const reviews = n.reviewPass + n.reviewFail;
|
|
299
|
+
const isSelected = n.type === "loop" && selectedNode?.key === key;
|
|
300
|
+
return /* @__PURE__ */ jsxs(Text, { children: [
|
|
301
|
+
" ".repeat(Math.max(0, n.depth - 1)),
|
|
302
|
+
/* @__PURE__ */ jsx(Text, { color: isSelected ? "cyan" : "gray", children: isSelected ? "\u25B6 " : " " }),
|
|
303
|
+
/* @__PURE__ */ jsxs(Text, { color: statusColor(n.status), children: [
|
|
304
|
+
n.status ? statusGlyph(n.status) : g,
|
|
305
|
+
" "
|
|
306
|
+
] }),
|
|
307
|
+
/* @__PURE__ */ jsx(Text, { bold: true, underline: isSelected, children: n.name }),
|
|
308
|
+
n.type === "loop" && /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
|
|
309
|
+
" ",
|
|
310
|
+
"iter ",
|
|
311
|
+
n.iteration,
|
|
312
|
+
n.max ? `/${n.max}` : ""
|
|
313
|
+
] }),
|
|
314
|
+
reviews > 0 && /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
|
|
315
|
+
" ",
|
|
316
|
+
"\xB7 review ",
|
|
317
|
+
n.reviewPass,
|
|
318
|
+
"\u2714/",
|
|
319
|
+
n.reviewFail,
|
|
320
|
+
"\u2718"
|
|
321
|
+
] })
|
|
322
|
+
] }, key);
|
|
323
|
+
})
|
|
324
|
+
] }),
|
|
325
|
+
selectedNode && /* @__PURE__ */ jsx(
|
|
326
|
+
Box,
|
|
327
|
+
{
|
|
328
|
+
flexDirection: "column",
|
|
329
|
+
marginTop: 1,
|
|
330
|
+
borderStyle: "round",
|
|
331
|
+
borderColor: "cyan",
|
|
332
|
+
paddingX: 1,
|
|
333
|
+
children: /* @__PURE__ */ jsx(
|
|
334
|
+
IterationDetail,
|
|
335
|
+
{
|
|
336
|
+
node: selectedNode,
|
|
337
|
+
record: selectedRecord,
|
|
338
|
+
index: selectedIndex
|
|
339
|
+
}
|
|
340
|
+
)
|
|
341
|
+
}
|
|
342
|
+
),
|
|
343
|
+
/* @__PURE__ */ jsxs(Box, { marginTop: 1, justifyContent: "space-between", children: [
|
|
344
|
+
/* @__PURE__ */ jsxs(Text, { color: "gray", children: [
|
|
345
|
+
m.calls,
|
|
346
|
+
" call(s) \xB7 ",
|
|
347
|
+
m.tokensIn,
|
|
348
|
+
" in / ",
|
|
349
|
+
m.tokensOut,
|
|
350
|
+
" out tok"
|
|
351
|
+
] }),
|
|
352
|
+
m.errors.length > 0 ? /* @__PURE__ */ jsxs(Text, { color: "red", children: [
|
|
353
|
+
m.errors.length,
|
|
354
|
+
" error(s)"
|
|
355
|
+
] }) : /* @__PURE__ */ jsx(Text, { color: "green", children: " " })
|
|
356
|
+
] }),
|
|
357
|
+
/* @__PURE__ */ jsxs(Box, { justifyContent: "space-between", children: [
|
|
358
|
+
/* @__PURE__ */ jsx(Text, { color: "gray", children: "\u2191\u2193/jk loop \xB7 \u2190\u2192/hl iter \xB7 f/space follow \xB7 q stop" }),
|
|
359
|
+
/* @__PURE__ */ jsx(Text, { color: following ? "green" : "yellow", children: following ? "\u25CF LIVE" : "\u23F8 BROWSE" })
|
|
360
|
+
] })
|
|
361
|
+
] });
|
|
362
|
+
}
|
|
363
|
+
function IterationDetail({
|
|
364
|
+
node,
|
|
365
|
+
record,
|
|
366
|
+
index
|
|
367
|
+
}) {
|
|
368
|
+
const total = node.iterations.length;
|
|
369
|
+
if (!record) {
|
|
370
|
+
return /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
|
|
371
|
+
"loop ",
|
|
372
|
+
node.name,
|
|
373
|
+
" \u2014 no iterations yet"
|
|
374
|
+
] });
|
|
375
|
+
}
|
|
376
|
+
const durMs = record.endedAt != null ? record.endedAt - record.startedAt : Date.now() - record.startedAt;
|
|
377
|
+
const dur = `${(durMs / 1e3).toFixed(1)}s`;
|
|
378
|
+
const transcriptLines = record.transcript.split("\n").slice(-10);
|
|
379
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
380
|
+
/* @__PURE__ */ jsxs(Text, { children: [
|
|
381
|
+
/* @__PURE__ */ jsxs(Text, { bold: true, children: [
|
|
382
|
+
"loop ",
|
|
383
|
+
node.name
|
|
384
|
+
] }),
|
|
385
|
+
/* @__PURE__ */ jsxs(Text, { color: "gray", children: [
|
|
386
|
+
" ",
|
|
387
|
+
"\u2014 iteration ",
|
|
388
|
+
index + 1,
|
|
389
|
+
"/",
|
|
390
|
+
total,
|
|
391
|
+
" "
|
|
392
|
+
] }),
|
|
393
|
+
/* @__PURE__ */ jsxs(
|
|
394
|
+
Text,
|
|
395
|
+
{
|
|
396
|
+
color: statusColor(
|
|
397
|
+
record.status === "running" ? void 0 : record.status
|
|
398
|
+
),
|
|
399
|
+
bold: true,
|
|
400
|
+
children: [
|
|
401
|
+
"[",
|
|
402
|
+
record.status,
|
|
403
|
+
"]"
|
|
404
|
+
]
|
|
405
|
+
}
|
|
406
|
+
)
|
|
407
|
+
] }),
|
|
408
|
+
record.bodyStatus && /* @__PURE__ */ jsxs(Text, { children: [
|
|
409
|
+
/* @__PURE__ */ jsx(Text, { color: "gray", children: "body " }),
|
|
410
|
+
/* @__PURE__ */ jsx(Text, { color: statusColor(record.bodyStatus), children: record.bodyStatus }),
|
|
411
|
+
record.bodySummary ? /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
|
|
412
|
+
" \u2014 ",
|
|
413
|
+
record.bodySummary
|
|
414
|
+
] }) : null
|
|
415
|
+
] }),
|
|
416
|
+
record.until && /* @__PURE__ */ jsxs(Text, { children: [
|
|
417
|
+
/* @__PURE__ */ jsx(Text, { color: "magenta", children: "until " }),
|
|
418
|
+
record.until.met ? /* @__PURE__ */ jsx(Text, { color: "green", children: "met" }) : /* @__PURE__ */ jsx(Text, { color: "gray", children: "not met" }),
|
|
419
|
+
/* @__PURE__ */ jsxs(Text, { color: "gray", children: [
|
|
420
|
+
" \u2014 ",
|
|
421
|
+
record.until.reason
|
|
422
|
+
] }),
|
|
423
|
+
record.until.confidence != null ? /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
|
|
424
|
+
" (",
|
|
425
|
+
record.until.confidence.toFixed(2),
|
|
426
|
+
")"
|
|
427
|
+
] }) : null
|
|
428
|
+
] }),
|
|
429
|
+
record.stopOn && /* @__PURE__ */ jsxs(Text, { children: [
|
|
430
|
+
/* @__PURE__ */ jsx(Text, { color: "magenta", children: "stopOn " }),
|
|
431
|
+
record.stopOn.met ? /* @__PURE__ */ jsx(Text, { color: "red", children: "met" }) : /* @__PURE__ */ jsx(Text, { color: "gray", children: "not met" }),
|
|
432
|
+
/* @__PURE__ */ jsxs(Text, { color: "gray", children: [
|
|
433
|
+
" \u2014 ",
|
|
434
|
+
record.stopOn.reason
|
|
435
|
+
] })
|
|
436
|
+
] }),
|
|
437
|
+
record.review && /* @__PURE__ */ jsxs(Text, { children: [
|
|
438
|
+
/* @__PURE__ */ jsx(Text, { color: "blue", children: "review " }),
|
|
439
|
+
/* @__PURE__ */ jsx(Text, { color: statusColor(record.review.status), children: record.review.status }),
|
|
440
|
+
record.review.summary ? /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
|
|
441
|
+
" \u2014 ",
|
|
442
|
+
record.review.summary
|
|
443
|
+
] }) : null
|
|
444
|
+
] }),
|
|
445
|
+
/* @__PURE__ */ jsxs(Text, { color: "gray", children: [
|
|
446
|
+
record.tokensIn,
|
|
447
|
+
" in / ",
|
|
448
|
+
record.tokensOut,
|
|
449
|
+
" out tok \xB7 ",
|
|
450
|
+
record.calls,
|
|
451
|
+
" ",
|
|
452
|
+
"call(s) \xB7 ",
|
|
453
|
+
dur
|
|
454
|
+
] }),
|
|
455
|
+
transcriptLines.length > 0 && record.transcript.length > 0 && /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginTop: 1, children: transcriptLines.map((l, i) => /* @__PURE__ */ jsx(Text, { color: "white", wrap: "truncate-end", children: l || " " }, i)) })
|
|
456
|
+
] });
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
export { App };
|
|
460
|
+
//# sourceMappingURL=App-3YQS6DXA.js.map
|
|
461
|
+
//# sourceMappingURL=App-3YQS6DXA.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/tui/theme.ts","../src/tui/model.ts","../src/tui/App.tsx"],"names":["m"],"mappings":";;;;;;;AAIO,IAAM,KAAA,GAAQ;AAAA,EACnB,IAAA,EAAM,QAAA;AAAA,EACN,GAAA,EAAK,QAAA;AAAA,EACL,IAAA,EAAM,QAAA;AAAA,EACN,IAAA,EAAM,QAAA;AAAA,EACN,OAAA,EAAS,QAAA;AAAA,EACT,SAAA,EAAW,QAAA;AAAA,EACX,MAAA,EAAQ,QAAA;AAAA,EACR,OAAA,EAAS;AACX,CAAA;AAEO,SAAS,YAAY,MAAA,EAA+C;AACzE,EAAA,QAAQ,MAAA;AAAQ,IACd,KAAK,MAAA;AACH,MAAA,OAAO,OAAA;AAAA,IACT,KAAK,MAAA;AACH,MAAA,OAAO,KAAA;AAAA,IACT,KAAK,WAAA;AACH,MAAA,OAAO,QAAA;AAAA,IACT,KAAK,SAAA;AACH,MAAA,OAAO,MAAA;AAAA,IACT,KAAK,QAAA;AACH,MAAA,OAAO,MAAA;AAAA,IACT;AACE,MAAA,OAAO,MAAA;AAAA;AAEb;AAEO,SAAS,YAAY,MAAA,EAA+C;AACzE,EAAA,QAAQ,MAAA;AAAQ,IACd,KAAK,MAAA;AACH,MAAA,OAAO,KAAA,CAAM,IAAA;AAAA,IACf,KAAK,MAAA;AACH,MAAA,OAAO,KAAA,CAAM,IAAA;AAAA,IACf,KAAK,WAAA;AACH,MAAA,OAAO,KAAA,CAAM,SAAA;AAAA,IACf,KAAK,SAAA;AACH,MAAA,OAAO,KAAA,CAAM,OAAA;AAAA,IACf,KAAK,QAAA;AACH,MAAA,OAAO,KAAA,CAAM,MAAA;AAAA,IACf;AACE,MAAA,OAAO,KAAA,CAAM,OAAA;AAAA;AAEnB;ACqBO,SAAS,OAAA,GAAqB;AACnC,EAAA,OAAO;AAAA,IACL,KAAA,sBAAW,GAAA,EAAI;AAAA,IACf,OAAO,EAAC;AAAA,IACR,MAAA,EAAQ,EAAA;AAAA,IACR,QAAA,EAAU,CAAA;AAAA,IACV,SAAA,EAAW,CAAA;AAAA,IACX,KAAA,EAAO,CAAA;AAAA,IACP,QAAQ,EAAC;AAAA,IACT,SAAA,EAAW,KAAK,GAAA;AAAI,GACtB;AACF;AAGA,SAAS,iBAAiB,IAAA,EAA6C;AACrE,EAAA,OAAO,IAAA,CAAK,UAAA,CAAW,IAAA,CAAK,UAAA,CAAW,SAAS,CAAC,CAAA;AACnD;AAGO,SAAS,MAAA,CAAO,IAAe,CAAA,EAAoB;AACxD,EAAA,MAAM,GAAA,GAAM,CAAA,CAAE,IAAA,CAAK,IAAA,CAAK,KAAK,CAAA;AAC7B,EAAA,MAAM,MAAA,GAAS,CAAC,IAAA,KAAmC;AACjD,IAAA,IAAI,CAAA,GAAI,EAAA,CAAG,KAAA,CAAM,GAAA,CAAI,GAAG,CAAA;AACxB,IAAA,IAAI,CAAC,CAAA,EAAG;AACN,MAAA,CAAA,GAAI;AAAA,QACF,GAAA;AAAA,QACA,MAAM,CAAA,CAAE,IAAA,CAAK,EAAE,IAAA,CAAK,MAAA,GAAS,CAAC,CAAA,IAAK,QAAA;AAAA,QACnC,KAAA,EAAO,EAAE,IAAA,CAAK,MAAA;AAAA,QACd,IAAA;AAAA,QACA,SAAA,EAAW,CAAA;AAAA,QACX,UAAA,EAAY,CAAA;AAAA,QACZ,UAAA,EAAY,CAAA;AAAA,QACZ,YAAY;AAAC,OACf;AACA,MAAA,EAAA,CAAG,KAAA,CAAM,GAAA,CAAI,GAAA,EAAK,CAAC,CAAA;AACnB,MAAA,EAAA,CAAG,KAAA,CAAM,KAAK,GAAG,CAAA;AAAA,IACnB;AACA,IAAA,OAAO,CAAA;AAAA,EACT,CAAA;AAEA,EAAA,MAAM,SAAS,MAA4B;AACzC,IAAA,MAAM,CAAA,GAAI,EAAA,CAAG,KAAA,CAAM,GAAA,CAAI,GAAG,CAAA;AAC1B,IAAA,OAAO,CAAA,EAAG,IAAA,KAAS,MAAA,GAAS,CAAA,GAAI,MAAA;AAAA,EAClC,CAAA;AAEA,EAAA,QAAQ,EAAE,IAAA;AAAM,IACd,KAAK,YAAA;AACH,MAAA,MAAA,CAAO,MAAM,CAAA,CAAE,GAAA,GAAM,CAAA,CAAE,GAAA;AACvB,MAAA;AAAA,IACF,KAAK,gBAAA,EAAkB;AACrB,MAAA,MAAM,CAAA,GAAI,OAAO,MAAM,CAAA;AACvB,MAAA,CAAA,CAAE,YAAY,CAAA,CAAE,SAAA;AAEhB,MAAA,MAAM,IAAA,GAAO,iBAAiB,CAAC,CAAA;AAC/B,MAAA,IAAI,IAAA,IAAQ,IAAA,CAAK,MAAA,KAAW,SAAA,EAAW;AACrC,QAAA,IAAA,CAAK,MAAA,GAAS,KAAK,UAAA,IAAc,MAAA;AACjC,QAAA,IAAA,CAAK,UAAU,CAAA,CAAE,EAAA;AAAA,MACnB;AACA,MAAA,CAAA,CAAE,WAAW,IAAA,CAAK;AAAA,QAChB,WAAW,CAAA,CAAE,SAAA;AAAA,QACb,MAAA,EAAQ,SAAA;AAAA,QACR,QAAA,EAAU,CAAA;AAAA,QACV,SAAA,EAAW,CAAA;AAAA,QACX,KAAA,EAAO,CAAA;AAAA,QACP,UAAA,EAAY,EAAA;AAAA,QACZ,WAAW,CAAA,CAAE;AAAA,OACd,CAAA;AACD,MAAA;AAAA,IACF;AAAA,IACA,KAAK,gBAAA,EAAkB;AACrB,MAAA,MAAM,GAAA,GAAM,MAAA,EAAO,IAAK,gBAAA,CAAiB,QAAS,CAAA;AAClD,MAAA,IAAI,GAAA,EAAK;AACP,QAAA,IAAI,EAAE,KAAA,KAAU,OAAA;AACd,UAAA,GAAA,CAAI,KAAA,GAAQ;AAAA,YACV,GAAA,EAAK,EAAE,MAAA,CAAO,GAAA;AAAA,YACd,MAAA,EAAQ,EAAE,MAAA,CAAO,MAAA;AAAA,YACjB,UAAA,EAAY,EAAE,MAAA,CAAO;AAAA,WACvB;AAAA,aAAA,IACO,EAAE,KAAA,KAAU,QAAA;AACnB,UAAA,GAAA,CAAI,MAAA,GAAS,EAAE,GAAA,EAAK,CAAA,CAAE,OAAO,GAAA,EAAK,MAAA,EAAQ,CAAA,CAAE,MAAA,CAAO,MAAA,EAAO;AAAA,MAC9D;AACA,MAAA;AAAA,IACF;AAAA,IACA,KAAK,aAAA,EAAe;AAClB,MAAA,MAAM,CAAA,GAAI,OAAO,MAAM,CAAA;AACvB,MAAA,IAAI,CAAA,CAAE,OAAA,CAAQ,MAAA,KAAW,MAAA,IAAU,UAAA,IAAc,CAAA;AAAA,aAC1C,UAAA,IAAc,CAAA;AACrB,MAAA,MAAM,GAAA,GAAM,iBAAiB,CAAC,CAAA;AAC9B,MAAA,IAAI,GAAA,EAAK;AACP,QAAA,GAAA,CAAI,MAAA,GAAS,EAAE,MAAA,EAAQ,CAAA,CAAE,QAAQ,MAAA,EAAQ,OAAA,EAAS,CAAA,CAAE,OAAA,CAAQ,OAAA,EAAQ;AAEpE,QAAA,IAAI,CAAA,CAAE,OAAA,CAAQ,MAAA,KAAW,MAAA,MAAY,MAAA,GAAS,MAAA;AAAA,MAChD;AACA,MAAA;AAAA,IACF;AAAA,IACA,KAAK,UAAA,EAAY;AACf,MAAA,MAAM,CAAA,GAAI,OAAO,MAAM,CAAA;AACvB,MAAA,CAAA,CAAE,MAAA,GAAS,EAAE,OAAA,CAAQ,MAAA;AACrB,MAAA,MAAM,GAAA,GAAM,iBAAiB,CAAC,CAAA;AAC9B,MAAA,IAAI,GAAA,IAAO,GAAA,CAAI,MAAA,KAAW,SAAA,EAAW;AACnC,QAAA,GAAA,CAAI,MAAA,GAAS,EAAE,OAAA,CAAQ,MAAA;AACvB,QAAA,GAAA,CAAI,UAAU,CAAA,CAAE,EAAA;AAAA,MAClB,CAAA,MAAA,IAAW,GAAA,IAAO,GAAA,CAAI,OAAA,IAAW,IAAA,EAAM;AACrC,QAAA,GAAA,CAAI,UAAU,CAAA,CAAE,EAAA;AAAA,MAClB;AACA,MAAA;AAAA,IACF;AAAA,IACA,KAAK,WAAA;AACH,MAAA,MAAA,CAAO,KAAK,CAAA;AACZ,MAAA;AAAA,IACF,KAAK,SAAA;AACH,MAAA,MAAA,CAAO,KAAK,CAAA,CAAE,MAAA,GAAS,CAAA,CAAE,OAAA,CAAQ,MAAA;AACjC,MAAA;AAAA,IACF,KAAK,WAAA;AACH,MAAA,EAAA,CAAG,cAAc,CAAA,CAAE,KAAA;AACnB,MAAA,EAAA,CAAG,MAAA,GAAS,EAAA;AACZ,MAAA;AAAA,IACF,KAAK,SAAA,EAAW;AAId,MAAA,MAAM,GAAA,GAAM,MAAA,EAAO,IAAK,gBAAA,CAAiB,QAAS,CAAA;AAClD,MAAA,IAAI,GAAA,EAAK;AACP,QAAA,GAAA,CAAI,UAAA,GAAa,EAAE,OAAA,CAAQ,MAAA;AAC3B,QAAA,GAAA,CAAI,WAAA,GAAc,EAAE,OAAA,CAAQ,OAAA;AAAA,MAC9B;AACA,MAAA;AAAA,IACF;AAAA,IACA,KAAK,aAAA,EAAe;AAClB,MAAA,EAAA,CAAG,UAAU,EAAA,CAAG,MAAA,GAAS,EAAE,KAAA,EAAO,KAAA,CAAM,KAAW,CAAA;AACnD,MAAA,MAAM,GAAA,GAAM,MAAA,EAAO,IAAK,gBAAA,CAAiB,QAAS,CAAA;AAClD,MAAA,IAAI,GAAA;AACF,QAAA,GAAA,CAAI,cAAc,GAAA,CAAI,UAAA,GAAa,EAAE,KAAA,EAAO,KAAA,CAAM,IAAe,CAAA;AACnE,MAAA;AAAA,IACF;AAAA,IACA,KAAK,cAAA,EAAgB;AACnB,MAAA,EAAA,CAAG,KAAA,IAAS,CAAA;AACZ,MAAA,EAAA,CAAG,QAAA,IAAY,EAAE,KAAA,CAAM,WAAA;AACvB,MAAA,EAAA,CAAG,SAAA,IAAa,EAAE,KAAA,CAAM,YAAA;AACxB,MAAA,MAAM,GAAA,GAAM,MAAA,EAAO,IAAK,gBAAA,CAAiB,QAAS,CAAA;AAClD,MAAA,IAAI,GAAA,EAAK;AACP,QAAA,GAAA,CAAI,KAAA,IAAS,CAAA;AACb,QAAA,GAAA,CAAI,QAAA,IAAY,EAAE,KAAA,CAAM,WAAA;AACxB,QAAA,GAAA,CAAI,SAAA,IAAa,EAAE,KAAA,CAAM,YAAA;AAAA,MAC3B;AACA,MAAA;AAAA,IACF;AAAA,IACA,KAAK,OAAA;AACH,MAAA,EAAA,CAAG,MAAA,CAAO,KAAK,CAAA,CAAA,EAAI,CAAA,CAAE,IAAI,CAAA,EAAA,EAAK,CAAA,CAAE,OAAO,CAAA,CAAE,CAAA;AACzC,MAAA;AAAA;AAEN;ACpLA,SAAS,SAAS,CAAA,EAAwB;AACxC,EAAA,OAAO,CAAA,CAAE,KAAA,CAAM,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,KAAA,CAAM,GAAA,CAAI,CAAC,CAAA,EAAG,IAAA,KAAS,MAAM,CAAA;AAC9D;AAGA,SAAS,cAAc,CAAA,EAAkC;AACvD,EAAA,MAAM,IAAA,GAAO,SAAS,CAAC,CAAA;AACvB,EAAA,KAAA,IAAS,IAAI,IAAA,CAAK,MAAA,GAAS,CAAA,EAAG,CAAA,IAAK,GAAG,CAAA,EAAA,EAAK;AACzC,IAAA,MAAM,IAAI,CAAA,CAAE,KAAA,CAAM,GAAA,CAAI,IAAA,CAAK,CAAC,CAAE,CAAA;AAC9B,IAAA,IAAI,EAAE,UAAA,CAAW,MAAA,GAAS,CAAA,EAAG,OAAO,KAAK,CAAC,CAAA;AAAA,EAC5C;AACA,EAAA,OAAO,IAAA,CAAK,IAAA,CAAK,MAAA,GAAS,CAAC,CAAA;AAC7B;AAOA,SAAS,gBAAA,CACP,GACA,GAAA,EACoC;AACpC,EAAa,SAAS,CAAC;AACvB,EAAA,IAAI,MAAM,GAAA,CAAI,OAAA;AACd,EAAA,IAAI,GAAA,CAAI,UAAA,IAAc,CAAC,GAAA,IAAO,CAAC,CAAA,CAAE,KAAA,CAAM,GAAA,CAAI,GAAG,CAAA,EAAG,GAAA,GAAM,aAAA,CAAc,CAAC,CAAA;AACtE,EAAA,MAAM,OAAO,GAAA,GAAM,CAAA,CAAE,KAAA,CAAM,GAAA,CAAI,GAAG,CAAA,GAAI,MAAA;AACtC,EAAA,IAAI,CAAC,IAAA,EAAM,OAAO,EAAE,OAAO,CAAA,EAAE;AAC7B,EAAA,MAAM,KAAA,GAAQ,KAAK,UAAA,CAAW,MAAA;AAC9B,EAAA,IAAI,KAAA,GAAQ,GAAA,CAAI,UAAA,GAAa,KAAA,GAAQ,IAAI,GAAA,CAAI,cAAA;AAC7C,EAAA,IAAI,KAAA,IAAS,KAAA,EAAO,KAAA,GAAQ,KAAA,GAAQ,CAAA;AACpC,EAAA,IAAI,KAAA,GAAQ,GAAG,KAAA,GAAQ,CAAA;AACvB,EAAA,OAAO,EAAE,MAAM,KAAA,EAAM;AACvB;AAEO,SAAS,GAAA,CAAI,EAAE,GAAA,EAAK,KAAA,EAAO,SAAQ,EAAiC;AACzE,EAAA,MAAM,EAAA,GAAK,MAAA,CAAkB,OAAA,EAAS,CAAA;AACtC,EAAA,MAAM,MAAM,MAAA,CAAkB,EAAE,gBAAgB,CAAA,EAAG,UAAA,EAAY,MAAM,CAAA;AACrE,EAAA,MAAM,GAAG,OAAO,CAAA,GAAI,WAAW,CAAC,CAAA,KAAc,CAAA,GAAI,CAAA,EAAG,CAAC,CAAA;AAEtD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,MAAM,WAAA,GAAc,IAAI,SAAA,CAAU,CAAC,UAAU,MAAA,CAAO,EAAA,CAAG,OAAA,EAAS,KAAK,CAAC,CAAA;AACtE,IAAA,MAAM,KAAA,GAAQ,WAAA,CAAY,OAAA,EAAS,EAAE,CAAA;AACrC,IAAA,OAAO,MAAM;AACX,MAAA,WAAA,EAAY;AACZ,MAAA,aAAA,CAAc,KAAK,CAAA;AAAA,IACrB,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,GAAG,CAAC,CAAA;AAER,EAAA,QAAA,CAAS,CAAC,OAAO,CAAA,KAAM;AACrB,IAAA,IAAI,UAAU,GAAA,IAAO,CAAA,CAAE,UAAW,CAAA,CAAE,IAAA,IAAQ,UAAU,GAAA,EAAM;AAC1D,MAAA,OAAA,EAAQ;AACR,MAAA;AAAA,IACF;AACA,IAAA,MAAMA,KAAI,EAAA,CAAG,OAAA;AACb,IAAA,MAAM,IAAI,GAAA,CAAI,OAAA;AACd,IAAA,MAAM,IAAA,GAAO,SAASA,EAAC,CAAA;AAGvB,IAAA,IAAI,KAAA,KAAU,GAAA,IAAO,KAAA,KAAU,GAAA,EAAK;AAClC,MAAA,CAAA,CAAE,UAAA,GAAa,CAAC,CAAA,CAAE,UAAA;AAClB,MAAA,IAAI,CAAC,EAAE,UAAA,EAAY;AAEjB,QAAA,MAAM,EAAE,IAAA,EAAM,KAAA,EAAM,GAAI,gBAAA,CAAiBA,IAAG,CAAC,CAAA;AAC7C,QAAA,CAAA,CAAE,UAAU,IAAA,EAAM,GAAA;AAClB,QAAA,CAAA,CAAE,cAAA,GAAiB,KAAA;AAAA,MACrB;AACA,MAAA,OAAA,EAAQ;AACR,MAAA;AAAA,IACF;AAGA,IAAA,MAAM,QAAA,GAAW,CAAC,KAAA,KAAwB;AACxC,MAAA,IAAI,IAAA,CAAK,WAAW,CAAA,EAAG;AACvB,MAAA,CAAA,CAAE,UAAA,GAAa,KAAA;AACf,MAAA,MAAM,EAAE,IAAA,EAAK,GAAI,gBAAA,CAAiBA,IAAG,CAAC,CAAA;AACtC,MAAA,MAAM,MAAM,IAAA,GAAO,IAAA,CAAK,OAAA,CAAQ,IAAA,CAAK,GAAG,CAAA,GAAI,EAAA;AAC5C,MAAA,IAAI,IAAA,GAAA,CAAQ,GAAA,GAAM,CAAA,GAAI,CAAA,GAAI,GAAA,IAAO,KAAA;AACjC,MAAA,IAAI,IAAA,GAAO,GAAG,IAAA,GAAO,CAAA;AACrB,MAAA,IAAI,IAAA,IAAQ,IAAA,CAAK,MAAA,EAAQ,IAAA,GAAO,KAAK,MAAA,GAAS,CAAA;AAC9C,MAAA,CAAA,CAAE,OAAA,GAAU,KAAK,IAAI,CAAA;AAErB,MAAA,MAAM,CAAA,GAAIA,EAAAA,CAAE,KAAA,CAAM,GAAA,CAAI,EAAE,OAAQ,CAAA;AAChC,MAAA,CAAA,CAAE,cAAA,GAAiB,IAAI,IAAA,CAAK,GAAA,CAAI,GAAG,CAAA,CAAE,UAAA,CAAW,MAAA,GAAS,CAAC,CAAA,GAAI,CAAA;AAC9D,MAAA,OAAA,EAAQ;AAAA,IACV,CAAA;AAGA,IAAA,MAAM,aAAA,GAAgB,CAAC,KAAA,KAAwB;AAC7C,MAAA,CAAA,CAAE,UAAA,GAAa,KAAA;AACf,MAAA,MAAM,EAAE,IAAA,EAAM,KAAA,EAAM,GAAI,gBAAA,CAAiBA,IAAG,CAAC,CAAA;AAC7C,MAAA,IAAI,CAAC,IAAA,EAAM;AACX,MAAA,CAAA,CAAE,UAAU,IAAA,CAAK,GAAA;AACjB,MAAA,IAAI,OAAO,KAAA,GAAQ,KAAA;AACnB,MAAA,IAAI,IAAA,GAAO,GAAG,IAAA,GAAO,CAAA;AACrB,MAAA,IAAI,QAAQ,IAAA,CAAK,UAAA,CAAW,QAAQ,IAAA,GAAO,IAAA,CAAK,WAAW,MAAA,GAAS,CAAA;AACpE,MAAA,CAAA,CAAE,cAAA,GAAiB,IAAA;AACnB,MAAA,OAAA,EAAQ;AAAA,IACV,CAAA;AAEA,IAAA,IAAI,CAAA,CAAE,OAAA,IAAW,KAAA,KAAU,GAAA,WAAc,EAAE,CAAA;AAAA,SAAA,IAClC,CAAA,CAAE,SAAA,IAAa,KAAA,KAAU,GAAA,WAAc,CAAC,CAAA;AAAA,SAAA,IACxC,CAAA,CAAE,SAAA,IAAa,KAAA,KAAU,GAAA,gBAAmB,EAAE,CAAA;AAAA,SAAA,IAC9C,CAAA,CAAE,UAAA,IAAc,KAAA,KAAU,GAAA,gBAAmB,CAAC,CAAA;AAAA,EACzD,CAAC,CAAA;AAED,EAAA,MAAM,IAAI,EAAA,CAAG,OAAA;AACb,EAAA,MAAM,OAAA,GAAA,CAAA,CAAY,KAAK,GAAA,EAAI,GAAI,EAAE,SAAA,IAAa,GAAA,EAAM,QAAQ,CAAC,CAAA;AAC7D,EAAA,MAAM,EAAE,IAAA,EAAM,YAAA,EAAc,KAAA,EAAO,eAAc,GAAI,gBAAA;AAAA,IACnD,CAAA;AAAA,IACA,GAAA,CAAI;AAAA,GACN;AACA,EAAA,MAAM,cAAA,GACJ,YAAA,EAAc,UAAA,CAAW,aAAa,CAAA;AACxC,EAAA,MAAM,SAAA,GAAY,IAAI,OAAA,CAAQ,UAAA;AAE9B,EAAA,uBACE,IAAA,CAAC,GAAA,EAAA,EAAI,aAAA,EAAc,QAAA,EAAS,UAAU,CAAA,EACpC,QAAA,EAAA;AAAA,oBAAA,IAAA,CAAC,GAAA,EAAA,EAAI,gBAAe,eAAA,EAClB,QAAA,EAAA;AAAA,sBAAA,IAAA,CAAC,IAAA,EAAA,EAAK,IAAA,EAAI,IAAA,EAAC,KAAA,EAAM,MAAA,EACd,QAAA,EAAA;AAAA,QAAA,KAAA,CAAM,IAAA;AAAA,QAAK,GAAA;AAAA,QAAE;AAAA,OAAA,EAChB,CAAA;AAAA,sBACA,IAAA,CAAC,IAAA,EAAA,EAAK,KAAA,EAAM,MAAA,EAAQ,QAAA,EAAA;AAAA,QAAA,OAAA;AAAA,QAAQ;AAAA,OAAA,EAAa;AAAA,KAAA,EAC3C,CAAA;AAAA,oBAEA,IAAA,CAAC,GAAA,EAAA,EAAI,aAAA,EAAc,QAAA,EAAS,WAAW,CAAA,EACpC,QAAA,EAAA;AAAA,MAAA,CAAA,CAAE,MAAM,MAAA,KAAW,CAAA,wBAAM,IAAA,EAAA,EAAK,KAAA,EAAM,QAAO,QAAA,EAAA,gBAAA,EAAS,CAAA;AAAA,MACpD,CAAA,CAAE,KAAA,CAAM,GAAA,CAAI,CAAC,GAAA,KAAQ;AACpB,QAAA,MAAM,CAAA,GAAI,CAAA,CAAE,KAAA,CAAM,GAAA,CAAI,GAAG,CAAA;AACzB,QAAA,MAAM,IAAI,CAAA,CAAE,IAAA,KAAS,KAAA,GAAQ,KAAA,CAAM,MAAM,KAAA,CAAM,IAAA;AAC/C,QAAA,MAAM,OAAA,GAAU,CAAA,CAAE,UAAA,GAAa,CAAA,CAAE,UAAA;AACjC,QAAA,MAAM,UAAA,GAAa,CAAA,CAAE,IAAA,KAAS,MAAA,IAAU,cAAc,GAAA,KAAQ,GAAA;AAC9D,QAAA,4BACG,IAAA,EAAA,EACE,QAAA,EAAA;AAAA,UAAA,IAAA,CAAK,OAAO,IAAA,CAAK,GAAA,CAAI,GAAG,CAAA,CAAE,KAAA,GAAQ,CAAC,CAAC,CAAA;AAAA,0BACrC,GAAA,CAAC,QAAK,KAAA,EAAO,UAAA,GAAa,SAAS,MAAA,EAChC,QAAA,EAAA,UAAA,GAAa,YAAO,IAAA,EACvB,CAAA;AAAA,+BACC,IAAA,EAAA,EAAK,KAAA,EAAO,WAAA,CAAY,CAAA,CAAE,MAAM,CAAA,EAC9B,QAAA,EAAA;AAAA,YAAA,CAAA,CAAE,MAAA,GAAS,WAAA,CAAY,CAAA,CAAE,MAAM,CAAA,GAAI,CAAA;AAAA,YAAG;AAAA,WAAA,EACzC,CAAA;AAAA,8BACC,IAAA,EAAA,EAAK,IAAA,EAAI,MAAC,SAAA,EAAW,UAAA,EACnB,YAAE,IAAA,EACL,CAAA;AAAA,UACC,EAAE,IAAA,KAAS,MAAA,oBACV,IAAA,CAAC,IAAA,EAAA,EAAK,OAAM,MAAA,EACT,QAAA,EAAA;AAAA,YAAA,GAAA;AAAA,YAAI,OAAA;AAAA,YACC,CAAA,CAAE,SAAA;AAAA,YACP,CAAA,CAAE,GAAA,GAAM,CAAA,CAAA,EAAI,CAAA,CAAE,GAAG,CAAA,CAAA,GAAK;AAAA,WAAA,EACzB,CAAA;AAAA,UAED,OAAA,GAAU,CAAA,oBACT,IAAA,CAAC,IAAA,EAAA,EAAK,OAAM,MAAA,EACT,QAAA,EAAA;AAAA,YAAA,GAAA;AAAA,YAAI,cAAA;AAAA,YACK,CAAA,CAAE,UAAA;AAAA,YAAW,SAAA;AAAA,YAAG,CAAA,CAAE,UAAA;AAAA,YAAW;AAAA,WAAA,EACzC;AAAA,SAAA,EAAA,EAtBO,GAwBX,CAAA;AAAA,MAEJ,CAAC;AAAA,KAAA,EACH,CAAA;AAAA,IAEC,YAAA,oBACC,GAAA;AAAA,MAAC,GAAA;AAAA,MAAA;AAAA,QACC,aAAA,EAAc,QAAA;AAAA,QACd,SAAA,EAAW,CAAA;AAAA,QACX,WAAA,EAAY,OAAA;AAAA,QACZ,WAAA,EAAY,MAAA;AAAA,QACZ,QAAA,EAAU,CAAA;AAAA,QAEV,QAAA,kBAAA,GAAA;AAAA,UAAC,eAAA;AAAA,UAAA;AAAA,YACC,IAAA,EAAM,YAAA;AAAA,YACN,MAAA,EAAQ,cAAA;AAAA,YACR,KAAA,EAAO;AAAA;AAAA;AACT;AAAA,KACF;AAAA,oBAGF,IAAA,CAAC,GAAA,EAAA,EAAI,SAAA,EAAW,CAAA,EAAG,gBAAe,eAAA,EAChC,QAAA,EAAA;AAAA,sBAAA,IAAA,CAAC,IAAA,EAAA,EAAK,OAAM,MAAA,EACT,QAAA,EAAA;AAAA,QAAA,CAAA,CAAE,KAAA;AAAA,QAAM,gBAAA;AAAA,QAAY,CAAA,CAAE,QAAA;AAAA,QAAS,QAAA;AAAA,QAAO,CAAA,CAAE,SAAA;AAAA,QAAU;AAAA,OAAA,EACrD,CAAA;AAAA,MACC,EAAE,MAAA,CAAO,MAAA,GAAS,oBACjB,IAAA,CAAC,IAAA,EAAA,EAAK,OAAM,KAAA,EAAO,QAAA,EAAA;AAAA,QAAA,CAAA,CAAE,MAAA,CAAO,MAAA;AAAA,QAAO;AAAA,OAAA,EAAS,CAAA,mBAE5C,GAAA,CAAC,IAAA,EAAA,EAAK,KAAA,EAAM,SAAQ,QAAA,EAAA,GAAA,EAAC;AAAA,KAAA,EAEzB,CAAA;AAAA,oBAEA,IAAA,CAAC,GAAA,EAAA,EAAI,cAAA,EAAe,eAAA,EAClB,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,IAAA,EAAA,EAAK,KAAA,EAAM,MAAA,EAAO,QAAA,EAAA,gFAAA,EAEnB,CAAA;AAAA,sBACA,GAAA,CAAC,QAAK,KAAA,EAAO,SAAA,GAAY,UAAU,QAAA,EAChC,QAAA,EAAA,SAAA,GAAY,gBAAW,eAAA,EAC1B;AAAA,KAAA,EACF;AAAA,GAAA,EACF,CAAA;AAEJ;AAEA,SAAS,eAAA,CAAgB;AAAA,EACvB,IAAA;AAAA,EACA,MAAA;AAAA,EACA;AACF,CAAA,EAIuB;AACrB,EAAA,MAAM,KAAA,GAAQ,KAAK,UAAA,CAAW,MAAA;AAC9B,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,uBAAO,IAAA,CAAC,IAAA,EAAA,EAAK,KAAA,EAAM,MAAA,EAAO,QAAA,EAAA;AAAA,MAAA,OAAA;AAAA,MAAM,IAAA,CAAK,IAAA;AAAA,MAAK;AAAA,KAAA,EAAoB,CAAA;AAAA,EAChE;AACA,EAAA,MAAM,KAAA,GACJ,MAAA,CAAO,OAAA,IAAW,IAAA,GACd,MAAA,CAAO,OAAA,GAAU,MAAA,CAAO,SAAA,GACxB,IAAA,CAAK,GAAA,EAAI,GAAI,MAAA,CAAO,SAAA;AAC1B,EAAA,MAAM,MAAM,CAAA,EAAA,CAAI,KAAA,GAAQ,GAAA,EAAM,OAAA,CAAQ,CAAC,CAAC,CAAA,CAAA,CAAA;AACxC,EAAA,MAAM,kBAAkB,MAAA,CAAO,UAAA,CAAW,MAAM,IAAI,CAAA,CAAE,MAAM,GAAG,CAAA;AAE/D,EAAA,uBACE,IAAA,CAAA,QAAA,EAAA,EACE,QAAA,EAAA;AAAA,oBAAA,IAAA,CAAC,IAAA,EAAA,EACC,QAAA,EAAA;AAAA,sBAAA,IAAA,CAAC,IAAA,EAAA,EAAK,MAAI,IAAA,EAAC,QAAA,EAAA;AAAA,QAAA,OAAA;AAAA,QAAM,IAAA,CAAK;AAAA,OAAA,EAAK,CAAA;AAAA,sBAC3B,IAAA,CAAC,IAAA,EAAA,EAAK,KAAA,EAAM,MAAA,EACT,QAAA,EAAA;AAAA,QAAA,GAAA;AAAA,QAAI,mBAAA;AAAA,QACQ,KAAA,GAAQ,CAAA;AAAA,QAAE,GAAA;AAAA,QAAE,KAAA;AAAA,QAAO;AAAA,OAAA,EAClC,CAAA;AAAA,sBACA,IAAA;AAAA,QAAC,IAAA;AAAA,QAAA;AAAA,UACC,KAAA,EAAO,WAAA;AAAA,YACL,MAAA,CAAO,MAAA,KAAW,SAAA,GAAY,MAAA,GAAY,MAAA,CAAO;AAAA,WACnD;AAAA,UACA,IAAA,EAAI,IAAA;AAAA,UACL,QAAA,EAAA;AAAA,YAAA,GAAA;AAAA,YACG,MAAA,CAAO,MAAA;AAAA,YAAO;AAAA;AAAA;AAAA;AAClB,KAAA,EACF,CAAA;AAAA,IAEC,MAAA,CAAO,UAAA,oBACN,IAAA,CAAC,IAAA,EAAA,EACC,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,IAAA,EAAA,EAAK,KAAA,EAAM,MAAA,EAAO,QAAA,EAAA,OAAA,EAAK,CAAA;AAAA,sBACxB,GAAA,CAAC,QAAK,KAAA,EAAO,WAAA,CAAY,OAAO,UAAU,CAAA,EACvC,iBAAO,UAAA,EACV,CAAA;AAAA,MACC,MAAA,CAAO,WAAA,mBACN,IAAA,CAAC,IAAA,EAAA,EAAK,OAAM,MAAA,EAAO,QAAA,EAAA;AAAA,QAAA,UAAA;AAAA,QAAI,MAAA,CAAO;AAAA,OAAA,EAAY,CAAA,GACxC;AAAA,KAAA,EACN,CAAA;AAAA,IAGD,MAAA,CAAO,KAAA,oBACN,IAAA,CAAC,IAAA,EAAA,EACC,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,IAAA,EAAA,EAAK,KAAA,EAAM,SAAA,EAAU,QAAA,EAAA,QAAA,EAAM,CAAA;AAAA,MAC3B,MAAA,CAAO,KAAA,CAAM,GAAA,mBACZ,GAAA,CAAC,IAAA,EAAA,EAAK,KAAA,EAAM,OAAA,EAAQ,QAAA,EAAA,KAAA,EAAG,CAAA,mBAEvB,GAAA,CAAC,IAAA,EAAA,EAAK,KAAA,EAAM,QAAO,QAAA,EAAA,SAAA,EAAO,CAAA;AAAA,sBAE5B,IAAA,CAAC,IAAA,EAAA,EAAK,KAAA,EAAM,MAAA,EAAO,QAAA,EAAA;AAAA,QAAA,UAAA;AAAA,QAAI,OAAO,KAAA,CAAM;AAAA,OAAA,EAAO,CAAA;AAAA,MAC1C,OAAO,KAAA,CAAM,UAAA,IAAc,uBAC1B,IAAA,CAAC,IAAA,EAAA,EAAK,OAAM,MAAA,EAAO,QAAA,EAAA;AAAA,QAAA,IAAA;AAAA,QAAG,MAAA,CAAO,KAAA,CAAM,UAAA,CAAW,OAAA,CAAQ,CAAC,CAAA;AAAA,QAAE;AAAA,OAAA,EAAC,CAAA,GACxD;AAAA,KAAA,EACN,CAAA;AAAA,IAGD,MAAA,CAAO,MAAA,oBACN,IAAA,CAAC,IAAA,EAAA,EACC,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,IAAA,EAAA,EAAK,KAAA,EAAM,SAAA,EAAU,QAAA,EAAA,SAAA,EAAO,CAAA;AAAA,MAC5B,MAAA,CAAO,MAAA,CAAO,GAAA,mBACb,GAAA,CAAC,IAAA,EAAA,EAAK,KAAA,EAAM,KAAA,EAAM,QAAA,EAAA,KAAA,EAAG,CAAA,mBAErB,GAAA,CAAC,IAAA,EAAA,EAAK,KAAA,EAAM,QAAO,QAAA,EAAA,SAAA,EAAO,CAAA;AAAA,sBAE5B,IAAA,CAAC,IAAA,EAAA,EAAK,KAAA,EAAM,MAAA,EAAO,QAAA,EAAA;AAAA,QAAA,UAAA;AAAA,QAAI,OAAO,MAAA,CAAO;AAAA,OAAA,EAAO;AAAA,KAAA,EAC9C,CAAA;AAAA,IAGD,MAAA,CAAO,MAAA,oBACN,IAAA,CAAC,IAAA,EAAA,EACC,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,IAAA,EAAA,EAAK,KAAA,EAAM,MAAA,EAAO,QAAA,EAAA,SAAA,EAAO,CAAA;AAAA,sBAC1B,GAAA,CAAC,IAAA,EAAA,EAAK,KAAA,EAAO,WAAA,CAAY,MAAA,CAAO,OAAO,MAAM,CAAA,EAC1C,QAAA,EAAA,MAAA,CAAO,MAAA,CAAO,MAAA,EACjB,CAAA;AAAA,MACC,OAAO,MAAA,CAAO,OAAA,mBACb,IAAA,CAAC,IAAA,EAAA,EAAK,OAAM,MAAA,EAAO,QAAA,EAAA;AAAA,QAAA,UAAA;AAAA,QAAI,OAAO,MAAA,CAAO;AAAA,OAAA,EAAQ,CAAA,GAC3C;AAAA,KAAA,EACN,CAAA;AAAA,oBAGF,IAAA,CAAC,IAAA,EAAA,EAAK,KAAA,EAAM,MAAA,EACT,QAAA,EAAA;AAAA,MAAA,MAAA,CAAO,QAAA;AAAA,MAAS,QAAA;AAAA,MAAO,MAAA,CAAO,SAAA;AAAA,MAAU,gBAAA;AAAA,MAAY,MAAA,CAAO,KAAA;AAAA,MAAO,GAAA;AAAA,MAAI,eAAA;AAAA,MAC5D;AAAA,KAAA,EACb,CAAA;AAAA,IAEC,eAAA,CAAgB,MAAA,GAAS,CAAA,IAAK,MAAA,CAAO,UAAA,CAAW,MAAA,GAAS,CAAA,oBACxD,GAAA,CAAC,GAAA,EAAA,EAAI,aAAA,EAAc,QAAA,EAAS,SAAA,EAAW,CAAA,EACpC,QAAA,EAAA,eAAA,CAAgB,GAAA,CAAI,CAAC,CAAA,EAAG,CAAA,qBACvB,GAAA,CAAC,IAAA,EAAA,EAAa,KAAA,EAAM,OAAA,EAAQ,IAAA,EAAK,cAAA,EAC9B,QAAA,EAAA,CAAA,IAAK,GAAA,EAAA,EADG,CAEX,CACD,CAAA,EACH;AAAA,GAAA,EAEJ,CAAA;AAEJ","file":"App-3YQS6DXA.js","sourcesContent":["/** Shared colour + glyph vocabulary for the TUI. */\n\nimport type { Outcome } from '../core/types.ts';\n\nexport const glyph = {\n loop: '↻',\n dag: '▤',\n pass: '✔',\n fail: '✘',\n aborted: '◼',\n exhausted: '⊘',\n paused: '⏸',\n running: '◐',\n} as const;\n\nexport function statusColor(status: Outcome['status'] | undefined): string {\n switch (status) {\n case 'pass':\n return 'green';\n case 'fail':\n return 'red';\n case 'exhausted':\n return 'yellow';\n case 'aborted':\n return 'gray';\n case 'paused':\n return 'cyan';\n default:\n return 'cyan';\n }\n}\n\nexport function statusGlyph(status: Outcome['status'] | undefined): string {\n switch (status) {\n case 'pass':\n return glyph.pass;\n case 'fail':\n return glyph.fail;\n case 'exhausted':\n return glyph.exhausted;\n case 'aborted':\n return glyph.aborted;\n case 'paused':\n return glyph.paused;\n default:\n return glyph.running;\n }\n}\n","/**\n * The TUI view-model — a pure fold of events into render state. Kept free of\n * React/Ink so it is trivially unit-testable; `App.tsx` just renders it.\n *\n * Each loop node retains a per-iteration history (`IterationRecord[]`) derived\n * entirely from the event stream, so the TUI can browse the result of every\n * iteration after the fact. Attribution is by path: an event at path P updates\n * the loop node whose key === `P.join(' / ')`, and within that loop it lands on\n * the current (latest) iteration record. Nested loops therefore each track\n * their own iterations without colliding — a nested loop's events carry a longer\n * path and so attribute to the nested loop node, not its parent.\n */\n\nimport type { LoopEvent, Outcome } from '../core/types.ts';\n\nexport type IterationStatus =\n | 'running'\n | 'pass'\n | 'fail'\n | 'aborted'\n | 'exhausted'\n | 'paused';\n\nexport interface IterationRecord {\n iteration: number;\n status: IterationStatus;\n bodyStatus?: Outcome['status'];\n bodySummary?: string;\n until?: { met: boolean; reason: string; confidence?: number };\n stopOn?: { met: boolean; reason: string };\n review?: { status: Outcome['status']; summary?: string };\n tokensIn: number;\n tokensOut: number;\n calls: number;\n transcript: string;\n startedAt: number;\n endedAt?: number;\n}\n\nexport interface NodeView {\n key: string;\n name: string;\n depth: number;\n type: 'loop' | 'dag';\n iteration: number;\n max?: number;\n status?: Outcome['status'];\n reviewPass: number;\n reviewFail: number;\n iterations: IterationRecord[];\n}\n\nexport interface ViewModel {\n nodes: Map<string, NodeView>;\n order: string[];\n activeLabel?: string;\n stream: string;\n tokensIn: number;\n tokensOut: number;\n calls: number;\n errors: string[];\n startedAt: number;\n}\n\nexport const STREAM_CAP = 1600;\n/** Per-iteration transcript buffer cap, so history stays bounded under long runs. */\nexport const TRANSCRIPT_CAP = 2000;\n\nexport function emptyVM(): ViewModel {\n return {\n nodes: new Map(),\n order: [],\n stream: '',\n tokensIn: 0,\n tokensOut: 0,\n calls: 0,\n errors: [],\n startedAt: Date.now(),\n };\n}\n\n/** The latest (current) iteration record of a loop node, if any. */\nfunction currentIteration(node: NodeView): IterationRecord | undefined {\n return node.iterations[node.iterations.length - 1];\n}\n\n/** Fold one event into the view-model in place. */\nexport function reduce(vm: ViewModel, e: LoopEvent): void {\n const key = e.path.join(' / ');\n const ensure = (type: 'loop' | 'dag'): NodeView => {\n let n = vm.nodes.get(key);\n if (!n) {\n n = {\n key,\n name: e.path[e.path.length - 1] ?? '(root)',\n depth: e.path.length,\n type,\n iteration: 0,\n reviewPass: 0,\n reviewFail: 0,\n iterations: [],\n };\n vm.nodes.set(key, n);\n vm.order.push(key);\n }\n return n;\n };\n /** The loop node owning this event's path, only if one already exists. */\n const loopAt = (): NodeView | undefined => {\n const n = vm.nodes.get(key);\n return n?.type === 'loop' ? n : undefined;\n };\n\n switch (e.kind) {\n case 'loop:start':\n ensure('loop').max = e.max;\n break;\n case 'loop:iteration': {\n const n = ensure('loop');\n n.iteration = e.iteration;\n // Boundary: finalize the previous running record, then push a new one.\n const prev = currentIteration(n);\n if (prev && prev.status === 'running') {\n prev.status = prev.bodyStatus ?? 'pass';\n prev.endedAt = e.ts;\n }\n n.iterations.push({\n iteration: e.iteration,\n status: 'running',\n tokensIn: 0,\n tokensOut: 0,\n calls: 0,\n transcript: '',\n startedAt: e.ts,\n });\n break;\n }\n case 'loop:condition': {\n const cur = loopAt() && currentIteration(loopAt()!);\n if (cur) {\n if (e.which === 'until')\n cur.until = {\n met: e.result.met,\n reason: e.result.reason,\n confidence: e.result.confidence,\n };\n else if (e.which === 'stopOn')\n cur.stopOn = { met: e.result.met, reason: e.result.reason };\n }\n break;\n }\n case 'loop:review': {\n const n = ensure('loop');\n if (e.outcome.status === 'pass') n.reviewPass += 1;\n else n.reviewFail += 1;\n const cur = currentIteration(n);\n if (cur) {\n cur.review = { status: e.outcome.status, summary: e.outcome.summary };\n // A failing review keeps the iteration \"fail\"-flavoured even if the body passed.\n if (e.outcome.status !== 'pass') cur.status = 'fail';\n }\n break;\n }\n case 'loop:end': {\n const n = ensure('loop');\n n.status = e.outcome.status;\n const cur = currentIteration(n);\n if (cur && cur.status === 'running') {\n cur.status = e.outcome.status;\n cur.endedAt = e.ts;\n } else if (cur && cur.endedAt == null) {\n cur.endedAt = e.ts;\n }\n break;\n }\n case 'dag:start':\n ensure('dag');\n break;\n case 'dag:end':\n ensure('dag').status = e.outcome.status;\n break;\n case 'job:start':\n vm.activeLabel = e.label;\n vm.stream = '';\n break;\n case 'job:end': {\n // The loop body runs at the loop's own path; attribute its outcome to the\n // current iteration of that loop (when one exists). Jobs at non-loop paths\n // (e.g. DAG nodes) are ignored for iteration purposes.\n const cur = loopAt() && currentIteration(loopAt()!);\n if (cur) {\n cur.bodyStatus = e.outcome.status;\n cur.bodySummary = e.outcome.summary;\n }\n break;\n }\n case 'engine:text': {\n vm.stream = (vm.stream + e.delta).slice(-STREAM_CAP);\n const cur = loopAt() && currentIteration(loopAt()!);\n if (cur)\n cur.transcript = (cur.transcript + e.delta).slice(-TRANSCRIPT_CAP);\n break;\n }\n case 'engine:usage': {\n vm.calls += 1;\n vm.tokensIn += e.usage.inputTokens;\n vm.tokensOut += e.usage.outputTokens;\n const cur = loopAt() && currentIteration(loopAt()!);\n if (cur) {\n cur.calls += 1;\n cur.tokensIn += e.usage.inputTokens;\n cur.tokensOut += e.usage.outputTokens;\n }\n break;\n }\n case 'error':\n vm.errors.push(`[${e.code}] ${e.message}`);\n break;\n }\n}\n","/**\n * The Ink TUI. It subscribes to the event hub, folds events into a small view\n * model in a ref (synchronous, no per-token re-render), and repaints on a timer\n * — so a fast token stream never thrashes React. Shows the live loop/dag tree, a\n * detail panel for the selected loop iteration, and a stats footer.\n *\n * Navigation: up/down (or k/j) move the selection across loop nodes in tree\n * order; left/right (or h/l) step through the selected loop's iterations; f or\n * space toggles follow-live (auto-track the newest loop + iteration). q/Esc/\n * Ctrl-C abort. Selection state lives in a ref so the 90ms repaint timer drives\n * rendering without a re-render per keypress.\n */\n\nimport React, { useEffect, useReducer, useRef } from 'react';\nimport { Box, Text, useInput } from 'ink';\n\nimport type { Hub } from '../runtime/hub.ts';\nimport { statusColor, statusGlyph, glyph } from './theme.ts';\nimport {\n emptyVM,\n reduce,\n type ViewModel,\n type NodeView,\n type IterationRecord,\n} from './model.ts';\n\nexport interface AppProps {\n hub: Hub;\n title: string;\n onAbort: () => void;\n}\n\ninterface Selection {\n loopKey?: string;\n iterationIndex: number;\n followLive: boolean;\n}\n\n/** Loop nodes in tree (insertion) order — the navigable set. */\nfunction loopKeys(m: ViewModel): string[] {\n return m.order.filter((k) => m.nodes.get(k)?.type === 'loop');\n}\n\n/** The newest loop with at least one iteration, else the newest loop. */\nfunction newestLoopKey(m: ViewModel): string | undefined {\n const keys = loopKeys(m);\n for (let i = keys.length - 1; i >= 0; i--) {\n const n = m.nodes.get(keys[i]!)!;\n if (n.iterations.length > 0) return keys[i];\n }\n return keys[keys.length - 1];\n}\n\n/**\n * Reconcile the selection against the current model. When following live, snap\n * to the newest loop + its newest iteration. Otherwise clamp the existing\n * selection so it stays valid as iterations stream in.\n */\nfunction resolveSelection(\n m: ViewModel,\n sel: Selection,\n): { node?: NodeView; index: number } {\n const keys = loopKeys(m);\n let key = sel.loopKey;\n if (sel.followLive || !key || !m.nodes.has(key)) key = newestLoopKey(m);\n const node = key ? m.nodes.get(key) : undefined;\n if (!node) return { index: 0 };\n const count = node.iterations.length;\n let index = sel.followLive ? count - 1 : sel.iterationIndex;\n if (index >= count) index = count - 1;\n if (index < 0) index = 0;\n return { node, index };\n}\n\nexport function App({ hub, title, onAbort }: AppProps): React.ReactElement {\n const vm = useRef<ViewModel>(emptyVM());\n const sel = useRef<Selection>({ iterationIndex: 0, followLive: true });\n const [, repaint] = useReducer((n: number) => n + 1, 0);\n\n useEffect(() => {\n const unsubscribe = hub.subscribe((event) => reduce(vm.current, event));\n const timer = setInterval(repaint, 90);\n return () => {\n unsubscribe();\n clearInterval(timer);\n };\n }, [hub]);\n\n useInput((input, k) => {\n if (input === 'q' || k.escape || (k.ctrl && input === 'c')) {\n onAbort();\n return;\n }\n const m = vm.current;\n const s = sel.current;\n const keys = loopKeys(m);\n\n // Toggle follow-live.\n if (input === 'f' || input === ' ') {\n s.followLive = !s.followLive;\n if (!s.followLive) {\n // Freeze on whatever is currently shown.\n const { node, index } = resolveSelection(m, s);\n s.loopKey = node?.key;\n s.iterationIndex = index;\n }\n repaint();\n return;\n }\n\n // Move selection across loop nodes (tree order).\n const moveLoop = (delta: number): void => {\n if (keys.length === 0) return;\n s.followLive = false;\n const { node } = resolveSelection(m, s);\n const cur = node ? keys.indexOf(node.key) : -1;\n let next = (cur < 0 ? 0 : cur) + delta;\n if (next < 0) next = 0;\n if (next >= keys.length) next = keys.length - 1;\n s.loopKey = keys[next];\n // Land on the newest iteration of the newly-selected loop.\n const n = m.nodes.get(s.loopKey!);\n s.iterationIndex = n ? Math.max(0, n.iterations.length - 1) : 0;\n repaint();\n };\n\n // Step through iterations of the selected loop.\n const moveIteration = (delta: number): void => {\n s.followLive = false;\n const { node, index } = resolveSelection(m, s);\n if (!node) return;\n s.loopKey = node.key;\n let next = index + delta;\n if (next < 0) next = 0;\n if (next >= node.iterations.length) next = node.iterations.length - 1;\n s.iterationIndex = next;\n repaint();\n };\n\n if (k.upArrow || input === 'k') moveLoop(-1);\n else if (k.downArrow || input === 'j') moveLoop(1);\n else if (k.leftArrow || input === 'h') moveIteration(-1);\n else if (k.rightArrow || input === 'l') moveIteration(1);\n });\n\n const m = vm.current;\n const elapsed = ((Date.now() - m.startedAt) / 1000).toFixed(1);\n const { node: selectedNode, index: selectedIndex } = resolveSelection(\n m,\n sel.current,\n );\n const selectedRecord: IterationRecord | undefined =\n selectedNode?.iterations[selectedIndex];\n const following = sel.current.followLive;\n\n return (\n <Box flexDirection=\"column\" paddingX={1}>\n <Box justifyContent=\"space-between\">\n <Text bold color=\"cyan\">\n {glyph.loop} {title}\n </Text>\n <Text color=\"gray\">{elapsed}s · q to stop</Text>\n </Box>\n\n <Box flexDirection=\"column\" marginTop={1}>\n {m.order.length === 0 && <Text color=\"gray\">starting…</Text>}\n {m.order.map((key) => {\n const n = m.nodes.get(key)!;\n const g = n.type === 'dag' ? glyph.dag : glyph.loop;\n const reviews = n.reviewPass + n.reviewFail;\n const isSelected = n.type === 'loop' && selectedNode?.key === key;\n return (\n <Text key={key}>\n {' '.repeat(Math.max(0, n.depth - 1))}\n <Text color={isSelected ? 'cyan' : 'gray'}>\n {isSelected ? '▶ ' : ' '}\n </Text>\n <Text color={statusColor(n.status)}>\n {n.status ? statusGlyph(n.status) : g}{' '}\n </Text>\n <Text bold underline={isSelected}>\n {n.name}\n </Text>\n {n.type === 'loop' && (\n <Text color=\"gray\">\n {' '}\n iter {n.iteration}\n {n.max ? `/${n.max}` : ''}\n </Text>\n )}\n {reviews > 0 && (\n <Text color=\"gray\">\n {' '}\n · review {n.reviewPass}✔/{n.reviewFail}✘\n </Text>\n )}\n </Text>\n );\n })}\n </Box>\n\n {selectedNode && (\n <Box\n flexDirection=\"column\"\n marginTop={1}\n borderStyle=\"round\"\n borderColor=\"cyan\"\n paddingX={1}\n >\n <IterationDetail\n node={selectedNode}\n record={selectedRecord}\n index={selectedIndex}\n />\n </Box>\n )}\n\n <Box marginTop={1} justifyContent=\"space-between\">\n <Text color=\"gray\">\n {m.calls} call(s) · {m.tokensIn} in / {m.tokensOut} out tok\n </Text>\n {m.errors.length > 0 ? (\n <Text color=\"red\">{m.errors.length} error(s)</Text>\n ) : (\n <Text color=\"green\"> </Text>\n )}\n </Box>\n\n <Box justifyContent=\"space-between\">\n <Text color=\"gray\">\n ↑↓/jk loop · ←→/hl iter · f/space follow · q stop\n </Text>\n <Text color={following ? 'green' : 'yellow'}>\n {following ? '● LIVE' : '⏸ BROWSE'}\n </Text>\n </Box>\n </Box>\n );\n}\n\nfunction IterationDetail({\n node,\n record,\n index,\n}: {\n node: NodeView;\n record?: IterationRecord;\n index: number;\n}): React.ReactElement {\n const total = node.iterations.length;\n if (!record) {\n return <Text color=\"gray\">loop {node.name} — no iterations yet</Text>;\n }\n const durMs =\n record.endedAt != null\n ? record.endedAt - record.startedAt\n : Date.now() - record.startedAt;\n const dur = `${(durMs / 1000).toFixed(1)}s`;\n const transcriptLines = record.transcript.split('\\n').slice(-10);\n\n return (\n <>\n <Text>\n <Text bold>loop {node.name}</Text>\n <Text color=\"gray\">\n {' '}\n — iteration {index + 1}/{total}{' '}\n </Text>\n <Text\n color={statusColor(\n record.status === 'running' ? undefined : record.status,\n )}\n bold\n >\n [{record.status}]\n </Text>\n </Text>\n\n {record.bodyStatus && (\n <Text>\n <Text color=\"gray\">body </Text>\n <Text color={statusColor(record.bodyStatus)}>\n {record.bodyStatus}\n </Text>\n {record.bodySummary ? (\n <Text color=\"gray\"> — {record.bodySummary}</Text>\n ) : null}\n </Text>\n )}\n\n {record.until && (\n <Text>\n <Text color=\"magenta\">until </Text>\n {record.until.met ? (\n <Text color=\"green\">met</Text>\n ) : (\n <Text color=\"gray\">not met</Text>\n )}\n <Text color=\"gray\"> — {record.until.reason}</Text>\n {record.until.confidence != null ? (\n <Text color=\"gray\"> ({record.until.confidence.toFixed(2)})</Text>\n ) : null}\n </Text>\n )}\n\n {record.stopOn && (\n <Text>\n <Text color=\"magenta\">stopOn </Text>\n {record.stopOn.met ? (\n <Text color=\"red\">met</Text>\n ) : (\n <Text color=\"gray\">not met</Text>\n )}\n <Text color=\"gray\"> — {record.stopOn.reason}</Text>\n </Text>\n )}\n\n {record.review && (\n <Text>\n <Text color=\"blue\">review </Text>\n <Text color={statusColor(record.review.status)}>\n {record.review.status}\n </Text>\n {record.review.summary ? (\n <Text color=\"gray\"> — {record.review.summary}</Text>\n ) : null}\n </Text>\n )}\n\n <Text color=\"gray\">\n {record.tokensIn} in / {record.tokensOut} out tok · {record.calls}{' '}\n call(s) · {dur}\n </Text>\n\n {transcriptLines.length > 0 && record.transcript.length > 0 && (\n <Box flexDirection=\"column\" marginTop={1}>\n {transcriptLines.map((l, i) => (\n <Text key={i} color=\"white\" wrap=\"truncate-end\">\n {l || ' '}\n </Text>\n ))}\n </Box>\n )}\n </>\n );\n}\n"]}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { newAccumulator, mapMessage } from './chunk-CXEPZHSR.js';
|
|
2
|
+
import { SUBAGENT_TOOLS } from './chunk-XC46B4FD.js';
|
|
3
|
+
import { LoopError } from './chunk-I3STY7U6.js';
|
|
4
|
+
import pTimeout from 'p-timeout';
|
|
5
|
+
|
|
6
|
+
function classifySdkLimit(error) {
|
|
7
|
+
const err = error ?? {};
|
|
8
|
+
const tag = typeof err.error === "string" ? err.error : "";
|
|
9
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
10
|
+
const haystack = `${tag} ${message}`.toLowerCase();
|
|
11
|
+
const info = err.rate_limit_info ?? {};
|
|
12
|
+
const resetAt = typeof info.resetsAt === "number" ? info.resetsAt : typeof info.overageResetsAt === "number" ? info.overageResetsAt : void 0;
|
|
13
|
+
const isUsage = tag === "billing_error" || info.errorCode === "credits_required" || /billing|credit|usage limit|quota/.test(haystack);
|
|
14
|
+
if (isUsage) {
|
|
15
|
+
return new LoopError({
|
|
16
|
+
code: "QUOTA",
|
|
17
|
+
phase: "engine",
|
|
18
|
+
message: `agent-sdk usage/billing limit: ${message}`,
|
|
19
|
+
cause: error,
|
|
20
|
+
resetAt
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
const isRate = tag === "rate_limit" || tag === "overloaded" || /rate limit|rate-limit|too many requests|overloaded/.test(haystack);
|
|
24
|
+
if (isRate) {
|
|
25
|
+
return new LoopError({
|
|
26
|
+
code: "RATE_LIMIT",
|
|
27
|
+
phase: "engine",
|
|
28
|
+
message: `agent-sdk rate limited: ${message}`,
|
|
29
|
+
cause: error,
|
|
30
|
+
resetAt
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
return void 0;
|
|
34
|
+
}
|
|
35
|
+
var AgentSdkEngine = class {
|
|
36
|
+
constructor(opts = {}) {
|
|
37
|
+
this.opts = opts;
|
|
38
|
+
}
|
|
39
|
+
opts;
|
|
40
|
+
name = "agent-sdk";
|
|
41
|
+
async run(req, onEvent, signal) {
|
|
42
|
+
const { query } = await import('@anthropic-ai/claude-agent-sdk');
|
|
43
|
+
const acc = newAccumulator(
|
|
44
|
+
req.model ?? this.opts.defaultModel ?? "unknown"
|
|
45
|
+
);
|
|
46
|
+
const abort = new AbortController();
|
|
47
|
+
const onAbort = () => abort.abort();
|
|
48
|
+
if (signal.aborted) abort.abort();
|
|
49
|
+
else signal.addEventListener("abort", onAbort, { once: true });
|
|
50
|
+
const options = {
|
|
51
|
+
model: req.model ?? this.opts.defaultModel,
|
|
52
|
+
systemPrompt: req.system,
|
|
53
|
+
cwd: req.cwd,
|
|
54
|
+
allowedTools: req.allowedTools,
|
|
55
|
+
// A leaf agent may not spawn sub-agents — disallow the spawn tool.
|
|
56
|
+
disallowedTools: req.leaf ? SUBAGENT_TOOLS : void 0,
|
|
57
|
+
permissionMode: this.opts.permissionMode,
|
|
58
|
+
includePartialMessages: true,
|
|
59
|
+
abortController: abort
|
|
60
|
+
};
|
|
61
|
+
try {
|
|
62
|
+
const response = query({
|
|
63
|
+
prompt: req.prompt,
|
|
64
|
+
options
|
|
65
|
+
});
|
|
66
|
+
const consume = (async () => {
|
|
67
|
+
for await (const message of response) mapMessage(message, acc, onEvent);
|
|
68
|
+
})();
|
|
69
|
+
await (req.timeoutMs ? pTimeout(consume, { milliseconds: req.timeoutMs }) : consume);
|
|
70
|
+
} catch (e) {
|
|
71
|
+
if (signal.aborted)
|
|
72
|
+
throw new LoopError({
|
|
73
|
+
code: "ABORTED",
|
|
74
|
+
phase: "engine",
|
|
75
|
+
message: "agent-sdk run aborted"
|
|
76
|
+
});
|
|
77
|
+
const limit = classifySdkLimit(e);
|
|
78
|
+
if (limit) throw limit;
|
|
79
|
+
throw LoopError.from(e, { code: "ENGINE", phase: "engine" });
|
|
80
|
+
} finally {
|
|
81
|
+
signal.removeEventListener("abort", onAbort);
|
|
82
|
+
}
|
|
83
|
+
onEvent({ type: "usage", usage: acc.usage, model: acc.model });
|
|
84
|
+
return {
|
|
85
|
+
text: acc.text,
|
|
86
|
+
usage: acc.usage,
|
|
87
|
+
model: acc.model,
|
|
88
|
+
stopReason: acc.stopReason
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export { AgentSdkEngine };
|
|
94
|
+
//# sourceMappingURL=agent-sdk-RF5VJZAT.js.map
|
|
95
|
+
//# sourceMappingURL=agent-sdk-RF5VJZAT.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/engines/agent-sdk.ts"],"names":[],"mappings":"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","file":"agent-sdk-RF5VJZAT.js","sourcesContent":["/**\n * Engine adapter: the Claude Agent SDK (`@anthropic-ai/claude-agent-sdk`).\n * Each `run` is a fresh `query()` — a clean context per loop iteration, which\n * is the whole point. Uses the host's Claude Code auth, so it needs no API key.\n */\n\nimport pTimeout from 'p-timeout';\n\nimport {\n SUBAGENT_TOOLS,\n type AgentRequest,\n type AgentResult,\n type Engine,\n type EngineEventSink,\n type EngineOptions,\n} from './engine.ts';\nimport { mapMessage, newAccumulator } from './message-map.ts';\nimport { LoopError } from '../core/errors.ts';\n\n/**\n * Best-effort classification of an Agent SDK error into a provider-limit\n * `LoopError`, or `undefined` to fall through to the generic ENGINE mapping.\n * The SDK exposes limit state in a few shapes (a thrown error message, an\n * `error` field carrying an `SDKAssistantMessageError` string, and a\n * `rate_limit_info.resetsAt` epoch). We read defensively rather than depend on\n * an exact internal shape:\n * - a rate-limit / overloaded signal → RATE_LIMIT (resets on its own).\n * - a billing / usage / credits signal → QUOTA. A `resetsAt` (when present)\n * makes it auto-waitable; otherwise QUOTA has no reset.\n */\nfunction classifySdkLimit(error: unknown): LoopError | undefined {\n const err = (error ?? {}) as Record<string, unknown>;\n const tag = typeof err.error === 'string' ? err.error : '';\n const message = error instanceof Error ? error.message : String(error);\n const haystack = `${tag} ${message}`.toLowerCase();\n\n const info = (err.rate_limit_info ?? {}) as Record<string, unknown>;\n const resetAt =\n typeof info.resetsAt === 'number'\n ? info.resetsAt\n : typeof info.overageResetsAt === 'number'\n ? info.overageResetsAt\n : undefined;\n\n const isUsage =\n tag === 'billing_error' ||\n info.errorCode === 'credits_required' ||\n /billing|credit|usage limit|quota/.test(haystack);\n if (isUsage) {\n return new LoopError({\n code: 'QUOTA',\n phase: 'engine',\n message: `agent-sdk usage/billing limit: ${message}`,\n cause: error,\n resetAt,\n });\n }\n const isRate =\n tag === 'rate_limit' ||\n tag === 'overloaded' ||\n /rate limit|rate-limit|too many requests|overloaded/.test(haystack);\n if (isRate) {\n return new LoopError({\n code: 'RATE_LIMIT',\n phase: 'engine',\n message: `agent-sdk rate limited: ${message}`,\n cause: error,\n resetAt,\n });\n }\n return undefined;\n}\n\nexport class AgentSdkEngine implements Engine {\n readonly name = 'agent-sdk';\n constructor(private readonly opts: EngineOptions = {}) {}\n\n async run(\n req: AgentRequest,\n onEvent: EngineEventSink,\n signal: AbortSignal,\n ): Promise<AgentResult> {\n // Lazy import so installs/runs that never touch this engine don't pay for it.\n const { query } = await import('@anthropic-ai/claude-agent-sdk');\n\n const acc = newAccumulator(\n req.model ?? this.opts.defaultModel ?? 'unknown',\n );\n const abort = new AbortController();\n const onAbort = () => abort.abort();\n if (signal.aborted) abort.abort();\n else signal.addEventListener('abort', onAbort, { once: true });\n\n // The SDK option surface drifts across versions; cast at this boundary.\n const options = {\n model: req.model ?? this.opts.defaultModel,\n systemPrompt: req.system,\n cwd: req.cwd,\n allowedTools: req.allowedTools,\n // A leaf agent may not spawn sub-agents — disallow the spawn tool.\n disallowedTools: req.leaf ? SUBAGENT_TOOLS : undefined,\n permissionMode: this.opts.permissionMode,\n includePartialMessages: true,\n abortController: abort,\n } as Record<string, unknown>;\n\n try {\n const response = query({\n prompt: req.prompt,\n options,\n } as never) as AsyncIterable<unknown>;\n const consume = (async () => {\n for await (const message of response) mapMessage(message, acc, onEvent);\n })();\n await (req.timeoutMs\n ? pTimeout(consume, { milliseconds: req.timeoutMs })\n : consume);\n } catch (e) {\n if (signal.aborted)\n throw new LoopError({\n code: 'ABORTED',\n phase: 'engine',\n message: 'agent-sdk run aborted',\n });\n const limit = classifySdkLimit(e);\n if (limit) throw limit;\n throw LoopError.from(e, { code: 'ENGINE', phase: 'engine' });\n } finally {\n signal.removeEventListener('abort', onAbort);\n }\n\n onEvent({ type: 'usage', usage: acc.usage, model: acc.model });\n return {\n text: acc.text,\n usage: acc.usage,\n model: acc.model,\n stopReason: acc.stopReason,\n };\n }\n}\n"]}
|