@wrongstack/tui 0.264.0 → 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
@@ -1,15 +1,16 @@
1
- import { writeErr, resolveProjectDir, wstackGlobalRoot, GlobalMailbox, resolveWstackPaths, loadGoal, InputBuilder, DefaultSessionRewinder, writeOut, formatTodosList, buildGoalPreamble, expectDefined as expectDefined$1, shouldEnhance, enhanceUserPrompt, recentTextTurns, normalizedEqual, buildChildEnv } from '@wrongstack/core';
1
+ import { writeErr, resolveProjectDir, wstackGlobalRoot, GlobalMailbox, resolveWstackPaths, loadGoal, InputBuilder, DefaultSessionRewinder, writeOut, formatTodosList, buildGoalPreamble, expectDefined as expectDefined$1, projectSlug, shouldEnhance, enhanceUserPrompt, recentTextTurns, normalizedEqual, buildChildEnv } from '@wrongstack/core';
2
2
  export { buildGoalPreamble } from '@wrongstack/core';
3
3
  import { Box as Box$1, useInput, useStdin, useStdout, Text as Text$1, render, useApp, measureElement, Static } from 'ink';
4
4
  import { randomUUID } from 'crypto';
5
- import * as path4 from 'path';
5
+ import * as path5 from 'path';
6
6
  import React5, { forwardRef, useState, useEffect, useMemo, memo, useRef, useCallback, useReducer, useLayoutEffect } from 'react';
7
- import * as fs2 from 'fs/promises';
8
- import { expectDefined, toErrorMessage } from '@wrongstack/core/utils';
7
+ import * as fs3 from 'fs/promises';
8
+ import { expectDefined, toErrorMessage, resolveWstackPaths as resolveWstackPaths$1 } from '@wrongstack/core/utils';
9
9
  import { routeImagesForModel } from '@wrongstack/runtime/vision';
10
10
  import { getIndexState, onIndexStateChange, getProcessRegistry } from '@wrongstack/tools';
11
11
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
12
12
  import { readClipboardText, readClipboardImage } from '@wrongstack/runtime/clipboard';
13
+ import { getToolIcon, TOOL_ICON_CONFIG } from '@wrongstack/tools/tool-icons';
13
14
  import * as v8 from 'v8';
14
15
  import { spawn } from 'child_process';
15
16
 
@@ -108,6 +109,18 @@ function useTokenCounterRefresh(tokenCounter, events) {
108
109
  }, [tokenCounter, events]);
109
110
  return data;
110
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
+ }
111
124
  var MODE_ICONS = {
112
125
  teach: "\u{1F9D1}\u200D\u{1F3EB}",
113
126
  brief: "\u26A1",
@@ -166,6 +179,7 @@ function StatusBar({
166
179
  eternalStage,
167
180
  goalSummary,
168
181
  indexState,
182
+ breakerCountdown,
169
183
  modeLabel,
170
184
  debugStreamStats,
171
185
  enhanceCountdown,
@@ -175,7 +189,8 @@ function StatusBar({
175
189
  sessionCount,
176
190
  mailbox,
177
191
  tokenSavingMode,
178
- toolCount
192
+ toolCount,
193
+ visibleChips = []
179
194
  }) {
180
195
  const { stdout } = useStdout();
181
196
  const [termWidth, setTermWidth] = useState(stdout?.columns ?? 90);
@@ -216,13 +231,13 @@ function StatusBar({
216
231
  const hasAutoProceed = autoProceedCountdown != null && autoProceedCountdown > 0;
217
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;
218
233
  const fleetHasActivity = fleet && (fleet.running > 0 || fleet.idle > 0 || fleet.pending > 0 || fleet.completed > 0) || subagentCount > 0;
219
- const hasBrainActivity = !!brain && brain.state !== "idle";
220
- const hasDebugStream = !!debugStreamStats;
221
- 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);
222
237
  const hasNextStepsAutoSubmit = nextStepsAutoSubmitCountdown != null && nextStepsAutoSubmitCountdown > 0;
223
238
  const countdownColor = nextStepsAutoSubmitCountdown != null ? nextStepsAutoSubmitCountdown > 20 ? "green" : nextStepsAutoSubmitCountdown > 10 ? "yellow" : "red" : "green";
224
239
  const hasTaskActivity = tasks && (tasks.pending > 0 || tasks.inProgress > 0 || tasks.completed > 0 || tasks.blocked > 0 || tasks.failed > 0);
225
- 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;
226
241
  return /* @__PURE__ */ jsxs(
227
242
  Box,
228
243
  {
@@ -302,7 +317,7 @@ function StatusBar({
302
317
  "%"
303
318
  ] })
304
319
  ] }) : null,
305
- cost && cost.total > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
320
+ cost && cost.total > 0 && !hiddenSet.has("cost") ? /* @__PURE__ */ jsxs(Fragment, { children: [
306
321
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
307
322
  /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
308
323
  "$",
@@ -340,7 +355,21 @@ function StatusBar({
340
355
  ] }) : indexState?.circuit?.state === "open" ? /* @__PURE__ */ jsxs(Fragment, { children: [
341
356
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
342
357
  /* @__PURE__ */ jsx(Text, { color: "red", children: "\u2699 index paused (/reindex)" })
343
- ] }) : null
358
+ ] }) : null,
359
+ breakerCountdown ? (() => {
360
+ const secs = Math.ceil(breakerCountdown.remainingMs / 1e3);
361
+ const ratio = breakerCountdown.totalMs > 0 ? breakerCountdown.remainingMs / breakerCountdown.totalMs : 0;
362
+ const c = secs > 20 ? "green" : secs > 10 ? "yellow" : "red";
363
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
364
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
365
+ /* @__PURE__ */ jsxs(Text, { color: c, bold: true, children: [
366
+ "\u26A1 kill/reset in ",
367
+ secs,
368
+ "s",
369
+ ratio <= 0.25 ? "!" : ""
370
+ ] })
371
+ ] });
372
+ })() : null
344
373
  ] })
345
374
  ) }),
346
375
  hasSecondLine ? /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 2, children: [
@@ -416,7 +445,7 @@ function StatusBar({
416
445
  "s"
417
446
  ] })
418
447
  ] }) : null,
419
- git ? /* @__PURE__ */ jsxs(Fragment, { children: [
448
+ git && !hiddenSet.has("git") ? /* @__PURE__ */ jsxs(Fragment, { children: [
420
449
  yolo || startedAt != null || projectName || workingDir ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
421
450
  /* @__PURE__ */ jsxs(Text, { children: [
422
451
  /* @__PURE__ */ jsxs(Text, { color: "magenta", children: [
@@ -434,7 +463,7 @@ function StatusBar({
434
463
  ] })
435
464
  ] }) : null,
436
465
  sessionCount != null && sessionCount > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
437
- 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,
438
467
  /* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
439
468
  "\u29C9 ",
440
469
  sessionCount,
@@ -443,7 +472,7 @@ function StatusBar({
443
472
  ] })
444
473
  ] }) : null,
445
474
  toolCount != null ? /* @__PURE__ */ jsxs(Fragment, { children: [
446
- 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,
447
476
  /* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
448
477
  "\u{1F527} ",
449
478
  toolCount,
@@ -452,12 +481,12 @@ function StatusBar({
452
481
  ] })
453
482
  ] }) : null,
454
483
  tokenSavingMode ? /* @__PURE__ */ jsxs(Fragment, { children: [
455
- 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,
456
485
  /* @__PURE__ */ jsx(Text, { color: "yellow", bold: true, children: "\u{1F4BE} save" })
457
486
  ] }) : null
458
487
  ] }) : /* @__PURE__ */ jsx(Box, { height: 1, children: /* @__PURE__ */ jsx(Text, { children: " " }) }),
459
488
  hasThirdLine ? /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 2, children: [
460
- 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: [
461
490
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "todos " }),
462
491
  todos.inProgress > 0 ? /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
463
492
  "\u231B",
@@ -474,8 +503,8 @@ function StatusBar({
474
503
  todos.completed
475
504
  ] }) : null
476
505
  ] }) : null,
477
- plan && (plan.open > 0 || plan.inProgress > 0 || plan.done > 0) ? /* @__PURE__ */ jsxs(Fragment, { children: [
478
- 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,
479
508
  /* @__PURE__ */ jsxs(Text, { children: [
480
509
  /* @__PURE__ */ jsx(Text, { color: "cyan", children: "\u{1F4CB} " }),
481
510
  plan.inProgress > 0 ? /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
@@ -491,11 +520,16 @@ function StatusBar({
491
520
  plan.done > 0 ? /* @__PURE__ */ jsxs(Text, { color: "green", children: [
492
521
  "\u2713",
493
522
  plan.done
523
+ ] }) : null,
524
+ plan.scope ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
525
+ " [",
526
+ plan.scope,
527
+ "]"
494
528
  ] }) : null
495
529
  ] })
496
530
  ] }) : null,
497
- hasTaskActivity ? /* @__PURE__ */ jsxs(Fragment, { children: [
498
- 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,
499
533
  /* @__PURE__ */ jsxs(Text, { children: [
500
534
  /* @__PURE__ */ jsx(Text, { color: "magenta", children: "\u26A1 " }),
501
535
  tasks.inProgress > 0 ? /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
@@ -521,11 +555,16 @@ function StatusBar({
521
555
  tasks.failed > 0 ? /* @__PURE__ */ jsxs(Text, { color: "red", children: [
522
556
  "\u2717",
523
557
  tasks.failed
558
+ ] }) : null,
559
+ tasks.scope ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
560
+ " [",
561
+ tasks.scope,
562
+ "]"
524
563
  ] }) : null
525
564
  ] })
526
565
  ] }) : null,
527
- fleetHasActivity ? /* @__PURE__ */ jsxs(Fragment, { children: [
528
- 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,
529
568
  fleet ? /* @__PURE__ */ jsxs(Text, { children: [
530
569
  /* @__PURE__ */ jsx(Text, { color: "blue", children: "\u{1F310} " }),
531
570
  fleet.running > 0 ? /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
@@ -555,12 +594,12 @@ function StatusBar({
555
594
  subagentCount === 1 ? "" : "s"
556
595
  ] })
557
596
  ] }) : null,
558
- hasBrainActivity && brain ? /* @__PURE__ */ jsxs(Fragment, { children: [
559
- 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,
560
599
  /* @__PURE__ */ jsx(BrainChip, { brain })
561
600
  ] }) : null,
562
- hasDebugStream && debugStreamStats ? /* @__PURE__ */ jsxs(Fragment, { children: [
563
- 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,
564
603
  /* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
565
604
  /* @__PURE__ */ jsx(Text, { bold: true, children: "\u{1F41B} stream" }),
566
605
  /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
@@ -583,8 +622,8 @@ function StatusBar({
583
622
  ] })
584
623
  ] })
585
624
  ] }) : null,
