@carboncode/cli 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/README.md +15 -24
  2. package/README.zh-CN.md +13 -11
  3. package/dist/cli/{acp-35C4ME6Y.js → acp-E6QAGSG4.js} +17 -16
  4. package/dist/cli/acp-E6QAGSG4.js.map +1 -0
  5. package/dist/cli/{chat-A6UJDPGV.js → chat-6MBLB7MU.js} +21 -21
  6. package/dist/cli/{chunk-J5BYPUB5.js → chunk-2EKLWOE3.js} +794 -554
  7. package/dist/cli/chunk-2EKLWOE3.js.map +1 -0
  8. package/dist/cli/{chunk-UI66BH6D.js → chunk-2UXHZAXP.js} +2 -2
  9. package/dist/cli/{chunk-IX6XI2RG.js → chunk-3PNIUDTA.js} +2 -2
  10. package/dist/cli/{chunk-JKGYMRX5.js → chunk-676EW5HH.js} +2 -2
  11. package/dist/cli/{chunk-BSINVTTL.js → chunk-7R3PKZXB.js} +7 -7
  12. package/dist/cli/{chunk-3T6VBZCL.js → chunk-B2RA3NMS.js} +2 -2
  13. package/dist/cli/{chunk-CPKCNHRR.js → chunk-BYBOY5UY.js} +5 -5
  14. package/dist/cli/{chunk-3OAR6NVL.js → chunk-GG2V37EH.js} +2 -2
  15. package/dist/cli/{chunk-4IBIPQVB.js → chunk-J6UWUIT2.js} +3 -3
  16. package/dist/cli/{chunk-4TVNJWMA.js → chunk-LRXTF6NZ.js} +178 -18
  17. package/dist/cli/chunk-LRXTF6NZ.js.map +1 -0
  18. package/dist/cli/{chunk-T5TQ4NDT.js → chunk-MDQWQYBS.js} +3 -3
  19. package/dist/cli/{chunk-TH756VLN.js → chunk-NCMC7AMN.js} +240 -191
  20. package/dist/cli/chunk-NCMC7AMN.js.map +1 -0
  21. package/dist/cli/{chunk-ILJOIQ5W.js → chunk-NTF4IE7G.js} +2 -2
  22. package/dist/cli/{chunk-XJ5SRLKK.js → chunk-OYAIE6C7.js} +2 -2
  23. package/dist/cli/{chunk-BSGCXZQN.js → chunk-PT4UDK7Z.js} +2 -2
  24. package/dist/cli/{chunk-QJG7OF27.js → chunk-QLPHVU3W.js} +27 -10
  25. package/dist/cli/chunk-QLPHVU3W.js.map +1 -0
  26. package/dist/cli/{chunk-WRN65TRD.js → chunk-RLQQOIBS.js} +2 -2
  27. package/dist/cli/{chunk-QVC75MR3.js → chunk-U7RHC7D6.js} +2 -2
  28. package/dist/cli/{chunk-IAUOP25G.js → chunk-V6A26HU5.js} +34 -20
  29. package/dist/cli/chunk-V6A26HU5.js.map +1 -0
  30. package/dist/cli/{chunk-D5NFKRGO.js → chunk-VVQTSZWX.js} +2 -2
  31. package/dist/cli/{chunk-7L2WTRNU.js → chunk-X3IHKOYW.js} +2 -2
  32. package/dist/cli/{chunk-S2KIUQKQ.js → chunk-XJIF545V.js} +7 -6
  33. package/dist/cli/{chunk-S2KIUQKQ.js.map → chunk-XJIF545V.js.map} +1 -1
  34. package/dist/cli/{chunk-4MQ3VURH.js → chunk-ZADUQPQP.js} +24 -24
  35. package/dist/cli/chunk-ZADUQPQP.js.map +1 -0
  36. package/dist/cli/{code-4TUTAGO5.js → code-LBRSX6ZI.js} +24 -33
  37. package/dist/cli/code-LBRSX6ZI.js.map +1 -0
  38. package/dist/cli/{commands-KMOZEYCF.js → commands-PCHFC3CL.js} +4 -4
  39. package/dist/cli/{commit-DTFA56VQ.js → commit-HDN6VJBA.js} +3 -3
  40. package/dist/cli/{desktop-7N3MHNBD.js → desktop-RHWSCBHO.js} +17 -17
  41. package/dist/cli/{diff-E5OWTF4C.js → diff-MV5JNUH4.js} +8 -8
  42. package/dist/cli/{doctor-IEJQRJMN.js → doctor-QLO4V4DD.js} +8 -8
  43. package/dist/cli/index.js +32 -32
  44. package/dist/cli/{mcp-PDI2PDLG.js → mcp-JSHFAINM.js} +2 -2
  45. package/dist/cli/{mcp-browse-OSPXOFPZ.js → mcp-browse-ESMKKKYH.js} +2 -2
  46. package/dist/cli/{mcp-inspect-QRFVTHMF.js → mcp-inspect-WSUN36FM.js} +2 -2
  47. package/dist/cli/{prompt-3CDII3UO.js → prompt-5LMDCF4M.js} +3 -3
  48. package/dist/cli/{replay-HYOSRQIV.js → replay-D3ILR2YO.js} +8 -8
  49. package/dist/cli/{run-2ZHADOUP.js → run-6NN3P5JM.js} +13 -13
  50. package/dist/cli/{server-X75PAZG5.js → server-HE7LFAHH.js} +10 -10
  51. package/dist/cli/{sessions-POOZA5CQ.js → sessions-HXDBQM3V.js} +12 -12
  52. package/dist/cli/{setup-YLPFI3OH.js → setup-EP3UPG3F.js} +5 -5
  53. package/dist/cli/{stats-NXJ3TO2D.js → stats-5RC6P5TN.js} +6 -6
  54. package/dist/cli/{version-NXXWE3WN.js → version-AIR25TRN.js} +12 -12
  55. package/dist/index.d.ts +15 -2
  56. package/dist/index.js +328 -89
  57. package/dist/index.js.map +1 -1
  58. package/package.json +2 -2
  59. package/dist/cli/acp-35C4ME6Y.js.map +0 -1
  60. package/dist/cli/chunk-4MQ3VURH.js.map +0 -1
  61. package/dist/cli/chunk-4TVNJWMA.js.map +0 -1
  62. package/dist/cli/chunk-IAUOP25G.js.map +0 -1
  63. package/dist/cli/chunk-J5BYPUB5.js.map +0 -1
  64. package/dist/cli/chunk-QJG7OF27.js.map +0 -1
  65. package/dist/cli/chunk-TH756VLN.js.map +0 -1
  66. package/dist/cli/code-4TUTAGO5.js.map +0 -1
  67. /package/dist/cli/{chat-A6UJDPGV.js.map → chat-6MBLB7MU.js.map} +0 -0
  68. /package/dist/cli/{chunk-UI66BH6D.js.map → chunk-2UXHZAXP.js.map} +0 -0
  69. /package/dist/cli/{chunk-IX6XI2RG.js.map → chunk-3PNIUDTA.js.map} +0 -0
  70. /package/dist/cli/{chunk-JKGYMRX5.js.map → chunk-676EW5HH.js.map} +0 -0
  71. /package/dist/cli/{chunk-BSINVTTL.js.map → chunk-7R3PKZXB.js.map} +0 -0
  72. /package/dist/cli/{chunk-3T6VBZCL.js.map → chunk-B2RA3NMS.js.map} +0 -0
  73. /package/dist/cli/{chunk-CPKCNHRR.js.map → chunk-BYBOY5UY.js.map} +0 -0
  74. /package/dist/cli/{chunk-3OAR6NVL.js.map → chunk-GG2V37EH.js.map} +0 -0
  75. /package/dist/cli/{chunk-4IBIPQVB.js.map → chunk-J6UWUIT2.js.map} +0 -0
  76. /package/dist/cli/{chunk-T5TQ4NDT.js.map → chunk-MDQWQYBS.js.map} +0 -0
  77. /package/dist/cli/{chunk-ILJOIQ5W.js.map → chunk-NTF4IE7G.js.map} +0 -0
  78. /package/dist/cli/{chunk-XJ5SRLKK.js.map → chunk-OYAIE6C7.js.map} +0 -0
  79. /package/dist/cli/{chunk-BSGCXZQN.js.map → chunk-PT4UDK7Z.js.map} +0 -0
  80. /package/dist/cli/{chunk-WRN65TRD.js.map → chunk-RLQQOIBS.js.map} +0 -0
  81. /package/dist/cli/{chunk-QVC75MR3.js.map → chunk-U7RHC7D6.js.map} +0 -0
  82. /package/dist/cli/{chunk-D5NFKRGO.js.map → chunk-VVQTSZWX.js.map} +0 -0
  83. /package/dist/cli/{chunk-7L2WTRNU.js.map → chunk-X3IHKOYW.js.map} +0 -0
  84. /package/dist/cli/{commands-KMOZEYCF.js.map → commands-PCHFC3CL.js.map} +0 -0
  85. /package/dist/cli/{commit-DTFA56VQ.js.map → commit-HDN6VJBA.js.map} +0 -0
  86. /package/dist/cli/{desktop-7N3MHNBD.js.map → desktop-RHWSCBHO.js.map} +0 -0
  87. /package/dist/cli/{diff-E5OWTF4C.js.map → diff-MV5JNUH4.js.map} +0 -0
  88. /package/dist/cli/{doctor-IEJQRJMN.js.map → doctor-QLO4V4DD.js.map} +0 -0
  89. /package/dist/cli/{mcp-PDI2PDLG.js.map → mcp-JSHFAINM.js.map} +0 -0
  90. /package/dist/cli/{mcp-browse-OSPXOFPZ.js.map → mcp-browse-ESMKKKYH.js.map} +0 -0
  91. /package/dist/cli/{mcp-inspect-QRFVTHMF.js.map → mcp-inspect-WSUN36FM.js.map} +0 -0
  92. /package/dist/cli/{prompt-3CDII3UO.js.map → prompt-5LMDCF4M.js.map} +0 -0
  93. /package/dist/cli/{replay-HYOSRQIV.js.map → replay-D3ILR2YO.js.map} +0 -0
  94. /package/dist/cli/{run-2ZHADOUP.js.map → run-6NN3P5JM.js.map} +0 -0
  95. /package/dist/cli/{server-X75PAZG5.js.map → server-HE7LFAHH.js.map} +0 -0
  96. /package/dist/cli/{sessions-POOZA5CQ.js.map → sessions-HXDBQM3V.js.map} +0 -0
  97. /package/dist/cli/{setup-YLPFI3OH.js.map → setup-EP3UPG3F.js.map} +0 -0
  98. /package/dist/cli/{stats-NXJ3TO2D.js.map → stats-5RC6P5TN.js.map} +0 -0
  99. /package/dist/cli/{version-NXXWE3WN.js.map → version-AIR25TRN.js.map} +0 -0
@@ -9,7 +9,7 @@ import {
9
9
  } from "./chunk-JMBMLOBP.js";
10
10
  import {
11
11
  createMcpRuntime
12
- } from "./chunk-CPKCNHRR.js";
12
+ } from "./chunk-BYBOY5UY.js";
13
13
  import {
14
14
  Eventizer,
15
15
  autoResolveVerdict,
@@ -19,7 +19,7 @@ import {
19
19
  import {
20
20
  formatMcpLifecycleEvent,
21
21
  formatMcpSlowToast
22
- } from "./chunk-XJ5SRLKK.js";
22
+ } from "./chunk-OYAIE6C7.js";
23
23
  import {
24
24
  buildTransportFromSpec
25
25
  } from "./chunk-VPMBGAND.js";
@@ -41,6 +41,7 @@ import {
41
41
  looksLikeAbsoluteSystemPath,
42
42
  parseAtQuery,
43
43
  parseEditBlocks,
44
+ parseUnifiedPatch,
44
45
  pathIsUnder,
45
46
  rankPickerCandidates,
46
47
  registerChoiceTool,
@@ -53,19 +54,19 @@ import {
53
54
  toWholeFileEditBlock,
54
55
  walkFilesStream,
55
56
  webFetch
56
- } from "./chunk-4TVNJWMA.js";
57
+ } from "./chunk-LRXTF6NZ.js";
57
58
  import {
58
59
  openTranscriptFile,
59
60
  recordFromLoopEvent,
60
61
  writeRecord
61
- } from "./chunk-T5TQ4NDT.js";
62
+ } from "./chunk-MDQWQYBS.js";
62
63
  import {
63
64
  McpClient
64
65
  } from "./chunk-GALC45Q2.js";
65
66
  import {
66
67
  MemoryStore,
67
68
  effectivePriority
68
- } from "./chunk-QJG7OF27.js";
69
+ } from "./chunk-QLPHVU3W.js";
69
70
  import {
70
71
  wrapper_default
71
72
  } from "./chunk-FEZK652I.js";
@@ -73,7 +74,7 @@ import {
73
74
  KeystrokeProvider,
74
75
  SingleSelect,
75
76
  useKeystroke
76
- } from "./chunk-UI66BH6D.js";
77
+ } from "./chunk-2UXHZAXP.js";
77
78
  import {
78
79
  COLOR,
79
80
  GLYPH,
@@ -81,7 +82,7 @@ import {
81
82
  ThemeProvider,
82
83
  useColor,
83
84
  useThemeTokens
84
- } from "./chunk-D5NFKRGO.js";
85
+ } from "./chunk-VVQTSZWX.js";
85
86
  import {
86
87
  Box_default,
87
88
  Text,
@@ -101,20 +102,20 @@ import {
101
102
  } from "./chunk-2425HK6U.js";
102
103
  import {
103
104
  runDoctorChecks
104
- } from "./chunk-BSINVTTL.js";
105
+ } from "./chunk-7R3PKZXB.js";
105
106
  import {
106
107
  countTokensBounded
107
108
  } from "./chunk-6OWJV3YW.js";
108
109
  import {
109
110
  DeepSeekClient,
110
111
  pickPrimaryBalance
111
- } from "./chunk-BSGCXZQN.js";
112
+ } from "./chunk-PT4UDK7Z.js";
112
113
  import {
113
114
  loadDotenv
114
115
  } from "./chunk-2UQP6H6T.js";
