@wrongstack/tui 0.68.0 → 0.77.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -15
- package/dist/index.d.ts +49 -17
- package/dist/index.js +1309 -801
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { writeErr, InputBuilder, DefaultSessionRewinder, writeOut, formatTodosList, buildGoalPreamble, buildChildEnv } from '@wrongstack/core';
|
|
1
|
+
import { writeErr, InputBuilder, DefaultSessionRewinder, writeOut, formatTodosList, buildGoalPreamble, shouldEnhance, enhanceUserPrompt, recentTextTurns, normalizedEqual, buildChildEnv } from '@wrongstack/core';
|
|
3
2
|
export { buildGoalPreamble } from '@wrongstack/core';
|
|
4
3
|
import { Box, Text, render, useApp, useStdout, measureElement, Static, useInput, useStdin } from 'ink';
|
|
5
4
|
import React6, { useState, useEffect, useReducer, useRef, useMemo, useCallback, useLayoutEffect } from 'react';
|
|
6
5
|
import * as fs2 from 'fs/promises';
|
|
7
6
|
import * as path2 from 'path';
|
|
8
7
|
import { routeImagesForModel } from '@wrongstack/runtime/vision';
|
|
9
|
-
import { getProcessRegistry } from '@wrongstack/tools';
|
|
8
|
+
import { getIndexState, onIndexStateChange, getProcessRegistry } from '@wrongstack/tools';
|
|
10
9
|
import { readClipboardImage } from '@wrongstack/runtime/clipboard';
|
|
11
10
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
12
11
|
import { spawn } from 'child_process';
|
|
@@ -35,8 +34,28 @@ var theme = Object.freeze({
|
|
|
35
34
|
diffAddBg: "greenBright",
|
|
36
35
|
diffDelBg: "redBright"
|
|
37
36
|
});
|
|
37
|
+
var MODE_ICONS = {
|
|
38
|
+
teach: "\u{1F9D1}\u200D\u{1F3EB}",
|
|
39
|
+
brief: "\u26A1",
|
|
40
|
+
"code-reviewer": "\u{1F50D}",
|
|
41
|
+
"bug-hunter": "\u{1F41B}",
|
|
42
|
+
"security-scanner": "\u{1F6E1}\uFE0F",
|
|
43
|
+
"refactor-planner": "\u{1F527}",
|
|
44
|
+
architect: "\u{1F3D7}\uFE0F",
|
|
45
|
+
debugger: "\u{1FAB2}",
|
|
46
|
+
test: "\u{1F9EA}",
|
|
47
|
+
document: "\u{1F4DD}",
|
|
48
|
+
"skill-creator": "\u{1F6E0}\uFE0F"
|
|
49
|
+
};
|
|
50
|
+
function modeIcon(label) {
|
|
51
|
+
if (!label) return "";
|
|
52
|
+
const icon = MODE_ICONS[label] ?? "\u25AA";
|
|
53
|
+
return `${icon} ${label}`;
|
|
54
|
+
}
|
|
38
55
|
var COMPACT_THRESHOLD = 50;
|
|
39
56
|
var COMFORTABLE_THRESHOLD = 90;
|
|
57
|
+
var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
58
|
+
var SPINNER_INTERVAL_MS = 130;
|
|
40
59
|
function StatusBar({
|
|
41
60
|
model,
|
|
42
61
|
version,
|
|
@@ -59,7 +78,9 @@ function StatusBar({
|
|
|
59
78
|
processCount,
|
|
60
79
|
hiddenItems,
|
|
61
80
|
eternalStage,
|
|
62
|
-
goalSummary
|
|
81
|
+
goalSummary,
|
|
82
|
+
indexState,
|
|
83
|
+
modeLabel
|
|
63
84
|
}) {
|
|
64
85
|
const { stdout } = useStdout();
|
|
65
86
|
const [termWidth, setTermWidth] = useState(stdout?.columns ?? 90);
|
|
@@ -77,8 +98,19 @@ function StatusBar({
|
|
|
77
98
|
const usage = tokenCounter?.total();
|
|
78
99
|
const cost = tokenCounter?.estimateCost();
|
|
79
100
|
const cache2 = tokenCounter?.cacheStats();
|
|
101
|
+
const [spinnerIdx, setSpinnerIdx] = useState(0);
|
|
102
|
+
useEffect(() => {
|
|
103
|
+
if (state === "idle" || state === "aborting") return;
|
|
104
|
+
const t = setInterval(
|
|
105
|
+
() => setSpinnerIdx((n) => (n + 1) % SPINNER_FRAMES.length),
|
|
106
|
+
SPINNER_INTERVAL_MS
|
|
107
|
+
);
|
|
108
|
+
return () => clearInterval(t);
|
|
109
|
+
}, [state]);
|
|
110
|
+
const spinner = SPINNER_FRAMES[spinnerIdx];
|
|
80
111
|
const { label: stateLabel, color: stateColor } = stateChip(state, fleet?.running ?? 0);
|
|
81
|
-
const
|
|
112
|
+
const statePrefix = state === "idle" || state === "aborting" ? "\u25CF" : spinner;
|
|
113
|
+
const hasSecondLine = yolo || autonomy && autonomy !== "off" || elapsedMs !== void 0 || git !== null && git !== void 0 || projectName !== void 0 && projectName.length > 0 || goalSummary !== null && goalSummary !== void 0 || !!modeLabel;
|
|
82
114
|
const fleetHasActivity = fleet && (fleet.running > 0 || fleet.idle > 0 || fleet.pending > 0 || fleet.completed > 0) || subagentCount > 0;
|
|
83
115
|
const hasBrainActivity = !!brain && brain.state !== "idle";
|
|
84
116
|
const hasThirdLine = todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0) || plan && (plan.open > 0 || plan.inProgress > 0 || plan.done > 0) || fleetHasActivity || hasBrainActivity;
|
|
@@ -97,7 +129,7 @@ function StatusBar({
|
|
|
97
129
|
// Ultra-compact: state · model
|
|
98
130
|
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
99
131
|
/* @__PURE__ */ jsxs(Text, { color: stateColor, children: [
|
|
100
|
-
|
|
132
|
+
statePrefix,
|
|
101
133
|
stateLabel
|
|
102
134
|
] }),
|
|
103
135
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7" }),
|
|
@@ -117,7 +149,8 @@ function StatusBar({
|
|
|
117
149
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" })
|
|
118
150
|
] }) : null,
|
|
119
151
|
/* @__PURE__ */ jsxs(Text, { color: stateColor, children: [
|
|
120
|
-
|
|
152
|
+
statePrefix,
|
|
153
|
+
" ",
|
|
121
154
|
stateLabel
|
|
122
155
|
] }),
|
|
123
156
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
|
|
@@ -171,6 +204,15 @@ function StatusBar({
|
|
|
171
204
|
hint ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
172
205
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
|
|
173
206
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: hint })
|
|
207
|
+
] }) : null,
|
|
208
|
+
indexState && indexState.indexing ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
209
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
|
|
210
|
+
/* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
|
|
211
|
+
"\u2699 indexing ",
|
|
212
|
+
indexState.currentFile,
|
|
213
|
+
"/",
|
|
214
|
+
indexState.totalFiles
|
|
215
|
+
] })
|
|
174
216
|
] }) : null
|
|
175
217
|
] })
|
|
176
218
|
) }),
|
|
@@ -228,6 +270,10 @@ function StatusBar({
|
|
|
228
270
|
}
|
|
229
271
|
)
|
|
230
272
|
] }) : null,
|
|
273
|
+
modeLabel ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
274
|
+
yolo || autonomy && autonomy !== "off" || eternalStage || elapsedMs !== void 0 || projectName || goalSummary ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
|
|
275
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", children: modeIcon(modeLabel) })
|
|
276
|
+
] }) : null,
|
|
231
277
|
git ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
232
278
|
yolo || elapsedMs !== void 0 || projectName ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
|
|
233
279
|
/* @__PURE__ */ jsxs(Text, { children: [
|
|
@@ -249,7 +295,7 @@ function StatusBar({
|
|
|
249
295
|
] }) : null
|
|
250
296
|
] })
|
|
251
297
|
] }) : null
|
|
252
|
-
] }) :
|
|
298
|
+
] }) : /* @__PURE__ */ jsx(Box, { height: 1, children: /* @__PURE__ */ jsx(Text, { children: " " }) }),
|
|
253
299
|
hasThirdLine ? /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 2, children: [
|
|
254
300
|
todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0) ? /* @__PURE__ */ jsxs(Text, { children: [
|
|
255
301
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "todos " }),
|
|
@@ -323,7 +369,7 @@ function StatusBar({
|
|
|
323
369
|
todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0) || plan && (plan.open > 0 || plan.inProgress > 0 || plan.done > 0) || fleetHasActivity ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
|
|
324
370
|
/* @__PURE__ */ jsx(BrainChip, { brain })
|
|
325
371
|
] }) : null
|
|
326
|
-
] }) :
|
|
372
|
+
] }) : /* @__PURE__ */ jsx(Box, { height: 1, children: /* @__PURE__ */ jsx(Text, { children: " " }) }),
|
|
327
373
|
fleetAgents && fleetAgents.length > 0 ? /* @__PURE__ */ jsx(Box, { flexDirection: "row", gap: 2, children: fleetAgents.map((a, i) => (
|
|
328
374
|
// biome-ignore lint/suspicious/noArrayIndexKey: agent list is stable per render
|
|
329
375
|
/* @__PURE__ */ jsxs(Text, { children: [
|
|
@@ -349,7 +395,7 @@ function StatusBar({
|
|
|
349
395
|
] })
|
|
350
396
|
] }) : null
|
|
351
397
|
] }, i)
|
|
352
|
-
)) }) :
|
|
398
|
+
)) }) : /* @__PURE__ */ jsx(Box, { height: 1, children: /* @__PURE__ */ jsx(Text, { children: " " }) })
|
|
353
399
|
]
|
|
354
400
|
}
|
|
355
401
|
);
|
|
@@ -450,28 +496,6 @@ function ContextChip({ ctx }) {
|
|
|
450
496
|
] })
|
|
451
497
|
] });
|
|
452
498
|
}
|
|
453
|
-
var SB_GAP = 2;
|
|
454
|
-
var SB_PADX = 1;
|
|
455
|
-
function statusBarModelSpan(opts) {
|
|
456
|
-
let col = SB_PADX;
|
|
457
|
-
if (opts.version) {
|
|
458
|
-
col += `WS v${opts.version}`.length + SB_GAP;
|
|
459
|
-
col += 1 + SB_GAP;
|
|
460
|
-
}
|
|
461
|
-
const { label } = stateChip(opts.state, opts.fleetRunning ?? 0);
|
|
462
|
-
col += 2 + label.length + SB_GAP;
|
|
463
|
-
col += 1 + SB_GAP;
|
|
464
|
-
return { start: col, len: opts.model.length };
|
|
465
|
-
}
|
|
466
|
-
function statusBarAutonomySpan(opts) {
|
|
467
|
-
if (!opts.autonomy || opts.autonomy === "off") return null;
|
|
468
|
-
let col = SB_PADX;
|
|
469
|
-
if (opts.yolo) {
|
|
470
|
-
col += "\u26A0 YOLO".length + SB_GAP;
|
|
471
|
-
col += 1 + SB_GAP;
|
|
472
|
-
}
|
|
473
|
-
return { start: col, len: 2 + opts.autonomy.toUpperCase().length };
|
|
474
|
-
}
|
|
475
499
|
function stateChip(state, fleetRunning) {
|
|
476
500
|
if (state === "idle" && fleetRunning > 0) {
|
|
477
501
|
return { label: `agents \u25B6${fleetRunning}`, color: "magenta" };
|
|
@@ -802,10 +826,12 @@ function ContextBar({
|
|
|
802
826
|
function AgentsMonitor({
|
|
803
827
|
entries,
|
|
804
828
|
totalCost,
|
|
829
|
+
leaderCost = 0,
|
|
805
830
|
totalTokens,
|
|
806
831
|
nowTick
|
|
807
832
|
}) {
|
|
808
833
|
const all = Object.values(entries);
|
|
834
|
+
const grandCost = leaderCost + totalCost;
|
|
809
835
|
const live = selectLiveAgents(all, nowTick);
|
|
810
836
|
const running = live.filter((e) => e.status === "running").length;
|
|
811
837
|
const totalDone = all.filter((e) => e.status === "success").length;
|
|
@@ -847,9 +873,17 @@ function AgentsMonitor({
|
|
|
847
873
|
fmtTokens2(totalTokens.output),
|
|
848
874
|
"\u2193"
|
|
849
875
|
] }) : null,
|
|
850
|
-
/* @__PURE__ */
|
|
876
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "total" }),
|
|
877
|
+
/* @__PURE__ */ jsxs(Text, { color: "green", bold: true, children: [
|
|
851
878
|
"$",
|
|
852
|
-
|
|
879
|
+
grandCost.toFixed(3)
|
|
880
|
+
] }),
|
|
881
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
882
|
+
"(leader $",
|
|
883
|
+
leaderCost.toFixed(3),
|
|
884
|
+
" \xB7 fleet $",
|
|
885
|
+
totalCost.toFixed(3),
|
|
886
|
+
")"
|
|
853
887
|
] }),
|
|
854
888
|
hiddenIdle > 0 ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
855
889
|
"\xB7 ",
|
|
@@ -892,6 +926,10 @@ function AgentsMonitor({
|
|
|
892
926
|
e.extensions && e.extensions > 0 ? /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
|
|
893
927
|
"\u26A1\xD7",
|
|
894
928
|
e.extensions
|
|
929
|
+
] }) : null,
|
|
930
|
+
e.cost > 0 ? /* @__PURE__ */ jsxs(Text, { color: "green", children: [
|
|
931
|
+
"$",
|
|
932
|
+
e.cost.toFixed(3)
|
|
895
933
|
] }) : null
|
|
896
934
|
] }),
|
|
897
935
|
e.status === "running" && e.currentTool ? /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, paddingLeft: 2, children: [
|
|
@@ -977,7 +1015,7 @@ function AutonomyPicker({
|
|
|
977
1015
|
selected,
|
|
978
1016
|
hint
|
|
979
1017
|
}) {
|
|
980
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 1, children: [
|
|
1018
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "magenta", paddingX: 1, children: [
|
|
981
1019
|
/* @__PURE__ */ jsx(Text, { color: "cyan", bold: true, children: "\u2501\u2501 Autonomy Mode \u2501\u2501" }),
|
|
982
1020
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 navigate \xB7 Enter select \xB7 Esc cancel \xB7 Ctrl+C exit" }),
|
|
983
1021
|
options.map((opt, i) => /* @__PURE__ */ jsxs(
|
|
@@ -1100,7 +1138,7 @@ function CheckpointTimeline({
|
|
|
1100
1138
|
onConfirm(selected);
|
|
1101
1139
|
}
|
|
1102
1140
|
});
|
|
1103
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", padding: 1, children: [
|
|
1141
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", padding: 1, children: [
|
|
1104
1142
|
/* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
|
|
1105
1143
|
/* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "\u27F2 Session Rewind" }),
|
|
1106
1144
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " \u2014 \u2191/\u2193 navigate \xB7 Enter rewind \xB7 Esc cancel" })
|
|
@@ -1140,16 +1178,6 @@ function buttonLabels(suggestedPattern) {
|
|
|
1140
1178
|
{ decision: "deny", bracket: "[d]", rest: "eny" }
|
|
1141
1179
|
];
|
|
1142
1180
|
}
|
|
1143
|
-
function confirmButtonSegments(suggestedPattern) {
|
|
1144
|
-
const out = [];
|
|
1145
|
-
let col = 0;
|
|
1146
|
-
for (const l of buttonLabels(suggestedPattern)) {
|
|
1147
|
-
const len = l.bracket.length + l.rest.length;
|
|
1148
|
-
out.push({ decision: l.decision, start: col, len });
|
|
1149
|
-
col += len;
|
|
1150
|
-
}
|
|
1151
|
-
return out;
|
|
1152
|
-
}
|
|
1153
1181
|
function stringifyInput(input) {
|
|
1154
1182
|
if (!input || typeof input !== "object") return "";
|
|
1155
1183
|
const obj = input;
|
|
@@ -1215,15 +1243,76 @@ function ConfirmPrompt({
|
|
|
1215
1243
|
] }, l.decision)) }) })
|
|
1216
1244
|
] });
|
|
1217
1245
|
}
|
|
1246
|
+
function EnhancePanel({
|
|
1247
|
+
original,
|
|
1248
|
+
refined,
|
|
1249
|
+
delayMs,
|
|
1250
|
+
onDecision
|
|
1251
|
+
}) {
|
|
1252
|
+
const totalSecs = Math.max(1, Math.ceil(delayMs / 1e3));
|
|
1253
|
+
const [remaining, setRemaining] = React6.useState(totalSecs);
|
|
1254
|
+
const decideRef = React6.useRef(onDecision);
|
|
1255
|
+
decideRef.current = onDecision;
|
|
1256
|
+
React6.useEffect(() => {
|
|
1257
|
+
const id = setInterval(() => {
|
|
1258
|
+
setRemaining((r) => {
|
|
1259
|
+
if (r <= 1) {
|
|
1260
|
+
clearInterval(id);
|
|
1261
|
+
decideRef.current("refined");
|
|
1262
|
+
return 0;
|
|
1263
|
+
}
|
|
1264
|
+
return r - 1;
|
|
1265
|
+
});
|
|
1266
|
+
}, 1e3);
|
|
1267
|
+
return () => clearInterval(id);
|
|
1268
|
+
}, []);
|
|
1269
|
+
useInput((input, key) => {
|
|
1270
|
+
if (key.return) {
|
|
1271
|
+
onDecision("refined");
|
|
1272
|
+
} else if (key.escape) {
|
|
1273
|
+
onDecision("original");
|
|
1274
|
+
} else if (input?.toLowerCase() === "e") {
|
|
1275
|
+
onDecision("edit");
|
|
1276
|
+
}
|
|
1277
|
+
});
|
|
1278
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [
|
|
1279
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", children: [
|
|
1280
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "\u2728 Refined request" }),
|
|
1281
|
+
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
1282
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
1283
|
+
"\u2014 sending in ",
|
|
1284
|
+
remaining,
|
|
1285
|
+
"s"
|
|
1286
|
+
] })
|
|
1287
|
+
] }),
|
|
1288
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", children: [
|
|
1289
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "original: " }),
|
|
1290
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: original })
|
|
1291
|
+
] }),
|
|
1292
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", children: [
|
|
1293
|
+
/* @__PURE__ */ jsx(Text, { color: "green", children: "refined: " }),
|
|
1294
|
+
/* @__PURE__ */ jsx(Text, { color: "white", children: refined })
|
|
1295
|
+
] }),
|
|
1296
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }),
|
|
1297
|
+
/* @__PURE__ */ jsx(Box, { flexDirection: "row", children: /* @__PURE__ */ jsxs(Text, { children: [
|
|
1298
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "green", children: "[Enter]" }),
|
|
1299
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " send \xB7 " }),
|
|
1300
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "yellow", children: "[Esc]" }),
|
|
1301
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " use original \xB7 " }),
|
|
1302
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "[e]" }),
|
|
1303
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "dit" })
|
|
1304
|
+
] }) })
|
|
1305
|
+
] });
|
|
1306
|
+
}
|
|
1218
1307
|
function FilePicker({ query, matches, selected }) {
|
|
1219
1308
|
if (matches.length === 0) {
|
|
1220
|
-
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", paddingX: 1, children: /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
1309
|
+
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
1221
1310
|
"@",
|
|
1222
1311
|
query,
|
|
1223
1312
|
" \u2014 no matches"
|
|
1224
1313
|
] }) });
|
|
1225
1314
|
}
|
|
1226
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 1, children: [
|
|
1315
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [
|
|
1227
1316
|
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
1228
1317
|
"@",
|
|
1229
1318
|
query || "\u2026",
|
|
@@ -1306,13 +1395,6 @@ function FleetPanel({
|
|
|
1306
1395
|
function helpSections(opts) {
|
|
1307
1396
|
const nav = [];
|
|
1308
1397
|
if (opts.managed) nav.push({ keys: "PgUp/PgDn", desc: "scroll chat history" });
|
|
1309
|
-
if (opts.mouse)
|
|
1310
|
-
nav.push(
|
|
1311
|
-
{ keys: "wheel", desc: "scroll chat history" },
|
|
1312
|
-
{ keys: "drag scrollbar", desc: "scrub to any position" },
|
|
1313
|
-
{ keys: "click input", desc: "move the caret" },
|
|
1314
|
-
{ keys: "click", desc: "select / confirm" }
|
|
1315
|
-
);
|
|
1316
1398
|
nav.push(
|
|
1317
1399
|
{ keys: "\u2191/\u2193", desc: "previous / next input (empty prompt)" },
|
|
1318
1400
|
{ keys: "?", desc: "open this help (empty prompt)" }
|
|
@@ -1325,6 +1407,9 @@ function helpSections(opts) {
|
|
|
1325
1407
|
{ keys: "Ctrl+F / F2", desc: "fleet orchestration monitor" },
|
|
1326
1408
|
{ keys: "Ctrl+G / F3", desc: "agents live monitor" },
|
|
1327
1409
|
{ keys: "Ctrl+T / F4", desc: "worktree monitor" },
|
|
1410
|
+
{ keys: "F5", desc: "autonomy settings (also Ctrl+S)" },
|
|
1411
|
+
{ keys: "F6", desc: "todos monitor overlay" },
|
|
1412
|
+
{ keys: "F7", desc: "queue panel" },
|
|
1328
1413
|
{ keys: "Esc", desc: "close the open monitor / overlay" }
|
|
1329
1414
|
]
|
|
1330
1415
|
},
|
|
@@ -1353,10 +1438,9 @@ function helpSections(opts) {
|
|
|
1353
1438
|
];
|
|
1354
1439
|
}
|
|
1355
1440
|
function HelpOverlay({
|
|
1356
|
-
managed
|
|
1357
|
-
mouse
|
|
1441
|
+
managed
|
|
1358
1442
|
}) {
|
|
1359
|
-
const sections = helpSections({ managed
|
|
1443
|
+
const sections = helpSections({ managed });
|
|
1360
1444
|
const keyWidth = Math.max(...sections.flatMap((s2) => s2.entries.map((e) => e.keys.length)), 0);
|
|
1361
1445
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
|
|
1362
1446
|
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
@@ -1901,8 +1985,9 @@ function computeWidths(allRows, cols, maxWidth, sepWidths) {
|
|
|
1901
1985
|
for (const row of allRows) {
|
|
1902
1986
|
for (let c = 0; c < cols; c++) {
|
|
1903
1987
|
const cell = row[c] ?? "";
|
|
1904
|
-
const
|
|
1905
|
-
const
|
|
1988
|
+
const stripped = stripInlineMarkers(cell);
|
|
1989
|
+
const w = longestWord(stripped);
|
|
1990
|
+
const total = strWidth(stripped);
|
|
1906
1991
|
natural[c] = Math.max(natural[c], w, total);
|
|
1907
1992
|
}
|
|
1908
1993
|
}
|
|
@@ -1935,11 +2020,77 @@ function computeWidths(allRows, cols, maxWidth, sepWidths) {
|
|
|
1935
2020
|
return widths;
|
|
1936
2021
|
}
|
|
1937
2022
|
var MIN_COL_WIDTH = 4;
|
|
2023
|
+
var LIGATURE_PAIRS = [
|
|
2024
|
+
["-", ">"],
|
|
2025
|
+
// → arrow
|
|
2026
|
+
["<", "-"],
|
|
2027
|
+
// ←
|
|
2028
|
+
["=", ">"],
|
|
2029
|
+
// ⇒
|
|
2030
|
+
["<", "="],
|
|
2031
|
+
// ≤
|
|
2032
|
+
[">", "="],
|
|
2033
|
+
// ≥
|
|
2034
|
+
["!", "="],
|
|
2035
|
+
// ≠
|
|
2036
|
+
["=", "="],
|
|
2037
|
+
// equality (some fonts)
|
|
2038
|
+
["~", ">"],
|
|
2039
|
+
// ⇝
|
|
2040
|
+
["<", "~"]
|
|
2041
|
+
// ⇜
|
|
2042
|
+
];
|
|
2043
|
+
var ZWSP = "\u200B";
|
|
2044
|
+
function breakLigatures(text) {
|
|
2045
|
+
if (!/[-<=>!~]/.test(text)) return text;
|
|
2046
|
+
let result = "";
|
|
2047
|
+
for (let i = 0; i < text.length; i++) {
|
|
2048
|
+
result += text[i];
|
|
2049
|
+
if (i + 1 >= text.length) break;
|
|
2050
|
+
for (const [a, b] of LIGATURE_PAIRS) {
|
|
2051
|
+
if (text[i] === a && text[i + 1] === b) {
|
|
2052
|
+
result += ZWSP;
|
|
2053
|
+
break;
|
|
2054
|
+
}
|
|
2055
|
+
}
|
|
2056
|
+
}
|
|
2057
|
+
return result;
|
|
2058
|
+
}
|
|
1938
2059
|
function strWidth(s2) {
|
|
1939
2060
|
let width = 0;
|
|
1940
|
-
|
|
1941
|
-
|
|
2061
|
+
const len = s2.length;
|
|
2062
|
+
let i = 0;
|
|
2063
|
+
while (i < len) {
|
|
2064
|
+
if (s2[i] === "\x1B" && i + 1 < len && s2[i + 1] === "[") {
|
|
2065
|
+
i += 2;
|
|
2066
|
+
while (i < len && s2[i] !== "m") i++;
|
|
2067
|
+
if (i < len) i++;
|
|
2068
|
+
continue;
|
|
2069
|
+
}
|
|
2070
|
+
const code = s2.codePointAt(i);
|
|
2071
|
+
const cpLen = code > 65535 ? 2 : 1;
|
|
2072
|
+
if (code === 8205 || // ZWJ — Zero Width Joiner (emoji sequences)
|
|
2073
|
+
code === 8203 || // ZWSP — Zero Width Space
|
|
2074
|
+
code === 8204 || // ZWNJ — Zero Width Non-Joiner
|
|
2075
|
+
code === 8206 || // LRM — Left-to-Right Mark
|
|
2076
|
+
code === 8207 || // RLM — Right-to-Left Mark
|
|
2077
|
+
code === 8288 || // WJ — Word Joiner
|
|
2078
|
+
code === 65279 || // BOM / ZWNBSP
|
|
2079
|
+
code >= 65024 && code <= 65039 || // Variation Selectors 1–16
|
|
2080
|
+
code >= 917760 && code <= 917999) {
|
|
2081
|
+
i += cpLen;
|
|
2082
|
+
continue;
|
|
2083
|
+
}
|
|
1942
2084
|
if (code < 32 || code >= 127 && code < 160) {
|
|
2085
|
+
i += cpLen;
|
|
2086
|
+
continue;
|
|
2087
|
+
}
|
|
2088
|
+
if (code >= 768 && code <= 879 || // Combining Diacritical Marks
|
|
2089
|
+
code >= 6832 && code <= 6911 || // Combining Diacritical Marks Extended
|
|
2090
|
+
code >= 7616 && code <= 7679 || // Combining Diacritical Marks Supplement
|
|
2091
|
+
code >= 8400 && code <= 8447 || // Combining Diacritical Marks for Symbols
|
|
2092
|
+
code >= 65056 && code <= 65071) {
|
|
2093
|
+
i += cpLen;
|
|
1943
2094
|
continue;
|
|
1944
2095
|
}
|
|
1945
2096
|
if (code >= 126976 || // Supplementary Pictographs (U+1F000-U+1FFFF)
|
|
@@ -1952,11 +2103,11 @@ function strWidth(s2) {
|
|
|
1952
2103
|
code >= 9664 && code <= 9726 || // More Geometric Shapes (includes ▶)
|
|
1953
2104
|
code >= 9984 && code <= 10175) {
|
|
1954
2105
|
width += 2;
|
|
2106
|
+
i += cpLen;
|
|
1955
2107
|
continue;
|
|
1956
2108
|
}
|
|
1957
2109
|
if (code >= 4352 && code <= 4447 || // Hangul Jamo
|
|
1958
|
-
code === 9001 || //
|
|
1959
|
-
code === 9002 || // RIGHT-POINTING ANGLE BRACKET
|
|
2110
|
+
code === 9001 || code === 9002 || // Angle brackets
|
|
1960
2111
|
code >= 11904 && code <= 12350 || // CJK Radicals Supplement
|
|
1961
2112
|
code >= 12352 && code <= 42191 || // Hiragana, Katakana, CJK
|
|
1962
2113
|
code >= 44032 && code <= 55203 || // Hangul Syllables
|
|
@@ -1968,9 +2119,11 @@ function strWidth(s2) {
|
|
|
1968
2119
|
code >= 131072 && code <= 196605 || // CJK Extension B+
|
|
1969
2120
|
code >= 196608 && code <= 262141) {
|
|
1970
2121
|
width += 2;
|
|
2122
|
+
i += cpLen;
|
|
1971
2123
|
continue;
|
|
1972
2124
|
}
|
|
1973
2125
|
width += 1;
|
|
2126
|
+
i += cpLen;
|
|
1974
2127
|
}
|
|
1975
2128
|
return width;
|
|
1976
2129
|
}
|
|
@@ -1985,8 +2138,22 @@ function longestWord(s2) {
|
|
|
1985
2138
|
function border(left, mid, right, widths) {
|
|
1986
2139
|
return left + widths.map((w) => "\u2500".repeat(w + 2)).join(mid) + right;
|
|
1987
2140
|
}
|
|
2141
|
+
function stripInlineMarkers(text) {
|
|
2142
|
+
return text.replace(/\*\*(.+?)\*\*/g, "$1").replace(/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g, "$1").replace(/`(.+?)`/g, "$1").replace(/~~(.+?)~~/g, "$1");
|
|
2143
|
+
}
|
|
2144
|
+
var ANSI_BOLD = "\x1B[1m";
|
|
2145
|
+
var ANSI_RESET = "\x1B[22m";
|
|
2146
|
+
var ANSI_DIM = "\x1B[2m";
|
|
2147
|
+
var ANSI_CYAN = "\x1B[36m";
|
|
2148
|
+
var ANSI_STRIKE = "\x1B[9m";
|
|
2149
|
+
var ANSI_RESET_ALL = "\x1B[0m";
|
|
2150
|
+
function applyInlineAnsi(text) {
|
|
2151
|
+
return text.replace(/\*\*(.+?)\*\*/g, `${ANSI_BOLD}$1${ANSI_RESET}`).replace(/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g, `${ANSI_DIM}$1${ANSI_RESET_ALL}`).replace(/`(.+?)`/g, `${ANSI_CYAN}$1${ANSI_RESET_ALL}`).replace(/~~(.+?)~~/g, `${ANSI_STRIKE}$1${ANSI_RESET_ALL}`);
|
|
2152
|
+
}
|
|
1988
2153
|
function renderRow(cells, widths, aligns) {
|
|
1989
|
-
const
|
|
2154
|
+
const styled = cells.map((c) => applyInlineAnsi(c));
|
|
2155
|
+
const safe = styled.map((c) => breakLigatures(c));
|
|
2156
|
+
const wrapped = safe.map((c, i) => wrapCell(c, widths[i] ?? MIN_COL_WIDTH));
|
|
1990
2157
|
const height = Math.max(1, ...wrapped.map((w) => w.length));
|
|
1991
2158
|
const out = [];
|
|
1992
2159
|
for (let line = 0; line < height; line++) {
|
|
@@ -3435,52 +3602,6 @@ function layoutInputRows(prompt, value, cursor, width) {
|
|
|
3435
3602
|
if (row.length > 0 || rows.length === 0) rows.push(row);
|
|
3436
3603
|
return rows;
|
|
3437
3604
|
}
|
|
3438
|
-
function inputIndexAtRowCol(prompt, value, width, row, col) {
|
|
3439
|
-
const w = Math.max(1, Math.floor(width));
|
|
3440
|
-
const flat = [];
|
|
3441
|
-
for (let i = 0; i < prompt.length; i++) flat.push({ ch: prompt[i], buf: -1 });
|
|
3442
|
-
for (let i = 0; i < value.length; i++) flat.push({ ch: value[i], buf: i });
|
|
3443
|
-
const rows = [];
|
|
3444
|
-
const starts = [];
|
|
3445
|
-
let cur = [];
|
|
3446
|
-
let curStart = 0;
|
|
3447
|
-
for (const cell of flat) {
|
|
3448
|
-
if (cell.ch === "\n") {
|
|
3449
|
-
rows.push(cur);
|
|
3450
|
-
starts.push(curStart);
|
|
3451
|
-
cur = [];
|
|
3452
|
-
curStart = cell.buf + 1;
|
|
3453
|
-
continue;
|
|
3454
|
-
}
|
|
3455
|
-
if (cur.length === 0 && cell.buf >= 0) curStart = cell.buf;
|
|
3456
|
-
cur.push({ buf: cell.buf });
|
|
3457
|
-
if (cur.length >= w) {
|
|
3458
|
-
rows.push(cur);
|
|
3459
|
-
starts.push(curStart);
|
|
3460
|
-
cur = [];
|
|
3461
|
-
curStart = -1;
|
|
3462
|
-
}
|
|
3463
|
-
}
|
|
3464
|
-
if (cur.length > 0 || rows.length === 0) {
|
|
3465
|
-
rows.push(cur);
|
|
3466
|
-
starts.push(curStart);
|
|
3467
|
-
}
|
|
3468
|
-
const clamp = (n) => Math.max(0, Math.min(value.length, n));
|
|
3469
|
-
if (row < 0) return 0;
|
|
3470
|
-
if (row >= rows.length) return value.length;
|
|
3471
|
-
const r = rows[row];
|
|
3472
|
-
const c = Math.max(0, col);
|
|
3473
|
-
if (c < r.length) {
|
|
3474
|
-
const b = r[c].buf;
|
|
3475
|
-
return b < 0 ? 0 : clamp(b);
|
|
3476
|
-
}
|
|
3477
|
-
for (let k = r.length - 1; k >= 0; k--) {
|
|
3478
|
-
const b = r[k].buf;
|
|
3479
|
-
if (b >= 0) return clamp(b + 1);
|
|
3480
|
-
}
|
|
3481
|
-
const start = starts[row];
|
|
3482
|
-
return clamp(start !== void 0 && start >= 0 ? start : value.length);
|
|
3483
|
-
}
|
|
3484
3605
|
function renderRow2(cells, rowKey, promptColor) {
|
|
3485
3606
|
const out = [];
|
|
3486
3607
|
let run = "";
|
|
@@ -3529,6 +3650,11 @@ function isHomeEnd(data) {
|
|
|
3529
3650
|
return "end";
|
|
3530
3651
|
return null;
|
|
3531
3652
|
}
|
|
3653
|
+
function isBackspaceOrDelete(data) {
|
|
3654
|
+
if (data === "\x7F" || data === "\b") return "backspace";
|
|
3655
|
+
if (data === "\x1B[3~") return "delete";
|
|
3656
|
+
return null;
|
|
3657
|
+
}
|
|
3532
3658
|
var EMPTY_KEY = {
|
|
3533
3659
|
upArrow: false,
|
|
3534
3660
|
downArrow: false,
|
|
@@ -3564,15 +3690,24 @@ function Input({
|
|
|
3564
3690
|
if (!stdin || disabled) return;
|
|
3565
3691
|
const handleData = (data) => {
|
|
3566
3692
|
const s2 = data.toString();
|
|
3567
|
-
const
|
|
3568
|
-
if (
|
|
3693
|
+
const homeEnd = isHomeEnd(s2);
|
|
3694
|
+
if (homeEnd === "home") {
|
|
3569
3695
|
onKey("", { ...EMPTY_KEY, home: true });
|
|
3570
3696
|
return;
|
|
3571
3697
|
}
|
|
3572
|
-
if (
|
|
3698
|
+
if (homeEnd === "end") {
|
|
3573
3699
|
onKey("", { ...EMPTY_KEY, end: true });
|
|
3574
3700
|
return;
|
|
3575
3701
|
}
|
|
3702
|
+
const bsdel = isBackspaceOrDelete(s2);
|
|
3703
|
+
if (bsdel === "backspace") {
|
|
3704
|
+
onKey("", { ...EMPTY_KEY, backspace: true });
|
|
3705
|
+
return;
|
|
3706
|
+
}
|
|
3707
|
+
if (bsdel === "delete") {
|
|
3708
|
+
onKey("", { ...EMPTY_KEY, delete: true });
|
|
3709
|
+
return;
|
|
3710
|
+
}
|
|
3576
3711
|
const fn = fnKey(s2);
|
|
3577
3712
|
if (fn !== null) onKey("", { ...EMPTY_KEY, fn });
|
|
3578
3713
|
};
|
|
@@ -3620,8 +3755,7 @@ function hintsFor(ctx) {
|
|
|
3620
3755
|
return [
|
|
3621
3756
|
{ key: "\u2191\u2193", label: "move" },
|
|
3622
3757
|
{ key: "\u21B5", label: "select" },
|
|
3623
|
-
{ key: "Esc", label: "cancel" }
|
|
3624
|
-
...ctx.mouse ? [{ key: "click", label: "pick" }] : []
|
|
3758
|
+
{ key: "Esc", label: "cancel" }
|
|
3625
3759
|
];
|
|
3626
3760
|
}
|
|
3627
3761
|
if (ctx.monitor) {
|
|
@@ -3629,12 +3763,12 @@ function hintsFor(ctx) {
|
|
|
3629
3763
|
{ key: "Esc", label: "close" },
|
|
3630
3764
|
{ key: "^F", label: "fleet" },
|
|
3631
3765
|
{ key: "^G", label: "agents" },
|
|
3632
|
-
{ key: "^T", label: "worktrees" }
|
|
3766
|
+
{ key: "^T", label: "worktrees" },
|
|
3767
|
+
{ key: "F6", label: "todos" }
|
|
3633
3768
|
];
|
|
3634
3769
|
}
|
|
3635
3770
|
const base = [{ key: "?", label: "help" }];
|
|
3636
|
-
if (ctx.managed) base.push({ key: "PgUp/PgDn", label: "scroll" });
|
|
3637
|
-
if (ctx.mouse) base.push({ key: "wheel", label: "scroll" }, { key: "click", label: "select" });
|
|
3771
|
+
if (ctx.managed) base.push({ key: "PgUp/PgDn", label: "scroll" }, { key: "F5", label: "Settings" });
|
|
3638
3772
|
base.push({ key: "^G", label: "agents" }, { key: "^C", label: "stop" });
|
|
3639
3773
|
return base;
|
|
3640
3774
|
}
|
|
@@ -3680,7 +3814,10 @@ var LiveActivityStrip = React6.memo(function LiveActivityStrip2({
|
|
|
3680
3814
|
maxRows = 4
|
|
3681
3815
|
}) {
|
|
3682
3816
|
const running = Object.values(entries).filter((e) => e.status === "running").sort((a, b) => a.startedAt - b.startedAt).slice(0, maxRows);
|
|
3683
|
-
if (running.length === 0)
|
|
3817
|
+
if (running.length === 0) {
|
|
3818
|
+
if (Object.keys(entries).length === 0) return null;
|
|
3819
|
+
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", paddingX: 1, children: Array.from({ length: maxRows }, (_, i) => /* @__PURE__ */ jsx(Box, { height: 1, children: /* @__PURE__ */ jsx(Text, { children: " " }) }, `empty-${i}`)) });
|
|
3820
|
+
}
|
|
3684
3821
|
const now = Date.now();
|
|
3685
3822
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 1, children: [
|
|
3686
3823
|
running.map((e) => {
|
|
@@ -3750,7 +3887,7 @@ function ModelPicker({
|
|
|
3750
3887
|
hint
|
|
3751
3888
|
}) {
|
|
3752
3889
|
if (step === "provider") {
|
|
3753
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 1, children: [
|
|
3890
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
|
|
3754
3891
|
/* @__PURE__ */ jsx(Text, { color: "cyan", bold: true, children: "\u2501\u2501 Switch model \u2014 Step 1/2: Pick provider \u2501\u2501" }),
|
|
3755
3892
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 navigate \xB7 Enter select \xB7 Esc cancel \xB7 Ctrl+C exit" }),
|
|
3756
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, { color: i === selected ? "cyan" : void 0, inverse: i === selected, children: [
|
|
@@ -3775,7 +3912,7 @@ function ModelPicker({
|
|
|
3775
3912
|
const { start, end } = getVisibleWindow(selected, total);
|
|
3776
3913
|
const visibleItems = filteredOptions.slice(start, end);
|
|
3777
3914
|
const searchHint = searchQuery ? ` | filter:"${searchQuery}" \u2192 ${total} match${total === 1 ? "" : "es"}` : total > MAX_VISIBLE ? ` (${total} models \u2014 type to filter)` : "";
|
|
3778
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 1, children: [
|
|
3915
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
|
|
3779
3916
|
/* @__PURE__ */ jsxs(Text, { color: "cyan", bold: true, children: [
|
|
3780
3917
|
"\u2501\u2501 Switch model \u2014 Step 2/2: Pick model ",
|
|
3781
3918
|
"(",
|
|
@@ -3990,6 +4127,52 @@ function PhasePanel({ phases, nowTick }) {
|
|
|
3990
4127
|
}
|
|
3991
4128
|
);
|
|
3992
4129
|
}
|
|
4130
|
+
function QueuePanel({ items }) {
|
|
4131
|
+
const { stdout } = useStdout();
|
|
4132
|
+
const w = stdout?.columns ?? 80;
|
|
4133
|
+
const h = stdout?.rows ?? 24;
|
|
4134
|
+
const avail = Math.max(10, Math.floor(w * 0.3) - 4);
|
|
4135
|
+
const labelMax = Math.max(4, avail - 7);
|
|
4136
|
+
const trunc = (s2) => {
|
|
4137
|
+
if (s2.length <= labelMax) return s2;
|
|
4138
|
+
return s2.slice(0, labelMax - 1) + "\u2026";
|
|
4139
|
+
};
|
|
4140
|
+
const OVERHEAD = 7;
|
|
4141
|
+
const maxVisible = Math.max(4, h - OVERHEAD);
|
|
4142
|
+
const visible = items.slice(0, maxVisible);
|
|
4143
|
+
const overflow = items.length - visible.length;
|
|
4144
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", flexGrow: 1, borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [
|
|
4145
|
+
/* @__PURE__ */ jsx(Box, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
4146
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "QUEUE" }),
|
|
4147
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: items.length }),
|
|
4148
|
+
overflow > 0 ? /* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
|
|
4149
|
+
"+",
|
|
4150
|
+
overflow
|
|
4151
|
+
] }) : null,
|
|
4152
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502 F7 / Esc to close" })
|
|
4153
|
+
] }) }),
|
|
4154
|
+
items.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "No queued messages" }) : /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
4155
|
+
visible.map((item, i) => /* @__PURE__ */ jsxs(Box, { flexDirection: "row", flexShrink: 0, children: [
|
|
4156
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
4157
|
+
String(i + 1).padStart(2),
|
|
4158
|
+
"."
|
|
4159
|
+
] }),
|
|
4160
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
4161
|
+
" ",
|
|
4162
|
+
trunc(item.displayText)
|
|
4163
|
+
] })
|
|
4164
|
+
] }, item.id)),
|
|
4165
|
+
overflow > 0 ? /* @__PURE__ */ jsxs(Box, { flexDirection: "row", flexShrink: 0, marginTop: 0, children: [
|
|
4166
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2026" }),
|
|
4167
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
4168
|
+
" +",
|
|
4169
|
+
overflow,
|
|
4170
|
+
" more"
|
|
4171
|
+
] })
|
|
4172
|
+
] }) : null
|
|
4173
|
+
] })
|
|
4174
|
+
] });
|
|
4175
|
+
}
|
|
3993
4176
|
var MAX_MOUNTED = 500;
|
|
3994
4177
|
function scrollbarThumb(rows, offset, total) {
|
|
3995
4178
|
const scrollable = total > rows;
|
|
@@ -4000,13 +4183,6 @@ function scrollbarThumb(rows, offset, total) {
|
|
|
4000
4183
|
const top = Math.max(0, Math.min(rawTop, rows - size));
|
|
4001
4184
|
return { top, size, scrollable: true };
|
|
4002
4185
|
}
|
|
4003
|
-
function scrollOffsetForTrackRow(rows, total, cell) {
|
|
4004
|
-
if (total <= rows) return 0;
|
|
4005
|
-
const maxOffset = total - rows;
|
|
4006
|
-
const clampedCell = Math.max(0, Math.min(rows - 1, cell));
|
|
4007
|
-
const windowTop = Math.round(clampedCell / Math.max(1, rows - 1) * maxOffset);
|
|
4008
|
-
return Math.max(0, Math.min(maxOffset, maxOffset - windowTop));
|
|
4009
|
-
}
|
|
4010
4186
|
function Scrollbar({
|
|
4011
4187
|
rows,
|
|
4012
4188
|
offset,
|
|
@@ -4034,17 +4210,12 @@ function ScrollableHistory({
|
|
|
4034
4210
|
scrollOffset,
|
|
4035
4211
|
viewportRows,
|
|
4036
4212
|
totalLines,
|
|
4037
|
-
onMeasure
|
|
4213
|
+
onMeasure,
|
|
4214
|
+
maxWidth
|
|
4038
4215
|
}) {
|
|
4039
4216
|
const { stdout } = useStdout();
|
|
4040
|
-
const
|
|
4041
|
-
|
|
4042
|
-
const onResize = () => setTermWidth(stdout?.columns ?? 80);
|
|
4043
|
-
process.stdout.on("resize", onResize);
|
|
4044
|
-
return () => {
|
|
4045
|
-
process.stdout.off("resize", onResize);
|
|
4046
|
-
};
|
|
4047
|
-
}, [stdout]);
|
|
4217
|
+
const rawWidth = stdout?.columns ?? 80;
|
|
4218
|
+
const termWidth = maxWidth ? Math.min(rawWidth, maxWidth) : rawWidth;
|
|
4048
4219
|
const tail = streamingText ? tailForDisplay(streamingText, MAX_STREAM_DISPLAY_CHARS) : "";
|
|
4049
4220
|
const toolTail = toolStream?.text ? tailForDisplay(toolStream.text, MAX_STREAM_DISPLAY_CHARS) : "";
|
|
4050
4221
|
const hiddenCount = Math.max(0, entries.length - MAX_MOUNTED);
|
|
@@ -4100,46 +4271,221 @@ function ScrollableHistory({
|
|
|
4100
4271
|
}
|
|
4101
4272
|
var DELAY_PRESETS_MS = [0, 15e3, 3e4, 45e3, 6e4, 12e4];
|
|
4102
4273
|
var SETTINGS_MODES = ["off", "suggest", "auto"];
|
|
4274
|
+
var LOG_LEVELS = ["error", "warn", "info", "debug", "trace"];
|
|
4275
|
+
var AUDIT_LEVELS = ["minimal", "standard", "full"];
|
|
4276
|
+
var COMPACTOR_STRATEGIES = ["hybrid", "intelligent", "selective"];
|
|
4277
|
+
var MAX_ITERATIONS_PRESETS = [100, 200, 500, 1e3, 0];
|
|
4103
4278
|
function formatSettingsDelay(ms) {
|
|
4104
4279
|
if (ms === 0) return "disabled";
|
|
4105
4280
|
if (ms >= 6e4) return `${Math.round(ms / 6e4)}m`;
|
|
4106
4281
|
return `${Math.round(ms / 1e3)}s`;
|
|
4107
4282
|
}
|
|
4283
|
+
function formatMaxIterations(n) {
|
|
4284
|
+
if (n === 0) return "unlimited";
|
|
4285
|
+
return String(n);
|
|
4286
|
+
}
|
|
4108
4287
|
var MODE_DESC = {
|
|
4109
4288
|
off: "Agent stops after each turn (normal)",
|
|
4110
4289
|
suggest: "Shows next-step suggestions after each turn",
|
|
4111
4290
|
auto: "Self-driving \u2014 agent continues automatically"
|
|
4112
4291
|
};
|
|
4292
|
+
var SETTINGS_FIELD_COUNT = 19;
|
|
4113
4293
|
function SettingsPicker({
|
|
4114
4294
|
field,
|
|
4115
4295
|
mode,
|
|
4116
4296
|
delayMs,
|
|
4297
|
+
titleAnimation,
|
|
4298
|
+
yolo,
|
|
4299
|
+
streamFleet,
|
|
4300
|
+
chime,
|
|
4301
|
+
confirmExit,
|
|
4302
|
+
nextPrediction,
|
|
4303
|
+
featureMcp,
|
|
4304
|
+
featurePlugins,
|
|
4305
|
+
featureMemory,
|
|
4306
|
+
featureSkills,
|
|
4307
|
+
featureModelsRegistry,
|
|
4308
|
+
contextAutoCompact,
|
|
4309
|
+
contextStrategy,
|
|
4310
|
+
logLevel,
|
|
4311
|
+
auditLevel,
|
|
4312
|
+
indexOnStart,
|
|
4313
|
+
maxIterations,
|
|
4117
4314
|
hint
|
|
4118
4315
|
}) {
|
|
4316
|
+
const boolVal = (v) => v ? "on" : "off";
|
|
4119
4317
|
const rows = [
|
|
4318
|
+
// ── Autonomy ──
|
|
4319
|
+
{ section: "Autonomy" },
|
|
4120
4320
|
{ label: "Default autonomy mode", value: mode, detail: MODE_DESC[mode] },
|
|
4121
4321
|
{
|
|
4122
4322
|
label: "Auto-proceed delay",
|
|
4123
4323
|
value: formatSettingsDelay(delayMs),
|
|
4124
4324
|
detail: "Wait before auto-continuing in auto mode"
|
|
4325
|
+
},
|
|
4326
|
+
// ── UX ──
|
|
4327
|
+
{ section: "UX" },
|
|
4328
|
+
{
|
|
4329
|
+
label: "Terminal title animation",
|
|
4330
|
+
value: boolVal(titleAnimation),
|
|
4331
|
+
detail: "Animated window/tab title with status"
|
|
4332
|
+
},
|
|
4333
|
+
{
|
|
4334
|
+
label: "YOLO mode",
|
|
4335
|
+
value: boolVal(yolo),
|
|
4336
|
+
detail: "Skip all confirmation prompts"
|
|
4337
|
+
},
|
|
4338
|
+
{
|
|
4339
|
+
label: "Stream fleet to chat",
|
|
4340
|
+
value: boolVal(streamFleet),
|
|
4341
|
+
detail: "Show subagent messages in main chat"
|
|
4342
|
+
},
|
|
4343
|
+
{
|
|
4344
|
+
label: "Completion chime",
|
|
4345
|
+
value: boolVal(chime),
|
|
4346
|
+
detail: "Play a sound when agent finishes"
|
|
4347
|
+
},
|
|
4348
|
+
{
|
|
4349
|
+
label: "Confirm before exit",
|
|
4350
|
+
value: boolVal(confirmExit),
|
|
4351
|
+
detail: "Ask for confirmation on Ctrl+C exit"
|
|
4352
|
+
},
|
|
4353
|
+
{
|
|
4354
|
+
label: "Next-step prediction",
|
|
4355
|
+
value: boolVal(nextPrediction),
|
|
4356
|
+
detail: "Show LLM-predicted next steps (/next)"
|
|
4357
|
+
},
|
|
4358
|
+
// ── Features ──
|
|
4359
|
+
{ section: "Features" },
|
|
4360
|
+
{
|
|
4361
|
+
label: "MCP servers",
|
|
4362
|
+
value: boolVal(featureMcp),
|
|
4363
|
+
detail: "Load MCP servers from config"
|
|
4364
|
+
},
|
|
4365
|
+
{
|
|
4366
|
+
label: "Plugins",
|
|
4367
|
+
value: boolVal(featurePlugins),
|
|
4368
|
+
detail: "Load npm plugins from config"
|
|
4369
|
+
},
|
|
4370
|
+
{
|
|
4371
|
+
label: "Memory",
|
|
4372
|
+
value: boolVal(featureMemory),
|
|
4373
|
+
detail: "Enable remember/forget tools"
|
|
4374
|
+
},
|
|
4375
|
+
{
|
|
4376
|
+
label: "Skills",
|
|
4377
|
+
value: boolVal(featureSkills),
|
|
4378
|
+
detail: "Discover and load skills from disk"
|
|
4379
|
+
},
|
|
4380
|
+
{
|
|
4381
|
+
label: "Models registry",
|
|
4382
|
+
value: boolVal(featureModelsRegistry),
|
|
4383
|
+
detail: "Fetch models.dev catalog at startup"
|
|
4384
|
+
},
|
|
4385
|
+
// ── Context ──
|
|
4386
|
+
{ section: "Context" },
|
|
4387
|
+
{
|
|
4388
|
+
label: "Auto-compact",
|
|
4389
|
+
value: boolVal(contextAutoCompact),
|
|
4390
|
+
detail: "Auto-compact context when thresholds crossed"
|
|
4391
|
+
},
|
|
4392
|
+
{
|
|
4393
|
+
label: "Compactor strategy",
|
|
4394
|
+
value: contextStrategy,
|
|
4395
|
+
detail: "hybrid (fast) | intelligent (LLM) | selective"
|
|
4396
|
+
},
|
|
4397
|
+
// ── Logging ──
|
|
4398
|
+
{ section: "Logging" },
|
|
4399
|
+
{
|
|
4400
|
+
label: "Log level",
|
|
4401
|
+
value: logLevel,
|
|
4402
|
+
detail: "Console log verbosity"
|
|
4403
|
+
},
|
|
4404
|
+
// ── Session ──
|
|
4405
|
+
{ section: "Session" },
|
|
4406
|
+
{
|
|
4407
|
+
label: "Audit level",
|
|
4408
|
+
value: auditLevel,
|
|
4409
|
+
detail: "minimal | standard | full (large)"
|
|
4410
|
+
},
|
|
4411
|
+
// ── Indexing ──
|
|
4412
|
+
{ section: "Indexing" },
|
|
4413
|
+
{
|
|
4414
|
+
label: "Index on session start",
|
|
4415
|
+
value: boolVal(indexOnStart),
|
|
4416
|
+
detail: "Run incremental index at session start"
|
|
4417
|
+
},
|
|
4418
|
+
// ── Tools ──
|
|
4419
|
+
{ section: "Tools" },
|
|
4420
|
+
{
|
|
4421
|
+
label: "Max iterations",
|
|
4422
|
+
value: formatMaxIterations(maxIterations),
|
|
4423
|
+
detail: "100\u20131000 or unlimited (0)"
|
|
4125
4424
|
}
|
|
4126
4425
|
];
|
|
4127
|
-
|
|
4426
|
+
const fieldRowIndex = [];
|
|
4427
|
+
for (let i = 0; i < rows.length; i++) {
|
|
4428
|
+
if (!rows[i].section) fieldRowIndex.push(i);
|
|
4429
|
+
}
|
|
4430
|
+
const VISIBLE_FIELDS = 8;
|
|
4431
|
+
const totalFields = fieldRowIndex.length;
|
|
4432
|
+
const windowStart = totalFields <= VISIBLE_FIELDS ? 0 : Math.max(0, Math.min(field - Math.floor(VISIBLE_FIELDS / 2), totalFields - VISIBLE_FIELDS));
|
|
4433
|
+
const windowEnd = Math.min(windowStart + VISIBLE_FIELDS, totalFields);
|
|
4434
|
+
const hasAbove = windowStart > 0;
|
|
4435
|
+
const hasBelow = windowEnd < totalFields;
|
|
4436
|
+
const sectionFields = [];
|
|
4437
|
+
let curHeader = -1;
|
|
4438
|
+
for (let i = 0; i < rows.length; i++) {
|
|
4439
|
+
if (rows[i].section) curHeader = i;
|
|
4440
|
+
else if (curHeader >= 0) {
|
|
4441
|
+
const fieldIdx = fieldRowIndex.indexOf(i);
|
|
4442
|
+
if (fieldIdx === -1) continue;
|
|
4443
|
+
const entry = sectionFields.find((s2) => s2.headerIdx === curHeader);
|
|
4444
|
+
if (entry) {
|
|
4445
|
+
entry.fieldEnd = fieldIdx + 1;
|
|
4446
|
+
} else {
|
|
4447
|
+
sectionFields.push({ headerIdx: curHeader, fieldStart: fieldIdx, fieldEnd: fieldIdx + 1 });
|
|
4448
|
+
}
|
|
4449
|
+
}
|
|
4450
|
+
}
|
|
4451
|
+
const shouldShowSection = (headerIdx) => {
|
|
4452
|
+
const sec = sectionFields.find((s2) => s2.headerIdx === headerIdx);
|
|
4453
|
+
if (!sec) return false;
|
|
4454
|
+
return sec.fieldStart < windowEnd && sec.fieldEnd > windowStart;
|
|
4455
|
+
};
|
|
4456
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
|
|
4128
4457
|
/* @__PURE__ */ jsx(Text, { color: "cyan", bold: true, children: "\u2501\u2501 Settings \u2501\u2501" }),
|
|
4129
4458
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 field \xB7 \u2190/\u2192 change \xB7 Enter save \xB7 Esc cancel" }),
|
|
4130
|
-
|
|
4131
|
-
|
|
4132
|
-
|
|
4133
|
-
|
|
4134
|
-
|
|
4135
|
-
|
|
4459
|
+
hasAbove ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u2191 ${windowStart} field${windowStart === 1 ? "" : "s"} above` }) : null,
|
|
4460
|
+
rows.map((row, i) => {
|
|
4461
|
+
const fieldAtRow = fieldRowIndex.indexOf(i);
|
|
4462
|
+
if (fieldAtRow === -1) {
|
|
4463
|
+
if (shouldShowSection(i)) {
|
|
4464
|
+
return /* @__PURE__ */ jsxs(Text, { bold: true, color: "green", children: [
|
|
4465
|
+
"\u2500\u2500 ",
|
|
4466
|
+
row.section,
|
|
4467
|
+
" \u2500\u2500"
|
|
4468
|
+
] }, `section-${i}`);
|
|
4469
|
+
}
|
|
4470
|
+
return null;
|
|
4471
|
+
}
|
|
4472
|
+
if (fieldAtRow < windowStart || fieldAtRow >= windowEnd) return null;
|
|
4473
|
+
const selected = fieldAtRow === field;
|
|
4474
|
+
return /* @__PURE__ */ jsxs(Text, { color: selected ? "yellow" : void 0, inverse: selected, children: [
|
|
4475
|
+
selected ? "\u203A " : " ",
|
|
4476
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: (row.label ?? "").padEnd(26) }),
|
|
4477
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", children: String(row.value ?? "").padEnd(12) }),
|
|
4478
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: row.detail ?? "" })
|
|
4479
|
+
] }, `row-${i}`);
|
|
4480
|
+
}),
|
|
4481
|
+
hasBelow ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u2193 ${totalFields - windowEnd} field${totalFields - windowEnd === 1 ? "" : "s"} below` }) : null,
|
|
4136
4482
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Persisted to ~/.wrongstack/config.json" }),
|
|
4137
4483
|
hint ? /* @__PURE__ */ jsx(Text, { color: "yellow", children: hint }) : null
|
|
4138
4484
|
] });
|
|
4139
4485
|
}
|
|
4140
4486
|
function SlashMenu({ query, matches, selected }) {
|
|
4141
4487
|
const placeholder = query ? `/${query}` : "/";
|
|
4142
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 1, children: [
|
|
4488
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [
|
|
4143
4489
|
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
4144
4490
|
placeholder || "/",
|
|
4145
4491
|
" \u2014 \u2191/\u2193 select, Enter dispatch, Tab autocomplete, Esc close"
|
|
@@ -4159,6 +4505,110 @@ function SlashMenu({ query, matches, selected }) {
|
|
|
4159
4505
|
matches.length === 0 && /* @__PURE__ */ jsx(Text, { dimColor: true, children: "No matching commands" })
|
|
4160
4506
|
] });
|
|
4161
4507
|
}
|
|
4508
|
+
function TodosMonitor({ todos }) {
|
|
4509
|
+
const { stdout } = useStdout();
|
|
4510
|
+
useInput((_input, key) => {
|
|
4511
|
+
if (key.escape) ;
|
|
4512
|
+
});
|
|
4513
|
+
const done = todos.filter((t) => t.status === "completed").length;
|
|
4514
|
+
const inProgress = todos.filter((t) => t.status === "in_progress").length;
|
|
4515
|
+
const pending = todos.filter((t) => t.status === "pending").length;
|
|
4516
|
+
const w = stdout?.columns ?? 80;
|
|
4517
|
+
const twoCols = w >= 100;
|
|
4518
|
+
const mid = Math.ceil(todos.length / 2);
|
|
4519
|
+
const colWidth = twoCols ? Math.floor((w - 8) / 2) : w - 6;
|
|
4520
|
+
const trunc = (text, maxLen) => {
|
|
4521
|
+
if (text.length <= maxLen) return text;
|
|
4522
|
+
return text.slice(0, maxLen - 1) + "\u2026";
|
|
4523
|
+
};
|
|
4524
|
+
const renderRow3 = (t, idx) => {
|
|
4525
|
+
const num = String(idx + 1).padStart(2);
|
|
4526
|
+
const label = t.status === "in_progress" && t.activeForm ? t.activeForm : t.content;
|
|
4527
|
+
const display = trunc(label, colWidth - 8);
|
|
4528
|
+
if (t.status === "completed") {
|
|
4529
|
+
return /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
4530
|
+
" ",
|
|
4531
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
4532
|
+
num,
|
|
4533
|
+
"."
|
|
4534
|
+
] }),
|
|
4535
|
+
" ",
|
|
4536
|
+
/* @__PURE__ */ jsx(Text, { color: "green", children: "[x]" }),
|
|
4537
|
+
" ",
|
|
4538
|
+
display
|
|
4539
|
+
] }, t.id);
|
|
4540
|
+
}
|
|
4541
|
+
if (t.status === "in_progress") {
|
|
4542
|
+
return /* @__PURE__ */ jsxs(Text, { children: [
|
|
4543
|
+
" ",
|
|
4544
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
4545
|
+
num,
|
|
4546
|
+
"."
|
|
4547
|
+
] }),
|
|
4548
|
+
" ",
|
|
4549
|
+
/* @__PURE__ */ jsx(Text, { color: "yellow", bold: true, children: "[~]" }),
|
|
4550
|
+
" ",
|
|
4551
|
+
/* @__PURE__ */ jsx(Text, { color: "yellow", children: display })
|
|
4552
|
+
] }, t.id);
|
|
4553
|
+
}
|
|
4554
|
+
return /* @__PURE__ */ jsxs(Text, { children: [
|
|
4555
|
+
" ",
|
|
4556
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
4557
|
+
num,
|
|
4558
|
+
"."
|
|
4559
|
+
] }),
|
|
4560
|
+
" ",
|
|
4561
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "[ ]" }),
|
|
4562
|
+
" ",
|
|
4563
|
+
display
|
|
4564
|
+
] }, t.id);
|
|
4565
|
+
};
|
|
4566
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
|
|
4567
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, marginBottom: 1, children: [
|
|
4568
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "yellow", children: "TODOS" }),
|
|
4569
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
|
|
4570
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
4571
|
+
done,
|
|
4572
|
+
"/",
|
|
4573
|
+
todos.length,
|
|
4574
|
+
" done"
|
|
4575
|
+
] }),
|
|
4576
|
+
inProgress > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4577
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7" }),
|
|
4578
|
+
/* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
|
|
4579
|
+
"\u231B",
|
|
4580
|
+
inProgress
|
|
4581
|
+
] })
|
|
4582
|
+
] }) : null,
|
|
4583
|
+
pending > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4584
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7" }),
|
|
4585
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
4586
|
+
"\u2610",
|
|
4587
|
+
pending
|
|
4588
|
+
] })
|
|
4589
|
+
] }) : null,
|
|
4590
|
+
done > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4591
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7" }),
|
|
4592
|
+
/* @__PURE__ */ jsxs(Text, { color: "green", children: [
|
|
4593
|
+
"\u2713",
|
|
4594
|
+
done
|
|
4595
|
+
] })
|
|
4596
|
+
] }) : null,
|
|
4597
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502 F6 / Esc to close" })
|
|
4598
|
+
] }),
|
|
4599
|
+
todos.length === 0 ? /* @__PURE__ */ jsx(Box, { marginY: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "No todos. The agent will create them as it plans work." }) }) : twoCols ? (
|
|
4600
|
+
/* Two-column layout: split the list in half, render side-by-side.
|
|
4601
|
+
Pass the absolute position so numbering is continuous across columns. */
|
|
4602
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 2, children: [
|
|
4603
|
+
/* @__PURE__ */ jsx(Box, { flexDirection: "column", width: colWidth, children: todos.slice(0, mid).map((t, i) => renderRow3(t, i)) }),
|
|
4604
|
+
/* @__PURE__ */ jsx(Box, { flexDirection: "column", width: colWidth, children: todos.slice(mid).map((t, i) => renderRow3(t, mid + i)) })
|
|
4605
|
+
] })
|
|
4606
|
+
) : (
|
|
4607
|
+
/* Single column layout */
|
|
4608
|
+
/* @__PURE__ */ jsx(Box, { flexDirection: "column", children: todos.map(renderRow3) })
|
|
4609
|
+
)
|
|
4610
|
+
] });
|
|
4611
|
+
}
|
|
4162
4612
|
var fmtElapsed5 = (ms) => {
|
|
4163
4613
|
const s2 = Math.floor(ms / 1e3);
|
|
4164
4614
|
const m = Math.floor(s2 / 60);
|
|
@@ -4491,6 +4941,34 @@ function runGit(cwd, args) {
|
|
|
4491
4941
|
}
|
|
4492
4942
|
});
|
|
4493
4943
|
}
|
|
4944
|
+
function useBrainEvents(events, dispatch) {
|
|
4945
|
+
useEffect(() => {
|
|
4946
|
+
const requestSummary = (request) => `${request.source}: ${request.question}`.slice(0, 80);
|
|
4947
|
+
const addBrainEntry = (status, payload) => {
|
|
4948
|
+
const p = payload;
|
|
4949
|
+
const decision = p.decision.optionId ?? p.decision.text ?? p.decision.reason ?? p.decision.prompt ?? p.decision.type;
|
|
4950
|
+
dispatch({ type: "brainStatus", state: status, source: p.request.source, risk: p.request.risk, summary: decision });
|
|
4951
|
+
if (status === "ask_human") {
|
|
4952
|
+
dispatch({ type: "brainPromptSet", prompt: { requestId: p.request.id, source: p.request.source, risk: p.request.risk, question: p.request.question, context: p.request.context, options: p.request.options } });
|
|
4953
|
+
} else {
|
|
4954
|
+
dispatch({ type: "brainPromptClear" });
|
|
4955
|
+
}
|
|
4956
|
+
dispatch({ type: "addEntry", entry: { kind: "brain", status, source: p.request.source, risk: p.request.risk, question: p.request.question, decision, rationale: p.decision.rationale } });
|
|
4957
|
+
};
|
|
4958
|
+
const offRequested = events.on("brain.decision_requested", ({ request }) => {
|
|
4959
|
+
dispatch({ type: "brainStatus", state: "deciding", source: request.source, risk: request.risk, summary: requestSummary(request) });
|
|
4960
|
+
});
|
|
4961
|
+
const offAnswered = events.on("brain.decision_answered", (payload) => addBrainEntry("answered", payload));
|
|
4962
|
+
const offAskHuman = events.on("brain.decision_ask_human", (payload) => addBrainEntry("ask_human", payload));
|
|
4963
|
+
const offDenied = events.on("brain.decision_denied", (payload) => addBrainEntry("denied", payload));
|
|
4964
|
+
return () => {
|
|
4965
|
+
offRequested();
|
|
4966
|
+
offAnswered();
|
|
4967
|
+
offAskHuman();
|
|
4968
|
+
offDenied();
|
|
4969
|
+
};
|
|
4970
|
+
}, [events, dispatch]);
|
|
4971
|
+
}
|
|
4494
4972
|
var STREAM_COLORS = ["cyan", "magenta", "yellow", "green", "blue"];
|
|
4495
4973
|
function labelFor(labelsRef, id, name) {
|
|
4496
4974
|
const m = labelsRef.current;
|
|
@@ -4506,7 +4984,11 @@ function labelFor(labelsRef, id, name) {
|
|
|
4506
4984
|
}
|
|
4507
4985
|
function useSubagentEvents(events, dispatch, setActiveMaxContext) {
|
|
4508
4986
|
const labelsRef = useRef(/* @__PURE__ */ new Map());
|
|
4509
|
-
const lbl = (
|
|
4987
|
+
const lbl = useCallback(
|
|
4988
|
+
(id, name) => labelFor(labelsRef, id, name),
|
|
4989
|
+
[]
|
|
4990
|
+
// labelsRef is a stable ref
|
|
4991
|
+
);
|
|
4510
4992
|
useEffect(() => {
|
|
4511
4993
|
const offSpawned = events.on("subagent.spawned", (e) => {
|
|
4512
4994
|
const l = lbl(e.subagentId, e.name);
|
|
@@ -4553,6 +5035,12 @@ function useSubagentEvents(events, dispatch, setActiveMaxContext) {
|
|
|
4553
5035
|
const offCtxPct = events.on("subagent.ctx_pct", (e) => {
|
|
4554
5036
|
dispatch({ type: "fleetCtxPct", id: e.subagentId, load: e.load, tokens: e.tokens, maxContext: e.maxContext });
|
|
4555
5037
|
});
|
|
5038
|
+
const offConcurrencyChanged = events.on("concurrency.changed", (e) => {
|
|
5039
|
+
const { n } = e;
|
|
5040
|
+
if (typeof n === "number" && n > 0) {
|
|
5041
|
+
dispatch({ type: "fleetConcurrency", n });
|
|
5042
|
+
}
|
|
5043
|
+
});
|
|
4556
5044
|
const offLeaderCtxPct = events.on("ctx.pct", (e) => {
|
|
4557
5045
|
setActiveMaxContext(e.maxContext);
|
|
4558
5046
|
dispatch({ type: "leaderCtxPct", load: e.load, tokens: e.tokens, maxContext: e.maxContext });
|
|
@@ -4572,51 +5060,24 @@ function useSubagentEvents(events, dispatch, setActiveMaxContext) {
|
|
|
4572
5060
|
offBudgetExtended();
|
|
4573
5061
|
offIterationSummary();
|
|
4574
5062
|
offCtxPct();
|
|
5063
|
+
offConcurrencyChanged();
|
|
4575
5064
|
offLeaderCtxPct();
|
|
4576
5065
|
offLeaderMaxContext();
|
|
4577
5066
|
offTool();
|
|
4578
5067
|
};
|
|
4579
|
-
}, [events, dispatch, setActiveMaxContext]);
|
|
5068
|
+
}, [events, dispatch, setActiveMaxContext, lbl]);
|
|
4580
5069
|
}
|
|
4581
|
-
|
|
4582
|
-
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
4587
|
-
|
|
4588
|
-
|
|
4589
|
-
|
|
4590
|
-
|
|
4591
|
-
|
|
4592
|
-
}
|
|
4593
|
-
dispatch({ type: "addEntry", entry: { kind: "brain", status, source: p.request.source, risk: p.request.risk, question: p.request.question, decision, rationale: p.decision.rationale } });
|
|
4594
|
-
};
|
|
4595
|
-
const offRequested = events.on("brain.decision_requested", ({ request }) => {
|
|
4596
|
-
dispatch({ type: "brainStatus", state: "deciding", source: request.source, risk: request.risk, summary: requestSummary(request) });
|
|
4597
|
-
});
|
|
4598
|
-
const offAnswered = events.on("brain.decision_answered", (payload) => addBrainEntry("answered", payload));
|
|
4599
|
-
const offAskHuman = events.on("brain.decision_ask_human", (payload) => addBrainEntry("ask_human", payload));
|
|
4600
|
-
const offDenied = events.on("brain.decision_denied", (payload) => addBrainEntry("denied", payload));
|
|
4601
|
-
return () => {
|
|
4602
|
-
offRequested();
|
|
4603
|
-
offAnswered();
|
|
4604
|
-
offAskHuman();
|
|
4605
|
-
offDenied();
|
|
4606
|
-
};
|
|
4607
|
-
}, [events, dispatch]);
|
|
4608
|
-
}
|
|
4609
|
-
var USAGE = "Usage:\n /kill \u2014 list active processes + breaker state\n /kill list \u2014 same as /kill\n /kill all \u2014 kill all tracked processes (SIGTERM \u2192 SIGKILL)\n /kill force \u2014 kill all with SIGKILL immediately\n /kill reset \u2014 reset the circuit breaker to closed\n /kill <pid> \u2014 kill a specific process by PID";
|
|
4610
|
-
function createKillSlashCommand() {
|
|
4611
|
-
return {
|
|
4612
|
-
name: "kill",
|
|
4613
|
-
description: "List or kill active bash/exec processes managed by the process registry.",
|
|
4614
|
-
async run(args) {
|
|
4615
|
-
const trimmed = args.trim();
|
|
4616
|
-
const parts = trimmed.split(/\s+/);
|
|
4617
|
-
const sub = parts[0]?.toLowerCase() ?? "";
|
|
4618
|
-
if (sub === "" || sub === "list") {
|
|
4619
|
-
return { message: renderList() };
|
|
5070
|
+
var USAGE = "Usage:\n /kill \u2014 list active processes + breaker state\n /kill list \u2014 same as /kill\n /kill all \u2014 kill all tracked processes (SIGTERM \u2192 SIGKILL)\n /kill force \u2014 kill all with SIGKILL immediately\n /kill reset \u2014 reset the circuit breaker to closed\n /kill <pid> \u2014 kill a specific process by PID";
|
|
5071
|
+
function createKillSlashCommand() {
|
|
5072
|
+
return {
|
|
5073
|
+
name: "kill",
|
|
5074
|
+
description: "List or kill active bash/exec processes managed by the process registry.",
|
|
5075
|
+
async run(args) {
|
|
5076
|
+
const trimmed = args.trim();
|
|
5077
|
+
const parts = trimmed.split(/\s+/);
|
|
5078
|
+
const sub = parts[0]?.toLowerCase() ?? "";
|
|
5079
|
+
if (sub === "" || sub === "list") {
|
|
5080
|
+
return { message: renderList() };
|
|
4620
5081
|
}
|
|
4621
5082
|
if (sub === "all") {
|
|
4622
5083
|
const pids = getProcessRegistry().killAll();
|
|
@@ -4826,6 +5287,42 @@ function oneLine(s2, max) {
|
|
|
4826
5287
|
return collapsed.length <= max ? collapsed : `${collapsed.slice(0, max - 1)}\u2026`;
|
|
4827
5288
|
}
|
|
4828
5289
|
|
|
5290
|
+
// src/steering-preamble.ts
|
|
5291
|
+
function buildSteeringPreamble(snapshot, newDirection) {
|
|
5292
|
+
const lines = ["[STEERING \u2014 I pressed Esc to interrupt you mid-task on purpose.", ""];
|
|
5293
|
+
const ctx = [];
|
|
5294
|
+
if (snapshot?.runningTools && snapshot.runningTools.length > 0) {
|
|
5295
|
+
ctx.push(`- in-flight tools (now cancelled): ${snapshot.runningTools.join(", ")}`);
|
|
5296
|
+
}
|
|
5297
|
+
if (snapshot?.subagentsTerminated && snapshot.subagentsTerminated > 0) {
|
|
5298
|
+
const subDetails = snapshot.subagents.map((s2) => `${s2.label}${s2.tool ? ` (was running: ${s2.tool})` : ""}`).join(", ");
|
|
5299
|
+
ctx.push(
|
|
5300
|
+
`- subagents (${snapshot.subagentsTerminated} terminated by me, do NOT await them): ${subDetails}`
|
|
5301
|
+
);
|
|
5302
|
+
}
|
|
5303
|
+
if (snapshot?.partialAssistantText && snapshot.partialAssistantText.trim().length > 0) {
|
|
5304
|
+
const tail = snapshot.partialAssistantText.trim().slice(-300);
|
|
5305
|
+
ctx.push(`- your last partial output (truncated, for context only): "${tail}"`);
|
|
5306
|
+
}
|
|
5307
|
+
if (ctx.length > 0) {
|
|
5308
|
+
lines.push("What was happening when I cut you off:");
|
|
5309
|
+
lines.push(...ctx);
|
|
5310
|
+
lines.push("");
|
|
5311
|
+
}
|
|
5312
|
+
lines.push("You have authority to:");
|
|
5313
|
+
lines.push("- Abandon the prior plan entirely if the new direction makes it stale.");
|
|
5314
|
+
lines.push("- Re-spawn fresh subagents (with different roles or tasks) if needed.");
|
|
5315
|
+
lines.push('- Skip a polite "should I continue?" \u2014 just pivot.');
|
|
5316
|
+
lines.push("- Ask me to clarify if the new direction is genuinely ambiguous.");
|
|
5317
|
+
lines.push("");
|
|
5318
|
+
lines.push("New direction:");
|
|
5319
|
+
lines.push("---");
|
|
5320
|
+
lines.push(newDirection);
|
|
5321
|
+
lines.push("---");
|
|
5322
|
+
lines.push("]");
|
|
5323
|
+
return lines.join("\n");
|
|
5324
|
+
}
|
|
5325
|
+
|
|
4829
5326
|
// src/app-reducer.ts
|
|
4830
5327
|
function reducer(state, action) {
|
|
4831
5328
|
switch (action.type) {
|
|
@@ -4852,7 +5349,22 @@ function reducer(state, action) {
|
|
|
4852
5349
|
queue: [],
|
|
4853
5350
|
nextQueueId: 1,
|
|
4854
5351
|
scrollOffset: 0,
|
|
4855
|
-
pendingNewLines: 0
|
|
5352
|
+
pendingNewLines: 0,
|
|
5353
|
+
// Reset fleet state on /clear so old subagent entries don't
|
|
5354
|
+
// cause the LiveActivityStrip to render stale spacers, and
|
|
5355
|
+
// the fleet cost/tokens chips show zero.
|
|
5356
|
+
fleet: {},
|
|
5357
|
+
fleetCost: 0,
|
|
5358
|
+
fleetTokens: { input: 0, output: 0 },
|
|
5359
|
+
leader: {
|
|
5360
|
+
iterations: 0,
|
|
5361
|
+
toolCalls: 0,
|
|
5362
|
+
recentTools: [],
|
|
5363
|
+
currentTool: void 0,
|
|
5364
|
+
startedAt: Date.now(),
|
|
5365
|
+
lastEventAt: Date.now(),
|
|
5366
|
+
iterating: false
|
|
5367
|
+
}
|
|
4856
5368
|
};
|
|
4857
5369
|
}
|
|
4858
5370
|
case "streamDelta":
|
|
@@ -5133,6 +5645,23 @@ function reducer(state, action) {
|
|
|
5133
5645
|
field: 0,
|
|
5134
5646
|
mode: action.mode,
|
|
5135
5647
|
delayMs: action.delayMs,
|
|
5648
|
+
titleAnimation: action.titleAnimation,
|
|
5649
|
+
yolo: action.yolo,
|
|
5650
|
+
streamFleet: action.streamFleet,
|
|
5651
|
+
chime: action.chime,
|
|
5652
|
+
confirmExit: action.confirmExit,
|
|
5653
|
+
nextPrediction: action.nextPrediction,
|
|
5654
|
+
featureMcp: action.featureMcp,
|
|
5655
|
+
featurePlugins: action.featurePlugins,
|
|
5656
|
+
featureMemory: action.featureMemory,
|
|
5657
|
+
featureSkills: action.featureSkills,
|
|
5658
|
+
featureModelsRegistry: action.featureModelsRegistry,
|
|
5659
|
+
contextAutoCompact: action.contextAutoCompact,
|
|
5660
|
+
contextStrategy: action.contextStrategy,
|
|
5661
|
+
logLevel: action.logLevel,
|
|
5662
|
+
auditLevel: action.auditLevel,
|
|
5663
|
+
indexOnStart: action.indexOnStart,
|
|
5664
|
+
maxIterations: action.maxIterations,
|
|
5136
5665
|
hint: void 0
|
|
5137
5666
|
}
|
|
5138
5667
|
};
|
|
@@ -5142,37 +5671,68 @@ function reducer(state, action) {
|
|
|
5142
5671
|
settingsPicker: { ...state.settingsPicker, open: false, hint: void 0 }
|
|
5143
5672
|
};
|
|
5144
5673
|
case "settingsFieldMove": {
|
|
5145
|
-
const next = (state.settingsPicker.field + action.delta +
|
|
5674
|
+
const next = (state.settingsPicker.field + action.delta + SETTINGS_FIELD_COUNT) % SETTINGS_FIELD_COUNT;
|
|
5146
5675
|
return {
|
|
5147
5676
|
...state,
|
|
5148
5677
|
settingsPicker: { ...state.settingsPicker, field: next, hint: void 0 }
|
|
5149
5678
|
};
|
|
5150
5679
|
}
|
|
5151
5680
|
case "settingsFieldSet": {
|
|
5152
|
-
const field = action.field
|
|
5681
|
+
const field = action.field >= 0 && action.field < SETTINGS_FIELD_COUNT ? action.field : 0;
|
|
5153
5682
|
return { ...state, settingsPicker: { ...state.settingsPicker, field, hint: void 0 } };
|
|
5154
5683
|
}
|
|
5155
5684
|
case "settingsValueChange": {
|
|
5156
|
-
|
|
5157
|
-
|
|
5158
|
-
|
|
5159
|
-
const
|
|
5160
|
-
|
|
5161
|
-
|
|
5162
|
-
|
|
5163
|
-
|
|
5685
|
+
const sp = state.settingsPicker;
|
|
5686
|
+
const f = sp.field;
|
|
5687
|
+
if (f === 0) {
|
|
5688
|
+
const i = SETTINGS_MODES.indexOf(sp.mode);
|
|
5689
|
+
const base = i < 0 ? 0 : i;
|
|
5690
|
+
const next = (base + action.delta + SETTINGS_MODES.length) % SETTINGS_MODES.length;
|
|
5691
|
+
return { ...state, settingsPicker: { ...sp, mode: SETTINGS_MODES[next], hint: void 0 } };
|
|
5692
|
+
}
|
|
5693
|
+
if (f === 1) {
|
|
5694
|
+
const j = DELAY_PRESETS_MS.indexOf(sp.delayMs);
|
|
5695
|
+
const base = j < 0 ? 0 : j;
|
|
5696
|
+
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 } };
|
|
5698
|
+
}
|
|
5699
|
+
if (f === 2) return { ...state, settingsPicker: { ...sp, titleAnimation: !sp.titleAnimation, hint: void 0 } };
|
|
5700
|
+
if (f === 3) return { ...state, settingsPicker: { ...sp, yolo: !sp.yolo, hint: void 0 } };
|
|
5701
|
+
if (f === 4) return { ...state, settingsPicker: { ...sp, streamFleet: !sp.streamFleet, hint: void 0 } };
|
|
5702
|
+
if (f === 5) return { ...state, settingsPicker: { ...sp, chime: !sp.chime, hint: void 0 } };
|
|
5703
|
+
if (f === 6) return { ...state, settingsPicker: { ...sp, confirmExit: !sp.confirmExit, hint: void 0 } };
|
|
5704
|
+
if (f === 7) return { ...state, settingsPicker: { ...sp, nextPrediction: !sp.nextPrediction, hint: void 0 } };
|
|
5705
|
+
if (f === 8) return { ...state, settingsPicker: { ...sp, featureMcp: !sp.featureMcp, hint: void 0 } };
|
|
5706
|
+
if (f === 9) return { ...state, settingsPicker: { ...sp, featurePlugins: !sp.featurePlugins, hint: void 0 } };
|
|
5707
|
+
if (f === 10) return { ...state, settingsPicker: { ...sp, featureMemory: !sp.featureMemory, hint: void 0 } };
|
|
5708
|
+
if (f === 11) return { ...state, settingsPicker: { ...sp, featureSkills: !sp.featureSkills, hint: void 0 } };
|
|
5709
|
+
if (f === 12) return { ...state, settingsPicker: { ...sp, featureModelsRegistry: !sp.featureModelsRegistry, hint: void 0 } };
|
|
5710
|
+
if (f === 13) return { ...state, settingsPicker: { ...sp, contextAutoCompact: !sp.contextAutoCompact, hint: void 0 } };
|
|
5711
|
+
if (f === 14) {
|
|
5712
|
+
const i = COMPACTOR_STRATEGIES.indexOf(sp.contextStrategy);
|
|
5713
|
+
const base = i < 0 ? 0 : i;
|
|
5714
|
+
const next = (base + action.delta + COMPACTOR_STRATEGIES.length) % COMPACTOR_STRATEGIES.length;
|
|
5715
|
+
return { ...state, settingsPicker: { ...sp, contextStrategy: COMPACTOR_STRATEGIES[next], hint: void 0 } };
|
|
5716
|
+
}
|
|
5717
|
+
if (f === 15) {
|
|
5718
|
+
const i = LOG_LEVELS.indexOf(sp.logLevel);
|
|
5719
|
+
const base = i < 0 ? 0 : i;
|
|
5720
|
+
const next = (base + action.delta + LOG_LEVELS.length) % LOG_LEVELS.length;
|
|
5721
|
+
return { ...state, settingsPicker: { ...sp, logLevel: LOG_LEVELS[next], hint: void 0 } };
|
|
5722
|
+
}
|
|
5723
|
+
if (f === 16) {
|
|
5724
|
+
const i = AUDIT_LEVELS.indexOf(sp.auditLevel);
|
|
5725
|
+
const base = i < 0 ? 0 : i;
|
|
5726
|
+
const next = (base + action.delta + AUDIT_LEVELS.length) % AUDIT_LEVELS.length;
|
|
5727
|
+
return { ...state, settingsPicker: { ...sp, auditLevel: AUDIT_LEVELS[next], hint: void 0 } };
|
|
5728
|
+
}
|
|
5729
|
+
if (f === 17) return { ...state, settingsPicker: { ...sp, indexOnStart: !sp.indexOnStart, hint: void 0 } };
|
|
5730
|
+
{
|
|
5731
|
+
const j = MAX_ITERATIONS_PRESETS.indexOf(sp.maxIterations);
|
|
5732
|
+
const base = j < 0 ? 0 : j;
|
|
5733
|
+
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 } };
|
|
5164
5735
|
}
|
|
5165
|
-
const j = DELAY_PRESETS_MS.indexOf(state.settingsPicker.delayMs);
|
|
5166
|
-
const base = j < 0 ? 0 : j;
|
|
5167
|
-
const next = (base + action.delta + DELAY_PRESETS_MS.length) % DELAY_PRESETS_MS.length;
|
|
5168
|
-
return {
|
|
5169
|
-
...state,
|
|
5170
|
-
settingsPicker: {
|
|
5171
|
-
...state.settingsPicker,
|
|
5172
|
-
delayMs: DELAY_PRESETS_MS[next],
|
|
5173
|
-
hint: void 0
|
|
5174
|
-
}
|
|
5175
|
-
};
|
|
5176
5736
|
}
|
|
5177
5737
|
case "settingsHint":
|
|
5178
5738
|
return { ...state, settingsPicker: { ...state.settingsPicker, hint: action.text } };
|
|
@@ -5180,6 +5740,14 @@ function reducer(state, action) {
|
|
|
5180
5740
|
return { ...state, confirmQueue: [...state.confirmQueue, action.info] };
|
|
5181
5741
|
case "confirmClose":
|
|
5182
5742
|
return { ...state, confirmQueue: state.confirmQueue.slice(1) };
|
|
5743
|
+
case "enhanceOpen":
|
|
5744
|
+
return { ...state, enhance: action.info };
|
|
5745
|
+
case "enhanceClose":
|
|
5746
|
+
return { ...state, enhance: null };
|
|
5747
|
+
case "enhanceSet":
|
|
5748
|
+
return { ...state, enhanceEnabled: action.enabled };
|
|
5749
|
+
case "enhanceBusy":
|
|
5750
|
+
return { ...state, enhanceBusy: action.on };
|
|
5183
5751
|
case "resetContextChip":
|
|
5184
5752
|
return { ...state, contextChipVersion: state.contextChipVersion + 1 };
|
|
5185
5753
|
// --- Fleet ---
|
|
@@ -5411,8 +5979,24 @@ function reducer(state, action) {
|
|
|
5411
5979
|
};
|
|
5412
5980
|
}
|
|
5413
5981
|
case "fleetCost": {
|
|
5982
|
+
let fleet = state.fleet;
|
|
5983
|
+
if (action.perAgent) {
|
|
5984
|
+
let changed = false;
|
|
5985
|
+
const next = {};
|
|
5986
|
+
for (const [id, entry] of Object.entries(state.fleet)) {
|
|
5987
|
+
const cost = action.perAgent[id]?.cost;
|
|
5988
|
+
if (cost !== void 0 && cost !== entry.cost) {
|
|
5989
|
+
next[id] = { ...entry, cost };
|
|
5990
|
+
changed = true;
|
|
5991
|
+
} else {
|
|
5992
|
+
next[id] = entry;
|
|
5993
|
+
}
|
|
5994
|
+
}
|
|
5995
|
+
if (changed) fleet = next;
|
|
5996
|
+
}
|
|
5414
5997
|
return {
|
|
5415
5998
|
...state,
|
|
5999
|
+
fleet,
|
|
5416
6000
|
fleetCost: action.cost,
|
|
5417
6001
|
fleetTokens: action.input !== void 0 || action.output !== void 0 ? {
|
|
5418
6002
|
input: action.input ?? state.fleetTokens.input,
|
|
@@ -5420,6 +6004,9 @@ function reducer(state, action) {
|
|
|
5420
6004
|
} : state.fleetTokens
|
|
5421
6005
|
};
|
|
5422
6006
|
}
|
|
6007
|
+
case "fleetConcurrency": {
|
|
6008
|
+
return { ...state, fleetConcurrency: action.n };
|
|
6009
|
+
}
|
|
5423
6010
|
case "leaderIterStart": {
|
|
5424
6011
|
return {
|
|
5425
6012
|
...state,
|
|
@@ -5488,6 +6075,12 @@ function reducer(state, action) {
|
|
|
5488
6075
|
case "toggleHelp": {
|
|
5489
6076
|
return { ...state, helpOpen: !state.helpOpen };
|
|
5490
6077
|
}
|
|
6078
|
+
case "toggleTodosMonitor": {
|
|
6079
|
+
return { ...state, todosMonitorOpen: !state.todosMonitorOpen };
|
|
6080
|
+
}
|
|
6081
|
+
case "toggleQueuePanel": {
|
|
6082
|
+
return { ...state, queuePanelOpen: !state.queuePanelOpen };
|
|
6083
|
+
}
|
|
5491
6084
|
case "checkpointReceived": {
|
|
5492
6085
|
const existing = state.checkpoints.find((c) => c.promptIndex === action.cp.promptIndex);
|
|
5493
6086
|
if (existing) return state;
|
|
@@ -5608,7 +6201,7 @@ function reducer(state, action) {
|
|
|
5608
6201
|
case "worktreeMonitorToggle": {
|
|
5609
6202
|
return { ...state, worktreeMonitorOpen: !state.worktreeMonitorOpen };
|
|
5610
6203
|
}
|
|
5611
|
-
// --- In-app chat scroll
|
|
6204
|
+
// --- In-app chat scroll ---
|
|
5612
6205
|
case "scrollBy": {
|
|
5613
6206
|
const maxOffset = Math.max(0, state.totalLines - state.viewportRows);
|
|
5614
6207
|
const next = Math.max(0, Math.min(maxOffset, state.scrollOffset + action.delta));
|
|
@@ -5786,7 +6379,6 @@ function reducer(state, action) {
|
|
|
5786
6379
|
}
|
|
5787
6380
|
}
|
|
5788
6381
|
}
|
|
5789
|
-
var WHEEL_STEP = 3;
|
|
5790
6382
|
var MIN_VIEWPORT = 3;
|
|
5791
6383
|
var INPUT_PROMPT = "\u203A ";
|
|
5792
6384
|
function selectedSlashCommandLine(picker) {
|
|
@@ -5794,41 +6386,22 @@ function selectedSlashCommandLine(picker) {
|
|
|
5794
6386
|
const picked = picker.matches[picker.selected];
|
|
5795
6387
|
return picked ? `/${picked.name}` : null;
|
|
5796
6388
|
}
|
|
5797
|
-
|
|
5798
|
-
|
|
5799
|
-
const
|
|
5800
|
-
|
|
5801
|
-
|
|
5802
|
-
|
|
5803
|
-
|
|
5804
|
-
|
|
5805
|
-
|
|
5806
|
-
|
|
5807
|
-
|
|
5808
|
-
|
|
5809
|
-
}
|
|
5810
|
-
if (snapshot?.partialAssistantText && snapshot.partialAssistantText.trim().length > 0) {
|
|
5811
|
-
const tail = snapshot.partialAssistantText.trim().slice(-300);
|
|
5812
|
-
ctx.push(`- your last partial output (truncated, for context only): "${tail}"`);
|
|
5813
|
-
}
|
|
5814
|
-
if (ctx.length > 0) {
|
|
5815
|
-
lines.push("What was happening when I cut you off:");
|
|
5816
|
-
lines.push(...ctx);
|
|
5817
|
-
lines.push("");
|
|
6389
|
+
function rehydrateHistory(messages, startId) {
|
|
6390
|
+
const entries = [];
|
|
6391
|
+
for (const msg of messages) {
|
|
6392
|
+
if (msg.role === "system") continue;
|
|
6393
|
+
const text = typeof msg.content === "string" ? msg.content : msg.content.filter((b) => b.type === "text").map((b) => b.text).join("");
|
|
6394
|
+
const trimmed = text.trim();
|
|
6395
|
+
if (!trimmed) continue;
|
|
6396
|
+
if (msg.role === "user") {
|
|
6397
|
+
entries.push({ id: startId++, kind: "user", text: trimmed });
|
|
6398
|
+
} else if (msg.role === "assistant") {
|
|
6399
|
+
entries.push({ id: startId++, kind: "assistant", text: trimmed });
|
|
6400
|
+
}
|
|
5818
6401
|
}
|
|
5819
|
-
|
|
5820
|
-
lines.push("- Abandon the prior plan entirely if the new direction makes it stale.");
|
|
5821
|
-
lines.push("- Re-spawn fresh subagents (with different roles or tasks) if needed.");
|
|
5822
|
-
lines.push('- Skip a polite "should I continue?" \u2014 just pivot.');
|
|
5823
|
-
lines.push("- Ask me to clarify if the new direction is genuinely ambiguous.");
|
|
5824
|
-
lines.push("");
|
|
5825
|
-
lines.push("New direction:");
|
|
5826
|
-
lines.push("---");
|
|
5827
|
-
lines.push(newDirection);
|
|
5828
|
-
lines.push("---");
|
|
5829
|
-
lines.push("]");
|
|
5830
|
-
return lines.join("\n");
|
|
6402
|
+
return entries;
|
|
5831
6403
|
}
|
|
6404
|
+
var PASTE_THRESHOLD_CHARS = 200;
|
|
5832
6405
|
function App({
|
|
5833
6406
|
agent,
|
|
5834
6407
|
slashRegistry,
|
|
@@ -5841,6 +6414,11 @@ function App({
|
|
|
5841
6414
|
banner = true,
|
|
5842
6415
|
queueStore,
|
|
5843
6416
|
yolo = false,
|
|
6417
|
+
chime = false,
|
|
6418
|
+
confirmExit = true,
|
|
6419
|
+
enhanceEnabled = true,
|
|
6420
|
+
enhanceController,
|
|
6421
|
+
enhanceDelayMs = 4e3,
|
|
5844
6422
|
getYolo,
|
|
5845
6423
|
getAutonomy,
|
|
5846
6424
|
getEternalEngine,
|
|
@@ -5872,9 +6450,9 @@ function App({
|
|
|
5872
6450
|
initialGoal,
|
|
5873
6451
|
initialAsk,
|
|
5874
6452
|
sessionsDir,
|
|
5875
|
-
|
|
5876
|
-
|
|
5877
|
-
|
|
6453
|
+
managed = false,
|
|
6454
|
+
modeLabel,
|
|
6455
|
+
getModeLabel
|
|
5878
6456
|
}) {
|
|
5879
6457
|
const { exit } = useApp();
|
|
5880
6458
|
const [liveModel, setLiveModel] = useState(model);
|
|
@@ -5882,21 +6460,24 @@ function App({
|
|
|
5882
6460
|
const [activeMaxContext, setActiveMaxContext] = useState(effectiveMaxContext);
|
|
5883
6461
|
const [yoloLive, setYoloLive] = useState(yolo);
|
|
5884
6462
|
const [autonomyLive, setAutonomyLive] = useState(getAutonomy?.() ?? "off");
|
|
6463
|
+
const [liveModeLabel, setLiveModeLabel] = useState(modeLabel ?? "");
|
|
5885
6464
|
const [hiddenItems, setHiddenItems] = useState(statuslineHiddenItems);
|
|
6465
|
+
const [indexState, setIndexState] = useState(() => getIndexState());
|
|
6466
|
+
useEffect(() => {
|
|
6467
|
+
setIndexState(getIndexState());
|
|
6468
|
+
return onIndexStateChange((next) => setIndexState(next));
|
|
6469
|
+
}, []);
|
|
5886
6470
|
const { stdout } = useStdout();
|
|
5887
6471
|
const [termRows, setTermRows] = useState(stdout?.rows ?? 24);
|
|
5888
|
-
const [termCols, setTermCols] = useState(stdout?.columns ?? 80);
|
|
5889
6472
|
useEffect(() => {
|
|
5890
6473
|
const onResize = () => {
|
|
5891
6474
|
setTermRows(process.stdout.rows ?? 24);
|
|
5892
|
-
setTermCols(process.stdout.columns ?? 80);
|
|
5893
6475
|
};
|
|
5894
6476
|
process.stdout.on("resize", onResize);
|
|
5895
6477
|
return () => {
|
|
5896
6478
|
process.stdout.off("resize", onResize);
|
|
5897
6479
|
};
|
|
5898
6480
|
}, []);
|
|
5899
|
-
const [mouseLive, setMouseLive] = useState(mouse);
|
|
5900
6481
|
const [managedLive, setManagedLive] = useState(managed);
|
|
5901
6482
|
useEffect(() => {
|
|
5902
6483
|
setHiddenItems(statuslineHiddenItems);
|
|
@@ -5926,19 +6507,34 @@ function App({
|
|
|
5926
6507
|
}).catch(() => {
|
|
5927
6508
|
});
|
|
5928
6509
|
}, [projectRoot]);
|
|
6510
|
+
const restoredEntries = (() => {
|
|
6511
|
+
const msgs = agent.ctx.messages;
|
|
6512
|
+
if (!msgs || msgs.length === 0) return [];
|
|
6513
|
+
const visible = msgs.filter((m) => m.role !== "system");
|
|
6514
|
+
if (visible.length === 0) return [];
|
|
6515
|
+
return rehydrateHistory(
|
|
6516
|
+
visible,
|
|
6517
|
+
/* startId */
|
|
6518
|
+
1
|
|
6519
|
+
);
|
|
6520
|
+
})();
|
|
6521
|
+
const initialNextId = 1 + restoredEntries.length;
|
|
5929
6522
|
const [state, dispatch] = useReducer(reducer, {
|
|
5930
|
-
entries:
|
|
5931
|
-
|
|
5932
|
-
|
|
5933
|
-
|
|
5934
|
-
|
|
5935
|
-
|
|
5936
|
-
|
|
5937
|
-
|
|
5938
|
-
|
|
5939
|
-
|
|
5940
|
-
|
|
5941
|
-
|
|
6523
|
+
entries: [
|
|
6524
|
+
...banner ? [
|
|
6525
|
+
{
|
|
6526
|
+
id: 0,
|
|
6527
|
+
kind: "banner",
|
|
6528
|
+
version: appVersion ?? "dev",
|
|
6529
|
+
provider: provider ?? "agent",
|
|
6530
|
+
model,
|
|
6531
|
+
cwd: agent.ctx.cwd,
|
|
6532
|
+
family,
|
|
6533
|
+
keyTail
|
|
6534
|
+
}
|
|
6535
|
+
] : [],
|
|
6536
|
+
...restoredEntries
|
|
6537
|
+
],
|
|
5942
6538
|
buffer: "",
|
|
5943
6539
|
cursor: 0,
|
|
5944
6540
|
streamingText: "",
|
|
@@ -5950,7 +6546,7 @@ function App({
|
|
|
5950
6546
|
hint: "",
|
|
5951
6547
|
brain: { state: "idle" },
|
|
5952
6548
|
brainPrompt: null,
|
|
5953
|
-
nextId:
|
|
6549
|
+
nextId: initialNextId,
|
|
5954
6550
|
picker: { open: false, query: "", matches: [], selected: 0 },
|
|
5955
6551
|
slashPicker: { open: false, query: "", matches: [], selected: 0 },
|
|
5956
6552
|
runningTools: /* @__PURE__ */ new Map(),
|
|
@@ -5968,8 +6564,11 @@ function App({
|
|
|
5968
6564
|
searchQuery: ""
|
|
5969
6565
|
},
|
|
5970
6566
|
autonomyPicker: { open: false, options: [], selected: 0 },
|
|
5971
|
-
settingsPicker: { open: false, field: 0, mode: "off", delayMs: 0 },
|
|
6567
|
+
settingsPicker: { open: false, field: 0, mode: "off", delayMs: 0, titleAnimation: true, yolo: false, streamFleet: true, chime: false, confirmExit: true, nextPrediction: false, featureMcp: true, featurePlugins: true, featureMemory: true, featureSkills: true, featureModelsRegistry: true, contextAutoCompact: true, contextStrategy: "hybrid", logLevel: "info", auditLevel: "standard", indexOnStart: true, maxIterations: 500 },
|
|
5972
6568
|
confirmQueue: [],
|
|
6569
|
+
enhance: null,
|
|
6570
|
+
enhanceEnabled,
|
|
6571
|
+
enhanceBusy: false,
|
|
5973
6572
|
contextChipVersion: 0,
|
|
5974
6573
|
fleet: {},
|
|
5975
6574
|
leader: {
|
|
@@ -5983,10 +6582,13 @@ function App({
|
|
|
5983
6582
|
},
|
|
5984
6583
|
fleetCost: 0,
|
|
5985
6584
|
fleetTokens: { input: 0, output: 0 },
|
|
6585
|
+
fleetConcurrency: 4,
|
|
5986
6586
|
streamFleet: true,
|
|
5987
6587
|
monitorOpen: false,
|
|
5988
6588
|
agentsMonitorOpen: false,
|
|
5989
6589
|
helpOpen: false,
|
|
6590
|
+
todosMonitorOpen: false,
|
|
6591
|
+
queuePanelOpen: false,
|
|
5990
6592
|
collabSession: null,
|
|
5991
6593
|
checkpoints: [],
|
|
5992
6594
|
rewindOverlay: null,
|
|
@@ -6015,6 +6617,10 @@ function App({
|
|
|
6015
6617
|
const base = path2.basename(projectRoot);
|
|
6016
6618
|
return base && base !== path2.sep ? base : void 0;
|
|
6017
6619
|
}, [projectRoot]);
|
|
6620
|
+
const chimeRef = useRef(chime);
|
|
6621
|
+
chimeRef.current = chime;
|
|
6622
|
+
const confirmExitRef = useRef(confirmExit);
|
|
6623
|
+
confirmExitRef.current = confirmExit;
|
|
6018
6624
|
const streamingTextRef = useRef("");
|
|
6019
6625
|
const pendingDeltaRef = useRef("");
|
|
6020
6626
|
const flushTimerRef = useRef(null);
|
|
@@ -6023,21 +6629,11 @@ function App({
|
|
|
6023
6629
|
const draftRef = useRef({ buffer: state.buffer, cursor: state.cursor });
|
|
6024
6630
|
draftRef.current = { buffer: state.buffer, cursor: state.cursor };
|
|
6025
6631
|
const bottomRef = useRef(null);
|
|
6026
|
-
const prePickerRef = useRef(null);
|
|
6027
|
-
const preRowsRef = useRef(0);
|
|
6028
|
-
const liveStripRef = useRef(null);
|
|
6029
|
-
const liveStripRowsRef = useRef(0);
|
|
6030
6632
|
React6.useLayoutEffect(() => {
|
|
6031
6633
|
if (!managedLive) return;
|
|
6032
6634
|
const node = bottomRef.current;
|
|
6033
6635
|
if (!node) return;
|
|
6034
6636
|
const { height } = measureElement(node);
|
|
6035
|
-
if (prePickerRef.current) {
|
|
6036
|
-
preRowsRef.current = measureElement(prePickerRef.current).height;
|
|
6037
|
-
}
|
|
6038
|
-
if (liveStripRef.current) {
|
|
6039
|
-
liveStripRowsRef.current = measureElement(liveStripRef.current).height;
|
|
6040
|
-
}
|
|
6041
6637
|
const s2 = stateRef.current;
|
|
6042
6638
|
const affordance = s2.scrollOffset > 0 && s2.pendingNewLines > 0 ? 1 : 0;
|
|
6043
6639
|
const vp = Math.max(MIN_VIEWPORT, termRows - height - affordance - 1);
|
|
@@ -6046,213 +6642,6 @@ function App({
|
|
|
6046
6642
|
}
|
|
6047
6643
|
}, [managedLive, termRows]);
|
|
6048
6644
|
const handleKeyRef = useRef(null);
|
|
6049
|
-
const pendingClickConfirmRef = useRef(null);
|
|
6050
|
-
const openModelPickerRef = useRef(null);
|
|
6051
|
-
const openAutonomyPickerRef = useRef(null);
|
|
6052
|
-
const handleRewindToRef = useRef(null);
|
|
6053
|
-
const confirmRef = useRef(null);
|
|
6054
|
-
const confirmDecisionRef = useRef(null);
|
|
6055
|
-
const scrollbarDragRef = useRef(false);
|
|
6056
|
-
const lastLeftClickRef = useRef(null);
|
|
6057
|
-
const DOUBLE_CLICK_MS = 500;
|
|
6058
|
-
const DOUBLE_CLICK_DIST = 5;
|
|
6059
|
-
const statusChipRef = useRef({ version: appVersion, model, fleetRunning: 0, yolo, autonomy: "off" });
|
|
6060
|
-
const handleMouse = React6.useCallback(
|
|
6061
|
-
(ev) => {
|
|
6062
|
-
const s2 = stateRef.current;
|
|
6063
|
-
if (ev.type === "wheel") {
|
|
6064
|
-
const up = ev.button === "wheelUp";
|
|
6065
|
-
const step = up ? -1 : 1;
|
|
6066
|
-
if (s2.slashPicker.open) return dispatch({ type: "slashPickerMove", delta: step });
|
|
6067
|
-
if (s2.modelPicker.open) return dispatch({ type: "modelPickerMove", delta: step });
|
|
6068
|
-
if (s2.autonomyPicker.open) return dispatch({ type: "autonomyPickerMove", delta: step });
|
|
6069
|
-
if (s2.settingsPicker.open) return dispatch({ type: "settingsFieldMove", delta: step });
|
|
6070
|
-
if (s2.picker.open) return dispatch({ type: "pickerMove", delta: step });
|
|
6071
|
-
if (s2.rewindOverlay) return dispatch({ type: "rewindOverlayMove", delta: step });
|
|
6072
|
-
return dispatch({ type: "scrollBy", delta: up ? WHEEL_STEP : -WHEEL_STEP });
|
|
6073
|
-
}
|
|
6074
|
-
if (ev.type === "release") {
|
|
6075
|
-
scrollbarDragRef.current = false;
|
|
6076
|
-
return;
|
|
6077
|
-
}
|
|
6078
|
-
if (ev.button !== "left") return;
|
|
6079
|
-
const now = Date.now();
|
|
6080
|
-
const lastClick = lastLeftClickRef.current;
|
|
6081
|
-
const isMultiClick = lastClick !== null && now - lastClick.ts < DOUBLE_CLICK_MS && Math.abs(ev.x - lastClick.x) <= DOUBLE_CLICK_DIST && Math.abs(ev.y - lastClick.y) <= DOUBLE_CLICK_DIST;
|
|
6082
|
-
const clickCount = isMultiClick ? lastClick.count + 1 : 1;
|
|
6083
|
-
lastLeftClickRef.current = { x: ev.x, y: ev.y, ts: now, count: clickCount };
|
|
6084
|
-
{
|
|
6085
|
-
const rows = s2.viewportRows;
|
|
6086
|
-
if (ev.drag) {
|
|
6087
|
-
if (scrollbarDragRef.current && s2.totalLines > rows) {
|
|
6088
|
-
dispatch({
|
|
6089
|
-
type: "scrollTo",
|
|
6090
|
-
offset: scrollOffsetForTrackRow(rows, s2.totalLines, ev.y - 1)
|
|
6091
|
-
});
|
|
6092
|
-
}
|
|
6093
|
-
return;
|
|
6094
|
-
}
|
|
6095
|
-
const cols = termCols || 80;
|
|
6096
|
-
const onScrollbar = cols > 0 && ev.x >= cols - 2 && ev.y >= 1 && ev.y <= rows;
|
|
6097
|
-
if (onScrollbar && s2.totalLines > rows) {
|
|
6098
|
-
scrollbarDragRef.current = true;
|
|
6099
|
-
dispatch({
|
|
6100
|
-
type: "scrollTo",
|
|
6101
|
-
offset: scrollOffsetForTrackRow(rows, s2.totalLines, ev.y - 1)
|
|
6102
|
-
});
|
|
6103
|
-
return;
|
|
6104
|
-
}
|
|
6105
|
-
}
|
|
6106
|
-
if (ev.y > s2.viewportRows) {
|
|
6107
|
-
if (s2.helpOpen) return dispatch({ type: "toggleHelp" });
|
|
6108
|
-
if (s2.agentsMonitorOpen) return dispatch({ type: "toggleAgentsMonitor" });
|
|
6109
|
-
if (s2.monitorOpen) return dispatch({ type: "toggleMonitor" });
|
|
6110
|
-
if (s2.worktreeMonitorOpen) return dispatch({ type: "worktreeMonitorToggle" });
|
|
6111
|
-
if (s2.autoPhase?.monitorOpen) return dispatch({ type: "autoPhaseMonitorToggle" });
|
|
6112
|
-
}
|
|
6113
|
-
const affordance = s2.scrollOffset > 0 && s2.pendingNewLines > 0 ? 1 : 0;
|
|
6114
|
-
if (affordance && ev.y === s2.viewportRows + 1) {
|
|
6115
|
-
return dispatch({ type: "scrollToBottom" });
|
|
6116
|
-
}
|
|
6117
|
-
if (s2.confirmQueue.length > 0) {
|
|
6118
|
-
const node = confirmRef.current;
|
|
6119
|
-
const head = s2.confirmQueue[0];
|
|
6120
|
-
if (node && head) {
|
|
6121
|
-
const { height } = measureElement(node);
|
|
6122
|
-
const top = s2.viewportRows + affordance + preRowsRef.current + 1;
|
|
6123
|
-
const buttonsRow = top + height - 2;
|
|
6124
|
-
if (ev.y === buttonsRow) {
|
|
6125
|
-
const contentX = ev.x - 1 - 2;
|
|
6126
|
-
for (const seg of confirmButtonSegments(head.suggestedPattern)) {
|
|
6127
|
-
if (contentX >= seg.start && contentX < seg.start + seg.len) {
|
|
6128
|
-
confirmDecisionRef.current?.(seg.decision);
|
|
6129
|
-
return;
|
|
6130
|
-
}
|
|
6131
|
-
}
|
|
6132
|
-
}
|
|
6133
|
-
}
|
|
6134
|
-
return;
|
|
6135
|
-
}
|
|
6136
|
-
if (s2.rewindOverlay) {
|
|
6137
|
-
const cps = s2.rewindOverlay.checkpoints;
|
|
6138
|
-
const firstItemRow2 = s2.viewportRows + affordance + preRowsRef.current + 3 + 1;
|
|
6139
|
-
const index2 = ev.y - firstItemRow2;
|
|
6140
|
-
if (index2 < 0 || index2 >= cps.length) return;
|
|
6141
|
-
if (index2 === s2.rewindOverlay.selected) {
|
|
6142
|
-
handleRewindToRef.current?.(cps[index2].promptIndex);
|
|
6143
|
-
} else {
|
|
6144
|
-
dispatch({ type: "rewindOverlayMove", delta: index2 - s2.rewindOverlay.selected });
|
|
6145
|
-
}
|
|
6146
|
-
return;
|
|
6147
|
-
}
|
|
6148
|
-
if (s2.settingsPicker.open) {
|
|
6149
|
-
const firstRow = s2.viewportRows + affordance + preRowsRef.current + 2 + 1;
|
|
6150
|
-
const field = ev.y - firstRow;
|
|
6151
|
-
if (field < 0 || field > 1) return;
|
|
6152
|
-
if (field === s2.settingsPicker.field) {
|
|
6153
|
-
dispatch({ type: "settingsValueChange", delta: 1 });
|
|
6154
|
-
} else {
|
|
6155
|
-
dispatch({ type: "settingsFieldSet", field });
|
|
6156
|
-
}
|
|
6157
|
-
return;
|
|
6158
|
-
}
|
|
6159
|
-
const picker = s2.modelPicker.open ? {
|
|
6160
|
-
header: 2,
|
|
6161
|
-
count: s2.modelPicker.step === "provider" ? s2.modelPicker.providerOptions.length : s2.modelPicker.modelOptions.length,
|
|
6162
|
-
selected: s2.modelPicker.selected,
|
|
6163
|
-
move: (delta) => dispatch({ type: "modelPickerMove", delta })
|
|
6164
|
-
} : s2.autonomyPicker.open ? {
|
|
6165
|
-
header: 2,
|
|
6166
|
-
count: s2.autonomyPicker.options.length,
|
|
6167
|
-
selected: s2.autonomyPicker.selected,
|
|
6168
|
-
move: (delta) => dispatch({ type: "autonomyPickerMove", delta })
|
|
6169
|
-
} : s2.slashPicker.open ? {
|
|
6170
|
-
header: 1,
|
|
6171
|
-
count: s2.slashPicker.matches.length,
|
|
6172
|
-
selected: s2.slashPicker.selected,
|
|
6173
|
-
move: (delta) => dispatch({ type: "slashPickerMove", delta })
|
|
6174
|
-
} : s2.picker.open ? {
|
|
6175
|
-
header: 1,
|
|
6176
|
-
count: s2.picker.matches.length,
|
|
6177
|
-
selected: s2.picker.selected,
|
|
6178
|
-
move: (delta) => dispatch({ type: "pickerMove", delta })
|
|
6179
|
-
} : null;
|
|
6180
|
-
if (!picker || picker.count === 0) {
|
|
6181
|
-
const inputDisabled = s2.status === "aborting" && !s2.steeringPending;
|
|
6182
|
-
if (!inputDisabled) {
|
|
6183
|
-
const cols = termCols || 80;
|
|
6184
|
-
const inputTop = s2.viewportRows + affordance + liveStripRowsRef.current + 1;
|
|
6185
|
-
const inputRows = layoutInputRows(INPUT_PROMPT, s2.buffer, s2.cursor, cols).length;
|
|
6186
|
-
const rowIdx = ev.y - inputTop;
|
|
6187
|
-
if (rowIdx >= 0 && rowIdx < inputRows) {
|
|
6188
|
-
const next = inputIndexAtRowCol(INPUT_PROMPT, s2.buffer, cols, rowIdx, ev.x - 1);
|
|
6189
|
-
return dispatch({ type: "setBuffer", buffer: s2.buffer, cursor: next });
|
|
6190
|
-
}
|
|
6191
|
-
}
|
|
6192
|
-
if (!s2.helpOpen && !s2.agentsMonitorOpen && !s2.monitorOpen && !s2.worktreeMonitorOpen && !s2.autoPhase?.monitorOpen) {
|
|
6193
|
-
const chip = statusChipRef.current;
|
|
6194
|
-
const statusTop = s2.viewportRows + affordance + preRowsRef.current + 1;
|
|
6195
|
-
const contentX = ev.x - 1;
|
|
6196
|
-
if (ev.y === statusTop + 1) {
|
|
6197
|
-
const span = statusBarModelSpan({
|
|
6198
|
-
version: chip.version,
|
|
6199
|
-
state: s2.status,
|
|
6200
|
-
fleetRunning: chip.fleetRunning,
|
|
6201
|
-
model: chip.model
|
|
6202
|
-
});
|
|
6203
|
-
if (contentX >= span.start && contentX < span.start + span.len) {
|
|
6204
|
-
openModelPickerRef.current?.();
|
|
6205
|
-
}
|
|
6206
|
-
} else if (ev.y === statusTop + 2) {
|
|
6207
|
-
const span = statusBarAutonomySpan({ yolo: chip.yolo, autonomy: chip.autonomy });
|
|
6208
|
-
if (span && contentX >= span.start && contentX < span.start + span.len) {
|
|
6209
|
-
openAutonomyPickerRef.current?.();
|
|
6210
|
-
}
|
|
6211
|
-
}
|
|
6212
|
-
}
|
|
6213
|
-
return;
|
|
6214
|
-
}
|
|
6215
|
-
const firstItemRow = s2.viewportRows + affordance + preRowsRef.current + picker.header + 1;
|
|
6216
|
-
const index = ev.y - firstItemRow;
|
|
6217
|
-
if (index < 0 || index >= picker.count) return;
|
|
6218
|
-
if (index === picker.selected) {
|
|
6219
|
-
handleKeyRef.current?.("", { ...EMPTY_KEY, return: true });
|
|
6220
|
-
} else {
|
|
6221
|
-
pendingClickConfirmRef.current = index;
|
|
6222
|
-
picker.move(index - picker.selected);
|
|
6223
|
-
}
|
|
6224
|
-
},
|
|
6225
|
-
// dispatch is stable (useReducer); refs are mutable — no reactive deps.
|
|
6226
|
-
// termCols is stable (useState + resize effect).
|
|
6227
|
-
[termCols]
|
|
6228
|
-
);
|
|
6229
|
-
useEffect(() => {
|
|
6230
|
-
if (!subscribeMouse) return;
|
|
6231
|
-
return subscribeMouse(handleMouse);
|
|
6232
|
-
}, [subscribeMouse, handleMouse]);
|
|
6233
|
-
useEffect(() => {
|
|
6234
|
-
const target = pendingClickConfirmRef.current;
|
|
6235
|
-
if (target === null) return;
|
|
6236
|
-
const open = state.slashPicker.open || state.modelPicker.open || state.autonomyPicker.open || state.picker.open;
|
|
6237
|
-
if (!open) {
|
|
6238
|
-
pendingClickConfirmRef.current = null;
|
|
6239
|
-
return;
|
|
6240
|
-
}
|
|
6241
|
-
const sel = state.slashPicker.open ? state.slashPicker.selected : state.modelPicker.open ? state.modelPicker.selected : state.autonomyPicker.open ? state.autonomyPicker.selected : state.picker.selected;
|
|
6242
|
-
if (sel === target) {
|
|
6243
|
-
pendingClickConfirmRef.current = null;
|
|
6244
|
-
handleKeyRef.current?.("", { ...EMPTY_KEY, return: true });
|
|
6245
|
-
}
|
|
6246
|
-
}, [
|
|
6247
|
-
state.slashPicker.open,
|
|
6248
|
-
state.slashPicker.selected,
|
|
6249
|
-
state.modelPicker.open,
|
|
6250
|
-
state.modelPicker.selected,
|
|
6251
|
-
state.autonomyPicker.open,
|
|
6252
|
-
state.autonomyPicker.selected,
|
|
6253
|
-
state.picker.open,
|
|
6254
|
-
state.picker.selected
|
|
6255
|
-
]);
|
|
6256
6645
|
const handleRewindTo = React6.useCallback(
|
|
6257
6646
|
async (checkpointIndex) => {
|
|
6258
6647
|
const sessionId = agent.ctx.session.id;
|
|
@@ -6333,7 +6722,10 @@ function App({
|
|
|
6333
6722
|
toolCalls: state.leader.toolCalls,
|
|
6334
6723
|
recentTools: state.leader.recentTools,
|
|
6335
6724
|
recentMessages: [],
|
|
6336
|
-
cost
|
|
6725
|
+
// Leader (main session) cost — the same number the statusline shows.
|
|
6726
|
+
// Kept distinct from fleet (subagent) cost so the monitor can show a
|
|
6727
|
+
// trustworthy grand total = leader + fleet.
|
|
6728
|
+
cost: tokenCounter?.estimateCost().total ?? 0,
|
|
6337
6729
|
startedAt: state.leader.startedAt,
|
|
6338
6730
|
lastEventAt: state.leader.lastEventAt,
|
|
6339
6731
|
currentTool: state.leader.currentTool,
|
|
@@ -6342,7 +6734,7 @@ function App({
|
|
|
6342
6734
|
ctxMaxTokens: state.leader.ctxMaxTokens ?? effectiveMaxContext
|
|
6343
6735
|
};
|
|
6344
6736
|
return { leader: leaderEntry, ...state.fleet };
|
|
6345
|
-
}, [state.fleet, state.leader, state.status, provider, model, effectiveMaxContext]);
|
|
6737
|
+
}, [state.fleet, state.leader, state.status, provider, model, effectiveMaxContext, tokenCounter]);
|
|
6346
6738
|
const STREAM_COLORS2 = ["cyan", "magenta", "yellow", "green", "blue"];
|
|
6347
6739
|
const labelsRef = useRef(/* @__PURE__ */ new Map());
|
|
6348
6740
|
const labelFor2 = (id, name) => {
|
|
@@ -6393,19 +6785,23 @@ function App({
|
|
|
6393
6785
|
}, [agent.ctx.meta]);
|
|
6394
6786
|
const prevAnyOverlayOpen = useRef(false);
|
|
6395
6787
|
const prevEntriesCount = useRef(0);
|
|
6788
|
+
const prevToolStreamLen = useRef(0);
|
|
6396
6789
|
const eraseLiveRegion = useCallback(() => {
|
|
6397
6790
|
try {
|
|
6398
6791
|
writeOut("\x1B[J");
|
|
6399
6792
|
} catch {
|
|
6400
6793
|
}
|
|
6401
6794
|
}, []);
|
|
6402
|
-
|
|
6403
|
-
const anyOpenNow = state.picker.open || state.slashPicker.open || state.modelPicker.open || state.autonomyPicker.open || state.settingsPicker.open || state.confirmQueue.length > 0;
|
|
6795
|
+
React6.useLayoutEffect(() => {
|
|
6796
|
+
const anyOpenNow = state.picker.open || state.slashPicker.open || state.modelPicker.open || state.autonomyPicker.open || state.settingsPicker.open || state.enhanceBusy || state.enhance != null || state.confirmQueue.length > 0;
|
|
6404
6797
|
const overlayClosed = prevAnyOverlayOpen.current && !anyOpenNow;
|
|
6405
6798
|
const newEntryCommitted = state.entries.length > prevEntriesCount.current;
|
|
6799
|
+
const curToolStreamLen = state.toolStream?.text.length ?? 0;
|
|
6800
|
+
const toolStreamGrew = curToolStreamLen > 0 && curToolStreamLen > prevToolStreamLen.current;
|
|
6406
6801
|
prevAnyOverlayOpen.current = anyOpenNow;
|
|
6407
6802
|
prevEntriesCount.current = state.entries.length;
|
|
6408
|
-
|
|
6803
|
+
prevToolStreamLen.current = curToolStreamLen;
|
|
6804
|
+
if (overlayClosed || newEntryCommitted || toolStreamGrew) {
|
|
6409
6805
|
eraseLiveRegion();
|
|
6410
6806
|
}
|
|
6411
6807
|
}, [
|
|
@@ -6414,8 +6810,11 @@ function App({
|
|
|
6414
6810
|
state.modelPicker.open,
|
|
6415
6811
|
state.autonomyPicker.open,
|
|
6416
6812
|
state.settingsPicker.open,
|
|
6813
|
+
state.enhanceBusy,
|
|
6814
|
+
state.enhance,
|
|
6417
6815
|
state.confirmQueue.length,
|
|
6418
6816
|
state.entries.length,
|
|
6817
|
+
state.toolStream?.text,
|
|
6419
6818
|
eraseLiveRegion
|
|
6420
6819
|
]);
|
|
6421
6820
|
useEffect(() => {
|
|
@@ -6425,6 +6824,9 @@ function App({
|
|
|
6425
6824
|
process.stdout.off("resize", handleResize);
|
|
6426
6825
|
};
|
|
6427
6826
|
}, [eraseLiveRegion]);
|
|
6827
|
+
React6.useLayoutEffect(() => {
|
|
6828
|
+
if (state.enhanceBusy || state.enhance != null) eraseLiveRegion();
|
|
6829
|
+
}, [nowTick, state.enhanceBusy, state.enhance, eraseLiveRegion]);
|
|
6428
6830
|
useEffect(() => {
|
|
6429
6831
|
const detected = detectAtToken(state.buffer, state.cursor);
|
|
6430
6832
|
if (!detected) {
|
|
@@ -6635,60 +7037,6 @@ function App({
|
|
|
6635
7037
|
slashRegistry.unregister("altscreen");
|
|
6636
7038
|
};
|
|
6637
7039
|
}, [slashRegistry]);
|
|
6638
|
-
const mouseLiveRef = useRef(mouseLive);
|
|
6639
|
-
mouseLiveRef.current = mouseLive;
|
|
6640
|
-
useEffect(() => {
|
|
6641
|
-
const MOUSE_ON_SEQ = "\x1B[?1000h\x1B[?1006h";
|
|
6642
|
-
const MOUSE_OFF_SEQ = "\x1B[?1006l\x1B[?1000l";
|
|
6643
|
-
const ALT_ON = "\x1B[?1049h";
|
|
6644
|
-
const ALT_OFF = "\x1B[?1049l";
|
|
6645
|
-
const cmd = {
|
|
6646
|
-
name: "mouse",
|
|
6647
|
-
description: "Toggle mouse mode (clickable menus + wheel-scroll chat). Needs launch with --mouse to enable.",
|
|
6648
|
-
async run(args) {
|
|
6649
|
-
const arg = args.trim().toLowerCase();
|
|
6650
|
-
if (arg !== "on" && arg !== "off") {
|
|
6651
|
-
return {
|
|
6652
|
-
message: `Mouse mode is ${mouseLiveRef.current ? "ON" : "OFF"}. Usage: /mouse on|off`
|
|
6653
|
-
};
|
|
6654
|
-
}
|
|
6655
|
-
if (arg === "on") {
|
|
6656
|
-
if (!mouse) {
|
|
6657
|
-
return {
|
|
6658
|
-
message: "Mouse mode needs the --mouse launch flag (it rewires stdin so mouse bytes never reach the input). Restart with `wstack --tui --mouse`."
|
|
6659
|
-
};
|
|
6660
|
-
}
|
|
6661
|
-
try {
|
|
6662
|
-
writeOut(ALT_ON);
|
|
6663
|
-
writeOut("\x1B[H");
|
|
6664
|
-
writeOut(MOUSE_ON_SEQ);
|
|
6665
|
-
} catch {
|
|
6666
|
-
return { message: "Failed to enable mouse mode." };
|
|
6667
|
-
}
|
|
6668
|
-
setMouseLive(true);
|
|
6669
|
-
setManagedLive(true);
|
|
6670
|
-
return {
|
|
6671
|
-
message: "Mouse mode ON. Click menu items, wheel-scroll the chat (PgUp/PgDn too). Native terminal copy/scroll are suspended until `/mouse off`."
|
|
6672
|
-
};
|
|
6673
|
-
}
|
|
6674
|
-
try {
|
|
6675
|
-
writeOut(MOUSE_OFF_SEQ);
|
|
6676
|
-
writeOut(ALT_OFF);
|
|
6677
|
-
} catch {
|
|
6678
|
-
return { message: "Failed to disable mouse mode." };
|
|
6679
|
-
}
|
|
6680
|
-
setMouseLive(false);
|
|
6681
|
-
setManagedLive(false);
|
|
6682
|
-
return {
|
|
6683
|
-
message: "Mouse mode OFF. Native terminal scroll/copy restored; chat history flows into native scrollback again."
|
|
6684
|
-
};
|
|
6685
|
-
}
|
|
6686
|
-
};
|
|
6687
|
-
slashRegistry.register(cmd);
|
|
6688
|
-
return () => {
|
|
6689
|
-
slashRegistry.unregister("mouse");
|
|
6690
|
-
};
|
|
6691
|
-
}, [slashRegistry, mouse]);
|
|
6692
7040
|
useEffect(() => {
|
|
6693
7041
|
const cmd = {
|
|
6694
7042
|
name: "steer",
|
|
@@ -6800,14 +7148,31 @@ function App({
|
|
|
6800
7148
|
const providers = await getPickableProviders();
|
|
6801
7149
|
dispatch({ type: "modelPickerOpen", providers });
|
|
6802
7150
|
}, [getPickableProviders]);
|
|
6803
|
-
const openAutonomyPicker = React6.useCallback(() => {
|
|
6804
|
-
if (!switchAutonomy) return;
|
|
6805
|
-
dispatch({ type: "autonomyPickerOpen", options: AUTONOMY_OPTIONS });
|
|
6806
|
-
}, [switchAutonomy]);
|
|
6807
7151
|
const openSettings = React6.useCallback(() => {
|
|
6808
7152
|
if (!getSettings) return;
|
|
6809
7153
|
const s2 = getSettings();
|
|
6810
|
-
dispatch({
|
|
7154
|
+
dispatch({
|
|
7155
|
+
type: "settingsOpen",
|
|
7156
|
+
mode: s2.mode,
|
|
7157
|
+
delayMs: s2.delayMs,
|
|
7158
|
+
titleAnimation: s2.titleAnimation ?? true,
|
|
7159
|
+
yolo: s2.yolo ?? false,
|
|
7160
|
+
streamFleet: s2.streamFleet ?? true,
|
|
7161
|
+
chime: s2.chime ?? false,
|
|
7162
|
+
confirmExit: s2.confirmExit ?? true,
|
|
7163
|
+
nextPrediction: s2.nextPrediction ?? false,
|
|
7164
|
+
featureMcp: s2.featureMcp ?? true,
|
|
7165
|
+
featurePlugins: s2.featurePlugins ?? true,
|
|
7166
|
+
featureMemory: s2.featureMemory ?? true,
|
|
7167
|
+
featureSkills: s2.featureSkills ?? true,
|
|
7168
|
+
featureModelsRegistry: s2.featureModelsRegistry ?? true,
|
|
7169
|
+
contextAutoCompact: s2.contextAutoCompact ?? true,
|
|
7170
|
+
contextStrategy: s2.contextStrategy ?? "hybrid",
|
|
7171
|
+
logLevel: s2.logLevel ?? "info",
|
|
7172
|
+
auditLevel: s2.auditLevel ?? "standard",
|
|
7173
|
+
indexOnStart: s2.indexOnStart ?? true,
|
|
7174
|
+
maxIterations: s2.maxIterations ?? 500
|
|
7175
|
+
});
|
|
6811
7176
|
}, [getSettings]);
|
|
6812
7177
|
useEffect(() => {
|
|
6813
7178
|
if (!getPickableProviders || !switchProviderAndModel) return;
|
|
@@ -6820,7 +7185,7 @@ function App({
|
|
|
6820
7185
|
return { message: void 0 };
|
|
6821
7186
|
}
|
|
6822
7187
|
};
|
|
6823
|
-
slashRegistry.register(cmd);
|
|
7188
|
+
slashRegistry.register(cmd, "tui", { official: true });
|
|
6824
7189
|
return () => {
|
|
6825
7190
|
slashRegistry.unregister("model");
|
|
6826
7191
|
};
|
|
@@ -6830,13 +7195,13 @@ function App({
|
|
|
6830
7195
|
const cmd = {
|
|
6831
7196
|
name: "settings",
|
|
6832
7197
|
aliases: ["config", "prefs"],
|
|
6833
|
-
description: "
|
|
7198
|
+
description: "Open the interactive settings editor (19 config fields across 8 sections).",
|
|
6834
7199
|
async run() {
|
|
6835
7200
|
openSettings();
|
|
6836
7201
|
return { message: void 0 };
|
|
6837
7202
|
}
|
|
6838
7203
|
};
|
|
6839
|
-
slashRegistry.register(cmd);
|
|
7204
|
+
slashRegistry.register(cmd, "tui", { official: true });
|
|
6840
7205
|
return () => {
|
|
6841
7206
|
slashRegistry.unregister("settings");
|
|
6842
7207
|
};
|
|
@@ -6852,7 +7217,7 @@ function App({
|
|
|
6852
7217
|
return { message: void 0 };
|
|
6853
7218
|
}
|
|
6854
7219
|
};
|
|
6855
|
-
slashRegistry.register(cmd);
|
|
7220
|
+
slashRegistry.register(cmd, "tui", { official: true });
|
|
6856
7221
|
return () => {
|
|
6857
7222
|
slashRegistry.unregister("autonomy");
|
|
6858
7223
|
};
|
|
@@ -6893,23 +7258,25 @@ function App({
|
|
|
6893
7258
|
});
|
|
6894
7259
|
});
|
|
6895
7260
|
const offTool = events.on("tool.executed", (e) => {
|
|
6896
|
-
|
|
6897
|
-
|
|
6898
|
-
|
|
6899
|
-
|
|
6900
|
-
|
|
6901
|
-
|
|
6902
|
-
|
|
6903
|
-
|
|
6904
|
-
|
|
6905
|
-
|
|
6906
|
-
|
|
6907
|
-
|
|
6908
|
-
|
|
6909
|
-
|
|
6910
|
-
|
|
6911
|
-
|
|
6912
|
-
|
|
7261
|
+
if (e.name !== "delegate") {
|
|
7262
|
+
dispatch({
|
|
7263
|
+
type: "addEntry",
|
|
7264
|
+
entry: {
|
|
7265
|
+
kind: "tool",
|
|
7266
|
+
name: e.name,
|
|
7267
|
+
durationMs: e.durationMs,
|
|
7268
|
+
ok: e.ok,
|
|
7269
|
+
input: e.input,
|
|
7270
|
+
output: e.output,
|
|
7271
|
+
// Real model-visible sizes — forwarded so the size chip beside
|
|
7272
|
+
// the tool header can show what the model paid for instead of
|
|
7273
|
+
// the misleading preview-byte count we used to surface.
|
|
7274
|
+
outputBytes: e.outputBytes,
|
|
7275
|
+
outputTokens: e.outputTokens,
|
|
7276
|
+
outputLines: e.outputLines
|
|
7277
|
+
}
|
|
7278
|
+
});
|
|
7279
|
+
}
|
|
6913
7280
|
dispatch({ type: "toolEnded", name: e.name });
|
|
6914
7281
|
dispatch({ type: "toolStreamClear", name: e.name });
|
|
6915
7282
|
dispatch({ type: "leaderToolEnd", name: e.name, ok: e.ok, durationMs: e.durationMs });
|
|
@@ -6969,6 +7336,34 @@ function App({
|
|
|
6969
7336
|
}
|
|
6970
7337
|
});
|
|
6971
7338
|
});
|
|
7339
|
+
const offDelegateStart = events.on("delegate.started", (e) => {
|
|
7340
|
+
const task = e.task.length > 100 ? `${e.task.slice(0, 99)}\u2026` : e.task;
|
|
7341
|
+
dispatch({
|
|
7342
|
+
type: "addEntry",
|
|
7343
|
+
entry: {
|
|
7344
|
+
kind: "subagent",
|
|
7345
|
+
agentLabel: e.target,
|
|
7346
|
+
agentColor: "magenta",
|
|
7347
|
+
icon: "\u{1F91D}",
|
|
7348
|
+
text: "delegating",
|
|
7349
|
+
detail: task
|
|
7350
|
+
}
|
|
7351
|
+
});
|
|
7352
|
+
});
|
|
7353
|
+
const offDelegateDone = events.on("delegate.completed", (e) => {
|
|
7354
|
+
const cost = e.costUsd && e.costUsd > 0 ? `$${e.costUsd.toFixed(3)}` : void 0;
|
|
7355
|
+
dispatch({
|
|
7356
|
+
type: "addEntry",
|
|
7357
|
+
entry: {
|
|
7358
|
+
kind: "subagent",
|
|
7359
|
+
agentLabel: e.target,
|
|
7360
|
+
agentColor: e.ok ? "green" : "red",
|
|
7361
|
+
icon: e.ok ? "\u2713" : "\u2717",
|
|
7362
|
+
text: e.summary,
|
|
7363
|
+
detail: cost
|
|
7364
|
+
}
|
|
7365
|
+
});
|
|
7366
|
+
});
|
|
6972
7367
|
return () => {
|
|
6973
7368
|
offDelta();
|
|
6974
7369
|
offToolStart();
|
|
@@ -6981,6 +7376,8 @@ function App({
|
|
|
6981
7376
|
offProvResp();
|
|
6982
7377
|
offConfirmNeeded();
|
|
6983
7378
|
offTrustPersisted();
|
|
7379
|
+
offDelegateStart();
|
|
7380
|
+
offDelegateDone();
|
|
6984
7381
|
if (flushTimerRef.current) clearTimeout(flushTimerRef.current);
|
|
6985
7382
|
};
|
|
6986
7383
|
}, [events, agent.ctx.todos]);
|
|
@@ -6988,6 +7385,11 @@ function App({
|
|
|
6988
7385
|
useEffect(() => {
|
|
6989
7386
|
streamFleetRef.current = state.streamFleet;
|
|
6990
7387
|
}, [state.streamFleet]);
|
|
7388
|
+
const enhanceEnabledRef = useRef(state.enhanceEnabled);
|
|
7389
|
+
useEffect(() => {
|
|
7390
|
+
enhanceEnabledRef.current = state.enhanceEnabled;
|
|
7391
|
+
}, [state.enhanceEnabled]);
|
|
7392
|
+
const enhanceAbortRef = useRef(null);
|
|
6991
7393
|
useSubagentEvents(events, dispatch, setActiveMaxContext);
|
|
6992
7394
|
useEffect(() => {
|
|
6993
7395
|
const offCheckpoint = events.on("checkpoint.written", (e) => {
|
|
@@ -7213,6 +7615,18 @@ function App({
|
|
|
7213
7615
|
useEffect(() => {
|
|
7214
7616
|
if (fleetStreamController) fleetStreamController.enabled = state.streamFleet;
|
|
7215
7617
|
}, [state.streamFleet, fleetStreamController]);
|
|
7618
|
+
useEffect(() => {
|
|
7619
|
+
if (!enhanceController) return;
|
|
7620
|
+
enhanceController.enabled = state.enhanceEnabled;
|
|
7621
|
+
enhanceController.setEnabled = (enabled) => {
|
|
7622
|
+
dispatch({ type: "enhanceSet", enabled });
|
|
7623
|
+
};
|
|
7624
|
+
return () => {
|
|
7625
|
+
enhanceController.setEnabled = (enabled) => {
|
|
7626
|
+
enhanceController.enabled = enabled;
|
|
7627
|
+
};
|
|
7628
|
+
};
|
|
7629
|
+
}, [enhanceController, state.enhanceEnabled]);
|
|
7216
7630
|
useEffect(() => {
|
|
7217
7631
|
if (!agentsMonitorController) return;
|
|
7218
7632
|
agentsMonitorController.visible = state.agentsMonitorOpen;
|
|
@@ -7292,7 +7706,8 @@ function App({
|
|
|
7292
7706
|
type: "fleetCost",
|
|
7293
7707
|
cost: d.snapshot().total.cost,
|
|
7294
7708
|
input: d.snapshot().total.input,
|
|
7295
|
-
output: d.snapshot().total.output
|
|
7709
|
+
output: d.snapshot().total.output,
|
|
7710
|
+
perAgent: d.snapshot().perSubagent
|
|
7296
7711
|
});
|
|
7297
7712
|
const seen = new Set(Object.keys(status.subagents));
|
|
7298
7713
|
const pending = /* @__PURE__ */ new Map();
|
|
@@ -7421,7 +7836,8 @@ function App({
|
|
|
7421
7836
|
type: "fleetCost",
|
|
7422
7837
|
cost: d.snapshot().total.cost,
|
|
7423
7838
|
input: d.snapshot().total.input,
|
|
7424
|
-
output: d.snapshot().total.output
|
|
7839
|
+
output: d.snapshot().total.output,
|
|
7840
|
+
perAgent: d.snapshot().perSubagent
|
|
7425
7841
|
});
|
|
7426
7842
|
break;
|
|
7427
7843
|
}
|
|
@@ -7549,7 +7965,8 @@ function App({
|
|
|
7549
7965
|
type: "fleetCost",
|
|
7550
7966
|
cost: d.snapshot().total.cost,
|
|
7551
7967
|
input: d.snapshot().total.input,
|
|
7552
|
-
output: d.snapshot().total.output
|
|
7968
|
+
output: d.snapshot().total.output,
|
|
7969
|
+
perAgent: d.snapshot().perSubagent
|
|
7553
7970
|
});
|
|
7554
7971
|
if (streamFlushTimer) {
|
|
7555
7972
|
clearTimeout(streamFlushTimer);
|
|
@@ -7630,7 +8047,7 @@ function App({
|
|
|
7630
8047
|
type: "addEntry",
|
|
7631
8048
|
entry: {
|
|
7632
8049
|
kind: "warn",
|
|
7633
|
-
text: `Iteration cancelled${director ? " + fleet terminated" : ""}${procTag}. Dropped ${droppedCount} queued message${droppedCount === 1 ? "" : "s"}. Press Ctrl+C again to exit
|
|
8050
|
+
text: `Iteration cancelled${director ? " + fleet terminated" : ""}${procTag}. Dropped ${droppedCount} queued message${droppedCount === 1 ? "" : "s"}. ${confirmExitRef.current ? "Press Ctrl+C again to confirm exit." : "Press Ctrl+C again to exit."}`
|
|
7634
8051
|
}
|
|
7635
8052
|
});
|
|
7636
8053
|
} else {
|
|
@@ -7638,7 +8055,7 @@ function App({
|
|
|
7638
8055
|
type: "addEntry",
|
|
7639
8056
|
entry: {
|
|
7640
8057
|
kind: "warn",
|
|
7641
|
-
text: `Iteration cancelled${director ? " + fleet terminated" : ""}${procTag}. Press Ctrl+C again to exit
|
|
8058
|
+
text: `Iteration cancelled${director ? " + fleet terminated" : ""}${procTag}. ${confirmExitRef.current ? "Press Ctrl+C again to confirm exit." : "Press Ctrl+C again to exit."}`
|
|
7642
8059
|
}
|
|
7643
8060
|
});
|
|
7644
8061
|
}
|
|
@@ -7669,7 +8086,7 @@ function App({
|
|
|
7669
8086
|
type: "addEntry",
|
|
7670
8087
|
entry: {
|
|
7671
8088
|
kind: "warn",
|
|
7672
|
-
text: `${bits.join(" + ") || "Background work stopped"}. Press Ctrl+C again to exit
|
|
8089
|
+
text: `${bits.join(" + ") || "Background work stopped"}. ${confirmExitRef.current ? "Press Ctrl+C again to confirm exit." : "Press Ctrl+C again to exit."}`
|
|
7673
8090
|
}
|
|
7674
8091
|
});
|
|
7675
8092
|
return;
|
|
@@ -7712,10 +8129,16 @@ function App({
|
|
|
7712
8129
|
const handleKey = async (input, key) => {
|
|
7713
8130
|
if (state.status === "aborting" && !state.steeringPending && state.interrupts === 0) return;
|
|
7714
8131
|
if (state.confirmQueue.length > 0) return;
|
|
8132
|
+
if (state.enhanceBusy) {
|
|
8133
|
+
if (key.escape) enhanceAbortRef.current?.abort();
|
|
8134
|
+
return;
|
|
8135
|
+
}
|
|
8136
|
+
if (state.enhance) return;
|
|
7715
8137
|
if (state.helpOpen) {
|
|
7716
8138
|
if (key.escape || input === "?" || input === "q") dispatch({ type: "toggleHelp" });
|
|
7717
8139
|
return;
|
|
7718
8140
|
}
|
|
8141
|
+
state.todosMonitorOpen || state.monitorOpen || state.agentsMonitorOpen || state.worktreeMonitorOpen || !!state.autoPhase?.monitorOpen;
|
|
7719
8142
|
if (inputGateRef.current) return;
|
|
7720
8143
|
if (managedLive) {
|
|
7721
8144
|
if (key.pageUp) {
|
|
@@ -7887,8 +8310,8 @@ function App({
|
|
|
7887
8310
|
const now = Date.now();
|
|
7888
8311
|
if (now - lastEnterAtRef.current < 50) return;
|
|
7889
8312
|
lastEnterAtRef.current = now;
|
|
7890
|
-
const { mode, delayMs } = state.settingsPicker;
|
|
7891
|
-
const err = await saveSettings?.({ mode, delayMs });
|
|
8313
|
+
const { mode, delayMs, titleAnimation, yolo: yolo2, streamFleet, chime: chime2, confirmExit: confirmExit2, nextPrediction, featureMcp, featurePlugins, featureMemory, featureSkills, featureModelsRegistry, contextAutoCompact, contextStrategy, logLevel, auditLevel, indexOnStart, maxIterations } = state.settingsPicker;
|
|
8314
|
+
const err = await saveSettings?.({ mode, delayMs, titleAnimation, yolo: yolo2, streamFleet, chime: chime2, confirmExit: confirmExit2, nextPrediction, featureMcp, featurePlugins, featureMemory, featureSkills, featureModelsRegistry, contextAutoCompact, contextStrategy, logLevel, auditLevel, indexOnStart, maxIterations });
|
|
7892
8315
|
if (err) {
|
|
7893
8316
|
dispatch({ type: "settingsHint", text: err });
|
|
7894
8317
|
return;
|
|
@@ -8001,20 +8424,32 @@ function App({
|
|
|
8001
8424
|
return;
|
|
8002
8425
|
}
|
|
8003
8426
|
const toggleFleetOverlay = () => {
|
|
8004
|
-
if (state.
|
|
8005
|
-
dispatch({ type: "toggleAgentsMonitor" });
|
|
8006
|
-
dispatch({ type: "toggleMonitor" });
|
|
8007
|
-
} else {
|
|
8427
|
+
if (state.monitorOpen) {
|
|
8008
8428
|
dispatch({ type: "toggleMonitor" });
|
|
8429
|
+
return;
|
|
8009
8430
|
}
|
|
8431
|
+
if (state.agentsMonitorOpen) dispatch({ type: "toggleAgentsMonitor" });
|
|
8432
|
+
if (state.worktreeMonitorOpen) dispatch({ type: "worktreeMonitorToggle" });
|
|
8433
|
+
if (state.todosMonitorOpen) dispatch({ type: "toggleTodosMonitor" });
|
|
8434
|
+
if (state.autoPhase?.monitorOpen) dispatch({ type: "autoPhaseMonitorToggle" });
|
|
8435
|
+
if (state.settingsPicker.open) dispatch({ type: "settingsClose" });
|
|
8436
|
+
if (state.queuePanelOpen) dispatch({ type: "toggleQueuePanel" });
|
|
8437
|
+
if (state.helpOpen) dispatch({ type: "toggleHelp" });
|
|
8438
|
+
dispatch({ type: "toggleMonitor" });
|
|
8010
8439
|
};
|
|
8011
8440
|
const toggleAgentsOverlay = () => {
|
|
8012
|
-
if (state.
|
|
8013
|
-
dispatch({ type: "toggleMonitor" });
|
|
8014
|
-
dispatch({ type: "toggleAgentsMonitor" });
|
|
8015
|
-
} else {
|
|
8441
|
+
if (state.agentsMonitorOpen) {
|
|
8016
8442
|
dispatch({ type: "toggleAgentsMonitor" });
|
|
8443
|
+
return;
|
|
8017
8444
|
}
|
|
8445
|
+
if (state.monitorOpen) dispatch({ type: "toggleMonitor" });
|
|
8446
|
+
if (state.worktreeMonitorOpen) dispatch({ type: "worktreeMonitorToggle" });
|
|
8447
|
+
if (state.todosMonitorOpen) dispatch({ type: "toggleTodosMonitor" });
|
|
8448
|
+
if (state.autoPhase?.monitorOpen) dispatch({ type: "autoPhaseMonitorToggle" });
|
|
8449
|
+
if (state.settingsPicker.open) dispatch({ type: "settingsClose" });
|
|
8450
|
+
if (state.queuePanelOpen) dispatch({ type: "toggleQueuePanel" });
|
|
8451
|
+
if (state.helpOpen) dispatch({ type: "toggleHelp" });
|
|
8452
|
+
dispatch({ type: "toggleAgentsMonitor" });
|
|
8018
8453
|
};
|
|
8019
8454
|
const toggleWorktreeOverlay = () => {
|
|
8020
8455
|
if (state.worktreeMonitorOpen) {
|
|
@@ -8024,8 +8459,26 @@ function App({
|
|
|
8024
8459
|
if (state.agentsMonitorOpen) dispatch({ type: "toggleAgentsMonitor" });
|
|
8025
8460
|
if (state.monitorOpen) dispatch({ type: "toggleMonitor" });
|
|
8026
8461
|
if (state.autoPhase?.monitorOpen) dispatch({ type: "autoPhaseMonitorToggle" });
|
|
8462
|
+
if (state.todosMonitorOpen) dispatch({ type: "toggleTodosMonitor" });
|
|
8463
|
+
if (state.settingsPicker.open) dispatch({ type: "settingsClose" });
|
|
8464
|
+
if (state.queuePanelOpen) dispatch({ type: "toggleQueuePanel" });
|
|
8465
|
+
if (state.helpOpen) dispatch({ type: "toggleHelp" });
|
|
8027
8466
|
dispatch({ type: "worktreeMonitorToggle" });
|
|
8028
8467
|
};
|
|
8468
|
+
const toggleTodosOverlay = () => {
|
|
8469
|
+
if (state.todosMonitorOpen) {
|
|
8470
|
+
dispatch({ type: "toggleTodosMonitor" });
|
|
8471
|
+
return;
|
|
8472
|
+
}
|
|
8473
|
+
if (state.agentsMonitorOpen) dispatch({ type: "toggleAgentsMonitor" });
|
|
8474
|
+
if (state.monitorOpen) dispatch({ type: "toggleMonitor" });
|
|
8475
|
+
if (state.worktreeMonitorOpen) dispatch({ type: "worktreeMonitorToggle" });
|
|
8476
|
+
if (state.autoPhase?.monitorOpen) dispatch({ type: "autoPhaseMonitorToggle" });
|
|
8477
|
+
if (state.settingsPicker.open) dispatch({ type: "settingsClose" });
|
|
8478
|
+
if (state.queuePanelOpen) dispatch({ type: "toggleQueuePanel" });
|
|
8479
|
+
if (state.helpOpen) dispatch({ type: "toggleHelp" });
|
|
8480
|
+
dispatch({ type: "toggleTodosMonitor" });
|
|
8481
|
+
};
|
|
8029
8482
|
if (key.ctrl && input === "f" || key.fn === 2) {
|
|
8030
8483
|
toggleFleetOverlay();
|
|
8031
8484
|
return;
|
|
@@ -8038,12 +8491,96 @@ function App({
|
|
|
8038
8491
|
toggleWorktreeOverlay();
|
|
8039
8492
|
return;
|
|
8040
8493
|
}
|
|
8494
|
+
if (key.fn === 5) {
|
|
8495
|
+
if (state.settingsPicker.open) {
|
|
8496
|
+
dispatch({ type: "settingsClose" });
|
|
8497
|
+
} else if (getSettings && saveSettings) {
|
|
8498
|
+
if (state.agentsMonitorOpen) dispatch({ type: "toggleAgentsMonitor" });
|
|
8499
|
+
if (state.monitorOpen) dispatch({ type: "toggleMonitor" });
|
|
8500
|
+
if (state.worktreeMonitorOpen) dispatch({ type: "worktreeMonitorToggle" });
|
|
8501
|
+
if (state.todosMonitorOpen) dispatch({ type: "toggleTodosMonitor" });
|
|
8502
|
+
if (state.autoPhase?.monitorOpen) dispatch({ type: "autoPhaseMonitorToggle" });
|
|
8503
|
+
if (state.queuePanelOpen) dispatch({ type: "toggleQueuePanel" });
|
|
8504
|
+
if (state.helpOpen) dispatch({ type: "toggleHelp" });
|
|
8505
|
+
const cfg = getSettings();
|
|
8506
|
+
dispatch({
|
|
8507
|
+
type: "settingsOpen",
|
|
8508
|
+
mode: cfg.mode,
|
|
8509
|
+
delayMs: cfg.delayMs,
|
|
8510
|
+
titleAnimation: cfg.titleAnimation ?? true,
|
|
8511
|
+
yolo: cfg.yolo ?? false,
|
|
8512
|
+
streamFleet: cfg.streamFleet ?? true,
|
|
8513
|
+
chime: cfg.chime ?? false,
|
|
8514
|
+
confirmExit: cfg.confirmExit ?? true,
|
|
8515
|
+
nextPrediction: cfg.nextPrediction ?? false,
|
|
8516
|
+
featureMcp: cfg.featureMcp ?? true,
|
|
8517
|
+
featurePlugins: cfg.featurePlugins ?? true,
|
|
8518
|
+
featureMemory: cfg.featureMemory ?? true,
|
|
8519
|
+
featureSkills: cfg.featureSkills ?? true,
|
|
8520
|
+
featureModelsRegistry: cfg.featureModelsRegistry ?? true,
|
|
8521
|
+
contextAutoCompact: cfg.contextAutoCompact ?? true,
|
|
8522
|
+
contextStrategy: cfg.contextStrategy ?? "hybrid",
|
|
8523
|
+
logLevel: cfg.logLevel ?? "info",
|
|
8524
|
+
auditLevel: cfg.auditLevel ?? "standard",
|
|
8525
|
+
indexOnStart: cfg.indexOnStart ?? true,
|
|
8526
|
+
maxIterations: cfg.maxIterations ?? 500
|
|
8527
|
+
});
|
|
8528
|
+
}
|
|
8529
|
+
return;
|
|
8530
|
+
}
|
|
8531
|
+
if (key.fn === 6) {
|
|
8532
|
+
toggleTodosOverlay();
|
|
8533
|
+
return;
|
|
8534
|
+
}
|
|
8535
|
+
if (key.fn === 7) {
|
|
8536
|
+
if (state.queuePanelOpen) {
|
|
8537
|
+
dispatch({ type: "toggleQueuePanel" });
|
|
8538
|
+
} else {
|
|
8539
|
+
if (state.agentsMonitorOpen) dispatch({ type: "toggleAgentsMonitor" });
|
|
8540
|
+
if (state.monitorOpen) dispatch({ type: "toggleMonitor" });
|
|
8541
|
+
if (state.worktreeMonitorOpen) dispatch({ type: "worktreeMonitorToggle" });
|
|
8542
|
+
if (state.todosMonitorOpen) dispatch({ type: "toggleTodosMonitor" });
|
|
8543
|
+
if (state.autoPhase?.monitorOpen) dispatch({ type: "autoPhaseMonitorToggle" });
|
|
8544
|
+
if (state.settingsPicker.open) dispatch({ type: "settingsClose" });
|
|
8545
|
+
if (state.helpOpen) dispatch({ type: "toggleHelp" });
|
|
8546
|
+
dispatch({ type: "toggleQueuePanel" });
|
|
8547
|
+
}
|
|
8548
|
+
return;
|
|
8549
|
+
}
|
|
8041
8550
|
if (key.ctrl && input === "s") {
|
|
8042
8551
|
if (state.settingsPicker.open) {
|
|
8043
8552
|
dispatch({ type: "settingsClose" });
|
|
8044
8553
|
} else if (getSettings && saveSettings) {
|
|
8554
|
+
if (state.agentsMonitorOpen) dispatch({ type: "toggleAgentsMonitor" });
|
|
8555
|
+
if (state.monitorOpen) dispatch({ type: "toggleMonitor" });
|
|
8556
|
+
if (state.worktreeMonitorOpen) dispatch({ type: "worktreeMonitorToggle" });
|
|
8557
|
+
if (state.todosMonitorOpen) dispatch({ type: "toggleTodosMonitor" });
|
|
8558
|
+
if (state.autoPhase?.monitorOpen) dispatch({ type: "autoPhaseMonitorToggle" });
|
|
8559
|
+
if (state.queuePanelOpen) dispatch({ type: "toggleQueuePanel" });
|
|
8560
|
+
if (state.helpOpen) dispatch({ type: "toggleHelp" });
|
|
8045
8561
|
const cfg = getSettings();
|
|
8046
|
-
dispatch({
|
|
8562
|
+
dispatch({
|
|
8563
|
+
type: "settingsOpen",
|
|
8564
|
+
mode: cfg.mode,
|
|
8565
|
+
delayMs: cfg.delayMs,
|
|
8566
|
+
titleAnimation: cfg.titleAnimation ?? true,
|
|
8567
|
+
yolo: cfg.yolo ?? false,
|
|
8568
|
+
streamFleet: cfg.streamFleet ?? true,
|
|
8569
|
+
chime: cfg.chime ?? false,
|
|
8570
|
+
confirmExit: cfg.confirmExit ?? true,
|
|
8571
|
+
nextPrediction: cfg.nextPrediction ?? false,
|
|
8572
|
+
featureMcp: cfg.featureMcp ?? true,
|
|
8573
|
+
featurePlugins: cfg.featurePlugins ?? true,
|
|
8574
|
+
featureMemory: cfg.featureMemory ?? true,
|
|
8575
|
+
featureSkills: cfg.featureSkills ?? true,
|
|
8576
|
+
featureModelsRegistry: cfg.featureModelsRegistry ?? true,
|
|
8577
|
+
contextAutoCompact: cfg.contextAutoCompact ?? true,
|
|
8578
|
+
contextStrategy: cfg.contextStrategy ?? "hybrid",
|
|
8579
|
+
logLevel: cfg.logLevel ?? "info",
|
|
8580
|
+
auditLevel: cfg.auditLevel ?? "standard",
|
|
8581
|
+
indexOnStart: cfg.indexOnStart ?? true,
|
|
8582
|
+
maxIterations: cfg.maxIterations ?? 500
|
|
8583
|
+
});
|
|
8047
8584
|
}
|
|
8048
8585
|
return;
|
|
8049
8586
|
}
|
|
@@ -8060,12 +8597,34 @@ function App({
|
|
|
8060
8597
|
dispatch({ type: "worktreeMonitorToggle" });
|
|
8061
8598
|
return;
|
|
8062
8599
|
}
|
|
8600
|
+
if (state.todosMonitorOpen) {
|
|
8601
|
+
dispatch({ type: "toggleTodosMonitor" });
|
|
8602
|
+
return;
|
|
8603
|
+
}
|
|
8604
|
+
if (state.autoPhase?.monitorOpen) {
|
|
8605
|
+
dispatch({ type: "autoPhaseMonitorToggle" });
|
|
8606
|
+
return;
|
|
8607
|
+
}
|
|
8608
|
+
if (state.settingsPicker.open) {
|
|
8609
|
+
dispatch({ type: "settingsClose" });
|
|
8610
|
+
return;
|
|
8611
|
+
}
|
|
8612
|
+
if (state.queuePanelOpen) {
|
|
8613
|
+
dispatch({ type: "toggleQueuePanel" });
|
|
8614
|
+
return;
|
|
8615
|
+
}
|
|
8063
8616
|
}
|
|
8064
|
-
if (input === "?" && !key.ctrl && !key.meta && draftRef.current.buffer === "" && !state.slashPicker.open && !state.picker.open && !state.modelPicker.open && !state.autonomyPicker.open && !state.settingsPicker.open && !state.rewindOverlay && !state.monitorOpen && !state.agentsMonitorOpen && !state.worktreeMonitorOpen && !state.autoPhase?.monitorOpen) {
|
|
8617
|
+
if (input === "?" && !key.ctrl && !key.meta && draftRef.current.buffer === "" && !state.slashPicker.open && !state.picker.open && !state.modelPicker.open && !state.autonomyPicker.open && !state.settingsPicker.open && !state.rewindOverlay && !state.monitorOpen && !state.agentsMonitorOpen && !state.worktreeMonitorOpen && !state.todosMonitorOpen && !state.autoPhase?.monitorOpen) {
|
|
8065
8618
|
dispatch({ type: "toggleHelp" });
|
|
8066
8619
|
return;
|
|
8067
8620
|
}
|
|
8068
8621
|
if (isEnter) {
|
|
8622
|
+
if (key.shift) {
|
|
8623
|
+
const { buffer: buffer2, cursor: cursor2 } = draftRef.current;
|
|
8624
|
+
const next2 = buffer2.slice(0, cursor2) + "\n" + buffer2.slice(cursor2);
|
|
8625
|
+
setDraft(next2, cursor2 + 1);
|
|
8626
|
+
return;
|
|
8627
|
+
}
|
|
8069
8628
|
const now = Date.now();
|
|
8070
8629
|
if (now - lastEnterAtRef.current < 50) return;
|
|
8071
8630
|
lastEnterAtRef.current = now;
|
|
@@ -8073,36 +8632,41 @@ function App({
|
|
|
8073
8632
|
return;
|
|
8074
8633
|
}
|
|
8075
8634
|
const { buffer, cursor } = draftRef.current;
|
|
8076
|
-
if (key.backspace
|
|
8635
|
+
if (key.backspace) {
|
|
8077
8636
|
if (key.ctrl) {
|
|
8078
|
-
if (
|
|
8079
|
-
|
|
8080
|
-
|
|
8081
|
-
|
|
8082
|
-
|
|
8083
|
-
setDraft(next3, lastWordStart);
|
|
8084
|
-
} else {
|
|
8085
|
-
if (cursor >= buffer.length) return;
|
|
8086
|
-
const afterCursor = buffer.slice(cursor);
|
|
8087
|
-
const nextWordStart = afterCursor.indexOf(" ");
|
|
8088
|
-
const end = nextWordStart === -1 ? buffer.length : cursor + nextWordStart + 1;
|
|
8089
|
-
const next3 = buffer.slice(0, cursor) + buffer.slice(end);
|
|
8090
|
-
setDraft(next3, cursor);
|
|
8091
|
-
}
|
|
8637
|
+
if (cursor === 0) return;
|
|
8638
|
+
const beforeCursor = buffer.slice(0, cursor);
|
|
8639
|
+
const lastWordStart = beforeCursor.lastIndexOf(" ") + 1;
|
|
8640
|
+
const next3 = beforeCursor.slice(0, lastWordStart) + buffer.slice(cursor);
|
|
8641
|
+
setDraft(next3, lastWordStart);
|
|
8092
8642
|
return;
|
|
8093
8643
|
}
|
|
8094
|
-
|
|
8095
|
-
|
|
8096
|
-
|
|
8097
|
-
|
|
8098
|
-
return;
|
|
8099
|
-
}
|
|
8644
|
+
const tokenDel = deleteTokenBackward(buffer, cursor);
|
|
8645
|
+
if (tokenDel) {
|
|
8646
|
+
setDraft(tokenDel.buffer, tokenDel.cursor);
|
|
8647
|
+
return;
|
|
8100
8648
|
}
|
|
8101
8649
|
if (cursor === 0) return;
|
|
8102
8650
|
const next2 = buffer.slice(0, cursor - 1) + buffer.slice(cursor);
|
|
8103
8651
|
setDraft(next2, cursor - 1);
|
|
8104
8652
|
return;
|
|
8105
8653
|
}
|
|
8654
|
+
if (key.delete) {
|
|
8655
|
+
if (key.ctrl) {
|
|
8656
|
+
if (cursor >= buffer.length) return;
|
|
8657
|
+
const afterCursor = buffer.slice(cursor);
|
|
8658
|
+
const nextWordStart = afterCursor.indexOf(" ");
|
|
8659
|
+
const end = nextWordStart === -1 ? buffer.length : cursor + nextWordStart + 1;
|
|
8660
|
+
const next3 = buffer.slice(0, cursor) + buffer.slice(end);
|
|
8661
|
+
setDraft(next3, cursor);
|
|
8662
|
+
return;
|
|
8663
|
+
}
|
|
8664
|
+
if (cursor >= buffer.length) return;
|
|
8665
|
+
const span = tokenLengthForward(buffer, cursor) || 1;
|
|
8666
|
+
const next2 = buffer.slice(0, cursor) + buffer.slice(cursor + span);
|
|
8667
|
+
setDraft(next2, cursor);
|
|
8668
|
+
return;
|
|
8669
|
+
}
|
|
8106
8670
|
if (key.leftArrow) {
|
|
8107
8671
|
if (key.ctrl) {
|
|
8108
8672
|
if (cursor === 0) return;
|
|
@@ -8173,7 +8737,7 @@ function App({
|
|
|
8173
8737
|
setDraft("", 0);
|
|
8174
8738
|
return;
|
|
8175
8739
|
}
|
|
8176
|
-
if (key.
|
|
8740
|
+
if (key.ctrl && input === "d") {
|
|
8177
8741
|
if (cursor >= buffer.length) return;
|
|
8178
8742
|
const span = tokenLengthForward(buffer, cursor) || 1;
|
|
8179
8743
|
const next2 = buffer.slice(0, cursor) + buffer.slice(cursor + span);
|
|
@@ -8300,10 +8864,20 @@ function App({
|
|
|
8300
8864
|
} finally {
|
|
8301
8865
|
activeCtrlRef.current = null;
|
|
8302
8866
|
dispatch({ type: "status", status: "idle" });
|
|
8867
|
+
if (chimeRef.current) {
|
|
8868
|
+
try {
|
|
8869
|
+
process.stdout.write("\x07");
|
|
8870
|
+
} catch {
|
|
8871
|
+
}
|
|
8872
|
+
}
|
|
8303
8873
|
}
|
|
8304
8874
|
const head = stateRef.current.queue[0];
|
|
8305
8875
|
if (head) {
|
|
8306
8876
|
dispatch({ type: "dequeueFirst" });
|
|
8877
|
+
dispatch({
|
|
8878
|
+
type: "addEntry",
|
|
8879
|
+
entry: { kind: "user", text: head.displayText }
|
|
8880
|
+
});
|
|
8307
8881
|
await runBlocks(head.blocks);
|
|
8308
8882
|
}
|
|
8309
8883
|
};
|
|
@@ -8448,6 +9022,10 @@ function App({
|
|
|
8448
9022
|
void runParallelLoopRef.current();
|
|
8449
9023
|
}
|
|
8450
9024
|
}
|
|
9025
|
+
if (getModeLabel) {
|
|
9026
|
+
const currentMode = getModeLabel();
|
|
9027
|
+
if (currentMode !== liveModeLabel) setLiveModeLabel(currentMode);
|
|
9028
|
+
}
|
|
8451
9029
|
if (res?.exit) {
|
|
8452
9030
|
exit();
|
|
8453
9031
|
onExit(0);
|
|
@@ -8467,6 +9045,7 @@ function App({
|
|
|
8467
9045
|
const cmd = trimmed.slice(1).split(/\s+/, 1)[0];
|
|
8468
9046
|
if (cmd === "clear") {
|
|
8469
9047
|
onClearHistory?.(dispatch);
|
|
9048
|
+
tokenCounter?.reset();
|
|
8470
9049
|
}
|
|
8471
9050
|
} catch (err) {
|
|
8472
9051
|
dispatch({
|
|
@@ -8479,6 +9058,52 @@ function App({
|
|
|
8479
9058
|
const builder = builderRef.current;
|
|
8480
9059
|
if (!builder) return;
|
|
8481
9060
|
const steering = state.steeringPending;
|
|
9061
|
+
let effectiveText = trimmed;
|
|
9062
|
+
const hasChips = trimmed ? new RegExp(INLINE_TOKEN_SRC, "g").test(trimmed) : false;
|
|
9063
|
+
if (enhanceEnabledRef.current && state.status === "idle" && !steering && !hasChips && shouldEnhance(trimmed)) {
|
|
9064
|
+
dispatch({ type: "enhanceBusy", on: true });
|
|
9065
|
+
const ac = new AbortController();
|
|
9066
|
+
enhanceAbortRef.current = ac;
|
|
9067
|
+
let refined = null;
|
|
9068
|
+
let enhanceErr = null;
|
|
9069
|
+
try {
|
|
9070
|
+
refined = await enhanceUserPrompt({
|
|
9071
|
+
provider: agent.ctx.provider,
|
|
9072
|
+
model: agent.ctx.model,
|
|
9073
|
+
text: trimmed,
|
|
9074
|
+
signal: ac.signal,
|
|
9075
|
+
onError: (reason) => {
|
|
9076
|
+
enhanceErr = reason;
|
|
9077
|
+
},
|
|
9078
|
+
// Feed recent conversation so follow-ups ("do the same", "that file")
|
|
9079
|
+
// resolve against context instead of being refined blind.
|
|
9080
|
+
history: recentTextTurns(agent.ctx.messages)
|
|
9081
|
+
});
|
|
9082
|
+
} finally {
|
|
9083
|
+
enhanceAbortRef.current = null;
|
|
9084
|
+
dispatch({ type: "enhanceBusy", on: false });
|
|
9085
|
+
}
|
|
9086
|
+
if (refined === null && !ac.signal.aborted) {
|
|
9087
|
+
dispatch({
|
|
9088
|
+
type: "addEntry",
|
|
9089
|
+
entry: {
|
|
9090
|
+
kind: "info",
|
|
9091
|
+
text: enhanceErr ? `\u2728 refinement unavailable (${enhanceErr}) \u2014 sent your message as-is` : "\u2728 refinement unavailable \u2014 sent your message as-is"
|
|
9092
|
+
}
|
|
9093
|
+
});
|
|
9094
|
+
}
|
|
9095
|
+
if (refined && !normalizedEqual(refined, trimmed)) {
|
|
9096
|
+
const decision = await new Promise((resolve) => {
|
|
9097
|
+
dispatch({ type: "enhanceOpen", info: { original: trimmed, refined, resolve } });
|
|
9098
|
+
});
|
|
9099
|
+
dispatch({ type: "enhanceClose" });
|
|
9100
|
+
if (decision === "edit") {
|
|
9101
|
+
setDraft(refined, refined.length);
|
|
9102
|
+
return;
|
|
9103
|
+
}
|
|
9104
|
+
effectiveText = decision === "refined" ? refined : trimmed;
|
|
9105
|
+
}
|
|
9106
|
+
}
|
|
8482
9107
|
const sddContext = getSDDContext?.();
|
|
8483
9108
|
if (sddContext && trimmed) {
|
|
8484
9109
|
builder.appendText(`[SDD SESSION ACTIVE]
|
|
@@ -8489,11 +9114,11 @@ User message:
|
|
|
8489
9114
|
`);
|
|
8490
9115
|
}
|
|
8491
9116
|
if (trimmed) {
|
|
8492
|
-
const toAppend = steering ? buildSteeringPreamble(state.steerSnapshot,
|
|
9117
|
+
const toAppend = steering ? buildSteeringPreamble(state.steerSnapshot, effectiveText) : effectiveText;
|
|
8493
9118
|
builder.appendText(toAppend);
|
|
8494
9119
|
}
|
|
8495
9120
|
if (steering) dispatch({ type: "steerConsume" });
|
|
8496
|
-
const displayText = trimmed ? steering ? `\u21AF ${
|
|
9121
|
+
const displayText = trimmed ? steering ? `\u21AF ${effectiveText}` : effectiveText : "(attachments only)";
|
|
8497
9122
|
const pasteParts = [];
|
|
8498
9123
|
for (const m of trimmed.matchAll(new RegExp(INLINE_TOKEN_SRC, "g"))) {
|
|
8499
9124
|
const token = m[0];
|
|
@@ -8547,20 +9172,6 @@ User message:
|
|
|
8547
9172
|
})();
|
|
8548
9173
|
}, [initialAsk, initialGoal]);
|
|
8549
9174
|
handleKeyRef.current = handleKey;
|
|
8550
|
-
openModelPickerRef.current = () => {
|
|
8551
|
-
void openModelPicker();
|
|
8552
|
-
};
|
|
8553
|
-
openAutonomyPickerRef.current = openAutonomyPicker;
|
|
8554
|
-
handleRewindToRef.current = (promptIndex) => {
|
|
8555
|
-
void handleRewindTo(promptIndex);
|
|
8556
|
-
};
|
|
8557
|
-
statusChipRef.current = {
|
|
8558
|
-
version: appVersion,
|
|
8559
|
-
model: `${liveProvider}/${liveModel}`,
|
|
8560
|
-
fleetRunning: fleetCounts?.running ?? 0,
|
|
8561
|
-
yolo: yoloLive,
|
|
8562
|
-
autonomy: autonomyLive
|
|
8563
|
-
};
|
|
8564
9175
|
const inputHint = useMemo(() => {
|
|
8565
9176
|
if (state.status !== "idle") return "";
|
|
8566
9177
|
if (state.buffer.startsWith("/")) return "slash command \u2014 Enter to dispatch";
|
|
@@ -8568,7 +9179,8 @@ User message:
|
|
|
8568
9179
|
return "";
|
|
8569
9180
|
}, [state.buffer, state.status, state.picker.open]);
|
|
8570
9181
|
const affordanceShown = managedLive && state.scrollOffset > 0 && state.pendingNewLines > 0;
|
|
8571
|
-
|
|
9182
|
+
const enhanceActive = state.enhanceBusy || state.enhance != null;
|
|
9183
|
+
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", height: managedLive ? termRows : void 0, children: /* @__PURE__ */ jsxs(Box, { flexDirection: "column", flexGrow: 1, flexShrink: 0, children: [
|
|
8572
9184
|
managedLive ? /* @__PURE__ */ jsx(
|
|
8573
9185
|
ScrollableHistory,
|
|
8574
9186
|
{
|
|
@@ -8590,20 +9202,18 @@ User message:
|
|
|
8590
9202
|
),
|
|
8591
9203
|
affordanceShown ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u2193 ${state.pendingNewLines} new line${state.pendingNewLines === 1 ? "" : "s"} \u2014 PgDn or click to jump to bottom` }) : null,
|
|
8592
9204
|
/* @__PURE__ */ jsxs(Box, { ref: managedLive ? bottomRef : void 0, flexDirection: "column", flexShrink: 0, children: [
|
|
8593
|
-
/* @__PURE__ */
|
|
8594
|
-
|
|
8595
|
-
|
|
8596
|
-
|
|
8597
|
-
|
|
8598
|
-
|
|
8599
|
-
|
|
8600
|
-
|
|
8601
|
-
|
|
8602
|
-
|
|
8603
|
-
|
|
8604
|
-
|
|
8605
|
-
)
|
|
8606
|
-
] }),
|
|
9205
|
+
/* @__PURE__ */ jsx(LiveActivityStrip, { entries: state.fleet, nowTick }),
|
|
9206
|
+
/* @__PURE__ */ jsx(
|
|
9207
|
+
Input,
|
|
9208
|
+
{
|
|
9209
|
+
prompt: INPUT_PROMPT,
|
|
9210
|
+
value: enhanceActive ? "" : state.buffer,
|
|
9211
|
+
cursor: enhanceActive ? 0 : state.cursor,
|
|
9212
|
+
disabled: state.status === "aborting" && !state.steeringPending || state.confirmQueue.length > 0,
|
|
9213
|
+
hint: enhanceActive ? "" : inputHint,
|
|
9214
|
+
onKey: handleKey
|
|
9215
|
+
}
|
|
9216
|
+
),
|
|
8607
9217
|
state.picker.open ? /* @__PURE__ */ jsx(
|
|
8608
9218
|
FilePicker,
|
|
8609
9219
|
{
|
|
@@ -8647,6 +9257,23 @@ User message:
|
|
|
8647
9257
|
field: state.settingsPicker.field,
|
|
8648
9258
|
mode: state.settingsPicker.mode,
|
|
8649
9259
|
delayMs: state.settingsPicker.delayMs,
|
|
9260
|
+
titleAnimation: state.settingsPicker.titleAnimation,
|
|
9261
|
+
yolo: state.settingsPicker.yolo,
|
|
9262
|
+
streamFleet: state.settingsPicker.streamFleet,
|
|
9263
|
+
chime: state.settingsPicker.chime,
|
|
9264
|
+
confirmExit: state.settingsPicker.confirmExit,
|
|
9265
|
+
nextPrediction: state.settingsPicker.nextPrediction,
|
|
9266
|
+
featureMcp: state.settingsPicker.featureMcp,
|
|
9267
|
+
featurePlugins: state.settingsPicker.featurePlugins,
|
|
9268
|
+
featureMemory: state.settingsPicker.featureMemory,
|
|
9269
|
+
featureSkills: state.settingsPicker.featureSkills,
|
|
9270
|
+
featureModelsRegistry: state.settingsPicker.featureModelsRegistry,
|
|
9271
|
+
contextAutoCompact: state.settingsPicker.contextAutoCompact,
|
|
9272
|
+
contextStrategy: state.settingsPicker.contextStrategy,
|
|
9273
|
+
logLevel: state.settingsPicker.logLevel,
|
|
9274
|
+
auditLevel: state.settingsPicker.auditLevel,
|
|
9275
|
+
indexOnStart: state.settingsPicker.indexOnStart,
|
|
9276
|
+
maxIterations: state.settingsPicker.maxIterations,
|
|
8650
9277
|
hint: state.settingsPicker.hint
|
|
8651
9278
|
}
|
|
8652
9279
|
) : null,
|
|
@@ -8679,8 +9306,7 @@ User message:
|
|
|
8679
9306
|
head.resolve(decision);
|
|
8680
9307
|
dispatch({ type: "confirmClose" });
|
|
8681
9308
|
};
|
|
8682
|
-
|
|
8683
|
-
return /* @__PURE__ */ jsx(Box, { ref: confirmRef, flexDirection: "column", marginY: 1, flexShrink: 0, children: /* @__PURE__ */ jsx(
|
|
9309
|
+
return /* @__PURE__ */ jsx(
|
|
8684
9310
|
ConfirmPrompt,
|
|
8685
9311
|
{
|
|
8686
9312
|
toolName: head.toolName,
|
|
@@ -8688,8 +9314,27 @@ User message:
|
|
|
8688
9314
|
suggestedPattern: head.suggestedPattern,
|
|
8689
9315
|
onDecision
|
|
8690
9316
|
}
|
|
8691
|
-
)
|
|
9317
|
+
);
|
|
8692
9318
|
})(),
|
|
9319
|
+
state.enhanceBusy && !state.enhance ? /* @__PURE__ */ jsx(Box, { paddingX: 1, children: /* @__PURE__ */ jsx(Text, { color: "cyan", children: "\u2728 refining your request\u2026" }) }) : null,
|
|
9320
|
+
state.enhance ? (() => {
|
|
9321
|
+
const info = state.enhance;
|
|
9322
|
+
let resolved = false;
|
|
9323
|
+
const onDecision = (decision) => {
|
|
9324
|
+
if (resolved) return;
|
|
9325
|
+
resolved = true;
|
|
9326
|
+
info.resolve(decision);
|
|
9327
|
+
};
|
|
9328
|
+
return /* @__PURE__ */ jsx(
|
|
9329
|
+
EnhancePanel,
|
|
9330
|
+
{
|
|
9331
|
+
original: info.original,
|
|
9332
|
+
refined: info.refined,
|
|
9333
|
+
delayMs: enhanceDelayMs,
|
|
9334
|
+
onDecision
|
|
9335
|
+
}
|
|
9336
|
+
);
|
|
9337
|
+
})() : null,
|
|
8693
9338
|
/* @__PURE__ */ jsx(
|
|
8694
9339
|
StatusBar,
|
|
8695
9340
|
{
|
|
@@ -8713,7 +9358,9 @@ User message:
|
|
|
8713
9358
|
processCount: getProcessRegistry().activeCount,
|
|
8714
9359
|
hiddenItems,
|
|
8715
9360
|
eternalStage: state.eternalStage,
|
|
8716
|
-
goalSummary: state.goalSummary
|
|
9361
|
+
goalSummary: state.goalSummary,
|
|
9362
|
+
indexState,
|
|
9363
|
+
modeLabel: liveModeLabel || void 0
|
|
8717
9364
|
}
|
|
8718
9365
|
),
|
|
8719
9366
|
managedLive ? /* @__PURE__ */ jsx(
|
|
@@ -8722,18 +9369,18 @@ User message:
|
|
|
8722
9369
|
context: {
|
|
8723
9370
|
confirm: state.confirmQueue.length > 0,
|
|
8724
9371
|
picker: state.picker.open || state.slashPicker.open || state.modelPicker.open || state.autonomyPicker.open || state.settingsPicker.open || !!state.rewindOverlay,
|
|
8725
|
-
monitor: state.agentsMonitorOpen || state.monitorOpen || state.worktreeMonitorOpen || !!state.autoPhase?.monitorOpen,
|
|
8726
|
-
managed: managedLive
|
|
8727
|
-
mouse: mouseLive
|
|
9372
|
+
monitor: state.agentsMonitorOpen || state.monitorOpen || state.worktreeMonitorOpen || state.todosMonitorOpen || !!state.autoPhase?.monitorOpen,
|
|
9373
|
+
managed: managedLive
|
|
8728
9374
|
}
|
|
8729
9375
|
}
|
|
8730
9376
|
) : null,
|
|
8731
|
-
state.helpOpen ? /* @__PURE__ */ jsx(HelpOverlay, { managed: managedLive
|
|
9377
|
+
state.helpOpen ? /* @__PURE__ */ jsx(HelpOverlay, { managed: managedLive }) : null,
|
|
8732
9378
|
state.agentsMonitorOpen ? /* @__PURE__ */ jsx(
|
|
8733
9379
|
AgentsMonitor,
|
|
8734
9380
|
{
|
|
8735
9381
|
entries: entriesWithLeader,
|
|
8736
9382
|
totalCost: state.fleetCost,
|
|
9383
|
+
leaderCost: tokenCounter?.estimateCost().total ?? 0,
|
|
8737
9384
|
totalTokens: state.fleetTokens,
|
|
8738
9385
|
nowTick
|
|
8739
9386
|
}
|
|
@@ -8754,12 +9401,13 @@ User message:
|
|
|
8754
9401
|
nowTick,
|
|
8755
9402
|
onClose: () => dispatch({ type: "worktreeMonitorToggle" })
|
|
8756
9403
|
}
|
|
8757
|
-
) : state.monitorOpen ? /* @__PURE__ */ jsx(
|
|
9404
|
+
) : state.todosMonitorOpen && !managedLive ? /* @__PURE__ */ jsx(TodosMonitor, { todos: agent.ctx.todos }) : state.monitorOpen ? /* @__PURE__ */ jsx(
|
|
8758
9405
|
FleetMonitor,
|
|
8759
9406
|
{
|
|
8760
9407
|
entries: state.fleet,
|
|
8761
9408
|
totalCost: state.fleetCost,
|
|
8762
9409
|
totalTokens: state.fleetTokens,
|
|
9410
|
+
maxConcurrent: state.fleetConcurrency,
|
|
8763
9411
|
nowTick,
|
|
8764
9412
|
collabSession: state.collabSession
|
|
8765
9413
|
}
|
|
@@ -8780,9 +9428,10 @@ User message:
|
|
|
8780
9428
|
nowTick
|
|
8781
9429
|
}
|
|
8782
9430
|
) : null,
|
|
8783
|
-
Object.keys(state.worktrees).length > 0 && !state.worktreeMonitorOpen && !state.monitorOpen ? /* @__PURE__ */ jsx(WorktreePanel, { worktrees: state.worktrees, nowTick }) : null
|
|
9431
|
+
Object.keys(state.worktrees).length > 0 && !state.worktreeMonitorOpen && !state.monitorOpen ? /* @__PURE__ */ jsx(WorktreePanel, { worktrees: state.worktrees, nowTick }) : null,
|
|
9432
|
+
state.queuePanelOpen ? /* @__PURE__ */ jsx(QueuePanel, { items: state.queue }) : null
|
|
8784
9433
|
] })
|
|
8785
|
-
] });
|
|
9434
|
+
] }) });
|
|
8786
9435
|
}
|
|
8787
9436
|
function renderRunningTools(running) {
|
|
8788
9437
|
if (running.size === 0) return "";
|
|
@@ -8816,48 +9465,6 @@ function fmtTok3(n) {
|
|
|
8816
9465
|
return `${(n / 1e6).toFixed(1)}M`;
|
|
8817
9466
|
}
|
|
8818
9467
|
|
|
8819
|
-
// src/mouse.ts
|
|
8820
|
-
var SGR_MOUSE_RE = /\x1b?\[<(\d+);(\d+);(\d+)([Mm])/g;
|
|
8821
|
-
function stripSgrMouse(s2) {
|
|
8822
|
-
return s2.replace(SGR_MOUSE_RE, "");
|
|
8823
|
-
}
|
|
8824
|
-
function parseSgrMouse(s2) {
|
|
8825
|
-
const events = [];
|
|
8826
|
-
for (const m of s2.matchAll(SGR_MOUSE_RE)) {
|
|
8827
|
-
const cb = Number.parseInt(m[1] ?? "", 10);
|
|
8828
|
-
const x = Number.parseInt(m[2] ?? "", 10);
|
|
8829
|
-
const y = Number.parseInt(m[3] ?? "", 10);
|
|
8830
|
-
const final = m[4];
|
|
8831
|
-
if (!Number.isFinite(cb) || !Number.isFinite(x) || !Number.isFinite(y)) continue;
|
|
8832
|
-
const isWheel = (cb & 64) !== 0;
|
|
8833
|
-
const drag = (cb & 32) !== 0;
|
|
8834
|
-
const low = cb & 3;
|
|
8835
|
-
let button;
|
|
8836
|
-
let type;
|
|
8837
|
-
if (isWheel) {
|
|
8838
|
-
type = "wheel";
|
|
8839
|
-
button = low === 0 ? "wheelUp" : low === 1 ? "wheelDown" : "other";
|
|
8840
|
-
} else if (final === "m") {
|
|
8841
|
-
type = "release";
|
|
8842
|
-
button = low === 0 ? "left" : low === 1 ? "middle" : low === 2 ? "right" : "other";
|
|
8843
|
-
} else {
|
|
8844
|
-
type = "press";
|
|
8845
|
-
button = low === 0 ? "left" : low === 1 ? "middle" : low === 2 ? "right" : "other";
|
|
8846
|
-
}
|
|
8847
|
-
events.push({
|
|
8848
|
-
type,
|
|
8849
|
-
button,
|
|
8850
|
-
x,
|
|
8851
|
-
y,
|
|
8852
|
-
shift: (cb & 4) !== 0,
|
|
8853
|
-
alt: (cb & 8) !== 0,
|
|
8854
|
-
ctrl: (cb & 16) !== 0,
|
|
8855
|
-
drag
|
|
8856
|
-
});
|
|
8857
|
-
}
|
|
8858
|
-
return events;
|
|
8859
|
-
}
|
|
8860
|
-
|
|
8861
9468
|
// src/terminal-title.ts
|
|
8862
9469
|
var SPINNER = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
8863
9470
|
var setTitle = (s2) => `\x1B]0;${s2}\x07`;
|
|
@@ -8927,8 +9534,6 @@ var BRACKETED_PASTE_OFF = "\x1B[?2004l";
|
|
|
8927
9534
|
var ALT_SCREEN_ON = "\x1B[?1049h";
|
|
8928
9535
|
var ALT_SCREEN_OFF = "\x1B[?1049l";
|
|
8929
9536
|
var CURSOR_HOME = "\x1B[H";
|
|
8930
|
-
var MOUSE_ON = "\x1B[?1000h\x1B[?1002h\x1B[?1006h";
|
|
8931
|
-
var MOUSE_OFF = "\x1B[?1006l\x1B[?1002l\x1B[?1000l";
|
|
8932
9537
|
async function runTui(opts) {
|
|
8933
9538
|
const stdout = process.stdout;
|
|
8934
9539
|
const stdin = process.stdin;
|
|
@@ -8938,108 +9543,15 @@ async function runTui(opts) {
|
|
|
8938
9543
|
);
|
|
8939
9544
|
return 2;
|
|
8940
9545
|
}
|
|
8941
|
-
const
|
|
8942
|
-
const useAltScreen = opts.altScreen === true || useMouse;
|
|
9546
|
+
const useAltScreen = opts.altScreen === true;
|
|
8943
9547
|
if (useAltScreen) {
|
|
8944
9548
|
stdout.write(ALT_SCREEN_ON);
|
|
8945
9549
|
stdout.write(CURSOR_HOME);
|
|
8946
9550
|
}
|
|
8947
9551
|
stdout.write(BRACKETED_PASTE_ON);
|
|
8948
|
-
|
|
8949
|
-
|
|
8950
|
-
}
|
|
8951
|
-
const mouseListeners = /* @__PURE__ */ new Set();
|
|
8952
|
-
let inkStdin = stdin;
|
|
8953
|
-
let detachMouse = null;
|
|
8954
|
-
if (useMouse) {
|
|
8955
|
-
class KeyboardReadable extends Readable {
|
|
8956
|
-
pendingChunks = [];
|
|
8957
|
-
// eslint-disable-next-line no-useless-constructor
|
|
8958
|
-
constructor() {
|
|
8959
|
-
super({ encoding: "utf8", highWaterMark: 64 * 1024 });
|
|
8960
|
-
}
|
|
8961
|
-
_read(_size) {
|
|
8962
|
-
this.flushPending();
|
|
8963
|
-
}
|
|
8964
|
-
flushPending() {
|
|
8965
|
-
while (this.pendingChunks.length > 0) {
|
|
8966
|
-
const chunk = this.pendingChunks[0];
|
|
8967
|
-
const ok = this.push(chunk);
|
|
8968
|
-
this.pendingChunks.shift();
|
|
8969
|
-
if (!ok) {
|
|
8970
|
-
break;
|
|
8971
|
-
}
|
|
8972
|
-
}
|
|
8973
|
-
}
|
|
8974
|
-
/** Called by the stdin data handler when keyboard bytes are available. */
|
|
8975
|
-
doPush(chunk) {
|
|
8976
|
-
if (chunk.length === 0) return;
|
|
8977
|
-
const ok = this.push(chunk);
|
|
8978
|
-
if (ok) {
|
|
8979
|
-
if (this.pendingChunks.length > 0) {
|
|
8980
|
-
this.flushPending();
|
|
8981
|
-
}
|
|
8982
|
-
} else {
|
|
8983
|
-
if (this.pendingChunks.length >= 100) {
|
|
8984
|
-
this.pendingChunks.shift();
|
|
8985
|
-
}
|
|
8986
|
-
this.pendingChunks.push(chunk);
|
|
8987
|
-
}
|
|
8988
|
-
}
|
|
8989
|
-
/** Called on shutdown so the stream closes cleanly. */
|
|
8990
|
-
doEnd() {
|
|
8991
|
-
this.pendingChunks = [];
|
|
8992
|
-
this.push(null);
|
|
8993
|
-
}
|
|
8994
|
-
}
|
|
8995
|
-
const keyboardStream = new KeyboardReadable();
|
|
8996
|
-
const p = keyboardStream;
|
|
8997
|
-
p.isTTY = true;
|
|
8998
|
-
p.setRawMode = (mode) => {
|
|
8999
|
-
try {
|
|
9000
|
-
stdin.setRawMode?.(mode);
|
|
9001
|
-
} catch {
|
|
9002
|
-
}
|
|
9003
|
-
return p;
|
|
9004
|
-
};
|
|
9005
|
-
const realRef = stdin.ref?.bind(stdin);
|
|
9006
|
-
const realUnref = stdin.unref?.bind(stdin);
|
|
9007
|
-
p.ref = () => {
|
|
9008
|
-
realRef?.();
|
|
9009
|
-
return p;
|
|
9010
|
-
};
|
|
9011
|
-
p.unref = () => {
|
|
9012
|
-
realUnref?.();
|
|
9013
|
-
return p;
|
|
9014
|
-
};
|
|
9015
|
-
stdin.setEncoding("utf8");
|
|
9016
|
-
const onData = (chunk) => {
|
|
9017
|
-
const evs = parseSgrMouse(chunk);
|
|
9018
|
-
for (const ev of evs) {
|
|
9019
|
-
for (const fn of mouseListeners) {
|
|
9020
|
-
try {
|
|
9021
|
-
fn(ev);
|
|
9022
|
-
} catch {
|
|
9023
|
-
}
|
|
9024
|
-
}
|
|
9025
|
-
}
|
|
9026
|
-
const rest = stripSgrMouse(chunk);
|
|
9027
|
-
keyboardStream.doPush(rest);
|
|
9028
|
-
};
|
|
9029
|
-
stdin.on("data", onData);
|
|
9030
|
-
detachMouse = () => {
|
|
9031
|
-
stdin.off("data", onData);
|
|
9032
|
-
keyboardStream.doEnd();
|
|
9033
|
-
};
|
|
9034
|
-
inkStdin = p;
|
|
9035
|
-
}
|
|
9036
|
-
const subscribeMouse = useMouse ? (fn) => {
|
|
9037
|
-
mouseListeners.add(fn);
|
|
9038
|
-
return () => {
|
|
9039
|
-
mouseListeners.delete(fn);
|
|
9040
|
-
};
|
|
9041
|
-
} : void 0;
|
|
9042
|
-
const stopTitle = startTerminalTitle({ stdout, events: opts.events, model: opts.model });
|
|
9552
|
+
const inkStdin = stdin;
|
|
9553
|
+
const stopTitle = opts.titleAnimation !== false ? startTerminalTitle({ stdout, events: opts.events, model: opts.model }) : (() => {
|
|
9554
|
+
});
|
|
9043
9555
|
const swallowSignals = ["SIGTSTP", "SIGQUIT", "SIGTTIN", "SIGTTOU"];
|
|
9044
9556
|
const swallow = () => {
|
|
9045
9557
|
};
|
|
@@ -9057,15 +9569,8 @@ async function runTui(opts) {
|
|
|
9057
9569
|
stopTitle();
|
|
9058
9570
|
} catch {
|
|
9059
9571
|
}
|
|
9060
|
-
try {
|
|
9061
|
-
detachMouse?.();
|
|
9062
|
-
} catch {
|
|
9063
|
-
}
|
|
9064
9572
|
try {
|
|
9065
9573
|
stdout.write(BRACKETED_PASTE_OFF);
|
|
9066
|
-
if (useMouse) {
|
|
9067
|
-
stdout.write(MOUSE_OFF);
|
|
9068
|
-
}
|
|
9069
9574
|
if (useAltScreen) {
|
|
9070
9575
|
stdout.write(ALT_SCREEN_OFF);
|
|
9071
9576
|
}
|
|
@@ -9138,6 +9643,8 @@ async function runTui(opts) {
|
|
|
9138
9643
|
fleetRoster: opts.fleetRoster,
|
|
9139
9644
|
onClearHistory: opts.onClearHistory ? (dispatch) => opts.onClearHistory(dispatch) : void 0,
|
|
9140
9645
|
fleetStreamController: opts.fleetStreamController,
|
|
9646
|
+
enhanceController: opts.enhanceController,
|
|
9647
|
+
enhanceEnabled: opts.enhanceController?.enabled ?? true,
|
|
9141
9648
|
statuslineHiddenItems: opts.statuslineHiddenItems,
|
|
9142
9649
|
setStatuslineHiddenItems: opts.setStatuslineHiddenItems,
|
|
9143
9650
|
agentsMonitorController: opts.agentsMonitorController,
|
|
@@ -9150,12 +9657,13 @@ async function runTui(opts) {
|
|
|
9150
9657
|
getSettings: opts.getSettings,
|
|
9151
9658
|
saveSettings: opts.saveSettings,
|
|
9152
9659
|
predictNext: opts.predictNext,
|
|
9153
|
-
mouse: useMouse,
|
|
9154
|
-
subscribeMouse,
|
|
9155
9660
|
// Managed viewport (in-app scroll + collapsibility) follows
|
|
9156
|
-
// alt-screen: it owns the screen, so there's no native-scrollback
|
|
9157
|
-
|
|
9158
|
-
|
|
9661
|
+
// alt-screen: it owns the screen, so there's no native-scrollback leak.
|
|
9662
|
+
managed: useAltScreen,
|
|
9663
|
+
chime: opts.chime,
|
|
9664
|
+
confirmExit: opts.confirmExit,
|
|
9665
|
+
modeLabel: opts.modeLabel,
|
|
9666
|
+
getModeLabel: opts.getModeLabel
|
|
9159
9667
|
}),
|
|
9160
9668
|
{ exitOnCtrlC: false, stdin: inkStdin }
|
|
9161
9669
|
);
|