586
- hasEnhanceCountdown && enhanceCountdown != null ? /* @__PURE__ */ jsxs(Fragment, { children: [
587
- 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,
588
627
  /* @__PURE__ */ jsxs(Text, { color: enhanceCountdown > 15 ? "green" : enhanceCountdown > 5 ? "yellow" : "red", children: [
589
628
  "\u23F3 auto-send in ",
590
629
  enhanceCountdown,
@@ -592,7 +631,7 @@ function StatusBar({
592
631
  ] })
593
632
  ] }) : null,
594
633
  hasNextStepsAutoSubmit && nextStepsAutoSubmitCountdown != null ? /* @__PURE__ */ jsxs(Fragment, { children: [
595
- 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,
596
635
  /* @__PURE__ */ jsxs(Text, { color: countdownColor, bold: true, children: [
597
636
  "\u23F3 ",
598
637
  nextStepsAutoSubmitCountdown,
@@ -605,7 +644,7 @@ function StatusBar({
605
644
  ] })
606
645
  ] }) : null
607
646
  ] }) : /* @__PURE__ */ jsx(Box, { height: 1, children: /* @__PURE__ */ jsx(Text, { children: " " }) }),
608
- mailbox ? /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 2, children: [
647
+ mailbox && !hiddenSet.has("mailbox") ? /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 2, children: [
609
648
  mailbox.unread > 0 ? /* @__PURE__ */ jsxs(Text, { color: "yellow", bold: true, children: [
610
649
  "\u2709 ",
611
650
  mailbox.unread,
@@ -1765,8 +1804,8 @@ function FilePicker({ query, matches, selected }) {
1765
1804
  ] }, m))
1766
1805
  ] });
1767
1806
  }
1768
- function highlight(path6, _query) {
1769
- return path6;
1807
+ function highlight(path7, _query) {
1808
+ return path7;
1770
1809
  }
1771
1810
  function FleetPanel({
1772
1811
  entries,
@@ -1833,6 +1872,43 @@ function FleetPanel({
1833
1872
  ] }) : null
1834
1873
  ] });
1835
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
+ }
1836
1912
  function fmtTime(iso) {
1837
1913
  const d = new Date(iso);
1838
1914
  const now = Date.now();
@@ -1930,6 +2006,36 @@ function MailboxPanel({
1930
2006
  /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "/mailbox \u2014 Esc to close" }) })
1931
2007
  ] });
1932
2008
  }
2009
+ var TOOL_GLYPHS = {
2010
+ file: "\u25A4",
2011
+ edit: "\u270E",
2012
+ search: "\u2315",
2013
+ folder: "\u25A3",
2014
+ terminal: "\u2318",
2015
+ web: "\u25C8",
2016
+ git: "\u2387",
2017
+ tree: "\u2630",
2018
+ code: "\u2699",
2019
+ test: "\u2697",
2020
+ package: "\u2B22",
2021
+ document: "\u2637",
2022
+ scaffold: "\u2731",
2023
+ todo: "\u2610",
2024
+ plan: "\u2756",
2025
+ task: "\u25AA",
2026
+ meta: "\u274F",
2027
+ index: "\u229B",
2028
+ json: "\u2317",
2029
+ diff: "\u2206",
2030
+ logs: "\u2261",
2031
+ settings: "\u2699",
2032
+ brain: "\u2726",
2033
+ fallback: "\u2022"
2034
+ };
2035
+ function getToolVisual(name) {
2036
+ const id = getToolIcon(name);
2037
+ return { glyph: TOOL_GLYPHS[id], color: TOOL_ICON_CONFIG[id].color };
2038
+ }
1933
2039
  function helpSections() {
1934
2040
  const nav = [];
1935
2041
  nav.push(
@@ -1976,31 +2082,133 @@ function helpSections() {
1976
2082
  { keys: "/settings", desc: "autonomy defaults (also Ctrl+S)" },
1977
2083
  { keys: "/clear", desc: "clear the conversation" }
1978
2084
  ]
2085
+ },
2086
+ {
2087
+ title: "Tool Colors",
2088
+ entries: toolColorLegend()
1979
2089
  }
1980
2090
  ];
1981
2091
  }
2092
+ function toolColorLegend() {
2093
+ const tools = [
2094
+ // File operations (most common)
2095
+ { name: "read/write", tool: "read", desc: "file I/O" },
2096
+ { name: "write", tool: "write", desc: "create file" },
2097
+ { name: "edit", tool: "edit", desc: "edit file" },
2098
+ { name: "patch", tool: "patch", desc: "diff/patch" },
2099
+ // Search
2100
+ { name: "search", tool: "grep", desc: "search" },
2101
+ { name: "glob", tool: "glob", desc: "glob/pattern" },
2102
+ // Shell & web
2103
+ { name: "terminal", tool: "bash", desc: "shell" },
2104
+ { name: "web", tool: "fetch", desc: "web" },
2105
+ // Navigation & tree
2106
+ { name: "folder", tool: "ls", desc: "navigate" },
2107
+ { name: "tree", tool: "tree", desc: "tree view" },
2108
+ // VCS
2109
+ { name: "git", tool: "git", desc: "git" },
2110
+ // Code quality
2111
+ { name: "lint", tool: "lint", desc: "lint" },
2112
+ { name: "format", tool: "format", desc: "format" },
2113
+ { name: "typecheck", tool: "typecheck", desc: "typecheck" },
2114
+ // Testing & packages
2115
+ { name: "test", tool: "test", desc: "test" },
2116
+ { name: "package", tool: "install", desc: "packages" },
2117
+ { name: "audit", tool: "audit", desc: "audit" },
2118
+ // Planning & tracking
2119
+ { name: "todo", tool: "todo", desc: "todos" },
2120
+ { name: "plan", tool: "plan", desc: "planning" },
2121
+ { name: "task", tool: "task", desc: "tasks" },
2122
+ // Docs & scaffolding
2123
+ { name: "document", tool: "document", desc: "docs" },
2124
+ { name: "scaffold", tool: "scaffold", desc: "scaffold" },
2125
+ // Data & logs
2126
+ { name: "json", tool: "json", desc: "JSON" },
2127
+ { name: "logs", tool: "logs", desc: "logs" },
2128
+ // Memory & meta
2129
+ { name: "brain", tool: "remember", desc: "memory" },
2130
+ { name: "tool_use", tool: "tool_use", desc: "tool chain" }
2131
+ ];
2132
+ return tools.map(({ name, tool, desc }) => {
2133
+ const { glyph, color } = getToolVisual(tool);
2134
+ return {
2135
+ keys: `${glyph} ${name}`,
2136
+ desc: `${desc} (${color})`
2137
+ };
2138
+ });
2139
+ }
2140
+ function splitIntoColumns(entries) {
2141
+ const left = [];
2142
+ const right = [];
2143
+ for (const entry of entries) {
2144
+ if (left.length <= right.length) {
2145
+ left.push(entry);
2146
+ } else {
2147
+ right.push(entry);
2148
+ }
2149
+ }
2150
+ return [left, right];
2151
+ }
1982
2152
  function HelpOverlay() {
1983
2153
  const sections = helpSections();
1984
- const keyWidth = Math.max(...sections.flatMap((s2) => s2.entries.map((e) => e.keys.length)), 0);
2154
+ const otherSections = sections.filter((s2) => s2.title !== "Tool Colors");
2155
+ const otherKeyWidth = Math.max(
2156
+ ...otherSections.flatMap((s2) => s2.entries.map((e) => e.keys.length)),
2157
+ 0
2158
+ );
2159
+ const toolSection = sections.find((s2) => s2.title === "Tool Colors");
2160
+ const toolKeyWidth = toolSection ? Math.max(...toolSection.entries.map((e) => e.keys.length), 0) : 0;
1985
2161
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
1986
2162
  /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
1987
2163
  /* @__PURE__ */ jsx(Text, { bold: true, color: theme.accent, children: "Keyboard shortcuts" }),
1988
2164
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7 Esc to close" })
1989
2165
  ] }),
1990
- sections.map((sec) => /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
1991
- /* @__PURE__ */ jsx(Text, { bold: true, color: theme.brand, children: sec.title }),
1992
- sec.entries.map((e, i) => /* @__PURE__ */ jsxs(
1993
- Box,
1994
- {
1995
- flexDirection: "row",
1996
- children: [
1997
- /* @__PURE__ */ jsx(Text, { color: theme.accent, children: e.keys.padEnd(keyWidth + 2) }),
1998
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: e.desc })
1999
- ]
2000
- },
2001
- i
2002
- ))
2003
- ] }, sec.title))
2166
+ sections.map((sec) => {
2167
+ if (sec.title === "Tool Colors") {
2168
+ const [leftCol, rightCol] = splitIntoColumns(sec.entries);
2169
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
2170
+ /* @__PURE__ */ jsx(Text, { bold: true, color: theme.brand, children: sec.title }),
2171
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 2, children: [
2172
+ /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: leftCol.map((e, i) => /* @__PURE__ */ jsxs(
2173
+ Box,
2174
+ {
2175
+ flexDirection: "row",
2176
+ children: [
2177
+ /* @__PURE__ */ jsx(Text, { color: theme.accent, children: e.keys.padEnd(toolKeyWidth + 2) }),
2178
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: e.desc })
2179
+ ]
2180
+ },
2181
+ i
2182
+ )) }),
2183
+ /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: rightCol.map((e, i) => /* @__PURE__ */ jsxs(
2184
+ Box,
2185
+ {
2186
+ flexDirection: "row",
2187
+ children: [
2188
+ /* @__PURE__ */ jsx(Text, { color: theme.accent, children: e.keys.padEnd(toolKeyWidth + 2) }),
2189
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: e.desc })
2190
+ ]
2191
+ },
2192
+ i
2193
+ )) })
2194
+ ] })
2195
+ ] }, sec.title);
2196
+ }
2197
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
2198
+ /* @__PURE__ */ jsx(Text, { bold: true, color: theme.brand, children: sec.title }),
2199
+ sec.entries.map((e, i) => /* @__PURE__ */ jsxs(
2200
+ Box,
2201
+ {
2202
+ flexDirection: "row",
2203
+ children: [
2204
+ /* @__PURE__ */ jsx(Text, { color: theme.accent, children: e.keys.padEnd(otherKeyWidth + 2) }),
2205
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: e.desc })
2206
+ ]
2207
+ },
2208
+ i
2209
+ ))
2210
+ ] }, sec.title);
2211
+ })
2004
2212
  ] });
