reasonix 0.40.0 → 0.41.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 (130) hide show
  1. package/README.md +21 -13
  2. package/README.zh-CN.md +19 -13
  3. package/dashboard/app.css +8 -4
  4. package/dashboard/dist/app.js +279 -224
  5. package/dashboard/dist/app.js.map +1 -1
  6. package/dist/cli/acp-64VQZLDJ.js +708 -0
  7. package/dist/cli/acp-64VQZLDJ.js.map +1 -0
  8. package/dist/cli/chat-ZAGX52RV.js +46 -0
  9. package/dist/cli/{chunk-UCMTWZKU.js → chunk-2CXPDAWX.js} +2 -2
  10. package/dist/cli/{chunk-CLAN6PVH.js → chunk-4H3ZRJ2U.js} +19 -7
  11. package/dist/cli/chunk-4H3ZRJ2U.js.map +1 -0
  12. package/dist/cli/{chunk-A5LSGEEK.js → chunk-4W2CICFQ.js} +21 -10
  13. package/dist/cli/{chunk-A5LSGEEK.js.map → chunk-4W2CICFQ.js.map} +1 -1
  14. package/dist/cli/{chunk-CZSJILQP.js → chunk-65Q5HQ26.js} +39 -1
  15. package/dist/cli/chunk-65Q5HQ26.js.map +1 -0
  16. package/dist/cli/{chunk-XHQIK7B6.js → chunk-7SPOFTMT.js} +2 -2
  17. package/dist/cli/{chunk-5GKJLNP2.js → chunk-7VFNPMKG.js} +2 -2
  18. package/dist/cli/{chunk-UVRXTSK3.js → chunk-A3LL4XDV.js} +8 -2
  19. package/dist/cli/chunk-A3LL4XDV.js.map +1 -0
  20. package/dist/cli/{chunk-VLNRQMCI.js → chunk-A7VHMMDE.js} +2 -2
  21. package/dist/cli/{chunk-R4YTW7PR.js → chunk-ARF3N2SY.js} +56 -12
  22. package/dist/cli/chunk-ARF3N2SY.js.map +1 -0
  23. package/dist/cli/{chunk-AVB3WZWU.js → chunk-AT6GGIBV.js} +10 -10
  24. package/dist/cli/{chunk-RFX7TYVV.js → chunk-BOFL3T45.js} +14 -1
  25. package/dist/cli/chunk-BOFL3T45.js.map +1 -0
  26. package/dist/cli/{chunk-SZH34P45.js → chunk-BYZGO3BX.js} +43 -17
  27. package/dist/cli/chunk-BYZGO3BX.js.map +1 -0
  28. package/dist/cli/{chunk-7DLHHBGN.js → chunk-CD4SCQL4.js} +6 -4
  29. package/dist/cli/chunk-CD4SCQL4.js.map +1 -0
  30. package/dist/cli/{chunk-HCC42PEI.js → chunk-CFY2XLY6.js} +6 -2
  31. package/dist/cli/chunk-CFY2XLY6.js.map +1 -0
  32. package/dist/cli/{chunk-26UDIXLD.js → chunk-F2AV2QDK.js} +493 -460
  33. package/dist/cli/chunk-F2AV2QDK.js.map +1 -0
  34. package/dist/cli/{chunk-KMWKGPFZ.js → chunk-H4OLWRSX.js} +10 -1
  35. package/dist/cli/chunk-H4OLWRSX.js.map +1 -0
  36. package/dist/cli/{chunk-4YV2GBYG.js → chunk-IEA6JOIP.js} +291 -98
  37. package/dist/cli/chunk-IEA6JOIP.js.map +1 -0
  38. package/dist/cli/{chunk-WKOMCPXP.js → chunk-KZYLMMU5.js} +21 -13
  39. package/dist/cli/chunk-KZYLMMU5.js.map +1 -0
  40. package/dist/cli/{chunk-JWCTX5S4.js → chunk-L7W3HJZQ.js} +2 -2
  41. package/dist/cli/{chunk-MRLXEMZ7.js → chunk-LN27AKV3.js} +1 -1
  42. package/dist/cli/chunk-LN27AKV3.js.map +1 -0
  43. package/dist/cli/{chunk-IYF36OCJ.js → chunk-LTXADNCO.js} +2 -2
  44. package/dist/cli/{chunk-H7PHYVPM.js → chunk-MHGPBJ2T.js} +44 -8
  45. package/dist/cli/chunk-MHGPBJ2T.js.map +1 -0
  46. package/dist/cli/{chunk-ULBW7DYL.js → chunk-RAUPWSYA.js} +2 -2
  47. package/dist/cli/chunk-SXLJBFIV.js +245 -0
  48. package/dist/cli/chunk-SXLJBFIV.js.map +1 -0
  49. package/dist/cli/{chunk-4X3NY5ZM.js → chunk-UV7XJUJH.js} +2 -2
  50. package/dist/cli/{chunk-XJLZ4HKU.js → chunk-VFG4GIT3.js} +2 -2
  51. package/dist/cli/{chunk-FFNOMR32.js → chunk-WE3YZULK.js} +2 -2
  52. package/dist/cli/chunk-Y5XNV3NX.js +25 -0
  53. package/dist/cli/chunk-Y5XNV3NX.js.map +1 -0
  54. package/dist/cli/{chunk-XST7BSZJ.js → chunk-YJFKFTAL.js} +7 -1
  55. package/dist/cli/chunk-YJFKFTAL.js.map +1 -0
  56. package/dist/cli/{code-YQGVLIT2.js → code-X3M6ENTQ.js} +38 -35
  57. package/dist/cli/{code-YQGVLIT2.js.map → code-X3M6ENTQ.js.map} +1 -1
  58. package/dist/cli/{commands-FQZOBLLZ.js → commands-QY7MSQG7.js} +4 -4
  59. package/dist/cli/{commit-ZS24SHPG.js → commit-BRCQ3OQO.js} +3 -3
  60. package/dist/cli/{desktop-6OLENOOO.js → desktop-ZTMHQR2Y.js} +247 -28
  61. package/dist/cli/desktop-ZTMHQR2Y.js.map +1 -0
  62. package/dist/cli/{diff-2VUKNGEI.js → diff-YASCB7PU.js} +7 -7
  63. package/dist/cli/{doctor-JO2WNN6C.js → doctor-XCN5ETVP.js} +9 -9
  64. package/dist/cli/{events-APSVNROZ.js → events-2AJTXR7I.js} +3 -3
  65. package/dist/cli/index.js +69 -35
  66. package/dist/cli/index.js.map +1 -1
  67. package/dist/cli/{mcp-DCKOE5RF.js → mcp-YMWBLRR7.js} +2 -2
  68. package/dist/cli/{mcp-browse-D6GBP5RQ.js → mcp-browse-XLDUE6SB.js} +7 -3
  69. package/dist/cli/mcp-browse-XLDUE6SB.js.map +1 -0
  70. package/dist/cli/{mcp-inspect-KFGFPJ3E.js → mcp-inspect-H4D2HSJP.js} +5 -7
  71. package/dist/cli/{mcp-inspect-KFGFPJ3E.js.map → mcp-inspect-H4D2HSJP.js.map} +1 -1
  72. package/dist/cli/{prompt-PKCCLLAD.js → prompt-RSIHN62V.js} +4 -3
  73. package/dist/cli/{prune-sessions-LV33R47N.js → prune-sessions-4N3BVST2.js} +2 -2
  74. package/dist/cli/{replay-WFCYX7XF.js → replay-3GTWM75X.js} +8 -8
  75. package/dist/cli/{run-IUJYEPMT.js → run-BLZPTRDX.js} +19 -21
  76. package/dist/cli/{run-IUJYEPMT.js.map → run-BLZPTRDX.js.map} +1 -1
  77. package/dist/cli/{server-CN4QPPVJ.js → server-DRFPXXSH.js} +16 -12
  78. package/dist/cli/{server-CN4QPPVJ.js.map → server-DRFPXXSH.js.map} +1 -1
  79. package/dist/cli/{sessions-F5GPGTJN.js → sessions-BOWFPTXT.js} +13 -13
  80. package/dist/cli/{setup-WWMDBPSB.js → setup-FQL2JJC2.js} +5 -5
  81. package/dist/cli/version-XQXYSJ5L.js +30 -0
  82. package/dist/index.d.ts +148 -103
  83. package/dist/index.js +468 -134
  84. package/dist/index.js.map +1 -1
  85. package/package.json +2 -1
  86. package/dist/cli/chat-G7CUW4ZI.js +0 -45
  87. package/dist/cli/chunk-26UDIXLD.js.map +0 -1
  88. package/dist/cli/chunk-4YV2GBYG.js.map +0 -1
  89. package/dist/cli/chunk-7DLHHBGN.js.map +0 -1
  90. package/dist/cli/chunk-CLAN6PVH.js.map +0 -1
  91. package/dist/cli/chunk-CPTZ5OHX.js +0 -18
  92. package/dist/cli/chunk-CPTZ5OHX.js.map +0 -1
  93. package/dist/cli/chunk-CZSJILQP.js.map +0 -1
  94. package/dist/cli/chunk-H7PHYVPM.js.map +0 -1
  95. package/dist/cli/chunk-HCC42PEI.js.map +0 -1
  96. package/dist/cli/chunk-KMWKGPFZ.js.map +0 -1
  97. package/dist/cli/chunk-MRLXEMZ7.js.map +0 -1
  98. package/dist/cli/chunk-R4YTW7PR.js.map +0 -1
  99. package/dist/cli/chunk-RFX7TYVV.js.map +0 -1
  100. package/dist/cli/chunk-SZH34P45.js.map +0 -1
  101. package/dist/cli/chunk-UVRXTSK3.js.map +0 -1
  102. package/dist/cli/chunk-WKOMCPXP.js.map +0 -1
  103. package/dist/cli/chunk-XST7BSZJ.js.map +0 -1
  104. package/dist/cli/desktop-6OLENOOO.js.map +0 -1
  105. package/dist/cli/mcp-browse-D6GBP5RQ.js.map +0 -1
  106. package/dist/cli/version-KQUPV6T5.js +0 -30
  107. /package/dist/cli/{chat-G7CUW4ZI.js.map → chat-ZAGX52RV.js.map} +0 -0
  108. /package/dist/cli/{chunk-UCMTWZKU.js.map → chunk-2CXPDAWX.js.map} +0 -0
  109. /package/dist/cli/{chunk-XHQIK7B6.js.map → chunk-7SPOFTMT.js.map} +0 -0
  110. /package/dist/cli/{chunk-5GKJLNP2.js.map → chunk-7VFNPMKG.js.map} +0 -0
  111. /package/dist/cli/{chunk-VLNRQMCI.js.map → chunk-A7VHMMDE.js.map} +0 -0
  112. /package/dist/cli/{chunk-AVB3WZWU.js.map → chunk-AT6GGIBV.js.map} +0 -0
  113. /package/dist/cli/{chunk-JWCTX5S4.js.map → chunk-L7W3HJZQ.js.map} +0 -0
  114. /package/dist/cli/{chunk-IYF36OCJ.js.map → chunk-LTXADNCO.js.map} +0 -0
  115. /package/dist/cli/{chunk-ULBW7DYL.js.map → chunk-RAUPWSYA.js.map} +0 -0
  116. /package/dist/cli/{chunk-4X3NY5ZM.js.map → chunk-UV7XJUJH.js.map} +0 -0
  117. /package/dist/cli/{chunk-XJLZ4HKU.js.map → chunk-VFG4GIT3.js.map} +0 -0
  118. /package/dist/cli/{chunk-FFNOMR32.js.map → chunk-WE3YZULK.js.map} +0 -0
  119. /package/dist/cli/{commands-FQZOBLLZ.js.map → commands-QY7MSQG7.js.map} +0 -0
  120. /package/dist/cli/{commit-ZS24SHPG.js.map → commit-BRCQ3OQO.js.map} +0 -0
  121. /package/dist/cli/{diff-2VUKNGEI.js.map → diff-YASCB7PU.js.map} +0 -0
  122. /package/dist/cli/{doctor-JO2WNN6C.js.map → doctor-XCN5ETVP.js.map} +0 -0
  123. /package/dist/cli/{events-APSVNROZ.js.map → events-2AJTXR7I.js.map} +0 -0
  124. /package/dist/cli/{mcp-DCKOE5RF.js.map → mcp-YMWBLRR7.js.map} +0 -0
  125. /package/dist/cli/{prompt-PKCCLLAD.js.map → prompt-RSIHN62V.js.map} +0 -0
  126. /package/dist/cli/{prune-sessions-LV33R47N.js.map → prune-sessions-4N3BVST2.js.map} +0 -0
  127. /package/dist/cli/{replay-WFCYX7XF.js.map → replay-3GTWM75X.js.map} +0 -0
  128. /package/dist/cli/{sessions-F5GPGTJN.js.map → sessions-BOWFPTXT.js.map} +0 -0
  129. /package/dist/cli/{setup-WWMDBPSB.js.map → setup-FQL2JJC2.js.map} +0 -0
  130. /package/dist/cli/{version-KQUPV6T5.js.map → version-XQXYSJ5L.js.map} +0 -0
@@ -1,19 +1,22 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- formatMcpLifecycleEvent,
4
- formatMcpSlowToast
5
- } from "./chunk-IYF36OCJ.js";
3
+ loadOverlay
4
+ } from "./chunk-Y5XNV3NX.js";
6
5
  import {
7
- buildTransportFromSpec
8
- } from "./chunk-CPTZ5OHX.js";
6
+ createMcpRuntime
7
+ } from "./chunk-SXLJBFIV.js";
9
8
  import {
10
9
  Eventizer,
11
10
  registerSkillTools,
12
11
  shouldAutoResolveCheckpoint
13
- } from "./chunk-VLNRQMCI.js";
12
+ } from "./chunk-A7VHMMDE.js";
14
13
  import {
15
- preflightStdioSpec
16
- } from "./chunk-RFX7TYVV.js";
14
+ formatMcpLifecycleEvent,
15
+ formatMcpSlowToast
16
+ } from "./chunk-LTXADNCO.js";
17
+ import {
18
+ buildTransportFromSpec
19
+ } from "./chunk-BOFL3T45.js";
17
20
  import {
18
21
  dumpStartupProfile,
19
22
  markPhase
@@ -23,7 +26,6 @@ import {
23
26
  ImmutablePrefix,
24
27
  ToolRegistry,
25
28
  applyEditBlocks,
26
- bridgeMcpTools,
27
29
  detectAtPicker,
28
30
  expandAtMentions,
29
31
  expandAtUrls,
@@ -42,25 +44,25 @@ import {
42
44
  toWholeFileEditBlock,
43
45
  walkFilesStream,
44
46
  webFetch
45
- } from "./chunk-4YV2GBYG.js";
46
- import {
47
- McpClient,
48
- inspectMcpServer,
49
- parseMcpSpec
50
- } from "./chunk-HCC42PEI.js";
47
+ } from "./chunk-IEA6JOIP.js";
51
48
  import {
52
49
  openTranscriptFile,
53
50
  recordFromLoopEvent,
54
51
  writeRecord
55
- } from "./chunk-XHQIK7B6.js";
52
+ } from "./chunk-7SPOFTMT.js";
56
53
  import {
57
- MemoryStore
58
- } from "./chunk-R4YTW7PR.js";
54
+ McpClient,
55
+ parseMcpSpec
56
+ } from "./chunk-CFY2XLY6.js";
57
+ import {
58
+ MemoryStore,
59
+ effectivePriority
60
+ } from "./chunk-ARF3N2SY.js";
59
61
  import {
60
62
  KeystrokeProvider,
61
63
  SingleSelect,
62
64
  useKeystroke
63
- } from "./chunk-A5LSGEEK.js";
65
+ } from "./chunk-4W2CICFQ.js";
64
66
  import {
65
67
  COLOR,
66
68
  GLYPH,
@@ -68,7 +70,7 @@ import {
68
70
  ThemeProvider,
69
71
  useColor,
70
72
  useThemeTokens
71
- } from "./chunk-4X3NY5ZM.js";
73
+ } from "./chunk-UV7XJUJH.js";
72
74
  import {
73
75
  PRESETS,
74
76
  PRESET_DESCRIPTIONS,
@@ -76,13 +78,14 @@ import {
76
78
  } from "./chunk-E46ECXJD.js";
77
79
  import {
78
80
  runDoctorChecks
79
- } from "./chunk-WKOMCPXP.js";
81
+ } from "./chunk-KZYLMMU5.js";
80
82
  import {
81
83
  countTokens
82
84
  } from "./chunk-DAEAAVDF.js";
83
85
  import {
84
- DeepSeekClient
85
- } from "./chunk-KMWKGPFZ.js";
86
+ DeepSeekClient,
87
+ pickPrimaryBalance
88
+ } from "./chunk-H4OLWRSX.js";
86
89
  import {
87
90
  loadDotenv
88
91
  } from "./chunk-3Q3C4W66.js";
