@wrongstack/tui 0.77.0 → 0.82.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -10
- package/dist/index.d.ts +44 -61
- package/dist/index.js +279 -406
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
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';
|
|
@@ -34,6 +34,12 @@ var theme = Object.freeze({
|
|
|
34
34
|
diffAddBg: "greenBright",
|
|
35
35
|
diffDelBg: "redBright"
|
|
36
36
|
});
|
|
37
|
+
function expectDefined(value) {
|
|
38
|
+
if (value === null || value === void 0) {
|
|
39
|
+
throw new Error("Expected value to be defined");
|
|
40
|
+
}
|
|
41
|
+
return value;
|
|
42
|
+
}
|
|
37
43
|
var MODE_ICONS = {
|
|
38
44
|
teach: "\u{1F9D1}\u200D\u{1F3EB}",
|
|
39
45
|
brief: "\u26A1",
|
|
@@ -55,7 +61,7 @@ function modeIcon(label) {
|
|
|
55
61
|
var COMPACT_THRESHOLD = 50;
|
|
56
62
|
var COMFORTABLE_THRESHOLD = 90;
|
|
57
63
|
var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
58
|
-
var SPINNER_INTERVAL_MS =
|
|
64
|
+
var SPINNER_INTERVAL_MS = 250;
|
|
59
65
|
function StatusBar({
|
|
60
66
|
model,
|
|
61
67
|
version,
|
|
@@ -65,7 +71,7 @@ function StatusBar({
|
|
|
65
71
|
queueCount = 0,
|
|
66
72
|
yolo = false,
|
|
67
73
|
autonomy,
|
|
68
|
-
|
|
74
|
+
startedAt,
|
|
69
75
|
todos,
|
|
70
76
|
plan,
|
|
71
77
|
fleet,
|
|
@@ -98,6 +104,12 @@ function StatusBar({
|
|
|
98
104
|
const usage = tokenCounter?.total();
|
|
99
105
|
const cost = tokenCounter?.estimateCost();
|
|
100
106
|
const cache2 = tokenCounter?.cacheStats();
|
|
107
|
+
const [elapsedMs, setElapsedMs] = useState(startedAt ? Date.now() - startedAt : 0);
|
|
108
|
+
useEffect(() => {
|
|
109
|
+
if (startedAt == null) return;
|
|
110
|
+
const t = setInterval(() => setElapsedMs(Date.now() - startedAt), 1e3);
|
|
111
|
+
return () => clearInterval(t);
|
|
112
|
+
}, [startedAt]);
|
|
101
113
|
const [spinnerIdx, setSpinnerIdx] = useState(0);
|
|
102
114
|
useEffect(() => {
|
|
103
115
|
if (state === "idle" || state === "aborting") return;
|
|
@@ -107,10 +119,11 @@ function StatusBar({
|
|
|
107
119
|
);
|
|
108
120
|
return () => clearInterval(t);
|
|
109
121
|
}, [state]);
|
|
110
|
-
const spinner = SPINNER_FRAMES[spinnerIdx];
|
|
122
|
+
const spinner = expectDefined(SPINNER_FRAMES[spinnerIdx]);
|
|
111
123
|
const { label: stateLabel, color: stateColor } = stateChip(state, fleet?.running ?? 0);
|
|
112
124
|
const statePrefix = state === "idle" || state === "aborting" ? "\u25CF" : spinner;
|
|
113
|
-
const
|
|
125
|
+
const thinking = state === "running" || state === "streaming";
|
|
126
|
+
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
127
|
const fleetHasActivity = fleet && (fleet.running > 0 || fleet.idle > 0 || fleet.pending > 0 || fleet.completed > 0) || subagentCount > 0;
|
|
115
128
|
const hasBrainActivity = !!brain && brain.state !== "idle";
|
|
116
129
|
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 +141,7 @@ function StatusBar({
|
|
|
128
141
|
/* @__PURE__ */ jsx(Box, { flexDirection: "row", gap: 2, children: isCompact ? (
|
|
129
142
|
// Ultra-compact: state · model
|
|
130
143
|
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
131
|
-
/* @__PURE__ */ jsxs(Text, { color: stateColor, children: [
|
|
144
|
+
thinking ? /* @__PURE__ */ jsx(WaveText, { text: `${statePrefix}${stateLabel}`, phase: spinnerIdx }) : /* @__PURE__ */ jsxs(Text, { color: stateColor, children: [
|
|
132
145
|
statePrefix,
|
|
133
146
|
stateLabel
|
|
134
147
|
] }),
|
|
@@ -148,7 +161,7 @@ function StatusBar({
|
|
|
148
161
|
] }),
|
|
149
162
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" })
|
|
150
163
|
] }) : null,
|
|
151
|
-
/* @__PURE__ */ jsxs(Text, { color: stateColor, children: [
|
|
164
|
+
thinking ? /* @__PURE__ */ jsx(WaveText, { text: `${statePrefix} ${stateLabel}`, phase: spinnerIdx }) : /* @__PURE__ */ jsxs(Text, { color: stateColor, children: [
|
|
152
165
|
statePrefix,
|
|
153
166
|
" ",
|
|
154
167
|
stateLabel
|
|
@@ -205,7 +218,7 @@ function StatusBar({
|
|
|
205
218
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
|
|
206
219
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: hint })
|
|
207
220
|
] }) : null,
|
|
208
|
-
indexState
|
|
221
|
+
indexState?.indexing ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
209
222
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
|
|
210
223
|
/* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
|
|
211
224
|
"\u2699 indexing ",
|
|
@@ -244,14 +257,14 @@ function StatusBar({
|
|
|
244
257
|
] })
|
|
245
258
|
] }) : null,
|
|
246
259
|
projectName ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
247
|
-
yolo ||
|
|
260
|
+
yolo || startedAt != null ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
|
|
248
261
|
/* @__PURE__ */ jsxs(Text, { color: "blue", children: [
|
|
249
262
|
"\u{1F4C1} ",
|
|
250
263
|
projectName
|
|
251
264
|
] })
|
|
252
265
|
] }) : null,
|
|
253
266
|
goalSummary ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
254
|
-
yolo ||
|
|
267
|
+
yolo || startedAt != null || projectName ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
|
|
255
268
|
/* @__PURE__ */ jsxs(
|
|
256
269
|
Text,
|
|
257
270
|
{
|
|
@@ -271,11 +284,11 @@ function StatusBar({
|
|
|
271
284
|
)
|
|
272
285
|
] }) : null,
|
|
273
286
|
modeLabel ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
274
|
-
yolo || autonomy && autonomy !== "off" || eternalStage ||
|
|
287
|
+
yolo || autonomy && autonomy !== "off" || eternalStage || startedAt != null || projectName || goalSummary ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
|
|
275
288
|
/* @__PURE__ */ jsx(Text, { color: "cyan", children: modeIcon(modeLabel) })
|
|
276
289
|
] }) : null,
|
|
277
290
|
git ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
278
|
-
yolo ||
|
|
291
|
+
yolo || startedAt != null || projectName ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
|
|
279
292
|
/* @__PURE__ */ jsxs(Text, { children: [
|
|
280
293
|
/* @__PURE__ */ jsxs(Text, { color: "magenta", children: [
|
|
281
294
|
"\u2387 ",
|
|
@@ -375,7 +388,7 @@ function StatusBar({
|
|
|
375
388
|
/* @__PURE__ */ jsxs(Text, { children: [
|
|
376
389
|
/* @__PURE__ */ jsx(Text, { color: a.color, bold: true, children: a.label }),
|
|
377
390
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " " }),
|
|
378
|
-
/* @__PURE__ */ jsx(Text, {
|
|
391
|
+
/* @__PURE__ */ jsx(Text, { dimColor: !a.running, ...a.running ? { color: "yellow" } : {}, children: a.running ? "\u25B6" : "\xB7" }),
|
|
379
392
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " " }),
|
|
380
393
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: fmtElapsed(a.elapsedMs) }),
|
|
381
394
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " \xB7 " }),
|
|
@@ -504,6 +517,26 @@ function stateChip(state, fleetRunning) {
|
|
|
504
517
|
if (state === "aborting") return { label: "aborting\u2026", color: "yellow" };
|
|
505
518
|
return { label: "thinking\u2026", color: "green" };
|
|
506
519
|
}
|
|
520
|
+
var WAVE_COLORS = [
|
|
521
|
+
"#ff5f5f",
|
|
522
|
+
"#ff8f3f",
|
|
523
|
+
"#ffd23f",
|
|
524
|
+
"#bce84a",
|
|
525
|
+
"#6bcb77",
|
|
526
|
+
"#3dd9c0",
|
|
527
|
+
"#3fb6ff",
|
|
528
|
+
"#5f8bff",
|
|
529
|
+
"#845ef7",
|
|
530
|
+
"#b15bff",
|
|
531
|
+
"#f06595",
|
|
532
|
+
"#ff5fa2"
|
|
533
|
+
];
|
|
534
|
+
function WaveText({ text, phase }) {
|
|
535
|
+
return /* @__PURE__ */ jsx(Text, { bold: true, children: Array.from(text).map((ch, i) => (
|
|
536
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: glyph order is positional and re-rendered each tick
|
|
537
|
+
/* @__PURE__ */ jsx(Text, { color: WAVE_COLORS[(i + phase) % WAVE_COLORS.length], children: ch }, i)
|
|
538
|
+
)) });
|
|
539
|
+
}
|
|
507
540
|
var FILLED = "\u2588";
|
|
508
541
|
var EMPTY = "\u2591";
|
|
509
542
|
function renderProgress(ratio, width) {
|
|
@@ -565,7 +598,7 @@ function bucketActivity(recentTools, now, bins = 12, binMs = 2e3) {
|
|
|
565
598
|
let idx = Math.floor((t.at - windowStart) / binMs);
|
|
566
599
|
if (idx < 0) idx = 0;
|
|
567
600
|
if (idx >= bins) idx = bins - 1;
|
|
568
|
-
out[idx]
|
|
601
|
+
out[idx] = (out[idx] ?? 0) + 1;
|
|
569
602
|
}
|
|
570
603
|
return out;
|
|
571
604
|
}
|
|
@@ -694,7 +727,7 @@ function FleetMonitor({
|
|
|
694
727
|
// biome-ignore lint/suspicious/noArrayIndexKey: timeline is rebuilt per render
|
|
695
728
|
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
696
729
|
/* @__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 }),
|
|
730
|
+
/* @__PURE__ */ jsx(Text, { ...ev.color ? { color: ev.color } : {}, children: ev.icon }),
|
|
698
731
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: ev.text })
|
|
699
732
|
] }, i)
|
|
700
733
|
)) }) : null
|
|
@@ -1021,8 +1054,8 @@ function AutonomyPicker({
|
|
|
1021
1054
|
options.map((opt, i) => /* @__PURE__ */ jsxs(
|
|
1022
1055
|
Text,
|
|
1023
1056
|
{
|
|
1024
|
-
color: i === selected ? opt.color : void 0,
|
|
1025
1057
|
inverse: i === selected,
|
|
1058
|
+
...i === selected ? { color: opt.color } : {},
|
|
1026
1059
|
children: [
|
|
1027
1060
|
i === selected ? "\u203A " : " ",
|
|
1028
1061
|
/* @__PURE__ */ jsx(Text, { bold: true, children: opt.label.padEnd(12) }),
|
|
@@ -1147,8 +1180,8 @@ function CheckpointTimeline({
|
|
|
1147
1180
|
const isSelected = i === selected;
|
|
1148
1181
|
const label = `[${cp.promptIndex}] ${cp.promptPreview}`;
|
|
1149
1182
|
return /* @__PURE__ */ jsxs(Box, { children: [
|
|
1150
|
-
/* @__PURE__ */ jsx(Text, {
|
|
1151
|
-
/* @__PURE__ */ jsx(Text, {
|
|
1183
|
+
/* @__PURE__ */ jsx(Text, { bold: isSelected, ...isSelected ? { color: "cyan" } : {}, children: isSelected ? "\u25B8 " : " " }),
|
|
1184
|
+
/* @__PURE__ */ jsx(Text, { bold: isSelected, ...isSelected ? { color: "cyan" } : {}, children: label }),
|
|
1152
1185
|
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
1153
1186
|
" ",
|
|
1154
1187
|
new Date(cp.ts).toLocaleTimeString()
|
|
@@ -1193,7 +1226,7 @@ function hasDiff(input) {
|
|
|
1193
1226
|
}
|
|
1194
1227
|
function renderDiffLine(line) {
|
|
1195
1228
|
const prefix = line.startsWith("+") ? "green" : line.startsWith("-") ? "red" : line.startsWith("@@") ? "cyan" : void 0;
|
|
1196
|
-
return /* @__PURE__ */ jsxs(Text, { color: prefix, children: [
|
|
1229
|
+
return /* @__PURE__ */ jsxs(Text, { ...prefix ? { color: prefix } : {}, children: [
|
|
1197
1230
|
line,
|
|
1198
1231
|
"\n"
|
|
1199
1232
|
] }, line);
|
|
@@ -1318,7 +1351,7 @@ function FilePicker({ query, matches, selected }) {
|
|
|
1318
1351
|
query || "\u2026",
|
|
1319
1352
|
" \u2014 \u2191/\u2193 select, Enter attach, Esc cancel"
|
|
1320
1353
|
] }),
|
|
1321
|
-
matches.map((m, i) => /* @__PURE__ */ jsxs(Text, {
|
|
1354
|
+
matches.map((m, i) => /* @__PURE__ */ jsxs(Text, { inverse: i === selected, ...i === selected ? { color: "cyan" } : {}, children: [
|
|
1322
1355
|
i === selected ? "\u203A " : " ",
|
|
1323
1356
|
highlight(m)
|
|
1324
1357
|
] }, m))
|
|
@@ -1392,9 +1425,8 @@ function FleetPanel({
|
|
|
1392
1425
|
] }) : null
|
|
1393
1426
|
] });
|
|
1394
1427
|
}
|
|
1395
|
-
function helpSections(
|
|
1428
|
+
function helpSections() {
|
|
1396
1429
|
const nav = [];
|
|
1397
|
-
if (opts.managed) nav.push({ keys: "PgUp/PgDn", desc: "scroll chat history" });
|
|
1398
1430
|
nav.push(
|
|
1399
1431
|
{ keys: "\u2191/\u2193", desc: "previous / next input (empty prompt)" },
|
|
1400
1432
|
{ keys: "?", desc: "open this help (empty prompt)" }
|
|
@@ -1437,10 +1469,8 @@ function helpSections(opts) {
|
|
|
1437
1469
|
}
|
|
1438
1470
|
];
|
|
1439
1471
|
}
|
|
1440
|
-
function HelpOverlay({
|
|
1441
|
-
|
|
1442
|
-
}) {
|
|
1443
|
-
const sections = helpSections({ managed });
|
|
1472
|
+
function HelpOverlay() {
|
|
1473
|
+
const sections = helpSections();
|
|
1444
1474
|
const keyWidth = Math.max(...sections.flatMap((s2) => s2.entries.map((e) => e.keys.length)), 0);
|
|
1445
1475
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
|
|
1446
1476
|
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
@@ -1905,6 +1935,12 @@ function detectLang(fenceInfo) {
|
|
|
1905
1935
|
}
|
|
1906
1936
|
|
|
1907
1937
|
// src/markdown-table.ts
|
|
1938
|
+
function expectDefined2(value) {
|
|
1939
|
+
if (value === null || value === void 0) {
|
|
1940
|
+
throw new Error("Expected value to be defined");
|
|
1941
|
+
}
|
|
1942
|
+
return value;
|
|
1943
|
+
}
|
|
1908
1944
|
var ROW_RE = /^\s*\|.*\|\s*$/;
|
|
1909
1945
|
var SEP_RE = /^\s*\|[\s\-:|]+\|\s*$/;
|
|
1910
1946
|
function detectTable(lines, start) {
|
|
@@ -1988,14 +2024,14 @@ function computeWidths(allRows, cols, maxWidth, sepWidths) {
|
|
|
1988
2024
|
const stripped = stripInlineMarkers(cell);
|
|
1989
2025
|
const w = longestWord(stripped);
|
|
1990
2026
|
const total = strWidth(stripped);
|
|
1991
|
-
natural[c] = Math.max(natural[c], w, total);
|
|
2027
|
+
natural[c] = Math.max(expectDefined2(natural[c]), w, total);
|
|
1992
2028
|
}
|
|
1993
2029
|
}
|
|
1994
2030
|
if (sepWidths) {
|
|
1995
2031
|
for (let c = 0; c < cols && c < sepWidths.length; c++) {
|
|
1996
2032
|
const sepW = sepWidths[c];
|
|
1997
2033
|
if (sepW != null) {
|
|
1998
|
-
natural[c] = Math.max(natural[c], sepW);
|
|
2034
|
+
natural[c] = Math.max(expectDefined2(natural[c]), sepW);
|
|
1999
2035
|
}
|
|
2000
2036
|
}
|
|
2001
2037
|
}
|
|
@@ -2007,14 +2043,14 @@ function computeWidths(allRows, cols, maxWidth, sepWidths) {
|
|
|
2007
2043
|
let maxIdx = -1;
|
|
2008
2044
|
let maxVal = MIN_COL_WIDTH;
|
|
2009
2045
|
for (let i = 0; i < cols; i++) {
|
|
2010
|
-
const w = widths[i];
|
|
2046
|
+
const w = expectDefined2(widths[i]);
|
|
2011
2047
|
if (w > maxVal) {
|
|
2012
2048
|
maxVal = w;
|
|
2013
2049
|
maxIdx = i;
|
|
2014
2050
|
}
|
|
2015
2051
|
}
|
|
2016
2052
|
if (maxIdx < 0) break;
|
|
2017
|
-
widths[maxIdx]
|
|
2053
|
+
widths[maxIdx] = (widths[maxIdx] ?? 0) - 1;
|
|
2018
2054
|
sum--;
|
|
2019
2055
|
}
|
|
2020
2056
|
return widths;
|
|
@@ -2067,7 +2103,7 @@ function strWidth(s2) {
|
|
|
2067
2103
|
if (i < len) i++;
|
|
2068
2104
|
continue;
|
|
2069
2105
|
}
|
|
2070
|
-
const code = s2.codePointAt(i);
|
|
2106
|
+
const code = expectDefined2(s2.codePointAt(i));
|
|
2071
2107
|
const cpLen = code > 65535 ? 2 : 1;
|
|
2072
2108
|
if (code === 8205 || // ZWJ — Zero Width Joiner (emoji sequences)
|
|
2073
2109
|
code === 8203 || // ZWSP — Zero Width Space
|
|
@@ -2310,10 +2346,10 @@ function InlineLine({ tokens, dim }) {
|
|
|
2310
2346
|
Text,
|
|
2311
2347
|
{
|
|
2312
2348
|
color: t.code ? theme.accent : "white",
|
|
2313
|
-
bold: t.bold,
|
|
2314
|
-
italic: t.italic,
|
|
2315
|
-
strikethrough: t.strike,
|
|
2316
|
-
dimColor: dim,
|
|
2349
|
+
bold: Boolean(t.bold),
|
|
2350
|
+
italic: Boolean(t.italic),
|
|
2351
|
+
strikethrough: Boolean(t.strike),
|
|
2352
|
+
dimColor: Boolean(dim),
|
|
2317
2353
|
children: t.text
|
|
2318
2354
|
},
|
|
2319
2355
|
j
|
|
@@ -2938,7 +2974,22 @@ function formatToolOutput(toolName, output, ok, _outputBytes, outputLines) {
|
|
|
2938
2974
|
}
|
|
2939
2975
|
var MAX_STREAM_DISPLAY_CHARS = 480;
|
|
2940
2976
|
var MAX_STREAM_LINES = 8;
|
|
2941
|
-
|
|
2977
|
+
function streamBoxRows(text, maxLines, contentWidth) {
|
|
2978
|
+
const trunc = (line) => line.length > contentWidth ? `${line.slice(0, contentWidth - 1)}\u2026` : line;
|
|
2979
|
+
const lines = text.split("\n");
|
|
2980
|
+
const totalLines = lines.length;
|
|
2981
|
+
const hidden = Math.max(0, totalLines - maxLines);
|
|
2982
|
+
const rows = [];
|
|
2983
|
+
if (hidden > 0) {
|
|
2984
|
+
rows.push({ text: ` \u2026 ${hidden} more line${hidden === 1 ? "" : "s"} above`, italic: true });
|
|
2985
|
+
for (const line of lines.slice(totalLines - (maxLines - 1))) rows.push({ text: trunc(line) });
|
|
2986
|
+
} else {
|
|
2987
|
+
for (let i = 0; i < maxLines - totalLines; i++) rows.push({ text: "" });
|
|
2988
|
+
for (const line of lines) rows.push({ text: trunc(line) });
|
|
2989
|
+
}
|
|
2990
|
+
return rows;
|
|
2991
|
+
}
|
|
2992
|
+
React6.memo(function ToolStreamBox2({
|
|
2942
2993
|
name,
|
|
2943
2994
|
text,
|
|
2944
2995
|
startedAt,
|
|
@@ -2950,11 +3001,10 @@ var ToolStreamBox = React6.memo(function ToolStreamBox2({
|
|
|
2950
3001
|
return () => clearInterval(t);
|
|
2951
3002
|
}, []);
|
|
2952
3003
|
const elapsedMs = Date.now() - startedAt;
|
|
2953
|
-
const
|
|
2954
|
-
const totalLines = lines.length;
|
|
3004
|
+
const totalLines = text.split("\n").length;
|
|
2955
3005
|
const hidden = Math.max(0, totalLines - MAX_STREAM_LINES);
|
|
2956
|
-
const visible = hidden > 0 ? lines.slice(hidden) : lines;
|
|
2957
3006
|
const contentWidth = Math.max(20, Math.min(termWidth - 4, 100));
|
|
3007
|
+
const rows = streamBoxRows(text, MAX_STREAM_LINES, contentWidth);
|
|
2958
3008
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 0, children: [
|
|
2959
3009
|
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", children: [
|
|
2960
3010
|
/* @__PURE__ */ jsx(Text, { color: theme.warn, children: "\u25C6 " }),
|
|
@@ -2962,13 +3012,10 @@ var ToolStreamBox = React6.memo(function ToolStreamBox2({
|
|
|
2962
3012
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u23F1 ${fmtDuration(elapsedMs)}` }),
|
|
2963
3013
|
hidden > 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` (${totalLines} lines, showing last ${MAX_STREAM_LINES})` }) : null
|
|
2964
3014
|
] }),
|
|
2965
|
-
/* @__PURE__ */
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
return /* @__PURE__ */ jsx(Text, { dimColor: true, children: trimmed || " " }, i);
|
|
2970
|
-
})
|
|
2971
|
-
] })
|
|
3015
|
+
/* @__PURE__ */ jsx(Box, { flexDirection: "column", marginLeft: 2, children: rows.map((r, i) => (
|
|
3016
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: fixed-height block, index is the row
|
|
3017
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, italic: Boolean(r.italic), children: r.text || " " }, i)
|
|
3018
|
+
)) })
|
|
2972
3019
|
] });
|
|
2973
3020
|
});
|
|
2974
3021
|
function tailForDisplay(text, maxChars) {
|
|
@@ -3014,9 +3061,15 @@ function CodeBlock({
|
|
|
3014
3061
|
// biome-ignore lint/suspicious/noArrayIndexKey: code lines are positional
|
|
3015
3062
|
/* @__PURE__ */ jsxs(Text, { children: [
|
|
3016
3063
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: `${String(i + 1).padStart(gutterW, " ")} ` }),
|
|
3017
|
-
tokens.length === 0 ? " " : tokens.map((t, j) => (
|
|
3018
|
-
|
|
3019
|
-
|
|
3064
|
+
tokens.length === 0 ? " " : tokens.map((t, j) => /* @__PURE__ */ jsx(
|
|
3065
|
+
Text,
|
|
3066
|
+
{
|
|
3067
|
+
dimColor: Boolean(t.dim),
|
|
3068
|
+
bold: Boolean(t.bold),
|
|
3069
|
+
...t.color ? { color: t.color } : {},
|
|
3070
|
+
children: t.text
|
|
3071
|
+
},
|
|
3072
|
+
j
|
|
3020
3073
|
))
|
|
3021
3074
|
] }, i)
|
|
3022
3075
|
)),
|
|
@@ -3170,7 +3223,22 @@ function AssistantBody({
|
|
|
3170
3223
|
)
|
|
3171
3224
|
) });
|
|
3172
3225
|
}
|
|
3173
|
-
|
|
3226
|
+
var ASSISTANT_TAIL_LINES = 8;
|
|
3227
|
+
function assistantTailRows(text, tailLines, contentWidth) {
|
|
3228
|
+
const tail = text.split("\n").slice(-tailLines);
|
|
3229
|
+
const rows = [];
|
|
3230
|
+
for (let i = 0; i < tailLines - tail.length; i++) rows.push("");
|
|
3231
|
+
for (const line of tail) {
|
|
3232
|
+
rows.push(line.length > contentWidth ? `${line.slice(0, contentWidth - 1)}\u2026` : line);
|
|
3233
|
+
}
|
|
3234
|
+
return rows;
|
|
3235
|
+
}
|
|
3236
|
+
function AssistantTail({
|
|
3237
|
+
text,
|
|
3238
|
+
termWidth
|
|
3239
|
+
}) {
|
|
3240
|
+
const contentWidth = Math.max(20, termWidth - 3);
|
|
3241
|
+
const rows = assistantTailRows(text, ASSISTANT_TAIL_LINES, contentWidth);
|
|
3174
3242
|
return /* @__PURE__ */ jsxs(
|
|
3175
3243
|
Box,
|
|
3176
3244
|
{
|
|
@@ -3187,7 +3255,10 @@ function AssistantTail({ text }) {
|
|
|
3187
3255
|
/* @__PURE__ */ jsx(Text, { bold: true, color: theme.assistant, children: "ASSISTANT" }),
|
|
3188
3256
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " (streaming\u2026)" })
|
|
3189
3257
|
] }),
|
|
3190
|
-
/* @__PURE__ */ jsx(
|
|
3258
|
+
/* @__PURE__ */ jsx(Box, { flexDirection: "column", children: rows.map((r, i) => (
|
|
3259
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: fixed-height block, index is the row
|
|
3260
|
+
/* @__PURE__ */ jsx(Text, { color: "white", children: r || " " }, i)
|
|
3261
|
+
)) })
|
|
3191
3262
|
]
|
|
3192
3263
|
}
|
|
3193
3264
|
);
|
|
@@ -3350,8 +3421,8 @@ var Entry = React6.memo(function Entry2({
|
|
|
3350
3421
|
/* @__PURE__ */ jsx(
|
|
3351
3422
|
Text,
|
|
3352
3423
|
{
|
|
3353
|
-
color: !entry.ok || line.startsWith("!") ? "red" : void 0,
|
|
3354
3424
|
dimColor: entry.ok && !line.startsWith("!"),
|
|
3425
|
+
...!entry.ok || line.startsWith("!") ? { color: "red" } : {},
|
|
3355
3426
|
children: line
|
|
3356
3427
|
}
|
|
3357
3428
|
)
|
|
@@ -3484,19 +3555,9 @@ function History({ entries, streamingText, toolStream }) {
|
|
|
3484
3555
|
}, [stdout]);
|
|
3485
3556
|
const termWidth = termSize.columns;
|
|
3486
3557
|
const tail = streamingText ? tailForDisplay(streamingText, MAX_STREAM_DISPLAY_CHARS) : "";
|
|
3487
|
-
const toolTail = toolStream?.text ? tailForDisplay(toolStream.text, MAX_STREAM_DISPLAY_CHARS) : "";
|
|
3488
3558
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3489
3559
|
/* @__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
|
|
3560
|
+
tail ? /* @__PURE__ */ jsx(AssistantTail, { text: tail, termWidth }) : null
|
|
3500
3561
|
] });
|
|
3501
3562
|
}
|
|
3502
3563
|
|
|
@@ -3602,6 +3663,12 @@ function layoutInputRows(prompt, value, cursor, width) {
|
|
|
3602
3663
|
if (row.length > 0 || rows.length === 0) rows.push(row);
|
|
3603
3664
|
return rows;
|
|
3604
3665
|
}
|
|
3666
|
+
function expectDefined3(value) {
|
|
3667
|
+
if (value === null || value === void 0) {
|
|
3668
|
+
throw new Error("Expected value to be defined");
|
|
3669
|
+
}
|
|
3670
|
+
return value;
|
|
3671
|
+
}
|
|
3605
3672
|
function renderRow2(cells, rowKey, promptColor) {
|
|
3606
3673
|
const out = [];
|
|
3607
3674
|
let run = "";
|
|
@@ -3655,6 +3722,14 @@ function isBackspaceOrDelete(data) {
|
|
|
3655
3722
|
if (data === "\x1B[3~") return "delete";
|
|
3656
3723
|
return null;
|
|
3657
3724
|
}
|
|
3725
|
+
function parseMouseWheel(data) {
|
|
3726
|
+
const m = data.match(new RegExp(`^${String.fromCharCode(27)}\\[<(\\d+);(\\d+);(\\d+)([Mm])$`, "u"));
|
|
3727
|
+
if (!m) return null;
|
|
3728
|
+
const cb = Number.parseInt(expectDefined3(m[1]), 10);
|
|
3729
|
+
if (cb === 64) return 1;
|
|
3730
|
+
if (cb === 65) return -1;
|
|
3731
|
+
return null;
|
|
3732
|
+
}
|
|
3658
3733
|
var EMPTY_KEY = {
|
|
3659
3734
|
upArrow: false,
|
|
3660
3735
|
downArrow: false,
|
|
@@ -3708,6 +3783,11 @@ function Input({
|
|
|
3708
3783
|
onKey("", { ...EMPTY_KEY, delete: true });
|
|
3709
3784
|
return;
|
|
3710
3785
|
}
|
|
3786
|
+
const wheelDelta = parseMouseWheel(s2);
|
|
3787
|
+
if (wheelDelta !== null) {
|
|
3788
|
+
onKey("", { ...EMPTY_KEY, wheelDeltaY: wheelDelta });
|
|
3789
|
+
return;
|
|
3790
|
+
}
|
|
3711
3791
|
const fn = fnKey(s2);
|
|
3712
3792
|
if (fn !== null) onKey("", { ...EMPTY_KEY, fn });
|
|
3713
3793
|
};
|
|
@@ -3742,46 +3822,6 @@ function Input({
|
|
|
3742
3822
|
hint ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: hint }) : null
|
|
3743
3823
|
] });
|
|
3744
3824
|
}
|
|
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
3825
|
function fmtElapsed2(ms) {
|
|
3786
3826
|
if (ms < 1e3) return `${ms}ms`;
|
|
3787
3827
|
if (ms < 6e4) return `${(ms / 1e3).toFixed(1)}s`;
|
|
@@ -3816,7 +3856,7 @@ var LiveActivityStrip = React6.memo(function LiveActivityStrip2({
|
|
|
3816
3856
|
const running = Object.values(entries).filter((e) => e.status === "running").sort((a, b) => a.startedAt - b.startedAt).slice(0, maxRows);
|
|
3817
3857
|
if (running.length === 0) {
|
|
3818
3858
|
if (Object.keys(entries).length === 0) return null;
|
|
3819
|
-
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", paddingX: 1, children: Array.from({ length: maxRows }, (_,
|
|
3859
|
+
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
3860
|
}
|
|
3821
3861
|
const now = Date.now();
|
|
3822
3862
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 1, children: [
|
|
@@ -3890,7 +3930,7 @@ function ModelPicker({
|
|
|
3890
3930
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
|
|
3891
3931
|
/* @__PURE__ */ jsx(Text, { color: "cyan", bold: true, children: "\u2501\u2501 Switch model \u2014 Step 1/2: Pick provider \u2501\u2501" }),
|
|
3892
3932
|
/* @__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, {
|
|
3933
|
+
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
3934
|
i === selected ? "\u203A " : " ",
|
|
3895
3935
|
/* @__PURE__ */ jsx(Text, { bold: true, children: p.id.padEnd(28) }),
|
|
3896
3936
|
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
@@ -3933,8 +3973,8 @@ function ModelPicker({
|
|
|
3933
3973
|
return /* @__PURE__ */ jsxs(
|
|
3934
3974
|
Text,
|
|
3935
3975
|
{
|
|
3936
|
-
color: absoluteIndex === selected ? "cyan" : void 0,
|
|
3937
3976
|
inverse: absoluteIndex === selected,
|
|
3977
|
+
...absoluteIndex === selected ? { color: "cyan" } : {},
|
|
3938
3978
|
children: [
|
|
3939
3979
|
absoluteIndex === selected ? "\u203A " : " ",
|
|
3940
3980
|
id
|
|
@@ -4173,102 +4213,6 @@ function QueuePanel({ items }) {
|
|
|
4173
4213
|
] })
|
|
4174
4214
|
] });
|
|
4175
4215
|
}
|
|
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
4216
|
var DELAY_PRESETS_MS = [0, 15e3, 3e4, 45e3, 6e4, 12e4];
|
|
4273
4217
|
var SETTINGS_MODES = ["off", "suggest", "auto"];
|
|
4274
4218
|
var LOG_LEVELS = ["error", "warn", "info", "debug", "trace"];
|
|
@@ -4425,7 +4369,7 @@ function SettingsPicker({
|
|
|
4425
4369
|
];
|
|
4426
4370
|
const fieldRowIndex = [];
|
|
4427
4371
|
for (let i = 0; i < rows.length; i++) {
|
|
4428
|
-
if (!rows[i]
|
|
4372
|
+
if (!rows[i]?.section) fieldRowIndex.push(i);
|
|
4429
4373
|
}
|
|
4430
4374
|
const VISIBLE_FIELDS = 8;
|
|
4431
4375
|
const totalFields = fieldRowIndex.length;
|
|
@@ -4436,7 +4380,7 @@ function SettingsPicker({
|
|
|
4436
4380
|
const sectionFields = [];
|
|
4437
4381
|
let curHeader = -1;
|
|
4438
4382
|
for (let i = 0; i < rows.length; i++) {
|
|
4439
|
-
if (rows[i]
|
|
4383
|
+
if (rows[i]?.section) curHeader = i;
|
|
4440
4384
|
else if (curHeader >= 0) {
|
|
4441
4385
|
const fieldIdx = fieldRowIndex.indexOf(i);
|
|
4442
4386
|
if (fieldIdx === -1) continue;
|
|
@@ -4465,18 +4409,18 @@ function SettingsPicker({
|
|
|
4465
4409
|
"\u2500\u2500 ",
|
|
4466
4410
|
row.section,
|
|
4467
4411
|
" \u2500\u2500"
|
|
4468
|
-
] }, `section-${i}`);
|
|
4412
|
+
] }, `section-${row.section ?? i}`);
|
|
4469
4413
|
}
|
|
4470
4414
|
return null;
|
|
4471
4415
|
}
|
|
4472
4416
|
if (fieldAtRow < windowStart || fieldAtRow >= windowEnd) return null;
|
|
4473
4417
|
const selected = fieldAtRow === field;
|
|
4474
|
-
return /* @__PURE__ */ jsxs(Text, {
|
|
4418
|
+
return /* @__PURE__ */ jsxs(Text, { inverse: selected, ...selected ? { color: "yellow" } : {}, children: [
|
|
4475
4419
|
selected ? "\u203A " : " ",
|
|
4476
4420
|
/* @__PURE__ */ jsx(Text, { bold: true, children: (row.label ?? "").padEnd(26) }),
|
|
4477
4421
|
/* @__PURE__ */ jsx(Text, { color: "cyan", children: String(row.value ?? "").padEnd(12) }),
|
|
4478
4422
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: row.detail ?? "" })
|
|
4479
|
-
] }, `row-${
|
|
4423
|
+
] }, `row-${row.label ?? fieldAtRow}`);
|
|
4480
4424
|
}),
|
|
4481
4425
|
hasBelow ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u2193 ${totalFields - windowEnd} field${totalFields - windowEnd === 1 ? "" : "s"} below` }) : null,
|
|
4482
4426
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Persisted to ~/.wrongstack/config.json" }),
|
|
@@ -4485,31 +4429,47 @@ function SettingsPicker({
|
|
|
4485
4429
|
}
|
|
4486
4430
|
function SlashMenu({ query, matches, selected }) {
|
|
4487
4431
|
const placeholder = query ? `/${query}` : "/";
|
|
4432
|
+
const rows = [];
|
|
4433
|
+
let lastCategory = "";
|
|
4434
|
+
for (let i = 0; i < matches.length; i++) {
|
|
4435
|
+
const m = matches[i];
|
|
4436
|
+
if (m.category !== lastCategory) {
|
|
4437
|
+
lastCategory = m.category;
|
|
4438
|
+
rows.push({ type: "header", category: m.category });
|
|
4439
|
+
}
|
|
4440
|
+
rows.push({ type: "item", match: m, index: i });
|
|
4441
|
+
}
|
|
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
4445
|
" \u2014 \u2191/\u2193 select, Enter dispatch, Tab autocomplete, Esc close"
|
|
4492
4446
|
] }),
|
|
4493
|
-
|
|
4494
|
-
|
|
4495
|
-
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
4447
|
+
rows.map((row) => {
|
|
4448
|
+
if (row.type === "header") {
|
|
4449
|
+
return /* @__PURE__ */ jsxs(Text, { bold: true, color: "yellow", dimColor: true, children: [
|
|
4450
|
+
" ",
|
|
4451
|
+
row.category
|
|
4452
|
+
] }, `cat-${row.category}`);
|
|
4453
|
+
}
|
|
4454
|
+
const { match: m, index: i } = row;
|
|
4455
|
+
return /* @__PURE__ */ jsxs(Text, { inverse: i === selected, ...i === selected ? { color: "cyan" } : {}, children: [
|
|
4456
|
+
i === selected ? "\u203A " : " ",
|
|
4457
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: m.name }),
|
|
4458
|
+
m.argsHint ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
4459
|
+
" ",
|
|
4460
|
+
m.argsHint
|
|
4461
|
+
] }) : null,
|
|
4462
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
4463
|
+
" \u2014 ",
|
|
4464
|
+
m.description
|
|
4465
|
+
] })
|
|
4466
|
+
] }, m.name);
|
|
4467
|
+
}),
|
|
4505
4468
|
matches.length === 0 && /* @__PURE__ */ jsx(Text, { dimColor: true, children: "No matching commands" })
|
|
4506
4469
|
] });
|
|
4507
4470
|
}
|
|
4508
4471
|
function TodosMonitor({ todos }) {
|
|
4509
4472
|
const { stdout } = useStdout();
|
|
4510
|
-
useInput((_input, key) => {
|
|
4511
|
-
if (key.escape) ;
|
|
4512
|
-
});
|
|
4513
4473
|
const done = todos.filter((t) => t.status === "completed").length;
|
|
4514
4474
|
const inProgress = todos.filter((t) => t.status === "in_progress").length;
|
|
4515
4475
|
const pending = todos.filter((t) => t.status === "pending").length;
|
|
@@ -4949,7 +4909,15 @@ function useBrainEvents(events, dispatch) {
|
|
|
4949
4909
|
const decision = p.decision.optionId ?? p.decision.text ?? p.decision.reason ?? p.decision.prompt ?? p.decision.type;
|
|
4950
4910
|
dispatch({ type: "brainStatus", state: status, source: p.request.source, risk: p.request.risk, summary: decision });
|
|
4951
4911
|
if (status === "ask_human") {
|
|
4952
|
-
|
|
4912
|
+
const prompt = {
|
|
4913
|
+
requestId: p.request.id,
|
|
4914
|
+
source: p.request.source,
|
|
4915
|
+
risk: p.request.risk,
|
|
4916
|
+
question: p.request.question
|
|
4917
|
+
};
|
|
4918
|
+
if (p.request.context !== void 0) prompt.context = p.request.context;
|
|
4919
|
+
if (p.request.options !== void 0) prompt.options = p.request.options;
|
|
4920
|
+
dispatch({ type: "brainPromptSet", prompt });
|
|
4953
4921
|
} else {
|
|
4954
4922
|
dispatch({ type: "brainPromptClear" });
|
|
4955
4923
|
}
|
|
@@ -4969,6 +4937,12 @@ function useBrainEvents(events, dispatch) {
|
|
|
4969
4937
|
};
|
|
4970
4938
|
}, [events, dispatch]);
|
|
4971
4939
|
}
|
|
4940
|
+
function expectDefined4(value) {
|
|
4941
|
+
if (value === null || value === void 0) {
|
|
4942
|
+
throw new Error("Expected value to be defined");
|
|
4943
|
+
}
|
|
4944
|
+
return value;
|
|
4945
|
+
}
|
|
4972
4946
|
var STREAM_COLORS = ["cyan", "magenta", "yellow", "green", "blue"];
|
|
4973
4947
|
function labelFor(labelsRef, id, name) {
|
|
4974
4948
|
const m = labelsRef.current;
|
|
@@ -4977,7 +4951,7 @@ function labelFor(labelsRef, id, name) {
|
|
|
4977
4951
|
const n = m.size + 1;
|
|
4978
4952
|
const v = {
|
|
4979
4953
|
label: name && name !== id ? name : `AGENT#${n}`,
|
|
4980
|
-
color: STREAM_COLORS[(n - 1) % STREAM_COLORS.length]
|
|
4954
|
+
color: expectDefined4(STREAM_COLORS[(n - 1) % STREAM_COLORS.length])
|
|
4981
4955
|
};
|
|
4982
4956
|
m.set(id, v);
|
|
4983
4957
|
return v;
|
|
@@ -5324,6 +5298,12 @@ function buildSteeringPreamble(snapshot, newDirection) {
|
|
|
5324
5298
|
}
|
|
5325
5299
|
|
|
5326
5300
|
// src/app-reducer.ts
|
|
5301
|
+
function expectDefined5(value) {
|
|
5302
|
+
if (value === null || value === void 0) {
|
|
5303
|
+
throw new Error("Expected value to be defined");
|
|
5304
|
+
}
|
|
5305
|
+
return value;
|
|
5306
|
+
}
|
|
5327
5307
|
function reducer(state, action) {
|
|
5328
5308
|
switch (action.type) {
|
|
5329
5309
|
case "addEntry": {
|
|
@@ -5688,13 +5668,13 @@ function reducer(state, action) {
|
|
|
5688
5668
|
const i = SETTINGS_MODES.indexOf(sp.mode);
|
|
5689
5669
|
const base = i < 0 ? 0 : i;
|
|
5690
5670
|
const next = (base + action.delta + SETTINGS_MODES.length) % SETTINGS_MODES.length;
|
|
5691
|
-
return { ...state, settingsPicker: { ...sp, mode: SETTINGS_MODES[next], hint: void 0 } };
|
|
5671
|
+
return { ...state, settingsPicker: { ...sp, mode: expectDefined5(SETTINGS_MODES[next]), hint: void 0 } };
|
|
5692
5672
|
}
|
|
5693
5673
|
if (f === 1) {
|
|
5694
5674
|
const j = DELAY_PRESETS_MS.indexOf(sp.delayMs);
|
|
5695
5675
|
const base = j < 0 ? 0 : j;
|
|
5696
5676
|
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 } };
|
|
5677
|
+
return { ...state, settingsPicker: { ...sp, delayMs: expectDefined5(DELAY_PRESETS_MS[next]), hint: void 0 } };
|
|
5698
5678
|
}
|
|
5699
5679
|
if (f === 2) return { ...state, settingsPicker: { ...sp, titleAnimation: !sp.titleAnimation, hint: void 0 } };
|
|
5700
5680
|
if (f === 3) return { ...state, settingsPicker: { ...sp, yolo: !sp.yolo, hint: void 0 } };
|
|
@@ -5712,26 +5692,26 @@ function reducer(state, action) {
|
|
|
5712
5692
|
const i = COMPACTOR_STRATEGIES.indexOf(sp.contextStrategy);
|
|
5713
5693
|
const base = i < 0 ? 0 : i;
|
|
5714
5694
|
const next = (base + action.delta + COMPACTOR_STRATEGIES.length) % COMPACTOR_STRATEGIES.length;
|
|
5715
|
-
return { ...state, settingsPicker: { ...sp, contextStrategy: COMPACTOR_STRATEGIES[next], hint: void 0 } };
|
|
5695
|
+
return { ...state, settingsPicker: { ...sp, contextStrategy: expectDefined5(COMPACTOR_STRATEGIES[next]), hint: void 0 } };
|
|
5716
5696
|
}
|
|
5717
5697
|
if (f === 15) {
|
|
5718
5698
|
const i = LOG_LEVELS.indexOf(sp.logLevel);
|
|
5719
5699
|
const base = i < 0 ? 0 : i;
|
|
5720
5700
|
const next = (base + action.delta + LOG_LEVELS.length) % LOG_LEVELS.length;
|
|
5721
|
-
return { ...state, settingsPicker: { ...sp, logLevel: LOG_LEVELS[next], hint: void 0 } };
|
|
5701
|
+
return { ...state, settingsPicker: { ...sp, logLevel: expectDefined5(LOG_LEVELS[next]), hint: void 0 } };
|
|
5722
5702
|
}
|
|
5723
5703
|
if (f === 16) {
|
|
5724
5704
|
const i = AUDIT_LEVELS.indexOf(sp.auditLevel);
|
|
5725
5705
|
const base = i < 0 ? 0 : i;
|
|
5726
5706
|
const next = (base + action.delta + AUDIT_LEVELS.length) % AUDIT_LEVELS.length;
|
|
5727
|
-
return { ...state, settingsPicker: { ...sp, auditLevel: AUDIT_LEVELS[next], hint: void 0 } };
|
|
5707
|
+
return { ...state, settingsPicker: { ...sp, auditLevel: expectDefined5(AUDIT_LEVELS[next]), hint: void 0 } };
|
|
5728
5708
|
}
|
|
5729
5709
|
if (f === 17) return { ...state, settingsPicker: { ...sp, indexOnStart: !sp.indexOnStart, hint: void 0 } };
|
|
5730
5710
|
{
|
|
5731
5711
|
const j = MAX_ITERATIONS_PRESETS.indexOf(sp.maxIterations);
|
|
5732
5712
|
const base = j < 0 ? 0 : j;
|
|
5733
5713
|
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 } };
|
|
5714
|
+
return { ...state, settingsPicker: { ...sp, maxIterations: expectDefined5(MAX_ITERATIONS_PRESETS[next]), hint: void 0 } };
|
|
5735
5715
|
}
|
|
5736
5716
|
}
|
|
5737
5717
|
case "settingsHint":
|
|
@@ -6379,7 +6359,12 @@ function reducer(state, action) {
|
|
|
6379
6359
|
}
|
|
6380
6360
|
}
|
|
6381
6361
|
}
|
|
6382
|
-
|
|
6362
|
+
function expectDefined6(value) {
|
|
6363
|
+
if (value === null || value === void 0) {
|
|
6364
|
+
throw new Error("Expected value to be defined");
|
|
6365
|
+
}
|
|
6366
|
+
return value;
|
|
6367
|
+
}
|
|
6383
6368
|
var INPUT_PROMPT = "\u203A ";
|
|
6384
6369
|
function selectedSlashCommandLine(picker) {
|
|
6385
6370
|
if (!picker.open || picker.matches.length === 0) return null;
|
|
@@ -6388,15 +6373,16 @@ function selectedSlashCommandLine(picker) {
|
|
|
6388
6373
|
}
|
|
6389
6374
|
function rehydrateHistory(messages, startId) {
|
|
6390
6375
|
const entries = [];
|
|
6376
|
+
let nextId = startId;
|
|
6391
6377
|
for (const msg of messages) {
|
|
6392
6378
|
if (msg.role === "system") continue;
|
|
6393
6379
|
const text = typeof msg.content === "string" ? msg.content : msg.content.filter((b) => b.type === "text").map((b) => b.text).join("");
|
|
6394
6380
|
const trimmed = text.trim();
|
|
6395
6381
|
if (!trimmed) continue;
|
|
6396
6382
|
if (msg.role === "user") {
|
|
6397
|
-
entries.push({ id:
|
|
6383
|
+
entries.push({ id: nextId++, kind: "user", text: trimmed });
|
|
6398
6384
|
} else if (msg.role === "assistant") {
|
|
6399
|
-
entries.push({ id:
|
|
6385
|
+
entries.push({ id: nextId++, kind: "assistant", text: trimmed });
|
|
6400
6386
|
}
|
|
6401
6387
|
}
|
|
6402
6388
|
return entries;
|
|
@@ -6450,7 +6436,6 @@ function App({
|
|
|
6450
6436
|
initialGoal,
|
|
6451
6437
|
initialAsk,
|
|
6452
6438
|
sessionsDir,
|
|
6453
|
-
managed = false,
|
|
6454
6439
|
modeLabel,
|
|
6455
6440
|
getModeLabel
|
|
6456
6441
|
}) {
|
|
@@ -6467,18 +6452,6 @@ function App({
|
|
|
6467
6452
|
setIndexState(getIndexState());
|
|
6468
6453
|
return onIndexStateChange((next) => setIndexState(next));
|
|
6469
6454
|
}, []);
|
|
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
6455
|
useEffect(() => {
|
|
6483
6456
|
setHiddenItems(statuslineHiddenItems);
|
|
6484
6457
|
}, [statuslineHiddenItems]);
|
|
@@ -6628,19 +6601,6 @@ function App({
|
|
|
6628
6601
|
stateRef.current = state;
|
|
6629
6602
|
const draftRef = useRef({ buffer: state.buffer, cursor: state.cursor });
|
|
6630
6603
|
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
6604
|
const handleKeyRef = useRef(null);
|
|
6645
6605
|
const handleRewindTo = React6.useCallback(
|
|
6646
6606
|
async (checkpointIndex) => {
|
|
@@ -6663,10 +6623,21 @@ function App({
|
|
|
6663
6623
|
const startedAtRef = useRef(Date.now());
|
|
6664
6624
|
const [nowTick, setNowTick] = React6.useState(Date.now());
|
|
6665
6625
|
useEffect(() => {
|
|
6666
|
-
const t = setInterval(() => setNowTick(Date.now()),
|
|
6626
|
+
const t = setInterval(() => setNowTick(Date.now()), 1e4);
|
|
6667
6627
|
return () => clearInterval(t);
|
|
6668
6628
|
}, []);
|
|
6669
|
-
const
|
|
6629
|
+
const todosRef = useRef(JSON.stringify([]));
|
|
6630
|
+
useEffect(() => {
|
|
6631
|
+
const poll = () => {
|
|
6632
|
+
const snap = JSON.stringify(agent.ctx.todos.map((t2) => ({ s: t2.status })));
|
|
6633
|
+
if (snap !== todosRef.current) {
|
|
6634
|
+
todosRef.current = snap;
|
|
6635
|
+
setNowTick(Date.now());
|
|
6636
|
+
}
|
|
6637
|
+
};
|
|
6638
|
+
const t = setInterval(poll, 2e3);
|
|
6639
|
+
return () => clearInterval(t);
|
|
6640
|
+
}, [agent.ctx.todos]);
|
|
6670
6641
|
const [gitInfo, setGitInfo] = React6.useState(null);
|
|
6671
6642
|
useEffect(() => {
|
|
6672
6643
|
let cancelled = false;
|
|
@@ -6744,7 +6715,7 @@ function App({
|
|
|
6744
6715
|
const n = m.size + 1;
|
|
6745
6716
|
const v = {
|
|
6746
6717
|
label: name && name !== id ? name : `AGENT#${n}`,
|
|
6747
|
-
color: STREAM_COLORS2[(n - 1) % STREAM_COLORS2.length]
|
|
6718
|
+
color: STREAM_COLORS2[(n - 1) % STREAM_COLORS2.length] ?? "cyan"
|
|
6748
6719
|
};
|
|
6749
6720
|
m.set(id, v);
|
|
6750
6721
|
return v;
|
|
@@ -6826,7 +6797,7 @@ function App({
|
|
|
6826
6797
|
}, [eraseLiveRegion]);
|
|
6827
6798
|
React6.useLayoutEffect(() => {
|
|
6828
6799
|
if (state.enhanceBusy || state.enhance != null) eraseLiveRegion();
|
|
6829
|
-
}, [
|
|
6800
|
+
}, [state.enhanceBusy, state.enhance, eraseLiveRegion]);
|
|
6830
6801
|
useEffect(() => {
|
|
6831
6802
|
const detected = detectAtToken(state.buffer, state.cursor);
|
|
6832
6803
|
if (!detected) {
|
|
@@ -6858,16 +6829,22 @@ function App({
|
|
|
6858
6829
|
}
|
|
6859
6830
|
const query = trimmed.slice(1).toLowerCase();
|
|
6860
6831
|
const allCommands = slashRegistry.listWithOwner();
|
|
6832
|
+
const CATEGORY_ORDER = ["Run", "Session", "Inspect", "Agent", "Config", "App"];
|
|
6861
6833
|
const matches = allCommands.filter(({ cmd }) => {
|
|
6862
6834
|
const name = cmd.name.toLowerCase();
|
|
6863
6835
|
const aliases = cmd.aliases ?? [];
|
|
6864
6836
|
return name.includes(query) || aliases.some((a) => a.toLowerCase().includes(query));
|
|
6865
|
-
}).
|
|
6837
|
+
}).map(({ cmd, owner }) => ({
|
|
6866
6838
|
name: cmd.name,
|
|
6867
6839
|
description: cmd.description,
|
|
6868
6840
|
argsHint: cmd.argsHint,
|
|
6869
|
-
isBuiltin: owner === "core"
|
|
6870
|
-
|
|
6841
|
+
isBuiltin: owner === "core",
|
|
6842
|
+
category: cmd.category ?? "App"
|
|
6843
|
+
})).sort((a, b) => {
|
|
6844
|
+
const catDiff = CATEGORY_ORDER.indexOf(a.category) - CATEGORY_ORDER.indexOf(b.category);
|
|
6845
|
+
if (catDiff !== 0) return catDiff;
|
|
6846
|
+
return a.name.localeCompare(b.name);
|
|
6847
|
+
});
|
|
6871
6848
|
if (!state.slashPicker.open) {
|
|
6872
6849
|
dispatch({ type: "slashPickerOpen", query, matches });
|
|
6873
6850
|
} else if (state.slashPicker.query !== query) {
|
|
@@ -6999,44 +6976,6 @@ function App({
|
|
|
6999
6976
|
getProcessRegistry().killAll();
|
|
7000
6977
|
};
|
|
7001
6978
|
}, []);
|
|
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
6979
|
useEffect(() => {
|
|
7041
6980
|
const cmd = {
|
|
7042
6981
|
name: "steer",
|
|
@@ -8138,26 +8077,7 @@ function App({
|
|
|
8138
8077
|
if (key.escape || input === "?" || input === "q") dispatch({ type: "toggleHelp" });
|
|
8139
8078
|
return;
|
|
8140
8079
|
}
|
|
8141
|
-
state.todosMonitorOpen || state.monitorOpen || state.agentsMonitorOpen || state.worktreeMonitorOpen || !!state.autoPhase?.monitorOpen;
|
|
8142
8080
|
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
8081
|
if (key.escape) {
|
|
8162
8082
|
const now = Date.now();
|
|
8163
8083
|
if (state.buffer.length > 0 && now - lastEscAtRef.current < ESC_DOUBLE_PRESS_MS) {
|
|
@@ -8692,19 +8612,11 @@ function App({
|
|
|
8692
8612
|
return;
|
|
8693
8613
|
}
|
|
8694
8614
|
if (key.home) {
|
|
8695
|
-
|
|
8696
|
-
dispatch({ type: "scrollToTop" });
|
|
8697
|
-
} else {
|
|
8698
|
-
setDraft(buffer, 0);
|
|
8699
|
-
}
|
|
8615
|
+
setDraft(buffer, 0);
|
|
8700
8616
|
return;
|
|
8701
8617
|
}
|
|
8702
8618
|
if (key.end) {
|
|
8703
|
-
|
|
8704
|
-
dispatch({ type: "scrollToBottom" });
|
|
8705
|
-
} else {
|
|
8706
|
-
setDraft(buffer, buffer.length);
|
|
8707
|
-
}
|
|
8619
|
+
setDraft(buffer, buffer.length);
|
|
8708
8620
|
return;
|
|
8709
8621
|
}
|
|
8710
8622
|
if (key.upArrow) {
|
|
@@ -9178,21 +9090,9 @@ User message:
|
|
|
9178
9090
|
if (state.picker.open) return "";
|
|
9179
9091
|
return "";
|
|
9180
9092
|
}, [state.buffer, state.status, state.picker.open]);
|
|
9181
|
-
const affordanceShown = managedLive && state.scrollOffset > 0 && state.pendingNewLines > 0;
|
|
9182
9093
|
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(
|
|
9094
|
+
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: /* @__PURE__ */ jsxs(Box, { flexDirection: "column", flexGrow: 1, flexShrink: 0, children: [
|
|
9095
|
+
/* @__PURE__ */ jsx(
|
|
9196
9096
|
History,
|
|
9197
9097
|
{
|
|
9198
9098
|
entries: state.entries,
|
|
@@ -9200,8 +9100,7 @@ User message:
|
|
|
9200
9100
|
toolStream: state.toolStream
|
|
9201
9101
|
}
|
|
9202
9102
|
),
|
|
9203
|
-
|
|
9204
|
-
/* @__PURE__ */ jsxs(Box, { ref: managedLive ? bottomRef : void 0, flexDirection: "column", flexShrink: 0, children: [
|
|
9103
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", flexShrink: 0, children: [
|
|
9205
9104
|
/* @__PURE__ */ jsx(LiveActivityStrip, { entries: state.fleet, nowTick }),
|
|
9206
9105
|
/* @__PURE__ */ jsx(
|
|
9207
9106
|
Input,
|
|
@@ -9277,16 +9176,22 @@ User message:
|
|
|
9277
9176
|
hint: state.settingsPicker.hint
|
|
9278
9177
|
}
|
|
9279
9178
|
) : null,
|
|
9280
|
-
state.rewindOverlay ?
|
|
9281
|
-
|
|
9282
|
-
|
|
9283
|
-
|
|
9284
|
-
|
|
9285
|
-
|
|
9286
|
-
|
|
9287
|
-
|
|
9288
|
-
|
|
9289
|
-
|
|
9179
|
+
state.rewindOverlay ? (() => {
|
|
9180
|
+
const overlay = state.rewindOverlay;
|
|
9181
|
+
return /* @__PURE__ */ jsx(
|
|
9182
|
+
CheckpointTimeline,
|
|
9183
|
+
{
|
|
9184
|
+
checkpoints: overlay.checkpoints,
|
|
9185
|
+
selected: overlay.selected,
|
|
9186
|
+
onSelect: (i) => dispatch({ type: "rewindOverlayMove", delta: i - overlay.selected }),
|
|
9187
|
+
onConfirm: (i) => {
|
|
9188
|
+
const checkpoint = overlay.checkpoints[i];
|
|
9189
|
+
if (checkpoint) handleRewindTo(checkpoint.promptIndex);
|
|
9190
|
+
},
|
|
9191
|
+
onClose: () => dispatch({ type: "rewindOverlayClose" })
|
|
9192
|
+
}
|
|
9193
|
+
);
|
|
9194
|
+
})() : null,
|
|
9290
9195
|
state.brainPrompt ? /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginY: 1, flexShrink: 0, children: /* @__PURE__ */ jsx(
|
|
9291
9196
|
BrainDecisionPrompt,
|
|
9292
9197
|
{
|
|
@@ -9298,7 +9203,7 @@ User message:
|
|
|
9298
9203
|
}
|
|
9299
9204
|
) }) : null,
|
|
9300
9205
|
state.confirmQueue.length > 0 && (() => {
|
|
9301
|
-
const head = state.confirmQueue[0];
|
|
9206
|
+
const head = expectDefined6(state.confirmQueue[0]);
|
|
9302
9207
|
let resolved = false;
|
|
9303
9208
|
const onDecision = (decision) => {
|
|
9304
9209
|
if (resolved) return;
|
|
@@ -9346,7 +9251,7 @@ User message:
|
|
|
9346
9251
|
queueCount: state.queue.length,
|
|
9347
9252
|
yolo: yoloLive,
|
|
9348
9253
|
autonomy: autonomyLive,
|
|
9349
|
-
|
|
9254
|
+
startedAt: startedAtRef.current,
|
|
9350
9255
|
todos,
|
|
9351
9256
|
plan: planCounts ?? void 0,
|
|
9352
9257
|
fleet: fleetCounts,
|
|
@@ -9363,18 +9268,7 @@ User message:
|
|
|
9363
9268
|
modeLabel: liveModeLabel || void 0
|
|
9364
9269
|
}
|
|
9365
9270
|
),
|
|
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,
|
|
9271
|
+
state.helpOpen ? /* @__PURE__ */ jsx(HelpOverlay, {}) : null,
|
|
9378
9272
|
state.agentsMonitorOpen ? /* @__PURE__ */ jsx(
|
|
9379
9273
|
AgentsMonitor,
|
|
9380
9274
|
{
|
|
@@ -9401,7 +9295,7 @@ User message:
|
|
|
9401
9295
|
nowTick,
|
|
9402
9296
|
onClose: () => dispatch({ type: "worktreeMonitorToggle" })
|
|
9403
9297
|
}
|
|
9404
|
-
) : state.todosMonitorOpen
|
|
9298
|
+
) : state.todosMonitorOpen ? /* @__PURE__ */ jsx(TodosMonitor, { todos: agent.ctx.todos }) : state.monitorOpen ? /* @__PURE__ */ jsx(
|
|
9405
9299
|
FleetMonitor,
|
|
9406
9300
|
{
|
|
9407
9301
|
entries: state.fleet,
|
|
@@ -9531,9 +9425,6 @@ function startTerminalTitle(opts) {
|
|
|
9531
9425
|
// src/run-tui.ts
|
|
9532
9426
|
var BRACKETED_PASTE_ON = "\x1B[?2004h";
|
|
9533
9427
|
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
9428
|
async function runTui(opts) {
|
|
9538
9429
|
const stdout = process.stdout;
|
|
9539
9430
|
const stdin = process.stdin;
|
|
@@ -9543,12 +9434,8 @@ async function runTui(opts) {
|
|
|
9543
9434
|
);
|
|
9544
9435
|
return 2;
|
|
9545
9436
|
}
|
|
9546
|
-
const useAltScreen = opts.altScreen === true;
|
|
9547
|
-
if (useAltScreen) {
|
|
9548
|
-
stdout.write(ALT_SCREEN_ON);
|
|
9549
|
-
stdout.write(CURSOR_HOME);
|
|
9550
|
-
}
|
|
9551
9437
|
stdout.write(BRACKETED_PASTE_ON);
|
|
9438
|
+
stdout.write("\x1B[2J\x1B[H");
|
|
9552
9439
|
const inkStdin = stdin;
|
|
9553
9440
|
const stopTitle = opts.titleAnimation !== false ? startTerminalTitle({ stdout, events: opts.events, model: opts.model }) : (() => {
|
|
9554
9441
|
});
|
|
@@ -9571,9 +9458,6 @@ async function runTui(opts) {
|
|
|
9571
9458
|
}
|
|
9572
9459
|
try {
|
|
9573
9460
|
stdout.write(BRACKETED_PASTE_OFF);
|
|
9574
|
-
if (useAltScreen) {
|
|
9575
|
-
stdout.write(ALT_SCREEN_OFF);
|
|
9576
|
-
}
|
|
9577
9461
|
} catch {
|
|
9578
9462
|
}
|
|
9579
9463
|
};
|
|
@@ -9600,12 +9484,6 @@ async function runTui(opts) {
|
|
|
9600
9484
|
const settle = (code) => {
|
|
9601
9485
|
cleanup();
|
|
9602
9486
|
detachListeners();
|
|
9603
|
-
if (useAltScreen && opts.onAfterExit) {
|
|
9604
|
-
try {
|
|
9605
|
-
opts.onAfterExit();
|
|
9606
|
-
} catch {
|
|
9607
|
-
}
|
|
9608
|
-
}
|
|
9609
9487
|
resolve(code);
|
|
9610
9488
|
};
|
|
9611
9489
|
let instance;
|
|
@@ -9641,7 +9519,7 @@ async function runTui(opts) {
|
|
|
9641
9519
|
onExit,
|
|
9642
9520
|
director: opts.director ?? null,
|
|
9643
9521
|
fleetRoster: opts.fleetRoster,
|
|
9644
|
-
onClearHistory: opts.onClearHistory ? (dispatch) => opts.onClearHistory(dispatch) : void 0,
|
|
9522
|
+
onClearHistory: opts.onClearHistory ? (dispatch) => opts.onClearHistory?.(dispatch) : void 0,
|
|
9645
9523
|
fleetStreamController: opts.fleetStreamController,
|
|
9646
9524
|
enhanceController: opts.enhanceController,
|
|
9647
9525
|
enhanceEnabled: opts.enhanceController?.enabled ?? true,
|
|
@@ -9657,9 +9535,6 @@ async function runTui(opts) {
|
|
|
9657
9535
|
getSettings: opts.getSettings,
|
|
9658
9536
|
saveSettings: opts.saveSettings,
|
|
9659
9537
|
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
9538
|
chime: opts.chime,
|
|
9664
9539
|
confirmExit: opts.confirmExit,
|
|
9665
9540
|
modeLabel: opts.modeLabel,
|
|
@@ -9676,16 +9551,14 @@ async function runTui(opts) {
|
|
|
9676
9551
|
return;
|
|
9677
9552
|
}
|
|
9678
9553
|
let detachResize = null;
|
|
9679
|
-
|
|
9680
|
-
|
|
9681
|
-
|
|
9682
|
-
|
|
9683
|
-
|
|
9684
|
-
|
|
9685
|
-
|
|
9686
|
-
|
|
9687
|
-
detachResize = () => stdout.off("resize", onResize);
|
|
9688
|
-
}
|
|
9554
|
+
const onResize = () => {
|
|
9555
|
+
try {
|
|
9556
|
+
stdout.write("\x1B[J");
|
|
9557
|
+
} catch {
|
|
9558
|
+
}
|
|
9559
|
+
};
|
|
9560
|
+
stdout.on("resize", onResize);
|
|
9561
|
+
detachResize = () => stdout.off("resize", onResize);
|
|
9689
9562
|
instance.waitUntilExit().then(() => {
|
|
9690
9563
|
detachResize?.();
|
|
9691
9564
|
settle(exitCode);
|