2005
2213
  }
2006
2214
 
@@ -3525,6 +3733,7 @@ var ToolStreamBox = React5.memo(function ToolStreamBox2({
3525
3733
  startedAt,
3526
3734
  termWidth
3527
3735
  }) {
3736
+ const { glyph, color } = getToolVisual(name);
3528
3737
  const [tick, setTick] = useState(0);
3529
3738
  useEffect(() => {
3530
3739
  const t = setInterval(() => setTick((n) => n + 1), 500);
@@ -3537,8 +3746,11 @@ var ToolStreamBox = React5.memo(function ToolStreamBox2({
3537
3746
  const rows = streamBoxRows(text, MAX_STREAM_LINES, contentWidth);
3538
3747
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 0, children: [
3539
3748
  /* @__PURE__ */ jsxs(Box, { flexDirection: "row", children: [
3540
- /* @__PURE__ */ jsx(Text, { color: theme.warn, children: "\u25C6 " }),
3541
- /* @__PURE__ */ jsx(Text, { bold: true, color: theme.tool, children: name }),
3749
+ /* @__PURE__ */ jsxs(Text, { color, children: [
3750
+ glyph,
3751
+ " "
3752
+ ] }),
3753
+ /* @__PURE__ */ jsx(Text, { bold: true, color, children: name }),
3542
3754
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u23F1 ${fmtDuration(elapsedMs)}` }),
3543
3755
  hidden > 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` (${totalLines} lines, showing last ${MAX_STREAM_LINES})` }) : null
3544
3756
  ] }),
@@ -3811,7 +4023,7 @@ function Banner({
3811
4023
  entry
3812
4024
  }) {
3813
4025
  const cwdShort = shortenPath(entry.cwd, 48);
3814
- const projectLabel = path4.basename(entry.cwd);
4026
+ const projectLabel = path5.basename(entry.cwd);
3815
4027
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "magenta", paddingX: 2, paddingY: 0, children: [
3816
4028
  /* @__PURE__ */ jsxs(Text, { children: [
3817
4029
  /* @__PURE__ */ jsx(Text, { color: "magenta", bold: true, children: " \u259F\u259B " }),
@@ -4093,6 +4305,7 @@ var Entry = React5.memo(function Entry2({
4093
4305
  ] });
4094
4306
  }
4095
4307
  case "tool": {
4308
+ const { glyph, color } = getToolVisual(entry.name);
4096
4309
  const argSummary = formatToolArgs(entry.name, entry.input);
4097
4310
  const outLines = formatToolOutput(
4098
4311
  entry.name,
@@ -4118,9 +4331,9 @@ var Entry = React5.memo(function Entry2({
4118
4331
  })();
4119
4332
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
4120
4333
  /* @__PURE__ */ jsxs(Text, { children: [
4121
- /* @__PURE__ */ jsx(Text, { color: entry.ok ? theme.success : theme.error, children: entry.ok ? "\u25CF" : "\u2717" }),
4122
- " ",
4123
- /* @__PURE__ */ jsx(Text, { bold: true, color: theme.tool, children: entry.name }),
4334
+ /* @__PURE__ */ jsx(Text, { color, children: glyph }),
4335
+ /* @__PURE__ */ jsx(Text, { children: " " }),
4336
+ /* @__PURE__ */ jsx(Text, { bold: true, color, children: entry.name }),
4124
4337
  argSummary ? /* @__PURE__ */ jsxs(Fragment, { children: [
4125
4338
  /* @__PURE__ */ jsx(Text, { children: " " }),
4126
4339
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: argSummary })
@@ -4387,7 +4600,7 @@ function ScrollableHistory({
4387
4600
  }
4388
4601
  var MB = 1024 * 1024;
4389
4602
  function defaultHeapLogPath() {
4390
- return path4.join(wstackGlobalRoot(), "logs", "heap.jsonl");
4603
+ return path5.join(wstackGlobalRoot(), "logs", "heap.jsonl");
4391
4604
  }
4392
4605
  function takeHeapSample() {
4393
4606
  const m = process.memoryUsage();
@@ -4417,10 +4630,10 @@ function startHeapWatchdog(opts = {}) {
4417
4630
  const append = (line) => {
4418
4631
  writeChain = writeChain.then(async () => {
4419
4632
  if (!dirReady) {
4420
- await fs2.mkdir(path4.dirname(logPath), { recursive: true });
4633
+ await fs3.mkdir(path5.dirname(logPath), { recursive: true });
4421
4634
  dirReady = true;
4422
4635
  }
4423
- await fs2.appendFile(logPath, `${line}
4636
+ await fs3.appendFile(logPath, `${line}
4424
4637
  `, "utf8");
4425
4638
  }).catch(() => void 0);
4426
4639
  };
@@ -4593,6 +4806,52 @@ function layoutInputRows(prompt, value, cursor, width) {
4593
4806
  if (row.length > 0 || rows.length === 0) rows.push(row);
4594
4807
  return rows;
4595
4808
  }
4809
+ function inputIndexAtRowCol(prompt, value, width, row, col) {
4810
+ const w = Math.max(1, Math.floor(width));
4811
+ const flat = [];
4812
+ for (let i = 0; i < prompt.length; i++) flat.push({ ch: prompt[i], buf: -1 });
4813
+ for (let i = 0; i < value.length; i++) flat.push({ ch: value[i], buf: i });
4814
+ const rows = [];
4815
+ const starts = [];
4816
+ let cur = [];
4817
+ let curStart = 0;
4818
+ for (const cell of flat) {
4819
+ if (cell.ch === "\n") {
4820
+ rows.push(cur);
4821
+ starts.push(curStart);
4822
+ cur = [];
4823
+ curStart = cell.buf + 1;
4824
+ continue;
4825
+ }
4826
+ if (cur.length === 0 && cell.buf >= 0) curStart = cell.buf;
4827
+ cur.push({ buf: cell.buf });
4828
+ if (cur.length >= w) {
4829
+ rows.push(cur);
4830
+ starts.push(curStart);
4831
+ cur = [];
4832
+ curStart = -1;
4833
+ }
4834
+ }
4835
+ if (cur.length > 0 || rows.length === 0) {
4836
+ rows.push(cur);
4837
+ starts.push(curStart);
4838
+ }
4839
+ const clamp = (n) => Math.max(0, Math.min(value.length, n));
4840
+ if (row < 0) return 0;
4841
+ if (row >= rows.length) return value.length;
4842
+ const r = rows[row];
4843
+ const c = Math.max(0, col);
4844
+ if (c < r.length) {
4845
+ const b = r[c].buf;
4846
+ return b < 0 ? 0 : clamp(b);
4847
+ }
4848
+ for (let k = r.length - 1; k >= 0; k--) {
4849
+ const b = r[k].buf;
4850
+ if (b >= 0) return clamp(b + 1);
4851
+ }
4852
+ const start = starts[row];
4853
+ return clamp(start !== void 0 && start >= 0 ? start : value.length);
4854
+ }
4596
4855
 
4597
4856
  // src/mouse.ts
4598
4857
  var ESC = String.fromCharCode(27);
@@ -5224,21 +5483,33 @@ function ProcessListMonitor() {
5224
5483
  const all = registry.list();
5225
5484
  const stats = registry.stats();
5226
5485
  const safeIndex = Math.min(selectedIndex, Math.max(0, all.length - 1));
5486
+ if (safeIndex !== selectedIndex) {
5487
+ setSelectedIndex(safeIndex);
5488
+ }
5227
5489
  const selected = all[safeIndex];
5228
5490
  const now = Date.now();
5229
5491
  const running = all.filter((p) => !p.killed).length;
5230
5492
  const b = stats.breaker;
5231
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));
5232
5495
  useInput((input, key) => {
5233
5496
  if (key.upArrow) {
5234
5497
  setSelectedIndex((prev) => Math.max(0, prev - 1));
5235
5498
  } else if (key.downArrow) {
5236
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));
5237
5508
  } else if (key.return && selected) {
5238
5509
  getProcessRegistry().kill(selected.pid);
5239
5510
  } else if (key.delete && selected) {
5240
5511
  getProcessRegistry().kill(selected.pid, { force: true });
5241
- } else if (input === "a") {
5512
+ } else if (input === "a" && !key.ctrl) {
5242
5513
  getProcessRegistry().killAll();
5243
5514
  } else if (input === "A") {
5244
5515
  getProcessRegistry().killAll({ force: true });
@@ -5284,6 +5555,13 @@ function ProcessListMonitor() {
5284
5555
  /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, marginTop: 1, children: [
5285
5556
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191\u2193 nav" }),
5286
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: [
5287
5565
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Enter kill (SIGTERM)" }),
5288
5566
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7" }),
5289
5567
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Del force kill (SIGKILL)" }),
@@ -5294,7 +5572,25 @@ function ProcessListMonitor() {
5294
5572
  ] })
5295
5573
  ] });
5296
5574
  }
5297
- function GoalPanel({ goal }) {
5575
+ function GoalPanel({
5576
+ goal,
5577
+ onCoordinatorStart,
5578
+ onCoordinatorStop,
5579
+ coordinatorRunning
5580
+ }) {
5581
+ useInput((input) => {
5582
+ if (input === "c" || input === "C") {
5583
+ if (onCoordinatorStart && goal) {
5584
+ const goalText = goal.refinedGoal || goal.goal;
5585
+ onCoordinatorStart(goalText);
5586
+ }
5587
+ }
5588
+ if (input === "S") {
5589
+ if (onCoordinatorStop) {
5590
+ onCoordinatorStop();
5591
+ }
5592
+ }
5593
+ });
5298
5594
  if (!goal) {
5299
5595
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", padding: 1, children: [
5300
5596
  /* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsx(Text, { bold: true, color: theme.accent, children: "\u{1F3AF} Goal" }) }),
@@ -5306,7 +5602,11 @@ function GoalPanel({ goal }) {
5306
5602
  ] }),
5307
5603
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: " to create one." })
5308
5604
  ] }),
5309
- /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Press F9 to close." }) })
5605
+ /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Press F9 to close." }) }),
5606
+ /* @__PURE__ */ jsx(Box, { marginTop: 1, children: coordinatorRunning ? /* @__PURE__ */ jsxs(Fragment, { children: [
5607
+ /* @__PURE__ */ jsx(Text, { color: "green", children: "\u25CF Coordinator running " }),
5608
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "[S] Stop coordinator" })
5609
+ ] }) : /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "[C] Start coordinator" }) }) })
5310
5610
  ] });