@@ -114,7 +117,7 @@ import {
114
117
  restoreCheckpoint,
115
118
  savePlanState,
116
119
  suggestSlashCommands
117
- } from "./chunk-UVRXTSK3.js";
120
+ } from "./chunk-A3LL4XDV.js";
118
121
  import {
119
122
  fetchSmitheryDetail,
120
123
  loadMorePages,
@@ -124,20 +127,20 @@ import {
124
127
  import {
125
128
  eventLogPath,
126
129
  openEventSink
127
- } from "./chunk-5GKJLNP2.js";
130
+ } from "./chunk-7VFNPMKG.js";
128
131
  import {
129
132
  BUILTIN_ALLOWLIST,
130
133
  formatCommandResult,
131
134
  pauseGate,
132
135
  runCommand
133
- } from "./chunk-SZH34P45.js";
136
+ } from "./chunk-BYZGO3BX.js";
134
137
  import {
135
138
  PROJECT_MEMORY_FILE,
136
139
  SkillStore,
137
140
  memoryEnabled,
138
141
  readProjectMemory,
139
142
  resolveProjectMemoryWritePath
140
- } from "./chunk-7DLHHBGN.js";
143
+ } from "./chunk-CD4SCQL4.js";
141
144
  import {
142
145
  HOOK_EVENTS,
143
146
  formatHookOutcomeMessage,
@@ -145,10 +148,11 @@ import {
145
148
  loadHooks,
146
149
  projectSettingsPath,
147
150
  runHooks
148
- } from "./chunk-FFNOMR32.js";
151
+ } from "./chunk-WE3YZULK.js";
149
152
  import {
150
153
  deleteSession,
151
154
  detectGitBranch,
155
+ freshSessionName,
152
156
  listSessionsForWorkspace,
153
157
  loadSessionMessages,
154
158
  loadSessionMeta,
@@ -157,7 +161,7 @@ import {
157
161
  resolveSession,
158
162
  sanitizeName,
159
163
  sessionsDir
160
- } from "./chunk-XST7BSZJ.js";
164
+ } from "./chunk-YJFKFTAL.js";
161
165
  import {
162
166
  getLanguage,
163
167
  getSupportedLanguages,
@@ -166,7 +170,7 @@ import {
166
170
  setLanguage,
167
171
  t,
168
172
  tObj
169
- } from "./chunk-H7PHYVPM.js";
173
+ } from "./chunk-MHGPBJ2T.js";
170
174
  import {
171
175
  CARD,
172
176
  FG,
@@ -200,13 +204,12 @@ import {
200
204
  saveApiKey,
201
205
  saveEditMode,
202
206
  savePreset,
203
- saveReasoningEffort,
204
207
  saveTheme,
205
208
  searchEnabled,
206
209
  webSearchEndpoint,
207
210
  webSearchEngine,
208
211
  writeConfig
209
- } from "./chunk-CZSJILQP.js";
212
+ } from "./chunk-65Q5HQ26.js";
210
213
  import {
211
214
  aggregateUsage,
212
215
  appendUsage,
@@ -228,31 +231,13 @@ import {
228
231
 
229
232
  // src/cli/commands/chat.tsx
230
233
  import { render } from "ink";
231
- import React69, { useState as useState30 } from "react";
232
-
233
- // src/mcp/summary.ts
234
- function buildMcpServerSummary(opts) {
235
- return {
236
- label: opts.label,
237
- spec: opts.spec,
238
- toolCount: opts.toolCount,
239
- report: opts.report,
240
- host: opts.host,
241
- bridgeEnv: opts.bridgeEnv,
242
- readResource(uri) {
243
- return opts.host.client.readResource(uri);
244
- },
245
- getPrompt(name, args) {
246
- return args !== void 0 ? opts.host.client.getPrompt(name, args) : opts.host.client.getPrompt(name);
247
- }
248
- };
249
- }
234
+ import React69, { useState as useState31 } from "react";
250
235
 
251
236
  // src/cli/ui/App.tsx
252
237
  import { statSync } from "fs";
253
238
  import { resolve } from "path";
254
- import { Box as Box54, Text as Text57, useStdin, useStdout as useStdout17 } from "ink";
255
- import React66, { useCallback as useCallback13, useEffect as useEffect17, useMemo as useMemo11, useRef as useRef10, useState as useState28 } from "react";
239
+ import { Box as Box54, Text as Text57, useStdin, useStdout as useStdout18 } from "ink";
240
+ import React66, { useCallback as useCallback13, useEffect as useEffect17, useMemo as useMemo12, useRef as useRef10, useState as useState29 } from "react";
256
241
 
257
242
  // src/code/pending-edits.ts
258
243
  import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "fs";
@@ -522,7 +507,7 @@ function BootSplash() {
522
507
  return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", alignItems: "center", marginY: 1 }, /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", alignItems: "flex-start", marginBottom: 1 }, REASONIX_LOGO.map((line) => /* @__PURE__ */ React2.createElement(Text2, { key: line, color: TONE.brand, bold: true }, line))), /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", alignItems: "flex-start" }, spout.map((line, i) => (
523
508
  // biome-ignore lint/suspicious/noArrayIndexKey: fixed-length spout column, position is the identity
524
509
  /* @__PURE__ */ React2.createElement(Text2, { key: i, color: TONE.accent }, line.length > 0 ? line : " ")
525
- )), WHALE_LINES.map((line) => /* @__PURE__ */ React2.createElement(Text2, { key: line, color: TONE.brand, bold: true }, line)), /* @__PURE__ */ React2.createElement(Text2, { color: FG.faint }, wave)), /* @__PURE__ */ React2.createElement(Box2, { marginTop: 1 }, /* @__PURE__ */ React2.createElement(Text2, { color: FG.meta }, `loading${dots}`)));
510
+ )), WHALE_LINES.map((line) => /* @__PURE__ */ React2.createElement(Text2, { key: line, color: TONE.brand, bold: true }, line)), /* @__PURE__ */ React2.createElement(Text2, { color: FG.faint }, wave)), /* @__PURE__ */ React2.createElement(Box2, { marginTop: 1 }, /* @__PURE__ */ React2.createElement(Text2, { color: FG.meta }, `${t("common.loading")}${dots}`)));
526
511
  }
527
512
 
528
513
  // src/cli/ui/CheckpointPicker.tsx
@@ -688,7 +673,7 @@ function ApprovalCard({
688
673
  const { stdout } = useStdout2();
689
674
  const cols = stdout?.columns ?? 80;
690
675
  const ruleWidth = Math.max(MIN_SEPARATOR, cols - SEPARATOR_PAD);
691
- return /* @__PURE__ */ React4.createElement(Box4, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ React4.createElement(Box4, { flexDirection: "row" }, /* @__PURE__ */ React4.createElement(Text4, { color: palette.color, backgroundColor: SURFACE.bgElev }, " \u258E "), /* @__PURE__ */ React4.createElement(Text4, { bold: true, color: palette.color, backgroundColor: SURFACE.bgElev }, `${headerGlyph} `), /* @__PURE__ */ React4.createElement(Text4, { bold: true, color: FG.strong, backgroundColor: SURFACE.bgElev }, ` ${title} `), metaRight !== void 0 && /* @__PURE__ */ React4.createElement(Text4, { color: metaRightColor ?? FG.faint, backgroundColor: SURFACE.bgElev }, ` ${metaRight} `)), /* @__PURE__ */ React4.createElement(Box4, { flexDirection: "column", paddingX: 2, marginTop: 1 }, children), /* @__PURE__ */ React4.createElement(Box4, { paddingX: 2, marginTop: 1 }, /* @__PURE__ */ React4.createElement(Text4, { color: FG.faint }, "\u2500".repeat(ruleWidth))), /* @__PURE__ */ React4.createElement(Box4, { paddingX: 2 }, /* @__PURE__ */ React4.createElement(Text4, { color: FG.faint }, effectiveFooter)));
676
+ return /* @__PURE__ */ React4.createElement(Box4, { flexDirection: "column", marginY: 1, flexShrink: 0 }, /* @__PURE__ */ React4.createElement(Box4, { flexDirection: "row" }, /* @__PURE__ */ React4.createElement(Text4, { color: palette.color, backgroundColor: SURFACE.bgElev }, " \u258E "), /* @__PURE__ */ React4.createElement(Text4, { bold: true, color: palette.color, backgroundColor: SURFACE.bgElev }, `${headerGlyph} `), /* @__PURE__ */ React4.createElement(Text4, { bold: true, color: FG.strong, backgroundColor: SURFACE.bgElev }, ` ${title} `), metaRight !== void 0 && /* @__PURE__ */ React4.createElement(Text4, { color: metaRightColor ?? FG.faint, backgroundColor: SURFACE.bgElev }, ` ${metaRight} `)), /* @__PURE__ */ React4.createElement(Box4, { flexDirection: "column", paddingX: 2, marginTop: 1, flexShrink: 0 }, children), /* @__PURE__ */ React4.createElement(Box4, { paddingX: 2, marginTop: 1, flexShrink: 0 }, /* @__PURE__ */ React4.createElement(Text4, { color: FG.faint }, "\u2500".repeat(ruleWidth))), /* @__PURE__ */ React4.createElement(Box4, { paddingX: 2, flexShrink: 0 }, /* @__PURE__ */ React4.createElement(Text4, { color: FG.faint }, effectiveFooter)));
692
677
  }
693
678
 
694
679
  // src/cli/ui/layout/viewport-budget.tsx
@@ -1734,6 +1719,7 @@ function McpMarketplace({ onClose, postInfo, reloadMcp, pickerPorts }) {
1734
1719
  setState((s) => ({ ...s, query: s.query + ev.input, selected: 0 }));
1735
1720
  }
1736
1721
  });
