reasonix 0.33.1 → 0.34.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/dashboard/dist/app.js +1 -21
  2. package/dashboard/dist/app.js.map +1 -1
  3. package/dist/cli/{chat-Q5ZCVIOO.js → chat-TL4HMNEQ.js} +15 -13
  4. package/dist/cli/chunk-2EBODRRO.js +149 -0
  5. package/dist/cli/chunk-2EBODRRO.js.map +1 -0
  6. package/dist/cli/{chunk-DULSP7JH.js → chunk-5JXXEPDM.js} +34 -1
  7. package/dist/cli/chunk-5JXXEPDM.js.map +1 -0
  8. package/dist/cli/{chunk-MDHVWCJ4.js → chunk-5SAMVHA3.js} +591 -299
  9. package/dist/cli/chunk-5SAMVHA3.js.map +1 -0
  10. package/dist/cli/chunk-DAEAAVDF.js +199 -0
  11. package/dist/cli/chunk-DAEAAVDF.js.map +1 -0
  12. package/dist/cli/{chunk-D5DKXIP5.js → chunk-F3ILWP2L.js} +18 -27
  13. package/dist/cli/chunk-F3ILWP2L.js.map +1 -0
  14. package/dist/cli/{chunk-SDE5U32Z.js → chunk-KZHMKOJH.js} +13 -8
  15. package/dist/cli/{chunk-SDE5U32Z.js.map → chunk-KZHMKOJH.js.map} +1 -1
  16. package/dist/cli/{chunk-Q6YFXW7H.js → chunk-LNTORE5K.js} +246 -339
  17. package/dist/cli/chunk-LNTORE5K.js.map +1 -0
  18. package/dist/cli/chunk-MRLXEMZ7.js +26 -0
  19. package/dist/cli/chunk-MRLXEMZ7.js.map +1 -0
  20. package/dist/cli/{chunk-WBDE4IRI.js → chunk-OERAGRJX.js} +2 -2
  21. package/dist/cli/{chunk-QGE6AF76.js → chunk-Q36KBLSU.js} +207 -8
  22. package/dist/cli/chunk-Q36KBLSU.js.map +1 -0
  23. package/dist/cli/{chunk-RZILUXUC.js → chunk-RXGEGA7K.js} +2 -2
  24. package/dist/cli/{chunk-FXGQ5NHE.js → chunk-SA4UGZPG.js} +21 -1
  25. package/dist/cli/chunk-SA4UGZPG.js.map +1 -0
  26. package/dist/cli/{chunk-J5VLP23S.js → chunk-SW3CCXEV.js} +2 -2
  27. package/dist/cli/{chunk-W4LDFAZ6.js → chunk-SX6L4HZZ.js} +2 -2
  28. package/dist/cli/chunk-WUI3P4RA.js +319 -0
  29. package/dist/cli/chunk-WUI3P4RA.js.map +1 -0
  30. package/dist/cli/{code-DLR77NPZ.js → code-V6F4BKMG.js} +16 -14
  31. package/dist/cli/{code-DLR77NPZ.js.map → code-V6F4BKMG.js.map} +1 -1
  32. package/dist/cli/{commands-JWT2MWVH.js → commands-MEZPSEHV.js} +4 -3
  33. package/dist/cli/{commands-JWT2MWVH.js.map → commands-MEZPSEHV.js.map} +1 -1
  34. package/dist/cli/{commit-RPZBOZS2.js → commit-CE4EFTUQ.js} +3 -2
  35. package/dist/cli/{commit-RPZBOZS2.js.map → commit-CE4EFTUQ.js.map} +1 -1
  36. package/dist/cli/{doctor-3TGB2NZN.js → doctor-YASM64X6.js} +8 -6
  37. package/dist/cli/index.js +23 -21
  38. package/dist/cli/index.js.map +1 -1
  39. package/dist/cli/{mcp-ARTNQ24O.js → mcp-LDFK5QJI.js} +3 -2
  40. package/dist/cli/{mcp-ARTNQ24O.js.map → mcp-LDFK5QJI.js.map} +1 -1
  41. package/dist/cli/{mcp-browse-HLO2ENDL.js → mcp-browse-FYHEITCM.js} +3 -2
  42. package/dist/cli/{mcp-browse-HLO2ENDL.js.map → mcp-browse-FYHEITCM.js.map} +1 -1
  43. package/dist/cli/{replay-Q43DSMG6.js → replay-JEDLU7F2.js} +8 -6
  44. package/dist/cli/{replay-Q43DSMG6.js.map → replay-JEDLU7F2.js.map} +1 -1
  45. package/dist/cli/{run-JMEOTQCG.js → run-NHD2RSTD.js} +8 -6
  46. package/dist/cli/{run-JMEOTQCG.js.map → run-NHD2RSTD.js.map} +1 -1
  47. package/dist/cli/{server-SYC3OVOP.js → server-MC4A4WAJ.js} +9 -8
  48. package/dist/cli/{server-SYC3OVOP.js.map → server-MC4A4WAJ.js.map} +1 -1
  49. package/dist/cli/{sessions-MOJAALJI.js → sessions-ZHWJEW4L.js} +8 -6
  50. package/dist/cli/{sessions-MOJAALJI.js.map → sessions-ZHWJEW4L.js.map} +1 -1
  51. package/dist/cli/{setup-CCJZAWTY.js → setup-DK43MT47.js} +6 -5
  52. package/dist/cli/{setup-CCJZAWTY.js.map → setup-DK43MT47.js.map} +1 -1
  53. package/dist/cli/{version-3MYFE4G6.js → version-O362UKPM.js} +8 -6
  54. package/dist/cli/{version-3MYFE4G6.js.map → version-O362UKPM.js.map} +1 -1
  55. package/dist/index.d.ts +45 -1
  56. package/dist/index.js +569 -27
  57. package/dist/index.js.map +1 -1
  58. package/package.json +1 -1
  59. package/dist/cli/chunk-63KAV5DX.js +0 -106
  60. package/dist/cli/chunk-63KAV5DX.js.map +0 -1
  61. package/dist/cli/chunk-D5DKXIP5.js.map +0 -1
  62. package/dist/cli/chunk-DULSP7JH.js.map +0 -1
  63. package/dist/cli/chunk-FXGQ5NHE.js.map +0 -1
  64. package/dist/cli/chunk-MDHVWCJ4.js.map +0 -1
  65. package/dist/cli/chunk-Q6YFXW7H.js.map +0 -1
  66. package/dist/cli/chunk-QGE6AF76.js.map +0 -1
  67. package/dist/cli/chunk-ZPTSJGX5.js +0 -88
  68. package/dist/cli/chunk-ZPTSJGX5.js.map +0 -1
  69. /package/dist/cli/{chat-Q5ZCVIOO.js.map → chat-TL4HMNEQ.js.map} +0 -0
  70. /package/dist/cli/{chunk-WBDE4IRI.js.map → chunk-OERAGRJX.js.map} +0 -0
  71. /package/dist/cli/{chunk-RZILUXUC.js.map → chunk-RXGEGA7K.js.map} +0 -0
  72. /package/dist/cli/{chunk-J5VLP23S.js.map → chunk-SW3CCXEV.js.map} +0 -0
  73. /package/dist/cli/{chunk-W4LDFAZ6.js.map → chunk-SX6L4HZZ.js.map} +0 -0
  74. /package/dist/cli/{doctor-3TGB2NZN.js.map → doctor-YASM64X6.js.map} +0 -0
