@wrongstack/tui 0.109.1 → 0.119.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { expectDefined, writeErr, resolveWstackPaths, loadGoal, InputBuilder, DefaultSessionRewinder, writeOut, formatTodosList, buildGoalPreamble, shouldEnhance, enhanceUserPrompt, recentTextTurns, normalizedEqual, buildChildEnv } from '@wrongstack/core';
2
2
  export { buildGoalPreamble } from '@wrongstack/core';
3
3
  import { Box, Text, useInput, useStdin, useStdout, render, useApp, Static } from 'ink';
4
- import React6, { useState, useEffect, memo, useCallback, useReducer, useRef, useMemo } from 'react';
4
+ import React6, { useState, useEffect, memo, useRef, useCallback, useReducer, useMemo } from 'react';
5
5
  import * as fs2 from 'fs/promises';
6
6
  import * as path2 from 'path';
7
7
  import { routeImagesForModel } from '@wrongstack/runtime/vision';
@@ -58,7 +58,8 @@ function StatusBar({
58
58
  eternalStage,
59
59
  goalSummary,
60
60
  indexState,
61
- modeLabel
61
+ modeLabel,
62
+ debugStreamStats
62
63
  }) {
63
64
  const { stdout } = useStdout();
64
65
  const [termWidth, setTermWidth] = useState(stdout?.columns ?? 90);
@@ -98,7 +99,8 @@ function StatusBar({
98
99
  const hasSecondLine = yolo || autonomy && autonomy !== "off" || startedAt != null || git !== null && git !== void 0 || projectName !== void 0 && projectName.length > 0 || goalSummary !== null && goalSummary !== void 0 || !!modeLabel;
99
100
  const fleetHasActivity = fleet && (fleet.running > 0 || fleet.idle > 0 || fleet.pending > 0 || fleet.completed > 0) || subagentCount > 0;
100
101
  const hasBrainActivity = !!brain && brain.state !== "idle";
101
- const hasThirdLine = todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0) || plan && (plan.open > 0 || plan.inProgress > 0 || plan.done > 0) || fleetHasActivity || hasBrainActivity;
102
+ const hasDebugStream = !!debugStreamStats;
103
+ const hasThirdLine = todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0) || plan && (plan.open > 0 || plan.inProgress > 0 || plan.done > 0) || fleetHasActivity || hasBrainActivity || hasDebugStream;
102
104
  return /* @__PURE__ */ jsxs(
103
105
  Box,
104
106
  {
@@ -359,6 +361,30 @@ function StatusBar({
359
361
  hasBrainActivity && brain ? /* @__PURE__ */ jsxs(Fragment, { children: [
360
362
  todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0) || plan && (plan.open > 0 || plan.inProgress > 0 || plan.done > 0) || fleetHasActivity ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
361
363
  /* @__PURE__ */ jsx(BrainChip, { brain })
364
+ ] }) : null,
365
+ hasDebugStream && debugStreamStats ? /* @__PURE__ */ jsxs(Fragment, { children: [
366
+ todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0) || plan && (plan.open > 0 || plan.inProgress > 0 || plan.done > 0) || fleetHasActivity || hasBrainActivity ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
367
+ /* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
368
+ /* @__PURE__ */ jsx(Text, { bold: true, children: "\u{1F41B} stream" }),
369
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
370
+ " #",
371
+ debugStreamStats.chunkCount
372
+ ] }),
373
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
374
+ " \xB7 ",
375
+ debugStreamStats.lastChunkSize,
376
+ "B"
377
+ ] }),
378
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
379
+ " \xB7 +",
380
+ debugStreamStats.lastDeltaMs,
381
+ "ms"
382
+ ] }),
383
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
384
+ " \xB7 ",
385
+ fmtDebugBytes(debugStreamStats.totalBytes)
386
+ ] })
387
+ ] })
362
388
  ] }) : null
363
389
  ] }) : /* @__PURE__ */ jsx(Box, { height: 1, children: /* @__PURE__ */ jsx(Text, { children: " " }) }),
