@wrongstack/tui 0.265.1 → 0.267.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
@@ -109,6 +109,18 @@ function useTokenCounterRefresh(tokenCounter, events) {
109
109
  }, [tokenCounter, events]);
110
110
  return data;
111
111
  }
112
+ function chipExpired(meta, now = Date.now()) {
113
+ if (meta.expiresIn == null) return false;
114
+ return now >= meta.shownAt + meta.expiresIn * 6e4;
115
+ }
116
+ function isStreamChipVisible(key, dataIsPresent, hiddenSet, visibleChips) {
117
+ if (!dataIsPresent) return false;
118
+ if (hiddenSet.has(key)) return false;
119
+ const meta = visibleChips.find((c) => c.key === key);
120
+ if (!meta) return false;
121
+ if (chipExpired(meta)) return false;
122
+ return true;
123
+ }
112
124
  var MODE_ICONS = {
113
125
  teach: "\u{1F9D1}\u200D\u{1F3EB}",
114
126
  brief: "\u26A1",
@@ -177,7 +189,8 @@ function StatusBar({
177
189
  sessionCount,
178
190
  mailbox,
179
191
  tokenSavingMode,
180
- toolCount
192
+ toolCount,
193
+ visibleChips = []
181
194
  }) {
182
195
  const { stdout } = useStdout();
183
196
  const [termWidth, setTermWidth] = useState(stdout?.columns ?? 90);
@@ -218,13 +231,13 @@ function StatusBar({
218
231
  const hasAutoProceed = autoProceedCountdown != null && autoProceedCountdown > 0;
219
232
  const hasSecondLine = yolo || autonomy && autonomy !== "off" || startedAt != null || git !== null && git !== void 0 || projectName !== void 0 && projectName.length > 0 || workingDir !== void 0 && workingDir.length > 0 || goalSummary !== null && goalSummary !== void 0 || !!modeLabel || hasAutoProceed || tokenSavingMode || typeof toolCount === "number" && toolCount > 0;
220
233
  const fleetHasActivity = fleet && (fleet.running > 0 || fleet.idle > 0 || fleet.pending > 0 || fleet.completed > 0) || subagentCount > 0;
221
- const hasBrainActivity = !!brain && brain.state !== "idle";
222
- const hasDebugStream = !!debugStreamStats;
223
- const hasEnhanceCountdown = enhanceCountdown != null && enhanceCountdown > 0;
234
+ const showBrain = isStreamChipVisible("brain", brain, hiddenSet ?? /* @__PURE__ */ new Set(), visibleChips);
235
+ const showDebugStream = isStreamChipVisible("debug_stream", debugStreamStats, hiddenSet ?? /* @__PURE__ */ new Set(), visibleChips);
236
+ const showEnhance = isStreamChipVisible("enhance", enhanceCountdown, hiddenSet ?? /* @__PURE__ */ new Set(), visibleChips);
224
237
  const hasNextStepsAutoSubmit = nextStepsAutoSubmitCountdown != null && nextStepsAutoSubmitCountdown > 0;
225
238
  const countdownColor = nextStepsAutoSubmitCountdown != null ? nextStepsAutoSubmitCountdown > 20 ? "green" : nextStepsAutoSubmitCountdown > 10 ? "yellow" : "red" : "green";
226
239
  const hasTaskActivity = tasks && (tasks.pending > 0 || tasks.inProgress > 0 || tasks.completed > 0 || tasks.blocked > 0 || tasks.failed > 0);
227
- const hasThirdLine = todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0) || plan && (plan.open > 0 || plan.inProgress > 0 || plan.done > 0) || hasTaskActivity || fleetHasActivity || hasBrainActivity || hasDebugStream || hasEnhanceCountdown || hasNextStepsAutoSubmit;
240
+ const hasThirdLine = todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0) && !hiddenSet.has("todos") || plan && (plan.open > 0 || plan.inProgress > 0 || plan.done > 0) && !hiddenSet.has("plan") || hasTaskActivity && !hiddenSet.has("tasks") || fleetHasActivity && !hiddenSet.has("fleet") || showBrain || showDebugStream || showEnhance || hasNextStepsAutoSubmit;
228
241
  return /* @__PURE__ */ jsxs(
229
242
  Box,
230
243
  {
@@ -304,7 +317,7 @@ function StatusBar({
304
317
  "%"
305
318
  ] })
306
319
  ] }) : null,
307
- cost && cost.total > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
320
+ cost && cost.total > 0 && !hiddenSet.has("cost") ? /* @__PURE__ */ jsxs(Fragment, { children: [
308
321
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
309
322
  /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
310
323
  "$",
@@ -432,7 +445,7 @@ function StatusBar({
432
445
  "s"
433
446
  ] })
434
447
  ] }) : null,
