@wrongstack/tui 0.73.1 → 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/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
- 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';
2
2
  export { buildGoalPreamble } from '@wrongstack/core';
3
3
  import { Box, Text, render, useApp, useStdout, measureElement, Static, useInput, useStdin } from 'ink';
4
- import React5, { useState, useEffect, useReducer, useRef, useMemo, useCallback, useLayoutEffect } from 'react';
4
+ import React6, { useState, useEffect, useReducer, useRef, useMemo, useCallback, useLayoutEffect } from 'react';
5
5
  import * as fs2 from 'fs/promises';
6
6
  import * as path2 from 'path';
7
7
  import { routeImagesForModel } from '@wrongstack/runtime/vision';
8
- import { getProcessRegistry } from '@wrongstack/tools';
8
+ import { getIndexState, onIndexStateChange, getProcessRegistry } from '@wrongstack/tools';
9
9
  import { readClipboardImage } from '@wrongstack/runtime/clipboard';
10
10
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
11
11
  import { spawn } from 'child_process';
@@ -34,8 +34,28 @@ var theme = Object.freeze({
34
34
  diffAddBg: "greenBright",
35
35
  diffDelBg: "redBright"
36
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
+ }
37
55
  var COMPACT_THRESHOLD = 50;
38
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;
39
59
  function StatusBar({
40
60
  model,
41
61
  version,
@@ -58,7 +78,9 @@ function StatusBar({
58
78
  processCount,
59
79
  hiddenItems,
60
80
  eternalStage,
61
- goalSummary
81
+ goalSummary,
82
+ indexState,
83
+ modeLabel
62
84
  }) {
63
85
  const { stdout } = useStdout();
64
86
  const [termWidth, setTermWidth] = useState(stdout?.columns ?? 90);
@@ -76,8 +98,19 @@ function StatusBar({
76
98
  const usage = tokenCounter?.total();
77
99
  const cost = tokenCounter?.estimateCost();
78
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];
79
111
  const { label: stateLabel, color: stateColor } = stateChip(state, fleet?.running ?? 0);
80
- 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;
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;
81
114
  const fleetHasActivity = fleet && (fleet.running > 0 || fleet.idle > 0 || fleet.pending > 0 || fleet.completed > 0) || subagentCount > 0;
82
115
  const hasBrainActivity = !!brain && brain.state !== "idle";
83
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;
@@ -96,7 +129,7 @@ function StatusBar({
96
129
  // Ultra-compact: state · model
97
130
  /* @__PURE__ */ jsxs(Fragment, { children: [
98
131
  /* @__PURE__ */ jsxs(Text, { color: stateColor, children: [
99
- "\u25CF",
132
+ statePrefix,
100
133
  stateLabel
101
134
  ] }),
102
135
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7" }),
@@ -116,7 +149,8 @@ function StatusBar({
116
149
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" })
117
150
  ] }) : null,
118
151
  /* @__PURE__ */ jsxs(Text, { color: stateColor, children: [
119
- "\u25CF ",
152
+ statePrefix,
153
+ " ",
120
154
  stateLabel
121
155
  ] }),
122
156
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
@@ -170,6 +204,15 @@ function StatusBar({
170
204
  hint ? /* @__PURE__ */ jsxs(Fragment, { children: [
171
205
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
172
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
+ ] })
173
216
  ] }) : null
174
217
  ] })
175
218
  ) }),
@@ -227,6 +270,10 @@ function StatusBar({
227
270
  }
228
271
  )
229
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,
230
277
  git ? /* @__PURE__ */ jsxs(Fragment, { children: [
231
278
  yolo || elapsedMs !== void 0 || projectName ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
232
279
  /* @__PURE__ */ jsxs(Text, { children: [
@@ -248,7 +295,7 @@ function StatusBar({
248
295
  ] }) : null
249
296
  ] })
250
297
  ] }) : null
251
- ] }) : null,
298
+ ] }) : /* @__PURE__ */ jsx(Box, { height: 1, children: /* @__PURE__ */ jsx(Text, { children: " " }) }),
252
299
  hasThirdLine ? /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 2, children: [
253
300
  todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0) ? /* @__PURE__ */ jsxs(Text, { children: [
254
301
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "todos " }),
@@ -322,7 +369,7 @@ function StatusBar({
322
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,
323
370
  /* @__PURE__ */ jsx(BrainChip, { brain })
324
371
  ] }) : null
325
- ] }) : null,
372
+ ] }) : /* @__PURE__ */ jsx(Box, { height: 1, children: /* @__PURE__ */ jsx(Text, { children: " " }) }),
326
373
  fleetAgents && fleetAgents.length > 0 ? /* @__PURE__ */ jsx(Box, { flexDirection: "row", gap: 2, children: fleetAgents.map((a, i) => (
327
374
  // biome-ignore lint/suspicious/noArrayIndexKey: agent list is stable per render
328
375
  /* @__PURE__ */ jsxs(Text, { children: [
@@ -348,7 +395,7 @@ function StatusBar({
348
395
  ] })
349
396
  ] }) : null
350
397
  ] }, i)
351
- )) }) : null
398
+ )) }) : /* @__PURE__ */ jsx(Box, { height: 1, children: /* @__PURE__ */ jsx(Text, { children: " " }) })
352
399
  ]
353
400
  }
354
401
  );
@@ -779,10 +826,12 @@ function ContextBar({
779
826
  function AgentsMonitor({
780
827
  entries,
781
828
  totalCost,
829
+ leaderCost = 0,
782
830
  totalTokens,
783
831
  nowTick
784
832
  }) {
785
833
  const all = Object.values(entries);
834
+ const grandCost = leaderCost + totalCost;
786
835
  const live = selectLiveAgents(all, nowTick);
787
836
  const running = live.filter((e) => e.status === "running").length;
788
837
  const totalDone = all.filter((e) => e.status === "success").length;
@@ -824,9 +873,17 @@ function AgentsMonitor({
824
873
  fmtTokens2(totalTokens.output),
825
874
  "\u2193"
826
875
  ] }) : null,
827
- /* @__PURE__ */ jsxs(Text, { color: "green", children: [
876
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "total" }),
877
+ /* @__PURE__ */ jsxs(Text, { color: "green", bold: true, children: [
828
878
  "$",
829
- totalCost.toFixed(3)
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
+ ")"
830
887
  ] }),
831
888
  hiddenIdle > 0 ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
832
889
  "\xB7 ",
@@ -869,6 +926,10 @@ function AgentsMonitor({
869
926
  e.extensions && e.extensions > 0 ? /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
870
927
  "\u26A1\xD7",
871
928
  e.extensions
929
+ ] }) : null,
930
+ e.cost > 0 ? /* @__PURE__ */ jsxs(Text, { color: "green", children: [
931
+ "$",
932
+ e.cost.toFixed(3)
872
933
  ] }) : null
873
934
  ] }),