364
390
  fleetAgents && fleetAgents.length > 0 ? /* @__PURE__ */ jsx(Box, { flexDirection: "row", gap: 2, children: fleetAgents.map((a, i) => (
@@ -536,6 +562,11 @@ function fmtElapsed(ms) {
536
562
  }
537
563
  return `${pad2(m)}:${pad2(s2)}`;
538
564
  }
565
+ function fmtDebugBytes(n) {
566
+ if (n < 1024) return `${n}B`;
567
+ if (n < 1048576) return `${(n / 1024).toFixed(1)}KB`;
568
+ return `${(n / 1048576).toFixed(1)}MB`;
569
+ }
539
570
  function pad2(n) {
540
571
  return n < 10 ? `0${n}` : String(n);
541
572
  }
@@ -826,11 +857,16 @@ function AgentRow({
826
857
  const s2 = STATUS2[entry.status];
827
858
  const elapsed = entry.status === "running" ? fmtElapsed(Math.max(0, now - entry.startedAt)) : entry.status;
828
859
  const modelLabel = fmtModelLabel(entry.provider, entry.model);
860
+ const ctxCostStr = entry.ctxCost !== void 0 && entry.ctxCost > 0 ? ` ctx ${entry.ctxCost.toFixed(4)}` : "";
829
861
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
830
862
  /* @__PURE__ */ jsx(Text, { color: selected ? "magenta" : "gray", children: selected ? "\u25B6" : " " }),
831
863
  /* @__PURE__ */ jsx(Text, { color: s2.color, bold: true, children: s2.icon }),
832
864
  /* @__PURE__ */ jsx(Text, { bold: selected, color: selected ? "magenta" : void 0, children: entry.name }),
833
865
  modelLabel ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: modelLabel }) : null,
866
+ entry.provider || entry.model ? /* @__PURE__ */ jsxs(Text, { color: "blue", children: [
867
+ entry.provider ? `${entry.provider}/` : "",
868
+ entry.model ?? ""
869
+ ] }) : null,
834
870
  /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
835
871
  "L",
836
872
  entry.iterations,
@@ -839,6 +875,7 @@ function AgentRow({
839
875
  "t"
840
876
  ] }),
841
877
  entry.ctxPct !== void 0 ? /* @__PURE__ */ jsx(ContextBar, { pct: entry.ctxPct, tokens: entry.ctxTokens, maxTokens: entry.ctxMaxTokens }) : null,
878
+ ctxCostStr ? /* @__PURE__ */ jsx(Text, { color: "yellow", children: ctxCostStr }) : null,
842
879
  entry.status === "running" && entry.currentTool ? /* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
843
880
  "\u2192 ",
844
881
  entry.currentTool.name,
@@ -877,6 +914,26 @@ function AgentDetail({
877
914
  lastTool.ok === false ? " \u2717" : ""
878
915
  ] }) : null
879
916
  ] }) : null,
917
+ entry.provider || entry.model ? /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
918
+ "provider: ",
919
+ entry.provider || "(leader)",
920
+ " \xB7 model: ",
921
+ entry.model || "\u2014"
922
+ ] }) }) : null,
923
+ entry.cost > 0 || entry.ctxCost && entry.ctxCost > 0 ? /* @__PURE__ */ jsxs(Box, { children: [
924
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "cost: " }),
925
+ entry.cost > 0 ? /* @__PURE__ */ jsxs(Text, { color: "green", children: [
926
+ "$",
927
+ entry.cost.toFixed(4),
928
+ " total"
929
+ ] }) : null,
930
+ entry.cost > 0 && entry.ctxCost && entry.ctxCost > 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: " \xB7 " }) : null,
931
+ entry.ctxCost && entry.ctxCost > 0 ? /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
932
+ "$",
933
+ entry.ctxCost.toFixed(4),
934
+ " ctx"
935
+ ] }) : null
936
+ ] }) : null,
880
937
  entry.status === "running" && streamTail ? /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
881
938
  ">",
882
939
  " ",
@@ -949,6 +1006,20 @@ function AgentsMonitor({
949
1006
  ] }) : null,
950
1007
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7 \u2191\u2193 nav \xB7 Ctrl+G / F3 close" })
951
1008
  ] }),
1009
+ live.length > 0 ? /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
1010
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "models" }),
1011
+ (() => {
1012
+ const seen = /* @__PURE__ */ new Map();
1013
+ for (const e of live) {
1014
+ if (e.model) seen.set(e.name ?? e.id, `${e.provider ?? "?"}/${e.model}`);
1015
+ }
1016
+ return [...seen.entries()].slice(0, 4).map(([name, mod]) => /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1017
+ name,
1018
+ ":",
1019
+ mod
1020
+ ] }, name));
1021
+ })()
1022
+ ] }) : null,
952
1023
  /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
953
1024
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "shown" }),
954
1025
  /* @__PURE__ */ jsx(Text, { color: "magenta", children: live.length }),
@@ -2430,7 +2501,10 @@ function MarkdownView({
2430
2501
  rows.push(
2431
2502
  /* @__PURE__ */ jsxs(Box, { flexDirection: "row", children: [
2432
2503
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: " " }),
2433
- /[\u2500-\u257F]/.test(qContent) ? /* @__PURE__ */ jsx(Box, { flexDirection: "row", children: [...qContent].slice(0, (contentWidth ?? termWidth) - 2).map((ch, ci) => /* @__PURE__ */ jsx(Text, { dimColor: true, children: ch }, ci)) }) : /* @__PURE__ */ jsx(InlineLine, { tokens: parseInline(qContent), dim: true })
2504
+ /[\u2500-\u257F]/.test(qContent) ? /* @__PURE__ */ jsx(Box, { flexDirection: "row", children: [...qContent].slice(0, (contentWidth ?? termWidth) - 2).map((ch, ci) => (
2505
+ /* biome-ignore lint/suspicious/noArrayIndexKey: characters are not reorderable */
2506
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: ch }, ci)
2507
+ )) }) : /* @__PURE__ */ jsx(InlineLine, { tokens: parseInline(qContent), dim: true })
2434
2508
  ] }, `q${key++}`)