5311
5611
  }
5312
5612
  const displayGoal = goal.refinedGoal || goal.goal;
@@ -5372,7 +5672,11 @@ function GoalPanel({ goal }) {
5372
5672
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Last task: " }),
5373
5673
  /* @__PURE__ */ jsx(Text, { children: goal.lastTask.length > 50 ? goal.lastTask.slice(0, 47) + "\u2026" : goal.lastTask })
5374
5674
  ] }),
5375
- /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Press F9 to close." }) })
5675
+ /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Press F9 to close." }) }),
5676
+ /* @__PURE__ */ jsx(Box, { marginTop: 1, children: coordinatorRunning ? /* @__PURE__ */ jsxs(Fragment, { children: [
5677
+ /* @__PURE__ */ jsx(Text, { color: "green", children: "\u25CF Coordinator running " }),
5678
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "[S] Stop coordinator" })
5679
+ ] }) : /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "[C] Start coordinator" }) }) })
5376
5680
  ] })
5377
5681
  ] });
5378
5682
  }
@@ -5397,6 +5701,152 @@ function renderProgressBar(progress, trend) {
5397
5701
  ] })
5398
5702
  ] });
5399
5703
  }
5704
+ var STATUS_COLOR = {
5705
+ open: "gray",
5706
+ in_progress: "yellow",
5707
+ done: "green"
5708
+ };
5709
+ var STATUS_ICON = {
5710
+ open: "\u25CB",
5711
+ in_progress: "\u25D0",
5712
+ done: "\u2713"
5713
+ };
5714
+ function planFilePath(projectRoot, sessionId, scope) {
5715
+ const base = resolveWstackPaths$1({ projectRoot }).projectSessions;
5716
+ if (scope === "project") {
5717
+ return path5.join(base, "backlog.plan.json");
5718
+ }
5719
+ if (sessionId) {
5720
+ return path5.join(base, `${sessionId}.plan.json`);
5721
+ }
5722
+ return path5.join(base, "backlog.plan.json");
5723
+ }
5724
+ function PlanPanel({ projectRoot, sessionId, onClose: _onClose }) {
5725
+ const [items, setItems] = useState([]);
5726
+ const [title, setTitle2] = useState(void 0);
5727
+ const [scope, setScope] = useState("session");
5728
+ const [loading, setLoading] = useState(true);
5729
+ const [error, setError] = useState(null);
5730
+ async function load(scope_) {
5731
+ setLoading(true);
5732
+ setError(null);
5733
+ try {
5734
+ const filePath = planFilePath(projectRoot, sessionId, scope_);
5735
+ let content;
5736
+ try {
5737
+ content = await fs3.readFile(filePath, "utf-8");
5738
+ } catch {
5739
+ setItems([]);
5740
+ setTitle2(void 0);
5741
+ setScope(scope_);
5742
+ setLoading(false);
5743
+ return;
5744
+ }
5745
+ const parsed = JSON.parse(content);
5746
+ setItems(parsed.items ?? []);
5747
+ setTitle2(parsed.title);
5748
+ setScope(scope_);
5749
+ } catch (err) {
5750
+ setError(err instanceof Error ? err.message : String(err));
5751
+ } finally {
5752
+ setLoading(false);
5753
+ }
5754
+ }
5755
+ useEffect(() => {
5756
+ void load("session");
5757
+ }, []);
5758
+ async function handleScopeSwitch(newScope) {
5759
+ await load(newScope);
5760
+ }
5761
+ useInput((input) => {
5762
+ if (input === "s" || input === "S") {
5763
+ void handleScopeSwitch(scope === "session" ? "project" : "session");
5764
+ }
5765
+ });
5766
+ const open = items.filter((i) => i.status === "open");
5767
+ const inProgress = items.filter((i) => i.status === "in_progress");
5768
+ const done = items.filter((i) => i.status === "done");
5769
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [
5770
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, marginBottom: 1, children: [
5771
+ /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "\u{1F4CB} PLAN" }),
5772
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
5773
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: scope === "session" ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "session-scoped" }) : /* @__PURE__ */ jsx(Text, { color: "yellow", children: "project-scoped" }) }),
5774
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
5775
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
5776
+ items.length,
5777
+ " item",
5778
+ items.length !== 1 ? "s" : ""
5779
+ ] }),
5780
+ title ? /* @__PURE__ */ jsxs(Fragment, { children: [
5781
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
5782
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: title })
5783
+ ] }) : null,
5784
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502 F5/Esc to close" })
5785
+ ] }),
5786
+ loading ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Loading plan..." }) : error ? /* @__PURE__ */ jsxs(Text, { color: "red", children: [
5787
+ "Error: ",
5788
+ error
5789
+ ] }) : items.length === 0 ? /* @__PURE__ */ jsxs(Box, { flexDirection: "column", gap: 0, children: [
5790
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "No plan items yet." }),
5791
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
5792
+ "Use ",
5793
+ /* @__PURE__ */ jsx(Text, { color: theme.accent, children: "/plan add <title>" }),
5794
+ " to create one."
5795
+ ] })
5796
+ ] }) : /* @__PURE__ */ jsxs(Box, { flexDirection: "column", gap: 0, children: [
5797
+ inProgress.length > 0 && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
5798
+ /* @__PURE__ */ jsxs(Text, { color: "yellow", bold: true, children: [
5799
+ "In Progress (",
5800
+ inProgress.length,
5801
+ ")"
5802
+ ] }),
5803
+ inProgress.map((item) => /* @__PURE__ */ jsx(PlanRow, { item }, item.id))
5804
+ ] }),
5805
+ open.length > 0 && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
5806
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, bold: true, children: [
5807
+ "Open (",
5808
+ open.length,
5809
+ ")"
5810
+ ] }),
5811
+ open.map((item) => /* @__PURE__ */ jsx(PlanRow, { item }, item.id))
5812
+ ] }),
5813
+ done.length > 0 && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
5814
+ /* @__PURE__ */ jsxs(Text, { color: "green", bold: true, children: [
5815
+ "Done (",
5816
+ done.length,
5817
+ ")"
5818
+ ] }),
5819
+ done.map((item) => /* @__PURE__ */ jsx(PlanRow, { item }, item.id))
5820
+ ] })
5821
+ ] }),
5822
+ /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
5823
+ "[",
5824
+ /* @__PURE__ */ jsx(Text, { color: "cyan", children: "S" }),
5825
+ "] Switch scope to",
5826
+ " ",
5827
+ scope === "session" ? /* @__PURE__ */ jsx(Text, { color: "yellow", children: "project" }) : /* @__PURE__ */ jsx(Text, { color: "cyan", children: "session" }),
5828
+ " ",
5829
+ "\xB7 Use ",
5830
+ /* @__PURE__ */ jsx(Text, { color: theme.accent, children: "/plan add" }),
5831
+ " to add items \xB7",
5832
+ " ",
5833
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "F5/Esc to close" })
5834
+ ] }) })
5835
+ ] });
5836
+ }
5837
+ function PlanRow({ item }) {
5838
+ const icon = STATUS_ICON[item.status] ?? "?";
5839
+ const color = STATUS_COLOR[item.status] ?? "white";
5840
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
5841
+ /* @__PURE__ */ jsx(Text, { color, children: icon }),
5842
+ /* @__PURE__ */ jsx(Text, { color, children: item.title }),
5843
+ item.details ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
5844
+ " \u2014 ",
5845
+ item.details.slice(0, 60),
5846
+ item.details.length > 60 ? "\u2026" : ""
5847
+ ] }) : null
5848
+ ] });
5849
+ }
5400
5850
  var KIND_COLOR = {
5401
5851
  goal: "cyan",
5402
5852
  task: "yellow",
@@ -5705,10 +6155,26 @@ var SETTINGS_MODES = ["off", "suggest", "auto"];
5705
6155
  var LOG_LEVELS = ["error", "warn", "info", "debug", "trace"];
5706
6156
  var AUDIT_LEVELS = ["minimal", "standard", "full"];
5707
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
+ };
5708
6165
  var MAX_ITERATIONS_PRESETS = [100, 200, 500, 1e3, 0];
6166
+ var MAX_CONCURRENT_PRESETS = [1, 3, 5, 10, 25, 50, 0];
5709
6167
  var AUTO_PROCEED_MAX_PRESETS = [10, 25, 50, 100, 250, 0];
5710
6168
  var ENHANCE_DELAY_PRESETS = [3e4, 45e3, 6e4, 9e4, 12e4];
5711
6169
  var ENHANCE_LANGUAGES = ["original", "english"];