@@ -6,16 +6,6 @@ import {
6
6
  import {
7
7
  preflightStdioSpec
8
8
  } from "./chunk-RFX7TYVV.js";
9
- import {
10
- CARD,
11
- FG,
12
- SURFACE,
13
- TONE,
14
- TONE_ACTIVE,
15
- balanceColor,
16
- formatBalance,
17
- formatCost
18
- } from "./chunk-63KAV5DX.js";
19
9
  import {
20
10
  dumpStartupProfile,
21
11
  markPhase
@@ -26,12 +16,12 @@ import {
26
16
  ToolRegistry,
27
17
  applyEditBlocks,
28
18
  bridgeMcpTools,
29
- countTokens,
30
19
  detectAtPicker,
31
20
  expandAtMentions,
32
21
  expandAtUrls,
33
22
  formatSubagentResult,
34
- listFilesWithStatsAsync,
23
+ listDirectory,
24
+ parseAtQuery,
35
25
  parseEditBlocks,
36
26
  rankPickerCandidates,
37
27
  registerChoiceTool,
@@ -42,8 +32,9 @@ import {
42
32
  snapshotBeforeEdits,
43
33
  spawnSubagent,
44
34
  toWholeFileEditBlock,
35
+ walkFilesStream,
45
36
  webFetch
46
- } from "./chunk-Q6YFXW7H.js";
37
+ } from "./chunk-LNTORE5K.js";
47
38
  import {
48
39
  McpClient,
49
40
  SseTransport,
@@ -64,12 +55,15 @@ import {
64
55
  KeystrokeProvider,
65
56
  SingleSelect,
66
57
  useKeystroke
67
- } from "./chunk-SDE5U32Z.js";
58
+ } from "./chunk-KZHMKOJH.js";
68
59
  import {
69
60
  COLOR,
70
61
  GLYPH,
71
- GRADIENT
72
- } from "./chunk-ZPTSJGX5.js";
62
+ GRADIENT,
63
+ ThemeProvider,
64
+ useColor,
65
+ useThemeTokens
66
+ } from "./chunk-2EBODRRO.js";
73
67
  import {
74
68
  PRESETS,
75
69
  PRESET_DESCRIPTIONS,
@@ -77,7 +71,10 @@ import {
77
71
  } from "./chunk-MHDNZXJJ.js";
78
72
  import {
79
73
  runDoctorChecks
80
- } from "./chunk-D5DKXIP5.js";
74
+ } from "./chunk-F3ILWP2L.js";
75
+ import {
76
+ countTokens
77
+ } from "./chunk-DAEAAVDF.js";
81
78
  import {
82
79
  DeepSeekClient
83
80
  } from "./chunk-KMWKGPFZ.js";
@@ -100,7 +97,7 @@ import {
100
97
  resolveSlashAlias,
101
98
  savePlanState,
102
99
  suggestSlashCommands
103
- } from "./chunk-FXGQ5NHE.js";
100
+ } from "./chunk-SA4UGZPG.js";
104
101
  import {
105
102
  eventLogPath,
106
103
  openEventSink
@@ -116,7 +113,7 @@ import {
116
113
  formatCommandResult,
117
114
  pauseGate,
118
115
  runCommand
119
- } from "./chunk-W4LDFAZ6.js";
116
+ } from "./chunk-SX6L4HZZ.js";
120
117
  import {
121
118
  PROJECT_MEMORY_FILE,
122
119
  SkillStore,
@@ -130,7 +127,7 @@ import {
130
127
  loadHooks,
131
128
  projectSettingsPath,
132
129
  runHooks
133
- } from "./chunk-WBDE4IRI.js";
130
+ } from "./chunk-OERAGRJX.js";
134
131
  import {
135
132
  VERSION,
136
133
  compareVersions,
@@ -155,8 +152,9 @@ import {
155
152
  notifyLanguageChange,
156
153
  onLanguageChange,
157
154
  setLanguage,
158
- t
159
- } from "./chunk-QGE6AF76.js";
155
+ t,
156
+ tObj
157
+ } from "./chunk-Q36KBLSU.js";
160
158
  import {
161
159
  addProjectShellAllowed,
162
160
  clearProjectShellAllowed,
@@ -167,18 +165,35 @@ import {
167
165
  loadEditMode,
168
166
  loadProjectShellAllowed,
169
167
  loadReasoningEffort,
168
+ loadTheme,
170
169
  markEditModeHintShown,
170
+ markMouseClipboardHintShown,
171
+ mouseClipboardHintShown,
171
172
  readConfig,
172
173
  redactKey,
173
174
  removeProjectShellAllowed,
175
+ resolveThemePreference,
174
176
  saveApiKey,
175
177
  saveEditMode,
176
178
  saveReasoningEffort,
179
+ saveTheme,
177
180
  searchEnabled,
178
181
  webSearchEndpoint,
179
182
  webSearchEngine,
180
183
  writeConfig
181
- } from "./chunk-DULSP7JH.js";
184
+ } from "./chunk-5JXXEPDM.js";
185
+ import {
186
+ CARD,
187
+ FG,
188
+ SURFACE,
189
+ TONE,
190
+ TONE_ACTIVE,
191
+ balanceColor,
192
+ formatBalance,
193
+ formatCost,
194
+ isThemeName,
195
+ listThemeNames
196
+ } from "./chunk-WUI3P4RA.js";
182
197
  import {
183
198
  aggregateUsage,
184
199
  appendUsage,
@@ -193,7 +208,7 @@ import {
193
208
 
194
209
  // src/cli/commands/chat.tsx
195
210
  import { render } from "ink";
196
- import React62, { useState as useState22 } from "react";
211
+ import React63, { useState as useState22 } from "react";
197
212
 
198
213
  // src/mcp/summary.ts
199
214
  function buildMcpServerSummary(opts) {
@@ -216,8 +231,8 @@ function buildMcpServerSummary(opts) {
216
231
  // src/cli/ui/App.tsx
217
232
  import { statSync } from "fs";
218
233
  import { resolve as resolve2 } from "path";
219
- import { Box as Box48, Text as Text51, useStdout as useStdout14 } from "ink";
220
- import React59, { useCallback as useCallback11, useEffect as useEffect12, useMemo as useMemo9, useRef as useRef8, useState as useState20 } from "react";
234
+ import { Box as Box49, Text as Text52, useStdout as useStdout14 } from "ink";
235
+ import React60, { useCallback as useCallback11, useEffect as useEffect12, useMemo as useMemo9, useRef as useRef8, useState as useState20 } from "react";
221
236
 
222
237
  // src/code/checkpoints.ts
223
238
  import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "fs";
@@ -849,28 +864,64 @@ ${skill2.body}${argsBlock}`;
849
864
  // src/cli/ui/AtMentionSuggestions.tsx
850
865
  import { Box, Text } from "ink";
851
866
  import React from "react";
867
+ var ROW_WINDOW = 8;
852
868
  function AtMentionSuggestions({
853
- matches,
854
- selectedIndex,
855
- query
869
+ state,
870
+ selectedIndex
856
871
  }) {
857
- if (matches === null) return null;
858
- if (matches.length === 0) {
859
- return /* @__PURE__ */ React.createElement(Box, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { color: COLOR.warn, bold: true }, GLYPH.warn), /* @__PURE__ */ React.createElement(Text, null, " "), /* @__PURE__ */ React.createElement(Text, { color: COLOR.warn }, `no files match "@${query}"`), /* @__PURE__ */ React.createElement(Text, { dimColor: true }, " \u2014 keep typing or Backspace; paths resolve from the code root"));
860
- }
861
- const MAX = 8;
862
- const total = matches.length;
863
- const windowStart = total <= MAX ? 0 : Math.max(0, Math.min(selectedIndex - Math.floor(MAX / 2), total - MAX));
864
- const shown = matches.slice(windowStart, windowStart + MAX);
872
+ const color = useColor();
873
+ if (!state) return null;
874
+ const isBrowse = state.kind === "browse";
875
+ const entries = state.entries;
876
+ const total = entries.length;
877
+ const windowStart = total <= ROW_WINDOW ? 0 : Math.max(0, Math.min(selectedIndex - Math.floor(ROW_WINDOW / 2), total - ROW_WINDOW));
878
+ const shown = entries.slice(windowStart, windowStart + ROW_WINDOW);
865
879
  const hiddenAbove = windowStart;
866
880
  const hiddenBelow = total - windowStart - shown.length;
867
- return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: COLOR.primary, bold: true }, "@ "), /* @__PURE__ */ React.createElement(Text, { dimColor: true }, query ? `${total} match${total === 1 ? "" : "es"} for "${query}"` : `${total} file${total === 1 ? "" : "s"}`), hiddenAbove > 0 ? /* @__PURE__ */ React.createElement(Text, { dimColor: true }, ` \u2191 ${hiddenAbove} above`) : null), shown.map((path, i) => /* @__PURE__ */ React.createElement(FileRow, { key: path, path, isSelected: windowStart + i === selectedIndex })), hiddenBelow > 0 ? /* @__PURE__ */ React.createElement(Text, { dimColor: true }, ` \u2193 ${hiddenBelow} below`) : null, /* @__PURE__ */ React.createElement(Box, { marginTop: 0 }, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, " \u2191\u2193 navigate \xB7 Tab / \u23CE insert as @path \xB7 esc cancel")));
881
+ return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React.createElement(HeaderRow, { state, hiddenAbove }), total === 0 ? /* @__PURE__ */ React.createElement(EmptyRow, { state, color }) : null, shown.map((entry, i) => /* @__PURE__ */ React.createElement(
882
+ EntryRow,
883
+ {
884
+ key: `${entry.insertPath}:${entry.isDir ? "d" : "f"}`,
885
+ entry,
886
+ isSelected: windowStart + i === selectedIndex
887
+ }
888
+ )), hiddenBelow > 0 ? /* @__PURE__ */ React.createElement(Text, { dimColor: true }, ` \u2193 ${hiddenBelow} below`) : null, /* @__PURE__ */ React.createElement(FooterRow, { isBrowse, hasFolder: shown.some((e) => e.isDir) }));
868
889
  }
869
- function FileRow({ path, isSelected }) {
870
- const slash = path.lastIndexOf("/");
871
- const dir = slash >= 0 ? `${path.slice(0, slash)}/` : "";
872
- const base = slash >= 0 ? path.slice(slash + 1) : path;
873
- return /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: isSelected ? COLOR.primary : COLOR.info, bold: isSelected }, isSelected ? `${GLYPH.cur} ` : " "), /* @__PURE__ */ React.createElement(Text, { color: COLOR.primary, bold: isSelected }, base.padEnd(20)), dir ? /* @__PURE__ */ React.createElement(Text, { dimColor: true }, ` ${dir}`) : null);
890
+ function HeaderRow({
891
+ state,
892
+ hiddenAbove
893
+ }) {
894
+ const color = useColor();
895
+ const total = state.entries.length;
896
+ const lead = /* @__PURE__ */ React.createElement(Text, { color: color.primary, bold: true }, "@ ");
897
+ if (state.kind === "browse") {
898
+ const where = state.baseDir === "" ? "/" : `${state.baseDir}/`;
899
+ const counter = state.loading ? "loading\u2026" : `${total} ${total === 1 ? "entry" : "entries"}`;
900
+ return /* @__PURE__ */ React.createElement(Box, null, lead, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, `${where} ${counter}`), hiddenAbove > 0 ? /* @__PURE__ */ React.createElement(Text, { dimColor: true }, ` \u2191 ${hiddenAbove} above`) : null);
901
+ }
902
+ const status2 = state.searching ? `searching\u2026 ${state.scanned} scanned \xB7 ${total} ${total === 1 ? "match" : "matches"}` : `${total} ${total === 1 ? "match" : "matches"} for "${state.filter}"`;
903
+ return /* @__PURE__ */ React.createElement(Box, null, lead, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, status2), hiddenAbove > 0 ? /* @__PURE__ */ React.createElement(Text, { dimColor: true }, ` \u2191 ${hiddenAbove} above`) : null);
904
+ }
905
+ function EmptyRow({ state, color }) {
906
+ if (state.kind === "browse") {
907
+ if (state.loading) return null;
908
+ return /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: color.warn, bold: true }, GLYPH.warn), /* @__PURE__ */ React.createElement(Text, null, " "), /* @__PURE__ */ React.createElement(Text, { color: color.warn }, "empty directory"));
909
+ }
910
+ if (state.searching) {
911
+ return /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, "scanning the tree\u2026"));
912
+ }
913
+ return /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: color.warn, bold: true }, GLYPH.warn), /* @__PURE__ */ React.createElement(Text, null, " "), /* @__PURE__ */ React.createElement(Text, { color: color.warn }, `no files match "${state.filter}"`));
914
+ }
915
+ function EntryRow({ entry, isSelected }) {
916
+ const color = useColor();
917
+ const cursor = isSelected ? `${GLYPH.cur} ` : " ";
918
+ const labelColor = entry.isDir ? color.accent : color.primary;
919
+ const labelText = entry.isDir ? `${entry.label}/` : entry.label;
920
+ return /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: isSelected ? color.primary : color.info, bold: isSelected }, cursor), /* @__PURE__ */ React.createElement(Text, { color: labelColor, bold: isSelected }, labelText.padEnd(20)), entry.dirSuffix ? /* @__PURE__ */ React.createElement(Text, { dimColor: true }, ` ${entry.dirSuffix}`) : null);
921
+ }
922
+ function FooterRow({ isBrowse, hasFolder }) {
923
+ const hint = isBrowse ? hasFolder ? "\u2191\u2193 navigate \xB7 Tab drill into folder \xB7 \u23CE insert \xB7 esc cancel" : "\u2191\u2193 navigate \xB7 Tab / \u23CE insert as @path \xB7 esc cancel" : "\u2191\u2193 navigate \xB7 Tab / \u23CE insert as @path \xB7 esc cancel";
924
+ return /* @__PURE__ */ React.createElement(Box, { marginTop: 0 }, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, ` ${hint}`));
874
925
  }
875
926
 
876
927
  // src/cli/ui/CheckpointPicker.tsx
@@ -5264,12 +5315,12 @@ function processMultilineKey(value, cursor, keyIn) {
5264
5315
  return { next: null, cursor: Math.min(value.length, cursor + 1), submit: false };
5265
5316
  }
5266
5317
  if (key.upArrow) {
5267
- if (value.length === 0) return { ...NOOP, chatScrollHandoff: "up" };
5318
+ if (value.length === 0) return { ...NOOP, historyHandoff: "prev" };
5268
5319
  const moved = moveCursorUp(value, cursor);
5269
5320
  return moved === cursor ? NOOP : { next: null, cursor: moved, submit: false };
5270
5321
  }
5271
5322
  if (key.downArrow) {
5272
- if (value.length === 0) return { ...NOOP, chatScrollHandoff: "down" };
5323
+ if (value.length === 0) return { ...NOOP, historyHandoff: "next" };
5273
5324
  const moved = moveCursorDown(value, cursor);
5274
5325
  return moved === cursor ? NOOP : { next: null, cursor: moved, submit: false };
5275
5326
  }
@@ -5622,9 +5673,7 @@ function PromptInput({
5622
5673
  disabled,
5623
5674
  placeholder,
5624
5675
  onHistoryPrev,
5625
- onHistoryNext,
5626
- onChatScrollUp,
5627
- onChatScrollDown
5676
+ onHistoryNext
5628
5677
  }) {
5629
5678
  const inputLineCount = value.length > 0 ? value.split("\n").length : 1;
5630
5679
  const reserveMax = Math.min(Math.ceil(inputLineCount / 4) * 4 + 3, 24);
@@ -5706,8 +5755,6 @@ function PromptInput({
5706
5755
  }
5707
5756
  if (action.historyHandoff === "prev") onHistoryPrev?.();
5708
5757
  if (action.historyHandoff === "next") onHistoryNext?.();
5709
- if (action.chatScrollHandoff === "up") onChatScrollUp?.();
5710
- if (action.chatScrollHandoff === "down") onChatScrollDown?.();
5711
5758
  }, !disabled);
5712
5759
  const { stdout } = useStdout6();
5713
5760
  const cols = stdout?.columns ?? 80;
@@ -6334,13 +6381,14 @@ function SlashArgPicker({
6334
6381
  kind,
6335
6382
  partial
6336
6383
  }) {
6337
- const headerRow = /* @__PURE__ */ React26.createElement(Box22, null, /* @__PURE__ */ React26.createElement(Text22, { color: COLOR.accent, bold: true }, "/ "), /* @__PURE__ */ React26.createElement(Text22, { color: COLOR.accent, bold: true }, `/${spec.cmd}`), spec.argsHint ? /* @__PURE__ */ React26.createElement(Text22, { dimColor: true }, ` ${spec.argsHint}`) : null, /* @__PURE__ */ React26.createElement(Text22, { dimColor: true }, ` ${spec.summary}`));
6384
+ const color = useColor();
6385
+ const headerRow = /* @__PURE__ */ React26.createElement(Box22, null, /* @__PURE__ */ React26.createElement(Text22, { color: color.accent, bold: true }, "/ "), /* @__PURE__ */ React26.createElement(Text22, { color: color.accent, bold: true }, `/${spec.cmd}`), spec.argsHint ? /* @__PURE__ */ React26.createElement(Text22, { dimColor: true }, ` ${spec.argsHint}`) : null, /* @__PURE__ */ React26.createElement(Text22, { dimColor: true }, ` ${spec.summary}`));
6338
6386
  if (kind === "hint") {
6339
6387
  return /* @__PURE__ */ React26.createElement(Box22, { paddingX: 1, marginTop: 1 }, headerRow);
6340
6388
  }
6341
6389
  if (matches === null) return null;
6342
6390
  if (matches.length === 0) {
6343
- return /* @__PURE__ */ React26.createElement(Box22, { flexDirection: "column", paddingX: 1, marginTop: 1 }, headerRow, /* @__PURE__ */ React26.createElement(Box22, null, /* @__PURE__ */ React26.createElement(Text22, { color: COLOR.warn, bold: true }, GLYPH.warn), /* @__PURE__ */ React26.createElement(Text22, { color: COLOR.warn }, ` no match for "${partial}"`), /* @__PURE__ */ React26.createElement(Text22, { dimColor: true }, " \u2014 keep typing, or Backspace to edit")));
6391
+ return /* @__PURE__ */ React26.createElement(Box22, { flexDirection: "column", paddingX: 1, marginTop: 1 }, headerRow, /* @__PURE__ */ React26.createElement(Box22, null, /* @__PURE__ */ React26.createElement(Text22, { color: color.warn, bold: true }, GLYPH.warn), /* @__PURE__ */ React26.createElement(Text22, { color: color.warn }, ` no match for "${partial}"`), /* @__PURE__ */ React26.createElement(Text22, { dimColor: true }, " \u2014 keep typing, or Backspace to edit")));
6344
6392
  }
6345
6393
  const MAX = 8;
6346
6394
  const total = matches.length;
@@ -6351,7 +6399,8 @@ function SlashArgPicker({
6351
6399
  return /* @__PURE__ */ React26.createElement(Box22, { flexDirection: "column", paddingX: 1, marginTop: 1 }, headerRow, hiddenAbove > 0 ? /* @__PURE__ */ React26.createElement(Text22, { dimColor: true }, ` \u2191 ${hiddenAbove} above`) : null, shown.map((value, i) => /* @__PURE__ */ React26.createElement(ArgRow, { key: value, value, isSelected: windowStart + i === selectedIndex })), hiddenBelow > 0 ? /* @__PURE__ */ React26.createElement(Text22, { dimColor: true }, ` \u2193 ${hiddenBelow} below`) : null, /* @__PURE__ */ React26.createElement(Box22, { marginTop: 0 }, /* @__PURE__ */ React26.createElement(Text22, { dimColor: true }, " \u2191\u2193 navigate \xB7 Tab / \u23CE pick \xB7 esc cancel")));
6352
6400
  }
6353
6401
  function ArgRow({ value, isSelected }) {
6354
- return /* @__PURE__ */ React26.createElement(Box22, null, /* @__PURE__ */ React26.createElement(Text22, { color: isSelected ? COLOR.primary : COLOR.info, bold: isSelected }, isSelected ? `${GLYPH.cur} ` : " "), /* @__PURE__ */ React26.createElement(Text22, { color: isSelected ? COLOR.user : COLOR.info, bold: isSelected, dimColor: !isSelected }, value));
6402
+ const color = useColor();
6403
+ return /* @__PURE__ */ React26.createElement(Box22, null, /* @__PURE__ */ React26.createElement(Text22, { color: isSelected ? color.primary : color.info, bold: isSelected }, isSelected ? `${GLYPH.cur} ` : " "), /* @__PURE__ */ React26.createElement(Text22, { color: isSelected ? color.user : color.info, bold: isSelected, dimColor: !isSelected }, value));
6355
6404
  }
6356
6405
 
6357
6406
  // src/cli/ui/SlashSuggestions.tsx
@@ -6373,9 +6422,10 @@ function SlashSuggestions({
6373
6422
  groupMode,
6374
6423
  advancedHidden
6375
6424
  }) {
6425
+ const color = useColor();
6376
6426
  if (matches === null) return null;
6377
6427
  if (matches.length === 0) {
6378
- return /* @__PURE__ */ React27.createElement(Box23, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React27.createElement(Text23, { color: COLOR.warn, bold: true }, GLYPH.warn), /* @__PURE__ */ React27.createElement(Text23, null, " "), /* @__PURE__ */ React27.createElement(Text23, { color: COLOR.warn }, "no slash command matches that prefix"), /* @__PURE__ */ React27.createElement(Text23, { dimColor: true }, " \u2014 Backspace to edit, or /help for the full list"));
6428
+ return /* @__PURE__ */ React27.createElement(Box23, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React27.createElement(Text23, { color: color.warn, bold: true }, GLYPH.warn), /* @__PURE__ */ React27.createElement(Text23, null, " "), /* @__PURE__ */ React27.createElement(Text23, { color: color.warn }, "no slash command matches that prefix"), /* @__PURE__ */ React27.createElement(Text23, { dimColor: true }, " \u2014 Backspace to edit, or /help for the full list"));
6379
6429
  }
6380
6430
  const MAX = groupMode ? 24 : 8;
6381
6431
  const total = matches.length;
@@ -6385,7 +6435,7 @@ function SlashSuggestions({
6385
6435
  const hiddenBelow = total - windowStart - shown.length;
6386
6436
  let lastGroup = null;
6387
6437
  if (windowStart > 0) lastGroup = matches[windowStart - 1]?.group ?? null;
6388
- return /* @__PURE__ */ React27.createElement(Box23, { flexDirection: "column", paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React27.createElement(Box23, null, /* @__PURE__ */ React27.createElement(Text23, { color: COLOR.accent, bold: true }, "/ "), /* @__PURE__ */ React27.createElement(Text23, { dimColor: true }, `${total} command${total === 1 ? "" : "s"}`), hiddenAbove > 0 ? /* @__PURE__ */ React27.createElement(Text23, { dimColor: true }, ` \u2191 ${hiddenAbove} above`) : null), shown.map((spec, i) => {
6438
+ return /* @__PURE__ */ React27.createElement(Box23, { flexDirection: "column", paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React27.createElement(Box23, null, /* @__PURE__ */ React27.createElement(Text23, { color: color.accent, bold: true }, "/ "), /* @__PURE__ */ React27.createElement(Text23, { dimColor: true }, `${total} command${total === 1 ? "" : "s"}`), hiddenAbove > 0 ? /* @__PURE__ */ React27.createElement(Text23, { dimColor: true }, ` \u2191 ${hiddenAbove} above`) : null), shown.map((spec, i) => {
6389
6439
  const idx = windowStart + i;
6390
6440
  const showHeader = groupMode && spec.group !== lastGroup;
6391
6441
  lastGroup = spec.group;
@@ -6393,13 +6443,14 @@ function SlashSuggestions({
6393
6443
  }), hiddenBelow > 0 ? /* @__PURE__ */ React27.createElement(Text23, { dimColor: true }, ` \u2193 ${hiddenBelow} below`) : null, groupMode && advancedHidden && advancedHidden > 0 ? /* @__PURE__ */ React27.createElement(Box23, { marginTop: 1 }, /* @__PURE__ */ React27.createElement(Text23, { dimColor: true }, ` + ${advancedHidden} advanced \xB7 type a letter to search`)) : null, /* @__PURE__ */ React27.createElement(Box23, { marginTop: 0 }, /* @__PURE__ */ React27.createElement(Text23, { dimColor: true }, " \u2191\u2193 navigate \xB7 Tab / \u23CE pick \xB7 esc cancel")));
6394
6444
  }
6395
6445
  function SuggestionRow({ spec, isSelected }) {
6446
+ const color = useColor();
6396
6447
  const name = `/${spec.cmd}`;
6397
6448
  const argsSuffix = spec.argsHint ? spec.argsHint : "";
6398
6449
  const key = `slash.${spec.cmd}.description`;
6399
6450
  const translated = t(key);
6400
6451
  const summary = translated === key ? spec.summary : translated;
6401
6452
  const aliasHint = spec.aliases?.length ? ` \xB7 /${spec.aliases.join(" /")}` : "";
6402
- return /* @__PURE__ */ React27.createElement(Box23, null, /* @__PURE__ */ React27.createElement(Text23, { color: isSelected ? COLOR.primary : COLOR.info, bold: isSelected }, isSelected ? `${GLYPH.cur} ` : " "), /* @__PURE__ */ React27.createElement(Text23, { color: COLOR.accent, bold: isSelected }, name.padEnd(14)), /* @__PURE__ */ React27.createElement(Text23, { dimColor: true }, argsSuffix.padEnd(14)), /* @__PURE__ */ React27.createElement(Text23, null, " "), /* @__PURE__ */ React27.createElement(Text23, { color: isSelected ? COLOR.user : COLOR.info, dimColor: !isSelected }, summary), aliasHint ? /* @__PURE__ */ React27.createElement(Text23, { dimColor: true }, aliasHint) : null);
6453
+ return /* @__PURE__ */ React27.createElement(Box23, null, /* @__PURE__ */ React27.createElement(Text23, { color: isSelected ? color.primary : color.info, bold: isSelected }, isSelected ? `${GLYPH.cur} ` : " "), /* @__PURE__ */ React27.createElement(Text23, { color: color.accent, bold: isSelected }, name.padEnd(14)), /* @__PURE__ */ React27.createElement(Text23, { dimColor: true }, argsSuffix.padEnd(14)), /* @__PURE__ */ React27.createElement(Text23, null, " "), /* @__PURE__ */ React27.createElement(Text23, { color: isSelected ? color.user : color.info, dimColor: !isSelected }, summary), aliasHint ? /* @__PURE__ */ React27.createElement(Text23, { dimColor: true }, aliasHint) : null);
6403
6454
  }
6404
6455
 
6405
6456
  // src/cli/ui/WelcomeBanner.tsx
@@ -7152,6 +7203,16 @@ function reduce(state, event) {
7152
7203
  text: event.text,
7153
7204
  meta: event.meta
7154
7205
  });
7206
+ case "tip.show":
7207
+ return appendCard(state, {
7208
+ kind: "tip",
7209
+ id: event.id,
7210
+ ts: event.ts,
7211
+ topic: event.topic,
7212
+ sections: event.sections,
7213
+ footer: event.footer,
7214
+ oneTime: event.oneTime
7215
+ });
7155
7216
  case "session.reset":
7156
7217
  return { ...state, cards: [], focusedCardId: null, toasts: [] };
7157
7218
  case "plan.show":
@@ -7457,6 +7518,22 @@ ${stack}` : message
7457
7518
  });
7458
7519
  return id;
7459
7520
  },
7521
+ pushTip({ topic, sections, footer, oneTime = true }) {
7522
+ const id = nextId2("tip");
7523
+ dispatch({
7524
+ type: "tip.show",
7525
+ id,
7526
+ ts: Date.now(),
7527
+ topic,
7528
+ sections: sections.map((s) => ({
7529
+ title: s.title,
7530
+ rows: s.rows.map((r) => ({ key: r.key, text: r.text }))
7531
+ })),
7532
+ footer,
7533
+ oneTime
7534
+ });
7535
+ return id;
7536
+ },
7460
7537
  pushCtxPressureIfHigh(usedTokens, ctxMax) {
7461
7538
  if (ctxMax <= 0) return;
7462
7539
  const pct = usedTokens / ctxMax * 100;
@@ -7621,12 +7698,12 @@ function useTranscriptWriter(transcriptRef, model2, prefixHash) {
7621
7698
  }
7622
7699
 
7623
7700
  // src/cli/ui/layout/CardStream.tsx
7624
- import { Box as Box43, Text as Text45, useBoxMetrics } from "ink";
7625
- import React52, { useEffect as useEffect7, useRef as useRef4 } from "react";
7701
+ import { Box as Box44, Text as Text46, useBoxMetrics } from "ink";
7702
+ import React53, { useEffect as useEffect7, useRef as useRef4 } from "react";
7626
7703
 
7627
7704
  // src/cli/ui/cards/CardRenderer.tsx
7628
- import { Box as Box42, Text as Text44 } from "ink";
7629
- import React51 from "react";
7705
+ import { Box as Box43, Text as Text45 } from "ink";
7706
+ import React52 from "react";
7630
7707
 
7631
7708
  // src/cli/ui/cards/CtxCard.tsx
7632
7709
  import { Box as Box27, Text as Text26 } from "ink";
@@ -7750,11 +7827,6 @@ function DiffCard({ card }) {
7750
7827
  // src/cli/ui/cards/DoctorCard.tsx
7751
7828
  import { Box as Box29, Text as Text28 } from "ink";
7752
7829
  import React34 from "react";
7753
- var LEVEL_COLOR = {
7754
- ok: TONE.ok,
7755
- warn: TONE.warn,
7756
- fail: TONE.err
7757
- };
7758
7830
  var LEVEL_GLYPH = {
7759
7831
  ok: "\u2713",
7760
7832
  warn: "\u26A0",
@@ -7766,12 +7838,18 @@ var LEVEL_TAG = {
7766
7838
  fail: "FAIL"
7767
7839
  };
7768
7840
  function DoctorCard({ card }) {
7841
+ const { fg, tone } = useThemeTokens();
7842
+ const levelColor = {
7843
+ ok: tone.ok,
7844
+ warn: tone.warn,
7845
+ fail: tone.err
7846
+ };
7769
7847
  const ok = card.checks.filter((c) => c.level === "ok").length;
7770
7848
  const warn = card.checks.filter((c) => c.level === "warn").length;
7771
7849
  const fail = card.checks.filter((c) => c.level === "fail").length;
7772
7850
  const labelWidth = card.checks.reduce((m, c) => Math.max(m, c.label.length), 0);
7773
7851
  const summary = `${card.checks.length} checks \xB7 ${ok} passed${warn > 0 ? ` \xB7 ${warn} warn` : ""}${fail > 0 ? ` \xB7 ${fail} fail` : ""}`;
7774
- return /* @__PURE__ */ React34.createElement(Card, { tone: CARD.tool.color }, /* @__PURE__ */ React34.createElement(CardHeader, { glyph: "\u2695", tone: CARD.tool.color, title: "doctor", meta: [summary] }), card.checks.map((c) => /* @__PURE__ */ React34.createElement(Box29, { key: c.label, flexDirection: "row", gap: 1 }, /* @__PURE__ */ React34.createElement(Text28, { color: LEVEL_COLOR[c.level] }, LEVEL_GLYPH[c.level]), /* @__PURE__ */ React34.createElement(Text28, { bold: true, color: FG.body }, c.label.padEnd(labelWidth + 1)), /* @__PURE__ */ React34.createElement(Text28, { color: FG.sub }, c.detail), /* @__PURE__ */ React34.createElement(Text28, { color: LEVEL_COLOR[c.level] }, LEVEL_TAG[c.level]))));
7852
+ return /* @__PURE__ */ React34.createElement(Card, { tone: CARD.tool.color }, /* @__PURE__ */ React34.createElement(CardHeader, { glyph: "\u2695", tone: CARD.tool.color, title: "doctor", meta: [summary] }), card.checks.map((c) => /* @__PURE__ */ React34.createElement(Box29, { key: c.label, flexDirection: "row", gap: 1 }, /* @__PURE__ */ React34.createElement(Text28, { color: levelColor[c.level] }, LEVEL_GLYPH[c.level]), /* @__PURE__ */ React34.createElement(Text28, { bold: true, color: fg.body }, c.label.padEnd(labelWidth + 1)), /* @__PURE__ */ React34.createElement(Text28, { color: fg.sub }, c.detail), /* @__PURE__ */ React34.createElement(Text28, { color: levelColor[c.level] }, LEVEL_TAG[c.level]))));
7775
7853
  }
7776
7854
 
7777
7855
  // src/cli/ui/cards/ErrorCard.tsx
@@ -7911,27 +7989,28 @@ var STATUS_GLYPH = {
7911
7989
  blocked: "!",
7912
7990
  skipped: "s"
7913
7991
  };
7914
- var STATUS_COLOR = {
7915
- queued: FG.faint,
7916
- running: TONE_ACTIVE.brand,
7917
- done: TONE.ok,
7918
- failed: TONE.err,
7919
- blocked: TONE.warn,
7920
- skipped: FG.faint
7921
- };
7922
7992
  var VISIBLE_WINDOW = 5;
7923
7993
  function PlanCard({ card }) {
7994
+ const { fg, tone, toneActive } = useThemeTokens();
7995
+ const statusColor = {
7996
+ queued: fg.faint,
7997
+ running: toneActive.brand,
7998
+ done: tone.ok,
7999
+ failed: tone.err,
8000
+ blocked: tone.warn,
8001
+ skipped: fg.faint
8002
+ };
7924
8003
  const doneCount = card.steps.filter((s) => s.status === "done").length;
7925
8004
  const variantTag = card.variant === "resumed" ? "resumed \xB7 " : card.variant === "replay" ? "\u23EA archive \xB7 " : "";
7926
8005
  const progress = `${variantTag}${doneCount}/${card.steps.length} done`;
7927
8006
  const hasRunning = card.steps.some((s) => s.status === "running");
7928
- const tone = hasRunning ? TONE_ACTIVE.accent : TONE.accent;
8007
+ const cardTone = hasRunning ? toneActive.accent : tone.accent;
7929
8008
  const window = pickWindow(card.steps);
7930
- return /* @__PURE__ */ React39.createElement(Card, { tone }, /* @__PURE__ */ React39.createElement(CardHeader, { glyph: "\u229E", tone, title: card.title, meta: [progress] }), window.hiddenBefore > 0 ? /* @__PURE__ */ React39.createElement(Box33, { flexDirection: "row", gap: 1 }, /* @__PURE__ */ React39.createElement(Text33, { color: TONE.ok }, "\u2713"), /* @__PURE__ */ React39.createElement(Text33, { color: FG.faint }, `\u22EF ${window.hiddenBefore} done`)) : null, window.steps.map((step) => {
8009
+ return /* @__PURE__ */ React39.createElement(Card, { tone: cardTone }, /* @__PURE__ */ React39.createElement(CardHeader, { glyph: "\u229E", tone: cardTone, title: card.title, meta: [progress] }), window.hiddenBefore > 0 ? /* @__PURE__ */ React39.createElement(Box33, { flexDirection: "row", gap: 1 }, /* @__PURE__ */ React39.createElement(Text33, { color: tone.ok }, "\u2713"), /* @__PURE__ */ React39.createElement(Text33, { color: fg.faint }, `\u22EF ${window.hiddenBefore} done`)) : null, window.steps.map((step) => {
7931
8010
  const isActive = step.status === "running";
7932
- const titleColor = isActive ? FG.strong : FG.sub;
7933
- return /* @__PURE__ */ React39.createElement(Box33, { key: step.id, flexDirection: "row", gap: 1 }, /* @__PURE__ */ React39.createElement(Text33, { color: STATUS_COLOR[step.status] }, STATUS_GLYPH[step.status]), /* @__PURE__ */ React39.createElement(Text33, { bold: isActive, color: titleColor }, `${step.indexLabel}. ${step.title}`), isActive ? /* @__PURE__ */ React39.createElement(Text33, { color: TONE_ACTIVE.brand }, "\u2190 in progress") : null);
7934
- }), window.hiddenAfter > 0 ? /* @__PURE__ */ React39.createElement(Box33, { flexDirection: "row", gap: 1 }, /* @__PURE__ */ React39.createElement(Text33, { color: FG.faint }, "\u25CB"), /* @__PURE__ */ React39.createElement(Text33, { color: FG.faint }, `\u22EF ${window.hiddenAfter} upcoming`)) : null);
8011
+ const titleColor = isActive ? fg.strong : fg.sub;
8012
+ return /* @__PURE__ */ React39.createElement(Box33, { key: step.id, flexDirection: "row", gap: 1 }, /* @__PURE__ */ React39.createElement(Text33, { color: statusColor[step.status] }, STATUS_GLYPH[step.status]), /* @__PURE__ */ React39.createElement(Text33, { bold: isActive, color: titleColor }, `${step.indexLabel}. ${step.title}`), isActive ? /* @__PURE__ */ React39.createElement(Text33, { color: toneActive.brand }, "\u2190 in progress") : null);
8013
+ }), window.hiddenAfter > 0 ? /* @__PURE__ */ React39.createElement(Box33, { flexDirection: "row", gap: 1 }, /* @__PURE__ */ React39.createElement(Text33, { color: fg.faint }, "\u25CB"), /* @__PURE__ */ React39.createElement(Text33, { color: fg.faint }, `\u22EF ${window.hiddenAfter} upcoming`)) : null);
7935
8014
  }
7936
8015
  function pickWindow(steps) {
7937
8016
  if (steps.length <= VISIBLE_WINDOW) {
@@ -8544,13 +8623,14 @@ function StreamingCard({ card }) {
8544
8623
  // src/cli/ui/cards/SubAgentCard.tsx
8545
8624
  import { Box as Box38, Text as Text39 } from "ink";
8546
8625
  import React45, { useContext as useContext6 } from "react";
8547
- var STATUS_COLOR2 = {
8548
- running: TONE_ACTIVE.violet,
8549
- done: TONE.ok,
8550
- failed: TONE.err
8551
- };
8552
8626
  function SubAgentCard({ card }) {
8553
- const headColor = STATUS_COLOR2[card.status];
8627
+ const { fg, tone, toneActive } = useThemeTokens();
8628
+ const statusColor = {
8629
+ running: toneActive.violet,
8630
+ done: tone.ok,
8631
+ failed: tone.err
8632
+ };
8633
+ const headColor = statusColor[card.status];
8554
8634
  const headGlyph = card.status === "failed" ? "\u2716" : "\u232C";
8555
8635
  const runningChildren = card.children.filter((c) => !isChildDone(c)).length;
8556
8636
  const isRunning = card.status === "running";
@@ -8562,11 +8642,11 @@ function SubAgentCard({ card }) {
8562
8642
  glyph: headGlyph,
8563
8643
  tone: headColor,
8564
8644
  title: "subagent",
8565
- titleColor: TONE.violet,
8645
+ titleColor: tone.violet,
8566
8646
  subtitle: card.task,
8567
8647
  meta: headerMeta2
8568
8648
  }
8569
- ), card.name ? /* @__PURE__ */ React45.createElement(Text39, { color: FG.faint }, `agent \xB7 ${card.name}`) : null, card.tools && card.tools.length > 0 && /* @__PURE__ */ React45.createElement(Text39, { color: FG.faint }, `tools \xB7 ${card.tools.join(", ")}`), card.children.map((child) => /* @__PURE__ */ React45.createElement(Box38, { key: child.id, flexDirection: "row", gap: 1 }, inLive ? null : /* @__PURE__ */ React45.createElement(Text39, { color: TONE.violet }, "\u258E"), /* @__PURE__ */ React45.createElement(ChildRow, { card: child }))));
8649
+ ), card.name ? /* @__PURE__ */ React45.createElement(Text39, { color: fg.faint }, `agent \xB7 ${card.name}`) : null, card.tools && card.tools.length > 0 && /* @__PURE__ */ React45.createElement(Text39, { color: fg.faint }, `tools \xB7 ${card.tools.join(", ")}`), card.children.map((child) => /* @__PURE__ */ React45.createElement(Box38, { key: child.id, flexDirection: "row", gap: 1 }, inLive ? null : /* @__PURE__ */ React45.createElement(Text39, { color: tone.violet }, "\u258E"), /* @__PURE__ */ React45.createElement(ChildRow, { card: child }))));
8570
8650
  }
8571
8651
  function isChildDone(card) {
8572
8652
  switch (card.kind) {
@@ -8580,9 +8660,10 @@ function isChildDone(card) {
8580
8660
  }
8581
8661
  }
8582
8662
  function ChildRow({ card }) {
8583
- const v = childVisual(card);
8663
+ const { fg, tone } = useThemeTokens();
8664
+ const v = childVisual(card, tone.ok, tone.err, fg.faint);
8584
8665
  const isDone = isChildDone(card);
8585
- return /* @__PURE__ */ React45.createElement(React45.Fragment, null, v.statusGlyph, /* @__PURE__ */ React45.createElement(Text39, { color: v.kindColor }, v.kindGlyph), /* @__PURE__ */ React45.createElement(Text39, { dimColor: isDone, color: FG.body }, v.text));
8666
+ return /* @__PURE__ */ React45.createElement(React45.Fragment, null, v.statusGlyph, /* @__PURE__ */ React45.createElement(Text39, { color: v.kindColor }, v.kindGlyph), /* @__PURE__ */ React45.createElement(Text39, { dimColor: isDone, color: fg.body }, v.text));
8586
8667
  }
8587
8668
  function runningGlyph(color) {
8588
8669
  return /* @__PURE__ */ React45.createElement(Spinner, { kind: "circle", color });
@@ -8590,15 +8671,15 @@ function runningGlyph(color) {
8590
8671
  function doneGlyph(color) {
8591
8672
  return /* @__PURE__ */ React45.createElement(Text39, { color }, "\u2713");
8592
8673
  }
8593
- function failedGlyph() {
8594
- return /* @__PURE__ */ React45.createElement(Text39, { color: TONE.err }, "\u2716");
8674
+ function failedGlyph(color) {
8675
+ return /* @__PURE__ */ React45.createElement(Text39, { color }, "\u2716");
8595
8676
  }
8596
- function childVisual(card) {
8677
+ function childVisual(card, doneColor, failedColor, fallbackColor) {
8597
8678
  switch (card.kind) {
8598
8679
  case "reasoning": {
8599
8680
  const done = !card.streaming;
8600
8681
  return {
8601
- statusGlyph: done ? doneGlyph(TONE.ok) : runningGlyph(CARD.reasoning.color),
8682
+ statusGlyph: done ? doneGlyph(doneColor) : runningGlyph(CARD.reasoning.color),
8602
8683
  kindGlyph: "\u25C6",
8603
8684
  kindColor: CARD.reasoning.color,
8604
8685
  text: `reasoning \xB7 ${card.paragraphs} \xB6`
@@ -8607,7 +8688,7 @@ function childVisual(card) {
8607
8688
  case "tool": {
8608
8689
  const elapsed = card.elapsedMs > 0 ? ` \xB7 ${(card.elapsedMs / 1e3).toFixed(2)}s` : "";
8609
8690
  return {
8610
- statusGlyph: card.done ? doneGlyph(TONE.ok) : runningGlyph(CARD.tool.color),
8691
+ statusGlyph: card.done ? doneGlyph(doneColor) : runningGlyph(CARD.tool.color),
8611
8692
  kindGlyph: "\u25A3",
8612
8693
  kindColor: CARD.tool.color,
8613
8694
  text: `${card.name}${elapsed}`
@@ -8615,30 +8696,30 @@ function childVisual(card) {
8615
8696
  }
8616
8697
  case "streaming":
8617
8698
  return {
8618
- statusGlyph: card.done ? doneGlyph(TONE.ok) : runningGlyph(CARD.streaming.color),
8699
+ statusGlyph: card.done ? doneGlyph(doneColor) : runningGlyph(CARD.streaming.color),
8619
8700
  kindGlyph: "\u25C8",
8620
8701
  kindColor: CARD.streaming.color,
8621
8702
  text: card.done ? "response" : "writing \u2026"
8622
8703
  };
8623
8704
  case "diff":
8624
8705
  return {
8625
- statusGlyph: doneGlyph(TONE.ok),
8706
+ statusGlyph: doneGlyph(doneColor),
8626
8707
  kindGlyph: "\xB1",
8627
8708
  kindColor: CARD.diff.color,
8628
8709
  text: card.file
8629
8710
  };
8630
8711
  case "error":
8631
8712
  return {
8632
- statusGlyph: failedGlyph(),
8713
+ statusGlyph: failedGlyph(failedColor),
8633
8714
  kindGlyph: "\u2716",
8634
8715
  kindColor: CARD.error.color,
8635
8716
  text: card.title
8636
8717
  };
8637
8718
  default:
8638
8719
  return {
8639
- statusGlyph: /* @__PURE__ */ React45.createElement(Text39, { color: FG.faint }, "\xB7"),
8720
+ statusGlyph: /* @__PURE__ */ React45.createElement(Text39, { color: fallbackColor }, "\xB7"),
8640
8721
  kindGlyph: "\xB7",
8641
- kindColor: FG.faint,
8722
+ kindColor: fallbackColor,
8642
8723
  text: card.kind
8643
8724
  };
8644
8725
  }
@@ -8653,39 +8734,70 @@ var STEP_GLYPH = {
8653
8734
  done: "\u2713",
8654
8735
  failed: "\u2717"
8655
8736
  };
8656
- var STEP_COLOR = {
8657
- queued: FG.faint,
8658
- running: TONE.warn,
8659
- done: TONE.ok,
8660
- failed: TONE.err
8661
- };
8662
- var TASK_COLOR = {
8663
- running: TONE.warn,
8664
- done: TONE.ok,
8665
- failed: TONE.err
8666
- };
8667
8737
  var TASK_GLYPH = {
8668
8738
  running: "\u25B6",
8669
8739
  done: "\u2713",
8670
8740
  failed: "\u2717"
8671
8741
  };
8672
8742
  function TaskCard({ card }) {
8743
+ const { fg, tone } = useThemeTokens();
8744
+ const stepColor = {
8745
+ queued: fg.faint,
8746
+ running: tone.warn,
8747
+ done: tone.ok,
8748
+ failed: tone.err
8749
+ };
8750
+ const taskColor = {
8751
+ running: tone.warn,
8752
+ done: tone.ok,
8753
+ failed: tone.err
8754
+ };
8673
8755
  const elapsed = `${(card.elapsedMs / 1e3).toFixed(1)}s`;
8674
- return /* @__PURE__ */ React46.createElement(Card, { tone: TASK_COLOR[card.status] }, /* @__PURE__ */ React46.createElement(
8756
+ return /* @__PURE__ */ React46.createElement(Card, { tone: taskColor[card.status] }, /* @__PURE__ */ React46.createElement(
8675
8757
  CardHeader,
8676
8758
  {
8677
8759
  glyph: TASK_GLYPH[card.status],
8678
- tone: TASK_COLOR[card.status],
8760
+ tone: taskColor[card.status],
8679
8761
  title: `step ${card.index}/${card.total}`,
8680
8762
  subtitle: card.title,
8681
8763
  meta: [elapsed, card.status]
8682
8764
  }
8683
- ), card.steps.map((step) => /* @__PURE__ */ React46.createElement(Box39, { key: step.id, flexDirection: "row", gap: 1 }, /* @__PURE__ */ React46.createElement(Text40, { color: STEP_COLOR[step.status] }, STEP_GLYPH[step.status]), /* @__PURE__ */ React46.createElement(Text40, { bold: true, color: FG.body }, (step.toolName ?? "step").padEnd(7)), /* @__PURE__ */ React46.createElement(Text40, { color: FG.sub }, step.title), step.detail ? /* @__PURE__ */ React46.createElement(Text40, { color: FG.faint }, step.detail) : null, step.elapsedMs !== void 0 ? /* @__PURE__ */ React46.createElement(Text40, { color: FG.faint }, `${(step.elapsedMs / 1e3).toFixed(2)}s`) : null)));
8765
+ ), card.steps.map((step) => /* @__PURE__ */ React46.createElement(Box39, { key: step.id, flexDirection: "row", gap: 1 }, /* @__PURE__ */ React46.createElement(Text40, { color: stepColor[step.status] }, STEP_GLYPH[step.status]), /* @__PURE__ */ React46.createElement(Text40, { bold: true, color: fg.body }, (step.toolName ?? "step").padEnd(7)), /* @__PURE__ */ React46.createElement(Text40, { color: fg.sub }, step.title), step.detail ? /* @__PURE__ */ React46.createElement(Text40, { color: fg.faint }, step.detail) : null, step.elapsedMs !== void 0 ? /* @__PURE__ */ React46.createElement(Text40, { color: fg.faint }, `${(step.elapsedMs / 1e3).toFixed(2)}s`) : null)));
8684
8766
  }
8685
8767
 
8686
- // src/cli/ui/cards/ToolCard.tsx
8687
- import { Text as Text41, useStdout as useStdout11 } from "ink";
8768
+ // src/cli/ui/cards/TipCard.tsx
8769
+ import { Box as Box40, Text as Text41 } from "ink";
8688
8770
  import React47 from "react";
8771
+ import stringWidth2 from "string-width";
8772
+ var KEY_GUTTER = 4;
8773
+ function TipCard({ card }) {
8774
+ const keyWidth = card.sections.reduce(
8775
+ (max, sec) => sec.rows.reduce((m, r) => Math.max(m, stringWidth2(r.key)), max),
8776
+ 0
8777
+ );
8778
+ return /* @__PURE__ */ React47.createElement(Box40, { flexDirection: "column", paddingLeft: 2, marginY: 1 }, /* @__PURE__ */ React47.createElement(Box40, { flexDirection: "row", justifyContent: "space-between" }, /* @__PURE__ */ React47.createElement(Box40, { flexDirection: "row", gap: 1 }, /* @__PURE__ */ React47.createElement(Text41, { color: TONE.accent, bold: true }, "\u24D8"), /* @__PURE__ */ React47.createElement(Text41, { color: FG.body, bold: true }, card.topic)), card.oneTime ? /* @__PURE__ */ React47.createElement(Text41, { color: FG.faint }, t("ui.tipShownOnce")) : null), card.sections.map((section, i) => /* @__PURE__ */ React47.createElement(Box40, { key: section.title ?? `section-${i}`, flexDirection: "column", marginTop: 1 }, section.title ? /* @__PURE__ */ React47.createElement(Box40, { marginBottom: 0 }, /* @__PURE__ */ React47.createElement(Text41, { color: FG.sub }, section.title)) : null, section.rows.map((row2) => /* @__PURE__ */ React47.createElement(
8779
+ TipRowRender,
8780
+ {
8781
+ key: row2.key,
8782
+ row: row2,
8783
+ keyWidth,
8784
+ indent: section.title ? 2 : 0
8785
+ }
8786
+ )))), card.footer ? /* @__PURE__ */ React47.createElement(Box40, { marginTop: 1 }, /* @__PURE__ */ React47.createElement(Text41, { color: FG.faint }, card.footer)) : null);
8787
+ }
8788
+ function TipRowRender({
8789
+ row: row2,
8790
+ keyWidth,
8791
+ indent
8792
+ }) {
8793
+ const pad = " ".repeat(Math.max(0, keyWidth - stringWidth2(row2.key) + KEY_GUTTER));
8794
+ const lead = indent > 0 ? " ".repeat(indent) : "";
8795
+ return /* @__PURE__ */ React47.createElement(Box40, { flexDirection: "row" }, lead ? /* @__PURE__ */ React47.createElement(Text41, null, lead) : null, /* @__PURE__ */ React47.createElement(Text41, { color: TONE.accent }, row2.key), /* @__PURE__ */ React47.createElement(Text41, null, pad), /* @__PURE__ */ React47.createElement(Text41, { color: FG.body }, row2.text));
8796
+ }
8797
+
8798
+ // src/cli/ui/cards/ToolCard.tsx
8799
+ import { Text as Text42, useStdout as useStdout11 } from "ink";
8800
+ import React48 from "react";
8689
8801
  var READ_TAIL = 2;
8690
8802
  var OTHER_TAIL = 5;
8691
8803
  function tailLinesFor(name) {
@@ -8714,7 +8826,7 @@ function ToolCard({ card }) {
8714
8826
  meta.push({ text: "rejected", color: TONE.err });
8715
8827
  }
8716
8828
  for (const part of metaTrail(card)) meta.push(part);
8717
- return /* @__PURE__ */ React47.createElement(Card, { tone: headColor }, /* @__PURE__ */ React47.createElement(
8829
+ return /* @__PURE__ */ React48.createElement(Card, { tone: headColor }, /* @__PURE__ */ React48.createElement(
8718
8830
  CardHeader,
8719
8831
  {
8720
8832
  glyph: statusGlyph2(status2),
@@ -8722,10 +8834,10 @@ function ToolCard({ card }) {
8722
8834
  title: card.name,
8723
8835
  subtitle: argsLabel || void 0,
8724
8836
  meta: meta.length > 0 ? meta : void 0,
8725
- right: status2 === "running" ? /* @__PURE__ */ React47.createElement(Spinner, { kind: "braille", color: TONE_ACTIVE.brand, bold: true }) : void 0
8837
+ right: status2 === "running" ? /* @__PURE__ */ React48.createElement(Spinner, { kind: "braille", color: TONE_ACTIVE.brand, bold: true }) : void 0
8726
8838
  }
8727
- ), showBody && /* @__PURE__ */ React47.createElement(React47.Fragment, null, hidden > 0 ? /* @__PURE__ */ React47.createElement(Text41, { color: FG.faint }, `\u22EE ${hidden} earlier line${hidden === 1 ? "" : "s"} (use /tool to read full)`) : null, visible.map((line, i) => /* @__PURE__ */ React47.createElement(
8728
- Text41,
8839
+ ), showBody && /* @__PURE__ */ React48.createElement(React48.Fragment, null, hidden > 0 ? /* @__PURE__ */ React48.createElement(Text42, { color: FG.faint }, `\u22EE ${hidden} earlier line${hidden === 1 ? "" : "s"} (use /tool to read full)`) : null, visible.map((line, i) => /* @__PURE__ */ React48.createElement(
8840
+ Text42,
8729
8841
  {
8730
8842
  key: `${card.id}:${hidden + i}`,
8731
8843
  color: errColor,
@@ -8780,15 +8892,15 @@ function metaTrail(card) {
8780
8892
  function formatArgsSummary(args) {
8781
8893
  if (typeof args === "string") return args.length > 60 ? `${args.slice(0, 60)}\u2026` : args;
8782
8894
  if (args && typeof args === "object") {
8783
- const keys = Object.keys(args);
8784
- if (keys.length === 0) return "";
8785
- const first = keys[0];
8895
+ const keys2 = Object.keys(args);
8896
+ if (keys2.length === 0) return "";
8897
+ const first = keys2[0];
8786
8898
  const value = args[first];
8787
8899
  if (typeof value === "string") {
8788
8900
  const trimmed = value.length > 40 ? `${value.slice(0, 40)}\u2026` : value;
8789
- return keys.length === 1 ? trimmed : `${trimmed} +${keys.length - 1}`;
8901
+ return keys2.length === 1 ? trimmed : `${trimmed} +${keys2.length - 1}`;
8790
8902
  }
8791
- return keys.join(" ");
8903
+ return keys2.join(" ");
8792
8904
  }
8793
8905
  return "";
8794
8906
  }
@@ -8811,8 +8923,8 @@ function formatBytes(n) {
8811
8923
  }
8812
8924
 
8813
8925
  // src/cli/ui/cards/UsageCard.tsx
8814
- import { Box as Box41, Text as Text42 } from "ink";
8815
- import React48 from "react";
8926
+ import { Box as Box42, Text as Text43 } from "ink";
8927
+ import React49 from "react";
8816
8928
  var BAR_CELLS2 = 30;
8817
8929
  function compactNum(n) {
8818
8930
  if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
@@ -8822,25 +8934,25 @@ function compactNum(n) {
8822
8934
  function bar(ratio, color) {
8823
8935
  const filled = Math.max(0, Math.min(BAR_CELLS2, Math.round(ratio * BAR_CELLS2)));
8824
8936
  const empty = BAR_CELLS2 - filled;
8825
- return /* @__PURE__ */ React48.createElement(React48.Fragment, null, /* @__PURE__ */ React48.createElement(Text42, { color }, "\u2588".repeat(filled)), /* @__PURE__ */ React48.createElement(Text42, { color: FG.faint }, "\u2591".repeat(empty)));
8937
+ return /* @__PURE__ */ React49.createElement(React49.Fragment, null, /* @__PURE__ */ React49.createElement(Text43, { color }, "\u2588".repeat(filled)), /* @__PURE__ */ React49.createElement(Text43, { color: FG.faint }, "\u2591".repeat(empty)));
8826
8938
  }
8827
8939
  function UsageCard({ card }) {
8828
- if (card.compact) return /* @__PURE__ */ React48.createElement(CompactUsageRow, { card });
8940
+ if (card.compact) return /* @__PURE__ */ React49.createElement(CompactUsageRow, { card });
8829
8941
  const cap = Math.max(1, card.tokens.promptCap);
8830
8942
  const promptRatio = card.tokens.prompt / cap;
8831
8943
  const reasonRatio = card.tokens.reason / cap;
8832
8944
  const outputRatio = card.tokens.output / cap;
8833
8945
  const headerMeta2 = [`turn ${card.turn}`, formatCost(card.cost, card.balanceCurrency)];
8834
8946
  if (card.elapsedMs !== void 0) headerMeta2.push(`${(card.elapsedMs / 1e3).toFixed(1)}s`);
8835
- return /* @__PURE__ */ React48.createElement(Card, { tone: FG.meta }, /* @__PURE__ */ React48.createElement(CardHeader, { glyph: "\u03A3", tone: FG.meta, title: "usage", meta: headerMeta2 }), /* @__PURE__ */ React48.createElement(Box41, { flexDirection: "row", gap: 1 }, /* @__PURE__ */ React48.createElement(Text42, { color: FG.sub }, "prompt"), bar(promptRatio, TONE.brand), /* @__PURE__ */ React48.createElement(Text42, { bold: true, color: FG.body }, card.tokens.prompt.toLocaleString()), /* @__PURE__ */ React48.createElement(Text42, { color: FG.faint }, `/ 1M \xB7 ${(promptRatio * 100).toFixed(1)}%`)), /* @__PURE__ */ React48.createElement(Box41, { flexDirection: "row", gap: 1 }, /* @__PURE__ */ React48.createElement(Text42, { color: FG.sub }, "reason"), bar(reasonRatio, TONE.accent), /* @__PURE__ */ React48.createElement(Text42, { bold: true, color: FG.body }, card.tokens.reason.toLocaleString())), /* @__PURE__ */ React48.createElement(Box41, { flexDirection: "row", gap: 1 }, /* @__PURE__ */ React48.createElement(Text42, { color: FG.sub }, "output"), bar(outputRatio, TONE.brand), /* @__PURE__ */ React48.createElement(Text42, { bold: true, color: FG.body }, card.tokens.output.toLocaleString())), /* @__PURE__ */ React48.createElement(Box41, { flexDirection: "row", gap: 1 }, /* @__PURE__ */ React48.createElement(Text42, { color: FG.sub }, "cache "), bar(card.cacheHit, TONE.ok), /* @__PURE__ */ React48.createElement(Text42, { bold: true, color: TONE.ok }, `${(card.cacheHit * 100).toFixed(1)}%`)), /* @__PURE__ */ React48.createElement(Box41, { flexDirection: "row", gap: 1 }, /* @__PURE__ */ React48.createElement(Text42, { color: FG.faint }, "session"), /* @__PURE__ */ React48.createElement(Text42, { bold: true, color: FG.body }, `\u26C1 ${formatCost(card.sessionCost, card.balanceCurrency, 3)}`), card.balance !== void 0 ? /* @__PURE__ */ React48.createElement(React48.Fragment, null, /* @__PURE__ */ React48.createElement(Text42, { color: FG.faint }, "\xB7 balance"), /* @__PURE__ */ React48.createElement(Text42, { bold: true, color: TONE.brand }, formatBalance(card.balance, card.balanceCurrency))) : null));
8947
+ return /* @__PURE__ */ React49.createElement(Card, { tone: FG.meta }, /* @__PURE__ */ React49.createElement(CardHeader, { glyph: "\u03A3", tone: FG.meta, title: "usage", meta: headerMeta2 }), /* @__PURE__ */ React49.createElement(Box42, { flexDirection: "row", gap: 1 }, /* @__PURE__ */ React49.createElement(Text43, { color: FG.sub }, "prompt"), bar(promptRatio, TONE.brand), /* @__PURE__ */ React49.createElement(Text43, { bold: true, color: FG.body }, card.tokens.prompt.toLocaleString()), /* @__PURE__ */ React49.createElement(Text43, { color: FG.faint }, `/ 1M \xB7 ${(promptRatio * 100).toFixed(1)}%`)), /* @__PURE__ */ React49.createElement(Box42, { flexDirection: "row", gap: 1 }, /* @__PURE__ */ React49.createElement(Text43, { color: FG.sub }, "reason"), bar(reasonRatio, TONE.accent), /* @__PURE__ */ React49.createElement(Text43, { bold: true, color: FG.body }, card.tokens.reason.toLocaleString())), /* @__PURE__ */ React49.createElement(Box42, { flexDirection: "row", gap: 1 }, /* @__PURE__ */ React49.createElement(Text43, { color: FG.sub }, "output"), bar(outputRatio, TONE.brand), /* @__PURE__ */ React49.createElement(Text43, { bold: true, color: FG.body }, card.tokens.output.toLocaleString())), /* @__PURE__ */ React49.createElement(Box42, { flexDirection: "row", gap: 1 }, /* @__PURE__ */ React49.createElement(Text43, { color: FG.sub }, "cache "), bar(card.cacheHit, TONE.ok), /* @__PURE__ */ React49.createElement(Text43, { bold: true, color: TONE.ok }, `${(card.cacheHit * 100).toFixed(1)}%`)), /* @__PURE__ */ React49.createElement(Box42, { flexDirection: "row", gap: 1 }, /* @__PURE__ */ React49.createElement(Text43, { color: FG.faint }, "session"), /* @__PURE__ */ React49.createElement(Text43, { bold: true, color: FG.body }, `\u26C1 ${formatCost(card.sessionCost, card.balanceCurrency, 3)}`), card.balance !== void 0 ? /* @__PURE__ */ React49.createElement(React49.Fragment, null, /* @__PURE__ */ React49.createElement(Text43, { color: FG.faint }, "\xB7 balance"), /* @__PURE__ */ React49.createElement(Text43, { bold: true, color: TONE.brand }, formatBalance(card.balance, card.balanceCurrency))) : null));
8836
8948
  }
8837
8949
  function CompactUsageRow({ card }) {
8838
8950
  const elapsed = card.elapsedMs !== void 0 ? ` \xB7 ${(card.elapsedMs / 1e3).toFixed(1)}s` : "";
8839
- return /* @__PURE__ */ React48.createElement(Box41, { flexDirection: "row", gap: 1, marginTop: 1 }, /* @__PURE__ */ React48.createElement(Text42, { color: FG.meta }, "\u03A3"), /* @__PURE__ */ React48.createElement(Text42, { color: FG.faint }, `turn ${card.turn}`), /* @__PURE__ */ React48.createElement(Text42, { color: FG.meta }, `\xB7 ${compactNum(card.tokens.prompt)} prompt \xB7 ${compactNum(card.tokens.output)} out`), /* @__PURE__ */ React48.createElement(Text42, { color: FG.faint }, "\xB7 cache"), /* @__PURE__ */ React48.createElement(Text42, { color: TONE.ok }, `${(card.cacheHit * 100).toFixed(0)}%`), /* @__PURE__ */ React48.createElement(Text42, { color: FG.faint }, `\xB7 ${formatCost(card.cost, card.balanceCurrency)}${elapsed}`), card.balance !== void 0 ? /* @__PURE__ */ React48.createElement(Text42, { color: TONE.brand }, `\xB7 ${formatBalance(card.balance, card.balanceCurrency)}`) : null);
8951
+ return /* @__PURE__ */ React49.createElement(Box42, { flexDirection: "row", gap: 1, marginTop: 1 }, /* @__PURE__ */ React49.createElement(Text43, { color: FG.meta }, "\u03A3"), /* @__PURE__ */ React49.createElement(Text43, { color: FG.faint }, `turn ${card.turn}`), /* @__PURE__ */ React49.createElement(Text43, { color: FG.meta }, `\xB7 ${compactNum(card.tokens.prompt)} prompt \xB7 ${compactNum(card.tokens.output)} out`), /* @__PURE__ */ React49.createElement(Text43, { color: FG.faint }, "\xB7 cache"), /* @__PURE__ */ React49.createElement(Text43, { color: TONE.ok }, `${(card.cacheHit * 100).toFixed(0)}%`), /* @__PURE__ */ React49.createElement(Text43, { color: FG.faint }, `\xB7 ${formatCost(card.cost, card.balanceCurrency)}${elapsed}`), card.balance !== void 0 ? /* @__PURE__ */ React49.createElement(Text43, { color: TONE.brand }, `\xB7 ${formatBalance(card.balance, card.balanceCurrency)}`) : null);
8840
8952
  }
8841
8953
 
8842
8954
  // src/cli/ui/cards/UserCard.tsx
8843
- import React49 from "react";
8955
+ import React50 from "react";
8844
8956
 
8845
8957
  // src/cli/ui/cards/time.ts
8846
8958
  function formatRelativeTime(ts, now = Date.now()) {
@@ -8857,7 +8969,7 @@ function formatRelativeTime(ts, now = Date.now()) {
8857
8969
 
8858
8970
  // src/cli/ui/cards/UserCard.tsx
8859
8971
  function UserCard({ card }) {
8860
- return /* @__PURE__ */ React49.createElement(Card, { tone: TONE.accent }, /* @__PURE__ */ React49.createElement(
8972
+ return /* @__PURE__ */ React50.createElement(Card, { tone: TONE.accent }, /* @__PURE__ */ React50.createElement(
8861
8973
  CardHeader,
8862
8974
  {
8863
8975
  glyph: "\u203A",
@@ -8866,15 +8978,15 @@ function UserCard({ card }) {
8866
8978
  titleColor: FG.sub,
8867
8979
  meta: [formatRelativeTime(card.ts)]
8868
8980
  }
8869
- ), /* @__PURE__ */ React49.createElement(Markdown, { text: card.text }));
8981
+ ), /* @__PURE__ */ React50.createElement(Markdown, { text: card.text }));
8870
8982
  }
8871
8983
 
8872
8984
  // src/cli/ui/cards/WarnCard.tsx
8873
- import { Text as Text43 } from "ink";
8874
- import React50 from "react";
8985
+ import { Text as Text44 } from "ink";
8986
+ import React51 from "react";
8875
8987
  function WarnCard({ card }) {
8876
8988
  const messageLines = card.message.length > 0 ? card.message.split("\n") : [];
8877
- return /* @__PURE__ */ React50.createElement(Card, { tone: TONE.warn }, /* @__PURE__ */ React50.createElement(
8989
+ return /* @__PURE__ */ React51.createElement(Card, { tone: TONE.warn }, /* @__PURE__ */ React51.createElement(
8878
8990
  CardHeader,
8879
8991
  {
8880
8992
  glyph: "\u26A0",
@@ -8882,55 +8994,57 @@ function WarnCard({ card }) {
8882
8994
  title: card.title,
8883
8995
  meta: card.detail ? [card.detail] : void 0
8884
8996
  }
8885
- ), messageLines.map((line, i) => /* @__PURE__ */ React50.createElement(Text43, { key: `${card.id}:${i}`, color: FG.body }, line || " ")));
8997
+ ), messageLines.map((line, i) => /* @__PURE__ */ React51.createElement(Text44, { key: `${card.id}:${i}`, color: FG.body }, line || " ")));
8886
8998
  }
8887
8999
 
8888
9000
  // src/cli/ui/cards/CardRenderer.tsx
8889
- var CardRenderer = React51.memo(function CardRenderer2({
9001
+ var CardRenderer = React52.memo(function CardRenderer2({
8890
9002
  card
8891
9003
  }) {
8892
- return /* @__PURE__ */ React51.createElement(Box42, { flexDirection: "column" }, renderCard(card));
9004
+ return /* @__PURE__ */ React52.createElement(Box43, { flexDirection: "column" }, renderCard(card));
8893
9005
  });
8894
9006
  function renderCard(card) {
8895
9007
  switch (card.kind) {
8896
9008
  case "user":
8897
- return /* @__PURE__ */ React51.createElement(UserCard, { card });
9009
+ return /* @__PURE__ */ React52.createElement(UserCard, { card });
8898
9010
  case "reasoning":
8899
- return /* @__PURE__ */ React51.createElement(ReasoningCard, { card, expanded: true });
9011
+ return /* @__PURE__ */ React52.createElement(ReasoningCard, { card, expanded: true });
8900
9012
  case "streaming":
8901
- return /* @__PURE__ */ React51.createElement(StreamingCard, { card });
9013
+ return /* @__PURE__ */ React52.createElement(StreamingCard, { card });
8902
9014
  case "tool":
8903
- return /* @__PURE__ */ React51.createElement(ToolCard, { card });
9015
+ return /* @__PURE__ */ React52.createElement(ToolCard, { card });
8904
9016
  case "task":
8905
- return /* @__PURE__ */ React51.createElement(TaskCard, { card });
9017
+ return /* @__PURE__ */ React52.createElement(TaskCard, { card });
8906
9018
  case "plan":
8907
- return /* @__PURE__ */ React51.createElement(PlanCard, { card });
9019
+ return /* @__PURE__ */ React52.createElement(PlanCard, { card });
8908
9020
  case "diff":
8909
- return /* @__PURE__ */ React51.createElement(DiffCard, { card });
9021
+ return /* @__PURE__ */ React52.createElement(DiffCard, { card });
8910
9022
  case "error":
8911
- return /* @__PURE__ */ React51.createElement(ErrorCard, { card });
9023
+ return /* @__PURE__ */ React52.createElement(ErrorCard, { card });
8912
9024
  case "warn":
8913
- return /* @__PURE__ */ React51.createElement(WarnCard, { card });
9025
+ return /* @__PURE__ */ React52.createElement(WarnCard, { card });
8914
9026
  case "usage":
8915
- return /* @__PURE__ */ React51.createElement(UsageCard, { card });
9027
+ return /* @__PURE__ */ React52.createElement(UsageCard, { card });
8916
9028
  case "memory":
8917
- return /* @__PURE__ */ React51.createElement(MemoryCard, { card });
9029
+ return /* @__PURE__ */ React52.createElement(MemoryCard, { card });
8918
9030
  case "subagent":
8919
- return /* @__PURE__ */ React51.createElement(SubAgentCard, { card });
9031
+ return /* @__PURE__ */ React52.createElement(SubAgentCard, { card });
8920
9032
  case "search":
8921
- return /* @__PURE__ */ React51.createElement(SearchCard, { card });
9033
+ return /* @__PURE__ */ React52.createElement(SearchCard, { card });
8922
9034
  case "live":
8923
- return /* @__PURE__ */ React51.createElement(LiveCard, { card });
9035
+ return /* @__PURE__ */ React52.createElement(LiveCard, { card });
9036
+ case "tip":
9037
+ return /* @__PURE__ */ React52.createElement(TipCard, { card });
8924
9038
  case "ctx":
8925
- return /* @__PURE__ */ React51.createElement(CtxCard, { card });
9039
+ return /* @__PURE__ */ React52.createElement(CtxCard, { card });
8926
9040
  case "doctor":
8927
- return /* @__PURE__ */ React51.createElement(DoctorCard, { card });
9041
+ return /* @__PURE__ */ React52.createElement(DoctorCard, { card });
8928
9042
  default:
8929
- return /* @__PURE__ */ React51.createElement(FallbackCard, { card });
9043
+ return /* @__PURE__ */ React52.createElement(FallbackCard, { card });
8930
9044
  }
8931
9045
  }
8932
9046
  function FallbackCard({ card }) {
8933
- return /* @__PURE__ */ React51.createElement(Box42, { flexDirection: "row" }, /* @__PURE__ */ React51.createElement(Text44, { color: FG.faint }, ` \xB7 ${card.kind} card \xB7 not yet migrated`));
9047
+ return /* @__PURE__ */ React52.createElement(Box43, { flexDirection: "row" }, /* @__PURE__ */ React52.createElement(Text45, { color: FG.faint }, ` \xB7 ${card.kind} card \xB7 not yet migrated`));
8934
9048
  }
8935
9049
 
8936
9050
  // src/cli/ui/layout/CardStream.tsx
@@ -8952,7 +9066,7 @@ function CardStream({
8952
9066
  if (suppressLive && cards.length > 0 && !isFullySettled(cards[cards.length - 1])) {
8953
9067
  visible = cards.slice(0, -1);
8954
9068
  }
8955
- return /* @__PURE__ */ React52.createElement(React52.Fragment, null, scrollRows > 0 ? /* @__PURE__ */ React52.createElement(Text45, { color: FG.faint }, " \u2191 earlier \u2014 PgUp / wheel / \u2191") : null, /* @__PURE__ */ React52.createElement(Box43, { ref: outerRef, flexDirection: "column", flexGrow: 1, overflow: "hidden" }, /* @__PURE__ */ React52.createElement(Box43, { ref: innerRef, flexDirection: "column", marginTop: -scrollRows, flexShrink: 0 }, visible.map((card) => /* @__PURE__ */ React52.createElement(CardRenderer, { key: card.id, card })))));
9069
+ return /* @__PURE__ */ React53.createElement(React53.Fragment, null, scrollRows > 0 ? /* @__PURE__ */ React53.createElement(Text46, { color: FG.faint }, " \u2191 earlier \u2014 PgUp / wheel / \u2191") : null, /* @__PURE__ */ React53.createElement(Box44, { ref: outerRef, flexDirection: "column", flexGrow: 1, overflow: "hidden" }, /* @__PURE__ */ React53.createElement(Box44, { ref: innerRef, flexDirection: "column", marginTop: -scrollRows, flexShrink: 0 }, visible.map((card) => /* @__PURE__ */ React53.createElement(CardRenderer, { key: card.id, card })))));
8956
9070
  }
8957
9071
  function isFullySettled(card) {
8958
9072
  switch (card.kind) {
@@ -8972,12 +9086,13 @@ function isFullySettled(card) {
8972
9086
  }
8973
9087
 
8974
9088
  // src/cli/ui/layout/LiveRows.tsx
8975
- import { Box as Box44, Text as Text46 } from "ink";
8976
- import React53 from "react";
9089
+ import { Box as Box45, Text as Text47 } from "ink";
9090
+ import React54 from "react";
8977
9091
  var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
8978
9092
  function ThinkingRow({ text }) {
8979
9093
  const elapsed = useElapsedSeconds();
8980
- return /* @__PURE__ */ React53.createElement(Box44, { marginY: 1, paddingX: 1, gap: 1 }, /* @__PURE__ */ React53.createElement(Spinner, { kind: "circle", color: TONE.accent }), /* @__PURE__ */ React53.createElement(Text46, { italic: true, color: FG.sub }, text), /* @__PURE__ */ React53.createElement(Text46, { color: FG.faint }, `${elapsed}s`));
9094
+ const { fg, tone } = useThemeTokens();
9095
+ return /* @__PURE__ */ React54.createElement(Box45, { marginY: 1, paddingX: 1, gap: 1 }, /* @__PURE__ */ React54.createElement(Spinner, { kind: "circle", color: TONE.accent }), /* @__PURE__ */ React54.createElement(Text47, { italic: true, color: FG.sub }, text), /* @__PURE__ */ React54.createElement(Text47, { color: FG.faint }, `${elapsed}s`));
8981
9096
  }
8982
9097
  function ModeStatusBar({
8983
9098
  editMode,
@@ -8989,24 +9104,24 @@ function ModeStatusBar({
8989
9104
  }) {
8990
9105
  useSlowTick();
8991
9106
  const running = jobs2?.runningCount() ?? 0;
8992
- const jobsTag = running > 0 ? /* @__PURE__ */ React53.createElement(Text46, { color: TONE.warn, bold: true }, ` \xB7 \u23F5 ${running} job${running === 1 ? "" : "s"}`) : null;
9107
+ const jobsTag = running > 0 ? /* @__PURE__ */ React54.createElement(Text47, { color: TONE.warn, bold: true }, ` \xB7 \u23F5 ${running} job${running === 1 ? "" : "s"}`) : null;
8993
9108
  if (planMode) {
8994
- return /* @__PURE__ */ React53.createElement(ModeBarFrame, null, /* @__PURE__ */ React53.createElement(ModePill, { label: "PLAN MODE", color: TONE.err, flash }), /* @__PURE__ */ React53.createElement(Text46, { color: FG.faint }, " writes gated \xB7 /plan off to leave"), jobsTag);
9109
+ return /* @__PURE__ */ React54.createElement(ModeBarFrame, null, /* @__PURE__ */ React54.createElement(ModePill, { label: "PLAN MODE", color: TONE.err, flash }), /* @__PURE__ */ React54.createElement(Text47, { color: FG.faint }, " writes gated \xB7 /plan off to leave"), jobsTag);
8995
9110
  }
8996
9111
  const label = editMode === "yolo" ? "YOLO" : editMode === "auto" ? "AUTO" : "REVIEW";
8997
9112
  const pillColor = editMode === "yolo" ? TONE.err : editMode === "auto" ? TONE.accent : TONE.brand;
8998
9113
  const mid = editMode === "yolo" ? "edits + shell auto \xB7 /undo to roll back" : editMode === "auto" ? "edits land now \xB7 u to undo" : pendingCount > 0 ? `${pendingCount} queued \xB7 y apply \xB7 n discard` : "edits queued \xB7 y apply \xB7 n discard";
8999
- return /* @__PURE__ */ React53.createElement(ModeBarFrame, null, /* @__PURE__ */ React53.createElement(ModePill, { label, color: pillColor, flash }), /* @__PURE__ */ React53.createElement(Text46, { color: FG.faint }, ` ${mid} \xB7 Shift+Tab to flip`), jobsTag);
9114
+ return /* @__PURE__ */ React54.createElement(ModeBarFrame, null, /* @__PURE__ */ React54.createElement(ModePill, { label, color: pillColor, flash }), /* @__PURE__ */ React54.createElement(Text47, { color: FG.faint }, ` ${mid} \xB7 Shift+Tab to flip`), jobsTag);
9000
9115
  }
9001
9116
  function ModeBarFrame({ children }) {
9002
- return /* @__PURE__ */ React53.createElement(Box44, { paddingX: 1 }, children);
9117
+ return /* @__PURE__ */ React54.createElement(Box45, { paddingX: 1 }, children);
9003
9118
  }
9004
9119
  function ModePill({
9005
9120
  label,
9006
9121
  color,
9007
9122
  flash
9008
9123
  }) {
9009
- return /* @__PURE__ */ React53.createElement(Text46, { color, bold: true, inverse: flash }, `[${label}]`);
9124
+ return /* @__PURE__ */ React54.createElement(Text47, { color, bold: true, inverse: flash }, `[${label}]`);
9010
9125
  }
9011
9126
  function UndoBanner({
9012
9127
  banner
@@ -9021,7 +9136,7 @@ function UndoBanner({
9021
9136
  const urgent = !paused && remainingSec <= 1;
9022
9137
  const pct = remainingMs / totalMs * 100;
9023
9138
  const tone = paused ? TONE.warn : urgent ? TONE.err : TONE.accent;
9024
- return /* @__PURE__ */ React53.createElement(Box44, { marginY: 1, paddingX: 1 }, /* @__PURE__ */ React53.createElement(Text46, { backgroundColor: TONE.accent, color: "black", bold: true }, ` \u2713 AUTO-APPLIED ${ok}/${total} `), /* @__PURE__ */ React53.createElement(Text46, { color: FG.faint }, " press "), /* @__PURE__ */ React53.createElement(Text46, { backgroundColor: TONE.brand, color: "black", bold: true }, " u "), /* @__PURE__ */ React53.createElement(Text46, { color: FG.faint }, paused ? " to undo \xB7 " : " to undo \xB7 "), /* @__PURE__ */ React53.createElement(Text46, { backgroundColor: paused ? TONE.warn : FG.faint, color: "black", bold: true }, " space "), /* @__PURE__ */ React53.createElement(Text46, { color: FG.faint }, paused ? " to resume " : " to pause "), /* @__PURE__ */ React53.createElement(CharBar, { pct, width: 20, color: tone, showLabel: false }), /* @__PURE__ */ React53.createElement(Text46, { color: FG.faint }, " "), /* @__PURE__ */ React53.createElement(Text46, { color: tone, bold: urgent || paused }, paused ? `${remainingSec}s \xB7 paused` : `${remainingSec}s`));
9139
+ return /* @__PURE__ */ React54.createElement(Box45, { marginY: 1, paddingX: 1 }, /* @__PURE__ */ React54.createElement(Text47, { backgroundColor: TONE.accent, color: "black", bold: true }, ` \u2713 AUTO-APPLIED ${ok}/${total} `), /* @__PURE__ */ React54.createElement(Text47, { color: FG.faint }, " press "), /* @__PURE__ */ React54.createElement(Text47, { backgroundColor: TONE.brand, color: "black", bold: true }, " u "), /* @__PURE__ */ React54.createElement(Text47, { color: FG.faint }, paused ? " to undo \xB7 " : " to undo \xB7 "), /* @__PURE__ */ React54.createElement(Text47, { backgroundColor: paused ? TONE.warn : FG.faint, color: "black", bold: true }, " space "), /* @__PURE__ */ React54.createElement(Text47, { color: FG.faint }, paused ? " to resume " : " to pause "), /* @__PURE__ */ React54.createElement(CharBar, { pct, width: 20, color: tone, showLabel: false }), /* @__PURE__ */ React54.createElement(Text47, { color: FG.faint }, " "), /* @__PURE__ */ React54.createElement(Text47, { color: tone, bold: urgent || paused }, paused ? `${remainingSec}s \xB7 paused` : `${remainingSec}s`));
9025
9140
  }
9026
9141
  function subagentPhaseLabel(phase, iter, elapsedMs) {
9027
9142
  if (phase === "summarising") return "summarising findings\u2026";
@@ -9036,7 +9151,7 @@ function SubagentRow({ activity }) {
9036
9151
  const last = activity.lastInner;
9037
9152
  const subtitle = activity.skillName ?? truncate2(activity.task, 48);
9038
9153
  const modelBadge = activity.model ? modelBadgeFor(activity.model) : null;
9039
- return /* @__PURE__ */ React53.createElement(Card, { tone: CARD.subagent.color }, /* @__PURE__ */ React53.createElement(
9154
+ return /* @__PURE__ */ React54.createElement(Card, { tone: CARD.subagent.color }, /* @__PURE__ */ React54.createElement(
9040
9155
  CardHeader,
9041
9156
  {
9042
9157
  glyph: "\u232C",
@@ -9046,9 +9161,9 @@ function SubagentRow({ activity }) {
9046
9161
  titleBg: PILL_SECTION.plan.bg,
9047
9162
  subtitle,
9048
9163
  meta: [`iter ${activity.iter}`, `${seconds}s`],
9049
- right: /* @__PURE__ */ React53.createElement(React53.Fragment, null, modelBadge ? /* @__PURE__ */ React53.createElement(Pill, { label: modelBadge.label, ...PILL_MODEL[modelBadge.kind], bold: false }) : null, /* @__PURE__ */ React53.createElement(Spinner, { kind: "braille", color: CARD.subagent.color }))
9164
+ right: /* @__PURE__ */ React54.createElement(React54.Fragment, null, modelBadge ? /* @__PURE__ */ React54.createElement(Pill, { label: modelBadge.label, ...PILL_MODEL[modelBadge.kind], bold: false }) : null, /* @__PURE__ */ React54.createElement(Spinner, { kind: "braille", color: CARD.subagent.color }))
9050
9165
  }
9051
- ), /* @__PURE__ */ React53.createElement(Text46, { color: FG.faint }, "task ", /* @__PURE__ */ React53.createElement(Text46, { color: FG.sub }, activity.task)), /* @__PURE__ */ React53.createElement(Text46, { color: FG.faint }, "last ", last ? /* @__PURE__ */ React53.createElement(React53.Fragment, null, /* @__PURE__ */ React53.createElement(Text46, { color: last.color }, `${last.glyph} `), /* @__PURE__ */ React53.createElement(Text46, { color: FG.body }, last.label), last.meta ? /* @__PURE__ */ React53.createElement(Text46, { color: FG.faint }, ` ${last.meta}`) : null) : /* @__PURE__ */ React53.createElement(Text46, { color: FG.faint }, "queued\u2026")), /* @__PURE__ */ React53.createElement(Text46, { color: TONE.brand }, "\u25B6 ", phase));
9166
+ ), /* @__PURE__ */ React54.createElement(Text47, { color: FG.faint }, "task ", /* @__PURE__ */ React54.createElement(Text47, { color: FG.sub }, activity.task)), /* @__PURE__ */ React54.createElement(Text47, { color: FG.faint }, "last ", last ? /* @__PURE__ */ React54.createElement(React54.Fragment, null, /* @__PURE__ */ React54.createElement(Text47, { color: last.color }, `${last.glyph} `), /* @__PURE__ */ React54.createElement(Text47, { color: FG.body }, last.label), last.meta ? /* @__PURE__ */ React54.createElement(Text47, { color: FG.faint }, ` ${last.meta}`) : null) : /* @__PURE__ */ React54.createElement(Text47, { color: FG.faint }, "queued\u2026")), /* @__PURE__ */ React54.createElement(Text47, { color: TONE.brand }, "\u25B6 ", phase));
9052
9167
  }
9053
9168
  function SubagentLiveStack({
9054
9169
  activities,
@@ -9056,13 +9171,13 @@ function SubagentLiveStack({
9056
9171
  }) {
9057
9172
  const tick = useTick();
9058
9173
  if (activities.length === 0) return null;
9059
- if (activities.length === 1) return /* @__PURE__ */ React53.createElement(SubagentRow, { activity: activities[0] });
9174
+ if (activities.length === 1) return /* @__PURE__ */ React54.createElement(SubagentRow, { activity: activities[0] });
9060
9175
  const visible = activities.slice(0, max);
9061
9176
  const overflow = activities.length - visible.length;
9062
9177
  const summarising = activities.filter((a) => a.phase === "summarising").length;
9063
9178
  const metaParts = [`${activities.length} running`];
9064
9179
  if (summarising > 0) metaParts.push(`${summarising} summarising`);
9065
- return /* @__PURE__ */ React53.createElement(Card, { tone: CARD.subagent.color }, /* @__PURE__ */ React53.createElement(
9180
+ return /* @__PURE__ */ React54.createElement(Card, { tone: CARD.subagent.color }, /* @__PURE__ */ React54.createElement(
9066
9181
  CardHeader,
9067
9182
  {
9068
9183
  glyph: "\u232C",
@@ -9071,9 +9186,9 @@ function SubagentLiveStack({
9071
9186
  titleColor: PILL_SECTION.plan.fg,
9072
9187
  titleBg: PILL_SECTION.plan.bg,
9073
9188
  subtitle: metaParts.join(" \xB7 "),
9074
- right: /* @__PURE__ */ React53.createElement(Spinner, { kind: "braille", color: CARD.subagent.color })
9189
+ right: /* @__PURE__ */ React54.createElement(Spinner, { kind: "braille", color: CARD.subagent.color })
9075
9190
  }
9076
- ), visible.map((a, i) => /* @__PURE__ */ React53.createElement(CompactSubagentLine, { key: a.runId, activity: a, tick, index: i })), overflow > 0 ? /* @__PURE__ */ React53.createElement(Text46, { color: FG.faint }, ` +${overflow} more running\u2026`) : null);
9191
+ ), visible.map((a, i) => /* @__PURE__ */ React54.createElement(CompactSubagentLine, { key: a.runId, activity: a, tick, index: i })), overflow > 0 ? /* @__PURE__ */ React54.createElement(Text47, { color: FG.faint }, ` +${overflow} more running\u2026`) : null);
9077
9192
  }
9078
9193
  function CompactSubagentLine({
9079
9194
  activity,
@@ -9088,7 +9203,7 @@ function CompactSubagentLine({
9088
9203
  const title = activity.skillName ?? truncate2(activity.task, 28);
9089
9204
  const titlePadded = title.padEnd(28);
9090
9205
  const last = activity.lastInner;
9091
- return /* @__PURE__ */ React53.createElement(Box44, { flexDirection: "row" }, /* @__PURE__ */ React53.createElement(Text46, { color: glyphColor, bold: true }, ` ${glyph} `), /* @__PURE__ */ React53.createElement(Text46, { color: FG.body }, titlePadded), /* @__PURE__ */ React53.createElement(Text46, { color: FG.faint }, ` iter ${String(activity.iter).padStart(2)} \xB7 ${seconds}s \xB7 `), last ? /* @__PURE__ */ React53.createElement(React53.Fragment, null, /* @__PURE__ */ React53.createElement(Text46, { color: last.color }, `${last.glyph} `), /* @__PURE__ */ React53.createElement(Text46, { color: FG.body }, truncate2(last.label, 18)), last.meta ? /* @__PURE__ */ React53.createElement(Text46, { color: FG.faint }, ` ${last.meta}`) : null) : /* @__PURE__ */ React53.createElement(Text46, { color: FG.faint }, "queued\u2026"));
9206
+ return /* @__PURE__ */ React54.createElement(Box45, { flexDirection: "row" }, /* @__PURE__ */ React54.createElement(Text47, { color: glyphColor, bold: true }, ` ${glyph} `), /* @__PURE__ */ React54.createElement(Text47, { color: FG.body }, titlePadded), /* @__PURE__ */ React54.createElement(Text47, { color: FG.faint }, ` iter ${String(activity.iter).padStart(2)} \xB7 ${seconds}s \xB7 `), last ? /* @__PURE__ */ React54.createElement(React54.Fragment, null, /* @__PURE__ */ React54.createElement(Text47, { color: last.color }, `${last.glyph} `), /* @__PURE__ */ React54.createElement(Text47, { color: FG.body }, truncate2(last.label, 18)), last.meta ? /* @__PURE__ */ React54.createElement(Text47, { color: FG.faint }, ` ${last.meta}`) : null) : /* @__PURE__ */ React54.createElement(Text47, { color: FG.faint }, "queued\u2026"));
9092
9207
  }
9093
9208
  function truncate2(text, max) {
9094
9209
  return text.length > max ? `${text.slice(0, max)}\u2026` : text;
@@ -9100,7 +9215,7 @@ function OngoingToolRow({
9100
9215
  const tick = useTick();
9101
9216
  const elapsed = useElapsedSeconds();
9102
9217
  const summary = summarizeToolArgs(tool.name, tool.args);
9103
- return /* @__PURE__ */ React53.createElement(Box44, { marginY: 1, flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React53.createElement(Box44, null, /* @__PURE__ */ React53.createElement(Text46, { color: CARD.tool.color, bold: true }, SPINNER_FRAMES[tick % SPINNER_FRAMES.length]), /* @__PURE__ */ React53.createElement(Text46, null, " "), /* @__PURE__ */ React53.createElement(Text46, { color: CARD.tool.color, bold: true }, `\u25A3 ${tool.name}`), /* @__PURE__ */ React53.createElement(Text46, { color: FG.faint }, ` running \xB7 ${elapsed}s`)), progress ? /* @__PURE__ */ React53.createElement(Box44, { paddingLeft: 3 }, /* @__PURE__ */ React53.createElement(Text46, { color: TONE.brand }, renderProgressLine(progress))) : null, summary ? /* @__PURE__ */ React53.createElement(Box44, { paddingLeft: 3 }, /* @__PURE__ */ React53.createElement(Text46, { color: FG.faint }, summary)) : null);
9218
+ return /* @__PURE__ */ React54.createElement(Box45, { marginY: 1, flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React54.createElement(Box45, null, /* @__PURE__ */ React54.createElement(Text47, { color: CARD.tool.color, bold: true }, SPINNER_FRAMES[tick % SPINNER_FRAMES.length]), /* @__PURE__ */ React54.createElement(Text47, null, " "), /* @__PURE__ */ React54.createElement(Text47, { color: CARD.tool.color, bold: true }, `\u25A3 ${tool.name}`), /* @__PURE__ */ React54.createElement(Text47, { color: FG.faint }, ` running \xB7 ${elapsed}s`)), progress ? /* @__PURE__ */ React54.createElement(Box45, { paddingLeft: 3 }, /* @__PURE__ */ React54.createElement(Text47, { color: TONE.brand }, renderProgressLine(progress))) : null, summary ? /* @__PURE__ */ React54.createElement(Box45, { paddingLeft: 3 }, /* @__PURE__ */ React54.createElement(Text47, { color: FG.faint }, summary)) : null);
9104
9219
  }
9105
9220
  function renderProgressLine(p) {
9106
9221
  const msg = p.message ? ` ${p.message}` : "";
@@ -9156,16 +9271,16 @@ function summarizeToolArgs(name, args) {
9156
9271
  }
9157
9272
 
9158
9273
  // src/cli/ui/layout/StatusRow.tsx
9159
- import { Box as Box45, Text as Text48, useStdout as useStdout12 } from "ink";
9160
- import React55 from "react";
9274
+ import { Box as Box46, Text as Text49, useStdout as useStdout12 } from "ink";
9275
+ import React56 from "react";
9161
9276
 
9162
9277
  // src/cli/ui/primitives/Countdown.tsx
9163
- import { Text as Text47 } from "ink";
9164
- import React54 from "react";
9278
+ import { Text as Text48 } from "ink";
9279
+ import React55 from "react";
9165
9280
  function Countdown({ endsAt, color = TONE.brand }) {
9166
9281
  useSlowTick();
9167
9282
  const remainingSec = Math.max(0, Math.ceil((endsAt - Date.now()) / 1e3));
9168
- return /* @__PURE__ */ React54.createElement(Text47, { bold: true, color }, String(remainingSec));
9283
+ return /* @__PURE__ */ React55.createElement(Text48, { bold: true, color }, String(remainingSec));
9169
9284
  }
9170
9285
 
9171
9286
  // src/cli/ui/layout/StatusRow.tsx
@@ -9182,7 +9297,7 @@ function StatusRow() {
9182
9297
  const hasSession = status2.sessionCost > 0;
9183
9298
  const hasBalance = typeof status2.balance === "number";
9184
9299
  const showWallet = cols >= WALLET_MIN_COLS && (hasSession || hasBalance);
9185
- return /* @__PURE__ */ React55.createElement(Box45, { flexDirection: "column" }, /* @__PURE__ */ React55.createElement(Box45, null, /* @__PURE__ */ React55.createElement(Text48, null, " "), /* @__PURE__ */ React55.createElement(Text48, { color: FG.faint }, "\u2500".repeat(ruleWidth))), /* @__PURE__ */ React55.createElement(Box45, { flexDirection: "row" }, /* @__PURE__ */ React55.createElement(Text48, null, " "), status2.recording ? /* @__PURE__ */ React55.createElement(RecordingPill, { rec: status2.recording }) : status2.countdownSeconds !== void 0 ? /* @__PURE__ */ React55.createElement(CountdownRow, { mode: status2.mode, secondsLeft: status2.countdownSeconds }) : /* @__PURE__ */ React55.createElement(ModePill2, { mode: status2.mode, network: status2.network, detail: status2.networkDetail }), /* @__PURE__ */ React55.createElement(Sep, null), /* @__PURE__ */ React55.createElement(Text48, { color: FG.sub }, `${session.id} \xB7 ${session.branch}`), hasTurn && /* @__PURE__ */ React55.createElement(React55.Fragment, null, /* @__PURE__ */ React55.createElement(Sep, null), /* @__PURE__ */ React55.createElement(Text48, { bold: true, color: TONE.brand }, "\u25B8 "), /* @__PURE__ */ React55.createElement(Text48, { bold: true, color: FG.body }, `${formatCost(status2.cost, status2.balanceCurrency)} turn`)), /* @__PURE__ */ React55.createElement(Sep, null), /* @__PURE__ */ React55.createElement(Text48, { color: TONE.accent }, `cache ${Math.round(status2.cacheHit * 100)}%`), showWallet && /* @__PURE__ */ React55.createElement(
9300
+ return /* @__PURE__ */ React56.createElement(Box46, { flexDirection: "column" }, /* @__PURE__ */ React56.createElement(Box46, null, /* @__PURE__ */ React56.createElement(Text49, null, " "), /* @__PURE__ */ React56.createElement(Text49, { color: FG.faint }, "\u2500".repeat(ruleWidth))), /* @__PURE__ */ React56.createElement(Box46, { flexDirection: "row" }, /* @__PURE__ */ React56.createElement(Text49, null, " "), status2.recording ? /* @__PURE__ */ React56.createElement(RecordingPill, { rec: status2.recording }) : status2.countdownSeconds !== void 0 ? /* @__PURE__ */ React56.createElement(CountdownRow, { mode: status2.mode, secondsLeft: status2.countdownSeconds }) : /* @__PURE__ */ React56.createElement(ModePill2, { mode: status2.mode, network: status2.network, detail: status2.networkDetail }), /* @__PURE__ */ React56.createElement(Sep, null), /* @__PURE__ */ React56.createElement(Text49, { color: FG.sub }, `${session.id} \xB7 ${session.branch}`), hasTurn && /* @__PURE__ */ React56.createElement(React56.Fragment, null, /* @__PURE__ */ React56.createElement(Sep, null), /* @__PURE__ */ React56.createElement(Text49, { bold: true, color: TONE.brand }, "\u25B8 "), /* @__PURE__ */ React56.createElement(Text49, { bold: true, color: FG.body }, `${formatCost(status2.cost, status2.balanceCurrency)} turn`)), /* @__PURE__ */ React56.createElement(Sep, null), /* @__PURE__ */ React56.createElement(Text49, { color: TONE.accent }, `cache ${Math.round(status2.cacheHit * 100)}%`), showWallet && /* @__PURE__ */ React56.createElement(
9186
9301
  WalletPill,
9187
9302
  {
9188
9303
  sessionCostUsd: status2.sessionCost,
@@ -9198,7 +9313,7 @@ function WalletPill({
9198
9313
  }) {
9199
9314
  const showSpent = sessionCostUsd > 0;
9200
9315
  const showBalance = typeof balance === "number";
9201
- return /* @__PURE__ */ React55.createElement(React55.Fragment, null, /* @__PURE__ */ React55.createElement(Sep, null), /* @__PURE__ */ React55.createElement(Text48, { color: FG.meta }, "\u26C1 "), showSpent && /* @__PURE__ */ React55.createElement(Text48, { color: FG.body }, `${formatCost(sessionCostUsd, currency, 2)} spent`), showSpent && showBalance && /* @__PURE__ */ React55.createElement(Text48, { color: FG.meta }, " / "), showBalance && /* @__PURE__ */ React55.createElement(Text48, { bold: true, color: balanceColor(balance, currency) }, formatBalance(balance, currency, { fractionDigits: 2 })), showBalance && /* @__PURE__ */ React55.createElement(Text48, { color: FG.faint }, " left"));
9316
+ return /* @__PURE__ */ React56.createElement(React56.Fragment, null, /* @__PURE__ */ React56.createElement(Sep, null), /* @__PURE__ */ React56.createElement(Text49, { color: FG.meta }, "\u26C1 "), showSpent && /* @__PURE__ */ React56.createElement(Text49, { color: FG.body }, `${formatCost(sessionCostUsd, currency, 2)} spent`), showSpent && showBalance && /* @__PURE__ */ React56.createElement(Text49, { color: FG.meta }, " / "), showBalance && /* @__PURE__ */ React56.createElement(Text49, { bold: true, color: balanceColor(balance, currency) }, formatBalance(balance, currency, { fractionDigits: 2 })), showBalance && /* @__PURE__ */ React56.createElement(Text49, { color: FG.faint }, " left"));
9202
9317
  }
9203
9318
  function ModePill2({
9204
9319
  mode: mode2,
@@ -9207,18 +9322,18 @@ function ModePill2({
9207
9322
  }) {
9208
9323
  if (network === "online") {
9209
9324
  const pill = modeGlyph(mode2);
9210
- return /* @__PURE__ */ React55.createElement(Box45, { flexDirection: "row" }, /* @__PURE__ */ React55.createElement(Text48, { color: pill.color }, pill.glyph), /* @__PURE__ */ React55.createElement(Text48, { color: FG.sub }, ` ${mode2}`));
9325
+ return /* @__PURE__ */ React56.createElement(Box46, { flexDirection: "row" }, /* @__PURE__ */ React56.createElement(Text49, { color: pill.color }, pill.glyph), /* @__PURE__ */ React56.createElement(Text49, { color: FG.sub }, ` ${mode2}`));
9211
9326
  }
9212
9327
  const dot = networkDot(network);
9213
9328
  if (network === "slow") {
9214
9329
  const tail = detail ? ` \xB7 ${detail}` : "";
9215
- return /* @__PURE__ */ React55.createElement(Box45, { flexDirection: "row" }, /* @__PURE__ */ React55.createElement(Text48, { color: dot.color }, dot.glyph), /* @__PURE__ */ React55.createElement(Text48, { color: dot.color }, ` ${mode2} \xB7 slow${tail}`));
9330
+ return /* @__PURE__ */ React56.createElement(Box46, { flexDirection: "row" }, /* @__PURE__ */ React56.createElement(Text49, { color: dot.color }, dot.glyph), /* @__PURE__ */ React56.createElement(Text49, { color: dot.color }, ` ${mode2} \xB7 slow${tail}`));
9216
9331
  }
9217
9332
  if (network === "disconnected") {
9218
9333
  const tail = detail ? ` \xB7 ${detail}` : "";
9219
- return /* @__PURE__ */ React55.createElement(Box45, { flexDirection: "row" }, /* @__PURE__ */ React55.createElement(Text48, { color: dot.color }, dot.glyph), /* @__PURE__ */ React55.createElement(Text48, { color: dot.color }, ` disconnect${tail}`));
9334
+ return /* @__PURE__ */ React56.createElement(Box46, { flexDirection: "row" }, /* @__PURE__ */ React56.createElement(Text49, { color: dot.color }, dot.glyph), /* @__PURE__ */ React56.createElement(Text49, { color: dot.color }, ` disconnect${tail}`));
9220
9335
  }
9221
- return /* @__PURE__ */ React55.createElement(Box45, { flexDirection: "row" }, /* @__PURE__ */ React55.createElement(Text48, { color: dot.color }, dot.glyph), /* @__PURE__ */ React55.createElement(Text48, { color: dot.color }, " reconnecting\u2026"));
9336
+ return /* @__PURE__ */ React56.createElement(Box46, { flexDirection: "row" }, /* @__PURE__ */ React56.createElement(Text49, { color: dot.color }, dot.glyph), /* @__PURE__ */ React56.createElement(Text49, { color: dot.color }, " reconnecting\u2026"));
9222
9337
  }
9223
9338
  function CountdownRow({
9224
9339
  mode: mode2,
@@ -9226,14 +9341,14 @@ function CountdownRow({
9226
9341
  }) {
9227
9342
  const pill = modeGlyph(mode2);
9228
9343
  const endsAt = Date.now() + secondsLeft * 1e3;
9229
- return /* @__PURE__ */ React55.createElement(Box45, { flexDirection: "row" }, /* @__PURE__ */ React55.createElement(Text48, { color: pill.color }, pill.glyph), /* @__PURE__ */ React55.createElement(Text48, { color: FG.sub }, ` ${mode2} \xB7 `), /* @__PURE__ */ React55.createElement(Text48, { color: TONE.warn }, "approving in "), /* @__PURE__ */ React55.createElement(Countdown, { endsAt }), /* @__PURE__ */ React55.createElement(Text48, { color: TONE.warn }, "s \xB7 esc to interrupt"));
9344
+ return /* @__PURE__ */ React56.createElement(Box46, { flexDirection: "row" }, /* @__PURE__ */ React56.createElement(Text49, { color: pill.color }, pill.glyph), /* @__PURE__ */ React56.createElement(Text49, { color: FG.sub }, ` ${mode2} \xB7 `), /* @__PURE__ */ React56.createElement(Text49, { color: TONE.warn }, "approving in "), /* @__PURE__ */ React56.createElement(Countdown, { endsAt }), /* @__PURE__ */ React56.createElement(Text49, { color: TONE.warn }, "s \xB7 esc to interrupt"));
9230
9345
  }
9231
9346
  function RecordingPill({ rec }) {
9232
9347
  const sizeMb = (rec.sizeBytes / (1024 * 1024)).toFixed(1);
9233
- return /* @__PURE__ */ React55.createElement(Box45, { flexDirection: "row" }, /* @__PURE__ */ React55.createElement(Text48, { bold: true, color: TONE.err }, "\u25CFREC"), /* @__PURE__ */ React55.createElement(Text48, { color: TONE.err }, ` ${sizeMb} MB \xB7 ${rec.events} evt`));
9348
+ return /* @__PURE__ */ React56.createElement(Box46, { flexDirection: "row" }, /* @__PURE__ */ React56.createElement(Text49, { bold: true, color: TONE.err }, "\u25CFREC"), /* @__PURE__ */ React56.createElement(Text49, { color: TONE.err }, ` ${sizeMb} MB \xB7 ${rec.events} evt`));
9234
9349
  }
9235
9350
  function Sep() {
9236
- return /* @__PURE__ */ React55.createElement(Text48, { color: FG.meta }, " \xB7 ");
9351
+ return /* @__PURE__ */ React56.createElement(Text49, { color: FG.meta }, " \xB7 ");
9237
9352
  }
9238
9353
  function modeGlyph(mode2) {
9239
9354
  switch (mode2) {
@@ -9261,8 +9376,8 @@ function networkDot(state) {
9261
9376
  }
9262
9377
 
9263
9378
  // src/cli/ui/layout/ToastRail.tsx
9264
- import { Box as Box46, Text as Text49, useStdout as useStdout13 } from "ink";
9265
- import React56, { useEffect as useEffect8 } from "react";
9379
+ import { Box as Box47, Text as Text50, useStdout as useStdout13 } from "ink";
9380
+ import React57, { useEffect as useEffect8 } from "react";
9266
9381
  var TONE_COLOR = {
9267
9382
  ok: TONE.ok,
9268
9383
  info: TONE.brand,
@@ -9300,17 +9415,17 @@ function ToastRail() {
9300
9415
  }, [toasts, dispatch]);
9301
9416
  const visible = toasts.filter((t2) => now - t2.bornAt < t2.ttlMs);
9302
9417
  if (visible.length === 0) return null;
9303
- return /* @__PURE__ */ React56.createElement(Box46, { flexDirection: "column" }, visible.map((t2) => {
9418
+ return /* @__PURE__ */ React57.createElement(Box47, { flexDirection: "column" }, visible.map((t2) => {
9304
9419
  const color = TONE_COLOR[t2.tone];
9305
9420
  const glyph = TONE_GLYPH[t2.tone];
9306
9421
  const body = bodyColor(t2, now);
9307
9422
  const remainingSec = Math.max(0, Math.ceil((t2.ttlMs - (now - t2.bornAt)) / 1e3));
9308
- return /* @__PURE__ */ React56.createElement(Box46, { key: t2.id, flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React56.createElement(Text49, { color }, rule), /* @__PURE__ */ React56.createElement(Box46, { flexDirection: "row" }, /* @__PURE__ */ React56.createElement(Text49, { color }, glyph), /* @__PURE__ */ React56.createElement(Text49, { bold: true, color: body }, ` ${t2.title}`), t2.detail !== void 0 && /* @__PURE__ */ React56.createElement(Text49, { color: FG.sub }, ` \xB7 ${t2.detail}`), /* @__PURE__ */ React56.createElement(Box46, { flexGrow: 1 }), /* @__PURE__ */ React56.createElement(Text49, { color: FG.faint }, `${remainingSec}s`)));
9423
+ return /* @__PURE__ */ React57.createElement(Box47, { key: t2.id, flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React57.createElement(Text50, { color }, rule), /* @__PURE__ */ React57.createElement(Box47, { flexDirection: "row" }, /* @__PURE__ */ React57.createElement(Text50, { color }, glyph), /* @__PURE__ */ React57.createElement(Text50, { bold: true, color: body }, ` ${t2.title}`), t2.detail !== void 0 && /* @__PURE__ */ React57.createElement(Text50, { color: FG.sub }, ` \xB7 ${t2.detail}`), /* @__PURE__ */ React57.createElement(Box47, { flexGrow: 1 }), /* @__PURE__ */ React57.createElement(Text50, { color: FG.faint }, `${remainingSec}s`)));
9309
9424
  }));
9310
9425
  }
9311
9426
 
9312
9427
  // src/cli/ui/layout/plan-live-row.tsx
9313
- import React57 from "react";
9428
+ import React58 from "react";
9314
9429
  function isActivePlanInFlight(card) {
9315
9430
  if (card.kind !== "plan") return false;
9316
9431
  if (card.variant !== "active") return false;
@@ -9325,7 +9440,7 @@ function PlanLiveRow() {
9325
9440
  return null;
9326
9441
  });
9327
9442
  if (!planCard) return null;
9328
- return /* @__PURE__ */ React57.createElement(PlanCard, { card: planCard });
9443
+ return /* @__PURE__ */ React58.createElement(PlanCard, { card: planCard });
9329
9444
  }
9330
9445
 
9331
9446
  // src/cli/ui/loop.ts
@@ -9853,12 +9968,19 @@ var loop = (args, _loop, ctx) => {
9853
9968
  })
9854
9969
  };
9855
9970
  };
9971
+ var keys = (_args, _loop, ctx) => {
9972
+ if (!ctx.postKeys) return { info: t("handlers.basic.keysNeedsTui") };
9973
+ const ref = tObj("ui.keysReference");
9974
+ ctx.postKeys({ topic: ref.topic, sections: ref.sections, footer: ref.footer });
9975
+ return {};
9976
+ };
9856
9977
  var handlers2 = {
9857
9978
  exit,
9858
9979
  new: resetLog,
9859
9980
  help,
9860
9981
  retry,
9861
- loop
9982
+ loop,
9983
+ keys
9862
9984
  };
9863
9985
 
9864
9986
  // src/cli/ui/slash/handlers/dashboard.ts
@@ -10777,8 +10899,8 @@ var handlers10 = {
10777
10899
  };
10778
10900
 
10779
10901
  // src/cli/ui/ctx-breakdown.tsx
10780
- import { Box as Box47, Text as Text50 } from "ink";
10781
- import React58 from "react";
10902
+ import { Box as Box48, Text as Text51 } from "ink";
10903
+ import React59 from "react";
10782
10904
  function computeCtxBreakdown(loop2) {
10783
10905
  const systemTokens = countTokens(loop2.prefix.system);
10784
10906
  const toolsTokens = countTokens(JSON.stringify(loop2.prefix.toolSpecs));
@@ -11308,8 +11430,40 @@ var handlers15 = {
11308
11430
  skills: skill
11309
11431
  };
11310
11432
 
11311
- // src/cli/ui/slash/handlers/web-search-engine.ts
11433
+ // src/cli/ui/slash/handlers/theme.ts
11434
+ var themeChoices = ["auto", ...listThemeNames()];
11435
+ function formatThemeStatus() {
11436
+ const configured = loadTheme();
11437
+ const active = resolveThemePreference(configured, process.env.REASONIX_THEME);
11438
+ const source = configured && configured !== "auto" ? "config" : "env/default";
11439
+ return [
11440
+ `theme: ${active} (${source})`,
11441
+ `configured: ${configured ?? "unset"}`,
11442
+ `available: ${themeChoices.join(", ")}`,
11443
+ "usage: /theme <name|auto>"
11444
+ ].join("\n");
11445
+ }
11446
+ function isThemeChoice(value) {
11447
+ return value === "auto" || isThemeName(value);
11448
+ }
11449
+ var theme = (args) => {
11450
+ const next = args[0];
11451
+ if (!next) return { info: formatThemeStatus() };
11452
+ if (!isThemeChoice(next)) {
11453
+ return { info: `unknown theme: ${next}
11454
+ available: ${themeChoices.join(", ")}` };
11455
+ }
11456
+ saveTheme(next);
11457
+ const active = resolveThemePreference(next, process.env.REASONIX_THEME);
11458
+ return { info: `theme saved: ${next}
11459
+ active on next launch: ${active}` };
11460
+ };
11312
11461
  var handlers16 = {
11462
+ theme
11463
+ };
11464
+
11465
+ // src/cli/ui/slash/handlers/web-search-engine.ts
11466
+ var handlers17 = {
11313
11467
  "search-engine": (args, _loop, ctx) => {
11314
11468
  const engine = args[0];
11315
11469
  if (!engine || engine !== "mojeek" && engine !== "searxng") {
@@ -11342,7 +11496,7 @@ var handlers16 = {
11342
11496
  const detail = engine === "searxng" ? t("handlers.webSearchEngine.confirmedDetail", { endpoint: webSearchEndpoint() }) : "";
11343
11497
  return { info: t("handlers.webSearchEngine.confirmed", { engine, detail }) };
11344
11498
  },
11345
- se: (args, loop2, ctx) => handlers16["search-engine"](args, loop2, ctx)
11499
+ se: (args, loop2, ctx) => handlers17["search-engine"](args, loop2, ctx)
11346
11500
  };
11347
11501
 
11348
11502
  // src/cli/ui/slash/dispatch.ts
@@ -11361,8 +11515,9 @@ var HANDLERS = {
11361
11515
  ...handlers12,
11362
11516
  ...handlers13,
11363
11517
  ...handlers14,
11518
+ ...handlers16,
11364
11519
  ...handlers15,
11365
- ...handlers16
11520
+ ...handlers17
11366
11521
  };
11367
11522
  function handleSlash(cmd, args, loop2, ctx = {}) {
11368
11523
  const h = HANDLERS[resolveSlashAlias(cmd)];
@@ -11499,6 +11654,20 @@ ${card.meta}` : card.text
11499
11654
  case "ctx":
11500
11655
  out.push({ id: card.id, role: "info", text: card.text });
11501
11656
  break;
11657
+ case "tip": {
11658
+ const sectionTexts = card.sections.map((sec) => {
11659
+ const body2 = sec.rows.map((r) => `${r.key} ${r.text}`).join("\n");
11660
+ return sec.title ? `[${sec.title}]
11661
+ ${body2}` : body2;
11662
+ });
11663
+ const body = sectionTexts.join("\n\n");
11664
+ const text = card.footer ? `${card.topic}
11665
+ ${body}
11666
+ ${card.footer}` : `${card.topic}
11667
+ ${body}`;
11668
+ out.push({ id: card.id, role: "info", text });
11669
+ break;
11670
+ }
11502
11671
  case "plan": {
11503
11672
  const done = card.steps.filter((s) => s.status === "done").length;
11504
11673
  const tag2 = card.variant === "resumed" ? "[resumed]" : card.variant === "replay" ? "[replay]" : "";
@@ -11581,7 +11750,10 @@ function hydrateCardsFromMessages(messages) {
11581
11750
  }
11582
11751
 
11583
11752
  // src/cli/ui/useCompletionPickers.ts
11584
- import { useCallback as useCallback8, useEffect as useEffect9, useMemo as useMemo8, useRef as useRef5, useState as useState16 } from "react";
11753
+ import { useCallback as useCallback8, useEffect as useEffect9, useMemo as useMemo8, useReducer as useReducer2, useRef as useRef5, useState as useState16 } from "react";
11754
+ var SEARCH_DEBOUNCE_MS = 80;
11755
+ var SEARCH_FLUSH_MS = 50;
11756
+ var SEARCH_RESULT_CAP = 200;
11585
11757
  function useCompletionPickers({
11586
11758
  input,
11587
11759
  setInput,
@@ -11609,22 +11781,6 @@ function useCompletionPickers({
11609
11781
  });
11610
11782
  }, [slashMatches]);
11611
11783
  const [atSelected, setAtSelected] = useState16(0);
11612
- const [atFiles, setAtFiles] = useState16([]);
11613
- useEffect9(() => {
11614
- if (!codeMode) {
11615
- setAtFiles([]);
11616
- return;
11617
- }
11618
- let cancelled = false;
11619
- listFilesWithStatsAsync(rootDir, { maxResults: 500 }).then((files) => {
11620
- if (!cancelled) setAtFiles(files);
11621
- }).catch(() => {
11622
- if (!cancelled) setAtFiles([]);
11623
- });
11624
- return () => {
11625
- cancelled = true;
11626
- };
11627
- }, [codeMode, rootDir]);
11628
11784
  const recentFilesRef = useRef5([]);
11629
11785
  const recordRecentFile = useCallback8((p) => {
11630
11786
  const list2 = recentFilesRef.current;
@@ -11638,25 +11794,50 @@ function useCompletionPickers({
11638
11794
  if (slashMatches !== null) return null;
11639
11795
  return detectAtPicker(input);
11640
11796
  }, [codeMode, input, slashMatches]);
11641
- const atMatches = useMemo8(() => {
11642
- if (!atPicker) return null;
11643
- return rankPickerCandidates(atFiles, atPicker.query, {
11644
- limit: 40,
11645
- recentlyUsed: recentFilesRef.current
11646
- });
11647
- }, [atPicker, atFiles]);
11797
+ const parsed = useMemo8(
11798
+ () => atPicker ? parseAtQuery(atPicker.query) : null,
11799
+ [atPicker]
11800
+ );
11801
+ const atMode = parsed ? parsed.trailingSlash || parsed.filter === "" ? "browse" : "search" : null;
11802
+ const browseDir = parsed && atMode === "browse" ? parsed.dir : "";
11803
+ const browse = useBrowseListing(rootDir, atMode === "browse" ? browseDir : null);
11804
+ const search = useStreamingSearch(
11805
+ rootDir,
11806
+ atMode === "search" && parsed ? parsed.filter : null,
11807
+ recentFilesRef
11808
+ );
11809
+ const atState = useMemo8(() => {
11810
+ if (!parsed) return null;
11811
+ if (atMode === "browse") {
11812
+ return {
11813
+ kind: "browse",
11814
+ baseDir: browseDir,
11815
+ entries: browse.entries,
11816
+ loading: browse.loading
11817
+ };
11818
+ }
11819
+ return {
11820
+ kind: "search",
11821
+ filter: parsed.filter,
11822
+ entries: search.entries,
11823
+ scanned: search.scanned,
11824
+ searching: search.searching
11825
+ };
11826
+ }, [parsed, atMode, browseDir, browse, search]);
11648
11827
  useEffect9(() => {
11649
11828
  setAtSelected((prev) => {
11650
- if (!atMatches || atMatches.length === 0) return 0;
11651
- if (prev >= atMatches.length) return atMatches.length - 1;
11829
+ const len = atState?.entries.length ?? 0;
11830
+ if (len === 0) return 0;
11831
+ if (prev >= len) return len - 1;
11652
11832
  return prev;
11653
11833
  });
11654
- }, [atMatches]);
11834
+ }, [atState]);
11655
11835
  const pickAtMention = useCallback8(
11656
- (chosenPath) => {
11836
+ (entry, action) => {
11657
11837
  if (!atPicker) return;
11658
11838
  const before = input.slice(0, atPicker.atOffset);
11659
- setInput(`${before}@${chosenPath} `);
11839
+ const tail = action === "drill" && entry.isDir ? `${entry.insertPath}/` : `${entry.insertPath} `;
11840
+ setInput(`${before}@${tail}`);
11660
11841
  },
11661
11842
  [atPicker, input, setInput]
11662
11843
  );
@@ -11727,8 +11908,7 @@ function useCompletionPickers({
11727
11908
  setSlashSelected,
11728
11909
  slashGroupMode,
11729
11910
  slashAdvancedHidden,
11730
- atPicker,
11731
- atMatches,
11911
+ atState,
11732
11912
  atSelected,
11733
11913
  setAtSelected,
11734
11914
  pickAtMention,
@@ -11740,6 +11920,113 @@ function useCompletionPickers({
11740
11920
  pickSlashArg
11741
11921
  };
11742
11922
  }
11923
+ function useBrowseListing(rootDir, dir) {
11924
+ const [entries, setEntries] = useState16([]);
11925
+ const [loading, setLoading] = useState16(false);
11926
+ useEffect9(() => {
11927
+ if (dir === null) {
11928
+ setEntries([]);
11929
+ setLoading(false);
11930
+ return;
11931
+ }
11932
+ let cancelled = false;
11933
+ setLoading(true);
11934
+ listDirectory(rootDir, dir).then(
11935
+ (raw) => {
11936
+ if (cancelled) return;
11937
+ setEntries(raw.map(toBrowseEntry));
11938
+ setLoading(false);
11939
+ },
11940
+ () => {
11941
+ if (cancelled) return;
11942
+ setEntries([]);
11943
+ setLoading(false);
11944
+ }
11945
+ );
11946
+ return () => {
11947
+ cancelled = true;
11948
+ };
11949
+ }, [rootDir, dir]);
11950
+ return { entries, loading };
11951
+ }
11952
+ function toBrowseEntry(d) {
11953
+ return { label: d.name, insertPath: d.path, dirSuffix: "", isDir: d.isDir };
11954
+ }
11955
+ function useStreamingSearch(rootDir, filter, recentFilesRef) {
11956
+ const [, bumpRender] = useReducer2((x) => x + 1, 0);
11957
+ const hitsRef = useRef5([]);
11958
+ const scannedRef = useRef5(0);
11959
+ const searchingRef = useRef5(false);
11960
+ const rankedRef = useRef5([]);
11961
+ useEffect9(() => {
11962
+ if (filter === null) {
11963
+ hitsRef.current = [];
11964
+ scannedRef.current = 0;
11965
+ searchingRef.current = false;
11966
+ rankedRef.current = [];
11967
+ bumpRender();
11968
+ return;
11969
+ }
11970
+ hitsRef.current = [];
11971
+ scannedRef.current = 0;
11972
+ searchingRef.current = true;
11973
+ rankedRef.current = [];
11974
+ bumpRender();
11975
+ const ac = new AbortController();
11976
+ let flushTimer = null;
11977
+ const scheduleFlush = () => {
11978
+ if (flushTimer) return;
11979
+ flushTimer = setTimeout(() => {
11980
+ flushTimer = null;
11981
+ rankedRef.current = rankSearchHits(hitsRef.current, filter, recentFilesRef.current ?? []);
11982
+ bumpRender();
11983
+ }, SEARCH_FLUSH_MS);
11984
+ };
11985
+ const debounce = setTimeout(() => {
11986
+ walkFilesStream(rootDir, {
11987
+ signal: ac.signal,
11988
+ onEntry: (e) => {
11989
+ hitsRef.current.push(e);
11990
+ if (hitsRef.current.length >= SEARCH_RESULT_CAP * 8) return false;
11991
+ scheduleFlush();
11992
+ },
11993
+ onProgress: (n) => {
11994
+ scannedRef.current = n;
11995
+ scheduleFlush();
11996
+ }
11997
+ }).then(() => {
11998
+ searchingRef.current = false;
11999
+ rankedRef.current = rankSearchHits(hitsRef.current, filter, recentFilesRef.current ?? []);
12000
+ bumpRender();
12001
+ });
12002
+ }, SEARCH_DEBOUNCE_MS);
12003
+ return () => {
12004
+ clearTimeout(debounce);
12005
+ if (flushTimer) clearTimeout(flushTimer);
12006
+ ac.abort();
12007
+ };
12008
+ }, [rootDir, filter, recentFilesRef]);
12009
+ return {
12010
+ entries: rankedRef.current,
12011
+ scanned: scannedRef.current,
12012
+ searching: searchingRef.current
12013
+ };
12014
+ }
12015
+ function rankSearchHits(hits, filter, recent) {
12016
+ const ranked = rankPickerCandidates(hits, filter, {
12017
+ limit: SEARCH_RESULT_CAP,
12018
+ recentlyUsed: recent
12019
+ });
12020
+ return ranked.map((path) => {
12021
+ const slash = path.lastIndexOf("/");
12022
+ return {
12023
+ label: slash >= 0 ? path.slice(slash + 1) : path,
12024
+ insertPath: path,
12025
+ dirSuffix: slash >= 0 ? `${path.slice(0, slash)}/` : "",
12026
+ isDir: false
12027
+ };
12028
+ });
12029
+ }
11743
12030
 
11744
12031
  // src/cli/ui/useEditHistory.ts
11745
12032
  import { useCallback as useCallback9, useRef as useRef6, useState as useState17 } from "react";
@@ -12164,13 +12451,13 @@ var PLAIN_UI = process.env.REASONIX_UI === "plain";
12164
12451
  function LoopStatusRow({
12165
12452
  loop: loop2
12166
12453
  }) {
12167
- const [, setTick] = React59.useState(0);
12168
- React59.useEffect(() => {
12454
+ const [, setTick] = React60.useState(0);
12455
+ React60.useEffect(() => {
12169
12456
  const id = setInterval(() => setTick((t2) => t2 + 1), 1e3);
12170
12457
  return () => clearInterval(id);
12171
12458
  }, []);
12172
12459
  const nextFireMs = Math.max(0, loop2.nextFireAt - Date.now());
12173
- return /* @__PURE__ */ React59.createElement(Box48, null, /* @__PURE__ */ React59.createElement(Text51, { color: "cyan" }, `\u25B8 ${formatLoopStatus(loop2.prompt, nextFireMs, loop2.iter)} \xB7 /loop stop or type to cancel`));
12460
+ return /* @__PURE__ */ React60.createElement(Box49, null, /* @__PURE__ */ React60.createElement(Text52, { color: "cyan" }, `\u25B8 ${formatLoopStatus(loop2.prompt, nextFireMs, loop2.iter)} \xB7 /loop stop or type to cancel`));
12174
12461
  }
12175
12462
  function App(props) {
12176
12463
  markPhase("app_render_start");
@@ -12179,11 +12466,12 @@ function App(props) {
12179
12466
  model: props.model,
12180
12467
  workspace: props.codeMode?.rootDir ?? process.cwd()
12181
12468
  });
12182
- const initialCards = React59.useMemo(
12469
+ const initialCards = React60.useMemo(
12183
12470
  () => props.session ? hydrateCardsFromMessages(loadSessionMessages(props.session)) : [],
12184
12471
  [props.session]
12185
12472
  );
12186
- return /* @__PURE__ */ React59.createElement(AgentStoreProvider, { session, initialCards }, /* @__PURE__ */ React59.createElement(AppInner, { ...props }));
12473
+ const themeName = resolveThemePreference(loadTheme(), process.env.REASONIX_THEME);
12474
+ return /* @__PURE__ */ React60.createElement(ThemeProvider, { name: themeName }, /* @__PURE__ */ React60.createElement(AgentStoreProvider, { session, initialCards }, /* @__PURE__ */ React60.createElement(AppInner, { ...props })));
12187
12475
  }
12188
12476
  function AppInner({
12189
12477
  model: model2,
@@ -12235,7 +12523,9 @@ function AppInner({
12235
12523
  if (!stdout || !stdout.isTTY) return;
12236
12524
  stdout.write("\x1B[?2004h");
12237
12525
  stdout.write("\x1B[>4;2m");
12526
+ stdout.write("\x1B[?1006h\x1B[?1000h");
12238
12527
  return () => {
12528
+ stdout.write("\x1B[?1000l\x1B[?1006l");
12239
12529
  stdout.write("\x1B[?2004l");
12240
12530
  stdout.write("\x1B[>4m");
12241
12531
  };
@@ -12623,8 +12913,7 @@ function AppInner({
12623
12913
  setSlashSelected,
12624
12914
  slashGroupMode,
12625
12915
  slashAdvancedHidden,
12626
- atPicker,
12627
- atMatches,
12916
+ atState,
12628
12917
  atSelected,
12629
12918
  setAtSelected,
12630
12919
  pickAtMention,
@@ -12697,14 +12986,20 @@ function AppInner({
12697
12986
  }
12698
12987
  }
12699
12988
  if (codeMode && !editModeHintShown()) {
12700
- log.pushInfo(t("ui.tipEditBindings"));
12989
+ const tip = tObj("ui.tipEditBindings");
12990
+ log.pushTip({ topic: tip.topic, sections: tip.sections, footer: tip.footer });
12701
12991
  markEditModeHintShown();
12702
12992
  }
12993
+ if (!mouseClipboardHintShown()) {
12994
+ const tip = tObj("ui.tipMouseClipboard");
12995
+ log.pushTip({ topic: tip.topic, sections: tip.sections, footer: tip.footer });
12996
+ markMouseClipboardHintShown();
12997
+ }
12703
12998
  }, [session, loop2, codeMode, syncPendingCount, log]);
12704
12999
  const quitProcess = useQuit(transcriptRef);
12705
13000
  useKeystroke((ev) => {
12706
- if (ev.pageUp) chatScroll.scrollUp();
12707
- else if (ev.pageDown) chatScroll.scrollDown();
13001
+ if (ev.pageUp || ev.mouseScrollUp) chatScroll.scrollUp();
13002
+ else if (ev.pageDown || ev.mouseScrollDown) chatScroll.scrollDown();
12708
13003
  else if (ev.end) chatScroll.jumpToBottom();
12709
13004
  else if ((!chatScroll.pinned || busy) && ev.upArrow) chatScroll.scrollUp();
12710
13005
  else if ((!chatScroll.pinned || busy) && ev.downArrow) chatScroll.scrollDown();
@@ -12736,7 +13031,7 @@ function AppInner({
12736
13031
  stopLoop();
12737
13032
  return;
12738
13033
  }
12739
- if (key.escape && !busy && (slashMatches || atMatches || slashArgContext)) {
13034
+ if (key.escape && !busy && (slashMatches || atState || slashArgContext)) {
12740
13035
  setInput("");
12741
13036
  return;
12742
13037
  }
@@ -12774,18 +13069,19 @@ function AppInner({
12774
13069
  }
12775
13070
  if (busy) return;
12776
13071
  if (pendingShell) return;
12777
- if (atMatches && atMatches.length > 0) {
13072
+ if (atState && atState.entries.length > 0) {
13073
+ const entries = atState.entries;
12778
13074
  if (key.upArrow) {
12779
13075
  setAtSelected((i) => Math.max(0, i - 1));
12780
13076
  return;
12781
13077
  }
12782
13078
  if (key.downArrow) {
12783
- setAtSelected((i) => Math.min(atMatches.length - 1, i + 1));
13079
+ setAtSelected((i) => Math.min(entries.length - 1, i + 1));
12784
13080
  return;
12785
13081
  }
12786
13082
  if (key.tab) {
12787
- const sel = atMatches[atSelected] ?? atMatches[0];
12788
- if (sel) pickAtMention(sel);
13083
+ const sel = entries[atSelected] ?? entries[0];
13084
+ if (sel) pickAtMention(sel, sel.isDir ? "drill" : "commit");
12789
13085
  return;
12790
13086
  }
12791
13087
  }
@@ -12921,7 +13217,7 @@ function AppInner({
12921
13217
  if (dashboardRef.current) return dashboardRef.current.url;
12922
13218
  if (dashboardStartingRef.current) return dashboardStartingRef.current;
12923
13219
  const startup = (async () => {
12924
- const { startDashboardServer } = await import("./server-SYC3OVOP.js");
13220
+ const { startDashboardServer } = await import("./server-MC4A4WAJ.js");
12925
13221
  const handle = await startDashboardServer({
12926
13222
  mode: "attached",
12927
13223
  configPath: defaultConfigPath(),
@@ -13229,10 +13525,10 @@ function AppInner({
13229
13525
  }
13230
13526
  clearFiringFlag();
13231
13527
  if (busy) return;
13232
- if (atMatches && atMatches.length > 0 && atPicker) {
13233
- const sel = atMatches[atSelected] ?? atMatches[0];
13528
+ if (atState && atState.entries.length > 0) {
13529
+ const sel = atState.entries[atSelected] ?? atState.entries[0];
13234
13530
  if (sel) {
13235
- pickAtMention(sel);
13531
+ pickAtMention(sel, "commit");
13236
13532
  return;
13237
13533
  }
13238
13534
  }
@@ -13360,6 +13656,12 @@ function AppInner({
13360
13656
  postInfo: (text2) => log.pushInfo(text2),
13361
13657
  postDoctor: (checks) => log.showDoctor(checks),
13362
13658
  postUsage: (args) => log.showUsageVerbose(args),
13659
+ postKeys: (args) => log.pushTip({
13660
+ topic: args.topic,
13661
+ sections: args.sections,
13662
+ footer: args.footer,
13663
+ oneTime: false
13664
+ }),
13363
13665
  dispatch: agentStore.dispatch,
13364
13666
  reloadHooks: () => {
13365
13667
  const fresh = loadHooks({ projectRoot: codeMode ? currentRootDir : void 0 });
@@ -13732,8 +14034,7 @@ function AppInner({
13732
14034
  planMode,
13733
14035
  session,
13734
14036
  slashSelected,
13735
- atMatches,
13736
- atPicker,
14037
+ atState,
13737
14038
  atSelected,
13738
14039
  pickAtMention,
13739
14040
  recordRecentFile,
@@ -14205,14 +14506,14 @@ Stay in plan mode \u2014 address the feedback (explore more if needed), then sub
14205
14506
  []
14206
14507
  );
14207
14508
  const tickerSuspended = PLAIN_UI || modalOpen || !busy && !isStreaming;
14208
- return /* @__PURE__ */ React59.createElement(React59.Fragment, null, /* @__PURE__ */ React59.createElement(TickerProvider, { disabled: tickerSuspended }, /* @__PURE__ */ React59.createElement(ViewportBudgetProvider, null, /* @__PURE__ */ React59.createElement(Box48, { flexDirection: "row", height: stdout?.rows ?? 24 }, /* @__PURE__ */ React59.createElement(Box48, { flexDirection: "column", flexGrow: 1 }, /* @__PURE__ */ React59.createElement(Box48, { flexDirection: "column", flexGrow: 1 }, /* @__PURE__ */ React59.createElement(LiveExpandContext.Provider, { value: liveExpand }, /* @__PURE__ */ React59.createElement(
14509
+ return /* @__PURE__ */ React60.createElement(React60.Fragment, null, /* @__PURE__ */ React60.createElement(TickerProvider, { disabled: tickerSuspended }, /* @__PURE__ */ React60.createElement(ViewportBudgetProvider, null, /* @__PURE__ */ React60.createElement(Box49, { flexDirection: "row", height: stdout?.rows ?? 24 }, /* @__PURE__ */ React60.createElement(Box49, { flexDirection: "column", flexGrow: 1 }, /* @__PURE__ */ React60.createElement(Box49, { flexDirection: "column", flexGrow: 1 }, /* @__PURE__ */ React60.createElement(LiveExpandContext.Provider, { value: liveExpand }, /* @__PURE__ */ React60.createElement(
14209
14510
  CardStream,
14210
14511
  {
14211
14512
  suppressLive: modalOpen,
14212
14513
  scrollRows: chatScroll.scrollRows,
14213
14514
  onMaxScrollChange: chatScroll.setMaxScroll
14214
14515
  }
14215
- )), !hasConversation && !busy && !isStreaming ? /* @__PURE__ */ React59.createElement(
14516
+ )), !hasConversation && !busy && !isStreaming ? /* @__PURE__ */ React60.createElement(
14216
14517
  WelcomeBanner,
14217
14518
  {
14218
14519
  inCodeMode: !!codeMode,
@@ -14220,28 +14521,28 @@ Stay in plan mode \u2014 address the feedback (explore more if needed), then sub
14220
14521
  dashboardUrl,
14221
14522
  languageVersion
14222
14523
  }
14223
- ) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !pendingReviseEditor && !pendingSessionsPicker && !pendingCheckpointPicker && !pendingMcpHub && !stagedInput && !pendingEditReview && ongoingTool ? /* @__PURE__ */ React59.createElement(OngoingToolRow, { tool: ongoingTool, progress: toolProgress }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !pendingReviseEditor && !pendingSessionsPicker && !pendingCheckpointPicker && !pendingMcpHub && !stagedInput && !pendingEditReview && subagentActivities.length > 0 ? /* @__PURE__ */ React59.createElement(SubagentLiveStack, { activities: subagentActivities, max: 3 }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !pendingReviseEditor && !pendingSessionsPicker && !pendingCheckpointPicker && !pendingMcpHub && !stagedInput && !pendingEditReview && !ongoingTool && statusLine ? /* @__PURE__ */ React59.createElement(ThinkingRow, { text: statusLine }) : null, !PLAIN_UI && undoBanner && !pendingShell && !pendingPlan && !pendingReviseEditor && !pendingSessionsPicker && !pendingCheckpointPicker && !pendingMcpHub && !stagedInput && !pendingEditReview && !pendingChoice && !stagedChoiceCustom && !pendingRevision && !stagedCheckpointRevise && !pendingCheckpoint ? /* @__PURE__ */ React59.createElement(UndoBanner, { banner: undoBanner }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !pendingReviseEditor && !pendingSessionsPicker && !pendingCheckpointPicker && !pendingMcpHub && !stagedInput && !pendingEditReview && busy && !isStreaming && !ongoingTool && !statusLine ? /* @__PURE__ */ React59.createElement(ThinkingRow, { text: "processing\u2026" }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !pendingReviseEditor && !pendingSessionsPicker && !pendingCheckpointPicker && !pendingMcpHub && !stagedInput && !pendingEditReview ? /* @__PURE__ */ React59.createElement(PlanLiveRow, null) : null, /* @__PURE__ */ React59.createElement(ToastRail, null)), stagedInput ? /* @__PURE__ */ React59.createElement(
14524
+ ) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !pendingReviseEditor && !pendingSessionsPicker && !pendingCheckpointPicker && !pendingMcpHub && !stagedInput && !pendingEditReview && ongoingTool ? /* @__PURE__ */ React60.createElement(OngoingToolRow, { tool: ongoingTool, progress: toolProgress }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !pendingReviseEditor && !pendingSessionsPicker && !pendingCheckpointPicker && !pendingMcpHub && !stagedInput && !pendingEditReview && subagentActivities.length > 0 ? /* @__PURE__ */ React60.createElement(SubagentLiveStack, { activities: subagentActivities, max: 3 }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !pendingReviseEditor && !pendingSessionsPicker && !pendingCheckpointPicker && !pendingMcpHub && !stagedInput && !pendingEditReview && !ongoingTool && statusLine ? /* @__PURE__ */ React60.createElement(ThinkingRow, { text: statusLine }) : null, !PLAIN_UI && undoBanner && !pendingShell && !pendingPlan && !pendingReviseEditor && !pendingSessionsPicker && !pendingCheckpointPicker && !pendingMcpHub && !stagedInput && !pendingEditReview && !pendingChoice && !stagedChoiceCustom && !pendingRevision && !stagedCheckpointRevise && !pendingCheckpoint ? /* @__PURE__ */ React60.createElement(UndoBanner, { banner: undoBanner }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !pendingReviseEditor && !pendingSessionsPicker && !pendingCheckpointPicker && !pendingMcpHub && !stagedInput && !pendingEditReview && busy && !isStreaming && !ongoingTool && !statusLine ? /* @__PURE__ */ React60.createElement(ThinkingRow, { text: "processing\u2026" }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !pendingReviseEditor && !pendingSessionsPicker && !pendingCheckpointPicker && !pendingMcpHub && !stagedInput && !pendingEditReview ? /* @__PURE__ */ React60.createElement(PlanLiveRow, null) : null, /* @__PURE__ */ React60.createElement(ToastRail, null)), stagedInput ? /* @__PURE__ */ React60.createElement(
14224
14525
  PlanRefineInput,
14225
14526
  {
14226
14527
  mode: stagedInput.mode,
14227
14528
  onSubmit: handleStagedInputSubmit,
14228
14529
  onCancel: handleStagedInputCancel
14229
14530
  }
14230
- ) : stagedChoiceCustom ? /* @__PURE__ */ React59.createElement(
14531
+ ) : stagedChoiceCustom ? /* @__PURE__ */ React60.createElement(
14231
14532
  PlanRefineInput,
14232
14533
  {
14233
14534
  mode: "choice-custom",
14234
14535
  onSubmit: handleChoiceCustomSubmit,
14235
14536
  onCancel: handleChoiceCustomCancel
14236
14537
  }
14237
- ) : stagedCheckpointRevise ? /* @__PURE__ */ React59.createElement(
14538
+ ) : stagedCheckpointRevise ? /* @__PURE__ */ React60.createElement(
14238
14539
  PlanRefineInput,
14239
14540
  {
14240
14541
  mode: "checkpoint-revise",
14241
14542
  onSubmit: (text) => handleCheckpointReviseSubmit(text, stagedCheckpointRevise),
14242
14543
  onCancel: handleCheckpointReviseCancel
14243
14544
  }
14244
- ) : pendingChoice ? /* @__PURE__ */ React59.createElement(
14545
+ ) : pendingChoice ? /* @__PURE__ */ React60.createElement(
14245
14546
  ChoiceConfirm,
14246
14547
  {
14247
14548
  question: pendingChoice.question,
@@ -14249,7 +14550,7 @@ Stay in plan mode \u2014 address the feedback (explore more if needed), then sub
14249
14550
  allowCustom: pendingChoice.allowCustom,
14250
14551
  onChoose: stableHandleChoiceConfirm
14251
14552
  }
14252
- ) : pendingRevision ? /* @__PURE__ */ React59.createElement(
14553
+ ) : pendingRevision ? /* @__PURE__ */ React60.createElement(
14253
14554
  PlanReviseConfirm,
14254
14555
  {
14255
14556
  reason: pendingRevision.reason,
@@ -14260,7 +14561,7 @@ Stay in plan mode \u2014 address the feedback (explore more if needed), then sub
14260
14561
  summary: pendingRevision.summary,
14261
14562
  onChoose: stableHandleReviseConfirm
14262
14563
  }
14263
- ) : pendingCheckpoint ? /* @__PURE__ */ React59.createElement(
14564
+ ) : pendingCheckpoint ? /* @__PURE__ */ React60.createElement(
14264
14565
  PlanCheckpointConfirm,
14265
14566
  {
14266
14567
  stepId: pendingCheckpoint.stepId,
@@ -14271,7 +14572,7 @@ Stay in plan mode \u2014 address the feedback (explore more if needed), then sub
14271
14572
  completedStepIds: completedStepIdsRef.current,
14272
14573
  onChoose: stableHandleCheckpointConfirm
14273
14574
  }
14274
- ) : pendingCheckpointPicker ? /* @__PURE__ */ React59.createElement(
14575
+ ) : pendingCheckpointPicker ? /* @__PURE__ */ React60.createElement(
14275
14576
  CheckpointPicker,
14276
14577
  {
14277
14578
  checkpoints: checkpointPickerList,
@@ -14316,7 +14617,7 @@ Stay in plan mode \u2014 address the feedback (explore more if needed), then sub
14316
14617
  }
14317
14618
  }
14318
14619
  }
14319
- ) : pendingSessionsPicker ? /* @__PURE__ */ React59.createElement(
14620
+ ) : pendingSessionsPicker ? /* @__PURE__ */ React60.createElement(
14320
14621
  SessionPicker,
14321
14622
  {
14322
14623
  sessions: sessionsPickerList,
@@ -14361,7 +14662,7 @@ Stay in plan mode \u2014 address the feedback (explore more if needed), then sub
14361
14662
  }
14362
14663
  }
14363
14664
  }
14364
- ) : pendingModelPicker ? /* @__PURE__ */ React59.createElement(
14665
+ ) : pendingModelPicker ? /* @__PURE__ */ React60.createElement(
14365
14666
  ModelPicker,
14366
14667
  {
14367
14668
  models,
@@ -14393,7 +14694,7 @@ Stay in plan mode \u2014 address the feedback (explore more if needed), then sub
14393
14694
  }
14394
14695
  }
14395
14696
  }
14396
- ) : pendingMcpHub ? /* @__PURE__ */ React59.createElement(
14697
+ ) : pendingMcpHub ? /* @__PURE__ */ React60.createElement(
14397
14698
  McpHub,
14398
14699
  {
14399
14700
  initialTab: pendingMcpHub.tab,
@@ -14413,7 +14714,7 @@ Stay in plan mode \u2014 address the feedback (explore more if needed), then sub
14413
14714
  return r;
14414
14715
  } : void 0
14415
14716
  }
14416
- ) : pendingPlan ? /* @__PURE__ */ React59.createElement(
14717
+ ) : pendingPlan ? /* @__PURE__ */ React60.createElement(
14417
14718
  PlanConfirm,
14418
14719
  {
14419
14720
  plan: pendingPlan,
@@ -14422,7 +14723,7 @@ Stay in plan mode \u2014 address the feedback (explore more if needed), then sub
14422
14723
  onChoose: stableHandlePlanConfirm,
14423
14724
  projectRoot: currentRootDir
14424
14725
  }
14425
- ) : pendingReviseEditor ? /* @__PURE__ */ React59.createElement(
14726
+ ) : pendingReviseEditor ? /* @__PURE__ */ React60.createElement(
14426
14727
  PlanReviseEditor,
14427
14728
  {
14428
14729
  steps: planStepsRef.current ?? [],
@@ -14441,7 +14742,7 @@ Stay in plan mode \u2014 address the feedback (explore more if needed), then sub
14441
14742
  setPendingPlan(planText);
14442
14743
  }
14443
14744
  }
14444
- ) : pendingShell ? /* @__PURE__ */ React59.createElement(
14745
+ ) : pendingShell ? /* @__PURE__ */ React60.createElement(
14445
14746
  ShellConfirm,
14446
14747
  {
14447
14748
  command: pendingShell.command,
@@ -14449,7 +14750,7 @@ Stay in plan mode \u2014 address the feedback (explore more if needed), then sub
14449
14750
  kind: pendingShell.kind,
14450
14751
  onChoose: handleShellConfirm
14451
14752
  }
14452
- ) : pendingEditReview ? /* @__PURE__ */ React59.createElement(
14753
+ ) : pendingEditReview ? /* @__PURE__ */ React60.createElement(
14453
14754
  EditConfirm,
14454
14755
  {
14455
14756
  block: pendingEditReview,
@@ -14461,14 +14762,14 @@ Stay in plan mode \u2014 address the feedback (explore more if needed), then sub
14461
14762
  }
14462
14763
  }
14463
14764
  }
14464
- ) : walkthroughActive && pendingEdits.current.length > 0 ? /* @__PURE__ */ React59.createElement(
14765
+ ) : walkthroughActive && pendingEdits.current.length > 0 ? /* @__PURE__ */ React60.createElement(
14465
14766
  EditConfirm,
14466
14767
  {
14467
14768
  key: `walk-${pendingTick}`,
14468
14769
  block: pendingEdits.current[0],
14469
14770
  onChoose: handleWalkChoice
14470
14771
  }
14471
- ) : !chatScroll.pinned ? /* @__PURE__ */ React59.createElement(Text51, { color: FG.faint }, " \u{1F4D6} reading history \u2014 End / PgDn to return \xB7 \u2193 to advance one line") : /* @__PURE__ */ React59.createElement(React59.Fragment, null, codeMode ? /* @__PURE__ */ React59.createElement(
14772
+ ) : !chatScroll.pinned ? /* @__PURE__ */ React60.createElement(Text52, { color: FG.faint }, " \u{1F4D6} reading history \u2014 End / PgDn to return \xB7 \u2193 to advance one line") : /* @__PURE__ */ React60.createElement(React60.Fragment, null, codeMode ? /* @__PURE__ */ React60.createElement(
14472
14773
  ModeStatusBar,
14473
14774
  {
14474
14775
  editMode,
@@ -14478,7 +14779,7 @@ Stay in plan mode \u2014 address the feedback (explore more if needed), then sub
14478
14779
  undoArmed: !!undoBanner || hasUndoable(),
14479
14780
  jobs: codeMode.jobs
14480
14781
  }
14481
- ) : null, activeLoop ? /* @__PURE__ */ React59.createElement(LoopStatusRow, { loop: activeLoop }) : null, /* @__PURE__ */ React59.createElement(StatusRow, null), /* @__PURE__ */ React59.createElement(
14782
+ ) : null, activeLoop ? /* @__PURE__ */ React60.createElement(LoopStatusRow, { loop: activeLoop }) : null, /* @__PURE__ */ React60.createElement(StatusRow, null), /* @__PURE__ */ React60.createElement(
14482
14783
  PromptInput,
14483
14784
  {
14484
14785
  value: input,
@@ -14486,11 +14787,9 @@ Stay in plan mode \u2014 address the feedback (explore more if needed), then sub
14486
14787
  onSubmit: handleSubmit,
14487
14788
  disabled: busy,
14488
14789
  onHistoryPrev: recallPrev,
14489
- onHistoryNext: recallNext,
14490
- onChatScrollUp: chatScroll.scrollUp,
14491
- onChatScrollDown: chatScroll.scrollDown
14790
+ onHistoryNext: recallNext
14492
14791
  }
14493
- ), slashMatches !== null ? /* @__PURE__ */ React59.createElement(
14792
+ ), slashMatches !== null ? /* @__PURE__ */ React60.createElement(
14494
14793
  SlashSuggestions,
14495
14794
  {
14496
14795
  matches: slashMatches,
@@ -14498,14 +14797,7 @@ Stay in plan mode \u2014 address the feedback (explore more if needed), then sub
14498
14797
  groupMode: slashGroupMode,
14499
14798
  advancedHidden: slashAdvancedHidden
14500
14799
  }
14501
- ) : null, atMatches !== null ? /* @__PURE__ */ React59.createElement(
14502
- AtMentionSuggestions,
14503
- {
14504
- matches: atMatches,
14505
- selectedIndex: atSelected,
14506
- query: atPicker?.query ?? ""
14507
- }
14508
- ) : null, slashArgContext ? /* @__PURE__ */ React59.createElement(
14800
+ ) : null, atState !== null ? /* @__PURE__ */ React60.createElement(AtMentionSuggestions, { state: atState, selectedIndex: atSelected }) : null, slashArgContext ? /* @__PURE__ */ React60.createElement(
14509
14801
  SlashArgPicker,
14510
14802
  {
14511
14803
  matches: slashArgMatches,
@@ -14518,12 +14810,12 @@ Stay in plan mode \u2014 address the feedback (explore more if needed), then sub
14518
14810
  }
14519
14811
 
14520
14812
  // src/cli/ui/Setup.tsx
14521
- import { Box as Box49, Text as Text53, useApp } from "ink";
14522
- import React61, { useState as useState21 } from "react";
14813
+ import { Box as Box50, Text as Text54, useApp } from "ink";
14814
+ import React62, { useState as useState21 } from "react";
14523
14815
 
14524
14816
  // src/cli/ui/MaskedInput.tsx
14525
- import { Text as Text52, useInput } from "ink";
14526
- import React60, { useRef as useRef9 } from "react";
14817
+ import { Text as Text53, useInput } from "ink";
14818
+ import React61, { useRef as useRef9 } from "react";
14527
14819
  function stripPasteMarkers(s) {
14528
14820
  return s.replace(/\u001b?\[20[01]~/g, "").replace(/\u001b/g, "");
14529
14821
  }
@@ -14558,11 +14850,11 @@ function MaskedInput({
14558
14850
  });
14559
14851
  if (value.length === 0) {
14560
14852
  if (placeholder.length === 0) {
14561
- return /* @__PURE__ */ React60.createElement(Text52, { inverse: true }, " ");
14853
+ return /* @__PURE__ */ React61.createElement(Text53, { inverse: true }, " ");
14562
14854
  }
14563
- return /* @__PURE__ */ React60.createElement(React60.Fragment, null, /* @__PURE__ */ React60.createElement(Text52, { inverse: true }, placeholder[0]), /* @__PURE__ */ React60.createElement(Text52, { color: FG.faint }, placeholder.slice(1)));
14855
+ return /* @__PURE__ */ React61.createElement(React61.Fragment, null, /* @__PURE__ */ React61.createElement(Text53, { inverse: true }, placeholder[0]), /* @__PURE__ */ React61.createElement(Text53, { color: FG.faint }, placeholder.slice(1)));
14564
14856
  }
14565
- return /* @__PURE__ */ React60.createElement(React60.Fragment, null, /* @__PURE__ */ React60.createElement(Text52, null, mask.repeat(value.length)), /* @__PURE__ */ React60.createElement(Text52, { inverse: true }, " "));
14857
+ return /* @__PURE__ */ React61.createElement(React61.Fragment, null, /* @__PURE__ */ React61.createElement(Text53, null, mask.repeat(value.length)), /* @__PURE__ */ React61.createElement(Text53, { inverse: true }, " "));
14566
14858
  }
14567
14859
 
14568
14860
  // src/cli/ui/Setup.tsx
@@ -14589,7 +14881,7 @@ function Setup({ onReady }) {
14589
14881
  }
14590
14882
  onReady(trimmed);
14591
14883
  };
14592
- return /* @__PURE__ */ React61.createElement(Box49, { flexDirection: "column", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React61.createElement(Box49, null, /* @__PURE__ */ React61.createElement(Text53, { bold: true, color: GRADIENT[0] }, GLYPH.brand), /* @__PURE__ */ React61.createElement(Text53, null, " "), /* @__PURE__ */ React61.createElement(Text53, { bold: true }, "Welcome to "), /* @__PURE__ */ React61.createElement(Text53, { bold: true, color: GRADIENT[2] }, "REASONIX")), /* @__PURE__ */ React61.createElement(Box49, { marginTop: 1 }, /* @__PURE__ */ React61.createElement(Text53, { color: COLOR.info }, "Paste your DeepSeek API key to get started.")), /* @__PURE__ */ React61.createElement(Box49, null, /* @__PURE__ */ React61.createElement(Text53, { dimColor: true }, " sign up at \xB7 "), /* @__PURE__ */ React61.createElement(Text53, { color: COLOR.primary }, "https://platform.deepseek.com/api_keys")), /* @__PURE__ */ React61.createElement(Box49, null, /* @__PURE__ */ React61.createElement(Text53, { dimColor: true }, " saved to "), /* @__PURE__ */ React61.createElement(Text53, { dimColor: true }, defaultConfigPath())), /* @__PURE__ */ React61.createElement(Box49, { marginTop: 1 }, /* @__PURE__ */ React61.createElement(Text53, { bold: true, color: COLOR.brand }, GLYPH.bar), /* @__PURE__ */ React61.createElement(Text53, { bold: true, color: COLOR.primary }, " \u203A "), /* @__PURE__ */ React61.createElement(
14884
+ return /* @__PURE__ */ React62.createElement(Box50, { flexDirection: "column", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React62.createElement(Box50, null, /* @__PURE__ */ React62.createElement(Text54, { bold: true, color: GRADIENT[0] }, GLYPH.brand), /* @__PURE__ */ React62.createElement(Text54, null, " "), /* @__PURE__ */ React62.createElement(Text54, { bold: true }, "Welcome to "), /* @__PURE__ */ React62.createElement(Text54, { bold: true, color: GRADIENT[2] }, "REASONIX")), /* @__PURE__ */ React62.createElement(Box50, { marginTop: 1 }, /* @__PURE__ */ React62.createElement(Text54, { color: COLOR.info }, "Paste your DeepSeek API key to get started.")), /* @__PURE__ */ React62.createElement(Box50, null, /* @__PURE__ */ React62.createElement(Text54, { dimColor: true }, " sign up at \xB7 "), /* @__PURE__ */ React62.createElement(Text54, { color: COLOR.primary }, "https://platform.deepseek.com/api_keys")), /* @__PURE__ */ React62.createElement(Box50, null, /* @__PURE__ */ React62.createElement(Text54, { dimColor: true }, " saved to "), /* @__PURE__ */ React62.createElement(Text54, { dimColor: true }, defaultConfigPath())), /* @__PURE__ */ React62.createElement(Box50, { marginTop: 1 }, /* @__PURE__ */ React62.createElement(Text54, { bold: true, color: COLOR.brand }, GLYPH.bar), /* @__PURE__ */ React62.createElement(Text54, { bold: true, color: COLOR.primary }, " \u203A "), /* @__PURE__ */ React62.createElement(
14593
14885
  MaskedInput,
14594
14886
  {
14595
14887
  value,
@@ -14598,7 +14890,7 @@ function Setup({ onReady }) {
14598
14890
  mask: "\u2022",
14599
14891
  placeholder: "sk-..."
14600
14892
  }
14601
- )), error ? /* @__PURE__ */ React61.createElement(Box49, { marginTop: 1 }, /* @__PURE__ */ React61.createElement(Text53, { color: COLOR.err, bold: true }, GLYPH.err), /* @__PURE__ */ React61.createElement(Text53, { color: COLOR.err }, ` ${error}`)) : value ? /* @__PURE__ */ React61.createElement(Box49, { marginTop: 1 }, /* @__PURE__ */ React61.createElement(Text53, { dimColor: true }, ` preview \xB7 ${redactKey(value)}`)) : null, /* @__PURE__ */ React61.createElement(Box49, { marginTop: 1 }, /* @__PURE__ */ React61.createElement(Text53, { dimColor: true }, " /exit to abort")));
14893
+ )), error ? /* @__PURE__ */ React62.createElement(Box50, { marginTop: 1 }, /* @__PURE__ */ React62.createElement(Text54, { color: COLOR.err, bold: true }, GLYPH.err), /* @__PURE__ */ React62.createElement(Text54, { color: COLOR.err }, ` ${error}`)) : value ? /* @__PURE__ */ React62.createElement(Box50, { marginTop: 1 }, /* @__PURE__ */ React62.createElement(Text54, { dimColor: true }, ` preview \xB7 ${redactKey(value)}`)) : null, /* @__PURE__ */ React62.createElement(Box50, { marginTop: 1 }, /* @__PURE__ */ React62.createElement(Text54, { dimColor: true }, " /exit to abort")));
14602
14894
  }
14603
14895
 
14604
14896
  // src/cli/ui/drain-tty.ts
@@ -14809,7 +15101,7 @@ function Root({
14809
15101
  const workspaceRoot = appProps.codeMode?.rootDir ?? process.cwd();
14810
15102
  const [sessions2, setSessions] = useState22(() => listSessionsForWorkspace(workspaceRoot));
14811
15103
  if (!key) {
14812
- return /* @__PURE__ */ React62.createElement(
15104
+ return /* @__PURE__ */ React63.createElement(
14813
15105
  Setup,
14814
15106
  {
14815
15107
  onReady: (k) => {
@@ -14821,7 +15113,7 @@ function Root({
14821
15113
  }
14822
15114
  process.env.DEEPSEEK_API_KEY = key;
14823
15115
  if (pickerOpen) {
14824
- return /* @__PURE__ */ React62.createElement(KeystrokeProvider, null, /* @__PURE__ */ React62.createElement(
15116
+ return /* @__PURE__ */ React63.createElement(KeystrokeProvider, null, /* @__PURE__ */ React63.createElement(
14825
15117
  SessionPicker,
14826
15118
  {
14827
15119
  sessions: sessions2,
@@ -14854,7 +15146,7 @@ function Root({
14854
15146
  }
14855
15147
  ));
14856
15148
  }
14857
- return /* @__PURE__ */ React62.createElement(KeystrokeProvider, null, /* @__PURE__ */ React62.createElement(
15149
+ return /* @__PURE__ */ React63.createElement(KeystrokeProvider, null, /* @__PURE__ */ React63.createElement(
14858
15150
  App,
14859
15151
  {
14860
15152
  key: activeSession ?? "__new__",
@@ -14926,7 +15218,7 @@ async function chatCommand(opts) {
14926
15218
  const showPicker = !opts.session && !opts.forceResume && listSessionsForWorkspace(launchWorkspace).length > 0;
14927
15219
  markPhase("ink_render_call");
14928
15220
  const { waitUntilExit } = render(
14929
- /* @__PURE__ */ React62.createElement(
15221
+ /* @__PURE__ */ React63.createElement(
14930
15222
  Root,
14931
15223
  {
14932
15224
  initialKey,
@@ -14962,4 +15254,4 @@ async function chatCommand(opts) {
14962
15254
  export {
14963
15255
  chatCommand
14964
15256
  };
14965
- //# sourceMappingURL=chunk-MDHVWCJ4.js.map
15257
+ //# sourceMappingURL=chunk-5SAMVHA3.js.map