2435
2509
  );
2436
2510
  continue;
@@ -2459,7 +2533,10 @@ function MarkdownView({
2459
2533
  const maxW = contentWidth ?? termWidth;
2460
2534
  const chars = [...line].slice(0, maxW);
2461
2535
  rows.push(
2462
- /* @__PURE__ */ jsx(Box, { flexDirection: "row", children: chars.map((ch, ci) => /* @__PURE__ */ jsx(Text, { children: ch }, ci)) }, `bx${key++}`)
2536
+ /* @__PURE__ */ jsx(Box, { flexDirection: "row", children: chars.map((ch, ci) => (
2537
+ /* biome-ignore lint/suspicious/noArrayIndexKey: characters are not reorderable */
2538
+ /* @__PURE__ */ jsx(Text, { children: ch }, ci)
2539
+ )) }, `bx${key++}`)
2463
2540
  );
2464
2541
  continue;
2465
2542
  }
@@ -3767,6 +3844,7 @@ function isHomeEnd(data) {
3767
3844
  return null;
3768
3845
  }
3769
3846
  function isBackspaceOrDelete(data) {
3847
+ if (data === "\x1B\x7F" || data === "\x1B\b") return "metaBackspace";
3770
3848
  if (data === "\x7F" || data === "\b") return "backspace";
3771
3849
  if (data === "\x1B[3~") return "delete";
3772
3850
  return null;
@@ -3807,15 +3885,38 @@ var Input = memo(function Input2({
3807
3885
  placeholderHeight,
3808
3886
  onKey
3809
3887
  }) {
3888
+ const suppressInkEscRef = useRef(false);
3810
3889
  useInput((input, key) => {
3811
3890
  if (disabled) return;
3891
+ if (key.escape && suppressInkEscRef.current) {
3892
+ suppressInkEscRef.current = false;
3893
+ return;
3894
+ }
3812
3895
  onKey(input, key);
3813
3896
  });
3814
3897
  const { stdin } = useStdin();
3815
3898
  useEffect(() => {
3816
3899
  if (!stdin || disabled) return;
3900
+ let escTimer = null;
3817
3901
  const handleData = (data) => {
3818
3902
  const s2 = data.toString();
3903
+ if (s2 === "\x1B") {
3904
+ escTimer = setTimeout(() => {
3905
+ escTimer = null;
3906
+ suppressInkEscRef.current = true;
3907
+ onKey("", { ...EMPTY_KEY, escape: true });
3908
+ }, 10);
3909
+ return;
3910
+ }
3911
+ if (escTimer !== null) {
3912
+ clearTimeout(escTimer);
3913
+ escTimer = null;
3914
+ if (s2 === "\x7F" || s2 === "\b") {
3915
+ onKey("", { ...EMPTY_KEY, backspace: true, ctrl: true });
3916
+ return;
3917
+ }
3918
+ return;
3919
+ }
3819
3920
  const homeEnd = isHomeEnd(s2);
3820
3921
  if (homeEnd === "home") {
3821
3922
  onKey("", { ...EMPTY_KEY, home: true });
@@ -3834,6 +3935,10 @@ var Input = memo(function Input2({
3834
3935
  onKey("", { ...EMPTY_KEY, delete: true });
3835
3936
  return;
3836
3937
  }
3938
+ if (bsdel === "metaBackspace") {
3939
+ onKey("", { ...EMPTY_KEY, backspace: true, ctrl: true });
3940
+ return;
3941
+ }
3837
3942
  const wheelDelta = parseMouseWheel(s2);
3838
3943
  if (wheelDelta !== null) {
3839
3944
  onKey("", { ...EMPTY_KEY, wheelDeltaY: wheelDelta });
@@ -3844,6 +3949,7 @@ var Input = memo(function Input2({
3844
3949
  };
3845
3950
  stdin.on("data", handleData);
3846
3951
  return () => {
3952
+ if (escTimer !== null) clearTimeout(escTimer);
3847
3953
  stdin.off("data", handleData);
3848
3954
  };
3849
3955
  }, [stdin, disabled, onKey]);
@@ -4383,12 +4489,15 @@ function GoalPanel({ goal }) {
4383
4489
  ] }) }),
4384
4490
  goal.deliverables.map((d, i) => {
4385
4491
  const done = /^\[[x✓]\]|✅|\(done\)/i.test(d);
4386
- return /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { color: done ? "green" : void 0, dimColor: !done, children: [
4387
- " ",
4388
- done ? "\u2713" : "\u25CB",
4389
- " ",
4390
- d
4391
- ] }) }, i);
4492
+ return (
4493
+ // biome-ignore lint/suspicious/noArrayIndexKey: deliverables are stable text strings
4494
+ /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { color: done ? "green" : void 0, dimColor: !done, children: [
4495
+ " ",
4496
+ done ? "\u2713" : "\u25CB",
4497
+ " ",
4498
+ d
4499
+ ] }) }, i)
4500
+ );
4392
4501
  })
4393
4502
  ] }),
