@wrongstack/tui 0.63.4 → 0.68.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/dist/index.d.ts +1 -49
- package/dist/index.js +1107 -1251
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { Readable } from 'stream';
|
|
|
2
2
|
import { writeErr, InputBuilder, DefaultSessionRewinder, writeOut, formatTodosList, buildGoalPreamble, buildChildEnv } from '@wrongstack/core';
|
|
3
3
|
export { buildGoalPreamble } from '@wrongstack/core';
|
|
4
4
|
import { Box, Text, render, useApp, useStdout, measureElement, Static, useInput, useStdin } from 'ink';
|
|
5
|
-
import
|
|
5
|
+
import React6, { useState, useEffect, useReducer, useRef, useMemo, useCallback, useLayoutEffect } from 'react';
|
|
6
6
|
import * as fs2 from 'fs/promises';
|
|
7
7
|
import * as path2 from 'path';
|
|
8
8
|
import { routeImagesForModel } from '@wrongstack/runtime/vision';
|
|
@@ -1180,7 +1180,7 @@ function ConfirmPrompt({
|
|
|
1180
1180
|
suggestedPattern,
|
|
1181
1181
|
onDecision
|
|
1182
1182
|
}) {
|
|
1183
|
-
|
|
1183
|
+
React6.useEffect(() => {
|
|
1184
1184
|
writeOut("\x07");
|
|
1185
1185
|
}, []);
|
|
1186
1186
|
useInput((input2, _key) => {
|
|
@@ -1209,7 +1209,7 @@ function ConfirmPrompt({
|
|
|
1209
1209
|
inputSummary ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: inputSummary }) : null,
|
|
1210
1210
|
showDiff && diff ? /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginY: 1, children: renderDiff(diff) }) : null,
|
|
1211
1211
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }),
|
|
1212
|
-
/* @__PURE__ */ jsx(Box, { flexDirection: "row", children: /* @__PURE__ */ jsx(Text, { children: buttonLabels(suggestedPattern).map((l) => /* @__PURE__ */ jsxs(
|
|
1212
|
+
/* @__PURE__ */ jsx(Box, { flexDirection: "row", children: /* @__PURE__ */ jsx(Text, { children: buttonLabels(suggestedPattern).map((l) => /* @__PURE__ */ jsxs(React6.Fragment, { children: [
|
|
1213
1213
|
/* @__PURE__ */ jsx(Text, { bold: true, color: BUTTON_COLOR[l.decision], children: l.bracket }),
|
|
1214
1214
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: l.rest })
|
|
1215
1215
|
] }, l.decision)) }) })
|
|
@@ -2218,705 +2218,294 @@ function MarkdownView({
|
|
|
2218
2218
|
}
|
|
2219
2219
|
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: rows });
|
|
2220
2220
|
}
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
return
|
|
2221
|
+
function shortenPath(p, max) {
|
|
2222
|
+
if (p.length <= max) return p;
|
|
2223
|
+
return `\u2026${p.slice(p.length - (max - 1))}`;
|
|
2224
2224
|
}
|
|
2225
|
-
function
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
});
|
|
2231
|
-
useEffect(() => {
|
|
2232
|
-
const handleResize = () => {
|
|
2233
|
-
setTermSize({ columns: stdout?.columns ?? 80, rows: stdout?.rows ?? 24 });
|
|
2234
|
-
};
|
|
2235
|
-
process.stdout.on("resize", handleResize);
|
|
2236
|
-
return () => {
|
|
2237
|
-
process.stdout.off("resize", handleResize);
|
|
2238
|
-
};
|
|
2239
|
-
}, [stdout]);
|
|
2240
|
-
const termWidth = termSize.columns;
|
|
2241
|
-
const tail = streamingText ? tailForDisplay(streamingText, MAX_STREAM_DISPLAY_CHARS) : "";
|
|
2242
|
-
const toolTail = toolStream?.text ? tailForDisplay(toolStream.text, MAX_STREAM_DISPLAY_CHARS) : "";
|
|
2243
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2244
|
-
/* @__PURE__ */ jsx(Static, { items: entries, children: (entry) => /* @__PURE__ */ jsx(Box, { marginBottom: entry.kind === "turn-summary" ? 1 : 0, children: /* @__PURE__ */ jsx(Entry, { entry, termWidth }) }, entry.id) }),
|
|
2245
|
-
tail ? /* @__PURE__ */ jsx(AssistantTail, { text: tail }) : null,
|
|
2246
|
-
toolTail ? /* @__PURE__ */ jsx(
|
|
2247
|
-
ToolStreamBox,
|
|
2248
|
-
{
|
|
2249
|
-
name: toolStream.name,
|
|
2250
|
-
text: toolTail,
|
|
2251
|
-
startedAt: toolStream.startedAt,
|
|
2252
|
-
termWidth
|
|
2253
|
-
}
|
|
2254
|
-
) : null
|
|
2255
|
-
] });
|
|
2225
|
+
function fmtTok2(n) {
|
|
2226
|
+
if (!Number.isFinite(n) || n <= 0) return "0";
|
|
2227
|
+
if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
|
|
2228
|
+
if (n >= 1e3) return `${(n / 1e3).toFixed(n >= 1e4 ? 0 : 1)}k`;
|
|
2229
|
+
return String(n);
|
|
2256
2230
|
}
|
|
2257
|
-
function
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
marginY: 1,
|
|
2263
|
-
borderStyle: "single",
|
|
2264
|
-
borderTop: false,
|
|
2265
|
-
borderRight: false,
|
|
2266
|
-
borderBottom: false,
|
|
2267
|
-
borderColor: theme.assistant,
|
|
2268
|
-
paddingLeft: 1,
|
|
2269
|
-
children: [
|
|
2270
|
-
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", children: [
|
|
2271
|
-
/* @__PURE__ */ jsx(Text, { bold: true, color: theme.assistant, children: "ASSISTANT" }),
|
|
2272
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " (streaming\u2026)" })
|
|
2273
|
-
] }),
|
|
2274
|
-
/* @__PURE__ */ jsx(Text, { color: "white", children: text })
|
|
2275
|
-
]
|
|
2276
|
-
}
|
|
2277
|
-
);
|
|
2231
|
+
function fmtDuration(ms) {
|
|
2232
|
+
if (ms < 1e3) return `${ms}ms`;
|
|
2233
|
+
if (ms < 6e4) return `${(ms / 1e3).toFixed(1)}s`;
|
|
2234
|
+
const totalSec = Math.floor(ms / 1e3);
|
|
2235
|
+
return `${Math.floor(totalSec / 60)}m${totalSec % 60}s`;
|
|
2278
2236
|
}
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2237
|
+
function fmtBytes(n) {
|
|
2238
|
+
if (n < 1024) return `${n}B`;
|
|
2239
|
+
if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)}KB`;
|
|
2240
|
+
return `${(n / (1024 * 1024)).toFixed(1)}MB`;
|
|
2241
|
+
}
|
|
2242
|
+
function truncMid(s2, max) {
|
|
2243
|
+
if (s2.length <= max) return s2;
|
|
2244
|
+
return `${s2.slice(0, max - 1)}\u2026`;
|
|
2245
|
+
}
|
|
2246
|
+
function stringOf(v) {
|
|
2247
|
+
return typeof v === "string" && v.length > 0 ? v : void 0;
|
|
2248
|
+
}
|
|
2249
|
+
function numOf(v) {
|
|
2250
|
+
return typeof v === "number" && Number.isFinite(v) ? v : void 0;
|
|
2251
|
+
}
|
|
2252
|
+
function tryParseJson(s2) {
|
|
2253
|
+
const t = s2.trimStart();
|
|
2254
|
+
if (!t.startsWith("{") && !t.startsWith("[")) return void 0;
|
|
2255
|
+
try {
|
|
2256
|
+
return JSON.parse(s2);
|
|
2257
|
+
} catch {
|
|
2258
|
+
return void 0;
|
|
2259
|
+
}
|
|
2260
|
+
}
|
|
2261
|
+
function scanNumberedRange(text) {
|
|
2262
|
+
let first;
|
|
2263
|
+
let last;
|
|
2264
|
+
let count = 0;
|
|
2265
|
+
for (const line of text.split("\n")) {
|
|
2266
|
+
const m = line.match(/^\s*(\d+)→/);
|
|
2267
|
+
if (m?.[1]) {
|
|
2268
|
+
const n = Number.parseInt(m[1], 10);
|
|
2269
|
+
if (Number.isFinite(n)) {
|
|
2270
|
+
if (first === void 0) first = n;
|
|
2271
|
+
last = n;
|
|
2272
|
+
count++;
|
|
2303
2273
|
}
|
|
2304
|
-
continue;
|
|
2305
2274
|
}
|
|
2306
|
-
if (code !== null) code.push(line);
|
|
2307
|
-
else prose.push(line);
|
|
2308
2275
|
}
|
|
2309
|
-
|
|
2310
|
-
flushProse();
|
|
2311
|
-
return segs;
|
|
2276
|
+
return { first, last, count };
|
|
2312
2277
|
}
|
|
2313
|
-
function
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
contentWidth
|
|
2317
|
-
}) {
|
|
2318
|
-
let lines = code.replace(/\n+$/, "").split("\n");
|
|
2319
|
-
const hidden = Math.max(0, lines.length - MAX_CODE_LINES);
|
|
2320
|
-
if (hidden > 0) lines = lines.slice(0, MAX_CODE_LINES);
|
|
2321
|
-
const gutterW = String(lines.length).length;
|
|
2322
|
-
const maxW = Math.max(20, Math.min(contentWidth - 6 - gutterW - 1, 120));
|
|
2323
|
-
let carry = {};
|
|
2324
|
-
const rows = lines.map((raw) => {
|
|
2325
|
-
const display = raw.length > maxW ? `${raw.slice(0, maxW - 1)}\u2026` : raw;
|
|
2326
|
-
const r = highlightLine(display, lang, carry);
|
|
2327
|
-
carry = r.carry;
|
|
2328
|
-
return r.tokens;
|
|
2329
|
-
});
|
|
2330
|
-
return /* @__PURE__ */ jsxs(
|
|
2331
|
-
Box,
|
|
2332
|
-
{
|
|
2333
|
-
flexDirection: "column",
|
|
2334
|
-
marginLeft: 2,
|
|
2335
|
-
marginY: 0,
|
|
2336
|
-
borderStyle: "round",
|
|
2337
|
-
borderColor: theme.borderDefault,
|
|
2338
|
-
paddingX: 1,
|
|
2339
|
-
children: [
|
|
2340
|
-
lang !== "plain" ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: lang }) : null,
|
|
2341
|
-
rows.map((tokens, i) => (
|
|
2342
|
-
// biome-ignore lint/suspicious/noArrayIndexKey: code lines are positional
|
|
2343
|
-
/* @__PURE__ */ jsxs(Text, { children: [
|
|
2344
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: `${String(i + 1).padStart(gutterW, " ")} ` }),
|
|
2345
|
-
tokens.length === 0 ? " " : tokens.map((t, j) => (
|
|
2346
|
-
// biome-ignore lint/suspicious/noArrayIndexKey: token order is stable per line
|
|
2347
|
-
/* @__PURE__ */ jsx(Text, { color: t.color, dimColor: t.dim, bold: t.bold, children: t.text }, j)
|
|
2348
|
-
))
|
|
2349
|
-
] }, i)
|
|
2350
|
-
)),
|
|
2351
|
-
hidden > 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, italic: true, children: `\u2026 +${hidden} more line${hidden === 1 ? "" : "s"}` }) : null
|
|
2352
|
-
]
|
|
2353
|
-
}
|
|
2354
|
-
);
|
|
2278
|
+
function countLines(text) {
|
|
2279
|
+
if (!text) return 0;
|
|
2280
|
+
return text.replace(/\n$/, "").split("\n").length;
|
|
2355
2281
|
}
|
|
2356
|
-
function
|
|
2357
|
-
text
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
}) {
|
|
2361
|
-
const segments = splitFencedBlocks(text);
|
|
2362
|
-
const inner = contentWidth ?? termWidth;
|
|
2363
|
-
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: segments.map(
|
|
2364
|
-
(seg, i) => seg.type === "code" ? (
|
|
2365
|
-
// biome-ignore lint/suspicious/noArrayIndexKey: segment order is stable
|
|
2366
|
-
/* @__PURE__ */ jsx(CodeBlock, { code: seg.text, lang: seg.lang ?? "plain", contentWidth: inner }, i)
|
|
2367
|
-
) : (
|
|
2368
|
-
// biome-ignore lint/suspicious/noArrayIndexKey: segment order is stable
|
|
2369
|
-
/* @__PURE__ */ jsx(MarkdownView, { text: seg.text, termWidth: inner }, i)
|
|
2370
|
-
)
|
|
2371
|
-
) });
|
|
2282
|
+
function firstNonEmpty(text) {
|
|
2283
|
+
if (!text) return void 0;
|
|
2284
|
+
const line = text.split("\n").find((l) => l.trim());
|
|
2285
|
+
return line ? line.replace(/\s+/g, " ").trim() : void 0;
|
|
2372
2286
|
}
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
}, []);
|
|
2386
|
-
const elapsedMs = Date.now() - startedAt;
|
|
2387
|
-
const lines = text.split("\n");
|
|
2388
|
-
const totalLines = lines.length;
|
|
2389
|
-
const hidden = Math.max(0, totalLines - MAX_STREAM_LINES);
|
|
2390
|
-
const visible = hidden > 0 ? lines.slice(hidden) : lines;
|
|
2391
|
-
const contentWidth = Math.max(20, Math.min(termWidth - 4, 100));
|
|
2392
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 0, children: [
|
|
2393
|
-
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", children: [
|
|
2394
|
-
/* @__PURE__ */ jsx(Text, { color: theme.warn, children: "\u25C6 " }),
|
|
2395
|
-
/* @__PURE__ */ jsx(Text, { bold: true, color: theme.tool, children: name }),
|
|
2396
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u23F1 ${fmtDuration(elapsedMs)}` }),
|
|
2397
|
-
hidden > 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` (${totalLines} lines, showing last ${MAX_STREAM_LINES})` }) : null
|
|
2398
|
-
] }),
|
|
2399
|
-
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginLeft: 2, children: [
|
|
2400
|
-
hidden > 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, italic: true, children: ` \u2026 ${hidden} more line${hidden === 1 ? "" : "s"} above` }) : null,
|
|
2401
|
-
visible.map((line, i) => {
|
|
2402
|
-
const key = i;
|
|
2403
|
-
const trimmed = line.length > contentWidth ? `${line.slice(0, contentWidth - 1)}\u2026` : line;
|
|
2404
|
-
return /* @__PURE__ */ jsx(Text, { dimColor: true, children: trimmed || " " }, key);
|
|
2405
|
-
})
|
|
2406
|
-
] })
|
|
2407
|
-
] });
|
|
2408
|
-
});
|
|
2409
|
-
function tailForDisplay(text, maxChars) {
|
|
2410
|
-
if (text.length <= maxChars) return text;
|
|
2411
|
-
const cut = text.length - maxChars;
|
|
2412
|
-
const nl = text.indexOf("\n", cut);
|
|
2413
|
-
if (nl !== -1 && nl < cut + 80) {
|
|
2414
|
-
return `\u2026 ${text.slice(nl + 1)}`;
|
|
2287
|
+
function formatMatchHit(hit) {
|
|
2288
|
+
if (typeof hit === "string") return truncMid(hit, 70);
|
|
2289
|
+
if (hit && typeof hit === "object") {
|
|
2290
|
+
const o = hit;
|
|
2291
|
+
const file = stringOf(o["file"]) ?? stringOf(o["path"]);
|
|
2292
|
+
const line = numOf(o["line"]) ?? numOf(o["lineNumber"]);
|
|
2293
|
+
const snippet2 = stringOf(o["text"]) ?? stringOf(o["match"]) ?? stringOf(o["preview"]);
|
|
2294
|
+
if (file) {
|
|
2295
|
+
const head = line !== void 0 ? `${shortenPath(file, 40)}:${line}` : shortenPath(file, 50);
|
|
2296
|
+
return snippet2 ? `${head} ${truncMid(snippet2.replace(/\s+/g, " "), 40)}` : head;
|
|
2297
|
+
}
|
|
2298
|
+
if (snippet2) return truncMid(snippet2, 70);
|
|
2415
2299
|
}
|
|
2416
|
-
return
|
|
2300
|
+
return void 0;
|
|
2417
2301
|
}
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2302
|
+
var ARG_BUDGET = 60;
|
|
2303
|
+
function formatToolArgs(toolName, input) {
|
|
2304
|
+
if (!input || typeof input !== "object") return "";
|
|
2305
|
+
const obj = input;
|
|
2306
|
+
switch (toolName) {
|
|
2307
|
+
case "read":
|
|
2308
|
+
case "write":
|
|
2309
|
+
case "edit":
|
|
2310
|
+
case "patch":
|
|
2311
|
+
case "document":
|
|
2312
|
+
case "list_dir":
|
|
2313
|
+
case "ls":
|
|
2314
|
+
case "tree": {
|
|
2315
|
+
const p = stringOf(obj["path"]) ?? stringOf(obj["file"]);
|
|
2316
|
+
return p ? shortenPath(p, ARG_BUDGET) : "";
|
|
2425
2317
|
}
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
const
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
}
|
|
2434
|
-
|
|
2435
|
-
|
|
2318
|
+
case "grep":
|
|
2319
|
+
case "search":
|
|
2320
|
+
case "replace": {
|
|
2321
|
+
const pat = stringOf(obj["pattern"]) ?? stringOf(obj["query"]);
|
|
2322
|
+
const scope = stringOf(obj["path"]) ?? stringOf(obj["glob"]);
|
|
2323
|
+
const head = pat ? `"${truncMid(pat, 36)}"` : "";
|
|
2324
|
+
const tail = scope ? ` in ${shortenPath(scope, 28)}` : "";
|
|
2325
|
+
return `${head}${tail}` || (stringOf(obj["command"]) ?? "");
|
|
2326
|
+
}
|
|
2327
|
+
case "glob": {
|
|
2328
|
+
const pat = stringOf(obj["pattern"]) ?? stringOf(obj["glob"]);
|
|
2329
|
+
return pat ? `"${truncMid(pat, ARG_BUDGET - 2)}"` : "";
|
|
2330
|
+
}
|
|
2331
|
+
case "bash":
|
|
2332
|
+
case "shell":
|
|
2333
|
+
case "exec":
|
|
2334
|
+
case "install":
|
|
2335
|
+
case "git": {
|
|
2336
|
+
const cmd = stringOf(obj["command"]) ?? stringOf(obj["args"]);
|
|
2337
|
+
return cmd ? truncMid(cmd, ARG_BUDGET) : "";
|
|
2338
|
+
}
|
|
2339
|
+
case "diff": {
|
|
2340
|
+
const files = Array.isArray(obj["files"]) ? obj["files"] : void 0;
|
|
2341
|
+
if (files && files.length > 0) {
|
|
2342
|
+
const head = stringOf(files[0]) ?? "";
|
|
2343
|
+
const rest = files.length > 1 ? ` (+${files.length - 1})` : "";
|
|
2344
|
+
return head ? `${shortenPath(head, 50)}${rest}` : "";
|
|
2436
2345
|
}
|
|
2437
|
-
const
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2346
|
+
const mode = stringOf(obj["mode"]);
|
|
2347
|
+
return mode ? `mode: ${mode}` : "";
|
|
2348
|
+
}
|
|
2349
|
+
case "fetch":
|
|
2350
|
+
case "webfetch":
|
|
2351
|
+
case "web_fetch": {
|
|
2352
|
+
const u = stringOf(obj["url"]);
|
|
2353
|
+
return u ? truncMid(u, ARG_BUDGET) : "";
|
|
2354
|
+
}
|
|
2355
|
+
case "todo": {
|
|
2356
|
+
const list = obj["todos"];
|
|
2357
|
+
if (Array.isArray(list)) return `${list.length} item${list.length === 1 ? "" : "s"}`;
|
|
2358
|
+
return "";
|
|
2359
|
+
}
|
|
2360
|
+
case "lint":
|
|
2361
|
+
case "format":
|
|
2362
|
+
case "typecheck":
|
|
2363
|
+
case "test":
|
|
2364
|
+
case "audit":
|
|
2365
|
+
case "outdated": {
|
|
2366
|
+
const files = obj["files"];
|
|
2367
|
+
if (Array.isArray(files) && files.length > 0) {
|
|
2368
|
+
const first = stringOf(files[0]);
|
|
2369
|
+
const more = files.length > 1 ? ` (+${files.length - 1})` : "";
|
|
2370
|
+
return first ? `${shortenPath(first, 50)}${more}` : `${files.length} files`;
|
|
2441
2371
|
}
|
|
2442
|
-
const
|
|
2443
|
-
return
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
}
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
return {
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
case "
|
|
2458
|
-
|
|
2459
|
-
case "
|
|
2460
|
-
|
|
2372
|
+
const filter = stringOf(obj["filter"]) ?? stringOf(obj["pattern"]);
|
|
2373
|
+
return filter ? `"${truncMid(filter, ARG_BUDGET - 2)}"` : "";
|
|
2374
|
+
}
|
|
2375
|
+
case "json": {
|
|
2376
|
+
const file = stringOf(obj["file"]);
|
|
2377
|
+
const q = stringOf(obj["query"]);
|
|
2378
|
+
if (file) return q ? `${shortenPath(file, 40)} ${q}` : shortenPath(file, ARG_BUDGET);
|
|
2379
|
+
return q ? truncMid(q, ARG_BUDGET) : "";
|
|
2380
|
+
}
|
|
2381
|
+
case "scaffold": {
|
|
2382
|
+
const tmpl = stringOf(obj["template"]) ?? stringOf(obj["type"]);
|
|
2383
|
+
const name = stringOf(obj["name"]);
|
|
2384
|
+
if (tmpl && name) return `${tmpl} \u2192 ${truncMid(name, ARG_BUDGET - tmpl.length - 4)}`;
|
|
2385
|
+
return name ?? tmpl ?? "";
|
|
2386
|
+
}
|
|
2387
|
+
case "remember":
|
|
2388
|
+
case "forget":
|
|
2389
|
+
case "memory": {
|
|
2390
|
+
const key = stringOf(obj["key"]) ?? stringOf(obj["name"]);
|
|
2391
|
+
return key ? truncMid(key, ARG_BUDGET) : "";
|
|
2392
|
+
}
|
|
2393
|
+
case "mode": {
|
|
2394
|
+
const m = stringOf(obj["mode"]) ?? stringOf(obj["name"]);
|
|
2395
|
+
return m ? truncMid(m, ARG_BUDGET) : "";
|
|
2396
|
+
}
|
|
2397
|
+
case "logs": {
|
|
2398
|
+
const target = stringOf(obj["target"]) ?? stringOf(obj["service"]) ?? stringOf(obj["path"]);
|
|
2399
|
+
return target ? truncMid(target, ARG_BUDGET) : "";
|
|
2400
|
+
}
|
|
2401
|
+
}
|
|
2402
|
+
for (const key of ["path", "file", "url", "name", "query", "pattern", "command"]) {
|
|
2403
|
+
const v = stringOf(obj[key]);
|
|
2404
|
+
if (v) return truncMid(v, ARG_BUDGET);
|
|
2405
|
+
}
|
|
2406
|
+
try {
|
|
2407
|
+
return truncMid(JSON.stringify(obj), ARG_BUDGET);
|
|
2408
|
+
} catch {
|
|
2409
|
+
return "";
|
|
2461
2410
|
}
|
|
2462
2411
|
}
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2412
|
+
var OUT_BUDGET = 80;
|
|
2413
|
+
var GENERIC_BUDGET = 240;
|
|
2414
|
+
function summarizeJsonObject(obj) {
|
|
2415
|
+
const keys = Object.keys(obj);
|
|
2416
|
+
if (keys.length === 0) return null;
|
|
2417
|
+
const priority = [
|
|
2418
|
+
"ok",
|
|
2419
|
+
"status",
|
|
2420
|
+
"timedOut",
|
|
2421
|
+
"stopReason",
|
|
2422
|
+
"reason",
|
|
2423
|
+
"error",
|
|
2424
|
+
"message",
|
|
2425
|
+
"result",
|
|
2426
|
+
"summary",
|
|
2427
|
+
"iterations",
|
|
2428
|
+
"toolCalls",
|
|
2429
|
+
"durationMs",
|
|
2430
|
+
"subagentId",
|
|
2431
|
+
"taskId"
|
|
2432
|
+
];
|
|
2433
|
+
const ordered = [
|
|
2434
|
+
...priority.filter((k) => keys.includes(k)),
|
|
2435
|
+
...keys.filter((k) => !priority.includes(k))
|
|
2436
|
+
];
|
|
2437
|
+
const parts = [];
|
|
2438
|
+
let used = 0;
|
|
2439
|
+
for (const key of ordered) {
|
|
2440
|
+
const v = obj[key];
|
|
2441
|
+
if (v === void 0 || v === null) continue;
|
|
2442
|
+
const rendered = typeof v === "string" ? `${key}="${truncMid(v.replace(/\s+/g, " "), 80)}"` : typeof v === "number" || typeof v === "boolean" ? `${key}=${v}` : Array.isArray(v) ? `${key}=[${v.length}]` : `${key}={\u2026}`;
|
|
2443
|
+
if (used + rendered.length > GENERIC_BUDGET) {
|
|
2444
|
+
parts.push("\u2026");
|
|
2445
|
+
break;
|
|
2446
|
+
}
|
|
2447
|
+
parts.push(rendered);
|
|
2448
|
+
used += rendered.length + 3;
|
|
2473
2449
|
}
|
|
2450
|
+
return parts.length > 0 ? parts.join(" \xB7 ") : null;
|
|
2474
2451
|
}
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
);
|
|
2504
|
-
case "assistant": {
|
|
2505
|
-
const contentWidth = assistantContentWidth(termWidth);
|
|
2506
|
-
return /* @__PURE__ */ jsxs(
|
|
2507
|
-
Box,
|
|
2508
|
-
{
|
|
2509
|
-
flexDirection: "column",
|
|
2510
|
-
marginY: 1,
|
|
2511
|
-
borderStyle: "single",
|
|
2512
|
-
borderTop: false,
|
|
2513
|
-
borderRight: false,
|
|
2514
|
-
borderBottom: false,
|
|
2515
|
-
borderColor: theme.assistant,
|
|
2516
|
-
paddingLeft: 1,
|
|
2517
|
-
children: [
|
|
2518
|
-
/* @__PURE__ */ jsx(Box, { flexDirection: "row", children: /* @__PURE__ */ jsx(Text, { bold: true, color: theme.assistant, children: "ASSISTANT" }) }),
|
|
2519
|
-
/* @__PURE__ */ jsx(AssistantBody, { text: entry.text, termWidth, contentWidth })
|
|
2520
|
-
]
|
|
2521
|
-
}
|
|
2522
|
-
);
|
|
2452
|
+
function formatToolOutput(toolName, output, ok, _outputBytes, outputLines) {
|
|
2453
|
+
if (!output) return ok ? [] : ["failed"];
|
|
2454
|
+
const text = output.trim();
|
|
2455
|
+
if (!text) return ok ? [] : ["failed"];
|
|
2456
|
+
const json = tryParseJson(text);
|
|
2457
|
+
if (toolName === "write" && json && typeof json === "object") {
|
|
2458
|
+
const o = json;
|
|
2459
|
+
const bytes = numOf(o["bytes_written"]) ?? numOf(o["bytes"]);
|
|
2460
|
+
const created = o["created"] === true;
|
|
2461
|
+
const tag = created ? "created" : "updated";
|
|
2462
|
+
return bytes !== void 0 ? [`${tag} \xB7 ${fmtBytes(bytes)}`] : [tag];
|
|
2463
|
+
}
|
|
2464
|
+
if (toolName === "edit" && json && typeof json === "object") {
|
|
2465
|
+
const o = json;
|
|
2466
|
+
const reps = numOf(o["replacements"]);
|
|
2467
|
+
if (reps !== void 0) return [`${reps} replacement${reps === 1 ? "" : "s"}`];
|
|
2468
|
+
}
|
|
2469
|
+
if (toolName === "patch" && json && typeof json === "object") {
|
|
2470
|
+
const o = json;
|
|
2471
|
+
const applied = numOf(o["applied"]);
|
|
2472
|
+
const rejected = numOf(o["rejected"]);
|
|
2473
|
+
const files = Array.isArray(o["files"]) ? o["files"] : void 0;
|
|
2474
|
+
const lines = [];
|
|
2475
|
+
if (applied !== void 0 || rejected !== void 0) {
|
|
2476
|
+
const parts = [];
|
|
2477
|
+
if (applied !== void 0) parts.push(`${applied} applied`);
|
|
2478
|
+
if (rejected !== void 0 && rejected > 0) parts.push(`${rejected} rejected`);
|
|
2479
|
+
lines.push(parts.join(" \xB7 "));
|
|
2523
2480
|
}
|
|
2524
|
-
|
|
2525
|
-
const
|
|
2526
|
-
const
|
|
2527
|
-
|
|
2528
|
-
entry.output,
|
|
2529
|
-
entry.ok,
|
|
2530
|
-
entry.outputBytes,
|
|
2531
|
-
entry.outputLines
|
|
2532
|
-
);
|
|
2533
|
-
const diff = entry.ok ? extractDiffPreview(entry.name, entry.output) : void 0;
|
|
2534
|
-
const sizeChip = (() => {
|
|
2535
|
-
if (!entry.ok) return "";
|
|
2536
|
-
const parts = [];
|
|
2537
|
-
if (entry.outputLines !== void 0 && entry.outputLines > 0) {
|
|
2538
|
-
parts.push(`${entry.outputLines} L`);
|
|
2539
|
-
}
|
|
2540
|
-
if (entry.outputBytes && entry.outputBytes > 0) {
|
|
2541
|
-
parts.push(fmtBytes(entry.outputBytes));
|
|
2542
|
-
}
|
|
2543
|
-
if (entry.outputTokens && entry.outputTokens > 0) {
|
|
2544
|
-
parts.push(`\u2248${fmtTok2(entry.outputTokens)} tok`);
|
|
2545
|
-
}
|
|
2546
|
-
return parts.join(" \xB7 ");
|
|
2547
|
-
})();
|
|
2548
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
2549
|
-
/* @__PURE__ */ jsxs(Text, { children: [
|
|
2550
|
-
/* @__PURE__ */ jsx(Text, { color: entry.ok ? theme.success : theme.error, children: entry.ok ? "\u25CF" : "\u2717" }),
|
|
2551
|
-
" ",
|
|
2552
|
-
/* @__PURE__ */ jsx(Text, { bold: true, color: theme.tool, children: entry.name }),
|
|
2553
|
-
argSummary ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2554
|
-
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
2555
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: argSummary })
|
|
2556
|
-
] }) : null,
|
|
2557
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \xB7 ${fmtDuration(entry.durationMs)}` }),
|
|
2558
|
-
sizeChip ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \xB7 ${sizeChip}` }) : null
|
|
2559
|
-
] }),
|
|
2560
|
-
outLines.map((line, i) => (
|
|
2561
|
-
// biome-ignore lint/suspicious/noArrayIndexKey: tool output lines are static, index is stable
|
|
2562
|
-
/* @__PURE__ */ jsxs(Text, { children: [
|
|
2563
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: i === outLines.length - 1 && !diff ? " \u2514\u2500 " : " \u251C\u2500 " }),
|
|
2564
|
-
/* @__PURE__ */ jsx(
|
|
2565
|
-
Text,
|
|
2566
|
-
{
|
|
2567
|
-
color: !entry.ok || line.startsWith("!") ? "red" : void 0,
|
|
2568
|
-
dimColor: entry.ok && !line.startsWith("!"),
|
|
2569
|
-
children: line
|
|
2570
|
-
}
|
|
2571
|
-
)
|
|
2572
|
-
] }, i)
|
|
2573
|
-
)),
|
|
2574
|
-
diff ? /* @__PURE__ */ jsx(DiffBlock, { rows: diff.rows, hidden: diff.hidden }) : null
|
|
2575
|
-
] });
|
|
2576
|
-
}
|
|
2577
|
-
case "info":
|
|
2578
|
-
return /* @__PURE__ */ jsx(Text, { dimColor: true, children: entry.text });
|
|
2579
|
-
case "warn":
|
|
2580
|
-
return /* @__PURE__ */ jsx(
|
|
2581
|
-
Box,
|
|
2582
|
-
{
|
|
2583
|
-
borderStyle: "single",
|
|
2584
|
-
borderTop: false,
|
|
2585
|
-
borderRight: false,
|
|
2586
|
-
borderBottom: false,
|
|
2587
|
-
borderColor: theme.warn,
|
|
2588
|
-
paddingLeft: 1,
|
|
2589
|
-
children: /* @__PURE__ */ jsx(Text, { color: theme.warn, children: entry.text })
|
|
2590
|
-
}
|
|
2591
|
-
);
|
|
2592
|
-
case "error":
|
|
2593
|
-
return /* @__PURE__ */ jsx(
|
|
2594
|
-
Box,
|
|
2595
|
-
{
|
|
2596
|
-
borderStyle: "single",
|
|
2597
|
-
borderTop: false,
|
|
2598
|
-
borderRight: false,
|
|
2599
|
-
borderBottom: false,
|
|
2600
|
-
borderColor: theme.error,
|
|
2601
|
-
paddingLeft: 1,
|
|
2602
|
-
children: /* @__PURE__ */ jsx(Text, { color: theme.error, children: entry.text })
|
|
2603
|
-
}
|
|
2604
|
-
);
|
|
2605
|
-
case "turn-summary":
|
|
2606
|
-
return /* @__PURE__ */ jsx(Text, { dimColor: true, children: entry.text });
|
|
2607
|
-
case "brain": {
|
|
2608
|
-
const statusStyle = brainStatusStyle(entry.status);
|
|
2609
|
-
const riskColor2 = brainRiskColor(entry.risk);
|
|
2610
|
-
return /* @__PURE__ */ jsxs(
|
|
2611
|
-
Box,
|
|
2612
|
-
{
|
|
2613
|
-
flexDirection: "column",
|
|
2614
|
-
marginY: 1,
|
|
2615
|
-
borderStyle: "single",
|
|
2616
|
-
borderTop: false,
|
|
2617
|
-
borderRight: false,
|
|
2618
|
-
borderBottom: false,
|
|
2619
|
-
borderColor: "magenta",
|
|
2620
|
-
paddingLeft: 1,
|
|
2621
|
-
children: [
|
|
2622
|
-
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
2623
|
-
/* @__PURE__ */ jsx(Text, { bold: true, color: "magenta", children: "BRAIN" }),
|
|
2624
|
-
/* @__PURE__ */ jsx(Text, { color: statusStyle.color, children: statusStyle.icon }),
|
|
2625
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: entry.source }),
|
|
2626
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7" }),
|
|
2627
|
-
/* @__PURE__ */ jsx(Text, { color: riskColor2, children: entry.risk })
|
|
2628
|
-
] }),
|
|
2629
|
-
/* @__PURE__ */ jsx(Text, { color: "white", children: entry.question }),
|
|
2630
|
-
entry.decision ? /* @__PURE__ */ jsxs(Text, { children: [
|
|
2631
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Decision: " }),
|
|
2632
|
-
/* @__PURE__ */ jsx(Text, { color: statusStyle.color, children: entry.decision })
|
|
2633
|
-
] }) : null,
|
|
2634
|
-
entry.rationale ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: entry.rationale }) : null
|
|
2635
|
-
]
|
|
2636
|
-
}
|
|
2637
|
-
);
|
|
2638
|
-
}
|
|
2639
|
-
case "confirm":
|
|
2640
|
-
return /* @__PURE__ */ jsxs(
|
|
2641
|
-
Box,
|
|
2642
|
-
{
|
|
2643
|
-
flexDirection: "column",
|
|
2644
|
-
borderStyle: "round",
|
|
2645
|
-
borderColor: "yellow",
|
|
2646
|
-
paddingX: 1,
|
|
2647
|
-
marginY: 1,
|
|
2648
|
-
children: [
|
|
2649
|
-
/* @__PURE__ */ jsxs(Text, { bold: true, color: "yellow", children: [
|
|
2650
|
-
"\u26A0 Confirm: ",
|
|
2651
|
-
entry.toolName
|
|
2652
|
-
] }),
|
|
2653
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Waiting for y / n / a / d..." })
|
|
2654
|
-
]
|
|
2655
|
-
}
|
|
2656
|
-
);
|
|
2657
|
-
case "banner":
|
|
2658
|
-
return /* @__PURE__ */ jsx(Banner, { entry });
|
|
2659
|
-
case "subagent": {
|
|
2660
|
-
const lines = entry.text.split("\n");
|
|
2661
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
2662
|
-
/* @__PURE__ */ jsxs(Text, { children: [
|
|
2663
|
-
/* @__PURE__ */ jsx(Text, { color: entry.agentColor, bold: true, children: `[${entry.agentLabel}]` }),
|
|
2664
|
-
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
2665
|
-
/* @__PURE__ */ jsx(Text, { color: entry.agentColor, children: entry.icon }),
|
|
2666
|
-
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
2667
|
-
/* @__PURE__ */ jsx(Text, { children: lines[0] ?? "" }),
|
|
2668
|
-
entry.detail ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2669
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " \xB7 " }),
|
|
2670
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: entry.detail })
|
|
2671
|
-
] }) : null
|
|
2672
|
-
] }),
|
|
2673
|
-
lines.slice(1).map((line, i) => (
|
|
2674
|
-
// biome-ignore lint/suspicious/noArrayIndexKey: stable line index
|
|
2675
|
-
/* @__PURE__ */ jsxs(Text, { children: [
|
|
2676
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " " }),
|
|
2677
|
-
/* @__PURE__ */ jsx(Text, { children: line })
|
|
2678
|
-
] }, i)
|
|
2679
|
-
))
|
|
2680
|
-
] });
|
|
2681
|
-
}
|
|
2682
|
-
}
|
|
2683
|
-
});
|
|
2684
|
-
function Banner({
|
|
2685
|
-
entry
|
|
2686
|
-
}) {
|
|
2687
|
-
const cwdShort = shortenPath(entry.cwd, 48);
|
|
2688
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "magenta", paddingX: 2, paddingY: 0, children: [
|
|
2689
|
-
/* @__PURE__ */ jsxs(Text, { children: [
|
|
2690
|
-
/* @__PURE__ */ jsx(Text, { color: "magenta", bold: true, children: " \u259F\u259B " }),
|
|
2691
|
-
/* @__PURE__ */ jsx(Text, { color: "magenta", bold: true, children: "WrongStack" }),
|
|
2692
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " v" }),
|
|
2693
|
-
/* @__PURE__ */ jsx(Text, { children: entry.version })
|
|
2694
|
-
] }),
|
|
2695
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, italic: true, children: " Built on the wrong stack. Shipped anyway." }),
|
|
2696
|
-
/* @__PURE__ */ jsxs(Text, { children: [
|
|
2697
|
-
/* @__PURE__ */ jsx(Text, { color: "cyan", children: " provider " }),
|
|
2698
|
-
/* @__PURE__ */ jsxs(Text, { children: [
|
|
2699
|
-
entry.provider,
|
|
2700
|
-
"/",
|
|
2701
|
-
entry.model
|
|
2702
|
-
] })
|
|
2703
|
-
] }),
|
|
2704
|
-
entry.family ? /* @__PURE__ */ jsxs(Text, { children: [
|
|
2705
|
-
/* @__PURE__ */ jsx(Text, { color: "cyan", children: " family " }),
|
|
2706
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: entry.family })
|
|
2707
|
-
] }) : null,
|
|
2708
|
-
entry.keyTail ? /* @__PURE__ */ jsxs(Text, { children: [
|
|
2709
|
-
/* @__PURE__ */ jsx(Text, { color: "cyan", children: " key " }),
|
|
2710
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u25CF\u25CF\u25CF\u2026" }),
|
|
2711
|
-
/* @__PURE__ */ jsx(Text, { children: entry.keyTail })
|
|
2712
|
-
] }) : null,
|
|
2713
|
-
/* @__PURE__ */ jsxs(Text, { children: [
|
|
2714
|
-
/* @__PURE__ */ jsx(Text, { color: "cyan", children: " cwd " }),
|
|
2715
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: cwdShort })
|
|
2716
|
-
] }),
|
|
2717
|
-
/* @__PURE__ */ jsxs(Text, { children: [
|
|
2718
|
-
/* @__PURE__ */ jsx(Text, { color: "cyan", children: " hints " }),
|
|
2719
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "/help \xB7 /init \xB7 /memory \xB7 /queue \xB7 /exit" })
|
|
2720
|
-
] })
|
|
2721
|
-
] });
|
|
2722
|
-
}
|
|
2723
|
-
function shortenPath(p, max) {
|
|
2724
|
-
if (p.length <= max) return p;
|
|
2725
|
-
return `\u2026${p.slice(p.length - (max - 1))}`;
|
|
2726
|
-
}
|
|
2727
|
-
function fmtTok2(n) {
|
|
2728
|
-
if (!Number.isFinite(n) || n <= 0) return "0";
|
|
2729
|
-
if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
|
|
2730
|
-
if (n >= 1e3) return `${(n / 1e3).toFixed(n >= 1e4 ? 0 : 1)}k`;
|
|
2731
|
-
return String(n);
|
|
2732
|
-
}
|
|
2733
|
-
function fmtDuration(ms) {
|
|
2734
|
-
if (ms < 1e3) return `${ms}ms`;
|
|
2735
|
-
if (ms < 6e4) return `${(ms / 1e3).toFixed(1)}s`;
|
|
2736
|
-
const totalSec = Math.floor(ms / 1e3);
|
|
2737
|
-
return `${Math.floor(totalSec / 60)}m${totalSec % 60}s`;
|
|
2738
|
-
}
|
|
2739
|
-
var ARG_BUDGET = 60;
|
|
2740
|
-
var OUT_BUDGET = 80;
|
|
2741
|
-
function formatToolArgs(toolName, input) {
|
|
2742
|
-
if (!input || typeof input !== "object") return "";
|
|
2743
|
-
const obj = input;
|
|
2744
|
-
switch (toolName) {
|
|
2745
|
-
case "read":
|
|
2746
|
-
case "write":
|
|
2747
|
-
case "edit":
|
|
2748
|
-
case "patch":
|
|
2749
|
-
case "document":
|
|
2750
|
-
case "list_dir":
|
|
2751
|
-
case "ls":
|
|
2752
|
-
case "tree": {
|
|
2753
|
-
const p = stringOf(obj["path"]) ?? stringOf(obj["file"]);
|
|
2754
|
-
return p ? shortenPath(p, ARG_BUDGET) : "";
|
|
2755
|
-
}
|
|
2756
|
-
case "grep":
|
|
2757
|
-
case "search":
|
|
2758
|
-
case "replace": {
|
|
2759
|
-
const pat = stringOf(obj["pattern"]) ?? stringOf(obj["query"]);
|
|
2760
|
-
const scope = stringOf(obj["path"]) ?? stringOf(obj["glob"]);
|
|
2761
|
-
const head = pat ? `"${truncMid(pat, 36)}"` : "";
|
|
2762
|
-
const tail = scope ? ` in ${shortenPath(scope, 28)}` : "";
|
|
2763
|
-
return `${head}${tail}` || (stringOf(obj["command"]) ?? "");
|
|
2764
|
-
}
|
|
2765
|
-
case "glob": {
|
|
2766
|
-
const pat = stringOf(obj["pattern"]) ?? stringOf(obj["glob"]);
|
|
2767
|
-
return pat ? `"${truncMid(pat, ARG_BUDGET - 2)}"` : "";
|
|
2768
|
-
}
|
|
2769
|
-
case "bash":
|
|
2770
|
-
case "shell":
|
|
2771
|
-
case "exec":
|
|
2772
|
-
case "install":
|
|
2773
|
-
case "git": {
|
|
2774
|
-
const cmd = stringOf(obj["command"]) ?? stringOf(obj["args"]);
|
|
2775
|
-
return cmd ? truncMid(cmd, ARG_BUDGET) : "";
|
|
2776
|
-
}
|
|
2777
|
-
case "diff": {
|
|
2778
|
-
const files = Array.isArray(obj["files"]) ? obj["files"] : void 0;
|
|
2779
|
-
if (files && files.length > 0) {
|
|
2780
|
-
const head = stringOf(files[0]) ?? "";
|
|
2781
|
-
const rest = files.length > 1 ? ` (+${files.length - 1})` : "";
|
|
2782
|
-
return head ? `${shortenPath(head, 50)}${rest}` : "";
|
|
2783
|
-
}
|
|
2784
|
-
const mode = stringOf(obj["mode"]);
|
|
2785
|
-
return mode ? `mode: ${mode}` : "";
|
|
2786
|
-
}
|
|
2787
|
-
case "fetch":
|
|
2788
|
-
case "webfetch":
|
|
2789
|
-
case "web_fetch": {
|
|
2790
|
-
const u = stringOf(obj["url"]);
|
|
2791
|
-
return u ? truncMid(u, ARG_BUDGET) : "";
|
|
2792
|
-
}
|
|
2793
|
-
case "todo": {
|
|
2794
|
-
const list = obj["todos"];
|
|
2795
|
-
if (Array.isArray(list)) return `${list.length} item${list.length === 1 ? "" : "s"}`;
|
|
2796
|
-
return "";
|
|
2797
|
-
}
|
|
2798
|
-
case "lint":
|
|
2799
|
-
case "format":
|
|
2800
|
-
case "typecheck":
|
|
2801
|
-
case "test":
|
|
2802
|
-
case "audit":
|
|
2803
|
-
case "outdated": {
|
|
2804
|
-
const files = obj["files"];
|
|
2805
|
-
if (Array.isArray(files) && files.length > 0) {
|
|
2806
|
-
const first = stringOf(files[0]);
|
|
2807
|
-
const more = files.length > 1 ? ` (+${files.length - 1})` : "";
|
|
2808
|
-
return first ? `${shortenPath(first, 50)}${more}` : `${files.length} files`;
|
|
2809
|
-
}
|
|
2810
|
-
const filter = stringOf(obj["filter"]) ?? stringOf(obj["pattern"]);
|
|
2811
|
-
return filter ? `"${truncMid(filter, ARG_BUDGET - 2)}"` : "";
|
|
2812
|
-
}
|
|
2813
|
-
case "json": {
|
|
2814
|
-
const file = stringOf(obj["file"]);
|
|
2815
|
-
const q = stringOf(obj["query"]);
|
|
2816
|
-
if (file) return q ? `${shortenPath(file, 40)} ${q}` : shortenPath(file, ARG_BUDGET);
|
|
2817
|
-
return q ? truncMid(q, ARG_BUDGET) : "";
|
|
2818
|
-
}
|
|
2819
|
-
case "scaffold": {
|
|
2820
|
-
const tmpl = stringOf(obj["template"]) ?? stringOf(obj["type"]);
|
|
2821
|
-
const name = stringOf(obj["name"]);
|
|
2822
|
-
if (tmpl && name) return `${tmpl} \u2192 ${truncMid(name, ARG_BUDGET - tmpl.length - 4)}`;
|
|
2823
|
-
return name ?? tmpl ?? "";
|
|
2824
|
-
}
|
|
2825
|
-
case "remember":
|
|
2826
|
-
case "forget":
|
|
2827
|
-
case "memory": {
|
|
2828
|
-
const key = stringOf(obj["key"]) ?? stringOf(obj["name"]);
|
|
2829
|
-
return key ? truncMid(key, ARG_BUDGET) : "";
|
|
2830
|
-
}
|
|
2831
|
-
case "mode": {
|
|
2832
|
-
const m = stringOf(obj["mode"]) ?? stringOf(obj["name"]);
|
|
2833
|
-
return m ? truncMid(m, ARG_BUDGET) : "";
|
|
2834
|
-
}
|
|
2835
|
-
case "logs": {
|
|
2836
|
-
const target = stringOf(obj["target"]) ?? stringOf(obj["service"]) ?? stringOf(obj["path"]);
|
|
2837
|
-
return target ? truncMid(target, ARG_BUDGET) : "";
|
|
2838
|
-
}
|
|
2839
|
-
}
|
|
2840
|
-
for (const key of ["path", "file", "url", "name", "query", "pattern", "command"]) {
|
|
2841
|
-
const v = stringOf(obj[key]);
|
|
2842
|
-
if (v) return truncMid(v, ARG_BUDGET);
|
|
2843
|
-
}
|
|
2844
|
-
try {
|
|
2845
|
-
return truncMid(JSON.stringify(obj), ARG_BUDGET);
|
|
2846
|
-
} catch {
|
|
2847
|
-
return "";
|
|
2848
|
-
}
|
|
2849
|
-
}
|
|
2850
|
-
function formatToolOutput(toolName, output, ok, _outputBytes, outputLines) {
|
|
2851
|
-
if (!output) return ok ? [] : ["failed"];
|
|
2852
|
-
const text = output.trim();
|
|
2853
|
-
if (!text) return ok ? [] : ["failed"];
|
|
2854
|
-
const json = tryParseJson(text);
|
|
2855
|
-
if (toolName === "write") {
|
|
2856
|
-
if (json && typeof json === "object") {
|
|
2857
|
-
const o = json;
|
|
2858
|
-
const bytes = numOf(o["bytes_written"]) ?? numOf(o["bytes"]);
|
|
2859
|
-
const created = o["created"] === true;
|
|
2860
|
-
const tag = created ? "created" : "updated";
|
|
2861
|
-
if (bytes !== void 0) return [`${tag} \xB7 ${fmtBytes(bytes)}`];
|
|
2862
|
-
return [tag];
|
|
2863
|
-
}
|
|
2864
|
-
}
|
|
2865
|
-
if (toolName === "edit") {
|
|
2866
|
-
if (json && typeof json === "object") {
|
|
2867
|
-
const o = json;
|
|
2868
|
-
const reps = numOf(o["replacements"]);
|
|
2869
|
-
if (reps !== void 0) return [`${reps} replacement${reps === 1 ? "" : "s"}`];
|
|
2870
|
-
}
|
|
2871
|
-
}
|
|
2872
|
-
if (toolName === "patch") {
|
|
2873
|
-
if (json && typeof json === "object") {
|
|
2874
|
-
const o = json;
|
|
2875
|
-
const applied = numOf(o["applied"]);
|
|
2876
|
-
const rejected = numOf(o["rejected"]);
|
|
2877
|
-
const files = Array.isArray(o["files"]) ? o["files"] : void 0;
|
|
2878
|
-
const lines = [];
|
|
2879
|
-
if (applied !== void 0 || rejected !== void 0) {
|
|
2880
|
-
const parts = [];
|
|
2881
|
-
if (applied !== void 0) parts.push(`${applied} applied`);
|
|
2882
|
-
if (rejected !== void 0 && rejected > 0) parts.push(`${rejected} rejected`);
|
|
2883
|
-
lines.push(parts.join(" \xB7 "));
|
|
2884
|
-
}
|
|
2885
|
-
if (files && files.length > 0) {
|
|
2886
|
-
const first = stringOf(files[0]) ?? "";
|
|
2887
|
-
const more = files.length > 1 ? ` (+${files.length - 1})` : "";
|
|
2888
|
-
lines.push(`${shortenPath(first, 60)}${more}`);
|
|
2889
|
-
}
|
|
2890
|
-
if (lines.length > 0) return lines;
|
|
2481
|
+
if (files && files.length > 0) {
|
|
2482
|
+
const first = stringOf(files[0]) ?? "";
|
|
2483
|
+
const more = files.length > 1 ? ` (+${files.length - 1})` : "";
|
|
2484
|
+
lines.push(`${shortenPath(first, 60)}${more}`);
|
|
2891
2485
|
}
|
|
2486
|
+
if (lines.length > 0) return lines;
|
|
2892
2487
|
}
|
|
2893
|
-
if (toolName === "replace") {
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
return [
|
|
2900
|
-
`${reps} replacement${reps === 1 ? "" : "s"} in ${files} file${files === 1 ? "" : "s"}`
|
|
2901
|
-
];
|
|
2902
|
-
}
|
|
2488
|
+
if (toolName === "replace" && json && typeof json === "object") {
|
|
2489
|
+
const o = json;
|
|
2490
|
+
const files = numOf(o["files_modified"]);
|
|
2491
|
+
const reps = numOf(o["total_replacements"]);
|
|
2492
|
+
if (files !== void 0 && reps !== void 0) {
|
|
2493
|
+
return [`${reps} replacement${reps === 1 ? "" : "s"} in ${files} file${files === 1 ? "" : "s"}`];
|
|
2903
2494
|
}
|
|
2904
2495
|
}
|
|
2905
|
-
if (toolName === "diff") {
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
return head.length > 0 ? [head.join(" \xB7 ")] : [];
|
|
2919
|
-
}
|
|
2496
|
+
if (toolName === "diff" && json && typeof json === "object") {
|
|
2497
|
+
const o = json;
|
|
2498
|
+
const diffFiles = Array.isArray(o["files"]) ? o["files"] : void 0;
|
|
2499
|
+
const truncated = o["truncated"] === true;
|
|
2500
|
+
const mode = stringOf(o["mode"]);
|
|
2501
|
+
const diff = stringOf(o["diff"]);
|
|
2502
|
+
if (!diff) return [diffFiles && diffFiles.length === 0 ? "no changes" : "empty diff"];
|
|
2503
|
+
const head = [];
|
|
2504
|
+
if (mode) head.push(mode);
|
|
2505
|
+
if (diffFiles && diffFiles.length > 0)
|
|
2506
|
+
head.push(`${diffFiles.length} file${diffFiles.length === 1 ? "" : "s"}`);
|
|
2507
|
+
if (truncated) head.push("truncated");
|
|
2508
|
+
return head.length > 0 ? [head.join(" \xB7 ")] : [];
|
|
2920
2509
|
}
|
|
2921
2510
|
if (toolName === "read") {
|
|
2922
2511
|
if (outputLines !== void 0) return [];
|
|
@@ -2927,9 +2516,7 @@ function formatToolOutput(toolName, output, ok, _outputBytes, outputLines) {
|
|
|
2927
2516
|
}
|
|
2928
2517
|
const range = scanNumberedRange(text);
|
|
2929
2518
|
if (range.count > 0 && range.first !== void 0 && range.last !== void 0) {
|
|
2930
|
-
if (range.first === range.last) {
|
|
2931
|
-
return [`L${range.first} \xB7 ${fmtBytes(text.length)}`];
|
|
2932
|
-
}
|
|
2519
|
+
if (range.first === range.last) return [`L${range.first} \xB7 ${fmtBytes(text.length)}`];
|
|
2933
2520
|
const contiguous = range.count === range.last - range.first + 1;
|
|
2934
2521
|
const head = `L${range.first}\u2013${range.last}`;
|
|
2935
2522
|
const tail = contiguous ? `${range.count} line${range.count === 1 ? "" : "s"}` : `${range.count} lines (gaps)`;
|
|
@@ -2978,9 +2565,7 @@ function formatToolOutput(toolName, output, ok, _outputBytes, outputLines) {
|
|
|
2978
2565
|
if (lines.length > 0) return lines;
|
|
2979
2566
|
}
|
|
2980
2567
|
}
|
|
2981
|
-
if (toolName === "todo")
|
|
2982
|
-
return ok ? [] : [text.split("\n")[0] ?? ""];
|
|
2983
|
-
}
|
|
2568
|
+
if (toolName === "todo") return ok ? [] : [text.split("\n")[0] ?? ""];
|
|
2984
2569
|
if (toolName === "fetch" || toolName === "webfetch" || toolName === "web_fetch") {
|
|
2985
2570
|
if (json && typeof json === "object") {
|
|
2986
2571
|
const o = json;
|
|
@@ -3000,200 +2585,174 @@ function formatToolOutput(toolName, output, ok, _outputBytes, outputLines) {
|
|
|
3000
2585
|
if (lines.length > 0) return lines;
|
|
3001
2586
|
}
|
|
3002
2587
|
}
|
|
3003
|
-
if (toolName === "git") {
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
if (lines.length > 0) return lines;
|
|
3022
|
-
}
|
|
2588
|
+
if (toolName === "git" && json && typeof json === "object") {
|
|
2589
|
+
const o = json;
|
|
2590
|
+
const exit = numOf(o["exitCode"]) ?? numOf(o["exit_code"]);
|
|
2591
|
+
const stdout = stringOf(o["stdout"]) ?? "";
|
|
2592
|
+
const stderr = stringOf(o["stderr"]) ?? "";
|
|
2593
|
+
const head = [];
|
|
2594
|
+
if (exit !== void 0) head.push(`exit ${exit}`);
|
|
2595
|
+
const stdoutLines = countLines(stdout);
|
|
2596
|
+
const stderrLines = countLines(stderr);
|
|
2597
|
+
const lparts = [];
|
|
2598
|
+
if (stdoutLines > 0) lparts.push(`${stdoutLines} out`);
|
|
2599
|
+
if (stderrLines > 0) lparts.push(`${stderrLines} err`);
|
|
2600
|
+
if (lparts.length > 0) head.push(lparts.join(" \xB7 "));
|
|
2601
|
+
const lines = [];
|
|
2602
|
+
if (head.length > 0) lines.push(head.join(" \xB7 "));
|
|
2603
|
+
const preview = firstNonEmpty(stdout) ?? firstNonEmpty(stderr);
|
|
2604
|
+
if (preview) lines.push(`"${truncMid(preview, 70)}"`);
|
|
2605
|
+
if (lines.length > 0) return lines;
|
|
3023
2606
|
}
|
|
3024
|
-
if (toolName === "lint") {
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
return [head.join(" \xB7 ")];
|
|
3039
|
-
}
|
|
2607
|
+
if (toolName === "lint" && json && typeof json === "object") {
|
|
2608
|
+
const o = json;
|
|
2609
|
+
const linter = stringOf(o["linter"]);
|
|
2610
|
+
const files = numOf(o["files_checked"]);
|
|
2611
|
+
const errors = numOf(o["errors"]) ?? 0;
|
|
2612
|
+
const warnings = numOf(o["warnings"]) ?? 0;
|
|
2613
|
+
const fix = o["fix_applied"] === true;
|
|
2614
|
+
const head = [];
|
|
2615
|
+
if (linter && linter !== "none") head.push(linter);
|
|
2616
|
+
head.push(`${errors} error${errors === 1 ? "" : "s"}`);
|
|
2617
|
+
head.push(`${warnings} warning${warnings === 1 ? "" : "s"}`);
|
|
2618
|
+
if (files !== void 0) head.push(`${files} file${files === 1 ? "" : "s"}`);
|
|
2619
|
+
if (fix) head.push("fixed");
|
|
2620
|
+
return [head.join(" \xB7 ")];
|
|
3040
2621
|
}
|
|
3041
|
-
if (toolName === "format") {
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
}
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
return head.length > 0 ? [head.join(" \xB7 ")] : [];
|
|
3055
|
-
}
|
|
2622
|
+
if (toolName === "format" && json && typeof json === "object") {
|
|
2623
|
+
const o = json;
|
|
2624
|
+
const fixer = stringOf(o["fixer"]);
|
|
2625
|
+
const checked = numOf(o["files_checked"]);
|
|
2626
|
+
const changed = numOf(o["files_changed"]);
|
|
2627
|
+
const head = [];
|
|
2628
|
+
if (fixer && fixer !== "none") head.push(fixer);
|
|
2629
|
+
if (changed !== void 0 && checked !== void 0) {
|
|
2630
|
+
head.push(`${changed}/${checked} changed`);
|
|
2631
|
+
} else if (changed !== void 0) {
|
|
2632
|
+
head.push(`${changed} changed`);
|
|
2633
|
+
}
|
|
2634
|
+
return head.length > 0 ? [head.join(" \xB7 ")] : [];
|
|
3056
2635
|
}
|
|
3057
|
-
if (toolName === "typecheck") {
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
if (lines.length > 0) return lines;
|
|
3071
|
-
}
|
|
2636
|
+
if (toolName === "typecheck" && json && typeof json === "object") {
|
|
2637
|
+
const o = json;
|
|
2638
|
+
const exit = numOf(o["exit_code"]) ?? numOf(o["exitCode"]);
|
|
2639
|
+
const errors = numOf(o["errors"]);
|
|
2640
|
+
const head = [];
|
|
2641
|
+
if (errors !== void 0) head.push(`${errors} error${errors === 1 ? "" : "s"}`);
|
|
2642
|
+
if (exit !== void 0) head.push(`exit ${exit}`);
|
|
2643
|
+
const stdout = stringOf(o["output"]) ?? stringOf(o["stdout"]) ?? "";
|
|
2644
|
+
const lines = [];
|
|
2645
|
+
if (head.length > 0) lines.push(head.join(" \xB7 "));
|
|
2646
|
+
const preview = firstNonEmpty(stdout);
|
|
2647
|
+
if (preview && (!errors || errors > 0)) lines.push(`"${truncMid(preview, 70)}"`);
|
|
2648
|
+
if (lines.length > 0) return lines;
|
|
3072
2649
|
}
|
|
3073
|
-
if (toolName === "test") {
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
return [head.join(" \xB7 ")];
|
|
3087
|
-
}
|
|
2650
|
+
if (toolName === "test" && json && typeof json === "object") {
|
|
2651
|
+
const o = json;
|
|
2652
|
+
const runner = stringOf(o["runner"]);
|
|
2653
|
+
const total = numOf(o["tests_run"]) ?? 0;
|
|
2654
|
+
const passed = numOf(o["passed"]) ?? 0;
|
|
2655
|
+
const failed = numOf(o["failed"]) ?? 0;
|
|
2656
|
+
const duration = numOf(o["duration_ms"]);
|
|
2657
|
+
const head = [];
|
|
2658
|
+
if (runner && runner !== "none") head.push(runner);
|
|
2659
|
+
head.push(`${passed}/${total} passed`);
|
|
2660
|
+
if (failed > 0) head.push(`${failed} failed`);
|
|
2661
|
+
if (duration !== void 0) head.push(fmtDuration(duration));
|
|
2662
|
+
return [head.join(" \xB7 ")];
|
|
3088
2663
|
}
|
|
3089
|
-
if (toolName === "audit") {
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
return summary && summary.toLowerCase() !== head.toLowerCase() ? [head, truncMid(summary, OUT_BUDGET)] : [head];
|
|
3097
|
-
}
|
|
2664
|
+
if (toolName === "audit" && json && typeof json === "object") {
|
|
2665
|
+
const o = json;
|
|
2666
|
+
const total = numOf(o["total"]) ?? 0;
|
|
2667
|
+
const summary = stringOf(o["summary"]);
|
|
2668
|
+
if (total === 0) return ["no vulnerabilities"];
|
|
2669
|
+
const head = `${total} vulnerabilit${total === 1 ? "y" : "ies"}`;
|
|
2670
|
+
return summary && summary.toLowerCase() !== head.toLowerCase() ? [head, truncMid(summary, OUT_BUDGET)] : [head];
|
|
3098
2671
|
}
|
|
3099
|
-
if (toolName === "outdated") {
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
return lines;
|
|
3118
|
-
}
|
|
2672
|
+
if (toolName === "outdated" && json && typeof json === "object") {
|
|
2673
|
+
const o = json;
|
|
2674
|
+
const total = numOf(o["total"]) ?? 0;
|
|
2675
|
+
const pkgs = Array.isArray(o["packages"]) ? o["packages"] : void 0;
|
|
2676
|
+
if (total === 0) return ["all up to date"];
|
|
2677
|
+
const lines = [`${total} outdated`];
|
|
2678
|
+
if (pkgs && pkgs.length > 0) {
|
|
2679
|
+
const first = pkgs[0];
|
|
2680
|
+
if (first && typeof first === "object") {
|
|
2681
|
+
const p = first;
|
|
2682
|
+
const name = stringOf(p["name"]) ?? stringOf(p["package"]);
|
|
2683
|
+
const cur = stringOf(p["current"]);
|
|
2684
|
+
const wanted = stringOf(p["wanted"]) ?? stringOf(p["latest"]);
|
|
2685
|
+
if (name && cur && wanted) lines.push(`${name}: ${cur} \u2192 ${wanted}`);
|
|
2686
|
+
else if (name) lines.push(name);
|
|
2687
|
+
}
|
|
2688
|
+
}
|
|
2689
|
+
return lines;
|
|
3119
2690
|
}
|
|
3120
|
-
if (toolName === "tree") {
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
return parts.length > 0 ? [parts.join(" \xB7 ")] : [];
|
|
3131
|
-
}
|
|
2691
|
+
if (toolName === "tree" && json && typeof json === "object") {
|
|
2692
|
+
const o = json;
|
|
2693
|
+
const files = numOf(o["total_files"]);
|
|
2694
|
+
const dirs = numOf(o["total_dirs"]);
|
|
2695
|
+
const truncated = o["truncated"] === true;
|
|
2696
|
+
const parts = [];
|
|
2697
|
+
if (files !== void 0) parts.push(`${files} file${files === 1 ? "" : "s"}`);
|
|
2698
|
+
if (dirs !== void 0) parts.push(`${dirs} dir${dirs === 1 ? "" : "s"}`);
|
|
2699
|
+
if (truncated) parts.push("truncated");
|
|
2700
|
+
return parts.length > 0 ? [parts.join(" \xB7 ")] : [];
|
|
3132
2701
|
}
|
|
3133
|
-
if (toolName === "json") {
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
return parts.length > 0 ? [parts.join(" \xB7 ")] : [];
|
|
3144
|
-
}
|
|
2702
|
+
if (toolName === "json" && json && typeof json === "object") {
|
|
2703
|
+
const o = json;
|
|
2704
|
+
const err = stringOf(o["error"]);
|
|
2705
|
+
if (err) return [truncMid(err, OUT_BUDGET)];
|
|
2706
|
+
const type = stringOf(o["type"]);
|
|
2707
|
+
const keys = Array.isArray(o["keys"]) ? o["keys"] : void 0;
|
|
2708
|
+
const parts = [];
|
|
2709
|
+
if (type) parts.push(type);
|
|
2710
|
+
if (keys) parts.push(`${keys.length} key${keys.length === 1 ? "" : "s"}`);
|
|
2711
|
+
return parts.length > 0 ? [parts.join(" \xB7 ")] : [];
|
|
3145
2712
|
}
|
|
3146
|
-
if (toolName === "install") {
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
if (lines.length > 0) return lines;
|
|
3162
|
-
}
|
|
2713
|
+
if (toolName === "install" && json && typeof json === "object") {
|
|
2714
|
+
const o = json;
|
|
2715
|
+
const exit = numOf(o["exit_code"]) ?? numOf(o["exitCode"]);
|
|
2716
|
+
const added = numOf(o["added"]);
|
|
2717
|
+
const removed = numOf(o["removed"]);
|
|
2718
|
+
const head = [];
|
|
2719
|
+
if (exit !== void 0) head.push(`exit ${exit}`);
|
|
2720
|
+
if (added !== void 0) head.push(`+${added}`);
|
|
2721
|
+
if (removed !== void 0) head.push(`-${removed}`);
|
|
2722
|
+
const stdout = stringOf(o["stdout"]) ?? stringOf(o["output"]) ?? "";
|
|
2723
|
+
const lines = [];
|
|
2724
|
+
if (head.length > 0) lines.push(head.join(" \xB7 "));
|
|
2725
|
+
const preview = firstNonEmpty(stdout);
|
|
2726
|
+
if (preview) lines.push(`"${truncMid(preview, 70)}"`);
|
|
2727
|
+
if (lines.length > 0) return lines;
|
|
3163
2728
|
}
|
|
3164
|
-
if (toolName === "scaffold") {
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
if (parts.length > 0) return [parts.join(" \xB7 ")];
|
|
3173
|
-
}
|
|
2729
|
+
if (toolName === "scaffold" && json && typeof json === "object") {
|
|
2730
|
+
const o = json;
|
|
2731
|
+
const created = Array.isArray(o["created"]) ? o["created"] : void 0;
|
|
2732
|
+
const skipped = Array.isArray(o["skipped"]) ? o["skipped"] : void 0;
|
|
2733
|
+
const parts = [];
|
|
2734
|
+
if (created !== void 0) parts.push(`${created.length} created`);
|
|
2735
|
+
if (skipped !== void 0 && skipped.length > 0) parts.push(`${skipped.length} skipped`);
|
|
2736
|
+
if (parts.length > 0) return [parts.join(" \xB7 ")];
|
|
3174
2737
|
}
|
|
3175
2738
|
if (toolName === "remember" || toolName === "forget" || toolName === "memory") {
|
|
3176
2739
|
return ok ? [toolName === "forget" ? "removed" : "saved"] : [text.split("\n")[0] ?? ""];
|
|
3177
2740
|
}
|
|
3178
|
-
if (toolName === "mode") {
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
if (mode) return [`mode: ${mode}`];
|
|
3183
|
-
}
|
|
2741
|
+
if (toolName === "mode" && json && typeof json === "object") {
|
|
2742
|
+
const o = json;
|
|
2743
|
+
const mode = stringOf(o["mode"]) ?? stringOf(o["active"]) ?? stringOf(o["name"]);
|
|
2744
|
+
if (mode) return [`mode: ${mode}`];
|
|
3184
2745
|
}
|
|
3185
|
-
if (toolName === "search") {
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
if (count
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
return lines;
|
|
3196
|
-
}
|
|
2746
|
+
if (toolName === "search" && json && typeof json === "object") {
|
|
2747
|
+
const o = json;
|
|
2748
|
+
const matches = Array.isArray(o["matches"]) ? o["matches"] : Array.isArray(o["results"]) ? o["results"] : void 0;
|
|
2749
|
+
const count = numOf(o["count"]) ?? matches?.length;
|
|
2750
|
+
if (count !== void 0) {
|
|
2751
|
+
if (count === 0) return ["no results"];
|
|
2752
|
+
const lines = [`${count} result${count === 1 ? "" : "s"}`];
|
|
2753
|
+
const firstHit = matches && matches.length > 0 ? formatMatchHit(matches[0]) : void 0;
|
|
2754
|
+
if (firstHit) lines.push(firstHit);
|
|
2755
|
+
return lines;
|
|
3197
2756
|
}
|
|
3198
2757
|
}
|
|
3199
2758
|
if (toolName === "logs") {
|
|
@@ -3210,66 +2769,168 @@ function formatToolOutput(toolName, output, ok, _outputBytes, outputLines) {
|
|
|
3210
2769
|
const collapsed = text.replace(/\s+/g, " ").trim();
|
|
3211
2770
|
return [truncMid(collapsed, GENERIC_BUDGET)];
|
|
3212
2771
|
}
|
|
3213
|
-
var
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
2772
|
+
var MAX_STREAM_DISPLAY_CHARS = 480;
|
|
2773
|
+
var MAX_STREAM_LINES = 8;
|
|
2774
|
+
var ToolStreamBox = React6.memo(function ToolStreamBox2({
|
|
2775
|
+
name,
|
|
2776
|
+
text,
|
|
2777
|
+
startedAt,
|
|
2778
|
+
termWidth
|
|
2779
|
+
}) {
|
|
2780
|
+
const [tick, setTick] = useState(0);
|
|
2781
|
+
useEffect(() => {
|
|
2782
|
+
const t = setInterval(() => setTick((n) => n + 1), 500);
|
|
2783
|
+
return () => clearInterval(t);
|
|
2784
|
+
}, []);
|
|
2785
|
+
const elapsedMs = Date.now() - startedAt;
|
|
2786
|
+
const lines = text.split("\n");
|
|
2787
|
+
const totalLines = lines.length;
|
|
2788
|
+
const hidden = Math.max(0, totalLines - MAX_STREAM_LINES);
|
|
2789
|
+
const visible = hidden > 0 ? lines.slice(hidden) : lines;
|
|
2790
|
+
const contentWidth = Math.max(20, Math.min(termWidth - 4, 100));
|
|
2791
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 0, children: [
|
|
2792
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", children: [
|
|
2793
|
+
/* @__PURE__ */ jsx(Text, { color: theme.warn, children: "\u25C6 " }),
|
|
2794
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: theme.tool, children: name }),
|
|
2795
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u23F1 ${fmtDuration(elapsedMs)}` }),
|
|
2796
|
+
hidden > 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` (${totalLines} lines, showing last ${MAX_STREAM_LINES})` }) : null
|
|
2797
|
+
] }),
|
|
2798
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginLeft: 2, children: [
|
|
2799
|
+
hidden > 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, italic: true, children: ` \u2026 ${hidden} more line${hidden === 1 ? "" : "s"} above` }) : null,
|
|
2800
|
+
visible.map((line, i) => {
|
|
2801
|
+
const trimmed = line.length > contentWidth ? `${line.slice(0, contentWidth - 1)}\u2026` : line;
|
|
2802
|
+
return /* @__PURE__ */ jsx(Text, { dimColor: true, children: trimmed || " " }, i);
|
|
2803
|
+
})
|
|
2804
|
+
] })
|
|
2805
|
+
] });
|
|
2806
|
+
});
|
|
2807
|
+
function tailForDisplay(text, maxChars) {
|
|
2808
|
+
if (text.length <= maxChars) return text;
|
|
2809
|
+
const cut = text.length - maxChars;
|
|
2810
|
+
const nl = text.indexOf("\n", cut);
|
|
2811
|
+
if (nl !== -1 && nl < cut + 80) {
|
|
2812
|
+
return `\u2026 ${text.slice(nl + 1)}`;
|
|
2813
|
+
}
|
|
2814
|
+
return `\u2026 ${text.slice(cut)}`;
|
|
2815
|
+
}
|
|
2816
|
+
var MAX_CODE_LINES = 80;
|
|
2817
|
+
var DIFF_MAX_LINES = 8;
|
|
2818
|
+
function CodeBlock({
|
|
2819
|
+
code,
|
|
2820
|
+
lang,
|
|
2821
|
+
contentWidth
|
|
2822
|
+
}) {
|
|
2823
|
+
let lines = code.replace(/\n+$/, "").split("\n");
|
|
2824
|
+
const hidden = Math.max(0, lines.length - MAX_CODE_LINES);
|
|
2825
|
+
if (hidden > 0) lines = lines.slice(0, MAX_CODE_LINES);
|
|
2826
|
+
const gutterW = String(lines.length).length;
|
|
2827
|
+
const maxW = Math.max(20, Math.min(contentWidth - 6 - gutterW - 1, 120));
|
|
2828
|
+
let carry = {};
|
|
2829
|
+
const rows = lines.map((raw) => {
|
|
2830
|
+
const display = raw.length > maxW ? `${raw.slice(0, maxW - 1)}\u2026` : raw;
|
|
2831
|
+
const r = highlightLine(display, lang, carry);
|
|
2832
|
+
carry = r.carry;
|
|
2833
|
+
return r.tokens;
|
|
2834
|
+
});
|
|
2835
|
+
return /* @__PURE__ */ jsxs(
|
|
2836
|
+
Box,
|
|
2837
|
+
{
|
|
2838
|
+
flexDirection: "column",
|
|
2839
|
+
marginLeft: 2,
|
|
2840
|
+
marginY: 0,
|
|
2841
|
+
borderStyle: "round",
|
|
2842
|
+
borderColor: theme.borderDefault,
|
|
2843
|
+
paddingX: 1,
|
|
2844
|
+
children: [
|
|
2845
|
+
lang !== "plain" ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: lang }) : null,
|
|
2846
|
+
rows.map((tokens, i) => (
|
|
2847
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: code lines are positional
|
|
2848
|
+
/* @__PURE__ */ jsxs(Text, { children: [
|
|
2849
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: `${String(i + 1).padStart(gutterW, " ")} ` }),
|
|
2850
|
+
tokens.length === 0 ? " " : tokens.map((t, j) => (
|
|
2851
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: token order is stable per line
|
|
2852
|
+
/* @__PURE__ */ jsx(Text, { color: t.color, dimColor: t.dim, bold: t.bold, children: t.text }, j)
|
|
2853
|
+
))
|
|
2854
|
+
] }, i)
|
|
2855
|
+
)),
|
|
2856
|
+
hidden > 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, italic: true, children: `\u2026 +${hidden} more line${hidden === 1 ? "" : "s"}` }) : null
|
|
2857
|
+
]
|
|
2858
|
+
}
|
|
2859
|
+
);
|
|
2860
|
+
}
|
|
2861
|
+
function DiffBlock({ rows, hidden }) {
|
|
2862
|
+
let gutterWidth = 1;
|
|
2863
|
+
for (const r of rows) {
|
|
2864
|
+
const n = r.kind === "del" ? r.oldLine : r.newLine;
|
|
2865
|
+
if (typeof n === "number") {
|
|
2866
|
+
const w = String(n).length;
|
|
2867
|
+
if (w > gutterWidth) gutterWidth = w;
|
|
3246
2868
|
}
|
|
3247
|
-
parts.push(rendered);
|
|
3248
|
-
used += rendered.length + 3;
|
|
3249
2869
|
}
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
2870
|
+
const blank = " ".repeat(gutterWidth);
|
|
2871
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginLeft: 4, marginTop: 0, children: [
|
|
2872
|
+
rows.map((row, i) => {
|
|
2873
|
+
const key = i;
|
|
2874
|
+
if (row.kind === "hunk") {
|
|
2875
|
+
return /* @__PURE__ */ jsx(Text, { color: "cyan", dimColor: true, children: row.text }, key);
|
|
2876
|
+
}
|
|
2877
|
+
if (row.kind === "meta") {
|
|
2878
|
+
return /* @__PURE__ */ jsx(Text, { dimColor: true, children: `${blank} ${row.text}` }, key);
|
|
2879
|
+
}
|
|
2880
|
+
const lnNumber = row.kind === "del" ? row.oldLine : row.newLine;
|
|
2881
|
+
const lnText = typeof lnNumber === "number" ? String(lnNumber).padStart(gutterWidth, " ") : blank;
|
|
2882
|
+
if (row.kind === "ctx") {
|
|
2883
|
+
return /* @__PURE__ */ jsx(Text, { dimColor: true, children: `${lnText} ${row.text}` }, key);
|
|
2884
|
+
}
|
|
2885
|
+
const bg = row.kind === "add" ? theme.diffAddBg : theme.diffDelBg;
|
|
2886
|
+
return /* @__PURE__ */ jsxs(Text, { children: [
|
|
2887
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: `${lnText} ` }),
|
|
2888
|
+
/* @__PURE__ */ jsx(Text, { backgroundColor: bg, color: "black", children: row.text })
|
|
2889
|
+
] }, key);
|
|
2890
|
+
}),
|
|
2891
|
+
hidden > 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, italic: true, children: `${blank} \u2026 ${hidden} more line${hidden === 1 ? "" : "s"}` }) : null
|
|
2892
|
+
] });
|
|
3256
2893
|
}
|
|
3257
|
-
function
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
const line =
|
|
3263
|
-
|
|
3264
|
-
if (
|
|
3265
|
-
|
|
3266
|
-
|
|
2894
|
+
function parseUnifiedDiff(diff, maxLines) {
|
|
2895
|
+
const all = [];
|
|
2896
|
+
let oldLn = 0;
|
|
2897
|
+
let newLn = 0;
|
|
2898
|
+
for (const raw of diff.split("\n")) {
|
|
2899
|
+
const line = raw.replace(/\r$/, "");
|
|
2900
|
+
if (line.startsWith("+++") || line.startsWith("---")) continue;
|
|
2901
|
+
if (line.startsWith("diff --git") || line.startsWith("index ")) continue;
|
|
2902
|
+
if (line.startsWith("@@")) {
|
|
2903
|
+
const m = line.match(/^@@\s+-(\d+)(?:,\d+)?\s+\+(\d+)(?:,\d+)?\s+@@/);
|
|
2904
|
+
if (m) {
|
|
2905
|
+
oldLn = Number.parseInt(m[1] ?? "0", 10) || 0;
|
|
2906
|
+
newLn = Number.parseInt(m[2] ?? "0", 10) || 0;
|
|
2907
|
+
}
|
|
2908
|
+
all.push({ kind: "hunk", text: truncMid(line, 60) });
|
|
2909
|
+
continue;
|
|
3267
2910
|
}
|
|
3268
|
-
if (
|
|
2911
|
+
if (line.startsWith("+")) {
|
|
2912
|
+
all.push({ kind: "add", text: truncMid(line, 100), newLine: newLn });
|
|
2913
|
+
newLn++;
|
|
2914
|
+
continue;
|
|
2915
|
+
}
|
|
2916
|
+
if (line.startsWith("-")) {
|
|
2917
|
+
all.push({ kind: "del", text: truncMid(line, 100), oldLine: oldLn });
|
|
2918
|
+
oldLn++;
|
|
2919
|
+
continue;
|
|
2920
|
+
}
|
|
2921
|
+
if (line.startsWith("\\ No newline")) {
|
|
2922
|
+
all.push({ kind: "meta", text: line });
|
|
2923
|
+
continue;
|
|
2924
|
+
}
|
|
2925
|
+
if (line.length === 0) continue;
|
|
2926
|
+
all.push({ kind: "ctx", text: truncMid(line, 100), oldLine: oldLn, newLine: newLn });
|
|
2927
|
+
oldLn++;
|
|
2928
|
+
newLn++;
|
|
3269
2929
|
}
|
|
3270
|
-
return
|
|
2930
|
+
if (all.length === 0) return { rows: [], hidden: 0 };
|
|
2931
|
+
if (all.length <= maxLines) return { rows: all, hidden: 0 };
|
|
2932
|
+
return { rows: all.slice(0, maxLines), hidden: all.length - maxLines };
|
|
3271
2933
|
}
|
|
3272
|
-
var DIFF_MAX_LINES = 8;
|
|
3273
2934
|
function extractDiffPreview(toolName, output) {
|
|
3274
2935
|
if (!output) return void 0;
|
|
3275
2936
|
const text = output.trim();
|
|
@@ -3291,90 +2952,385 @@ function extractDiffPreview(toolName, output) {
|
|
|
3291
2952
|
if (!diff || !diff.trim() || diff.startsWith("(no-op")) return void 0;
|
|
3292
2953
|
return parseUnifiedDiff(diff, DIFF_MAX_LINES);
|
|
3293
2954
|
}
|
|
3294
|
-
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
if (
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
2955
|
+
var MESSAGE_PANEL_CHROME_WIDTH = 2;
|
|
2956
|
+
function splitFencedBlocks(text) {
|
|
2957
|
+
const lines = text.split("\n");
|
|
2958
|
+
const segs = [];
|
|
2959
|
+
let prose = [];
|
|
2960
|
+
let code = null;
|
|
2961
|
+
let lang = "plain";
|
|
2962
|
+
const flushProse = () => {
|
|
2963
|
+
if (prose.length > 0) {
|
|
2964
|
+
segs.push({ type: "prose", text: prose.join("\n") });
|
|
2965
|
+
prose = [];
|
|
2966
|
+
}
|
|
2967
|
+
};
|
|
2968
|
+
for (const line of lines) {
|
|
2969
|
+
const fence = line.match(/^\s*```(.*)$/);
|
|
2970
|
+
if (fence) {
|
|
2971
|
+
if (code === null) {
|
|
2972
|
+
flushProse();
|
|
2973
|
+
code = [];
|
|
2974
|
+
lang = detectLang(fence[1] ?? "");
|
|
2975
|
+
} else {
|
|
2976
|
+
segs.push({ type: "code", text: code.join("\n"), lang });
|
|
2977
|
+
code = null;
|
|
2978
|
+
lang = "plain";
|
|
3307
2979
|
}
|
|
3308
|
-
all.push({ kind: "hunk", text: truncMid(line, 60) });
|
|
3309
2980
|
continue;
|
|
3310
2981
|
}
|
|
3311
|
-
if (
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
2982
|
+
if (code !== null) code.push(line);
|
|
2983
|
+
else prose.push(line);
|
|
2984
|
+
}
|
|
2985
|
+
if (code !== null) segs.push({ type: "code", text: code.join("\n"), lang });
|
|
2986
|
+
flushProse();
|
|
2987
|
+
return segs;
|
|
2988
|
+
}
|
|
2989
|
+
function AssistantBody({
|
|
2990
|
+
text,
|
|
2991
|
+
termWidth,
|
|
2992
|
+
contentWidth
|
|
2993
|
+
}) {
|
|
2994
|
+
const segments = splitFencedBlocks(text);
|
|
2995
|
+
const inner = contentWidth ?? termWidth;
|
|
2996
|
+
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: segments.map(
|
|
2997
|
+
(seg, i) => seg.type === "code" ? (
|
|
2998
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: segment order is stable
|
|
2999
|
+
/* @__PURE__ */ jsx(CodeBlock, { code: seg.text, lang: seg.lang ?? "plain", contentWidth: inner }, i)
|
|
3000
|
+
) : (
|
|
3001
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: segment order is stable
|
|
3002
|
+
/* @__PURE__ */ jsx(MarkdownView, { text: seg.text, termWidth: inner }, i)
|
|
3003
|
+
)
|
|
3004
|
+
) });
|
|
3005
|
+
}
|
|
3006
|
+
function AssistantTail({ text }) {
|
|
3007
|
+
return /* @__PURE__ */ jsxs(
|
|
3008
|
+
Box,
|
|
3009
|
+
{
|
|
3010
|
+
flexDirection: "column",
|
|
3011
|
+
marginY: 1,
|
|
3012
|
+
borderStyle: "single",
|
|
3013
|
+
borderTop: false,
|
|
3014
|
+
borderRight: false,
|
|
3015
|
+
borderBottom: false,
|
|
3016
|
+
borderColor: theme.assistant,
|
|
3017
|
+
paddingLeft: 1,
|
|
3018
|
+
children: [
|
|
3019
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", children: [
|
|
3020
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: theme.assistant, children: "ASSISTANT" }),
|
|
3021
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " (streaming\u2026)" })
|
|
3022
|
+
] }),
|
|
3023
|
+
/* @__PURE__ */ jsx(Text, { color: "white", children: text })
|
|
3024
|
+
]
|
|
3025
|
+
}
|
|
3026
|
+
);
|
|
3027
|
+
}
|
|
3028
|
+
function Banner({
|
|
3029
|
+
entry
|
|
3030
|
+
}) {
|
|
3031
|
+
const cwdShort = shortenPath(entry.cwd, 48);
|
|
3032
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "magenta", paddingX: 2, paddingY: 0, children: [
|
|
3033
|
+
/* @__PURE__ */ jsxs(Text, { children: [
|
|
3034
|
+
/* @__PURE__ */ jsx(Text, { color: "magenta", bold: true, children: " \u259F\u259B " }),
|
|
3035
|
+
/* @__PURE__ */ jsx(Text, { color: "magenta", bold: true, children: "WrongStack" }),
|
|
3036
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " v" }),
|
|
3037
|
+
/* @__PURE__ */ jsx(Text, { children: entry.version })
|
|
3038
|
+
] }),
|
|
3039
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, italic: true, children: " Built on the wrong stack. Shipped anyway." }),
|
|
3040
|
+
/* @__PURE__ */ jsxs(Text, { children: [
|
|
3041
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", children: " provider " }),
|
|
3042
|
+
/* @__PURE__ */ jsxs(Text, { children: [
|
|
3043
|
+
entry.provider,
|
|
3044
|
+
"/",
|
|
3045
|
+
entry.model
|
|
3046
|
+
] })
|
|
3047
|
+
] }),
|
|
3048
|
+
entry.family ? /* @__PURE__ */ jsxs(Text, { children: [
|
|
3049
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", children: " family " }),
|
|
3050
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: entry.family })
|
|
3051
|
+
] }) : null,
|
|
3052
|
+
entry.keyTail ? /* @__PURE__ */ jsxs(Text, { children: [
|
|
3053
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", children: " key " }),
|
|
3054
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u25CF\u25CF\u25CF\u2026" }),
|
|
3055
|
+
/* @__PURE__ */ jsx(Text, { children: entry.keyTail })
|
|
3056
|
+
] }) : null,
|
|
3057
|
+
/* @__PURE__ */ jsxs(Text, { children: [
|
|
3058
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", children: " cwd " }),
|
|
3059
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: cwdShort })
|
|
3060
|
+
] }),
|
|
3061
|
+
/* @__PURE__ */ jsxs(Text, { children: [
|
|
3062
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", children: " hints " }),
|
|
3063
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "/help \xB7 /init \xB7 /memory \xB7 /queue \xB7 /exit" })
|
|
3064
|
+
] })
|
|
3065
|
+
] });
|
|
3066
|
+
}
|
|
3067
|
+
function brainStatusStyle(status) {
|
|
3068
|
+
switch (status) {
|
|
3069
|
+
case "thinking":
|
|
3070
|
+
return { icon: "\u2026", color: "magenta" };
|
|
3071
|
+
case "answered":
|
|
3072
|
+
return { icon: "\u2696", color: "cyan" };
|
|
3073
|
+
case "ask_human":
|
|
3074
|
+
return { icon: "?", color: "yellow" };
|
|
3075
|
+
case "denied":
|
|
3076
|
+
return { icon: "\xD7", color: "red" };
|
|
3077
|
+
}
|
|
3078
|
+
}
|
|
3079
|
+
function brainRiskColor(risk) {
|
|
3080
|
+
switch (risk) {
|
|
3081
|
+
case "low":
|
|
3082
|
+
return "green";
|
|
3083
|
+
case "medium":
|
|
3084
|
+
return "cyan";
|
|
3085
|
+
case "high":
|
|
3086
|
+
return "yellow";
|
|
3087
|
+
case "critical":
|
|
3088
|
+
return "red";
|
|
3089
|
+
}
|
|
3090
|
+
}
|
|
3091
|
+
function assistantContentWidth(termWidth) {
|
|
3092
|
+
return Math.max(20, termWidth - MESSAGE_PANEL_CHROME_WIDTH);
|
|
3093
|
+
}
|
|
3094
|
+
var Entry = React6.memo(function Entry2({
|
|
3095
|
+
entry,
|
|
3096
|
+
termWidth
|
|
3097
|
+
}) {
|
|
3098
|
+
switch (entry.kind) {
|
|
3099
|
+
case "user":
|
|
3100
|
+
return /* @__PURE__ */ jsx(
|
|
3101
|
+
Box,
|
|
3102
|
+
{
|
|
3103
|
+
borderStyle: "single",
|
|
3104
|
+
borderTop: false,
|
|
3105
|
+
borderRight: false,
|
|
3106
|
+
borderBottom: false,
|
|
3107
|
+
borderColor: theme.user,
|
|
3108
|
+
paddingLeft: 1,
|
|
3109
|
+
children: /* @__PURE__ */ jsxs(Text, { children: [
|
|
3110
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: theme.user, children: "USER " }),
|
|
3111
|
+
/* @__PURE__ */ jsx(Text, { color: "white", children: entry.text }),
|
|
3112
|
+
entry.queued ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: " (queued)" }) : null,
|
|
3113
|
+
entry.pasteContent ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3114
|
+
entry.text ? "\n" : null,
|
|
3115
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
3116
|
+
" \u21B3 ",
|
|
3117
|
+
entry.pasteContent
|
|
3118
|
+
] })
|
|
3119
|
+
] }) : null
|
|
3120
|
+
] })
|
|
3121
|
+
}
|
|
3122
|
+
);
|
|
3123
|
+
case "assistant": {
|
|
3124
|
+
const contentWidth = assistantContentWidth(termWidth);
|
|
3125
|
+
return /* @__PURE__ */ jsxs(
|
|
3126
|
+
Box,
|
|
3127
|
+
{
|
|
3128
|
+
flexDirection: "column",
|
|
3129
|
+
marginY: 1,
|
|
3130
|
+
borderStyle: "single",
|
|
3131
|
+
borderTop: false,
|
|
3132
|
+
borderRight: false,
|
|
3133
|
+
borderBottom: false,
|
|
3134
|
+
borderColor: theme.assistant,
|
|
3135
|
+
paddingLeft: 1,
|
|
3136
|
+
children: [
|
|
3137
|
+
/* @__PURE__ */ jsx(Box, { flexDirection: "row", children: /* @__PURE__ */ jsx(Text, { bold: true, color: theme.assistant, children: "ASSISTANT" }) }),
|
|
3138
|
+
/* @__PURE__ */ jsx(AssistantBody, { text: entry.text, termWidth, contentWidth })
|
|
3139
|
+
]
|
|
3140
|
+
}
|
|
3141
|
+
);
|
|
3142
|
+
}
|
|
3143
|
+
case "tool": {
|
|
3144
|
+
const argSummary = formatToolArgs(entry.name, entry.input);
|
|
3145
|
+
const outLines = formatToolOutput(
|
|
3146
|
+
entry.name,
|
|
3147
|
+
entry.output,
|
|
3148
|
+
entry.ok,
|
|
3149
|
+
entry.outputBytes,
|
|
3150
|
+
entry.outputLines
|
|
3151
|
+
);
|
|
3152
|
+
const diff = entry.ok ? extractDiffPreview(entry.name, entry.output) : void 0;
|
|
3153
|
+
const sizeChip = (() => {
|
|
3154
|
+
if (!entry.ok) return "";
|
|
3155
|
+
const parts = [];
|
|
3156
|
+
if (entry.outputLines !== void 0 && entry.outputLines > 0) {
|
|
3157
|
+
parts.push(`${entry.outputLines} L`);
|
|
3158
|
+
}
|
|
3159
|
+
if (entry.outputBytes && entry.outputBytes > 0) {
|
|
3160
|
+
parts.push(fmtBytes(entry.outputBytes));
|
|
3161
|
+
}
|
|
3162
|
+
if (entry.outputTokens && entry.outputTokens > 0) {
|
|
3163
|
+
parts.push(`\u2248${fmtTok2(entry.outputTokens)} tok`);
|
|
3164
|
+
}
|
|
3165
|
+
return parts.join(" \xB7 ");
|
|
3166
|
+
})();
|
|
3167
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
3168
|
+
/* @__PURE__ */ jsxs(Text, { children: [
|
|
3169
|
+
/* @__PURE__ */ jsx(Text, { color: entry.ok ? theme.success : theme.error, children: entry.ok ? "\u25CF" : "\u2717" }),
|
|
3170
|
+
" ",
|
|
3171
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: theme.tool, children: entry.name }),
|
|
3172
|
+
argSummary ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3173
|
+
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
3174
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: argSummary })
|
|
3175
|
+
] }) : null,
|
|
3176
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \xB7 ${fmtDuration(entry.durationMs)}` }),
|
|
3177
|
+
sizeChip ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \xB7 ${sizeChip}` }) : null
|
|
3178
|
+
] }),
|
|
3179
|
+
outLines.map((line, i) => (
|
|
3180
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: tool output lines are static, index is stable
|
|
3181
|
+
/* @__PURE__ */ jsxs(Text, { children: [
|
|
3182
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: i === outLines.length - 1 && !diff ? " \u2514\u2500 " : " \u251C\u2500 " }),
|
|
3183
|
+
/* @__PURE__ */ jsx(
|
|
3184
|
+
Text,
|
|
3185
|
+
{
|
|
3186
|
+
color: !entry.ok || line.startsWith("!") ? "red" : void 0,
|
|
3187
|
+
dimColor: entry.ok && !line.startsWith("!"),
|
|
3188
|
+
children: line
|
|
3189
|
+
}
|
|
3190
|
+
)
|
|
3191
|
+
] }, i)
|
|
3192
|
+
)),
|
|
3193
|
+
diff ? /* @__PURE__ */ jsx(DiffBlock, { rows: diff.rows, hidden: diff.hidden }) : null
|
|
3194
|
+
] });
|
|
3315
3195
|
}
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3196
|
+
case "info":
|
|
3197
|
+
return /* @__PURE__ */ jsx(Text, { dimColor: true, children: entry.text });
|
|
3198
|
+
case "warn":
|
|
3199
|
+
return /* @__PURE__ */ jsx(
|
|
3200
|
+
Box,
|
|
3201
|
+
{
|
|
3202
|
+
borderStyle: "single",
|
|
3203
|
+
borderTop: false,
|
|
3204
|
+
borderRight: false,
|
|
3205
|
+
borderBottom: false,
|
|
3206
|
+
borderColor: theme.warn,
|
|
3207
|
+
paddingLeft: 1,
|
|
3208
|
+
children: /* @__PURE__ */ jsx(Text, { color: theme.warn, children: entry.text })
|
|
3209
|
+
}
|
|
3210
|
+
);
|
|
3211
|
+
case "error":
|
|
3212
|
+
return /* @__PURE__ */ jsx(
|
|
3213
|
+
Box,
|
|
3214
|
+
{
|
|
3215
|
+
borderStyle: "single",
|
|
3216
|
+
borderTop: false,
|
|
3217
|
+
borderRight: false,
|
|
3218
|
+
borderBottom: false,
|
|
3219
|
+
borderColor: theme.error,
|
|
3220
|
+
paddingLeft: 1,
|
|
3221
|
+
children: /* @__PURE__ */ jsx(Text, { color: theme.error, children: entry.text })
|
|
3222
|
+
}
|
|
3223
|
+
);
|
|
3224
|
+
case "turn-summary":
|
|
3225
|
+
return /* @__PURE__ */ jsx(Text, { dimColor: true, children: entry.text });
|
|
3226
|
+
case "brain": {
|
|
3227
|
+
const statusStyle = brainStatusStyle(entry.status);
|
|
3228
|
+
const riskColor2 = brainRiskColor(entry.risk);
|
|
3229
|
+
return /* @__PURE__ */ jsxs(
|
|
3230
|
+
Box,
|
|
3231
|
+
{
|
|
3232
|
+
flexDirection: "column",
|
|
3233
|
+
marginY: 1,
|
|
3234
|
+
borderStyle: "single",
|
|
3235
|
+
borderTop: false,
|
|
3236
|
+
borderRight: false,
|
|
3237
|
+
borderBottom: false,
|
|
3238
|
+
borderColor: "magenta",
|
|
3239
|
+
paddingLeft: 1,
|
|
3240
|
+
children: [
|
|
3241
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
3242
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "magenta", children: "BRAIN" }),
|
|
3243
|
+
/* @__PURE__ */ jsx(Text, { color: statusStyle.color, children: statusStyle.icon }),
|
|
3244
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: entry.source }),
|
|
3245
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7" }),
|
|
3246
|
+
/* @__PURE__ */ jsx(Text, { color: riskColor2, children: entry.risk })
|
|
3247
|
+
] }),
|
|
3248
|
+
/* @__PURE__ */ jsx(Text, { color: "white", children: entry.question }),
|
|
3249
|
+
entry.decision ? /* @__PURE__ */ jsxs(Text, { children: [
|
|
3250
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Decision: " }),
|
|
3251
|
+
/* @__PURE__ */ jsx(Text, { color: statusStyle.color, children: entry.decision })
|
|
3252
|
+
] }) : null,
|
|
3253
|
+
entry.rationale ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: entry.rationale }) : null
|
|
3254
|
+
]
|
|
3255
|
+
}
|
|
3256
|
+
);
|
|
3320
3257
|
}
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3258
|
+
case "confirm":
|
|
3259
|
+
return /* @__PURE__ */ jsxs(
|
|
3260
|
+
Box,
|
|
3261
|
+
{
|
|
3262
|
+
flexDirection: "column",
|
|
3263
|
+
borderStyle: "round",
|
|
3264
|
+
borderColor: "yellow",
|
|
3265
|
+
paddingX: 1,
|
|
3266
|
+
marginY: 1,
|
|
3267
|
+
children: [
|
|
3268
|
+
/* @__PURE__ */ jsxs(Text, { bold: true, color: "yellow", children: [
|
|
3269
|
+
"\u26A0 Confirm: ",
|
|
3270
|
+
entry.toolName
|
|
3271
|
+
] }),
|
|
3272
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Waiting for y / n / a / d..." })
|
|
3273
|
+
]
|
|
3274
|
+
}
|
|
3275
|
+
);
|
|
3276
|
+
case "banner":
|
|
3277
|
+
return /* @__PURE__ */ jsx(Banner, { entry });
|
|
3278
|
+
case "subagent": {
|
|
3279
|
+
const lines = entry.text.split("\n");
|
|
3280
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
3281
|
+
/* @__PURE__ */ jsxs(Text, { children: [
|
|
3282
|
+
/* @__PURE__ */ jsx(Text, { color: entry.agentColor, bold: true, children: `[${entry.agentLabel}]` }),
|
|
3283
|
+
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
3284
|
+
/* @__PURE__ */ jsx(Text, { color: entry.agentColor, children: entry.icon }),
|
|
3285
|
+
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
3286
|
+
/* @__PURE__ */ jsx(Text, { children: lines[0] ?? "" }),
|
|
3287
|
+
entry.detail ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3288
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " \xB7 " }),
|
|
3289
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: entry.detail })
|
|
3290
|
+
] }) : null
|
|
3291
|
+
] }),
|
|
3292
|
+
lines.slice(1).map((line, i) => (
|
|
3293
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: stable line index
|
|
3294
|
+
/* @__PURE__ */ jsxs(Text, { children: [
|
|
3295
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " " }),
|
|
3296
|
+
/* @__PURE__ */ jsx(Text, { children: line })
|
|
3297
|
+
] }, i)
|
|
3298
|
+
))
|
|
3299
|
+
] });
|
|
3324
3300
|
}
|
|
3325
|
-
if (line.length === 0) continue;
|
|
3326
|
-
all.push({ kind: "ctx", text: truncMid(line, 100), oldLine: oldLn, newLine: newLn });
|
|
3327
|
-
oldLn++;
|
|
3328
|
-
newLn++;
|
|
3329
|
-
}
|
|
3330
|
-
if (all.length === 0) return { rows: [], hidden: 0 };
|
|
3331
|
-
if (all.length <= maxLines) return { rows: all, hidden: 0 };
|
|
3332
|
-
return { rows: all.slice(0, maxLines), hidden: all.length - maxLines };
|
|
3333
|
-
}
|
|
3334
|
-
function stringOf(v) {
|
|
3335
|
-
return typeof v === "string" && v.length > 0 ? v : void 0;
|
|
3336
|
-
}
|
|
3337
|
-
function numOf(v) {
|
|
3338
|
-
return typeof v === "number" && Number.isFinite(v) ? v : void 0;
|
|
3339
|
-
}
|
|
3340
|
-
function tryParseJson(s2) {
|
|
3341
|
-
const t = s2.trimStart();
|
|
3342
|
-
if (!t.startsWith("{") && !t.startsWith("[")) return void 0;
|
|
3343
|
-
try {
|
|
3344
|
-
return JSON.parse(s2);
|
|
3345
|
-
} catch {
|
|
3346
|
-
return void 0;
|
|
3347
3301
|
}
|
|
3348
|
-
}
|
|
3349
|
-
function
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3302
|
+
});
|
|
3303
|
+
function History({ entries, streamingText, toolStream }) {
|
|
3304
|
+
const { stdout } = useStdout();
|
|
3305
|
+
const [termSize, setTermSize] = useState({
|
|
3306
|
+
columns: stdout?.columns ?? 80,
|
|
3307
|
+
rows: stdout?.rows ?? 24
|
|
3308
|
+
});
|
|
3309
|
+
useEffect(() => {
|
|
3310
|
+
const handleResize = () => {
|
|
3311
|
+
setTermSize({ columns: stdout?.columns ?? 80, rows: stdout?.rows ?? 24 });
|
|
3312
|
+
};
|
|
3313
|
+
process.stdout.on("resize", handleResize);
|
|
3314
|
+
return () => {
|
|
3315
|
+
process.stdout.off("resize", handleResize);
|
|
3316
|
+
};
|
|
3317
|
+
}, [stdout]);
|
|
3318
|
+
const termWidth = termSize.columns;
|
|
3319
|
+
const tail = streamingText ? tailForDisplay(streamingText, MAX_STREAM_DISPLAY_CHARS) : "";
|
|
3320
|
+
const toolTail = toolStream?.text ? tailForDisplay(toolStream.text, MAX_STREAM_DISPLAY_CHARS) : "";
|
|
3321
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3322
|
+
/* @__PURE__ */ jsx(Static, { items: entries, children: (entry) => /* @__PURE__ */ jsx(Box, { marginBottom: entry.kind === "turn-summary" ? 1 : 0, children: /* @__PURE__ */ jsx(Entry, { entry, termWidth }) }, entry.id) }),
|
|
3323
|
+
tail ? /* @__PURE__ */ jsx(AssistantTail, { text: tail }) : null,
|
|
3324
|
+
toolTail ? /* @__PURE__ */ jsx(
|
|
3325
|
+
ToolStreamBox,
|
|
3326
|
+
{
|
|
3327
|
+
name: toolStream.name,
|
|
3328
|
+
text: toolTail,
|
|
3329
|
+
startedAt: toolStream.startedAt,
|
|
3330
|
+
termWidth
|
|
3361
3331
|
}
|
|
3362
|
-
|
|
3363
|
-
}
|
|
3364
|
-
return { first, last, count };
|
|
3365
|
-
}
|
|
3366
|
-
function countLines(text) {
|
|
3367
|
-
if (!text) return 0;
|
|
3368
|
-
return text.replace(/\n$/, "").split("\n").length;
|
|
3369
|
-
}
|
|
3370
|
-
function fmtBytes(n) {
|
|
3371
|
-
if (n < 1024) return `${n}B`;
|
|
3372
|
-
if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)}KB`;
|
|
3373
|
-
return `${(n / (1024 * 1024)).toFixed(1)}MB`;
|
|
3374
|
-
}
|
|
3375
|
-
function truncMid(s2, max) {
|
|
3376
|
-
if (s2.length <= max) return s2;
|
|
3377
|
-
return `${s2.slice(0, max - 1)}\u2026`;
|
|
3332
|
+
) : null
|
|
3333
|
+
] });
|
|
3378
3334
|
}
|
|
3379
3335
|
|
|
3380
3336
|
// src/fn-keys.ts
|
|
@@ -3718,7 +3674,7 @@ function fmtRecentMessage(message) {
|
|
|
3718
3674
|
const text = message.text.replace(/\s+/g, " ");
|
|
3719
3675
|
return text.length > 48 ? `${text.slice(0, 47)}...` : text;
|
|
3720
3676
|
}
|
|
3721
|
-
var LiveActivityStrip =
|
|
3677
|
+
var LiveActivityStrip = React6.memo(function LiveActivityStrip2({
|
|
3722
3678
|
entries,
|
|
3723
3679
|
nowTick,
|
|
3724
3680
|
maxRows = 4
|
|
@@ -4535,6 +4491,121 @@ function runGit(cwd, args) {
|
|
|
4535
4491
|
}
|
|
4536
4492
|
});
|
|
4537
4493
|
}
|
|
4494
|
+
var STREAM_COLORS = ["cyan", "magenta", "yellow", "green", "blue"];
|
|
4495
|
+
function labelFor(labelsRef, id, name) {
|
|
4496
|
+
const m = labelsRef.current;
|
|
4497
|
+
const existing = m.get(id);
|
|
4498
|
+
if (existing) return existing;
|
|
4499
|
+
const n = m.size + 1;
|
|
4500
|
+
const v = {
|
|
4501
|
+
label: name && name !== id ? name : `AGENT#${n}`,
|
|
4502
|
+
color: STREAM_COLORS[(n - 1) % STREAM_COLORS.length]
|
|
4503
|
+
};
|
|
4504
|
+
m.set(id, v);
|
|
4505
|
+
return v;
|
|
4506
|
+
}
|
|
4507
|
+
function useSubagentEvents(events, dispatch, setActiveMaxContext) {
|
|
4508
|
+
const labelsRef = useRef(/* @__PURE__ */ new Map());
|
|
4509
|
+
const lbl = (id, name) => labelFor(labelsRef, id, name);
|
|
4510
|
+
useEffect(() => {
|
|
4511
|
+
const offSpawned = events.on("subagent.spawned", (e) => {
|
|
4512
|
+
const l = lbl(e.subagentId, e.name);
|
|
4513
|
+
dispatch({ type: "fleetSpawn", id: e.subagentId, name: e.name, provider: e.provider, model: e.model, transcriptPath: e.transcriptPath });
|
|
4514
|
+
const where = e.provider && e.model ? `${e.provider}/${e.model}` : "spawned";
|
|
4515
|
+
const desc = e.description ? ` \u2014 ${e.description.slice(0, 80)}` : "";
|
|
4516
|
+
dispatch({ type: "addEntry", entry: { kind: "subagent", agentLabel: l.label, agentColor: l.color, icon: "\u25B6", text: `${where}${desc}` } });
|
|
4517
|
+
});
|
|
4518
|
+
const offStarted = events.on("subagent.task_started", (e) => {
|
|
4519
|
+
const l = lbl(e.subagentId);
|
|
4520
|
+
dispatch({ type: "fleetStart", id: e.subagentId, taskId: e.taskId });
|
|
4521
|
+
const desc = e.description ? ` \u2014 ${e.description.slice(0, 80)}` : "";
|
|
4522
|
+
dispatch({ type: "addEntry", entry: { kind: "subagent", agentLabel: l.label, agentColor: l.color, icon: "\u25CF", text: `task started${desc}` } });
|
|
4523
|
+
});
|
|
4524
|
+
const offCompleted = events.on("subagent.task_completed", (e) => {
|
|
4525
|
+
const l = lbl(e.subagentId);
|
|
4526
|
+
const errKind = e.error?.kind;
|
|
4527
|
+
dispatch({ type: "fleetDone", id: e.subagentId, status: e.status, iterations: e.iterations, toolCalls: e.toolCalls, failureReason: errKind });
|
|
4528
|
+
const icon = e.status === "success" ? "\u2713" : e.status === "timeout" ? "\u23F1" : e.status === "stopped" ? "\u2298" : "\u2717";
|
|
4529
|
+
const errMsg = e.error?.message;
|
|
4530
|
+
const errMsgTail = errMsg ? ` \u2014 ${errMsg.replace(/\s+/g, " ").slice(0, 100)}${errMsg.length > 100 ? "\u2026" : ""}` : "";
|
|
4531
|
+
const errChip = errKind ? ` [${errKind}]` : "";
|
|
4532
|
+
const secs = (e.durationMs / 1e3).toFixed(e.durationMs < 1e4 ? 1 : 0);
|
|
4533
|
+
dispatch({ type: "addEntry", entry: { kind: "subagent", agentLabel: l.label, agentColor: l.color, icon, text: `${e.status} (${e.iterations} iter \xB7 ${e.toolCalls} tools \xB7 ${secs}s)${errChip}${errMsgTail}` } });
|
|
4534
|
+
});
|
|
4535
|
+
const offBudgetWarning = events.on("subagent.budget_warning", (e) => {
|
|
4536
|
+
const l = lbl(e.subagentId);
|
|
4537
|
+
dispatch({ type: "fleetBudgetWarning", id: e.subagentId, kind: e.kind, used: e.used, limit: e.limit });
|
|
4538
|
+
const timeoutSuffix = e.kind === "timeout" ? " (subagent continues running)" : " \u2014 extending";
|
|
4539
|
+
dispatch({ type: "addEntry", entry: { kind: "subagent", agentLabel: l.label, agentColor: l.color, icon: "\u26A1", text: `hitting ${e.kind} limit (${e.used}/${e.limit})${timeoutSuffix}` } });
|
|
4540
|
+
});
|
|
4541
|
+
const offBudgetExtended = events.on("subagent.budget_extended", (e) => {
|
|
4542
|
+
const l = lbl(e.subagentId);
|
|
4543
|
+
dispatch({ type: "fleetBudgetExtended", id: e.subagentId, totalExtensions: e.totalExtensions });
|
|
4544
|
+
dispatch({ type: "addEntry", entry: { kind: "subagent", agentLabel: l.label, agentColor: l.color, icon: "\u26A1", text: `extended ${e.kind} \u2192 ${e.newLimit} (\xD7${e.totalExtensions})` } });
|
|
4545
|
+
});
|
|
4546
|
+
const offIterationSummary = events.on("subagent.iteration_summary", (e) => {
|
|
4547
|
+
const l = lbl(e.subagentId);
|
|
4548
|
+
const costStr = e.costUsd > 0 ? ` \xB7 ${e.costUsd.toFixed(3)}` : "";
|
|
4549
|
+
const toolStr = e.currentTool ? ` \xB7 doing ${e.currentTool}` : "";
|
|
4550
|
+
const partial = e.partialText ? ` \xB7 "${e.partialText.slice(0, 60)}${e.partialText.length > 60 ? "\u2026" : ""}"` : "";
|
|
4551
|
+
dispatch({ type: "addEntry", entry: { kind: "subagent", agentLabel: l.label, agentColor: l.color, icon: "\u{1F4AC}", text: `L${e.iteration} \xB7 ${e.toolCalls} tools${costStr}${toolStr}${partial}` } });
|
|
4552
|
+
});
|
|
4553
|
+
const offCtxPct = events.on("subagent.ctx_pct", (e) => {
|
|
4554
|
+
dispatch({ type: "fleetCtxPct", id: e.subagentId, load: e.load, tokens: e.tokens, maxContext: e.maxContext });
|
|
4555
|
+
});
|
|
4556
|
+
const offLeaderCtxPct = events.on("ctx.pct", (e) => {
|
|
4557
|
+
setActiveMaxContext(e.maxContext);
|
|
4558
|
+
dispatch({ type: "leaderCtxPct", load: e.load, tokens: e.tokens, maxContext: e.maxContext });
|
|
4559
|
+
});
|
|
4560
|
+
const offLeaderMaxContext = events.on("ctx.max_context", (e) => {
|
|
4561
|
+
if (e.maxContext > 0) setActiveMaxContext(e.maxContext);
|
|
4562
|
+
});
|
|
4563
|
+
const offTool = events.on("subagent.tool_executed", (e) => {
|
|
4564
|
+
dispatch({ type: "fleetTool", id: e.subagentId, name: e.name, ok: e.ok, durationMs: e.durationMs, outputBytes: e.outputBytes });
|
|
4565
|
+
dispatch({ type: "fleetToolEnd", id: e.subagentId });
|
|
4566
|
+
});
|
|
4567
|
+
return () => {
|
|
4568
|
+
offSpawned();
|
|
4569
|
+
offStarted();
|
|
4570
|
+
offCompleted();
|
|
4571
|
+
offBudgetWarning();
|
|
4572
|
+
offBudgetExtended();
|
|
4573
|
+
offIterationSummary();
|
|
4574
|
+
offCtxPct();
|
|
4575
|
+
offLeaderCtxPct();
|
|
4576
|
+
offLeaderMaxContext();
|
|
4577
|
+
offTool();
|
|
4578
|
+
};
|
|
4579
|
+
}, [events, dispatch, setActiveMaxContext]);
|
|
4580
|
+
}
|
|
4581
|
+
function useBrainEvents(events, dispatch) {
|
|
4582
|
+
useEffect(() => {
|
|
4583
|
+
const requestSummary = (request) => `${request.source}: ${request.question}`.slice(0, 80);
|
|
4584
|
+
const addBrainEntry = (status, payload) => {
|
|
4585
|
+
const p = payload;
|
|
4586
|
+
const decision = p.decision.optionId ?? p.decision.text ?? p.decision.reason ?? p.decision.prompt ?? p.decision.type;
|
|
4587
|
+
dispatch({ type: "brainStatus", state: status, source: p.request.source, risk: p.request.risk, summary: decision });
|
|
4588
|
+
if (status === "ask_human") {
|
|
4589
|
+
dispatch({ type: "brainPromptSet", prompt: { requestId: p.request.id, source: p.request.source, risk: p.request.risk, question: p.request.question, context: p.request.context, options: p.request.options } });
|
|
4590
|
+
} else {
|
|
4591
|
+
dispatch({ type: "brainPromptClear" });
|
|
4592
|
+
}
|
|
4593
|
+
dispatch({ type: "addEntry", entry: { kind: "brain", status, source: p.request.source, risk: p.request.risk, question: p.request.question, decision, rationale: p.decision.rationale } });
|
|
4594
|
+
};
|
|
4595
|
+
const offRequested = events.on("brain.decision_requested", ({ request }) => {
|
|
4596
|
+
dispatch({ type: "brainStatus", state: "deciding", source: request.source, risk: request.risk, summary: requestSummary(request) });
|
|
4597
|
+
});
|
|
4598
|
+
const offAnswered = events.on("brain.decision_answered", (payload) => addBrainEntry("answered", payload));
|
|
4599
|
+
const offAskHuman = events.on("brain.decision_ask_human", (payload) => addBrainEntry("ask_human", payload));
|
|
4600
|
+
const offDenied = events.on("brain.decision_denied", (payload) => addBrainEntry("denied", payload));
|
|
4601
|
+
return () => {
|
|
4602
|
+
offRequested();
|
|
4603
|
+
offAnswered();
|
|
4604
|
+
offAskHuman();
|
|
4605
|
+
offDenied();
|
|
4606
|
+
};
|
|
4607
|
+
}, [events, dispatch]);
|
|
4608
|
+
}
|
|
4538
4609
|
var USAGE = "Usage:\n /kill \u2014 list active processes + breaker state\n /kill list \u2014 same as /kill\n /kill all \u2014 kill all tracked processes (SIGTERM \u2192 SIGKILL)\n /kill force \u2014 kill all with SIGKILL immediately\n /kill reset \u2014 reset the circuit breaker to closed\n /kill <pid> \u2014 kill a specific process by PID";
|
|
4539
4610
|
function createKillSlashCommand() {
|
|
4540
4611
|
return {
|
|
@@ -4754,14 +4825,8 @@ function oneLine(s2, max) {
|
|
|
4754
4825
|
const collapsed = s2.replace(/\s+/g, " ").trim();
|
|
4755
4826
|
return collapsed.length <= max ? collapsed : `${collapsed.slice(0, max - 1)}\u2026`;
|
|
4756
4827
|
}
|
|
4757
|
-
|
|
4758
|
-
|
|
4759
|
-
var INPUT_PROMPT = "\u203A ";
|
|
4760
|
-
function selectedSlashCommandLine(picker) {
|
|
4761
|
-
if (!picker.open || picker.matches.length === 0) return null;
|
|
4762
|
-
const picked = picker.matches[picker.selected];
|
|
4763
|
-
return picked ? `/${picked.name}` : null;
|
|
4764
|
-
}
|
|
4828
|
+
|
|
4829
|
+
// src/app-reducer.ts
|
|
4765
4830
|
function reducer(state, action) {
|
|
4766
4831
|
switch (action.type) {
|
|
4767
4832
|
case "addEntry": {
|
|
@@ -5721,6 +5786,14 @@ function reducer(state, action) {
|
|
|
5721
5786
|
}
|
|
5722
5787
|
}
|
|
5723
5788
|
}
|
|
5789
|
+
var WHEEL_STEP = 3;
|
|
5790
|
+
var MIN_VIEWPORT = 3;
|
|
5791
|
+
var INPUT_PROMPT = "\u203A ";
|
|
5792
|
+
function selectedSlashCommandLine(picker) {
|
|
5793
|
+
if (!picker.open || picker.matches.length === 0) return null;
|
|
5794
|
+
const picked = picker.matches[picker.selected];
|
|
5795
|
+
return picked ? `/${picked.name}` : null;
|
|
5796
|
+
}
|
|
5724
5797
|
var PASTE_THRESHOLD_CHARS = 200;
|
|
5725
5798
|
function buildSteeringPreamble(snapshot, newDirection) {
|
|
5726
5799
|
const lines = ["[STEERING \u2014 I pressed Esc to interrupt you mid-task on purpose.", ""];
|
|
@@ -5938,7 +6011,7 @@ function App({
|
|
|
5938
6011
|
const inputGateRef = useRef(false);
|
|
5939
6012
|
const lastEnterAtRef = useRef(0);
|
|
5940
6013
|
const tokenPreviewsRef = useRef(/* @__PURE__ */ new Map());
|
|
5941
|
-
const projectName =
|
|
6014
|
+
const projectName = React6.useMemo(() => {
|
|
5942
6015
|
const base = path2.basename(projectRoot);
|
|
5943
6016
|
return base && base !== path2.sep ? base : void 0;
|
|
5944
6017
|
}, [projectRoot]);
|
|
@@ -5954,7 +6027,7 @@ function App({
|
|
|
5954
6027
|
const preRowsRef = useRef(0);
|
|
5955
6028
|
const liveStripRef = useRef(null);
|
|
5956
6029
|
const liveStripRowsRef = useRef(0);
|
|
5957
|
-
|
|
6030
|
+
React6.useLayoutEffect(() => {
|
|
5958
6031
|
if (!managedLive) return;
|
|
5959
6032
|
const node = bottomRef.current;
|
|
5960
6033
|
if (!node) return;
|
|
@@ -5984,7 +6057,7 @@ function App({
|
|
|
5984
6057
|
const DOUBLE_CLICK_MS = 500;
|
|
5985
6058
|
const DOUBLE_CLICK_DIST = 5;
|
|
5986
6059
|
const statusChipRef = useRef({ version: appVersion, model, fleetRunning: 0, yolo, autonomy: "off" });
|
|
5987
|
-
const handleMouse =
|
|
6060
|
+
const handleMouse = React6.useCallback(
|
|
5988
6061
|
(ev) => {
|
|
5989
6062
|
const s2 = stateRef.current;
|
|
5990
6063
|
if (ev.type === "wheel") {
|
|
@@ -6180,7 +6253,7 @@ function App({
|
|
|
6180
6253
|
state.picker.open,
|
|
6181
6254
|
state.picker.selected
|
|
6182
6255
|
]);
|
|
6183
|
-
const handleRewindTo =
|
|
6256
|
+
const handleRewindTo = React6.useCallback(
|
|
6184
6257
|
async (checkpointIndex) => {
|
|
6185
6258
|
const sessionId = agent.ctx.session.id;
|
|
6186
6259
|
if (!sessionId) return;
|
|
@@ -6199,13 +6272,13 @@ function App({
|
|
|
6199
6272
|
dispatch({ type: "clearInput" });
|
|
6200
6273
|
};
|
|
6201
6274
|
const startedAtRef = useRef(Date.now());
|
|
6202
|
-
const [nowTick, setNowTick] =
|
|
6275
|
+
const [nowTick, setNowTick] = React6.useState(Date.now());
|
|
6203
6276
|
useEffect(() => {
|
|
6204
6277
|
const t = setInterval(() => setNowTick(Date.now()), 1e3);
|
|
6205
6278
|
return () => clearInterval(t);
|
|
6206
6279
|
}, []);
|
|
6207
6280
|
const elapsedMs = nowTick - startedAtRef.current;
|
|
6208
|
-
const [gitInfo, setGitInfo] =
|
|
6281
|
+
const [gitInfo, setGitInfo] = React6.useState(null);
|
|
6209
6282
|
useEffect(() => {
|
|
6210
6283
|
let cancelled = false;
|
|
6211
6284
|
const refresh = () => {
|
|
@@ -6270,16 +6343,16 @@ function App({
|
|
|
6270
6343
|
};
|
|
6271
6344
|
return { leader: leaderEntry, ...state.fleet };
|
|
6272
6345
|
}, [state.fleet, state.leader, state.status, provider, model, effectiveMaxContext]);
|
|
6273
|
-
const
|
|
6346
|
+
const STREAM_COLORS2 = ["cyan", "magenta", "yellow", "green", "blue"];
|
|
6274
6347
|
const labelsRef = useRef(/* @__PURE__ */ new Map());
|
|
6275
|
-
const
|
|
6348
|
+
const labelFor2 = (id, name) => {
|
|
6276
6349
|
const m = labelsRef.current;
|
|
6277
6350
|
const existing = m.get(id);
|
|
6278
6351
|
if (existing) return existing;
|
|
6279
6352
|
const n = m.size + 1;
|
|
6280
6353
|
const v = {
|
|
6281
6354
|
label: name && name !== id ? name : `AGENT#${n}`,
|
|
6282
|
-
color:
|
|
6355
|
+
color: STREAM_COLORS2[(n - 1) % STREAM_COLORS2.length]
|
|
6283
6356
|
};
|
|
6284
6357
|
m.set(id, v);
|
|
6285
6358
|
return v;
|
|
@@ -6722,16 +6795,16 @@ function App({
|
|
|
6722
6795
|
slashRegistry.unregister("agents");
|
|
6723
6796
|
};
|
|
6724
6797
|
}, [slashRegistry]);
|
|
6725
|
-
const openModelPicker =
|
|
6798
|
+
const openModelPicker = React6.useCallback(async () => {
|
|
6726
6799
|
if (!getPickableProviders) return;
|
|
6727
6800
|
const providers = await getPickableProviders();
|
|
6728
6801
|
dispatch({ type: "modelPickerOpen", providers });
|
|
6729
6802
|
}, [getPickableProviders]);
|
|
6730
|
-
const openAutonomyPicker =
|
|
6803
|
+
const openAutonomyPicker = React6.useCallback(() => {
|
|
6731
6804
|
if (!switchAutonomy) return;
|
|
6732
6805
|
dispatch({ type: "autonomyPickerOpen", options: AUTONOMY_OPTIONS });
|
|
6733
6806
|
}, [switchAutonomy]);
|
|
6734
|
-
const openSettings =
|
|
6807
|
+
const openSettings = React6.useCallback(() => {
|
|
6735
6808
|
if (!getSettings) return;
|
|
6736
6809
|
const s2 = getSettings();
|
|
6737
6810
|
dispatch({ type: "settingsOpen", mode: s2.mode, delayMs: s2.delayMs });
|
|
@@ -6915,172 +6988,7 @@ function App({
|
|
|
6915
6988
|
useEffect(() => {
|
|
6916
6989
|
streamFleetRef.current = state.streamFleet;
|
|
6917
6990
|
}, [state.streamFleet]);
|
|
6918
|
-
|
|
6919
|
-
const offSpawned = events.on("subagent.spawned", (e) => {
|
|
6920
|
-
const lbl = labelFor(e.subagentId, e.name);
|
|
6921
|
-
dispatch({
|
|
6922
|
-
type: "fleetSpawn",
|
|
6923
|
-
id: e.subagentId,
|
|
6924
|
-
name: e.name,
|
|
6925
|
-
provider: e.provider,
|
|
6926
|
-
model: e.model,
|
|
6927
|
-
transcriptPath: e.transcriptPath
|
|
6928
|
-
});
|
|
6929
|
-
const where = e.provider && e.model ? `${e.provider}/${e.model}` : "spawned";
|
|
6930
|
-
const desc = e.description ? ` \u2014 ${e.description.slice(0, 80)}` : "";
|
|
6931
|
-
dispatch({
|
|
6932
|
-
type: "addEntry",
|
|
6933
|
-
entry: {
|
|
6934
|
-
kind: "subagent",
|
|
6935
|
-
agentLabel: lbl.label,
|
|
6936
|
-
agentColor: lbl.color,
|
|
6937
|
-
icon: "\u25B6",
|
|
6938
|
-
text: `${where}${desc}`
|
|
6939
|
-
}
|
|
6940
|
-
});
|
|
6941
|
-
});
|
|
6942
|
-
const offStarted = events.on("subagent.task_started", (e) => {
|
|
6943
|
-
const lbl = labelFor(e.subagentId);
|
|
6944
|
-
dispatch({ type: "fleetStart", id: e.subagentId, taskId: e.taskId });
|
|
6945
|
-
const desc = e.description ? ` \u2014 ${e.description.slice(0, 80)}` : "";
|
|
6946
|
-
dispatch({
|
|
6947
|
-
type: "addEntry",
|
|
6948
|
-
entry: {
|
|
6949
|
-
kind: "subagent",
|
|
6950
|
-
agentLabel: lbl.label,
|
|
6951
|
-
agentColor: lbl.color,
|
|
6952
|
-
icon: "\u25CF",
|
|
6953
|
-
text: `task started${desc}`
|
|
6954
|
-
}
|
|
6955
|
-
});
|
|
6956
|
-
});
|
|
6957
|
-
const offCompleted = events.on("subagent.task_completed", (e) => {
|
|
6958
|
-
const lbl = labelFor(e.subagentId);
|
|
6959
|
-
const errKind = e.error?.kind;
|
|
6960
|
-
dispatch({
|
|
6961
|
-
type: "fleetDone",
|
|
6962
|
-
id: e.subagentId,
|
|
6963
|
-
status: e.status,
|
|
6964
|
-
iterations: e.iterations,
|
|
6965
|
-
toolCalls: e.toolCalls,
|
|
6966
|
-
failureReason: errKind
|
|
6967
|
-
});
|
|
6968
|
-
const icon = e.status === "success" ? "\u2713" : e.status === "timeout" ? "\u23F1" : e.status === "stopped" ? "\u2298" : "\u2717";
|
|
6969
|
-
const errMsg = e.error?.message;
|
|
6970
|
-
const errMsgTail = errMsg ? ` \u2014 ${errMsg.replace(/\s+/g, " ").slice(0, 100)}${errMsg.length > 100 ? "\u2026" : ""}` : "";
|
|
6971
|
-
const errChip = errKind ? ` [${errKind}]` : "";
|
|
6972
|
-
const secs = (e.durationMs / 1e3).toFixed(e.durationMs < 1e4 ? 1 : 0);
|
|
6973
|
-
dispatch({
|
|
6974
|
-
type: "addEntry",
|
|
6975
|
-
entry: {
|
|
6976
|
-
kind: "subagent",
|
|
6977
|
-
agentLabel: lbl.label,
|
|
6978
|
-
agentColor: lbl.color,
|
|
6979
|
-
icon,
|
|
6980
|
-
text: `${e.status} (${e.iterations} iter \xB7 ${e.toolCalls} tools \xB7 ${secs}s)${errChip}${errMsgTail}`
|
|
6981
|
-
}
|
|
6982
|
-
});
|
|
6983
|
-
});
|
|
6984
|
-
const offBudgetWarning = events.on("subagent.budget_warning", (e) => {
|
|
6985
|
-
const lbl = labelFor(e.subagentId);
|
|
6986
|
-
dispatch({
|
|
6987
|
-
type: "fleetBudgetWarning",
|
|
6988
|
-
id: e.subagentId,
|
|
6989
|
-
kind: e.kind,
|
|
6990
|
-
used: e.used,
|
|
6991
|
-
limit: e.limit
|
|
6992
|
-
});
|
|
6993
|
-
const timeoutSuffix = e.kind === "timeout" ? " (subagent continues running)" : " \u2014 extending";
|
|
6994
|
-
dispatch({
|
|
6995
|
-
type: "addEntry",
|
|
6996
|
-
entry: {
|
|
6997
|
-
kind: "subagent",
|
|
6998
|
-
agentLabel: lbl.label,
|
|
6999
|
-
agentColor: lbl.color,
|
|
7000
|
-
icon: "\u26A1",
|
|
7001
|
-
text: `hitting ${e.kind} limit (${e.used}/${e.limit})${timeoutSuffix}`
|
|
7002
|
-
}
|
|
7003
|
-
});
|
|
7004
|
-
});
|
|
7005
|
-
const offBudgetExtended = events.on("subagent.budget_extended", (e) => {
|
|
7006
|
-
const lbl = labelFor(e.subagentId);
|
|
7007
|
-
dispatch({
|
|
7008
|
-
type: "fleetBudgetExtended",
|
|
7009
|
-
id: e.subagentId,
|
|
7010
|
-
totalExtensions: e.totalExtensions
|
|
7011
|
-
});
|
|
7012
|
-
dispatch({
|
|
7013
|
-
type: "addEntry",
|
|
7014
|
-
entry: {
|
|
7015
|
-
kind: "subagent",
|
|
7016
|
-
agentLabel: lbl.label,
|
|
7017
|
-
agentColor: lbl.color,
|
|
7018
|
-
icon: "\u26A1",
|
|
7019
|
-
text: `extended ${e.kind} \u2192 ${e.newLimit} (\xD7${e.totalExtensions})`
|
|
7020
|
-
}
|
|
7021
|
-
});
|
|
7022
|
-
});
|
|
7023
|
-
const offIterationSummary = events.on("subagent.iteration_summary", (e) => {
|
|
7024
|
-
const lbl = labelFor(e.subagentId);
|
|
7025
|
-
const costStr = e.costUsd > 0 ? ` \xB7 ${e.costUsd.toFixed(3)}` : "";
|
|
7026
|
-
const toolStr = e.currentTool ? ` \xB7 doing ${e.currentTool}` : "";
|
|
7027
|
-
const partial = e.partialText ? ` \xB7 "${e.partialText.slice(0, 60)}${e.partialText.length > 60 ? "\u2026" : ""}"` : "";
|
|
7028
|
-
dispatch({
|
|
7029
|
-
type: "addEntry",
|
|
7030
|
-
entry: {
|
|
7031
|
-
kind: "subagent",
|
|
7032
|
-
agentLabel: lbl.label,
|
|
7033
|
-
agentColor: lbl.color,
|
|
7034
|
-
icon: "\u{1F4AC}",
|
|
7035
|
-
text: `L${e.iteration} \xB7 ${e.toolCalls} tools${costStr}${toolStr}${partial}`
|
|
7036
|
-
}
|
|
7037
|
-
});
|
|
7038
|
-
});
|
|
7039
|
-
const offCtxPct = events.on("subagent.ctx_pct", (e) => {
|
|
7040
|
-
dispatch({
|
|
7041
|
-
type: "fleetCtxPct",
|
|
7042
|
-
id: e.subagentId,
|
|
7043
|
-
load: e.load,
|
|
7044
|
-
tokens: e.tokens,
|
|
7045
|
-
maxContext: e.maxContext
|
|
7046
|
-
});
|
|
7047
|
-
});
|
|
7048
|
-
const offLeaderCtxPct = events.on("ctx.pct", (e) => {
|
|
7049
|
-
setActiveMaxContext(e.maxContext);
|
|
7050
|
-
dispatch({
|
|
7051
|
-
type: "leaderCtxPct",
|
|
7052
|
-
load: e.load,
|
|
7053
|
-
tokens: e.tokens,
|
|
7054
|
-
maxContext: e.maxContext
|
|
7055
|
-
});
|
|
7056
|
-
});
|
|
7057
|
-
const offLeaderMaxContext = events.on("ctx.max_context", (e) => {
|
|
7058
|
-
if (e.maxContext > 0) setActiveMaxContext(e.maxContext);
|
|
7059
|
-
});
|
|
7060
|
-
const offTool = events.on("subagent.tool_executed", (e) => {
|
|
7061
|
-
dispatch({
|
|
7062
|
-
type: "fleetTool",
|
|
7063
|
-
id: e.subagentId,
|
|
7064
|
-
name: e.name,
|
|
7065
|
-
ok: e.ok,
|
|
7066
|
-
durationMs: e.durationMs,
|
|
7067
|
-
outputBytes: e.outputBytes
|
|
7068
|
-
});
|
|
7069
|
-
dispatch({ type: "fleetToolEnd", id: e.subagentId });
|
|
7070
|
-
});
|
|
7071
|
-
return () => {
|
|
7072
|
-
offSpawned();
|
|
7073
|
-
offStarted();
|
|
7074
|
-
offCompleted();
|
|
7075
|
-
offBudgetWarning();
|
|
7076
|
-
offBudgetExtended();
|
|
7077
|
-
offIterationSummary();
|
|
7078
|
-
offCtxPct();
|
|
7079
|
-
offLeaderCtxPct();
|
|
7080
|
-
offLeaderMaxContext();
|
|
7081
|
-
offTool();
|
|
7082
|
-
};
|
|
7083
|
-
}, [events, director]);
|
|
6991
|
+
useSubagentEvents(events, dispatch, setActiveMaxContext);
|
|
7084
6992
|
useEffect(() => {
|
|
7085
6993
|
const offCheckpoint = events.on("checkpoint.written", (e) => {
|
|
7086
6994
|
dispatch({
|
|
@@ -7105,71 +7013,7 @@ function App({
|
|
|
7105
7013
|
offRewound();
|
|
7106
7014
|
};
|
|
7107
7015
|
}, [events, onClearHistory]);
|
|
7108
|
-
|
|
7109
|
-
const requestSummary = (request) => `${request.source}: ${request.question}`.slice(0, 80);
|
|
7110
|
-
const addBrainEntry = (status, payload) => {
|
|
7111
|
-
const p = payload;
|
|
7112
|
-
const decision = p.decision.optionId ?? p.decision.text ?? p.decision.reason ?? p.decision.prompt ?? p.decision.type;
|
|
7113
|
-
dispatch({
|
|
7114
|
-
type: "brainStatus",
|
|
7115
|
-
state: status,
|
|
7116
|
-
source: p.request.source,
|
|
7117
|
-
risk: p.request.risk,
|
|
7118
|
-
summary: decision
|
|
7119
|
-
});
|
|
7120
|
-
if (status === "ask_human") {
|
|
7121
|
-
dispatch({
|
|
7122
|
-
type: "brainPromptSet",
|
|
7123
|
-
prompt: {
|
|
7124
|
-
requestId: p.request.id,
|
|
7125
|
-
source: p.request.source,
|
|
7126
|
-
risk: p.request.risk,
|
|
7127
|
-
question: p.request.question,
|
|
7128
|
-
context: p.request.context,
|
|
7129
|
-
options: p.request.options
|
|
7130
|
-
}
|
|
7131
|
-
});
|
|
7132
|
-
} else {
|
|
7133
|
-
dispatch({ type: "brainPromptClear" });
|
|
7134
|
-
}
|
|
7135
|
-
dispatch({
|
|
7136
|
-
type: "addEntry",
|
|
7137
|
-
entry: {
|
|
7138
|
-
kind: "brain",
|
|
7139
|
-
status,
|
|
7140
|
-
source: p.request.source,
|
|
7141
|
-
risk: p.request.risk,
|
|
7142
|
-
question: p.request.question,
|
|
7143
|
-
decision,
|
|
7144
|
-
rationale: p.decision.rationale
|
|
7145
|
-
}
|
|
7146
|
-
});
|
|
7147
|
-
};
|
|
7148
|
-
const offRequested = events.on("brain.decision_requested", ({ request }) => {
|
|
7149
|
-
dispatch({
|
|
7150
|
-
type: "brainStatus",
|
|
7151
|
-
state: "deciding",
|
|
7152
|
-
source: request.source,
|
|
7153
|
-
risk: request.risk,
|
|
7154
|
-
summary: requestSummary(request)
|
|
7155
|
-
});
|
|
7156
|
-
});
|
|
7157
|
-
const offAnswered = events.on("brain.decision_answered", (payload) => {
|
|
7158
|
-
addBrainEntry("answered", payload);
|
|
7159
|
-
});
|
|
7160
|
-
const offAskHuman = events.on("brain.decision_ask_human", (payload) => {
|
|
7161
|
-
addBrainEntry("ask_human", payload);
|
|
7162
|
-
});
|
|
7163
|
-
const offDenied = events.on("brain.decision_denied", (payload) => {
|
|
7164
|
-
addBrainEntry("denied", payload);
|
|
7165
|
-
});
|
|
7166
|
-
return () => {
|
|
7167
|
-
offRequested();
|
|
7168
|
-
offAnswered();
|
|
7169
|
-
offAskHuman();
|
|
7170
|
-
offDenied();
|
|
7171
|
-
};
|
|
7172
|
-
}, [events]);
|
|
7016
|
+
useBrainEvents(events, dispatch);
|
|
7173
7017
|
useEffect(() => {
|
|
7174
7018
|
if (!subscribeAutoPhase) return;
|
|
7175
7019
|
const handler = (event, payload) => {
|
|
@@ -7414,7 +7258,7 @@ function App({
|
|
|
7414
7258
|
for (const [id, text] of streamBuf) {
|
|
7415
7259
|
const trimmed = text.trim();
|
|
7416
7260
|
if (!trimmed) continue;
|
|
7417
|
-
const lbl =
|
|
7261
|
+
const lbl = labelFor2(id);
|
|
7418
7262
|
enq({ type: "fleetMessage", id, text: trimmed });
|
|
7419
7263
|
if (streamFleetRef.current) {
|
|
7420
7264
|
enq({
|
|
@@ -7442,7 +7286,7 @@ function App({
|
|
|
7442
7286
|
provider: meta?.provider,
|
|
7443
7287
|
model: meta?.model
|
|
7444
7288
|
});
|
|
7445
|
-
|
|
7289
|
+
labelFor2(s2.id, meta?.name ?? s2.name);
|
|
7446
7290
|
}
|
|
7447
7291
|
dispatch({
|
|
7448
7292
|
type: "fleetCost",
|
|
@@ -7473,7 +7317,7 @@ function App({
|
|
|
7473
7317
|
provider: meta?.provider,
|
|
7474
7318
|
model: meta?.model
|
|
7475
7319
|
});
|
|
7476
|
-
const lbl =
|
|
7320
|
+
const lbl = labelFor2(e.subagentId, meta?.name);
|
|
7477
7321
|
if (streamFleetRef.current) {
|
|
7478
7322
|
const where = meta?.provider && meta?.model ? `${meta.provider}/${meta.model}` : "spawned";
|
|
7479
7323
|
dispatch2({
|
|
@@ -7558,7 +7402,7 @@ function App({
|
|
|
7558
7402
|
});
|
|
7559
7403
|
dispatch2({ type: "fleetToolEnd", id: e.subagentId });
|
|
7560
7404
|
if (streamFleetRef.current && p?.name) {
|
|
7561
|
-
const lbl =
|
|
7405
|
+
const lbl = labelFor2(e.subagentId);
|
|
7562
7406
|
dispatch2({
|
|
7563
7407
|
type: "addEntry",
|
|
7564
7408
|
entry: {
|
|
@@ -7951,6 +7795,9 @@ function App({
|
|
|
7951
7795
|
return;
|
|
7952
7796
|
}
|
|
7953
7797
|
if (isEnter) {
|
|
7798
|
+
const now = Date.now();
|
|
7799
|
+
if (now - lastEnterAtRef.current < 50) return;
|
|
7800
|
+
lastEnterAtRef.current = now;
|
|
7954
7801
|
inputGateRef.current = true;
|
|
7955
7802
|
try {
|
|
7956
7803
|
if (state.modelPicker.step === "provider") {
|
|
@@ -8000,6 +7847,9 @@ function App({
|
|
|
8000
7847
|
return;
|
|
8001
7848
|
}
|
|
8002
7849
|
if (isEnter) {
|
|
7850
|
+
const now = Date.now();
|
|
7851
|
+
if (now - lastEnterAtRef.current < 50) return;
|
|
7852
|
+
lastEnterAtRef.current = now;
|
|
8003
7853
|
const opt = state.autonomyPicker.options[state.autonomyPicker.selected];
|
|
8004
7854
|
if (!opt) return;
|
|
8005
7855
|
const err = switchAutonomy?.(opt.mode);
|
|
@@ -8034,6 +7884,9 @@ function App({
|
|
|
8034
7884
|
return;
|
|
8035
7885
|
}
|
|
8036
7886
|
if (isEnter) {
|
|
7887
|
+
const now = Date.now();
|
|
7888
|
+
if (now - lastEnterAtRef.current < 50) return;
|
|
7889
|
+
lastEnterAtRef.current = now;
|
|
8037
7890
|
const { mode, delayMs } = state.settingsPicker;
|
|
8038
7891
|
const err = await saveSettings?.({ mode, delayMs });
|
|
8039
7892
|
if (err) {
|
|
@@ -8095,6 +7948,9 @@ function App({
|
|
|
8095
7948
|
return;
|
|
8096
7949
|
}
|
|
8097
7950
|
if (isEnter) {
|
|
7951
|
+
const now = Date.now();
|
|
7952
|
+
if (now - lastEnterAtRef.current < 50) return;
|
|
7953
|
+
lastEnterAtRef.current = now;
|
|
8098
7954
|
inputGateRef.current = true;
|
|
8099
7955
|
try {
|
|
8100
7956
|
await acceptPickerSelection();
|
|
@@ -9250,7 +9106,7 @@ async function runTui(opts) {
|
|
|
9250
9106
|
let instance;
|
|
9251
9107
|
try {
|
|
9252
9108
|
instance = render(
|
|
9253
|
-
|
|
9109
|
+
React6.createElement(App, {
|
|
9254
9110
|
agent: opts.agent,
|
|
9255
9111
|
slashRegistry: opts.slashRegistry,
|
|
9256
9112
|
attachments: opts.attachments,
|