@wrongstack/tui 0.280.1 → 0.281.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,4 +1,4 @@
1
- import { hasOpenTodos, writeErr, resolveProjectDir, wstackGlobalRoot, createHqPublisherFromEnv, startFleetTelemetryBridge, startBrainTelemetryBridge, startWorktreeTelemetryBridge, startToolTelemetryBridge, startCostTelemetryBridge, GlobalMailbox, resolveWstackPaths, loadGoal, InputBuilder, DefaultSessionRewinder, writeOut, formatTodosList, buildGoalPreamble, expectDefined as expectDefined$1, getDesignKitLoader, clearActiveKit, clearPersistedActiveKit, recordOverrides, setDesignOverrides, loadActiveKit, isDesignStack, materializeTokens, applyTokenOverrides, setActiveKit, projectSlug, shouldEnhance, enhanceUserPrompt, recentTextTurns, normalizedEqual, setBtwNote, buildChildEnv, DefaultPromptLoader, PromptUsageStore } from '@wrongstack/core';
1
+ import { hasOpenTodos, writeErr, resolveProjectDir, wstackGlobalRoot, createHqPublisherFromEnv, startFleetTelemetryBridge, startBrainTelemetryBridge, startWorktreeTelemetryBridge, startToolTelemetryBridge, startCostTelemetryBridge, GlobalMailbox, resolveWstackPaths, loadGoal, InputHistoryStore, DefaultSecretScrubber, INPUT_HISTORY_DEFAULT_MAX, InputBuilder, DefaultSessionRewinder, writeOut, formatTodosList, buildGoalPreamble, expectDefined as expectDefined$1, getDesignKitLoader, clearActiveKit, clearPersistedActiveKit, recordOverrides, setDesignOverrides, loadActiveKit, isDesignStack, materializeTokens, applyTokenOverrides, setActiveKit, projectSlug, shouldEnhance, enhanceUserPrompt, recentTextTurns, normalizedEqual, setBtwNote, buildChildEnv, DefaultPromptLoader, PromptUsageStore } from '@wrongstack/core';
2
2
  export { buildGoalPreamble } from '@wrongstack/core';
3
3
  import { Box as Box$1, useStdout, Static, useInput, useStdin, measureElement, Text as Text$1, render, useApp } from 'ink';
4
4
  import { randomUUID } from 'crypto';
@@ -423,6 +423,93 @@ function pickRandomTuiThinkingWord(previous) {
423
423
  const idx = Math.floor(Math.random() * list.length);
424
424
  return list[idx] ?? list[0] ?? DEFAULT_TUI_THINKING_WORD;
425
425
  }