874
935
  e.status === "running" && e.currentTool ? /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, paddingLeft: 2, children: [
@@ -954,7 +1015,7 @@ function AutonomyPicker({
954
1015
  selected,
955
1016
  hint
956
1017
  }) {
957
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 1, children: [
1018
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "magenta", paddingX: 1, children: [
958
1019
  /* @__PURE__ */ jsx(Text, { color: "cyan", bold: true, children: "\u2501\u2501 Autonomy Mode \u2501\u2501" }),
959
1020
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 navigate \xB7 Enter select \xB7 Esc cancel \xB7 Ctrl+C exit" }),
960
1021
  options.map((opt, i) => /* @__PURE__ */ jsxs(
@@ -1077,7 +1138,7 @@ function CheckpointTimeline({
1077
1138
  onConfirm(selected);
1078
1139
  }
1079
1140
  });
1080
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", padding: 1, children: [
1141
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", padding: 1, children: [
1081
1142
  /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
1082
1143
  /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "\u27F2 Session Rewind" }),
1083
1144
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: " \u2014 \u2191/\u2193 navigate \xB7 Enter rewind \xB7 Esc cancel" })
@@ -1147,7 +1208,7 @@ function ConfirmPrompt({
1147
1208
  suggestedPattern,
1148
1209
  onDecision
1149
1210
  }) {
1150
- React5.useEffect(() => {
1211
+ React6.useEffect(() => {
1151
1212
  writeOut("\x07");
1152
1213
  }, []);
1153
1214
  useInput((input2, _key) => {
@@ -1176,21 +1237,82 @@ function ConfirmPrompt({
1176
1237
  inputSummary ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: inputSummary }) : null,
1177
1238
  showDiff && diff ? /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginY: 1, children: renderDiff(diff) }) : null,
1178
1239
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }),
1179
- /* @__PURE__ */ jsx(Box, { flexDirection: "row", children: /* @__PURE__ */ jsx(Text, { children: buttonLabels(suggestedPattern).map((l) => /* @__PURE__ */ jsxs(React5.Fragment, { children: [
1240
+ /* @__PURE__ */ jsx(Box, { flexDirection: "row", children: /* @__PURE__ */ jsx(Text, { children: buttonLabels(suggestedPattern).map((l) => /* @__PURE__ */ jsxs(React6.Fragment, { children: [
1180
1241
  /* @__PURE__ */ jsx(Text, { bold: true, color: BUTTON_COLOR[l.decision], children: l.bracket }),
1181
1242
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: l.rest })
1182
1243
  ] }, l.decision)) }) })
1183
1244
  ] });
1184
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
+ }
1185
1307
  function FilePicker({ query, matches, selected }) {
1186
1308
  if (matches.length === 0) {
1187
- 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: [
1188
1310
  "@",
1189
1311
  query,
1190
1312
  " \u2014 no matches"
1191
1313
  ] }) });
1192
1314
  }
1193
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 1, children: [
1315
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [
1194
1316
  /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1195
1317
  "@",
1196
1318
  query || "\u2026",
@@ -1285,6 +1407,9 @@ function helpSections(opts) {
1285
1407
  { keys: "Ctrl+F / F2", desc: "fleet orchestration monitor" },
1286
1408
  { keys: "Ctrl+G / F3", desc: "agents live monitor" },
1287
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" },
1288
1413
  { keys: "Esc", desc: "close the open monitor / overlay" }
1289
1414
  ]
1290
1415
  },
@@ -1860,8 +1985,9 @@ function computeWidths(allRows, cols, maxWidth, sepWidths) {
1860
1985
  for (const row of allRows) {
1861
1986
  for (let c = 0; c < cols; c++) {
1862
1987
  const cell = row[c] ?? "";
1863
- const w = longestWord(cell);
1864
- const total = strWidth(cell);
1988
+ const stripped = stripInlineMarkers(cell);
1989
+ const w = longestWord(stripped);
1990
+ const total = strWidth(stripped);
1865
1991
  natural[c] = Math.max(natural[c], w, total);
1866
1992
  }
1867
1993
  }
@@ -1894,11 +2020,77 @@ function computeWidths(allRows, cols, maxWidth, sepWidths) {
1894
2020
  return widths;
1895
2021
  }
1896
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
+ }
1897
2059
  function strWidth(s2) {
1898
2060
  let width = 0;
1899
- for (const cp of s2) {
1900
- const code = cp.codePointAt(0);
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
+ }
1901
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;
1902
2094
  continue;
1903
2095
  }
1904
2096
  if (code >= 126976 || // Supplementary Pictographs (U+1F000-U+1FFFF)
@@ -1911,11 +2103,11 @@ function strWidth(s2) {
1911
2103
  code >= 9664 && code <= 9726 || // More Geometric Shapes (includes ▶)
1912
2104
  code >= 9984 && code <= 10175) {
1913
2105
  width += 2;
2106
+ i += cpLen;
1914
2107
  continue;
1915
2108
  }
1916
2109
  if (code >= 4352 && code <= 4447 || // Hangul Jamo
1917
- code === 9001 || // LEFT-POINTING ANGLE BRACKET
1918
- code === 9002 || // RIGHT-POINTING ANGLE BRACKET
2110
+ code === 9001 || code === 9002 || // Angle brackets
1919
2111
  code >= 11904 && code <= 12350 || // CJK Radicals Supplement
1920
2112
  code >= 12352 && code <= 42191 || // Hiragana, Katakana, CJK
1921
2113
  code >= 44032 && code <= 55203 || // Hangul Syllables
@@ -1927,9 +2119,11 @@ function strWidth(s2) {
1927
2119
  code >= 131072 && code <= 196605 || // CJK Extension B+
1928
2120
  code >= 196608 && code <= 262141) {
1929
2121
  width += 2;
2122
+ i += cpLen;
1930
2123
  continue;
1931
2124
  }
1932
2125
  width += 1;
2126
+ i += cpLen;
1933
2127
  }
1934
2128
  return width;
1935
2129
  }
@@ -1944,8 +2138,22 @@ function longestWord(s2) {
1944
2138
  function border(left, mid, right, widths) {
1945
2139
  return left + widths.map((w) => "\u2500".repeat(w + 2)).join(mid) + right;
1946
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
+ }
1947
2153
  function renderRow(cells, widths, aligns) {
1948
- const wrapped = cells.map((c, i) => wrapCell(c, widths[i] ?? MIN_COL_WIDTH));
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));
1949
2157
  const height = Math.max(1, ...wrapped.map((w) => w.length));
1950
2158
  const out = [];
1951
2159
  for (let line = 0; line < height; line++) {
@@ -2730,7 +2938,7 @@ function formatToolOutput(toolName, output, ok, _outputBytes, outputLines) {
2730
2938
  }
2731
2939
  var MAX_STREAM_DISPLAY_CHARS = 480;
2732
2940
  var MAX_STREAM_LINES = 8;
2733
- var ToolStreamBox = React5.memo(function ToolStreamBox2({
2941
+ var ToolStreamBox = React6.memo(function ToolStreamBox2({
2734
2942
  name,
2735
2943
  text,
2736
2944
  startedAt,
@@ -3050,7 +3258,7 @@ function brainRiskColor(risk) {
3050
3258
  function assistantContentWidth(termWidth) {
3051
3259
  return Math.max(20, termWidth - MESSAGE_PANEL_CHROME_WIDTH);
3052
3260
  }
3053
- var Entry = React5.memo(function Entry2({
3261
+ var Entry = React6.memo(function Entry2({
3054
3262
  entry,
3055
3263
  termWidth
3056
3264
  }) {
@@ -3442,6 +3650,11 @@ function isHomeEnd(data) {
3442
3650
  return "end";
3443
3651
  return null;
3444
3652
  }
3653
+ function isBackspaceOrDelete(data) {
3654
+ if (data === "\x7F" || data === "\b") return "backspace";
3655
+ if (data === "\x1B[3~") return "delete";
3656
+ return null;
3657
+ }
3445
3658
  var EMPTY_KEY = {
3446
3659
  upArrow: false,
3447
3660
  downArrow: false,
@@ -3477,15 +3690,24 @@ function Input({
3477
3690
  if (!stdin || disabled) return;
3478
3691
  const handleData = (data) => {
3479
3692
  const s2 = data.toString();
3480
- const kind = isHomeEnd(s2);
3481
- if (kind === "home") {
3693
+ const homeEnd = isHomeEnd(s2);
3694
+ if (homeEnd === "home") {
3482
3695
  onKey("", { ...EMPTY_KEY, home: true });
3483
3696
  return;
3484
3697
  }
3485
- if (kind === "end") {
3698
+ if (homeEnd === "end") {
3486
3699
  onKey("", { ...EMPTY_KEY, end: true });
3487
3700
  return;
3488
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
+ }
3489
3711
  const fn = fnKey(s2);
3490
3712
  if (fn !== null) onKey("", { ...EMPTY_KEY, fn });
3491
3713
  };
@@ -3541,11 +3763,12 @@ function hintsFor(ctx) {
3541
3763
  { key: "Esc", label: "close" },
3542
3764
  { key: "^F", label: "fleet" },
3543
3765
  { key: "^G", label: "agents" },
3544
- { key: "^T", label: "worktrees" }
3766
+ { key: "^T", label: "worktrees" },
3767
+ { key: "F6", label: "todos" }
3545
3768
  ];
3546
3769
  }
3547
3770
  const base = [{ key: "?", label: "help" }];
3548
- if (ctx.managed) base.push({ key: "PgUp/PgDn", label: "scroll" });
3771
+ if (ctx.managed) base.push({ key: "PgUp/PgDn", label: "scroll" }, { key: "F5", label: "Settings" });
3549
3772
  base.push({ key: "^G", label: "agents" }, { key: "^C", label: "stop" });
3550
3773
  return base;
3551
3774
  }
@@ -3585,13 +3808,16 @@ function fmtRecentMessage(message) {
3585
3808
  const text = message.text.replace(/\s+/g, " ");
3586
3809
  return text.length > 48 ? `${text.slice(0, 47)}...` : text;
3587
3810
  }
3588
- var LiveActivityStrip = React5.memo(function LiveActivityStrip2({
3811
+ var LiveActivityStrip = React6.memo(function LiveActivityStrip2({
3589
3812
  entries,
3590
3813
  nowTick,
3591
3814
  maxRows = 4
3592
3815
  }) {
3593
3816
  const running = Object.values(entries).filter((e) => e.status === "running").sort((a, b) => a.startedAt - b.startedAt).slice(0, maxRows);
3594
- if (running.length === 0) return null;
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
+ }
3595
3821
  const now = Date.now();
3596
3822
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 1, children: [
3597
3823
  running.map((e) => {
@@ -3661,7 +3887,7 @@ function ModelPicker({
3661
3887
  hint
3662
3888
  }) {
3663
3889
  if (step === "provider") {
3664
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 1, children: [
3890
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
3665
3891
  /* @__PURE__ */ jsx(Text, { color: "cyan", bold: true, children: "\u2501\u2501 Switch model \u2014 Step 1/2: Pick provider \u2501\u2501" }),
3666
3892
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 navigate \xB7 Enter select \xB7 Esc cancel \xB7 Ctrl+C exit" }),
3667
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: [
@@ -3686,7 +3912,7 @@ function ModelPicker({
3686
3912
  const { start, end } = getVisibleWindow(selected, total);
3687
3913
  const visibleItems = filteredOptions.slice(start, end);
3688
3914
  const searchHint = searchQuery ? ` | filter:"${searchQuery}" \u2192 ${total} match${total === 1 ? "" : "es"}` : total > MAX_VISIBLE ? ` (${total} models \u2014 type to filter)` : "";
3689
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 1, children: [
3915
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
3690
3916
  /* @__PURE__ */ jsxs(Text, { color: "cyan", bold: true, children: [
3691
3917
  "\u2501\u2501 Switch model \u2014 Step 2/2: Pick model ",
3692
3918
  "(",
@@ -3901,6 +4127,52 @@ function PhasePanel({ phases, nowTick }) {
3901
4127
  }
3902
4128
  );
3903
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
+ }
3904
4176
  var MAX_MOUNTED = 500;
3905
4177
  function scrollbarThumb(rows, offset, total) {
3906
4178
  const scrollable = total > rows;
@@ -3938,17 +4210,12 @@ function ScrollableHistory({
3938
4210
  scrollOffset,
3939
4211
  viewportRows,
3940
4212
  totalLines,
3941
- onMeasure
4213
+ onMeasure,
4214
+ maxWidth
3942
4215
  }) {
3943
4216
  const { stdout } = useStdout();
3944
- const [termWidth, setTermWidth] = useState(stdout?.columns ?? 80);
3945
- useEffect(() => {
3946
- const onResize = () => setTermWidth(stdout?.columns ?? 80);
3947
- process.stdout.on("resize", onResize);
3948
- return () => {
3949
- process.stdout.off("resize", onResize);
3950
- };
3951
- }, [stdout]);
4217
+ const rawWidth = stdout?.columns ?? 80;
4218
+ const termWidth = maxWidth ? Math.min(rawWidth, maxWidth) : rawWidth;
3952
4219
  const tail = streamingText ? tailForDisplay(streamingText, MAX_STREAM_DISPLAY_CHARS) : "";
3953
4220
  const toolTail = toolStream?.text ? tailForDisplay(toolStream.text, MAX_STREAM_DISPLAY_CHARS) : "";
3954
4221
  const hiddenCount = Math.max(0, entries.length - MAX_MOUNTED);
@@ -4004,46 +4271,221 @@ function ScrollableHistory({
4004
4271
  }
4005
4272
  var DELAY_PRESETS_MS = [0, 15e3, 3e4, 45e3, 6e4, 12e4];
4006
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];
4007
4278
  function formatSettingsDelay(ms) {
4008
4279
  if (ms === 0) return "disabled";
4009
4280
  if (ms >= 6e4) return `${Math.round(ms / 6e4)}m`;
4010
4281
  return `${Math.round(ms / 1e3)}s`;
4011
4282
  }
4283
+ function formatMaxIterations(n) {
4284
+ if (n === 0) return "unlimited";
4285
+ return String(n);
4286
+ }
4012
4287
  var MODE_DESC = {
4013
4288
  off: "Agent stops after each turn (normal)",
4014
4289
  suggest: "Shows next-step suggestions after each turn",
4015
4290
  auto: "Self-driving \u2014 agent continues automatically"
4016
4291
  };
4292
+ var SETTINGS_FIELD_COUNT = 19;
4017
4293
  function SettingsPicker({
4018
4294
  field,
4019
4295
  mode,
4020
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,
4021
4314
  hint
4022
4315
  }) {
4316
+ const boolVal = (v) => v ? "on" : "off";
4023
4317
  const rows = [
4318
+ // ── Autonomy ──
4319
+ { section: "Autonomy" },
4024
4320
  { label: "Default autonomy mode", value: mode, detail: MODE_DESC[mode] },
4025
4321
  {
4026
4322
  label: "Auto-proceed delay",
4027
4323
  value: formatSettingsDelay(delayMs),
4028
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)"
4029
4424
  }
4030
4425
  ];
4031
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 1, children: [
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: [
4032
4457
  /* @__PURE__ */ jsx(Text, { color: "cyan", bold: true, children: "\u2501\u2501 Settings \u2501\u2501" }),
4033
4458
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 field \xB7 \u2190/\u2192 change \xB7 Enter save \xB7 Esc cancel" }),
4034
- rows.map((row, i) => /* @__PURE__ */ jsxs(Text, { color: i === field ? "yellow" : void 0, inverse: i === field, children: [
4035
- i === field ? "\u203A " : " ",
4036
- /* @__PURE__ */ jsx(Text, { bold: true, children: row.label.padEnd(22) }),
4037
- /* @__PURE__ */ jsx(Text, { color: "cyan", children: String(row.value).padEnd(10) }),
4038
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: row.detail })
4039
- ] }, row.label)),
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,
4040
4482
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Persisted to ~/.wrongstack/config.json" }),
4041
4483
  hint ? /* @__PURE__ */ jsx(Text, { color: "yellow", children: hint }) : null
4042
4484
  ] });
4043
4485
  }
4044
4486
  function SlashMenu({ query, matches, selected }) {
4045
4487
  const placeholder = query ? `/${query}` : "/";
4046
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 1, children: [
4488
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [
4047
4489
  /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
4048
4490
  placeholder || "/",
4049
4491
  " \u2014 \u2191/\u2193 select, Enter dispatch, Tab autocomplete, Esc close"
@@ -4063,6 +4505,110 @@ function SlashMenu({ query, matches, selected }) {
4063
4505
  matches.length === 0 && /* @__PURE__ */ jsx(Text, { dimColor: true, children: "No matching commands" })
4064
4506
  ] });
4065
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
+ }
4066
4612
  var fmtElapsed5 = (ms) => {
4067
4613
  const s2 = Math.floor(ms / 1e3);
4068
4614
  const m = Math.floor(s2 / 60);
@@ -4395,6 +4941,34 @@ function runGit(cwd, args) {
4395
4941
  }
4396
4942
  });
4397
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
+ }
4398
4972
  var STREAM_COLORS = ["cyan", "magenta", "yellow", "green", "blue"];
4399
4973
  function labelFor(labelsRef, id, name) {
4400
4974
  const m = labelsRef.current;
@@ -4493,34 +5067,6 @@ function useSubagentEvents(events, dispatch, setActiveMaxContext) {
4493
5067
  };
4494
5068
  }, [events, dispatch, setActiveMaxContext, lbl]);
4495
5069
  }
4496
- function useBrainEvents(events, dispatch) {
4497
- useEffect(() => {
4498
- const requestSummary = (request) => `${request.source}: ${request.question}`.slice(0, 80);
4499
- const addBrainEntry = (status, payload) => {
4500
- const p = payload;
4501
- const decision = p.decision.optionId ?? p.decision.text ?? p.decision.reason ?? p.decision.prompt ?? p.decision.type;
4502
- dispatch({ type: "brainStatus", state: status, source: p.request.source, risk: p.request.risk, summary: decision });
4503
- if (status === "ask_human") {
4504
- 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 } });
4505
- } else {
4506
- dispatch({ type: "brainPromptClear" });
4507
- }
4508
- dispatch({ type: "addEntry", entry: { kind: "brain", status, source: p.request.source, risk: p.request.risk, question: p.request.question, decision, rationale: p.decision.rationale } });
4509
- };
4510
- const offRequested = events.on("brain.decision_requested", ({ request }) => {
4511
- dispatch({ type: "brainStatus", state: "deciding", source: request.source, risk: request.risk, summary: requestSummary(request) });
4512
- });
4513
- const offAnswered = events.on("brain.decision_answered", (payload) => addBrainEntry("answered", payload));
4514
- const offAskHuman = events.on("brain.decision_ask_human", (payload) => addBrainEntry("ask_human", payload));
4515
- const offDenied = events.on("brain.decision_denied", (payload) => addBrainEntry("denied", payload));
4516
- return () => {
4517
- offRequested();
4518
- offAnswered();
4519
- offAskHuman();
4520
- offDenied();
4521
- };
4522
- }, [events, dispatch]);
4523
- }
4524
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";
4525
5071
  function createKillSlashCommand() {
4526
5072
  return {
@@ -4803,7 +5349,22 @@ function reducer(state, action) {
4803
5349
  queue: [],
4804
5350
  nextQueueId: 1,
4805
5351
  scrollOffset: 0,
4806
- 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
+ }
4807
5368
  };
4808
5369
  }
4809
5370
  case "streamDelta":
@@ -5084,6 +5645,23 @@ function reducer(state, action) {
5084
5645
  field: 0,
5085
5646
  mode: action.mode,
5086
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,
5087
5665
  hint: void 0
5088
5666
  }
5089
5667
  };
@@ -5093,37 +5671,68 @@ function reducer(state, action) {
5093
5671
  settingsPicker: { ...state.settingsPicker, open: false, hint: void 0 }
5094
5672
  };
5095
5673
  case "settingsFieldMove": {
5096
- const next = (state.settingsPicker.field + action.delta + 2) % 2;
5674
+ const next = (state.settingsPicker.field + action.delta + SETTINGS_FIELD_COUNT) % SETTINGS_FIELD_COUNT;
5097
5675
  return {
5098
5676
  ...state,
5099
5677
  settingsPicker: { ...state.settingsPicker, field: next, hint: void 0 }
5100
5678
  };
5101
5679
  }
5102
5680
  case "settingsFieldSet": {
5103
- const field = action.field === 1 ? 1 : 0;
5681
+ const field = action.field >= 0 && action.field < SETTINGS_FIELD_COUNT ? action.field : 0;
5104
5682
  return { ...state, settingsPicker: { ...state.settingsPicker, field, hint: void 0 } };
5105
5683
  }
5106
5684
  case "settingsValueChange": {
5107
- if (state.settingsPicker.field === 0) {
5108
- const i = SETTINGS_MODES.indexOf(state.settingsPicker.mode);
5109
- const base2 = i < 0 ? 0 : i;
5110
- const next2 = (base2 + action.delta + SETTINGS_MODES.length) % SETTINGS_MODES.length;
5111
- return {
5112
- ...state,
5113
- settingsPicker: { ...state.settingsPicker, mode: SETTINGS_MODES[next2], hint: void 0 }
5114
- };
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 } };
5115
5735
  }
5116
- const j = DELAY_PRESETS_MS.indexOf(state.settingsPicker.delayMs);
5117
- const base = j < 0 ? 0 : j;
5118
- const next = (base + action.delta + DELAY_PRESETS_MS.length) % DELAY_PRESETS_MS.length;
5119
- return {
5120
- ...state,
5121
- settingsPicker: {
5122
- ...state.settingsPicker,
5123
- delayMs: DELAY_PRESETS_MS[next],
5124
- hint: void 0
5125
- }
5126
- };
5127
5736
  }
5128
5737
  case "settingsHint":
5129
5738
  return { ...state, settingsPicker: { ...state.settingsPicker, hint: action.text } };
@@ -5131,6 +5740,14 @@ function reducer(state, action) {
5131
5740
  return { ...state, confirmQueue: [...state.confirmQueue, action.info] };
5132
5741
  case "confirmClose":
5133
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 };
5134
5751
  case "resetContextChip":
5135
5752
  return { ...state, contextChipVersion: state.contextChipVersion + 1 };
5136
5753
  // --- Fleet ---
@@ -5362,8 +5979,24 @@ function reducer(state, action) {
5362
5979
  };
5363
5980
  }
5364
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
+ }
5365
5997
  return {
5366
5998
  ...state,
5999
+ fleet,
5367
6000
  fleetCost: action.cost,
5368
6001
  fleetTokens: action.input !== void 0 || action.output !== void 0 ? {
5369
6002
  input: action.input ?? state.fleetTokens.input,
@@ -5442,6 +6075,12 @@ function reducer(state, action) {
5442
6075
  case "toggleHelp": {
5443
6076
  return { ...state, helpOpen: !state.helpOpen };
5444
6077
  }
6078
+ case "toggleTodosMonitor": {
6079
+ return { ...state, todosMonitorOpen: !state.todosMonitorOpen };
6080
+ }
6081
+ case "toggleQueuePanel": {
6082
+ return { ...state, queuePanelOpen: !state.queuePanelOpen };
6083
+ }
5445
6084
  case "checkpointReceived": {
5446
6085
  const existing = state.checkpoints.find((c) => c.promptIndex === action.cp.promptIndex);
5447
6086
  if (existing) return state;
@@ -5747,6 +6386,21 @@ function selectedSlashCommandLine(picker) {
5747
6386
  const picked = picker.matches[picker.selected];
5748
6387
  return picked ? `/${picked.name}` : null;
5749
6388
  }
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
+ }
6401
+ }
6402
+ return entries;
6403
+ }
5750
6404
  var PASTE_THRESHOLD_CHARS = 200;
5751
6405
  function App({
5752
6406
  agent,
@@ -5760,6 +6414,11 @@ function App({
5760
6414
  banner = true,
5761
6415
  queueStore,
5762
6416
  yolo = false,
6417
+ chime = false,
6418
+ confirmExit = true,
6419
+ enhanceEnabled = true,
6420
+ enhanceController,
6421
+ enhanceDelayMs = 4e3,
5763
6422
  getYolo,
5764
6423
  getAutonomy,
5765
6424
  getEternalEngine,
@@ -5791,7 +6450,9 @@ function App({
5791
6450
  initialGoal,
5792
6451
  initialAsk,
5793
6452
  sessionsDir,
5794
- managed = false
6453
+ managed = false,
6454
+ modeLabel,
6455
+ getModeLabel
5795
6456
  }) {
5796
6457
  const { exit } = useApp();
5797
6458
  const [liveModel, setLiveModel] = useState(model);
@@ -5799,7 +6460,13 @@ function App({
5799
6460
  const [activeMaxContext, setActiveMaxContext] = useState(effectiveMaxContext);
5800
6461
  const [yoloLive, setYoloLive] = useState(yolo);
5801
6462
  const [autonomyLive, setAutonomyLive] = useState(getAutonomy?.() ?? "off");
6463
+ const [liveModeLabel, setLiveModeLabel] = useState(modeLabel ?? "");
5802
6464
  const [hiddenItems, setHiddenItems] = useState(statuslineHiddenItems);
6465
+ const [indexState, setIndexState] = useState(() => getIndexState());
6466
+ useEffect(() => {
6467
+ setIndexState(getIndexState());
6468
+ return onIndexStateChange((next) => setIndexState(next));
6469
+ }, []);
5803
6470
  const { stdout } = useStdout();
5804
6471
  const [termRows, setTermRows] = useState(stdout?.rows ?? 24);
5805
6472
  useEffect(() => {
@@ -5840,19 +6507,34 @@ function App({
5840
6507
  }).catch(() => {
5841
6508
  });
5842
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;
5843
6522
  const [state, dispatch] = useReducer(reducer, {
5844
- entries: banner ? [
5845
- {
5846
- id: 0,
5847
- kind: "banner",
5848
- version: appVersion ?? "dev",
5849
- provider: provider ?? "agent",
5850
- model,
5851
- cwd: agent.ctx.cwd,
5852
- family,
5853
- keyTail
5854
- }
5855
- ] : [],
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
+ ],
5856
6538
  buffer: "",
5857
6539
  cursor: 0,
5858
6540
  streamingText: "",
@@ -5864,7 +6546,7 @@ function App({
5864
6546
  hint: "",
5865
6547
  brain: { state: "idle" },
5866
6548
  brainPrompt: null,
5867
- nextId: 1,
6549
+ nextId: initialNextId,
5868
6550
  picker: { open: false, query: "", matches: [], selected: 0 },
5869
6551
  slashPicker: { open: false, query: "", matches: [], selected: 0 },
5870
6552
  runningTools: /* @__PURE__ */ new Map(),
@@ -5882,8 +6564,11 @@ function App({
5882
6564
  searchQuery: ""
5883
6565
  },
5884
6566
  autonomyPicker: { open: false, options: [], selected: 0 },
5885
- 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 },
5886
6568
  confirmQueue: [],
6569
+ enhance: null,
6570
+ enhanceEnabled,
6571
+ enhanceBusy: false,
5887
6572
  contextChipVersion: 0,
5888
6573
  fleet: {},
5889
6574
  leader: {
@@ -5902,6 +6587,8 @@ function App({
5902
6587
  monitorOpen: false,
5903
6588
  agentsMonitorOpen: false,
5904
6589
  helpOpen: false,
6590
+ todosMonitorOpen: false,
6591
+ queuePanelOpen: false,
5905
6592
  collabSession: null,
5906
6593
  checkpoints: [],
5907
6594
  rewindOverlay: null,
@@ -5926,10 +6613,14 @@ function App({
5926
6613
  const inputGateRef = useRef(false);
5927
6614
  const lastEnterAtRef = useRef(0);
5928
6615
  const tokenPreviewsRef = useRef(/* @__PURE__ */ new Map());
5929
- const projectName = React5.useMemo(() => {
6616
+ const projectName = React6.useMemo(() => {
5930
6617
  const base = path2.basename(projectRoot);
5931
6618
  return base && base !== path2.sep ? base : void 0;
5932
6619
  }, [projectRoot]);
6620
+ const chimeRef = useRef(chime);
6621
+ chimeRef.current = chime;
6622
+ const confirmExitRef = useRef(confirmExit);
6623
+ confirmExitRef.current = confirmExit;
5933
6624
  const streamingTextRef = useRef("");
5934
6625
  const pendingDeltaRef = useRef("");
5935
6626
  const flushTimerRef = useRef(null);
@@ -5938,7 +6629,7 @@ function App({
5938
6629
  const draftRef = useRef({ buffer: state.buffer, cursor: state.cursor });
5939
6630
  draftRef.current = { buffer: state.buffer, cursor: state.cursor };
5940
6631
  const bottomRef = useRef(null);
5941
- React5.useLayoutEffect(() => {
6632
+ React6.useLayoutEffect(() => {
5942
6633
  if (!managedLive) return;
5943
6634
  const node = bottomRef.current;
5944
6635
  if (!node) return;
@@ -5951,7 +6642,7 @@ function App({
5951
6642
  }
5952
6643
  }, [managedLive, termRows]);
5953
6644
  const handleKeyRef = useRef(null);
5954
- const handleRewindTo = React5.useCallback(
6645
+ const handleRewindTo = React6.useCallback(
5955
6646
  async (checkpointIndex) => {
5956
6647
  const sessionId = agent.ctx.session.id;
5957
6648
  if (!sessionId) return;
@@ -5970,13 +6661,13 @@ function App({
5970
6661
  dispatch({ type: "clearInput" });
5971
6662
  };
5972
6663
  const startedAtRef = useRef(Date.now());
5973
- const [nowTick, setNowTick] = React5.useState(Date.now());
6664
+ const [nowTick, setNowTick] = React6.useState(Date.now());
5974
6665
  useEffect(() => {
5975
6666
  const t = setInterval(() => setNowTick(Date.now()), 1e3);
5976
6667
  return () => clearInterval(t);
5977
6668
  }, []);
5978
6669
  const elapsedMs = nowTick - startedAtRef.current;
5979
- const [gitInfo, setGitInfo] = React5.useState(null);
6670
+ const [gitInfo, setGitInfo] = React6.useState(null);
5980
6671
  useEffect(() => {
5981
6672
  let cancelled = false;
5982
6673
  const refresh = () => {
@@ -6031,7 +6722,10 @@ function App({
6031
6722
  toolCalls: state.leader.toolCalls,
6032
6723
  recentTools: state.leader.recentTools,
6033
6724
  recentMessages: [],
6034
- cost: 0,
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,
6035
6729
  startedAt: state.leader.startedAt,
6036
6730
  lastEventAt: state.leader.lastEventAt,
6037
6731
  currentTool: state.leader.currentTool,
@@ -6040,7 +6734,7 @@ function App({
6040
6734
  ctxMaxTokens: state.leader.ctxMaxTokens ?? effectiveMaxContext
6041
6735
  };
6042
6736
  return { leader: leaderEntry, ...state.fleet };
6043
- }, [state.fleet, state.leader, state.status, provider, model, effectiveMaxContext]);
6737
+ }, [state.fleet, state.leader, state.status, provider, model, effectiveMaxContext, tokenCounter]);
6044
6738
  const STREAM_COLORS2 = ["cyan", "magenta", "yellow", "green", "blue"];
6045
6739
  const labelsRef = useRef(/* @__PURE__ */ new Map());
6046
6740
  const labelFor2 = (id, name) => {
@@ -6091,19 +6785,23 @@ function App({
6091
6785
  }, [agent.ctx.meta]);
6092
6786
  const prevAnyOverlayOpen = useRef(false);
6093
6787
  const prevEntriesCount = useRef(0);
6788
+ const prevToolStreamLen = useRef(0);
6094
6789
  const eraseLiveRegion = useCallback(() => {
6095
6790
  try {
6096
6791
  writeOut("\x1B[J");
6097
6792
  } catch {
6098
6793
  }
6099
6794
  }, []);
6100
- useEffect(() => {
6101
- 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;
6102
6797
  const overlayClosed = prevAnyOverlayOpen.current && !anyOpenNow;
6103
6798
  const newEntryCommitted = state.entries.length > prevEntriesCount.current;
6799
+ const curToolStreamLen = state.toolStream?.text.length ?? 0;
6800
+ const toolStreamGrew = curToolStreamLen > 0 && curToolStreamLen > prevToolStreamLen.current;
6104
6801
  prevAnyOverlayOpen.current = anyOpenNow;
6105
6802
  prevEntriesCount.current = state.entries.length;
6106
- if (overlayClosed || newEntryCommitted) {
6803
+ prevToolStreamLen.current = curToolStreamLen;
6804
+ if (overlayClosed || newEntryCommitted || toolStreamGrew) {
6107
6805
  eraseLiveRegion();
6108
6806
  }
6109
6807
  }, [
@@ -6112,8 +6810,11 @@ function App({
6112
6810
  state.modelPicker.open,
6113
6811
  state.autonomyPicker.open,
6114
6812
  state.settingsPicker.open,
6813
+ state.enhanceBusy,
6814
+ state.enhance,
6115
6815
  state.confirmQueue.length,
6116
6816
  state.entries.length,
6817
+ state.toolStream?.text,
6117
6818
  eraseLiveRegion
6118
6819
  ]);
6119
6820
  useEffect(() => {
@@ -6123,6 +6824,9 @@ function App({
6123
6824
  process.stdout.off("resize", handleResize);
6124
6825
  };
6125
6826
  }, [eraseLiveRegion]);
6827
+ React6.useLayoutEffect(() => {
6828
+ if (state.enhanceBusy || state.enhance != null) eraseLiveRegion();
6829
+ }, [nowTick, state.enhanceBusy, state.enhance, eraseLiveRegion]);
6126
6830
  useEffect(() => {
6127
6831
  const detected = detectAtToken(state.buffer, state.cursor);
6128
6832
  if (!detected) {
@@ -6439,15 +7143,36 @@ function App({
6439
7143
  slashRegistry.unregister("agents");
6440
7144
  };
6441
7145
  }, [slashRegistry]);
6442
- const openModelPicker = React5.useCallback(async () => {
7146
+ const openModelPicker = React6.useCallback(async () => {
6443
7147
  if (!getPickableProviders) return;
6444
7148
  const providers = await getPickableProviders();
6445
7149
  dispatch({ type: "modelPickerOpen", providers });
6446
7150
  }, [getPickableProviders]);
6447
- const openSettings = React5.useCallback(() => {
7151
+ const openSettings = React6.useCallback(() => {
6448
7152
  if (!getSettings) return;
6449
7153
  const s2 = getSettings();
6450
- dispatch({ type: "settingsOpen", mode: s2.mode, delayMs: s2.delayMs });
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
+ });
6451
7176
  }, [getSettings]);
6452
7177
  useEffect(() => {
6453
7178
  if (!getPickableProviders || !switchProviderAndModel) return;
@@ -6460,7 +7185,7 @@ function App({
6460
7185
  return { message: void 0 };
6461
7186
  }
6462
7187
  };
6463
- slashRegistry.register(cmd);
7188
+ slashRegistry.register(cmd, "tui", { official: true });
6464
7189
  return () => {
6465
7190
  slashRegistry.unregister("model");
6466
7191
  };
@@ -6470,13 +7195,13 @@ function App({
6470
7195
  const cmd = {
6471
7196
  name: "settings",
6472
7197
  aliases: ["config", "prefs"],
6473
- description: "Edit autonomy defaults (mode + auto-proceed delay).",
7198
+ description: "Open the interactive settings editor (19 config fields across 8 sections).",
6474
7199
  async run() {
6475
7200
  openSettings();
6476
7201
  return { message: void 0 };
6477
7202
  }
6478
7203
  };
6479
- slashRegistry.register(cmd);
7204
+ slashRegistry.register(cmd, "tui", { official: true });
6480
7205
  return () => {
6481
7206
  slashRegistry.unregister("settings");
6482
7207
  };
@@ -6492,7 +7217,7 @@ function App({
6492
7217
  return { message: void 0 };
6493
7218
  }
6494
7219
  };
6495
- slashRegistry.register(cmd);
7220
+ slashRegistry.register(cmd, "tui", { official: true });
6496
7221
  return () => {
6497
7222
  slashRegistry.unregister("autonomy");
6498
7223
  };
@@ -6533,23 +7258,25 @@ function App({
6533
7258
  });
6534
7259
  });
6535
7260
  const offTool = events.on("tool.executed", (e) => {
6536
- dispatch({
6537
- type: "addEntry",
6538
- entry: {
6539
- kind: "tool",
6540
- name: e.name,
6541
- durationMs: e.durationMs,
6542
- ok: e.ok,
6543
- input: e.input,
6544
- output: e.output,
6545
- // Real model-visible sizes — forwarded so the size chip beside
6546
- // the tool header can show what the model paid for instead of
6547
- // the misleading preview-byte count we used to surface.
6548
- outputBytes: e.outputBytes,
6549
- outputTokens: e.outputTokens,
6550
- outputLines: e.outputLines
6551
- }
6552
- });
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
+ }
6553
7280
  dispatch({ type: "toolEnded", name: e.name });
6554
7281
  dispatch({ type: "toolStreamClear", name: e.name });
6555
7282
  dispatch({ type: "leaderToolEnd", name: e.name, ok: e.ok, durationMs: e.durationMs });
@@ -6609,6 +7336,34 @@ function App({
6609
7336
  }
6610
7337
  });
6611
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
+ });
6612
7367
  return () => {
6613
7368
  offDelta();
6614
7369
  offToolStart();
@@ -6621,6 +7376,8 @@ function App({
6621
7376
  offProvResp();
6622
7377
  offConfirmNeeded();
6623
7378
  offTrustPersisted();
7379
+ offDelegateStart();
7380
+ offDelegateDone();
6624
7381
  if (flushTimerRef.current) clearTimeout(flushTimerRef.current);
6625
7382
  };
6626
7383
  }, [events, agent.ctx.todos]);
@@ -6628,6 +7385,11 @@ function App({
6628
7385
  useEffect(() => {
6629
7386
  streamFleetRef.current = state.streamFleet;
6630
7387
  }, [state.streamFleet]);
7388
+ const enhanceEnabledRef = useRef(state.enhanceEnabled);
7389
+ useEffect(() => {
7390
+ enhanceEnabledRef.current = state.enhanceEnabled;
7391
+ }, [state.enhanceEnabled]);
7392
+ const enhanceAbortRef = useRef(null);
6631
7393
  useSubagentEvents(events, dispatch, setActiveMaxContext);
6632
7394
  useEffect(() => {
6633
7395
  const offCheckpoint = events.on("checkpoint.written", (e) => {
@@ -6853,6 +7615,18 @@ function App({
6853
7615
  useEffect(() => {
6854
7616
  if (fleetStreamController) fleetStreamController.enabled = state.streamFleet;
6855
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]);
6856
7630
  useEffect(() => {
6857
7631
  if (!agentsMonitorController) return;
6858
7632
  agentsMonitorController.visible = state.agentsMonitorOpen;
@@ -6932,7 +7706,8 @@ function App({
6932
7706
  type: "fleetCost",
6933
7707
  cost: d.snapshot().total.cost,
6934
7708
  input: d.snapshot().total.input,
6935
- output: d.snapshot().total.output
7709
+ output: d.snapshot().total.output,
7710
+ perAgent: d.snapshot().perSubagent
6936
7711
  });
6937
7712
  const seen = new Set(Object.keys(status.subagents));
6938
7713
  const pending = /* @__PURE__ */ new Map();
@@ -7061,7 +7836,8 @@ function App({
7061
7836
  type: "fleetCost",
7062
7837
  cost: d.snapshot().total.cost,
7063
7838
  input: d.snapshot().total.input,
7064
- output: d.snapshot().total.output
7839
+ output: d.snapshot().total.output,
7840
+ perAgent: d.snapshot().perSubagent
7065
7841
  });
7066
7842
  break;
7067
7843
  }
@@ -7189,7 +7965,8 @@ function App({
7189
7965
  type: "fleetCost",
7190
7966
  cost: d.snapshot().total.cost,
7191
7967
  input: d.snapshot().total.input,
7192
- output: d.snapshot().total.output
7968
+ output: d.snapshot().total.output,
7969
+ perAgent: d.snapshot().perSubagent
7193
7970
  });
7194
7971
  if (streamFlushTimer) {
7195
7972
  clearTimeout(streamFlushTimer);
@@ -7270,7 +8047,7 @@ function App({
7270
8047
  type: "addEntry",
7271
8048
  entry: {
7272
8049
  kind: "warn",
7273
- 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."}`
7274
8051
  }
7275
8052
  });
7276
8053
  } else {
@@ -7278,7 +8055,7 @@ function App({
7278
8055
  type: "addEntry",
7279
8056
  entry: {
7280
8057
  kind: "warn",
7281
- 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."}`
7282
8059
  }
7283
8060
  });
7284
8061
  }
@@ -7309,7 +8086,7 @@ function App({
7309
8086
  type: "addEntry",
7310
8087
  entry: {
7311
8088
  kind: "warn",
7312
- 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."}`
7313
8090
  }
7314
8091
  });
7315
8092
  return;
@@ -7352,10 +8129,16 @@ function App({
7352
8129
  const handleKey = async (input, key) => {
7353
8130
  if (state.status === "aborting" && !state.steeringPending && state.interrupts === 0) return;
7354
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;
7355
8137
  if (state.helpOpen) {
7356
8138
  if (key.escape || input === "?" || input === "q") dispatch({ type: "toggleHelp" });
7357
8139
  return;
7358
8140
  }
8141
+ state.todosMonitorOpen || state.monitorOpen || state.agentsMonitorOpen || state.worktreeMonitorOpen || !!state.autoPhase?.monitorOpen;
7359
8142
  if (inputGateRef.current) return;
7360
8143
  if (managedLive) {
7361
8144
  if (key.pageUp) {
@@ -7527,8 +8310,8 @@ function App({
7527
8310
  const now = Date.now();
7528
8311
  if (now - lastEnterAtRef.current < 50) return;
7529
8312
  lastEnterAtRef.current = now;
7530
- const { mode, delayMs } = state.settingsPicker;
7531
- 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 });
7532
8315
  if (err) {
7533
8316
  dispatch({ type: "settingsHint", text: err });
7534
8317
  return;
@@ -7641,20 +8424,32 @@ function App({
7641
8424
  return;
7642
8425
  }
7643
8426
  const toggleFleetOverlay = () => {
7644
- if (state.agentsMonitorOpen) {
7645
- dispatch({ type: "toggleAgentsMonitor" });
7646
- dispatch({ type: "toggleMonitor" });
7647
- } else {
8427
+ if (state.monitorOpen) {
7648
8428
  dispatch({ type: "toggleMonitor" });
8429
+ return;
7649
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" });
7650
8439
  };
7651
8440
  const toggleAgentsOverlay = () => {
7652
- if (state.monitorOpen) {
7653
- dispatch({ type: "toggleMonitor" });
7654
- dispatch({ type: "toggleAgentsMonitor" });
7655
- } else {
8441
+ if (state.agentsMonitorOpen) {
7656
8442
  dispatch({ type: "toggleAgentsMonitor" });
8443
+ return;
7657
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" });
7658
8453
  };
7659
8454
  const toggleWorktreeOverlay = () => {
7660
8455
  if (state.worktreeMonitorOpen) {
@@ -7664,8 +8459,26 @@ function App({
7664
8459
  if (state.agentsMonitorOpen) dispatch({ type: "toggleAgentsMonitor" });
7665
8460
  if (state.monitorOpen) dispatch({ type: "toggleMonitor" });
7666
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" });
7667
8466
  dispatch({ type: "worktreeMonitorToggle" });
7668
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
+ };
7669
8482
  if (key.ctrl && input === "f" || key.fn === 2) {
7670
8483
  toggleFleetOverlay();
7671
8484
  return;
@@ -7678,12 +8491,96 @@ function App({
7678
8491
  toggleWorktreeOverlay();
7679
8492
  return;
7680
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
+ }
7681
8550
  if (key.ctrl && input === "s") {
7682
8551
  if (state.settingsPicker.open) {
7683
8552
  dispatch({ type: "settingsClose" });
7684
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" });
7685
8561
  const cfg = getSettings();
7686
- dispatch({ type: "settingsOpen", mode: cfg.mode, delayMs: cfg.delayMs });
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
+ });
7687
8584
  }
7688
8585
  return;
7689
8586
  }
@@ -7700,12 +8597,34 @@ function App({
7700
8597
  dispatch({ type: "worktreeMonitorToggle" });
7701
8598
  return;
7702
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
+ }
7703
8616
  }
7704
- 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) {
7705
8618
  dispatch({ type: "toggleHelp" });
7706
8619
  return;
7707
8620
  }
7708
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
+ }
7709
8628
  const now = Date.now();
7710
8629
  if (now - lastEnterAtRef.current < 50) return;
7711
8630
  lastEnterAtRef.current = now;
@@ -7713,36 +8632,41 @@ function App({
7713
8632
  return;
7714
8633
  }
7715
8634
  const { buffer, cursor } = draftRef.current;
7716
- if (key.backspace || key.delete) {
8635
+ if (key.backspace) {
7717
8636
  if (key.ctrl) {
7718
- if (key.backspace) {
7719
- if (cursor === 0) return;
7720
- const beforeCursor = buffer.slice(0, cursor);
7721
- const lastWordStart = beforeCursor.lastIndexOf(" ") + 1;
7722
- const next3 = beforeCursor.slice(0, lastWordStart) + buffer.slice(cursor);
7723
- setDraft(next3, lastWordStart);
7724
- } else {
7725
- if (cursor >= buffer.length) return;
7726
- const afterCursor = buffer.slice(cursor);
7727
- const nextWordStart = afterCursor.indexOf(" ");
7728
- const end = nextWordStart === -1 ? buffer.length : cursor + nextWordStart + 1;
7729
- const next3 = buffer.slice(0, cursor) + buffer.slice(end);
7730
- setDraft(next3, cursor);
7731
- }
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);
7732
8642
  return;
7733
8643
  }
7734
- if (key.backspace) {
7735
- const tokenDel = deleteTokenBackward(buffer, cursor);
7736
- if (tokenDel) {
7737
- setDraft(tokenDel.buffer, tokenDel.cursor);
7738
- return;
7739
- }
8644
+ const tokenDel = deleteTokenBackward(buffer, cursor);
8645
+ if (tokenDel) {
8646
+ setDraft(tokenDel.buffer, tokenDel.cursor);
8647
+ return;
7740
8648
  }
7741
8649
  if (cursor === 0) return;
7742
8650
  const next2 = buffer.slice(0, cursor - 1) + buffer.slice(cursor);
7743
8651
  setDraft(next2, cursor - 1);
7744
8652
  return;
7745
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
+ }
7746
8670
  if (key.leftArrow) {
7747
8671
  if (key.ctrl) {
7748
8672
  if (cursor === 0) return;
@@ -7813,7 +8737,7 @@ function App({
7813
8737
  setDraft("", 0);
7814
8738
  return;
7815
8739
  }
7816
- if (key.delete || key.ctrl && input === "d") {
8740
+ if (key.ctrl && input === "d") {
7817
8741
  if (cursor >= buffer.length) return;
7818
8742
  const span = tokenLengthForward(buffer, cursor) || 1;
7819
8743
  const next2 = buffer.slice(0, cursor) + buffer.slice(cursor + span);
@@ -7940,10 +8864,20 @@ function App({
7940
8864
  } finally {
7941
8865
  activeCtrlRef.current = null;
7942
8866
  dispatch({ type: "status", status: "idle" });
8867
+ if (chimeRef.current) {
8868
+ try {
8869
+ process.stdout.write("\x07");
8870
+ } catch {
8871
+ }
8872
+ }
7943
8873
  }
7944
8874
  const head = stateRef.current.queue[0];
7945
8875
  if (head) {
7946
8876
  dispatch({ type: "dequeueFirst" });
8877
+ dispatch({
8878
+ type: "addEntry",
8879
+ entry: { kind: "user", text: head.displayText }
8880
+ });
7947
8881
  await runBlocks(head.blocks);
7948
8882
  }
7949
8883
  };
@@ -8088,6 +9022,10 @@ function App({
8088
9022
  void runParallelLoopRef.current();
8089
9023
  }
8090
9024
  }
9025
+ if (getModeLabel) {
9026
+ const currentMode = getModeLabel();
9027
+ if (currentMode !== liveModeLabel) setLiveModeLabel(currentMode);
9028
+ }
8091
9029
  if (res?.exit) {
8092
9030
  exit();
8093
9031
  onExit(0);
@@ -8107,6 +9045,7 @@ function App({
8107
9045
  const cmd = trimmed.slice(1).split(/\s+/, 1)[0];
8108
9046
  if (cmd === "clear") {
8109
9047
  onClearHistory?.(dispatch);
9048
+ tokenCounter?.reset();
8110
9049
  }
8111
9050
  } catch (err) {
8112
9051
  dispatch({
@@ -8119,6 +9058,52 @@ function App({
8119
9058
  const builder = builderRef.current;
8120
9059
  if (!builder) return;
8121
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
+ }
8122
9107
  const sddContext = getSDDContext?.();
8123
9108
  if (sddContext && trimmed) {
8124
9109
  builder.appendText(`[SDD SESSION ACTIVE]
@@ -8129,11 +9114,11 @@ User message:
8129
9114
  `);
8130
9115
  }
8131
9116
  if (trimmed) {
8132
- const toAppend = steering ? buildSteeringPreamble(state.steerSnapshot, trimmed) : trimmed;
9117
+ const toAppend = steering ? buildSteeringPreamble(state.steerSnapshot, effectiveText) : effectiveText;
8133
9118
  builder.appendText(toAppend);
8134
9119
  }
8135
9120
  if (steering) dispatch({ type: "steerConsume" });
8136
- const displayText = trimmed ? steering ? `\u21AF ${trimmed}` : trimmed : "(attachments only)";
9121
+ const displayText = trimmed ? steering ? `\u21AF ${effectiveText}` : effectiveText : "(attachments only)";
8137
9122
  const pasteParts = [];
8138
9123
  for (const m of trimmed.matchAll(new RegExp(INLINE_TOKEN_SRC, "g"))) {
8139
9124
  const token = m[0];
@@ -8194,7 +9179,8 @@ User message:
8194
9179
  return "";
8195
9180
  }, [state.buffer, state.status, state.picker.open]);
8196
9181
  const affordanceShown = managedLive && state.scrollOffset > 0 && state.pendingNewLines > 0;
8197
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", height: managedLive ? termRows : void 0, children: [
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: [
8198
9184
  managedLive ? /* @__PURE__ */ jsx(
8199
9185
  ScrollableHistory,
8200
9186
  {
@@ -8221,10 +9207,10 @@ User message:
8221
9207
  Input,
8222
9208
  {
8223
9209
  prompt: INPUT_PROMPT,
8224
- value: state.buffer,
8225
- cursor: state.cursor,
9210
+ value: enhanceActive ? "" : state.buffer,
9211
+ cursor: enhanceActive ? 0 : state.cursor,
8226
9212
  disabled: state.status === "aborting" && !state.steeringPending || state.confirmQueue.length > 0,
8227
- hint: inputHint,
9213
+ hint: enhanceActive ? "" : inputHint,
8228
9214
  onKey: handleKey
8229
9215
  }
8230
9216
  ),
@@ -8271,6 +9257,23 @@ User message:
8271
9257
  field: state.settingsPicker.field,
8272
9258
  mode: state.settingsPicker.mode,
8273
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,
8274
9277
  hint: state.settingsPicker.hint
8275
9278
  }
8276
9279
  ) : null,
@@ -8313,6 +9316,25 @@ User message:
8313
9316
  }
8314
9317
  );
8315
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,
8316
9338
  /* @__PURE__ */ jsx(
8317
9339
  StatusBar,
8318
9340
  {
@@ -8336,7 +9358,9 @@ User message:
8336
9358
  processCount: getProcessRegistry().activeCount,
8337
9359
  hiddenItems,
8338
9360
  eternalStage: state.eternalStage,
8339
- goalSummary: state.goalSummary
9361
+ goalSummary: state.goalSummary,
9362
+ indexState,
9363
+ modeLabel: liveModeLabel || void 0
8340
9364
  }
8341
9365
  ),
8342
9366
  managedLive ? /* @__PURE__ */ jsx(
@@ -8345,7 +9369,7 @@ User message:
8345
9369
  context: {
8346
9370
  confirm: state.confirmQueue.length > 0,
8347
9371
  picker: state.picker.open || state.slashPicker.open || state.modelPicker.open || state.autonomyPicker.open || state.settingsPicker.open || !!state.rewindOverlay,
8348
- monitor: state.agentsMonitorOpen || state.monitorOpen || state.worktreeMonitorOpen || !!state.autoPhase?.monitorOpen,
9372
+ monitor: state.agentsMonitorOpen || state.monitorOpen || state.worktreeMonitorOpen || state.todosMonitorOpen || !!state.autoPhase?.monitorOpen,
8349
9373
  managed: managedLive
8350
9374
  }
8351
9375
  }
@@ -8356,6 +9380,7 @@ User message:
8356
9380
  {
8357
9381
  entries: entriesWithLeader,
8358
9382
  totalCost: state.fleetCost,
9383
+ leaderCost: tokenCounter?.estimateCost().total ?? 0,
8359
9384
  totalTokens: state.fleetTokens,
8360
9385
  nowTick
8361
9386
  }
@@ -8376,7 +9401,7 @@ User message:
8376
9401
  nowTick,
8377
9402
  onClose: () => dispatch({ type: "worktreeMonitorToggle" })
8378
9403
  }
8379
- ) : state.monitorOpen ? /* @__PURE__ */ jsx(
9404
+ ) : state.todosMonitorOpen && !managedLive ? /* @__PURE__ */ jsx(TodosMonitor, { todos: agent.ctx.todos }) : state.monitorOpen ? /* @__PURE__ */ jsx(
8380
9405
  FleetMonitor,
8381
9406
  {
8382
9407
  entries: state.fleet,
@@ -8403,9 +9428,10 @@ User message:
8403
9428
  nowTick
8404
9429
  }
8405
9430
  ) : null,
8406
- 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
8407
9433
  ] })
8408
- ] });
9434
+ ] }) });
8409
9435
  }
8410
9436
  function renderRunningTools(running) {
8411
9437
  if (running.size === 0) return "";
@@ -8524,7 +9550,8 @@ async function runTui(opts) {
8524
9550
  }
8525
9551
  stdout.write(BRACKETED_PASTE_ON);
8526
9552
  const inkStdin = stdin;
8527
- const stopTitle = startTerminalTitle({ stdout, events: opts.events, model: opts.model });
9553
+ const stopTitle = opts.titleAnimation !== false ? startTerminalTitle({ stdout, events: opts.events, model: opts.model }) : (() => {
9554
+ });
8528
9555
  const swallowSignals = ["SIGTSTP", "SIGQUIT", "SIGTTIN", "SIGTTOU"];
8529
9556
  const swallow = () => {
8530
9557
  };
@@ -8584,7 +9611,7 @@ async function runTui(opts) {
8584
9611
  let instance;
8585
9612
  try {
8586
9613
  instance = render(
8587
- React5.createElement(App, {
9614
+ React6.createElement(App, {
8588
9615
  agent: opts.agent,
8589
9616
  slashRegistry: opts.slashRegistry,
8590
9617
  attachments: opts.attachments,
@@ -8616,6 +9643,8 @@ async function runTui(opts) {
8616
9643
  fleetRoster: opts.fleetRoster,
8617
9644
  onClearHistory: opts.onClearHistory ? (dispatch) => opts.onClearHistory(dispatch) : void 0,
8618
9645
  fleetStreamController: opts.fleetStreamController,
9646
+ enhanceController: opts.enhanceController,
9647
+ enhanceEnabled: opts.enhanceController?.enabled ?? true,
8619
9648
  statuslineHiddenItems: opts.statuslineHiddenItems,
8620
9649
  setStatuslineHiddenItems: opts.setStatuslineHiddenItems,
8621
9650
  agentsMonitorController: opts.agentsMonitorController,
@@ -8630,7 +9659,11 @@ async function runTui(opts) {
8630
9659
  predictNext: opts.predictNext,
8631
9660
  // Managed viewport (in-app scroll + collapsibility) follows
8632
9661
  // alt-screen: it owns the screen, so there's no native-scrollback leak.
8633
- managed: useAltScreen
9662
+ managed: useAltScreen,
9663
+ chime: opts.chime,
9664
+ confirmExit: opts.confirmExit,
9665
+ modeLabel: opts.modeLabel,
9666
+ getModeLabel: opts.getModeLabel
8634
9667
  }),
8635
9668
  { exitOnCtrlC: false, stdin: inkStdin }
8636
9669
  );