115
116
  import {
116
117
  renderDashboard
117
- } from "./chunk-4IBIPQVB.js";
118
+ } from "./chunk-J6UWUIT2.js";
118
119
  import {
119
120
  MANUAL_UPDATE_COMMANDS,
120
121
  planUpdate
@@ -153,10 +154,11 @@ import {
153
154
  } from "./chunk-4VR6XF4P.js";
154
155
  import {
155
156
  BUILTIN_ALLOWLIST,
157
+ applyMultiEdit,
156
158
  formatCommandResult,
157
159
  pauseGate,
158
160
  runCommand
159
- } from "./chunk-TH756VLN.js";
161
+ } from "./chunk-NCMC7AMN.js";
160
162
  import {
161
163
  PROJECT_MEMORY_FILE,
162
164
  SkillStore,
@@ -171,7 +173,7 @@ import {
171
173
  loadHooks,
172
174
  projectSettingsPath,
173
175
  runHooks
174
- } from "./chunk-IX6XI2RG.js";
176
+ } from "./chunk-3PNIUDTA.js";
175
177
  import {
176
178
  deleteSession,
177
179
  detectGitBranch,
@@ -194,12 +196,12 @@ import {
194
196
  appendUsage,
195
197
  defaultUsageLogPath,
196
198
  readUsageLog
197
- } from "./chunk-QVC75MR3.js";
199
+ } from "./chunk-U7RHC7D6.js";
198
200
  import {
199
201
  DEEPSEEK_CONTEXT_TOKENS,
200
202
  DEFAULT_CONTEXT_TOKENS,
201
203
  pricingFor
202
- } from "./chunk-ILJOIQ5W.js";
204
+ } from "./chunk-NTF4IE7G.js";
203
205
  import {
204
206
  getLanguage,
205
207
  getSupportedLanguages,
@@ -208,7 +210,7 @@ import {
208
210
  setLanguage,
209
211
  t,
210
212
  tObj
211
- } from "./chunk-IAUOP25G.js";
213
+ } from "./chunk-V6A26HU5.js";
212
214
  import {
213
215
  CARD,
214
216
  FG,
@@ -261,7 +263,7 @@ import {
261
263
  webSearchEndpoint,
262
264
  webSearchEngine,
263
265
  writeConfig
264
- } from "./chunk-4MQ3VURH.js";
266
+ } from "./chunk-ZADUQPQP.js";
265
267
  import {
266
268
  VERSION,
267
269
  compareVersions,
@@ -44717,9 +44719,9 @@ var QQChannel = class {
44717
44719
  try {
44718
44720
  await bot.start();
44719
44721
  const readyOrError = await Promise.race([
44720
- new Promise((resolve4) => bot.once("online", () => resolve4("ready"))),
44721
- new Promise((resolve4) => bot.once("bot_error", () => resolve4("error"))),
44722
- new Promise((resolve4) => setTimeout(() => resolve4("timeout"), 15e3))
44722
+ new Promise((resolve6) => bot.once("online", () => resolve6("ready"))),
44723
+ new Promise((resolve6) => bot.once("bot_error", () => resolve6("error"))),
44724
+ new Promise((resolve6) => setTimeout(() => resolve6("timeout"), 15e3))
44723
44725
  ]);
44724
44726
  if (readyOrError === "error") {
44725
44727
  throw new Error("QQ bot authentication failed - check your appId and appSecret");
@@ -44760,7 +44762,7 @@ var QQChannel = class {
44760
44762
 
44761
44763
  // src/cli/ui/App.tsx
44762
44764
  import { statSync as statSync2 } from "fs";
44763
- import { relative as relative2, resolve as resolve3 } from "path";
44765
+ import { resolve as resolve4 } from "path";
44764
44766
  var import_react90 = __toESM(require_react(), 1);
44765
44767
 
44766
44768
  // src/code/pending-edits.ts
@@ -44896,8 +44898,8 @@ function useQQChannel({
44896
44898
  if (isRawModeSupported) setRawMode(false);
44897
44899
  const rl = createInterface({ input: process.stdin, output: process.stdout });
44898
44900
  try {
44899
- const answer = await new Promise((resolve4) => {
44900
- rl.question(prompt, resolve4);
44901
+ const answer = await new Promise((resolve6) => {
44902
+ rl.question(prompt, resolve6);
44901
44903
  });
44902
44904
  return answer.trim() || fallback || "";
44903
44905
  } finally {
@@ -45714,14 +45716,14 @@ async function openInExternalEditor(initial2) {
45714
45716
  }
45715
45717
  }
45716
45718
  function spawnEditor(editor, path) {
45717
- return new Promise((resolve4, reject) => {
45719
+ return new Promise((resolve6, reject) => {
45718
45720
  const child = spawn(`${editor} "${path}"`, {
45719
45721
  shell: true,
45720
45722
  stdio: "inherit"
45721
45723
  });
45722
45724
  child.on("error", reject);
45723
45725
  child.on("exit", (code) => {
45724
- if (code === 0 || code === null) resolve4();
45726
+ if (code === 0 || code === null) resolve6();
45725
45727
  else reject(new Error(String(code)));
45726
45728
  });
45727
45729
  });
@@ -45734,55 +45736,8 @@ function normalizeEditorBuffer(s) {
45734
45736
 
45735
45737
  // src/cli/ui/BootSplash.tsx
45736
45738
  var import_react2 = __toESM(require_react(), 1);
45737
- var CARBON_CODE_LOGO = [
45738
- "CARBON CODE",
45739
- " \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557",
45740
- "\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D",
45741
- "\u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2557 ",
45742
- "\u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u255D ",
45743
- "\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557",
45744
- " \u255A\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D"
45745
- ];
45746
- var WHALE_LINES = [
45747
- " _____:_____",
45748
- " __.-'' ''-.__",
45749
- " ,-' \u2591\u2591\u2592\u2592\u2592\u2592\u2592\u2592\u2592\u2592\u2592\u2592\u2592\u2592\u2591\u2591 '-.",
45750
- " ,' \u2591\u2592\u2592\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2592\u2592\u2591 '\\",
45751
- " / \u2591\u2592\u2593\u2593\u2593\u2593\u25C9\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2592\u2591 '\\___",
45752
- " | \u2591\u2592\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2592\u2591 '\\\\__",
45753
- " | \u2591\u2592\u2593\u2593\u2593\u2593\u2593\u2593 \u203F\u203F\u203F \u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2592\u2591 \\\\__\\",
45754
- " | \u2591\u2592\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2592\u2591 //__/",
45755
- " \\ \u2591\u2592\u2592\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2592\u2592\u2591 //",
45756
- " '\\. \u2591\u2591\u2592\u2592\u2592\u2592\u2592\u2592\u2592\u2592\u2592\u2592\u2592\u2592\u2592\u2592\u2592\u2591\u2591 __,/'",
45757
- " '-..___ ___..-'",
45758
- " '''---..........---'''"
45759
- ];
45760
- var SPOUT_FRAMES = [
45761
- [" ", " ", " "],
45762
- [" ", " ", " ."],
45763
- [" ", " .", " :"],
45764
- [" .", " :", " :"],
45765
- [" . ' .", " :", " :"],
45766
- [" ' . '", " '", " :"],
45767
- [" . .", " '", " "]
45768
- ];
45769
- var WAVE_SOURCE = "~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^";
45770
- var WAVE_WIDTH = 44;
45771
- var FRAME_MS = 200;
45772
45739
  function BootSplash() {
45773
- const [frame, setFrame] = (0, import_react2.useState)(0);
45774
- (0, import_react2.useEffect)(() => {
45775
- const t2 = setInterval(() => setFrame((f) => f + 1), FRAME_MS);
45776
- return () => clearInterval(t2);
45777
- }, []);
45778
- const spout = SPOUT_FRAMES[frame % SPOUT_FRAMES.length];
45779
- const waveOffset = frame % 4;
45780
- const wave = WAVE_SOURCE.slice(waveOffset, waveOffset + WAVE_WIDTH);
45781
- const dots = ".".repeat(frame % 4 + 1);
45782
- return /* @__PURE__ */ import_react2.default.createElement(Box_default, { flexDirection: "column", alignItems: "center", marginY: 1 }, /* @__PURE__ */ import_react2.default.createElement(Box_default, { flexDirection: "column", alignItems: "flex-start", marginBottom: 1 }, CARBON_CODE_LOGO.map((line) => /* @__PURE__ */ import_react2.default.createElement(Text, { key: line, color: TONE.brand, bold: true }, line))), /* @__PURE__ */ import_react2.default.createElement(Box_default, { flexDirection: "column", alignItems: "flex-start" }, spout.map((line, i) => (
45783
- // biome-ignore lint/suspicious/noArrayIndexKey: fixed-length spout column, position is the identity
45784
- /* @__PURE__ */ import_react2.default.createElement(Text, { key: i, color: TONE.accent }, line.length > 0 ? line : " ")
45785
- )), WHALE_LINES.map((line) => /* @__PURE__ */ import_react2.default.createElement(Text, { key: line, color: TONE.brand, bold: true }, line)), /* @__PURE__ */ import_react2.default.createElement(Text, { color: FG.faint }, wave)), /* @__PURE__ */ import_react2.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react2.default.createElement(Text, { color: FG.meta }, `${t("common.loading")}${dots}`)));
45740
+ return /* @__PURE__ */ import_react2.default.createElement(Box_default, { flexDirection: "row", gap: 1, marginY: 1 }, /* @__PURE__ */ import_react2.default.createElement(Text, { bold: true, color: TONE.brand }, "Carbon Code"), /* @__PURE__ */ import_react2.default.createElement(Text, { color: FG.meta }, t("common.loading")));
45786
45741
  }
45787
45742
 
45788
45743
  // src/cli/ui/CheckpointPicker.tsx
@@ -46086,7 +46041,7 @@ function ChoiceConfirmInner({ question, options: options2, allowCustom, onChoose
46086
46041
  var ChoiceConfirm = import_react7.default.memo(ChoiceConfirmInner);
46087
46042
 
46088
46043
  // src/cli/ui/ComposerArea.tsx
46089
- var import_react23 = __toESM(require_react(), 1);
46044
+ var import_react22 = __toESM(require_react(), 1);
46090
46045
 
46091
46046
  // src/cli/ui/AtMentionSuggestions.tsx
46092
46047
  var import_react8 = __toESM(require_react(), 1);
@@ -46710,7 +46665,7 @@ function PromptInput({
46710
46665
  const { line: cursorLine, col: cursorCol } = lineAndColumn(value, cursor);
46711
46666
  const renderItems = collapseLinesForDisplay(lines, cursorLine);
46712
46667
  const showHugeBufferHints = lines.length > 20;
46713
- return /* @__PURE__ */ import_react9.default.createElement(Box_default, { flexDirection: "column", borderStyle: "round", borderColor: accentColor, paddingX: 1 }, (() => {
46668
+ return /* @__PURE__ */ import_react9.default.createElement(Box_default, { flexDirection: "column", paddingX: 1 }, (() => {
46714
46669
  const rows = [];
46715
46670
  let firstRowEmitted = false;
46716
46671
  for (let renderIdx = 0; renderIdx < renderItems.length; renderIdx++) {
@@ -46823,18 +46778,7 @@ function PromptInput({
46823
46778
  }
46824
46779
  }
46825
46780
  return rows;
46826
- })(), showHugeBufferHints && !disabled ? /* @__PURE__ */ import_react9.default.createElement(Box_default, null, /* @__PURE__ */ import_react9.default.createElement(Text, { color: FG.faint }, ` [${lines.length} lines \xB7 PgUp/PgDn jump \xB7 Ctrl+U clear \xB7 Ctrl+W del word]`)) : null, !disabled ? /* @__PURE__ */ import_react9.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react9.default.createElement(HintRow, null)) : /* @__PURE__ */ import_react9.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react9.default.createElement(Text, { color: FG.faint }, " esc to stop")));
46827
- }
46828
- function HintRow() {
46829
- const items = [
46830
- { key: "\u23CE", tKey: "composer.hintSend" },
46831
- { key: "\u21E7\u23CE", tKey: "composer.hintNewline" },
46832
- { key: "^U", tKey: "composer.hintClear" },
46833
- { key: "^P/^N", tKey: "composer.hintHistory" },
46834
- { key: "esc", tKey: "composer.hintAbort" },
46835
- { key: "^C", tKey: "composer.hintQuit" }
46836
- ];
46837
- return /* @__PURE__ */ import_react9.default.createElement(Box_default, { flexDirection: "row" }, /* @__PURE__ */ import_react9.default.createElement(Text, null, " "), items.map((item, i) => /* @__PURE__ */ import_react9.default.createElement(import_react9.default.Fragment, { key: item.key }, i > 0 && /* @__PURE__ */ import_react9.default.createElement(Text, { color: FG.faint }, " \xB7 "), /* @__PURE__ */ import_react9.default.createElement(Text, { color: FG.meta }, item.key), /* @__PURE__ */ import_react9.default.createElement(Text, { color: FG.faint }, ` ${t(item.tKey)}`))));
46781
+ })(), showHugeBufferHints && !disabled ? /* @__PURE__ */ import_react9.default.createElement(Box_default, null, /* @__PURE__ */ import_react9.default.createElement(Text, { color: FG.faint }, ` [${lines.length} lines \xB7 PgUp/PgDn jump \xB7 Ctrl+U clear \xB7 Ctrl+W del word]`)) : null, disabled ? /* @__PURE__ */ import_react9.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react9.default.createElement(Text, { color: FG.faint }, " esc to stop")) : null);
46838
46782
  }
46839
46783
  function splitLineByPastes(line) {
46840
46784
  const out = [];
@@ -47223,33 +47167,17 @@ function truncateCells(value, maxCells) {
47223
47167
  }
47224
47168
 
47225
47169
  // src/cli/ui/layout/LiveRows.tsx
47226
- var import_react18 = __toESM(require_react(), 1);
47227
-
47228
- // src/cli/ui/char-bar.tsx
47229
- var import_react12 = __toESM(require_react(), 1);
47230
- function CharBar({
47231
- pct,
47232
- width = 24,
47233
- color = COLOR.primary,
47234
- emptyColor,
47235
- showLabel = true,
47236
- label
47237
- }) {
47238
- const total = Math.max(4, width);
47239
- const clamped = Math.max(0, Math.min(100, Number.isFinite(pct) ? pct : 0));
47240
- const filled = Math.round(total * clamped / 100);
47241
- return /* @__PURE__ */ import_react12.default.createElement(Box_default, null, /* @__PURE__ */ import_react12.default.createElement(Text, { color }, GLYPH.block.repeat(filled)), /* @__PURE__ */ import_react12.default.createElement(Text, { color: emptyColor ?? COLOR.info, dimColor: true }, GLYPH.shade1.repeat(total - filled)), showLabel ? /* @__PURE__ */ import_react12.default.createElement(Text, { dimColor: true }, ` ${label ?? `${Math.round(clamped)}%`}`) : null);
47242
- }
47170
+ var import_react17 = __toESM(require_react(), 1);
47243
47171
 
47244
47172
  // src/cli/ui/primitives/Card.tsx
47245
- var import_react13 = __toESM(require_react(), 1);
47246
- var ActiveCardContext = import_react13.default.createContext(true);
47173
+ var import_react12 = __toESM(require_react(), 1);
47174
+ var ActiveCardContext = import_react12.default.createContext(true);
47247
47175
  function Card({ children }) {
47248
- return /* @__PURE__ */ import_react13.default.createElement(Box_default, { flexDirection: "column", marginTop: 1, width: "100%" }, children);
47176
+ return /* @__PURE__ */ import_react12.default.createElement(Box_default, { flexDirection: "column", marginTop: 1, width: "100%" }, children);
47249
47177
  }
47250
47178
 
47251
47179
  // src/cli/ui/primitives/CardHeader.tsx
47252
- var import_react14 = __toESM(require_react(), 1);
47180
+ var import_react13 = __toESM(require_react(), 1);
47253
47181
  function CardHeader({
47254
47182
  glyph,
47255
47183
  tone,
@@ -47258,36 +47186,24 @@ function CardHeader({
47258
47186
  meta,
47259
47187
  right
47260
47188
  }) {
47261
- const active = (0, import_react14.useContext)(ActiveCardContext);
47189
+ const active = (0, import_react13.useContext)(ActiveCardContext);
47262
47190
  const visibleMeta = active ? meta : meta?.filter((item) => typeof item !== "string");
47263
- return /* @__PURE__ */ import_react14.default.createElement(Box_default, { flexDirection: "row", gap: 1 }, /* @__PURE__ */ import_react14.default.createElement(Text, { color: tone }, glyph), /* @__PURE__ */ import_react14.default.createElement(Text, { bold: true, color: tone }, title2), subtitle ? /* @__PURE__ */ import_react14.default.createElement(Text, { color: FG.body }, subtitle) : null, visibleMeta?.map((item, i) => {
47191
+ return /* @__PURE__ */ import_react13.default.createElement(Box_default, { flexDirection: "row", gap: 1 }, /* @__PURE__ */ import_react13.default.createElement(Text, { color: tone }, glyph), /* @__PURE__ */ import_react13.default.createElement(Text, { bold: true, color: tone }, title2), subtitle ? /* @__PURE__ */ import_react13.default.createElement(Text, { color: FG.body }, subtitle) : null, visibleMeta?.map((item, i) => {
47264
47192
  const isStr = typeof item === "string";
47265
47193
  const text = isStr ? item : item.text;
47266
47194
  const color = isStr ? FG.faint : item.color;
47267
47195
  return (
47268
47196
  // biome-ignore lint/suspicious/noArrayIndexKey: meta items are positional
47269
- /* @__PURE__ */ import_react14.default.createElement(import_react14.default.Fragment, { key: `m-${i}` }, /* @__PURE__ */ import_react14.default.createElement(Text, { color: FG.faint }, "\xB7"), /* @__PURE__ */ import_react14.default.createElement(Text, { color }, text))
47197
+ /* @__PURE__ */ import_react13.default.createElement(import_react13.default.Fragment, { key: `m-${i}` }, /* @__PURE__ */ import_react13.default.createElement(Text, { color: FG.faint }, "\xB7"), /* @__PURE__ */ import_react13.default.createElement(Text, { color }, text))
47270
47198
  );
47271
47199
  }), active ? right : null);
47272
47200
  }
47273
47201
 
47274
47202
  // src/cli/ui/primitives/Pill.tsx
47275
- var import_react15 = __toESM(require_react(), 1);
47203
+ var import_react14 = __toESM(require_react(), 1);
47276
47204
  function Pill({ label, bg, fg, bold = true }) {
47277
- return /* @__PURE__ */ import_react15.default.createElement(Text, { backgroundColor: bg, color: fg, bold }, ` ${label} `);
47278
- }
47279
- var PILL_SECTION = {
47280
- reason: { bg: "#2a1f3d", fg: "#d2a8ff" },
47281
- output: { bg: "#0d1d2e", fg: "#79c0ff" },
47282
- tool: { bg: "#0f2230", fg: "#79c0ff" },
47283
- shell: { bg: "#0f2230", fg: "#79c0ff" },
47284
- task: { bg: "#0d1d2e", fg: "#79c0ff" },
47285
- taskDone: { bg: "#102815", fg: "#7ee787" },
47286
- taskFailed: { bg: "#2c1416", fg: "#ff8b81" },
47287
- plan: { bg: "#2a1f3d", fg: "#d2a8ff" },
47288
- user: { bg: "#1a2433", fg: "#79c0ff" },
47289
- empty: { bg: "#11141a", fg: "#6e7681" }
47290
- };
47205
+ return /* @__PURE__ */ import_react14.default.createElement(Text, { backgroundColor: bg, color: fg, bold }, ` ${label} `);
47206
+ }
47291
47207
  var PILL_PATH = { bg: "#11141a", fg: "#8b949e" };
47292
47208
  var PILL_MODEL = {
47293
47209
  flash: { bg: "#11141a", fg: "#79c0ff" },
@@ -47305,18 +47221,18 @@ function modelBadgeFor(model2) {
47305
47221
  }
47306
47222
 
47307
47223
  // src/cli/ui/primitives/Spinner.tsx
47308
- var import_react17 = __toESM(require_react(), 1);
47224
+ var import_react16 = __toESM(require_react(), 1);
47309
47225
 
47310
47226
  // src/cli/ui/ticker.tsx
47311
- var import_react16 = __toESM(require_react(), 1);
47227
+ var import_react15 = __toESM(require_react(), 1);
47312
47228
  var FAST_TICK_MS = 120;
47313
47229
  var SLOW_TICK_MS = 1e3;
47314
- var TickerActiveContext = (0, import_react16.createContext)(true);
47230
+ var TickerActiveContext = (0, import_react15.createContext)(true);
47315
47231
  function TickerProvider({ children, disabled }) {
47316
- return /* @__PURE__ */ import_react16.default.createElement(TickerActiveContext.Provider, { value: !disabled }, children);
47232
+ return /* @__PURE__ */ import_react15.default.createElement(TickerActiveContext.Provider, { value: !disabled }, children);
47317
47233
  }
47318
47234
  function useTickerActive() {
47319
- return (0, import_react16.useContext)(TickerActiveContext);
47235
+ return (0, import_react15.useContext)(TickerActiveContext);
47320
47236
  }
47321
47237
  function useTick() {
47322
47238
  const isActive = useTickerActive();
@@ -47327,7 +47243,7 @@ function useSlowTick() {
47327
47243
  return useAnimation({ interval: SLOW_TICK_MS, isActive }).frame;
47328
47244
  }
47329
47245
  function useElapsedSeconds() {
47330
- const [start] = (0, import_react16.useState)(() => Date.now());
47246
+ const [start] = (0, import_react15.useState)(() => Date.now());
47331
47247
  useSlowTick();
47332
47248
  return Math.floor((Date.now() - start) / 1e3);
47333
47249
  }
@@ -47341,7 +47257,7 @@ function Spinner({ kind = "circle", color, bold }) {
47341
47257
  const frames = FRAMES[kind];
47342
47258
  const tick = useTick();
47343
47259
  const frame = tick % frames.length;
47344
- return /* @__PURE__ */ import_react17.default.createElement(Text, { bold, color }, frames[frame]);
47260
+ return /* @__PURE__ */ import_react16.default.createElement(Text, { bold, color }, frames[frame]);
47345
47261
  }
47346
47262
 
47347
47263
  // src/cli/ui/layout/LiveRows.tsx
@@ -47349,51 +47265,49 @@ var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834"
47349
47265
  function ThinkingRow({ text }) {
47350
47266
  const elapsed = useElapsedSeconds();
47351
47267
  const { fg, tone } = useThemeTokens();
47352
- return /* @__PURE__ */ import_react18.default.createElement(Box_default, { marginY: 1, paddingX: 1, gap: 1 }, /* @__PURE__ */ import_react18.default.createElement(Spinner, { kind: "circle", color: TONE.accent }), /* @__PURE__ */ import_react18.default.createElement(Text, { italic: true, color: FG.sub }, text), /* @__PURE__ */ import_react18.default.createElement(Text, { color: FG.faint }, `${elapsed}s`));
47268
+ return /* @__PURE__ */ import_react17.default.createElement(Box_default, { marginY: 1, paddingX: 1, gap: 1 }, /* @__PURE__ */ import_react17.default.createElement(Spinner, { kind: "circle", color: TONE.accent }), /* @__PURE__ */ import_react17.default.createElement(Text, { italic: true, color: FG.sub }, text), /* @__PURE__ */ import_react17.default.createElement(Text, { color: FG.faint }, `${elapsed}s`));
47353
47269
  }
47354
47270
  function ModeStatusBar({
47355
47271
  editMode,
47356
47272
  pendingCount,
47357
47273
  flash,
47358
47274
  planMode,
47359
- undoArmed,
47360
47275
  jobs: jobs2
47361
47276
  }) {
47362
47277
  useSlowTick();
47363
47278
  const running = jobs2?.runningCount() ?? 0;
47364
- const jobsTag = running > 0 ? /* @__PURE__ */ import_react18.default.createElement(Text, { color: TONE.warn, bold: true }, ` \xB7 \u23F5 ${running} job${running === 1 ? "" : "s"}`) : null;
47279
+ const jobsTag = running > 0 ? /* @__PURE__ */ import_react17.default.createElement(Text, { color: TONE.warn, bold: true }, ` \xB7 \u23F5 ${running} job${running === 1 ? "" : "s"}`) : null;
47365
47280
  if (planMode) {
47366
- return /* @__PURE__ */ import_react18.default.createElement(ModeBarFrame, null, /* @__PURE__ */ import_react18.default.createElement(ModePill, { label: t("editMode.plan"), color: TONE.err, flash }), /* @__PURE__ */ import_react18.default.createElement(Text, { color: FG.faint }, t("editMode.writesGated")), jobsTag);
47281
+ return /* @__PURE__ */ import_react17.default.createElement(ModeBarFrame, null, /* @__PURE__ */ import_react17.default.createElement(ModePill, { label: t("editMode.plan"), color: TONE.err, flash }), /* @__PURE__ */ import_react17.default.createElement(Text, { color: FG.faint }, t("editMode.writesGated")), jobsTag);
47367
47282
  }
47368
47283
  const label = editMode === "yolo" ? t("editMode.yolo") : editMode === "auto" ? t("editMode.auto") : t("editMode.review");
47369
47284
  const pillColor = editMode === "yolo" ? TONE.err : editMode === "auto" ? TONE.accent : TONE.brand;
47370
47285
  const mid = editMode === "yolo" ? t("editMode.editsShellAuto") : editMode === "auto" ? t("editMode.editsLandNow") : pendingCount > 0 ? t("editMode.queuedApplyDiscard", { count: pendingCount }) : t("editMode.editsQueued");
47371
- return /* @__PURE__ */ import_react18.default.createElement(ModeBarFrame, null, /* @__PURE__ */ import_react18.default.createElement(ModePill, { label, color: pillColor, flash }), /* @__PURE__ */ import_react18.default.createElement(Text, { color: FG.faint }, t("editMode.shiftTabFlip", { mid })), jobsTag);
47286
+ if (pendingCount === 0 && running === 0) return null;
47287
+ return /* @__PURE__ */ import_react17.default.createElement(ModeBarFrame, null, /* @__PURE__ */ import_react17.default.createElement(ModePill, { label, color: pillColor, flash }), /* @__PURE__ */ import_react17.default.createElement(Text, { color: FG.faint }, t("editMode.shiftTabFlip", { mid })), jobsTag);
47372
47288
  }
47373
47289
  function ModeBarFrame({ children }) {
47374
- return /* @__PURE__ */ import_react18.default.createElement(Box_default, { paddingX: 1 }, children);
47290
+ return /* @__PURE__ */ import_react17.default.createElement(Box_default, { paddingX: 1 }, children);
47375
47291
  }
47376
47292
  function ModePill({
47377
47293
  label,
47378
47294
  color,
47379
47295
  flash
47380
47296
  }) {
47381
- return /* @__PURE__ */ import_react18.default.createElement(Text, { color, bold: true, inverse: flash }, `[${label}]`);
47297
+ return /* @__PURE__ */ import_react17.default.createElement(Text, { color, bold: true, inverse: flash }, `[${label}]`);
47382
47298
  }
47383
47299
  function UndoBanner({
47384
47300
  banner
47385
47301
  }) {
47386
47302
  useTick();
47387
- const totalMs = 5e3;
47388
47303
  const paused = banner.pausedRemainingMs !== null;
47389
47304
  const remainingMs = paused ? banner.pausedRemainingMs ?? 0 : Math.max(0, banner.expiresAt - Date.now());
47390
47305
  const remainingSec = Math.ceil(remainingMs / 1e3);
47391
47306
  const ok = banner.results.filter((r) => r.status === "applied" || r.status === "created").length;
47392
47307
  const total = banner.results.length;
47393
47308
  const urgent = !paused && remainingSec <= 1;
47394
- const pct = remainingMs / totalMs * 100;
47395
47309
  const tone = paused ? TONE.warn : urgent ? TONE.err : TONE.accent;
47396
- return /* @__PURE__ */ import_react18.default.createElement(Box_default, { marginY: 1, paddingX: 1 }, /* @__PURE__ */ import_react18.default.createElement(Text, { backgroundColor: TONE.accent, color: "black", bold: true }, ` \u2713 AUTO-APPLIED ${ok}/${total} `), /* @__PURE__ */ import_react18.default.createElement(Text, { color: FG.faint }, " press "), /* @__PURE__ */ import_react18.default.createElement(Text, { backgroundColor: TONE.brand, color: "black", bold: true }, " u "), /* @__PURE__ */ import_react18.default.createElement(Text, { color: FG.faint }, paused ? " to undo \xB7 " : " to undo \xB7 "), /* @__PURE__ */ import_react18.default.createElement(Text, { backgroundColor: paused ? TONE.warn : FG.faint, color: "black", bold: true }, " space "), /* @__PURE__ */ import_react18.default.createElement(Text, { color: FG.faint }, paused ? " to resume " : " to pause "), /* @__PURE__ */ import_react18.default.createElement(CharBar, { pct, width: 20, color: tone, showLabel: false }), /* @__PURE__ */ import_react18.default.createElement(Text, { color: FG.faint }, " "), /* @__PURE__ */ import_react18.default.createElement(Text, { color: tone, bold: urgent || paused }, paused ? `${remainingSec}s \xB7 paused` : `${remainingSec}s`));
47310
+ return /* @__PURE__ */ import_react17.default.createElement(Box_default, { paddingX: 1 }, /* @__PURE__ */ import_react17.default.createElement(Text, { color: TONE.accent, bold: true }, `\u2713 ${t("editMode.undoApplied", { ok, total })}`), /* @__PURE__ */ import_react17.default.createElement(Text, { color: FG.faint }, ` \xB7 ${t(paused ? "editMode.undoPausedHint" : "editMode.undoHint")}`), /* @__PURE__ */ import_react17.default.createElement(Text, { color: FG.faint }, " \xB7 "), /* @__PURE__ */ import_react17.default.createElement(Text, { color: tone, bold: urgent || paused }, paused ? `${remainingSec}s \xB7 paused` : `${remainingSec}s`));
47397
47311
  }
47398
47312
  function subagentPhaseLabel(phase, iter, elapsedMs) {
47399
47313
  if (phase === "summarising") return "summarising findings\u2026";
@@ -47408,7 +47322,7 @@ function SubagentRow({ activity }) {
47408
47322
  const last = activity.lastInner;
47409
47323
  const subtitle = activity.skillName ?? truncate(activity.task, 48);
47410
47324
  const modelBadge = activity.model ? modelBadgeFor(activity.model) : null;
47411
- return /* @__PURE__ */ import_react18.default.createElement(Card, { tone: CARD.subagent.color }, /* @__PURE__ */ import_react18.default.createElement(
47325
+ return /* @__PURE__ */ import_react17.default.createElement(Card, { tone: CARD.subagent.color }, /* @__PURE__ */ import_react17.default.createElement(
47412
47326
  CardHeader,
47413
47327
  {
47414
47328
  glyph: "\u25CF",
@@ -47416,9 +47330,9 @@ function SubagentRow({ activity }) {
47416
47330
  title: "subagent",
47417
47331
  subtitle,
47418
47332
  meta: [`iter ${activity.iter}`, `${seconds}s`],
47419
- right: /* @__PURE__ */ import_react18.default.createElement(import_react18.default.Fragment, null, modelBadge ? /* @__PURE__ */ import_react18.default.createElement(Pill, { label: modelBadge.label, ...PILL_MODEL[modelBadge.kind], bold: false }) : null, /* @__PURE__ */ import_react18.default.createElement(Spinner, { kind: "braille", color: CARD.subagent.color }))
47333
+ right: /* @__PURE__ */ import_react17.default.createElement(import_react17.default.Fragment, null, modelBadge ? /* @__PURE__ */ import_react17.default.createElement(Pill, { label: modelBadge.label, ...PILL_MODEL[modelBadge.kind], bold: false }) : null, /* @__PURE__ */ import_react17.default.createElement(Spinner, { kind: "braille", color: CARD.subagent.color }))
47420
47334
  }
47421
- ), /* @__PURE__ */ import_react18.default.createElement(Text, { color: FG.faint }, "task ", /* @__PURE__ */ import_react18.default.createElement(Text, { color: FG.sub }, activity.task)), /* @__PURE__ */ import_react18.default.createElement(Text, { color: FG.faint }, "last ", last ? /* @__PURE__ */ import_react18.default.createElement(import_react18.default.Fragment, null, /* @__PURE__ */ import_react18.default.createElement(Text, { color: last.color }, `${last.glyph} `), /* @__PURE__ */ import_react18.default.createElement(Text, { color: FG.body }, last.label), last.meta ? /* @__PURE__ */ import_react18.default.createElement(Text, { color: FG.faint }, ` ${last.meta}`) : null) : /* @__PURE__ */ import_react18.default.createElement(Text, { color: FG.faint }, t("editMode.queuedDots"))), /* @__PURE__ */ import_react18.default.createElement(Text, { color: TONE.brand }, "\u25B6 ", phase));
47335
+ ), /* @__PURE__ */ import_react17.default.createElement(Text, { color: FG.faint }, "task ", /* @__PURE__ */ import_react17.default.createElement(Text, { color: FG.sub }, activity.task)), /* @__PURE__ */ import_react17.default.createElement(Text, { color: FG.faint }, "last ", last ? /* @__PURE__ */ import_react17.default.createElement(import_react17.default.Fragment, null, /* @__PURE__ */ import_react17.default.createElement(Text, { color: last.color }, `${last.glyph} `), /* @__PURE__ */ import_react17.default.createElement(Text, { color: FG.body }, last.label), last.meta ? /* @__PURE__ */ import_react17.default.createElement(Text, { color: FG.faint }, ` ${last.meta}`) : null) : /* @__PURE__ */ import_react17.default.createElement(Text, { color: FG.faint }, t("editMode.queuedDots"))), /* @__PURE__ */ import_react17.default.createElement(Text, { color: TONE.brand }, "\u25B6 ", phase));
47422
47336
  }
47423
47337
  function SubagentLiveStack({
47424
47338
  activities,
@@ -47426,22 +47340,22 @@ function SubagentLiveStack({
47426
47340
  }) {
47427
47341
  const tick = useTick();
47428
47342
  if (activities.length === 0) return null;
47429
- if (activities.length === 1) return /* @__PURE__ */ import_react18.default.createElement(SubagentRow, { activity: activities[0] });
47343
+ if (activities.length === 1) return /* @__PURE__ */ import_react17.default.createElement(SubagentRow, { activity: activities[0] });
47430
47344
  const visible = activities.slice(0, max);
47431
47345
  const overflow = activities.length - visible.length;
47432
47346
  const summarising = activities.filter((a) => a.phase === "summarising").length;
47433
47347
  const metaParts = [`${activities.length} running`];
47434
47348
  if (summarising > 0) metaParts.push(`${summarising} summarising`);
47435
- return /* @__PURE__ */ import_react18.default.createElement(Card, { tone: CARD.subagent.color }, /* @__PURE__ */ import_react18.default.createElement(
47349
+ return /* @__PURE__ */ import_react17.default.createElement(Card, { tone: CARD.subagent.color }, /* @__PURE__ */ import_react17.default.createElement(
47436
47350
  CardHeader,
47437
47351
  {
47438
47352
  glyph: "\u25CF",
47439
47353
  tone: CARD.subagent.color,
47440
47354
  title: "subagents",
47441
47355
  subtitle: metaParts.join(" \xB7 "),
47442
- right: /* @__PURE__ */ import_react18.default.createElement(Spinner, { kind: "braille", color: CARD.subagent.color })
47356
+ right: /* @__PURE__ */ import_react17.default.createElement(Spinner, { kind: "braille", color: CARD.subagent.color })
47443
47357
  }
47444
- ), visible.map((a, i) => /* @__PURE__ */ import_react18.default.createElement(CompactSubagentLine, { key: a.runId, activity: a, tick, index: i })), overflow > 0 ? /* @__PURE__ */ import_react18.default.createElement(Text, { color: FG.faint }, ` +${overflow} more running\u2026`) : null);
47358
+ ), visible.map((a, i) => /* @__PURE__ */ import_react17.default.createElement(CompactSubagentLine, { key: a.runId, activity: a, tick, index: i })), overflow > 0 ? /* @__PURE__ */ import_react17.default.createElement(Text, { color: FG.faint }, ` +${overflow} more running\u2026`) : null);
47445
47359
  }
47446
47360
  function CompactSubagentLine({
47447
47361
  activity,
@@ -47456,7 +47370,7 @@ function CompactSubagentLine({
47456
47370
  const title2 = activity.skillName ?? truncate(activity.task, 28);
47457
47371
  const titlePadded = title2.padEnd(28);
47458
47372
  const last = activity.lastInner;
47459
- return /* @__PURE__ */ import_react18.default.createElement(Box_default, { flexDirection: "row" }, /* @__PURE__ */ import_react18.default.createElement(Text, { color: glyphColor, bold: true }, ` ${glyph} `), /* @__PURE__ */ import_react18.default.createElement(Text, { color: FG.body }, titlePadded), /* @__PURE__ */ import_react18.default.createElement(Text, { color: FG.faint }, ` iter ${String(activity.iter).padStart(2)} \xB7 ${seconds}s \xB7 `), last ? /* @__PURE__ */ import_react18.default.createElement(import_react18.default.Fragment, null, /* @__PURE__ */ import_react18.default.createElement(Text, { color: last.color }, `${last.glyph} `), /* @__PURE__ */ import_react18.default.createElement(Text, { color: FG.body }, truncate(last.label, 18)), last.meta ? /* @__PURE__ */ import_react18.default.createElement(Text, { color: FG.faint }, ` ${last.meta}`) : null) : /* @__PURE__ */ import_react18.default.createElement(Text, { color: FG.faint }, t("editMode.queuedDots")));
47373
+ return /* @__PURE__ */ import_react17.default.createElement(Box_default, { flexDirection: "row" }, /* @__PURE__ */ import_react17.default.createElement(Text, { color: glyphColor, bold: true }, ` ${glyph} `), /* @__PURE__ */ import_react17.default.createElement(Text, { color: FG.body }, titlePadded), /* @__PURE__ */ import_react17.default.createElement(Text, { color: FG.faint }, ` iter ${String(activity.iter).padStart(2)} \xB7 ${seconds}s \xB7 `), last ? /* @__PURE__ */ import_react17.default.createElement(import_react17.default.Fragment, null, /* @__PURE__ */ import_react17.default.createElement(Text, { color: last.color }, `${last.glyph} `), /* @__PURE__ */ import_react17.default.createElement(Text, { color: FG.body }, truncate(last.label, 18)), last.meta ? /* @__PURE__ */ import_react17.default.createElement(Text, { color: FG.faint }, ` ${last.meta}`) : null) : /* @__PURE__ */ import_react17.default.createElement(Text, { color: FG.faint }, t("editMode.queuedDots")));
47460
47374
  }
47461
47375
  function truncate(text, max) {
47462
47376
  return text.length > max ? `${text.slice(0, max)}\u2026` : text;
@@ -47468,7 +47382,7 @@ function OngoingToolRow({
47468
47382
  const tick = useTick();
47469
47383
  const elapsed = useElapsedSeconds();
47470
47384
  const summary = summarizeToolArgs(tool.name, tool.args);
47471
- return /* @__PURE__ */ import_react18.default.createElement(Box_default, { marginY: 1, flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ import_react18.default.createElement(Box_default, null, /* @__PURE__ */ import_react18.default.createElement(Text, { color: CARD.tool.color, bold: true }, SPINNER_FRAMES[tick % SPINNER_FRAMES.length]), /* @__PURE__ */ import_react18.default.createElement(Text, null, " "), /* @__PURE__ */ import_react18.default.createElement(Text, { color: CARD.tool.color, bold: true }, `\u25A3 ${tool.name}`), /* @__PURE__ */ import_react18.default.createElement(Text, { color: FG.faint }, ` running \xB7 ${elapsed}s`)), progress ? /* @__PURE__ */ import_react18.default.createElement(Box_default, { paddingLeft: 3 }, /* @__PURE__ */ import_react18.default.createElement(Text, { color: TONE.brand }, renderProgressLine(progress))) : null, summary ? /* @__PURE__ */ import_react18.default.createElement(Box_default, { paddingLeft: 3 }, /* @__PURE__ */ import_react18.default.createElement(Text, { color: FG.faint }, summary)) : null);
47385
+ return /* @__PURE__ */ import_react17.default.createElement(Box_default, { marginY: 1, flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ import_react17.default.createElement(Box_default, null, /* @__PURE__ */ import_react17.default.createElement(Text, { color: CARD.tool.color, bold: true }, SPINNER_FRAMES[tick % SPINNER_FRAMES.length]), /* @__PURE__ */ import_react17.default.createElement(Text, null, " "), /* @__PURE__ */ import_react17.default.createElement(Text, { color: CARD.tool.color, bold: true }, `\u25A3 ${tool.name}`), /* @__PURE__ */ import_react17.default.createElement(Text, { color: FG.faint }, ` running \xB7 ${elapsed}s`)), progress ? /* @__PURE__ */ import_react17.default.createElement(Box_default, { paddingLeft: 3 }, /* @__PURE__ */ import_react17.default.createElement(Text, { color: TONE.brand }, renderProgressLine(progress))) : null, summary ? /* @__PURE__ */ import_react17.default.createElement(Box_default, { paddingLeft: 3 }, /* @__PURE__ */ import_react17.default.createElement(Text, { color: FG.faint }, summary)) : null);
47472
47386
  }
47473
47387
  function renderProgressLine(p) {
47474
47388
  const msg = p.message ? ` ${p.message}` : "";
@@ -47524,18 +47438,85 @@ function summarizeToolArgs(name, args) {
47524
47438
  }
47525
47439
 
47526
47440
  // src/cli/ui/layout/StatusRow.tsx
47527
- var import_react21 = __toESM(require_react(), 1);
47441
+ var import_react20 = __toESM(require_react(), 1);
47528
47442
 
47529
47443
  // src/cli/ui/primitives/Countdown.tsx
47530
- var import_react19 = __toESM(require_react(), 1);
47444
+ var import_react18 = __toESM(require_react(), 1);
47531
47445
  function Countdown({ endsAt, color = TONE.brand }) {
47532
47446
  useSlowTick();
47533
47447
  const remainingSec = Math.max(0, Math.ceil((endsAt - Date.now()) / 1e3));
47534
- return /* @__PURE__ */ import_react19.default.createElement(Text, { bold: true, color }, String(remainingSec));
47448
+ return /* @__PURE__ */ import_react18.default.createElement(Text, { bold: true, color }, String(remainingSec));
47535
47449
  }
47536
47450
 
47537
47451
  // src/cli/ui/state/provider.tsx
47538
- var import_react20 = __toESM(require_react(), 1);
47452
+ var import_react19 = __toESM(require_react(), 1);
47453
+
47454
+ // src/cli/ui/interrupt-cleanup.ts
47455
+ function cleanupInterruptedCards(cards, endedAt = Date.now()) {
47456
+ let changed = false;
47457
+ const next = [];
47458
+ for (const card of cards) {
47459
+ if (card.kind === "live" && card.variant === "thinking") {
47460
+ changed = true;
47461
+ continue;
47462
+ }
47463
+ const cleaned = cleanupInterruptedCard(card, endedAt);
47464
+ if (cleaned !== card) changed = true;
47465
+ next.push(cleaned);
47466
+ }
47467
+ return changed ? next : cards;
47468
+ }
47469
+ function cleanupInterruptedCard(card, endedAt) {
47470
+ if (card.kind === "reasoning" && card.streaming) {
47471
+ return {
47472
+ ...card,
47473
+ streaming: false,
47474
+ aborted: true,
47475
+ endedAt,
47476
+ paragraphs: card.paragraphs || countParagraphs(card.text),
47477
+ tokens: card.tokens || Math.round(card.text.length / 4)
47478
+ };
47479
+ }
47480
+ if (card.kind === "streaming" && !card.done) {
47481
+ return { ...card, done: true, aborted: true, endedAt };
47482
+ }
47483
+ if (card.kind === "tool" && !card.done) {
47484
+ return { ...card, done: true, aborted: true };
47485
+ }
47486
+ if (card.kind === "task" && card.status === "running") {
47487
+ return cleanupTaskCard(card);
47488
+ }
47489
+ if (card.kind === "subagent" && card.status === "running") {
47490
+ return cleanupSubagentCard(card, endedAt);
47491
+ }
47492
+ return card;
47493
+ }
47494
+ function cleanupTaskCard(card) {
47495
+ let stepChanged = false;
47496
+ const steps = card.steps.map((step) => {
47497
+ if (step.status !== "running") return step;
47498
+ stepChanged = true;
47499
+ return { ...step, status: "failed" };
47500
+ });
47501
+ return {
47502
+ ...card,
47503
+ status: "failed",
47504
+ steps: stepChanged ? steps : card.steps
47505
+ };
47506
+ }
47507
+ function cleanupSubagentCard(card, endedAt) {
47508
+ const children = cleanupInterruptedCards(card.children, endedAt);
47509
+ return {
47510
+ ...card,
47511
+ status: "failed",
47512
+ children: children === card.children ? card.children : [...children]
47513
+ };
47514
+ }
47515
+ function countParagraphs(text) {
47516
+ const trimmed = text.trim();
47517
+ if (!trimmed) return 0;
47518
+ return trimmed.split(/\n\s*\n/).length;
47519
+ }
47539
47520
 
47540
47521
  // src/cli/ui/state/reducer.ts
47541
47522
  function reduce(state, event) {
@@ -47580,11 +47561,12 @@ function reduce(state, event) {
47580
47561
  case "tool.end": {
47581
47562
  const finalOutput = event.output ?? "";
47582
47563
  const rejected = isPlanModeRejection(finalOutput);
47564
+ const exitCode = event.exitCode ?? inferToolExitCode(finalOutput);
47583
47565
  return mutateCard(state, event.id, "tool", (c) => ({
47584
47566
  ...c,
47585
47567
  done: true,
47586
47568
  output: event.output ?? c.output,
47587
- exitCode: event.exitCode,
47569
+ exitCode,
47588
47570
  elapsedMs: event.elapsedMs,
47589
47571
  ...event.aborted ? { aborted: true } : {},
47590
47572
  ...rejected ? { rejected: true } : {}
@@ -47601,6 +47583,23 @@ function reduce(state, event) {
47601
47583
  turnInProgress: false,
47602
47584
  composer: { ...state.composer, abortedHint: true }
47603
47585
  };
47586
+ case "turn.interrupt.cleanup":
47587
+ return appendCard(
47588
+ {
47589
+ ...state,
47590
+ cards: cleanupInterruptedCards(state.cards, event.ts),
47591
+ turnInProgress: false,
47592
+ composer: { ...state.composer, abortedHint: true }
47593
+ },
47594
+ {
47595
+ kind: "live",
47596
+ id: event.id,
47597
+ ts: event.ts,
47598
+ variant: "aborted",
47599
+ tone: "warn",
47600
+ text: event.text
47601
+ }
47602
+ );
47604
47603
  case "turn.end": {
47605
47604
  const sessionCost = state.status.sessionCost + event.usage.cost;
47606
47605
  const sessionInputTokens = state.status.sessionInputTokens + event.usage.prompt;
@@ -47904,6 +47903,22 @@ function isPlanModeRejection(output) {
47904
47903
  return false;
47905
47904
  }
47906
47905
  }
47906
+ function inferToolExitCode(output) {
47907
+ if (!output) return void 0;
47908
+ try {
47909
+ const parsed = JSON.parse(output.trim());
47910
+ if (!parsed || typeof parsed !== "object") return void 0;
47911
+ const error = parsed.error;
47912
+ if (typeof error !== "string") return void 0;
47913
+ return isControlSignalError(error) ? void 0 : 1;
47914
+ } catch {
47915
+ return void 0;
47916
+ }
47917
+ }
47918
+ function isControlSignalError(error) {
47919
+ const tag2 = error.split(":", 1)[0]?.trim();
47920
+ return tag2 === "PlanProposedError" || tag2 === "PlanRevisionProposedError" || tag2 === "ChoiceRequestedError" || tag2 === "NeedsConfirmationError";
47921
+ }
47907
47922
 
47908
47923
  // src/cli/ui/state/state.ts
47909
47924
  function initialState(session, cards = []) {
@@ -47964,26 +47979,26 @@ function createStore(session, initialCards) {
47964
47979
  }
47965
47980
 
47966
47981
  // src/cli/ui/state/provider.tsx
47967
- var StoreCtx = import_react20.default.createContext(null);
47982
+ var StoreCtx = import_react19.default.createContext(null);
47968
47983
  function AgentStoreProvider({
47969
47984
  session,
47970
47985
  initialCards,
47971
47986
  children
47972
47987
  }) {
47973
- const initialCardsRef = import_react20.default.useRef(initialCards);
47974
- const store = import_react20.default.useMemo(() => createStore(session, initialCardsRef.current), [session]);
47975
- return /* @__PURE__ */ import_react20.default.createElement(StoreCtx.Provider, { value: store }, children);
47988
+ const initialCardsRef = import_react19.default.useRef(initialCards);
47989
+ const store = import_react19.default.useMemo(() => createStore(session, initialCardsRef.current), [session]);
47990
+ return /* @__PURE__ */ import_react19.default.createElement(StoreCtx.Provider, { value: store }, children);
47976
47991
  }
47977
47992
  function useAgentStore() {
47978
- const store = import_react20.default.useContext(StoreCtx);
47993
+ const store = import_react19.default.useContext(StoreCtx);
47979
47994
  if (!store) throw new Error("useAgentStore must be used inside AgentStoreProvider");
47980
47995
  return store;
47981
47996
  }
47982
47997
  function useAgentState(selector) {
47983
47998
  const store = useAgentStore();
47984
- const subscribe = import_react20.default.useCallback((cb) => store.subscribe(cb), [store]);
47985
- const getSnapshot = import_react20.default.useCallback(() => selector(store.getState()), [store, selector]);
47986
- return import_react20.default.useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
47999
+ const subscribe = import_react19.default.useCallback((cb) => store.subscribe(cb), [store]);
48000
+ const getSnapshot = import_react19.default.useCallback(() => selector(store.getState()), [store, selector]);
48001
+ return import_react19.default.useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
47987
48002
  }
47988
48003
  function useDispatch() {
47989
48004
  return useAgentStore().dispatch;
@@ -47998,6 +48013,9 @@ var CTX_TOKENS_MIN_COLS = 90;
47998
48013
  var CTX_BAR_MIN_COLS = 110;
47999
48014
  var CTX_BAR_CELLS = 8;
48000
48015
  var DEFAULT_STATUS_BAR_CONFIG = {
48016
+ showMode: true,
48017
+ showPreset: true,
48018
+ showSessionInfo: true,
48001
48019
  showBalance: true,
48002
48020
  showSessionCost: true,
48003
48021
  showTurnCost: true,
@@ -48017,29 +48035,82 @@ function StatusRow({
48017
48035
  const hasSession = status2.sessionCost > 0;
48018
48036
  const hasBalance = typeof status2.balance === "number";
48019
48037
  const showWallet = cols >= WALLET_MIN_COLS && (hasSession && statusBar.showSessionCost || hasBalance && statusBar.showBalance);
48020
- return /* @__PURE__ */ import_react21.default.createElement(Box_default, { flexDirection: "column", flexShrink: 0 }, /* @__PURE__ */ import_react21.default.createElement(Box_default, { flexDirection: "row", flexWrap: "wrap", flexShrink: 0 }, /* @__PURE__ */ import_react21.default.createElement(Text, null, " "), status2.recording ? /* @__PURE__ */ import_react21.default.createElement(RecordingPill, { rec: status2.recording }) : status2.countdownSeconds !== void 0 ? /* @__PURE__ */ import_react21.default.createElement(CountdownRow, { mode: status2.mode, secondsLeft: status2.countdownSeconds }) : /* @__PURE__ */ import_react21.default.createElement(ModePill2, { mode: status2.mode, network: status2.network, detail: status2.networkDetail }), cols >= PRESET_MIN_COLS && status2.preset !== void 0 && /* @__PURE__ */ import_react21.default.createElement(PresetPill, { preset: status2.preset, model: session.model }), /* @__PURE__ */ import_react21.default.createElement(Sep, null), /* @__PURE__ */ import_react21.default.createElement(Text, { color: FG.sub }, `${session.id} \xB7 ${session.branch}`), hasTurn && statusBar.showTurnCost && /* @__PURE__ */ import_react21.default.createElement(import_react21.default.Fragment, null, /* @__PURE__ */ import_react21.default.createElement(Sep, null), /* @__PURE__ */ import_react21.default.createElement(Text, { bold: true, color: TONE.brand }, "\u25B8 "), /* @__PURE__ */ import_react21.default.createElement(Text, { bold: true, color: FG.body }, `${formatCost(status2.cost, status2.balanceCurrency)} ${t("statusBar.turn")}`)), statusBar.showCacheHit && /* @__PURE__ */ import_react21.default.createElement(import_react21.default.Fragment, null, /* @__PURE__ */ import_react21.default.createElement(Sep, null), /* @__PURE__ */ import_react21.default.createElement(
48021
- Text,
48022
- {
48023
- color: TONE.accent
48024
- },
48025
- `${t("statusBar.cache")} ${Math.round(status2.cacheHit * 100)}%`
48026
- )), statusBar.showCtxUsage && status2.promptTokens !== void 0 && status2.promptTokens > 0 && /* @__PURE__ */ import_react21.default.createElement(
48027
- CtxUsagePill,
48028
- {
48029
- tokens: status2.promptTokens,
48030
- cap: status2.promptCap ?? DEEPSEEK_CONTEXT_TOKENS[session.model] ?? DEFAULT_CONTEXT_TOKENS,
48031
- cols
48032
- }
48033
- ), status2.mcpLoading && status2.mcpLoading.ready < status2.mcpLoading.total && /* @__PURE__ */ import_react21.default.createElement(McpLoadingPill, { ready: status2.mcpLoading.ready, total: status2.mcpLoading.total }), showWallet && /* @__PURE__ */ import_react21.default.createElement(
48034
- WalletPill,
48035
- {
48036
- sessionCostUsd: status2.sessionCost,
48037
- balance: status2.balance,
48038
- currency: status2.balanceCurrency,
48039
- showSessionCost: statusBar.showSessionCost,
48040
- showBalance: statusBar.showBalance
48041
- }
48042
- ), statusBar.showVersion && cols >= VERSION_MIN_COLS && /* @__PURE__ */ import_react21.default.createElement(import_react21.default.Fragment, null, /* @__PURE__ */ import_react21.default.createElement(Sep, null), /* @__PURE__ */ import_react21.default.createElement(Text, { color: FG.faint }, `v${VERSION}`)), statusBar.showFeedbackHint && cols >= FEEDBACK_HINT_MIN_COLS && /* @__PURE__ */ import_react21.default.createElement(import_react21.default.Fragment, null, /* @__PURE__ */ import_react21.default.createElement(Sep, null), /* @__PURE__ */ import_react21.default.createElement(Text, { color: FG.meta }, "\u2691 "), /* @__PURE__ */ import_react21.default.createElement(Text, { color: FG.sub }, "/feedback"))));
48038
+ const segments = [];
48039
+ if (statusBar.showMode) {
48040
+ segments.push({
48041
+ key: "mode",
48042
+ node: status2.recording ? /* @__PURE__ */ import_react20.default.createElement(RecordingPill, { rec: status2.recording }) : status2.countdownSeconds !== void 0 ? /* @__PURE__ */ import_react20.default.createElement(CountdownRow, { mode: status2.mode, secondsLeft: status2.countdownSeconds }) : /* @__PURE__ */ import_react20.default.createElement(ModePill2, { mode: status2.mode, network: status2.network, detail: status2.networkDetail })
48043
+ });
48044
+ }
48045
+ if (statusBar.showPreset && cols >= PRESET_MIN_COLS && status2.preset !== void 0) {
48046
+ segments.push({
48047
+ key: "preset",
48048
+ node: /* @__PURE__ */ import_react20.default.createElement(PresetPill, { preset: status2.preset, model: session.model })
48049
+ });
48050
+ }
48051
+ if (statusBar.showSessionInfo) {
48052
+ segments.push({
48053
+ key: "session",
48054
+ node: /* @__PURE__ */ import_react20.default.createElement(Text, { color: FG.sub }, `${session.id} \xB7 ${session.branch}`)
48055
+ });
48056
+ }
48057
+ if (hasTurn && statusBar.showTurnCost) {
48058
+ segments.push({
48059
+ key: "turn",
48060
+ node: /* @__PURE__ */ import_react20.default.createElement(import_react20.default.Fragment, null, /* @__PURE__ */ import_react20.default.createElement(Text, { bold: true, color: TONE.brand }, "\u25B8 "), /* @__PURE__ */ import_react20.default.createElement(Text, { bold: true, color: FG.body }, `${formatCost(status2.cost, status2.balanceCurrency)} ${t("statusBar.turn")}`))
48061
+ });
48062
+ }
48063
+ if (statusBar.showCacheHit) {
48064
+ segments.push({
48065
+ key: "cache",
48066
+ node: /* @__PURE__ */ import_react20.default.createElement(Text, { color: TONE.accent }, `${t("statusBar.cache")} ${Math.round(status2.cacheHit * 100)}%`)
48067
+ });
48068
+ }
48069
+ if (statusBar.showCtxUsage && status2.promptTokens !== void 0 && status2.promptTokens > 0) {
48070
+ segments.push({
48071
+ key: "ctx",
48072
+ node: /* @__PURE__ */ import_react20.default.createElement(
48073
+ CtxUsagePill,
48074
+ {
48075
+ tokens: status2.promptTokens,
48076
+ cap: status2.promptCap ?? DEEPSEEK_CONTEXT_TOKENS[session.model] ?? DEFAULT_CONTEXT_TOKENS,
48077
+ cols
48078
+ }
48079
+ )
48080
+ });
48081
+ }
48082
+ if (status2.mcpLoading && status2.mcpLoading.ready < status2.mcpLoading.total) {
48083
+ segments.push({
48084
+ key: "mcp",
48085
+ node: /* @__PURE__ */ import_react20.default.createElement(McpLoadingPill, { ready: status2.mcpLoading.ready, total: status2.mcpLoading.total })
48086
+ });
48087
+ }
48088
+ if (showWallet) {
48089
+ segments.push({
48090
+ key: "wallet",
48091
+ node: /* @__PURE__ */ import_react20.default.createElement(
48092
+ WalletPill,
48093
+ {
48094
+ sessionCostUsd: status2.sessionCost,
48095
+ balance: status2.balance,
48096
+ currency: status2.balanceCurrency,
48097
+ showSessionCost: statusBar.showSessionCost,
48098
+ showBalance: statusBar.showBalance
48099
+ }
48100
+ )
48101
+ });
48102
+ }
48103
+ if (statusBar.showVersion && cols >= VERSION_MIN_COLS) {
48104
+ segments.push({ key: "version", node: /* @__PURE__ */ import_react20.default.createElement(Text, { color: FG.faint }, `v${VERSION}`) });
48105
+ }
48106
+ if (statusBar.showFeedbackHint && cols >= FEEDBACK_HINT_MIN_COLS) {
48107
+ segments.push({
48108
+ key: "feedback",
48109
+ node: /* @__PURE__ */ import_react20.default.createElement(import_react20.default.Fragment, null, /* @__PURE__ */ import_react20.default.createElement(Text, { color: FG.meta }, "\u2691 "), /* @__PURE__ */ import_react20.default.createElement(Text, { color: FG.sub }, "/feedback"))
48110
+ });
48111
+ }
48112
+ if (segments.length === 0) return /* @__PURE__ */ import_react20.default.createElement(Box_default, { flexDirection: "column", flexShrink: 0 });
48113
+ return /* @__PURE__ */ import_react20.default.createElement(Box_default, { flexDirection: "column", flexShrink: 0 }, /* @__PURE__ */ import_react20.default.createElement(Box_default, { flexDirection: "row", flexWrap: "wrap", flexShrink: 0 }, /* @__PURE__ */ import_react20.default.createElement(Text, null, " "), segments.map((segment, index) => /* @__PURE__ */ import_react20.default.createElement(import_react20.default.Fragment, { key: segment.key }, index > 0 ? /* @__PURE__ */ import_react20.default.createElement(Sep, null) : null, segment.node))));
48043
48114
  }
48044
48115
  function PresetPill({
48045
48116
  preset: preset2,
@@ -48047,7 +48118,7 @@ function PresetPill({
48047
48118
  }) {
48048
48119
  const label = preset2 ?? shortModelLabel(model2);
48049
48120
  const color = preset2 === "pro" ? TONE.accent : preset2 === "flash" ? TONE.brand : FG.sub;
48050
- return /* @__PURE__ */ import_react21.default.createElement(import_react21.default.Fragment, null, /* @__PURE__ */ import_react21.default.createElement(Sep, null), /* @__PURE__ */ import_react21.default.createElement(Text, { color: FG.meta, wrap: "truncate" }, "\u25B4 "), /* @__PURE__ */ import_react21.default.createElement(Text, { color, wrap: "truncate" }, label));
48121
+ return /* @__PURE__ */ import_react20.default.createElement(import_react20.default.Fragment, null, /* @__PURE__ */ import_react20.default.createElement(Text, { color: FG.meta, wrap: "truncate" }, "\u25B4 "), /* @__PURE__ */ import_react20.default.createElement(Text, { color, wrap: "truncate" }, label));
48051
48122
  }
48052
48123
  function shortModelLabel(model2) {
48053
48124
  if (model2 === "deepseek-v4-flash") return "flash";
@@ -48065,13 +48136,13 @@ function CtxUsagePill({
48065
48136
  const showTokens = cols >= CTX_TOKENS_MIN_COLS;
48066
48137
  const showBar = cols >= CTX_BAR_MIN_COLS;
48067
48138
  const filled = Math.round(CTX_BAR_CELLS * ratio);
48068
- return /* @__PURE__ */ import_react21.default.createElement(import_react21.default.Fragment, null, /* @__PURE__ */ import_react21.default.createElement(Sep, null), /* @__PURE__ */ import_react21.default.createElement(Text, { color: FG.meta, wrap: "truncate" }, `${t("statusBar.ctx")} `), showBar && /* @__PURE__ */ import_react21.default.createElement(import_react21.default.Fragment, null, /* @__PURE__ */ import_react21.default.createElement(Text, { color, wrap: "truncate" }, GLYPH.block.repeat(filled)), /* @__PURE__ */ import_react21.default.createElement(Text, { color: FG.faint, wrap: "truncate" }, GLYPH.shade1.repeat(CTX_BAR_CELLS - filled)), /* @__PURE__ */ import_react21.default.createElement(Text, { wrap: "truncate" }, " ")), /* @__PURE__ */ import_react21.default.createElement(Text, { color, wrap: "truncate" }, `${pct}%`), showTokens && /* @__PURE__ */ import_react21.default.createElement(Text, { color: FG.faint }, ` \xB7 ${formatTokens(tokens)}/${formatTokens(cap)}`));
48139
+ return /* @__PURE__ */ import_react20.default.createElement(import_react20.default.Fragment, null, /* @__PURE__ */ import_react20.default.createElement(Text, { color: FG.meta, wrap: "truncate" }, `${t("statusBar.ctx")} `), showBar && /* @__PURE__ */ import_react20.default.createElement(import_react20.default.Fragment, null, /* @__PURE__ */ import_react20.default.createElement(Text, { color, wrap: "truncate" }, GLYPH.block.repeat(filled)), /* @__PURE__ */ import_react20.default.createElement(Text, { color: FG.faint, wrap: "truncate" }, GLYPH.shade1.repeat(CTX_BAR_CELLS - filled)), /* @__PURE__ */ import_react20.default.createElement(Text, { wrap: "truncate" }, " ")), /* @__PURE__ */ import_react20.default.createElement(Text, { color, wrap: "truncate" }, `${pct}%`), showTokens && /* @__PURE__ */ import_react20.default.createElement(Text, { color: FG.faint }, ` \xB7 ${formatTokens(tokens)}/${formatTokens(cap)}`));
48069
48140
  }
48070
48141
  function McpLoadingPill({
48071
48142
  ready,
48072
48143
  total
48073
48144
  }) {
48074
- return /* @__PURE__ */ import_react21.default.createElement(import_react21.default.Fragment, null, /* @__PURE__ */ import_react21.default.createElement(Sep, null), /* @__PURE__ */ import_react21.default.createElement(Text, { color: TONE.brand, wrap: "truncate" }, "\u2301 "), /* @__PURE__ */ import_react21.default.createElement(Text, { color: FG.body }, `${t("statusBar.mcpLoading")} ${ready}/${total}`));
48145
+ return /* @__PURE__ */ import_react20.default.createElement(import_react20.default.Fragment, null, /* @__PURE__ */ import_react20.default.createElement(Text, { color: TONE.brand, wrap: "truncate" }, "\u2301 "), /* @__PURE__ */ import_react20.default.createElement(Text, { color: FG.body }, `${t("statusBar.mcpLoading")} ${ready}/${total}`));
48075
48146
  }
48076
48147
  function WalletPill({
48077
48148
  sessionCostUsd,
@@ -48082,13 +48153,13 @@ function WalletPill({
48082
48153
  }) {
48083
48154
  const showSpent = showSessionCost && sessionCostUsd > 0;
48084
48155
  const showBalanceLine = showBalanceCfg && typeof balance === "number";
48085
- return /* @__PURE__ */ import_react21.default.createElement(import_react21.default.Fragment, null, /* @__PURE__ */ import_react21.default.createElement(Sep, null), /* @__PURE__ */ import_react21.default.createElement(Text, { color: FG.meta, wrap: "truncate" }, "\u26C1 "), showSpent && /* @__PURE__ */ import_react21.default.createElement(
48156
+ return /* @__PURE__ */ import_react20.default.createElement(import_react20.default.Fragment, null, /* @__PURE__ */ import_react20.default.createElement(Text, { color: FG.meta, wrap: "truncate" }, "\u26C1 "), showSpent && /* @__PURE__ */ import_react20.default.createElement(
48086
48157
  Text,
48087
48158
  {
48088
48159
  color: FG.body
48089
48160
  },
48090
48161
  `${formatCost(sessionCostUsd, currency, 2)} ${t("statusBar.spent")}`
48091
- ), showSpent && showBalanceLine && /* @__PURE__ */ import_react21.default.createElement(Text, { color: FG.meta, wrap: "truncate" }, " / "), showBalanceLine && /* @__PURE__ */ import_react21.default.createElement(Text, { bold: true, color: balanceColor(balance, currency), wrap: "truncate" }, formatBalance(balance, currency, { fractionDigits: 2 })), showBalanceLine && /* @__PURE__ */ import_react21.default.createElement(Text, { color: FG.faint, wrap: "truncate" }, t("statusBar.left")));
48162
+ ), showSpent && showBalanceLine && /* @__PURE__ */ import_react20.default.createElement(Text, { color: FG.meta, wrap: "truncate" }, " / "), showBalanceLine && /* @__PURE__ */ import_react20.default.createElement(Text, { bold: true, color: balanceColor(balance, currency), wrap: "truncate" }, formatBalance(balance, currency, { fractionDigits: 2 })), showBalanceLine && /* @__PURE__ */ import_react20.default.createElement(Text, { color: FG.faint, wrap: "truncate" }, t("statusBar.left")));
48092
48163
  }
48093
48164
  function ModePill2({
48094
48165
  mode: mode2,
@@ -48098,18 +48169,18 @@ function ModePill2({
48098
48169
  const modeLabel = `${t("statusBar.editsLabel")}${mode2}`;
48099
48170
  if (network === "online") {
48100
48171
  const pill = modeGlyph(mode2);
48101
- return /* @__PURE__ */ import_react21.default.createElement(Box_default, { flexDirection: "row", height: 1, flexWrap: "nowrap" }, /* @__PURE__ */ import_react21.default.createElement(Text, { color: pill.color, wrap: "truncate" }, pill.glyph), /* @__PURE__ */ import_react21.default.createElement(Text, { color: FG.sub, wrap: "truncate" }, ` ${modeLabel}`));
48172
+ return /* @__PURE__ */ import_react20.default.createElement(Box_default, { flexDirection: "row", height: 1, flexWrap: "nowrap" }, /* @__PURE__ */ import_react20.default.createElement(Text, { color: pill.color, wrap: "truncate" }, pill.glyph), /* @__PURE__ */ import_react20.default.createElement(Text, { color: FG.sub, wrap: "truncate" }, ` ${modeLabel}`));
48102
48173
  }
48103
48174
  const dot = networkDot(network);
48104
48175
  if (network === "slow") {
48105
48176
  const tail = detail ? ` \xB7 ${detail}` : "";
48106
- return /* @__PURE__ */ import_react21.default.createElement(Box_default, { flexDirection: "row", height: 1, flexWrap: "nowrap" }, /* @__PURE__ */ import_react21.default.createElement(Text, { color: dot.color, wrap: "truncate" }, dot.glyph), /* @__PURE__ */ import_react21.default.createElement(Text, { color: dot.color }, ` ${modeLabel} \xB7 ${t("statusBar.slow")}${tail}`));
48177
+ return /* @__PURE__ */ import_react20.default.createElement(Box_default, { flexDirection: "row", height: 1, flexWrap: "nowrap" }, /* @__PURE__ */ import_react20.default.createElement(Text, { color: dot.color, wrap: "truncate" }, dot.glyph), /* @__PURE__ */ import_react20.default.createElement(Text, { color: dot.color }, ` ${modeLabel} \xB7 ${t("statusBar.slow")}${tail}`));
48107
48178
  }
48108
48179
  if (network === "disconnected") {
48109
48180
  const tail = detail ? ` \xB7 ${detail}` : "";
48110
- return /* @__PURE__ */ import_react21.default.createElement(Box_default, { flexDirection: "row", height: 1, flexWrap: "nowrap" }, /* @__PURE__ */ import_react21.default.createElement(Text, { color: dot.color, wrap: "truncate" }, dot.glyph), /* @__PURE__ */ import_react21.default.createElement(Text, { color: dot.color, wrap: "truncate" }, ` ${t("statusBar.disconnect")}${tail}`));
48181
+ return /* @__PURE__ */ import_react20.default.createElement(Box_default, { flexDirection: "row", height: 1, flexWrap: "nowrap" }, /* @__PURE__ */ import_react20.default.createElement(Text, { color: dot.color, wrap: "truncate" }, dot.glyph), /* @__PURE__ */ import_react20.default.createElement(Text, { color: dot.color, wrap: "truncate" }, ` ${t("statusBar.disconnect")}${tail}`));
48111
48182
  }
48112
- return /* @__PURE__ */ import_react21.default.createElement(Box_default, { flexDirection: "row", height: 1, flexWrap: "nowrap" }, /* @__PURE__ */ import_react21.default.createElement(Text, { color: dot.color, wrap: "truncate" }, dot.glyph), /* @__PURE__ */ import_react21.default.createElement(Text, { color: dot.color, wrap: "truncate" }, ` ${t("statusBar.reconnecting")}`));
48183
+ return /* @__PURE__ */ import_react20.default.createElement(Box_default, { flexDirection: "row", height: 1, flexWrap: "nowrap" }, /* @__PURE__ */ import_react20.default.createElement(Text, { color: dot.color, wrap: "truncate" }, dot.glyph), /* @__PURE__ */ import_react20.default.createElement(Text, { color: dot.color, wrap: "truncate" }, ` ${t("statusBar.reconnecting")}`));
48113
48184
  }
48114
48185
  function CountdownRow({
48115
48186
  mode: mode2,
@@ -48117,11 +48188,11 @@ function CountdownRow({
48117
48188
  }) {
48118
48189
  const pill = modeGlyph(mode2);
48119
48190
  const endsAt = Date.now() + secondsLeft * 1e3;
48120
- return /* @__PURE__ */ import_react21.default.createElement(Box_default, { flexDirection: "row", height: 1, flexWrap: "nowrap" }, /* @__PURE__ */ import_react21.default.createElement(Text, { color: pill.color, wrap: "truncate" }, pill.glyph), /* @__PURE__ */ import_react21.default.createElement(Text, { color: FG.sub, wrap: "truncate" }, ` ${t("statusBar.editsLabel")}${mode2} \xB7 `), /* @__PURE__ */ import_react21.default.createElement(Text, { color: TONE.warn, wrap: "truncate" }, t("statusBar.approvingIn")), /* @__PURE__ */ import_react21.default.createElement(Countdown, { endsAt }), /* @__PURE__ */ import_react21.default.createElement(Text, { color: TONE.warn, wrap: "truncate" }, t("statusBar.escToInterrupt")));
48191
+ return /* @__PURE__ */ import_react20.default.createElement(Box_default, { flexDirection: "row", height: 1, flexWrap: "nowrap" }, /* @__PURE__ */ import_react20.default.createElement(Text, { color: pill.color, wrap: "truncate" }, pill.glyph), /* @__PURE__ */ import_react20.default.createElement(Text, { color: FG.sub, wrap: "truncate" }, ` ${t("statusBar.editsLabel")}${mode2} \xB7 `), /* @__PURE__ */ import_react20.default.createElement(Text, { color: TONE.warn, wrap: "truncate" }, t("statusBar.approvingIn")), /* @__PURE__ */ import_react20.default.createElement(Countdown, { endsAt }), /* @__PURE__ */ import_react20.default.createElement(Text, { color: TONE.warn, wrap: "truncate" }, t("statusBar.escToInterrupt")));
48121
48192
  }
48122
48193
  function RecordingPill({ rec }) {
48123
48194
  const sizeMb = (rec.sizeBytes / (1024 * 1024)).toFixed(1);
48124
- return /* @__PURE__ */ import_react21.default.createElement(Box_default, { flexDirection: "row", height: 1, flexWrap: "nowrap" }, /* @__PURE__ */ import_react21.default.createElement(Text, { bold: true, color: TONE.err, wrap: "truncate" }, t("statusBar.recordingGlyph")), /* @__PURE__ */ import_react21.default.createElement(
48195
+ return /* @__PURE__ */ import_react20.default.createElement(Box_default, { flexDirection: "row", height: 1, flexWrap: "nowrap" }, /* @__PURE__ */ import_react20.default.createElement(Text, { bold: true, color: TONE.err, wrap: "truncate" }, t("statusBar.recordingGlyph")), /* @__PURE__ */ import_react20.default.createElement(
48125
48196
  Text,
48126
48197
  {
48127
48198
  color: TONE.err
@@ -48130,7 +48201,7 @@ function RecordingPill({ rec }) {
48130
48201
  ));
48131
48202
  }
48132
48203
  function Sep() {
48133
- return /* @__PURE__ */ import_react21.default.createElement(Text, { color: FG.meta, wrap: "truncate" }, " \xB7 ");
48204
+ return /* @__PURE__ */ import_react20.default.createElement(Text, { color: FG.meta, wrap: "truncate" }, " \xB7 ");
48134
48205
  }
48135
48206
  function modeGlyph(mode2) {
48136
48207
  switch (mode2) {
@@ -48217,7 +48288,7 @@ function formatDuration(ms) {
48217
48288
  }
48218
48289
 
48219
48290
  // src/cli/ui/state/chat-scroll-provider.tsx
48220
- var import_react22 = __toESM(require_react(), 1);
48291
+ var import_react21 = __toESM(require_react(), 1);
48221
48292
 
48222
48293
  // src/cli/ui/state/chat-scroll-store.ts
48223
48294
  var SCROLL_ARROW_ROWS = 3;
@@ -48346,44 +48417,43 @@ function createChatScrollStore() {
48346
48417
  }
48347
48418
 
48348
48419
  // src/cli/ui/state/chat-scroll-provider.tsx
48349
- var Ctx = import_react22.default.createContext(null);
48420
+ var Ctx = import_react21.default.createContext(null);
48350
48421
  function ChatScrollProvider({
48351
48422
  children
48352
48423
  }) {
48353
- const store = import_react22.default.useMemo(() => createChatScrollStore(), []);
48354
- return /* @__PURE__ */ import_react22.default.createElement(Ctx.Provider, { value: store }, children);
48424
+ const store = import_react21.default.useMemo(() => createChatScrollStore(), []);
48425
+ return /* @__PURE__ */ import_react21.default.createElement(Ctx.Provider, { value: store }, children);
48355
48426
  }
48356
48427
  function useStore() {
48357
- const s = import_react22.default.useContext(Ctx);
48428
+ const s = import_react21.default.useContext(Ctx);
48358
48429
  if (!s) throw new Error("useChatScroll* must be used inside ChatScrollProvider");
48359
48430
  return s;
48360
48431
  }
48361
48432
  function useChatScrollState(selector) {
48362
48433
  const store = useStore();
48363
- const subscribe = import_react22.default.useCallback((cb) => store.subscribe(cb), [store]);
48364
- const getSnapshot = import_react22.default.useCallback(() => selector(store.getState()), [store, selector]);
48365
- return import_react22.default.useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
48434
+ const subscribe = import_react21.default.useCallback((cb) => store.subscribe(cb), [store]);
48435
+ const getSnapshot = import_react21.default.useCallback(() => selector(store.getState()), [store, selector]);
48436
+ return import_react21.default.useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
48366
48437
  }
48367
48438
  function useChatScrollActions() {
48368
48439
  return useStore();
48369
48440
  }
48370
48441
 
48371
48442
  // src/cli/ui/ComposerArea.tsx
48372
- var HistoryHint = import_react23.default.memo(({ children }) => {
48443
+ var HistoryHint = import_react22.default.memo(({ children }) => {
48373
48444
  const pinned = useChatScrollState((s) => s.pinned);
48374
48445
  if (!pinned) {
48375
- return /* @__PURE__ */ import_react23.default.createElement(Text, { color: FG.faint }, "scrolled up \u2014 reading history \u2014 End / PgDn to return \u2014 \u2193 to advance one line");
48446
+ return /* @__PURE__ */ import_react22.default.createElement(Text, { color: FG.faint }, "scrolled up \u2014 reading history \u2014 End / PgDn to return \u2014 \u2193 to advance one line");
48376
48447
  }
48377
- return /* @__PURE__ */ import_react23.default.createElement(import_react23.default.Fragment, null, children);
48448
+ return /* @__PURE__ */ import_react22.default.createElement(import_react22.default.Fragment, null, children);
48378
48449
  });
48379
48450
  HistoryHint.displayName = "HistoryHint";
48380
- var ComposerArea = import_react23.default.memo(
48451
+ var ComposerArea = import_react22.default.memo(
48381
48452
  ({
48382
48453
  editMode,
48383
48454
  pendingCount,
48384
48455
  modeFlash,
48385
48456
  planMode,
48386
- undoArmed,
48387
48457
  jobs: jobs2,
48388
48458
  activeLoop,
48389
48459
  statusBar,
@@ -48405,7 +48475,7 @@ var ComposerArea = import_react23.default.memo(
48405
48475
  slashArgMatches,
48406
48476
  slashArgSelected
48407
48477
  }) => {
48408
- const inputArea = /* @__PURE__ */ import_react23.default.createElement(Box_default, { flexDirection: "column", flexShrink: 0, flexWrap: "nowrap" }, /* @__PURE__ */ import_react23.default.createElement(Box_default, { flexDirection: "column", flexShrink: 0, flexWrap: "nowrap" }, slashMatches !== null ? /* @__PURE__ */ import_react23.default.createElement(
48478
+ const inputArea = /* @__PURE__ */ import_react22.default.createElement(Box_default, { flexDirection: "column", flexShrink: 0, flexWrap: "nowrap" }, /* @__PURE__ */ import_react22.default.createElement(Box_default, { flexDirection: "column", flexShrink: 0, flexWrap: "nowrap" }, slashMatches !== null ? /* @__PURE__ */ import_react22.default.createElement(
48409
48479
  SlashSuggestions,
48410
48480
  {
48411
48481
  key: `slash-suggestions:${slashGroupMode ? "group" : "search"}`,
@@ -48414,7 +48484,7 @@ var ComposerArea = import_react23.default.memo(
48414
48484
  groupMode: slashGroupMode,
48415
48485
  advancedHidden: slashAdvancedHidden
48416
48486
  }
48417
- ) : null, atState !== null ? /* @__PURE__ */ import_react23.default.createElement(AtMentionSuggestions, { state: atState, selectedIndex: atSelected }) : null, slashArgContext ? /* @__PURE__ */ import_react23.default.createElement(
48487
+ ) : null, atState !== null ? /* @__PURE__ */ import_react22.default.createElement(AtMentionSuggestions, { state: atState, selectedIndex: atSelected }) : null, slashArgContext ? /* @__PURE__ */ import_react22.default.createElement(
48418
48488
  SlashArgPicker,
48419
48489
  {
48420
48490
  matches: slashArgMatches,
@@ -48423,7 +48493,7 @@ var ComposerArea = import_react23.default.memo(
48423
48493
  kind: slashArgContext.kind,
48424
48494
  partial: slashArgContext.partial
48425
48495
  }
48426
- ) : null), /* @__PURE__ */ import_react23.default.createElement(
48496
+ ) : null), /* @__PURE__ */ import_react22.default.createElement(
48427
48497
  PromptInput,
48428
48498
  {
48429
48499
  value: input,
@@ -48435,35 +48505,34 @@ var ComposerArea = import_react23.default.memo(
48435
48505
  onOpenExternalEditor,
48436
48506
  onCursorChange
48437
48507
  }
48438
- ), activeLoop ? /* @__PURE__ */ import_react23.default.createElement(LoopStatusRow, { loop: activeLoop }) : null, jobs2 ? /* @__PURE__ */ import_react23.default.createElement(
48508
+ ), activeLoop ? /* @__PURE__ */ import_react22.default.createElement(LoopStatusRow, { loop: activeLoop }) : null, jobs2 ? /* @__PURE__ */ import_react22.default.createElement(
48439
48509
  ModeStatusBar,
48440
48510
  {
48441
48511
  editMode,
48442
48512
  pendingCount,
48443
48513
  flash: modeFlash,
48444
48514
  planMode,
48445
- undoArmed,
48446
48515
  jobs: jobs2
48447
48516
  }
48448
- ) : null, /* @__PURE__ */ import_react23.default.createElement(StatusRow, { statusBar }));
48449
- return /* @__PURE__ */ import_react23.default.createElement(HistoryHint, null, inputArea);
48517
+ ) : null, /* @__PURE__ */ import_react22.default.createElement(StatusRow, { statusBar }));
48518
+ return /* @__PURE__ */ import_react22.default.createElement(HistoryHint, null, inputArea);
48450
48519
  }
48451
48520
  );
48452
48521
  ComposerArea.displayName = "ComposerArea";
48453
48522
  function LoopStatusRow({
48454
48523
  loop: loop2
48455
48524
  }) {
48456
- const [, setTick] = import_react23.default.useState(0);
48457
- import_react23.default.useEffect(() => {
48525
+ const [, setTick] = import_react22.default.useState(0);
48526
+ import_react22.default.useEffect(() => {
48458
48527
  const id = setInterval(() => setTick((t2) => t2 + 1), 1e3);
48459
48528
  return () => clearInterval(id);
48460
48529
  }, []);
48461
48530
  const nextFireMs = Math.max(0, loop2.nextFireAt - Date.now());
48462
- return /* @__PURE__ */ import_react23.default.createElement(Box_default, null, /* @__PURE__ */ import_react23.default.createElement(Text, { color: "cyan" }, `loop: ${formatLoopStatus(loop2.prompt, nextFireMs, loop2.iter)} \u2014 /loop stop or type to cancel`));
48531
+ return /* @__PURE__ */ import_react22.default.createElement(Box_default, null, /* @__PURE__ */ import_react22.default.createElement(Text, { color: "cyan" }, `loop: ${formatLoopStatus(loop2.prompt, nextFireMs, loop2.iter)} \u2014 /loop stop or type to cancel`));
48463
48532
  }
48464
48533
 
48465
48534
  // src/cli/ui/EditConfirm.tsx
48466
- var import_react26 = __toESM(require_react(), 1);
48535
+ var import_react25 = __toESM(require_react(), 1);
48467
48536
 
48468
48537
  // src/code/diff-preview.ts
48469
48538
  function formatEditBlockDiff(block2, opts = {}) {
@@ -48615,14 +48684,14 @@ function capLines(lines, maxLines, indent) {
48615
48684
  }
48616
48685
 
48617
48686
  // src/cli/ui/DenyContextInput.tsx
48618
- var import_react24 = __toESM(require_react(), 1);
48687
+ var import_react23 = __toESM(require_react(), 1);
48619
48688
  var DEFAULT_DESCRIPTION = t("denyContextInput.description");
48620
48689
  function DenyContextInput({
48621
48690
  description = DEFAULT_DESCRIPTION,
48622
48691
  onSubmit,
48623
48692
  onCancel
48624
48693
  }) {
48625
- const [value, setValue] = (0, import_react24.useState)("");
48694
+ const [value, setValue] = (0, import_react23.useState)("");
48626
48695
  useKeystroke((ev) => {
48627
48696
  if (ev.paste) {
48628
48697
  setValue((v) => v + ev.input);
@@ -48644,17 +48713,17 @@ function DenyContextInput({
48644
48713
  setValue((v) => v + ev.input);
48645
48714
  }
48646
48715
  });
48647
- return /* @__PURE__ */ import_react24.default.createElement(Box_default, { flexDirection: "column" }, /* @__PURE__ */ import_react24.default.createElement(Box_default, { flexDirection: "column", marginBottom: 1 }, /* @__PURE__ */ import_react24.default.createElement(Text, { color: FG.sub }, description)), /* @__PURE__ */ import_react24.default.createElement(Box_default, null, /* @__PURE__ */ import_react24.default.createElement(Text, { bold: true, color: TONE.brand }, "\u203A "), /* @__PURE__ */ import_react24.default.createElement(Text, { color: FG.body }, value), /* @__PURE__ */ import_react24.default.createElement(Text, { backgroundColor: TONE.brand, color: "#000" }, " ")));
48716
+ return /* @__PURE__ */ import_react23.default.createElement(Box_default, { flexDirection: "column" }, /* @__PURE__ */ import_react23.default.createElement(Box_default, { flexDirection: "column", marginBottom: 1 }, /* @__PURE__ */ import_react23.default.createElement(Text, { color: FG.sub }, description)), /* @__PURE__ */ import_react23.default.createElement(Box_default, null, /* @__PURE__ */ import_react23.default.createElement(Text, { bold: true, color: TONE.brand }, "\u203A "), /* @__PURE__ */ import_react23.default.createElement(Text, { color: FG.body }, value), /* @__PURE__ */ import_react23.default.createElement(Text, { backgroundColor: TONE.brand, color: "#000" }, " ")));
48648
48717
  }
48649
48718
 
48650
48719
  // src/cli/ui/SplitDiff.tsx
48651
- var import_react25 = __toESM(require_react(), 1);
48720
+ var import_react24 = __toESM(require_react(), 1);
48652
48721
  function SplitDiff({ rows, totalCols }) {
48653
48722
  const { stdout } = use_stdout_default();
48654
48723
  const cols = totalCols ?? stdout?.columns ?? 80;
48655
48724
  const innerCols = Math.max(40, cols - 6);
48656
48725
  const halfCols = Math.floor((innerCols - 3) / 2);
48657
- return /* @__PURE__ */ import_react25.default.createElement(Box_default, { flexDirection: "column" }, rows.map((row2, i) => /* @__PURE__ */ import_react25.default.createElement(Box_default, { key: `r-${i}-${row2.left.num ?? "p"}-${row2.right.num ?? "p"}` }, /* @__PURE__ */ import_react25.default.createElement(Cell, { side: row2.left, width: halfCols, which: "left" }), /* @__PURE__ */ import_react25.default.createElement(Text, { color: COLOR.info, dimColor: true }, " \u2502 "), /* @__PURE__ */ import_react25.default.createElement(Cell, { side: row2.right, width: halfCols, which: "right" }))));
48726
+ return /* @__PURE__ */ import_react24.default.createElement(Box_default, { flexDirection: "column" }, rows.map((row2, i) => /* @__PURE__ */ import_react24.default.createElement(Box_default, { key: `r-${i}-${row2.left.num ?? "p"}-${row2.right.num ?? "p"}` }, /* @__PURE__ */ import_react24.default.createElement(Cell, { side: row2.left, width: halfCols, which: "left" }), /* @__PURE__ */ import_react24.default.createElement(Text, { color: COLOR.info, dimColor: true }, " \u2502 "), /* @__PURE__ */ import_react24.default.createElement(Cell, { side: row2.right, width: halfCols, which: "right" }))));
48658
48727
  }
48659
48728
  function Cell({
48660
48729
  side,
@@ -48674,35 +48743,57 @@ function Cell({
48674
48743
  const truncated = raw.length > inner ? `${raw.slice(0, inner - 1)}\u2026` : raw;
48675
48744
  const padded = truncated.padEnd(inner);
48676
48745
  if (side.kind === "del") {
48677
- return /* @__PURE__ */ import_react25.default.createElement(Text, { color: "#fbc8c8", backgroundColor: "#2a1212" }, `${numStr} ${sign} ${padded}`);
48746
+ return /* @__PURE__ */ import_react24.default.createElement(Text, { color: "#fbc8c8", backgroundColor: "#2a1212" }, `${numStr} ${sign} ${padded}`);
48678
48747
  }
48679
48748
  if (side.kind === "add") {
48680
- return /* @__PURE__ */ import_react25.default.createElement(Text, { color: "#bef0c8", backgroundColor: "#0c2718" }, `${numStr} ${sign} ${padded}`);
48749
+ return /* @__PURE__ */ import_react24.default.createElement(Text, { color: "#bef0c8", backgroundColor: "#0c2718" }, `${numStr} ${sign} ${padded}`);
48681
48750
  }
48682
48751
  if (side.kind === "pad") {
48683
- return /* @__PURE__ */ import_react25.default.createElement(Text, { color: COLOR.info, dimColor: true, italic: !!raw }, `${numStr} ${sign} ${padded}`);
48752
+ return /* @__PURE__ */ import_react24.default.createElement(Text, { color: COLOR.info, dimColor: true, italic: !!raw }, `${numStr} ${sign} ${padded}`);
48684
48753
  }
48685
- return /* @__PURE__ */ import_react25.default.createElement(Text, { dimColor: true }, `${numStr} ${sign} ${padded}`);
48754
+ return /* @__PURE__ */ import_react24.default.createElement(Text, { dimColor: true }, `${numStr} ${sign} ${padded}`);
48686
48755
  }
48687
48756
 
48688
48757
  // src/cli/ui/EditConfirm.tsx
48689
48758
  var MODAL_OVERHEAD_ROWS = 18;
48690
48759
  var MIN_DIFF_ROWS = 8;
48691
- function EditConfirm({ block: block2, onChoose }) {
48760
+ function EditConfirm({ block: block2, blocks, onChoose }) {
48761
+ const effectiveBlocks = (0, import_react25.useMemo)(() => {
48762
+ if (blocks && blocks.length > 0) return [...blocks];
48763
+ return block2 ? [block2] : [];
48764
+ }, [block2, blocks]);
48765
+ const firstBlock = effectiveBlocks[0];
48692
48766
  const rows = useTotalRows();
48693
48767
  const allocated = useReserveRows("modal", {
48694
48768
  min: MODAL_OVERHEAD_ROWS + MIN_DIFF_ROWS,
48695
48769
  max: Math.max(MODAL_OVERHEAD_ROWS + MIN_DIFF_ROWS, rows - 4)
48696
48770
  });
48697
48771
  const budget2 = Math.max(MIN_DIFF_ROWS, allocated - MODAL_OVERHEAD_ROWS);
48698
- const allRows = (0, import_react26.useMemo)(
48699
- () => formatEditBlockSplit(block2, { contextLines: 2, maxLines: 1e5 }),
48700
- [block2]
48701
- );
48702
- const [scroll, setScroll] = (0, import_react26.useState)(0);
48772
+ const allRows = (0, import_react25.useMemo)(() => {
48773
+ const multi = effectiveBlocks.length > 1;
48774
+ return effectiveBlocks.flatMap((b, index) => {
48775
+ const diffRows = formatEditBlockSplit(b, { contextLines: 2, maxLines: 1e5 }).map(
48776
+ (row2) => ({
48777
+ kind: "diff",
48778
+ key: diffRowKey(b, row2),
48779
+ row: row2
48780
+ })
48781
+ );
48782
+ if (!multi) return diffRows;
48783
+ return [
48784
+ {
48785
+ kind: "header",
48786
+ key: `h:${b.path}:${b.search.length}:${b.replace.length}`,
48787
+ text: `${index + 1}. ${b.path}`
48788
+ },
48789
+ ...diffRows
48790
+ ];
48791
+ });
48792
+ }, [effectiveBlocks]);
48793
+ const [scroll, setScroll] = (0, import_react25.useState)(0);
48703
48794
  const maxScroll = Math.max(0, allRows.length - budget2);
48704
48795
  const effectiveScroll = Math.min(scroll, maxScroll);
48705
- const [phase, setPhase] = (0, import_react26.useState)("review");
48796
+ const [phase, setPhase] = (0, import_react25.useState)("review");
48706
48797
  useKeystroke((ev) => {
48707
48798
  if (ev.paste) return;
48708
48799
  if (phase === "context") return;
@@ -48724,6 +48815,10 @@ function EditConfirm({ block: block2, onChoose }) {
48724
48815
  onChoose("flip-to-auto");
48725
48816
  return;
48726
48817
  }
48818
+ if (key.escape) {
48819
+ onChoose("reject");
48820
+ return;
48821
+ }
48727
48822
  if (key.downArrow || input === "j") {
48728
48823
  setScroll((s) => Math.min(maxScroll, s + 1));
48729
48824
  return;
@@ -48749,9 +48844,16 @@ function EditConfirm({ block: block2, onChoose }) {
48749
48844
  return;
48750
48845
  }
48751
48846
  });
48752
- const isNew = block2.search === "";
48753
- const removed = isNew ? 0 : (block2.search.match(/\n/g)?.length ?? 0) + 1;
48754
- const added = block2.replace === "" ? 0 : (block2.replace.match(/\n/g)?.length ?? 0) + 1;
48847
+ if (!firstBlock) return /* @__PURE__ */ import_react25.default.createElement(import_react25.default.Fragment, null);
48848
+ const isNew = effectiveBlocks.every((b) => b.search === "");
48849
+ const removed = effectiveBlocks.reduce(
48850
+ (sum, b) => sum + (b.search === "" ? 0 : countLines2(b.search)),
48851
+ 0
48852
+ );
48853
+ const added = effectiveBlocks.reduce(
48854
+ (sum, b) => sum + (b.replace === "" ? 0 : countLines2(b.replace)),
48855
+ 0
48856
+ );
48755
48857
  const tag2 = isNew ? t("editConfirm.newTag") : t("editConfirm.editTag");
48756
48858
  const tone = isNew ? "ok" : "warn";
48757
48859
  const glyph = isNew ? "\u271A" : "\u270E";
@@ -48771,7 +48873,7 @@ function EditConfirm({ block: block2, onChoose }) {
48771
48873
  );
48772
48874
  }
48773
48875
  if (phase === "context") {
48774
- return /* @__PURE__ */ import_react26.default.createElement(
48876
+ return /* @__PURE__ */ import_react25.default.createElement(
48775
48877
  ApprovalCard,
48776
48878
  {
48777
48879
  tone: "error",
@@ -48780,7 +48882,7 @@ function EditConfirm({ block: block2, onChoose }) {
48780
48882
  metaRight: t("shellConfirm.optional"),
48781
48883
  footerHint: t("editConfirm.denyFooter")
48782
48884
  },
48783
- /* @__PURE__ */ import_react26.default.createElement(
48885
+ /* @__PURE__ */ import_react25.default.createElement(
48784
48886
  DenyContextInput,
48785
48887
  {
48786
48888
  onSubmit: (context2) => onChoose("reject", context2),
@@ -48789,31 +48891,48 @@ function EditConfirm({ block: block2, onChoose }) {
48789
48891
  )
48790
48892
  );
48791
48893
  }
48792
- return /* @__PURE__ */ import_react26.default.createElement(
48894
+ return /* @__PURE__ */ import_react25.default.createElement(
48793
48895
  ApprovalCard,
48794
48896
  {
48795
48897
  tone,
48796
48898
  glyph,
48797
- title: `${tag2} ${block2.path}`,
48899
+ title: effectiveBlocks.length === 1 ? `${tag2} ${firstBlock.path}` : `${tag2} ${new Set(effectiveBlocks.map((b) => b.path)).size} files`,
48798
48900
  metaRight: metaParts.join(" \xB7 "),
48799
48901
  footerHint: t("editConfirm.footer")
48800
48902
  },
48801
- hiddenAbove > 0 ? /* @__PURE__ */ import_react26.default.createElement(Text, { dimColor: true }, t(hiddenAbove === 1 ? "editConfirm.linesAbove" : "editConfirm.linesAbovePlural", {
48903
+ hiddenAbove > 0 ? /* @__PURE__ */ import_react25.default.createElement(Text, { dimColor: true }, t(hiddenAbove === 1 ? "editConfirm.linesAbove" : "editConfirm.linesAbovePlural", {
48802
48904
  count: hiddenAbove
48803
48905
  })) : null,
48804
- /* @__PURE__ */ import_react26.default.createElement(SplitDiff, { rows: visibleRows }),
48805
- /* @__PURE__ */ import_react26.default.createElement(Box_default, null, /* @__PURE__ */ import_react26.default.createElement(Text, { color: "#fbc8c8", backgroundColor: "#2a1212" }, t("editConfirm.oldLabel")), /* @__PURE__ */ import_react26.default.createElement(Text, null, " "), /* @__PURE__ */ import_react26.default.createElement(Text, { color: "#bef0c8", backgroundColor: "#0c2718" }, t("editConfirm.newLabel")), /* @__PURE__ */ import_react26.default.createElement(Text, { dimColor: true }, t("editConfirm.sideBySide"))),
48806
- hiddenBelow > 0 ? /* @__PURE__ */ import_react26.default.createElement(Text, { dimColor: true }, t(hiddenBelow === 1 ? "editConfirm.linesBelow" : "editConfirm.linesBelowPlural", {
48906
+ visibleRows.map(
48907
+ (row2) => row2.kind === "header" ? /* @__PURE__ */ import_react25.default.createElement(Text, { key: row2.key, bold: true }, row2.text) : /* @__PURE__ */ import_react25.default.createElement(SplitDiff, { key: row2.key, rows: [row2.row] })
48908
+ ),
48909
+ /* @__PURE__ */ import_react25.default.createElement(Box_default, null, /* @__PURE__ */ import_react25.default.createElement(Text, { color: "#fbc8c8", backgroundColor: "#2a1212" }, t("editConfirm.oldLabel")), /* @__PURE__ */ import_react25.default.createElement(Text, null, " "), /* @__PURE__ */ import_react25.default.createElement(Text, { color: "#bef0c8", backgroundColor: "#0c2718" }, t("editConfirm.newLabel")), /* @__PURE__ */ import_react25.default.createElement(Text, { dimColor: true }, t("editConfirm.sideBySide"))),
48910
+ hiddenBelow > 0 ? /* @__PURE__ */ import_react25.default.createElement(Text, { dimColor: true }, t(hiddenBelow === 1 ? "editConfirm.linesBelow" : "editConfirm.linesBelowPlural", {
48807
48911
  count: hiddenBelow
48808
48912
  })) : null
48809
48913
  );
48810
48914
  }
48915
+ function countLines2(text) {
48916
+ return (text.match(/\n/g)?.length ?? 0) + 1;
48917
+ }
48918
+ function diffRowKey(block2, row2) {
48919
+ return [
48920
+ "d",
48921
+ block2.path,
48922
+ row2.left.num ?? "x",
48923
+ row2.right.num ?? "x",
48924
+ row2.left.kind,
48925
+ row2.right.kind,
48926
+ row2.left.text,
48927
+ row2.right.text
48928
+ ].join(":");
48929
+ }
48811
48930
 
48812
48931
  // src/cli/ui/LiveActivityArea.tsx
48813
- var import_react30 = __toESM(require_react(), 1);
48932
+ var import_react29 = __toESM(require_react(), 1);
48814
48933
 
48815
48934
  // src/cli/ui/layout/ToastRail.tsx
48816
- var import_react27 = __toESM(require_react(), 1);
48935
+ var import_react26 = __toESM(require_react(), 1);
48817
48936
  var TONE_COLOR = {
48818
48937
  ok: TONE.ok,
48819
48938
  info: TONE.brand,
@@ -48839,7 +48958,7 @@ function ToastRail() {
48839
48958
  const cols = stdout?.columns ?? 80;
48840
48959
  const rule = "\u2501".repeat(Math.max(20, cols - 4));
48841
48960
  const now = Date.now();
48842
- (0, import_react27.useEffect)(() => {
48961
+ (0, import_react26.useEffect)(() => {
48843
48962
  const timers = [];
48844
48963
  for (const t2 of toasts) {
48845
48964
  const remaining = Math.max(0, t2.ttlMs - (Date.now() - t2.bornAt));
@@ -48851,20 +48970,20 @@ function ToastRail() {
48851
48970
  }, [toasts, dispatch]);
48852
48971
  const visible = toasts.filter((t2) => now - t2.bornAt < t2.ttlMs);
48853
48972
  if (visible.length === 0) return null;
48854
- return /* @__PURE__ */ import_react27.default.createElement(Box_default, { flexDirection: "column" }, visible.map((t2) => {
48973
+ return /* @__PURE__ */ import_react26.default.createElement(Box_default, { flexDirection: "column" }, visible.map((t2) => {
48855
48974
  const color = TONE_COLOR[t2.tone];
48856
48975
  const glyph = TONE_GLYPH[t2.tone];
48857
48976
  const body = bodyColor(t2, now);
48858
48977
  const remainingSec = Math.max(0, Math.ceil((t2.ttlMs - (now - t2.bornAt)) / 1e3));
48859
- return /* @__PURE__ */ import_react27.default.createElement(Box_default, { key: t2.id, flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ import_react27.default.createElement(Text, { color }, rule), /* @__PURE__ */ import_react27.default.createElement(Box_default, { flexDirection: "row" }, /* @__PURE__ */ import_react27.default.createElement(Text, { color }, glyph), /* @__PURE__ */ import_react27.default.createElement(Text, { bold: true, color: body }, ` ${t2.title}`), t2.detail !== void 0 && /* @__PURE__ */ import_react27.default.createElement(Text, { color: FG.sub }, ` \xB7 ${t2.detail}`), /* @__PURE__ */ import_react27.default.createElement(Box_default, { flexGrow: 1 }), /* @__PURE__ */ import_react27.default.createElement(Text, { color: FG.faint }, `${remainingSec}s`)));
48978
+ return /* @__PURE__ */ import_react26.default.createElement(Box_default, { key: t2.id, flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ import_react26.default.createElement(Text, { color }, rule), /* @__PURE__ */ import_react26.default.createElement(Box_default, { flexDirection: "row" }, /* @__PURE__ */ import_react26.default.createElement(Text, { color }, glyph), /* @__PURE__ */ import_react26.default.createElement(Text, { bold: true, color: body }, ` ${t2.title}`), t2.detail !== void 0 && /* @__PURE__ */ import_react26.default.createElement(Text, { color: FG.sub }, ` \xB7 ${t2.detail}`), /* @__PURE__ */ import_react26.default.createElement(Box_default, { flexGrow: 1 }), /* @__PURE__ */ import_react26.default.createElement(Text, { color: FG.faint }, `${remainingSec}s`)));
48860
48979
  }));
48861
48980
  }
48862
48981
 
48863
48982
  // src/cli/ui/layout/plan-live-row.tsx
48864
- var import_react29 = __toESM(require_react(), 1);
48983
+ var import_react28 = __toESM(require_react(), 1);
48865
48984
 
48866
48985
  // src/cli/ui/cards/PlanCard.tsx
48867
- var import_react28 = __toESM(require_react(), 1);
48986
+ var import_react27 = __toESM(require_react(), 1);
48868
48987
  var STATUS_GLYPH = {
48869
48988
  queued: "\u25CB",
48870
48989
  running: "\u25CF",
@@ -48890,11 +49009,11 @@ function PlanCard({ card }) {
48890
49009
  const hasRunning = card.steps.some((s) => s.status === "running");
48891
49010
  const cardTone = hasRunning ? toneActive.accent : tone.accent;
48892
49011
  const window2 = pickWindow(card.steps);
48893
- return /* @__PURE__ */ import_react28.default.createElement(Card, { tone: cardTone }, /* @__PURE__ */ import_react28.default.createElement(CardHeader, { glyph: "\u25CF", tone: cardTone, title: card.title, meta: [progress] }), window2.hiddenBefore > 0 ? /* @__PURE__ */ import_react28.default.createElement(Box_default, { flexDirection: "row", gap: 1 }, /* @__PURE__ */ import_react28.default.createElement(Text, { color: tone.ok }, "\u2713"), /* @__PURE__ */ import_react28.default.createElement(Text, { color: fg.faint }, `\u22EF ${window2.hiddenBefore} ${t("cardLabels.done")}`)) : null, window2.steps.map((step) => {
49012
+ return /* @__PURE__ */ import_react27.default.createElement(Card, { tone: cardTone }, /* @__PURE__ */ import_react27.default.createElement(CardHeader, { glyph: "\u25CF", tone: cardTone, title: card.title, meta: [progress] }), window2.hiddenBefore > 0 ? /* @__PURE__ */ import_react27.default.createElement(Box_default, { flexDirection: "row", gap: 1 }, /* @__PURE__ */ import_react27.default.createElement(Text, { color: tone.ok }, "\u2713"), /* @__PURE__ */ import_react27.default.createElement(Text, { color: fg.faint }, `\u22EF ${window2.hiddenBefore} ${t("cardLabels.done")}`)) : null, window2.steps.map((step) => {
48894
49013
  const isActive = step.status === "running";
48895
49014
  const titleColor = isActive ? fg.strong : fg.sub;
48896
- return /* @__PURE__ */ import_react28.default.createElement(Box_default, { key: step.id, flexDirection: "row", gap: 1 }, /* @__PURE__ */ import_react28.default.createElement(Text, { color: statusColor[step.status] }, STATUS_GLYPH[step.status]), /* @__PURE__ */ import_react28.default.createElement(Text, { bold: isActive, color: titleColor }, `${step.indexLabel}. ${step.title}`), isActive ? /* @__PURE__ */ import_react28.default.createElement(Text, { color: toneActive.brand }, t("cardLabels.inProgress")) : null);
48897
- }), window2.hiddenAfter > 0 ? /* @__PURE__ */ import_react28.default.createElement(Box_default, { flexDirection: "row", gap: 1 }, /* @__PURE__ */ import_react28.default.createElement(Text, { color: fg.faint }, "\u25CB"), /* @__PURE__ */ import_react28.default.createElement(Text, { color: fg.faint }, `\u22EF ${window2.hiddenAfter} ${t("cardLabels.upcoming")}`)) : null);
49015
+ return /* @__PURE__ */ import_react27.default.createElement(Box_default, { key: step.id, flexDirection: "row", gap: 1 }, /* @__PURE__ */ import_react27.default.createElement(Text, { color: statusColor[step.status] }, STATUS_GLYPH[step.status]), /* @__PURE__ */ import_react27.default.createElement(Text, { bold: isActive, color: titleColor }, `${step.indexLabel}. ${step.title}`), isActive ? /* @__PURE__ */ import_react27.default.createElement(Text, { color: toneActive.brand }, t("cardLabels.inProgress")) : null);
49016
+ }), window2.hiddenAfter > 0 ? /* @__PURE__ */ import_react27.default.createElement(Box_default, { flexDirection: "row", gap: 1 }, /* @__PURE__ */ import_react27.default.createElement(Text, { color: fg.faint }, "\u25CB"), /* @__PURE__ */ import_react27.default.createElement(Text, { color: fg.faint }, `\u22EF ${window2.hiddenAfter} ${t("cardLabels.upcoming")}`)) : null);
48898
49017
  }
48899
49018
  function pickWindow(steps) {
48900
49019
  if (steps.length <= VISIBLE_WINDOW) {
@@ -48936,11 +49055,11 @@ function PlanLiveRow() {
48936
49055
  return null;
48937
49056
  });
48938
49057
  if (!planCard) return null;
48939
- return /* @__PURE__ */ import_react29.default.createElement(PlanCard, { card: planCard });
49058
+ return /* @__PURE__ */ import_react28.default.createElement(PlanCard, { card: planCard });
48940
49059
  }
48941
49060
 
48942
49061
  // src/cli/ui/LiveActivityArea.tsx
48943
- var LiveActivityArea = import_react30.default.memo(
49062
+ var LiveActivityArea = import_react29.default.memo(
48944
49063
  ({
48945
49064
  noTakeoverOverlay,
48946
49065
  ongoingTool,
@@ -48953,16 +49072,16 @@ var LiveActivityArea = import_react30.default.memo(
48953
49072
  undoBanner,
48954
49073
  hideUndo
48955
49074
  }) => {
48956
- return /* @__PURE__ */ import_react30.default.createElement(Box_default, { flexDirection: "column", flexShrink: 0, flexWrap: "nowrap" }, noTakeoverOverlay && ongoingTool ? /* @__PURE__ */ import_react30.default.createElement(OngoingToolRow, { tool: ongoingTool, progress: toolProgress }) : null, noTakeoverOverlay && subagentActivities.length > 0 ? /* @__PURE__ */ import_react30.default.createElement(SubagentLiveStack, { activities: subagentActivities, max: 3 }) : null, noTakeoverOverlay && !ongoingTool && statusLine ? /* @__PURE__ */ import_react30.default.createElement(ThinkingRow, { text: statusLine }) : null, undoBanner && !hideUndo ? /* @__PURE__ */ import_react30.default.createElement(UndoBanner, { banner: undoBanner }) : null, noTakeoverOverlay && busy && !isStreaming && !ongoingTool && !statusLine ? /* @__PURE__ */ import_react30.default.createElement(ThinkingRow, { text: activityLabel }) : null, noTakeoverOverlay ? /* @__PURE__ */ import_react30.default.createElement(PlanLiveRow, null) : null, /* @__PURE__ */ import_react30.default.createElement(ToastRail, null));
49075
+ return /* @__PURE__ */ import_react29.default.createElement(Box_default, { flexDirection: "column", flexShrink: 0, flexWrap: "nowrap" }, noTakeoverOverlay && ongoingTool ? /* @__PURE__ */ import_react29.default.createElement(OngoingToolRow, { tool: ongoingTool, progress: toolProgress }) : null, noTakeoverOverlay && subagentActivities.length > 0 ? /* @__PURE__ */ import_react29.default.createElement(SubagentLiveStack, { activities: subagentActivities, max: 3 }) : null, noTakeoverOverlay && !ongoingTool && statusLine ? /* @__PURE__ */ import_react29.default.createElement(ThinkingRow, { text: statusLine }) : null, undoBanner && !hideUndo ? /* @__PURE__ */ import_react29.default.createElement(UndoBanner, { banner: undoBanner }) : null, noTakeoverOverlay && busy && !isStreaming && !ongoingTool && !statusLine ? /* @__PURE__ */ import_react29.default.createElement(ThinkingRow, { text: activityLabel }) : null, noTakeoverOverlay ? /* @__PURE__ */ import_react29.default.createElement(PlanLiveRow, null) : null, /* @__PURE__ */ import_react29.default.createElement(ToastRail, null));
48957
49076
  }
48958
49077
  );
48959
49078
  LiveActivityArea.displayName = "LiveActivityArea";
48960
49079
 
48961
49080
  // src/cli/ui/McpHub.tsx
48962
- var import_react33 = __toESM(require_react(), 1);
49081
+ var import_react32 = __toESM(require_react(), 1);
48963
49082
 
48964
49083
  // src/cli/ui/McpBrowser.tsx
48965
- var import_react31 = __toESM(require_react(), 1);
49084
+ var import_react30 = __toESM(require_react(), 1);
48966
49085
 
48967
49086
  // src/cli/ui/mcp-disable.ts
48968
49087
  function toggleMcpDisabled(action, name) {
@@ -49199,7 +49318,7 @@ function McpBrowser({
49199
49318
  postInfo,
49200
49319
  applyAppend
49201
49320
  }) {
49202
- const [index, setIndex] = (0, import_react31.useState)(0);
49321
+ const [index, setIndex] = (0, import_react30.useState)(0);
49203
49322
  const max = Math.max(0, servers.length - 1);
49204
49323
  useKeystroke((ev) => {
49205
49324
  if (ev.paste) return;
@@ -49218,13 +49337,13 @@ function McpBrowser({
49218
49337
  onClose();
49219
49338
  }
49220
49339
  });
49221
- return /* @__PURE__ */ import_react31.default.createElement(Box_default, { flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ import_react31.default.createElement(Box_default, null, /* @__PURE__ */ import_react31.default.createElement(Text, { bold: true, color: COLOR.brand }, t("mcpBrowser.title")), /* @__PURE__ */ import_react31.default.createElement(
49340
+ return /* @__PURE__ */ import_react30.default.createElement(Box_default, { flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ import_react30.default.createElement(Box_default, null, /* @__PURE__ */ import_react30.default.createElement(Text, { bold: true, color: COLOR.brand }, t("mcpBrowser.title")), /* @__PURE__ */ import_react30.default.createElement(
49222
49341
  Text,
49223
49342
  {
49224
49343
  dimColor: true
49225
49344
  },
49226
49345
  ` \xB7 ${configPath} \xB7 ${t("mcpBrowser.serverCount", { count: servers.length, s: servers.length === 1 ? "" : "s" })}`
49227
- )), /* @__PURE__ */ import_react31.default.createElement(Box_default, { marginTop: 1, flexDirection: "column" }, servers.length === 0 ? /* @__PURE__ */ import_react31.default.createElement(Text, { dimColor: true }, t("mcpBrowser.empty")) : servers.map((s, i) => /* @__PURE__ */ import_react31.default.createElement(ServerRow, { key: s.label + s.spec, server: s, active: i === index }))), /* @__PURE__ */ import_react31.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react31.default.createElement(Text, { dimColor: true }, t("mcpBrowser.footer"))));
49346
+ )), /* @__PURE__ */ import_react30.default.createElement(Box_default, { marginTop: 1, flexDirection: "column" }, servers.length === 0 ? /* @__PURE__ */ import_react30.default.createElement(Text, { dimColor: true }, t("mcpBrowser.empty")) : servers.map((s, i) => /* @__PURE__ */ import_react30.default.createElement(ServerRow, { key: s.label + s.spec, server: s, active: i === index }))), /* @__PURE__ */ import_react30.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react30.default.createElement(Text, { dimColor: true }, t("mcpBrowser.footer"))));
49228
49347
  }
49229
49348
  function ServerRow({ server, active }) {
49230
49349
  const { label, toolCount, report } = server;
@@ -49233,7 +49352,7 @@ function ServerRow({ server, active }) {
49233
49352
  const elapsed = report.elapsedMs;
49234
49353
  const health = healthBadge(elapsed);
49235
49354
  const counts = `${toolCount} tools \xB7 ${resourceCount} resources \xB7 ${promptCount} prompts`;
49236
- return /* @__PURE__ */ import_react31.default.createElement(Box_default, { flexDirection: "column", marginBottom: active ? 1 : 0 }, /* @__PURE__ */ import_react31.default.createElement(Box_default, null, /* @__PURE__ */ import_react31.default.createElement(Text, { color: active ? COLOR.brand : void 0 }, active ? "\u25B8 " : " "), /* @__PURE__ */ import_react31.default.createElement(Text, { bold: active, color: active ? "#e6edf3" : void 0 }, label.padEnd(14)), /* @__PURE__ */ import_react31.default.createElement(Text, { color: health.color }, `${health.glyph} ${health.label}`), /* @__PURE__ */ import_react31.default.createElement(Text, { dimColor: true }, ` ${counts}`)), active ? /* @__PURE__ */ import_react31.default.createElement(Box_default, null, /* @__PURE__ */ import_react31.default.createElement(Text, { dimColor: true }, ` ${capabilityList(server)}`)) : null);
49355
+ return /* @__PURE__ */ import_react30.default.createElement(Box_default, { flexDirection: "column", marginBottom: active ? 1 : 0 }, /* @__PURE__ */ import_react30.default.createElement(Box_default, null, /* @__PURE__ */ import_react30.default.createElement(Text, { color: active ? COLOR.brand : void 0 }, active ? "\u25B8 " : " "), /* @__PURE__ */ import_react30.default.createElement(Text, { bold: active, color: active ? "#e6edf3" : void 0 }, label.padEnd(14)), /* @__PURE__ */ import_react30.default.createElement(Text, { color: health.color }, `${health.glyph} ${health.label}`), /* @__PURE__ */ import_react30.default.createElement(Text, { dimColor: true }, ` ${counts}`)), active ? /* @__PURE__ */ import_react30.default.createElement(Box_default, null, /* @__PURE__ */ import_react30.default.createElement(Text, { dimColor: true }, ` ${capabilityList(server)}`)) : null);
49237
49356
  }
49238
49357
  function capabilityList(s) {
49239
49358
  const caps = ["tools/list", "tools/call"];
@@ -49243,7 +49362,7 @@ function capabilityList(s) {
49243
49362
  }
49244
49363
 
49245
49364
  // src/cli/ui/McpMarketplace.tsx
49246
- var import_react32 = __toESM(require_react(), 1);
49365
+ var import_react31 = __toESM(require_react(), 1);
49247
49366
  var VISIBLE_ROWS = 10;
49248
49367
  function buildMarketplacePickerSnapshot(args) {
49249
49368
  return {
@@ -49288,7 +49407,7 @@ function isInstalled(installedSpecs, entry) {
49288
49407
  }
49289
49408
  }
49290
49409
  function McpMarketplace({ onClose, postInfo, reloadMcp, pickerPorts }) {
49291
- const [state, setState] = (0, import_react32.useState)({
49410
+ const [state, setState] = (0, import_react31.useState)({
49292
49411
  handle: null,
49293
49412
  loading: true,
49294
49413
  query: "",
@@ -49296,7 +49415,7 @@ function McpMarketplace({ onClose, postInfo, reloadMcp, pickerPorts }) {
49296
49415
  status: t("mcpMarketplace.opening"),
49297
49416
  installedSpecs: readInstalledSpecs()
49298
49417
  });
49299
- (0, import_react32.useEffect)(() => {
49418
+ (0, import_react31.useEffect)(() => {
49300
49419
  let cancelled = false;
49301
49420
  (async () => {
49302
49421
  try {
@@ -49321,12 +49440,12 @@ function McpMarketplace({ onClose, postInfo, reloadMcp, pickerPorts }) {
49321
49440
  cancelled = true;
49322
49441
  };
49323
49442
  }, []);
49324
- const filtered = (0, import_react32.useMemo)(() => {
49443
+ const filtered = (0, import_react31.useMemo)(() => {
49325
49444
  if (!state.handle) return [];
49326
49445
  return rankAndFilter(state.handle.cache.entries, state.query);
49327
49446
  }, [state.handle, state.query]);
49328
49447
  const selected = filtered[state.selected];
49329
- const fetchMore = (0, import_react32.useCallback)(async () => {
49448
+ const fetchMore = (0, import_react31.useCallback)(async () => {
49330
49449
  if (!state.handle || state.loading) return;
49331
49450
  if (state.handle.cache.pagination.nextCursor === null) {
49332
49451
  setState((s) => ({ ...s, status: t("mcpMarketplace.allLoaded") }));
@@ -49344,7 +49463,7 @@ function McpMarketplace({ onClose, postInfo, reloadMcp, pickerPorts }) {
49344
49463
  setState((s) => ({ ...s, loading: false, status: `error: ${err.message}` }));
49345
49464
  }
49346
49465
  }, [state.handle, state.loading]);
49347
- const doUninstall = (0, import_react32.useCallback)(
49466
+ const doUninstall = (0, import_react31.useCallback)(
49348
49467
  async (entry, installed) => {
49349
49468
  const cfg = readConfig();
49350
49469
  const next = (cfg.mcp ?? []).filter((s) => s !== installed);
@@ -49365,7 +49484,7 @@ function McpMarketplace({ onClose, postInfo, reloadMcp, pickerPorts }) {
49365
49484
  },
49366
49485
  [postInfo, reloadMcp]
49367
49486
  );
49368
- const doInstall = (0, import_react32.useCallback)(
49487
+ const doInstall = (0, import_react31.useCallback)(
49369
49488
  async (entry) => {
49370
49489
  let install = entry.install;
49371
49490
  if (!install && entry.source === "smithery") {
@@ -49426,7 +49545,7 @@ function McpMarketplace({ onClose, postInfo, reloadMcp, pickerPorts }) {
49426
49545
  },
49427
49546
  [postInfo, reloadMcp]
49428
49547
  );
49429
- const installOrToggle = (0, import_react32.useCallback)(
49548
+ const installOrToggle = (0, import_react31.useCallback)(
49430
49549
  async (entry) => {
49431
49550
  const installed = isInstalled(state.installedSpecs, entry);
49432
49551
  if (installed) await doUninstall(entry, installed);
@@ -49434,7 +49553,7 @@ function McpMarketplace({ onClose, postInfo, reloadMcp, pickerPorts }) {
49434
49553
  },
49435
49554
  [state.installedSpecs, doInstall, doUninstall]
49436
49555
  );
49437
- const pickerSnapshot = (0, import_react32.useMemo)(
49556
+ const pickerSnapshot = (0, import_react31.useMemo)(
49438
49557
  () => buildMarketplacePickerSnapshot({
49439
49558
  filtered,
49440
49559
  installedSpecs: state.installedSpecs,
@@ -49514,31 +49633,31 @@ function McpMarketplace({ onClose, postInfo, reloadMcp, pickerPorts }) {
49514
49633
  setState((s) => ({ ...s, query: s.query + ev.input, selected: 0 }));
49515
49634
  }
49516
49635
  });
49517
- const overlay = (0, import_react32.useMemo)(() => loadOverlay("zh-CN"), []);
49636
+ const overlay = (0, import_react31.useMemo)(() => loadOverlay("zh-CN"), []);
49518
49637
  const start = Math.max(
49519
49638
  0,
49520
49639
  Math.min(state.selected - Math.floor(VISIBLE_ROWS / 2), filtered.length - VISIBLE_ROWS)
49521
49640
  );
49522
49641
  const window2 = filtered.slice(Math.max(0, start), Math.max(0, start) + VISIBLE_ROWS);
49523
- return /* @__PURE__ */ import_react32.default.createElement(Box_default, { flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ import_react32.default.createElement(Box_default, null, /* @__PURE__ */ import_react32.default.createElement(Text, { bold: true, color: COLOR.brand }, "\u25C8 MCP marketplace"), /* @__PURE__ */ import_react32.default.createElement(Text, { dimColor: true }, ` \xB7 ${state.status}`)), /* @__PURE__ */ import_react32.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react32.default.createElement(Text, null, t("mcpMarketplace.filter")), /* @__PURE__ */ import_react32.default.createElement(Text, null, state.query || t("mcpMarketplace.filterPlaceholder")), /* @__PURE__ */ import_react32.default.createElement(
49642
+ return /* @__PURE__ */ import_react31.default.createElement(Box_default, { flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ import_react31.default.createElement(Box_default, null, /* @__PURE__ */ import_react31.default.createElement(Text, { bold: true, color: COLOR.brand }, "\u25C8 MCP marketplace"), /* @__PURE__ */ import_react31.default.createElement(Text, { dimColor: true }, ` \xB7 ${state.status}`)), /* @__PURE__ */ import_react31.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react31.default.createElement(Text, null, t("mcpMarketplace.filter")), /* @__PURE__ */ import_react31.default.createElement(Text, null, state.query || t("mcpMarketplace.filterPlaceholder")), /* @__PURE__ */ import_react31.default.createElement(
49524
49643
  Text,
49525
49644
  {
49526
49645
  dimColor: true
49527
49646
  },
49528
49647
  ` ${t(filtered.length === 1 ? "mcpMarketplace.matchSingular" : "mcpMarketplace.matchPlural", { n: filtered.length })}`
49529
- )), /* @__PURE__ */ import_react32.default.createElement(Box_default, { marginTop: 1, flexDirection: "column" }, window2.length === 0 ? /* @__PURE__ */ import_react32.default.createElement(Text, { dimColor: true }, state.loading ? t("mcpMarketplace.loading") : t("mcpMarketplace.noEntries")) : window2.map((e, i) => {
49648
+ )), /* @__PURE__ */ import_react31.default.createElement(Box_default, { marginTop: 1, flexDirection: "column" }, window2.length === 0 ? /* @__PURE__ */ import_react31.default.createElement(Text, { dimColor: true }, state.loading ? t("mcpMarketplace.loading") : t("mcpMarketplace.noEntries")) : window2.map((e, i) => {
49530
49649
  const idx = (start || 0) + i;
49531
49650
  const active = idx === state.selected;
49532
49651
  const tag2 = e.source === "official" ? "[off]" : e.source === "smithery" ? "[smt]" : "[loc]";
49533
49652
  const installedSpec = isInstalled(state.installedSpecs, e);
49534
49653
  const installedBadge = installedSpec ? " \u2713" : "";
49535
49654
  const pop = e.popularity !== void 0 ? ` \xB7 ${e.popularity.toLocaleString()}` : "";
49536
- return /* @__PURE__ */ import_react32.default.createElement(Box_default, { key: e.name }, /* @__PURE__ */ import_react32.default.createElement(Text, { color: active ? COLOR.brand : void 0 }, active ? "\u25B8 " : " "), /* @__PURE__ */ import_react32.default.createElement(Text, { bold: active }, e.name.padEnd(38).slice(0, 38)), /* @__PURE__ */ import_react32.default.createElement(Text, { dimColor: true }, ` ${tag2}${pop}${installedBadge}`));
49537
- })), selected ? /* @__PURE__ */ import_react32.default.createElement(Box_default, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ import_react32.default.createElement(Text, { bold: true }, overlay?.[selected.name]?.title ?? selected.title, overlay?.[selected.name] ? /* @__PURE__ */ import_react32.default.createElement(Text, { dimColor: true }, ` \xB7 ${selected.title}`) : null), /* @__PURE__ */ import_react32.default.createElement(Text, { dimColor: true }, overlay?.[selected.name]?.description ?? selected.description?.slice(0, 200) ?? null), selected.install ? /* @__PURE__ */ import_react32.default.createElement(Text, { dimColor: true }, t("mcpMarketplace.specLine", {
49655
+ return /* @__PURE__ */ import_react31.default.createElement(Box_default, { key: e.name }, /* @__PURE__ */ import_react31.default.createElement(Text, { color: active ? COLOR.brand : void 0 }, active ? "\u25B8 " : " "), /* @__PURE__ */ import_react31.default.createElement(Text, { bold: active }, e.name.padEnd(38).slice(0, 38)), /* @__PURE__ */ import_react31.default.createElement(Text, { dimColor: true }, ` ${tag2}${pop}${installedBadge}`));
49656
+ })), selected ? /* @__PURE__ */ import_react31.default.createElement(Box_default, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ import_react31.default.createElement(Text, { bold: true }, overlay?.[selected.name]?.title ?? selected.title, overlay?.[selected.name] ? /* @__PURE__ */ import_react31.default.createElement(Text, { dimColor: true }, ` \xB7 ${selected.title}`) : null), /* @__PURE__ */ import_react31.default.createElement(Text, { dimColor: true }, overlay?.[selected.name]?.description ?? selected.description?.slice(0, 200) ?? null), selected.install ? /* @__PURE__ */ import_react31.default.createElement(Text, { dimColor: true }, t("mcpMarketplace.specLine", {
49538
49657
  runtime: selected.install.runtime,
49539
49658
  id: selected.install.packageId ?? selected.install.url ?? "\u2014",
49540
49659
  transport: selected.install.transport
49541
- })) : /* @__PURE__ */ import_react32.default.createElement(Text, { dimColor: true }, t("mcpMarketplace.smitheryDetail")), selected.install?.requiredEnv?.length ? /* @__PURE__ */ import_react32.default.createElement(Text, { color: "yellow" }, t("mcpMarketplace.needsEnv", { env: selected.install.requiredEnv.join(", ") })) : null) : null, /* @__PURE__ */ import_react32.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react32.default.createElement(Text, { dimColor: true }, t("mcpMarketplace.footerHint"))));
49660
+ })) : /* @__PURE__ */ import_react31.default.createElement(Text, { dimColor: true }, t("mcpMarketplace.smitheryDetail")), selected.install?.requiredEnv?.length ? /* @__PURE__ */ import_react31.default.createElement(Text, { color: "yellow" }, t("mcpMarketplace.needsEnv", { env: selected.install.requiredEnv.join(", ") })) : null) : null, /* @__PURE__ */ import_react31.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react31.default.createElement(Text, { dimColor: true }, t("mcpMarketplace.footerHint"))));
49542
49661
  }
49543
49662
 
49544
49663
  // src/cli/ui/McpHub.tsx
@@ -49552,19 +49671,19 @@ function McpHub({
49552
49671
  reloadMcp,
49553
49672
  pickerPorts
49554
49673
  }) {
49555
- const [tab, setTab] = (0, import_react33.useState)(initialTab);
49674
+ const [tab, setTab] = (0, import_react32.useState)(initialTab);
49556
49675
  useKeystroke((ev) => {
49557
49676
  if (ev.paste) return;
49558
49677
  if (ev.tab) setTab((t2) => t2 === "live" ? "marketplace" : "live");
49559
49678
  });
49560
- return /* @__PURE__ */ import_react33.default.createElement(Box_default, { flexDirection: "column" }, /* @__PURE__ */ import_react33.default.createElement(Box_default, { paddingX: 1 }, /* @__PURE__ */ import_react33.default.createElement(Text, { bold: true, color: COLOR.brand }, "\u25C8 MCP"), /* @__PURE__ */ import_react33.default.createElement(Text, null, " "), /* @__PURE__ */ import_react33.default.createElement(
49679
+ return /* @__PURE__ */ import_react32.default.createElement(Box_default, { flexDirection: "column" }, /* @__PURE__ */ import_react32.default.createElement(Box_default, { paddingX: 1 }, /* @__PURE__ */ import_react32.default.createElement(Text, { bold: true, color: COLOR.brand }, "\u25C8 MCP"), /* @__PURE__ */ import_react32.default.createElement(Text, null, " "), /* @__PURE__ */ import_react32.default.createElement(
49561
49680
  TabPill,
49562
49681
  {
49563
49682
  label: t("handlers.mcp.liveTab"),
49564
49683
  count: liveServers.length,
49565
49684
  active: tab === "live"
49566
49685
  }
49567
- ), /* @__PURE__ */ import_react33.default.createElement(Text, null, " "), /* @__PURE__ */ import_react33.default.createElement(TabPill, { label: t("handlers.mcp.marketplaceTab"), active: tab === "marketplace" }), /* @__PURE__ */ import_react33.default.createElement(Text, { dimColor: true }, ` ${t("handlers.mcp.tabHint")}`)), tab === "live" ? /* @__PURE__ */ import_react33.default.createElement(
49686
+ ), /* @__PURE__ */ import_react32.default.createElement(Text, null, " "), /* @__PURE__ */ import_react32.default.createElement(TabPill, { label: t("handlers.mcp.marketplaceTab"), active: tab === "marketplace" }), /* @__PURE__ */ import_react32.default.createElement(Text, { dimColor: true }, ` ${t("handlers.mcp.tabHint")}`)), tab === "live" ? /* @__PURE__ */ import_react32.default.createElement(
49568
49687
  McpBrowser,
49569
49688
  {
49570
49689
  servers: liveServers,
@@ -49573,7 +49692,7 @@ function McpHub({
49573
49692
  postInfo,
49574
49693
  applyAppend
49575
49694
  }
49576
- ) : /* @__PURE__ */ import_react33.default.createElement(
49695
+ ) : /* @__PURE__ */ import_react32.default.createElement(
49577
49696
  McpMarketplace,
49578
49697
  {
49579
49698
  onClose,
@@ -49586,13 +49705,13 @@ function McpHub({
49586
49705
  function TabPill({ label, count, active }) {
49587
49706
  const text = count !== void 0 ? `${label} (${count})` : label;
49588
49707
  if (active) {
49589
- return /* @__PURE__ */ import_react33.default.createElement(Text, { bold: true, color: COLOR.brand }, "[", text, "]");
49708
+ return /* @__PURE__ */ import_react32.default.createElement(Text, { bold: true, color: COLOR.brand }, "[", text, "]");
49590
49709
  }
49591
- return /* @__PURE__ */ import_react33.default.createElement(Text, { dimColor: true }, ` ${text} `);
49710
+ return /* @__PURE__ */ import_react32.default.createElement(Text, { dimColor: true }, ` ${text} `);
49592
49711
  }
49593
49712
 
49594
49713
  // src/cli/ui/ModelPicker.tsx
49595
- var import_react34 = __toESM(require_react(), 1);
49714
+ var import_react33 = __toESM(require_react(), 1);
49596
49715
  var PAGE_MARGIN2 = 8;
49597
49716
  var PRESET_NAMES = ["auto", "flash", "pro"];
49598
49717
  function ModelPicker({
@@ -49610,7 +49729,7 @@ function ModelPicker({
49610
49729
  const rows = [...presetRows, ...modelRows];
49611
49730
  const activePreset = detectActivePreset(current, currentEffort, currentAutoEscalate);
49612
49731
  const initialIndex = activePreset ? PRESET_NAMES.indexOf(activePreset) : presetRows.length + Math.max(0, modelList.indexOf(current));
49613
- const [focus, setFocus] = (0, import_react34.useState)(initialIndex);
49732
+ const [focus, setFocus] = (0, import_react33.useState)(initialIndex);
49614
49733
  const { stdout } = use_stdout_default();
49615
49734
  const termRows = stdout?.rows ?? 40;
49616
49735
  const visibleCount = Math.max(6, termRows - PAGE_MARGIN2);
@@ -49639,13 +49758,13 @@ function ModelPicker({
49639
49758
  const loading = models === null;
49640
49759
  const empty = models !== null && models.length === 0;
49641
49760
  let lastSection = null;
49642
- return /* @__PURE__ */ import_react34.default.createElement(Box_default, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ import_react34.default.createElement(Box_default, null, /* @__PURE__ */ import_react34.default.createElement(Text, { bold: true, color: TONE.brand }, t("modelPicker.header")), /* @__PURE__ */ import_react34.default.createElement(Text, { color: FG.meta }, loading ? t("modelPicker.loading") : empty ? t("modelPicker.catalogEmpty") : t("modelPicker.modelsAvailable", { count: modelList.length }))), /* @__PURE__ */ import_react34.default.createElement(Box_default, { height: 1 }), hiddenAbove > 0 ? /* @__PURE__ */ import_react34.default.createElement(Box_default, null, /* @__PURE__ */ import_react34.default.createElement(Text, { color: FG.faint }, ` \u2026 ${hiddenAbove}`)) : null, shown.map((row2, i) => {
49761
+ return /* @__PURE__ */ import_react33.default.createElement(Box_default, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ import_react33.default.createElement(Box_default, null, /* @__PURE__ */ import_react33.default.createElement(Text, { bold: true, color: TONE.brand }, t("modelPicker.header")), /* @__PURE__ */ import_react33.default.createElement(Text, { color: FG.meta }, loading ? t("modelPicker.loading") : empty ? t("modelPicker.catalogEmpty") : t("modelPicker.modelsAvailable", { count: modelList.length }))), /* @__PURE__ */ import_react33.default.createElement(Box_default, { height: 1 }), hiddenAbove > 0 ? /* @__PURE__ */ import_react33.default.createElement(Box_default, null, /* @__PURE__ */ import_react33.default.createElement(Text, { color: FG.faint }, ` \u2026 ${hiddenAbove}`)) : null, shown.map((row2, i) => {
49643
49762
  const idx = start + i;
49644
49763
  const focused = idx === focus;
49645
49764
  const showHeader = row2.kind !== lastSection;
49646
49765
  lastSection = row2.kind;
49647
- const header = showHeader ? /* @__PURE__ */ import_react34.default.createElement(Box_default, { key: `hdr-${row2.kind}`, marginTop: idx === 0 ? 0 : 1 }, /* @__PURE__ */ import_react34.default.createElement(Text, { color: FG.meta }, row2.kind === "preset" ? t("modelPicker.presetsHeader") : t("modelPicker.modelsHeader"))) : null;
49648
- const body = row2.kind === "preset" ? /* @__PURE__ */ import_react34.default.createElement(
49766
+ const header = showHeader ? /* @__PURE__ */ import_react33.default.createElement(Box_default, { key: `hdr-${row2.kind}`, marginTop: idx === 0 ? 0 : 1 }, /* @__PURE__ */ import_react33.default.createElement(Text, { color: FG.meta }, row2.kind === "preset" ? t("modelPicker.presetsHeader") : t("modelPicker.modelsHeader"))) : null;
49767
+ const body = row2.kind === "preset" ? /* @__PURE__ */ import_react33.default.createElement(
49649
49768
  PresetRow,
49650
49769
  {
49651
49770
  key: `p-${row2.name}`,
@@ -49653,7 +49772,7 @@ function ModelPicker({
49653
49772
  focused,
49654
49773
  active: activePreset === row2.name
49655
49774
  }
49656
- ) : /* @__PURE__ */ import_react34.default.createElement(
49775
+ ) : /* @__PURE__ */ import_react33.default.createElement(
49657
49776
  ModelRow,
49658
49777
  {
49659
49778
  key: `m-${row2.id}`,
@@ -49662,8 +49781,8 @@ function ModelPicker({
49662
49781
  active: !activePreset && row2.id === current
49663
49782
  }
49664
49783
  );
49665
- return /* @__PURE__ */ import_react34.default.createElement(import_react34.default.Fragment, { key: `row-${idx}` }, header, body);
49666
- }), hiddenBelow > 0 ? /* @__PURE__ */ import_react34.default.createElement(Box_default, null, /* @__PURE__ */ import_react34.default.createElement(Text, { color: FG.faint }, t("cardLabels.more", { count: hiddenBelow }))) : null, /* @__PURE__ */ import_react34.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react34.default.createElement(Text, { color: FG.faint }, t("modelPicker.pickerFooter"))));
49784
+ return /* @__PURE__ */ import_react33.default.createElement(import_react33.default.Fragment, { key: `row-${idx}` }, header, body);
49785
+ }), hiddenBelow > 0 ? /* @__PURE__ */ import_react33.default.createElement(Box_default, null, /* @__PURE__ */ import_react33.default.createElement(Text, { color: FG.faint }, t("cardLabels.more", { count: hiddenBelow }))) : null, /* @__PURE__ */ import_react33.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react33.default.createElement(Text, { color: FG.faint }, t("modelPicker.pickerFooter"))));
49667
49786
  }
49668
49787
  function PresetRow({
49669
49788
  name,
@@ -49671,7 +49790,7 @@ function PresetRow({
49671
49790
  active
49672
49791
  }) {
49673
49792
  const desc = PRESET_DESCRIPTIONS[name];
49674
- return /* @__PURE__ */ import_react34.default.createElement(Box_default, null, /* @__PURE__ */ import_react34.default.createElement(Text, { color: focused ? TONE.brand : FG.faint }, focused ? " \u25B8 " : " "), /* @__PURE__ */ import_react34.default.createElement(Text, { bold: focused, color: focused ? FG.strong : FG.sub }, name.padEnd(8)), /* @__PURE__ */ import_react34.default.createElement(Text, { color: focused ? FG.body : FG.meta }, desc.headline.padEnd(28)), /* @__PURE__ */ import_react34.default.createElement(Text, { color: FG.meta }, ` ${desc.cost}`), active ? /* @__PURE__ */ import_react34.default.createElement(Text, { color: TONE.brand }, t("modelPicker.currentLabel")) : null);
49793
+ return /* @__PURE__ */ import_react33.default.createElement(Box_default, null, /* @__PURE__ */ import_react33.default.createElement(Text, { color: focused ? TONE.brand : FG.faint }, focused ? " \u25B8 " : " "), /* @__PURE__ */ import_react33.default.createElement(Text, { bold: focused, color: focused ? FG.strong : FG.sub }, name.padEnd(8)), /* @__PURE__ */ import_react33.default.createElement(Text, { color: focused ? FG.body : FG.meta }, desc.headline.padEnd(28)), /* @__PURE__ */ import_react33.default.createElement(Text, { color: FG.meta }, ` ${desc.cost}`), active ? /* @__PURE__ */ import_react33.default.createElement(Text, { color: TONE.brand }, t("modelPicker.currentLabel")) : null);
49675
49794
  }
49676
49795
  function ModelRow({
49677
49796
  id,
@@ -49679,7 +49798,7 @@ function ModelRow({
49679
49798
  active
49680
49799
  }) {
49681
49800
  const badge = modelBadgeFor(id);
49682
- return /* @__PURE__ */ import_react34.default.createElement(Box_default, null, /* @__PURE__ */ import_react34.default.createElement(Text, { color: focused ? TONE.brand : FG.faint }, focused ? " \u25B8 " : " "), /* @__PURE__ */ import_react34.default.createElement(Text, { bold: focused, color: focused ? FG.strong : FG.sub }, id.padEnd(24)), /* @__PURE__ */ import_react34.default.createElement(Text, null, " "), /* @__PURE__ */ import_react34.default.createElement(Pill, { label: badge.label, ...PILL_MODEL[badge.kind], bold: false }), active ? /* @__PURE__ */ import_react34.default.createElement(Text, { color: TONE.brand }, t("modelPicker.currentLabel")) : null);
49801
+ return /* @__PURE__ */ import_react33.default.createElement(Box_default, null, /* @__PURE__ */ import_react33.default.createElement(Text, { color: focused ? TONE.brand : FG.faint }, focused ? " \u25B8 " : " "), /* @__PURE__ */ import_react33.default.createElement(Text, { bold: focused, color: focused ? FG.strong : FG.sub }, id.padEnd(24)), /* @__PURE__ */ import_react33.default.createElement(Text, null, " "), /* @__PURE__ */ import_react33.default.createElement(Pill, { label: badge.label, ...PILL_MODEL[badge.kind], bold: false }), active ? /* @__PURE__ */ import_react33.default.createElement(Text, { color: TONE.brand }, t("modelPicker.currentLabel")) : null);
49683
49802
  }
49684
49803
  function detectActivePreset(model2, effort, autoEscalate) {
49685
49804
  for (const name of PRESET_NAMES) {
@@ -49699,7 +49818,7 @@ var FALLBACK_MODELS = [
49699
49818
 
49700
49819
  // src/cli/ui/PathConfirm.tsx
49701
49820
  import { homedir as homedir3 } from "os";
49702
- var import_react35 = __toESM(require_react(), 1);
49821
+ var import_react34 = __toESM(require_react(), 1);
49703
49822
  function tildeify(p) {
49704
49823
  const home = homedir3();
49705
49824
  if (!home) return p;
@@ -49718,9 +49837,9 @@ function PathConfirm({
49718
49837
  onChoose
49719
49838
  }) {
49720
49839
  useReserveRows("modal", { min: 8, max: 14 });
49721
- const [phase, setPhase] = (0, import_react35.useState)("pick");
49840
+ const [phase, setPhase] = (0, import_react34.useState)("pick");
49722
49841
  if (phase === "deny") {
49723
- return /* @__PURE__ */ import_react35.default.createElement(
49842
+ return /* @__PURE__ */ import_react34.default.createElement(
49724
49843
  ApprovalCard,
49725
49844
  {
49726
49845
  tone: "error",
@@ -49729,7 +49848,7 @@ function PathConfirm({
49729
49848
  metaRight: t("pathConfirm.optional"),
49730
49849
  footerHint: t("pathConfirm.denyFooter")
49731
49850
  },
49732
- /* @__PURE__ */ import_react35.default.createElement(
49851
+ /* @__PURE__ */ import_react34.default.createElement(
49733
49852
  DenyContextInput,
49734
49853
  {
49735
49854
  onSubmit: (context2) => onChoose("deny", context2 || void 0),
@@ -49738,7 +49857,7 @@ function PathConfirm({
49738
49857
  )
49739
49858
  );
49740
49859
  }
49741
- return /* @__PURE__ */ import_react35.default.createElement(
49860
+ return /* @__PURE__ */ import_react34.default.createElement(
49742
49861
  ApprovalCard,
49743
49862
  {
49744
49863
  tone: "warn",
@@ -49747,10 +49866,10 @@ function PathConfirm({
49747
49866
  metaRight: t("pathConfirm.awaiting"),
49748
49867
  footerHint: t("pathConfirm.pickFooter")
49749
49868
  },
49750
- /* @__PURE__ */ import_react35.default.createElement(Box_default, { marginBottom: 1 }, /* @__PURE__ */ import_react35.default.createElement(Text, { color: FG.faint }, t(intent === "write" ? "pathConfirm.subtitleWrite" : "pathConfirm.subtitleRead", {
49869
+ /* @__PURE__ */ import_react34.default.createElement(Box_default, { marginBottom: 1 }, /* @__PURE__ */ import_react34.default.createElement(Text, { color: FG.faint }, t(intent === "write" ? "pathConfirm.subtitleWrite" : "pathConfirm.subtitleRead", {
49751
49870
  tool: toolName
49752
49871
  }))),
49753
- /* @__PURE__ */ import_react35.default.createElement(
49872
+ /* @__PURE__ */ import_react34.default.createElement(
49754
49873
  InfoRows,
49755
49874
  {
49756
49875
  path: tildeify(path),
@@ -49758,7 +49877,7 @@ function PathConfirm({
49758
49877
  allowPrefix: tildeify(allowPrefix)
49759
49878
  }
49760
49879
  ),
49761
- /* @__PURE__ */ import_react35.default.createElement(
49880
+ /* @__PURE__ */ import_react34.default.createElement(
49762
49881
  SingleSelect,
49763
49882
  {
49764
49883
  initialValue: "run_once",
@@ -49804,7 +49923,7 @@ function InfoRows({
49804
49923
  rows.push({ label: t("pathConfirm.allowPrefixLabel"), value: allowPrefix });
49805
49924
  }
49806
49925
  const labelWidth = Math.max(...rows.map((r) => r.label.length));
49807
- return /* @__PURE__ */ import_react35.default.createElement(Box_default, { flexDirection: "column", marginBottom: 1 }, rows.map((r) => /* @__PURE__ */ import_react35.default.createElement(Box_default, { key: r.label, flexDirection: "row", gap: 1 }, /* @__PURE__ */ import_react35.default.createElement(Text, { color: FG.faint }, r.label.padEnd(labelWidth)), /* @__PURE__ */ import_react35.default.createElement(Text, { color: FG.body }, r.value))));
49926
+ return /* @__PURE__ */ import_react34.default.createElement(Box_default, { flexDirection: "column", marginBottom: 1 }, rows.map((r) => /* @__PURE__ */ import_react34.default.createElement(Box_default, { key: r.label, flexDirection: "row", gap: 1 }, /* @__PURE__ */ import_react34.default.createElement(Text, { color: FG.faint }, r.label.padEnd(labelWidth)), /* @__PURE__ */ import_react34.default.createElement(Text, { color: FG.body }, r.value))));
49808
49927
  }
49809
49928
 
49810
49929
  // src/cli/ui/PlanCheckpointConfirm.tsx
@@ -49812,6 +49931,24 @@ var import_react37 = __toESM(require_react(), 1);
49812
49931
 
49813
49932
  // src/cli/ui/PlanStepList.tsx
49814
49933
  var import_react36 = __toESM(require_react(), 1);
49934
+
49935
+ // src/cli/ui/char-bar.tsx
49936
+ var import_react35 = __toESM(require_react(), 1);
49937
+ function CharBar({
49938
+ pct,
49939
+ width = 24,
49940
+ color = COLOR.primary,
49941
+ emptyColor,
49942
+ showLabel = true,
49943
+ label
49944
+ }) {
49945
+ const total = Math.max(4, width);
49946
+ const clamped = Math.max(0, Math.min(100, Number.isFinite(pct) ? pct : 0));
49947
+ const filled = Math.round(total * clamped / 100);
49948
+ return /* @__PURE__ */ import_react35.default.createElement(Box_default, null, /* @__PURE__ */ import_react35.default.createElement(Text, { color }, GLYPH.block.repeat(filled)), /* @__PURE__ */ import_react35.default.createElement(Text, { color: emptyColor ?? COLOR.info, dimColor: true }, GLYPH.shade1.repeat(total - filled)), showLabel ? /* @__PURE__ */ import_react35.default.createElement(Text, { dimColor: true }, ` ${label ?? `${Math.round(clamped)}%`}`) : null);
49949
+ }
49950
+
49951
+ // src/cli/ui/PlanStepList.tsx
49815
49952
  function getStatus(stepId, statuses) {
49816
49953
  if (!statuses) return "pending";
49817
49954
  if (statuses instanceof Map) {
@@ -53036,7 +53173,7 @@ function relativeTime2(date) {
53036
53173
  // src/cli/ui/ShellConfirm.tsx
53037
53174
  import { homedir as homedir4 } from "os";
53038
53175
  var import_react44 = __toESM(require_react(), 1);
53039
- var CHROME_ROWS = 18;
53176
+ var CHROME_ROWS = 14;
53040
53177
  var MIN_COMMAND_LINES = 3;
53041
53178
  function clampCommand(command, max) {
53042
53179
  const lines = command.split("\n");
@@ -53066,7 +53203,6 @@ function ShellConfirm({
53066
53203
  const maxCommandLines = Math.max(MIN_COMMAND_LINES, totalRows - CHROME_ROWS);
53067
53204
  const { preview, hidden } = clampCommand(command, maxCommandLines);
53068
53205
  const isBackground = kind === "run_background";
53069
- const subtitle = isBackground ? t("shellConfirm.bgSubtitle") : t("shellConfirm.subtitle");
53070
53206
  const [phase, setPhase] = (0, import_react44.useState)("pick");
53071
53207
  if (phase === "deny") {
53072
53208
  return /* @__PURE__ */ import_react44.default.createElement(
@@ -53096,7 +53232,6 @@ function ShellConfirm({
53096
53232
  metaRight: t("shellConfirm.awaiting"),
53097
53233
  footerHint: t("shellConfirm.pickFooter")
53098
53234
  },
53099
- /* @__PURE__ */ import_react44.default.createElement(Box_default, { marginBottom: 1 }, /* @__PURE__ */ import_react44.default.createElement(Text, { color: FG.faint }, subtitle)),
53100
53235
  /* @__PURE__ */ import_react44.default.createElement(Box_default, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ import_react44.default.createElement(Box_default, null, /* @__PURE__ */ import_react44.default.createElement(Text, { bold: true, color: TONE.err }, "$ "), /* @__PURE__ */ import_react44.default.createElement(Text, { bold: true, color: FG.strong }, preview)), hidden > 0 ? /* @__PURE__ */ import_react44.default.createElement(Text, { color: FG.faint }, t(hidden === 1 ? "shellConfirm.previewMore" : "shellConfirm.previewMorePlural", {
53101
53236
  n: hidden
53102
53237
  })) : null),
@@ -53108,18 +53243,15 @@ function ShellConfirm({
53108
53243
  items: [
53109
53244
  {
53110
53245
  value: "run_once",
53111
- label: t("shellConfirm.allowOnce"),
53112
- hint: t("shellConfirm.allowOnceDesc")
53246
+ label: t("shellConfirm.allowOnce")
53113
53247
  },
53114
53248
  {
53115
53249
  value: "always_allow",
53116
- label: t("shellConfirm.allowAlways"),
53117
- hint: t("shellConfirm.allowAlwaysDesc", { prefix: allowPrefix })
53250
+ label: t("shellConfirm.allowAlways")
53118
53251
  },
53119
53252
  {
53120
53253
  value: "deny",
53121
- label: t("shellConfirm.deny"),
53122
- hint: t("shellConfirm.denyDesc")
53254
+ label: t("shellConfirm.deny")
53123
53255
  }
53124
53256
  ],
53125
53257
  onSubmit: (v) => {
@@ -53214,28 +53346,12 @@ function describeTheme(value, currentPreference, activeTheme) {
53214
53346
 
53215
53347
  // src/cli/ui/WelcomeBanner.tsx
53216
53348
  var import_react46 = __toESM(require_react(), 1);
53217
- var HINTS = ["/help", "/init", "/memory", "/cost"];
53218
53349
  function WelcomeBanner({
53219
53350
  inCodeMode,
53220
- workspaceRoot,
53221
- dashboardUrl
53351
+ workspaceRoot
53222
53352
  }) {
53223
53353
  const tagline = inCodeMode ? t("ui.taglineCode") : t("ui.taglineChat");
53224
- const taglineSub = t("ui.taglineSub");
53225
- const startTextRaw = t("ui.startSessionHint");
53226
- return /* @__PURE__ */ import_react46.default.createElement(Box_default, { flexDirection: "column", alignItems: "center", marginY: 1 }, /* @__PURE__ */ import_react46.default.createElement(
53227
- Box_default,
53228
- {
53229
- flexDirection: "column",
53230
- alignItems: "center",
53231
- borderStyle: "round",
53232
- borderColor: TONE.brand,
53233
- paddingX: 4,
53234
- paddingY: 1
53235
- },
53236
- /* @__PURE__ */ import_react46.default.createElement(Box_default, { flexDirection: "row", gap: 2 }, /* @__PURE__ */ import_react46.default.createElement(Text, { color: TONE.brand, bold: true }, "Carbon Code"), /* @__PURE__ */ import_react46.default.createElement(Text, { color: FG.faint }, "\xD7"), /* @__PURE__ */ import_react46.default.createElement(Box_default, { flexDirection: "row", gap: 1 }, /* @__PURE__ */ import_react46.default.createElement(Text, null, "\u{1F40B}"), /* @__PURE__ */ import_react46.default.createElement(Text, { color: TONE.accent, bold: true }, "DeepSeek"))),
53237
- /* @__PURE__ */ import_react46.default.createElement(Box_default, { marginTop: 1, flexDirection: "column", alignItems: "center" }, /* @__PURE__ */ import_react46.default.createElement(Text, { color: FG.body }, tagline), /* @__PURE__ */ import_react46.default.createElement(Text, { color: FG.meta }, taglineSub))
53238
- ), /* @__PURE__ */ import_react46.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react46.default.createElement(Text, { color: FG.sub }, startTextRaw)), /* @__PURE__ */ import_react46.default.createElement(Box_default, { marginTop: 1, flexDirection: "row", gap: 3 }, HINTS.map((cmd) => /* @__PURE__ */ import_react46.default.createElement(Text, { key: cmd, color: FG.meta }, cmd))), inCodeMode && workspaceRoot ? /* @__PURE__ */ import_react46.default.createElement(Box_default, { marginTop: 1, flexDirection: "row", gap: 1 }, /* @__PURE__ */ import_react46.default.createElement(Text, { color: TONE.brand }, t("welcomeBanner.workspace")), /* @__PURE__ */ import_react46.default.createElement(Text, { color: FG.faint }, "\xB7"), /* @__PURE__ */ import_react46.default.createElement(Text, { color: FG.body }, workspaceRoot), /* @__PURE__ */ import_react46.default.createElement(Text, { color: FG.faint }, t("welcomeBanner.relaunchHint"))) : null, dashboardUrl ? /* @__PURE__ */ import_react46.default.createElement(Box_default, { marginTop: 1, flexDirection: "row", gap: 1 }, /* @__PURE__ */ import_react46.default.createElement(Text, { color: TONE.brand, bold: true }, t("welcomeBanner.dashboard")), /* @__PURE__ */ import_react46.default.createElement(Text, { color: FG.faint }, "\xB7"), /* @__PURE__ */ import_react46.default.createElement(Text, { color: TONE.accent }, dashboardUrl)) : null);
53354
+ return /* @__PURE__ */ import_react46.default.createElement(Box_default, { flexDirection: "column", marginY: 1, paddingX: 1 }, /* @__PURE__ */ import_react46.default.createElement(Box_default, { flexDirection: "row", gap: 1 }, /* @__PURE__ */ import_react46.default.createElement(Text, { color: TONE.brand, bold: true }, "Carbon Code"), /* @__PURE__ */ import_react46.default.createElement(Text, { color: FG.meta }, tagline)), inCodeMode && workspaceRoot ? /* @__PURE__ */ import_react46.default.createElement(Box_default, { flexDirection: "row", gap: 1 }, /* @__PURE__ */ import_react46.default.createElement(Text, { color: FG.meta }, t("welcomeBanner.workspace")), /* @__PURE__ */ import_react46.default.createElement(Text, { color: FG.faint }, "\xB7"), /* @__PURE__ */ import_react46.default.createElement(Text, { color: FG.body }, workspaceRoot)) : null);
53239
53355
  }
53240
53356
 
53241
53357
  // src/cli/ui/WorkspacePicker.tsx
@@ -53660,6 +53776,70 @@ function formatUndoRows(results) {
53660
53776
  });
53661
53777
  }
53662
53778
 
53779
+ // src/cli/ui/edit-tool-gate.ts
53780
+ import { relative, resolve as resolve2 } from "path";
53781
+ var EDIT_TOOL_NAMES = /* @__PURE__ */ new Set(["edit_file", "write_file", "multi_edit", "apply_patch"]);
53782
+ function buildEditToolBlocks(name, args, rootDir) {
53783
+ if (!EDIT_TOOL_NAMES.has(name)) return null;
53784
+ if (name === "apply_patch") {
53785
+ const patch = typeof args.patch === "string" ? args.patch : "";
53786
+ if (!patch) return null;
53787
+ try {
53788
+ return parseUnifiedPatch(patch).map((block2) => {
53789
+ const relPath2 = normalizeToolPath(block2.path, rootDir);
53790
+ if (!relPath2) throw new Error("path escapes root");
53791
+ return { ...block2, path: relPath2 };
53792
+ });
53793
+ } catch {
53794
+ return null;
53795
+ }
53796
+ }
53797
+ if (name === "multi_edit") {
53798
+ const edits = Array.isArray(args.edits) ? args.edits : null;
53799
+ if (!edits || edits.length === 0) return null;
53800
+ const blocks = [];
53801
+ for (const edit2 of edits) {
53802
+ if (!edit2 || typeof edit2 !== "object") return null;
53803
+ const entry = edit2;
53804
+ const relPath2 = normalizeToolPath(entry.path, rootDir);
53805
+ if (!relPath2) return null;
53806
+ const search = typeof entry.search === "string" ? entry.search : "";
53807
+ const replace = typeof entry.replace === "string" ? entry.replace : "";
53808
+ blocks.push({ path: relPath2, search, replace, offset: 0 });
53809
+ }
53810
+ return blocks;
53811
+ }
53812
+ const relPath = normalizeToolPath(args.path, rootDir);
53813
+ if (!relPath) return null;
53814
+ if (name === "edit_file") {
53815
+ const search = typeof args.search === "string" ? args.search : "";
53816
+ const replace = typeof args.replace === "string" ? args.replace : "";
53817
+ if (!search) return null;
53818
+ return [{ path: relPath, search, replace, offset: 0 }];
53819
+ }
53820
+ const content = typeof args.content === "string" ? args.content : "";
53821
+ return [toWholeFileEditBlock(relPath, content, rootDir)];
53822
+ }
53823
+ function normalizeToolPath(raw, rootDir) {
53824
+ if (typeof raw !== "string" || raw.length === 0) return null;
53825
+ const absRoot = resolve2(rootDir);
53826
+ if (looksLikeAbsoluteSystemPath(raw)) {
53827
+ const abs2 = resolve2(raw);
53828
+ if (!pathIsUnder(abs2, absRoot)) return null;
53829
+ const rel2 = relative(absRoot, abs2);
53830
+ return rel2 ? rel2.replaceAll("\\", "/") : null;
53831
+ }
53832
+ let stripped = raw;
53833
+ while (stripped.startsWith("/") || stripped.startsWith("\\")) {
53834
+ stripped = stripped.slice(1);
53835
+ }
53836
+ if (!stripped) return null;
53837
+ const abs = resolve2(absRoot, stripped);
53838
+ if (!pathIsUnder(abs, absRoot)) return null;
53839
+ const rel = relative(absRoot, abs);
53840
+ return rel ? rel.replaceAll("\\", "/") : null;
53841
+ }
53842
+
53663
53843
  // src/cli/ui/effects/loop-to-dashboard.ts
53664
53844
  function loopEventToDashboard(ev, ctx) {
53665
53845
  const id = `${ctx.assistantId}-${ev.role}-${Date.now()}`;
@@ -53908,7 +54088,7 @@ function handleToolEvent(ev, ctx) {
53908
54088
  ctx.flush();
53909
54089
  ctx.setOngoingTool(null);
53910
54090
  ctx.setToolProgress(null);
53911
- ctx.translator.toolEnd(ev.content);
54091
+ ctx.translator.toolEnd(ev.content, ev.elapsedMs);
53912
54092
  ctx.toolStartedAtRef.current = null;
53913
54093
  if (ev.toolName === "mark_step_complete") {
53914
54094
  try {
@@ -53937,10 +54117,12 @@ function handleToolEvent(ev, ctx) {
53937
54117
 
53938
54118
  // src/cli/ui/hooks/useActivityPhase.ts
53939
54119
  function deriveActivityLabel(cards) {
53940
- if (cards.some((c) => c.kind === "reasoning" && c.streaming)) return "thinking\u2026";
54120
+ if (cards.some((c) => c.kind === "reasoning" && c.streaming)) {
54121
+ return t("ui.activityThinking");
54122
+ }
53941
54123
  const last = cards[cards.length - 1];
53942
- if (!last || last.kind === "user") return "waiting for model\u2026";
53943
- return "processing\u2026";
54124
+ if (!last || last.kind === "user") return t("ui.activityWaitingForModel");
54125
+ return t("ui.activityProcessing");
53944
54126
  }
53945
54127
  function useActivityLabel() {
53946
54128
  return useAgentState((s) => deriveActivityLabel(s.cards));
@@ -54834,38 +55016,16 @@ function ReasoningHeader({
54834
55016
  const headColor = card.aborted ? TONE.err : streamingActive ? TONE_ACTIVE.accent : isEmpty ? FG.faint : TONE.accent;
54835
55017
  const glyph = streamingActive ? "\u25CB" : "\u25CF";
54836
55018
  const title2 = streamingActive ? t("cardTitles.reasoningEllipsis") : card.aborted ? t("cardTitles.reasoningAborted") : t("cardTitles.reasoning");
54837
- const pill = isEmpty ? PILL_SECTION.empty : PILL_SECTION.reason;
54838
- const meta = [];
54839
- const m = headerMeta(card);
54840
- if (m) meta.push(m);
54841
- const duration = headerDuration(card);
54842
- if (duration) meta.push(duration);
54843
- const modelBadge = card.model ? modelBadgeFor(card.model) : null;
54844
55019
  return /* @__PURE__ */ import_react70.default.createElement(
54845
55020
  CardHeader,
54846
55021
  {
54847
55022
  glyph,
54848
55023
  tone: headColor,
54849
55024
  title: title2,
54850
- meta: meta.length > 0 ? meta : void 0,
54851
- right: /* @__PURE__ */ import_react70.default.createElement(import_react70.default.Fragment, null, streamingActive ? /* @__PURE__ */ import_react70.default.createElement(Spinner, { kind: "braille", color: TONE_ACTIVE.accent }) : null, modelBadge ? /* @__PURE__ */ import_react70.default.createElement(Pill, { label: modelBadge.label, ...PILL_MODEL[modelBadge.kind], bold: false }) : null)
55025
+ right: streamingActive ? /* @__PURE__ */ import_react70.default.createElement(Spinner, { kind: "braille", color: TONE_ACTIVE.accent }) : null
54852
55026
  }
54853
55027
  );
54854
55028
  }
54855
- function headerMeta(card) {
54856
- if (card.streaming) {
54857
- return card.tokens > 0 ? `${card.tokens.toLocaleString()} ${t("cardLabels.tok")}` : "";
54858
- }
54859
- const parts = [];
54860
- if (card.tokens > 0) parts.push(`${card.tokens.toLocaleString()} ${t("cardLabels.tok")}`);
54861
- if (card.paragraphs > 0) parts.push(`${card.paragraphs} ${t("cardLabels.pilcrow")}`);
54862
- return parts.join(" \xB7 ");
54863
- }
54864
- function headerDuration(card) {
54865
- if (card.streaming || !card.endedAt) return "";
54866
- const seconds = Math.max(0, (card.endedAt - card.ts) / 1e3);
54867
- return `${seconds.toFixed(1)}s`;
54868
- }
54869
55029
  function StreamingPreview({ card, visualLines, lineCells }) {
54870
55030
  const visible = visualLines.slice(-STREAMING_PREVIEW_LINES);
54871
55031
  const hasOverflow = visualLines.length > visible.length;
@@ -55295,50 +55455,6 @@ function plainText(tokens) {
55295
55455
  // src/cli/ui/cards/StreamingCard.tsx
55296
55456
  var STREAMING_PREVIEW_LINES2 = 4;
55297
55457
  var EXPANDED_MAX_LINES = 60;
55298
- var MIN_ELAPSED_MS_FOR_RATE = 500;
55299
- var MIN_TOKENS_FOR_RATE = 4;
55300
- var LIVE_TOKEN_CALIBRATION_CHARS = 1e3;
55301
- var ESTIMATED_CHARS_PER_TOKEN = 4;
55302
- function formatTokenCount(n) {
55303
- if (n >= 1e4) return `${(n / 1e3).toFixed(1)}k`;
55304
- if (n >= 1e3) return `${(n / 1e3).toFixed(2)}k`;
55305
- return String(n);
55306
- }
55307
- function rateFromTokens(tokens, startTs, endTs) {
55308
- const elapsedMs = endTs - startTs;
55309
- if (elapsedMs < MIN_ELAPSED_MS_FOR_RATE || tokens < MIN_TOKENS_FOR_RATE) {
55310
- return { tokens, tps: null };
55311
- }
55312
- return { tokens, tps: Math.round(tokens * 1e3 / elapsedMs) };
55313
- }
55314
- function tokenRate(text, startTs, endTs) {
55315
- return rateFromTokens(countTokensBounded(text), startTs, endTs);
55316
- }
55317
- function estimateLiveTokenCount(text, cardId, calibration, countFn = countTokensBounded) {
55318
- const chars = text.length;
55319
- const shouldCalibrate = chars > 0 && (!calibration || calibration.cardId !== cardId || chars < calibration.chars || calibration.chars === 0 && chars > 0 || chars - calibration.chars >= LIVE_TOKEN_CALIBRATION_CHARS);
55320
- if (shouldCalibrate) {
55321
- const tokens = countFn(text);
55322
- return { tokens, calibration: { cardId, chars, tokens }, exact: true };
55323
- }
55324
- const base = calibration?.cardId === cardId && chars >= calibration.chars ? calibration : null;
55325
- const baseChars = base?.chars ?? 0;
55326
- const baseTokens = base?.tokens ?? 0;
55327
- const estimatedDelta = Math.ceil(Math.max(0, chars - baseChars) / ESTIMATED_CHARS_PER_TOKEN);
55328
- return {
55329
- tokens: baseTokens + estimatedDelta,
55330
- calibration: base ?? { cardId, chars: 0, tokens: 0 },
55331
- exact: false
55332
- };
55333
- }
55334
- function useLiveTokenRate(card, enabled) {
55335
- const calibrationRef = import_react74.default.useRef(null);
55336
- if (!enabled) return { tokens: 0, tps: null };
55337
- const estimate = estimateLiveTokenCount(card.text, card.id, calibrationRef.current);
55338
- calibrationRef.current = estimate.calibration;
55339
- return rateFromTokens(estimate.tokens, card.ts, Date.now());
55340
- }
55341
- var PILL_RATE = { bg: "#11141a", fg: "#8b949e" };
55342
55458
  function StreamingCard({ card }) {
55343
55459
  const { stdout } = use_stdout_default();
55344
55460
  const cols = stdout?.columns ?? 80;
@@ -55349,23 +55465,10 @@ function StreamingCard({ card }) {
55349
55465
  max: reserveCap
55350
55466
  });
55351
55467
  useSlowTick();
55352
- const liveRate = useLiveTokenRate(card, !card.done && !card.aborted);
55353
55468
  const lineCells = Math.max(20, cols - 4);
55354
55469
  const visualLines = useIncrementalWrap(card.text, lineCells);
55355
- const modelBadge = card.model ? modelBadgeFor(card.model) : null;
55356
- const modelPill = modelBadge ? /* @__PURE__ */ import_react74.default.createElement(Pill, { label: modelBadge.label, ...PILL_MODEL[modelBadge.kind], bold: false }) : null;
55357
55470
  if (card.done && !card.aborted) {
55358
- const { tokens, tps } = tokenRate(card.text, card.ts, card.endedAt ?? Date.now());
55359
- const ratePill = tokens >= MIN_TOKENS_FOR_RATE && tps !== null ? /* @__PURE__ */ import_react74.default.createElement(Pill, { label: `${formatTokenCount(tokens)} tok \xB7 ${tps} t/s`, ...PILL_RATE, bold: false }) : null;
55360
- return /* @__PURE__ */ import_react74.default.createElement(Card, { tone: TONE.ok }, /* @__PURE__ */ import_react74.default.createElement(
55361
- CardHeader,
55362
- {
55363
- glyph: "\u2039",
55364
- tone: TONE.ok,
55365
- title: t("cardTitles.reply"),
55366
- right: /* @__PURE__ */ import_react74.default.createElement(import_react74.default.Fragment, null, ratePill, modelPill)
55367
- }
55368
- ), /* @__PURE__ */ import_react74.default.createElement(Markdown, { text: card.text }));
55471
+ return /* @__PURE__ */ import_react74.default.createElement(Card, { tone: TONE.ok }, /* @__PURE__ */ import_react74.default.createElement(CardHeader, { glyph: "\u2039", tone: TONE.ok, title: t("cardTitles.reply") }), /* @__PURE__ */ import_react74.default.createElement(Markdown, { text: card.text }));
55369
55472
  }
55370
55473
  const cap = expanded ? EXPANDED_MAX_LINES : STREAMING_PREVIEW_LINES2;
55371
55474
  const visible = visualLines.slice(-cap);
@@ -55374,15 +55477,13 @@ function StreamingCard({ card }) {
55374
55477
  const headColor = aborted ? TONE.err : TONE_ACTIVE.brand;
55375
55478
  const glyph = aborted ? "\u2298" : "\u25CF";
55376
55479
  const headLabel = aborted ? t("cardLabels.aborted") : t("cardLabels.writing");
55377
- const liveRatePill = !aborted && liveRate.tokens >= MIN_TOKENS_FOR_RATE && liveRate.tps !== null ? /* @__PURE__ */ import_react74.default.createElement(Pill, { label: `${liveRate.tps} t/s`, ...PILL_RATE, bold: false }) : null;
55378
- const expandPill = !aborted ? /* @__PURE__ */ import_react74.default.createElement(Pill, { label: expanded ? "expanded \u2303o" : "preview \u2303o", ...PILL_RATE, bold: false }) : null;
55379
55480
  return /* @__PURE__ */ import_react74.default.createElement(Card, { tone: headColor }, /* @__PURE__ */ import_react74.default.createElement(
55380
55481
  CardHeader,
55381
55482
  {
55382
55483
  glyph,
55383
55484
  tone: headColor,
55384
55485
  title: headLabel,
55385
- right: /* @__PURE__ */ import_react74.default.createElement(import_react74.default.Fragment, null, liveRatePill, expandPill, aborted ? null : /* @__PURE__ */ import_react74.default.createElement(Spinner, { kind: "braille", color: TONE_ACTIVE.brand }), modelPill)
55486
+ right: aborted ? null : /* @__PURE__ */ import_react74.default.createElement(Spinner, { kind: "braille", color: TONE_ACTIVE.brand })
55386
55487
  }
55387
55488
  ), expanded && droppedAbove > 0 ? /* @__PURE__ */ import_react74.default.createElement(Text, { color: FG.faint }, t(droppedAbove === 1 ? "cardLabels.earlierLine" : "cardLabels.earlierLines", {
55388
55489
  count: droppedAbove
@@ -55403,7 +55504,7 @@ function SubAgentCard({ card }) {
55403
55504
  const runningChildren = card.children.filter((c) => !isChildDone(c)).length;
55404
55505
  const isRunning = card.status === "running";
55405
55506
  const inLive = (0, import_react75.useContext)(ActiveCardContext);
55406
- const headerMeta2 = isRunning ? runningChildren > 0 ? [`${runningChildren} ${t("cardLabels.runningLabel")}`] : [t("cardLabels.workingLabel")] : [{ text: card.status, color: headColor }];
55507
+ const headerMeta = isRunning ? runningChildren > 0 ? [`${runningChildren} ${t("cardLabels.runningLabel")}`] : [t("cardLabels.workingLabel")] : [{ text: card.status, color: headColor }];
55407
55508
  return /* @__PURE__ */ import_react75.default.createElement(Card, { tone: headColor }, /* @__PURE__ */ import_react75.default.createElement(
55408
55509
  CardHeader,
55409
55510
  {
@@ -55411,7 +55512,7 @@ function SubAgentCard({ card }) {
55411
55512
  tone: headColor,
55412
55513
  title: t("cardTitles.subagent"),
55413
55514
  subtitle: card.task,
55414
- meta: headerMeta2
55515
+ meta: headerMeta
55415
55516
  }
55416
55517
  ), card.name ? /* @__PURE__ */ import_react75.default.createElement(Text, { color: fg.faint }, `${t("cardLabels.agent")} \xB7 ${card.name}`) : null, card.tools && card.tools.length > 0 && /* @__PURE__ */ import_react75.default.createElement(Text, { color: fg.faint }, `${t("cardLabels.tools")} \xB7 ${card.tools.join(", ")}`), card.children.map((child) => /* @__PURE__ */ import_react75.default.createElement(Box_default, { key: child.id, flexDirection: "row", gap: 1 }, inLive ? null : /* @__PURE__ */ import_react75.default.createElement(Text, { color: tone.violet }, "\u23BF"), /* @__PURE__ */ import_react75.default.createElement(ChildRow, { card: child }))));
55417
55518
  }
@@ -55582,12 +55683,113 @@ function useIsInflight(id) {
55582
55683
  var noop = () => {
55583
55684
  };
55584
55685
 
55686
+ // src/cli/ui/tool-summary.ts
55687
+ var MAX_SUMMARY_CHARS = 80;
55688
+ var TRAILING_ELLIPSIS = "\u2026";
55689
+ function clip(s, max) {
55690
+ if (s.length <= max) return s;
55691
+ return s.slice(0, Math.max(1, max - TRAILING_ELLIPSIS.length)) + TRAILING_ELLIPSIS;
55692
+ }
55693
+ function firstNonEmptyLine(text) {
55694
+ for (const line of text.split(/\r?\n/)) {
55695
+ const trimmed = line.trim();
55696
+ if (trimmed) return trimmed;
55697
+ }
55698
+ return "";
55699
+ }
55700
+ function summarizeCommandOutput(content) {
55701
+ const lines = content.split(/\r?\n/);
55702
+ const nonEmpty = lines.map((line) => line.trim()).filter(Boolean);
55703
+ const failures = [];
55704
+ const seen = /* @__PURE__ */ new Set();
55705
+ let headline = "";
55706
+ const addFailure = (text) => {
55707
+ const trimmed = text.trim();
55708
+ if (!trimmed || seen.has(trimmed)) return;
55709
+ seen.add(trimmed);
55710
+ failures.push(trimmed);
55711
+ };
55712
+ for (const rawLine of lines) {
55713
+ const line = rawLine.trim();
55714
+ if (!line) continue;
55715
+ const vitestFail = line.match(/^FAIL\s+(.+)/);
55716
+ if (vitestFail?.[1]) addFailure(vitestFail[1]);
55717
+ const stackLine = line.match(/^[❯>]\s+(.+\.(?:[cm]?[jt]sx?|tsx?):\d+:\d+)$/);
55718
+ if (stackLine?.[1]) addFailure(stackLine[1]);
55719
+ const tapFail = line.match(/^not ok\s+\d+\s+-\s+(.+)/);
55720
+ if (tapFail?.[1]) addFailure(tapFail[1]);
55721
+ const testsLine = line.match(/^Tests?\s+(.+)/);
55722
+ if (testsLine?.[1] && /\bfailed\b/i.test(testsLine[1])) headline = testsLine[1];
55723
+ const tapSummary = line.match(/^#\s*fail\s+(\d+)/i);
55724
+ if (tapSummary?.[1]) headline = `${tapSummary[1]} failed`;
55725
+ }
55726
+ if (!headline) {
55727
+ const testFilesLine = nonEmpty.find(
55728
+ (line) => /^Test Files\s+/.test(line) && /\bfailed\b/i.test(line)
55729
+ );
55730
+ if (testFilesLine) headline = testFilesLine.replace(/^Test Files\s+/, "");
55731
+ }
55732
+ const exitMatch = content.match(/(?:^|\n)\s*(?:\[?exit(?: code)?\s+(-?\d+)\]?)/i);
55733
+ const exitCode = exitMatch?.[1] ? Number(exitMatch[1]) : null;
55734
+ const failed = failures.length > 0 || /\b\d+\s+failed\b/i.test(headline) || exitCode !== null && exitCode !== 0;
55735
+ const passed = !failed && (exitCode === 0 || /\bpassed\b/i.test(content));
55736
+ if (!headline) {
55737
+ if (exitCode !== null) headline = `exit ${exitCode}`;
55738
+ else if (failed) headline = "failed";
55739
+ else if (passed) headline = "passed";
55740
+ else headline = firstNonEmptyLine(content) || "(no output)";
55741
+ }
55742
+ return {
55743
+ status: failed ? "failed" : passed ? "passed" : "unknown",
55744
+ headline: clip(headline, MAX_SUMMARY_CHARS),
55745
+ failures: failures.slice(0, 6),
55746
+ tail: nonEmpty.slice(-5)
55747
+ };
55748
+ }
55749
+ function summarizeStructured(content) {
55750
+ const trimmed = content.trim();
55751
+ if (!trimmed.startsWith("{")) return null;
55752
+ try {
55753
+ const parsed = JSON.parse(trimmed);
55754
+ if (!parsed || typeof parsed !== "object") return null;
55755
+ const obj = parsed;
55756
+ if (typeof obj.error === "string") {
55757
+ const tag2 = obj.error.split(":", 1)[0]?.trim() ?? "error";
55758
+ const detail = obj.error.slice(tag2.length + 1).trim();
55759
+ const summary = detail ? `${tag2} \u2014 ${detail}` : tag2;
55760
+ const isControlSignal = tag2 === "PlanProposedError" || tag2 === "PlanRevisionProposedError" || tag2 === "ChoiceRequestedError" || tag2 === "NeedsConfirmationError";
55761
+ return { summary: clip(summary, MAX_SUMMARY_CHARS), isError: !isControlSignal };
55762
+ }
55763
+ if (obj.kind === "step_completed" && typeof obj.stepId === "string") {
55764
+ const result = typeof obj.result === "string" ? obj.result : "";
55765
+ return {
55766
+ summary: clip(`\u2713 ${obj.stepId}: ${result}`, MAX_SUMMARY_CHARS),
55767
+ isError: false
55768
+ };
55769
+ }
55770
+ return null;
55771
+ } catch {
55772
+ return null;
55773
+ }
55774
+ }
55775
+ function formatStructuredErrorOutput(content) {
55776
+ const structured = summarizeStructured(content);
55777
+ if (!structured?.isError) return content;
55778
+ return structured.summary;
55779
+ }
55780
+
55585
55781
  // src/cli/ui/cards/ToolCard.tsx
55586
55782
  var READ_TAIL = 2;
55587
55783
  var OTHER_TAIL = 5;
55588
- function tailLinesFor(name) {
55784
+ function isReadStyleTool(name) {
55589
55785
  const lower = name.toLowerCase();
55590
- return /(?:^|_)(read|search|list|tree|get|status|diff|fetch|grep)(_|$)/.test(lower) || lower === "job_output" ? READ_TAIL : OTHER_TAIL;
55786
+ return /(?:^|_)(read|search|list|tree|get|status|diff|fetch|grep)(_|$)/.test(lower) || lower === "job_output";
55787
+ }
55788
+ function tailLinesFor(name) {
55789
+ return isReadStyleTool(name) ? READ_TAIL : OTHER_TAIL;
55790
+ }
55791
+ function isShellTool(name) {
55792
+ return name === "run_command" || name === "run_background" || /(?:^|_)(run_command|run_background)$/.test(name);
55591
55793
  }
55592
55794
  function ToolCard({ card }) {
55593
55795
  const { stdout } = use_stdout_default();
@@ -55598,7 +55800,14 @@ function ToolCard({ card }) {
55598
55800
  () => unwrapSubagentMarkdown(card.name, card.output),
55599
55801
  [card.name, card.output]
55600
55802
  );
55601
- const allLines = card.output.length > 0 ? card.output.split("\n") : [];
55803
+ const displayOutput = import_react79.default.useMemo(() => {
55804
+ const formatted = formatStructuredErrorOutput(card.output);
55805
+ if (!isShellTool(card.name)) return formatted;
55806
+ const summary = summarizeCommandOutput(formatted);
55807
+ if (summary.status !== "failed" || summary.failures.length === 0) return formatted;
55808
+ return [summary.headline, ...summary.failures].join("\n");
55809
+ }, [card.name, card.output]);
55810
+ const allLines = displayOutput.length > 0 ? displayOutput.split("\n") : [];
55602
55811
  const tail = tailLinesFor(card.name);
55603
55812
  const truncated = allLines.length > tail;
55604
55813
  const visible = truncated ? allLines.slice(-tail) : allLines;
@@ -55607,7 +55816,8 @@ function ToolCard({ card }) {
55607
55816
  const status2 = toolStatus(card, isInflight);
55608
55817
  const headColor = headerColorFor(status2);
55609
55818
  const errColor = card.exitCode && card.exitCode !== 0 ? TONE.err : FG.sub;
55610
- const showBody = !card.rejected && (subagentMarkdown !== null || visible.length > 0);
55819
+ const readStyleSuccess = isReadStyleTool(card.name) && status2 === "ok";
55820
+ const showBody = !card.rejected && !readStyleSuccess && (subagentMarkdown !== null || visible.length > 0);
55611
55821
  const meta = [];
55612
55822
  if (card.retry) {
55613
55823
  meta.push({ text: `\u21BB ${card.retry.attempt}/${card.retry.max}`, color: TONE.warn });
@@ -55748,12 +55958,12 @@ function UsageCard({ card }) {
55748
55958
  const promptRatio = card.tokens.prompt / cap;
55749
55959
  const reasonRatio = card.tokens.reason / cap;
55750
55960
  const outputRatio = card.tokens.output / cap;
55751
- const headerMeta2 = [
55961
+ const headerMeta = [
55752
55962
  `${t("cardLabels.turn")} ${card.turn}`,
55753
55963
  formatCost(card.cost, card.balanceCurrency)
55754
55964
  ];
55755
- if (card.elapsedMs !== void 0) headerMeta2.push(`${(card.elapsedMs / 1e3).toFixed(1)}s`);
55756
- return /* @__PURE__ */ import_react80.default.createElement(Card, { tone: FG.meta }, /* @__PURE__ */ import_react80.default.createElement(CardHeader, { glyph: "\u03A3", tone: FG.meta, title: t("cardTitles.usage"), meta: headerMeta2 }), /* @__PURE__ */ import_react80.default.createElement(Box_default, { flexDirection: "row", gap: 1 }, /* @__PURE__ */ import_react80.default.createElement(Text, { color: FG.sub }, t("cardLabels.prompt")), bar(promptRatio, TONE.brand), /* @__PURE__ */ import_react80.default.createElement(Text, { bold: true, color: FG.body }, card.tokens.prompt.toLocaleString()), /* @__PURE__ */ import_react80.default.createElement(Text, { color: FG.faint }, `/ 1M \xB7 ${(promptRatio * 100).toFixed(1)}%`)), /* @__PURE__ */ import_react80.default.createElement(Box_default, { flexDirection: "row", gap: 1 }, /* @__PURE__ */ import_react80.default.createElement(Text, { color: FG.sub }, t("cardLabels.reason")), bar(reasonRatio, TONE.accent), /* @__PURE__ */ import_react80.default.createElement(Text, { bold: true, color: FG.body }, card.tokens.reason.toLocaleString())), /* @__PURE__ */ import_react80.default.createElement(Box_default, { flexDirection: "row", gap: 1 }, /* @__PURE__ */ import_react80.default.createElement(Text, { color: FG.sub }, t("cardLabels.output")), bar(outputRatio, TONE.brand), /* @__PURE__ */ import_react80.default.createElement(Text, { bold: true, color: FG.body }, card.tokens.output.toLocaleString())), /* @__PURE__ */ import_react80.default.createElement(Box_default, { flexDirection: "row", gap: 1 }, /* @__PURE__ */ import_react80.default.createElement(Text, { color: FG.sub }, t("cardLabels.cache"), " "), bar(card.cacheHit, TONE.ok), /* @__PURE__ */ import_react80.default.createElement(Text, { bold: true, color: TONE.ok }, `${(card.cacheHit * 100).toFixed(1)}%`)), /* @__PURE__ */ import_react80.default.createElement(Box_default, { flexDirection: "row", gap: 1 }, /* @__PURE__ */ import_react80.default.createElement(Text, { color: FG.faint }, t("cardLabels.session")), /* @__PURE__ */ import_react80.default.createElement(Text, { bold: true, color: FG.body }, `\u25CF ${formatCost(card.sessionCost, card.balanceCurrency, 3)}`), card.balance !== void 0 ? /* @__PURE__ */ import_react80.default.createElement(import_react80.default.Fragment, null, /* @__PURE__ */ import_react80.default.createElement(Text, { color: FG.faint }, `\xB7 ${t("cardLabels.balance")}`), /* @__PURE__ */ import_react80.default.createElement(Text, { bold: true, color: TONE.brand }, formatBalance(card.balance, card.balanceCurrency))) : null));
55965
+ if (card.elapsedMs !== void 0) headerMeta.push(`${(card.elapsedMs / 1e3).toFixed(1)}s`);
55966
+ return /* @__PURE__ */ import_react80.default.createElement(Card, { tone: FG.meta }, /* @__PURE__ */ import_react80.default.createElement(CardHeader, { glyph: "\u03A3", tone: FG.meta, title: t("cardTitles.usage"), meta: headerMeta }), /* @__PURE__ */ import_react80.default.createElement(Box_default, { flexDirection: "row", gap: 1 }, /* @__PURE__ */ import_react80.default.createElement(Text, { color: FG.sub }, t("cardLabels.prompt")), bar(promptRatio, TONE.brand), /* @__PURE__ */ import_react80.default.createElement(Text, { bold: true, color: FG.body }, card.tokens.prompt.toLocaleString()), /* @__PURE__ */ import_react80.default.createElement(Text, { color: FG.faint }, `/ 1M \xB7 ${(promptRatio * 100).toFixed(1)}%`)), /* @__PURE__ */ import_react80.default.createElement(Box_default, { flexDirection: "row", gap: 1 }, /* @__PURE__ */ import_react80.default.createElement(Text, { color: FG.sub }, t("cardLabels.reason")), bar(reasonRatio, TONE.accent), /* @__PURE__ */ import_react80.default.createElement(Text, { bold: true, color: FG.body }, card.tokens.reason.toLocaleString())), /* @__PURE__ */ import_react80.default.createElement(Box_default, { flexDirection: "row", gap: 1 }, /* @__PURE__ */ import_react80.default.createElement(Text, { color: FG.sub }, t("cardLabels.output")), bar(outputRatio, TONE.brand), /* @__PURE__ */ import_react80.default.createElement(Text, { bold: true, color: FG.body }, card.tokens.output.toLocaleString())), /* @__PURE__ */ import_react80.default.createElement(Box_default, { flexDirection: "row", gap: 1 }, /* @__PURE__ */ import_react80.default.createElement(Text, { color: FG.sub }, t("cardLabels.cache"), " "), bar(card.cacheHit, TONE.ok), /* @__PURE__ */ import_react80.default.createElement(Text, { bold: true, color: TONE.ok }, `${(card.cacheHit * 100).toFixed(1)}%`)), /* @__PURE__ */ import_react80.default.createElement(Box_default, { flexDirection: "row", gap: 1 }, /* @__PURE__ */ import_react80.default.createElement(Text, { color: FG.faint }, t("cardLabels.session")), /* @__PURE__ */ import_react80.default.createElement(Text, { bold: true, color: FG.body }, `\u25CF ${formatCost(card.sessionCost, card.balanceCurrency, 3)}`), card.balance !== void 0 ? /* @__PURE__ */ import_react80.default.createElement(import_react80.default.Fragment, null, /* @__PURE__ */ import_react80.default.createElement(Text, { color: FG.faint }, `\xB7 ${t("cardLabels.balance")}`), /* @__PURE__ */ import_react80.default.createElement(Text, { bold: true, color: TONE.brand }, formatBalance(card.balance, card.balanceCurrency))) : null));
55757
55967
  }
55758
55968
  function CompactUsageRow({ card }) {
55759
55969
  const elapsed = card.elapsedMs !== void 0 ? ` \xB7 ${(card.elapsedMs / 1e3).toFixed(1)}s` : "";
@@ -55762,31 +55972,8 @@ function CompactUsageRow({ card }) {
55762
55972
 
55763
55973
  // src/cli/ui/cards/UserCard.tsx
55764
55974
  var import_react81 = __toESM(require_react(), 1);
55765
-
55766
- // src/cli/ui/cards/time.ts
55767
- function formatRelativeTime(ts, now = Date.now()) {
55768
- const diffSec = Math.max(0, Math.floor((now - ts) / 1e3));
55769
- if (diffSec < 5) return "just now";
55770
- if (diffSec < 60) return `${diffSec}s ago`;
55771
- const diffMin = Math.floor(diffSec / 60);
55772
- if (diffMin < 60) return `${diffMin}m ago`;
55773
- const diffHr = Math.floor(diffMin / 60);
55774
- if (diffHr < 24) return `${diffHr}h ago`;
55775
- const diffDay = Math.floor(diffHr / 24);
55776
- return `${diffDay}d ago`;
55777
- }
55778
-
55779
- // src/cli/ui/cards/UserCard.tsx
55780
55975
  function UserCard({ card }) {
55781
- return /* @__PURE__ */ import_react81.default.createElement(Card, { tone: CARD.user.color }, /* @__PURE__ */ import_react81.default.createElement(
55782
- CardHeader,
55783
- {
55784
- glyph: CARD.user.glyph,
55785
- tone: CARD.user.color,
55786
- title: t("cardTitles.you"),
55787
- meta: [formatRelativeTime(card.ts)]
55788
- }
55789
- ), /* @__PURE__ */ import_react81.default.createElement(Box_default, { flexDirection: "row", gap: 1 }, /* @__PURE__ */ import_react81.default.createElement(Text, { color: FG.sub }, "\u21B3"), /* @__PURE__ */ import_react81.default.createElement(Text, null, card.text)));
55976
+ return /* @__PURE__ */ import_react81.default.createElement(Card, { tone: CARD.user.color }, /* @__PURE__ */ import_react81.default.createElement(Box_default, { flexDirection: "row", gap: 1 }, /* @__PURE__ */ import_react81.default.createElement(Text, { bold: true, color: CARD.user.color }, "\u203A"), /* @__PURE__ */ import_react81.default.createElement(Text, null, card.text)));
55790
55977
  }
55791
55978
 
55792
55979
  // src/cli/ui/cards/WarnCard.tsx
@@ -55815,7 +56002,7 @@ function renderCard(card) {
55815
56002
  case "user":
55816
56003
  return /* @__PURE__ */ import_react83.default.createElement(UserCard, { card });
55817
56004
  case "reasoning":
55818
- return /* @__PURE__ */ import_react83.default.createElement(ReasoningCard, { card, expanded: true });
56005
+ return /* @__PURE__ */ import_react83.default.createElement(ReasoningCard, { card, expanded: false });
55819
56006
  case "streaming":
55820
56007
  return /* @__PURE__ */ import_react83.default.createElement(StreamingCard, { card });
55821
56008
  case "tool":
@@ -58361,11 +58548,11 @@ var TurnTranslator = class {
58361
58548
  this.toolStartedAt = Date.now();
58362
58549
  this.toolCardId = this.log.startTool(name, args, callId);
58363
58550
  }
58364
- toolEnd(output) {
58551
+ toolEnd(output, elapsedMs) {
58365
58552
  if (this.toolCardId) {
58366
58553
  this.log.endTool(this.toolCardId, {
58367
58554
  output,
58368
- elapsedMs: Date.now() - this.toolStartedAt
58555
+ elapsedMs: elapsedMs ?? Date.now() - this.toolStartedAt
58369
58556
  });
58370
58557
  this.toolCardId = null;
58371
58558
  }
@@ -58576,6 +58763,7 @@ function handleTurnInterrupt(key, {
58576
58763
  turnActiveRef,
58577
58764
  abortedThisTurn,
58578
58765
  resetPendingModals,
58766
+ cleanupInterruptedTurn,
58579
58767
  isLoopActive,
58580
58768
  stopLoop,
58581
58769
  loop: loop2,
@@ -58585,6 +58773,7 @@ function handleTurnInterrupt(key, {
58585
58773
  if (abortedThisTurn.current) return "already-aborted";
58586
58774
  abortedThisTurn.current = true;
58587
58775
  resetPendingModals();
58776
+ cleanupInterruptedTurn?.();
58588
58777
  if (isLoopActive()) stopLoop();
58589
58778
  loop2.abort();
58590
58779
  return "aborted";
@@ -58602,7 +58791,7 @@ function handleTurnInterrupt(key, {
58602
58791
 
58603
58792
  // src/cli/ui/useCompletionPickers.ts
58604
58793
  var import_react86 = __toESM(require_react(), 1);
58605
- import { isAbsolute, parse, relative, resolve as resolve2 } from "path";
58794
+ import { isAbsolute, parse, relative as relative2, resolve as resolve3 } from "path";
58606
58795
  var SEARCH_DEBOUNCE_MS = 80;
58607
58796
  var SEARCH_FLUSH_MS = 50;
58608
58797
  var SEARCH_RESULT_CAP = 200;
@@ -58822,8 +59011,8 @@ function usePathCandidates(rootDir, partial, isActive) {
58822
59011
  relPartial = partial.slice(root.length).replace(/\\/g, "/");
58823
59012
  insertIsAbsolute = true;
58824
59013
  } else {
58825
- const resolved = resolve2(rootDir, partial);
58826
- const relToRoot = relative(rootDir, resolved);
59014
+ const resolved = resolve3(rootDir, partial);
59015
+ const relToRoot = relative2(rootDir, resolved);
58827
59016
  if (relToRoot.startsWith("..") || isAbsolute(relToRoot)) {
58828
59017
  const root = parse(resolved).root;
58829
59018
  listRoot = root;
@@ -59168,14 +59357,14 @@ function useEditHistory(codeMode) {
59168
59357
  const files = [...new Set(entry.blocks.map((b) => b.path))];
59169
59358
  const status2 = entryStatus(entry);
59170
59359
  const header = `\u25B8 edit #${entry.id} \xB7 ${when} \xB7 ${entry.source} \xB7 ${status2} \xB7 ${files.length} file(s)`;
59171
- const countLines2 = (s) => s.length === 0 ? 0 : (s.match(/\n/g)?.length ?? 0) + 1;
59360
+ const countLines3 = (s) => s.length === 0 ? 0 : (s.match(/\n/g)?.length ?? 0) + 1;
59172
59361
  const fileLines = files.map((path) => {
59173
59362
  const fileBlocks = entry.blocks.filter((b) => b.path === path);
59174
59363
  let removed = 0;
59175
59364
  let added = 0;
59176
59365
  for (const b of fileBlocks) {
59177
- removed += countLines2(b.search);
59178
- added += countLines2(b.replace);
59366
+ removed += countLines3(b.search);
59367
+ added += countLines3(b.replace);
59179
59368
  }
59180
59369
  const state = entry.undoneFiles.has(path) ? "UNDONE" : "applied";
59181
59370
  return ` ${state.padEnd(7)} -${String(removed).padStart(3)}/+${String(added).padStart(3)} ${path} (${fileBlocks.length} block${fileBlocks.length === 1 ? "" : "s"})`;
@@ -59482,13 +59671,16 @@ function App(props) {
59482
59671
  const statusBar = import_react90.default.useMemo(() => {
59483
59672
  const cfg = readConfig().statusBar ?? {};
59484
59673
  return {
59485
- showBalance: cfg.showBalance !== false,
59486
- showSessionCost: cfg.showSessionCost !== false,
59674
+ showMode: cfg.showMode === true,
59675
+ showPreset: cfg.showPreset === true,
59676
+ showSessionInfo: cfg.showSessionInfo === true,
59677
+ showBalance: cfg.showBalance === true,
59678
+ showSessionCost: cfg.showSessionCost === true,
59487
59679
  showTurnCost: cfg.showTurnCost !== false,
59488
- showCacheHit: cfg.showCacheHit !== false,
59680
+ showCacheHit: cfg.showCacheHit === true,
59489
59681
  showCtxUsage: cfg.showCtxUsage !== false,
59490
- showVersion: cfg.showVersion !== false,
59491
- showFeedbackHint: cfg.showFeedbackHint !== false
59682
+ showVersion: cfg.showVersion === true,
59683
+ showFeedbackHint: cfg.showFeedbackHint === true
59492
59684
  };
59493
59685
  }, []);
59494
59686
  return /* @__PURE__ */ import_react90.default.createElement(ThemeProvider, { name: themeName }, /* @__PURE__ */ import_react90.default.createElement(AgentStoreProvider, { session, initialCards }, /* @__PURE__ */ import_react90.default.createElement(ChatScrollProvider, null, /* @__PURE__ */ import_react90.default.createElement(
@@ -59835,7 +60027,7 @@ function AppInner({
59835
60027
  const switchWorkspaceRoot = (0, import_react90.useCallback)(
59836
60028
  (newPath) => {
59837
60029
  if (!codeMode?.reregisterTools) return { ok: false, info: t("handlers.edits.cwdCodeOnly") };
59838
- const resolved = resolve3(newPath);
60030
+ const resolved = resolve4(newPath);
59839
60031
  let stat;
59840
60032
  try {
59841
60033
  stat = statSync2(resolved);
@@ -60086,24 +60278,27 @@ run \`carboncode setup\` to remove this entry, or fix the underlying issue (miss
60086
60278
  }, [pendingPlan, broadcastDashboardEvent]);
60087
60279
  (0, import_react90.useEffect)(() => {
60088
60280
  if (!pendingEditReview) return;
60089
- const previewLines = (pendingEditReview.search || pendingEditReview.replace || "").split("\n").slice(0, 12);
60281
+ const firstBlock = pendingEditReview[0];
60282
+ if (!firstBlock) return;
60283
+ const previewLines = (firstBlock.search || firstBlock.replace || "").split("\n").slice(0, 12);
60090
60284
  const preview = previewLines.join("\n");
60285
+ const fileCount = new Set(pendingEditReview.map((block2) => block2.path)).size;
60091
60286
  broadcastDashboardEvent({
60092
60287
  kind: "modal-up",
60093
60288
  modal: {
60094
60289
  kind: "edit-review",
60095
- path: pendingEditReview.path,
60096
- search: pendingEditReview.search ?? "",
60097
- replace: pendingEditReview.replace ?? "",
60290
+ path: fileCount === 1 ? firstBlock.path : `${fileCount} files`,
60291
+ search: firstBlock.search ?? "",
60292
+ replace: firstBlock.replace ?? "",
60098
60293
  preview,
60099
- total: pendingEdits.current.length,
60100
- remaining: pendingEdits.current.length
60294
+ total: pendingEditReview.length,
60295
+ remaining: pendingEditReview.length
60101
60296
  }
60102
60297
  });
60103
60298
  return () => {
60104
60299
  broadcastDashboardEvent({ kind: "modal-down", modalKind: "edit-review" });
60105
60300
  };
60106
- }, [pendingEditReview, broadcastDashboardEvent, pendingEdits]);
60301
+ }, [pendingEditReview, broadcastDashboardEvent]);
60107
60302
  (0, import_react90.useEffect)(() => {
60108
60303
  if (!pendingRevision) return;
60109
60304
  broadcastDashboardEvent({
@@ -60220,12 +60415,8 @@ run \`carboncode setup\` to remove this entry, or fix the underlying issue (miss
60220
60415
  (0, import_react90.useEffect)(() => {
60221
60416
  if (sessionBannerShown.current) return;
60222
60417
  sessionBannerShown.current = true;
60223
- if (!session) {
60224
- log.pushInfo(t("ui.ephemeralSession"));
60225
- } else if (loop2.resumedMessageCount > 0) {
60418
+ if (session && loop2.resumedMessageCount > 0) {
60226
60419
  log.pushInfo(t("ui.resumedSession", { name: session, count: loop2.resumedMessageCount }));
60227
- } else {
60228
- log.pushInfo(t("ui.newSession", { name: session }));
60229
60420
  }
60230
60421
  for (const hint of startupInfoHints ?? []) log.pushInfo(hint);
60231
60422
  if (session && codeMode) {
@@ -60269,6 +60460,15 @@ run \`carboncode setup\` to remove this entry, or fix the underlying issue (miss
60269
60460
  }
60270
60461
  }, [session, loop2, codeMode, syncPendingCount, log, pendingEdits, startupInfoHints]);
60271
60462
  const quitProcess = useQuit(transcriptRef);
60463
+ const cleanupInterruptedTurn = (0, import_react90.useCallback)(() => {
60464
+ const ts = Date.now();
60465
+ agentStore.dispatch({
60466
+ type: "turn.interrupt.cleanup",
60467
+ id: `interrupt-${ts}`,
60468
+ ts,
60469
+ text: t("app.turnInterrupted")
60470
+ });
60471
+ }, [agentStore]);
60272
60472
  useKeystroke((ev) => {
60273
60473
  if (ev.ctrl && ev.input === "d") quitProcess();
60274
60474
  });
@@ -60291,6 +60491,7 @@ run \`carboncode setup\` to remove this entry, or fix the underlying issue (miss
60291
60491
  turnActiveRef: submittingRef,
60292
60492
  abortedThisTurn,
60293
60493
  resetPendingModals,
60494
+ cleanupInterruptedTurn,
60294
60495
  isLoopActive,
60295
60496
  stopLoop,
60296
60497
  loop: loop2,
@@ -60303,6 +60504,7 @@ run \`carboncode setup\` to remove this entry, or fix the underlying issue (miss
60303
60504
  turnActiveRef: submittingRef,
60304
60505
  abortedThisTurn,
60305
60506
  resetPendingModals,
60507
+ cleanupInterruptedTurn,
60306
60508
  isLoopActive,
60307
60509
  stopLoop,
60308
60510
  loop: loop2,
@@ -60397,71 +60599,81 @@ run \`carboncode setup\` to remove this entry, or fix the underlying issue (miss
60397
60599
  });
60398
60600
  (0, import_react90.useEffect)(() => {
60399
60601
  if (!tools || !codeMode) return;
60400
- tools.setToolInterceptor(async (name, args) => {
60401
- if (name !== "edit_file" && name !== "write_file") return null;
60402
- const rawPath = typeof args.path === "string" ? args.path : "";
60403
- if (!rawPath) return null;
60602
+ tools.setToolInterceptor(async (name, args, ctx) => {
60404
60603
  const rootForEdit = currentRootDirRef.current;
60405
- const absRoot = resolve3(rootForEdit);
60406
- let relPath;
60407
- if (looksLikeAbsoluteSystemPath(rawPath)) {
60408
- const abs = resolve3(rawPath);
60409
- if (!pathIsUnder(abs, absRoot)) return null;
60410
- const rel = relative2(absRoot, abs);
60411
- if (!rel) return null;
60412
- relPath = rel;
60413
- } else {
60414
- let stripped = rawPath;
60415
- while (stripped.startsWith("/") || stripped.startsWith("\\")) {
60416
- stripped = stripped.slice(1);
60417
- }
60418
- if (!stripped) return null;
60419
- relPath = stripped;
60420
- }
60421
- let block2;
60422
- if (name === "edit_file") {
60423
- const search = typeof args.search === "string" ? args.search : "";
60424
- const replace = typeof args.replace === "string" ? args.replace : "";
60425
- if (!search) return null;
60426
- block2 = { path: relPath, search, replace, offset: 0 };
60427
- } else {
60428
- const content = typeof args.content === "string" ? args.content : "";
60429
- block2 = toWholeFileEditBlock(relPath, content, rootForEdit);
60430
- }
60431
- const applyNow = () => {
60432
- const snaps = snapshotBeforeEdits([block2], rootForEdit);
60433
- const results = applyEditBlocks([block2], rootForEdit);
60604
+ const blocks = buildEditToolBlocks(name, args, rootForEdit);
60605
+ if (!blocks) return null;
60606
+ const applyNow = async (opts = {}) => {
60607
+ const snaps = snapshotBeforeEdits(blocks, rootForEdit);
60608
+ if (name === "multi_edit" || name === "apply_patch") {
60609
+ let output;
60610
+ try {
60611
+ output = await applyMultiEdit(
60612
+ rootForEdit,
60613
+ blocks.map((block2) => ({
60614
+ abs: resolve4(rootForEdit, block2.path),
60615
+ search: block2.search,
60616
+ replace: block2.replace
60617
+ }))
60618
+ );
60619
+ } catch (err) {
60620
+ if (name === "apply_patch") {
60621
+ return `apply_patch: no files written \u2014 ${err.message}`;
60622
+ }
60623
+ throw err;
60624
+ }
60625
+ const results2 = blocks.map((block2) => ({
60626
+ path: block2.path,
60627
+ status: block2.search.length === 0 ? "created" : "applied"
60628
+ }));
60629
+ recordEdit(opts.source ?? "auto", blocks, results2, snaps);
60630
+ if (opts.showUndoBanner ?? true) armUndoBanner(results2);
60631
+ if (name !== "apply_patch") return output;
60632
+ const fileCount = new Set(blocks.map((block2) => block2.path)).size;
60633
+ const fileNoun = fileCount === 1 ? "file" : "files";
60634
+ const created = blocks.filter((block2) => block2.search.length === 0).map((block2) => `created ${block2.path}`);
60635
+ return [`apply_patch: applied ${fileCount} ${fileNoun}`, ...created, output].join("\n");
60636
+ }
60637
+ const results = applyEditBlocks(blocks, rootForEdit);
60434
60638
  const good = results.some((r) => r.status === "applied" || r.status === "created");
60435
60639
  if (good) {
60436
- recordEdit("auto", [block2], results, snaps);
60437
- armUndoBanner(results);
60640
+ recordEdit(opts.source ?? "auto", blocks, results, snaps);
60641
+ if (opts.showUndoBanner ?? true) armUndoBanner(results);
60438
60642
  }
60439
60643
  return formatEditResults(results);
60440
60644
  };
60441
60645
  if (editModeRef.current === "auto" || editModeRef.current === "yolo") return applyNow();
60442
60646
  if (turnEditPolicyRef.current === "apply-all") return applyNow();
60443
- const { choice, denyContext } = await new Promise((resolveChoice) => {
60647
+ const waitStartedAt = Date.now();
60648
+ const result = await new Promise((resolveChoice) => {
60444
60649
  editReviewResolveRef.current = resolveChoice;
60445
- setPendingEditReview(block2);
60650
+ setPendingEditReview(blocks);
60446
60651
  });
60652
+ ctx?.onInteractiveWait?.(Date.now() - waitStartedAt);
60447
60653
  editReviewResolveRef.current = null;
60448
60654
  setPendingEditReview(null);
60655
+ const choice = result.choice;
60656
+ const denyContext = result.denyContext;
60449
60657
  if (choice === "reject") {
60450
60658
  const context2 = denyContext ? ` because: ${denyContext}` : "";
60451
- log.pushInfo(t("app.rejectedEdit", { path: block2.path, context: context2 }));
60452
- return `User rejected this edit to ${block2.path}${context2}. Don't retry the same SEARCH/REPLACE; either try a different approach or ask the user what they want instead.`;
60659
+ const path = blocks.length === 1 ? blocks[0]?.path ?? "(unknown)" : `${blocks.length} files`;
60660
+ log.pushInfo(t("app.rejectedEdit", { path, context: context2 }));
60661
+ if (blocks.length > 1) {
60662
+ return `User rejected this ${name} before any edits were applied${context2}. Don't retry the same patch or SEARCH/REPLACE batch; either try a different approach or ask the user what they want instead.`;
60663
+ }
60664
+ return `User rejected this edit to ${path}${context2}. Don't retry the same SEARCH/REPLACE; either try a different approach or ask the user what they want instead.`;
60453
60665
  }
60454
60666
  if (choice === "apply-rest-of-turn") {
60455
60667
  turnEditPolicyRef.current = "apply-all";
60456
60668
  log.pushInfo(t("app.autoApprovingRest"));
60457
- return applyNow();
60669
+ return applyNow({ source: "review-apply", showUndoBanner: false });
60458
60670
  }
60459
60671
  if (choice === "flip-to-auto") {
60460
60672
  setEditMode("auto");
60461
60673
  log.pushInfo(t("app.flippedAutoSession"));
60462
60674
  return applyNow();
60463
60675
  }
60464
- return applyNow();
60676
+ return applyNow({ source: "review-apply", showUndoBanner: false });
60465
60677
  });
60466
60678
  return () => {
60467
60679
  tools.setToolInterceptor(null);
@@ -60507,7 +60719,7 @@ run \`carboncode setup\` to remove this entry, or fix the underlying issue (miss
60507
60719
  if (dashboardRef.current) return dashboardRef.current.url;
60508
60720
  if (dashboardStartingRef.current) return dashboardStartingRef.current;
60509
60721
  const startup = (async () => {
60510
- const { startDashboardServer } = await import("./server-X75PAZG5.js");
60722
+ const { startDashboardServer } = await import("./server-HE7LFAHH.js");
60511
60723
  const handle = await startDashboardServer(
60512
60724
  {
60513
60725
  mode: "attached",
@@ -60635,15 +60847,17 @@ run \`carboncode setup\` to remove this entry, or fix the underlying issue (miss
60635
60847
  return { kind: "plan", body: pendingPlanRef.current };
60636
60848
  }
60637
60849
  const er = pendingEditReview;
60638
- if (er) {
60850
+ if (er?.[0]) {
60851
+ const firstBlock = er[0];
60852
+ const fileCount = new Set(er.map((block2) => block2.path)).size;
60639
60853
  return {
60640
60854
  kind: "edit-review",
60641
- path: er.path,
60642
- search: er.search ?? "",
60643
- replace: er.replace ?? "",
60644
- preview: (er.search || er.replace || "").split("\n").slice(0, 12).join("\n"),
60645
- total: pendingEdits.current.length,
60646
- remaining: pendingEdits.current.length
60855
+ path: fileCount === 1 ? firstBlock.path : `${fileCount} files`,
60856
+ search: firstBlock.search ?? "",
60857
+ replace: firstBlock.replace ?? "",
60858
+ preview: (firstBlock.search || firstBlock.replace || "").split("\n").slice(0, 12).join("\n"),
60859
+ total: er.length,
60860
+ remaining: er.length
60647
60861
  };
60648
60862
  }
60649
60863
  if (pendingRevision) {
@@ -60695,11 +60909,11 @@ run \`carboncode setup\` to remove this entry, or fix the underlying issue (miss
60695
60909
  handleStagedInputSubmitRef.current(text ?? "", { plan: plan2, mode: choice }).catch(() => void 0);
60696
60910
  },
60697
60911
  resolveEditReview: (choice) => {
60698
- const resolve4 = editReviewResolveRef.current;
60699
- if (resolve4) {
60912
+ const resolve6 = editReviewResolveRef.current;
60913
+ if (resolve6) {
60700
60914
  editReviewResolveRef.current = null;
60701
60915
  setPendingEditReview(null);
60702
- resolve4({ choice, denyContext: void 0 });
60916
+ resolve6({ choice, denyContext: void 0 });
60703
60917
  }
60704
60918
  },
60705
60919
  resolveCheckpointConfirm: (choice, text) => {
@@ -61589,7 +61803,7 @@ ${answer}`, "brand");
61589
61803
  (choice, denyContext) => {
61590
61804
  const pending = pendingShell;
61591
61805
  if (!pending || !codeMode) return;
61592
- const { id, command: cmd, kind } = pending;
61806
+ const { id, command: cmd } = pending;
61593
61807
  setPendingShell(null);
61594
61808
  if (choice === "deny") {
61595
61809
  const context2 = denyContext ? ` because: ${denyContext}` : "";
@@ -61600,9 +61814,6 @@ ${answer}`, "brand");
61600
61814
  log.pushInfo(t("app.alwaysAllowed", { prefix, dir: currentRootDir }));
61601
61815
  pauseGate.resolve(id, { type: "always_allow", prefix });
61602
61816
  } else {
61603
- log.pushInfo(
61604
- kind === "run_background" ? t("app.startingBackground", { cmd }) : t("app.runningCommand", { cmd })
61605
- );
61606
61817
  pauseGate.resolve(id, { type: "run_once" });
61607
61818
  }
61608
61819
  },
@@ -62420,12 +62631,12 @@ ${answer}`, "brand");
62420
62631
  ) : pendingEditReview ? /* @__PURE__ */ import_react90.default.createElement(
62421
62632
  EditConfirm,
62422
62633
  {
62423
- block: pendingEditReview,
62634
+ blocks: pendingEditReview,
62424
62635
  onChoose: (choice, denyContext) => {
62425
- const resolve4 = editReviewResolveRef.current;
62426
- if (resolve4) {
62636
+ const resolve6 = editReviewResolveRef.current;
62637
+ if (resolve6) {
62427
62638
  editReviewResolveRef.current = null;
62428
- resolve4({ choice, denyContext });
62639
+ resolve6({ choice, denyContext });
62429
62640
  }
62430
62641
  }
62431
62642
  }
@@ -62443,7 +62654,6 @@ ${answer}`, "brand");
62443
62654
  pendingCount,
62444
62655
  modeFlash,
62445
62656
  planMode,
62446
- undoArmed: !!undoBanner || hasUndoable(),
62447
62657
  jobs: codeMode ? codeMode.jobs : void 0,
62448
62658
  activeLoop,
62449
62659
  statusBar,
@@ -62565,7 +62775,7 @@ async function drainTtyResponses(timeoutMs = 50) {
62565
62775
  return;
62566
62776
  }
62567
62777
  stdin.resume();
62568
- await new Promise((resolve4) => {
62778
+ await new Promise((resolve6) => {
62569
62779
  const onData = (_chunk) => {
62570
62780
  };
62571
62781
  stdin.on("data", onData);
@@ -62578,12 +62788,41 @@ async function drainTtyResponses(timeoutMs = 50) {
62578
62788
  } catch {
62579
62789
  }
62580
62790
  }
62581
- resolve4();
62791
+ resolve6();
62582
62792
  }, timeoutMs);
62583
62793
  timer.unref();
62584
62794
  });
62585
62795
  }
62586
62796
 
62797
+ // src/cli/ui/rule-summary.ts
62798
+ import { basename as basename5, relative as relative3, resolve as resolve5 } from "path";
62799
+ function collectStartupRuleFiles(rootDir) {
62800
+ if (!memoryEnabled()) return [];
62801
+ const mem = readProjectMemory(rootDir);
62802
+ return mem ? [mem.path] : [];
62803
+ }
62804
+ function formatRuleSummary(rootDir, files) {
62805
+ const labels = unique(files).map((file) => displayRulePath(rootDir, file)).filter((label) => label.length > 0);
62806
+ if (labels.length === 0) return null;
62807
+ return `rules \xB7 ${labels.join(", ")}`;
62808
+ }
62809
+ function unique(files) {
62810
+ const seen = /* @__PURE__ */ new Set();
62811
+ const out = [];
62812
+ for (const file of files) {
62813
+ const normalized = resolve5(file);
62814
+ if (seen.has(normalized)) continue;
62815
+ seen.add(normalized);
62816
+ out.push(normalized);
62817
+ }
62818
+ return out;
62819
+ }
62820
+ function displayRulePath(rootDir, file) {
62821
+ const rel = relative3(resolve5(rootDir), resolve5(file)).replaceAll("\\", "/");
62822
+ if (!rel || rel.startsWith("../") || rel === "..") return basename5(file);
62823
+ return rel;
62824
+ }
62825
+
62587
62826
  // src/cli/commands/chat.tsx
62588
62827
  function Root({
62589
62828
  initialKey,
@@ -62713,12 +62952,6 @@ async function chatCommand(opts) {
62713
62952
  const mcpServers = [];
62714
62953
  const cfg = readConfig();
62715
62954
  const startupInfoHints = [];
62716
- if (cfg.setupCompleted === true && (cfg.mcp?.length ?? 0) === 0 && mcpSpecs.length === 0) {
62717
- startupInfoHints.push(t("mcpHealth.emptyHint"));
62718
- }
62719
- startupInfoHints.push(
62720
- "/copy \u2192 vim-style copy mode (j/k navigate, v select, y yank to clipboard)"
62721
- );
62722
62955
  if (searchEnabled()) {
62723
62956
  if (!tools) tools = new ToolRegistry();
62724
62957
  registerWebTools(tools, {
@@ -62737,6 +62970,13 @@ async function chatCommand(opts) {
62737
62970
  opts.forceResume
62738
62971
  );
62739
62972
  const launchWorkspace = opts.codeMode?.rootDir ?? process.cwd();
62973
+ if (opts.codeMode) {
62974
+ const ruleSummary = formatRuleSummary(
62975
+ launchWorkspace,
62976
+ collectStartupRuleFiles(launchWorkspace)
62977
+ );
62978
+ if (ruleSummary) startupInfoHints.push(`\u25B8 ${ruleSummary}`);
62979
+ }
62740
62980
  const showPicker = !opts.session && !opts.forceResume && listSessionsForWorkspace(launchWorkspace).length > 0;
62741
62981
  markPhase("ink_render_call");
62742
62982
  const qqSubmitRef = { current: null };
@@ -62792,4 +63032,4 @@ async function chatCommand(opts) {
62792
63032
  export {
62793
63033
  chatCommand
62794
63034
  };
62795
- //# sourceMappingURL=chunk-J5BYPUB5.js.map
63035
+ //# sourceMappingURL=chunk-2EKLWOE3.js.map