426
+
427
+ // src/components/animation-style.tsx
428
+ var HUE_WHEEL = [
429
+ "#f38ba8",
430
+ // red
431
+ "#eba0ac",
432
+ // maroon
433
+ "#fab387",
434
+ // peach
435
+ "#f9e2af",
436
+ // yellow
437
+ "#a6e3a1",
438
+ // green
439
+ "#94e2d5",
440
+ // teal
441
+ "#89dceb",
442
+ // sky
443
+ "#89b4fa",
444
+ // blue
445
+ "#b4befe",
446
+ // lavender
447
+ "#cba6f7",
448
+ // mauve
449
+ "#f5c2e7",
450
+ // pink
451
+ "#f2cdcd"
452
+ // flamingo
453
+ ];
454
+ var ACCENT = "#fab387";
455
+ var DIM = "#3b3b4f";
456
+ var BREATHE_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
457
+ var DOTS_FRAMES = ["", ".", "..", "...", "..", "."];
458
+ var ANIMATION_STYLES = ["rainbow", "wave", "pulse", "dots", "breathe"];
459
+ var ANIMATION_STYLE_DESCS = {
460
+ rainbow: "Per-glyph hue cycle (default)",
461
+ wave: "Single-color brightness sweep",
462
+ pulse: "Whole-text brightness pulse",
463
+ dots: "Trailing dots ellipsis (. .. ... .. .)",
464
+ breathe: "Spinning braille glyph prefix, flat text"
465
+ };
466
+ var CYCLE_INTERVAL_SECONDS = 12;
467
+ var CYCLE_TICK_INTERVAL_MS = 1e3;
468
+ var CYCLE_ORDER = ["wave", "pulse", "dots", "breathe"];
469
+ function styleForCycleTick(tick) {
470
+ const idx = Math.max(0, Math.floor(tick / CYCLE_INTERVAL_SECONDS));
471
+ const i = idx % CYCLE_ORDER.length;
472
+ return CYCLE_ORDER[i] ?? CYCLE_ORDER[0];
473
+ }
474
+ function mixHex(a, b, t) {
475
+ const ca = parseHex(a);
476
+ const cb = parseHex(b);
477
+ if (!ca || !cb) return b;
478
+ const k = Math.max(0, Math.min(1, t));
479
+ const r = Math.round(ca[0] + (cb[0] - ca[0]) * k);
480
+ const g = Math.round(ca[1] + (cb[1] - ca[1]) * k);
481
+ const bl = Math.round(ca[2] + (cb[2] - ca[2]) * k);
482
+ return `#${toHex(r)}${toHex(g)}${toHex(bl)}`;
483
+ }
484
+ function parseHex(s2) {
485
+ if (!/^#[0-9a-f]{6}$/i.test(s2)) return null;
486
+ return [parseInt(s2.slice(1, 3), 16), parseInt(s2.slice(3, 5), 16), parseInt(s2.slice(5, 7), 16)];
487
+ }
488
+ function toHex(n) {
489
+ return n.toString(16).padStart(2, "0");
490
+ }
491
+ function waveColor(charIndex, phase, length) {
492
+ const t = length > 0 ? charIndex / length : 0;
493
+ const sweep = Math.sin(t * Math.PI * 2 + phase / 10);
494
+ return mixHex(DIM, ACCENT, (sweep + 1) / 2);
495
+ }
496
+ function pulseColor(phase) {
497
+ const t = phase % 16 / 16;
498
+ const k = 0.5 - 0.5 * Math.cos(t * Math.PI * 2);
499
+ return mixHex(DIM, ACCENT, k);
500
+ }
501
+ function stripTrailingDots(text) {
502
+ let s2 = text;
503
+ while (s2.length > 0) {
504
+ const last = s2.charAt(s2.length - 1);
505
+ if (last === "." || last === " " || last === "\u2026" || last === "\xB7") {
506
+ s2 = s2.slice(0, -1);
507
+ } else {
508
+ break;
509
+ }
510
+ }
511
+ return s2;
512
+ }
426
513
  var DELAY_PRESETS_MS = [0, 15e3, 3e4, 45e3, 6e4, 12e4];
427
514
  var SETTINGS_MODES = ["off", "suggest", "auto"];
428
515
  var LOG_LEVELS = ["error", "warn", "info", "debug", "trace"];
@@ -473,12 +560,17 @@ function formatMultiDiffSummaryThreshold(n) {
473
560
  function formatEnhanceDelay(ms) {
474
561
  return `${Math.round(ms / 1e3)}s`;
475
562
  }
563
+ var ANIMATION_STYLE_CHOICES = [...ANIMATION_STYLES, "cycle"];
564
+ function formatAnimationStyle(style) {
565
+ if (style === "cycle") return "cycle (shuffle all)";
566
+ return ANIMATION_STYLE_DESCS[style];
567
+ }
476
568
  var MODE_DESC = {
477
569
  off: "Agent stops after each turn (normal)",
478
570
  suggest: "Shows next-step suggestions after each turn",
479
571
  auto: "Self-driving \u2014 agent continues automatically"
480
572
  };
481
- var SETTINGS_FIELD_COUNT = 36;
573
+ var SETTINGS_FIELD_COUNT = 37;
482
574
  var THINKING_WORD_FIELD = 22;
483
575
  var SETTINGS_PICKER_JUMP_CHORDS = Object.freeze([
484
576
  // ── Ctrl chords (Tools / Reasoning / Fleet / Debug sections) ──
@@ -514,7 +606,12 @@ var SETTINGS_PICKER_JUMP_CHORDS = Object.freeze([
514
606
  { mod: "alt-shift", letter: "l", field: 31, label: "Log level" },
515
607
  { mod: "alt-shift", letter: "a", field: 32, label: "Audit level" },
516
608
  { mod: "alt-shift", letter: "b", field: 33, label: "Stream debug logging" },
517
- { mod: "alt-shift", letter: "g", field: 35, label: "Config scope" }
609
+ { mod: "alt-shift", letter: "g", field: 35, label: "Config scope" },
610
+ // ── Unmapped / Chord for Animation ──
611
+ // 'N' for a**N**imation — Alt+N is unlisted (only Alt+B,C,D,E,F are taken).
612
+ // Animation sits in the UX section alongside the rest of the visible-only
613
+ // toggle rows and is newly added after the Debug section at field 36.
614
+ { mod: "alt", letter: "n", field: 36, label: "Animation" }
518
615
  ]);
519
616
  function settingsPickerJumpField(mod, letter) {
520
617
  const lower = letter.toLowerCase();
@@ -636,8 +733,10 @@ var SETTINGS_FIELD_LABELS = [
636
733
  // 33
637
734
  "Statusline",
638
735
  // 34
639
- "Config scope"
736
+ "Config scope",
640
737
  // 35
738
+ "Animation"
739
+ // 36
641
740
  ];
642
741
  function resolveSettingsFieldValue(field, input) {
643
742
  const raw = input.trim().toLowerCase();
@@ -683,7 +782,8 @@ function resolveSettingsFieldValue(field, input) {
683
782
  [31, "logLevel", LOG_LEVELS],
684
783
  [32, "auditLevel", AUDIT_LEVELS],
685
784
  [34, "statuslineMode", STATUSLINE_MODES],
686
- [35, "configScope", CONFIG_SCOPES]
785
+ [35, "configScope", CONFIG_SCOPES],
786
+ [36, "animationStyle", ANIMATION_STYLE_CHOICES]
687
787
  ];
688
788
  for (const [f, key, values] of ENUM_FIELDS) {
689
789
  if (field !== f) continue;
@@ -776,7 +876,8 @@ function getSettingsFieldValue(values, field) {
776
876
  [31, "logLevel"],
777
877
  [32, "auditLevel"],
778
878
  [34, "statuslineMode"],
779
- [35, "configScope"]
879
+ [35, "configScope"],
880
+ [36, "animationStyle"]
780
881
  ];
781
882
  for (const [f, key] of ENUM_KEYS) {
782
883
  if (field !== f) continue;
@@ -835,7 +936,7 @@ var SETTINGS_SECTIONS = [
835
936
  },
836
937
  {
837
938
  name: "Debug",
838
- fields: [33, 34, 35]
939
+ fields: [33, 34, 35, 36]
839
940
  }
840
941
  ];
841
942
  function formatAllSettingsSummary(values) {
@@ -890,7 +991,8 @@ var SETTINGS_DEFAULTS = Object.freeze({
890
991
  reasoningPreserve: false,
891
992
  thinkingWord: "thinking",
892
993
  cacheTtl: "default",
893
- configScope: "global"
994
+ configScope: "global",
995
+ animationStyle: "rainbow"
894
996
  });
895
997
  function resetSettingsFieldValue(field) {
896
998
  const result = getSettingsFieldValue(SETTINGS_DEFAULTS, field);
@@ -936,7 +1038,8 @@ function buildResetPatch(field) {
936
1038
  [32, "auditLevel"],
937
1039
  [33, "debugStream"],
938
1040
  [34, "statuslineMode"],
939
- [35, "configScope"]
1041
+ [35, "configScope"],
1042
+ [36, "animationStyle"]
940
1043
  ];
941
1044
  for (const [f, key] of KEY_MAP) {
942
1045
  if (f === field) {
@@ -986,6 +1089,7 @@ function SettingsPicker({
986
1089
  debugStream,
987
1090
  statuslineMode,
988
1091
  configScope,
1092
+ animationStyle,
989
1093
  hint
990
1094
  }) {
991
1095
  const boolVal = (v) => v ? "on" : "off";
@@ -1183,6 +1287,11 @@ function SettingsPicker({
1183
1287
  label: "Config scope",
1184
1288
  value: configScope,
1185
1289
  detail: "global (~/.wrongstack/) or project (.wrongstack/)"
1290
+ },
1291
+ {
1292
+ label: "Animation",
1293
+ value: animationStyle,
1294
+ detail: formatAnimationStyle(animationStyle)
1186
1295
  }
1187
1296
  ];
1188
1297
  const fieldRowIndex = [];
@@ -1969,6 +2078,7 @@ function reducer(state, action) {
1969
2078
  buffer: "",
1970
2079
  cursor: 0,
1971
2080
  historyIndex: 0,
2081
+ historyDraft: "",
1972
2082
  picker: { open: false, query: "", matches: [], selected: 0 },
1973
2083
  slashPicker: { open: false, query: "", matches: [], selected: 0 }
1974
2084
  };
@@ -2160,13 +2270,34 @@ function reducer(state, action) {
2160
2270
  if (state.inputHistory.length === 0) return state;
2161
2271
  const next = Math.min(state.historyIndex + 1, state.inputHistory.length);
2162
2272
  const entry = state.inputHistory[next - 1] ?? "";
2163
- return { ...state, historyIndex: next, buffer: entry, cursor: entry.length };
2273
+ const historyDraft = state.historyIndex === 0 ? state.buffer : state.historyDraft;
2274
+ return {
2275
+ ...state,
2276
+ historyIndex: next,
2277
+ buffer: entry,
2278
+ cursor: entry.length,
2279
+ historyDraft
2280
+ };
2164
2281
  }
2165
2282
  case "historyDown": {
2166
2283
  if (state.historyIndex === 0) return state;
2167
2284
  const next = state.historyIndex - 1;
2168
- const entry = next === 0 ? "" : state.inputHistory[next - 1] ?? "";
2169
- return { ...state, historyIndex: next, buffer: entry, cursor: entry.length };
2285
+ const entry = next === 0 ? state.historyDraft : state.inputHistory[next - 1] ?? "";
2286
+ return {
2287
+ ...state,
2288
+ historyIndex: next,
2289
+ buffer: entry,
2290
+ cursor: entry.length,
2291
+ // Clear the draft snapshot once we're back at the buffer; the next
2292
+ // Up will capture whatever the user has typed by then.
2293
+ historyDraft: next === 0 ? "" : state.historyDraft
2294
+ };
2295
+ }
2296
+ case "setInputHistory": {
2297
+ return { ...state, inputHistory: action.entries.slice(0, 100) };
2298
+ }
2299
+ case "clearInputHistory": {
2300
+ return { ...state, inputHistory: [], historyIndex: 0, historyDraft: "" };
2170
2301
  }
2171
2302
  case "modelPickerOpen":
2172
2303
  return {
@@ -2458,6 +2589,7 @@ function reducer(state, action) {
2458
2589
  filter: "",
2459
2590
  cacheTtl: action.cacheTtl,
2460
2591
  configScope: action.configScope,
2592
+ animationStyle: action.animationStyle,
2461
2593
  hint: void 0
2462
2594
  }
2463
2595
  };
@@ -2815,6 +2947,19 @@ function reducer(state, action) {
2815
2947
  }
2816
2948
  };
2817
2949
  }
2950
+ if (f === 36) {
2951
+ const i = ANIMATION_STYLE_CHOICES.indexOf(sp.animationStyle);
2952
+ const base = i < 0 ? 0 : i;
2953
+ const next = (base + action.delta + ANIMATION_STYLE_CHOICES.length) % ANIMATION_STYLE_CHOICES.length;
2954
+ return {
2955
+ ...state,
2956
+ settingsPicker: {
2957
+ ...sp,
2958
+ animationStyle: expectDefined$1(ANIMATION_STYLE_CHOICES[next]),
2959
+ hint: void 0
2960
+ }
2961
+ };
2962
+ }
2818
2963
  return state;
2819
2964
  }
2820
2965
  case "settingsValueSet": {
@@ -3902,6 +4047,7 @@ function StatusBar({
3902
4047
  version,
3903
4048
  state,
3904
4049
  thinkingWord,
4050
+ thinkingAnimationStyle,
3905
4051
  tokenCounter,
3906
4052
  hint,
3907
4053
  queueCount = 0,
@@ -3980,14 +4126,31 @@ function StatusBar({
3980
4126
  return () => clearInterval(t);
3981
4127
  }, [state]);
3982
4128
  const spinner = expectDefined$1(SPINNER_FRAMES[spinnerIdx]);
3983
- const { label: stateLabel, color: stateColor } = stateChip(state, fleet?.running ?? 0, thinkingWord);
4129
+ const animationStyle = thinkingAnimationStyle ?? "rainbow";
4130
+ const [cycleTick, setCycleTick] = useState(0);
4131
+ useEffect(() => {
4132
+ if (animationStyle !== "cycle") return;
4133
+ if (state === "idle" || state === "aborting") return;
4134
+ const t = setInterval(() => setCycleTick((n) => n + 1), CYCLE_TICK_INTERVAL_MS);
4135
+ return () => clearInterval(t);
4136
+ }, [animationStyle, state]);
4137
+ const { label: stateLabel, color: stateColor } = stateChip(
4138
+ state,
4139
+ fleet?.running ?? 0,
4140
+ thinkingWord
4141
+ );
3984
4142
  const statePrefix = state === "idle" || state === "aborting" ? "\u25CF" : spinner;
3985
4143
  const thinking = state === "running" || state === "streaming";
3986
4144
  const hasAutoProceed = autoProceedCountdown != null && autoProceedCountdown > 0;
3987
- const hasSecondLine = yolo && showChip("yolo") || autonomy && autonomy !== "off" && showChip("autonomy") || eternalStage != null && showChip("eternal_stage") || startedAt != null && showChip("elapsed") || git !== null && git !== void 0 && showChip("git") || projectName !== void 0 && projectName.length > 0 && showChip("project") || workingDir !== void 0 && workingDir.length > 0 && showChip("working_dir") || goalSummary !== null && goalSummary !== void 0 && showChip("goal") || !!modeLabel && showChip("mode") || hasAutoProceed && showChip("auto_proceed") || tokenSavingMode && showChip("token_saving") || typeof toolCount === "number" && toolCount > 0 && showChip("tools") || sessionCount != null && sessionCount > 0 && showChip("sessions");
4145
+ const hasSecondLine = yolo && showChip("yolo") || autonomy && autonomy !== "off" && showChip("autonomy") || eternalStage != null && showChip("eternal_stage") || startedAt != null && showChip("elapsed") || git !== null && git !== void 0 && showChip("git") || projectName !== void 0 && projectName.length > 0 && showChip("project") || workingDir !== void 0 && workingDir.length > 0 && showChip("working_dir") || goalSummary !== null && goalSummary !== void 0 && showChip("goal") || !!modeLabel && showChip("mode") || hasAutoProceed && showChip("auto_proceed") || tokenSavingMode !== void 0 && tokenSavingMode !== "off" && showChip("token_saving") || typeof toolCount === "number" && toolCount > 0 && showChip("tools") || sessionCount != null && sessionCount > 0 && showChip("sessions");
3988
4146
  const fleetHasActivity = fleet && (fleet.running > 0 || fleet.idle > 0 || fleet.pending > 0 || fleet.completed > 0) || subagentCount > 0;
3989
4147
  const showBrain = isStreamChipVisible("brain", brain, hiddenSet, visibleChips);
3990
- const showDebugStream = isStreamChipVisible("debug_stream", debugStreamStats, hiddenSet, visibleChips);
4148
+ const showDebugStream = isStreamChipVisible(
4149
+ "debug_stream",
4150
+ debugStreamStats,
4151
+ hiddenSet,
4152
+ visibleChips
4153
+ );
3991
4154
  const showEnhance = isStreamChipVisible("enhance", enhanceCountdown, hiddenSet, visibleChips);
3992
4155
  const showMailbox = showChip("mailbox") && hasMailboxActivity(mailbox);
3993
4156
  const hasNextStepsAutoSubmit = nextStepsAutoSubmitCountdown != null && nextStepsAutoSubmitCountdown > 0;
@@ -4025,7 +4188,15 @@ function StatusBar({
4025
4188
  ] })
4026
4189
  ] }) : null,
4027
4190
  version && showChip("version") && (showChip("state") || showChip("model")) ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
4028
- showChip("state") && thinking ? /* @__PURE__ */ jsx(WaveText, { text: `${statePrefix} ${stateLabel}`, phase: spinnerIdx }) : showChip("state") ? /* @__PURE__ */ jsxs(Text, { color: stateColor, children: [
4191
+ showChip("state") && thinking ? /* @__PURE__ */ jsx(
4192
+ ThinkingChip,
4193
+ {
4194
+ text: `${statePrefix} ${stateLabel}`,
4195
+ style: thinkingAnimationStyle ?? "rainbow",
4196
+ phase: spinnerIdx,
4197
+ cycleTick
4198
+ }
4199
+ ) : showChip("state") ? /* @__PURE__ */ jsxs(Text, { color: stateColor, children: [
4029
4200
  statePrefix,
4030
4201
  " ",
4031
4202
  stateLabel
@@ -4034,12 +4205,18 @@ function StatusBar({
4034
4205
  showChip("model") ? /* @__PURE__ */ jsx(Text, { color: "magenta", children: model }) : null,
4035
4206
  ctxClampedRatio !== void 0 && ctxPctText && ctxMax !== void 0 && showChip("context") ? /* @__PURE__ */ jsxs(Fragment, { children: [
4036
4207
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
4037
- /* @__PURE__ */ jsxs(Text, { color: ctxClampedRatio < 0.6 ? "green" : ctxClampedRatio < 0.75 ? "yellow" : "red", children: [
4038
- "ctx ",
4039
- ctxPctText,
4040
- "/",
4041
- fmtTok(ctxMax)
4042
- ] })
4208
+ /* @__PURE__ */ jsxs(
4209
+ Text,
4210
+ {
4211
+ color: ctxClampedRatio < 0.6 ? "green" : ctxClampedRatio < 0.75 ? "yellow" : "red",
4212
+ children: [
4213
+ "ctx ",
4214
+ ctxPctText,
4215
+ "/",
4216
+ fmtTok(ctxMax)
4217
+ ]
4218
+ }
4219
+ )
4043
4220
  ] }) : null,
4044
4221
  showTokenDisplay && showChip("tokens") ? /* @__PURE__ */ jsxs(Fragment, { children: [
4045
4222
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
@@ -4080,7 +4257,15 @@ function StatusBar({
4080
4257
  /* @__PURE__ */ jsx(Box, { flexDirection: "row", gap: 2, children: isCompact ? (
4081
4258
  // Ultra-compact: state · model
4082
4259
  /* @__PURE__ */ jsxs(Fragment, { children: [
4083
- showChip("state") && thinking ? /* @__PURE__ */ jsx(WaveText, { text: `${statePrefix}${stateLabel}`, phase: spinnerIdx }) : showChip("state") ? /* @__PURE__ */ jsxs(Text, { color: stateColor, children: [
4260
+ showChip("state") && thinking ? /* @__PURE__ */ jsx(
4261
+ ThinkingChip,
4262
+ {
4263
+ text: `${statePrefix}${stateLabel}`,
4264
+ style: animationStyle,
4265
+ phase: spinnerIdx,
4266
+ cycleTick
4267
+ }
4268
+ ) : showChip("state") ? /* @__PURE__ */ jsxs(Text, { color: stateColor, children: [
4084
4269
  statePrefix,
4085
4270
  stateLabel
4086
4271
  ] }) : null,
@@ -4100,7 +4285,15 @@ function StatusBar({
4100
4285
  ] }),
4101
4286
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" })
4102
4287
  ] }) : null,
4103
- showChip("state") && thinking ? /* @__PURE__ */ jsx(WaveText, { text: `${statePrefix} ${stateLabel}`, phase: spinnerIdx }) : showChip("state") ? /* @__PURE__ */ jsxs(Text, { color: stateColor, children: [
4288
+ showChip("state") && thinking ? /* @__PURE__ */ jsx(
4289
+ ThinkingChip,
4290
+ {
4291
+ text: `${statePrefix} ${stateLabel}`,
4292
+ style: animationStyle,
4293
+ phase: spinnerIdx,
4294
+ cycleTick
4295
+ }
4296
+ ) : showChip("state") ? /* @__PURE__ */ jsxs(Text, { color: stateColor, children: [
4104
4297
  statePrefix,
4105
4298
  " ",
4106
4299
  stateLabel
@@ -4115,19 +4308,25 @@ function StatusBar({
4115
4308
  const ratio = context.used / context.max;
4116
4309
  const clampedRatio = Math.min(ratio, 1);
4117
4310
  const pctText = `${Math.min(Math.round(ratio * 100), 100)}%`;
4118
- return /* @__PURE__ */ jsxs(Text, { color: clampedRatio < 0.6 ? "green" : clampedRatio < 0.75 ? "yellow" : "red", children: [
4119
- "ctx ",
4120
- renderMeter(clampedRatio, 8),
4121
- " ",
4122
- pctText,
4123
- "/",
4124
- fmtTok(context.max),
4125
- contextStrategy ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
4126
- " [",
4127
- contextStrategy,
4128
- "]"
4129
- ] }) : null
4130
- ] });
4311
+ return /* @__PURE__ */ jsxs(
4312
+ Text,
4313
+ {
4314
+ color: clampedRatio < 0.6 ? "green" : clampedRatio < 0.75 ? "yellow" : "red",
4315
+ children: [
4316
+ "ctx ",
4317
+ renderMeter(clampedRatio, 8),
4318
+ " ",
4319
+ pctText,
4320
+ "/",
4321
+ fmtTok(context.max),
4322
+ contextStrategy ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
4323
+ " [",
4324
+ contextStrategy,
4325
+ "]"
4326
+ ] }) : null
4327
+ ]
4328
+ }
4329
+ );
4131
4330
  })()
4132
4331
  ] }) : null,
4133
4332
  showTokenDisplay && showChip("tokens") ? /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -4248,11 +4447,17 @@ function StatusBar({
4248
4447
  }
4249
4448
  ) : null,
4250
4449
  modeLabel && showChip("mode") ? /* @__PURE__ */ jsx(Text, { color: "cyan", children: modeIcon(modeLabel) }) : null,
4251
- hasAutoProceed && showChip("auto_proceed") ? /* @__PURE__ */ jsxs(Text, { color: autoProceedCountdown != null && autoProceedCountdown <= 5 ? "yellow" : "cyan", children: [
4252
- "\u23F3 auto in ",
4253
- autoProceedCountdown,
4254
- "s"
4255
- ] }) : null,
4450
+ hasAutoProceed && showChip("auto_proceed") ? /* @__PURE__ */ jsxs(
4451
+ Text,
4452
+ {
4453
+ color: autoProceedCountdown != null && autoProceedCountdown <= 5 ? "yellow" : "cyan",
4454
+ children: [
4455
+ "\u23F3 auto in ",
4456
+ autoProceedCountdown,
4457
+ "s"
4458
+ ]
4459
+ }
4460
+ ) : null,
4256
4461
  git && showChip("git") ? /* @__PURE__ */ jsxs(Text, { children: [
4257
4462
  /* @__PURE__ */ jsxs(Text, { color: "magenta", children: [
4258
4463
  "\u2387 ",
@@ -4279,7 +4484,10 @@ function StatusBar({
4279
4484
  " tool",
4280
4485
  toolCount === 1 ? "" : "s"
4281
4486
  ] }) : null,
4282
- tokenSavingMode && showChip("token_saving") ? /* @__PURE__ */ jsx(Text, { color: "yellow", bold: true, children: "\u{1F4BE} save" }) : null,
4487
+ tokenSavingMode !== void 0 && tokenSavingMode !== "off" && showChip("token_saving") ? /* @__PURE__ */ jsxs(Text, { color: "yellow", bold: true, children: [
4488
+ "\u{1F4BE} ",
4489
+ tokenSavingMode
4490
+ ] }) : null,
4283
4491
  sideEffectCount > 0 ? /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
4284
4492
  "\u26A0 ",
4285
4493
  sideEffectCount,
@@ -4446,15 +4654,18 @@ function StatusBar({
4446
4654
  mailbox.onlineAgents === 1 ? "" : "s",
4447
4655
  mailbox.onlineClients.tui + mailbox.onlineClients.webui + mailbox.onlineClients.repl > 0 ? /* @__PURE__ */ jsxs(Text, { color: "green", children: [
4448
4656
  mailbox.onlineClients.tui > 0 ? /* @__PURE__ */ jsxs(Text, { color: "green", children: [
4449
- " \xB7 \u{1F5A5} TUI",
4657
+ " ",
4658
+ "\xB7 \u{1F5A5} TUI",
4450
4659
  mailbox.onlineClients.tui > 1 ? `\xD7${mailbox.onlineClients.tui}` : ""
4451
4660
  ] }) : null,
4452
4661
  mailbox.onlineClients.webui > 0 ? /* @__PURE__ */ jsxs(Text, { color: "green", children: [
4453
- " \xB7 \u{1F310} WebUI",
4662
+ " ",
4663
+ "\xB7 \u{1F310} WebUI",
4454
4664
  mailbox.onlineClients.webui > 1 ? `\xD7${mailbox.onlineClients.webui}` : ""
4455
4665
  ] }) : null,
4456
4666
  mailbox.onlineClients.repl > 0 ? /* @__PURE__ */ jsxs(Text, { color: "green", children: [
4457
- " \xB7 \u2328 REPL",
4667
+ " ",
4668
+ "\xB7 \u2328 REPL",
4458
4669
  mailbox.onlineClients.repl > 1 ? `\xD7${mailbox.onlineClients.repl}` : ""
4459
4670
  ] }) : null
4460
4671
  ] }) : null
@@ -4628,35 +4839,6 @@ function stateChip(state, fleetRunning, thinkingWord) {
4628
4839
  if (state === "aborting") return { label: "aborting\u2026", color: "yellow" };
4629
4840
  return { label: `${normalizeTuiThinkingWord(thinkingWord)}\u2026`, color: "green" };
4630
4841
  }
4631
- var WAVE_COLORS = [
4632
- "#f38ba8",
4633
- // red
4634
- "#eba0ac",
4635
- // maroon
4636
- "#fab387",
4637
- // peach
4638
- "#f9e2af",
4639
- // yellow
4640
- "#a6e3a1",
4641
- // green
4642
- "#94e2d5",
4643
- // teal
4644
- "#89dceb",
4645
- // sky
4646
- "#89b4fa",
4647
- // blue
4648
- "#b4befe",
4649
- // lavender
4650
- "#cba6f7",
4651
- // mauve
4652
- "#f5c2e7",
4653
- // pink
4654
- "#f2cdcd"
4655
- // flamingo
4656
- ];
4657
- function WaveText({ text, phase }) {
4658
- return /* @__PURE__ */ jsx(Text, { bold: true, children: Array.from(text).map((ch, i) => /* @__PURE__ */ jsx(Text, { color: WAVE_COLORS[(i + phase) % WAVE_COLORS.length] ?? "#ffffff", children: ch }, i)) });
4659
- }
4660
4842
  var FILLED = "\u2588";
4661
4843
  var EMPTY = "\u2591";
4662
4844
  function renderProgress(ratio, width) {
@@ -4706,6 +4888,40 @@ function fmtDebugBytes(n) {
4706
4888
  function pad2(n) {
4707
4889
  return n < 10 ? `0${n}` : String(n);
4708
4890
  }
4891
+ function ThinkingChip({
4892
+ text,
4893
+ style,
4894
+ phase,
4895
+ cycleTick
4896
+ }) {
4897
+ const live = style === "cycle" ? styleForCycleTick(cycleTick) : style;
4898
+ if (live === "rainbow") {
4899
+ return /* @__PURE__ */ jsx(Text, { bold: true, children: Array.from(text).map((ch, i) => /* @__PURE__ */ jsx(Text, { color: HUE_WHEEL[(i + phase) % HUE_WHEEL.length] ?? "#ffffff", children: ch }, i)) });
4900
+ }
4901
+ if (live === "wave") {
4902
+ const len = Array.from(text).length;
4903
+ return /* @__PURE__ */ jsx(Text, { bold: true, children: Array.from(text).map((ch, i) => /* @__PURE__ */ jsx(Text, { color: waveColor(i, phase, len), children: ch }, i)) });
4904
+ }
4905
+ if (live === "pulse") {
4906
+ return /* @__PURE__ */ jsx(Text, { bold: true, color: pulseColor(phase), children: text });
4907
+ }
4908
+ if (live === "dots") {
4909
+ const stripped = stripTrailingDots(text);
4910
+ const idx2 = phase % DOTS_FRAMES.length;
4911
+ const suffix = DOTS_FRAMES[idx2] ?? "";
4912
+ return /* @__PURE__ */ jsxs(Text, { bold: true, color: "green", children: [
4913
+ stripped,
4914
+ suffix ? ` ${suffix}` : ""
4915
+ ] });
4916
+ }
4917
+ const idx = phase % BREATHE_FRAMES.length;
4918
+ const prefix = BREATHE_FRAMES[idx] ?? "\u280B";
4919
+ return /* @__PURE__ */ jsxs(Text, { bold: true, color: "green", children: [
4920
+ prefix,
4921
+ " ",
4922
+ text
4923
+ ] });
4924
+ }
4709
4925
  function shortSessionId(sessionId) {
4710
4926
  const leaf = sessionId.split("/").pop() ?? sessionId;
4711
4927
  return leaf.length > 12 ? `${leaf.slice(0, 12)}\u2026` : leaf;
@@ -6330,7 +6546,12 @@ function formatToolArgs(toolName, input) {
6330
6546
  const filter = stringOf(obj["filter"]);
6331
6547
  const since = stringOf(obj["since"]);
6332
6548
  const lines = typeof obj["lines"] === "number" ? `${obj["lines"]} lines` : "";
6333
- return [target ? shortenPath(target, 34) : "", filter ? `/${truncMid(filter, 16)}/` : "", since, lines].filter(Boolean).join(" \xB7 ");
6549
+ return [
6550
+ target ? shortenPath(target, 34) : "",
6551
+ filter ? `/${truncMid(filter, 16)}/` : "",
6552
+ since,
6553
+ lines
6554
+ ].filter(Boolean).join(" \xB7 ");
6334
6555
  }
6335
6556
  case "tool_help": {
6336
6557
  const tool = stringOf(obj["tool"]) ?? "all";
@@ -6364,7 +6585,11 @@ function formatToolArgs(toolName, input) {
6364
6585
  }
6365
6586
  case "codebase-search": {
6366
6587
  const query = stringOf(obj["query"]);
6367
- const filters = [stringOf(obj["kind"]), stringOf(obj["lang"]), stringOf(obj["file"]) ? `in ${shortenPath(String(obj["file"]), 24)}` : ""].filter(Boolean).join(" \xB7 ");
6588
+ const filters = [
6589
+ stringOf(obj["kind"]),
6590
+ stringOf(obj["lang"]),
6591
+ stringOf(obj["file"]) ? `in ${shortenPath(String(obj["file"]), 24)}` : ""
6592
+ ].filter(Boolean).join(" \xB7 ");
6368
6593
  return [query ? `"${truncMid(query, 30)}"` : "", filters].filter(Boolean).join(" \xB7 ");
6369
6594
  }
6370
6595
  case "codebase-stats":
@@ -6465,7 +6690,9 @@ function formatToolOutput(toolName, output, ok, _outputBytes, outputLines) {
6465
6690
  const files = numOf(o["files_modified"]);
6466
6691
  const reps = numOf(o["total_replacements"]);
6467
6692
  if (files !== void 0 && reps !== void 0) {
6468
- return [`${reps} replacement${reps === 1 ? "" : "s"} in ${files} file${files === 1 ? "" : "s"}`];
6693
+ return [
6694
+ `${reps} replacement${reps === 1 ? "" : "s"} in ${files} file${files === 1 ? "" : "s"}`
6695
+ ];
6469
6696
  }
6470
6697
  }
6471
6698
  if (toolName === "diff" && json && typeof json === "object") {
@@ -6817,8 +7044,10 @@ function formatToolVisualOutput(toolName, output, ok, input) {
6817
7044
  }
6818
7045
  if (toolName === "logs") return visualLogs(text);
6819
7046
  if (toolName === "document") return visualDocument(text);
6820
- if (toolName === "tool_help" || toolName === "tool_search") return visualToolCatalog(toolName, text);
6821
- if (toolName === "tool_use" || toolName === "batch_tool_use") return visualMetaExecution(toolName, text, ok);
7047
+ if (toolName === "tool_help" || toolName === "tool_search")
7048
+ return visualToolCatalog(toolName, text);
7049
+ if (toolName === "tool_use" || toolName === "batch_tool_use")
7050
+ return visualMetaExecution(toolName, text, ok);
6822
7051
  if (toolName === "codebase-index" || toolName === "codebase-search" || toolName === "codebase-stats") {
6823
7052
  return visualCodebase(toolName, text, ok);
6824
7053
  }
@@ -6826,7 +7055,10 @@ function formatToolVisualOutput(toolName, output, ok, input) {
6826
7055
  if (toolName === "mode") return visualMode(text, ok);
6827
7056
  return void 0;
6828
7057
  }
6829
- function ToolOutputLines({ lines, hasFollowingBlock }) {
7058
+ function ToolOutputLines({
7059
+ lines,
7060
+ hasFollowingBlock
7061
+ }) {
6830
7062
  return /* @__PURE__ */ jsx(Fragment, { children: lines.map((line, i) => {
6831
7063
  const branch = i === lines.length - 1 && !hasFollowingBlock ? " \u2514\u2500 " : " \u251C\u2500 ";
6832
7064
  const color = colorForVisualKind(line.kind);
@@ -6924,13 +7156,21 @@ function visualRead(text) {
6924
7156
  const first = firstNonEmpty(lines.join("\n"));
6925
7157
  return first ? [{ kind: "meta", text: first }] : void 0;
6926
7158
  }
6927
- const rows = numbered.slice(0, 5).map((match) => ({
7159
+ const rows = numbered.slice(0, 10).map((match) => ({
6928
7160
  kind: "code",
6929
7161
  lineNo: match[1],
6930
7162
  text: match[2] ?? ""
6931
7163
  }));
6932
- if (numbered.length > rows.length) {
6933
- rows.push({ kind: "meta", text: `${numbered.length - rows.length} more read line(s)` });
7164
+ if (numbered.length > 10) {
7165
+ const extra = numbered.slice(10, 15).map((match) => ({
7166
+ kind: "code",
7167
+ lineNo: match[1],
7168
+ text: match[2] ?? ""
7169
+ }));
7170
+ rows.push(...extra);
7171
+ if (numbered.length > 15) {
7172
+ rows.push({ kind: "meta", text: `more ${numbered.length - 15} line(s)` });
7173
+ }
6934
7174
  }
6935
7175
  return rows;
6936
7176
  }
@@ -6968,7 +7208,8 @@ function visualSearch(toolName, text) {
6968
7208
  consumed++;
6969
7209
  }
6970
7210
  }
6971
- if (lines.length > consumed) rows.push({ kind: "meta", text: `${lines.length - consumed} more result line(s)` });
7211
+ if (lines.length > consumed)
7212
+ rows.push({ kind: "meta", text: `${lines.length - consumed} more result line(s)` });
6972
7213
  return rows.length > 0 ? rows : void 0;
6973
7214
  }
6974
7215
  function visualSearchMatches(matches, count) {
@@ -6978,8 +7219,10 @@ function visualSearchMatches(matches, count) {
6978
7219
  const hit = parseMatchHit(match);
6979
7220
  if (hit) rows.push({ kind: "match", path: hit.path, lineNo: hit.line, text: hit.text });
6980
7221
  }
6981
- if (rows.length === 0) return count > 0 ? [{ kind: "meta", text: `${count} result${count === 1 ? "" : "s"}` }] : void 0;
6982
- if (count > rows.length) rows.push({ kind: "meta", text: `${count - rows.length} more result(s)` });
7222
+ if (rows.length === 0)
7223
+ return count > 0 ? [{ kind: "meta", text: `${count} result${count === 1 ? "" : "s"}` }] : void 0;
7224
+ if (count > rows.length)
7225
+ rows.push({ kind: "meta", text: `${count - rows.length} more result(s)` });
6983
7226
  return rows;
6984
7227
  }
6985
7228
  function parseMatchHit(hit) {
@@ -7000,24 +7243,32 @@ function parseMatchHit(hit) {
7000
7243
  }
7001
7244
  function visualPathList(toolName, text) {
7002
7245
  const json = tryParseJson(text);
7003
- const files = json && typeof json === "object" && Array.isArray(json["files"]) ? json["files"].filter((v) => typeof v === "string") : bodyLines(text).filter((line) => line.trim() && !line.startsWith(`${toolName}:`));
7246
+ const files = json && typeof json === "object" && Array.isArray(json["files"]) ? json["files"].filter(
7247
+ (v) => typeof v === "string"
7248
+ ) : bodyLines(text).filter((line) => line.trim() && !line.startsWith(`${toolName}:`));
7004
7249
  if (files.length === 0) return void 0;
7005
- const rows = files.slice(0, VISUAL_MAX_LINES).map((file) => ({
7006
- kind: "path",
7007
- path: file,
7008
- text: ""
7009
- }));
7010
- if (files.length > rows.length) rows.push({ kind: "meta", text: `${files.length - rows.length} more path(s)` });
7250
+ const rows = files.slice(0, VISUAL_MAX_LINES).map(
7251
+ (file) => ({
7252
+ kind: "path",
7253
+ path: file,
7254
+ text: ""
7255
+ })
7256
+ );
7257
+ if (files.length > rows.length)
7258
+ rows.push({ kind: "meta", text: `${files.length - rows.length} more path(s)` });
7011
7259
  return rows;
7012
7260
  }
7013
7261
  function visualTree(text) {
7014
7262
  const lines = bodyLines(text).filter((line) => line.trim());
7015
7263
  if (lines.length === 0) return void 0;
7016
- const rows = lines.slice(0, VISUAL_MAX_LINES).map((line) => ({
7017
- kind: line.includes("\u2500\u2500") || line.includes("|--") ? "path" : "meta",
7018
- text: line
7019
- }));
7020
- if (lines.length > rows.length) rows.push({ kind: "meta", text: `${lines.length - rows.length} more tree line(s)` });
7264
+ const rows = lines.slice(0, VISUAL_MAX_LINES).map(
7265
+ (line) => ({
7266
+ kind: line.includes("\u2500\u2500") || line.includes("|--") ? "path" : "meta",
7267
+ text: line
7268
+ })
7269
+ );
7270
+ if (lines.length > rows.length)
7271
+ rows.push({ kind: "meta", text: `${lines.length - rows.length} more tree line(s)` });
7021
7272
  return rows;
7022
7273
  }
7023
7274
  function visualCommand(toolName, text, ok) {
@@ -7047,7 +7298,11 @@ function commandRows(opts) {
7047
7298
  const rows = [];
7048
7299
  const statusKind = opts.timedOut ? "warn" : opts.ok && (opts.exit ?? 0) === 0 ? "ok" : "error";
7049
7300
  const status = opts.timedOut ? "timed out" : opts.exit !== void 0 ? `exit ${opts.exit}` : opts.ok ? "completed" : "failed";
7050
- rows.push({ kind: statusKind, marker: statusKind === "ok" ? "ok " : statusKind === "warn" ? "! " : "x ", text: opts.label ? `${opts.label} ${status}` : status });
7301
+ rows.push({
7302
+ kind: statusKind,
7303
+ marker: statusKind === "ok" ? "ok " : statusKind === "warn" ? "! " : "x ",
7304
+ text: opts.label ? `${opts.label} ${status}` : status
7305
+ });
7051
7306
  appendOutputPreview(rows, opts.stdout, "stdout");
7052
7307
  appendOutputPreview(rows, opts.stderr, "stderr");
7053
7308
  return rows.length > 0 ? rows.slice(0, VISUAL_MAX_LINES) : void 0;
@@ -7067,7 +7322,13 @@ function visualVerifier(toolName, text, ok) {
7067
7322
  changed2 > 0 ? `${changed2} changed` : void 0,
7068
7323
  toolName === "test" ? `${numOf(obj["passed"]) ?? 0}/${numOf(obj["tests_run"]) ?? 0} passed` : void 0
7069
7324
  ].filter(Boolean);
7070
- return [{ kind: statusKind2, marker: statusKind2 === "ok" ? "ok " : statusKind2 === "warn" ? "! " : "x ", text: parts.join(" \xB7 ") || toolName }];
7325
+ return [
7326
+ {
7327
+ kind: statusKind2,
7328
+ marker: statusKind2 === "ok" ? "ok " : statusKind2 === "warn" ? "! " : "x ",
7329
+ text: parts.join(" \xB7 ") || toolName
7330
+ }
7331
+ ];
7071
7332
  }
7072
7333
  const header = parseHeaderLine(text);
7073
7334
  const sections = parseNamedSections(text);
@@ -7079,17 +7340,19 @@ function visualVerifier(toolName, text, ok) {
7079
7340
  const warningCount = numberFromParsedField(fields, "warnings") ?? 0;
7080
7341
  const changed = numberFromParsedField(fields, "files_changed") ?? 0;
7081
7342
  const statusKind = !ok || errorContext || errorCount > 0 ? "error" : status === "changed" || changed > 0 ? "warn" : "ok";
7082
- const rows = [{
7083
- kind: statusKind,
7084
- marker: statusKind === "ok" ? "ok " : statusKind === "warn" ? "! " : "x ",
7085
- text: [
7086
- toolName,
7087
- status ? `status=${status}` : void 0,
7088
- errorCount > 0 ? `${errorCount} error${errorCount === 1 ? "" : "s"}` : void 0,
7089
- warningCount > 0 ? `${warningCount} warning${warningCount === 1 ? "" : "s"}` : void 0,
7090
- changed > 0 ? `${changed} changed` : void 0
7091
- ].filter(Boolean).join(" \xB7 ")
7092
- }];
7343
+ const rows = [
7344
+ {
7345
+ kind: statusKind,
7346
+ marker: statusKind === "ok" ? "ok " : statusKind === "warn" ? "! " : "x ",
7347
+ text: [
7348
+ toolName,
7349
+ status ? `status=${status}` : void 0,
7350
+ errorCount > 0 ? `${errorCount} error${errorCount === 1 ? "" : "s"}` : void 0,
7351
+ warningCount > 0 ? `${warningCount} warning${warningCount === 1 ? "" : "s"}` : void 0,
7352
+ changed > 0 ? `${changed} changed` : void 0
7353
+ ].filter(Boolean).join(" \xB7 ")
7354
+ }
7355
+ ];
7093
7356
  appendOutputPreview(rows, errorContext, "stderr");
7094
7357
  return rows.slice(0, VISUAL_MAX_LINES);
7095
7358
  }
@@ -7111,11 +7374,13 @@ function visualFetch(text) {
7111
7374
  }
7112
7375
  function fetchRows(status, contentType, content) {
7113
7376
  const kind = status === void 0 ? "meta" : status >= 200 && status < 300 ? "ok" : status >= 300 && status < 400 ? "warn" : "error";
7114
- const rows = [{
7115
- kind,
7116
- marker: kind === "ok" ? "ok " : kind === "warn" ? "! " : kind === "error" ? "x " : void 0,
7117
- text: [status !== void 0 ? `HTTP ${status}` : "HTTP", contentType?.split(";")[0]].filter(Boolean).join(" \xB7 ")
7118
- }];
7377
+ const rows = [
7378
+ {
7379
+ kind,
7380
+ marker: kind === "ok" ? "ok " : kind === "warn" ? "! " : kind === "error" ? "x " : void 0,
7381
+ text: [status !== void 0 ? `HTTP ${status}` : "HTTP", contentType?.split(";")[0]].filter(Boolean).join(" \xB7 ")
7382
+ }
7383
+ ];
7119
7384
  const preview = firstNonEmpty(content ?? "");
7120
7385
  if (preview) rows.push({ kind: "stdout", text: preview });
7121
7386
  return rows;
@@ -7128,7 +7393,13 @@ function visualJson(text) {
7128
7393
  if (err) return [{ kind: "error", marker: "x ", text: err }];
7129
7394
  const type = stringOf(obj["type"]);
7130
7395
  const keys = Array.isArray(obj["keys"]) ? obj["keys"].length : void 0;
7131
- return [{ kind: "ok", marker: "ok ", text: [type ?? "json", keys !== void 0 ? `${keys} key${keys === 1 ? "" : "s"}` : void 0].filter(Boolean).join(" \xB7 ") }];
7396
+ return [
7397
+ {
7398
+ kind: "ok",
7399
+ marker: "ok ",
7400
+ text: [type ?? "json", keys !== void 0 ? `${keys} key${keys === 1 ? "" : "s"}` : void 0].filter(Boolean).join(" \xB7 ")
7401
+ }
7402
+ ];
7132
7403
  }
7133
7404
  function visualOutdated(text) {
7134
7405
  const lines = bodyLines(text).filter((line) => line.trim() && !line.startsWith("outdated"));
@@ -7138,11 +7409,13 @@ function visualOutdated(text) {
7138
7409
  function visualAudit(text) {
7139
7410
  const lines = bodyLines(text).filter((line) => line.trim() && !line.startsWith("audit"));
7140
7411
  if (lines.length === 0) return void 0;
7141
- return lines.slice(0, VISUAL_MAX_LINES).map((line) => ({
7142
- kind: /^critical|^high/i.test(line) ? "error" : /^moderate|^medium/i.test(line) ? "warn" : "meta",
7143
- marker: /^critical|^high/i.test(line) ? "x " : /^moderate|^medium/i.test(line) ? "! " : void 0,
7144
- text: line
7145
- }));
7412
+ return lines.slice(0, VISUAL_MAX_LINES).map(
7413
+ (line) => ({
7414
+ kind: /^critical|^high/i.test(line) ? "error" : /^moderate|^medium/i.test(line) ? "warn" : "meta",
7415
+ marker: /^critical|^high/i.test(line) ? "x " : /^moderate|^medium/i.test(line) ? "! " : void 0,
7416
+ text: line
7417
+ })
7418
+ );
7146
7419
  }
7147
7420
  function visualScaffold(text) {
7148
7421
  const json = tryParseJson(text);
@@ -7154,7 +7427,8 @@ function visualScaffold(text) {
7154
7427
  for (const file of created.slice(0, 5)) {
7155
7428
  if (typeof file === "string") rows.push({ kind: "ok", marker: "+ ", path: file, text: "" });
7156
7429
  }
7157
- if (skipped.length > 0) rows.push({ kind: "warn", marker: "! ", text: `${skipped.length} skipped` });
7430
+ if (skipped.length > 0)
7431
+ rows.push({ kind: "warn", marker: "! ", text: `${skipped.length} skipped` });
7158
7432
  return rows.length > 0 ? rows : void 0;
7159
7433
  }
7160
7434
  function visualTodo(text) {
@@ -7162,11 +7436,13 @@ function visualTodo(text) {
7162
7436
  const fields = json && typeof json === "object" && !Array.isArray(json) ? recordToStringFields(json) : parseHeaderLine(text).fields;
7163
7437
  const count = numberFromParsedField(fields, "count") ?? 0;
7164
7438
  const inProgress = numberFromParsedField(fields, "in_progress") ?? 0;
7165
- return [{
7166
- kind: count > 0 ? "ok" : "meta",
7167
- marker: count > 0 ? "ok " : void 0,
7168
- text: `${count} todo${count === 1 ? "" : "s"}${inProgress > 0 ? ` \xB7 ${inProgress} in progress` : ""}`
7169
- }];
7439
+ return [
7440
+ {
7441
+ kind: count > 0 ? "ok" : "meta",
7442
+ marker: count > 0 ? "ok " : void 0,
7443
+ text: `${count} todo${count === 1 ? "" : "s"}${inProgress > 0 ? ` \xB7 ${inProgress} in progress` : ""}`
7444
+ }
7445
+ ];
7170
7446
  }
7171
7447
  function visualWorkBoard(toolName, text, ok) {
7172
7448
  const json = tryParseJson(text);
@@ -7179,7 +7455,11 @@ function visualWorkBoard(toolName, text, ok) {
7179
7455
  for (const todo of todos.slice(0, 3)) {
7180
7456
  if (todo && typeof todo === "object") {
7181
7457
  const o = todo;
7182
- rows2.push({ kind: "path", marker: "+ ", text: stringOf(o["content"]) ?? stringOf(o["id"]) ?? "todo" });
7458
+ rows2.push({
7459
+ kind: "path",
7460
+ marker: "+ ",
7461
+ text: stringOf(o["content"]) ?? stringOf(o["id"]) ?? "todo"
7462
+ });
7183
7463
  }
7184
7464
  }
7185
7465
  return rows2.slice(0, VISUAL_MAX_LINES);
@@ -7187,7 +7467,10 @@ function visualWorkBoard(toolName, text, ok) {
7187
7467
  const header = parseHeaderLine(text);
7188
7468
  const sections = parseNamedSections(text);
7189
7469
  const rows = boardSummaryRows(toolName, header.fields, ok);
7190
- appendBoardPreview(rows, sections.get("message") ?? sections.get("plan") ?? bodyLines(text).join("\n"));
7470
+ appendBoardPreview(
7471
+ rows,
7472
+ sections.get("message") ?? sections.get("plan") ?? bodyLines(text).join("\n")
7473
+ );
7191
7474
  return rows.slice(0, VISUAL_MAX_LINES);
7192
7475
  }
7193
7476
  function boardSummaryRows(toolName, fields, ok) {
@@ -7203,17 +7486,22 @@ function boardSummaryRows(toolName, fields, ok) {
7203
7486
  completed !== void 0 ? `${completed} done` : void 0,
7204
7487
  inProgress !== void 0 && inProgress > 0 ? `${inProgress} in progress` : void 0
7205
7488
  ].filter(Boolean);
7206
- return [{
7207
- kind: success ? "ok" : "error",
7208
- marker: success ? "ok " : "x ",
7209
- text: parts.join(" \xB7 ") || toolName
7210
- }];
7489
+ return [
7490
+ {
7491
+ kind: success ? "ok" : "error",
7492
+ marker: success ? "ok " : "x ",
7493
+ text: parts.join(" \xB7 ") || toolName
7494
+ }
7495
+ ];
7211
7496
  }
7212
7497
  function appendBoardPreview(rows, text) {
7213
7498
  if (!text) return;
7214
7499
  const lines = text.split(/\r?\n/).map((line) => line.replace(/^[\s│├└─>*-]+/, "").trim()).filter((line) => line && !line.startsWith("{") && !line.startsWith("["));
7215
7500
  for (const line of lines.slice(0, 4)) {
7216
- rows.push({ kind: line.includes("failed") || line.includes("not configured") ? "error" : "meta", text: line });
7501
+ rows.push({
7502
+ kind: line.includes("failed") || line.includes("not configured") ? "error" : "meta",
7503
+ text: line
7504
+ });
7217
7505
  }
7218
7506
  }
7219
7507
  function visualMemory(toolName, text, ok) {
@@ -7246,7 +7534,11 @@ function memoryResultRows(results) {
7246
7534
  const parsed = tryParseJson(result);
7247
7535
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
7248
7536
  const o = parsed;
7249
- rows.push({ kind: "meta", marker: tagMarker(stringOf(o["priority"])), text: memoryText(o) });
7537
+ rows.push({
7538
+ kind: "meta",
7539
+ marker: tagMarker(stringOf(o["priority"])),
7540
+ text: memoryText(o)
7541
+ });
7250
7542
  } else {
7251
7543
  rows.push({ kind: "meta", text: result });
7252
7544
  }
@@ -7255,7 +7547,8 @@ function memoryResultRows(results) {
7255
7547
  rows.push({ kind: "meta", marker: tagMarker(stringOf(o["priority"])), text: memoryText(o) });
7256
7548
  }
7257
7549
  }
7258
- if (results.length > rows.length) rows.push({ kind: "meta", text: `${results.length - rows.length} more memory result(s)` });
7550
+ if (results.length > rows.length)
7551
+ rows.push({ kind: "meta", text: `${results.length - rows.length} more memory result(s)` });
7259
7552
  return rows;
7260
7553
  }
7261
7554
  function memoryText(o) {
@@ -7272,16 +7565,23 @@ function visualLogs(text) {
7272
7565
  const json = tryParseJson(text);
7273
7566
  if (json && typeof json === "object" && !Array.isArray(json)) {
7274
7567
  const obj = json;
7275
- const rows2 = [{
7276
- kind: "meta",
7277
- text: `${stringOf(obj["source"]) ?? "logs"} \xB7 ${numOf(obj["total"]) ?? 0} entries${obj["truncated"] === true ? " \xB7 truncated" : ""}`
7278
- }];
7568
+ const rows2 = [
7569
+ {
7570
+ kind: "meta",
7571
+ text: `${stringOf(obj["source"]) ?? "logs"} \xB7 ${numOf(obj["total"]) ?? 0} entries${obj["truncated"] === true ? " \xB7 truncated" : ""}`
7572
+ }
7573
+ ];
7279
7574
  const entries = Array.isArray(obj["entries"]) ? obj["entries"] : [];
7280
7575
  appendLogEntries(rows2, entries);
7281
7576
  return rows2;
7282
7577
  }
7283
7578
  const header = parseHeaderLine(text);
7284
- const rows = [{ kind: "meta", text: `${header.label}${header.fields["total"] ? ` \xB7 ${header.fields["total"]} entries` : ""}` }];
7579
+ const rows = [
7580
+ {
7581
+ kind: "meta",
7582
+ text: `${header.label}${header.fields["total"] ? ` \xB7 ${header.fields["total"]} entries` : ""}`
7583
+ }
7584
+ ];
7285
7585
  appendLogEntries(rows, bodyLines(text));
7286
7586
  return rows.slice(0, VISUAL_MAX_LINES);
7287
7587
  }
@@ -7291,10 +7591,20 @@ function appendLogEntries(rows, entries) {
7291
7591
  rows.push(logLine(entry));
7292
7592
  } else if (entry && typeof entry === "object") {
7293
7593
  const o = entry;
7294
- rows.push(logLine([stringOf(o["timestamp"]), stringOf(o["level"]), stringOf(o["source"]), stringOf(o["message"])].filter(Boolean).join(" ")));
7594
+ rows.push(
7595
+ logLine(
7596
+ [
7597
+ stringOf(o["timestamp"]),
7598
+ stringOf(o["level"]),
7599
+ stringOf(o["source"]),
7600
+ stringOf(o["message"])
7601
+ ].filter(Boolean).join(" ")
7602
+ )
7603
+ );
7295
7604
  }
7296
7605
  }
7297
- if (entries.length > 5) rows.push({ kind: "meta", text: `${entries.length - 5} more log line(s)` });
7606
+ if (entries.length > 5)
7607
+ rows.push({ kind: "meta", text: `${entries.length - 5} more log line(s)` });
7298
7608
  }
7299
7609
  function logLine(line) {
7300
7610
  const kind = /\b(error|fatal|panic)\b/i.test(line) ? "error" : /\b(warn|warning)\b/i.test(line) ? "warn" : "stdout";
@@ -7345,7 +7655,11 @@ function visualToolCatalog(toolName, text) {
7345
7655
  if (json && typeof json === "object" && !Array.isArray(json)) {
7346
7656
  const obj = json;
7347
7657
  const total = numOf(obj["total"]) ?? 0;
7348
- rows.push({ kind: total > 0 ? "ok" : "warn", marker: total > 0 ? "ok " : "! ", text: `${toolName} \xB7 ${total} result${total === 1 ? "" : "s"}` });
7658
+ rows.push({
7659
+ kind: total > 0 ? "ok" : "warn",
7660
+ marker: total > 0 ? "ok " : "! ",
7661
+ text: `${toolName} \xB7 ${total} result${total === 1 ? "" : "s"}`
7662
+ });
7349
7663
  const tools = Array.isArray(obj["tools"]) ? obj["tools"] : [];
7350
7664
  for (const tool of tools.slice(0, 5)) {
7351
7665
  if (tool && typeof tool === "object") {
@@ -7366,26 +7680,32 @@ function visualMetaExecution(toolName, text, ok) {
7366
7680
  const json = tryParseJson(text);
7367
7681
  if (!json || typeof json !== "object" || Array.isArray(json)) {
7368
7682
  const header = parseHeaderLine(text);
7369
- return [{ kind: ok ? "ok" : "error", marker: ok ? "ok " : "x ", text: header.label || toolName }];
7683
+ return [
7684
+ { kind: ok ? "ok" : "error", marker: ok ? "ok " : "x ", text: header.label || toolName }
7685
+ ];
7370
7686
  }
7371
7687
  const obj = json;
7372
7688
  if (toolName === "tool_use") {
7373
7689
  const success = obj["success"] !== false && ok;
7374
7690
  const target = stringOf(obj["tool"]) ?? "tool";
7375
- return [{
7376
- kind: success ? "ok" : "error",
7377
- marker: success ? "ok " : "x ",
7378
- text: `${target} \xB7 ${numOf(obj["executionMs"]) ?? 0}ms${success ? "" : ` \xB7 ${stringOf(obj["error"]) ?? "failed"}`}`
7379
- }];
7691
+ return [
7692
+ {
7693
+ kind: success ? "ok" : "error",
7694
+ marker: success ? "ok " : "x ",
7695
+ text: `${target} \xB7 ${numOf(obj["executionMs"]) ?? 0}ms${success ? "" : ` \xB7 ${stringOf(obj["error"]) ?? "failed"}`}`
7696
+ }
7697
+ ];
7380
7698
  }
7381
7699
  const total = numOf(obj["total"]) ?? 0;
7382
7700
  const succeeded = numOf(obj["succeeded"]) ?? 0;
7383
7701
  const failed = numOf(obj["failed"]) ?? 0;
7384
- const rows = [{
7385
- kind: failed > 0 || !ok ? "error" : "ok",
7386
- marker: failed > 0 || !ok ? "x " : "ok ",
7387
- text: `${succeeded}/${total} succeeded${failed > 0 ? ` \xB7 ${failed} failed` : ""}`
7388
- }];
7702
+ const rows = [
7703
+ {
7704
+ kind: failed > 0 || !ok ? "error" : "ok",
7705
+ marker: failed > 0 || !ok ? "x " : "ok ",
7706
+ text: `${succeeded}/${total} succeeded${failed > 0 ? ` \xB7 ${failed} failed` : ""}`
7707
+ }
7708
+ ];
7389
7709
  const results = Array.isArray(obj["results"]) ? obj["results"] : [];
7390
7710
  for (const result of results.slice(0, 5)) {
7391
7711
  if (result && typeof result === "object") {
@@ -7404,17 +7724,21 @@ function visualCodebase(toolName, text, ok) {
7404
7724
  const json = tryParseJson(text);
7405
7725
  if (!json || typeof json !== "object" || Array.isArray(json)) {
7406
7726
  const header = parseHeaderLine(text);
7407
- return [{ kind: ok ? "ok" : "warn", marker: ok ? "ok " : "! ", text: header.label || toolName }];
7727
+ return [
7728
+ { kind: ok ? "ok" : "warn", marker: ok ? "ok " : "! ", text: header.label || toolName }
7729
+ ];
7408
7730
  }
7409
7731
  const obj = json;
7410
7732
  if (toolName === "codebase-search") {
7411
7733
  const status2 = stringOf(obj["indexStatus"]);
7412
7734
  const total = numOf(obj["total"]) ?? 0;
7413
- const rows = [{
7414
- kind: status2 ? "warn" : "ok",
7415
- marker: status2 ? "! " : "ok ",
7416
- text: status2 ?? `${total} symbol result${total === 1 ? "" : "s"} for "${stringOf(obj["query"]) ?? ""}"`
7417
- }];
7735
+ const rows = [
7736
+ {
7737
+ kind: status2 ? "warn" : "ok",
7738
+ marker: status2 ? "! " : "ok ",
7739
+ text: status2 ?? `${total} symbol result${total === 1 ? "" : "s"} for "${stringOf(obj["query"]) ?? ""}"`
7740
+ }
7741
+ ];
7418
7742
  const results = Array.isArray(obj["results"]) ? obj["results"] : [];
7419
7743
  for (const result of results.slice(0, 5)) {
7420
7744
  if (result && typeof result === "object") {
@@ -7431,30 +7755,36 @@ function visualCodebase(toolName, text, ok) {
7431
7755
  }
7432
7756
  if (toolName === "codebase-index") {
7433
7757
  const errors = Array.isArray(obj["errors"]) ? obj["errors"] : [];
7434
- return [{
7435
- kind: errors.length > 0 || !ok ? "error" : stringOf(obj["note"]) ? "warn" : "ok",
7436
- marker: errors.length > 0 || !ok ? "x " : stringOf(obj["note"]) ? "! " : "ok ",
7437
- text: stringOf(obj["note"]) ?? `${numOf(obj["filesIndexed"]) ?? 0} files \xB7 ${numOf(obj["symbolsIndexed"]) ?? 0} symbols \xB7 ${fmtDuration(numOf(obj["durationMs"]) ?? 0)}`
7438
- }];
7758
+ return [
7759
+ {
7760
+ kind: errors.length > 0 || !ok ? "error" : stringOf(obj["note"]) ? "warn" : "ok",
7761
+ marker: errors.length > 0 || !ok ? "x " : stringOf(obj["note"]) ? "! " : "ok ",
7762
+ text: stringOf(obj["note"]) ?? `${numOf(obj["filesIndexed"]) ?? 0} files \xB7 ${numOf(obj["symbolsIndexed"]) ?? 0} symbols \xB7 ${fmtDuration(numOf(obj["durationMs"]) ?? 0)}`
7763
+ }
7764
+ ];
7439
7765
  }
7440
7766
  const status = stringOf(obj["indexStatus"]);
7441
- return [{
7442
- kind: status ? "warn" : "ok",
7443
- marker: status ? "! " : "ok ",
7444
- text: status ?? `${numOf(obj["totalSymbols"]) ?? 0} symbols \xB7 ${numOf(obj["totalFiles"]) ?? 0} files \xB7 ${fmtBytes(numOf(obj["sizeBytes"]) ?? 0)}`
7445
- }];
7767
+ return [
7768
+ {
7769
+ kind: status ? "warn" : "ok",
7770
+ marker: status ? "! " : "ok ",
7771
+ text: status ?? `${numOf(obj["totalSymbols"]) ?? 0} symbols \xB7 ${numOf(obj["totalFiles"]) ?? 0} files \xB7 ${fmtBytes(numOf(obj["sizeBytes"]) ?? 0)}`
7772
+ }
7773
+ ];
7446
7774
  }
7447
7775
  function visualWorkingDir(text, ok) {
7448
7776
  const json = tryParseJson(text);
7449
7777
  const obj = json && typeof json === "object" && !Array.isArray(json) ? json : void 0;
7450
7778
  if (!obj) return void 0;
7451
7779
  const err = stringOf(obj["error"]);
7452
- return [{
7453
- kind: err || !ok ? "error" : "ok",
7454
- marker: err || !ok ? "x " : "ok ",
7455
- path: stringOf(obj["current"]),
7456
- text: err ?? stringOf(obj["message"]) ?? "working directory"
7457
- }];
7780
+ return [
7781
+ {
7782
+ kind: err || !ok ? "error" : "ok",
7783
+ marker: err || !ok ? "x " : "ok ",
7784
+ path: stringOf(obj["current"]),
7785
+ text: err ?? stringOf(obj["message"]) ?? "working directory"
7786
+ }
7787
+ ];
7458
7788
  }
7459
7789
  function visualMode(text, ok) {
7460
7790
  const json = tryParseJson(text);
@@ -7462,21 +7792,32 @@ function visualMode(text, ok) {
7462
7792
  if (!obj) return void 0;
7463
7793
  if (Array.isArray(obj["modes"])) {
7464
7794
  const modes = obj["modes"];
7465
- const rows = [{ kind: "ok", marker: "ok ", text: `${modes.length} mode${modes.length === 1 ? "" : "s"}` }];
7795
+ const rows = [
7796
+ { kind: "ok", marker: "ok ", text: `${modes.length} mode${modes.length === 1 ? "" : "s"}` }
7797
+ ];
7466
7798
  for (const mode of modes.slice(0, 5)) {
7467
7799
  if (mode && typeof mode === "object") {
7468
7800
  const m = mode;
7469
- rows.push({ kind: "path", text: [stringOf(m["id"]), stringOf(m["name"]), stringOf(m["description"])].filter(Boolean).join(" \xB7 ") });
7801
+ rows.push({
7802
+ kind: "path",
7803
+ text: [stringOf(m["id"]), stringOf(m["name"]), stringOf(m["description"])].filter(Boolean).join(" \xB7 ")
7804
+ });
7470
7805
  }
7471
7806
  }
7472
7807
  return rows;
7473
7808
  }
7474
7809
  const success = obj["success"] !== false && ok;
7475
- return [{
7476
- kind: success ? "ok" : "error",
7477
- marker: success ? "ok " : "x ",
7478
- text: [stringOf(obj["action"]) ?? "mode", stringOf(obj["currentMode"]), stringOf(obj["message"])].filter(Boolean).join(" \xB7 ")
7479
- }];
7810
+ return [
7811
+ {
7812
+ kind: success ? "ok" : "error",
7813
+ marker: success ? "ok " : "x ",
7814
+ text: [
7815
+ stringOf(obj["action"]) ?? "mode",
7816
+ stringOf(obj["currentMode"]),
7817
+ stringOf(obj["message"])
7818
+ ].filter(Boolean).join(" \xB7 ")
7819
+ }
7820
+ ];
7480
7821
  }
7481
7822
  function recordToStringFields(obj) {
7482
7823
  const out = {};
@@ -7492,7 +7833,8 @@ function appendOutputPreview(rows, output, kind) {
7492
7833
  if (!output) return;
7493
7834
  const lines = output.split(/\r?\n/).filter((line) => line.trim());
7494
7835
  for (const line of lines.slice(0, 3)) rows.push({ kind, text: line.trim() });
7495
- if (lines.length > 3) rows.push({ kind: "meta", text: `${lines.length - 3} more ${kind} line(s)` });
7836
+ if (lines.length > 3)
7837
+ rows.push({ kind: "meta", text: `${lines.length - 3} more ${kind} line(s)` });
7496
7838
  }
7497
7839
  function bodyLines(text) {
7498
7840
  const lines = text.replace(/\r/g, "").split("\n");
@@ -7800,6 +8142,12 @@ function DiffBlock({
7800
8142
  };
7801
8143
  const stats = showStats ? formatDiffStats(added, removed) : null;
7802
8144
  const bodyBudget = typeof contentWidth === "number" ? Math.max(16, contentWidth - (2 + 3 + gutterWidth + 3)) : DIFF_FALLBACK_WRAP_WIDTH;
8145
+ const hasWidth = typeof contentWidth === "number";
8146
+ const padBody = (seg) => {
8147
+ if (!hasWidth) return 0;
8148
+ const len = seg.reduce((n, t) => n + t.text.length, 0);
8149
+ return Math.max(0, bodyBudget - len);
8150
+ };
7803
8151
  const contPrefix = ` ${blank} `;
7804
8152
  const hiddenStats = [];
7805
8153
  if (hiddenAdded > 0) hiddenStats.push(`+${hiddenAdded}`);
@@ -7833,14 +8181,18 @@ function DiffBlock({
7833
8181
  const markerColor = row.kind === "add" ? theme.success : theme.error;
7834
8182
  if (useColor) {
7835
8183
  const bg = row.kind === "add" ? theme.diffAddBg : theme.diffDelBg;
7836
- return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: segments.map((seg, si) => /* @__PURE__ */ jsx(Box, { backgroundColor: bg, minWidth: 1, flexShrink: 0, children: /* @__PURE__ */ jsxs(Text, { children: [
7837
- si === 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
7838
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` ${ln} ` }),
7839
- /* @__PURE__ */ jsx(Text, { color: markerColor, bold: true, children: marker }),
7840
- /* @__PURE__ */ jsx(Text, { children: " " })
7841
- ] }) : /* @__PURE__ */ jsx(Text, { dimColor: true, children: contPrefix }),
7842
- renderTokens(seg)
7843
- ] }) }, si)) }, key);
8184
+ return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: segments.map((seg, si) => {
8185
+ const pad = padBody(seg);
8186
+ return /* @__PURE__ */ jsxs(Text, { backgroundColor: bg, children: [
8187
+ si === 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
8188
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` ${ln} ` }),
8189
+ /* @__PURE__ */ jsx(Text, { color: markerColor, bold: true, children: marker }),
8190
+ /* @__PURE__ */ jsx(Text, { children: " " })
8191
+ ] }) : /* @__PURE__ */ jsx(Text, { dimColor: true, children: contPrefix }),
8192
+ renderTokens(seg),
8193
+ pad > 0 ? /* @__PURE__ */ jsx(Text, { children: " ".repeat(pad) }) : null
8194
+ ] }, si);
8195
+ }) }, key);
7844
8196
  }
7845
8197
  return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: segments.map((seg, si) => /* @__PURE__ */ jsxs(Text, { children: [
7846
8198
  si === 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -10003,16 +10355,21 @@ var Entry = React5.memo(function Entry2({
10003
10355
  if (mutation) {
10004
10356
  const statsText = formatDiffStats(mutation.added, mutation.removed) ?? "No line changes";
10005
10357
  const targetBudget = Math.max(24, termWidth - mutation.verb.length - 16);
10358
+ const hasCounts = mutation.added > 0 || mutation.removed > 0;
10006
10359
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
10007
10360
  /* @__PURE__ */ jsxs(Text, { children: [
10008
- /* @__PURE__ */ jsx(Text, { color: theme.success, children: "\u25CF" }),
10361
+ /* @__PURE__ */ jsx(Text, { color, children: glyph2 }),
10009
10362
  /* @__PURE__ */ jsx(Text, { children: " " }),
10010
- /* @__PURE__ */ jsx(Text, { bold: true, color: "white", children: `${mutation.verb}(${shortenPath(mutation.target, targetBudget)})` }),
10363
+ /* @__PURE__ */ jsx(Text, { bold: true, color, children: `${mutation.verb}(${shortenPath(mutation.target, targetBudget)})` }),
10011
10364
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \xB7 ${fmtDuration(entry.durationMs)}` })
10012
10365
  ] }),
10013
10366
  /* @__PURE__ */ jsxs(Text, { children: [
10014
10367
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: " \u23BF " }),
10015
- /* @__PURE__ */ jsx(Text, { children: statsText })
10368
+ mutation.added > 0 ? /* @__PURE__ */ jsx(Text, { bold: true, color: theme.success, children: `+${mutation.added}` }) : null,
10369
+ mutation.added > 0 && mutation.removed > 0 ? /* @__PURE__ */ jsx(Text, { children: " " }) : null,
10370
+ mutation.removed > 0 ? /* @__PURE__ */ jsx(Text, { bold: true, color: theme.error, children: `-${mutation.removed}` }) : null,
10371
+ hasCounts ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: " " }) : null,
10372
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: statsText })
10016
10373
  ] }),
10017
10374
  entry.resultRenderMode !== "simple" && multiDiffs ? /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
10018
10375
  (() => {
@@ -15244,14 +15601,16 @@ function createPanelOpenDispatcher(deps) {
15244
15601
  }
15245
15602
  };
15246
15603
  }
15247
- var INPUT_PROMPT = "\u203A ";
15248
- function selectedSlashCommandLine(picker) {
15249
- if (!picker.open || picker.matches.length === 0) return null;
15250
- const picked = picker.matches[picker.selected];
15251
- return picked ? `/${picked.name}` : null;
15252
- }
15604
+
15605
+ // src/input-editing.ts
15606
+ var WORD_SEPARATORS = new Set(
15607
+ // dashes
15608
+ "-/\\.,;:!?\u2026()[]{}<>\"'`+=*^%|~@#$&\xB7\u2022\u2014\u2013".split("")
15609
+ );
15253
15610
  function isInputWordSeparator(ch) {
15254
- return ch === void 0 || /\s/.test(ch);
15611
+ if (ch === void 0) return true;
15612
+ if (/\s/.test(ch)) return true;
15613
+ return WORD_SEPARATORS.has(ch);
15255
15614
  }
15256
15615
  function previousInputWordStart(buffer, cursor) {
15257
15616
  let i = Math.max(0, Math.min(cursor, buffer.length));
@@ -15286,6 +15645,34 @@ function nextInputWordStart(buffer, cursor) {
15286
15645
  while (i < buffer.length && isInputWordSeparator(buffer[i])) i++;
15287
15646
  return i;
15288
15647
  }
15648
+ function deleteWordBackward(buffer, cursor) {
15649
+ if (cursor === 0) return null;
15650
+ const chip = tokenSpanAt(buffer, cursor);
15651
+ const deleteStart = chip && cursor > chip.start && cursor < chip.end ? chip.start : previousInputWordStart(buffer, cursor);
15652
+ const deleteEnd = chip && cursor > chip.start && cursor < chip.end ? chip.end : cursor;
15653
+ if (deleteStart === deleteEnd) return null;
15654
+ return {
15655
+ buffer: buffer.slice(0, deleteStart) + buffer.slice(deleteEnd),
15656
+ cursor: deleteStart
15657
+ };
15658
+ }
15659
+ function deleteWordForward(buffer, cursor) {
15660
+ if (cursor >= buffer.length) return null;
15661
+ const chip = tokenSpanAt(buffer, cursor);
15662
+ const deleteStart = chip && cursor > chip.start && cursor < chip.end ? chip.start : cursor;
15663
+ const deleteEnd = chip && cursor > chip.start && cursor < chip.end ? chip.end : nextInputWordStart(buffer, cursor);
15664
+ if (deleteStart === deleteEnd) return null;
15665
+ return {
15666
+ buffer: buffer.slice(0, deleteStart) + buffer.slice(deleteEnd),
15667
+ cursor: deleteStart
15668
+ };
15669
+ }
15670
+ var INPUT_PROMPT = "\u203A ";
15671
+ function selectedSlashCommandLine(picker) {
15672
+ if (!picker.open || picker.matches.length === 0) return null;
15673
+ const picked = picker.matches[picker.selected];
15674
+ return picked ? `/${picked.name}` : null;
15675
+ }
15289
15676
  function rehydrateHistory(messages, startId, toolCalls) {
15290
15677
  const entries = [];
15291
15678
  const toolCallsById = /* @__PURE__ */ new Map();
@@ -15624,6 +16011,7 @@ function App({
15624
16011
  nextQueueId: 1,
15625
16012
  inputHistory: [],
15626
16013
  historyIndex: 0,
16014
+ historyDraft: "",
15627
16015
  modelPicker: {
15628
16016
  open: false,
15629
16017
  step: "provider",
@@ -15693,7 +16081,8 @@ function App({
15693
16081
  thinkingWordEditing: false,
15694
16082
  thinkingWordDraft: "",
15695
16083
  cacheTtl: "default",
15696
- configScope: "global"
16084
+ configScope: "global",
16085
+ animationStyle: "rainbow"
15697
16086
  },
15698
16087
  statuslinePicker: { open: false, field: 0, hiddenItems: [], visibleChips: [], hint: void 0 },
15699
16088
  pluginPicker: { open: false, items: [], selected: 0, busy: false, hint: void 0 },
@@ -15763,6 +16152,44 @@ function App({
15763
16152
  debugStreamStats: null,
15764
16153
  countdown: null
15765
16154
  });
16155
+ const inputHistoryStore = useMemo(() => {
16156
+ if (!projectRoot) return null;
16157
+ const file = resolveWstackPaths({ projectRoot }).projectInputHistory;
16158
+ return new InputHistoryStore(file, new DefaultSecretScrubber(), INPUT_HISTORY_DEFAULT_MAX);
16159
+ }, [projectRoot]);
16160
+ const inputHistoryLoadedRef = useRef(false);
16161
+ const inputHistorySaveTimerRef = useRef(void 0);
16162
+ const inputHistoryLastSavedRef = useRef("");
16163
+ useEffect(() => {
16164
+ if (!inputHistoryStore) return;
16165
+ let cancelled = false;
16166
+ inputHistoryStore.load().then((entries) => {
16167
+ if (cancelled) return;
16168
+ inputHistoryLoadedRef.current = true;
16169
+ inputHistoryLastSavedRef.current = JSON.stringify(entries);
16170
+ if (entries.length === 0) return;
16171
+ dispatch({ type: "setInputHistory", entries });
16172
+ }).catch(() => {
16173
+ if (!cancelled) inputHistoryLoadedRef.current = true;
16174
+ });
16175
+ return () => {
16176
+ cancelled = true;
16177
+ };
16178
+ }, [inputHistoryStore]);
16179
+ useEffect(() => {
16180
+ if (!inputHistoryStore || !inputHistoryLoadedRef.current) return;
16181
+ const snapshot = JSON.stringify(state.inputHistory);
16182
+ if (snapshot === inputHistoryLastSavedRef.current) return;
16183
+ if (inputHistorySaveTimerRef.current) clearTimeout(inputHistorySaveTimerRef.current);
16184
+ inputHistorySaveTimerRef.current = setTimeout(() => {
16185
+ inputHistoryLastSavedRef.current = snapshot;
16186
+ inputHistoryStore.save(state.inputHistory).catch(() => {
16187
+ });
16188
+ }, 200);
16189
+ return () => {
16190
+ if (inputHistorySaveTimerRef.current) clearTimeout(inputHistorySaveTimerRef.current);
16191
+ };
16192
+ }, [state.inputHistory, inputHistoryStore]);
15766
16193
  const getPromptLoader = () => {
15767
16194
  if (!promptLoaderRef.current && projectRoot) {
15768
16195
  let bundledDir;
@@ -15882,6 +16309,7 @@ function App({
15882
16309
  }, [agent.ctx, projectRoot]);
15883
16310
  const liveSettings = getSettings?.();
15884
16311
  const liveStatuslineMode = liveSettings?.statuslineMode ?? "detailed";
16312
+ const liveAnimationStyle = liveSettings?.animationStyle ?? "rainbow";
15885
16313
  const liveThinkingWord = liveSettings?.thinkingWord ?? "thinking";
15886
16314
  const [rolledThinkingWord, setRolledThinkingWord] = useState(() => pickRandomTuiThinkingWord());
15887
16315
  const thinkingWorking = state.status === "running" || state.status === "streaming";
@@ -16528,7 +16956,8 @@ function App({
16528
16956
  reasoningPreserve: sp.reasoningPreserve,
16529
16957
  thinkingWord: sp.thinkingWord,
16530
16958
  cacheTtl: sp.cacheTtl,
16531
- configScope: sp.configScope
16959
+ configScope: sp.configScope,
16960
+ animationStyle: sp.animationStyle
16532
16961
  });
16533
16962
  }
16534
16963
  if (prev.projectPicker) {
@@ -16748,7 +17177,13 @@ function App({
16748
17177
  return () => {
16749
17178
  if (onPanelOpen) onPanelOpen.current = null;
16750
17179
  };
16751
- }, [onPanelOpen, dispatch, openProjectPicker, openStatuslinePicker, authPanelController.openAuthPanel]);
17180
+ }, [
17181
+ onPanelOpen,
17182
+ dispatch,
17183
+ openProjectPicker,
17184
+ openStatuslinePicker,
17185
+ authPanelController.openAuthPanel
17186
+ ]);
16752
17187
  useEffect(() => {
16753
17188
  if (!state.sessionsPanelOpen || !getLiveSessions) return void 0;
16754
17189
  const t = setInterval(() => {
@@ -16797,7 +17232,8 @@ function App({
16797
17232
  reasoningPreserve: s2.reasoningPreserve ?? false,
16798
17233
  thinkingWord: s2.thinkingWord ?? "thinking",
16799
17234
  cacheTtl: s2.cacheTtl ?? "default",
16800
- configScope: s2.configScope ?? "global"
17235
+ configScope: s2.configScope ?? "global",
17236
+ animationStyle: s2.animationStyle ?? "rainbow"
16801
17237
  });
16802
17238
  }, [getSettings]);
16803
17239
  const refreshPluginPicker = React5.useCallback(() => {
@@ -16985,7 +17421,8 @@ function App({
16985
17421
  reasoningPreserve: sp.reasoningPreserve,
16986
17422
  thinkingWord: sp.thinkingWord,
16987
17423
  cacheTtl: sp.cacheTtl,
16988
- configScope: sp.configScope
17424
+ configScope: sp.configScope,
17425
+ animationStyle: sp.animationStyle
16989
17426
  })
16990
17427
  ).then((err) => {
16991
17428
  if (err) dispatch({ type: "settingsHint", text: err });
@@ -17027,6 +17464,7 @@ function App({
17027
17464
  state.settingsPicker.thinkingWord,
17028
17465
  state.settingsPicker.cacheTtl,
17029
17466
  state.settingsPicker.configScope,
17467
+ state.settingsPicker.animationStyle,
17030
17468
  saveSettings
17031
17469
  ]);
17032
17470
  useEffect(() => {
@@ -17664,6 +18102,14 @@ Available chords:
17664
18102
  const [nextStepsAutoSubmitLabel, setNextStepsAutoSubmitLabel] = useState(null);
17665
18103
  const nextStepsAutoSubmitSuggestionRef = useRef(null);
17666
18104
  const nextStepsAutoSubmitTimerRef = useRef(void 0);
18105
+ const cancelNextStepsCountdown = useCallback(() => {
18106
+ if (nextStepsAutoSubmitTimerRef.current == null) return;
18107
+ clearInterval(nextStepsAutoSubmitTimerRef.current);
18108
+ nextStepsAutoSubmitTimerRef.current = void 0;
18109
+ setNextStepsAutoSubmitCountdown(null);
18110
+ setNextStepsAutoSubmitLabel(null);
18111
+ nextStepsAutoSubmitSuggestionRef.current = null;
18112
+ }, []);
17667
18113
  const getActiveSessionId = useCallback(() => agent.ctx.session.id, [agent]);
17668
18114
  useTuiEventBridge({
17669
18115
  events,
@@ -18452,7 +18898,8 @@ Available chords:
18452
18898
  reasoningPreserve: cfg.reasoningPreserve ?? false,
18453
18899
  thinkingWord: cfg.thinkingWord ?? "thinking",
18454
18900
  cacheTtl: cfg.cacheTtl ?? "default",
18455
- configScope: cfg.configScope ?? "global"
18901
+ configScope: cfg.configScope ?? "global",
18902
+ animationStyle: cfg.animationStyle ?? "rainbow"
18456
18903
  });
18457
18904
  }
18458
18905
  return;
@@ -18538,19 +18985,11 @@ Available chords:
18538
18985
  }
18539
18986
  if (key.backspace) {
18540
18987
  if (key.ctrl) {
18541
- if (cursor === 0) return;
18542
- const chip = tokenSpanAt(buffer, cursor);
18543
- const deleteStart = chip && cursor > chip.start && cursor < chip.end ? chip.start : previousInputWordStart(buffer, cursor);
18544
- const deleteEnd = chip && cursor > chip.start && cursor < chip.end ? chip.end : cursor;
18545
- const next3 = buffer.slice(0, deleteStart) + buffer.slice(deleteEnd);
18546
- if (nextStepsAutoSubmitTimerRef.current != null) {
18547
- clearInterval(nextStepsAutoSubmitTimerRef.current);
18548
- nextStepsAutoSubmitTimerRef.current = void 0;
18549
- setNextStepsAutoSubmitCountdown(null);
18550
- setNextStepsAutoSubmitLabel(null);
18551
- nextStepsAutoSubmitSuggestionRef.current = null;
18552
- }
18553
- setDraft(next3, deleteStart);
18988
+ const res = deleteWordBackward(buffer, cursor);
18989
+ if (res) {
18990
+ cancelNextStepsCountdown();
18991
+ setDraft(res.buffer, res.cursor);
18992
+ }
18554
18993
  return;
18555
18994
  }
18556
18995
  const tokenDel = deleteTokenBackward(buffer, cursor);
@@ -18560,43 +18999,31 @@ Available chords:
18560
18999
  }
18561
19000
  if (cursor === 0) return;
18562
19001
  const next2 = buffer.slice(0, cursor - 1) + buffer.slice(cursor);
18563
- if (nextStepsAutoSubmitTimerRef.current != null) {
18564
- clearInterval(nextStepsAutoSubmitTimerRef.current);
18565
- nextStepsAutoSubmitTimerRef.current = void 0;
18566
- setNextStepsAutoSubmitCountdown(null);
18567
- setNextStepsAutoSubmitLabel(null);
18568
- nextStepsAutoSubmitSuggestionRef.current = null;
18569
- }
19002
+ cancelNextStepsCountdown();
18570
19003
  setDraft(next2, cursor - 1);
18571
19004
  return;
18572
19005
  }
19006
+ if (key.ctrl && input === "w") {
19007
+ const res = deleteWordBackward(buffer, cursor);
19008
+ if (res) {
19009
+ cancelNextStepsCountdown();
19010
+ setDraft(res.buffer, res.cursor);
19011
+ }
19012
+ return;
19013
+ }
18573
19014
  if (key.delete) {
18574
19015
  if (key.ctrl) {
18575
- if (cursor >= buffer.length) return;
18576
- const chip = tokenSpanAt(buffer, cursor);
18577
- const deleteStart = chip && cursor > chip.start && cursor < chip.end ? chip.start : cursor;
18578
- const deleteEnd = chip && cursor > chip.start && cursor < chip.end ? chip.end : nextInputWordStart(buffer, cursor);
18579
- const next3 = buffer.slice(0, deleteStart) + buffer.slice(deleteEnd);
18580
- if (nextStepsAutoSubmitTimerRef.current != null) {
18581
- clearInterval(nextStepsAutoSubmitTimerRef.current);
18582
- nextStepsAutoSubmitTimerRef.current = void 0;
18583
- setNextStepsAutoSubmitCountdown(null);
18584
- setNextStepsAutoSubmitLabel(null);
18585
- nextStepsAutoSubmitSuggestionRef.current = null;
18586
- }
18587
- setDraft(next3, deleteStart);
19016
+ const res = deleteWordForward(buffer, cursor);
19017
+ if (res) {
19018
+ cancelNextStepsCountdown();
19019
+ setDraft(res.buffer, res.cursor);
19020
+ }
18588
19021
  return;
18589
19022
  }
18590
19023
  if (cursor >= buffer.length) return;
18591
19024
  const span = tokenLengthForward(buffer, cursor) || 1;
18592
19025
  const next2 = buffer.slice(0, cursor) + buffer.slice(cursor + span);
18593
- if (nextStepsAutoSubmitTimerRef.current != null) {
18594
- clearInterval(nextStepsAutoSubmitTimerRef.current);
18595
- nextStepsAutoSubmitTimerRef.current = void 0;
18596
- setNextStepsAutoSubmitCountdown(null);
18597
- setNextStepsAutoSubmitLabel(null);
18598
- nextStepsAutoSubmitSuggestionRef.current = null;
18599
- }
19026
+ cancelNextStepsCountdown();
18600
19027
  setDraft(next2, cursor);
18601
19028
  return;
18602
19029
  }
@@ -18809,13 +19236,7 @@ Available chords:
18809
19236
  return;
18810
19237
  }
18811
19238
  if (key.ctrl && input === "u") {
18812
- if (nextStepsAutoSubmitTimerRef.current != null) {
18813
- clearInterval(nextStepsAutoSubmitTimerRef.current);
18814
- nextStepsAutoSubmitTimerRef.current = void 0;
18815
- setNextStepsAutoSubmitCountdown(null);
18816
- setNextStepsAutoSubmitLabel(null);
18817
- nextStepsAutoSubmitSuggestionRef.current = null;
18818
- }
19239
+ cancelNextStepsCountdown();
18819
19240
  setDraft("", 0);
18820
19241
  return;
18821
19242
  }
@@ -18823,26 +19244,14 @@ Available chords:
18823
19244
  if (cursor >= buffer.length) return;
18824
19245
  const span = tokenLengthForward(buffer, cursor) || 1;
18825
19246
  const next2 = buffer.slice(0, cursor) + buffer.slice(cursor + span);
18826
- if (nextStepsAutoSubmitTimerRef.current != null) {
18827
- clearInterval(nextStepsAutoSubmitTimerRef.current);
18828
- nextStepsAutoSubmitTimerRef.current = void 0;
18829
- setNextStepsAutoSubmitCountdown(null);
18830
- setNextStepsAutoSubmitLabel(null);
18831
- nextStepsAutoSubmitSuggestionRef.current = null;
18832
- }
19247
+ cancelNextStepsCountdown();
18833
19248
  setDraft(next2, cursor);
18834
19249
  return;
18835
19250
  }
18836
19251
  if (key.ctrl && input === "k") {
18837
19252
  if (cursor >= buffer.length) return;
18838
19253
  const next2 = buffer.slice(0, cursor);
18839
- if (nextStepsAutoSubmitTimerRef.current != null) {
18840
- clearInterval(nextStepsAutoSubmitTimerRef.current);
18841
- nextStepsAutoSubmitTimerRef.current = void 0;
18842
- setNextStepsAutoSubmitCountdown(null);
18843
- setNextStepsAutoSubmitLabel(null);
18844
- nextStepsAutoSubmitSuggestionRef.current = null;
18845
- }
19254
+ cancelNextStepsCountdown();
18846
19255
  setDraft(next2, cursor);
18847
19256
  return;
18848
19257
  }
@@ -18864,13 +19273,7 @@ Available chords:
18864
19273
  await commitPaste(input);
18865
19274
  return;
18866
19275
  }
18867
- if (nextStepsAutoSubmitTimerRef.current != null) {
18868
- clearInterval(nextStepsAutoSubmitTimerRef.current);
18869
- nextStepsAutoSubmitTimerRef.current = void 0;
18870
- setNextStepsAutoSubmitCountdown(null);
18871
- setNextStepsAutoSubmitLabel(null);
18872
- nextStepsAutoSubmitSuggestionRef.current = null;
18873
- }
19276
+ cancelNextStepsCountdown();
18874
19277
  const next = buffer.slice(0, cursor) + input + buffer.slice(cursor);
18875
19278
  setDraft(next, cursor + input.length);
18876
19279
  };
@@ -18900,10 +19303,15 @@ Available chords:
18900
19303
  }
18901
19304
  });
18902
19305
  }
19306
+ const assistantEntriesBeforeRun = stateRef.current.entries.filter(
19307
+ (entry) => entry.kind === "assistant"
19308
+ ).length;
18903
19309
  const result = await agent.run(routed.blocks, { signal: ctrl.signal });
18904
19310
  const lingering = streamingTextRef.current;
18905
19311
  if (lingering.trim()) {
18906
19312
  dispatch({ type: "addEntry", entry: { kind: "assistant", text: lingering } });
19313
+ } else if (result.status === "done" && result.finalText?.trim() && stateRef.current.entries.filter((entry) => entry.kind === "assistant").length === assistantEntriesBeforeRun) {
19314
+ dispatch({ type: "addEntry", entry: { kind: "assistant", text: result.finalText } });
18907
19315
  }
18908
19316
  streamingTextRef.current = "";
18909
19317
  pendingDeltaRef.current = "";
@@ -19607,6 +20015,7 @@ ${content}
19607
20015
  reasoningPreserve: state.settingsPicker.reasoningPreserve,
19608
20016
  cacheTtl: state.settingsPicker.cacheTtl,
19609
20017
  configScope: state.settingsPicker.configScope,
20018
+ animationStyle: state.settingsPicker.animationStyle,
19610
20019
  filter: state.settingsPicker.filter,
19611
20020
  hint: state.settingsPicker.hint
19612
20021
  }
@@ -19819,6 +20228,13 @@ ${content}
19819
20228
  version: appVersion,
19820
20229
  state: state.status,
19821
20230
  thinkingWord: displayThinkingWord,
20231
+ thinkingAnimationStyle: (
20232
+ // While the settings picker is open, preview the picker's live
20233
+ // ←/→ selection synchronously (saveSettings → configStore is
20234
+ // async, so liveAnimationStyle lags a keystroke). When closed,
20235
+ // use the persisted value from getSettings().
20236
+ state.settingsPicker.open ? state.settingsPicker.animationStyle : liveAnimationStyle
20237
+ ),
19822
20238
  tokenCounter,
19823
20239
  hint: renderRunningTools(state.runningTools) || state.hint,
19824
20240
  queueCount: state.queue.length,
@@ -19854,7 +20270,7 @@ ${content}
19854
20270
  autoProceedCountdown: state.countdown?.remainingSeconds ?? null,
19855
20271
  sessionCount,
19856
20272
  mailbox: mailboxStatus,
19857
- tokenSavingMode: getSettings ? getSettings().featureTokenSaving !== "off" : tokenSavingMode,
20273
+ tokenSavingMode: liveSettings?.featureTokenSaving ?? tokenSavingMode,
19858
20274
  toolCount,
19859
20275
  sideEffectCount: agent.ctx.sideEffects?.length ?? 0
19860
20276
  }