6170
+ var TOKEN_SAVING_TIERS = ["off", "minimal", "light", "medium", "aggressive"];
6171
+ var TOKEN_SAVING_TIER_DESCS = {
6172
+ off: "All tools enabled (full prompt)",
6173
+ minimal: "~3\u20134k tokens \u2014 core tools only",
6174
+ light: "~2\u20133k tokens \u2014 core + patterns",
6175
+ medium: "~1.5\u20132k tokens \u2014 most tools enabled",
6176
+ aggressive: "~4\u20135k tokens \u2014 trimmed prompt"
6177
+ };
5712
6178
  function formatSettingsDelay(ms) {
5713
6179
  if (ms === 0) return "disabled";
5714
6180
  if (ms >= 6e4) return `${Math.round(ms / 6e4)}m`;
@@ -5726,7 +6192,7 @@ var MODE_DESC = {
5726
6192
  suggest: "Shows next-step suggestions after each turn",
5727
6193
  auto: "Self-driving \u2014 agent continues automatically"
5728
6194
  };
5729
- var SETTINGS_FIELD_COUNT = 27;
6195
+ var SETTINGS_FIELD_COUNT = 29;
5730
6196
  var CONFIG_SCOPES = ["global", "project"];
5731
6197
  function SettingsPicker({
5732
6198
  field,
@@ -5743,10 +6209,12 @@ function SettingsPicker({
5743
6209
  featureMemory,
5744
6210
  featureSkills,
5745
6211
  featureModelsRegistry,
5746
- featureTokenSaving,
6212
+ tokenSavingTier,
5747
6213
  allowOutsideProjectRoot,
5748
6214
  contextAutoCompact,
5749
6215
  contextStrategy,
6216
+ contextMode,
6217
+ maxConcurrent,
5750
6218
  logLevel,
5751
6219
  auditLevel,
5752
6220
  indexOnStart,
@@ -5830,8 +6298,8 @@ function SettingsPicker({
5830
6298
  },
5831
6299
  {
5832
6300
  label: "Token-saving mode",
5833
- value: boolVal(featureTokenSaving),
5834
- detail: "Omit non-essential tools and trim system prompt to save tokens"
6301
+ value: tokenSavingTier,
6302
+ detail: TOKEN_SAVING_TIER_DESCS[tokenSavingTier]
5835
6303
  },
5836
6304
  {
5837
6305
  label: "Allow outside project",
@@ -5850,6 +6318,18 @@ function SettingsPicker({
5850
6318
  value: contextStrategy,
5851
6319
  detail: "hybrid (fast) | intelligent (LLM) | selective"
5852
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
+ },
5853
6333
  // ── Logging ──
5854
6334
  { section: "Logging" },
5855
6335
  {
@@ -5971,6 +6451,145 @@ function SettingsPicker({
5971
6451
  hint ? /* @__PURE__ */ jsx(Text, { color: "yellow", children: hint }) : null
5972
6452
  ] });
5973
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
+ }
5974
6593
  var MAX_VISIBLE_ITEMS = 8;
5975
6594
  function SlashMenu({ query, matches, selected }) {
5976
6595
  const placeholder = query ? `/${query}` : "/";
@@ -6448,10 +7067,10 @@ async function loadIndex(root) {
6448
7067
  async function walk(root, rel, depth, out) {
6449
7068
  if (out.length >= MAX_FILES_INDEXED) return;
6450
7069
  if (depth > MAX_DEPTH) return;
6451
- const dir = rel ? path4.join(root, rel) : root;
7070
+ const dir = rel ? path5.join(root, rel) : root;
6452
7071
  let entries;
6453
7072
  try {
6454
- entries = await fs2.readdir(dir, { withFileTypes: true });
7073
+ entries = await fs3.readdir(dir, { withFileTypes: true });
6455
7074
  } catch {
6456
7075
  return;
6457
7076
  }
@@ -6990,7 +7609,8 @@ function useTuiControllers({
6990
7609
  agentsMonitorOpen,
6991
7610
  fleetStreamController,
6992
7611
  enhanceController,
6993
- agentsMonitorController
7612
+ agentsMonitorController,
7613
+ onPanelOpen
6994
7614
  }) {
6995
7615
  useEffect(() => {
6996
7616
  if (!fleetStreamController) return;
@@ -7036,6 +7656,16 @@ function useTuiControllers({
7036
7656
  useEffect(() => {
7037
7657
  if (agentsMonitorController) agentsMonitorController.visible = agentsMonitorOpen;
7038
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]);
7039
7669
  }
7040
7670
  function useBrainEvents(events, dispatch) {
7041
7671
  useEffect(() => {
@@ -8055,10 +8685,12 @@ function reducer(state, action) {
8055
8685
  featureMemory: action.featureMemory,
8056
8686
  featureSkills: action.featureSkills,
8057
8687
  featureModelsRegistry: action.featureModelsRegistry,
8058
- featureTokenSaving: action.featureTokenSaving,
8688
+ tokenSavingTier: action.tokenSavingTier,
8059
8689
  allowOutsideProjectRoot: action.allowOutsideProjectRoot,
8060
8690
  contextAutoCompact: action.contextAutoCompact,
8061
8691
  contextStrategy: action.contextStrategy,
8692
+ contextMode: action.contextMode,
8693
+ maxConcurrent: action.maxConcurrent,
8062
8694
  logLevel: action.logLevel,
8063
8695
  auditLevel: action.auditLevel,
8064
8696
  indexOnStart: action.indexOnStart,
@@ -8115,7 +8747,12 @@ function reducer(state, action) {
8115
8747
  if (f === 10) return { ...state, settingsPicker: { ...sp, featureMemory: !sp.featureMemory, hint: bootHint } };
8116
8748
  if (f === 11) return { ...state, settingsPicker: { ...sp, featureSkills: !sp.featureSkills, hint: bootHint } };
8117
8749
  if (f === 12) return { ...state, settingsPicker: { ...sp, featureModelsRegistry: !sp.featureModelsRegistry, hint: bootHint } };
8118
- if (f === 13) return { ...state, settingsPicker: { ...sp, featureTokenSaving: !sp.featureTokenSaving, hint: bootHint } };
8750
+ if (f === 13) {
8751
+ const i = TOKEN_SAVING_TIERS.indexOf(sp.tokenSavingTier);
8752
+ const base = i < 0 ? 0 : i;
8753
+ const next = (base + action.delta + TOKEN_SAVING_TIERS.length) % TOKEN_SAVING_TIERS.length;
8754
+ return { ...state, settingsPicker: { ...sp, tokenSavingTier: TOKEN_SAVING_TIERS[next] ?? "off", hint: bootHint } };
8755
+ }
8119
8756
  if (f === 14) return { ...state, settingsPicker: { ...sp, allowOutsideProjectRoot: !sp.allowOutsideProjectRoot, hint: void 0 } };
8120
8757
  if (f === 15) return { ...state, settingsPicker: { ...sp, contextAutoCompact: !sp.contextAutoCompact, hint: void 0 } };
8121
8758
  if (f === 16) {
@@ -8125,45 +8762,57 @@ function reducer(state, action) {
8125
8762
  return { ...state, settingsPicker: { ...sp, contextStrategy: expectDefined$1(COMPACTOR_STRATEGIES[next]), hint: bootHint } };
8126
8763
  }
8127
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) {
8128
8777
  const i = LOG_LEVELS.indexOf(sp.logLevel);
8129
8778
  const base = i < 0 ? 0 : i;
8130
8779
  const next = (base + action.delta + LOG_LEVELS.length) % LOG_LEVELS.length;
8131
8780
  return { ...state, settingsPicker: { ...sp, logLevel: expectDefined$1(LOG_LEVELS[next]), hint: void 0 } };
8132
8781
  }
8133
- if (f === 18) {
8782
+ if (f === 20) {
8134
8783
  const i = AUDIT_LEVELS.indexOf(sp.auditLevel);
8135
8784
  const base = i < 0 ? 0 : i;
8136
8785
  const next = (base + action.delta + AUDIT_LEVELS.length) % AUDIT_LEVELS.length;
8137
8786
  return { ...state, settingsPicker: { ...sp, auditLevel: expectDefined$1(AUDIT_LEVELS[next]), hint: void 0 } };
8138
8787
  }
8139
- if (f === 19) return { ...state, settingsPicker: { ...sp, indexOnStart: !sp.indexOnStart, hint: bootHint } };
8140
- if (f === 20) {
8788
+ if (f === 21) return { ...state, settingsPicker: { ...sp, indexOnStart: !sp.indexOnStart, hint: bootHint } };
8789
+ if (f === 22) {
8141
8790
  const j = MAX_ITERATIONS_PRESETS.indexOf(sp.maxIterations);
8142
8791
  const base = j < 0 ? 0 : j;
8143
8792
  const next = (base + action.delta + MAX_ITERATIONS_PRESETS.length) % MAX_ITERATIONS_PRESETS.length;
8144
8793
  return { ...state, settingsPicker: { ...sp, maxIterations: expectDefined$1(MAX_ITERATIONS_PRESETS[next]), hint: void 0 } };
8145
8794
  }
8146
- if (f === 21) {
8795
+ if (f === 23) {
8147
8796
  const aj = AUTO_PROCEED_MAX_PRESETS.indexOf(sp.autoProceedMaxIterations);
8148
8797
  const abase = aj < 0 ? 0 : aj;
8149
8798
  const anext = (abase + action.delta + AUTO_PROCEED_MAX_PRESETS.length) % AUTO_PROCEED_MAX_PRESETS.length;
8150
8799
  return { ...state, settingsPicker: { ...sp, autoProceedMaxIterations: expectDefined$1(AUTO_PROCEED_MAX_PRESETS[anext]), hint: void 0 } };
8151
8800
  }
8152
- if (f === 22) {
8801
+ if (f === 24) {
8153
8802
  const ej = ENHANCE_DELAY_PRESETS.indexOf(sp.enhanceDelayMs);
8154
8803
  const ebase = ej < 0 ? 0 : ej;
8155
8804
  const enext = (ebase + action.delta + ENHANCE_DELAY_PRESETS.length) % ENHANCE_DELAY_PRESETS.length;
8156
8805
  return { ...state, settingsPicker: { ...sp, enhanceDelayMs: expectDefined$1(ENHANCE_DELAY_PRESETS[enext]), hint: void 0 } };
8157
8806
  }
8158
- if (f === 23) return { ...state, settingsPicker: { ...sp, enhanceEnabled: !sp.enhanceEnabled, hint: void 0 } };
8159
- if (f === 24) {
8807
+ if (f === 25) return { ...state, settingsPicker: { ...sp, enhanceEnabled: !sp.enhanceEnabled, hint: void 0 } };
8808
+ if (f === 26) {
8160
8809
  const i = ENHANCE_LANGUAGES.indexOf(sp.enhanceLanguage);
8161
8810
  const base = i < 0 ? 0 : i;
8162
8811
  const next = (base + action.delta + ENHANCE_LANGUAGES.length) % ENHANCE_LANGUAGES.length;
8163
8812
  return { ...state, settingsPicker: { ...sp, enhanceLanguage: expectDefined$1(ENHANCE_LANGUAGES[next]), hint: void 0 } };
8164
8813
  }
8165
- if (f === 25) return { ...state, settingsPicker: { ...sp, debugStream: !sp.debugStream, hint: void 0 } };
8166
- if (f === 26) {
8814
+ if (f === 27) return { ...state, settingsPicker: { ...sp, debugStream: !sp.debugStream, hint: void 0 } };
8815
+ if (f === 28) {
8167
8816
  const i = CONFIG_SCOPES.indexOf(sp.configScope);
8168
8817
  const base = i < 0 ? 0 : i;
8169
8818
  const next = (base + action.delta + CONFIG_SCOPES.length) % CONFIG_SCOPES.length;
@@ -8173,6 +8822,62 @@ function reducer(state, action) {
8173
8822
  }
8174
8823
  case "settingsHint":
8175
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
+ };
8176
8881
  case "projectPickerOpen":
8177
8882
  return {
8178
8883
  ...state,
@@ -8215,6 +8920,15 @@ function reducer(state, action) {
8215
8920
  }
8216
8921
  case "projectPickerHint":
8217
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
+ }
8218
8932
  case "confirmOpen":
8219
8933
  return { ...state, confirmQueue: [...state.confirmQueue, action.info] };
8220
8934
  case "confirmClose":
@@ -8574,6 +9288,10 @@ function reducer(state, action) {
8574
9288
  const opening = !state.processListOpen;
8575
9289
  return opening ? { ...state, processListOpen: true, monitorOpen: false, agentsMonitorOpen: false, helpOpen: false, todosMonitorOpen: false, queuePanelOpen: false, goalPanelOpen: false } : { ...state, processListOpen: false };
8576
9290
  }
9291
+ case "togglePlanPanel": {
9292
+ const opening = !state.planPanelOpen;
9293
+ return opening ? { ...state, planPanelOpen: true, monitorOpen: false, agentsMonitorOpen: false, helpOpen: false, todosMonitorOpen: false, queuePanelOpen: false, processListOpen: false, goalPanelOpen: false } : { ...state, planPanelOpen: false };
9294
+ }
8577
9295
  case "toggleGoalPanel": {
8578
9296
  const opening = !state.goalPanelOpen;
8579
9297
  return opening ? { ...state, goalPanelOpen: true, monitorOpen: false, agentsMonitorOpen: false, helpOpen: false, todosMonitorOpen: false, queuePanelOpen: false, processListOpen: false } : { ...state, goalPanelOpen: false };
@@ -9046,6 +9764,7 @@ function rehydrateHistory(messages, startId, toolCalls) {
9046
9764
  return entries;
9047
9765
  }
9048
9766
  var PASTE_THRESHOLD_CHARS = 200;
9767
+ var SB_PADX2 = 2;
9049
9768
  function App({
9050
9769
  agent,
9051
9770
  slashRegistry,
@@ -9103,6 +9822,7 @@ function App({
9103
9822
  interruptController,
9104
9823
  statuslineHiddenItems,
9105
9824
  setStatuslineHiddenItems,
9825
+ saveStatuslineHiddenItems,
9106
9826
  agentsMonitorController,
9107
9827
  initialGoal,
9108
9828
  initialAsk,
@@ -9118,7 +9838,12 @@ function App({
9118
9838
  getLiveSessions,
9119
9839
  onSwitchToSession,
9120
9840
  initialAgentsMonitorOpen,
9121
- subscribeCoordinatorEvents
9841
+ onPanelOpen,
9842
+ subscribeCoordinatorEvents,
9843
+ onCoordinatorStart,
9844
+ onCoordinatorStop,
9845
+ coordinatorRunning = false,
9846
+ clientId
9122
9847
  }) {
9123
9848
  const { exit } = useApp();
9124
9849
  const { stdout } = useStdout();
@@ -9148,18 +9873,45 @@ function App({
9148
9873
  modeLabel,
9149
9874
  statuslineHiddenItems
9150
9875
  });
9876
+ const hiddenItemsRef = useRef(hiddenItems);
9877
+ hiddenItemsRef.current = hiddenItems;
9151
9878
  const prevBranchRef = useRef(null);
9152
9879
  const [indexState, setIndexState] = useState(() => getIndexState());
9153
9880
  useEffect(() => {
9154
9881
  setIndexState(getIndexState());
9155
9882
  return onIndexStateChange((next) => setIndexState(next));
9156
9883
  }, []);
9884
+ const [breakerCountdown, setBreakerCountdown] = useState(
9885
+ () => getProcessRegistry().getBreakerCountdown()
9886
+ );
9887
+ useEffect(() => {
9888
+ const s2 = getSettings?.();
9889
+ if (s2) {
9890
+ getProcessRegistry().setBreakerConfig({
9891
+ enabled: s2.breakerEnabled ?? false,
9892
+ autoKillResetMs: s2.breakerAutoKillResetMs ?? 6e4
9893
+ });
9894
+ }
9895
+ return getProcessRegistry().onBreakerCountdownChange((snap) => setBreakerCountdown(snap));
9896
+ }, [getSettings]);
9897
+ const breakerArmed = breakerCountdown !== null;
9898
+ useEffect(() => {
9899
+ if (!breakerArmed) return;
9900
+ const t = setInterval(
9901
+ () => setBreakerCountdown(getProcessRegistry().getBreakerCountdown()),
9902
+ 1e3
9903
+ );
9904
+ return () => clearInterval(t);
9905
+ }, [breakerArmed]);
9157
9906
  useEffect(() => {
9158
9907
  setHiddenItems([...statuslineHiddenItems]);
9159
9908
  }, [statuslineHiddenItems]);
9160
9909
  useEffect(() => {
9161
9910
  setStatuslineHiddenItems(hiddenItems);
9162
- }, [setStatuslineHiddenItems, hiddenItems]);
9911
+ saveStatuslineHiddenItems(hiddenItems).catch?.((err) => {
9912
+ console.error("[statusline] failed to persist hidden items:", err);
9913
+ });
9914
+ }, [setStatuslineHiddenItems, saveStatuslineHiddenItems, hiddenItems]);
9163
9915
  const projectRoot = agent.ctx.projectRoot;
9164
9916
  const refreshGoalSummary = useCallback(() => {
9165
9917
  if (!projectRoot) return;
@@ -9251,8 +10003,10 @@ function App({
9251
10003
  },
9252
10004
  autonomyPicker: { open: false, options: [], selected: 0 },
9253
10005
  resumePicker: { open: false, sessions: [], selected: 0, busy: false, hint: void 0, error: void 0 },
9254
- 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, featureTokenSaving: false, 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 },
9255
10008
  projectPicker: { open: false, allItems: [], items: [], selected: 0, filter: "", hint: void 0 },
10009
+ fKeyPicker: { open: false, selected: 0 },
9256
10010
  confirmQueue: [],
9257
10011
  enhance: null,
9258
10012
  enhanceEnabled,
@@ -9279,6 +10033,7 @@ function App({
9279
10033
  todosMonitorOpen: false,
9280
10034
  queuePanelOpen: false,
9281
10035
  processListOpen: false,
10036
+ planPanelOpen: false,
9282
10037
  goalPanelOpen: false,
9283
10038
  sessionsPanelOpen: false,
9284
10039
  sessionsPanel: { sessions: [], busy: false, selected: -1 },
@@ -9305,6 +10060,52 @@ function App({
9305
10060
  debugStreamStats: null,
9306
10061
  countdown: null
9307
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]);
9308
10109
  useAutonomousCoordinator(subscribeCoordinatorEvents, dispatch);
9309
10110
  const builderRef = useRef(null);
9310
10111
  if (builderRef.current === null) {
@@ -9318,20 +10119,20 @@ function App({
9318
10119
  const lastEnterAtRef = useRef(0);
9319
10120
  const tokenPreviewsRef = useRef(/* @__PURE__ */ new Map());
9320
10121
  const projectName = React5.useMemo(() => {
9321
- const base = path4.basename(projectRoot);
9322
- return base && base !== path4.sep ? base : void 0;
10122
+ const base = path5.basename(projectRoot);
10123
+ return base && base !== path5.sep ? base : void 0;
9323
10124
  }, [projectRoot]);
9324
10125
  const [workingDirChip, setWorkingDirChip] = React5.useState(() => {
9325
10126
  const ctx = agent.ctx;
9326
10127
  if (ctx.workingDir && ctx.workingDir !== projectRoot) {
9327
- return path4.relative(projectRoot, ctx.workingDir) || ".";
10128
+ return path5.relative(projectRoot, ctx.workingDir) || ".";
9328
10129
  }
9329
10130
  return void 0;
9330
10131
  });
9331
10132
  React5.useEffect(() => {
9332
10133
  const ctx = agent.ctx;
9333
10134
  return ctx.onWorkingDirChanged((newDir) => {
9334
- const rel = path4.relative(projectRoot, newDir) || ".";
10135
+ const rel = path5.relative(projectRoot, newDir) || ".";
9335
10136
  setWorkingDirChip(rel === "." ? void 0 : rel);
9336
10137
  });
9337
10138
  }, [agent.ctx, projectRoot]);
@@ -9728,7 +10529,7 @@ function App({
9728
10529
  let cancelled = false;
9729
10530
  const poll = async () => {
9730
10531
  try {
9731
- const data = await fs2.readFile(planPath, "utf8");
10532
+ const data = await fs3.readFile(planPath, "utf8");
9732
10533
  const parsed = JSON.parse(data);
9733
10534
  if (cancelled) return;
9734
10535
  if (!Array.isArray(parsed.items)) {
@@ -9762,7 +10563,7 @@ function App({
9762
10563
  let cancelled = false;
9763
10564
  const poll = async () => {
9764
10565
  try {
9765
- const data = await fs2.readFile(taskPath, "utf8");
10566
+ const data = await fs3.readFile(taskPath, "utf8");
9766
10567
  const parsed = JSON.parse(data);
9767
10568
  if (cancelled) return;
9768
10569
  if (!Array.isArray(parsed.tasks)) {
@@ -9874,6 +10675,7 @@ function App({
9874
10675
  if (stateRef.current.todosMonitorOpen) dispatch({ type: "toggleTodosMonitor" });
9875
10676
  if (stateRef.current.queuePanelOpen) dispatch({ type: "toggleQueuePanel" });
9876
10677
  if (stateRef.current.processListOpen) dispatch({ type: "toggleProcessList" });
10678
+ if (stateRef.current.planPanelOpen) dispatch({ type: "togglePlanPanel" });
9877
10679
  if (stateRef.current.goalPanelOpen) dispatch({ type: "toggleGoalPanel" });
9878
10680
  if (stateRef.current.sessionsPanelOpen) dispatch({ type: "toggleSessionsPanel" });
9879
10681
  eraseLiveRegion();
@@ -9899,10 +10701,12 @@ function App({
9899
10701
  featureMemory: sp.featureMemory,
9900
10702
  featureSkills: sp.featureSkills,
9901
10703
  featureModelsRegistry: sp.featureModelsRegistry,
9902
- featureTokenSaving: sp.featureTokenSaving,
10704
+ tokenSavingTier: sp.tokenSavingTier,
9903
10705
  allowOutsideProjectRoot: sp.allowOutsideProjectRoot,
9904
10706
  contextAutoCompact: sp.contextAutoCompact,
9905
10707
  contextStrategy: sp.contextStrategy,
10708
+ contextMode: sp.contextMode,
10709
+ maxConcurrent: sp.maxConcurrent,
9906
10710
  logLevel: sp.logLevel,
9907
10711
  auditLevel: sp.auditLevel,
9908
10712
  indexOnStart: sp.indexOnStart,
@@ -9979,6 +10783,7 @@ function App({
9979
10783
  const allCommands = slashRegistry.listWithOwner();
9980
10784
  const CATEGORY_ORDER = ["Run", "Session", "Inspect", "Agent", "Config", "App"];
9981
10785
  const matches = allCommands.filter(({ cmd }) => {
10786
+ if (query === "" && cmd.hidden) return false;
9982
10787
  const name = cmd.name.toLowerCase();
9983
10788
  const aliases = cmd.aliases ?? [];
9984
10789
  return name.includes(query) || aliases.some((a) => a.toLowerCase().includes(query));
@@ -10061,9 +10866,9 @@ function App({
10061
10866
  dispatch({ type: "pickerClose" });
10062
10867
  return;
10063
10868
  }
10064
- const absPath = path4.isAbsolute(picked) ? picked : path4.join(projectRoot, picked);
10869
+ const absPath = path5.isAbsolute(picked) ? picked : path5.join(projectRoot, picked);
10065
10870
  try {
10066
- const data = await fs2.readFile(absPath, "utf8");
10871
+ const data = await fs3.readFile(absPath, "utf8");
10067
10872
  const token = await builder.registerFile({
10068
10873
  kind: "file",
10069
10874
  data,
@@ -10265,6 +11070,9 @@ function App({
10265
11070
  const items = await getProjectPickerItems();
10266
11071
  dispatch({ type: "projectPickerOpen", items });
10267
11072
  }, [getProjectPickerItems]);
11073
+ const openFKeyPicker = React5.useCallback(() => {
11074
+ dispatch({ type: "fKeyPickerOpen" });
11075
+ }, [dispatch]);
10268
11076
  const loadLiveSessions = React5.useCallback(async () => {
10269
11077
  if (!getLiveSessions) {
10270
11078
  dispatch({ type: "sessionsPanelSet", sessions: [] });
@@ -10303,10 +11111,12 @@ function App({
10303
11111
  featureMemory: s2.featureMemory ?? true,
10304
11112
  featureSkills: s2.featureSkills ?? true,
10305
11113
  featureModelsRegistry: s2.featureModelsRegistry ?? true,
10306
- featureTokenSaving: s2.featureTokenSaving ?? false,
11114
+ tokenSavingTier: s2.featureTokenSaving ?? "off",
10307
11115
  allowOutsideProjectRoot: s2.allowOutsideProjectRoot ?? true,
10308
11116
  contextAutoCompact: s2.contextAutoCompact ?? true,
10309
11117
  contextStrategy: s2.contextStrategy ?? "hybrid",
11118
+ contextMode: s2.contextMode ?? "balanced",
11119
+ maxConcurrent: s2.maxConcurrent ?? 10,
10310
11120
  logLevel: s2.logLevel ?? "info",
10311
11121
  auditLevel: s2.auditLevel ?? "standard",
10312
11122
  indexOnStart: s2.indexOnStart ?? true,
@@ -10439,10 +11249,12 @@ function App({
10439
11249
  featureMemory: sp.featureMemory,
10440
11250
  featureSkills: sp.featureSkills,
10441
11251
  featureModelsRegistry: sp.featureModelsRegistry,
10442
- featureTokenSaving: sp.featureTokenSaving,
11252
+ featureTokenSaving: sp.tokenSavingTier,
10443
11253
  allowOutsideProjectRoot: sp.allowOutsideProjectRoot,
10444
11254
  contextAutoCompact: sp.contextAutoCompact,
10445
11255
  contextStrategy: sp.contextStrategy,
11256
+ contextMode: sp.contextMode,
11257
+ maxConcurrent: sp.maxConcurrent,
10446
11258
  logLevel: sp.logLevel,
10447
11259
  auditLevel: sp.auditLevel,
10448
11260
  indexOnStart: sp.indexOnStart,
@@ -10471,10 +11283,12 @@ function App({
10471
11283
  state.settingsPicker.featureMemory,
10472
11284
  state.settingsPicker.featureSkills,
10473
11285
  state.settingsPicker.featureModelsRegistry,
10474
- state.settingsPicker.featureTokenSaving,
11286
+ state.settingsPicker.tokenSavingTier,
10475
11287
  state.settingsPicker.allowOutsideProjectRoot,
10476
11288
  state.settingsPicker.contextAutoCompact,
10477
11289
  state.settingsPicker.contextStrategy,
11290
+ state.settingsPicker.contextMode,
11291
+ state.settingsPicker.maxConcurrent,
10478
11292
  state.settingsPicker.logLevel,
10479
11293
  state.settingsPicker.auditLevel,
10480
11294
  state.settingsPicker.indexOnStart,
@@ -10502,6 +11316,20 @@ function App({
10502
11316
  slashRegistry.unregister("model");
10503
11317
  };
10504
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]);
10505
11333
  useEffect(() => {
10506
11334
  if (!getSettings || !saveSettings) return;
10507
11335
  const cmd = {
@@ -10518,6 +11346,26 @@ function App({
10518
11346
  slashRegistry.unregister("settings");
10519
11347
  };
10520
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]);
10521
11369
  useEffect(() => {
10522
11370
  const cmd = {
10523
11371
  name: "mailbox",
@@ -10746,6 +11594,47 @@ function App({
10746
11594
  if (flushTimerRef.current) clearTimeout(flushTimerRef.current);
10747
11595
  };
10748
11596
  }, [events, agent.ctx.todos]);
11597
+ useEffect(() => {
11598
+ if (!clientId || !events) return;
11599
+ let toolCalls = 0;
11600
+ const emitStatus = () => {
11601
+ const usage = tokenCounter?.total();
11602
+ const cost = tokenCounter?.estimateCost();
11603
+ const mode = getAutonomy?.() ?? "off";
11604
+ events.emit("client.status", {
11605
+ clientType: "tui",
11606
+ clientId,
11607
+ projectHash: agent.ctx.projectRoot ? projectSlug(agent.ctx.projectRoot) : "unknown",
11608
+ agentCount: 1,
11609
+ // TUI is a single leader agent
11610
+ model: agent.ctx.model,
11611
+ mode,
11612
+ toolCalls,
11613
+ inputTokens: usage?.input ?? 0,
11614
+ outputTokens: usage?.output ?? 0,
11615
+ cacheTokens: (usage?.cacheRead ?? 0) + (usage?.cacheWrite ?? 0),
11616
+ costUsd: cost?.total ?? 0,
11617
+ timestamp: Date.now(),
11618
+ projectSlug: agent.ctx.projectRoot ? projectSlug(agent.ctx.projectRoot) : "unknown"
11619
+ });
11620
+ };
11621
+ const offTool = events.on("tool.executed", () => {
11622
+ toolCalls++;
11623
+ emitStatus();
11624
+ });
11625
+ const offProviderResp = events.on("provider.response", () => {
11626
+ emitStatus();
11627
+ });
11628
+ const offIterCompleted = events.on("iteration.completed", () => {
11629
+ emitStatus();
11630
+ });
11631
+ emitStatus();
11632
+ return () => {
11633
+ offTool();
11634
+ offProviderResp();
11635
+ offIterCompleted();
11636
+ };
11637
+ }, [events, clientId, tokenCounter, getAutonomy, agent.ctx.model, agent.ctx.projectRoot]);
10749
11638
  useEffect(() => {
10750
11639
  if (!registerDebugStreamCallback) return;
10751
11640
  let cancelled = false;
@@ -10798,7 +11687,8 @@ function App({
10798
11687
  agentsMonitorOpen: state.agentsMonitorOpen,
10799
11688
  fleetStreamController,
10800
11689
  enhanceController,
10801
- agentsMonitorController
11690
+ agentsMonitorController,
11691
+ onPanelOpen
10802
11692
  });
10803
11693
  useEffect(() => {
10804
11694
  if (!interruptController) return;
@@ -11210,6 +12100,32 @@ function App({
11210
12100
  }
11211
12101
  return;
11212
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
+ }
11213
12129
  if (state.projectPicker.open) {
11214
12130
  if (key.escape) {
11215
12131
  if (state.projectPicker.filter) {
@@ -11401,6 +12317,29 @@ function App({
11401
12317
  return;
11402
12318
  }
11403
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
+ }
11404
12343
  if (state.picker.open) {
11405
12344
  if (key.escape) {
11406
12345
  dispatch({ type: "pickerClose" });
@@ -11566,6 +12505,21 @@ function App({
11566
12505
  toggleWorktreeOverlay();
11567
12506
  return;
11568
12507
  }
12508
+ if (key.fn === 5) {
12509
+ if (state.planPanelOpen) {
12510
+ dispatch({ type: "togglePlanPanel" });
12511
+ } else {
12512
+ if (state.agentsMonitorOpen) dispatch({ type: "toggleAgentsMonitor" });
12513
+ if (state.monitorOpen) dispatch({ type: "toggleMonitor" });
12514
+ if (state.worktreeMonitorOpen) dispatch({ type: "worktreeMonitorToggle" });
12515
+ if (state.todosMonitorOpen) dispatch({ type: "toggleTodosMonitor" });
12516
+ if (state.autoPhase?.monitorOpen) dispatch({ type: "autoPhaseMonitorToggle" });
12517
+ if (state.settingsPicker.open) dispatch({ type: "settingsClose" });
12518
+ if (state.helpOpen) dispatch({ type: "toggleHelp" });
12519
+ dispatch({ type: "togglePlanPanel" });
12520
+ }
12521
+ return;
12522
+ }
11569
12523
  if (key.fn === 6) {
11570
12524
  toggleTodosOverlay();
11571
12525
  return;
@@ -11668,10 +12622,12 @@ function App({
11668
12622
  featureMemory: cfg.featureMemory ?? true,
11669
12623
  featureSkills: cfg.featureSkills ?? true,
11670
12624
  featureModelsRegistry: cfg.featureModelsRegistry ?? true,
11671
- featureTokenSaving: cfg.featureTokenSaving ?? false,
12625
+ tokenSavingTier: cfg.tokenSavingTier ?? "off",
11672
12626
  allowOutsideProjectRoot: cfg.allowOutsideProjectRoot ?? true,
11673
12627
  contextAutoCompact: cfg.contextAutoCompact ?? true,
11674
12628
  contextStrategy: cfg.contextStrategy ?? "hybrid",
12629
+ contextMode: cfg.contextMode ?? "balanced",
12630
+ maxConcurrent: cfg.maxConcurrent ?? 10,
11675
12631
  logLevel: cfg.logLevel ?? "info",
11676
12632
  auditLevel: cfg.auditLevel ?? "standard",
11677
12633
  indexOnStart: cfg.indexOnStart ?? true,
@@ -11735,7 +12691,8 @@ function App({
11735
12691
  if (state.processListOpen) {
11736
12692
  return;
11737
12693
  }
11738
- 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) {
11739
12696
  dispatch({ type: "toggleHelp" });
11740
12697
  return;
11741
12698
  }
@@ -11851,7 +12808,57 @@ function App({
11851
12808
  setDraft(buffer, buffer.length);
11852
12809
  return;
11853
12810
  }
11854
- 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;
12811
+ if (!overlayOpen && (key.upArrow || key.downArrow || key.pageUp || key.pageDown)) {
12812
+ const width = stdout?.columns ?? 80;
12813
+ const rows = layoutInputRows(INPUT_PROMPT, buffer, cursor, width);
12814
+ if (rows.length <= 1) ; else {
12815
+ let row = 0, col = 0, offset = 0;
12816
+ outer: for (let r = 0; r < rows.length; r++) {
12817
+ const cells = rows[r];
12818
+ for (let c = 0; c < cells.length; c++) {
12819
+ if (offset === cursor) {
12820
+ row = r;
12821
+ col = c;
12822
+ break outer;
12823
+ }
12824
+ offset++;
12825
+ }
12826
+ if (cells.length < width) offset++;
12827
+ }
12828
+ if (key.upArrow) {
12829
+ if (row > 0) {
12830
+ const prevRowLen = rows[row - 1].filter((cell) => !cell.prompt && !cell.chip).length;
12831
+ const targetCol = Math.min(col, prevRowLen);
12832
+ const target = inputIndexAtRowCol(INPUT_PROMPT, buffer, width, row - 1, targetCol);
12833
+ setDraft(buffer, target);
12834
+ return;
12835
+ }
12836
+ return;
12837
+ }
12838
+ if (key.downArrow) {
12839
+ if (row < rows.length - 1) {
12840
+ const nextRowLen = rows[row + 1].filter((cell) => !cell.prompt && !cell.chip).length;
12841
+ const targetCol = Math.min(col, nextRowLen);
12842
+ const target = inputIndexAtRowCol(INPUT_PROMPT, buffer, width, row + 1, targetCol);
12843
+ setDraft(buffer, target);
12844
+ return;
12845
+ }
12846
+ return;
12847
+ }
12848
+ if (key.pageUp || key.pageDown) {
12849
+ const pageSize = Math.max(1, Math.floor((stdout?.rows ?? 24) / 2));
12850
+ const delta = key.pageUp ? -pageSize : pageSize;
12851
+ const targetRow = Math.max(0, Math.min(rows.length - 1, row + delta));
12852
+ if (targetRow !== row) {
12853
+ const targetRowLen = rows[targetRow].filter((cell) => !cell.prompt && !cell.chip).length;
12854
+ const targetCol = Math.min(col, targetRowLen);
12855
+ const target = inputIndexAtRowCol(INPUT_PROMPT, buffer, width, targetRow, targetCol);
12856
+ setDraft(buffer, target);
12857
+ }
12858
+ return;
12859
+ }
12860
+ }
12861
+ }
11855
12862
  if (mouseMode && !overlayOpen) {
11856
12863
  if (key.mouse?.kind === "wheel") {
11857
12864
  if (key.mouse.shift) dispatch({ type: "scrollPage", dir: key.mouse.wheel > 0 ? "up" : "down" });
@@ -11902,6 +12909,40 @@ function App({
11902
12909
  dispatch({ type: "toggleTodosMonitor" });
11903
12910
  return;
11904
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
+ }
11905
12946
  }
11906
12947
  if (key.pageUp) {
11907
12948
  dispatch({ type: "scrollPage", dir: "up" });
@@ -12626,10 +13667,12 @@ User message:
12626
13667
  featureMemory: state.settingsPicker.featureMemory,
12627
13668
  featureSkills: state.settingsPicker.featureSkills,
12628
13669
  featureModelsRegistry: state.settingsPicker.featureModelsRegistry,
12629
- featureTokenSaving: state.settingsPicker.featureTokenSaving,
13670
+ tokenSavingTier: state.settingsPicker.tokenSavingTier,
12630
13671
  allowOutsideProjectRoot: state.settingsPicker.allowOutsideProjectRoot,
12631
13672
  contextAutoCompact: state.settingsPicker.contextAutoCompact,
12632
13673
  contextStrategy: state.settingsPicker.contextStrategy,
13674
+ contextMode: state.settingsPicker.contextMode,
13675
+ maxConcurrent: state.settingsPicker.maxConcurrent,
12633
13676
  logLevel: state.settingsPicker.logLevel,
12634
13677
  auditLevel: state.settingsPicker.auditLevel,
12635
13678
  indexOnStart: state.settingsPicker.indexOnStart,
@@ -12643,6 +13686,15 @@ User message:
12643
13686
  hint: state.settingsPicker.hint
12644
13687
  }
12645
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,
12646
13698
  state.projectPicker.open ? /* @__PURE__ */ jsx(
12647
13699
  ProjectPicker,
12648
13700
  {
@@ -12652,6 +13704,7 @@ User message:
12652
13704
  hint: state.projectPicker.hint
12653
13705
  }
12654
13706
  ) : null,
13707
+ state.fKeyPicker.open ? /* @__PURE__ */ jsx(FKeyPicker, { selected: state.fKeyPicker.selected }) : null,
12655
13708
  state.sessionsPanelOpen ? /* @__PURE__ */ jsx(
12656
13709
  SessionsPanel,
12657
13710
  {
@@ -12807,10 +13860,12 @@ User message:
12807
13860
  subagentCount: Object.keys(state.fleet).length,
12808
13861
  processCount: getProcessRegistry().activeCount,
12809
13862
  hiddenItems,
13863
+ visibleChips: state.statuslinePicker.visibleChips,
12810
13864
  events,
12811
13865
  eternalStage: state.eternalStage,
12812
13866
  goalSummary: state.goalSummary,
12813
13867
  indexState,
13868
+ breakerCountdown,
12814
13869
  modeLabel: liveModeLabel || void 0,
12815
13870
  debugStreamStats: state.debugStreamStats,
12816
13871
  enhanceCountdown,
@@ -12819,7 +13874,7 @@ User message:
12819
13874
  autoProceedCountdown: state.countdown?.remainingSeconds ?? null,
12820
13875
  sessionCount,
12821
13876
  mailbox: mailboxStatus,
12822
- tokenSavingMode: getSettings ? getSettings().featureTokenSaving : tokenSavingMode,
13877
+ tokenSavingMode: getSettings ? getSettings().featureTokenSaving !== "off" : tokenSavingMode,
12823
13878
  toolCount
12824
13879
  }
12825
13880
  ) }),
@@ -12889,7 +13944,23 @@ User message:
12889
13944
  Object.keys(state.worktrees).length > 0 && !state.worktreeMonitorOpen && !state.monitorOpen ? /* @__PURE__ */ jsx(WorktreePanel, { worktrees: state.worktrees, nowTick }) : null,
12890
13945
  state.queuePanelOpen ? /* @__PURE__ */ jsx(QueuePanel, { items: state.queue }) : null,
12891
13946
  state.processListOpen ? /* @__PURE__ */ jsx(ProcessListMonitor, {}) : null,
12892
- state.goalPanelOpen ? /* @__PURE__ */ jsx(GoalPanel, { goal: state.goalSummary }) : null,
13947
+ state.planPanelOpen ? /* @__PURE__ */ jsx(
13948
+ PlanPanel,
13949
+ {
13950
+ projectRoot,
13951
+ sessionId: agent.ctx.session?.id ?? null,
13952
+ onClose: () => dispatch({ type: "togglePlanPanel" })
13953
+ }
13954
+ ) : null,
13955
+ state.goalPanelOpen ? /* @__PURE__ */ jsx(
13956
+ GoalPanel,
13957
+ {
13958
+ goal: state.goalSummary,
13959
+ onCoordinatorStart: onCoordinatorStart ?? void 0,
13960
+ onCoordinatorStop: onCoordinatorStop ?? void 0,
13961
+ coordinatorRunning
13962
+ }
13963
+ ) : null,
12893
13964
  (() => {
12894
13965
  const anyMonitorOpen = state.agentsMonitorOpen || (state.autoPhase?.monitorOpen ?? false) || state.worktreeMonitorOpen || state.todosMonitorOpen || state.monitorOpen || state.processListOpen || state.queuePanelOpen || state.goalPanelOpen;
12895
13966
  let nextPanelHint;
@@ -13072,7 +14143,7 @@ async function runTui(opts) {
13072
14143
  stdout,
13073
14144
  events: opts.events,
13074
14145
  model: opts.model,
13075
- appName: opts.projectRoot ? path4.basename(opts.projectRoot) : void 0
14146
+ appName: opts.projectRoot ? path5.basename(opts.projectRoot) : void 0
13076
14147
  });
13077
14148
  };
13078
14149
  const stopTitle = () => {
@@ -13142,7 +14213,7 @@ async function runTui(opts) {
13142
14213
  await mailbox.registerClient({
13143
14214
  clientId,
13144
14215
  sessionId: opts.projectRoot,
13145
- name: `TUI [${path4.basename(opts.projectRoot)}]`,
14216
+ name: `TUI [${path5.basename(opts.projectRoot)}]`,
13146
14217
  source: "tui",
13147
14218
  pid: process.pid
13148
14219
  });
@@ -13250,6 +14321,7 @@ async function runTui(opts) {
13250
14321
  enhanceEnabled: opts.enhanceController?.enabled ?? true,
13251
14322
  statuslineHiddenItems: opts.statuslineHiddenItems,
13252
14323
  setStatuslineHiddenItems: opts.setStatuslineHiddenItems,
14324
+ saveStatuslineHiddenItems: opts.saveStatuslineHiddenItems,
13253
14325
  agentsMonitorController: opts.agentsMonitorController,
13254
14326
  initialGoal: opts.initialGoal,
13255
14327
  initialAsk: opts.initialAsk,
@@ -13285,7 +14357,10 @@ async function runTui(opts) {
13285
14357
  getLiveSessions: opts.getLiveSessions,
13286
14358
  onSwitchToSession: opts.onSwitchToSession,
13287
14359
  initialAgentsMonitorOpen: opts.initialAgentsMonitorOpen,
13288
- subscribeCoordinatorEvents: opts.subscribeCoordinatorEvents
14360
+ subscribeCoordinatorEvents: opts.subscribeCoordinatorEvents,
14361
+ onPanelOpen: opts.onPanelOpen,
14362
+ onCoordinatorStart: opts.onCoordinatorStart,
14363
+ onCoordinatorStop: opts.onCoordinatorStop
13289
14364
  }),
13290
14365
  { exitOnCtrlC: false, stdin: inkStdin }
13291
14366
  );