1722
+ const overlay = useMemo4(() => loadOverlay("zh-CN"), []);
1737
1723
  const start = Math.max(
1738
1724
  0,
1739
1725
  Math.min(state.selected - Math.floor(VISIBLE_ROWS / 2), filtered.length - VISIBLE_ROWS)
@@ -1753,7 +1739,7 @@ function McpMarketplace({ onClose, postInfo, reloadMcp, pickerPorts }) {
1753
1739
  const installedBadge = installedSpec ? " \u2713" : "";
1754
1740
  const pop = e.popularity !== void 0 ? ` \xB7 ${e.popularity.toLocaleString()}` : "";
1755
1741
  return /* @__PURE__ */ React11.createElement(Box9, { key: e.name }, /* @__PURE__ */ React11.createElement(Text9, { color: active ? COLOR.brand : void 0 }, active ? "\u25B8 " : " "), /* @__PURE__ */ React11.createElement(Text9, { bold: active }, e.name.padEnd(38).slice(0, 38)), /* @__PURE__ */ React11.createElement(Text9, { dimColor: true }, ` ${tag2}${pop}${installedBadge}`));
1756
- })), selected ? /* @__PURE__ */ React11.createElement(Box9, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React11.createElement(Text9, { bold: true }, selected.title), selected.description ? /* @__PURE__ */ React11.createElement(Text9, { dimColor: true }, selected.description.slice(0, 200)) : null, selected.install ? /* @__PURE__ */ React11.createElement(Text9, { dimColor: true }, t("mcpMarketplace.specLine", {
1742
+ })), selected ? /* @__PURE__ */ React11.createElement(Box9, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React11.createElement(Text9, { bold: true }, overlay?.[selected.name]?.title ?? selected.title, overlay?.[selected.name] ? /* @__PURE__ */ React11.createElement(Text9, { dimColor: true }, ` \xB7 ${selected.title}`) : null), /* @__PURE__ */ React11.createElement(Text9, { dimColor: true }, overlay?.[selected.name]?.description ?? selected.description?.slice(0, 200) ?? null), selected.install ? /* @__PURE__ */ React11.createElement(Text9, { dimColor: true }, t("mcpMarketplace.specLine", {
1757
1743
  runtime: selected.install.runtime,
1758
1744
  id: selected.install.packageId ?? selected.install.url ?? "\u2014",
1759
1745
  transport: selected.install.transport
@@ -2105,8 +2091,8 @@ function statusGlyph(status2, isCur) {
2105
2091
  return { glyph: GLYPH.pending, color: COLOR.info };
2106
2092
  }
2107
2093
  function riskLabel(risk) {
2108
- if (risk === "med") return { text: `${GLYPH.warn} med`, color: COLOR.warn };
2109
- if (risk === "high") return { text: `${GLYPH.warn} high`, color: COLOR.err };
2094
+ if (risk === "med") return { text: `${GLYPH.warn}${t("planFlow.riskMed")}`, color: COLOR.warn };
2095
+ if (risk === "high") return { text: `${GLYPH.warn}${t("planFlow.riskHigh")}`, color: COLOR.err };
2110
2096
  return null;
2111
2097
  }
2112
2098
  function PlanStepListInner({ steps, statuses, focusStepId }) {
@@ -2200,11 +2186,11 @@ function buildStatusMap(steps, completedStepIds, currentStepId, isLast) {
2200
2186
  }
2201
2187
 
2202
2188
  // src/cli/ui/PlanConfirm.tsx
2203
- import { Box as Box17, Text as Text17 } from "ink";
2204
- import React20 from "react";
2189
+ import { Box as Box17, Text as Text17, useStdout as useStdout6 } from "ink";
2190
+ import React20, { useMemo as useMemo5, useState as useState10 } from "react";
2205
2191
 
2206
2192
  // src/cli/ui/markdown-view.tsx
2207
- import { Box as Box16, Text as Text16 } from "ink";
2193
+ import { Box as Box16, Text as Text16, Transform } from "ink";
2208
2194
  import React19 from "react";
2209
2195
 
2210
2196
  // node_modules/marked/lib/marked.esm.js
@@ -4660,7 +4646,7 @@ function SpanText({
4660
4646
  return /* @__PURE__ */ React19.createElement(Text16, { color: FG_STRONG, backgroundColor: SURFACE_ELEV }, ` ${span.text} `);
4661
4647
  }
4662
4648
  const color = span.fileRef ? TONE_BRAND : span.link ? TONE_BRAND : strongColor ? FG_STRONG : FG_BODY;
4663
- return /* @__PURE__ */ React19.createElement(
4649
+ const inner = /* @__PURE__ */ React19.createElement(
4664
4650
  Text16,
4665
4651
  {
4666
4652
  color,
@@ -4672,6 +4658,17 @@ function SpanText({
4672
4658
  },
4673
4659
  span.text
4674
4660
  );
4661
+ const target = linkTarget(span);
4662
+ if (!target) return inner;
4663
+ return /* @__PURE__ */ React19.createElement(Transform, { transform: (text) => `\x1B]8;;${target}\x1B\\${text}\x1B]8;;\x1B\\` }, inner);
4664
+ }
4665
+ function linkTarget(span) {
4666
+ if (span.link) return span.link;
4667
+ if (span.fileRef) {
4668
+ const { path, line } = span.fileRef;
4669
+ return line ? `file://${path}:${line}` : `file://${path}`;
4670
+ }
4671
+ return null;
4675
4672
  }
4676
4673
 
4677
4674
  // src/cli/ui/plan-open-questions.ts
@@ -4704,18 +4701,71 @@ function extractOpenQuestionsSection(plan2) {
4704
4701
  }
4705
4702
 
4706
4703
  // src/cli/ui/PlanConfirm.tsx
4707
- var PLAN_BODY_PREVIEW_LINES = 24;
4708
- function PlanConfirmInner({ plan: plan2, steps, onChoose }) {
4704
+ var DEFAULT_DETAIL_LINES = 12;
4705
+ var MIN_DETAIL_LINES = 6;
4706
+ var EXPANDED_MODAL_OVERHEAD_ROWS = 12;
4707
+ var EXPANDED_DETAIL_CHROME_ROWS = 4;
4708
+ function PlanConfirmInner({ plan: plan2, steps, summary, onChoose }) {
4709
+ const { stdout } = useStdout6();
4710
+ const totalRows = useTotalRows();
4711
+ const [expanded, setExpanded] = useState10(false);
4712
+ const [detailOffset, setDetailOffset] = useState10(0);
4709
4713
  const stepRows = steps?.length ?? 0;
4710
4714
  const hasSteps = stepRows > 0;
4711
4715
  const openQuestions = extractOpenQuestionsSection(plan2);
4712
- const planLines = plan2.split("\n");
4713
- const truncatedBody = planLines.length > PLAN_BODY_PREVIEW_LINES;
4714
- const previewBody = truncatedBody ? planLines.slice(0, PLAN_BODY_PREVIEW_LINES).join("\n") : plan2;
4715
- const previewRows = truncatedBody ? PLAN_BODY_PREVIEW_LINES : Math.min(planLines.length, PLAN_BODY_PREVIEW_LINES);
4716
- const reservedFor = hasSteps ? stepRows : previewRows;
4717
- const oqRows = openQuestions ? openQuestions.split("\n").length : 0;
4718
- useReserveRows("modal", { min: 10, max: Math.max(16, reservedFor + oqRows + 14) });
4716
+ const planLines = useMemo5(() => plan2.split("\n"), [plan2]);
4717
+ const effectiveSummary = useMemo5(
4718
+ () => summarizePlan(plan2, summary, steps),
4719
+ [plan2, summary, steps]
4720
+ );
4721
+ const oqRows = openQuestions ? Math.min(openQuestions.split("\n").length, 8) : 0;
4722
+ const modalRows = useReserveRows("modal", {
4723
+ min: 10,
4724
+ max: expanded ? Math.max(10, totalRows - EXPANDED_DETAIL_CHROME_ROWS) : Math.max(16, Math.min(32, (hasSteps ? stepRows + 2 : 2) + oqRows + 14))
4725
+ });
4726
+ const detailViewRows = expanded ? Math.max(10, modalRows - EXPANDED_MODAL_OVERHEAD_ROWS) : Math.max(
4727
+ MIN_DETAIL_LINES,
4728
+ Math.min(18, Math.floor(((stdout?.rows ?? 32) - 14) / 2) || DEFAULT_DETAIL_LINES)
4729
+ );
4730
+ const maxDetailOffset = Math.max(0, planLines.length - detailViewRows);
4731
+ const clampedDetailOffset = Math.min(detailOffset, maxDetailOffset);
4732
+ const rawSliceStart = clampedDetailOffset;
4733
+ const rawSliceEnd = Math.min(planLines.length, rawSliceStart + detailViewRows);
4734
+ const { displayStart, displayEnd } = (() => {
4735
+ let start = rawSliceStart;
4736
+ let end = rawSliceEnd;
4737
+ while (start < end && planLines[start]?.trim() === "" && end < planLines.length) {
4738
+ start += 1;
4739
+ end += 1;
4740
+ }
4741
+ return { displayStart: start, displayEnd: end };
4742
+ })();
4743
+ const visiblePlanLines = planLines.slice(displayStart, displayEnd);
4744
+ const detailOverflow = planLines.length > detailViewRows;
4745
+ const showDetailScrollHint = expanded && plan2.trim().length > 0 && detailOverflow;
4746
+ const detailOwnsScrollKey = expanded && detailOverflow;
4747
+ const isDetailScrollKey = (ev) => detailOwnsScrollKey && !!(ev.pageUp || ev.pageDown || ev.home || ev.end || ev.mouseScrollUp || ev.mouseScrollDown || ev.upArrow || ev.downArrow);
4748
+ useKeystroke((ev) => {
4749
+ if (ev.paste) return;
4750
+ if (ev.ctrl && ev.input === "p") {
4751
+ setExpanded((v) => !v);
4752
+ return;
4753
+ }
4754
+ if (!isDetailScrollKey(ev)) return;
4755
+ if (ev.pageUp || ev.mouseScrollUp) {
4756
+ setDetailOffset((n) => Math.max(0, n - detailViewRows));
4757
+ } else if (ev.pageDown || ev.mouseScrollDown) {
4758
+ setDetailOffset((n) => Math.min(maxDetailOffset, n + detailViewRows));
4759
+ } else if (ev.home) {
4760
+ setDetailOffset(0);
4761
+ } else if (ev.end) {
4762
+ setDetailOffset(maxDetailOffset);
4763
+ } else if (ev.upArrow) {
4764
+ setDetailOffset((n) => Math.max(0, n - 1));
4765
+ } else if (ev.downArrow) {
4766
+ setDetailOffset((n) => Math.min(maxDetailOffset, n + 1));
4767
+ }
4768
+ });
4719
4769
  const refineLabel = t("planFlow.picker.refine");
4720
4770
  const bannerTemplate = t("planFlow.openQuestionsBanner");
4721
4771
  const [bannerBefore, bannerAfter] = bannerTemplate.split("{refine}");
@@ -4729,10 +4779,18 @@ function PlanConfirmInner({ plan: plan2, steps, onChoose }) {
4729
4779
  metaRightColor: CARD.plan.color
4730
4780
  },
4731
4781
  openQuestions ? /* @__PURE__ */ React20.createElement(Box17, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React20.createElement(Text17, { color: TONE.warn }, bannerBefore ?? "", /* @__PURE__ */ React20.createElement(Text17, { bold: true }, refineLabel), bannerAfter ?? ""), /* @__PURE__ */ React20.createElement(Box17, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React20.createElement(Text17, { color: TONE.warn, bold: true }, t("planFlow.openQuestionsHeader")), /* @__PURE__ */ React20.createElement(MarkdownView, { text: openQuestions }))) : null,
4732
- hasSteps ? /* @__PURE__ */ React20.createElement(Box17, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React20.createElement(PlanStepList, { steps })) : plan2.trim().length > 0 ? /* @__PURE__ */ React20.createElement(Box17, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React20.createElement(MarkdownView, { text: previewBody }), truncatedBody ? /* @__PURE__ */ React20.createElement(Text17, { color: FG.faint }, t(
4733
- planLines.length - PLAN_BODY_PREVIEW_LINES === 1 ? "planFlow.truncatedBodyMore" : "planFlow.truncatedBodyMorePlural",
4734
- { n: planLines.length - PLAN_BODY_PREVIEW_LINES }
4735
- )) : null) : null,
4782
+ !expanded || plan2.trim().length === 0 ? /* @__PURE__ */ React20.createElement(Box17, { marginBottom: 1, flexDirection: "column" }, effectiveSummary ? /* @__PURE__ */ React20.createElement(Text17, { color: FG.body }, effectiveSummary) : /* @__PURE__ */ React20.createElement(Text17, { color: FG.faint }, t("planFlow.noPlanSummary")), !expanded && hasSteps ? /* @__PURE__ */ React20.createElement(Box17, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React20.createElement(PlanStepList, { steps })) : null, /* @__PURE__ */ React20.createElement(Text17, { color: FG.faint }, expanded ? t("planFlow.detailExpandedHint") : t("planFlow.detailCollapsedHint"))) : null,
4783
+ expanded && plan2.trim().length > 0 ? /* @__PURE__ */ React20.createElement(
4784
+ PlanDetailWindow,
4785
+ {
4786
+ lines: visiblePlanLines,
4787
+ overflow: detailOverflow,
4788
+ start: displayStart + 1,
4789
+ end: displayEnd,
4790
+ total: planLines.length
4791
+ }
4792
+ ) : null,
4793
+ showDetailScrollHint ? /* @__PURE__ */ React20.createElement(Box17, { marginBottom: 1 }, /* @__PURE__ */ React20.createElement(Text17, { color: FG.faint }, t("planFlow.detailScrollHint"))) : null,
4736
4794
  /* @__PURE__ */ React20.createElement(
4737
4795
  SingleSelect,
4738
4796
  {
@@ -4760,20 +4818,39 @@ function PlanConfirmInner({ plan: plan2, steps, onChoose }) {
4760
4818
  }
4761
4819
  ],
4762
4820
  onSubmit: (v) => onChoose(v),
4763
- onCancel: () => onChoose("cancel")
4821
+ onCancel: () => onChoose("cancel"),
4822
+ inlineHints: true,
4823
+ ignoreKey: isDetailScrollKey
4764
4824
  }
4765
4825
  )
4766
4826
  );
4767
4827
  }
4828
+ function PlanDetailWindow({
4829
+ lines,
4830
+ overflow,
4831
+ start,
4832
+ end,
4833
+ total
4834
+ }) {
4835
+ return /* @__PURE__ */ React20.createElement(Box17, { flexDirection: "column" }, overflow ? /* @__PURE__ */ React20.createElement(Text17, { color: FG.faint }, t("planFlow.detailWindow", { start, end, total })) : null, lines.map((line, i) => /* @__PURE__ */ React20.createElement(Text17, { key: `plan-detail-${start + i}`, wrap: "truncate" }, line.length > 0 ? line : " ")));
4836
+ }
4837
+ function summarizePlan(plan2, summary, steps) {
4838
+ const trimmedSummary = summary?.trim();
4839
+ if (trimmedSummary) return trimmedSummary;
4840
+ const firstTextLine = plan2.split("\n").map((line) => line.trim()).find((line) => line.length > 0 && !/^#{1,6}\s*$/.test(line));
4841
+ if (firstTextLine) return firstTextLine.replace(/^#{1,6}\s+/, "").slice(0, 160);
4842
+ if (steps && steps.length > 0) return steps[0]?.title ?? "";
4843
+ return "";
4844
+ }
4768
4845
  var PlanConfirm = React20.memo(PlanConfirmInner);
4769
4846
 
4770
4847
  // src/cli/ui/PlanRefineInput.tsx
4771
4848
  import { Box as Box18, Text as Text18 } from "ink";
4772
- import React22, { useState as useState11 } from "react";
4849
+ import React22, { useState as useState12 } from "react";
4773
4850
 
4774
4851
  // src/cli/ui/ticker.tsx
4775
4852
  import { useAnimation } from "ink";
4776
- import React21, { createContext as createContext2, useContext as useContext2, useState as useState10 } from "react";
4853
+ import React21, { createContext as createContext2, useContext as useContext2, useState as useState11 } from "react";
4777
4854
  var FAST_TICK_MS = 120;
4778
4855
  var SLOW_TICK_MS = 1e3;
4779
4856
  var TickerActiveContext = createContext2(true);
@@ -4791,8 +4868,13 @@ function useSlowTick() {
4791
4868
  const isActive = useTickerActive();
4792
4869
  return useAnimation({ interval: SLOW_TICK_MS, isActive }).frame;
4793
4870
  }
4871
+ function useCursorBlink() {
4872
+ const isActive = useTickerActive();
4873
+ const tick = useSlowTick();
4874
+ return !isActive || tick % 2 === 0;
4875
+ }
4794
4876
  function useElapsedSeconds() {
4795
- const [start] = useState10(() => Date.now());
4877
+ const [start] = useState11(() => Date.now());
4796
4878
  useSlowTick();
4797
4879
  return Math.floor((Date.now() - start) / 1e3);
4798
4880
  }
@@ -4817,7 +4899,7 @@ function modeMeta(mode2) {
4817
4899
  };
4818
4900
  }
4819
4901
  function PlanRefineInput({ mode: mode2, questions, onSubmit, onCancel }) {
4820
- const [value, setValue] = useState11("");
4902
+ const [value, setValue] = useState12("");
4821
4903
  useKeystroke((ev) => {
4822
4904
  if (ev.paste) {
4823
4905
  setValue((v) => v + ev.input.replace(/\r?\n/g, " "));
@@ -4943,18 +5025,18 @@ var PlanReviseConfirm = React23.memo(PlanReviseConfirmInner);
4943
5025
 
4944
5026
  // src/cli/ui/PlanReviseEditor.tsx
4945
5027
  import { Box as Box20, Text as Text20 } from "ink";
4946
- import React24, { useState as useState12 } from "react";
5028
+ import React24, { useState as useState13 } from "react";
4947
5029
  function PlanReviseEditor({
4948
5030
  steps,
4949
5031
  completedStepIds,
4950
5032
  onAccept,
4951
5033
  onCancel
4952
5034
  }) {
4953
- const [rows, setRows] = useState12(
5035
+ const [rows, setRows] = useState13(
4954
5036
  () => steps.map((s) => ({ step: s, done: completedStepIds?.has(s.id) ?? false, skipped: false }))
4955
5037
  );
4956
5038
  const firstEditableIndex = rows.findIndex((r) => !r.done);
4957
- const [focus, setFocus] = useState12(firstEditableIndex < 0 ? 0 : firstEditableIndex);
5039
+ const [focus, setFocus] = useState13(firstEditableIndex < 0 ? 0 : firstEditableIndex);
4958
5040
  useKeystroke((ev) => {
4959
5041
  if (ev.paste) return;
4960
5042
  if (ev.escape) {
@@ -5040,8 +5122,8 @@ function ReviseRow({
5040
5122
  }
5041
5123
 
5042
5124
  // src/cli/ui/PromptInput.tsx
5043
- import { Box as Box21, Text as Text21, useStdout as useStdout6 } from "ink";
5044
- import React25, { useRef, useState as useState13 } from "react";
5125
+ import { Box as Box21, Text as Text21, useStdout as useStdout7 } from "ink";
5126
+ import React25, { useRef, useState as useState14 } from "react";
5045
5127
 
5046
5128
  // src/cli/ui/key-normalize.ts
5047
5129
  var CSI_TAIL_TO_FLAGS = [
@@ -5489,7 +5571,7 @@ function PromptInput({
5489
5571
  const inputLineCount = value.length > 0 ? value.split("\n").length : 1;
5490
5572
  const reserveMax = Math.min(Math.ceil(inputLineCount / 4) * 4 + 3, 24);
5491
5573
  useReserveRows("input", { min: 1, max: reserveMax });
5492
- const [cursor, setCursor] = useState13(value.length);
5574
+ const [cursor, setCursor] = useState14(value.length);
5493
5575
  const pastesRef = useRef(/* @__PURE__ */ new Map());
5494
5576
  const nextPasteIdRef = useRef(0);
5495
5577
  const lastLocalValueRef = useRef(value);
@@ -5568,7 +5650,7 @@ function PromptInput({
5568
5650
  if (action.historyHandoff === "next") onHistoryNext?.();
5569
5651
  if (action.openExternalEditor) onOpenExternalEditor?.();
5570
5652
  }, !disabled);
5571
- const { stdout } = useStdout6();
5653
+ const { stdout } = useStdout7();
5572
5654
  const cols = stdout?.columns ?? 80;
5573
5655
  const promptPrefix = "\u203A ";
5574
5656
  const continuationIndent = " ";
@@ -5577,7 +5659,7 @@ function PromptInput({
5577
5659
  const effectivePlaceholder = disabled ? placeholder ?? t("composer.waitingForResponse") : placeholder ?? t("composer.placeholder");
5578
5660
  const lines = value.length > 0 ? value.split("\n") : [""];
5579
5661
  const accentColor = disabled ? FG.faint : TONE.brand;
5580
- const cursorVisible = useSlowTick() % 2 === 0;
5662
+ const cursorVisible = useCursorBlink();
5581
5663
  const { line: cursorLine, col: cursorCol } = lineAndColumn(value, cursor);
5582
5664
  const renderItems = collapseLinesForDisplay(lines, cursorLine);
5583
5665
  const showHugeBufferHints = lines.length > 20;
@@ -5936,8 +6018,8 @@ function collapseLinesForDisplay(lines, cursorLine) {
5936
6018
  }
5937
6019
 
5938
6020
  // src/cli/ui/SessionPicker.tsx
5939
- import { Box as Box22, Text as Text22, useStdout as useStdout7 } from "ink";
5940
- import React26, { useMemo as useMemo5, useState as useState14 } from "react";
6021
+ import { Box as Box22, Text as Text22, useStdout as useStdout8 } from "ink";
6022
+ import React26, { useMemo as useMemo6, useState as useState15 } from "react";
5941
6023
  var PAGE_MARGIN3 = 6;
5942
6024
  function SessionPicker({
5943
6025
  sessions: sessions2,
@@ -5946,12 +6028,12 @@ function SessionPicker({
5946
6028
  walletCurrency,
5947
6029
  pickerPorts
5948
6030
  }) {
5949
- const [focus, setFocus] = useState14(0);
5950
- const [renaming, setRenaming] = useState14(null);
5951
- const { stdout } = useStdout7();
6031
+ const [focus, setFocus] = useState15(0);
6032
+ const [renaming, setRenaming] = useState15(null);
6033
+ const { stdout } = useStdout8();
5952
6034
  const rows = stdout?.rows ?? 40;
5953
6035
  const visibleCount = Math.max(3, rows - PAGE_MARGIN3);
5954
- const snapshot = useMemo5(
6036
+ const snapshot = useMemo6(
5955
6037
  () => ({
5956
6038
  pickerKind: "sessions",
5957
6039
  title: t("sessionPicker.title", { workspace }),
@@ -6089,7 +6171,7 @@ function relativeTime2(date) {
6089
6171
  // src/cli/ui/ShellConfirm.tsx
6090
6172
  import { homedir as homedir3 } from "os";
6091
6173
  import { Box as Box23, Text as Text23 } from "ink";
6092
- import React27, { useState as useState15 } from "react";
6174
+ import React27, { useState as useState16 } from "react";
6093
6175
  var CHROME_ROWS = 18;
6094
6176
  var MIN_COMMAND_LINES = 3;
6095
6177
  function clampCommand(command, max) {
@@ -6121,7 +6203,7 @@ function ShellConfirm({
6121
6203
  const { preview, hidden } = clampCommand(command, maxCommandLines);
6122
6204
  const isBackground = kind === "run_background";
6123
6205
  const subtitle = isBackground ? t("shellConfirm.bgSubtitle") : t("shellConfirm.subtitle");
6124
- const [phase, setPhase] = useState15("pick");
6206
+ const [phase, setPhase] = useState16("pick");
6125
6207
  if (phase === "deny") {
6126
6208
  return /* @__PURE__ */ React27.createElement(
6127
6209
  ApprovalCard,
@@ -6267,7 +6349,7 @@ function ArgRow({ value, isSelected }) {
6267
6349
  }
6268
6350
 
6269
6351
  // src/cli/ui/SlashSuggestions.tsx
6270
- import { Box as Box25, Text as Text25, useStdout as useStdout8 } from "ink";
6352
+ import { Box as Box25, Text as Text25, useStdout as useStdout9 } from "ink";
6271
6353
  import React29 from "react";
6272
6354
  var GROUP_MODE_MAX_ROWS = 24;
6273
6355
  var SEARCH_MODE_MAX_ROWS = 8;
@@ -6284,7 +6366,7 @@ function SlashSuggestions({
6284
6366
  advancedHidden
6285
6367
  }) {
6286
6368
  const color = useColor();
6287
- const { stdout } = useStdout8();
6369
+ const { stdout } = useStdout9();
6288
6370
  const cols = stdout?.columns ?? 80;
6289
6371
  const [rememberedWindowStart, setRememberedWindowStart] = React29.useState(0);
6290
6372
  const maxRows = groupMode ? GROUP_MODE_MAX_ROWS : SEARCH_MODE_MAX_ROWS;
@@ -6458,8 +6540,8 @@ ${output}`;
6458
6540
  }
6459
6541
 
6460
6542
  // src/cli/ui/copy-mode/CopyMode.tsx
6461
- import { Box as Box28, Text as Text28, useStdout as useStdout9 } from "ink";
6462
- import React32, { useMemo as useMemo6, useState as useState16 } from "react";
6543
+ import { Box as Box28, Text as Text28, useStdout as useStdout10 } from "ink";
6544
+ import React32, { useMemo as useMemo7, useState as useState17 } from "react";
6463
6545
 
6464
6546
  // src/frame/width.ts
6465
6547
  import stringWidthLib from "string-width";
@@ -6573,16 +6655,16 @@ function isYankable(line) {
6573
6655
  // src/cli/ui/copy-mode/CopyMode.tsx
6574
6656
  var CHROME_ROWS2 = 3;
6575
6657
  function CopyMode({ cards, onClose }) {
6576
- const snapshot = useMemo6(() => buildSnapshot(cards), [cards]);
6577
- const { stdout } = useStdout9();
6658
+ const snapshot = useMemo7(() => buildSnapshot(cards), [cards]);
6659
+ const { stdout } = useStdout10();
6578
6660
  const termRows = stdout?.rows ?? 30;
6579
6661
  const termCols = stdout?.columns ?? 80;
6580
6662
  const bodyRows = Math.max(4, termRows - CHROME_ROWS2);
6581
6663
  const lastYankableIdx = findLastYankable(snapshot);
6582
6664
  const initialCursor = findFirstYankable(snapshot);
6583
- const [cursor, setCursor] = useState16(initialCursor);
6584
- const [anchor, setAnchor] = useState16(null);
6585
- const [status2, setStatus] = useState16(null);
6665
+ const [cursor, setCursor] = useState17(initialCursor);
6666
+ const [anchor, setAnchor] = useState17(null);
6667
+ const [status2, setStatus] = useState17(null);
6586
6668
  const stepDown = (i) => stepBy(snapshot, i, 1);
6587
6669
  const stepUp = (i) => stepBy(snapshot, i, -1);
6588
6670
  useKeystroke((ev) => {
@@ -7000,10 +7082,10 @@ function handleErrorEvent(ev, ctx) {
7000
7082
  ctx.setToolProgress(null);
7001
7083
  ctx.toolStartedAtRef.current = null;
7002
7084
  ctx.translator.toolAbort(ev.error ?? ev.content);
7003
- ctx.log.pushError("tool error", ev.error ?? ev.content);
7085
+ ctx.log.pushError(t("common.error"), ev.error ?? ev.content);
7004
7086
  }
7005
7087
  function handleWarningEvent(ev, ctx) {
7006
- ctx.log.pushWarning("warning", ev.content);
7088
+ ctx.log.pushWarning(t("common.warning"), ev.content);
7007
7089
  if (ev.content?.startsWith("\u21E7 ")) ctx.setTurnOnPro(true);
7008
7090
  }
7009
7091
 
@@ -7030,9 +7112,7 @@ function handleToolEvent(ev, ctx) {
7030
7112
  if (ctx.session && total > 0 && completed >= total) {
7031
7113
  const archive = archivePlanState(ctx.session);
7032
7114
  if (archive) {
7033
- ctx.log.pushInfo(
7034
- `\u25B8 plan complete \u2014 all ${total} step${total === 1 ? "" : "s"} done \xB7 archived`
7035
- );
7115
+ ctx.log.pushInfo(t("planFlow.completeMsg", { total, s: total === 1 ? "" : "s" }));
7036
7116
  }
7037
7117
  }
7038
7118
  }
@@ -7458,14 +7538,14 @@ function useActivityLabel() {
7458
7538
  }
7459
7539
 
7460
7540
  // src/cli/ui/hooks/useAgentSession.ts
7461
- import { useMemo as useMemo7 } from "react";
7541
+ import { useMemo as useMemo8 } from "react";
7462
7542
  function useAgentSession({
7463
7543
  sessionId,
7464
7544
  model: model2,
7465
7545
  workspace,
7466
7546
  branch
7467
7547
  }) {
7468
- return useMemo7(
7548
+ return useMemo8(
7469
7549
  () => ({
7470
7550
  id: sessionId ?? "default",
7471
7551
  branch: branch ?? "main",
@@ -7532,24 +7612,24 @@ import {
7532
7612
  useCallback as useCallback3,
7533
7613
  useEffect as useEffect5,
7534
7614
  useRef as useRef2,
7535
- useState as useState17
7615
+ useState as useState18
7536
7616
  } from "react";
7537
7617
  var FLASH_MS = 1200;
7538
7618
  function useEditGate(codeMode) {
7539
7619
  const pendingEdits = useRef2([]);
7540
- const [pendingCount, setPendingCount] = useState17(0);
7541
- const [pendingTick, setPendingTick] = useState17(0);
7620
+ const [pendingCount, setPendingCount] = useState18(0);
7621
+ const [pendingTick, setPendingTick] = useState18(0);
7542
7622
  const syncPendingCount = useCallback3(() => {
7543
7623
  setPendingCount(pendingEdits.current.length);
7544
7624
  setPendingTick((t2) => t2 + 1);
7545
7625
  }, []);
7546
- const [editMode, setEditMode] = useState17(() => codeMode ? loadEditMode() : "review");
7626
+ const [editMode, setEditMode] = useState18(() => codeMode ? loadEditMode() : "review");
7547
7627
  const editModeRef = useRef2(editMode);
7548
7628
  useEffect5(() => {
7549
7629
  editModeRef.current = editMode;
7550
7630
  if (codeMode) saveEditMode(editMode);
7551
7631
  }, [editMode, codeMode]);
7552
- const [modeFlash, setModeFlash] = useState17(false);
7632
+ const [modeFlash, setModeFlash] = useState18(false);
7553
7633
  const flashTimerRef = useRef2(null);
7554
7634
  const prevEditModeRef = useRef2(editMode);
7555
7635
  useEffect5(() => {
@@ -7575,9 +7655,9 @@ function useEditGate(codeMode) {
7575
7655
  }
7576
7656
 
7577
7657
  // src/cli/ui/hooks/useHookList.ts
7578
- import { useCallback as useCallback4, useState as useState18 } from "react";
7658
+ import { useCallback as useCallback4, useState as useState19 } from "react";
7579
7659
  function useHookList(initialProjectRoot) {
7580
- const [hookList, setHookList] = useState18(
7660
+ const [hookList, setHookList] = useState19(
7581
7661
  () => loadHooks({ projectRoot: initialProjectRoot })
7582
7662
  );
7583
7663
  const reloadHooks = useCallback4((projectRoot) => {
@@ -7617,18 +7697,18 @@ function useInputRecall(setInput) {
7617
7697
  }
7618
7698
 
7619
7699
  // src/cli/ui/hooks/useLanguageReload.ts
7620
- import { useEffect as useEffect6, useState as useState19 } from "react";
7700
+ import { useEffect as useEffect6, useState as useState20 } from "react";
7621
7701
  function useLanguageReload() {
7622
- const [version, setVersion] = useState19(0);
7702
+ const [version, setVersion] = useState20(0);
7623
7703
  useEffect6(() => onLanguageChange(() => setVersion((v) => v + 1)), []);
7624
7704
  return version;
7625
7705
  }
7626
7706
 
7627
7707
  // src/cli/ui/hooks/useLoopMode.ts
7628
- import { useCallback as useCallback6, useEffect as useEffect7, useRef as useRef4, useState as useState20 } from "react";
7708
+ import { useCallback as useCallback6, useEffect as useEffect7, useRef as useRef4, useState as useState21 } from "react";
7629
7709
  function useLoopMode(opts) {
7630
7710
  const { log, busyRef, handleSubmitRef } = opts;
7631
- const [activeLoop, setActiveLoop] = useState20(null);
7711
+ const [activeLoop, setActiveLoop] = useState21(null);
7632
7712
  const activeLoopRef = useRef4(null);
7633
7713
  const loopTimerRef = useRef4(null);
7634
7714
  const loopFiringRef = useRef4(false);
@@ -7712,13 +7792,13 @@ function useLoopMode(opts) {
7712
7792
  }
7713
7793
 
7714
7794
  // src/cli/ui/hooks/usePresetMode.ts
7715
- import { useState as useState21 } from "react";
7795
+ import { useState as useState22 } from "react";
7716
7796
  function usePresetMode(model2) {
7717
- const [preset2, setPreset] = useState21(
7797
+ const [preset2, setPreset] = useState22(
7718
7798
  () => model2 === "deepseek-v4-pro" ? "pro" : "auto"
7719
7799
  );
7720
- const [proArmed, setProArmed] = useState21(false);
7721
- const [turnOnPro, setTurnOnPro] = useState21(false);
7800
+ const [proArmed, setProArmed] = useState22(false);
7801
+ const [turnOnPro, setTurnOnPro] = useState22(false);
7722
7802
  return { preset: preset2, setPreset, proArmed, setProArmed, turnOnPro, setTurnOnPro };
7723
7803
  }
7724
7804
 
@@ -7739,7 +7819,7 @@ function useQuit(transcriptRef) {
7739
7819
  }
7740
7820
 
7741
7821
  // src/cli/ui/hooks/useScrollback.ts
7742
- import { useMemo as useMemo8 } from "react";
7822
+ import { useMemo as useMemo9 } from "react";
7743
7823
  var seq = 0;
7744
7824
  function nextId2(prefix) {
7745
7825
  seq += 1;
@@ -7752,7 +7832,7 @@ function formatTok(n) {
7752
7832
  }
7753
7833
  function useScrollback() {
7754
7834
  const dispatch = useDispatch();
7755
- return useMemo8(
7835
+ return useMemo9(
7756
7836
  () => ({
7757
7837
  pushUser(text) {
7758
7838
  const id = nextId2("u");
@@ -7965,10 +8045,10 @@ ${stack}` : message
7965
8045
  }
7966
8046
 
7967
8047
  // src/cli/ui/hooks/useTerminalSetup.ts
7968
- import { useStdout as useStdout10 } from "ink";
8048
+ import { useStdout as useStdout11 } from "ink";
7969
8049
  import { useEffect as useEffect9 } from "react";
7970
8050
  function useTerminalSetup(mouse) {
7971
- const { stdout } = useStdout10();
8051
+ const { stdout } = useStdout11();
7972
8052
  useEffect9(() => {
7973
8053
  if (!stdout || !stdout.isTTY) return;
7974
8054
  stdout.write("\x1B[?2004h");
@@ -7983,11 +8063,11 @@ function useTerminalSetup(mouse) {
7983
8063
  }
7984
8064
 
7985
8065
  // src/cli/ui/hooks/useToolProgressDisplay.ts
7986
- import { useCallback as useCallback8, useEffect as useEffect10, useState as useState22 } from "react";
8066
+ import { useCallback as useCallback8, useEffect as useEffect10, useState as useState23 } from "react";
7987
8067
  function useToolProgressDisplay(progressSink) {
7988
- const [ongoingTool, setOngoingTool] = useState22(null);
7989
- const [toolProgress, setToolProgress] = useState22(null);
7990
- const [statusLine, setStatusLine] = useState22(null);
8068
+ const [ongoingTool, setOngoingTool] = useState23(null);
8069
+ const [toolProgress, setToolProgress] = useState23(null);
8070
+ const [statusLine, setStatusLine] = useState23(null);
7991
8071
  useEffect10(() => {
7992
8072
  if (!progressSink) return;
7993
8073
  progressSink.current = (info) => {
@@ -8034,10 +8114,10 @@ function useTranscriptWriter(transcriptRef, model2, prefixHash) {
8034
8114
  import {
8035
8115
  useEffect as useEffect11,
8036
8116
  useRef as useRef5,
8037
- useState as useState23
8117
+ useState as useState24
8038
8118
  } from "react";
8039
8119
  function useWorkspaceRoot(launchRoot) {
8040
- const [currentRootDir, setCurrentRootDir] = useState23(() => launchRoot ?? process.cwd());
8120
+ const [currentRootDir, setCurrentRootDir] = useState24(() => launchRoot ?? process.cwd());
8041
8121
  const currentRootDirRef = useRef5(currentRootDir);
8042
8122
  useEffect11(() => {
8043
8123
  currentRootDirRef.current = currentRootDir;
@@ -8047,7 +8127,7 @@ function useWorkspaceRoot(launchRoot) {
8047
8127
 
8048
8128
  // src/cli/ui/layout/CardStream.tsx
8049
8129
  import { Box as Box49, Text as Text51, useBoxMetrics } from "ink";
8050
- import React59, { useEffect as useEffect12, useMemo as useMemo9, useRef as useRef6 } from "react";
8130
+ import React59, { useEffect as useEffect12, useMemo as useMemo10, useRef as useRef6 } from "react";
8051
8131
 
8052
8132
  // src/cli/ui/cards/CardRenderer.tsx
8053
8133
  import { Box as Box48, Text as Text50 } from "ink";
@@ -8414,7 +8494,7 @@ function anchorIndex(steps) {
8414
8494
  }
8415
8495
 
8416
8496
  // src/cli/ui/cards/ReasoningCard.tsx
8417
- import { Box as Box38, Text as Text39, useStdout as useStdout11 } from "ink";
8497
+ import { Box as Box38, Text as Text39, useStdout as useStdout12 } from "ink";
8418
8498
  import React45 from "react";
8419
8499
 
8420
8500
  // src/cli/ui/primitives/CursorBlock.tsx
@@ -8435,7 +8515,7 @@ function ReasoningCard({
8435
8515
  card,
8436
8516
  expanded
8437
8517
  }) {
8438
- const { stdout } = useStdout11();
8518
+ const { stdout } = useStdout12();
8439
8519
  const cols = stdout?.columns ?? 80;
8440
8520
  const lineCells = Math.max(20, cols - 4);
8441
8521
  const allLines = card.text.length > 0 ? card.text.split("\n") : [];
@@ -8600,7 +8680,7 @@ function groupByFile(hits) {
8600
8680
  }
8601
8681
 
8602
8682
  // src/cli/ui/cards/StreamingCard.tsx
8603
- import { Box as Box41, Text as Text42, useStdout as useStdout13 } from "ink";
8683
+ import { Box as Box41, Text as Text42, useStdout as useStdout14 } from "ink";
8604
8684
  import React48, { useContext as useContext5 } from "react";
8605
8685
 
8606
8686
  // src/cli/ui/layout/LiveExpandContext.ts
@@ -8609,7 +8689,7 @@ var LiveExpandContext = createContext3(false);
8609
8689
 
8610
8690
  // src/cli/ui/markdown.tsx
8611
8691
  import { highlight, supportsLanguage } from "cli-highlight";
8612
- import { Box as Box40, Text as Text41, useStdout as useStdout12 } from "ink";
8692
+ import { Box as Box40, Text as Text41, Transform as Transform2, useStdout as useStdout13 } from "ink";
8613
8693
  import React47 from "react";
8614
8694
  import stringWidth from "string-width";
8615
8695
  var BODY_LEFT_CELLS = 7;
@@ -8617,7 +8697,7 @@ var MarkdownWidthCtx = React47.createContext(void 0);
8617
8697
  function useWidth() {
8618
8698
  const ctx = React47.useContext(MarkdownWidthCtx);
8619
8699
  if (ctx !== void 0) return ctx;
8620
- return (useStdout12()?.stdout?.columns ?? process.stdout.columns ?? 80) - BODY_LEFT_CELLS;
8700
+ return (useStdout13()?.stdout?.columns ?? process.stdout.columns ?? 80) - BODY_LEFT_CELLS;
8621
8701
  }
8622
8702
  marked.setOptions({ gfm: true, breaks: false });
8623
8703
  function Markdown({ text, width }) {
@@ -8816,8 +8896,8 @@ function looksLikeFileRef(path, hasLine) {
8816
8896
  const ext = path.split(".").pop() ?? "";
8817
8897
  return ext.length >= 2;
8818
8898
  }
8819
- function osc8(label, _target, color) {
8820
- return /* @__PURE__ */ React47.createElement(Text41, { color, underline: true }, label);
8899
+ function osc8(children, target, color) {
8900
+ return /* @__PURE__ */ React47.createElement(Transform2, { transform: (text) => `\x1B]8;;${target}\x1B\\${text}\x1B]8;;\x1B\\` }, /* @__PURE__ */ React47.createElement(Text41, { color, underline: true }, children));
8821
8901
  }
8822
8902
  function renderInlineText(raw) {
8823
8903
  if (!raw) return /* @__PURE__ */ React47.createElement(Text41, null, raw);
@@ -8872,7 +8952,7 @@ function InlineToken({ token }) {
8872
8952
  return /* @__PURE__ */ React47.createElement(Text41, { color: TONE.err, strikethrough: true }, /* @__PURE__ */ React47.createElement(Inline, { tokens: token.tokens }));
8873
8953
  case "link": {
8874
8954
  const l = token;
8875
- return /* @__PURE__ */ React47.createElement(Text41, { color: TONE.brand, underline: true }, /* @__PURE__ */ React47.createElement(Inline, { tokens: l.tokens }));
8955
+ return osc8(/* @__PURE__ */ React47.createElement(Inline, { tokens: l.tokens }), l.href, TONE.brand);
8876
8956
  }
8877
8957
  case "image": {
8878
8958
  const im = token;
@@ -8966,7 +9046,7 @@ function useLiveTokenRate(card, enabled) {
8966
9046
  }
8967
9047
  var PILL_RATE = { bg: "#11141a", fg: "#8b949e" };
8968
9048
  function StreamingCard({ card }) {
8969
- const { stdout } = useStdout13();
9049
+ const { stdout } = useStdout14();
8970
9050
  const cols = stdout?.columns ?? 80;
8971
9051
  const expanded = useContext5(LiveExpandContext);
8972
9052
  const reserveCap = expanded ? EXPANDED_MAX_LINES + 2 : STREAMING_PREVIEW_LINES2 + 2;
@@ -9200,7 +9280,7 @@ function TipRowRender({
9200
9280
  }
9201
9281
 
9202
9282
  // src/cli/ui/cards/ToolCard.tsx
9203
- import { Text as Text46, useStdout as useStdout14 } from "ink";
9283
+ import { Text as Text46, useStdout as useStdout15 } from "ink";
9204
9284
  import React53 from "react";
9205
9285
 
9206
9286
  // src/cli/ui/state/inflight-context.tsx
@@ -9231,7 +9311,7 @@ function tailLinesFor(name) {
9231
9311
  return /(?:^|_)(read|search|list|tree|get|status|diff|fetch|grep)(_|$)/.test(lower) || lower === "job_output" ? READ_TAIL : OTHER_TAIL;
9232
9312
  }
9233
9313
  function ToolCard({ card }) {
9234
- const { stdout } = useStdout14();
9314
+ const { stdout } = useStdout15();
9235
9315
  const cols = stdout?.columns ?? 80;
9236
9316
  const lineCells = Math.max(20, cols - 4);
9237
9317
  const argsLabel = formatArgsSummary(card.args);
@@ -9706,7 +9786,7 @@ function CardStream({
9706
9786
  if (suppressLive && cards.length > 0 && !isFullySettled(cards[cards.length - 1])) {
9707
9787
  visible = cards.slice(0, -1);
9708
9788
  }
9709
- const items = useMemo9(
9789
+ const items = useMemo10(
9710
9790
  () => computeCardStreamItems(visible, cardHeights, scrollRows, outer.height),
9711
9791
  [visible, cardHeights, scrollRows, outer.height]
9712
9792
  );
@@ -9946,7 +10026,7 @@ function summarizeToolArgs(name, args) {
9946
10026
  }
9947
10027
 
9948
10028
  // src/cli/ui/layout/StatusRow.tsx
9949
- import { Box as Box51, Text as Text54, useStdout as useStdout15 } from "ink";
10029
+ import { Box as Box51, Text as Text54, useStdout as useStdout16 } from "ink";
9950
10030
  import React62 from "react";
9951
10031
 
9952
10032
  // src/cli/ui/primitives/Countdown.tsx
@@ -9965,31 +10045,43 @@ var WALLET_MIN_COLS = 90;
9965
10045
  var VERSION_MIN_COLS = 70;
9966
10046
  var FEEDBACK_HINT_MIN_COLS = 100;
9967
10047
  var PRESET_MIN_COLS = 60;
9968
- function StatusRow() {
10048
+ var DEFAULT_STATUS_BAR_CONFIG = {
10049
+ showBalance: true,
10050
+ showSessionCost: true,
10051
+ showTurnCost: true,
10052
+ showCacheHit: true,
10053
+ showVersion: true,
10054
+ showFeedbackHint: true
10055
+ };
10056
+ function StatusRow({
10057
+ statusBar = DEFAULT_STATUS_BAR_CONFIG
10058
+ }) {
9969
10059
  const status2 = useAgentState((s) => s.status);
9970
10060
  const session = useAgentState((s) => s.session);
9971
- const { stdout } = useStdout15();
10061
+ const { stdout } = useStdout16();
9972
10062
  const cols = stdout?.columns ?? 80;
9973
10063
  const ruleWidth = Math.max(RULE_MIN, cols - RULE_PAD);
9974
10064
  const hasTurn = status2.cost > 0;
9975
10065
  const hasSession = status2.sessionCost > 0;
9976
10066
  const hasBalance = typeof status2.balance === "number";
9977
- const showWallet = cols >= WALLET_MIN_COLS && (hasSession || hasBalance);
9978
- return /* @__PURE__ */ React62.createElement(Box51, { flexDirection: "column", flexShrink: 0, flexWrap: "nowrap" }, /* @__PURE__ */ React62.createElement(Box51, { height: 1, flexWrap: "nowrap" }, /* @__PURE__ */ React62.createElement(Text54, null, " "), /* @__PURE__ */ React62.createElement(Text54, { color: FG.faint, wrap: "truncate" }, "\u2500".repeat(ruleWidth))), /* @__PURE__ */ React62.createElement(Box51, { flexDirection: "row", height: 1, minHeight: 1, flexWrap: "nowrap", flexShrink: 0 }, /* @__PURE__ */ React62.createElement(Text54, { wrap: "truncate" }, " "), status2.recording ? /* @__PURE__ */ React62.createElement(RecordingPill, { rec: status2.recording }) : status2.countdownSeconds !== void 0 ? /* @__PURE__ */ React62.createElement(CountdownRow, { mode: status2.mode, secondsLeft: status2.countdownSeconds }) : /* @__PURE__ */ React62.createElement(ModePill2, { mode: status2.mode, network: status2.network, detail: status2.networkDetail }), cols >= PRESET_MIN_COLS && status2.preset !== void 0 && /* @__PURE__ */ React62.createElement(PresetPill, { preset: status2.preset, model: session.model }), /* @__PURE__ */ React62.createElement(Sep, null), /* @__PURE__ */ React62.createElement(Text54, { color: FG.sub, wrap: "truncate" }, `${session.id} \xB7 ${session.branch}`), hasTurn && /* @__PURE__ */ React62.createElement(React62.Fragment, null, /* @__PURE__ */ React62.createElement(Sep, null), /* @__PURE__ */ React62.createElement(Text54, { bold: true, color: TONE.brand, wrap: "truncate" }, "\u25B8 "), /* @__PURE__ */ React62.createElement(Text54, { bold: true, color: FG.body, wrap: "truncate" }, `${formatCost(status2.cost, status2.balanceCurrency)} ${t("statusBar.turn")}`)), /* @__PURE__ */ React62.createElement(Sep, null), /* @__PURE__ */ React62.createElement(
10067
+ const showWallet = cols >= WALLET_MIN_COLS && (hasSession && statusBar.showSessionCost || hasBalance && statusBar.showBalance);
10068
+ return /* @__PURE__ */ React62.createElement(Box51, { flexDirection: "column", flexShrink: 0, flexWrap: "nowrap" }, /* @__PURE__ */ React62.createElement(Box51, { height: 1, flexWrap: "nowrap" }, /* @__PURE__ */ React62.createElement(Text54, null, " "), /* @__PURE__ */ React62.createElement(Text54, { color: FG.faint, wrap: "truncate" }, "\u2500".repeat(ruleWidth))), /* @__PURE__ */ React62.createElement(Box51, { flexDirection: "row", height: 1, minHeight: 1, flexWrap: "nowrap", flexShrink: 0 }, /* @__PURE__ */ React62.createElement(Text54, { wrap: "truncate" }, " "), status2.recording ? /* @__PURE__ */ React62.createElement(RecordingPill, { rec: status2.recording }) : status2.countdownSeconds !== void 0 ? /* @__PURE__ */ React62.createElement(CountdownRow, { mode: status2.mode, secondsLeft: status2.countdownSeconds }) : /* @__PURE__ */ React62.createElement(ModePill2, { mode: status2.mode, network: status2.network, detail: status2.networkDetail }), cols >= PRESET_MIN_COLS && status2.preset !== void 0 && /* @__PURE__ */ React62.createElement(PresetPill, { preset: status2.preset, model: session.model }), /* @__PURE__ */ React62.createElement(Sep, null), /* @__PURE__ */ React62.createElement(Text54, { color: FG.sub, wrap: "truncate" }, `${session.id} \xB7 ${session.branch}`), hasTurn && statusBar.showTurnCost && /* @__PURE__ */ React62.createElement(React62.Fragment, null, /* @__PURE__ */ React62.createElement(Sep, null), /* @__PURE__ */ React62.createElement(Text54, { bold: true, color: TONE.brand, wrap: "truncate" }, "\u25B8 "), /* @__PURE__ */ React62.createElement(Text54, { bold: true, color: FG.body, wrap: "truncate" }, `${formatCost(status2.cost, status2.balanceCurrency)} ${t("statusBar.turn")}`)), statusBar.showCacheHit && /* @__PURE__ */ React62.createElement(React62.Fragment, null, /* @__PURE__ */ React62.createElement(Sep, null), /* @__PURE__ */ React62.createElement(
9979
10069
  Text54,
9980
10070
  {
9981
10071
  color: TONE.accent,
9982
10072
  wrap: "truncate"
9983
10073
  },
9984
10074
  `${t("statusBar.cache")} ${Math.round(status2.cacheHit * 100)}%`
9985
- ), status2.mcpLoading && status2.mcpLoading.ready < status2.mcpLoading.total && /* @__PURE__ */ React62.createElement(McpLoadingPill, { ready: status2.mcpLoading.ready, total: status2.mcpLoading.total }), showWallet && /* @__PURE__ */ React62.createElement(
10075
+ )), status2.mcpLoading && status2.mcpLoading.ready < status2.mcpLoading.total && /* @__PURE__ */ React62.createElement(McpLoadingPill, { ready: status2.mcpLoading.ready, total: status2.mcpLoading.total }), showWallet && /* @__PURE__ */ React62.createElement(
9986
10076
  WalletPill,
9987
10077
  {
9988
10078
  sessionCostUsd: status2.sessionCost,
9989
10079
  balance: status2.balance,
9990
- currency: status2.balanceCurrency
10080
+ currency: status2.balanceCurrency,
10081
+ showSessionCost: statusBar.showSessionCost,
10082
+ showBalance: statusBar.showBalance
9991
10083
  }
9992
- ), cols >= VERSION_MIN_COLS && /* @__PURE__ */ React62.createElement(React62.Fragment, null, /* @__PURE__ */ React62.createElement(Sep, null), /* @__PURE__ */ React62.createElement(Text54, { color: FG.faint, wrap: "truncate" }, `v${VERSION}`), cols >= FEEDBACK_HINT_MIN_COLS && /* @__PURE__ */ React62.createElement(React62.Fragment, null, /* @__PURE__ */ React62.createElement(Text54, { color: FG.faint, wrap: "truncate" }, " \xB7 "), /* @__PURE__ */ React62.createElement(Text54, { color: FG.meta, wrap: "truncate" }, "\u2691 "), /* @__PURE__ */ React62.createElement(Text54, { color: FG.sub, wrap: "truncate" }, "/feedback")))));
10084
+ ), statusBar.showVersion && cols >= VERSION_MIN_COLS && /* @__PURE__ */ React62.createElement(React62.Fragment, null, /* @__PURE__ */ React62.createElement(Sep, null), /* @__PURE__ */ React62.createElement(Text54, { color: FG.faint, wrap: "truncate" }, `v${VERSION}`)), statusBar.showFeedbackHint && cols >= FEEDBACK_HINT_MIN_COLS && /* @__PURE__ */ React62.createElement(React62.Fragment, null, /* @__PURE__ */ React62.createElement(Sep, null), /* @__PURE__ */ React62.createElement(Text54, { color: FG.meta, wrap: "truncate" }, "\u2691 "), /* @__PURE__ */ React62.createElement(Text54, { color: FG.sub, wrap: "truncate" }, "/feedback"))));
9993
10085
  }
9994
10086
  function PresetPill({
9995
10087
  preset: preset2,
@@ -10020,10 +10112,12 @@ function McpLoadingPill({
10020
10112
  function WalletPill({
10021
10113
  sessionCostUsd,
10022
10114
  balance,
10023
- currency
10115
+ currency,
10116
+ showSessionCost,
10117
+ showBalance: showBalanceCfg
10024
10118
  }) {
10025
- const showSpent = sessionCostUsd > 0;
10026
- const showBalance = typeof balance === "number";
10119
+ const showSpent = showSessionCost && sessionCostUsd > 0;
10120
+ const showBalanceLine = showBalanceCfg && typeof balance === "number";
10027
10121
  return /* @__PURE__ */ React62.createElement(React62.Fragment, null, /* @__PURE__ */ React62.createElement(Sep, null), /* @__PURE__ */ React62.createElement(Text54, { color: FG.meta, wrap: "truncate" }, "\u26C1 "), showSpent && /* @__PURE__ */ React62.createElement(
10028
10122
  Text54,
10029
10123
  {
@@ -10031,7 +10125,7 @@ function WalletPill({
10031
10125
  wrap: "truncate"
10032
10126
  },
10033
10127
  `${formatCost(sessionCostUsd, currency, 2)} ${t("statusBar.spent")}`
10034
- ), showSpent && showBalance && /* @__PURE__ */ React62.createElement(Text54, { color: FG.meta, wrap: "truncate" }, " / "), showBalance && /* @__PURE__ */ React62.createElement(Text54, { bold: true, color: balanceColor(balance, currency), wrap: "truncate" }, formatBalance(balance, currency, { fractionDigits: 2 })), showBalance && /* @__PURE__ */ React62.createElement(Text54, { color: FG.faint, wrap: "truncate" }, t("statusBar.left")));
10128
+ ), showSpent && showBalanceLine && /* @__PURE__ */ React62.createElement(Text54, { color: FG.meta, wrap: "truncate" }, " / "), showBalanceLine && /* @__PURE__ */ React62.createElement(Text54, { bold: true, color: balanceColor(balance, currency), wrap: "truncate" }, formatBalance(balance, currency, { fractionDigits: 2 })), showBalanceLine && /* @__PURE__ */ React62.createElement(Text54, { color: FG.faint, wrap: "truncate" }, t("statusBar.left")));
10035
10129
  }
10036
10130
  function ModePill2({
10037
10131
  mode: mode2,
@@ -10109,7 +10203,7 @@ function networkDot(state) {
10109
10203
  }
10110
10204
 
10111
10205
  // src/cli/ui/layout/ToastRail.tsx
10112
- import { Box as Box52, Text as Text55, useStdout as useStdout16 } from "ink";
10206
+ import { Box as Box52, Text as Text55, useStdout as useStdout17 } from "ink";
10113
10207
  import React63, { useEffect as useEffect13 } from "react";
10114
10208
  var TONE_COLOR = {
10115
10209
  ok: TONE.ok,
@@ -10132,7 +10226,7 @@ function ToastRail() {
10132
10226
  const toasts = useAgentState((s) => s.toasts);
10133
10227
  const dispatch = useDispatch();
10134
10228
  useSlowTick();
10135
- const { stdout } = useStdout16();
10229
+ const { stdout } = useStdout17();
10136
10230
  const cols = stdout?.columns ?? 80;
10137
10231
  const rule = "\u2501".repeat(Math.max(20, cols - 4));
10138
10232
  const now = Date.now();
@@ -10590,8 +10684,9 @@ var handlers = {
10590
10684
  // src/cli/ui/slash/handlers/basic.ts
10591
10685
  var exit = () => ({ exit: true });
10592
10686
  var resetLog = (_args, loop2) => {
10593
- const { dropped, archived } = loop2.clearLog();
10594
- const info = archived ? t("handlers.basic.newInfoArchived", { count: dropped, archived }) : t("handlers.basic.newInfo", { count: dropped });
10687
+ const { dropped, archived, systemRebuilt } = loop2.clearLog();
10688
+ const head = archived ? t("handlers.basic.newInfoArchived", { count: dropped, archived }) : t("handlers.basic.newInfo", { count: dropped });
10689
+ const info = systemRebuilt ? head + t("handlers.basic.newInfoSystemReloaded") : head;
10595
10690
  return { clear: true, info };
10596
10691
  };
10597
10692
  function groupHeader(group) {
@@ -11383,6 +11478,28 @@ var handlers8 = { mcp };
11383
11478
 
11384
11479
  // src/cli/ui/slash/handlers/memory.ts
11385
11480
  import { basename } from "path";
11481
+ function pickTypeFlag(args) {
11482
+ const rest = [];
11483
+ let type = null;
11484
+ for (let i = 0; i < args.length; i++) {
11485
+ const a = args[i] ?? "";
11486
+ if (a === "--type" || a === "-t") {
11487
+ const next = args[i + 1];
11488
+ if (next) {
11489
+ type = next;
11490
+ i++;
11491
+ }
11492
+ continue;
11493
+ }
11494
+ const eq = a.match(/^--type=(.+)$/);
11495
+ if (eq) {
11496
+ type = eq[1] ?? null;
11497
+ continue;
11498
+ }
11499
+ rest.push(a);
11500
+ }
11501
+ return { type, rest };
11502
+ }
11386
11503
  var memory = (args, _loop, ctx) => {
11387
11504
  if (!memoryEnabled()) {
11388
11505
  return { info: t("handlers.memory.disabled") };
@@ -11391,18 +11508,25 @@ var memory = (args, _loop, ctx) => {
11391
11508
  return { info: t("handlers.memory.noRoot") };
11392
11509
  }
11393
11510
  const store = new MemoryStore({ projectRoot: ctx.codeRoot });
11394
- const sub = (args[0] ?? "").toLowerCase();
11511
+ const { type: typeFilter, rest: filteredArgs } = pickTypeFlag(args);
11512
+ const sub = (filteredArgs[0] ?? args[0] ?? "").toLowerCase();
11395
11513
  if (sub === "list" || sub === "ls") {
11396
- const entries = store.list();
11514
+ const all = store.list();
11515
+ const entries = typeFilter ? all.filter((e) => e.type === typeFilter) : all;
11397
11516
  if (entries.length === 0) {
11398
- return { info: t("handlers.memory.listEmpty") };
11517
+ return {
11518
+ info: typeFilter ? `no memories with type='${typeFilter}'. (${all.length} total across all types)` : t("handlers.memory.listEmpty")
11519
+ };
11399
11520
  }
11400
- const lines = [t("handlers.memory.listHeader", { count: entries.length })];
11521
+ const header = typeFilter ? `\u25B8 memory entries \u2014 type=${typeFilter} (${entries.length}/${all.length})` : t("handlers.memory.listHeader", { count: entries.length });
11522
+ const lines = [header];
11401
11523
  for (const e of entries) {
11524
+ const prio = effectivePriority(e);
11525
+ const marker = prio === "high" ? "\u26A0 " : prio === "low" ? "\xB7 " : " ";
11402
11526
  const tag2 = `${e.scope}/${e.type}`.padEnd(18);
11403
11527
  const name = e.name.padEnd(28);
11404
11528
  const desc = e.description.length > 70 ? `${e.description.slice(0, 69)}\u2026` : e.description;
11405
- lines.push(` ${tag2} ${name} ${desc}`);
11529
+ lines.push(`${marker}${tag2} ${name} ${desc}`);
11406
11530
  }
11407
11531
  lines.push("");
11408
11532
  lines.push(t("handlers.memory.listFooter"));
@@ -11452,15 +11576,24 @@ var memory = (args, _loop, ctx) => {
11452
11576
  };
11453
11577
  }
11454
11578
  const scope = rawScope;
11455
- const entries = store.list().filter((e) => e.scope === scope);
11579
+ const all = store.list();
11580
+ const inScope = all.filter((e) => e.scope === scope);
11581
+ const expiring = scope === "project" ? all.filter((e) => e.scope === "global" && e.expires === "project_end") : [];
11456
11582
  let deleted = 0;
11457
- for (const e of entries) {
11583
+ for (const e of inScope) {
11458
11584
  try {
11459
11585
  if (store.delete(scope, e.name)) deleted++;
11460
11586
  } catch {
11461
11587
  }
11462
11588
  }
11463
- return { info: t("handlers.memory.cleared", { scope, count: deleted }) };
11589
+ for (const e of expiring) {
11590
+ try {
11591
+ if (store.delete("global", e.name)) deleted++;
11592
+ } catch {
11593
+ }
11594
+ }
11595
+ const extra = expiring.length > 0 ? ` (+${expiring.length} global expires=project_end)` : "";
11596
+ return { info: `${t("handlers.memory.cleared", { scope, count: deleted })}${extra}` };
11464
11597
  }
11465
11598
  const parts = [];
11466
11599
  const projMem = readProjectMemory(ctx.memoryRoot);
@@ -11549,7 +11682,6 @@ var preset = (args, loop2, ctx) => {
11549
11682
  ctx.dispatch?.({ type: "session.model.change", model: p.model });
11550
11683
  ctx.dispatch?.({ type: "session.preset.change", preset: presetName });
11551
11684
  try {
11552
- saveReasoningEffort(p.reasoningEffort);
11553
11685
  savePreset(presetName);
11554
11686
  } catch {
11555
11687
  }
@@ -12677,7 +12809,7 @@ function hydrateCardsFromMessages(messages) {
12677
12809
  }
12678
12810
 
12679
12811
  // src/cli/ui/useCompletionPickers.ts
12680
- import { useCallback as useCallback10, useEffect as useEffect14, useMemo as useMemo10, useReducer as useReducer2, useRef as useRef7, useState as useState24 } from "react";
12812
+ import { useCallback as useCallback10, useEffect as useEffect14, useMemo as useMemo11, useReducer as useReducer2, useRef as useRef7, useState as useState25 } from "react";
12681
12813
  var SEARCH_DEBOUNCE_MS = 80;
12682
12814
  var SEARCH_FLUSH_MS = 50;
12683
12815
  var SEARCH_RESULT_CAP = 200;
@@ -12690,13 +12822,13 @@ function useCompletionPickers({
12690
12822
  mcpServers,
12691
12823
  slashUsage
12692
12824
  }) {
12693
- const [slashSelected, setSlashSelected] = useState24(0);
12694
- const slashMatches = useMemo10(() => {
12825
+ const [slashSelected, setSlashSelected] = useState25(0);
12826
+ const slashMatches = useMemo11(() => {
12695
12827
  if (!input.startsWith("/") || input.includes(" ")) return null;
12696
12828
  return suggestSlashCommands(input.slice(1), !!codeMode, slashUsage);
12697
12829
  }, [input, codeMode, slashUsage]);
12698
12830
  const slashGroupMode = input === "/";
12699
- const slashAdvancedHidden = useMemo10(
12831
+ const slashAdvancedHidden = useMemo11(
12700
12832
  () => slashGroupMode ? countAdvancedCommands(!!codeMode) : 0,
12701
12833
  [slashGroupMode, codeMode]
12702
12834
  );
@@ -12707,7 +12839,7 @@ function useCompletionPickers({
12707
12839
  return prev;
12708
12840
  });
12709
12841
  }, [slashMatches]);
12710
- const [atSelected, setAtSelected] = useState24(0);
12842
+ const [atSelected, setAtSelected] = useState25(0);
12711
12843
  const recentFilesRef = useRef7([]);
12712
12844
  const recordRecentFile = useCallback10((p) => {
12713
12845
  const list2 = recentFilesRef.current;
@@ -12716,12 +12848,12 @@ function useCompletionPickers({
12716
12848
  list2.unshift(p);
12717
12849
  if (list2.length > 20) list2.length = 20;
12718
12850
  }, []);
12719
- const atPicker = useMemo10(() => {
12851
+ const atPicker = useMemo11(() => {
12720
12852
  if (!codeMode) return null;
12721
12853
  if (slashMatches !== null) return null;
12722
12854
  return detectAtPicker(input);
12723
12855
  }, [codeMode, input, slashMatches]);
12724
- const parsed = useMemo10(
12856
+ const parsed = useMemo11(
12725
12857
  () => atPicker ? parseAtQuery(atPicker.query) : null,
12726
12858
  [atPicker]
12727
12859
  );
@@ -12733,7 +12865,7 @@ function useCompletionPickers({
12733
12865
  atMode === "search" && parsed ? parsed.filter : null,
12734
12866
  recentFilesRef
12735
12867
  );
12736
- const atState = useMemo10(() => {
12868
+ const atState = useMemo11(() => {
12737
12869
  if (!parsed) return null;
12738
12870
  if (atMode === "browse") {
12739
12871
  return {
@@ -12768,13 +12900,13 @@ function useCompletionPickers({
12768
12900
  },
12769
12901
  [atPicker, input, setInput]
12770
12902
  );
12771
- const [slashArgSelected, setSlashArgSelected] = useState24(0);
12772
- const slashArgContext = useMemo10(() => {
12903
+ const [slashArgSelected, setSlashArgSelected] = useState25(0);
12904
+ const slashArgContext = useMemo11(() => {
12773
12905
  if (!input.startsWith("/")) return null;
12774
12906
  if (slashMatches !== null) return null;
12775
12907
  return detectSlashArgContext(input, !!codeMode);
12776
12908
  }, [input, slashMatches, codeMode]);
12777
- const slashArgMatches = useMemo10(() => {
12909
+ const slashArgMatches = useMemo11(() => {
12778
12910
  if (!slashArgContext || slashArgContext.kind !== "picker") return null;
12779
12911
  const completer = slashArgContext.spec.argCompleter;
12780
12912
  const partial = slashArgContext.partial;
@@ -12848,8 +12980,8 @@ function useCompletionPickers({
12848
12980
  };
12849
12981
  }
12850
12982
  function useBrowseListing(rootDir, dir) {
12851
- const [entries, setEntries] = useState24([]);
12852
- const [loading, setLoading] = useState24(false);
12983
+ const [entries, setEntries] = useState25([]);
12984
+ const [loading, setLoading] = useState25(false);
12853
12985
  useEffect14(() => {
12854
12986
  if (dir === null) {
12855
12987
  setEntries([]);
@@ -12956,12 +13088,12 @@ function rankSearchHits(hits, filter, recent) {
12956
13088
  }
12957
13089
 
12958
13090
  // src/cli/ui/useEditHistory.ts
12959
- import { useCallback as useCallback11, useRef as useRef8, useState as useState25 } from "react";
13091
+ import { useCallback as useCallback11, useRef as useRef8, useState as useState26 } from "react";
12960
13092
  function useEditHistory(codeMode) {
12961
13093
  const editHistory = useRef8([]);
12962
13094
  const nextHistoryId = useRef8(1);
12963
13095
  const currentTurnEntry = useRef8(null);
12964
- const [undoBanner, setUndoBanner] = useState25(null);
13096
+ const [undoBanner, setUndoBanner] = useState26(null);
12965
13097
  const undoTimeoutRef = useRef8(null);
12966
13098
  const recordEdit = useCallback11(
12967
13099
  (source, blocks, results, snaps) => {
@@ -13186,17 +13318,18 @@ function useEditHistory(codeMode) {
13186
13318
  }
13187
13319
 
13188
13320
  // src/cli/ui/useSessionInfo.ts
13189
- import { useCallback as useCallback12, useEffect as useEffect15, useState as useState26 } from "react";
13321
+ import { useCallback as useCallback12, useEffect as useEffect15, useState as useState27 } from "react";
13190
13322
  function useSessionInfo(loop2) {
13191
- const [balance, setBalance] = useState26(null);
13192
- const [models, setModels] = useState26(null);
13193
- const [latestVersion, setLatestVersion] = useState26(null);
13323
+ const [balance, setBalance] = useState27(null);
13324
+ const [models, setModels] = useState27(null);
13325
+ const [latestVersion, setLatestVersion] = useState27(null);
13194
13326
  useEffect15(() => {
13195
13327
  let cancelled = false;
13196
13328
  void (async () => {
13197
13329
  const bal = await loop2.client.getBalance().catch(() => null);
13198
- if (cancelled || !bal || !bal.balance_infos.length) return;
13199
- const primary = bal.balance_infos[0];
13330
+ if (cancelled || !bal) return;
13331
+ const primary = pickPrimaryBalance(bal.balance_infos);
13332
+ if (!primary) return;
13200
13333
  setBalance({ currency: primary.currency, total: Number(primary.total_balance) });
13201
13334
  })();
13202
13335
  return () => {
@@ -13229,9 +13362,9 @@ function useSessionInfo(loop2) {
13229
13362
  const refreshBalance = useCallback12(() => {
13230
13363
  void (async () => {
13231
13364
  const bal = await loop2.client.getBalance().catch(() => null);
13232
- if (bal?.balance_infos.length) {
13233
- const p = bal.balance_infos[0];
13234
- setBalance({ currency: p.currency, total: Number(p.total_balance) });
13365
+ const primary = bal ? pickPrimaryBalance(bal.balance_infos) : null;
13366
+ if (primary) {
13367
+ setBalance({ currency: primary.currency, total: Number(primary.total_balance) });
13235
13368
  }
13236
13369
  })();
13237
13370
  }, [loop2]);
@@ -13259,7 +13392,7 @@ function useSessionInfo(loop2) {
13259
13392
  }
13260
13393
 
13261
13394
  // src/cli/ui/useSubagent.ts
13262
- import { useEffect as useEffect16, useRef as useRef9, useState as useState27 } from "react";
13395
+ import { useEffect as useEffect16, useRef as useRef9, useState as useState28 } from "react";
13263
13396
  function reduceSubagentInnerEvent(prev, ev) {
13264
13397
  if (ev.kind === "inner") {
13265
13398
  if (!ev.inner) return prev;
@@ -13304,23 +13437,28 @@ function summariseInner(ev) {
13304
13437
  return {
13305
13438
  glyph: "\u25A3",
13306
13439
  color: CARD.tool.color,
13307
- label: ev.toolName ?? "tool",
13308
- meta: "running"
13440
+ label: ev.toolName ?? t("common.tool"),
13441
+ meta: t("common.running")
13309
13442
  };
13310
13443
  }
13311
13444
  if (ev.role === "tool") {
13312
13445
  return {
13313
13446
  glyph: "\u25A3",
13314
13447
  color: CARD.tool.color,
13315
- label: ev.toolName ?? "tool",
13316
- meta: "done"
13448
+ label: ev.toolName ?? t("common.tool"),
13449
+ meta: t("common.done")
13317
13450
  };
13318
13451
  }
13319
13452
  if (ev.role === "warning") {
13320
- return { glyph: "\u26A0", color: TONE.warn, label: "warning", meta: ev.content?.slice(0, 40) };
13453
+ return {
13454
+ glyph: "\u26A0",
13455
+ color: TONE.warn,
13456
+ label: t("common.warning"),
13457
+ meta: ev.content?.slice(0, 40)
13458
+ };
13321
13459
  }
13322
13460
  if (ev.role === "error") {
13323
- return { glyph: "\u2716", color: TONE.err, label: ev.error ?? "error" };
13461
+ return { glyph: "\u2716", color: TONE.err, label: ev.error ?? t("common.error") };
13324
13462
  }
13325
13463
  return null;
13326
13464
  }
@@ -13329,7 +13467,7 @@ function useSubagent({
13329
13467
  log,
13330
13468
  getWalletCurrency
13331
13469
  }) {
13332
- const [activities, setActivities] = useState27([]);
13470
+ const [activities, setActivities] = useState28([]);
13333
13471
  const sinkRef = useRef9({ current: null });
13334
13472
  const getWalletCurrencyRef = useRef9(getWalletCurrency);
13335
13473
  useEffect16(() => {
@@ -13403,6 +13541,29 @@ function InputAreaWithHistoryHint({
13403
13541
  }
13404
13542
  return /* @__PURE__ */ React66.createElement(React66.Fragment, null, inputArea);
13405
13543
  }
13544
+ function HistoryTypingCapture({
13545
+ input,
13546
+ setInput,
13547
+ enabled,
13548
+ onReturnToBottom
13549
+ }) {
13550
+ const pinned = useChatScrollState((s) => s.pinned);
13551
+ useKeystroke((ev) => {
13552
+ if (ev.paste) return;
13553
+ if (ev.return) {
13554
+ onReturnToBottom();
13555
+ return;
13556
+ }
13557
+ if (ev.backspace) {
13558
+ setInput(input.slice(0, -1));
13559
+ return;
13560
+ }
13561
+ if (ev.input.length > 0 && ev.input >= " ") {
13562
+ setInput(input + ev.input);
13563
+ }
13564
+ }, enabled && !pinned);
13565
+ return null;
13566
+ }
13406
13567
  function LoopStatusRow({
13407
13568
  loop: loop2
13408
13569
  }) {
@@ -13428,11 +13589,31 @@ function App(props) {
13428
13589
  const [themeName, setThemeName] = React66.useState(
13429
13590
  () => resolveThemePreference(loadTheme(), process.env.REASONIX_THEME)
13430
13591
  );
13431
- return /* @__PURE__ */ React66.createElement(ThemeProvider, { name: themeName }, /* @__PURE__ */ React66.createElement(AgentStoreProvider, { session, initialCards }, /* @__PURE__ */ React66.createElement(ChatScrollProvider, null, /* @__PURE__ */ React66.createElement(AppInner, { ...props, themeName, setThemeName }))));
13592
+ const statusBar = React66.useMemo(() => {
13593
+ const cfg = readConfig().statusBar ?? {};
13594
+ return {
13595
+ showBalance: cfg.showBalance !== false,
13596
+ showSessionCost: cfg.showSessionCost !== false,
13597
+ showTurnCost: cfg.showTurnCost !== false,
13598
+ showCacheHit: cfg.showCacheHit !== false,
13599
+ showVersion: cfg.showVersion !== false,
13600
+ showFeedbackHint: cfg.showFeedbackHint !== false
13601
+ };
13602
+ }, []);
13603
+ return /* @__PURE__ */ React66.createElement(ThemeProvider, { name: themeName }, /* @__PURE__ */ React66.createElement(AgentStoreProvider, { session, initialCards }, /* @__PURE__ */ React66.createElement(ChatScrollProvider, null, /* @__PURE__ */ React66.createElement(
13604
+ AppInner,
13605
+ {
13606
+ ...props,
13607
+ themeName,
13608
+ setThemeName,
13609
+ statusBar
13610
+ }
13611
+ ))));
13432
13612
  }
13433
13613
  function AppInner({
13434
13614
  model: model2,
13435
13615
  system,
13616
+ rebuildSystem,
13436
13617
  transcript,
13437
13618
  budgetUsd,
13438
13619
  failureThreshold,
@@ -13447,8 +13628,10 @@ function AppInner({
13447
13628
  dashboardPort,
13448
13629
  onSwitchSession,
13449
13630
  mouse = true,
13631
+ startupInfoHints,
13450
13632
  themeName,
13451
- setThemeName
13633
+ setThemeName,
13634
+ statusBar
13452
13635
  }) {
13453
13636
  markPhase("app_inner_start");
13454
13637
  const log = useScrollback();
@@ -13459,17 +13642,17 @@ function AppInner({
13459
13642
  const isStreaming = useAgentState((s) => s.cards.some((c) => c.kind === "streaming" && !c.done));
13460
13643
  const activityLabel = useActivityLabel();
13461
13644
  const chatScroll = useChatScrollActions();
13462
- const [input, setInput] = useState28("");
13463
- const [busy, setBusy] = useState28(false);
13464
- const [slashUsage, setSlashUsage] = useState28(
13645
+ const [input, setInput] = useState29("");
13646
+ const [busy, setBusy] = useState29(false);
13647
+ const [slashUsage, setSlashUsage] = useState29(
13465
13648
  () => loadSlashUsage()
13466
13649
  );
13467
- const [liveExpand, setLiveExpand] = useState28(false);
13650
+ const [liveExpand, setLiveExpand] = useState29(false);
13468
13651
  useEffect17(() => {
13469
13652
  if (!isStreaming && liveExpand) setLiveExpand(false);
13470
13653
  }, [isStreaming, liveExpand]);
13471
13654
  const languageVersion = useLanguageReload();
13472
- const [bootReady, setBootReady] = useState28(false);
13655
+ const [bootReady, setBootReady] = useState29(false);
13473
13656
  useEffect17(() => {
13474
13657
  const t2 = setTimeout(() => setBootReady(true), 1400);
13475
13658
  return () => clearTimeout(t2);
@@ -13478,7 +13661,7 @@ function AppInner({
13478
13661
  markPhase("first_paint");
13479
13662
  dumpStartupProfile();
13480
13663
  }, []);
13481
- const [liveMcpServers, setLiveMcpServers] = useState28(() => mcpServers ?? []);
13664
+ const [liveMcpServers, setLiveMcpServers] = useState29(() => mcpServers ?? []);
13482
13665
  const abortedThisTurn = useRef10(false);
13483
13666
  useEffect17(() => {
13484
13667
  busyRef.current = busy;
@@ -13492,7 +13675,7 @@ function AppInner({
13492
13675
  setStatusLine,
13493
13676
  clear: clearToolProgressDisplay
13494
13677
  } = useToolProgressDisplay(progressSink);
13495
- const { stdout } = useStdout17();
13678
+ const { stdout } = useStdout18();
13496
13679
  useTerminalSetup(mouse);
13497
13680
  const walletCurrencyRef = useRef10(void 0);
13498
13681
  const { activities: subagentActivities, sinkRef: subagentSinkRef } = useSubagent({
@@ -13529,31 +13712,31 @@ function AppInner({
13529
13712
  const { preset: preset2, setPreset, proArmed, setProArmed, turnOnPro, setTurnOnPro } = usePresetMode(model2);
13530
13713
  const planModeRef = useRef10(false);
13531
13714
  const latestVersionRef = useRef10(null);
13532
- const [pendingEditReview, setPendingEditReview] = useState28(null);
13533
- const [walkthroughActive, setWalkthroughActive] = useState28(false);
13715
+ const [pendingEditReview, setPendingEditReview] = useState29(null);
13716
+ const [walkthroughActive, setWalkthroughActive] = useState29(false);
13534
13717
  const editReviewResolveRef = useRef10(null);
13535
13718
  const turnEditPolicyRef = useRef10("ask");
13536
- const [pendingShell, setPendingShell] = useState28(null);
13537
- const [pendingPath, setPendingPath] = useState28(null);
13538
- const [pendingPlan, setPendingPlan] = useState28(null);
13539
- const [pendingReviseEditor, setPendingReviseEditor] = useState28(null);
13540
- const [pendingSessionsPicker, setPendingSessionsPicker] = useState28(false);
13541
- const [sessionsPickerList, setSessionsPickerList] = useState28([]);
13542
- const [pendingCheckpointPicker, setPendingCheckpointPicker] = useState28(false);
13543
- const [checkpointPickerList, setCheckpointPickerList] = useState28([]);
13544
- const [pendingMcpHub, setPendingMcpHub] = useState28(null);
13545
- const [pendingModelPicker, setPendingModelPicker] = useState28(false);
13546
- const [pendingThemePicker, setPendingThemePicker] = useState28(false);
13547
- const [pendingCopyMode, setPendingCopyMode] = useState28(false);
13548
- const [stagedInput, setStagedInput] = useState28(null);
13549
- const [pendingCheckpoint, setPendingCheckpoint] = useState28(null);
13550
- const [stagedCheckpointRevise, setStagedCheckpointRevise] = useState28(null);
13551
- const [pendingRevision, setPendingRevision] = useState28(null);
13552
- const [pendingChoice, setPendingChoice] = useState28(null);
13553
- const [stagedChoiceCustom, setStagedChoiceCustom] = useState28(null);
13719
+ const [pendingShell, setPendingShell] = useState29(null);
13720
+ const [pendingPath, setPendingPath] = useState29(null);
13721
+ const [pendingPlan, setPendingPlan] = useState29(null);
13722
+ const [pendingReviseEditor, setPendingReviseEditor] = useState29(null);
13723
+ const [pendingSessionsPicker, setPendingSessionsPicker] = useState29(false);
13724
+ const [sessionsPickerList, setSessionsPickerList] = useState29([]);
13725
+ const [pendingCheckpointPicker, setPendingCheckpointPicker] = useState29(false);
13726
+ const [checkpointPickerList, setCheckpointPickerList] = useState29([]);
13727
+ const [pendingMcpHub, setPendingMcpHub] = useState29(null);
13728
+ const [pendingModelPicker, setPendingModelPicker] = useState29(false);
13729
+ const [pendingThemePicker, setPendingThemePicker] = useState29(false);
13730
+ const [pendingCopyMode, setPendingCopyMode] = useState29(false);
13731
+ const [stagedInput, setStagedInput] = useState29(null);
13732
+ const [pendingCheckpoint, setPendingCheckpoint] = useState29(null);
13733
+ const [stagedCheckpointRevise, setStagedCheckpointRevise] = useState29(null);
13734
+ const [pendingRevision, setPendingRevision] = useState29(null);
13735
+ const [pendingChoice, setPendingChoice] = useState29(null);
13736
+ const [stagedChoiceCustom, setStagedChoiceCustom] = useState29(null);
13554
13737
  const modalOpen = !!pendingShell || !!pendingPlan || !!pendingReviseEditor || !!pendingSessionsPicker || !!pendingCheckpointPicker || !!pendingMcpHub || pendingModelPicker || pendingThemePicker || pendingCopyMode || !!stagedInput || !!pendingEditReview || walkthroughActive || !!pendingChoice || !!stagedChoiceCustom || !!pendingRevision || !!stagedCheckpointRevise || !!pendingCheckpoint;
13555
- const [planMode, setPlanMode] = useState28(false);
13556
- const [queuedSubmit, setQueuedSubmit] = useState28(null);
13738
+ const [planMode, setPlanMode] = useState29(false);
13739
+ const [queuedSubmit, setQueuedSubmit] = useState29(null);
13557
13740
  const { recallPrev, recallNext, pushHistory, resetCursor } = useInputRecall(setInput);
13558
13741
  const { setRawMode, isRawModeSupported } = useStdin();
13559
13742
  const handleOpenExternalEditor = useCallback13(async () => {
@@ -13581,7 +13764,7 @@ function AppInner({
13581
13764
  const activePickerSnapshotRef = useRef10(null);
13582
13765
  const activeViewerResolverRef = useRef10(null);
13583
13766
  const activeViewerSnapshotRef = useRef10(null);
13584
- const [pendingReplayViewer, setPendingReplayViewer] = useState28(null);
13767
+ const [pendingReplayViewer, setPendingReplayViewer] = useState29(null);
13585
13768
  const planStepsRef = useRef10(null);
13586
13769
  const completedStepIdsRef = useRef10(/* @__PURE__ */ new Set());
13587
13770
  const planBodyRef = useRef10(null);
@@ -13599,7 +13782,7 @@ function AppInner({
13599
13782
  if (planSummaryRef.current) extras.summary = planSummaryRef.current;
13600
13783
  savePlanState(session, steps, completedStepIdsRef.current, extras);
13601
13784
  }, [session]);
13602
- const [summary, setSummary] = useState28({
13785
+ const [summary, setSummary] = useState29({
13603
13786
  turns: 0,
13604
13787
  totalCostUsd: 0,
13605
13788
  totalInputCostUsd: 0,
@@ -13633,7 +13816,7 @@ function AppInner({
13633
13816
  };
13634
13817
  }, []);
13635
13818
  const loopRef = useRef10(null);
13636
- const loop2 = useMemo11(() => {
13819
+ const loop2 = useMemo12(() => {
13637
13820
  if (loopRef.current) return loopRef.current;
13638
13821
  const client = new DeepSeekClient({ baseUrl: loadBaseUrl() });
13639
13822
  if (tools && !tools.has("run_skill")) {
@@ -13678,11 +13861,12 @@ function AppInner({
13678
13861
  // Restore the user's last-chosen effort cap. Without this a
13679
13862
  // `/effort high` silently reverted to `max` on relaunch — the
13680
13863
  // loop's constructor default wins over persisted state.
13681
- reasoningEffort: loadReasoningEffort()
13864
+ reasoningEffort: loadReasoningEffort(),
13865
+ rebuildSystem
13682
13866
  });
13683
13867
  loopRef.current = l;
13684
13868
  return l;
13685
- }, [model2, system, budgetUsd, failureThreshold, session, tools, codeMode]);
13869
+ }, [model2, system, rebuildSystem, budgetUsd, failureThreshold, session, tools, codeMode]);
13686
13870
  useEffect17(() => {
13687
13871
  if (!session || !tools) return;
13688
13872
  tools.setAuditListener((event) => {
@@ -13818,7 +14002,7 @@ function AppInner({
13818
14002
  }
13819
14003
  }
13820
14004
  }, []);
13821
- const pickerPorts = useMemo11(
14005
+ const pickerPorts = useMemo12(
13822
14006
  () => ({
13823
14007
  broadcast: broadcastDashboardEvent,
13824
14008
  resolverRef: activePickerResolverRef,
@@ -13826,7 +14010,7 @@ function AppInner({
13826
14010
  }),
13827
14011
  [broadcastDashboardEvent]
13828
14012
  );
13829
- const viewerPorts = useMemo11(
14013
+ const viewerPorts = useMemo12(
13830
14014
  () => ({
13831
14015
  broadcast: broadcastDashboardEvent,
13832
14016
  resolverRef: activeViewerResolverRef,
@@ -14001,6 +14185,7 @@ function AppInner({
14001
14185
  } else {
14002
14186
  log.pushInfo(t("ui.newSession", { name: session }));
14003
14187
  }
14188
+ for (const hint of startupInfoHints ?? []) log.pushInfo(hint);
14004
14189
  if (session && codeMode) {
14005
14190
  const restored = loadPendingEdits(session);
14006
14191
  if (restored && restored.length > 0) {
@@ -14040,7 +14225,7 @@ function AppInner({
14040
14225
  log.pushTip({ topic: tip.topic, sections: tip.sections, footer: tip.footer });
14041
14226
  markMouseClipboardHintShown();
14042
14227
  }
14043
- }, [session, loop2, codeMode, syncPendingCount, log, pendingEdits]);
14228
+ }, [session, loop2, codeMode, syncPendingCount, log, pendingEdits, startupInfoHints]);
14044
14229
  const quitProcess = useQuit(transcriptRef);
14045
14230
  useKeystroke((ev) => {
14046
14231
  const pickerOwnsArrows = (atState?.entries.length ?? 0) > 0 || (slashMatches?.length ?? 0) > 0 || (slashArgMatches?.length ?? 0) > 0 || pendingShell != null || pendingPath != null;
@@ -14258,7 +14443,7 @@ function AppInner({
14258
14443
  if (dashboardRef.current) return dashboardRef.current.url;
14259
14444
  if (dashboardStartingRef.current) return dashboardStartingRef.current;
14260
14445
  const startup = (async () => {
14261
- const { startDashboardServer } = await import("./server-CN4QPPVJ.js");
14446
+ const { startDashboardServer } = await import("./server-DRFPXXSH.js");
14262
14447
  const handle = await startDashboardServer(
14263
14448
  {
14264
14449
  mode: "attached",
@@ -14526,7 +14711,7 @@ function AppInner({
14526
14711
  const getDashboardUrl = useCallback13(() => {
14527
14712
  return dashboardRef.current?.url ?? null;
14528
14713
  }, []);
14529
- const [dashboardUrl, setDashboardUrlState] = useState28(null);
14714
+ const [dashboardUrl, setDashboardUrlState] = useState29(null);
14530
14715
  useEffect17(() => {
14531
14716
  if (noDashboard) return;
14532
14717
  if (dashboardRef.current) return;
@@ -14648,6 +14833,37 @@ function AppInner({
14648
14833
  }
14649
14834
  return;
14650
14835
  }
14836
+ const btwMatch = /^\/btw(?:\s+([\s\S]+))?$/.exec(text);
14837
+ if (btwMatch) {
14838
+ const question = btwMatch[1]?.trim() ?? "";
14839
+ pushHistory(text);
14840
+ log.pushUser(text);
14841
+ if (!question) {
14842
+ log.pushInfo(t("app.btwUsage"));
14843
+ return;
14844
+ }
14845
+ setBusy(true);
14846
+ try {
14847
+ const reply = await loop2.client.chat({
14848
+ model: loop2.model,
14849
+ messages: [
14850
+ {
14851
+ role: "system",
14852
+ content: "You are answering a side question that is unrelated to the current coding conversation. Answer concisely (1-3 sentences) in plain prose. Do not call tools, do not ask clarifying questions, and do not reference any prior turns."
14853
+ },
14854
+ { role: "user", content: question }
14855
+ ]
14856
+ });
14857
+ const answer = reply.content.trim() || "(no answer)";
14858
+ log.pushInfo(`${t("app.btwHeader")}
14859
+ ${answer}`, "brand");
14860
+ } catch (err) {
14861
+ log.pushWarning(t("app.btwFailed"), err.message);
14862
+ } finally {
14863
+ setBusy(false);
14864
+ }
14865
+ return;
14866
+ }
14651
14867
  const mcpBrowseMatch = /^\/(resource|prompt)(?:\s+([\s\S]*))?$/.exec(text);
14652
14868
  if (mcpBrowseMatch) {
14653
14869
  const kind = mcpBrowseMatch[1];
@@ -15628,7 +15844,15 @@ function AppInner({
15628
15844
  );
15629
15845
  const tickerSuspended = modalOpen || !busy && !isStreaming;
15630
15846
  if (!bootReady) return /* @__PURE__ */ React66.createElement(BootSplash, null);
15631
- return /* @__PURE__ */ React66.createElement(React66.Fragment, null, /* @__PURE__ */ React66.createElement(TickerProvider, { disabled: tickerSuspended }, /* @__PURE__ */ React66.createElement(ViewportBudgetProvider, null, /* @__PURE__ */ React66.createElement(InflightProvider, { inflight: loop2.inflight }, /* @__PURE__ */ React66.createElement(Box54, { flexDirection: "row", height: stdout?.rows ?? 24 }, /* @__PURE__ */ React66.createElement(Box54, { flexDirection: "column", flexGrow: 1 }, /* @__PURE__ */ React66.createElement(Box54, { flexDirection: "column", flexGrow: 1 }, /* @__PURE__ */ React66.createElement(LiveExpandContext.Provider, { value: liveExpand }, /* @__PURE__ */ React66.createElement(CardStream, { suppressLive: modalOpen })), !hasConversation && !busy && !isStreaming && slashMatches === null ? /* @__PURE__ */ React66.createElement(
15847
+ return /* @__PURE__ */ React66.createElement(React66.Fragment, null, /* @__PURE__ */ React66.createElement(
15848
+ HistoryTypingCapture,
15849
+ {
15850
+ input,
15851
+ setInput,
15852
+ enabled: !modalOpen && !busy,
15853
+ onReturnToBottom: chatScroll.jumpToBottom
15854
+ }
15855
+ ), /* @__PURE__ */ React66.createElement(TickerProvider, { disabled: tickerSuspended }, /* @__PURE__ */ React66.createElement(ViewportBudgetProvider, null, /* @__PURE__ */ React66.createElement(InflightProvider, { inflight: loop2.inflight }, /* @__PURE__ */ React66.createElement(Box54, { flexDirection: "row", height: stdout?.rows ?? 24 }, /* @__PURE__ */ React66.createElement(Box54, { flexDirection: "column", flexGrow: 1 }, /* @__PURE__ */ React66.createElement(Box54, { flexDirection: "column", flexGrow: 1 }, /* @__PURE__ */ React66.createElement(LiveExpandContext.Provider, { value: liveExpand }, /* @__PURE__ */ React66.createElement(CardStream, { suppressLive: modalOpen })), !hasConversation && !busy && !isStreaming && slashMatches === null ? /* @__PURE__ */ React66.createElement(
15632
15856
  WelcomeBanner,
15633
15857
  {
15634
15858
  inCodeMode: !!codeMode,
@@ -15755,7 +15979,7 @@ function AppInner({
15755
15979
  if (outcome.kind === "new") {
15756
15980
  setPendingSessionsPicker(false);
15757
15981
  if (onSwitchSession) {
15758
- onSwitchSession(void 0);
15982
+ onSwitchSession(freshSessionName(session));
15759
15983
  } else {
15760
15984
  log.pushInfo(
15761
15985
  "\u25B8 to start a fresh session, quit and run: reasonix chat (no --session flag)"
@@ -15854,7 +16078,6 @@ function AppInner({
15854
16078
  preset: outcome.name
15855
16079
  });
15856
16080
  try {
15857
- saveReasoningEffort(p.reasoningEffort);
15858
16081
  savePreset(outcome.name);
15859
16082
  } catch {
15860
16083
  }
@@ -15963,7 +16186,7 @@ function AppInner({
15963
16186
  undoArmed: !!undoBanner || hasUndoable(),
15964
16187
  jobs: codeMode.jobs
15965
16188
  }
15966
- ) : null, activeLoop ? /* @__PURE__ */ React66.createElement(LoopStatusRow, { loop: activeLoop }) : null, /* @__PURE__ */ React66.createElement(StatusRow, null), /* @__PURE__ */ React66.createElement(
16189
+ ) : null, activeLoop ? /* @__PURE__ */ React66.createElement(LoopStatusRow, { loop: activeLoop }) : null, /* @__PURE__ */ React66.createElement(StatusRow, { statusBar }), /* @__PURE__ */ React66.createElement(
15967
16190
  PromptInput,
15968
16191
  {
15969
16192
  value: input,
@@ -15999,7 +16222,7 @@ function AppInner({
15999
16222
 
16000
16223
  // src/cli/ui/Setup.tsx
16001
16224
  import { Box as Box55, Text as Text59, useApp } from "ink";
16002
- import React68, { useState as useState29 } from "react";
16225
+ import React68, { useState as useState30 } from "react";
16003
16226
 
16004
16227
  // src/cli/ui/MaskedInput.tsx
16005
16228
  import { Text as Text58, useInput } from "ink";
@@ -16047,8 +16270,8 @@ function MaskedInput({
16047
16270
 
16048
16271
  // src/cli/ui/Setup.tsx
16049
16272
  function Setup({ onReady }) {
16050
- const [value, setValue] = useState29("");
16051
- const [error, setError] = useState29(null);
16273
+ const [value, setValue] = useState30("");
16274
+ const [error, setError] = useState30(null);
16052
16275
  const { exit: exit2 } = useApp();
16053
16276
  const handleSubmit = (raw) => {
16054
16277
  const trimmed = raw.trim();
@@ -16116,205 +16339,6 @@ async function drainTtyResponses(timeoutMs = 50) {
16116
16339
  }
16117
16340
 
16118
16341
  // src/cli/commands/chat.tsx
16119
- var stderrLifecycleSink = (n) => {
16120
- if (n.kind === "slow") {
16121
- process.stderr.write(
16122
- `${formatMcpSlowToast({ name: n.serverName, p95Ms: n.p95Ms, sampleSize: n.sampleSize })}
16123
- `
16124
- );
16125
- return;
16126
- }
16127
- if (n.kind === "failed") {
16128
- process.stderr.write(
16129
- `${formatMcpLifecycleEvent({ state: "failed", name: n.name, reason: n.reason })}
16130
- \u2192 run \`reasonix setup\` to remove this entry, or fix the underlying issue (missing npm package, network, etc.).
16131
- `
16132
- );
16133
- return;
16134
- }
16135
- if (n.kind === "connected") {
16136
- process.stderr.write(
16137
- `${formatMcpLifecycleEvent({
16138
- state: "connected",
16139
- name: n.name,
16140
- tools: n.tools,
16141
- resources: n.resources,
16142
- prompts: n.prompts,
16143
- ms: n.ms
16144
- })}
16145
- `
16146
- );
16147
- return;
16148
- }
16149
- process.stderr.write(`${formatMcpLifecycleEvent({ state: n.kind, name: n.name })}
16150
- `);
16151
- };
16152
- function createMcpRuntime(ctx) {
16153
- const records = /* @__PURE__ */ new Map();
16154
- const insertionOrder = [];
16155
- let sink = stderrLifecycleSink;
16156
- async function addSpec(raw, loop2) {
16157
- if (records.has(raw)) {
16158
- return { ok: true, summary: records.get(raw).summary };
16159
- }
16160
- const tools = ctx.getTools();
16161
- if (!tools) return { ok: false, reason: "no tool registry available" };
16162
- const disabledNames = new Set(readConfig().mcpDisabled ?? []);
16163
- let label = "anon";
16164
- let mcp2;
16165
- let resolveReady;
16166
- let rejectReady;
16167
- const ready = new Promise((resolve2, reject) => {
16168
- resolveReady = resolve2;
16169
- rejectReady = reject;
16170
- });
16171
- ready.catch(() => void 0);
16172
- try {
16173
- const spec = parseMcpSpec(raw);
16174
- label = spec.name ?? "anon";
16175
- if (spec.name && disabledNames.has(spec.name)) {
16176
- sink({ kind: "disabled", name: label });
16177
- rejectReady(new Error(`MCP server "${label}" is disabled`));
16178
- return { ok: false, reason: "disabled by user" };
16179
- }
16180
- sink({ kind: "handshake", name: label });
16181
- const t0 = Date.now();
16182
- const namePrefix = spec.name ? `${spec.name}_` : ctx.getRequestedCount() === 1 && ctx.getMcpPrefix() ? ctx.getMcpPrefix() : "";
16183
- if (spec.transport === "stdio") preflightStdioSpec(spec);
16184
- const transport = buildTransportFromSpec(spec, { env: mcpEnvFor(spec.name, readConfig()) });
16185
- mcp2 = new McpClient({ transport });
16186
- await mcp2.initialize();
16187
- const host = { client: mcp2 };
16188
- const bridge = await bridgeMcpTools(mcp2, {
16189
- registry: tools,
16190
- namePrefix,
16191
- serverName: label,
16192
- host,
16193
- ready,
16194
- onProgress: (info) => ctx.progressSink.current?.(info),
16195
- onSlow: (info) => sink({
16196
- kind: "slow",
16197
- serverName: info.serverName,
16198
- p95Ms: info.p95Ms,
16199
- sampleSize: info.sampleSize
16200
- })
16201
- });
16202
- let report;
16203
- try {
16204
- report = await inspectMcpServer(mcp2);
16205
- } catch {
16206
- report = {
16207
- protocolVersion: mcp2.protocolVersion,
16208
- serverInfo: mcp2.serverInfo,
16209
- capabilities: mcp2.serverCapabilities ?? {},
16210
- tools: { supported: true, items: [] },
16211
- resources: { supported: false, reason: "inspect failed" },
16212
- prompts: { supported: false, reason: "inspect failed" },
16213
- elapsedMs: 0
16214
- };
16215
- }
16216
- const ms = Date.now() - t0;
16217
- const resourceCount = report.resources.supported ? report.resources.items.length : 0;
16218
- const promptCount = report.prompts.supported ? report.prompts.items.length : 0;
16219
- sink({
16220
- kind: "connected",
16221
- name: label,
16222
- tools: bridge.registeredNames.length,
16223
- resources: resourceCount,
16224
- prompts: promptCount,
16225
- ms
16226
- });
16227
- resolveReady();
16228
- const summary = buildMcpServerSummary({
16229
- label,
16230
- spec: raw,
16231
- toolCount: bridge.registeredNames.length,
16232
- report,
16233
- host,
16234
- bridgeEnv: bridge.env
16235
- });
16236
- const allSpecs = tools.specs();
16237
- const registeredSpecs = allSpecs.filter(
16238
- (s) => bridge.registeredNames.includes(s.function.name)
16239
- );
16240
- records.set(raw, {
16241
- spec: raw,
16242
- client: mcp2,
16243
- summary,
16244
- registeredNames: bridge.registeredNames,
16245
- registeredSpecs
16246
- });
16247
- insertionOrder.push(raw);
16248
- if (loop2) for (const s of registeredSpecs) loop2.prefix.addTool(s);
16249
- return { ok: true, summary };
16250
- } catch (err) {
16251
- await mcp2?.close().catch(() => void 0);
16252
- const reason = err.message;
16253
- sink({ kind: "failed", name: label, reason });
16254
- rejectReady(new Error(`MCP server "${label}" failed to start: ${reason}`));
16255
- return { ok: false, reason };
16256
- }
16257
- }
16258
- async function removeSpec(raw, loop2) {
16259
- const record = records.get(raw);
16260
- if (!record) return false;
16261
- await record.client.close().catch(() => void 0);
16262
- const tools = ctx.getTools();
16263
- for (const name of record.registeredNames) {
16264
- tools?.unregister(name);
16265
- loop2?.prefix.removeTool(name);
16266
- }
16267
- records.delete(raw);
16268
- const idx = insertionOrder.indexOf(raw);
16269
- if (idx >= 0) insertionOrder.splice(idx, 1);
16270
- return true;
16271
- }
16272
- async function reloadFromConfig(loop2) {
16273
- const desired = readConfig().mcp ?? [];
16274
- const desiredSet = new Set(desired);
16275
- const currentSet = new Set(records.keys());
16276
- const added = [];
16277
- const removed = [];
16278
- const failed = [];
16279
- for (const spec of [...currentSet]) {
16280
- if (!desiredSet.has(spec)) {
16281
- await removeSpec(spec, loop2);
16282
- removed.push(spec);
16283
- }
16284
- }
16285
- for (const spec of desired) {
16286
- if (currentSet.has(spec)) continue;
16287
- const result = await addSpec(spec, loop2);
16288
- if (result.ok) added.push(spec);
16289
- else failed.push({ spec, reason: result.reason });
16290
- }
16291
- return { added, removed, failed, summaries: summaries() };
16292
- }
16293
- function specs() {
16294
- return [...insertionOrder];
16295
- }
16296
- function summaries() {
16297
- return insertionOrder.map((s) => records.get(s)?.summary).filter((s) => Boolean(s));
16298
- }
16299
- async function closeAll() {
16300
- for (const r of records.values()) await r.client.close().catch(() => void 0);
16301
- records.clear();
16302
- insertionOrder.length = 0;
16303
- }
16304
- function setLifecycleSink(s) {
16305
- sink = s;
16306
- }
16307
- return {
16308
- size: () => records.size,
16309
- specs,
16310
- summaries,
16311
- addSpec,
16312
- removeSpec,
16313
- reloadFromConfig,
16314
- closeAll,
16315
- setLifecycleSink
16316
- };
16317
- }
16318
16342
  function Root({
16319
16343
  initialKey,
16320
16344
  tools,
@@ -16323,13 +16347,14 @@ function Root({
16323
16347
  progressSink,
16324
16348
  showPicker,
16325
16349
  mcpRuntime,
16350
+ startupInfoHints,
16326
16351
  ...appProps
16327
16352
  }) {
16328
- const [key, setKey] = useState30(initialKey);
16329
- const [pickerOpen, setPickerOpen] = useState30(showPicker);
16330
- const [activeSession, setActiveSession] = useState30(appProps.session);
16353
+ const [key, setKey] = useState31(initialKey);
16354
+ const [pickerOpen, setPickerOpen] = useState31(showPicker);
16355
+ const [activeSession, setActiveSession] = useState31(appProps.session);
16331
16356
  const workspaceRoot = appProps.codeMode?.rootDir ?? process.cwd();
16332
- const [sessions2, setSessions] = useState30(() => listSessionsForWorkspace(workspaceRoot));
16357
+ const [sessions2, setSessions] = useState31(() => listSessionsForWorkspace(workspaceRoot));
16333
16358
  if (!key) {
16334
16359
  return /* @__PURE__ */ React69.createElement(
16335
16360
  Setup,
@@ -16355,7 +16380,7 @@ function Root({
16355
16380
  return;
16356
16381
  }
16357
16382
  if (outcome.kind === "new") {
16358
- setActiveSession(void 0);
16383
+ setActiveSession(freshSessionName(activeSession));
16359
16384
  setPickerOpen(false);
16360
16385
  return;
16361
16386
  }
@@ -16382,6 +16407,7 @@ function Root({
16382
16407
  key: activeSession ?? "__new__",
16383
16408
  model: appProps.model,
16384
16409
  system: appProps.system,
16410
+ rebuildSystem: appProps.rebuildSystem,
16385
16411
  transcript: appProps.transcript,
16386
16412
  budgetUsd: appProps.budgetUsd,
16387
16413
  failureThreshold: appProps.failureThreshold,
@@ -16391,6 +16417,7 @@ function Root({
16391
16417
  mcpServers,
16392
16418
  mcpRuntime,
16393
16419
  progressSink,
16420
+ startupInfoHints,
16394
16421
  codeMode: appProps.codeMode,
16395
16422
  noDashboard: appProps.noDashboard,
16396
16423
  dashboardPort: appProps.dashboardPort,
@@ -16416,6 +16443,11 @@ async function chatCommand(opts) {
16416
16443
  });
16417
16444
  const mcpSpecs = [...requestedSpecs];
16418
16445
  const mcpServers = [];
16446
+ const cfg = readConfig();
16447
+ const startupInfoHints = [];
16448
+ if (cfg.setupCompleted === true && (cfg.mcp?.length ?? 0) === 0 && mcpSpecs.length === 0) {
16449
+ startupInfoHints.push(t("mcpHealth.emptyHint"));
16450
+ }
16419
16451
  if (searchEnabled()) {
16420
16452
  if (!tools) tools = new ToolRegistry();
16421
16453
  registerWebTools(tools, {
@@ -16446,6 +16478,7 @@ async function chatCommand(opts) {
16446
16478
  mcpServers,
16447
16479
  mcpRuntime: runtime,
16448
16480
  progressSink,
16481
+ startupInfoHints,
16449
16482
  showPicker,
16450
16483
  ...opts,
16451
16484
  session: resolvedSession
@@ -16478,4 +16511,4 @@ async function chatCommand(opts) {
16478
16511
  export {
16479
16512
  chatCommand
16480
16513
  };
16481
- //# sourceMappingURL=chunk-26UDIXLD.js.map
16514
+ //# sourceMappingURL=chunk-F2AV2QDK.js.map