@wrongstack/tui 0.77.0 → 0.84.1
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/README.md +6 -10
- package/dist/index.d.ts +44 -61
- package/dist/index.js +326 -410
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { writeErr, InputBuilder, DefaultSessionRewinder, writeOut, formatTodosList, buildGoalPreamble, shouldEnhance, enhanceUserPrompt, recentTextTurns, normalizedEqual, buildChildEnv } from '@wrongstack/core';
|
|
2
2
|
export { buildGoalPreamble } from '@wrongstack/core';
|
|
3
|
-
import { Box, Text, render, useApp, useStdout,
|
|
4
|
-
import React6, { useState, useEffect, useReducer, useRef, useMemo, useCallback
|
|
3
|
+
import { Box, Text, render, useApp, useStdout, Static, useInput, useStdin } from 'ink';
|
|
4
|
+
import React6, { useState, useEffect, useReducer, useRef, useMemo, useCallback } from 'react';
|
|
5
5
|
import * as fs2 from 'fs/promises';
|
|
6
6
|
import * as path2 from 'path';
|
|
7
7
|
import { routeImagesForModel } from '@wrongstack/runtime/vision';
|
|
8
8
|
import { getIndexState, onIndexStateChange, getProcessRegistry } from '@wrongstack/tools';
|
|
9
9
|
import { readClipboardImage } from '@wrongstack/runtime/clipboard';
|
|
10
10
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
11
|
+
import { expectDefined as expectDefined$1 } from '@wrongstack/core/utils';
|
|
11
12
|
import { spawn } from 'child_process';
|
|
12
13
|
|
|
13
14
|
// src/run-tui.ts
|
|
@@ -34,6 +35,12 @@ var theme = Object.freeze({
|
|
|
34
35
|
diffAddBg: "greenBright",
|
|
35
36
|
diffDelBg: "redBright"
|
|
36
37
|
});
|
|
38
|
+
function expectDefined(value) {
|
|
39
|
+
if (value === null || value === void 0) {
|
|
40
|
+
throw new Error("Expected value to be defined");
|
|
41
|
+
}
|
|
42
|
+
return value;
|
|
43
|
+
}
|
|
37
44
|
var MODE_ICONS = {
|
|
38
45
|
teach: "\u{1F9D1}\u200D\u{1F3EB}",
|
|
39
46
|
brief: "\u26A1",
|
|
@@ -55,7 +62,7 @@ function modeIcon(label) {
|
|
|
55
62
|
var COMPACT_THRESHOLD = 50;
|
|
56
63
|
var COMFORTABLE_THRESHOLD = 90;
|
|
57
64
|
var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
58
|
-
var SPINNER_INTERVAL_MS =
|
|
65
|
+
var SPINNER_INTERVAL_MS = 250;
|
|
59
66
|
function StatusBar({
|
|
60
67
|
model,
|
|
61
68
|
version,
|
|
@@ -65,7 +72,7 @@ function StatusBar({
|
|
|
65
72
|
queueCount = 0,
|
|
66
73
|
yolo = false,
|
|
67
74
|
autonomy,
|
|
68
|
-
|
|
75
|
+
startedAt,
|
|
69
76
|
todos,
|
|
70
77
|
plan,
|
|
71
78
|
fleet,
|
|
@@ -98,6 +105,12 @@ function StatusBar({
|
|
|
98
105
|
const usage = tokenCounter?.total();
|
|
99
106
|
const cost = tokenCounter?.estimateCost();
|
|
100
107
|
const cache2 = tokenCounter?.cacheStats();
|
|
108
|
+
const [elapsedMs, setElapsedMs] = useState(startedAt ? Date.now() - startedAt : 0);
|
|
109
|
+
useEffect(() => {
|
|
110
|
+
if (startedAt == null) return;
|
|
111
|
+
const t = setInterval(() => setElapsedMs(Date.now() - startedAt), 1e3);
|
|
112
|
+
return () => clearInterval(t);
|
|
113
|
+
}, [startedAt]);
|
|
101
114
|
const [spinnerIdx, setSpinnerIdx] = useState(0);
|
|
102
115
|
useEffect(() => {
|
|
103
116
|
if (state === "idle" || state === "aborting") return;
|
|
@@ -107,10 +120,11 @@ function StatusBar({
|
|
|
107
120
|
);
|
|
108
121
|
return () => clearInterval(t);
|
|
109
122
|
}, [state]);
|
|
110
|
-
const spinner = SPINNER_FRAMES[spinnerIdx];
|
|
123
|
+
const spinner = expectDefined(SPINNER_FRAMES[spinnerIdx]);
|
|
111
124
|
const { label: stateLabel, color: stateColor } = stateChip(state, fleet?.running ?? 0);
|
|
112
125
|
const statePrefix = state === "idle" || state === "aborting" ? "\u25CF" : spinner;
|
|
113
|
-
const
|
|
126
|
+
const thinking = state === "running" || state === "streaming";
|
|
127
|
+
const hasSecondLine = yolo || autonomy && autonomy !== "off" || startedAt != null || git !== null && git !== void 0 || projectName !== void 0 && projectName.length > 0 || goalSummary !== null && goalSummary !== void 0 || !!modeLabel;
|
|
114
128
|
const fleetHasActivity = fleet && (fleet.running > 0 || fleet.idle > 0 || fleet.pending > 0 || fleet.completed > 0) || subagentCount > 0;
|
|
115
129
|
const hasBrainActivity = !!brain && brain.state !== "idle";
|
|
116
130
|
const hasThirdLine = todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0) || plan && (plan.open > 0 || plan.inProgress > 0 || plan.done > 0) || fleetHasActivity || hasBrainActivity;
|
|
@@ -128,7 +142,7 @@ function StatusBar({
|
|
|
128
142
|
/* @__PURE__ */ jsx(Box, { flexDirection: "row", gap: 2, children: isCompact ? (
|
|
129
143
|
// Ultra-compact: state · model
|
|
130
144
|
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
131
|
-
/* @__PURE__ */ jsxs(Text, { color: stateColor, children: [
|
|
145
|
+
thinking ? /* @__PURE__ */ jsx(WaveText, { text: `${statePrefix}${stateLabel}`, phase: spinnerIdx }) : /* @__PURE__ */ jsxs(Text, { color: stateColor, children: [
|
|
132
146
|
statePrefix,
|
|
133
147
|
stateLabel
|
|
134
148
|
] }),
|
|
@@ -148,7 +162,7 @@ function StatusBar({
|
|
|
148
162
|
] }),
|
|
149
163
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" })
|
|
150
164
|
] }) : null,
|
|
151
|
-
/* @__PURE__ */ jsxs(Text, { color: stateColor, children: [
|
|
165
|
+
thinking ? /* @__PURE__ */ jsx(WaveText, { text: `${statePrefix} ${stateLabel}`, phase: spinnerIdx }) : /* @__PURE__ */ jsxs(Text, { color: stateColor, children: [
|
|
152
166
|
statePrefix,
|
|
153
167
|
" ",
|
|
154
168
|
stateLabel
|
|
@@ -205,7 +219,7 @@ function StatusBar({
|
|
|
205
219
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
|
|
206
220
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: hint })
|
|
207
221
|
] }) : null,
|
|
208
|
-
indexState
|
|
222
|
+
indexState?.indexing ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
209
223
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
|
|
210
224
|
/* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
|
|
211
225
|
"\u2699 indexing ",
|
|
@@ -244,14 +258,14 @@ function StatusBar({
|
|
|
244
258
|
] })
|
|
245
259
|
] }) : null,
|
|
246
260
|
projectName ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
247
|
-
yolo ||
|
|
261
|
+
yolo || startedAt != null ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
|
|
248
262
|
/* @__PURE__ */ jsxs(Text, { color: "blue", children: [
|
|
249
263
|
"\u{1F4C1} ",
|
|
250
264
|
projectName
|
|
251
265
|
] })
|
|
252
266
|
] }) : null,
|
|
253
267
|
goalSummary ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
254
|
-
yolo ||
|
|
268
|
+
yolo || startedAt != null || projectName ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
|
|
255
269
|
/* @__PURE__ */ jsxs(
|
|
256
270
|
Text,
|
|
257
271
|
{
|
|
@@ -271,11 +285,11 @@ function StatusBar({
|
|
|
271
285
|
)
|
|
272
286
|
] }) : null,
|
|
273
287
|
modeLabel ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
274
|
-
yolo || autonomy && autonomy !== "off" || eternalStage ||
|
|
288
|
+
yolo || autonomy && autonomy !== "off" || eternalStage || startedAt != null || projectName || goalSummary ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
|
|
275
289
|
/* @__PURE__ */ jsx(Text, { color: "cyan", children: modeIcon(modeLabel) })
|
|
276
290
|
] }) : null,
|
|
277
291
|
git ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
278
|
-
yolo ||
|
|
292
|
+
yolo || startedAt != null || projectName ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
|
|
279
293
|
/* @__PURE__ */ jsxs(Text, { children: [
|
|
280
294
|
/* @__PURE__ */ jsxs(Text, { color: "magenta", children: [
|
|
281
295
|
"\u2387 ",
|
|
@@ -375,7 +389,7 @@ function StatusBar({
|
|
|
375
389
|
/* @__PURE__ */ jsxs(Text, { children: [
|
|
376
390
|
/* @__PURE__ */ jsx(Text, { color: a.color, bold: true, children: a.label }),
|
|
377
391
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " " }),
|
|
378
|
-
/* @__PURE__ */ jsx(Text, {
|
|
392
|
+
/* @__PURE__ */ jsx(Text, { dimColor: !a.running, ...a.running ? { color: "yellow" } : {}, children: a.running ? "\u25B6" : "\xB7" }),
|
|
379
393
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " " }),
|
|
380
394
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: fmtElapsed(a.elapsedMs) }),
|
|
381
395
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " \xB7 " }),
|
|
@@ -504,6 +518,26 @@ function stateChip(state, fleetRunning) {
|
|
|
504
518
|
if (state === "aborting") return { label: "aborting\u2026", color: "yellow" };
|
|
505
519
|
return { label: "thinking\u2026", color: "green" };
|
|
506
520
|
}
|
|
521
|
+
var WAVE_COLORS = [
|
|
522
|
+
"#ff5f5f",
|
|
523
|
+
"#ff8f3f",
|
|
524
|
+
"#ffd23f",
|
|
525
|
+
"#bce84a",
|
|
526
|
+
"#6bcb77",
|
|
527
|
+
"#3dd9c0",
|
|
528
|
+
"#3fb6ff",
|
|
529
|
+
"#5f8bff",
|
|
530
|
+
"#845ef7",
|
|
531
|
+
"#b15bff",
|
|
532
|
+
"#f06595",
|
|
533
|
+
"#ff5fa2"
|
|
534
|
+
];
|
|
535
|
+
function WaveText({ text, phase }) {
|
|
536
|
+
return /* @__PURE__ */ jsx(Text, { bold: true, children: Array.from(text).map((ch, i) => (
|
|
537
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: glyph order is positional and re-rendered each tick
|
|
538
|
+
/* @__PURE__ */ jsx(Text, { color: WAVE_COLORS[(i + phase) % WAVE_COLORS.length], children: ch }, i)
|
|
539
|
+
)) });
|
|
540
|
+
}
|
|
507
541
|
var FILLED = "\u2588";
|
|
508
542
|
var EMPTY = "\u2591";
|
|
509
543
|
function renderProgress(ratio, width) {
|
|
@@ -565,7 +599,7 @@ function bucketActivity(recentTools, now, bins = 12, binMs = 2e3) {
|
|
|
565
599
|
let idx = Math.floor((t.at - windowStart) / binMs);
|
|
566
600
|
if (idx < 0) idx = 0;
|
|
567
601
|
if (idx >= bins) idx = bins - 1;
|
|
568
|
-
out[idx]
|
|
602
|
+
out[idx] = (out[idx] ?? 0) + 1;
|
|
569
603
|
}
|
|
570
604
|
return out;
|
|
571
605
|
}
|
|
@@ -694,7 +728,7 @@ function FleetMonitor({
|
|
|
694
728
|
// biome-ignore lint/suspicious/noArrayIndexKey: timeline is rebuilt per render
|
|
695
729
|
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
696
730
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: `${fmtElapsed(Math.max(0, nowTick - ev.at))} ago`.padEnd(10) }),
|
|
697
|
-
/* @__PURE__ */ jsx(Text, { color: ev.color, children: ev.icon }),
|
|
731
|
+
/* @__PURE__ */ jsx(Text, { ...ev.color ? { color: ev.color } : {}, children: ev.icon }),
|
|
698
732
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: ev.text })
|
|
699
733
|
] }, i)
|
|
700
734
|
)) }) : null
|
|
@@ -1021,8 +1055,8 @@ function AutonomyPicker({
|
|
|
1021
1055
|
options.map((opt, i) => /* @__PURE__ */ jsxs(
|
|
1022
1056
|
Text,
|
|
1023
1057
|
{
|
|
1024
|
-
color: i === selected ? opt.color : void 0,
|
|
1025
1058
|
inverse: i === selected,
|
|
1059
|
+
...i === selected ? { color: opt.color } : {},
|
|
1026
1060
|
children: [
|
|
1027
1061
|
i === selected ? "\u203A " : " ",
|
|
1028
1062
|
/* @__PURE__ */ jsx(Text, { bold: true, children: opt.label.padEnd(12) }),
|
|
@@ -1147,8 +1181,8 @@ function CheckpointTimeline({
|
|
|
1147
1181
|
const isSelected = i === selected;
|
|
1148
1182
|
const label = `[${cp.promptIndex}] ${cp.promptPreview}`;
|
|
1149
1183
|
return /* @__PURE__ */ jsxs(Box, { children: [
|
|
1150
|
-
/* @__PURE__ */ jsx(Text, {
|
|
1151
|
-
/* @__PURE__ */ jsx(Text, {
|
|
1184
|
+
/* @__PURE__ */ jsx(Text, { bold: isSelected, ...isSelected ? { color: "cyan" } : {}, children: isSelected ? "\u25B8 " : " " }),
|
|
1185
|
+
/* @__PURE__ */ jsx(Text, { bold: isSelected, ...isSelected ? { color: "cyan" } : {}, children: label }),
|
|
1152
1186
|
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
1153
1187
|
" ",
|
|
1154
1188
|
new Date(cp.ts).toLocaleTimeString()
|
|
@@ -1193,7 +1227,7 @@ function hasDiff(input) {
|
|
|
1193
1227
|
}
|
|
1194
1228
|
function renderDiffLine(line) {
|
|
1195
1229
|
const prefix = line.startsWith("+") ? "green" : line.startsWith("-") ? "red" : line.startsWith("@@") ? "cyan" : void 0;
|
|
1196
|
-
return /* @__PURE__ */ jsxs(Text, { color: prefix, children: [
|
|
1230
|
+
return /* @__PURE__ */ jsxs(Text, { ...prefix ? { color: prefix } : {}, children: [
|
|
1197
1231
|
line,
|
|
1198
1232
|
"\n"
|
|
1199
1233
|
] }, line);
|
|
@@ -1318,7 +1352,7 @@ function FilePicker({ query, matches, selected }) {
|
|
|
1318
1352
|
query || "\u2026",
|
|
1319
1353
|
" \u2014 \u2191/\u2193 select, Enter attach, Esc cancel"
|
|
1320
1354
|
] }),
|
|
1321
|
-
matches.map((m, i) => /* @__PURE__ */ jsxs(Text, {
|
|
1355
|
+
matches.map((m, i) => /* @__PURE__ */ jsxs(Text, { inverse: i === selected, ...i === selected ? { color: "cyan" } : {}, children: [
|
|
1322
1356
|
i === selected ? "\u203A " : " ",
|
|
1323
1357
|
highlight(m)
|
|
1324
1358
|
] }, m))
|
|
@@ -1392,9 +1426,8 @@ function FleetPanel({
|
|
|
1392
1426
|
] }) : null
|
|
1393
1427
|
] });
|
|
1394
1428
|
}
|
|
1395
|
-
function helpSections(
|
|
1429
|
+
function helpSections() {
|
|
1396
1430
|
const nav = [];
|
|
1397
|
-
if (opts.managed) nav.push({ keys: "PgUp/PgDn", desc: "scroll chat history" });
|
|
1398
1431
|
nav.push(
|
|
1399
1432
|
{ keys: "\u2191/\u2193", desc: "previous / next input (empty prompt)" },
|
|
1400
1433
|
{ keys: "?", desc: "open this help (empty prompt)" }
|
|
@@ -1437,10 +1470,8 @@ function helpSections(opts) {
|
|
|
1437
1470
|
}
|
|
1438
1471
|
];
|
|
1439
1472
|
}
|
|
1440
|
-
function HelpOverlay({
|
|
1441
|
-
|
|
1442
|
-
}) {
|
|
1443
|
-
const sections = helpSections({ managed });
|
|
1473
|
+
function HelpOverlay() {
|
|
1474
|
+
const sections = helpSections();
|
|
1444
1475
|
const keyWidth = Math.max(...sections.flatMap((s2) => s2.entries.map((e) => e.keys.length)), 0);
|
|
1445
1476
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
|
|
1446
1477
|
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
@@ -1903,8 +1934,6 @@ function detectLang(fenceInfo) {
|
|
|
1903
1934
|
const tag = fenceInfo.trim().toLowerCase().split(/\s+/)[0] ?? "";
|
|
1904
1935
|
return LANG_ALIASES[tag] ?? "plain";
|
|
1905
1936
|
}
|
|
1906
|
-
|
|
1907
|
-
// src/markdown-table.ts
|
|
1908
1937
|
var ROW_RE = /^\s*\|.*\|\s*$/;
|
|
1909
1938
|
var SEP_RE = /^\s*\|[\s\-:|]+\|\s*$/;
|
|
1910
1939
|
function detectTable(lines, start) {
|
|
@@ -1988,14 +2017,14 @@ function computeWidths(allRows, cols, maxWidth, sepWidths) {
|
|
|
1988
2017
|
const stripped = stripInlineMarkers(cell);
|
|
1989
2018
|
const w = longestWord(stripped);
|
|
1990
2019
|
const total = strWidth(stripped);
|
|
1991
|
-
natural[c] = Math.max(natural[c], w, total);
|
|
2020
|
+
natural[c] = Math.max(expectDefined$1(natural[c]), w, total);
|
|
1992
2021
|
}
|
|
1993
2022
|
}
|
|
1994
2023
|
if (sepWidths) {
|
|
1995
2024
|
for (let c = 0; c < cols && c < sepWidths.length; c++) {
|
|
1996
2025
|
const sepW = sepWidths[c];
|
|
1997
2026
|
if (sepW != null) {
|
|
1998
|
-
natural[c] = Math.max(natural[c], sepW);
|
|
2027
|
+
natural[c] = Math.max(expectDefined$1(natural[c]), sepW);
|
|
1999
2028
|
}
|
|
2000
2029
|
}
|
|
2001
2030
|
}
|
|
@@ -2007,14 +2036,14 @@ function computeWidths(allRows, cols, maxWidth, sepWidths) {
|
|
|
2007
2036
|
let maxIdx = -1;
|
|
2008
2037
|
let maxVal = MIN_COL_WIDTH;
|
|
2009
2038
|
for (let i = 0; i < cols; i++) {
|
|
2010
|
-
const w = widths[i];
|
|
2039
|
+
const w = expectDefined$1(widths[i]);
|
|
2011
2040
|
if (w > maxVal) {
|
|
2012
2041
|
maxVal = w;
|
|
2013
2042
|
maxIdx = i;
|
|
2014
2043
|
}
|
|
2015
2044
|
}
|
|
2016
2045
|
if (maxIdx < 0) break;
|
|
2017
|
-
widths[maxIdx]
|
|
2046
|
+
widths[maxIdx] = (widths[maxIdx] ?? 0) - 1;
|
|
2018
2047
|
sum--;
|
|
2019
2048
|
}
|
|
2020
2049
|
return widths;
|
|
@@ -2067,7 +2096,7 @@ function strWidth(s2) {
|
|
|
2067
2096
|
if (i < len) i++;
|
|
2068
2097
|
continue;
|
|
2069
2098
|
}
|
|
2070
|
-
const code = s2.codePointAt(i);
|
|
2099
|
+
const code = expectDefined$1(s2.codePointAt(i));
|
|
2071
2100
|
const cpLen = code > 65535 ? 2 : 1;
|
|
2072
2101
|
if (code === 8205 || // ZWJ — Zero Width Joiner (emoji sequences)
|
|
2073
2102
|
code === 8203 || // ZWSP — Zero Width Space
|
|
@@ -2098,7 +2127,6 @@ function strWidth(s2) {
|
|
|
2098
2127
|
code >= 8960 && code <= 9215 || // Miscellaneous Technical
|
|
2099
2128
|
code >= 11088 && code <= 11093 || // Stars and similar
|
|
2100
2129
|
code >= 10548 && code <= 10549 || // Arrow forms
|
|
2101
|
-
code >= 8592 && code <= 8703 || // Arrows
|
|
2102
2130
|
code >= 9632 && code <= 9727 || // Geometric Shapes
|
|
2103
2131
|
code >= 9664 && code <= 9726 || // More Geometric Shapes (includes ▶)
|
|
2104
2132
|
code >= 9984 && code <= 10175) {
|
|
@@ -2310,10 +2338,10 @@ function InlineLine({ tokens, dim }) {
|
|
|
2310
2338
|
Text,
|
|
2311
2339
|
{
|
|
2312
2340
|
color: t.code ? theme.accent : "white",
|
|
2313
|
-
bold: t.bold,
|
|
2314
|
-
italic: t.italic,
|
|
2315
|
-
strikethrough: t.strike,
|
|
2316
|
-
dimColor: dim,
|
|
2341
|
+
bold: Boolean(t.bold),
|
|
2342
|
+
italic: Boolean(t.italic),
|
|
2343
|
+
strikethrough: Boolean(t.strike),
|
|
2344
|
+
dimColor: Boolean(dim),
|
|
2317
2345
|
children: t.text
|
|
2318
2346
|
},
|
|
2319
2347
|
j
|
|
@@ -2938,7 +2966,22 @@ function formatToolOutput(toolName, output, ok, _outputBytes, outputLines) {
|
|
|
2938
2966
|
}
|
|
2939
2967
|
var MAX_STREAM_DISPLAY_CHARS = 480;
|
|
2940
2968
|
var MAX_STREAM_LINES = 8;
|
|
2941
|
-
|
|
2969
|
+
function streamBoxRows(text, maxLines, contentWidth) {
|
|
2970
|
+
const trunc = (line) => line.length > contentWidth ? `${line.slice(0, contentWidth - 1)}\u2026` : line;
|
|
2971
|
+
const lines = text.split("\n");
|
|
2972
|
+
const totalLines = lines.length;
|
|
2973
|
+
const hidden = Math.max(0, totalLines - maxLines);
|
|
2974
|
+
const rows = [];
|
|
2975
|
+
if (hidden > 0) {
|
|
2976
|
+
rows.push({ text: ` \u2026 ${hidden} more line${hidden === 1 ? "" : "s"} above`, italic: true });
|
|
2977
|
+
for (const line of lines.slice(totalLines - (maxLines - 1))) rows.push({ text: trunc(line) });
|
|
2978
|
+
} else {
|
|
2979
|
+
for (let i = 0; i < maxLines - totalLines; i++) rows.push({ text: "" });
|
|
2980
|
+
for (const line of lines) rows.push({ text: trunc(line) });
|
|
2981
|
+
}
|
|
2982
|
+
return rows;
|
|
2983
|
+
}
|
|
2984
|
+
React6.memo(function ToolStreamBox2({
|
|
2942
2985
|
name,
|
|
2943
2986
|
text,
|
|
2944
2987
|
startedAt,
|
|
@@ -2950,11 +2993,10 @@ var ToolStreamBox = React6.memo(function ToolStreamBox2({
|
|
|
2950
2993
|
return () => clearInterval(t);
|
|
2951
2994
|
}, []);
|
|
2952
2995
|
const elapsedMs = Date.now() - startedAt;
|
|
2953
|
-
const
|
|
2954
|
-
const totalLines = lines.length;
|
|
2996
|
+
const totalLines = text.split("\n").length;
|
|
2955
2997
|
const hidden = Math.max(0, totalLines - MAX_STREAM_LINES);
|
|
2956
|
-
const visible = hidden > 0 ? lines.slice(hidden) : lines;
|
|
2957
2998
|
const contentWidth = Math.max(20, Math.min(termWidth - 4, 100));
|
|
2999
|
+
const rows = streamBoxRows(text, MAX_STREAM_LINES, contentWidth);
|
|
2958
3000
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 0, children: [
|
|
2959
3001
|
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", children: [
|
|
2960
3002
|
/* @__PURE__ */ jsx(Text, { color: theme.warn, children: "\u25C6 " }),
|
|
@@ -2962,13 +3004,10 @@ var ToolStreamBox = React6.memo(function ToolStreamBox2({
|
|
|
2962
3004
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u23F1 ${fmtDuration(elapsedMs)}` }),
|
|
2963
3005
|
hidden > 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` (${totalLines} lines, showing last ${MAX_STREAM_LINES})` }) : null
|
|
2964
3006
|
] }),
|
|
2965
|
-
/* @__PURE__ */
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
return /* @__PURE__ */ jsx(Text, { dimColor: true, children: trimmed || " " }, i);
|
|
2970
|
-
})
|
|
2971
|
-
] })
|
|
3007
|
+
/* @__PURE__ */ jsx(Box, { flexDirection: "column", marginLeft: 2, children: rows.map((r, i) => (
|
|
3008
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: fixed-height block, index is the row
|
|
3009
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, italic: Boolean(r.italic), children: r.text || " " }, i)
|
|
3010
|
+
)) })
|
|
2972
3011
|
] });
|
|
2973
3012
|
});
|
|
2974
3013
|
function tailForDisplay(text, maxChars) {
|
|
@@ -3014,9 +3053,15 @@ function CodeBlock({
|
|
|
3014
3053
|
// biome-ignore lint/suspicious/noArrayIndexKey: code lines are positional
|
|
3015
3054
|
/* @__PURE__ */ jsxs(Text, { children: [
|
|
3016
3055
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: `${String(i + 1).padStart(gutterW, " ")} ` }),
|
|
3017
|
-
tokens.length === 0 ? " " : tokens.map((t, j) => (
|
|
3018
|
-
|
|
3019
|
-
|
|
3056
|
+
tokens.length === 0 ? " " : tokens.map((t, j) => /* @__PURE__ */ jsx(
|
|
3057
|
+
Text,
|
|
3058
|
+
{
|
|
3059
|
+
dimColor: Boolean(t.dim),
|
|
3060
|
+
bold: Boolean(t.bold),
|
|
3061
|
+
...t.color ? { color: t.color } : {},
|
|
3062
|
+
children: t.text
|
|
3063
|
+
},
|
|
3064
|
+
j
|
|
3020
3065
|
))
|
|
3021
3066
|
] }, i)
|
|
3022
3067
|
)),
|
|
@@ -3170,7 +3215,22 @@ function AssistantBody({
|
|
|
3170
3215
|
)
|
|
3171
3216
|
) });
|
|
3172
3217
|
}
|
|
3173
|
-
|
|
3218
|
+
var ASSISTANT_TAIL_LINES = 8;
|
|
3219
|
+
function assistantTailRows(text, tailLines, contentWidth) {
|
|
3220
|
+
const tail = text.split("\n").slice(-tailLines);
|
|
3221
|
+
const rows = [];
|
|
3222
|
+
for (let i = 0; i < tailLines - tail.length; i++) rows.push("");
|
|
3223
|
+
for (const line of tail) {
|
|
3224
|
+
rows.push(line.length > contentWidth ? `${line.slice(0, contentWidth - 1)}\u2026` : line);
|
|
3225
|
+
}
|
|
3226
|
+
return rows;
|
|
3227
|
+
}
|
|
3228
|
+
function AssistantTail({
|
|
3229
|
+
text,
|
|
3230
|
+
termWidth
|
|
3231
|
+
}) {
|
|
3232
|
+
const contentWidth = Math.max(20, termWidth - 3);
|
|
3233
|
+
const rows = assistantTailRows(text, ASSISTANT_TAIL_LINES, contentWidth);
|
|
3174
3234
|
return /* @__PURE__ */ jsxs(
|
|
3175
3235
|
Box,
|
|
3176
3236
|
{
|
|
@@ -3187,7 +3247,10 @@ function AssistantTail({ text }) {
|
|
|
3187
3247
|
/* @__PURE__ */ jsx(Text, { bold: true, color: theme.assistant, children: "ASSISTANT" }),
|
|
3188
3248
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " (streaming\u2026)" })
|
|
3189
3249
|
] }),
|
|
3190
|
-
/* @__PURE__ */ jsx(
|
|
3250
|
+
/* @__PURE__ */ jsx(Box, { flexDirection: "column", children: rows.map((r, i) => (
|
|
3251
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: fixed-height block, index is the row
|
|
3252
|
+
/* @__PURE__ */ jsx(Text, { color: "white", children: r || " " }, i)
|
|
3253
|
+
)) })
|
|
3191
3254
|
]
|
|
3192
3255
|
}
|
|
3193
3256
|
);
|
|
@@ -3350,8 +3413,8 @@ var Entry = React6.memo(function Entry2({
|
|
|
3350
3413
|
/* @__PURE__ */ jsx(
|
|
3351
3414
|
Text,
|
|
3352
3415
|
{
|
|
3353
|
-
color: !entry.ok || line.startsWith("!") ? "red" : void 0,
|
|
3354
3416
|
dimColor: entry.ok && !line.startsWith("!"),
|
|
3417
|
+
...!entry.ok || line.startsWith("!") ? { color: "red" } : {},
|
|
3355
3418
|
children: line
|
|
3356
3419
|
}
|
|
3357
3420
|
)
|
|
@@ -3484,19 +3547,9 @@ function History({ entries, streamingText, toolStream }) {
|
|
|
3484
3547
|
}, [stdout]);
|
|
3485
3548
|
const termWidth = termSize.columns;
|
|
3486
3549
|
const tail = streamingText ? tailForDisplay(streamingText, MAX_STREAM_DISPLAY_CHARS) : "";
|
|
3487
|
-
const toolTail = toolStream?.text ? tailForDisplay(toolStream.text, MAX_STREAM_DISPLAY_CHARS) : "";
|
|
3488
3550
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3489
3551
|
/* @__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) }),
|
|
3490
|
-
tail ? /* @__PURE__ */ jsx(AssistantTail, { text: tail }) : null
|
|
3491
|
-
toolTail ? /* @__PURE__ */ jsx(
|
|
3492
|
-
ToolStreamBox,
|
|
3493
|
-
{
|
|
3494
|
-
name: toolStream.name,
|
|
3495
|
-
text: toolTail,
|
|
3496
|
-
startedAt: toolStream.startedAt,
|
|
3497
|
-
termWidth
|
|
3498
|
-
}
|
|
3499
|
-
) : null
|
|
3552
|
+
tail ? /* @__PURE__ */ jsx(AssistantTail, { text: tail, termWidth }) : null
|
|
3500
3553
|
] });
|
|
3501
3554
|
}
|
|
3502
3555
|
|
|
@@ -3602,6 +3655,12 @@ function layoutInputRows(prompt, value, cursor, width) {
|
|
|
3602
3655
|
if (row.length > 0 || rows.length === 0) rows.push(row);
|
|
3603
3656
|
return rows;
|
|
3604
3657
|
}
|
|
3658
|
+
function expectDefined3(value) {
|
|
3659
|
+
if (value === null || value === void 0) {
|
|
3660
|
+
throw new Error("Expected value to be defined");
|
|
3661
|
+
}
|
|
3662
|
+
return value;
|
|
3663
|
+
}
|
|
3605
3664
|
function renderRow2(cells, rowKey, promptColor) {
|
|
3606
3665
|
const out = [];
|
|
3607
3666
|
let run = "";
|
|
@@ -3655,6 +3714,14 @@ function isBackspaceOrDelete(data) {
|
|
|
3655
3714
|
if (data === "\x1B[3~") return "delete";
|
|
3656
3715
|
return null;
|
|
3657
3716
|
}
|
|
3717
|
+
function parseMouseWheel(data) {
|
|
3718
|
+
const m = data.match(new RegExp(`^${String.fromCharCode(27)}\\[<(\\d+);(\\d+);(\\d+)([Mm])$`, "u"));
|
|
3719
|
+
if (!m) return null;
|
|
3720
|
+
const cb = Number.parseInt(expectDefined3(m[1]), 10);
|
|
3721
|
+
if (cb === 64) return 1;
|
|
3722
|
+
if (cb === 65) return -1;
|
|
3723
|
+
return null;
|
|
3724
|
+
}
|
|
3658
3725
|
var EMPTY_KEY = {
|
|
3659
3726
|
upArrow: false,
|
|
3660
3727
|
downArrow: false,
|
|
@@ -3708,6 +3775,11 @@ function Input({
|
|
|
3708
3775
|
onKey("", { ...EMPTY_KEY, delete: true });
|
|
3709
3776
|
return;
|
|
3710
3777
|
}
|
|
3778
|
+
const wheelDelta = parseMouseWheel(s2);
|
|
3779
|
+
if (wheelDelta !== null) {
|
|
3780
|
+
onKey("", { ...EMPTY_KEY, wheelDeltaY: wheelDelta });
|
|
3781
|
+
return;
|
|
3782
|
+
}
|
|
3711
3783
|
const fn = fnKey(s2);
|
|
3712
3784
|
if (fn !== null) onKey("", { ...EMPTY_KEY, fn });
|
|
3713
3785
|
};
|
|
@@ -3742,46 +3814,6 @@ function Input({
|
|
|
3742
3814
|
hint ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: hint }) : null
|
|
3743
3815
|
] });
|
|
3744
3816
|
}
|
|
3745
|
-
function hintsFor(ctx) {
|
|
3746
|
-
if (ctx.confirm) {
|
|
3747
|
-
return [
|
|
3748
|
-
{ key: "y", label: "yes" },
|
|
3749
|
-
{ key: "n", label: "no" },
|
|
3750
|
-
{ key: "a", label: "always" },
|
|
3751
|
-
{ key: "d", label: "deny" }
|
|
3752
|
-
];
|
|
3753
|
-
}
|
|
3754
|
-
if (ctx.picker) {
|
|
3755
|
-
return [
|
|
3756
|
-
{ key: "\u2191\u2193", label: "move" },
|
|
3757
|
-
{ key: "\u21B5", label: "select" },
|
|
3758
|
-
{ key: "Esc", label: "cancel" }
|
|
3759
|
-
];
|
|
3760
|
-
}
|
|
3761
|
-
if (ctx.monitor) {
|
|
3762
|
-
return [
|
|
3763
|
-
{ key: "Esc", label: "close" },
|
|
3764
|
-
{ key: "^F", label: "fleet" },
|
|
3765
|
-
{ key: "^G", label: "agents" },
|
|
3766
|
-
{ key: "^T", label: "worktrees" },
|
|
3767
|
-
{ key: "F6", label: "todos" }
|
|
3768
|
-
];
|
|
3769
|
-
}
|
|
3770
|
-
const base = [{ key: "?", label: "help" }];
|
|
3771
|
-
if (ctx.managed) base.push({ key: "PgUp/PgDn", label: "scroll" }, { key: "F5", label: "Settings" });
|
|
3772
|
-
base.push({ key: "^G", label: "agents" }, { key: "^C", label: "stop" });
|
|
3773
|
-
return base;
|
|
3774
|
-
}
|
|
3775
|
-
function KeyHintBar({ context }) {
|
|
3776
|
-
const hints = hintsFor(context);
|
|
3777
|
-
return /* @__PURE__ */ jsx(Box, { flexDirection: "row", paddingX: 1, children: hints.map((h, i) => (
|
|
3778
|
-
// biome-ignore lint/suspicious/noArrayIndexKey: hints are positional + stable
|
|
3779
|
-
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", marginRight: 2, children: [
|
|
3780
|
-
/* @__PURE__ */ jsx(Text, { color: theme.accent, children: h.key }),
|
|
3781
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: ` ${h.label}` })
|
|
3782
|
-
] }, i)
|
|
3783
|
-
)) });
|
|
3784
|
-
}
|
|
3785
3817
|
function fmtElapsed2(ms) {
|
|
3786
3818
|
if (ms < 1e3) return `${ms}ms`;
|
|
3787
3819
|
if (ms < 6e4) return `${(ms / 1e3).toFixed(1)}s`;
|
|
@@ -3816,7 +3848,7 @@ var LiveActivityStrip = React6.memo(function LiveActivityStrip2({
|
|
|
3816
3848
|
const running = Object.values(entries).filter((e) => e.status === "running").sort((a, b) => a.startedAt - b.startedAt).slice(0, maxRows);
|
|
3817
3849
|
if (running.length === 0) {
|
|
3818
3850
|
if (Object.keys(entries).length === 0) return null;
|
|
3819
|
-
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", paddingX: 1, children: Array.from({ length: maxRows }, (_,
|
|
3851
|
+
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", paddingX: 1, children: Array.from({ length: maxRows }, (_, slot) => slot).map((slot) => /* @__PURE__ */ jsx(Box, { height: 1, children: /* @__PURE__ */ jsx(Text, { children: " " }) }, `empty-${slot}`)) });
|
|
3820
3852
|
}
|
|
3821
3853
|
const now = Date.now();
|
|
3822
3854
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 1, children: [
|
|
@@ -3890,7 +3922,7 @@ function ModelPicker({
|
|
|
3890
3922
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
|
|
3891
3923
|
/* @__PURE__ */ jsx(Text, { color: "cyan", bold: true, children: "\u2501\u2501 Switch model \u2014 Step 1/2: Pick provider \u2501\u2501" }),
|
|
3892
3924
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 navigate \xB7 Enter select \xB7 Esc cancel \xB7 Ctrl+C exit" }),
|
|
3893
|
-
providerOptions.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "(no providers with keys \u2014 add one via `wstack auth`)" }) : providerOptions.map((p, i) => /* @__PURE__ */ jsxs(Text, {
|
|
3925
|
+
providerOptions.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "(no providers with keys \u2014 add one via `wstack auth`)" }) : providerOptions.map((p, i) => /* @__PURE__ */ jsxs(Text, { inverse: i === selected, ...i === selected ? { color: "cyan" } : {}, children: [
|
|
3894
3926
|
i === selected ? "\u203A " : " ",
|
|
3895
3927
|
/* @__PURE__ */ jsx(Text, { bold: true, children: p.id.padEnd(28) }),
|
|
3896
3928
|
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
@@ -3933,8 +3965,8 @@ function ModelPicker({
|
|
|
3933
3965
|
return /* @__PURE__ */ jsxs(
|
|
3934
3966
|
Text,
|
|
3935
3967
|
{
|
|
3936
|
-
color: absoluteIndex === selected ? "cyan" : void 0,
|
|
3937
3968
|
inverse: absoluteIndex === selected,
|
|
3969
|
+
...absoluteIndex === selected ? { color: "cyan" } : {},
|
|
3938
3970
|
children: [
|
|
3939
3971
|
absoluteIndex === selected ? "\u203A " : " ",
|
|
3940
3972
|
id
|
|
@@ -4173,102 +4205,6 @@ function QueuePanel({ items }) {
|
|
|
4173
4205
|
] })
|
|
4174
4206
|
] });
|
|
4175
4207
|
}
|
|
4176
|
-
var MAX_MOUNTED = 500;
|
|
4177
|
-
function scrollbarThumb(rows, offset, total) {
|
|
4178
|
-
const scrollable = total > rows;
|
|
4179
|
-
if (!scrollable) return { top: 0, size: rows, scrollable: false };
|
|
4180
|
-
const windowTop = Math.max(0, total - rows - offset);
|
|
4181
|
-
const size = Math.max(1, Math.round(rows / total * rows));
|
|
4182
|
-
const rawTop = Math.round(windowTop / total * rows);
|
|
4183
|
-
const top = Math.max(0, Math.min(rawTop, rows - size));
|
|
4184
|
-
return { top, size, scrollable: true };
|
|
4185
|
-
}
|
|
4186
|
-
function Scrollbar({
|
|
4187
|
-
rows,
|
|
4188
|
-
offset,
|
|
4189
|
-
total
|
|
4190
|
-
}) {
|
|
4191
|
-
const { top: thumbTop, size: thumbSize, scrollable } = scrollbarThumb(rows, offset, total);
|
|
4192
|
-
const cells = [];
|
|
4193
|
-
for (let i = 0; i < rows; i++) {
|
|
4194
|
-
cells.push(i >= thumbTop && i < thumbTop + thumbSize ? "\u2588" : "\u2502");
|
|
4195
|
-
}
|
|
4196
|
-
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginLeft: 1, flexShrink: 0, children: cells.map((c, i) => /* @__PURE__ */ jsx(
|
|
4197
|
-
Text,
|
|
4198
|
-
{
|
|
4199
|
-
color: scrollable ? theme.accent : void 0,
|
|
4200
|
-
dimColor: !scrollable || c === "\u2502",
|
|
4201
|
-
children: c
|
|
4202
|
-
},
|
|
4203
|
-
i
|
|
4204
|
-
)) });
|
|
4205
|
-
}
|
|
4206
|
-
function ScrollableHistory({
|
|
4207
|
-
entries,
|
|
4208
|
-
streamingText,
|
|
4209
|
-
toolStream,
|
|
4210
|
-
scrollOffset,
|
|
4211
|
-
viewportRows,
|
|
4212
|
-
totalLines,
|
|
4213
|
-
onMeasure,
|
|
4214
|
-
maxWidth
|
|
4215
|
-
}) {
|
|
4216
|
-
const { stdout } = useStdout();
|
|
4217
|
-
const rawWidth = stdout?.columns ?? 80;
|
|
4218
|
-
const termWidth = maxWidth ? Math.min(rawWidth, maxWidth) : rawWidth;
|
|
4219
|
-
const tail = streamingText ? tailForDisplay(streamingText, MAX_STREAM_DISPLAY_CHARS) : "";
|
|
4220
|
-
const toolTail = toolStream?.text ? tailForDisplay(toolStream.text, MAX_STREAM_DISPLAY_CHARS) : "";
|
|
4221
|
-
const hiddenCount = Math.max(0, entries.length - MAX_MOUNTED);
|
|
4222
|
-
const shown = hiddenCount > 0 ? entries.slice(-MAX_MOUNTED) : entries;
|
|
4223
|
-
const contentRef = useRef(null);
|
|
4224
|
-
const lastReported = useRef(-1);
|
|
4225
|
-
useLayoutEffect(() => {
|
|
4226
|
-
const node = contentRef.current;
|
|
4227
|
-
if (!node) return;
|
|
4228
|
-
const { height } = measureElement(node);
|
|
4229
|
-
if (height !== lastReported.current) {
|
|
4230
|
-
lastReported.current = height;
|
|
4231
|
-
onMeasure(height);
|
|
4232
|
-
}
|
|
4233
|
-
}, [onMeasure]);
|
|
4234
|
-
const vp = Math.max(1, viewportRows);
|
|
4235
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", children: [
|
|
4236
|
-
/* @__PURE__ */ jsx(
|
|
4237
|
-
Box,
|
|
4238
|
-
{
|
|
4239
|
-
flexDirection: "column",
|
|
4240
|
-
flexGrow: 1,
|
|
4241
|
-
height: vp,
|
|
4242
|
-
overflowY: "hidden",
|
|
4243
|
-
justifyContent: "flex-end",
|
|
4244
|
-
children: /* @__PURE__ */ jsxs(
|
|
4245
|
-
Box,
|
|
4246
|
-
{
|
|
4247
|
-
ref: contentRef,
|
|
4248
|
-
flexDirection: "column",
|
|
4249
|
-
marginBottom: Math.max(0, scrollOffset),
|
|
4250
|
-
flexShrink: 0,
|
|
4251
|
-
children: [
|
|
4252
|
-
hiddenCount > 0 ? /* @__PURE__ */ jsx(Box, { flexShrink: 0, children: /* @__PURE__ */ jsx(Text, { dimColor: true, italic: true, children: ` \u2191 ${hiddenCount} earlier ${hiddenCount === 1 ? "entry" : "entries"} (scroll lives in this session; full log on disk)` }) }) : null,
|
|
4253
|
-
shown.map((entry) => /* @__PURE__ */ jsx(Box, { marginBottom: entry.kind === "turn-summary" ? 1 : 0, flexShrink: 0, children: /* @__PURE__ */ jsx(Entry, { entry, termWidth }) }, entry.id)),
|
|
4254
|
-
tail ? /* @__PURE__ */ jsx(AssistantTail, { text: tail }) : null,
|
|
4255
|
-
toolTail ? /* @__PURE__ */ jsx(
|
|
4256
|
-
ToolStreamBox,
|
|
4257
|
-
{
|
|
4258
|
-
name: toolStream.name,
|
|
4259
|
-
text: toolTail,
|
|
4260
|
-
startedAt: toolStream.startedAt,
|
|
4261
|
-
termWidth
|
|
4262
|
-
}
|
|
4263
|
-
) : null
|
|
4264
|
-
]
|
|
4265
|
-
}
|
|
4266
|
-
)
|
|
4267
|
-
}
|
|
4268
|
-
),
|
|
4269
|
-
/* @__PURE__ */ jsx(Scrollbar, { rows: vp, offset: Math.max(0, scrollOffset), total: totalLines })
|
|
4270
|
-
] });
|
|
4271
|
-
}
|
|
4272
4208
|
var DELAY_PRESETS_MS = [0, 15e3, 3e4, 45e3, 6e4, 12e4];
|
|
4273
4209
|
var SETTINGS_MODES = ["off", "suggest", "auto"];
|
|
4274
4210
|
var LOG_LEVELS = ["error", "warn", "info", "debug", "trace"];
|
|
@@ -4425,7 +4361,7 @@ function SettingsPicker({
|
|
|
4425
4361
|
];
|
|
4426
4362
|
const fieldRowIndex = [];
|
|
4427
4363
|
for (let i = 0; i < rows.length; i++) {
|
|
4428
|
-
if (!rows[i]
|
|
4364
|
+
if (!rows[i]?.section) fieldRowIndex.push(i);
|
|
4429
4365
|
}
|
|
4430
4366
|
const VISIBLE_FIELDS = 8;
|
|
4431
4367
|
const totalFields = fieldRowIndex.length;
|
|
@@ -4436,7 +4372,7 @@ function SettingsPicker({
|
|
|
4436
4372
|
const sectionFields = [];
|
|
4437
4373
|
let curHeader = -1;
|
|
4438
4374
|
for (let i = 0; i < rows.length; i++) {
|
|
4439
|
-
if (rows[i]
|
|
4375
|
+
if (rows[i]?.section) curHeader = i;
|
|
4440
4376
|
else if (curHeader >= 0) {
|
|
4441
4377
|
const fieldIdx = fieldRowIndex.indexOf(i);
|
|
4442
4378
|
if (fieldIdx === -1) continue;
|
|
@@ -4465,18 +4401,18 @@ function SettingsPicker({
|
|
|
4465
4401
|
"\u2500\u2500 ",
|
|
4466
4402
|
row.section,
|
|
4467
4403
|
" \u2500\u2500"
|
|
4468
|
-
] }, `section-${i}`);
|
|
4404
|
+
] }, `section-${row.section ?? i}`);
|
|
4469
4405
|
}
|
|
4470
4406
|
return null;
|
|
4471
4407
|
}
|
|
4472
4408
|
if (fieldAtRow < windowStart || fieldAtRow >= windowEnd) return null;
|
|
4473
4409
|
const selected = fieldAtRow === field;
|
|
4474
|
-
return /* @__PURE__ */ jsxs(Text, {
|
|
4410
|
+
return /* @__PURE__ */ jsxs(Text, { inverse: selected, ...selected ? { color: "yellow" } : {}, children: [
|
|
4475
4411
|
selected ? "\u203A " : " ",
|
|
4476
4412
|
/* @__PURE__ */ jsx(Text, { bold: true, children: (row.label ?? "").padEnd(26) }),
|
|
4477
4413
|
/* @__PURE__ */ jsx(Text, { color: "cyan", children: String(row.value ?? "").padEnd(12) }),
|
|
4478
4414
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: row.detail ?? "" })
|
|
4479
|
-
] }, `row-${
|
|
4415
|
+
] }, `row-${row.label ?? fieldAtRow}`);
|
|
4480
4416
|
}),
|
|
4481
4417
|
hasBelow ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u2193 ${totalFields - windowEnd} field${totalFields - windowEnd === 1 ? "" : "s"} below` }) : null,
|
|
4482
4418
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Persisted to ~/.wrongstack/config.json" }),
|
|
@@ -4485,31 +4421,98 @@ function SettingsPicker({
|
|
|
4485
4421
|
}
|
|
4486
4422
|
function SlashMenu({ query, matches, selected }) {
|
|
4487
4423
|
const placeholder = query ? `/${query}` : "/";
|
|
4424
|
+
const { stdout } = useStdout();
|
|
4425
|
+
const termRows = stdout?.rows ?? 24;
|
|
4426
|
+
const rows = [];
|
|
4427
|
+
let lastCategory = "";
|
|
4428
|
+
for (let i = 0; i < matches.length; i++) {
|
|
4429
|
+
const m = matches[i];
|
|
4430
|
+
if (m.category !== lastCategory) {
|
|
4431
|
+
lastCategory = m.category;
|
|
4432
|
+
rows.push({ type: "header", category: m.category });
|
|
4433
|
+
}
|
|
4434
|
+
rows.push({ type: "item", match: m, index: i });
|
|
4435
|
+
}
|
|
4436
|
+
const overhead = 1 + 2 + 2 + 2 + 6;
|
|
4437
|
+
const maxBodyRows = Math.max(4, termRows - overhead);
|
|
4438
|
+
const selectedRowIdx = rows.findIndex((r) => r.type === "item" && r.index === selected);
|
|
4439
|
+
const visible = windowRows(rows, selectedRowIdx < 0 ? 0 : selectedRowIdx, maxBodyRows);
|
|
4440
|
+
const hiddenAbove = visible.start;
|
|
4441
|
+
const hiddenBelow = rows.length - visible.end;
|
|
4488
4442
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [
|
|
4489
4443
|
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
4490
4444
|
placeholder || "/",
|
|
4491
|
-
" \u2014 \u2191/\u2193 select, Enter dispatch, Tab autocomplete, Esc close"
|
|
4445
|
+
" \u2014 \u2191/\u2193 select, Enter dispatch, Tab autocomplete, Esc close",
|
|
4446
|
+
matches.length > 0 ? ` (${selected + 1}/${matches.length})` : ""
|
|
4447
|
+
] }),
|
|
4448
|
+
hiddenAbove > 0 && /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
4449
|
+
" ",
|
|
4450
|
+
"\u2191 ",
|
|
4451
|
+
hiddenAbove,
|
|
4452
|
+
" more"
|
|
4453
|
+
] }),
|
|
4454
|
+
visible.contextHeader && /* @__PURE__ */ jsxs(Text, { bold: true, color: "yellow", dimColor: true, children: [
|
|
4455
|
+
" ",
|
|
4456
|
+
visible.contextHeader
|
|
4457
|
+
] }),
|
|
4458
|
+
visible.rows.map((row) => {
|
|
4459
|
+
if (row.type === "header") {
|
|
4460
|
+
return /* @__PURE__ */ jsxs(Text, { bold: true, color: "yellow", dimColor: true, children: [
|
|
4461
|
+
" ",
|
|
4462
|
+
row.category
|
|
4463
|
+
] }, `cat-${row.category}`);
|
|
4464
|
+
}
|
|
4465
|
+
const { match: m, index: i } = row;
|
|
4466
|
+
return /* @__PURE__ */ jsxs(Text, { inverse: i === selected, ...i === selected ? { color: "cyan" } : {}, children: [
|
|
4467
|
+
i === selected ? "\u203A " : " ",
|
|
4468
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: m.name }),
|
|
4469
|
+
m.argsHint ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
4470
|
+
" ",
|
|
4471
|
+
m.argsHint
|
|
4472
|
+
] }) : null,
|
|
4473
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
4474
|
+
" \u2014 ",
|
|
4475
|
+
m.description
|
|
4476
|
+
] })
|
|
4477
|
+
] }, m.name);
|
|
4478
|
+
}),
|
|
4479
|
+
hiddenBelow > 0 && /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
4480
|
+
" ",
|
|
4481
|
+
"\u2193 ",
|
|
4482
|
+
hiddenBelow,
|
|
4483
|
+
" more"
|
|
4492
4484
|
] }),
|
|
4493
|
-
matches.map((m, i) => /* @__PURE__ */ jsxs(Text, { color: i === selected ? "cyan" : void 0, inverse: i === selected, children: [
|
|
4494
|
-
i === selected ? "\u203A " : " ",
|
|
4495
|
-
/* @__PURE__ */ jsx(Text, { bold: true, children: m.name }),
|
|
4496
|
-
m.argsHint ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
4497
|
-
" ",
|
|
4498
|
-
m.argsHint
|
|
4499
|
-
] }) : null,
|
|
4500
|
-
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
4501
|
-
" \u2014 ",
|
|
4502
|
-
m.description
|
|
4503
|
-
] })
|
|
4504
|
-
] }, m.name)),
|
|
4505
4485
|
matches.length === 0 && /* @__PURE__ */ jsx(Text, { dimColor: true, children: "No matching commands" })
|
|
4506
4486
|
] });
|
|
4507
4487
|
}
|
|
4488
|
+
function windowRows(rows, focus, max) {
|
|
4489
|
+
if (rows.length <= max) {
|
|
4490
|
+
return { rows, start: 0, end: rows.length, contextHeader: null };
|
|
4491
|
+
}
|
|
4492
|
+
let start = focus - Math.floor(max / 2);
|
|
4493
|
+
if (start < 0) start = 0;
|
|
4494
|
+
let end = start + max;
|
|
4495
|
+
if (end > rows.length) {
|
|
4496
|
+
end = rows.length;
|
|
4497
|
+
start = end - max;
|
|
4498
|
+
}
|
|
4499
|
+
let contextHeader = null;
|
|
4500
|
+
if (start > 0) {
|
|
4501
|
+
const first = rows[start];
|
|
4502
|
+
if (first && first.type === "item") {
|
|
4503
|
+
for (let i = start - 1; i >= 0; i--) {
|
|
4504
|
+
const r = rows[i];
|
|
4505
|
+
if (r && r.type === "header") {
|
|
4506
|
+
contextHeader = r.category;
|
|
4507
|
+
break;
|
|
4508
|
+
}
|
|
4509
|
+
}
|
|
4510
|
+
}
|
|
4511
|
+
}
|
|
4512
|
+
return { rows: rows.slice(start, end), start, end, contextHeader };
|
|
4513
|
+
}
|
|
4508
4514
|
function TodosMonitor({ todos }) {
|
|
4509
4515
|
const { stdout } = useStdout();
|
|
4510
|
-
useInput((_input, key) => {
|
|
4511
|
-
if (key.escape) ;
|
|
4512
|
-
});
|
|
4513
4516
|
const done = todos.filter((t) => t.status === "completed").length;
|
|
4514
4517
|
const inProgress = todos.filter((t) => t.status === "in_progress").length;
|
|
4515
4518
|
const pending = todos.filter((t) => t.status === "pending").length;
|
|
@@ -4949,7 +4952,15 @@ function useBrainEvents(events, dispatch) {
|
|
|
4949
4952
|
const decision = p.decision.optionId ?? p.decision.text ?? p.decision.reason ?? p.decision.prompt ?? p.decision.type;
|
|
4950
4953
|
dispatch({ type: "brainStatus", state: status, source: p.request.source, risk: p.request.risk, summary: decision });
|
|
4951
4954
|
if (status === "ask_human") {
|
|
4952
|
-
|
|
4955
|
+
const prompt = {
|
|
4956
|
+
requestId: p.request.id,
|
|
4957
|
+
source: p.request.source,
|
|
4958
|
+
risk: p.request.risk,
|
|
4959
|
+
question: p.request.question
|
|
4960
|
+
};
|
|
4961
|
+
if (p.request.context !== void 0) prompt.context = p.request.context;
|
|
4962
|
+
if (p.request.options !== void 0) prompt.options = p.request.options;
|
|
4963
|
+
dispatch({ type: "brainPromptSet", prompt });
|
|
4953
4964
|
} else {
|
|
4954
4965
|
dispatch({ type: "brainPromptClear" });
|
|
4955
4966
|
}
|
|
@@ -4969,6 +4980,12 @@ function useBrainEvents(events, dispatch) {
|
|
|
4969
4980
|
};
|
|
4970
4981
|
}, [events, dispatch]);
|
|
4971
4982
|
}
|
|
4983
|
+
function expectDefined4(value) {
|
|
4984
|
+
if (value === null || value === void 0) {
|
|
4985
|
+
throw new Error("Expected value to be defined");
|
|
4986
|
+
}
|
|
4987
|
+
return value;
|
|
4988
|
+
}
|
|
4972
4989
|
var STREAM_COLORS = ["cyan", "magenta", "yellow", "green", "blue"];
|
|
4973
4990
|
function labelFor(labelsRef, id, name) {
|
|
4974
4991
|
const m = labelsRef.current;
|
|
@@ -4977,7 +4994,7 @@ function labelFor(labelsRef, id, name) {
|
|
|
4977
4994
|
const n = m.size + 1;
|
|
4978
4995
|
const v = {
|
|
4979
4996
|
label: name && name !== id ? name : `AGENT#${n}`,
|
|
4980
|
-
color: STREAM_COLORS[(n - 1) % STREAM_COLORS.length]
|
|
4997
|
+
color: expectDefined4(STREAM_COLORS[(n - 1) % STREAM_COLORS.length])
|
|
4981
4998
|
};
|
|
4982
4999
|
m.set(id, v);
|
|
4983
5000
|
return v;
|
|
@@ -5324,6 +5341,12 @@ function buildSteeringPreamble(snapshot, newDirection) {
|
|
|
5324
5341
|
}
|
|
5325
5342
|
|
|
5326
5343
|
// src/app-reducer.ts
|
|
5344
|
+
function expectDefined5(value) {
|
|
5345
|
+
if (value === null || value === void 0) {
|
|
5346
|
+
throw new Error("Expected value to be defined");
|
|
5347
|
+
}
|
|
5348
|
+
return value;
|
|
5349
|
+
}
|
|
5327
5350
|
function reducer(state, action) {
|
|
5328
5351
|
switch (action.type) {
|
|
5329
5352
|
case "addEntry": {
|
|
@@ -5688,13 +5711,13 @@ function reducer(state, action) {
|
|
|
5688
5711
|
const i = SETTINGS_MODES.indexOf(sp.mode);
|
|
5689
5712
|
const base = i < 0 ? 0 : i;
|
|
5690
5713
|
const next = (base + action.delta + SETTINGS_MODES.length) % SETTINGS_MODES.length;
|
|
5691
|
-
return { ...state, settingsPicker: { ...sp, mode: SETTINGS_MODES[next], hint: void 0 } };
|
|
5714
|
+
return { ...state, settingsPicker: { ...sp, mode: expectDefined5(SETTINGS_MODES[next]), hint: void 0 } };
|
|
5692
5715
|
}
|
|
5693
5716
|
if (f === 1) {
|
|
5694
5717
|
const j = DELAY_PRESETS_MS.indexOf(sp.delayMs);
|
|
5695
5718
|
const base = j < 0 ? 0 : j;
|
|
5696
5719
|
const next = (base + action.delta + DELAY_PRESETS_MS.length) % DELAY_PRESETS_MS.length;
|
|
5697
|
-
return { ...state, settingsPicker: { ...sp, delayMs: DELAY_PRESETS_MS[next], hint: void 0 } };
|
|
5720
|
+
return { ...state, settingsPicker: { ...sp, delayMs: expectDefined5(DELAY_PRESETS_MS[next]), hint: void 0 } };
|
|
5698
5721
|
}
|
|
5699
5722
|
if (f === 2) return { ...state, settingsPicker: { ...sp, titleAnimation: !sp.titleAnimation, hint: void 0 } };
|
|
5700
5723
|
if (f === 3) return { ...state, settingsPicker: { ...sp, yolo: !sp.yolo, hint: void 0 } };
|
|
@@ -5712,26 +5735,26 @@ function reducer(state, action) {
|
|
|
5712
5735
|
const i = COMPACTOR_STRATEGIES.indexOf(sp.contextStrategy);
|
|
5713
5736
|
const base = i < 0 ? 0 : i;
|
|
5714
5737
|
const next = (base + action.delta + COMPACTOR_STRATEGIES.length) % COMPACTOR_STRATEGIES.length;
|
|
5715
|
-
return { ...state, settingsPicker: { ...sp, contextStrategy: COMPACTOR_STRATEGIES[next], hint: void 0 } };
|
|
5738
|
+
return { ...state, settingsPicker: { ...sp, contextStrategy: expectDefined5(COMPACTOR_STRATEGIES[next]), hint: void 0 } };
|
|
5716
5739
|
}
|
|
5717
5740
|
if (f === 15) {
|
|
5718
5741
|
const i = LOG_LEVELS.indexOf(sp.logLevel);
|
|
5719
5742
|
const base = i < 0 ? 0 : i;
|
|
5720
5743
|
const next = (base + action.delta + LOG_LEVELS.length) % LOG_LEVELS.length;
|
|
5721
|
-
return { ...state, settingsPicker: { ...sp, logLevel: LOG_LEVELS[next], hint: void 0 } };
|
|
5744
|
+
return { ...state, settingsPicker: { ...sp, logLevel: expectDefined5(LOG_LEVELS[next]), hint: void 0 } };
|
|
5722
5745
|
}
|
|
5723
5746
|
if (f === 16) {
|
|
5724
5747
|
const i = AUDIT_LEVELS.indexOf(sp.auditLevel);
|
|
5725
5748
|
const base = i < 0 ? 0 : i;
|
|
5726
5749
|
const next = (base + action.delta + AUDIT_LEVELS.length) % AUDIT_LEVELS.length;
|
|
5727
|
-
return { ...state, settingsPicker: { ...sp, auditLevel: AUDIT_LEVELS[next], hint: void 0 } };
|
|
5750
|
+
return { ...state, settingsPicker: { ...sp, auditLevel: expectDefined5(AUDIT_LEVELS[next]), hint: void 0 } };
|
|
5728
5751
|
}
|
|
5729
5752
|
if (f === 17) return { ...state, settingsPicker: { ...sp, indexOnStart: !sp.indexOnStart, hint: void 0 } };
|
|
5730
5753
|
{
|
|
5731
5754
|
const j = MAX_ITERATIONS_PRESETS.indexOf(sp.maxIterations);
|
|
5732
5755
|
const base = j < 0 ? 0 : j;
|
|
5733
5756
|
const next = (base + action.delta + MAX_ITERATIONS_PRESETS.length) % MAX_ITERATIONS_PRESETS.length;
|
|
5734
|
-
return { ...state, settingsPicker: { ...sp, maxIterations: MAX_ITERATIONS_PRESETS[next], hint: void 0 } };
|
|
5757
|
+
return { ...state, settingsPicker: { ...sp, maxIterations: expectDefined5(MAX_ITERATIONS_PRESETS[next]), hint: void 0 } };
|
|
5735
5758
|
}
|
|
5736
5759
|
}
|
|
5737
5760
|
case "settingsHint":
|
|
@@ -6379,7 +6402,12 @@ function reducer(state, action) {
|
|
|
6379
6402
|
}
|
|
6380
6403
|
}
|
|
6381
6404
|
}
|
|
6382
|
-
|
|
6405
|
+
function expectDefined6(value) {
|
|
6406
|
+
if (value === null || value === void 0) {
|
|
6407
|
+
throw new Error("Expected value to be defined");
|
|
6408
|
+
}
|
|
6409
|
+
return value;
|
|
6410
|
+
}
|
|
6383
6411
|
var INPUT_PROMPT = "\u203A ";
|
|
6384
6412
|
function selectedSlashCommandLine(picker) {
|
|
6385
6413
|
if (!picker.open || picker.matches.length === 0) return null;
|
|
@@ -6388,15 +6416,16 @@ function selectedSlashCommandLine(picker) {
|
|
|
6388
6416
|
}
|
|
6389
6417
|
function rehydrateHistory(messages, startId) {
|
|
6390
6418
|
const entries = [];
|
|
6419
|
+
let nextId = startId;
|
|
6391
6420
|
for (const msg of messages) {
|
|
6392
6421
|
if (msg.role === "system") continue;
|
|
6393
6422
|
const text = typeof msg.content === "string" ? msg.content : msg.content.filter((b) => b.type === "text").map((b) => b.text).join("");
|
|
6394
6423
|
const trimmed = text.trim();
|
|
6395
6424
|
if (!trimmed) continue;
|
|
6396
6425
|
if (msg.role === "user") {
|
|
6397
|
-
entries.push({ id:
|
|
6426
|
+
entries.push({ id: nextId++, kind: "user", text: trimmed });
|
|
6398
6427
|
} else if (msg.role === "assistant") {
|
|
6399
|
-
entries.push({ id:
|
|
6428
|
+
entries.push({ id: nextId++, kind: "assistant", text: trimmed });
|
|
6400
6429
|
}
|
|
6401
6430
|
}
|
|
6402
6431
|
return entries;
|
|
@@ -6450,7 +6479,6 @@ function App({
|
|
|
6450
6479
|
initialGoal,
|
|
6451
6480
|
initialAsk,
|
|
6452
6481
|
sessionsDir,
|
|
6453
|
-
managed = false,
|
|
6454
6482
|
modeLabel,
|
|
6455
6483
|
getModeLabel
|
|
6456
6484
|
}) {
|
|
@@ -6467,18 +6495,6 @@ function App({
|
|
|
6467
6495
|
setIndexState(getIndexState());
|
|
6468
6496
|
return onIndexStateChange((next) => setIndexState(next));
|
|
6469
6497
|
}, []);
|
|
6470
|
-
const { stdout } = useStdout();
|
|
6471
|
-
const [termRows, setTermRows] = useState(stdout?.rows ?? 24);
|
|
6472
|
-
useEffect(() => {
|
|
6473
|
-
const onResize = () => {
|
|
6474
|
-
setTermRows(process.stdout.rows ?? 24);
|
|
6475
|
-
};
|
|
6476
|
-
process.stdout.on("resize", onResize);
|
|
6477
|
-
return () => {
|
|
6478
|
-
process.stdout.off("resize", onResize);
|
|
6479
|
-
};
|
|
6480
|
-
}, []);
|
|
6481
|
-
const [managedLive, setManagedLive] = useState(managed);
|
|
6482
6498
|
useEffect(() => {
|
|
6483
6499
|
setHiddenItems(statuslineHiddenItems);
|
|
6484
6500
|
}, [statuslineHiddenItems]);
|
|
@@ -6628,19 +6644,6 @@ function App({
|
|
|
6628
6644
|
stateRef.current = state;
|
|
6629
6645
|
const draftRef = useRef({ buffer: state.buffer, cursor: state.cursor });
|
|
6630
6646
|
draftRef.current = { buffer: state.buffer, cursor: state.cursor };
|
|
6631
|
-
const bottomRef = useRef(null);
|
|
6632
|
-
React6.useLayoutEffect(() => {
|
|
6633
|
-
if (!managedLive) return;
|
|
6634
|
-
const node = bottomRef.current;
|
|
6635
|
-
if (!node) return;
|
|
6636
|
-
const { height } = measureElement(node);
|
|
6637
|
-
const s2 = stateRef.current;
|
|
6638
|
-
const affordance = s2.scrollOffset > 0 && s2.pendingNewLines > 0 ? 1 : 0;
|
|
6639
|
-
const vp = Math.max(MIN_VIEWPORT, termRows - height - affordance - 1);
|
|
6640
|
-
if (vp !== s2.viewportRows) {
|
|
6641
|
-
dispatch({ type: "setViewportRows", rows: vp });
|
|
6642
|
-
}
|
|
6643
|
-
}, [managedLive, termRows]);
|
|
6644
6647
|
const handleKeyRef = useRef(null);
|
|
6645
6648
|
const handleRewindTo = React6.useCallback(
|
|
6646
6649
|
async (checkpointIndex) => {
|
|
@@ -6663,10 +6666,21 @@ function App({
|
|
|
6663
6666
|
const startedAtRef = useRef(Date.now());
|
|
6664
6667
|
const [nowTick, setNowTick] = React6.useState(Date.now());
|
|
6665
6668
|
useEffect(() => {
|
|
6666
|
-
const t = setInterval(() => setNowTick(Date.now()),
|
|
6669
|
+
const t = setInterval(() => setNowTick(Date.now()), 1e4);
|
|
6667
6670
|
return () => clearInterval(t);
|
|
6668
6671
|
}, []);
|
|
6669
|
-
const
|
|
6672
|
+
const todosRef = useRef(JSON.stringify([]));
|
|
6673
|
+
useEffect(() => {
|
|
6674
|
+
const poll = () => {
|
|
6675
|
+
const snap = JSON.stringify(agent.ctx.todos.map((t2) => ({ s: t2.status })));
|
|
6676
|
+
if (snap !== todosRef.current) {
|
|
6677
|
+
todosRef.current = snap;
|
|
6678
|
+
setNowTick(Date.now());
|
|
6679
|
+
}
|
|
6680
|
+
};
|
|
6681
|
+
const t = setInterval(poll, 2e3);
|
|
6682
|
+
return () => clearInterval(t);
|
|
6683
|
+
}, [agent.ctx.todos]);
|
|
6670
6684
|
const [gitInfo, setGitInfo] = React6.useState(null);
|
|
6671
6685
|
useEffect(() => {
|
|
6672
6686
|
let cancelled = false;
|
|
@@ -6744,7 +6758,7 @@ function App({
|
|
|
6744
6758
|
const n = m.size + 1;
|
|
6745
6759
|
const v = {
|
|
6746
6760
|
label: name && name !== id ? name : `AGENT#${n}`,
|
|
6747
|
-
color: STREAM_COLORS2[(n - 1) % STREAM_COLORS2.length]
|
|
6761
|
+
color: STREAM_COLORS2[(n - 1) % STREAM_COLORS2.length] ?? "cyan"
|
|
6748
6762
|
};
|
|
6749
6763
|
m.set(id, v);
|
|
6750
6764
|
return v;
|
|
@@ -6826,7 +6840,7 @@ function App({
|
|
|
6826
6840
|
}, [eraseLiveRegion]);
|
|
6827
6841
|
React6.useLayoutEffect(() => {
|
|
6828
6842
|
if (state.enhanceBusy || state.enhance != null) eraseLiveRegion();
|
|
6829
|
-
}, [
|
|
6843
|
+
}, [state.enhanceBusy, state.enhance, eraseLiveRegion]);
|
|
6830
6844
|
useEffect(() => {
|
|
6831
6845
|
const detected = detectAtToken(state.buffer, state.cursor);
|
|
6832
6846
|
if (!detected) {
|
|
@@ -6858,16 +6872,22 @@ function App({
|
|
|
6858
6872
|
}
|
|
6859
6873
|
const query = trimmed.slice(1).toLowerCase();
|
|
6860
6874
|
const allCommands = slashRegistry.listWithOwner();
|
|
6875
|
+
const CATEGORY_ORDER = ["Run", "Session", "Inspect", "Agent", "Config", "App"];
|
|
6861
6876
|
const matches = allCommands.filter(({ cmd }) => {
|
|
6862
6877
|
const name = cmd.name.toLowerCase();
|
|
6863
6878
|
const aliases = cmd.aliases ?? [];
|
|
6864
6879
|
return name.includes(query) || aliases.some((a) => a.toLowerCase().includes(query));
|
|
6865
|
-
}).
|
|
6880
|
+
}).map(({ cmd, owner }) => ({
|
|
6866
6881
|
name: cmd.name,
|
|
6867
6882
|
description: cmd.description,
|
|
6868
6883
|
argsHint: cmd.argsHint,
|
|
6869
|
-
isBuiltin: owner === "core"
|
|
6870
|
-
|
|
6884
|
+
isBuiltin: owner === "core",
|
|
6885
|
+
category: cmd.category ?? "App"
|
|
6886
|
+
})).sort((a, b) => {
|
|
6887
|
+
const catDiff = CATEGORY_ORDER.indexOf(a.category) - CATEGORY_ORDER.indexOf(b.category);
|
|
6888
|
+
if (catDiff !== 0) return catDiff;
|
|
6889
|
+
return a.name.localeCompare(b.name);
|
|
6890
|
+
});
|
|
6871
6891
|
if (!state.slashPicker.open) {
|
|
6872
6892
|
dispatch({ type: "slashPickerOpen", query, matches });
|
|
6873
6893
|
} else if (state.slashPicker.query !== query) {
|
|
@@ -6999,44 +7019,6 @@ function App({
|
|
|
6999
7019
|
getProcessRegistry().killAll();
|
|
7000
7020
|
};
|
|
7001
7021
|
}, []);
|
|
7002
|
-
useEffect(() => {
|
|
7003
|
-
const ALT_OFF = "\x1B[?1049l";
|
|
7004
|
-
const ALT_ON = "\x1B[?1049h";
|
|
7005
|
-
const cmd = {
|
|
7006
|
-
name: "altscreen",
|
|
7007
|
-
description: "Toggle the alt-screen buffer. Default is OFF (native scroll); /altscreen on for full-screen mode.",
|
|
7008
|
-
async run(args) {
|
|
7009
|
-
const arg = args.trim().toLowerCase();
|
|
7010
|
-
if (arg === "off") {
|
|
7011
|
-
try {
|
|
7012
|
-
writeOut(ALT_OFF);
|
|
7013
|
-
} catch {
|
|
7014
|
-
return { message: "Failed to exit alt-screen." };
|
|
7015
|
-
}
|
|
7016
|
-
setManagedLive(false);
|
|
7017
|
-
return {
|
|
7018
|
-
message: "Alt-screen disabled. New entries will land in normal scrollback (mouse wheel / Shift+PgUp work). On-screen history rendered before this command is no longer reachable via terminal scroll. Resize may now leak the live region \u2014 `/altscreen on` to re-enable."
|
|
7019
|
-
};
|
|
7020
|
-
}
|
|
7021
|
-
if (arg === "on") {
|
|
7022
|
-
try {
|
|
7023
|
-
writeOut(ALT_ON);
|
|
7024
|
-
} catch {
|
|
7025
|
-
return { message: "Failed to re-enter alt-screen." };
|
|
7026
|
-
}
|
|
7027
|
-
setManagedLive(true);
|
|
7028
|
-
return {
|
|
7029
|
-
message: "Alt-screen re-enabled. Managed scroll (PgUp/PgDn) is now active; native scroll is off."
|
|
7030
|
-
};
|
|
7031
|
-
}
|
|
7032
|
-
return { message: "Usage: /altscreen on|off" };
|
|
7033
|
-
}
|
|
7034
|
-
};
|
|
7035
|
-
slashRegistry.register(cmd);
|
|
7036
|
-
return () => {
|
|
7037
|
-
slashRegistry.unregister("altscreen");
|
|
7038
|
-
};
|
|
7039
|
-
}, [slashRegistry]);
|
|
7040
7022
|
useEffect(() => {
|
|
7041
7023
|
const cmd = {
|
|
7042
7024
|
name: "steer",
|
|
@@ -8138,26 +8120,7 @@ function App({
|
|
|
8138
8120
|
if (key.escape || input === "?" || input === "q") dispatch({ type: "toggleHelp" });
|
|
8139
8121
|
return;
|
|
8140
8122
|
}
|
|
8141
|
-
state.todosMonitorOpen || state.monitorOpen || state.agentsMonitorOpen || state.worktreeMonitorOpen || !!state.autoPhase?.monitorOpen;
|
|
8142
8123
|
if (inputGateRef.current) return;
|
|
8143
|
-
if (managedLive) {
|
|
8144
|
-
if (key.pageUp) {
|
|
8145
|
-
dispatch({ type: "scrollPage", dir: "up" });
|
|
8146
|
-
return;
|
|
8147
|
-
}
|
|
8148
|
-
if (key.pageDown) {
|
|
8149
|
-
dispatch({ type: "scrollPage", dir: "down" });
|
|
8150
|
-
return;
|
|
8151
|
-
}
|
|
8152
|
-
if (key.ctrl && key.home) {
|
|
8153
|
-
dispatch({ type: "scrollToTop" });
|
|
8154
|
-
return;
|
|
8155
|
-
}
|
|
8156
|
-
if (key.ctrl && key.end) {
|
|
8157
|
-
dispatch({ type: "scrollToBottom" });
|
|
8158
|
-
return;
|
|
8159
|
-
}
|
|
8160
|
-
}
|
|
8161
8124
|
if (key.escape) {
|
|
8162
8125
|
const now = Date.now();
|
|
8163
8126
|
if (state.buffer.length > 0 && now - lastEscAtRef.current < ESC_DOUBLE_PRESS_MS) {
|
|
@@ -8692,19 +8655,11 @@ function App({
|
|
|
8692
8655
|
return;
|
|
8693
8656
|
}
|
|
8694
8657
|
if (key.home) {
|
|
8695
|
-
|
|
8696
|
-
dispatch({ type: "scrollToTop" });
|
|
8697
|
-
} else {
|
|
8698
|
-
setDraft(buffer, 0);
|
|
8699
|
-
}
|
|
8658
|
+
setDraft(buffer, 0);
|
|
8700
8659
|
return;
|
|
8701
8660
|
}
|
|
8702
8661
|
if (key.end) {
|
|
8703
|
-
|
|
8704
|
-
dispatch({ type: "scrollToBottom" });
|
|
8705
|
-
} else {
|
|
8706
|
-
setDraft(buffer, buffer.length);
|
|
8707
|
-
}
|
|
8662
|
+
setDraft(buffer, buffer.length);
|
|
8708
8663
|
return;
|
|
8709
8664
|
}
|
|
8710
8665
|
if (key.upArrow) {
|
|
@@ -9178,21 +9133,9 @@ User message:
|
|
|
9178
9133
|
if (state.picker.open) return "";
|
|
9179
9134
|
return "";
|
|
9180
9135
|
}, [state.buffer, state.status, state.picker.open]);
|
|
9181
|
-
const affordanceShown = managedLive && state.scrollOffset > 0 && state.pendingNewLines > 0;
|
|
9182
9136
|
const enhanceActive = state.enhanceBusy || state.enhance != null;
|
|
9183
|
-
return /* @__PURE__ */ jsx(Box, { flexDirection: "column",
|
|
9184
|
-
|
|
9185
|
-
ScrollableHistory,
|
|
9186
|
-
{
|
|
9187
|
-
entries: state.entries,
|
|
9188
|
-
streamingText: state.streamingText,
|
|
9189
|
-
toolStream: state.toolStream,
|
|
9190
|
-
scrollOffset: state.scrollOffset,
|
|
9191
|
-
viewportRows: state.viewportRows || Math.max(MIN_VIEWPORT, termRows - 8),
|
|
9192
|
-
totalLines: state.totalLines,
|
|
9193
|
-
onMeasure: (total) => dispatch({ type: "setMeasuredLines", totalLines: total })
|
|
9194
|
-
}
|
|
9195
|
-
) : /* @__PURE__ */ jsx(
|
|
9137
|
+
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: /* @__PURE__ */ jsxs(Box, { flexDirection: "column", flexGrow: 1, flexShrink: 0, children: [
|
|
9138
|
+
/* @__PURE__ */ jsx(
|
|
9196
9139
|
History,
|
|
9197
9140
|
{
|
|
9198
9141
|
entries: state.entries,
|
|
@@ -9200,8 +9143,7 @@ User message:
|
|
|
9200
9143
|
toolStream: state.toolStream
|
|
9201
9144
|
}
|
|
9202
9145
|
),
|
|
9203
|
-
|
|
9204
|
-
/* @__PURE__ */ jsxs(Box, { ref: managedLive ? bottomRef : void 0, flexDirection: "column", flexShrink: 0, children: [
|
|
9146
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", flexShrink: 0, children: [
|
|
9205
9147
|
/* @__PURE__ */ jsx(LiveActivityStrip, { entries: state.fleet, nowTick }),
|
|
9206
9148
|
/* @__PURE__ */ jsx(
|
|
9207
9149
|
Input,
|
|
@@ -9277,16 +9219,22 @@ User message:
|
|
|
9277
9219
|
hint: state.settingsPicker.hint
|
|
9278
9220
|
}
|
|
9279
9221
|
) : null,
|
|
9280
|
-
state.rewindOverlay ?
|
|
9281
|
-
|
|
9282
|
-
|
|
9283
|
-
|
|
9284
|
-
|
|
9285
|
-
|
|
9286
|
-
|
|
9287
|
-
|
|
9288
|
-
|
|
9289
|
-
|
|
9222
|
+
state.rewindOverlay ? (() => {
|
|
9223
|
+
const overlay = state.rewindOverlay;
|
|
9224
|
+
return /* @__PURE__ */ jsx(
|
|
9225
|
+
CheckpointTimeline,
|
|
9226
|
+
{
|
|
9227
|
+
checkpoints: overlay.checkpoints,
|
|
9228
|
+
selected: overlay.selected,
|
|
9229
|
+
onSelect: (i) => dispatch({ type: "rewindOverlayMove", delta: i - overlay.selected }),
|
|
9230
|
+
onConfirm: (i) => {
|
|
9231
|
+
const checkpoint = overlay.checkpoints[i];
|
|
9232
|
+
if (checkpoint) handleRewindTo(checkpoint.promptIndex);
|
|
9233
|
+
},
|
|
9234
|
+
onClose: () => dispatch({ type: "rewindOverlayClose" })
|
|
9235
|
+
}
|
|
9236
|
+
);
|
|
9237
|
+
})() : null,
|
|
9290
9238
|
state.brainPrompt ? /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginY: 1, flexShrink: 0, children: /* @__PURE__ */ jsx(
|
|
9291
9239
|
BrainDecisionPrompt,
|
|
9292
9240
|
{
|
|
@@ -9298,7 +9246,7 @@ User message:
|
|
|
9298
9246
|
}
|
|
9299
9247
|
) }) : null,
|
|
9300
9248
|
state.confirmQueue.length > 0 && (() => {
|
|
9301
|
-
const head = state.confirmQueue[0];
|
|
9249
|
+
const head = expectDefined6(state.confirmQueue[0]);
|
|
9302
9250
|
let resolved = false;
|
|
9303
9251
|
const onDecision = (decision) => {
|
|
9304
9252
|
if (resolved) return;
|
|
@@ -9346,7 +9294,7 @@ User message:
|
|
|
9346
9294
|
queueCount: state.queue.length,
|
|
9347
9295
|
yolo: yoloLive,
|
|
9348
9296
|
autonomy: autonomyLive,
|
|
9349
|
-
|
|
9297
|
+
startedAt: startedAtRef.current,
|
|
9350
9298
|
todos,
|
|
9351
9299
|
plan: planCounts ?? void 0,
|
|
9352
9300
|
fleet: fleetCounts,
|
|
@@ -9363,18 +9311,7 @@ User message:
|
|
|
9363
9311
|
modeLabel: liveModeLabel || void 0
|
|
9364
9312
|
}
|
|
9365
9313
|
),
|
|
9366
|
-
|
|
9367
|
-
KeyHintBar,
|
|
9368
|
-
{
|
|
9369
|
-
context: {
|
|
9370
|
-
confirm: state.confirmQueue.length > 0,
|
|
9371
|
-
picker: state.picker.open || state.slashPicker.open || state.modelPicker.open || state.autonomyPicker.open || state.settingsPicker.open || !!state.rewindOverlay,
|
|
9372
|
-
monitor: state.agentsMonitorOpen || state.monitorOpen || state.worktreeMonitorOpen || state.todosMonitorOpen || !!state.autoPhase?.monitorOpen,
|
|
9373
|
-
managed: managedLive
|
|
9374
|
-
}
|
|
9375
|
-
}
|
|
9376
|
-
) : null,
|
|
9377
|
-
state.helpOpen ? /* @__PURE__ */ jsx(HelpOverlay, { managed: managedLive }) : null,
|
|
9314
|
+
state.helpOpen ? /* @__PURE__ */ jsx(HelpOverlay, {}) : null,
|
|
9378
9315
|
state.agentsMonitorOpen ? /* @__PURE__ */ jsx(
|
|
9379
9316
|
AgentsMonitor,
|
|
9380
9317
|
{
|
|
@@ -9401,7 +9338,7 @@ User message:
|
|
|
9401
9338
|
nowTick,
|
|
9402
9339
|
onClose: () => dispatch({ type: "worktreeMonitorToggle" })
|
|
9403
9340
|
}
|
|
9404
|
-
) : state.todosMonitorOpen
|
|
9341
|
+
) : state.todosMonitorOpen ? /* @__PURE__ */ jsx(TodosMonitor, { todos: agent.ctx.todos }) : state.monitorOpen ? /* @__PURE__ */ jsx(
|
|
9405
9342
|
FleetMonitor,
|
|
9406
9343
|
{
|
|
9407
9344
|
entries: state.fleet,
|
|
@@ -9531,9 +9468,6 @@ function startTerminalTitle(opts) {
|
|
|
9531
9468
|
// src/run-tui.ts
|
|
9532
9469
|
var BRACKETED_PASTE_ON = "\x1B[?2004h";
|
|
9533
9470
|
var BRACKETED_PASTE_OFF = "\x1B[?2004l";
|
|
9534
|
-
var ALT_SCREEN_ON = "\x1B[?1049h";
|
|
9535
|
-
var ALT_SCREEN_OFF = "\x1B[?1049l";
|
|
9536
|
-
var CURSOR_HOME = "\x1B[H";
|
|
9537
9471
|
async function runTui(opts) {
|
|
9538
9472
|
const stdout = process.stdout;
|
|
9539
9473
|
const stdin = process.stdin;
|
|
@@ -9543,12 +9477,8 @@ async function runTui(opts) {
|
|
|
9543
9477
|
);
|
|
9544
9478
|
return 2;
|
|
9545
9479
|
}
|
|
9546
|
-
const useAltScreen = opts.altScreen === true;
|
|
9547
|
-
if (useAltScreen) {
|
|
9548
|
-
stdout.write(ALT_SCREEN_ON);
|
|
9549
|
-
stdout.write(CURSOR_HOME);
|
|
9550
|
-
}
|
|
9551
9480
|
stdout.write(BRACKETED_PASTE_ON);
|
|
9481
|
+
stdout.write("\x1B[2J\x1B[H");
|
|
9552
9482
|
const inkStdin = stdin;
|
|
9553
9483
|
const stopTitle = opts.titleAnimation !== false ? startTerminalTitle({ stdout, events: opts.events, model: opts.model }) : (() => {
|
|
9554
9484
|
});
|
|
@@ -9571,9 +9501,6 @@ async function runTui(opts) {
|
|
|
9571
9501
|
}
|
|
9572
9502
|
try {
|
|
9573
9503
|
stdout.write(BRACKETED_PASTE_OFF);
|
|
9574
|
-
if (useAltScreen) {
|
|
9575
|
-
stdout.write(ALT_SCREEN_OFF);
|
|
9576
|
-
}
|
|
9577
9504
|
} catch {
|
|
9578
9505
|
}
|
|
9579
9506
|
};
|
|
@@ -9600,12 +9527,6 @@ async function runTui(opts) {
|
|
|
9600
9527
|
const settle = (code) => {
|
|
9601
9528
|
cleanup();
|
|
9602
9529
|
detachListeners();
|
|
9603
|
-
if (useAltScreen && opts.onAfterExit) {
|
|
9604
|
-
try {
|
|
9605
|
-
opts.onAfterExit();
|
|
9606
|
-
} catch {
|
|
9607
|
-
}
|
|
9608
|
-
}
|
|
9609
9530
|
resolve(code);
|
|
9610
9531
|
};
|
|
9611
9532
|
let instance;
|
|
@@ -9641,7 +9562,7 @@ async function runTui(opts) {
|
|
|
9641
9562
|
onExit,
|
|
9642
9563
|
director: opts.director ?? null,
|
|
9643
9564
|
fleetRoster: opts.fleetRoster,
|
|
9644
|
-
onClearHistory: opts.onClearHistory ? (dispatch) => opts.onClearHistory(dispatch) : void 0,
|
|
9565
|
+
onClearHistory: opts.onClearHistory ? (dispatch) => opts.onClearHistory?.(dispatch) : void 0,
|
|
9645
9566
|
fleetStreamController: opts.fleetStreamController,
|
|
9646
9567
|
enhanceController: opts.enhanceController,
|
|
9647
9568
|
enhanceEnabled: opts.enhanceController?.enabled ?? true,
|
|
@@ -9657,9 +9578,6 @@ async function runTui(opts) {
|
|
|
9657
9578
|
getSettings: opts.getSettings,
|
|
9658
9579
|
saveSettings: opts.saveSettings,
|
|
9659
9580
|
predictNext: opts.predictNext,
|
|
9660
|
-
// Managed viewport (in-app scroll + collapsibility) follows
|
|
9661
|
-
// alt-screen: it owns the screen, so there's no native-scrollback leak.
|
|
9662
|
-
managed: useAltScreen,
|
|
9663
9581
|
chime: opts.chime,
|
|
9664
9582
|
confirmExit: opts.confirmExit,
|
|
9665
9583
|
modeLabel: opts.modeLabel,
|
|
@@ -9676,16 +9594,14 @@ async function runTui(opts) {
|
|
|
9676
9594
|
return;
|
|
9677
9595
|
}
|
|
9678
9596
|
let detachResize = null;
|
|
9679
|
-
|
|
9680
|
-
|
|
9681
|
-
|
|
9682
|
-
|
|
9683
|
-
|
|
9684
|
-
|
|
9685
|
-
|
|
9686
|
-
|
|
9687
|
-
detachResize = () => stdout.off("resize", onResize);
|
|
9688
|
-
}
|
|
9597
|
+
const onResize = () => {
|
|
9598
|
+
try {
|
|
9599
|
+
stdout.write("\x1B[J");
|
|
9600
|
+
} catch {
|
|
9601
|
+
}
|
|
9602
|
+
};
|
|
9603
|
+
stdout.on("resize", onResize);
|
|
9604
|
+
detachResize = () => stdout.off("resize", onResize);
|
|
9689
9605
|
instance.waitUntilExit().then(() => {
|
|
9690
9606
|
detachResize?.();
|
|
9691
9607
|
settle(exitCode);
|