@wrongstack/tui 1.0.1 → 1.0.3

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
@@ -343,7 +343,7 @@ var init_connections_health = __esm({
343
343
 
344
344
  // src/app.tsx
345
345
  import * as path9 from "node:path";
346
- import React12, { useCallback as useCallback31, useEffect as useEffect72, useRef as useRef44 } from "react";
346
+ import React12, { useCallback as useCallback31, useEffect as useEffect73, useRef as useRef44 } from "react";
347
347
 
348
348
  // src/hooks/use-terminal-size.ts
349
349
  import { onResize } from "@wrongstack/core/utils";
@@ -8180,11 +8180,11 @@ function PhasePanel({ phases, nowTick }) {
8180
8180
  import * as fs from "node:fs/promises";
8181
8181
  import * as path from "node:path";
8182
8182
  import { resolveWstackPaths, sessionScopedPath } from "@wrongstack/core/utils";
8183
- import { useCallback as useCallback2, useEffect as useEffect10, useMemo as useMemo5, useState as useState12 } from "react";
8183
+ import { useCallback as useCallback2, useEffect as useEffect11, useMemo as useMemo5, useState as useState13 } from "react";
8184
8184
 
8185
8185
  // src/components/status-bar.tsx
8186
- import { expectDefined } from "@wrongstack/core/utils";
8187
8186
  import { effectiveDensity } from "@wrongstack/core/statusline";
8187
+ import { expectDefined } from "@wrongstack/core/utils";
8188
8188
  import { useMemo as useMemo4 } from "react";
8189
8189
 
8190
8190
  // src/hooks/use-chip-staleness-guard.ts
@@ -8290,13 +8290,46 @@ function computeTokenFingerprint(input, output, cost) {
8290
8290
  return `${input ?? 0}:${output ?? 0}:${cost != null ? cost.toFixed(4) : "0"}`;
8291
8291
  }
8292
8292
 
8293
+ // src/hooks/use-provider-quota.ts
8294
+ import {
8295
+ formatQuotaResetIn,
8296
+ getAllProviderQuota,
8297
+ onProviderQuota,
8298
+ quotaResetInMs,
8299
+ quotaWindowLabel,
8300
+ worstProviderQuotaWindow
8301
+ } from "@wrongstack/core/quota";
8302
+ import { useEffect as useEffect8, useState as useState10 } from "react";
8303
+ function readWorst() {
8304
+ const worst = worstProviderQuotaWindow(getAllProviderQuota());
8305
+ if (!worst) return void 0;
8306
+ const resetIn = formatQuotaResetIn(quotaResetInMs(worst.window));
8307
+ return {
8308
+ providerId: worst.snapshot.providerId,
8309
+ windowLabel: quotaWindowLabel(worst.window),
8310
+ usedPercent: worst.window.usedPercent,
8311
+ ...resetIn !== void 0 ? { resetIn } : {},
8312
+ reached: worst.snapshot.reachedWindowId === worst.window.id
8313
+ };
8314
+ }
8315
+ function useProviderQuota() {
8316
+ const [chip, setChip] = useState10(readWorst);
8317
+ useEffect8(() => {
8318
+ setChip(readWorst());
8319
+ return onProviderQuota(() => {
8320
+ setChip(readWorst());
8321
+ });
8322
+ }, []);
8323
+ return chip;
8324
+ }
8325
+
8293
8326
  // src/hooks/use-todos-auto-clear.ts
8294
- import { useEffect as useEffect8, useRef as useRef2, useState as useState10 } from "react";
8327
+ import { useEffect as useEffect9, useRef as useRef2, useState as useState11 } from "react";
8295
8328
  var TODOS_CLEAR_DELAY_MS = 3e3;
8296
8329
  function useTodosAutoClear(todos) {
8297
- const [todosCleared, setTodosCleared] = useState10(false);
8330
+ const [todosCleared, setTodosCleared] = useState11(false);
8298
8331
  const todosClearTimerRef = useRef2(null);
8299
- useEffect8(() => {
8332
+ useEffect9(() => {
8300
8333
  const hasActive = todos && (todos.pending > 0 || todos.inProgress > 0);
8301
8334
  if (hasActive) {
8302
8335
  if (todosClearTimerRef.current) {
@@ -8327,7 +8360,7 @@ function useTodosAutoClear(todos) {
8327
8360
  }
8328
8361
 
8329
8362
  // src/hooks/use-token-counter-refresh.ts
8330
- import { useEffect as useEffect9, useState as useState11 } from "react";
8363
+ import { useEffect as useEffect10, useState as useState12 } from "react";
8331
8364
  function snapshotTokenCounter(tokenCounter) {
8332
8365
  return {
8333
8366
  usage: tokenCounter.total(),
@@ -8337,10 +8370,10 @@ function snapshotTokenCounter(tokenCounter) {
8337
8370
  };
8338
8371
  }
8339
8372
  function useTokenCounterRefresh(tokenCounter, events, sessionId) {
8340
- const [data, setData] = useState11(
8373
+ const [data, setData] = useState12(
8341
8374
  () => tokenCounter ? snapshotTokenCounter(tokenCounter) : void 0
8342
8375
  );
8343
- useEffect9(() => {
8376
+ useEffect10(() => {
8344
8377
  if (!tokenCounter) {
8345
8378
  setData(void 0);
8346
8379
  return;
@@ -8760,6 +8793,7 @@ var STATUSLINE_ICONS = {
8760
8793
  processes: glyphs.process,
8761
8794
  project: glyphs.folder,
8762
8795
  prompt_variant: glyphs.terminal,
8796
+ quota: glyphs.target,
8763
8797
  queue: glyphs.queue,
8764
8798
  sessions: glyphs.sessions,
8765
8799
  side_effects: glyphs.audit,
@@ -9028,6 +9062,7 @@ function buildSafetyWorkEntries(p) {
9028
9062
  showEternalStage,
9029
9063
  eternalStage,
9030
9064
  breakerCountdown,
9065
+ quota,
9031
9066
  droppedTools,
9032
9067
  todos,
9033
9068
  todosCleared,
@@ -9072,6 +9107,39 @@ function buildSafetyWorkEntries(p) {
9072
9107
  ] })
9073
9108
  ]);
9074
9109
  })() : null,
9110
+ // Standing budget, beside the standing throttle: `breaker` says "this
9111
+ // session is paused for N seconds", `quota` says "this plan is N% spent".
9112
+ // A reader scanning for "why can't it just run" wants both in one place.
9113
+ quota && showChip("quota") ? (() => {
9114
+ const pct = Math.round(quota.usedPercent);
9115
+ const color = chipColor(
9116
+ quota.reached || pct >= 90 ? theme.error : pct >= 70 ? theme.warn : theme.textSecondary,
9117
+ isNoColor
9118
+ );
9119
+ const reset = quota.resetIn ? ` ${glyphs.clock}${quota.resetIn}` : "";
9120
+ return entry("quota", "quota", p, [
9121
+ /* @__PURE__ */ jsxs17(Text, { color, children: [
9122
+ icon(STATUSLINE_ICONS.quota, isNoColor),
9123
+ quota.windowLabel,
9124
+ " ",
9125
+ pct,
9126
+ "%",
9127
+ reset
9128
+ ] }),
9129
+ /* @__PURE__ */ jsxs17(Text, { color, children: [
9130
+ icon(STATUSLINE_ICONS.quota, isNoColor),
9131
+ quota.windowLabel,
9132
+ " ",
9133
+ pct,
9134
+ "%"
9135
+ ] }),
9136
+ /* @__PURE__ */ jsxs17(Text, { color, children: [
9137
+ isNoColor ? "" : STATUSLINE_ICONS.quota,
9138
+ pct,
9139
+ "%"
9140
+ ] })
9141
+ ]);
9142
+ })() : null,
9075
9143
  tokenSavingMode !== void 0 && tokenSavingMode !== "off" && showChip("token_saving") ? entry("token_saving", "token_saving", p, [
9076
9144
  /* @__PURE__ */ jsx18(Text, { color: chipColor(theme.warn, isNoColor), bold: true, children: isNoColor ? tokenSavingMode : `${STATUSLINE_ICONS.token_saving} ${tokenSavingMode}` }),
9077
9145
  /* @__PURE__ */ jsx18(Text, { color: chipColor(theme.warn, isNoColor), bold: true, children: isNoColor ? tokenSavingMode.slice(0, 1) : `${STATUSLINE_ICONS.token_saving}${tokenSavingMode.slice(0, 1).toUpperCase()}` })
@@ -10061,6 +10129,7 @@ function StatusBar({
10061
10129
  const modelShortChip = showChip("model") ? /* @__PURE__ */ jsx21(Text, { color: modelColor, children: model }) : null;
10062
10130
  const modelMicroChip = showChip("model") ? /* @__PURE__ */ jsx21(Text, { color: modelColor, children: truncateChip(model, 10) }) : null;
10063
10131
  const indexStatusChip = buildIndexStatusChip(indexState, showChip, isNoColor);
10132
+ const quota = useProviderQuota();
10064
10133
  const buildParams = {
10065
10134
  showChip,
10066
10135
  chipDensity,
@@ -10084,6 +10153,7 @@ function StatusBar({
10084
10153
  queueCount,
10085
10154
  hint,
10086
10155
  breakerCountdown,
10156
+ quota,
10087
10157
  projectName,
10088
10158
  workingDir,
10089
10159
  git,
@@ -10230,12 +10300,12 @@ function planFilePath(projectRoot, sessionId, scope) {
10230
10300
  return path.join(base, "backlog.plan.json");
10231
10301
  }
10232
10302
  function usePlanPanelData(projectRoot, sessionId, enabled = true) {
10233
- const [items, setItems] = useState12([]);
10234
- const [title, setTitle2] = useState12(void 0);
10235
- const [scope, setScope] = useState12("session");
10236
- const [loading, setLoading] = useState12(true);
10237
- const [error, setError] = useState12(null);
10238
- const [updatedAt, setUpdatedAt] = useState12(void 0);
10303
+ const [items, setItems] = useState13([]);
10304
+ const [title, setTitle2] = useState13(void 0);
10305
+ const [scope, setScope] = useState13("session");
10306
+ const [loading, setLoading] = useState13(true);
10307
+ const [error, setError] = useState13(null);
10308
+ const [updatedAt, setUpdatedAt] = useState13(void 0);
10239
10309
  const load = useCallback2(
10240
10310
  async (scope_, quiet = false) => {
10241
10311
  if (!quiet) setLoading(true);
@@ -10266,7 +10336,7 @@ function usePlanPanelData(projectRoot, sessionId, enabled = true) {
10266
10336
  },
10267
10337
  [projectRoot, sessionId]
10268
10338
  );
10269
- useEffect10(() => {
10339
+ useEffect11(() => {
10270
10340
  if (!enabled) return;
10271
10341
  void load(scope);
10272
10342
  const timer = setInterval(() => void load(scope, true), 3e3);
@@ -10285,7 +10355,7 @@ function PlanPanel({
10285
10355
  projectRoot,
10286
10356
  sessionId
10287
10357
  );
10288
- const [selected, setSelected] = useState12(0);
10358
+ const [selected, setSelected] = useState13(0);
10289
10359
  async function handleScopeSwitch(newScope) {
10290
10360
  await load(newScope);
10291
10361
  }
@@ -10303,7 +10373,7 @@ function PlanPanel({
10303
10373
  const inProgress = items.filter((i) => i.status === "in_progress");
10304
10374
  const done = items.filter((i) => i.status === "done");
10305
10375
  const ordered = useMemo5(() => [...inProgress, ...open2, ...done], [inProgress, open2, done]);
10306
- useEffect10(() => {
10376
+ useEffect11(() => {
10307
10377
  setSelected((value) => Math.min(Math.max(0, ordered.length - 1), value));
10308
10378
  }, [ordered.length]);
10309
10379
  const limit = Math.max(2, size.contentRows - 5);
@@ -10432,15 +10502,15 @@ function PlanRow({
10432
10502
  }
10433
10503
 
10434
10504
  // src/components/process-list.tsx
10435
- import { useEffect as useEffect11, useState as useState13 } from "react";
10505
+ import { useEffect as useEffect12, useState as useState14 } from "react";
10436
10506
  import { getProcessRegistry } from "@wrongstack/tools";
10437
10507
  import { jsx as jsx23, jsxs as jsxs23 } from "react/jsx-runtime";
10438
10508
  function ProcessListMonitor() {
10439
10509
  const size = useMonitorSize();
10440
- const [, setTick] = useState13(0);
10441
- const [selectedIndex, setSelectedIndex] = useState13(0);
10442
- const [pendingAction, setPendingAction] = useState13(null);
10443
- useEffect11(() => {
10510
+ const [, setTick] = useState14(0);
10511
+ const [selectedIndex, setSelectedIndex] = useState14(0);
10512
+ const [pendingAction, setPendingAction] = useState14(null);
10513
+ useEffect12(() => {
10444
10514
  const id = setInterval(() => setTick((t) => t + 1), 1e3);
10445
10515
  return () => clearInterval(id);
10446
10516
  }, []);
@@ -10448,7 +10518,7 @@ function ProcessListMonitor() {
10448
10518
  const all = registry.list();
10449
10519
  const stats = registry.stats();
10450
10520
  const safeIndex = Math.min(selectedIndex, Math.max(0, all.length - 1));
10451
- useEffect11(
10521
+ useEffect12(
10452
10522
  () => setSelectedIndex((value) => Math.min(value, Math.max(0, all.length - 1))),
10453
10523
  [all.length]
10454
10524
  );
@@ -10605,7 +10675,7 @@ function ProcessListMonitor() {
10605
10675
  }
10606
10676
 
10607
10677
  // src/components/queue-panel.tsx
10608
- import { useCallback as useCallback3, useEffect as useEffect12, useState as useState14 } from "react";
10678
+ import { useCallback as useCallback3, useEffect as useEffect13, useState as useState15 } from "react";
10609
10679
  import { jsx as jsx24, jsxs as jsxs24 } from "react/jsx-runtime";
10610
10680
  function QueuePanel({
10611
10681
  items,
@@ -10615,16 +10685,16 @@ function QueuePanel({
10615
10685
  onToggleRefine
10616
10686
  }) {
10617
10687
  const size = useMonitorSize();
10618
- const [selected, setSelected] = useState14(0);
10619
- const [confirmClear, setConfirmClear] = useState14(false);
10688
+ const [selected, setSelected] = useState15(0);
10689
+ const [confirmClear, setConfirmClear] = useState15(false);
10620
10690
  const maxVisible = Math.max(3, size.contentRows - 2);
10621
10691
  const window = panelWindow(items.length, selected, maxVisible);
10622
10692
  const visible = items.slice(window.start, window.end);
10623
10693
  const overflow = window.above + window.below;
10624
- useEffect12(() => {
10694
+ useEffect13(() => {
10625
10695
  setSelected((value) => Math.min(value, Math.max(0, items.length - 1)));
10626
10696
  }, [items.length]);
10627
- useEffect12(() => {
10697
+ useEffect13(() => {
10628
10698
  if (confirmClear && items.length === 0) setConfirmClear(false);
10629
10699
  }, [items.length, confirmClear]);
10630
10700
  const shortcutsEnabled = usePanelShortcutsEnabled();
@@ -11342,11 +11412,11 @@ function StatuslinePicker({
11342
11412
  }
11343
11413
 
11344
11414
  // src/components/todos-monitor.tsx
11345
- import { useEffect as useEffect13, useState as useState15 } from "react";
11415
+ import { useEffect as useEffect14, useState as useState16 } from "react";
11346
11416
  import { jsx as jsx28, jsxs as jsxs28 } from "react/jsx-runtime";
11347
11417
  function TodosMonitor({ todos }) {
11348
11418
  const size = useMonitorSize();
11349
- const [selected, setSelected] = useState15(0);
11419
+ const [selected, setSelected] = useState16(0);
11350
11420
  const done = todos.filter((t) => t.status === "completed").length;
11351
11421
  const inProgress = todos.filter((t) => t.status === "in_progress").length;
11352
11422
  const pending = todos.filter((t) => t.status === "pending").length;
@@ -11362,7 +11432,7 @@ function TodosMonitor({ todos }) {
11362
11432
  const visible = ordered.slice(window.start, window.end);
11363
11433
  const overflow = window.above + window.below;
11364
11434
  const mid = twoCols ? Math.ceil(visible.length / 2) : visible.length;
11365
- useEffect13(() => {
11435
+ useEffect14(() => {
11366
11436
  setSelected((value) => Math.min(value, Math.max(0, ordered.length - 1)));
11367
11437
  }, [ordered.length]);
11368
11438
  useInput((_input, key) => {
@@ -11476,7 +11546,7 @@ function TodosMonitor({ todos }) {
11476
11546
  }
11477
11547
 
11478
11548
  // src/components/worktree-monitor.tsx
11479
- import { useEffect as useEffect14, useState as useState16 } from "react";
11549
+ import { useEffect as useEffect15, useState as useState17 } from "react";
11480
11550
  import { jsx as jsx29, jsxs as jsxs29 } from "react/jsx-runtime";
11481
11551
  var fmtElapsed4 = (ms) => {
11482
11552
  const s2 = Math.floor(ms / 1e3);
@@ -11508,7 +11578,7 @@ function WorktreeMonitor({
11508
11578
  onClose
11509
11579
  }) {
11510
11580
  const size = useMonitorSize();
11511
- const [selected, setSelected] = useState16(0);
11581
+ const [selected, setSelected] = useState17(0);
11512
11582
  const shortcutsEnabled = usePanelShortcutsEnabled();
11513
11583
  useInput((input, key) => {
11514
11584
  if (key.escape === true || shortcutsEnabled && isWorktreeMonitorCloseKey(input, key))
@@ -11531,7 +11601,7 @@ function WorktreeMonitor({
11531
11601
  const merged = list.filter((w) => w.status === "merged").length;
11532
11602
  const failed = list.filter((w) => w.status === "failed" || w.status === "needs-review").length;
11533
11603
  const staleTerminal = list.length - recent.length;
11534
- useEffect14(() => {
11604
+ useEffect15(() => {
11535
11605
  setSelected((value) => Math.min(value, Math.max(0, recent.length - 1)));
11536
11606
  }, [recent.length]);
11537
11607
  const cardRows = size.columns >= 92 ? 3 : 4;
@@ -12177,6 +12247,7 @@ var AUTH_PANEL_INITIAL = {
12177
12247
  busy: false,
12178
12248
  providers: [],
12179
12249
  presets: [],
12250
+ oauthStrategies: [],
12180
12251
  catalog: [],
12181
12252
  selected: 0,
12182
12253
  filter: "",
@@ -12256,7 +12327,7 @@ function authPanelRows(state) {
12256
12327
  case "local":
12257
12328
  return state.presets.map((preset) => ({ kind: "local-preset", preset }));
12258
12329
  case "oauth":
12259
- return ["chatgpt", "claude", "copilot"].map((oauth) => ({
12330
+ return (state.oauthStrategies ?? []).map((oauth) => ({
12260
12331
  kind: "oauth-option",
12261
12332
  oauth
12262
12333
  }));
@@ -12410,7 +12481,7 @@ var LIST_ACTION_LABEL = {
12410
12481
  catalog: "\uFF0B Add provider (models.dev catalog)",
12411
12482
  local: "\uFF0B Add local server (OmniRoute / Ollama / vLLM / LM Studio)",
12412
12483
  custom: "\uFF0B Add custom provider",
12413
- oauth: "\u26A1 Sign in with OAuth (ChatGPT / Claude / Copilot)"
12484
+ oauth: "\u26A1 Sign in with provider OAuth"
12414
12485
  };
12415
12486
  var PROVIDER_ACTION_LABEL = {
12416
12487
  "add-key": "\uFF0B Add another key",
@@ -12424,11 +12495,6 @@ var PROVIDER_ACTION_LABEL = {
12424
12495
  remove: "\u2715 Remove this provider",
12425
12496
  "back-to-list": "\u2190 Back to providers"
12426
12497
  };
12427
- var OAUTH_LABEL = {
12428
- chatgpt: { title: "ChatGPT Plus/Pro", detail: "\u2192 openai-codex" },
12429
- claude: { title: "Claude Pro/Max", detail: "\u2192 anthropic-oauth" },
12430
- copilot: { title: "GitHub Copilot", detail: "\u2192 github-copilot" }
12431
- };
12432
12498
  function formatExpiry(expiresAt) {
12433
12499
  if (!expiresAt) return null;
12434
12500
  const expiry = Date.parse(expiresAt);
@@ -12529,15 +12595,15 @@ function renderRow(row, focused, i) {
12529
12595
  ] }, `l-${p.id}`);
12530
12596
  }
12531
12597
  case "oauth-option": {
12532
- const o = OAUTH_LABEL[row.oauth] ?? { title: row.oauth, detail: "" };
12533
- const kindColor = OAUTH_KIND_COLORS[row.oauth] ?? UI_COLORS.focused;
12598
+ const o = row.oauth;
12599
+ const kindColor = OAUTH_KIND_COLORS[o.id] ?? UI_COLORS.focused;
12534
12600
  return /* @__PURE__ */ jsxs33(Text, { color: rowColor, wrap: "truncate-end", children: [
12535
12601
  marker,
12536
12602
  " ",
12537
- /* @__PURE__ */ jsx33(Text, { bold: true, color: focused ? void 0 : kindColor, children: o.title.padEnd(20) }),
12603
+ /* @__PURE__ */ jsx33(Text, { bold: true, color: focused ? void 0 : kindColor, children: o.label.padEnd(20) }),
12538
12604
  " ",
12539
- /* @__PURE__ */ jsx33(Text, { dimColor: true, children: o.detail })
12540
- ] }, `o-${row.oauth}`);
12605
+ /* @__PURE__ */ jsx33(Text, { dimColor: true, children: o.description ?? `\u2192 ${o.providerId}` })
12606
+ ] }, `o-${o.id}`);
12541
12607
  }
12542
12608
  case "form-field": {
12543
12609
  const placeholder2 = row.field === "family" ? focused ? "\u25C0 \u25B6" : " " : focused ? "\u258F" : "";
@@ -16803,7 +16869,7 @@ function ConfirmPrompt({
16803
16869
 
16804
16870
  // src/components/connections-panel.tsx
16805
16871
  init_connections_health();
16806
- import { useCallback as useCallback4, useEffect as useEffect15, useRef as useRef3, useState as useState17 } from "react";
16872
+ import { useCallback as useCallback4, useEffect as useEffect16, useRef as useRef3, useState as useState18 } from "react";
16807
16873
  import { jsx as jsx43, jsxs as jsxs43 } from "react/jsx-runtime";
16808
16874
  var REFRESH_MS = 8e3;
16809
16875
  var STATUS_GLYPH = {
@@ -16873,9 +16939,9 @@ function ConnectionsPanel({
16873
16939
  projectRoot,
16874
16940
  onClose
16875
16941
  }) {
16876
- const [report, setReport] = useState17(null);
16877
- const [loading, setLoading] = useState17(true);
16878
- const [error, setError] = useState17(null);
16942
+ const [report, setReport] = useState18(null);
16943
+ const [loading, setLoading] = useState18(true);
16944
+ const [error, setError] = useState18(null);
16879
16945
  const cancelledRef = useRef3(false);
16880
16946
  const fetch2 = useCallback4(async () => {
16881
16947
  try {
@@ -16890,7 +16956,7 @@ function ConnectionsPanel({
16890
16956
  if (!cancelledRef.current) setLoading(false);
16891
16957
  }
16892
16958
  }, [projectRoot]);
16893
- useEffect15(() => {
16959
+ useEffect16(() => {
16894
16960
  cancelledRef.current = false;
16895
16961
  void fetch2();
16896
16962
  const timer = setInterval(() => void fetch2(), REFRESH_MS);
@@ -17085,7 +17151,7 @@ function BugHuntRunningPanel({
17085
17151
  }
17086
17152
 
17087
17153
  // src/components/coordinator-panel.tsx
17088
- import { useEffect as useEffect16, useState as useState18 } from "react";
17154
+ import { useEffect as useEffect17, useState as useState19 } from "react";
17089
17155
  import { jsx as jsx47, jsxs as jsxs47 } from "react/jsx-runtime";
17090
17156
  var KIND_COLOR = {
17091
17157
  goal: theme.accent,
@@ -17119,9 +17185,9 @@ function CoordinatorPanel({
17119
17185
  onClose
17120
17186
  }) {
17121
17187
  const size = useMonitorSize();
17122
- const [selectedGoal, setSelectedGoal] = useState18(0);
17188
+ const [selectedGoal, setSelectedGoal] = useState19(0);
17123
17189
  const { goals, timeline, knowledgeCount, healthy } = coordinator;
17124
- useEffect16(() => {
17190
+ useEffect17(() => {
17125
17191
  setSelectedGoal((value) => Math.min(value, Math.max(0, goals.length - 1)));
17126
17192
  }, [goals.length]);
17127
17193
  const shortcutsEnabled = usePanelShortcutsEnabled();
@@ -17325,7 +17391,7 @@ function DesignPicker({ kits, selected, stack }) {
17325
17391
  }
17326
17392
 
17327
17393
  // src/components/enhance-panel.tsx
17328
- import { useEffect as useEffect17, useRef as useRef4 } from "react";
17394
+ import { useEffect as useEffect18, useRef as useRef4 } from "react";
17329
17395
  import { Fragment as Fragment18, jsx as jsx49, jsxs as jsxs49 } from "react/jsx-runtime";
17330
17396
  function normalizePreviewText(text) {
17331
17397
  return text.replace(/\s+/g, " ").trim();
@@ -17516,7 +17582,7 @@ function EnhancePanel({
17516
17582
  decideRef.current = onDecision;
17517
17583
  const tickRef = useRef4(onTick);
17518
17584
  tickRef.current = onTick;
17519
- useEffect17(() => {
17585
+ useEffect18(() => {
17520
17586
  tickRef.current?.(remainingRef.current);
17521
17587
  const id = setInterval(() => {
17522
17588
  const remaining = remainingRef.current - 1;
@@ -17803,7 +17869,7 @@ function FKeyPicker({ selected }) {
17803
17869
  }
17804
17870
 
17805
17871
  // src/components/fallback-overlay.tsx
17806
- import { useEffect as useEffect18, useRef as useRef5, useState as useState19 } from "react";
17872
+ import { useEffect as useEffect19, useRef as useRef5, useState as useState20 } from "react";
17807
17873
  import { jsx as jsx53, jsxs as jsxs53 } from "react/jsx-runtime";
17808
17874
  function FallbackOverlay({
17809
17875
  from,
@@ -17814,7 +17880,7 @@ function FallbackOverlay({
17814
17880
  onChoose,
17815
17881
  onMove
17816
17882
  }) {
17817
- const [remaining, setRemaining] = useState19(Math.max(1, autoSwitchSeconds));
17883
+ const [remaining, setRemaining] = useState20(Math.max(1, autoSwitchSeconds));
17818
17884
  const resolvedRef = useRef5(false);
17819
17885
  const selectedRef = useRef5(selected);
17820
17886
  selectedRef.current = selected;
@@ -17822,7 +17888,7 @@ function FallbackOverlay({
17822
17888
  candidatesRef.current = candidates;
17823
17889
  const onChooseRef = useRef5(onChoose);
17824
17890
  onChooseRef.current = onChoose;
17825
- useEffect18(() => {
17891
+ useEffect19(() => {
17826
17892
  const id = setInterval(() => {
17827
17893
  setRemaining((prev) => {
17828
17894
  if (prev <= 1) {
@@ -18769,7 +18835,7 @@ function PromptPicker({
18769
18835
  }
18770
18836
 
18771
18837
  // src/components/refine-countdown-panel.tsx
18772
- import { useEffect as useEffect19, useRef as useRef6, useState as useState20 } from "react";
18838
+ import { useEffect as useEffect20, useRef as useRef6, useState as useState21 } from "react";
18773
18839
  import { jsx as jsx62, jsxs as jsxs62 } from "react/jsx-runtime";
18774
18840
  function RefineCountdownPanel({
18775
18841
  original,
@@ -18778,13 +18844,13 @@ function RefineCountdownPanel({
18778
18844
  providerId,
18779
18845
  model
18780
18846
  }) {
18781
- const [remaining, setRemaining] = useState20(Math.max(1, seconds));
18847
+ const [remaining, setRemaining] = useState21(Math.max(1, seconds));
18782
18848
  const resolvedRef = useRef6(false);
18783
18849
  const onDecisionRef = useRef6(onDecision);
18784
- useEffect19(() => {
18850
+ useEffect20(() => {
18785
18851
  onDecisionRef.current = onDecision;
18786
18852
  }, [onDecision]);
18787
- useEffect19(() => {
18853
+ useEffect20(() => {
18788
18854
  const id = setInterval(() => {
18789
18855
  setRemaining((prev) => {
18790
18856
  if (prev <= 1) {
@@ -18857,7 +18923,7 @@ function RefineCountdownPanel({
18857
18923
  }
18858
18924
 
18859
18925
  // src/components/refine-failure-panel.tsx
18860
- import { useState as useState21, useMemo as useMemo6 } from "react";
18926
+ import { useState as useState22, useMemo as useMemo6 } from "react";
18861
18927
  import { jsx as jsx63, jsxs as jsxs63 } from "react/jsx-runtime";
18862
18928
  function filterRefineModels(models, query) {
18863
18929
  const normalized = query.trim().toLowerCase();
@@ -18879,9 +18945,9 @@ function RefineFailurePanel({
18879
18945
  onDecision
18880
18946
  }) {
18881
18947
  const columns = useColumns();
18882
- const [view, setView] = useState21("options");
18883
- const [cursor, setCursor] = useState21(0);
18884
- const [query, setQuery] = useState21("");
18948
+ const [view, setView] = useState22("options");
18949
+ const [cursor, setCursor] = useState22(0);
18950
+ const [query, setQuery] = useState22("");
18885
18951
  const filteredModels = useMemo6(() => filterRefineModels(models, query), [models, query]);
18886
18952
  const width = Math.max(30, columns - 4);
18887
18953
  const canPick = models.length > 0;
@@ -19427,7 +19493,7 @@ function SendModePicker({
19427
19493
  }
19428
19494
 
19429
19495
  // src/components/settings-picker.tsx
19430
- import { useEffect as useEffect20 } from "react";
19496
+ import { useEffect as useEffect21 } from "react";
19431
19497
 
19432
19498
  // src/components/settings-picker-filter.ts
19433
19499
  function fuzzyMatch(haystack, needle) {
@@ -20808,7 +20874,7 @@ function SettingsPicker({
20808
20874
  for (let i = 0; i < rows.length; i++) {
20809
20875
  if (!rows[i]?.section) fieldRowIndex.push(i);
20810
20876
  }
20811
- useEffect20(() => {
20877
+ useEffect21(() => {
20812
20878
  onLayoutComputed?.({ rows, fieldRowIndex });
20813
20879
  });
20814
20880
  const { filterActive, rankedResults, filteredFieldIndices, highlightSegments } = buildSettingsFilterState(filter, SETTINGS_PICKER_JUMP_CHORDS);
@@ -24561,7 +24627,7 @@ function AppViewSidebar({
24561
24627
  }
24562
24628
 
24563
24629
  // src/components/input.tsx
24564
- import { memo as memo2, useEffect as useEffect21, useRef as useRef7, useState as useState22 } from "react";
24630
+ import { memo as memo2, useEffect as useEffect22, useRef as useRef7, useState as useState23 } from "react";
24565
24631
 
24566
24632
  // src/fn-keys.ts
24567
24633
  function fnKey(data) {
@@ -24949,10 +25015,11 @@ function ComposerTopRail({
24949
25015
  status,
24950
25016
  animationStyle,
24951
25017
  disabled,
24952
- workingTime
25018
+ workingTime,
25019
+ icon: icon2 = glyphs.brand,
25020
+ accent
24953
25021
  }) {
24954
25022
  const available = Math.max(0, width - 2);
24955
- const icon2 = glyphs.brand;
24956
25023
  const staticMode = animationStyle === "static";
24957
25024
  const requestedStatusWidth = composerStatusReservedWidth(status);
24958
25025
  const statusWidth = Math.min(requestedStatusWidth, Math.max(0, available - 3));
@@ -24964,7 +25031,7 @@ function ComposerTopRail({
24964
25031
  const titlePrefix = title ? `${titlePrefixRaw}${workingTimeChip} ` : "";
24965
25032
  const titleW = displayWidth(titlePrefix);
24966
25033
  const remaining = Math.max(0, available - titleW - statusSectionW);
24967
- return /* @__PURE__ */ jsxs87(Text, { bold: true, color: disabled ? theme.error : theme.brandPrimary, children: [
25034
+ return /* @__PURE__ */ jsxs87(Text, { bold: true, color: disabled ? theme.error : accent ?? theme.brandPrimary, children: [
24968
25035
  "\u256D",
24969
25036
  title ? /* @__PURE__ */ jsxs87(Fragment33, { children: [
24970
25037
  /* @__PURE__ */ jsx87(Text, { children: "\u2500 " }),
@@ -25074,6 +25141,8 @@ var Input = memo2(function Input2({
25074
25141
  disabled,
25075
25142
  hint,
25076
25143
  title = "ASK WRONGSTACK",
25144
+ railIcon,
25145
+ accent,
25077
25146
  status,
25078
25147
  animationStyle = "rainbow",
25079
25148
  workingTime,
@@ -25128,7 +25197,7 @@ var Input = memo2(function Input2({
25128
25197
  onKey(input, key);
25129
25198
  });
25130
25199
  const { stdin } = useStdin();
25131
- useEffect21(() => {
25200
+ useEffect22(() => {
25132
25201
  if (!stdin) return;
25133
25202
  let escTimer = null;
25134
25203
  const handleData = (data) => {
@@ -25242,7 +25311,7 @@ var Input = memo2(function Input2({
25242
25311
  };
25243
25312
  }, [stdin, disabled, onKey]);
25244
25313
  const { columns: cols } = useTerminalSize({ maxWidth });
25245
- const promptColor = disabled ? theme.error : theme.brandAccent;
25314
+ const promptColor = disabled ? theme.error : accent ?? theme.brandAccent;
25246
25315
  const contentWidth = inputContentWidth(cols);
25247
25316
  const rows = layoutInputRows(prompt, value, cursor, contentWidth);
25248
25317
  const MAX_VISIBLE_ROWS = 10;
@@ -25257,18 +25326,18 @@ var Input = memo2(function Input2({
25257
25326
  }
25258
25327
  }
25259
25328
  }
25260
- const [vScroll, setVScroll] = useState22(0);
25329
+ const [vScroll, setVScroll] = useState23(0);
25261
25330
  const vScrollRef = useRef7(vScroll);
25262
25331
  vScrollRef.current = vScroll;
25263
25332
  const clampedScroll = needsScroll ? Math.max(0, Math.min(vScroll, rows.length - MAX_VISIBLE_ROWS)) : 0;
25264
- useEffect21(() => {
25333
+ useEffect22(() => {
25265
25334
  if (!needsScroll || !onKey) return;
25266
25335
  const cur = vScrollRef.current;
25267
25336
  const clamped = Math.max(0, Math.min(cur, rows.length - MAX_VISIBLE_ROWS));
25268
25337
  if (cursorRow < clamped) setVScroll(cursorRow);
25269
25338
  else if (cursorRow >= clamped + MAX_VISIBLE_ROWS) setVScroll(cursorRow - MAX_VISIBLE_ROWS + 1);
25270
25339
  }, [cursorRow, needsScroll, onKey]);
25271
- useEffect21(() => {
25340
+ useEffect22(() => {
25272
25341
  if (!needsScroll && vScroll > 0) setVScroll(0);
25273
25342
  }, [needsScroll]);
25274
25343
  const visibleRows = needsScroll ? rows.slice(clampedScroll, clampedScroll + MAX_VISIBLE_ROWS) : rows;
@@ -25300,6 +25369,8 @@ var Input = memo2(function Input2({
25300
25369
  {
25301
25370
  width: cols,
25302
25371
  title,
25372
+ icon: railIcon,
25373
+ accent,
25303
25374
  status: railStatus,
25304
25375
  animationStyle,
25305
25376
  disabled: disabled ?? false,
@@ -25310,17 +25381,17 @@ var Input = memo2(function Input2({
25310
25381
  const rowWidth = displayWidth(row.map((cell) => cell.ch).join(""));
25311
25382
  const padding = " ".repeat(Math.max(0, contentWidth - rowWidth));
25312
25383
  return /* @__PURE__ */ jsxs87(Text, { children: [
25313
- /* @__PURE__ */ jsx87(Text, { color: disabled ? theme.error : theme.brandPrimary, children: "\u2502 " }),
25384
+ /* @__PURE__ */ jsx87(Text, { color: disabled ? theme.error : accent ?? theme.brandPrimary, children: "\u2502 " }),
25314
25385
  row.length === 0 ? null : renderRow2(row, `r${i}`, promptColor),
25315
25386
  /* @__PURE__ */ jsx87(Text, { children: padding }),
25316
- /* @__PURE__ */ jsx87(Text, { color: disabled ? theme.error : theme.brandPrimary, children: " \u2502" })
25387
+ /* @__PURE__ */ jsx87(Text, { color: disabled ? theme.error : accent ?? theme.brandPrimary, children: " \u2502" })
25317
25388
  ] }, i);
25318
25389
  }),
25319
25390
  /* @__PURE__ */ jsxs87(Text, { children: [
25320
- /* @__PURE__ */ jsx87(Text, { color: disabled ? theme.error : theme.brandPrimary, children: leftBorder }),
25391
+ /* @__PURE__ */ jsx87(Text, { color: disabled ? theme.error : accent ?? theme.brandPrimary, children: leftBorder }),
25321
25392
  /* @__PURE__ */ jsx87(Text, { color: theme.textMuted, children: shownHint }),
25322
25393
  scrollIndicator ? /* @__PURE__ */ jsx87(Text, { color: theme.textMuted, children: scrollIndicator }) : null,
25323
- /* @__PURE__ */ jsxs87(Text, { color: disabled ? theme.error : theme.brandPrimary, children: [
25394
+ /* @__PURE__ */ jsxs87(Text, { color: disabled ? theme.error : accent ?? theme.brandPrimary, children: [
25324
25395
  fillW > 0 ? " " : "",
25325
25396
  "\u2500".repeat(fillW),
25326
25397
  "\u256F"
@@ -25330,7 +25401,7 @@ var Input = memo2(function Input2({
25330
25401
  });
25331
25402
 
25332
25403
  // src/components/scrollable-history.tsx
25333
- import { memo as memo7, useCallback as useCallback6, useEffect as useEffect24, useLayoutEffect, useMemo as useMemo10, useRef as useRef10, useState as useState23 } from "react";
25404
+ import { memo as memo7, useCallback as useCallback6, useEffect as useEffect25, useLayoutEffect, useMemo as useMemo10, useRef as useRef10, useState as useState24 } from "react";
25334
25405
 
25335
25406
  // src/height-cache.ts
25336
25407
  var DEFAULT_ENTRY_HEIGHT = 3;
@@ -26010,7 +26081,7 @@ function copyableTextForEntry(entry2) {
26010
26081
  case "turn-summary":
26011
26082
  return textOrRaw(entry2.text, entry2);
26012
26083
  case "tool":
26013
- return textOrRaw(entry2.output ?? "", entry2);
26084
+ return textOrRaw(entry2.copyOutput ?? entry2.output ?? "", entry2);
26014
26085
  case "memory-lifecycle":
26015
26086
  return textOrRaw([entry2.label, entry2.detail].filter(Boolean).join("\n"), entry2);
26016
26087
  case "brain":
@@ -26028,7 +26099,13 @@ function copyableTextForEntry(entry2) {
26028
26099
  }
26029
26100
  }
26030
26101
  function copyableTextForEntries(entries) {
26031
- return stringifyRaw(entries);
26102
+ return stringifyRaw(
26103
+ entries.map((entry2) => {
26104
+ if (entry2.kind !== "tool" || entry2.copyOutput === void 0) return entry2;
26105
+ const { copyOutput, ...displayEntry } = entry2;
26106
+ return { ...displayEntry, output: copyOutput };
26107
+ })
26108
+ );
26032
26109
  }
26033
26110
  function isCopyableEntry(_entry) {
26034
26111
  return true;
@@ -26366,7 +26443,7 @@ import { memo as memo6, useRef as useRef8 } from "react";
26366
26443
  // src/components/history/entry.tsx
26367
26444
  import { hasOpenTodos } from "@wrongstack/core/utils";
26368
26445
  import { parseNextSteps } from "@wrongstack/tools/next-steps";
26369
- import React8, { useEffect as useEffect22, useMemo as useMemo8 } from "react";
26446
+ import React8, { useEffect as useEffect23, useMemo as useMemo8 } from "react";
26370
26447
 
26371
26448
  // src/history-entry.ts
26372
26449
  import { DEFAULT_MIN_IMPORTANCE, DEFAULT_MIN_SCORE, MIN_RELATION_STRENGTH } from "@wrongstack/sage";
@@ -27718,7 +27795,7 @@ var Entry = React8.memo(function Entry2({
27718
27795
  if (entry2.kind !== "assistant") return { steps: [], stripped: "" };
27719
27796
  return parseNextSteps(entry2.text, true);
27720
27797
  }, [entry2.kind, entry2.text]);
27721
- useEffect22(() => {
27798
+ useEffect23(() => {
27722
27799
  if (!setSuggestions) return;
27723
27800
  if (entry2.kind !== "assistant") return;
27724
27801
  if (openTodos) return;
@@ -28161,7 +28238,7 @@ var History = memo6(function History2({
28161
28238
  });
28162
28239
 
28163
28240
  // src/components/history/use-history-controller.ts
28164
- import { useCallback as useCallback5, useEffect as useEffect23, useMemo as useMemo9, useRef as useRef9 } from "react";
28241
+ import { useCallback as useCallback5, useEffect as useEffect24, useMemo as useMemo9, useRef as useRef9 } from "react";
28165
28242
 
28166
28243
  // src/clipboard.ts
28167
28244
  import {
@@ -28486,7 +28563,7 @@ function useHistoryController(opts) {
28486
28563
  toolStreamRef
28487
28564
  ]
28488
28565
  );
28489
- useEffect23(() => {
28566
+ useEffect24(() => {
28490
28567
  if (!controllerRef) return void 0;
28491
28568
  controllerRef.current = controller;
28492
28569
  return () => {
@@ -28574,12 +28651,12 @@ var ScrollableHistory = memo7(function ScrollableHistory2({
28574
28651
  const raw = stdout?.columns ?? 80;
28575
28652
  return maxWidth ? Math.min(raw, maxWidth) : raw;
28576
28653
  }, [stdout, maxWidth]);
28577
- const [viewportWidth, setViewportWidth] = useState23(resolveViewportWidth);
28654
+ const [viewportWidth, setViewportWidth] = useState24(resolveViewportWidth);
28578
28655
  const termWidth = useMemo10(
28579
28656
  () => Math.max(1, viewportWidth - SCROLLBAR_HIT_WIDTH),
28580
28657
  [viewportWidth]
28581
28658
  );
28582
- useEffect24(() => {
28659
+ useEffect25(() => {
28583
28660
  const handleResize = () => {
28584
28661
  setViewportWidth(resolveViewportWidth());
28585
28662
  };
@@ -28679,8 +28756,8 @@ var ScrollableHistory = memo7(function ScrollableHistory2({
28679
28756
  preparedEstimateWidthRef.current = termWidth;
28680
28757
  }
28681
28758
  const vp = Math.max(1, viewportRows);
28682
- const [anchor, setAnchor] = useState23(null);
28683
- const [mountBump, setMountBump] = useState23(0);
28759
+ const [anchor, setAnchor] = useState24(null);
28760
+ const [mountBump, setMountBump] = useState24(0);
28684
28761
  const prevTermWidthRef = useRef10(termWidth);
28685
28762
  if (prevTermWidthRef.current !== termWidth) {
28686
28763
  prevTermWidthRef.current = termWidth;
@@ -28691,7 +28768,7 @@ var ScrollableHistory = memo7(function ScrollableHistory2({
28691
28768
  prevVpRef.current = viewportRows;
28692
28769
  setMountBump(0);
28693
28770
  }
28694
- const [, setMeasureTick] = useState23(0);
28771
+ const [, setMeasureTick] = useState24(0);
28695
28772
  const geometry = {
28696
28773
  cache: heightCache,
28697
28774
  groupCount: groupedEntries.length,
@@ -28740,7 +28817,7 @@ var ScrollableHistory = memo7(function ScrollableHistory2({
28740
28817
  const requestOlderFiredRef = useRef10(false);
28741
28818
  const onRequestOlderEntriesRef = useRef10(onRequestOlderEntries);
28742
28819
  onRequestOlderEntriesRef.current = onRequestOlderEntries;
28743
- useEffect24(() => {
28820
+ useEffect25(() => {
28744
28821
  if (lastReportedScrolled.current === scrolled) return;
28745
28822
  lastReportedScrolled.current = scrolled;
28746
28823
  onScrollInfoRef.current?.({ scrolled });
@@ -28948,7 +29025,7 @@ var ScrollableHistory = memo7(function ScrollableHistory2({
28948
29025
 
28949
29026
  // src/hooks/use-sidebar-panel-data.ts
28950
29027
  import { getProcessRegistry as getProcessRegistry3 } from "@wrongstack/tools";
28951
- import { useEffect as useEffect25, useState as useState24 } from "react";
29028
+ import { useEffect as useEffect26, useState as useState25 } from "react";
28952
29029
  function sameList(a, b, eq) {
28953
29030
  if (a === b) return true;
28954
29031
  if (a.length !== b.length) return false;
@@ -28958,8 +29035,8 @@ function sameList(a, b, eq) {
28958
29035
  return true;
28959
29036
  }
28960
29037
  function useSidebarProcessList(enabled = true) {
28961
- const [data, setData] = useState24({ activeCount: 0, totalCount: 0, processes: [] });
28962
- useEffect25(() => {
29038
+ const [data, setData] = useState25({ activeCount: 0, totalCount: 0, processes: [] });
29039
+ useEffect26(() => {
28963
29040
  if (!enabled) return;
28964
29041
  const read = () => {
28965
29042
  const registry = getProcessRegistry3();
@@ -28986,8 +29063,8 @@ function useSidebarProcessList(enabled = true) {
28986
29063
  return data;
28987
29064
  }
28988
29065
  function useSidebarConnections(projectRoot, enabled = true) {
28989
- const [connections, setConnections] = useState24([]);
28990
- useEffect25(() => {
29066
+ const [connections, setConnections] = useState25([]);
29067
+ useEffect26(() => {
28991
29068
  if (!enabled) return;
28992
29069
  let cancelled = false;
28993
29070
  const poll = async () => {
@@ -29026,8 +29103,8 @@ function setProxyData(setData, next) {
29026
29103
  );
29027
29104
  }
29028
29105
  function useSidebarWrongProxy(url, enabled = true) {
29029
- const [data, setData] = useState24(null);
29030
- useEffect25(() => {
29106
+ const [data, setData] = useState25(null);
29107
+ useEffect26(() => {
29031
29108
  if (!enabled || !url) {
29032
29109
  setData(null);
29033
29110
  return;
@@ -29095,8 +29172,8 @@ function useSidebarWrongProxy(url, enabled = true) {
29095
29172
  return data;
29096
29173
  }
29097
29174
  function useSidebarKanban(projectRoot, enabled = true) {
29098
- const [data, setData] = useState24({ columns: [], totalActive: 0, activeCardTitles: [] });
29099
- useEffect25(() => {
29175
+ const [data, setData] = useState25({ columns: [], totalActive: 0, activeCardTitles: [] });
29176
+ useEffect26(() => {
29100
29177
  if (!enabled) return;
29101
29178
  let cancelled = false;
29102
29179
  const poll = async () => {
@@ -29160,6 +29237,9 @@ function useSidebarKanban(projectRoot, enabled = true) {
29160
29237
  // src/app-view.tsx
29161
29238
  import { jsx as jsx101, jsxs as jsxs99 } from "react/jsx-runtime";
29162
29239
  var INPUT_PROMPT = DEFAULT_INPUT_PROMPT;
29240
+ var BASH_PROMPT = "$ ";
29241
+ var BASH_TITLE = "BASH MODE";
29242
+ var BASH_HINT = "shell command \u2014 Enter run \xB7 Esc exit";
29163
29243
  function AppView({ host, runtime }) {
29164
29244
  const { agent, appVersion, setSuggestions } = host;
29165
29245
  const {
@@ -29179,6 +29259,7 @@ function AppView({ host, runtime }) {
29179
29259
  const { workingTimeMs } = activity;
29180
29260
  const { autonomyLive } = environment;
29181
29261
  const { inputHint, composerStatus, composerAnimationStyle, inputHeight, hideInput } = viewState;
29262
+ const bashMode = state.bashMode;
29182
29263
  const { columns: termCols } = useTerminalSize({ fallbackColumns: 80 });
29183
29264
  const { panelPositions, sidebarWidth, sidebarContentWidth, mainColumnWidth } = resolveAppSidebarLayout(state, termCols, liveSettings, mailbox.mailboxPanelOpen);
29184
29265
  const routedToSidebar = (id) => panelPositions[id] === "sidebar";
@@ -29249,17 +29330,19 @@ function AppView({ host, runtime }) {
29249
29330
  /* @__PURE__ */ jsx101(
29250
29331
  Input,
29251
29332
  {
29252
- prompt: INPUT_PROMPT,
29333
+ prompt: bashMode ? BASH_PROMPT : INPUT_PROMPT,
29253
29334
  value: state.buffer,
29254
29335
  cursor: state.cursor,
29255
- title: `WRONGSTACK${appVersion ? ` v${appVersion}` : ""}`,
29336
+ title: bashMode ? BASH_TITLE : `WRONGSTACK${appVersion ? ` v${appVersion}` : ""}`,
29337
+ railIcon: bashMode ? glyphs.terminal : void 0,
29338
+ accent: bashMode ? theme.warn : void 0,
29256
29339
  status: composerStatus,
29257
29340
  animationStyle: composerAnimationStyle,
29258
29341
  hidden: hideInput,
29259
29342
  placeholderHeight: inputHeight,
29260
29343
  maxWidth: mainColumnWidth,
29261
29344
  disabled: state.status === "aborting" && !state.steeringPending || state.confirmQueue.length > 0,
29262
- hint: inputHint,
29345
+ hint: bashMode ? BASH_HINT : inputHint,
29263
29346
  onKey: stableOnKey,
29264
29347
  workingTime: workingTimeMs
29265
29348
  }
@@ -29479,15 +29562,17 @@ function deleteWordForward(buffer, cursor) {
29479
29562
  var PASTE_THRESHOLD_CHARS = 200;
29480
29563
  async function routeInputKey(host, input, key) {
29481
29564
  const { buffer, cursor } = host.draft;
29482
- if (key.tab && host.nextSteps.timer.current != null) {
29483
- const pending = host.nextSteps.suggestion.current ?? host.nextSteps.label ?? "";
29484
- clearInterval(host.nextSteps.timer.current);
29485
- host.nextSteps.timer.current = void 0;
29486
- host.nextSteps.setCountdown(null);
29487
- host.nextSteps.setLabel(null);
29488
- host.nextSteps.suggestion.current = null;
29489
- const text = pending.trim();
29490
- if (text) host.setDraft(text, text.length);
29565
+ if (key.tab) {
29566
+ if (!host.state.bashMode && host.nextSteps.timer.current != null) {
29567
+ const pending = host.nextSteps.suggestion.current ?? host.nextSteps.label ?? "";
29568
+ clearInterval(host.nextSteps.timer.current);
29569
+ host.nextSteps.timer.current = void 0;
29570
+ host.nextSteps.setCountdown(null);
29571
+ host.nextSteps.setLabel(null);
29572
+ host.nextSteps.suggestion.current = null;
29573
+ const text = pending.trim();
29574
+ if (text) host.setDraft(text, text.length);
29575
+ }
29491
29576
  return true;
29492
29577
  }
29493
29578
  if (key.backspace) {
@@ -29499,6 +29584,10 @@ async function routeInputKey(host, input, key) {
29499
29584
  }
29500
29585
  return true;
29501
29586
  }
29587
+ if (host.state.bashMode && buffer === "") {
29588
+ host.dispatch({ type: "bashModeExit" });
29589
+ return true;
29590
+ }
29502
29591
  const token = deleteTokenBackward(buffer, cursor);
29503
29592
  if (token) {
29504
29593
  host.setDraft(token.buffer, token.cursor);
@@ -30323,6 +30412,11 @@ function createAppKeyHandler(options) {
30323
30412
  lastEscAtRef.current = 0;
30324
30413
  return;
30325
30414
  }
30415
+ if (state.bashMode) {
30416
+ dispatch({ type: "bashModeExit" });
30417
+ lastEscAtRef.current = 0;
30418
+ return;
30419
+ }
30326
30420
  }
30327
30421
  if (routeBusyInterruptKey(
30328
30422
  {
@@ -30383,7 +30477,7 @@ function createAppKeyHandler(options) {
30383
30477
  }
30384
30478
  }
30385
30479
  }
30386
- if (state.sddBoard?.monitorOpen && !key.ctrl && !key.meta && draftRef.current.buffer === "") {
30480
+ if (state.sddBoard?.monitorOpen && !key.ctrl && !key.meta && draftRef.current.buffer === "" && !state.bashMode) {
30387
30481
  if (key.rightArrow) {
30388
30482
  dispatch({ type: "sddBoardFocusNext" });
30389
30483
  return;
@@ -30471,10 +30565,14 @@ function createAppKeyHandler(options) {
30471
30565
  dispatch({ type: "toggleSidebarFocus" });
30472
30566
  }
30473
30567
  }
30474
- if (input === "?" && !key.ctrl && !key.meta && draftRef.current.buffer === "" && !overlayOpen) {
30568
+ if (input === "?" && !key.ctrl && !key.meta && draftRef.current.buffer === "" && !overlayOpen && !state.bashMode) {
30475
30569
  dispatch({ type: "toggleHelp" });
30476
30570
  return;
30477
30571
  }
30572
+ if (input === "!" && !key.ctrl && !key.meta && draftRef.current.buffer === "" && !overlayOpen && !state.bashMode) {
30573
+ dispatch({ type: "bashModeEnter" });
30574
+ return;
30575
+ }
30478
30576
  if (isEnter) {
30479
30577
  if (key.shift) {
30480
30578
  const { buffer, cursor } = draftRef.current;
@@ -30483,6 +30581,14 @@ function createAppKeyHandler(options) {
30483
30581
  lastEnterAtRef.current = Date.now();
30484
30582
  return;
30485
30583
  }
30584
+ if (state.bashMode) {
30585
+ const body = draftRef.current.buffer.trim();
30586
+ const command = body.startsWith("!") ? body.slice(1).trim() : body;
30587
+ dispatch({ type: "bashModeExit" });
30588
+ lastEnterAtRef.current = Date.now();
30589
+ if (command) detach(Promise.resolve(submit(`!${command}`)), "Send");
30590
+ return;
30591
+ }
30486
30592
  const now = Date.now();
30487
30593
  if (now - lastEnterAtRef.current < 50) return;
30488
30594
  lastEnterAtRef.current = now;
@@ -31695,7 +31801,7 @@ function createSubmitController(host) {
31695
31801
  }
31696
31802
  }
31697
31803
  const sddContext = await getSDDContext?.();
31698
- if (!steering && stateRef.current.status === "idle" && continueResolved === null && !sddContext) {
31804
+ if (!isAutomaticBugHuntReplay && !steering && stateRef.current.status === "idle" && continueResolved === null && !sddContext) {
31699
31805
  const liveState = stateRef.current;
31700
31806
  const advice = await topicAdvisorFor(agent).advise({
31701
31807
  prompt: trimmed,
@@ -31770,7 +31876,13 @@ New topic: ${advice.nextTopic}` : "";
31770
31876
  setModel: setRefineModel
31771
31877
  },
31772
31878
  trimmed,
31773
- { steering, continuationResolved: continueResolved !== null }
31879
+ {
31880
+ steering,
31881
+ // Internal bug-hunt continuation text is already generated by the
31882
+ // workflow. Treat it like a resolved continuation so a second model
31883
+ // cannot rewrite workflow control text before the main run sees it.
31884
+ continuationResolved: continueResolved !== null || isAutomaticBugHuntReplay
31885
+ }
31774
31886
  );
31775
31887
  if (refinement.kind === "cancel") return;
31776
31888
  let effectiveText = refinement.effectiveText;
@@ -31894,7 +32006,9 @@ User message:
31894
32006
  });
31895
32007
  return;
31896
32008
  }
31897
- dispatch({ type: "addEntry", entry: { kind: "user", text: displayText, pasteContent } });
32009
+ if (!isAutomaticBugHuntReplay) {
32010
+ dispatch({ type: "addEntry", entry: { kind: "user", text: displayText, pasteContent } });
32011
+ }
31898
32012
  if (autonomyLive === "auto" && nextStepsAutoSubmitTimerRef.current != null) {
31899
32013
  switchAutonomy?.("off");
31900
32014
  }
@@ -31930,7 +32044,7 @@ function useAppExecutionPipeline(args) {
31930
32044
 
31931
32045
  // src/hooks/use-app-picker-keys.ts
31932
32046
  import { toErrorMessage as toErrorMessage5 } from "@wrongstack/core/utils";
31933
- import { useEffect as useEffect26, useRef as useRef12 } from "react";
32047
+ import { useEffect as useEffect27, useRef as useRef12 } from "react";
31934
32048
 
31935
32049
  // src/resume-load.ts
31936
32050
  var STAGE_LABELS = {
@@ -33255,7 +33369,7 @@ function useAppPickerKeys({
33255
33369
  const resumeInFlightRef = useRef12(false);
33256
33370
  const sessionsResumeInFlightRef = useRef12(false);
33257
33371
  const mountedRef = useRef12(true);
33258
- useEffect26(() => {
33372
+ useEffect27(() => {
33259
33373
  mountedRef.current = true;
33260
33374
  return () => {
33261
33375
  mountedRef.current = false;
@@ -33762,7 +33876,7 @@ function buildAppPipelineArgs(params) {
33762
33876
  lastEnterAtRef,
33763
33877
  draftRef,
33764
33878
  setDraft,
33765
- submit: () => submitRef.current(),
33879
+ submit: (overrideRaw) => submitRef.current(overrideRaw),
33766
33880
  mouseMode,
33767
33881
  termRows,
33768
33882
  terminalColumns,
@@ -33923,7 +34037,7 @@ function buildAppPipelineArgs(params) {
33923
34037
 
33924
34038
  // src/hooks/use-app-runtime-refs.ts
33925
34039
  import { InputBuilder } from "@wrongstack/core/agent";
33926
- import { useEffect as useEffect27, useRef as useRef13 } from "react";
34040
+ import { useEffect as useEffect28, useRef as useRef13 } from "react";
33927
34041
  function useAppRuntimeRefs(attachments, state) {
33928
34042
  const promptUsageRef = useRef13(null);
33929
34043
  const builderRef = useRef13(null);
@@ -33931,7 +34045,7 @@ function useAppRuntimeRefs(attachments, state) {
33931
34045
  builderRef.current = new InputBuilder({ store: attachments });
33932
34046
  }
33933
34047
  const activeCtrlRef = useRef13(null);
33934
- useEffect27(
34048
+ useEffect28(
33935
34049
  () => () => {
33936
34050
  activeCtrlRef.current?.abort("TUI unmounted");
33937
34051
  activeCtrlRef.current = null;
@@ -33989,7 +34103,7 @@ function useAppRuntimeRefs(attachments, state) {
33989
34103
  }
33990
34104
 
33991
34105
  // src/hooks/use-app-session-state.ts
33992
- import { useEffect as useEffect28, useMemo as useMemo11, useReducer } from "react";
34106
+ import { useEffect as useEffect29, useMemo as useMemo11, useReducer } from "react";
33993
34107
 
33994
34108
  // src/components/history/replay.ts
33995
34109
  import {
@@ -34014,8 +34128,8 @@ function markerToEntry(marker) {
34014
34128
  if (marker.level === "warn") return { kind: "warn", text: marker.text };
34015
34129
  return { kind: "info", text: marker.text };
34016
34130
  }
34017
- function toolOutputPreview(content) {
34018
- return (typeof content === "string" ? content : JSON.stringify(content)).slice(0, 400);
34131
+ function toolOutputText(content) {
34132
+ return typeof content === "string" ? content : JSON.stringify(content);
34019
34133
  }
34020
34134
  function replaySessionMessages(messages, events, startId) {
34021
34135
  const timeline = projectSessionTimeline({
@@ -34059,7 +34173,7 @@ function timelineToEntry(item) {
34059
34173
  durationMs: item.durationMs ?? 0,
34060
34174
  ok: item.ok ?? false,
34061
34175
  input: item.input,
34062
- output: item.output === void 0 ? void 0 : toolOutputPreview(item.output),
34176
+ output: item.output === void 0 ? void 0 : toolOutputText(item.output),
34063
34177
  outputBytes: item.outputBytes,
34064
34178
  outputTokens: item.outputTokens,
34065
34179
  outputLines: item.outputLines
@@ -34091,7 +34205,8 @@ function entryBytes2(entry2) {
34091
34205
  if (cached !== void 0) return cached;
34092
34206
  let bytes;
34093
34207
  try {
34094
- bytes = Buffer.byteLength(JSON.stringify(entry2), "utf8");
34208
+ const budgetedEntry = entry2.kind === "tool" && entry2.copyOutput !== void 0 ? (({ copyOutput: _copyOutput, ...displayEntry }) => displayEntry)(entry2) : entry2;
34209
+ bytes = Buffer.byteLength(JSON.stringify(budgetedEntry), "utf8");
34095
34210
  } catch {
34096
34211
  bytes = TUI_HISTORY_MAX_BYTES + 1;
34097
34212
  }
@@ -34125,6 +34240,16 @@ function retainTextWithinEntryBudget(value, maxBytes, createEntry, original) {
34125
34240
  }
34126
34241
  function retainTuiHistoryEntry(entry2, maxBytes = TUI_HISTORY_MAX_ENTRY_BYTES) {
34127
34242
  if (entryBytes2(entry2) <= maxBytes) return entry2;
34243
+ if (entry2.kind === "tool") {
34244
+ const copyableEntry = entry2.output !== void 0 && entry2.copyOutput === void 0 ? { ...entry2, copyOutput: entry2.output } : entry2;
34245
+ const name = copyableEntry.name.length > 1024 ? `${copyableEntry.name.slice(0, 1024)}\u2026` : copyableEntry.name;
34246
+ return retainTextWithinEntryBudget(
34247
+ copyableEntry.output ?? "",
34248
+ maxBytes,
34249
+ (text) => ({ ...copyableEntry, name, input: void 0, output: text }),
34250
+ copyableEntry
34251
+ );
34252
+ }
34128
34253
  switch (entry2.kind) {
34129
34254
  case "user":
34130
34255
  return retainTextWithinEntryBudget(
@@ -34152,16 +34277,6 @@ function retainTuiHistoryEntry(entry2, maxBytes = TUI_HISTORY_MAX_ENTRY_BYTES) {
34152
34277
  (text) => ({ ...entry2, text, detail: void 0 }),
34153
34278
  entry2
34154
34279
  );
34155
- case "tool": {
34156
- const name = entry2.name.length > 1024 ? `${entry2.name.slice(0, 1024)}\u2026` : entry2.name;
34157
- const output = entry2.output ?? "";
34158
- return retainTextWithinEntryBudget(
34159
- output,
34160
- maxBytes,
34161
- (text) => ({ ...entry2, name, input: void 0, output: text }),
34162
- entry2
34163
- );
34164
- }
34165
34280
  case "banner": {
34166
34281
  const truncate5 = (value) => value.length > 1024 ? `${value.slice(0, 1024)}\u2026` : value;
34167
34282
  const compact2 = {
@@ -34414,6 +34529,7 @@ function createInitialState(options) {
34414
34529
  resumeLoad: null,
34415
34530
  buffer: "",
34416
34531
  cursor: 0,
34532
+ bashMode: false,
34417
34533
  streamingText: "",
34418
34534
  toolStream: null,
34419
34535
  status: "idle",
@@ -35374,6 +35490,7 @@ function reduceDialogs(state, action) {
35374
35490
  view: action.view ?? "list",
35375
35491
  providers: action.providers ?? state.authPanel.providers,
35376
35492
  presets: action.presets ?? state.authPanel.presets,
35493
+ oauthStrategies: action.oauthStrategies ?? state.authPanel.oauthStrategies,
35377
35494
  catalog: state.authPanel.catalog,
35378
35495
  busy: action.providers === void 0
35379
35496
  }
@@ -35674,6 +35791,8 @@ var composerActionTypes = [
35674
35791
  "queueClear",
35675
35792
  "queueDelete",
35676
35793
  "queueToggleRefine",
35794
+ "bashModeEnter",
35795
+ "bashModeExit",
35677
35796
  "slashPickerOpen",
35678
35797
  "slashPickerClose",
35679
35798
  "slashPickerMove",
@@ -35767,6 +35886,10 @@ function reduceComposer(state, action) {
35767
35886
  const next = (state.picker.selected + action.delta + n) % n;
35768
35887
  return { ...state, picker: { ...state.picker, selected: next } };
35769
35888
  }
35889
+ case "bashModeEnter":
35890
+ return state.bashMode ? state : { ...state, bashMode: true, historyIndex: 0, historyDraft: "" };
35891
+ case "bashModeExit":
35892
+ return state.bashMode ? { ...state, bashMode: false, historyIndex: 0, historyDraft: "" } : state;
35770
35893
  case "toolStarted": {
35771
35894
  const next = new Map(state.runningTools);
35772
35895
  next.set(action.id, { name: action.name, startedAt: Date.now() });
@@ -35882,9 +36005,11 @@ function reduceComposer(state, action) {
35882
36005
  return { ...state, inputHistory: [action.text, ...state.inputHistory].slice(0, 100) };
35883
36006
  }
35884
36007
  case "historyUp": {
35885
- if (state.inputHistory.length === 0) return state;
35886
- const next = Math.min(state.historyIndex + 1, state.inputHistory.length);
35887
- const entry2 = state.inputHistory[next - 1] ?? "";
36008
+ const entries = state.bashMode ? state.inputHistory.filter((entry3) => entry3.startsWith("!")) : state.inputHistory;
36009
+ if (entries.length === 0) return state;
36010
+ const next = Math.min(state.historyIndex + 1, entries.length);
36011
+ const raw = entries[next - 1] ?? "";
36012
+ const entry2 = state.bashMode ? raw.slice(1) : raw;
35888
36013
  const historyDraft = state.historyIndex === 0 ? state.buffer : state.historyDraft;
35889
36014
  return {
35890
36015
  ...state,
@@ -35895,9 +36020,11 @@ function reduceComposer(state, action) {
35895
36020
  };
35896
36021
  }
35897
36022
  case "historyDown": {
36023
+ const entries = state.bashMode ? state.inputHistory.filter((entry3) => entry3.startsWith("!")) : state.inputHistory;
35898
36024
  if (state.historyIndex === 0) return state;
35899
36025
  const next = state.historyIndex - 1;
35900
- const entry2 = next === 0 ? state.historyDraft : state.inputHistory[next - 1] ?? "";
36026
+ const raw = next === 0 ? state.historyDraft : entries[next - 1] ?? "";
36027
+ const entry2 = state.bashMode && next !== 0 ? raw.slice(1) : raw;
35901
36028
  return {
35902
36029
  ...state,
35903
36030
  historyIndex: next,
@@ -36570,6 +36697,7 @@ function reduceConversation(state, action) {
36570
36697
  bugHuntRunning: null,
36571
36698
  sendModePicker: null,
36572
36699
  shellCommandWarning: null,
36700
+ bashMode: false,
36573
36701
  escConfirm: null,
36574
36702
  exitConfirm: null,
36575
36703
  // Auto-proceed countdown from the old conversation.
@@ -38569,7 +38697,7 @@ function useAppSessionState(options) {
38569
38697
  }),
38570
38698
  [options.sessionsDir]
38571
38699
  );
38572
- useEffect28(() => {
38700
+ useEffect29(() => {
38573
38701
  void layoutStore.load();
38574
38702
  return () => {
38575
38703
  void layoutStore.flushNow();
@@ -38579,18 +38707,13 @@ function useAppSessionState(options) {
38579
38707
  }
38580
38708
 
38581
38709
  // src/hooks/use-auth-panel.ts
38582
- import { useCallback as useCallback9, useEffect as useEffect29, useRef as useRef14 } from "react";
38710
+ import { useCallback as useCallback9, useEffect as useEffect30, useRef as useRef14 } from "react";
38583
38711
  function abortError() {
38584
38712
  return Object.assign(new Error("Cancelled"), { name: "AbortError" });
38585
38713
  }
38586
38714
  function toMessage(err) {
38587
38715
  return err instanceof Error ? err.message : String(err);
38588
38716
  }
38589
- var OAUTH_TITLE = {
38590
- chatgpt: "Sign in with ChatGPT",
38591
- claude: "Sign in with Claude",
38592
- copilot: "Sign in with GitHub Copilot"
38593
- };
38594
38717
  function useAuthPanel(opts) {
38595
38718
  const { authHost, stateRef, dispatch, open: open2 } = opts;
38596
38719
  const flowAbortRef = useRef14(null);
@@ -38605,14 +38728,14 @@ function useAuthPanel(opts) {
38605
38728
  promptRef.current = null;
38606
38729
  pending?.reject(abortError());
38607
38730
  }, []);
38608
- useEffect29(() => {
38731
+ useEffect30(() => {
38609
38732
  mountedRef.current = true;
38610
38733
  return () => {
38611
38734
  mountedRef.current = false;
38612
38735
  abortLiveFlow();
38613
38736
  };
38614
38737
  }, [abortLiveFlow]);
38615
- useEffect29(() => {
38738
+ useEffect30(() => {
38616
38739
  if (!open2) abortLiveFlow();
38617
38740
  }, [open2, abortLiveFlow]);
38618
38741
  const reloadProviders = useCallback9(async () => {
@@ -38630,7 +38753,12 @@ function useAuthPanel(opts) {
38630
38753
  (view = "list") => {
38631
38754
  if (!authHost) return false;
38632
38755
  abortLiveFlow();
38633
- dispatch({ type: "authOpen", view, presets: authHost.localPresets() });
38756
+ dispatch({
38757
+ type: "authOpen",
38758
+ view,
38759
+ presets: authHost.localPresets(),
38760
+ oauthStrategies: authHost.oauthStrategies?.() ?? []
38761
+ });
38634
38762
  void reloadProviders();
38635
38763
  return true;
38636
38764
  },
@@ -38946,7 +39074,7 @@ function useAuthPanel(opts) {
38946
39074
  openLocalForm(row.preset);
38947
39075
  return;
38948
39076
  case "oauth-option":
38949
- runFlow(OAUTH_TITLE[row.oauth] ?? "Sign in", (io) => authHost.oauthLogin(row.oauth, io));
39077
+ runFlow(`Sign in with ${row.oauth.label}`, (io) => authHost.oauthLogin(row.oauth.id, io));
38950
39078
  return;
38951
39079
  default:
38952
39080
  return;
@@ -39126,7 +39254,7 @@ function useAuthPanel(opts) {
39126
39254
  }
39127
39255
 
39128
39256
  // src/hooks/use-autonomous-coordinator.ts
39129
- import { useCallback as useCallback10, useEffect as useEffect30, useRef as useRef15 } from "react";
39257
+ import { useCallback as useCallback10, useEffect as useEffect31, useRef as useRef15 } from "react";
39130
39258
  function useAutonomousCoordinator(subscribeCoordinatorEvents, dispatch) {
39131
39259
  const dispatchRef = useRef15(dispatch);
39132
39260
  dispatchRef.current = dispatch;
@@ -39136,7 +39264,7 @@ function useAutonomousCoordinator(subscribeCoordinatorEvents, dispatch) {
39136
39264
  event
39137
39265
  });
39138
39266
  }, []);
39139
- useEffect30(() => {
39267
+ useEffect31(() => {
39140
39268
  if (!subscribeCoordinatorEvents) return;
39141
39269
  const unsubscribe = subscribeCoordinatorEvents(handler);
39142
39270
  return unsubscribe;
@@ -39145,7 +39273,7 @@ function useAutonomousCoordinator(subscribeCoordinatorEvents, dispatch) {
39145
39273
 
39146
39274
  // src/hooks/use-autonomy-drivers.ts
39147
39275
  import { toErrorMessage as toErrorMessage6 } from "@wrongstack/core/utils";
39148
- import { useEffect as useEffect31, useRef as useRef16 } from "react";
39276
+ import { useEffect as useEffect32, useRef as useRef16 } from "react";
39149
39277
  var BETWEEN_ITERATION_YIELD_MS = 200;
39150
39278
  function yieldBetweenIterations(ms = BETWEEN_ITERATION_YIELD_MS) {
39151
39279
  return new Promise((resolve) => setTimeout(resolve, ms));
@@ -39165,7 +39293,7 @@ function useAutonomyDrivers({
39165
39293
  parallelLoopRunningRef
39166
39294
  }) {
39167
39295
  const mountedRef = useRef16(true);
39168
- useEffect31(() => {
39296
+ useEffect32(() => {
39169
39297
  mountedRef.current = true;
39170
39298
  return () => {
39171
39299
  mountedRef.current = false;
@@ -39257,7 +39385,7 @@ function useAutonomyDrivers({
39257
39385
  };
39258
39386
  const runParallelLoopRef = useRef16(runParallelLoop);
39259
39387
  runParallelLoopRef.current = runParallelLoop;
39260
- useEffect31(() => {
39388
+ useEffect32(() => {
39261
39389
  if (!subscribeEternalIteration) return;
39262
39390
  const unsub = subscribeEternalIteration((entry2) => {
39263
39391
  const mark = entry2.status === "success" ? "\u2713" : entry2.status === "failure" ? "\u2717" : entry2.status === "aborted" ? "\u2298" : "\xB7";
@@ -39268,7 +39396,7 @@ function useAutonomyDrivers({
39268
39396
  });
39269
39397
  return unsub;
39270
39398
  }, [subscribeEternalIteration]);
39271
- useEffect31(() => {
39399
+ useEffect32(() => {
39272
39400
  if (!subscribeEternalStage) return;
39273
39401
  const unsub = subscribeEternalStage((stage) => {
39274
39402
  dispatch({ type: "eternalStage", stage });
@@ -39615,7 +39743,7 @@ function useBrainPanel(opts) {
39615
39743
  }
39616
39744
 
39617
39745
  // src/hooks/use-brain-risk-sync.ts
39618
- import { useCallback as useCallback11, useEffect as useEffect32, useRef as useRef17 } from "react";
39746
+ import { useCallback as useCallback11, useEffect as useEffect33, useRef as useRef17 } from "react";
39619
39747
  function useBrainRiskSync({
39620
39748
  dispatch,
39621
39749
  riskLevel,
@@ -39629,7 +39757,7 @@ function useBrainRiskSync({
39629
39757
  [dispatch]
39630
39758
  );
39631
39759
  const prevRiskRef = useRef17(riskLevel);
39632
- useEffect32(() => {
39760
+ useEffect33(() => {
39633
39761
  if (!brainPanelOpen) return;
39634
39762
  if (riskLevel !== prevRiskRef.current && onBrainRiskLevel) {
39635
39763
  prevRiskRef.current = riskLevel;
@@ -39643,7 +39771,7 @@ function useBrainRiskSync({
39643
39771
 
39644
39772
  // src/hooks/use-client-telemetry.ts
39645
39773
  import { projectSlug } from "@wrongstack/core/utils";
39646
- import { useEffect as useEffect33 } from "react";
39774
+ import { useEffect as useEffect34 } from "react";
39647
39775
  function useClientTelemetry({
39648
39776
  events,
39649
39777
  clientId,
@@ -39654,7 +39782,7 @@ function useClientTelemetry({
39654
39782
  restoreDebugStreamCallback,
39655
39783
  dispatch
39656
39784
  }) {
39657
- useEffect33(() => {
39785
+ useEffect34(() => {
39658
39786
  if (!clientId || !events) return;
39659
39787
  let toolCalls = 0;
39660
39788
  const emitStatus = () => {
@@ -39696,7 +39824,7 @@ function useClientTelemetry({
39696
39824
  offIterCompleted();
39697
39825
  };
39698
39826
  }, [events, clientId, tokenCounter, getAutonomy, agent.ctx.model, agent.ctx.projectRoot]);
39699
- useEffect33(() => {
39827
+ useEffect34(() => {
39700
39828
  if (!registerDebugStreamCallback) return;
39701
39829
  let cancelled = false;
39702
39830
  registerDebugStreamCallback((stats) => {
@@ -39730,7 +39858,7 @@ import { toErrorMessage as toErrorMessage7 } from "@wrongstack/core/utils";
39730
39858
  import { getProcessRegistry as getProcessRegistry6 } from "@wrongstack/tools";
39731
39859
  import {
39732
39860
  useCallback as useCallback12,
39733
- useEffect as useEffect34,
39861
+ useEffect as useEffect35,
39734
39862
  useMemo as useMemo12
39735
39863
  } from "react";
39736
39864
 
@@ -41653,7 +41781,7 @@ function useCoreTuiCommands({
41653
41781
  }) {
41654
41782
  const stdout = { columns: terminalWidth };
41655
41783
  const getCronJobs = useMemo12(() => createCronJobsGetter(agent), [agent]);
41656
- useEffect34(() => {
41784
+ useEffect35(() => {
41657
41785
  const cleanups = [];
41658
41786
  cleanups.push(registerSlashCommandLifecycle(slashRegistry, createKillSlashCommand()));
41659
41787
  cleanups.push(registerSlashCommandLifecycle(slashRegistry, createPsSlashCommand()));
@@ -41728,7 +41856,7 @@ function useCoreTuiCommands({
41728
41856
  getModeLabel,
41729
41857
  getCronJobs
41730
41858
  ]);
41731
- useEffect34(() => {
41859
+ useEffect35(() => {
41732
41860
  return () => {
41733
41861
  getProcessRegistry6().killAll({ preserveBackground: true });
41734
41862
  };
@@ -41760,7 +41888,7 @@ function useCoreTuiCommands({
41760
41888
  },
41761
41889
  [liveDirector, clearPendingConfirms, dispatch]
41762
41890
  );
41763
- useEffect34(() => {
41891
+ useEffect35(() => {
41764
41892
  const cmd = {
41765
41893
  name: "steer",
41766
41894
  description: "Interrupt the running agent (incl. fleet) and redirect: /steer <new direction>",
@@ -41789,7 +41917,7 @@ function useCoreTuiCommands({
41789
41917
  };
41790
41918
  return registerSlashCommandLifecycle(slashRegistry, cmd);
41791
41919
  }, [slashRegistry, director, runSteerSequence]);
41792
- useEffect34(() => {
41920
+ useEffect35(() => {
41793
41921
  const cmd = {
41794
41922
  name: "rewind",
41795
41923
  description: "Open checkpoint timeline to rewind session: /rewind [checkpoint-index]",
@@ -41823,7 +41951,7 @@ function useCoreTuiCommands({
41823
41951
  };
41824
41952
  return registerSlashCommandLifecycle(slashRegistry, cmd);
41825
41953
  }, [slashRegistry, handleRewindTo]);
41826
- useEffect34(() => {
41954
+ useEffect35(() => {
41827
41955
  const original = slashRegistry.get("agents");
41828
41956
  const cmd = {
41829
41957
  name: "agents",
@@ -41848,7 +41976,7 @@ function useCoreTuiCommands({
41848
41976
  }
41849
41977
 
41850
41978
  // src/hooks/use-director-fleet-bridge.ts
41851
- import { useEffect as useEffect35, useRef as useRef19 } from "react";
41979
+ import { useEffect as useEffect36, useRef as useRef19 } from "react";
41852
41980
  import { stripNextStepsBlock } from "@wrongstack/tools/next-steps";
41853
41981
 
41854
41982
  // src/hooks/fleet-chat-coalescer.ts
@@ -41933,10 +42061,10 @@ function useDirectorFleetBridge({
41933
42061
  const labelsRef = useRef19(/* @__PURE__ */ new Map());
41934
42062
  const chatModeRef = useRef19(chatMode);
41935
42063
  const gate = useFleetGenerationGate(sessionGenerationRef);
41936
- useEffect35(() => {
42064
+ useEffect36(() => {
41937
42065
  chatModeRef.current = chatMode;
41938
42066
  }, [chatMode]);
41939
- useEffect35(() => {
42067
+ useEffect36(() => {
41940
42068
  const d = director;
41941
42069
  if (!d) return;
41942
42070
  const batch = [];
@@ -42371,24 +42499,24 @@ function handleCollabDone(event, dispatch, stateRef) {
42371
42499
  }
42372
42500
 
42373
42501
  // src/hooks/use-enhance-runtime-state.ts
42374
- import { useEffect as useEffect36, useRef as useRef20, useState as useState25 } from "react";
42502
+ import { useEffect as useEffect37, useRef as useRef20, useState as useState26 } from "react";
42375
42503
  function useEnhanceRuntimeState({
42376
42504
  enhanceEnabled,
42377
42505
  midRunSendPicker
42378
42506
  }) {
42379
42507
  const enhanceEnabledRef = useRef20(enhanceEnabled);
42380
- useEffect36(() => {
42508
+ useEffect37(() => {
42381
42509
  enhanceEnabledRef.current = enhanceEnabled;
42382
42510
  }, [enhanceEnabled]);
42383
42511
  const midRunSendPickerRef = useRef20(midRunSendPicker);
42384
42512
  const enhanceAbortRef = useRef20(null);
42385
42513
  const enhanceCancelledRef = useRef20(false);
42386
42514
  const enhanceOriginalRef = useRef20("");
42387
- const [enhanceCountdown, setEnhanceCountdown] = useState25(null);
42388
- const [enhanceStartedAt, setEnhanceStartedAt] = useState25(null);
42389
- const [enhanceDurationMs, setEnhanceDurationMs] = useState25(null);
42390
- const [refineProviderId, setRefineProviderId] = useState25(null);
42391
- const [refineModel, setRefineModel] = useState25(null);
42515
+ const [enhanceCountdown, setEnhanceCountdown] = useState26(null);
42516
+ const [enhanceStartedAt, setEnhanceStartedAt] = useState26(null);
42517
+ const [enhanceDurationMs, setEnhanceDurationMs] = useState26(null);
42518
+ const [refineProviderId, setRefineProviderId] = useState26(null);
42519
+ const [refineModel, setRefineModel] = useState26(null);
42392
42520
  return {
42393
42521
  enhanceEnabledRef,
42394
42522
  midRunSendPickerRef,
@@ -42410,7 +42538,7 @@ function useEnhanceRuntimeState({
42410
42538
 
42411
42539
  // src/hooks/use-exit-command.ts
42412
42540
  import { getProcessRegistry as getProcessRegistry7 } from "@wrongstack/tools";
42413
- import { useCallback as useCallback14, useEffect as useEffect37, useRef as useRef21 } from "react";
42541
+ import { useCallback as useCallback14, useEffect as useEffect38, useRef as useRef21 } from "react";
42414
42542
 
42415
42543
  // src/exit-slash.ts
42416
42544
  var DESCRIPTION = "Exit the TUI. While a leader run or any subagent is still active, asks for an explicit Enter/Esc confirmation before terminating them.";
@@ -42516,7 +42644,7 @@ function useExitCommand({
42516
42644
  },
42517
42645
  [dispatch, terminateWork]
42518
42646
  );
42519
- useEffect37(() => {
42647
+ useEffect38(() => {
42520
42648
  const cmd = createExitSlashCommand({
42521
42649
  isLeaderActive: () => interruptController?.isRunning?.() ?? stateRef.current.status !== "idle",
42522
42650
  countRunningSubagents: () => Object.values(stateRef.current.fleet).filter((e) => e.status === "running").length,
@@ -42536,7 +42664,7 @@ function useExitCommand({
42536
42664
  import * as fs3 from "node:fs/promises";
42537
42665
  import * as path4 from "node:path";
42538
42666
  import { toErrorMessage as toErrorMessage8 } from "@wrongstack/core/utils";
42539
- import { useEffect as useEffect38 } from "react";
42667
+ import { useEffect as useEffect39 } from "react";
42540
42668
 
42541
42669
  // src/file-search.ts
42542
42670
  import * as fs2 from "node:fs/promises";
@@ -42639,7 +42767,7 @@ function detectAtToken(buffer, cursor) {
42639
42767
  }
42640
42768
  function useFileSearch(options) {
42641
42769
  const { state, dispatch, projectRoot, builderRef, draftRef, setDraft, tokenPreviewsRef } = options;
42642
- useEffect38(() => {
42770
+ useEffect39(() => {
42643
42771
  const detected = detectAtToken(state.buffer, state.cursor);
42644
42772
  if (!detected) {
42645
42773
  if (state.picker.open) dispatch({ type: "pickerClose" });
@@ -42729,7 +42857,7 @@ function fileReadContract(filePath, bytes) {
42729
42857
 
42730
42858
  // src/hooks/use-git-session-status.ts
42731
42859
  import { watchProjectTree } from "@wrongstack/core/utils";
42732
- import { useEffect as useEffect39, useRef as useRef22, useState as useState26 } from "react";
42860
+ import { useEffect as useEffect40, useRef as useRef22, useState as useState27 } from "react";
42733
42861
 
42734
42862
  // src/git-info.ts
42735
42863
  import { spawn } from "node:child_process";
@@ -42826,13 +42954,13 @@ function useGitSessionStatus({
42826
42954
  setSessionCount,
42827
42955
  hiddenItems = []
42828
42956
  }) {
42829
- const [gitInfo, setGitInfo] = useState26(null);
42957
+ const [gitInfo, setGitInfo] = useState27(null);
42830
42958
  const previousBranchRef = useRef22(null);
42831
42959
  const gitHidden = hiddenItems.includes("git");
42832
- useEffect39(() => {
42960
+ useEffect40(() => {
42833
42961
  if (gitHidden) previousBranchRef.current = null;
42834
42962
  }, [gitHidden]);
42835
- useEffect39(() => {
42963
+ useEffect40(() => {
42836
42964
  if (gitHidden) return;
42837
42965
  let cancelled = false;
42838
42966
  let dirty = true;
@@ -42881,7 +43009,7 @@ function useGitSessionStatus({
42881
43009
  watcher?.close();
42882
43010
  };
42883
43011
  }, [agent.ctx, gitHidden]);
42884
- useEffect39(() => {
43012
+ useEffect40(() => {
42885
43013
  if (!getLiveSessions) return;
42886
43014
  let cancelled = false;
42887
43015
  const poll = async () => {
@@ -42921,7 +43049,7 @@ function useHelpPanel(dispatch, slashRegistry) {
42921
43049
  // src/hooks/use-history-archive.ts
42922
43050
  import * as fsp2 from "node:fs/promises";
42923
43051
  import * as path6 from "node:path";
42924
- import { useCallback as useCallback16, useEffect as useEffect40, useRef as useRef23, useState as useState27 } from "react";
43052
+ import { useCallback as useCallback16, useEffect as useEffect41, useRef as useRef23, useState as useState28 } from "react";
42925
43053
 
42926
43054
  // src/history-archive.ts
42927
43055
  import * as fsp from "node:fs/promises";
@@ -43126,8 +43254,8 @@ function useHistoryArchive({
43126
43254
  const loadingRef = useRef23(false);
43127
43255
  const entriesRef = useRef23(entries);
43128
43256
  entriesRef.current = entries;
43129
- const [archiveGeneration, setArchiveGeneration] = useState27(0);
43130
- useEffect40(() => {
43257
+ const [archiveGeneration, setArchiveGeneration] = useState28(0);
43258
+ useEffect41(() => {
43131
43259
  if (!sessionsDir || !sessionId) return;
43132
43260
  let disposed = false;
43133
43261
  let created = null;
@@ -43152,7 +43280,7 @@ function useHistoryArchive({
43152
43280
  void created?.close();
43153
43281
  };
43154
43282
  }, [sessionsDir, sessionId]);
43155
- useEffect40(() => {
43283
+ useEffect41(() => {
43156
43284
  const archive = archiveRef.current;
43157
43285
  if (!archive) return;
43158
43286
  const since = lastArchivedIdRef.current;
@@ -43209,7 +43337,7 @@ function useHistoryArchive({
43209
43337
  }
43210
43338
 
43211
43339
  // src/hooks/use-history-auto-scroll.ts
43212
- import { useCallback as useCallback17, useEffect as useEffect41, useRef as useRef24 } from "react";
43340
+ import { useCallback as useCallback17, useEffect as useEffect42, useRef as useRef24 } from "react";
43213
43341
  var HISTORY_AUTO_SCROLL_DELAY_MS = 3e4;
43214
43342
  function useHistoryAutoScroll({
43215
43343
  historyScrolled,
@@ -43223,7 +43351,7 @@ function useHistoryAutoScroll({
43223
43351
  historyScrollRef.current?.scrollToBottom();
43224
43352
  }, HISTORY_AUTO_SCROLL_DELAY_MS);
43225
43353
  }, [historyScrollRef]);
43226
- useEffect41(() => {
43354
+ useEffect42(() => {
43227
43355
  if (!historyScrolled) {
43228
43356
  if (timerRef.current) clearTimeout(timerRef.current);
43229
43357
  timerRef.current = null;
@@ -43232,7 +43360,7 @@ function useHistoryAutoScroll({
43232
43360
  schedule();
43233
43361
  return void 0;
43234
43362
  }, [historyScrolled, schedule]);
43235
- useEffect41(
43363
+ useEffect42(
43236
43364
  () => () => {
43237
43365
  if (timerRef.current) clearTimeout(timerRef.current);
43238
43366
  },
@@ -43244,33 +43372,56 @@ function useHistoryAutoScroll({
43244
43372
  }
43245
43373
 
43246
43374
  // src/hooks/use-bug-hunt-loop.ts
43247
- import { useCallback as useCallback18, useEffect as useEffect42, useRef as useRef25 } from "react";
43375
+ import { useCallback as useCallback18, useEffect as useEffect43, useRef as useRef25 } from "react";
43376
+ function parseBugHuntScope(command) {
43377
+ const args = command.replace(/^\/bughunt(?:\s+|$)/, "").trim();
43378
+ const match = args.match(/^--rounds(?:\s+|=)\d+(?:\s+([\s\S]*))?$/);
43379
+ const scope = (match?.[1] ?? (match ? "" : args)).trim();
43380
+ return scope || void 0;
43381
+ }
43382
+ function buildContinuationMessage(active) {
43383
+ const round = active.completedRounds + 1;
43384
+ const roundLabel = active.totalRounds ? `round ${round}/${active.totalRounds}` : `round ${round}`;
43385
+ const scope = active.scope ? ` Stay within the original scope: ${active.scope}.` : "";
43386
+ return `This is ${roundLabel}; we're continuing the bug hunt.${scope}`;
43387
+ }
43388
+ function submitAfterCurrentRun(submit, command) {
43389
+ setTimeout(() => submit(command), 0);
43390
+ }
43248
43391
  function useBugHuntLoop(dispatch, submit, historyGen) {
43249
43392
  const activeRef = useRef25(null);
43250
43393
  const replayCommandRef = useRef25(null);
43251
43394
  const lastHistoryGenRef = useRef25(historyGen);
43252
- useEffect42(() => {
43395
+ useEffect43(() => {
43253
43396
  if (historyGen === void 0) return;
43254
43397
  if (historyGen === lastHistoryGenRef.current) return;
43255
43398
  lastHistoryGenRef.current = historyGen;
43256
43399
  activeRef.current = null;
43257
43400
  replayCommandRef.current = null;
43258
43401
  }, [historyGen]);
43259
- const onBugHuntStarted = useCallback18((command, totalRounds) => {
43260
- const active = activeRef.current;
43261
- if (active?.command === command) {
43262
- dispatch({
43263
- type: "bugHuntRunningOpen",
43264
- info: {
43265
- currentRound: active.completedRounds + 1,
43266
- totalRounds: active.totalRounds
43267
- }
43268
- });
43269
- return;
43270
- }
43271
- activeRef.current = { command, totalRounds, completedRounds: 0 };
43272
- dispatch({ type: "bugHuntRunningOpen", info: { currentRound: 1, totalRounds } });
43273
- }, [dispatch]);
43402
+ const onBugHuntStarted = useCallback18(
43403
+ (command, totalRounds) => {
43404
+ const active = activeRef.current;
43405
+ if (active?.command === command) {
43406
+ dispatch({
43407
+ type: "bugHuntRunningOpen",
43408
+ info: {
43409
+ currentRound: active.completedRounds + 1,
43410
+ totalRounds: active.totalRounds
43411
+ }
43412
+ });
43413
+ return;
43414
+ }
43415
+ activeRef.current = {
43416
+ command,
43417
+ scope: parseBugHuntScope(command),
43418
+ totalRounds,
43419
+ completedRounds: 0
43420
+ };
43421
+ dispatch({ type: "bugHuntRunningOpen", info: { currentRound: 1, totalRounds } });
43422
+ },
43423
+ [dispatch]
43424
+ );
43274
43425
  const onRunFinished = useCallback18(
43275
43426
  (status) => {
43276
43427
  const active = activeRef.current;
@@ -43288,38 +43439,32 @@ function useBugHuntLoop(dispatch, submit, historyGen) {
43288
43439
  return;
43289
43440
  }
43290
43441
  active.completedRounds++;
43291
- if (active.totalRounds !== void 0 && active.completedRounds >= active.totalRounds) {
43442
+ const requestedRounds = active.totalRounds ?? 1;
43443
+ if (active.completedRounds >= requestedRounds) {
43292
43444
  activeRef.current = null;
43293
43445
  dispatch({
43294
43446
  type: "addEntry",
43295
43447
  entry: {
43296
43448
  kind: "info",
43297
- text: `Proof-Driven Bug Hunter completed ${active.completedRounds}/${active.totalRounds} requested rounds.`
43449
+ text: active.totalRounds === void 0 ? "Proof-Driven Bug Hunter completed its single round." : `Proof-Driven Bug Hunter completed ${active.completedRounds}/${active.totalRounds} requested rounds.`
43298
43450
  }
43299
43451
  });
43300
43452
  return;
43301
43453
  }
43302
43454
  const snapshot = { ...active };
43303
- dispatch({
43304
- type: "bugHuntContinueOpen",
43305
- info: {
43306
- completedRounds: snapshot.completedRounds,
43307
- totalRounds: snapshot.totalRounds,
43308
- resolve: (decision) => {
43309
- dispatch({ type: "bugHuntContinueClose" });
43310
- if (decision === "stop") {
43311
- activeRef.current = null;
43312
- dispatch({
43313
- type: "addEntry",
43314
- entry: { kind: "info", text: "Proof-Driven Bug Hunter loop stopped." }
43315
- });
43316
- return;
43317
- }
43318
- replayCommandRef.current = snapshot.command;
43319
- submit(snapshot.command);
43455
+ const continueWithNextRound = () => {
43456
+ const continuation = buildContinuationMessage(snapshot);
43457
+ replayCommandRef.current = continuation;
43458
+ dispatch({
43459
+ type: "bugHuntRunningOpen",
43460
+ info: {
43461
+ currentRound: snapshot.completedRounds + 1,
43462
+ totalRounds: snapshot.totalRounds
43320
43463
  }
43321
- }
43322
- });
43464
+ });
43465
+ submitAfterCurrentRun(submit, continuation);
43466
+ };
43467
+ continueWithNextRound();
43323
43468
  },
43324
43469
  [dispatch, submit]
43325
43470
  );
@@ -43333,7 +43478,7 @@ function useBugHuntLoop(dispatch, submit, historyGen) {
43333
43478
  }
43334
43479
 
43335
43480
  // src/hooks/use-history-copy-notice.ts
43336
- import { useCallback as useCallback19, useEffect as useEffect43, useRef as useRef26 } from "react";
43481
+ import { useCallback as useCallback19, useEffect as useEffect44, useRef as useRef26 } from "react";
43337
43482
  function useHistoryCopyNotice(dispatch) {
43338
43483
  const copiedHintTimerRef = useRef26(null);
43339
43484
  const onHistoryCopy = useCallback19(
@@ -43347,7 +43492,7 @@ function useHistoryCopyNotice(dispatch) {
43347
43492
  },
43348
43493
  [dispatch]
43349
43494
  );
43350
- useEffect43(
43495
+ useEffect44(
43351
43496
  () => () => {
43352
43497
  if (copiedHintTimerRef.current) clearTimeout(copiedHintTimerRef.current);
43353
43498
  },
@@ -43357,15 +43502,15 @@ function useHistoryCopyNotice(dispatch) {
43357
43502
  }
43358
43503
 
43359
43504
  // src/hooks/use-history-viewport-sync.ts
43360
- import { useEffect as useEffect44, useLayoutEffect as useLayoutEffect2, useRef as useRef27, useState as useState28 } from "react";
43505
+ import { useEffect as useEffect45, useLayoutEffect as useLayoutEffect2, useRef as useRef27, useState as useState29 } from "react";
43361
43506
  function useHistoryViewportSync(input) {
43362
43507
  const { stdoutRows, viewportRows, setViewportRows } = input;
43363
43508
  const bottomRegionRef = useRef27(null);
43364
43509
  const statusBarWrapRef = useRef27(null);
43365
43510
  const belowStatusBarRef = useRef27(null);
43366
- const [termRows, setTermRows] = useState28(stdoutRows ?? 24);
43367
- const [statusBarRows, setStatusBarRows] = useState28(2);
43368
- useEffect44(() => {
43511
+ const [termRows, setTermRows] = useState29(stdoutRows ?? 24);
43512
+ const [statusBarRows, setStatusBarRows] = useState29(2);
43513
+ useEffect45(() => {
43369
43514
  const handleResize = () => setTermRows(process.stdout.rows ?? 24);
43370
43515
  process.stdout.prependListener("resize", handleResize);
43371
43516
  return () => {
@@ -43393,7 +43538,7 @@ function useHistoryViewportSync(input) {
43393
43538
 
43394
43539
  // src/hooks/use-initial-prompt.ts
43395
43540
  import { buildGoalPreamble } from "@wrongstack/core/execution";
43396
- import { useEffect as useEffect45, useRef as useRef28 } from "react";
43541
+ import { useEffect as useEffect46, useRef as useRef28 } from "react";
43397
43542
  function useInitialPrompt({
43398
43543
  initialGoal,
43399
43544
  initialAsk,
@@ -43402,7 +43547,7 @@ function useInitialPrompt({
43402
43547
  dispatch
43403
43548
  }) {
43404
43549
  const bootInjectedRef = useRef28(false);
43405
- useEffect45(() => {
43550
+ useEffect46(() => {
43406
43551
  if (bootInjectedRef.current) return;
43407
43552
  const goal = initialGoal?.trim();
43408
43553
  const ask = initialAsk?.trim();
@@ -43449,7 +43594,7 @@ function useInitialPrompt({
43449
43594
  import { DefaultSecretScrubber } from "@wrongstack/core/security";
43450
43595
  import { INPUT_HISTORY_DEFAULT_MAX, InputHistoryStore } from "@wrongstack/core/storage";
43451
43596
  import { resolveWstackPaths as resolveWstackPaths3 } from "@wrongstack/core/utils";
43452
- import { useEffect as useEffect46, useMemo as useMemo14, useRef as useRef29 } from "react";
43597
+ import { useEffect as useEffect47, useMemo as useMemo14, useRef as useRef29 } from "react";
43453
43598
  function useInputHistoryPersistence({
43454
43599
  projectRoot,
43455
43600
  inputHistory,
@@ -43463,7 +43608,7 @@ function useInputHistoryPersistence({
43463
43608
  const inputHistoryLoadedRef = useRef29(false);
43464
43609
  const inputHistorySaveTimerRef = useRef29(void 0);
43465
43610
  const inputHistoryLastSavedRef = useRef29("");
43466
- useEffect46(() => {
43611
+ useEffect47(() => {
43467
43612
  if (!inputHistoryStore) return;
43468
43613
  let cancelled = false;
43469
43614
  inputHistoryStore.load().then((entries) => {
@@ -43479,7 +43624,7 @@ function useInputHistoryPersistence({
43479
43624
  cancelled = true;
43480
43625
  };
43481
43626
  }, [inputHistoryStore, dispatch]);
43482
- useEffect46(() => {
43627
+ useEffect47(() => {
43483
43628
  if (!inputHistoryStore || !inputHistoryLoadedRef.current) return;
43484
43629
  const snapshot = JSON.stringify(inputHistory);
43485
43630
  if (snapshot === inputHistoryLastSavedRef.current) return;
@@ -43497,7 +43642,7 @@ function useInputHistoryPersistence({
43497
43642
 
43498
43643
  // src/hooks/use-interrupt-ladder.ts
43499
43644
  import { getProcessRegistry as getProcessRegistry8 } from "@wrongstack/tools";
43500
- import { useCallback as useCallback20, useEffect as useEffect47, useRef as useRef30 } from "react";
43645
+ import { useCallback as useCallback20, useEffect as useEffect48, useRef as useRef30 } from "react";
43501
43646
  var INTERRUPT_PRESS_WINDOW_MS = 2e3;
43502
43647
  function useInterruptLadder({
43503
43648
  stateRef,
@@ -43694,7 +43839,7 @@ function useInterruptLadder({
43694
43839
  onExit,
43695
43840
  exit
43696
43841
  ]);
43697
- useEffect47(() => {
43842
+ useEffect48(() => {
43698
43843
  process.on("SIGINT", runInterruptLadder);
43699
43844
  return () => {
43700
43845
  process.off("SIGINT", runInterruptLadder);
@@ -43704,9 +43849,9 @@ function useInterruptLadder({
43704
43849
  }
43705
43850
 
43706
43851
  // src/hooks/use-kanban-board-focus.ts
43707
- import { useRef as useRef31, useState as useState29 } from "react";
43852
+ import { useRef as useRef31, useState as useState30 } from "react";
43708
43853
  function useKanbanBoardFocus() {
43709
- const [focusedBoardId, setFocusedBoardId] = useState29(null);
43854
+ const [focusedBoardId, setFocusedBoardId] = useState30(null);
43710
43855
  const boardFocusRef = useRef31(null);
43711
43856
  if (!boardFocusRef.current) {
43712
43857
  boardFocusRef.current = {
@@ -43720,7 +43865,7 @@ function useKanbanBoardFocus() {
43720
43865
  }
43721
43866
 
43722
43867
  // src/hooks/use-live-settings-state.ts
43723
- import { useEffect as useEffect48, useRef as useRef32 } from "react";
43868
+ import { useEffect as useEffect49, useRef as useRef32 } from "react";
43724
43869
  function useLiveSettingsState({
43725
43870
  getSettings,
43726
43871
  titleController,
@@ -43736,7 +43881,7 @@ function useLiveSettingsState({
43736
43881
  const confirmExitRef = useRef32(confirmExit);
43737
43882
  confirmExitRef.current = liveSettings?.confirmExit ?? confirmExit;
43738
43883
  const liveTitleAnimation = liveSettings?.titleAnimation;
43739
- useEffect48(() => {
43884
+ useEffect49(() => {
43740
43885
  if (!titleController) return;
43741
43886
  titleController.setEnabled(liveTitleAnimation !== false);
43742
43887
  }, [titleController, liveTitleAnimation]);
@@ -43751,10 +43896,10 @@ function useLiveSettingsState({
43751
43896
  }
43752
43897
 
43753
43898
  // src/hooks/use-live-todos.ts
43754
- import { useEffect as useEffect49, useState as useState30 } from "react";
43899
+ import { useEffect as useEffect50, useState as useState31 } from "react";
43755
43900
  function useLiveTodos(context) {
43756
- const [todos, setTodos] = useState30(() => [...context.todos]);
43757
- useEffect49(() => {
43901
+ const [todos, setTodos] = useState31(() => [...context.todos]);
43902
+ useEffect50(() => {
43758
43903
  setTodos([...context.todos]);
43759
43904
  return context.state.onChange((change) => {
43760
43905
  if (change.kind === "todos_replaced") setTodos([...change.todos]);
@@ -43764,17 +43909,17 @@ function useLiveTodos(context) {
43764
43909
  }
43765
43910
 
43766
43911
  // src/hooks/use-mailbox-view-model.ts
43767
- import { useEffect as useEffect50, useState as useState31 } from "react";
43912
+ import { useEffect as useEffect51, useState as useState32 } from "react";
43768
43913
  function useMailboxViewModel(events) {
43769
- const [mailboxStatus, setMailboxStatus] = useState31({
43914
+ const [mailboxStatus, setMailboxStatus] = useState32({
43770
43915
  unread: 0,
43771
43916
  onlineAgents: 0,
43772
43917
  onlineClients: { tui: 0, webui: 0, repl: 0 }
43773
43918
  });
43774
- const [mailboxPanelOpen, setMailboxPanelOpen] = useState31(false);
43775
- const [mailboxMessages, setMailboxMessages] = useState31([]);
43776
- const [mailboxAgents, setMailboxAgents] = useState31([]);
43777
- useEffect50(() => {
43919
+ const [mailboxPanelOpen, setMailboxPanelOpen] = useState32(false);
43920
+ const [mailboxMessages, setMailboxMessages] = useState32([]);
43921
+ const [mailboxAgents, setMailboxAgents] = useState32([]);
43922
+ useEffect51(() => {
43778
43923
  const AGENT_ONLINE_TTL_MS = 12e4;
43779
43924
  const lastSeen = /* @__PURE__ */ new Map();
43780
43925
  const unsubUnread = events.onPattern("mailbox.unread_count", (_event, payload) => {
@@ -43836,7 +43981,7 @@ function useMailboxViewModel(events) {
43836
43981
  unsubSnapshot();
43837
43982
  };
43838
43983
  }, [events]);
43839
- useEffect50(() => {
43984
+ useEffect51(() => {
43840
43985
  const unsubMessage = events.onPattern("mailbox.received", (_event, payload) => {
43841
43986
  const data = payload;
43842
43987
  if (!data?.messageId) return;
@@ -43984,11 +44129,11 @@ function useModelPickRequest(opts) {
43984
44129
  }
43985
44130
 
43986
44131
  // src/hooks/use-mouse-tracking.ts
43987
- import { useEffect as useEffect51, useRef as useRef33, useState as useState32 } from "react";
44132
+ import { useEffect as useEffect52, useRef as useRef33, useState as useState33 } from "react";
43988
44133
  function useMouseTracking(input) {
43989
44134
  const { initialMouseMode, initialNativeMouse, overlayOpen, protocol, stdout } = input;
43990
- const [mouseMode, setMouseMode] = useState32(initialMouseMode);
43991
- const [nativeMouse, setNativeMouse] = useState32(initialNativeMouse ?? false);
44135
+ const [mouseMode, setMouseMode] = useState33(initialMouseMode);
44136
+ const [nativeMouse, setNativeMouse] = useState33(initialNativeMouse ?? false);
43992
44137
  const mouseTrackingOn = shouldEnableMouseTracking({
43993
44138
  fullMode: mouseMode,
43994
44139
  overlayOpen,
@@ -43998,7 +44143,7 @@ function useMouseTracking(input) {
43998
44143
  });
43999
44144
  const mouseTrackingSequence = mouseTrackingOn ? MOUSE_DRAG_ON : MOUSE_OFF;
44000
44145
  const mouseWrittenRef = useRef33(null);
44001
- useEffect51(() => {
44146
+ useEffect52(() => {
44002
44147
  if (mouseWrittenRef.current === mouseTrackingSequence) return;
44003
44148
  mouseWrittenRef.current = mouseTrackingSequence;
44004
44149
  try {
@@ -44006,7 +44151,7 @@ function useMouseTracking(input) {
44006
44151
  } catch {
44007
44152
  }
44008
44153
  }, [mouseTrackingSequence, stdout]);
44009
- useEffect51(
44154
+ useEffect52(
44010
44155
  () => () => {
44011
44156
  const wasTracking = mouseWrittenRef.current !== null && mouseWrittenRef.current !== MOUSE_OFF;
44012
44157
  mouseWrittenRef.current = null;
@@ -44034,9 +44179,9 @@ import {
44034
44179
  import { todoTool as todoTool2 } from "@wrongstack/tools/todo";
44035
44180
  import {
44036
44181
  useCallback as useCallback22,
44037
- useEffect as useEffect52,
44182
+ useEffect as useEffect53,
44038
44183
  useRef as useRef34,
44039
- useState as useState33
44184
+ useState as useState34
44040
44185
  } from "react";
44041
44186
  async function commitTodoTransition(agent, todos) {
44042
44187
  if (!agent?.ctx?.state) return null;
@@ -44081,10 +44226,10 @@ function useNextStepsAutoSubmit({
44081
44226
  clearDraft,
44082
44227
  runBlocksRef
44083
44228
  }) {
44084
- const [nextStepsAutoSubmitCountdown, setNextStepsAutoSubmitCountdown] = useState33(
44229
+ const [nextStepsAutoSubmitCountdown, setNextStepsAutoSubmitCountdown] = useState34(
44085
44230
  null
44086
44231
  );
44087
- const [nextStepsAutoSubmitLabel, setNextStepsAutoSubmitLabel] = useState33(null);
44232
+ const [nextStepsAutoSubmitLabel, setNextStepsAutoSubmitLabel] = useState34(null);
44088
44233
  const nextStepsAutoSubmitSuggestionRef = useRef34(null);
44089
44234
  const nextStepsAutoSubmitSourceRef = useRef34(null);
44090
44235
  const nextStepsAutoSubmitTodoIdRef = useRef34(null);
@@ -44094,14 +44239,14 @@ function useNextStepsAutoSubmit({
44094
44239
  const autoSubmitCapWarnedRef = useRef34(false);
44095
44240
  const autoSubmitLoopGuardRef = useRef34(createAutoProceedLoopGuard());
44096
44241
  const continuationAttemptTrackerRef = useRef34(createContinuationAttemptTracker());
44097
- const [nextStepsRecheck, setNextStepsRecheck] = useState33(0);
44098
- useEffect52(() => {
44242
+ const [nextStepsRecheck, setNextStepsRecheck] = useState34(0);
44243
+ useEffect53(() => {
44099
44244
  autoSubmitStreakRef.current = 0;
44100
44245
  autoSubmitCapWarnedRef.current = false;
44101
44246
  autoSubmitLoopGuardRef.current.reset();
44102
44247
  continuationAttemptTrackerRef.current.reset();
44103
44248
  }, [autonomyLive]);
44104
- useEffect52(() => {
44249
+ useEffect53(() => {
44105
44250
  const liveAutonomy = getAutonomy?.() ?? autonomyLive;
44106
44251
  if (state.status !== "idle" || liveAutonomy !== "auto" || state.bugHuntRunning != null) {
44107
44252
  clearInterval(nextStepsAutoSubmitTimerRef.current);
@@ -44374,7 +44519,7 @@ ${GROUNDED_NO_PROGRESS_STEER}` : suggestion;
44374
44519
 
44375
44520
  // src/hooks/use-panel-controllers.ts
44376
44521
  import { toErrorMessage as toErrorMessage9 } from "@wrongstack/core/utils";
44377
- import React11, { useEffect as useEffect53 } from "react";
44522
+ import React11, { useEffect as useEffect54 } from "react";
44378
44523
 
44379
44524
  // src/on-panel-open.ts
44380
44525
  function createPanelOpenDispatcher(deps) {
@@ -44509,7 +44654,7 @@ function usePanelControllers({
44509
44654
  dispatch({ type: "sessionsPanelBusy", on: false });
44510
44655
  }
44511
44656
  }, [getLiveSessions]);
44512
- useEffect53(() => {
44657
+ useEffect54(() => {
44513
44658
  if (!onPanelOpen) return;
44514
44659
  const dispatcher = createPanelOpenDispatcher({
44515
44660
  dispatch,
@@ -44536,7 +44681,7 @@ function usePanelControllers({
44536
44681
  openShadowPanel,
44537
44682
  openHelpPanel
44538
44683
  ]);
44539
- useEffect53(() => {
44684
+ useEffect54(() => {
44540
44685
  if (!state.sessionsPanelOpen || !getLiveSessions) return void 0;
44541
44686
  const t = setInterval(() => {
44542
44687
  void loadLiveSessions();
@@ -44622,7 +44767,7 @@ function usePanelControllers({
44622
44767
  if (!getPluginItems) return;
44623
44768
  dispatch({ type: "pluginPickerSetItems", items: getPluginItems() });
44624
44769
  }, [getPluginItems]);
44625
- useEffect53(() => {
44770
+ useEffect54(() => {
44626
44771
  if (!state.pluginPicker.open) return;
44627
44772
  refreshPluginPicker();
44628
44773
  }, [state.pluginPicker.open, refreshPluginPicker]);
@@ -44654,7 +44799,7 @@ function usePanelControllers({
44654
44799
  if (!getMcpServers) return;
44655
44800
  dispatch({ type: "mcpPickerSetItems", items: getMcpServers() });
44656
44801
  }, [getMcpServers]);
44657
- useEffect53(() => {
44802
+ useEffect54(() => {
44658
44803
  if (!state.mcpPicker.open) return;
44659
44804
  refreshMcpPicker();
44660
44805
  }, [state.mcpPicker.open, refreshMcpPicker]);
@@ -44698,7 +44843,7 @@ function usePanelControllers({
44698
44843
  dispatch({ type: "toolsPickerSetItems", items });
44699
44844
  setLiveToolCount(items.filter((item) => item.enabled).length);
44700
44845
  }, [getToolsItems]);
44701
- useEffect53(() => {
44846
+ useEffect54(() => {
44702
44847
  if (!state.toolsPicker.open) return;
44703
44848
  refreshToolsPicker();
44704
44849
  }, [state.toolsPicker.open, refreshToolsPicker]);
@@ -44906,7 +45051,7 @@ function usePromptPicker({ projectRoot, dispatch }) {
44906
45051
  import { tuiStreamFlushMs } from "@wrongstack/core/utils";
44907
45052
  import { DEFAULT_MIN_IMPORTANCE as DEFAULT_MIN_IMPORTANCE2, DEFAULT_MIN_SCORE as DEFAULT_MIN_SCORE2, MIN_RELATION_STRENGTH as MIN_RELATION_STRENGTH2 } from "@wrongstack/sage";
44908
45053
  import { isFinalTurnStopReason as isFinalTurnStopReason2 } from "@wrongstack/tools/next-steps";
44909
- import { useEffect as useEffect54 } from "react";
45054
+ import { useEffect as useEffect55 } from "react";
44910
45055
 
44911
45056
  // src/memory-lifecycle-entry.ts
44912
45057
  function memoryLifecycleEntry(event, payload) {
@@ -45093,6 +45238,22 @@ function formatSageInjectionStats(run) {
45093
45238
  }
45094
45239
  return parts.join(" \xB7 ");
45095
45240
  }
45241
+ function fullToolResultFromState(agent, toolUseId) {
45242
+ if (!toolUseId) return void 0;
45243
+ const messages = agent.ctx.state?.messages;
45244
+ if (!Array.isArray(messages)) return void 0;
45245
+ for (let i = messages.length - 1; i >= 0; i--) {
45246
+ const content = messages[i]?.content;
45247
+ if (!Array.isArray(content)) continue;
45248
+ for (let j = content.length - 1; j >= 0; j--) {
45249
+ const block = content[j];
45250
+ if (block?.type === "tool_result" && block.tool_use_id === toolUseId) {
45251
+ return block.content;
45252
+ }
45253
+ }
45254
+ }
45255
+ return void 0;
45256
+ }
45096
45257
  function useProviderEventBridge({
45097
45258
  events,
45098
45259
  agent,
@@ -45106,10 +45267,25 @@ function useProviderEventBridge({
45106
45267
  assistantCommittedThisRunRef,
45107
45268
  setMemoryContextMonitor
45108
45269
  }) {
45109
- useEffect54(() => {
45270
+ useEffect55(() => {
45110
45271
  const FLUSH_MS2 = tuiStreamFlushMs();
45111
45272
  let pendingToolStream = null;
45112
45273
  const pendingSageStats = /* @__PURE__ */ new Map();
45274
+ const pendingToolEntries = /* @__PURE__ */ new Map();
45275
+ const flushCanonicalToolResults = () => {
45276
+ for (const [toolUseId, pending] of pendingToolEntries) {
45277
+ const output = fullToolResultFromState(agent, toolUseId);
45278
+ if (output === void 0) continue;
45279
+ pending.add(output);
45280
+ pendingToolEntries.delete(toolUseId);
45281
+ }
45282
+ };
45283
+ const state = agent.ctx.state;
45284
+ const offStateChange = typeof state?.onChange === "function" ? state.onChange((change) => {
45285
+ if (change.kind === "message_appended" || change.kind === "message_updated" || change.kind === "messages_replaced") {
45286
+ flushCanonicalToolResults();
45287
+ }
45288
+ }) : void 0;
45113
45289
  const appendStreamSegment = (kind, text) => {
45114
45290
  const last = streamSegmentsRef.current.at(-1);
45115
45291
  if (last?.kind === kind) {
@@ -45204,27 +45380,38 @@ function useProviderEventBridge({
45204
45380
  pendingToolStream = null;
45205
45381
  }
45206
45382
  if (e.name !== "delegate") {
45207
- dispatch({
45208
- type: "addEntry",
45209
- entry: {
45210
- kind: "tool",
45211
- name: e.name,
45212
- durationMs: e.durationMs,
45213
- ok: e.ok,
45214
- input: e.input,
45215
- output: e.output,
45216
- // SAGE-injected memory travels beside the output preview so it
45217
- // always renders as a memory block, never as tool text.
45218
- sageLines: e.sage,
45219
- ...pendingSageStats.has(e.name) ? { sageStats: pendingSageStats.get(e.name) } : {},
45220
- // Real model-visible sizes — forwarded so the size chip beside
45221
- // the tool header can show what the model paid for instead of
45222
- // the misleading preview-byte count we used to surface.
45223
- outputBytes: e.outputBytes,
45224
- outputTokens: e.outputTokens,
45225
- outputLines: e.outputLines
45226
- }
45227
- });
45383
+ const sageStats = pendingSageStats.get(e.name);
45384
+ const addToolEntry = (output) => {
45385
+ dispatch({
45386
+ type: "addEntry",
45387
+ entry: {
45388
+ kind: "tool",
45389
+ name: e.name,
45390
+ durationMs: e.durationMs,
45391
+ ok: e.ok,
45392
+ input: e.input,
45393
+ output,
45394
+ // SAGE-injected memory travels beside the output preview so it
45395
+ // always renders as a memory block, never as tool text.
45396
+ ...e.sage !== void 0 ? { sageLines: e.sage } : {},
45397
+ ...sageStats !== void 0 ? { sageStats } : {},
45398
+ // Real model-visible sizes — forwarded so the size chip beside
45399
+ // the tool header can show what the model paid for instead of
45400
+ // the misleading preview-byte count we used to surface.
45401
+ outputBytes: e.outputBytes,
45402
+ outputTokens: e.outputTokens,
45403
+ outputLines: e.outputLines
45404
+ }
45405
+ });
45406
+ };
45407
+ const canonicalOutput = fullToolResultFromState(agent, e.id);
45408
+ if (canonicalOutput !== void 0) {
45409
+ addToolEntry(canonicalOutput);
45410
+ } else if (e.id !== void 0 && typeof state?.onChange === "function") {
45411
+ pendingToolEntries.set(e.id, { add: addToolEntry });
45412
+ } else {
45413
+ addToolEntry(e.output);
45414
+ }
45228
45415
  }
45229
45416
  pendingSageStats.delete(e.name);
45230
45417
  dispatch({ type: "toolEnded", ...e.id !== void 0 ? { id: e.id } : {}, name: e.name });
@@ -45501,13 +45688,15 @@ function useProviderEventBridge({
45501
45688
  offMemoryContextSnapshot();
45502
45689
  offMemoryContextSession();
45503
45690
  offMemoryLifecycle();
45691
+ offStateChange?.();
45692
+ pendingToolEntries.clear();
45504
45693
  if (flushTimerRef.current) clearTimeout(flushTimerRef.current);
45505
45694
  };
45506
45695
  }, [events, agent.ctx.session.id]);
45507
45696
  }
45508
45697
 
45509
45698
  // src/hooks/use-queue-manager.ts
45510
- import { useEffect as useEffect55, useRef as useRef37 } from "react";
45699
+ import { useEffect as useEffect56, useRef as useRef37 } from "react";
45511
45700
 
45512
45701
  // src/queue-slash.ts
45513
45702
  var USAGE5 = "Usage:\n /queue \u2014 list pending messages\n /queue list \u2014 same as /queue\n /queue clear \u2014 drop all pending messages\n /queue delete N M\u2026 \u2014 drop messages at 1-based positions\n /queue picker on|off \u2014 toggle the mid-run send-mode picker (queue/btw/steer)\n /queue picker \u2014 show whether the picker is on";
@@ -45647,7 +45836,7 @@ function useQueueManager({
45647
45836
  }
45648
45837
  })();
45649
45838
  };
45650
- useEffect55(() => {
45839
+ useEffect56(() => {
45651
45840
  if (!queueStore) return;
45652
45841
  let cancelled = false;
45653
45842
  queueStore.read().then((items) => {
@@ -45682,7 +45871,7 @@ function useQueueManager({
45682
45871
  cancelled = true;
45683
45872
  };
45684
45873
  }, [queueStore]);
45685
- useEffect55(() => {
45874
+ useEffect56(() => {
45686
45875
  if (!queueStore) return;
45687
45876
  if (!hydrated.current) {
45688
45877
  pendingBeforeHydration.current = true;
@@ -45690,10 +45879,10 @@ function useQueueManager({
45690
45879
  }
45691
45880
  writeQueue(queueStore);
45692
45881
  }, [stateRef.current.queue, queueStore, stateRef]);
45693
- useEffect55(() => {
45882
+ useEffect56(() => {
45694
45883
  onQueueChange?.(stateRef.current.queue.map((q) => q.displayText));
45695
45884
  }, [stateRef.current.queue, onQueueChange, stateRef]);
45696
- useEffect55(() => {
45885
+ useEffect56(() => {
45697
45886
  const cmd = createQueueSlashCommand({
45698
45887
  getQueue: () => stateRef.current.queue,
45699
45888
  clear: () => dispatch({ type: "queueClear" }),
@@ -45716,7 +45905,7 @@ function useQueueManager({
45716
45905
  }
45717
45906
 
45718
45907
  // src/hooks/use-session-interrupt-controller.ts
45719
- import { useEffect as useEffect56 } from "react";
45908
+ import { useEffect as useEffect57 } from "react";
45720
45909
  function useSessionInterruptController({
45721
45910
  interruptController,
45722
45911
  dispatch,
@@ -45738,7 +45927,7 @@ function useSessionInterruptController({
45738
45927
  getSddRun,
45739
45928
  switchAutonomy
45740
45929
  }) {
45741
- useEffect56(() => {
45930
+ useEffect57(() => {
45742
45931
  if (!interruptController) return;
45743
45932
  let pendingClearResolve = null;
45744
45933
  let pendingSlashResolve = null;
@@ -45926,15 +46115,15 @@ function useSessionRewind({
45926
46115
  }
45927
46116
 
45928
46117
  // src/hooks/use-settings-auto-save.ts
45929
- import { useEffect as useEffect57, useRef as useRef38 } from "react";
46118
+ import { useEffect as useEffect58, useRef as useRef38 } from "react";
45930
46119
  function useSettingsAutoSave(state, saveSettings, dispatch) {
45931
46120
  const settingsAutoSaveGateRef = useRef38(true);
45932
- useEffect57(() => {
46121
+ useEffect58(() => {
45933
46122
  if (state.settingsPicker.open) {
45934
46123
  settingsAutoSaveGateRef.current = true;
45935
46124
  }
45936
46125
  }, [state.settingsPicker.open]);
45937
- useEffect57(() => {
46126
+ useEffect58(() => {
45938
46127
  const sp = state.settingsPicker;
45939
46128
  const save = saveSettings;
45940
46129
  if (!sp.open || !save) return;
@@ -46100,14 +46289,18 @@ function useShadowPanel(dispatch, host) {
46100
46289
  }
46101
46290
 
46102
46291
  // src/hooks/use-slash-picker.ts
46103
- import { useCallback as useCallback26, useEffect as useEffect58 } from "react";
46292
+ import { useCallback as useCallback26, useEffect as useEffect59 } from "react";
46104
46293
  function useSlashPicker({
46105
46294
  state,
46106
46295
  slashRegistry,
46107
46296
  dispatch,
46108
46297
  setDraft
46109
46298
  }) {
46110
- useEffect58(() => {
46299
+ useEffect59(() => {
46300
+ if (state.bashMode) {
46301
+ if (state.slashPicker.open) dispatch({ type: "slashPickerClose" });
46302
+ return;
46303
+ }
46111
46304
  const trimmed = state.buffer.trimStart();
46112
46305
  if (!trimmed.startsWith("/") || /\s/.test(trimmed)) {
46113
46306
  if (state.slashPicker.open) dispatch({ type: "slashPickerClose" });
@@ -46118,7 +46311,7 @@ function useSlashPicker({
46118
46311
  if (!state.slashPicker.open || state.slashPicker.query !== query) {
46119
46312
  dispatch({ type: "slashPickerOpen", query, matches });
46120
46313
  }
46121
- }, [state.buffer, state.slashPicker.open, state.slashPicker.query, slashRegistry, dispatch]);
46314
+ }, [state.buffer, state.bashMode, state.slashPicker.open, state.slashPicker.query, slashRegistry, dispatch]);
46122
46315
  return useCallback26(() => {
46123
46316
  const { open: open2, matches, selected } = state.slashPicker;
46124
46317
  if (!open2 || matches.length === 0) return;
@@ -46131,7 +46324,7 @@ function useSlashPicker({
46131
46324
  }
46132
46325
 
46133
46326
  // src/hooks/use-status-sync-interval.ts
46134
- import { useEffect as useEffect59, useRef as useRef39 } from "react";
46327
+ import { useEffect as useEffect60, useRef as useRef39 } from "react";
46135
46328
  function useStatusSyncInterval({
46136
46329
  getAutonomy,
46137
46330
  getYolo,
@@ -46153,7 +46346,7 @@ function useStatusSyncInterval({
46153
46346
  runParallelLoopRef
46154
46347
  }) {
46155
46348
  const staleGuardRef = useRef39(JSON.stringify({ a: "", y: false, m: "", model: "", provider: "" }));
46156
- useEffect59(() => {
46349
+ useEffect60(() => {
46157
46350
  const poll = () => {
46158
46351
  const a = getAutonomy?.() ?? "off";
46159
46352
  const y = getYolo?.() ?? false;
@@ -46200,7 +46393,7 @@ function useStatusSyncInterval({
46200
46393
  // src/hooks/use-statusbar-view-model.ts
46201
46394
  import * as fs4 from "node:fs/promises";
46202
46395
  import { getContextBreakdown } from "@wrongstack/core/utils";
46203
- import { useEffect as useEffect60, useMemo as useMemo15, useState as useState34 } from "react";
46396
+ import { useEffect as useEffect61, useMemo as useMemo15, useState as useState35 } from "react";
46204
46397
 
46205
46398
  // src/context-fill.ts
46206
46399
  function resolveContextFill(inputs) {
@@ -46336,8 +46529,8 @@ function useStatusbarViewModel({
46336
46529
  const planHidden = hiddenItems.includes("plan");
46337
46530
  const taskHidden = hiddenItems.includes("tasks");
46338
46531
  const planPath = agent.ctx.meta["plan.path"];
46339
- const [planCounts, setPlanCounts] = useState34(null);
46340
- useEffect60(() => {
46532
+ const [planCounts, setPlanCounts] = useState35(null);
46533
+ useEffect61(() => {
46341
46534
  if (planHidden) return;
46342
46535
  if (typeof planPath !== "string" || !planPath) {
46343
46536
  setPlanCounts(null);
@@ -46383,8 +46576,8 @@ function useStatusbarViewModel({
46383
46576
  };
46384
46577
  }, [planPath, planHidden]);
46385
46578
  const taskPath = agent.ctx.meta["task.path"];
46386
- const [taskCounts, setTaskCounts] = useState34(null);
46387
- useEffect60(() => {
46579
+ const [taskCounts, setTaskCounts] = useState35(null);
46580
+ useEffect61(() => {
46388
46581
  if (taskHidden) return;
46389
46582
  if (typeof taskPath !== "string" || !taskPath) {
46390
46583
  setTaskCounts(null);
@@ -46459,7 +46652,7 @@ function useStatusbarViewModel({
46459
46652
  }
46460
46653
 
46461
46654
  // src/hooks/use-statusline-hidden-sync.ts
46462
- import { useEffect as useEffect61 } from "react";
46655
+ import { useEffect as useEffect62 } from "react";
46463
46656
  function statuslineHiddenDiffers(hookHidden, pickerHidden) {
46464
46657
  const currentHidden = new Set(hookHidden);
46465
46658
  const pickerHiddenSet = new Set(pickerHidden);
@@ -46477,7 +46670,7 @@ function useStatuslineHiddenSync({
46477
46670
  hiddenItems,
46478
46671
  setHiddenItems
46479
46672
  }) {
46480
- useEffect61(() => {
46673
+ useEffect62(() => {
46481
46674
  if (!pickerOpen) return;
46482
46675
  if (statuslineHiddenDiffers(hiddenItems, pickerHidden)) {
46483
46676
  setHiddenItems([...pickerHidden]);
@@ -46494,18 +46687,18 @@ function useStatuslineLayoutSync({
46494
46687
  setLines,
46495
46688
  setDensities
46496
46689
  }) {
46497
- useEffect61(() => {
46690
+ useEffect62(() => {
46498
46691
  if (!pickerOpen || !layoutSeeded) return;
46499
46692
  if (statuslineLayoutDiffers(lines, pickerLines)) setLines({ ...pickerLines });
46500
46693
  }, [pickerOpen, layoutSeeded, pickerLines, lines, setLines]);
46501
- useEffect61(() => {
46694
+ useEffect62(() => {
46502
46695
  if (!pickerOpen || !layoutSeeded) return;
46503
46696
  if (statuslineLayoutDiffers(densities, pickerDensities)) setDensities({ ...pickerDensities });
46504
46697
  }, [pickerOpen, layoutSeeded, pickerDensities, densities, setDensities]);
46505
46698
  }
46506
46699
 
46507
46700
  // src/hooks/use-stream-chip-expiration.ts
46508
- import { useEffect as useEffect62, useRef as useRef40 } from "react";
46701
+ import { useEffect as useEffect63, useRef as useRef40 } from "react";
46509
46702
  function computeStreamChipActions(input) {
46510
46703
  const actions = [];
46511
46704
  const visible = new Set(input.visibleChipKeys);
@@ -46532,7 +46725,7 @@ function useStreamChipExpiration({
46532
46725
  }) {
46533
46726
  const prevBrainPromptRef = useRef40(brainPrompt);
46534
46727
  const prevEnhanceRef = useRef40(enhance);
46535
- useEffect62(() => {
46728
+ useEffect63(() => {
46536
46729
  const actions = computeStreamChipActions({
46537
46730
  brainPromptNow: !!brainPrompt,
46538
46731
  brainPromptPrev: !!prevBrainPromptRef.current,
@@ -46544,7 +46737,7 @@ function useStreamChipExpiration({
46544
46737
  prevBrainPromptRef.current = brainPrompt;
46545
46738
  prevEnhanceRef.current = enhance;
46546
46739
  }, [brainPrompt, enhance, visibleChips, dispatch]);
46547
- useEffect62(() => {
46740
+ useEffect63(() => {
46548
46741
  const interval = setInterval(() => {
46549
46742
  const expired = computeExpiredChipKeys(visibleChips, Date.now());
46550
46743
  for (const key of expired) {
@@ -46594,9 +46787,9 @@ function useThemePickerHandler({
46594
46787
  }
46595
46788
 
46596
46789
  // src/hooks/use-theme-state.ts
46597
- import { useEffect as useEffect63 } from "react";
46790
+ import { useEffect as useEffect64 } from "react";
46598
46791
  function useThemeState({ configStore }) {
46599
- useEffect63(() => {
46792
+ useEffect64(() => {
46600
46793
  if (!configStore) return;
46601
46794
  const initial = configStore.get().themePreset;
46602
46795
  if (initial && initial !== getActiveThemeName()) {
@@ -46619,7 +46812,7 @@ import * as fs5 from "node:fs/promises";
46619
46812
  import * as os from "node:os";
46620
46813
  import { loadGoal } from "@wrongstack/core/storage";
46621
46814
  import { resolveWstackPaths as resolveWstackPaths5 } from "@wrongstack/core/utils";
46622
- import { useCallback as useCallback28, useEffect as useEffect64, useMemo as useMemo16, useRef as useRef41, useState as useState35 } from "react";
46815
+ import { useCallback as useCallback28, useEffect as useEffect65, useMemo as useMemo16, useRef as useRef41, useState as useState36 } from "react";
46623
46816
 
46624
46817
  // src/heap-watchdog.ts
46625
46818
  import {
@@ -46664,10 +46857,10 @@ function useTuiActivity({
46664
46857
  builderRef
46665
46858
  }) {
46666
46859
  recordTuiAppRender();
46667
- const [rolledThinkingWord, setRolledThinkingWord] = useState35(() => pickRandomTuiThinkingWord());
46860
+ const [rolledThinkingWord, setRolledThinkingWord] = useState36(() => pickRandomTuiThinkingWord());
46668
46861
  const thinkingWorking = status === "running" || status === "streaming";
46669
46862
  const prevThinkingWorkingRef = useRef41(false);
46670
- useEffect64(() => {
46863
+ useEffect65(() => {
46671
46864
  if (thinkingWorking && !prevThinkingWorkingRef.current) {
46672
46865
  setRolledThinkingWord((previous) => pickRandomTuiThinkingWord(previous));
46673
46866
  }
@@ -46679,15 +46872,15 @@ function useTuiActivity({
46679
46872
  [fleet]
46680
46873
  );
46681
46874
  const startedAtRef = useRef41(Date.now());
46682
- const [nowTick, setNowTick] = useState35(Date.now());
46683
- useEffect64(() => {
46875
+ const [nowTick, setNowTick] = useState36(Date.now());
46876
+ useEffect65(() => {
46684
46877
  const timer = setInterval(() => setNowTick(Date.now()), 1e4);
46685
46878
  return () => clearInterval(timer);
46686
46879
  }, []);
46687
- const [workingTimeBase, setWorkingTimeBase] = useState35(0);
46880
+ const [workingTimeBase, setWorkingTimeBase] = useState36(0);
46688
46881
  const workingStartRef = useRef41(null);
46689
46882
  const prevStatusRef = useRef41(status);
46690
- useEffect64(() => {
46883
+ useEffect65(() => {
46691
46884
  if (prevStatusRef.current === status) return;
46692
46885
  const wasWorking = prevStatusRef.current === "running" || prevStatusRef.current === "streaming";
46693
46886
  const isWorking = status === "running" || status === "streaming";
@@ -46700,10 +46893,10 @@ function useTuiActivity({
46700
46893
  }
46701
46894
  prevStatusRef.current = status;
46702
46895
  }, [status]);
46703
- const [fleetWorkingBase, setFleetWorkingBase] = useState35(0);
46896
+ const [fleetWorkingBase, setFleetWorkingBase] = useState36(0);
46704
46897
  const fleetWorkingStartRef = useRef41(null);
46705
46898
  const prevFleetRunningRef = useRef41(0);
46706
- useEffect64(() => {
46899
+ useEffect65(() => {
46707
46900
  const running = fleetRunningCount;
46708
46901
  if (prevFleetRunningRef.current === running) return;
46709
46902
  const wasRunning = prevFleetRunningRef.current > 0;
@@ -46749,7 +46942,7 @@ function useTuiActivity({
46749
46942
  pushMetricHistory(cpuHistoryRef.current, pct / 100);
46750
46943
  return pct;
46751
46944
  }, [nowTick]);
46752
- useEffect64(() => {
46945
+ useEffect65(() => {
46753
46946
  const stopHeapWatchdog = startSharedHeapWatchdog({
46754
46947
  collectStats: () => {
46755
46948
  const currentState = stateRef.current;
@@ -46844,7 +47037,7 @@ function useTuiActivity({
46844
47037
  }).catch(() => {
46845
47038
  });
46846
47039
  }, [dispatch, projectRoot]);
46847
- useEffect64(() => {
47040
+ useEffect65(() => {
46848
47041
  refreshGoalSummary();
46849
47042
  }, [nowTick, refreshGoalSummary]);
46850
47043
  const enhanceDots = enhanceBusy ? timingFrame % 36 : 0;
@@ -46867,7 +47060,7 @@ function useTuiActivity({
46867
47060
  }
46868
47061
 
46869
47062
  // src/hooks/use-tui-controllers.ts
46870
- import { useEffect as useEffect65 } from "react";
47063
+ import { useEffect as useEffect66 } from "react";
46871
47064
  function useTuiControllers({
46872
47065
  dispatch,
46873
47066
  fleetChat,
@@ -46877,7 +47070,7 @@ function useTuiControllers({
46877
47070
  enhanceController,
46878
47071
  agentsMonitorController
46879
47072
  }) {
46880
- useEffect65(() => {
47073
+ useEffect66(() => {
46881
47074
  if (!fleetStreamController) return;
46882
47075
  fleetStreamController.mode = fleetChat;
46883
47076
  fleetStreamController.setMode = (mode) => {
@@ -46889,12 +47082,12 @@ function useTuiControllers({
46889
47082
  };
46890
47083
  };
46891
47084
  }, [dispatch, fleetStreamController, fleetChat]);
46892
- useEffect65(() => {
47085
+ useEffect66(() => {
46893
47086
  if (fleetStreamController) {
46894
47087
  fleetStreamController.mode = fleetChat;
46895
47088
  }
46896
47089
  }, [fleetStreamController, fleetChat]);
46897
- useEffect65(() => {
47090
+ useEffect66(() => {
46898
47091
  if (!enhanceController) return;
46899
47092
  enhanceController.enabled = enhanceEnabled;
46900
47093
  enhanceController.setEnabled = (enabled) => {
@@ -46906,7 +47099,7 @@ function useTuiControllers({
46906
47099
  };
46907
47100
  };
46908
47101
  }, [dispatch, enhanceController, enhanceEnabled]);
46909
- useEffect65(() => {
47102
+ useEffect66(() => {
46910
47103
  if (!agentsMonitorController) return;
46911
47104
  agentsMonitorController.visible = agentsMonitorOpen;
46912
47105
  agentsMonitorController.setVisible = (visible) => {
@@ -46920,32 +47113,32 @@ function useTuiControllers({
46920
47113
  };
46921
47114
  };
46922
47115
  }, [agentsMonitorController, agentsMonitorOpen, dispatch]);
46923
- useEffect65(() => {
47116
+ useEffect66(() => {
46924
47117
  if (agentsMonitorController) agentsMonitorController.visible = agentsMonitorOpen;
46925
47118
  }, [agentsMonitorController, agentsMonitorOpen]);
46926
47119
  }
46927
47120
 
46928
47121
  // src/hooks/use-tui-environment-state.ts
46929
47122
  import { getIndexState as getIndexState2, getProcessRegistry as getProcessRegistry9, onIndexStateChange } from "@wrongstack/tools";
46930
- import { useEffect as useEffect66, useRef as useRef42, useState as useState37 } from "react";
47123
+ import { useEffect as useEffect67, useRef as useRef42, useState as useState38 } from "react";
46931
47124
 
46932
47125
  // src/hooks/use-statusline-state.ts
46933
- import { useState as useState36 } from "react";
47126
+ import { useState as useState37 } from "react";
46934
47127
  function useStatuslineState(opts) {
46935
- const [liveModel, setLiveModel] = useState36(opts.model);
46936
- const [liveProvider, setLiveProvider] = useState36(opts.provider ?? "agent");
46937
- const [activeMaxContext, setActiveMaxContext] = useState36(
47128
+ const [liveModel, setLiveModel] = useState37(opts.model);
47129
+ const [liveProvider, setLiveProvider] = useState37(opts.provider ?? "agent");
47130
+ const [activeMaxContext, setActiveMaxContext] = useState37(
46938
47131
  opts.effectiveMaxContext
46939
47132
  );
46940
- const [yoloLive, setYoloLive] = useState36(opts.yolo);
46941
- const [autonomyLive, setAutonomyLive] = useState36(opts.getAutonomy?.() ?? "off");
46942
- const [liveModeLabel, setLiveModeLabel] = useState36(opts.modeLabel ?? "");
46943
- const [hiddenItems, setHiddenItems] = useState36(
47133
+ const [yoloLive, setYoloLive] = useState37(opts.yolo);
47134
+ const [autonomyLive, setAutonomyLive] = useState37(opts.getAutonomy?.() ?? "off");
47135
+ const [liveModeLabel, setLiveModeLabel] = useState37(opts.modeLabel ?? "");
47136
+ const [hiddenItems, setHiddenItems] = useState37(
46944
47137
  Array.isArray(opts.statuslineHiddenItems) ? [...opts.statuslineHiddenItems] : [...opts.statuslineHiddenItems]
46945
47138
  );
46946
- const [lines, setLines] = useState36(opts.statuslineLines ?? {});
46947
- const [densities, setDensities] = useState36(opts.statuslineDensities ?? {});
46948
- const [sessionCount, setSessionCount] = useState36(0);
47139
+ const [lines, setLines] = useState37(opts.statuslineLines ?? {});
47140
+ const [densities, setDensities] = useState37(opts.statuslineDensities ?? {});
47141
+ const [sessionCount, setSessionCount] = useState37(0);
46949
47142
  return {
46950
47143
  liveModel,
46951
47144
  setLiveModel,
@@ -47004,14 +47197,14 @@ function useTuiEnvironmentState({
47004
47197
  setStatuslineDensities,
47005
47198
  saveStatuslineDensities
47006
47199
  }) {
47007
- const [memoryContextMonitor, setMemoryContextMonitor] = useState37(emptyMemoryContextMonitor);
47008
- const [memoryRecordTotal, setMemoryRecordTotal] = useState37();
47200
+ const [memoryContextMonitor, setMemoryContextMonitor] = useState38(emptyMemoryContextMonitor);
47201
+ const [memoryRecordTotal, setMemoryRecordTotal] = useState38();
47009
47202
  const memoryContextMonitorRef = useRef42(memoryContextMonitor);
47010
47203
  memoryContextMonitorRef.current = memoryContextMonitor;
47011
47204
  const memoryRecordTotalRef = useRef42(memoryRecordTotal);
47012
47205
  memoryRecordTotalRef.current = memoryRecordTotal;
47013
47206
  const activeMemoryInContext = activeMemoryContextCount(memoryContextMonitor);
47014
- useEffect66(() => {
47207
+ useEffect67(() => {
47015
47208
  let cancelled = false;
47016
47209
  const refreshTotal = async () => {
47017
47210
  try {
@@ -47041,17 +47234,17 @@ function useTuiEnvironmentState({
47041
47234
  });
47042
47235
  const hiddenItemsRef = useRef42(statusline.hiddenItems);
47043
47236
  hiddenItemsRef.current = statusline.hiddenItems;
47044
- const [liveToolCount, setLiveToolCount] = useState37(toolCount);
47045
- useEffect66(() => setLiveToolCount(toolCount), [toolCount]);
47046
- const [indexState, setIndexState] = useState37(() => getIndexState2());
47047
- useEffect66(() => {
47237
+ const [liveToolCount, setLiveToolCount] = useState38(toolCount);
47238
+ useEffect67(() => setLiveToolCount(toolCount), [toolCount]);
47239
+ const [indexState, setIndexState] = useState38(() => getIndexState2());
47240
+ useEffect67(() => {
47048
47241
  setIndexState(getIndexState2());
47049
47242
  return onIndexStateChange(setIndexState);
47050
47243
  }, []);
47051
- const [breakerCountdown, setBreakerCountdown] = useState37(
47244
+ const [breakerCountdown, setBreakerCountdown] = useState38(
47052
47245
  () => getProcessRegistry9().getBreakerCountdown()
47053
47246
  );
47054
- useEffect66(() => {
47247
+ useEffect67(() => {
47055
47248
  const settings = getSettings?.();
47056
47249
  if (settings) {
47057
47250
  getProcessRegistry9().setBreakerConfig({
@@ -47062,7 +47255,7 @@ function useTuiEnvironmentState({
47062
47255
  return getProcessRegistry9().onBreakerCountdownChange(setBreakerCountdown);
47063
47256
  }, [getSettings]);
47064
47257
  const breakerArmed = breakerCountdown !== null;
47065
- useEffect66(() => {
47258
+ useEffect67(() => {
47066
47259
  if (!breakerArmed) return;
47067
47260
  const timer = setInterval(
47068
47261
  () => setBreakerCountdown(getProcessRegistry9().getBreakerCountdown()),
@@ -47070,10 +47263,10 @@ function useTuiEnvironmentState({
47070
47263
  );
47071
47264
  return () => clearInterval(timer);
47072
47265
  }, [breakerArmed]);
47073
- useEffect66(() => {
47266
+ useEffect67(() => {
47074
47267
  statusline.setHiddenItems([...statuslineHiddenItems]);
47075
47268
  }, [statuslineHiddenItems, statusline.setHiddenItems]);
47076
- useEffect66(() => {
47269
+ useEffect67(() => {
47077
47270
  setStatuslineHiddenItems(statusline.hiddenItems);
47078
47271
  saveStatuslineHiddenItems(statusline.hiddenItems).catch?.((error) => {
47079
47272
  console.error(
@@ -47087,7 +47280,7 @@ function useTuiEnvironmentState({
47087
47280
  });
47088
47281
  }, [setStatuslineHiddenItems, saveStatuslineHiddenItems, statusline.hiddenItems]);
47089
47282
  const layoutHydrated = useRef42(false);
47090
- useEffect66(() => {
47283
+ useEffect67(() => {
47091
47284
  if (!layoutHydrated.current) {
47092
47285
  layoutHydrated.current = true;
47093
47286
  return;
@@ -47098,7 +47291,7 @@ function useTuiEnvironmentState({
47098
47291
  );
47099
47292
  }, [setStatuslineLines, saveStatuslineLines, statusline.lines]);
47100
47293
  const densityHydrated = useRef42(false);
47101
- useEffect66(() => {
47294
+ useEffect67(() => {
47102
47295
  if (!densityHydrated.current) {
47103
47296
  densityHydrated.current = true;
47104
47297
  return;
@@ -47125,13 +47318,13 @@ function useTuiEnvironmentState({
47125
47318
  }
47126
47319
 
47127
47320
  // src/hooks/use-tui-event-bridge.ts
47128
- import { useCallback as useCallback30, useEffect as useEffect69 } from "react";
47321
+ import { useCallback as useCallback30, useEffect as useEffect70 } from "react";
47129
47322
 
47130
47323
  // src/hooks/use-brain-events.ts
47131
- import { useEffect as useEffect67 } from "react";
47324
+ import { useEffect as useEffect68 } from "react";
47132
47325
  var MONITOR_INTERVENTION_GRACE_MS = 5e3;
47133
47326
  function useBrainEvents(events, dispatch, getSessionId) {
47134
- useEffect67(() => {
47327
+ useEffect68(() => {
47135
47328
  const isCurrentSession2 = (sessionId) => {
47136
47329
  const current = getSessionId?.();
47137
47330
  return !sessionId || !current || sessionId === current;
@@ -47344,7 +47537,7 @@ function useBrainEvents(events, dispatch, getSessionId) {
47344
47537
 
47345
47538
  // src/hooks/use-subagent-events.ts
47346
47539
  import { expectDefined as expectDefined5 } from "@wrongstack/core/utils";
47347
- import { useCallback as useCallback29, useEffect as useEffect68, useRef as useRef43 } from "react";
47540
+ import { useCallback as useCallback29, useEffect as useEffect69, useRef as useRef43 } from "react";
47348
47541
  var STREAM_COLORS2 = ["cyan", "magenta", "yellow", "green", "blue"];
47349
47542
  function providerContextLimitHistoryEntry(event) {
47350
47543
  if (event.source !== "provider" || event.decreased !== true || typeof event.previousMaxContext !== "number" || event.previousMaxContext <= event.maxContext) {
@@ -47399,7 +47592,7 @@ function useSubagentEvents(events, dispatch, setActiveMaxContext, getSessionId,
47399
47592
  []
47400
47593
  // labelsRef is a stable ref
47401
47594
  );
47402
- useEffect68(() => {
47595
+ useEffect69(() => {
47403
47596
  const seen = /* @__PURE__ */ new Set();
47404
47597
  const isCurrentSession2 = (sessionId) => {
47405
47598
  const current = getSessionId?.();
@@ -47751,7 +47944,7 @@ function useTuiEventBridge({
47751
47944
  useGoalEvents(subscribeGoal, dispatch, stateRef, getSessionId);
47752
47945
  }
47753
47946
  function useSessionEvents(events, dispatch, onClearHistory, getSessionId) {
47754
- useEffect69(() => {
47947
+ useEffect70(() => {
47755
47948
  const isCurrentSession2 = (sessionId) => {
47756
47949
  const current = getSessionId?.();
47757
47950
  return !sessionId || !current || sessionId === current;
@@ -47782,7 +47975,7 @@ function useSessionEvents(events, dispatch, onClearHistory, getSessionId) {
47782
47975
  }, [events, dispatch, onClearHistory, getSessionId]);
47783
47976
  }
47784
47977
  function useGoalEvents(subscribeGoal, dispatch, stateRef, getSessionId) {
47785
- useEffect69(() => {
47978
+ useEffect70(() => {
47786
47979
  if (!subscribeGoal) return;
47787
47980
  const isCurrentSession2 = (sessionId) => {
47788
47981
  const current = getSessionId?.();
@@ -48013,7 +48206,7 @@ import {
48013
48206
  setSessionSubagentsAllowed
48014
48207
  } from "@wrongstack/core/coordination";
48015
48208
  import { toErrorMessage as toErrorMessage12 } from "@wrongstack/core/utils";
48016
- import { useEffect as useEffect70 } from "react";
48209
+ import { useEffect as useEffect71 } from "react";
48017
48210
  var RESUME_PICKER_SESSIONS = 500;
48018
48211
  function useTuiSlashCommands({
48019
48212
  slashRegistry,
@@ -48038,7 +48231,7 @@ function useTuiSlashCommands({
48038
48231
  listSessions,
48039
48232
  openPromptPicker
48040
48233
  }) {
48041
- useEffect70(() => {
48234
+ useEffect71(() => {
48042
48235
  const cmd = {
48043
48236
  name: "solo",
48044
48237
  description: "Control session-only subagents before the first message: /solo on|off|status.",
@@ -48068,7 +48261,7 @@ function useTuiSlashCommands({
48068
48261
  official: true
48069
48262
  });
48070
48263
  }, [agent, slashRegistry]);
48071
- useEffect70(() => {
48264
+ useEffect71(() => {
48072
48265
  if (!getPickableProviders || !switchProviderAndModel) return;
48073
48266
  const cmd = {
48074
48267
  name: "model",
@@ -48084,7 +48277,7 @@ function useTuiSlashCommands({
48084
48277
  official: true
48085
48278
  });
48086
48279
  }, [slashRegistry, getPickableProviders, switchProviderAndModel, openModelPicker]);
48087
- useEffect70(() => {
48280
+ useEffect71(() => {
48088
48281
  const cmd = {
48089
48282
  name: "f",
48090
48283
  description: "Open F-key panel picker. Arrow keys to navigate, Enter to open, Esc to close.",
@@ -48098,7 +48291,7 @@ function useTuiSlashCommands({
48098
48291
  official: true
48099
48292
  });
48100
48293
  }, [slashRegistry, openFKeyPicker]);
48101
- useEffect70(() => {
48294
+ useEffect71(() => {
48102
48295
  const cmd = {
48103
48296
  name: "design",
48104
48297
  description: "Design Studio: /design (picker) | <kit> [stack] | off | foundations | set <k=v> | tune <k=v> | swap <kit> | materialize [stack] [path] | verify.",
@@ -48230,7 +48423,7 @@ ${menu}` };
48230
48423
  official: true
48231
48424
  });
48232
48425
  }, [slashRegistry, projectRoot, agent]);
48233
- useEffect70(() => {
48426
+ useEffect71(() => {
48234
48427
  if (!getSettings || !saveSettings) return;
48235
48428
  const cmd = {
48236
48429
  name: "settings",
@@ -48337,7 +48530,7 @@ Available chords:
48337
48530
  official: true
48338
48531
  });
48339
48532
  }, [slashRegistry, getSettings, saveSettings, openSettings, dispatch]);
48340
- useEffect70(() => {
48533
+ useEffect71(() => {
48341
48534
  const cmd = {
48342
48535
  name: "settings-get",
48343
48536
  aliases: ["config-get", "get"],
@@ -48369,7 +48562,7 @@ Available chords:
48369
48562
  official: true
48370
48563
  });
48371
48564
  }, [slashRegistry, state.settingsPicker]);
48372
- useEffect70(() => {
48565
+ useEffect71(() => {
48373
48566
  const cmd = {
48374
48567
  name: "statusline",
48375
48568
  aliases: ["sl"],
@@ -48422,7 +48615,7 @@ Available chords:
48422
48615
  official: true
48423
48616
  });
48424
48617
  }, [slashRegistry, openStatuslinePicker, setHiddenItems]);
48425
- useEffect70(() => {
48618
+ useEffect71(() => {
48426
48619
  if (!getSettings || !saveSettings) return;
48427
48620
  const applyLayoutPreset = async (statuslineMode, showSidebar) => {
48428
48621
  const patch = { statuslineMode, showSidebar };
@@ -48467,7 +48660,7 @@ Available chords:
48467
48660
  teardownFull();
48468
48661
  };
48469
48662
  }, [slashRegistry, getSettings, saveSettings, dispatch]);
48470
- useEffect70(() => {
48663
+ useEffect71(() => {
48471
48664
  const cmd = {
48472
48665
  name: "mailbox",
48473
48666
  aliases: ["inbox", "mail"],
@@ -48482,7 +48675,7 @@ Available chords:
48482
48675
  official: true
48483
48676
  });
48484
48677
  }, [slashRegistry]);
48485
- useEffect70(() => {
48678
+ useEffect71(() => {
48486
48679
  if (!switchAutonomy) return;
48487
48680
  const cmd = {
48488
48681
  name: "autonomy",
@@ -48498,7 +48691,7 @@ Available chords:
48498
48691
  official: true
48499
48692
  });
48500
48693
  }, [slashRegistry, switchAutonomy]);
48501
- useEffect70(() => {
48694
+ useEffect71(() => {
48502
48695
  if (!skillLoader) return;
48503
48696
  const cmd = {
48504
48697
  name: "skill",
@@ -48532,7 +48725,7 @@ Available chords:
48532
48725
  official: true
48533
48726
  });
48534
48727
  }, [slashRegistry, skillLoader, dispatch]);
48535
- useEffect70(() => {
48728
+ useEffect71(() => {
48536
48729
  if (!getResourceMenu) return;
48537
48730
  const names = [
48538
48731
  "fallback",
@@ -48574,7 +48767,7 @@ Available chords:
48574
48767
  for (const cleanup of [...cleanups].reverse()) cleanup();
48575
48768
  };
48576
48769
  }, [slashRegistry, getResourceMenu, dispatch]);
48577
- useEffect70(() => {
48770
+ useEffect71(() => {
48578
48771
  const definitions = [
48579
48772
  { name: "cron", open: () => dispatch({ type: "toggleCronMonitor" }) },
48580
48773
  { name: "prompts", open: () => void openPromptPicker() }
@@ -48606,7 +48799,7 @@ Available chords:
48606
48799
  for (const cleanup of [...cleanups].reverse()) cleanup();
48607
48800
  };
48608
48801
  }, [slashRegistry, dispatch, openPromptPicker]);
48609
- useEffect70(() => {
48802
+ useEffect71(() => {
48610
48803
  const cmd = {
48611
48804
  name: "theme",
48612
48805
  description: "Pick a TUI color theme preset interactively (picker).",
@@ -48638,7 +48831,7 @@ Available chords:
48638
48831
  official: true
48639
48832
  });
48640
48833
  }, [slashRegistry, dispatch]);
48641
- useEffect70(() => {
48834
+ useEffect71(() => {
48642
48835
  const cmd = {
48643
48836
  name: "resume",
48644
48837
  aliases: ["load"],
@@ -48670,7 +48863,7 @@ Available chords:
48670
48863
 
48671
48864
  // src/hooks/use-working-dir-chip.ts
48672
48865
  import * as path8 from "node:path";
48673
- import { useEffect as useEffect71, useState as useState38 } from "react";
48866
+ import { useEffect as useEffect72, useState as useState39 } from "react";
48674
48867
  function formatWorkingDirChip(workingDir, projectRoot) {
48675
48868
  if (!workingDir || workingDir === projectRoot) return void 0;
48676
48869
  const impl = workingDir.includes("\\") || projectRoot.includes("\\") ? path8.win32 : path8;
@@ -48679,10 +48872,10 @@ function formatWorkingDirChip(workingDir, projectRoot) {
48679
48872
  return rel.replaceAll(impl.sep, "/");
48680
48873
  }
48681
48874
  function useWorkingDirChip(ctx, projectRoot) {
48682
- const [workingDirChip, setWorkingDirChip] = useState38(
48875
+ const [workingDirChip, setWorkingDirChip] = useState39(
48683
48876
  () => formatWorkingDirChip(ctx.workingDir, projectRoot)
48684
48877
  );
48685
- useEffect71(() => {
48878
+ useEffect72(() => {
48686
48879
  setWorkingDirChip(formatWorkingDirChip(ctx.workingDir, projectRoot));
48687
48880
  return ctx.onWorkingDirChanged((newDir) => {
48688
48881
  setWorkingDirChip(formatWorkingDirChip(newDir, projectRoot));
@@ -48979,7 +49172,7 @@ function App(props) {
48979
49172
  liveSettings,
48980
49173
  mailbox.mailboxPanelOpen
48981
49174
  );
48982
- useEffect72(() => {
49175
+ useEffect73(() => {
48983
49176
  titleController?.setModel(liveModel);
48984
49177
  }, [titleController, liveModel]);
48985
49178
  const activity = useTuiActivity({
@@ -49016,7 +49209,7 @@ function App(props) {
49016
49209
  dispatch,
49017
49210
  open: state.authPanel.open
49018
49211
  });
49019
- useEffect72(() => {
49212
+ useEffect73(() => {
49020
49213
  if (!secretInputController) return;
49021
49214
  const previousSecret = secretInputController.readSecret;
49022
49215
  const previousText = secretInputController.readText;