4394
4503
  /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
@@ -4439,6 +4548,7 @@ var LOG_LEVELS = ["error", "warn", "info", "debug", "trace"];
4439
4548
  var AUDIT_LEVELS = ["minimal", "standard", "full"];
4440
4549
  var COMPACTOR_STRATEGIES = ["hybrid", "intelligent", "selective"];
4441
4550
  var MAX_ITERATIONS_PRESETS = [100, 200, 500, 1e3, 0];
4551
+ var ENHANCE_DELAY_PRESETS = [3e4, 45e3, 6e4, 9e4, 12e4];
4442
4552
  function formatSettingsDelay(ms) {
4443
4553
  if (ms === 0) return "disabled";
4444
4554
  if (ms >= 6e4) return `${Math.round(ms / 6e4)}m`;
@@ -4448,12 +4558,16 @@ function formatMaxIterations(n) {
4448
4558
  if (n === 0) return "unlimited";
4449
4559
  return String(n);
4450
4560
  }
4561
+ function formatEnhanceDelay(ms) {
4562
+ return `${Math.round(ms / 1e3)}s`;
4563
+ }
4451
4564
  var MODE_DESC = {
4452
4565
  off: "Agent stops after each turn (normal)",
4453
4566
  suggest: "Shows next-step suggestions after each turn",
4454
4567
  auto: "Self-driving \u2014 agent continues automatically"
4455
4568
  };
4456
- var SETTINGS_FIELD_COUNT = 19;
4569
+ var SETTINGS_FIELD_COUNT = 22;
4570
+ var CONFIG_SCOPES = ["global", "project"];
4457
4571
  function SettingsPicker({
4458
4572
  field,
4459
4573
  mode,
@@ -4475,6 +4589,9 @@ function SettingsPicker({
4475
4589
  auditLevel,
4476
4590
  indexOnStart,
4477
4591
  maxIterations,
4592
+ enhanceDelayMs,
4593
+ debugStream,
4594
+ configScope,
4478
4595
  hint
4479
4596
  }) {
4480
4597
  const boolVal = (v) => v ? "on" : "off";
@@ -4585,6 +4702,23 @@ function SettingsPicker({
4585
4702
  label: "Max iterations",
4586
4703
  value: formatMaxIterations(maxIterations),
4587
4704
  detail: "100\u20131000 or unlimited (0)"
4705
+ },
4706
+ {
4707
+ label: "Refine preview countdown",
4708
+ value: formatEnhanceDelay(enhanceDelayMs),
4709
+ detail: "Timeout for prompt refinement preview (30s\u2013120s)"
4710
+ },
4711
+ // ── Debug ──
4712
+ { section: "Debug" },
4713
+ {
4714
+ label: "Stream debug logging",
4715
+ value: boolVal(debugStream),
4716
+ detail: "Hex-dump raw SSE bytes to stderr"
4717
+ },
4718
+ {
4719
+ label: "Config scope",
4720
+ value: configScope,
4721
+ detail: "global (~/.wrongstack/) or project (.wrongstack/)"
4588
4722
  }
4589
4723
  ];
4590
4724
  const fieldRowIndex = [];
@@ -4619,7 +4753,7 @@ function SettingsPicker({
4619
4753
  };
4620
4754
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
4621
4755
  /* @__PURE__ */ jsx(Text, { color: "cyan", bold: true, children: "\u2501\u2501 Settings \u2501\u2501" }),
4622
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 field \xB7 \u2190/\u2192 change (instant save) \xB7 Esc close" }),
4756
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 field \xB7 \u2190/\u2192 change (instant save) \xB7 Esc / F5 close" }),
4623
4757
  hasAbove ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u2191 ${windowStart} field${windowStart === 1 ? "" : "s"} above` }) : null,
4624
4758
  rows.map((row, i) => {
4625
4759
  const fieldAtRow = fieldRowIndex.indexOf(i);
@@ -6182,6 +6316,10 @@ function buildSteeringPreamble(snapshot, newDirection) {
6182
6316
  function reducer(state, action) {
6183
6317
  switch (action.type) {
6184
6318
  case "addEntry": {
6319
+ const e = action.entry;
6320
+ if ((e.kind === "user" || e.kind === "assistant" || e.kind === "info" || e.kind === "warn" || e.kind === "error" || e.kind === "turn-summary") && !e.text?.trim()) {
6321
+ return state;
6322
+ }
6185
6323
  const appended = [...state.entries, { ...action.entry, id: state.nextId }];
6186
6324
  return { ...state, entries: appended, nextId: state.nextId + 1 };
6187
6325
  }
@@ -6517,6 +6655,9 @@ function reducer(state, action) {
6517
6655
  auditLevel: action.auditLevel,
6518
6656
  indexOnStart: action.indexOnStart,
6519
6657
  maxIterations: action.maxIterations,
6658
+ enhanceDelayMs: action.enhanceDelayMs,
6659
+ debugStream: action.debugStream,
6660
+ configScope: action.configScope,
6520
6661
  hint: void 0
6521
6662
  }
6522
6663
  };
@@ -6582,12 +6723,26 @@ function reducer(state, action) {
6582
6723
  return { ...state, settingsPicker: { ...sp, auditLevel: expectDefined(AUDIT_LEVELS[next]), hint: void 0 } };
6583
6724
  }
6584
6725
  if (f === 17) return { ...state, settingsPicker: { ...sp, indexOnStart: !sp.indexOnStart, hint: void 0 } };
6585
- {
6726
+ if (f === 18) {
6586
6727
  const j = MAX_ITERATIONS_PRESETS.indexOf(sp.maxIterations);
6587
6728
  const base = j < 0 ? 0 : j;
6588
6729
  const next = (base + action.delta + MAX_ITERATIONS_PRESETS.length) % MAX_ITERATIONS_PRESETS.length;
6589
6730
  return { ...state, settingsPicker: { ...sp, maxIterations: expectDefined(MAX_ITERATIONS_PRESETS[next]), hint: void 0 } };
6590
6731
  }
6732
+ if (f === 19) {
6733
+ const ej = ENHANCE_DELAY_PRESETS.indexOf(sp.enhanceDelayMs);
6734
+ const ebase = ej < 0 ? 0 : ej;
6735
+ const enext = (ebase + action.delta + ENHANCE_DELAY_PRESETS.length) % ENHANCE_DELAY_PRESETS.length;
6736
+ return { ...state, settingsPicker: { ...sp, enhanceDelayMs: expectDefined(ENHANCE_DELAY_PRESETS[enext]), hint: void 0 } };
6737
+ }
6738
+ if (f === 20) return { ...state, settingsPicker: { ...sp, debugStream: !sp.debugStream, hint: void 0 } };
6739
+ if (f === 21) {
6740
+ const i = CONFIG_SCOPES.indexOf(sp.configScope);
6741
+ const base = i < 0 ? 0 : i;
6742
+ const next = (base + action.delta + CONFIG_SCOPES.length) % CONFIG_SCOPES.length;
6743
+ return { ...state, settingsPicker: { ...sp, configScope: expectDefined(CONFIG_SCOPES[next]), hint: void 0 } };
6744
+ }
6745
+ return state;
6591
6746
  }
6592
6747
  case "settingsHint":
6593
6748
  return { ...state, settingsPicker: { ...state.settingsPicker, hint: action.text } };
@@ -6832,6 +6987,7 @@ function reducer(state, action) {
6832
6987
  ctxPct: action.load,
6833
6988
  ctxTokens: action.tokens,
6834
6989
  ctxMaxTokens: action.maxContext,
6990
+ ctxCost: action.ctxCost,
6835
6991
  lastEventAt: Date.now()
6836
6992
  }
6837
6993
  }
@@ -7242,6 +7398,22 @@ function reducer(state, action) {
7242
7398
  }
7243
7399
  };
7244
7400
  }
7401
+ case "debugStreamStats": {
7402
+ return {
7403
+ ...state,
7404
+ debugStreamStats: {
7405
+ chunkCount: action.chunkCount,
7406
+ lastChunkSize: action.lastChunkSize,
7407
+ lastDeltaMs: action.lastDeltaMs,
7408
+ totalBytes: action.totalBytes,
7409
+ lastChunkAt: action.lastChunkAt
7410
+ }
7411
+ };
7412
+ }
7413
+ case "debugStreamStatsClear": {
7414
+ if (state.debugStreamStats === null) return state;
7415
+ return { ...state, debugStreamStats: null };
7416
+ }
7245
7417
  }
7246
7418
  }
7247
7419
  var INPUT_PROMPT = "\u203A ";
@@ -7316,7 +7488,9 @@ function App({
7316
7488
  initialAsk,
7317
7489
  sessionsDir,
7318
7490
  modeLabel,
7319
- getModeLabel
7491
+ getModeLabel,
7492
+ registerDebugStreamCallback,
7493
+ restoreDebugStreamCallback
7320
7494
  }) {
7321
7495
  const { exit } = useApp();
7322
7496
  const { stdout } = useStdout();
@@ -7343,7 +7517,10 @@ function App({
7343
7517
  if (!projectRoot) return;
7344
7518
  const goalPath = resolveWstackPaths({ projectRoot }).projectGoal;
7345
7519
  loadGoal(goalPath).then((goal) => {
7346
- if (!goal) return;
7520
+ if (!goal) {
7521
+ dispatch({ type: "goalSummary", summary: null });
7522
+ return;
7523
+ }
7347
7524
  const lastEntry = goal.journal?.[goal.journal.length - 1];
7348
7525
  dispatch({
7349
7526
  type: "goalSummary",
@@ -7423,7 +7600,7 @@ function App({
7423
7600
  searchQuery: ""
7424
7601
  },
7425
7602
  autonomyPicker: { open: false, options: [], selected: 0 },
7426
- settingsPicker: { open: false, field: 0, mode: "off", delayMs: 0, titleAnimation: true, yolo: false, streamFleet: true, chime: false, confirmExit: true, nextPrediction: false, featureMcp: true, featurePlugins: true, featureMemory: true, featureSkills: true, featureModelsRegistry: true, contextAutoCompact: true, contextStrategy: "hybrid", logLevel: "info", auditLevel: "standard", indexOnStart: true, maxIterations: 500 },
7603
+ settingsPicker: { open: false, field: 0, mode: "off", delayMs: 0, titleAnimation: true, yolo: false, streamFleet: true, chime: false, confirmExit: true, nextPrediction: false, featureMcp: true, featurePlugins: true, featureMemory: true, featureSkills: true, featureModelsRegistry: true, contextAutoCompact: true, contextStrategy: "hybrid", logLevel: "info", auditLevel: "standard", indexOnStart: true, maxIterations: 500, enhanceDelayMs: 6e4, debugStream: false, configScope: "global" },
7427
7604
  confirmQueue: [],
7428
7605
  enhance: null,
7429
7606
  enhanceEnabled,
@@ -7462,7 +7639,8 @@ function App({
7462
7639
  scrollOffset: 0,
7463
7640
  totalLines: 0,
7464
7641
  viewportRows: 0,
7465
- pendingNewLines: 0
7642
+ pendingNewLines: 0,
7643
+ debugStreamStats: null
7466
7644
  });
7467
7645
  const builderRef = useRef(null);
7468
7646
  if (builderRef.current === null) {
@@ -7536,6 +7714,42 @@ function App({
7536
7714
  const t = setInterval(poll, 2e3);
7537
7715
  return () => clearInterval(t);
7538
7716
  }, [agent.ctx.todos]);
7717
+ const staleGuardRef = useRef(JSON.stringify({ a: "", y: false, m: "", model: "", provider: "" }));
7718
+ useEffect(() => {
7719
+ const poll = () => {
7720
+ const a = getAutonomy?.() ?? "off";
7721
+ const y = getYolo?.() ?? false;
7722
+ const m = getModeLabel?.() ?? "";
7723
+ const curModel = agent.ctx.model;
7724
+ const curProvider = agent.ctx.provider?.id ?? "";
7725
+ const snap = JSON.stringify({ a, y, m, model: curModel, provider: curProvider });
7726
+ if (snap !== staleGuardRef.current) {
7727
+ staleGuardRef.current = snap;
7728
+ if (a !== autonomyLive) setAutonomyLive(a);
7729
+ if (y !== yoloLive) setYoloLive(y);
7730
+ if (m !== liveModeLabel) setLiveModeLabel(m);
7731
+ if (curModel !== liveModel) setLiveModel(curModel);
7732
+ if (curProvider !== liveProvider) setLiveProvider(curProvider);
7733
+ if (a === "eternal" && getEternalEngine) void runEternalLoopRef.current();
7734
+ if (a === "eternal-parallel" && getParallelEngine) void runParallelLoopRef.current();
7735
+ }
7736
+ };
7737
+ const t = setInterval(poll, 2e3);
7738
+ return () => clearInterval(t);
7739
+ }, [
7740
+ getAutonomy,
7741
+ getYolo,
7742
+ getModeLabel,
7743
+ getEternalEngine,
7744
+ getParallelEngine,
7745
+ autonomyLive,
7746
+ yoloLive,
7747
+ liveModeLabel,
7748
+ liveModel,
7749
+ liveProvider,
7750
+ agent.ctx.model,
7751
+ agent.ctx.provider
7752
+ ]);
7539
7753
  const [gitInfo, setGitInfo] = React6.useState(null);
7540
7754
  useEffect(() => {
7541
7755
  let cancelled = false;
@@ -7728,7 +7942,10 @@ function App({
7728
7942
  logLevel: sp.logLevel,
7729
7943
  auditLevel: sp.auditLevel,
7730
7944
  indexOnStart: sp.indexOnStart,
7731
- maxIterations: sp.maxIterations
7945
+ maxIterations: sp.maxIterations,
7946
+ enhanceDelayMs: sp.enhanceDelayMs,
7947
+ debugStream: sp.debugStream,
7948
+ configScope: sp.configScope
7732
7949
  });
7733
7950
  }
7734
7951
  if (prev.help) dispatch({ type: "toggleHelp" });
@@ -7950,7 +8167,7 @@ function App({
7950
8167
  const subagents = Object.values(s2.fleet).filter((e) => e.status === "running").map((e) => ({ label: e.name, status: e.status, tool: e.currentTool?.name }));
7951
8168
  const subagentsTerminated = subagents.length;
7952
8169
  const partialAssistantText = streamingTextRef.current.slice(-1500);
7953
- activeCtrlRef.current?.abort();
8170
+ activeCtrlRef.current?.abort("user interrupt (/steer)");
7954
8171
  dispatch({
7955
8172
  type: "steerStart",
7956
8173
  snapshot: { runningTools, subagents, subagentsTerminated, partialAssistantText }
@@ -8061,7 +8278,10 @@ function App({
8061
8278
  logLevel: s2.logLevel ?? "info",
8062
8279
  auditLevel: s2.auditLevel ?? "standard",
8063
8280
  indexOnStart: s2.indexOnStart ?? true,
8064
- maxIterations: s2.maxIterations ?? 500
8281
+ maxIterations: s2.maxIterations ?? 500,
8282
+ enhanceDelayMs: s2.enhanceDelayMs ?? 6e4,
8283
+ debugStream: s2.debugStream ?? false,
8284
+ configScope: s2.configScope ?? "global"
8065
8285
  });
8066
8286
  }, [getSettings]);
8067
8287
  const settingsAutoSaveGateRef = useRef(true);
@@ -8097,7 +8317,10 @@ function App({
8097
8317
  logLevel: sp.logLevel,
8098
8318
  auditLevel: sp.auditLevel,
8099
8319
  indexOnStart: sp.indexOnStart,
8100
- maxIterations: sp.maxIterations
8320
+ maxIterations: sp.maxIterations,
8321
+ enhanceDelayMs: sp.enhanceDelayMs,
8322
+ debugStream: sp.debugStream,
8323
+ configScope: sp.configScope
8101
8324
  })).then((err) => {
8102
8325
  if (err) dispatch({ type: "settingsHint", text: err });
8103
8326
  });
@@ -8122,6 +8345,7 @@ function App({
8122
8345
  state.settingsPicker.auditLevel,
8123
8346
  state.settingsPicker.indexOnStart,
8124
8347
  state.settingsPicker.maxIterations,
8348
+ state.settingsPicker.enhanceDelayMs,
8125
8349
  saveSettings
8126
8350
  ]);
8127
8351
  useEffect(() => {
@@ -8331,6 +8555,33 @@ function App({
8331
8555
  if (flushTimerRef.current) clearTimeout(flushTimerRef.current);
8332
8556
  };
8333
8557
  }, [events, agent.ctx.todos]);
8558
+ useEffect(() => {
8559
+ if (!registerDebugStreamCallback) return;
8560
+ let cancelled = false;
8561
+ registerDebugStreamCallback((stats) => {
8562
+ if (cancelled) return;
8563
+ dispatch({
8564
+ type: "debugStreamStats",
8565
+ chunkCount: stats.chunkCount,
8566
+ lastChunkSize: stats.lastChunkSize,
8567
+ lastDeltaMs: stats.lastDeltaMs,
8568
+ totalBytes: stats.totalBytes,
8569
+ lastChunkAt: stats.lastChunkAt
8570
+ });
8571
+ });
8572
+ const offResp = events.on("provider.response", () => {
8573
+ dispatch({ type: "debugStreamStatsClear" });
8574
+ });
8575
+ const offErr = events.on("provider.error", () => {
8576
+ dispatch({ type: "debugStreamStatsClear" });
8577
+ });
8578
+ return () => {
8579
+ cancelled = true;
8580
+ offResp();
8581
+ offErr();
8582
+ restoreDebugStreamCallback?.();
8583
+ };
8584
+ }, [events, registerDebugStreamCallback, restoreDebugStreamCallback]);
8334
8585
  const enhanceEnabledRef = useRef(state.enhanceEnabled);
8335
8586
  useEffect(() => {
8336
8587
  enhanceEnabledRef.current = state.enhanceEnabled;
@@ -8404,7 +8655,7 @@ function App({
8404
8655
  return;
8405
8656
  }
8406
8657
  if (activeCtrlRef.current) {
8407
- activeCtrlRef.current.abort();
8658
+ activeCtrlRef.current.abort("user interrupt (Ctrl+C)");
8408
8659
  dispatch({ type: "status", status: "aborting" });
8409
8660
  if (director) {
8410
8661
  const cap = new Promise((resolve) => {
@@ -8650,7 +8901,7 @@ function App({
8650
8901
  return;
8651
8902
  }
8652
8903
  if (state.settingsPicker.open) {
8653
- if (key.escape || key.ctrl && input === "s") {
8904
+ if (key.escape || key.ctrl && input === "s" || key.fn === 5) {
8654
8905
  dispatch({ type: "settingsClose" });
8655
8906
  return;
8656
8907
  }
@@ -8890,7 +9141,10 @@ function App({
8890
9141
  logLevel: cfg.logLevel ?? "info",
8891
9142
  auditLevel: cfg.auditLevel ?? "standard",
8892
9143
  indexOnStart: cfg.indexOnStart ?? true,
8893
- maxIterations: cfg.maxIterations ?? 500
9144
+ maxIterations: cfg.maxIterations ?? 500,
9145
+ enhanceDelayMs: cfg.enhanceDelayMs ?? 6e4,
9146
+ debugStream: cfg.debugStream ?? false,
9147
+ configScope: cfg.configScope ?? "global"
8894
9148
  });
8895
9149
  }
8896
9150
  return;
@@ -8979,7 +9233,10 @@ function App({
8979
9233
  logLevel: cfg.logLevel ?? "info",
8980
9234
  auditLevel: cfg.auditLevel ?? "standard",
8981
9235
  indexOnStart: cfg.indexOnStart ?? true,
8982
- maxIterations: cfg.maxIterations ?? 500
9236
+ maxIterations: cfg.maxIterations ?? 500,
9237
+ enhanceDelayMs: cfg.enhanceDelayMs ?? 6e4,
9238
+ debugStream: cfg.debugStream ?? false,
9239
+ configScope: cfg.configScope ?? "global"
8983
9240
  });
8984
9241
  }
8985
9242
  return;
@@ -9206,7 +9463,8 @@ function App({
9206
9463
  }
9207
9464
  dispatch({ type: "streamReset" });
9208
9465
  if (result.status === "aborted") {
9209
- dispatch({ type: "addEntry", entry: { kind: "warn", text: "Aborted." } });
9466
+ const reason = result.abortReason ? `Aborted (${result.abortReason}).` : "Aborted.";
9467
+ dispatch({ type: "addEntry", entry: { kind: "warn", text: reason } });
9210
9468
  } else if (result.status === "failed") {
9211
9469
  const err = result.error;
9212
9470
  const text = err ? `Failed [${err.severity}${err.recoverable ? ", recoverable" : ""}]: ${err.describe()}` : "Failed.";
@@ -9702,6 +9960,9 @@ User message:
9702
9960
  auditLevel: state.settingsPicker.auditLevel,
9703
9961
  indexOnStart: state.settingsPicker.indexOnStart,
9704
9962
  maxIterations: state.settingsPicker.maxIterations,
9963
+ enhanceDelayMs: state.settingsPicker.enhanceDelayMs,
9964
+ debugStream: state.settingsPicker.debugStream,
9965
+ configScope: state.settingsPicker.configScope,
9705
9966
  hint: state.settingsPicker.hint
9706
9967
  }
9707
9968
  ) : null,
@@ -9759,7 +10020,7 @@ User message:
9759
10020
  const escConfirm = state.escConfirm;
9760
10021
  if (!escConfirm) return;
9761
10022
  const { snapshot } = escConfirm;
9762
- activeCtrlRef.current?.abort();
10023
+ activeCtrlRef.current?.abort("user interrupt (Esc)");
9763
10024
  dispatch({ type: "status", status: "aborting" });
9764
10025
  dispatch({ type: "steerStart", snapshot });
9765
10026
  if (director && snapshot.subagentsTerminated > 0) {
@@ -9840,7 +10101,8 @@ User message:
9840
10101
  eternalStage: state.eternalStage,
9841
10102
  goalSummary: state.goalSummary,
9842
10103
  indexState,
9843
- modeLabel: liveModeLabel || void 0
10104
+ modeLabel: liveModeLabel || void 0,
10105
+ debugStreamStats: state.debugStreamStats
9844
10106
  }
9845
10107
  ),
9846
10108
  state.helpOpen ? /* @__PURE__ */ jsx(HelpOverlay, {}) : null,
@@ -10115,7 +10377,9 @@ async function runTui(opts) {
10115
10377
  chime: opts.chime,
10116
10378
  confirmExit: opts.confirmExit,
10117
10379
  modeLabel: opts.modeLabel,
10118
- getModeLabel: opts.getModeLabel
10380
+ getModeLabel: opts.getModeLabel,
10381
+ registerDebugStreamCallback: opts.registerDebugStreamCallback,
10382
+ restoreDebugStreamCallback: opts.restoreDebugStreamCallback
10119
10383
  }),
10120
10384
  { exitOnCtrlC: false, stdin: inkStdin }
10121
10385
  );