435
- git ? /* @__PURE__ */ jsxs(Fragment, { children: [
448
+ git && !hiddenSet.has("git") ? /* @__PURE__ */ jsxs(Fragment, { children: [
436
449
  yolo || startedAt != null || projectName || workingDir ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
437
450
  /* @__PURE__ */ jsxs(Text, { children: [
438
451
  /* @__PURE__ */ jsxs(Text, { color: "magenta", children: [
@@ -450,7 +463,7 @@ function StatusBar({
450
463
  ] })
451
464
  ] }) : null,
452
465
  sessionCount != null && sessionCount > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
453
- yolo || startedAt != null || projectName || workingDir || git ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
466
+ yolo || startedAt != null || projectName || workingDir || git && !hiddenSet.has("git") ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
454
467
  /* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
455
468
  "\u29C9 ",
456
469
  sessionCount,
@@ -459,7 +472,7 @@ function StatusBar({
459
472
  ] })
460
473
  ] }) : null,
461
474
  toolCount != null ? /* @__PURE__ */ jsxs(Fragment, { children: [
462
- yolo || startedAt != null || projectName || workingDir || git || sessionCount ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
475
+ yolo || startedAt != null || projectName || workingDir || git && !hiddenSet.has("git") || sessionCount ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
463
476
  /* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
464
477
  "\u{1F527} ",
465
478
  toolCount,
@@ -468,12 +481,12 @@ function StatusBar({
468
481
  ] })
469
482
  ] }) : null,
470
483
  tokenSavingMode ? /* @__PURE__ */ jsxs(Fragment, { children: [
471
- yolo || startedAt != null || projectName || workingDir || git || sessionCount || toolCount ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
484
+ yolo || startedAt != null || projectName || workingDir || git && !hiddenSet.has("git") || sessionCount || toolCount ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
472
485
  /* @__PURE__ */ jsx(Text, { color: "yellow", bold: true, children: "\u{1F4BE} save" })
473
486
  ] }) : null
474
487
  ] }) : /* @__PURE__ */ jsx(Box, { height: 1, children: /* @__PURE__ */ jsx(Text, { children: " " }) }),
475
488
  hasThirdLine ? /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 2, children: [
476
- todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0) ? /* @__PURE__ */ jsxs(Text, { children: [
489
+ todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0) && !hiddenSet.has("todos") ? /* @__PURE__ */ jsxs(Text, { children: [
477
490
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "todos " }),
478
491
  todos.inProgress > 0 ? /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
479
492
  "\u231B",
@@ -490,8 +503,8 @@ function StatusBar({
490
503
  todos.completed
491
504
  ] }) : null
492
505
  ] }) : null,
493
- plan && (plan.open > 0 || plan.inProgress > 0 || plan.done > 0) ? /* @__PURE__ */ jsxs(Fragment, { children: [
494
- todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0) ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
506
+ plan && (plan.open > 0 || plan.inProgress > 0 || plan.done > 0) && !hiddenSet.has("plan") ? /* @__PURE__ */ jsxs(Fragment, { children: [
507
+ todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0) && !hiddenSet.has("todos") ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
495
508
  /* @__PURE__ */ jsxs(Text, { children: [
496
509
  /* @__PURE__ */ jsx(Text, { color: "cyan", children: "\u{1F4CB} " }),
497
510
  plan.inProgress > 0 ? /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
@@ -515,8 +528,8 @@ function StatusBar({
515
528
  ] }) : null
516
529
  ] })
517
530
  ] }) : null,
518
- hasTaskActivity ? /* @__PURE__ */ jsxs(Fragment, { children: [
519
- todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0) || plan && (plan.open > 0 || plan.inProgress > 0 || plan.done > 0) ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
531
+ hasTaskActivity && !hiddenSet.has("tasks") ? /* @__PURE__ */ jsxs(Fragment, { children: [
532
+ todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0) && !hiddenSet.has("todos") || plan && (plan.open > 0 || plan.inProgress > 0 || plan.done > 0) && !hiddenSet.has("plan") ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
520
533
  /* @__PURE__ */ jsxs(Text, { children: [
521
534
  /* @__PURE__ */ jsx(Text, { color: "magenta", children: "\u26A1 " }),
522
535
  tasks.inProgress > 0 ? /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
@@ -550,8 +563,8 @@ function StatusBar({
550
563
  ] }) : null
551
564
  ] })
552
565
  ] }) : null,
553
- fleetHasActivity ? /* @__PURE__ */ jsxs(Fragment, { children: [
554
- todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0) || plan && (plan.open > 0 || plan.inProgress > 0 || plan.done > 0) ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
566
+ fleetHasActivity && !hiddenSet.has("fleet") ? /* @__PURE__ */ jsxs(Fragment, { children: [
567
+ todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0) && !hiddenSet.has("todos") || plan && (plan.open > 0 || plan.inProgress > 0 || plan.done > 0) && !hiddenSet.has("plan") ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
555
568
  fleet ? /* @__PURE__ */ jsxs(Text, { children: [
556
569
  /* @__PURE__ */ jsx(Text, { color: "blue", children: "\u{1F310} " }),
557
570
  fleet.running > 0 ? /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
@@ -581,12 +594,12 @@ function StatusBar({
581
594
  subagentCount === 1 ? "" : "s"
582
595
  ] })
583
596
  ] }) : null,
584
- hasBrainActivity && brain ? /* @__PURE__ */ jsxs(Fragment, { children: [
585
- 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,
597
+ showBrain ? /* @__PURE__ */ jsxs(Fragment, { children: [
598
+ todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0) && !hiddenSet.has("todos") || plan && (plan.open > 0 || plan.inProgress > 0 || plan.done > 0) && !hiddenSet.has("plan") || hasTaskActivity && !hiddenSet.has("tasks") || fleetHasActivity && !hiddenSet.has("fleet") ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
586
599
  /* @__PURE__ */ jsx(BrainChip, { brain })
587
600
  ] }) : null,
588
- hasDebugStream && debugStreamStats ? /* @__PURE__ */ jsxs(Fragment, { children: [
589
- todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0) || plan && (plan.open > 0 || plan.inProgress > 0 || plan.done > 0) || fleetHasActivity || hasBrainActivity ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
601
+ showDebugStream ? /* @__PURE__ */ jsxs(Fragment, { children: [
602
+ todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0) && !hiddenSet.has("todos") || plan && (plan.open > 0 || plan.inProgress > 0 || plan.done > 0) && !hiddenSet.has("plan") || hasTaskActivity && !hiddenSet.has("tasks") || fleetHasActivity && !hiddenSet.has("fleet") || showBrain ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
590
603
  /* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
591
604
  /* @__PURE__ */ jsx(Text, { bold: true, children: "\u{1F41B} stream" }),
592
605
  /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
@@ -609,8 +622,8 @@ function StatusBar({
609
622
  ] })
610
623
  ] })
611
624
  ] }) : null,
612
- hasEnhanceCountdown && enhanceCountdown != null ? /* @__PURE__ */ jsxs(Fragment, { children: [
613
- todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0) || plan && (plan.open > 0 || plan.inProgress > 0 || plan.done > 0) || fleetHasActivity || hasBrainActivity || hasDebugStream ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
625
+ showEnhance ? /* @__PURE__ */ jsxs(Fragment, { children: [
626
+ todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0) && !hiddenSet.has("todos") || plan && (plan.open > 0 || plan.inProgress > 0 || plan.done > 0) && !hiddenSet.has("plan") || hasTaskActivity && !hiddenSet.has("tasks") || fleetHasActivity && !hiddenSet.has("fleet") || showBrain || showDebugStream ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
614
627
  /* @__PURE__ */ jsxs(Text, { color: enhanceCountdown > 15 ? "green" : enhanceCountdown > 5 ? "yellow" : "red", children: [
615
628
  "\u23F3 auto-send in ",
616
629
  enhanceCountdown,
@@ -618,7 +631,7 @@ function StatusBar({
618
631
  ] })
619
632
  ] }) : null,
620
633
  hasNextStepsAutoSubmit && nextStepsAutoSubmitCountdown != null ? /* @__PURE__ */ jsxs(Fragment, { children: [
621
- todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0) || plan && (plan.open > 0 || plan.inProgress > 0 || plan.done > 0) || fleetHasActivity || hasBrainActivity || hasDebugStream || hasEnhanceCountdown ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
634
+ todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0) && !hiddenSet.has("todos") || plan && (plan.open > 0 || plan.inProgress > 0 || plan.done > 0) && !hiddenSet.has("plan") || hasTaskActivity && !hiddenSet.has("tasks") || fleetHasActivity && !hiddenSet.has("fleet") || showBrain || showDebugStream || showEnhance ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
622
635
  /* @__PURE__ */ jsxs(Text, { color: countdownColor, bold: true, children: [
623
636
  "\u23F3 ",
624
637
  nextStepsAutoSubmitCountdown,
@@ -631,7 +644,7 @@ function StatusBar({
631
644
  ] })
632
645
  ] }) : null
633
646
  ] }) : /* @__PURE__ */ jsx(Box, { height: 1, children: /* @__PURE__ */ jsx(Text, { children: " " }) }),
634
- mailbox ? /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 2, children: [
647
+ mailbox && !hiddenSet.has("mailbox") ? /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 2, children: [
635
648
  mailbox.unread > 0 ? /* @__PURE__ */ jsxs(Text, { color: "yellow", bold: true, children: [
636
649
  "\u2709 ",
637
650
  mailbox.unread,
@@ -1859,6 +1872,43 @@ function FleetPanel({
1859
1872
  ] }) : null
1860
1873
  ] });
1861
1874
  }
1875
+ var F_KEY_ENTRIES = [
1876
+ { key: 1, label: "Project switcher", action: "projectPickerOpen" },
1877
+ { key: 2, label: "Fleet orchestration monitor", action: "toggleMonitor" },
1878
+ { key: 3, label: "Agents live monitor", action: "toggleAgentsMonitor" },
1879
+ { key: 4, label: "Worktree monitor", action: "toggleWorktreeMonitor" },
1880
+ { key: 5, label: "Autonomy settings", action: "togglePlanPanel" },
1881
+ { key: 6, label: "Todos monitor overlay", action: "toggleTodosMonitor" },
1882
+ { key: 7, label: "Queue panel", action: "toggleQueuePanel" },
1883
+ { key: 8, label: "Process list overlay", action: "toggleProcessList" },
1884
+ { key: 9, label: "Goal panel", action: "toggleGoalPanel" },
1885
+ { key: 10, label: "Live sessions panel", action: "toggleSessionsPanel" },
1886
+ { key: 11, label: "Coordinator monitor", action: "toggleCoordinatorMonitor" },
1887
+ { key: 12, label: "Status line picker", action: "statuslineOpen" }
1888
+ ];
1889
+ function FKeyPicker({ selected }) {
1890
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, flexShrink: 0, children: [
1891
+ /* @__PURE__ */ jsx(Text, { color: "cyan", bold: true, children: "\u2501\u2501 F-Key Panels \u2501\u2501" }),
1892
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191\u2193 navigate \xB7 Enter open \xB7 Esc close" }),
1893
+ F_KEY_ENTRIES.map((entry) => {
1894
+ const idx = entry.key - 1;
1895
+ const isSelected = idx === selected;
1896
+ const marker = isSelected ? "\u25B8" : " ";
1897
+ const labelColor = isSelected ? "cyan" : void 0;
1898
+ return /* @__PURE__ */ jsxs(Box, { children: [
1899
+ /* @__PURE__ */ jsx(Box, { width: 4, flexShrink: 0, children: /* @__PURE__ */ jsx(Text, { color: "dimColor", children: marker }) }),
1900
+ /* @__PURE__ */ jsxs(Text, { color: "dimColor", children: [
1901
+ "F",
1902
+ entry.key
1903
+ ] }),
1904
+ /* @__PURE__ */ jsx(Text, { children: " " }),
1905
+ /* @__PURE__ */ jsx(Text, { color: labelColor, children: entry.label })
1906
+ ] }, entry.key);
1907
+ }),
1908
+ selected > 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191 Scroll up" }) : null,
1909
+ selected < 11 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2193 Scroll down" }) : null
1910
+ ] });
1911
+ }
1862
1912
  function fmtTime(iso) {
1863
1913
  const d = new Date(iso);
1864
1914
  const now = Date.now();
@@ -1961,7 +2011,7 @@ var TOOL_GLYPHS = {
1961
2011
  edit: "\u270E",
1962
2012
  search: "\u2315",
1963
2013
  folder: "\u25A3",
1964
- terminal: "\u25B8",
2014
+ terminal: "\u2318",
1965
2015
  web: "\u25C8",
1966
2016
  git: "\u2387",
1967
2017
  tree: "\u2630",
@@ -5433,21 +5483,33 @@ function ProcessListMonitor() {
5433
5483
  const all = registry.list();
5434
5484
  const stats = registry.stats();
5435
5485
  const safeIndex = Math.min(selectedIndex, Math.max(0, all.length - 1));
5486
+ if (safeIndex !== selectedIndex) {
5487
+ setSelectedIndex(safeIndex);
5488
+ }
5436
5489
  const selected = all[safeIndex];
5437
5490
  const now = Date.now();
5438
5491
  const running = all.filter((p) => !p.killed).length;
5439
5492
  const b = stats.breaker;
5440
5493
  const breakerState = b.state === "closed" ? "\u{1F7E2} closed" : b.state === "half-open" ? "\u{1F7E1} half-open" : "\u{1F534} open";
5494
+ const pageSize = Math.max(1, Math.floor(all.length / 2));
5441
5495
  useInput((input, key) => {
5442
5496
  if (key.upArrow) {
5443
5497
  setSelectedIndex((prev) => Math.max(0, prev - 1));
5444
5498
  } else if (key.downArrow) {
5445
5499
  setSelectedIndex((prev) => Math.min(all.length - 1, prev + 1));
5500
+ } else if (key.pageUp) {
5501
+ setSelectedIndex((prev) => Math.max(0, prev - pageSize));
5502
+ } else if (key.pageDown) {
5503
+ setSelectedIndex((prev) => Math.min(all.length - 1, prev + pageSize));
5504
+ } else if (key.home || key.ctrl && input === "a" || input === "g") {
5505
+ setSelectedIndex(0);
5506
+ } else if (key.end || key.ctrl && input === "e" || input === "G") {
5507
+ setSelectedIndex(Math.max(0, all.length - 1));
5446
5508
  } else if (key.return && selected) {
5447
5509
  getProcessRegistry().kill(selected.pid);
5448
5510
  } else if (key.delete && selected) {
5449
5511
  getProcessRegistry().kill(selected.pid, { force: true });
5450
- } else if (input === "a") {
5512
+ } else if (input === "a" && !key.ctrl) {
5451
5513
  getProcessRegistry().killAll();
5452
5514
  } else if (input === "A") {
5453
5515
  getProcessRegistry().killAll({ force: true });
@@ -5493,6 +5555,13 @@ function ProcessListMonitor() {
5493
5555
  /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, marginTop: 1, children: [
5494
5556
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191\u2193 nav" }),
5495
5557
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7" }),
5558
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "PgUp/PgDn page" }),
5559
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7" }),
5560
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Home/Ctrl+A/g first" }),
5561
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7" }),
5562
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "End/Ctrl+E/G last" })
5563
+ ] }),
5564
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
5496
5565
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Enter kill (SIGTERM)" }),
5497
5566
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7" }),
5498
5567
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Del force kill (SIGKILL)" }),
@@ -6086,7 +6155,15 @@ var SETTINGS_MODES = ["off", "suggest", "auto"];
6086
6155
  var LOG_LEVELS = ["error", "warn", "info", "debug", "trace"];
6087
6156
  var AUDIT_LEVELS = ["minimal", "standard", "full"];
6088
6157
  var COMPACTOR_STRATEGIES = ["hybrid", "intelligent", "selective"];
6158
+ var CONTEXT_MODES = ["balanced", "frugal", "deep", "archival"];
6159
+ var CONTEXT_MODE_DESCS = {
6160
+ balanced: "Normal context usage (default)",
6161
+ frugal: "Conservative token use",
6162
+ deep: "Larger context for complex tasks",
6163
+ archival: "Maximize context retention"
6164
+ };
6089
6165
  var MAX_ITERATIONS_PRESETS = [100, 200, 500, 1e3, 0];
6166
+ var MAX_CONCURRENT_PRESETS = [1, 3, 5, 10, 25, 50, 0];
6090
6167
  var AUTO_PROCEED_MAX_PRESETS = [10, 25, 50, 100, 250, 0];
6091
6168
  var ENHANCE_DELAY_PRESETS = [3e4, 45e3, 6e4, 9e4, 12e4];
6092
6169
  var ENHANCE_LANGUAGES = ["original", "english"];
@@ -6115,7 +6192,7 @@ var MODE_DESC = {
6115
6192
  suggest: "Shows next-step suggestions after each turn",
6116
6193
  auto: "Self-driving \u2014 agent continues automatically"
6117
6194
  };
6118
- var SETTINGS_FIELD_COUNT = 27;
6195
+ var SETTINGS_FIELD_COUNT = 29;
6119
6196
  var CONFIG_SCOPES = ["global", "project"];
6120
6197
  function SettingsPicker({
6121
6198
  field,
@@ -6136,6 +6213,8 @@ function SettingsPicker({
6136
6213
  allowOutsideProjectRoot,
6137
6214
  contextAutoCompact,
6138
6215
  contextStrategy,
6216
+ contextMode,
6217
+ maxConcurrent,
6139
6218
  logLevel,
6140
6219
  auditLevel,
6141
6220
  indexOnStart,
@@ -6239,6 +6318,18 @@ function SettingsPicker({
6239
6318
  value: contextStrategy,
6240
6319
  detail: "hybrid (fast) | intelligent (LLM) | selective"
6241
6320
  },
6321
+ {
6322
+ label: "Context mode",
6323
+ value: contextMode,
6324
+ detail: CONTEXT_MODE_DESCS[contextMode]
6325
+ },
6326
+ // ── Fleet ──
6327
+ { section: "Fleet" },
6328
+ {
6329
+ label: "Max concurrent",
6330
+ value: maxConcurrent === 0 ? "unlimited" : String(maxConcurrent),
6331
+ detail: "Max subagents (0 = unlimited)"
6332
+ },
6242
6333
  // ── Logging ──
6243
6334
  { section: "Logging" },
6244
6335
  {
@@ -6360,6 +6451,145 @@ function SettingsPicker({
6360
6451
  hint ? /* @__PURE__ */ jsx(Text, { color: "yellow", children: hint }) : null
6361
6452
  ] });
6362
6453
  }
6454
+ function isChipExpired(meta, now = Date.now()) {
6455
+ if (meta.expiresIn == null || meta.expiresIn === 0) return false;
6456
+ if (meta.shownAt == null || meta.shownAt === 0) return false;
6457
+ return now >= meta.shownAt + meta.expiresIn * 60 * 1e3;
6458
+ }
6459
+ var ITEM_DESCRIPTIONS = {
6460
+ todos: "Todo items (pending/in-progress/done)",
6461
+ plan: "Plan board items",
6462
+ tasks: "Task board items",
6463
+ fleet: "Fleet agent status",
6464
+ git: "Git branch name",
6465
+ elapsed: "Session elapsed time",
6466
+ context: "Context window usage %",
6467
+ cost: "Token cost estimate",
6468
+ working_dir: "Current working directory",
6469
+ brain: "Brain arbiter decisions",
6470
+ mailbox: "Mailbox unread messages",
6471
+ enhance: "Prompt-enhance countdown",
6472
+ debug_stream: "Stream debug telemetry"
6473
+ };
6474
+ var ITEM_LINE = {
6475
+ context: 1,
6476
+ cost: 1,
6477
+ elapsed: 2,
6478
+ working_dir: 2,
6479
+ git: 2,
6480
+ todos: 3,
6481
+ plan: 3,
6482
+ tasks: 3,
6483
+ fleet: 4,
6484
+ brain: 3,
6485
+ mailbox: 3,
6486
+ enhance: 3,
6487
+ debug_stream: 3
6488
+ };
6489
+ Object.keys(ITEM_LINE).length;
6490
+ var STATUSLINE_ITEMS = [
6491
+ // Line 1
6492
+ "context",
6493
+ "cost",
6494
+ // Line 2
6495
+ "elapsed",
6496
+ "git",
6497
+ "working_dir",
6498
+ // Line 3
6499
+ "brain",
6500
+ "debug_stream",
6501
+ "enhance",
6502
+ "mailbox",
6503
+ "plan",
6504
+ "tasks",
6505
+ "todos",
6506
+ // Line 4
6507
+ "fleet"
6508
+ ];
6509
+ var STREAM_CHIP_KEYS = ["brain", "mailbox", "enhance", "debug_stream"];
6510
+ function groupByLine(items) {
6511
+ const map = /* @__PURE__ */ new Map();
6512
+ for (const item of items) {
6513
+ const line = ITEM_LINE[item];
6514
+ if (!map.has(line)) map.set(line, []);
6515
+ map.get(line).push(item);
6516
+ }
6517
+ return map;
6518
+ }
6519
+ function StatuslinePicker({
6520
+ field,
6521
+ hiddenItems,
6522
+ visibleChips = [],
6523
+ hint
6524
+ }) {
6525
+ const hiddenSet = new Set(hiddenItems);
6526
+ const visibleChipsMap = new Map(visibleChips.map((c) => [c.key, c]));
6527
+ const totalFields = STATUSLINE_ITEMS.length;
6528
+ const byLine = groupByLine(STATUSLINE_ITEMS);
6529
+ const rows = [];
6530
+ for (const [line, items] of [...byLine.entries()].sort((a, b) => a[0] - b[0])) {
6531
+ rows.push({ section: `Line ${line}` });
6532
+ for (const item of items) {
6533
+ const fieldIdx = STATUSLINE_ITEMS.indexOf(item);
6534
+ rows.push({ item, fieldIdx });
6535
+ }
6536
+ }
6537
+ const VISIBLE_FIELDS = 7;
6538
+ const windowStart = Math.max(0, Math.min(field - Math.floor(VISIBLE_FIELDS / 2), totalFields - VISIBLE_FIELDS));
6539
+ const windowEnd = Math.min(windowStart + VISIBLE_FIELDS, totalFields);
6540
+ const hasAbove = windowStart > 0;
6541
+ const hasBelow = windowEnd < totalFields;
6542
+ const boolVal = (item) => {
6543
+ if (hiddenSet.has(item)) return "off";
6544
+ if (STREAM_CHIP_KEYS.includes(item)) {
6545
+ const meta = visibleChipsMap.get(item);
6546
+ if (!meta) return "off";
6547
+ if (meta.expiresIn == null) return "on ";
6548
+ const remainingMs = meta.shownAt + meta.expiresIn * 6e4 - Date.now();
6549
+ if (remainingMs <= 0) return "exp";
6550
+ const remainingMin = Math.max(1, Math.ceil(remainingMs / 6e4));
6551
+ return `~${remainingMin}m`;
6552
+ }
6553
+ return "on ";
6554
+ };
6555
+ const valColor = (item) => {
6556
+ if (hiddenSet.has(item)) return "red";
6557
+ if (STREAM_CHIP_KEYS.includes(item)) {
6558
+ const meta = visibleChipsMap.get(item);
6559
+ if (!meta) return "red";
6560
+ if (isChipExpired(meta)) return "red";
6561
+ return "yellow";
6562
+ }
6563
+ return "green";
6564
+ };
6565
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
6566
+ /* @__PURE__ */ jsx(Text, { color: "cyan", bold: true, children: "\u2501\u2501 Statusline \u2501\u2501" }),
6567
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 move \xB7 \u2190/\u2192 toggle \xB7 Esc to close" }),
6568
+ hasAbove ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u2191 ${windowStart} item${windowStart === 1 ? "" : "s"} above` }) : null,
6569
+ rows.map((row) => {
6570
+ if (row.section) {
6571
+ return /* @__PURE__ */ jsxs(Text, { bold: true, color: "green", children: [
6572
+ "\u2500\u2500 ",
6573
+ row.section,
6574
+ " \u2500\u2500"
6575
+ ] }, `section-${row.section}`);
6576
+ }
6577
+ const item = row.item;
6578
+ const fieldIdx = row.fieldIdx;
6579
+ const selected = fieldIdx === field;
6580
+ return /* @__PURE__ */ jsxs(Text, { inverse: selected, ...selected ? { color: "yellow" } : {}, children: [
6581
+ selected ? "\u203A " : " ",
6582
+ /* @__PURE__ */ jsx(Text, { bold: true, children: item.padEnd(12) }),
6583
+ /* @__PURE__ */ jsx(Text, { color: valColor(item), children: boolVal(item).padEnd(4) }),
6584
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: ITEM_DESCRIPTIONS[item] }),
6585
+ selected ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: " \u2190/\u2192 toggle" }) : null
6586
+ ] }, `row-${item}`);
6587
+ }),
6588
+ hasBelow ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u2193 ${totalFields - windowEnd} item${totalFields - windowEnd === 1 ? "" : "s"} below` }) : null,
6589
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Changes apply instantly \xB7 persisted to ~/.wrongstack/statusline.json \xB7 auto chips expire after ~5m" }),
6590
+ hint ? /* @__PURE__ */ jsx(Text, { color: "yellow", children: hint }) : null
6591
+ ] });
6592
+ }
6363
6593
  var MAX_VISIBLE_ITEMS = 8;
6364
6594
  function SlashMenu({ query, matches, selected }) {
6365
6595
  const placeholder = query ? `/${query}` : "/";
@@ -7379,7 +7609,8 @@ function useTuiControllers({
7379
7609
  agentsMonitorOpen,
7380
7610
  fleetStreamController,
7381
7611
  enhanceController,
7382
- agentsMonitorController
7612
+ agentsMonitorController,
7613
+ onPanelOpen
7383
7614
  }) {
7384
7615
  useEffect(() => {
7385
7616
  if (!fleetStreamController) return;
@@ -7425,6 +7656,16 @@ function useTuiControllers({
7425
7656
  useEffect(() => {
7426
7657
  if (agentsMonitorController) agentsMonitorController.visible = agentsMonitorOpen;
7427
7658
  }, [agentsMonitorController, agentsMonitorOpen]);
7659
+ useEffect(() => {
7660
+ if (!onPanelOpen) return;
7661
+ onPanelOpen.current = (action) => {
7662
+ dispatch({ type: action });
7663
+ return true;
7664
+ };
7665
+ return () => {
7666
+ onPanelOpen.current = null;
7667
+ };
7668
+ }, [onPanelOpen, dispatch]);
7428
7669
  }
7429
7670
  function useBrainEvents(events, dispatch) {
7430
7671
  useEffect(() => {
@@ -8448,6 +8689,8 @@ function reducer(state, action) {
8448
8689
  allowOutsideProjectRoot: action.allowOutsideProjectRoot,
8449
8690
  contextAutoCompact: action.contextAutoCompact,
8450
8691
  contextStrategy: action.contextStrategy,
8692
+ contextMode: action.contextMode,
8693
+ maxConcurrent: action.maxConcurrent,
8451
8694
  logLevel: action.logLevel,
8452
8695
  auditLevel: action.auditLevel,
8453
8696
  indexOnStart: action.indexOnStart,
@@ -8519,45 +8762,57 @@ function reducer(state, action) {
8519
8762
  return { ...state, settingsPicker: { ...sp, contextStrategy: expectDefined$1(COMPACTOR_STRATEGIES[next]), hint: bootHint } };
8520
8763
  }
8521
8764
  if (f === 17) {
8765
+ const i = CONTEXT_MODES.indexOf(sp.contextMode);
8766
+ const base = i < 0 ? 0 : i;
8767
+ const next = (base + action.delta + CONTEXT_MODES.length) % CONTEXT_MODES.length;
8768
+ return { ...state, settingsPicker: { ...sp, contextMode: expectDefined$1(CONTEXT_MODES[next]), hint: bootHint } };
8769
+ }
8770
+ if (f === 18) {
8771
+ const j = MAX_CONCURRENT_PRESETS.indexOf(sp.maxConcurrent);
8772
+ const base = j < 0 ? 0 : j;
8773
+ const next = (base + action.delta + MAX_CONCURRENT_PRESETS.length) % MAX_CONCURRENT_PRESETS.length;
8774
+ return { ...state, settingsPicker: { ...sp, maxConcurrent: expectDefined$1(MAX_CONCURRENT_PRESETS[next]), hint: void 0 } };
8775
+ }
8776
+ if (f === 19) {
8522
8777
  const i = LOG_LEVELS.indexOf(sp.logLevel);
8523
8778
  const base = i < 0 ? 0 : i;
8524
8779
  const next = (base + action.delta + LOG_LEVELS.length) % LOG_LEVELS.length;
8525
8780
  return { ...state, settingsPicker: { ...sp, logLevel: expectDefined$1(LOG_LEVELS[next]), hint: void 0 } };
8526
8781
  }
8527
- if (f === 18) {
8782
+ if (f === 20) {
8528
8783
  const i = AUDIT_LEVELS.indexOf(sp.auditLevel);
8529
8784
  const base = i < 0 ? 0 : i;
8530
8785
  const next = (base + action.delta + AUDIT_LEVELS.length) % AUDIT_LEVELS.length;
8531
8786
  return { ...state, settingsPicker: { ...sp, auditLevel: expectDefined$1(AUDIT_LEVELS[next]), hint: void 0 } };
8532
8787
  }
8533
- if (f === 19) return { ...state, settingsPicker: { ...sp, indexOnStart: !sp.indexOnStart, hint: bootHint } };
8534
- if (f === 20) {
8788
+ if (f === 21) return { ...state, settingsPicker: { ...sp, indexOnStart: !sp.indexOnStart, hint: bootHint } };
8789
+ if (f === 22) {
8535
8790
  const j = MAX_ITERATIONS_PRESETS.indexOf(sp.maxIterations);
8536
8791
  const base = j < 0 ? 0 : j;
8537
8792
  const next = (base + action.delta + MAX_ITERATIONS_PRESETS.length) % MAX_ITERATIONS_PRESETS.length;
8538
8793
  return { ...state, settingsPicker: { ...sp, maxIterations: expectDefined$1(MAX_ITERATIONS_PRESETS[next]), hint: void 0 } };
8539
8794
  }
8540
- if (f === 21) {
8795
+ if (f === 23) {
8541
8796
  const aj = AUTO_PROCEED_MAX_PRESETS.indexOf(sp.autoProceedMaxIterations);
8542
8797
  const abase = aj < 0 ? 0 : aj;
8543
8798
  const anext = (abase + action.delta + AUTO_PROCEED_MAX_PRESETS.length) % AUTO_PROCEED_MAX_PRESETS.length;
8544
8799
  return { ...state, settingsPicker: { ...sp, autoProceedMaxIterations: expectDefined$1(AUTO_PROCEED_MAX_PRESETS[anext]), hint: void 0 } };
8545
8800
  }
8546
- if (f === 22) {
8801
+ if (f === 24) {
8547
8802
  const ej = ENHANCE_DELAY_PRESETS.indexOf(sp.enhanceDelayMs);
8548
8803
  const ebase = ej < 0 ? 0 : ej;
8549
8804
  const enext = (ebase + action.delta + ENHANCE_DELAY_PRESETS.length) % ENHANCE_DELAY_PRESETS.length;
8550
8805
  return { ...state, settingsPicker: { ...sp, enhanceDelayMs: expectDefined$1(ENHANCE_DELAY_PRESETS[enext]), hint: void 0 } };
8551
8806
  }
8552
- if (f === 23) return { ...state, settingsPicker: { ...sp, enhanceEnabled: !sp.enhanceEnabled, hint: void 0 } };
8553
- if (f === 24) {
8807
+ if (f === 25) return { ...state, settingsPicker: { ...sp, enhanceEnabled: !sp.enhanceEnabled, hint: void 0 } };
8808
+ if (f === 26) {
8554
8809
  const i = ENHANCE_LANGUAGES.indexOf(sp.enhanceLanguage);
8555
8810
  const base = i < 0 ? 0 : i;
8556
8811
  const next = (base + action.delta + ENHANCE_LANGUAGES.length) % ENHANCE_LANGUAGES.length;
8557
8812
  return { ...state, settingsPicker: { ...sp, enhanceLanguage: expectDefined$1(ENHANCE_LANGUAGES[next]), hint: void 0 } };
8558
8813
  }
8559
- if (f === 25) return { ...state, settingsPicker: { ...sp, debugStream: !sp.debugStream, hint: void 0 } };
8560
- if (f === 26) {
8814
+ if (f === 27) return { ...state, settingsPicker: { ...sp, debugStream: !sp.debugStream, hint: void 0 } };
8815
+ if (f === 28) {
8561
8816
  const i = CONFIG_SCOPES.indexOf(sp.configScope);
8562
8817
  const base = i < 0 ? 0 : i;
8563
8818
  const next = (base + action.delta + CONFIG_SCOPES.length) % CONFIG_SCOPES.length;
@@ -8567,6 +8822,62 @@ function reducer(state, action) {
8567
8822
  }
8568
8823
  case "settingsHint":
8569
8824
  return { ...state, settingsPicker: { ...state.settingsPicker, hint: action.text } };
8825
+ // ── Statusline picker ───────────────────────────────────────────────
8826
+ case "statuslineOpen":
8827
+ return {
8828
+ ...state,
8829
+ statuslinePicker: { open: true, field: 0, hiddenItems: action.hiddenItems, visibleChips: state.statuslinePicker.visibleChips, hint: void 0 }
8830
+ };
8831
+ case "statuslineClose":
8832
+ return { ...state, statuslinePicker: { ...state.statuslinePicker, open: false, hint: void 0 } };
8833
+ case "statuslineFieldMove": {
8834
+ const totalFields = 13;
8835
+ const next = (state.statuslinePicker.field + action.delta + totalFields) % totalFields;
8836
+ return { ...state, statuslinePicker: { ...state.statuslinePicker, field: next, hint: void 0 } };
8837
+ }
8838
+ case "statuslineFieldSet": {
8839
+ const totalFields = 13;
8840
+ const field = action.field >= 0 && action.field < totalFields ? action.field : 0;
8841
+ return { ...state, statuslinePicker: { ...state.statuslinePicker, field, hint: void 0 } };
8842
+ }
8843
+ case "statuslineToggle": {
8844
+ const cur = state.statuslinePicker;
8845
+ const hiddenSet = new Set(cur.hiddenItems);
8846
+ if (hiddenSet.has(action.item)) {
8847
+ hiddenSet.delete(action.item);
8848
+ } else {
8849
+ hiddenSet.add(action.item);
8850
+ }
8851
+ return { ...state, statuslinePicker: { ...cur, hiddenItems: [...hiddenSet] } };
8852
+ }
8853
+ case "statuslineHint":
8854
+ return { ...state, statuslinePicker: { ...state.statuslinePicker, hint: action.text } };
8855
+ case "statuslineChipShow": {
8856
+ const cur = state.statuslinePicker;
8857
+ const existing = cur.visibleChips.findIndex((c) => c.key === action.key);
8858
+ const meta = action.expiresIn != null ? { key: action.key, shownAt: Date.now(), expiresIn: action.expiresIn } : { key: action.key, shownAt: Date.now() };
8859
+ if (existing >= 0) {
8860
+ const updated = [...cur.visibleChips];
8861
+ updated[existing] = meta;
8862
+ return { ...state, statuslinePicker: { ...cur, visibleChips: updated } };
8863
+ }
8864
+ return { ...state, statuslinePicker: { ...cur, visibleChips: [...cur.visibleChips, meta] } };
8865
+ }
8866
+ case "statuslineChipExpire": {
8867
+ const cur = state.statuslinePicker;
8868
+ return {
8869
+ ...state,
8870
+ statuslinePicker: {
8871
+ ...cur,
8872
+ visibleChips: cur.visibleChips.filter((c) => c.key !== action.key)
8873
+ }
8874
+ };
8875
+ }
8876
+ case "statuslineVisibleChipsSync":
8877
+ return {
8878
+ ...state,
8879
+ statuslinePicker: { ...state.statuslinePicker, visibleChips: action.visibleChips }
8880
+ };
8570
8881
  case "projectPickerOpen":
8571
8882
  return {
8572
8883
  ...state,
@@ -8609,6 +8920,15 @@ function reducer(state, action) {
8609
8920
  }
8610
8921
  case "projectPickerHint":
8611
8922
  return { ...state, projectPicker: { ...state.projectPicker, hint: action.text } };
8923
+ case "fKeyPickerOpen":
8924
+ return { ...state, fKeyPicker: { open: true, selected: 0 } };
8925
+ case "fKeyPickerClose":
8926
+ return { ...state, fKeyPicker: { open: false, selected: 0 } };
8927
+ case "fKeyPickerMove": {
8928
+ const count = 12;
8929
+ const next = (state.fKeyPicker.selected + action.delta + count) % count;
8930
+ return { ...state, fKeyPicker: { ...state.fKeyPicker, selected: next } };
8931
+ }
8612
8932
  case "confirmOpen":
8613
8933
  return { ...state, confirmQueue: [...state.confirmQueue, action.info] };
8614
8934
  case "confirmClose":
@@ -9444,6 +9764,7 @@ function rehydrateHistory(messages, startId, toolCalls) {
9444
9764
  return entries;
9445
9765
  }
9446
9766
  var PASTE_THRESHOLD_CHARS = 200;
9767
+ var SB_PADX2 = 2;
9447
9768
  function App({
9448
9769
  agent,
9449
9770
  slashRegistry,
@@ -9501,6 +9822,7 @@ function App({
9501
9822
  interruptController,
9502
9823
  statuslineHiddenItems,
9503
9824
  setStatuslineHiddenItems,
9825
+ saveStatuslineHiddenItems,
9504
9826
  agentsMonitorController,
9505
9827
  initialGoal,
9506
9828
  initialAsk,
@@ -9516,6 +9838,7 @@ function App({
9516
9838
  getLiveSessions,
9517
9839
  onSwitchToSession,
9518
9840
  initialAgentsMonitorOpen,
9841
+ onPanelOpen,
9519
9842
  subscribeCoordinatorEvents,
9520
9843
  onCoordinatorStart,
9521
9844
  onCoordinatorStop,
@@ -9550,6 +9873,8 @@ function App({
9550
9873
  modeLabel,
9551
9874
  statuslineHiddenItems
9552
9875
  });
9876
+ const hiddenItemsRef = useRef(hiddenItems);
9877
+ hiddenItemsRef.current = hiddenItems;
9553
9878
  const prevBranchRef = useRef(null);
9554
9879
  const [indexState, setIndexState] = useState(() => getIndexState());
9555
9880
  useEffect(() => {
@@ -9583,7 +9908,10 @@ function App({
9583
9908
  }, [statuslineHiddenItems]);
9584
9909
  useEffect(() => {
9585
9910
  setStatuslineHiddenItems(hiddenItems);
9586
- }, [setStatuslineHiddenItems, hiddenItems]);
9911
+ saveStatuslineHiddenItems(hiddenItems).catch?.((err) => {
9912
+ console.error("[statusline] failed to persist hidden items:", err);
9913
+ });
9914
+ }, [setStatuslineHiddenItems, saveStatuslineHiddenItems, hiddenItems]);
9587
9915
  const projectRoot = agent.ctx.projectRoot;
9588
9916
  const refreshGoalSummary = useCallback(() => {
9589
9917
  if (!projectRoot) return;
@@ -9675,8 +10003,10 @@ function App({
9675
10003
  },
9676
10004
  autonomyPicker: { open: false, options: [], selected: 0 },
9677
10005
  resumePicker: { open: false, sessions: [], selected: 0, busy: false, hint: void 0, error: void 0 },
9678
- 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, tokenSavingTier: "off", allowOutsideProjectRoot: true, contextAutoCompact: true, contextStrategy: "hybrid", logLevel: "info", auditLevel: "standard", indexOnStart: true, maxIterations: 500, autoProceedMaxIterations: 50, enhanceDelayMs: 6e4, enhanceEnabled: true, enhanceLanguage: "original", debugStream: false, configScope: "global" },
10006
+ 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, tokenSavingTier: "off", allowOutsideProjectRoot: true, contextAutoCompact: true, contextStrategy: "hybrid", contextMode: "balanced", maxConcurrent: 10, logLevel: "info", auditLevel: "standard", indexOnStart: true, maxIterations: 500, autoProceedMaxIterations: 50, enhanceDelayMs: 6e4, enhanceEnabled: true, enhanceLanguage: "original", debugStream: false, configScope: "global" },
10007
+ statuslinePicker: { open: false, field: 0, hiddenItems: [], visibleChips: [], hint: void 0 },
9679
10008
  projectPicker: { open: false, allItems: [], items: [], selected: 0, filter: "", hint: void 0 },
10009
+ fKeyPicker: { open: false, selected: 0 },
9680
10010
  confirmQueue: [],
9681
10011
  enhance: null,
9682
10012
  enhanceEnabled,
@@ -9730,6 +10060,52 @@ function App({
9730
10060
  debugStreamStats: null,
9731
10061
  countdown: null
9732
10062
  });
10063
+ useEffect(() => {
10064
+ if (state.statuslinePicker.open) {
10065
+ const pickerHidden = state.statuslinePicker.hiddenItems;
10066
+ const currentHidden = new Set(hiddenItems);
10067
+ const pickerHiddenSet = new Set(pickerHidden);
10068
+ const differs = currentHidden.size !== pickerHiddenSet.size || pickerHidden.some((item) => !currentHidden.has(item)) || hiddenItems.some((item) => !pickerHiddenSet.has(item));
10069
+ if (differs) {
10070
+ setHiddenItems([...pickerHidden]);
10071
+ }
10072
+ }
10073
+ }, [state.statuslinePicker.hiddenItems, state.statuslinePicker.open, setHiddenItems, hiddenItems]);
10074
+ const prevBrainPromptRef = useRef(state.brainPrompt);
10075
+ const prevEnhanceRef = useRef(state.enhance);
10076
+ useEffect(() => {
10077
+ if (state.brainPrompt && !prevBrainPromptRef.current) {
10078
+ dispatch({ type: "statuslineChipShow", key: "brain", expiresIn: 5 });
10079
+ } else if (!state.brainPrompt && prevBrainPromptRef.current) {
10080
+ if (state.statuslinePicker.visibleChips.some((c) => c.key === "brain")) {
10081
+ dispatch({ type: "statuslineChipExpire", key: "brain" });
10082
+ }
10083
+ }
10084
+ prevBrainPromptRef.current = state.brainPrompt;
10085
+ if (state.enhance && !prevEnhanceRef.current) {
10086
+ dispatch({ type: "statuslineChipShow", key: "enhance", expiresIn: 5 });
10087
+ } else if (!state.enhance && prevEnhanceRef.current) {
10088
+ if (state.statuslinePicker.visibleChips.some((c) => c.key === "enhance")) {
10089
+ dispatch({ type: "statuslineChipExpire", key: "enhance" });
10090
+ }
10091
+ }
10092
+ prevEnhanceRef.current = state.enhance;
10093
+ }, [
10094
+ state.brainPrompt,
10095
+ state.enhance,
10096
+ state.statuslinePicker.visibleChips,
10097
+ dispatch
10098
+ ]);
10099
+ useEffect(() => {
10100
+ const interval = setInterval(() => {
10101
+ const now = Date.now();
10102
+ const expired = state.statuslinePicker.visibleChips.filter((c) => isChipExpired(c, now));
10103
+ for (const chip of expired) {
10104
+ dispatch({ type: "statuslineChipExpire", key: chip.key });
10105
+ }
10106
+ }, 3e4);
10107
+ return () => clearInterval(interval);
10108
+ }, [state.statuslinePicker.visibleChips, dispatch]);
9733
10109
  useAutonomousCoordinator(subscribeCoordinatorEvents, dispatch);
9734
10110
  const builderRef = useRef(null);
9735
10111
  if (builderRef.current === null) {
@@ -10329,6 +10705,8 @@ function App({
10329
10705
  allowOutsideProjectRoot: sp.allowOutsideProjectRoot,
10330
10706
  contextAutoCompact: sp.contextAutoCompact,
10331
10707
  contextStrategy: sp.contextStrategy,
10708
+ contextMode: sp.contextMode,
10709
+ maxConcurrent: sp.maxConcurrent,
10332
10710
  logLevel: sp.logLevel,
10333
10711
  auditLevel: sp.auditLevel,
10334
10712
  indexOnStart: sp.indexOnStart,
@@ -10405,6 +10783,7 @@ function App({
10405
10783
  const allCommands = slashRegistry.listWithOwner();
10406
10784
  const CATEGORY_ORDER = ["Run", "Session", "Inspect", "Agent", "Config", "App"];
10407
10785
  const matches = allCommands.filter(({ cmd }) => {
10786
+ if (query === "" && cmd.hidden) return false;
10408
10787
  const name = cmd.name.toLowerCase();
10409
10788
  const aliases = cmd.aliases ?? [];
10410
10789
  return name.includes(query) || aliases.some((a) => a.toLowerCase().includes(query));
@@ -10691,6 +11070,9 @@ function App({
10691
11070
  const items = await getProjectPickerItems();
10692
11071
  dispatch({ type: "projectPickerOpen", items });
10693
11072
  }, [getProjectPickerItems]);
11073
+ const openFKeyPicker = React5.useCallback(() => {
11074
+ dispatch({ type: "fKeyPickerOpen" });
11075
+ }, [dispatch]);
10694
11076
  const loadLiveSessions = React5.useCallback(async () => {
10695
11077
  if (!getLiveSessions) {
10696
11078
  dispatch({ type: "sessionsPanelSet", sessions: [] });
@@ -10733,6 +11115,8 @@ function App({
10733
11115
  allowOutsideProjectRoot: s2.allowOutsideProjectRoot ?? true,
10734
11116
  contextAutoCompact: s2.contextAutoCompact ?? true,
10735
11117
  contextStrategy: s2.contextStrategy ?? "hybrid",
11118
+ contextMode: s2.contextMode ?? "balanced",
11119
+ maxConcurrent: s2.maxConcurrent ?? 10,
10736
11120
  logLevel: s2.logLevel ?? "info",
10737
11121
  auditLevel: s2.auditLevel ?? "standard",
10738
11122
  indexOnStart: s2.indexOnStart ?? true,
@@ -10869,6 +11253,8 @@ function App({
10869
11253
  allowOutsideProjectRoot: sp.allowOutsideProjectRoot,
10870
11254
  contextAutoCompact: sp.contextAutoCompact,
10871
11255
  contextStrategy: sp.contextStrategy,
11256
+ contextMode: sp.contextMode,
11257
+ maxConcurrent: sp.maxConcurrent,
10872
11258
  logLevel: sp.logLevel,
10873
11259
  auditLevel: sp.auditLevel,
10874
11260
  indexOnStart: sp.indexOnStart,
@@ -10901,6 +11287,8 @@ function App({
10901
11287
  state.settingsPicker.allowOutsideProjectRoot,
10902
11288
  state.settingsPicker.contextAutoCompact,
10903
11289
  state.settingsPicker.contextStrategy,
11290
+ state.settingsPicker.contextMode,
11291
+ state.settingsPicker.maxConcurrent,
10904
11292
  state.settingsPicker.logLevel,
10905
11293
  state.settingsPicker.auditLevel,
10906
11294
  state.settingsPicker.indexOnStart,
@@ -10928,6 +11316,20 @@ function App({
10928
11316
  slashRegistry.unregister("model");
10929
11317
  };
10930
11318
  }, [slashRegistry, getPickableProviders, switchProviderAndModel, openModelPicker]);
11319
+ useEffect(() => {
11320
+ const cmd = {
11321
+ name: "f",
11322
+ description: "Open F-key panel picker. Arrow keys to navigate, Enter to open, Esc to close.",
11323
+ async run() {
11324
+ openFKeyPicker();
11325
+ return { message: void 0 };
11326
+ }
11327
+ };
11328
+ slashRegistry.register(cmd, "tui", { official: true });
11329
+ return () => {
11330
+ slashRegistry.unregister("f");
11331
+ };
11332
+ }, [slashRegistry, openFKeyPicker]);
10931
11333
  useEffect(() => {
10932
11334
  if (!getSettings || !saveSettings) return;
10933
11335
  const cmd = {
@@ -10944,6 +11346,26 @@ function App({
10944
11346
  slashRegistry.unregister("settings");
10945
11347
  };
10946
11348
  }, [slashRegistry, getSettings, saveSettings, openSettings]);
11349
+ useEffect(() => {
11350
+ const cmd = {
11351
+ name: "statusline",
11352
+ aliases: ["sl"],
11353
+ description: "Customize status bar chips: /statusline (interactive) or /statusline <item> [on|off]",
11354
+ async run(args) {
11355
+ if (args.trim()) return { message: void 0 };
11356
+ const hookHidden = hiddenItemsRef.current;
11357
+ const reducerStreamHidden = stateRef.current.statuslinePicker.hiddenItems.filter(
11358
+ (item) => !hookHidden.includes(item)
11359
+ );
11360
+ dispatch({ type: "statuslineOpen", hiddenItems: [...hookHidden, ...reducerStreamHidden] });
11361
+ return { message: void 0 };
11362
+ }
11363
+ };
11364
+ slashRegistry.register(cmd, "tui", { official: true });
11365
+ return () => {
11366
+ slashRegistry.unregister("statusline");
11367
+ };
11368
+ }, [slashRegistry]);
10947
11369
  useEffect(() => {
10948
11370
  const cmd = {
10949
11371
  name: "mailbox",
@@ -11265,7 +11687,8 @@ function App({
11265
11687
  agentsMonitorOpen: state.agentsMonitorOpen,
11266
11688
  fleetStreamController,
11267
11689
  enhanceController,
11268
- agentsMonitorController
11690
+ agentsMonitorController,
11691
+ onPanelOpen
11269
11692
  });
11270
11693
  useEffect(() => {
11271
11694
  if (!interruptController) return;
@@ -11677,6 +12100,32 @@ function App({
11677
12100
  }
11678
12101
  return;
11679
12102
  }
12103
+ if (state.statuslinePicker.open) {
12104
+ if (key.escape) {
12105
+ dispatch({ type: "statuslineClose" });
12106
+ return;
12107
+ }
12108
+ if (key.mouse?.kind === "wheel") {
12109
+ dispatch({ type: "statuslineFieldMove", delta: key.mouse.wheel > 0 ? -1 : 1 });
12110
+ return;
12111
+ }
12112
+ if (key.upArrow) {
12113
+ dispatch({ type: "statuslineFieldMove", delta: -1 });
12114
+ return;
12115
+ }
12116
+ if (key.downArrow) {
12117
+ dispatch({ type: "statuslineFieldMove", delta: 1 });
12118
+ return;
12119
+ }
12120
+ if (key.leftArrow || key.rightArrow) {
12121
+ const focused = STATUSLINE_ITEMS[state.statuslinePicker.field];
12122
+ if (focused) {
12123
+ dispatch({ type: "statuslineToggle", item: focused });
12124
+ }
12125
+ return;
12126
+ }
12127
+ return;
12128
+ }
11680
12129
  if (state.projectPicker.open) {
11681
12130
  if (key.escape) {
11682
12131
  if (state.projectPicker.filter) {
@@ -11868,6 +12317,29 @@ function App({
11868
12317
  return;
11869
12318
  }
11870
12319
  }
12320
+ if (state.fKeyPicker.open) {
12321
+ if (key.escape) {
12322
+ dispatch({ type: "fKeyPickerClose" });
12323
+ return;
12324
+ }
12325
+ if (key.upArrow) {
12326
+ dispatch({ type: "fKeyPickerMove", delta: -1 });
12327
+ return;
12328
+ }
12329
+ if (key.downArrow) {
12330
+ dispatch({ type: "fKeyPickerMove", delta: 1 });
12331
+ return;
12332
+ }
12333
+ if (isEnter) {
12334
+ const selected = state.fKeyPicker.selected;
12335
+ const entry = F_KEY_ENTRIES[selected];
12336
+ if (!entry) return;
12337
+ dispatch({ type: "fKeyPickerClose" });
12338
+ dispatch({ type: entry.action });
12339
+ return;
12340
+ }
12341
+ return;
12342
+ }
11871
12343
  if (state.picker.open) {
11872
12344
  if (key.escape) {
11873
12345
  dispatch({ type: "pickerClose" });
@@ -12150,10 +12622,12 @@ function App({
12150
12622
  featureMemory: cfg.featureMemory ?? true,
12151
12623
  featureSkills: cfg.featureSkills ?? true,
12152
12624
  featureModelsRegistry: cfg.featureModelsRegistry ?? true,
12153
- tokenSavingTier: cfg.featureTokenSaving ?? "off",
12625
+ tokenSavingTier: cfg.tokenSavingTier ?? "off",
12154
12626
  allowOutsideProjectRoot: cfg.allowOutsideProjectRoot ?? true,
12155
12627
  contextAutoCompact: cfg.contextAutoCompact ?? true,
12156
12628
  contextStrategy: cfg.contextStrategy ?? "hybrid",
12629
+ contextMode: cfg.contextMode ?? "balanced",
12630
+ maxConcurrent: cfg.maxConcurrent ?? 10,
12157
12631
  logLevel: cfg.logLevel ?? "info",
12158
12632
  auditLevel: cfg.auditLevel ?? "standard",
12159
12633
  indexOnStart: cfg.indexOnStart ?? true,
@@ -12217,7 +12691,8 @@ function App({
12217
12691
  if (state.processListOpen) {
12218
12692
  return;
12219
12693
  }
12220
- 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.goalPanelOpen && !state.sessionsPanelOpen && !state.autoPhase?.monitorOpen) {
12694
+ const overlayOpen = state.monitorOpen || state.agentsMonitorOpen || state.worktreeMonitorOpen || state.todosMonitorOpen || state.queuePanelOpen || state.processListOpen || state.goalPanelOpen || state.sessionsPanelOpen || state.coordinator.monitorOpen || state.helpOpen || (state.autoPhase?.monitorOpen ?? false) || state.rewindOverlay !== null;
12695
+ if (input === "?" && !key.ctrl && !key.meta && draftRef.current.buffer === "" && !overlayOpen) {
12221
12696
  dispatch({ type: "toggleHelp" });
12222
12697
  return;
12223
12698
  }
@@ -12333,7 +12808,7 @@ function App({
12333
12808
  setDraft(buffer, buffer.length);
12334
12809
  return;
12335
12810
  }
12336
- if (key.upArrow || key.downArrow || key.pageUp || key.pageDown) {
12811
+ if (!overlayOpen && (key.upArrow || key.downArrow || key.pageUp || key.pageDown)) {
12337
12812
  const width = stdout?.columns ?? 80;
12338
12813
  const rows = layoutInputRows(INPUT_PROMPT, buffer, cursor, width);
12339
12814
  if (rows.length <= 1) ; else {
@@ -12384,7 +12859,6 @@ function App({
12384
12859
  }
12385
12860
  }
12386
12861
  }
12387
- const overlayOpen = state.monitorOpen || state.agentsMonitorOpen || state.worktreeMonitorOpen || state.todosMonitorOpen || state.queuePanelOpen || state.processListOpen || state.goalPanelOpen || state.sessionsPanelOpen || state.coordinator.monitorOpen || state.helpOpen || (state.autoPhase?.monitorOpen ?? false) || state.rewindOverlay !== null;
12388
12862
  if (mouseMode && !overlayOpen) {
12389
12863
  if (key.mouse?.kind === "wheel") {
12390
12864
  if (key.mouse.shift) dispatch({ type: "scrollPage", dir: key.mouse.wheel > 0 ? "up" : "down" });
@@ -12435,6 +12909,40 @@ function App({
12435
12909
  dispatch({ type: "toggleTodosMonitor" });
12436
12910
  return;
12437
12911
  }
12912
+ const hiddenSet = new Set(state.statuslinePicker.hiddenItems);
12913
+ if (my === rowFor(2)) {
12914
+ const mxLocal = mx - SB_PADX2 - 1;
12915
+ if (!hiddenSet.has("todos") && mxLocal >= 0 && mxLocal < 20) {
12916
+ dispatch({ type: "statuslineFieldSet", field: 11 });
12917
+ dispatch({ type: "statuslineOpen", hiddenItems: state.statuslinePicker.hiddenItems });
12918
+ return;
12919
+ }
12920
+ if (!hiddenSet.has("plan")) {
12921
+ const planStart = 21;
12922
+ if (mxLocal >= planStart && mxLocal < planStart + 22) {
12923
+ dispatch({ type: "statuslineFieldSet", field: 9 });
12924
+ dispatch({ type: "statuslineOpen", hiddenItems: state.statuslinePicker.hiddenItems });
12925
+ return;
12926
+ }
12927
+ }
12928
+ if (!hiddenSet.has("tasks")) {
12929
+ const tasksStart = 44;
12930
+ if (mxLocal >= tasksStart && mxLocal < tasksStart + 26) {
12931
+ dispatch({ type: "statuslineFieldSet", field: 10 });
12932
+ dispatch({ type: "statuslineOpen", hiddenItems: state.statuslinePicker.hiddenItems });
12933
+ return;
12934
+ }
12935
+ }
12936
+ }
12937
+ if (my === rowFor(3) && !hiddenSet.has("fleet")) {
12938
+ const mxLocal = mx - SB_PADX2 - 1;
12939
+ const fleetStart = 0;
12940
+ if (mxLocal >= fleetStart && mxLocal < fleetStart + 22) {
12941
+ dispatch({ type: "statuslineFieldSet", field: 12 });
12942
+ dispatch({ type: "statuslineOpen", hiddenItems: state.statuslinePicker.hiddenItems });
12943
+ return;
12944
+ }
12945
+ }
12438
12946
  }
12439
12947
  if (key.pageUp) {
12440
12948
  dispatch({ type: "scrollPage", dir: "up" });
@@ -12513,7 +13021,7 @@ function App({
12513
13021
  setDraft(next2, cursor);
12514
13022
  return;
12515
13023
  }
12516
- if (key.ctrl) {
13024
+ if (key.ctrl && input === "v") {
12517
13025
  await pasteClipboardText();
12518
13026
  return;
12519
13027
  }
@@ -13163,6 +13671,8 @@ User message:
13163
13671
  allowOutsideProjectRoot: state.settingsPicker.allowOutsideProjectRoot,
13164
13672
  contextAutoCompact: state.settingsPicker.contextAutoCompact,
13165
13673
  contextStrategy: state.settingsPicker.contextStrategy,
13674
+ contextMode: state.settingsPicker.contextMode,
13675
+ maxConcurrent: state.settingsPicker.maxConcurrent,
13166
13676
  logLevel: state.settingsPicker.logLevel,
13167
13677
  auditLevel: state.settingsPicker.auditLevel,
13168
13678
  indexOnStart: state.settingsPicker.indexOnStart,
@@ -13176,6 +13686,15 @@ User message:
13176
13686
  hint: state.settingsPicker.hint
13177
13687
  }
13178
13688
  ) : null,
13689
+ state.statuslinePicker.open ? /* @__PURE__ */ jsx(
13690
+ StatuslinePicker,
13691
+ {
13692
+ field: state.statuslinePicker.field,
13693
+ hiddenItems: state.statuslinePicker.hiddenItems,
13694
+ visibleChips: state.statuslinePicker.visibleChips,
13695
+ hint: state.statuslinePicker.hint
13696
+ }
13697
+ ) : null,
13179
13698
  state.projectPicker.open ? /* @__PURE__ */ jsx(
13180
13699
  ProjectPicker,
13181
13700
  {
@@ -13185,6 +13704,7 @@ User message:
13185
13704
  hint: state.projectPicker.hint
13186
13705
  }
13187
13706
  ) : null,
13707
+ state.fKeyPicker.open ? /* @__PURE__ */ jsx(FKeyPicker, { selected: state.fKeyPicker.selected }) : null,
13188
13708
  state.sessionsPanelOpen ? /* @__PURE__ */ jsx(
13189
13709
  SessionsPanel,
13190
13710
  {
@@ -13340,6 +13860,7 @@ User message:
13340
13860
  subagentCount: Object.keys(state.fleet).length,
13341
13861
  processCount: getProcessRegistry().activeCount,
13342
13862
  hiddenItems,
13863
+ visibleChips: state.statuslinePicker.visibleChips,
13343
13864
  events,
13344
13865
  eternalStage: state.eternalStage,
13345
13866
  goalSummary: state.goalSummary,
@@ -13800,6 +14321,7 @@ async function runTui(opts) {
13800
14321
  enhanceEnabled: opts.enhanceController?.enabled ?? true,
13801
14322
  statuslineHiddenItems: opts.statuslineHiddenItems,
13802
14323
  setStatuslineHiddenItems: opts.setStatuslineHiddenItems,
14324
+ saveStatuslineHiddenItems: opts.saveStatuslineHiddenItems,
13803
14325
  agentsMonitorController: opts.agentsMonitorController,
13804
14326
  initialGoal: opts.initialGoal,
13805
14327
  initialAsk: opts.initialAsk,
@@ -13836,6 +14358,7 @@ async function runTui(opts) {
13836
14358
  onSwitchToSession: opts.onSwitchToSession,
13837
14359
  initialAgentsMonitorOpen: opts.initialAgentsMonitorOpen,
13838
14360
  subscribeCoordinatorEvents: opts.subscribeCoordinatorEvents,
14361
+ onPanelOpen: opts.onPanelOpen,
13839
14362
  onCoordinatorStart: opts.onCoordinatorStart,
13840
14363
  onCoordinatorStop: opts.onCoordinatorStop
13841
14364
  }),