reasonix 0.47.1 → 0.48.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/README.md +5 -26
  2. package/README.zh-CN.md +5 -26
  3. package/dist/cli/{acp-GEOAKSTU.js → acp-4ROCGYNH.js} +17 -17
  4. package/dist/cli/{chat-YTPATMMG.js → chat-GZNB5625.js} +24 -24
  5. package/dist/cli/{chunk-BQ6HC66J.js → chunk-2QSTA2QV.js} +3 -13
  6. package/dist/cli/chunk-2QSTA2QV.js.map +1 -0
  7. package/dist/cli/{chunk-DQ6K5ZQ7.js → chunk-3WGTGXO4.js} +2 -2
  8. package/dist/cli/{chunk-6QC5RQLE.js → chunk-5OHHAQ4W.js} +2 -2
  9. package/dist/cli/{chunk-XMHP7BEE.js → chunk-6MZTZO7A.js} +514 -791
  10. package/dist/cli/chunk-6MZTZO7A.js.map +1 -0
  11. package/dist/cli/chunk-7M4YYMKW.js +5198 -0
  12. package/dist/cli/chunk-7M4YYMKW.js.map +1 -0
  13. package/dist/cli/{chunk-KYQVQ5X4.js → chunk-B5CZL2SE.js} +9 -4
  14. package/dist/cli/chunk-B5CZL2SE.js.map +1 -0
  15. package/dist/cli/chunk-CDVSFSAK.js +17732 -0
  16. package/dist/cli/chunk-CDVSFSAK.js.map +1 -0
  17. package/dist/cli/{chunk-TRWHTFG7.js → chunk-DOWEOA6E.js} +2 -2
  18. package/dist/cli/chunk-EMMENC4O.js +831 -0
  19. package/dist/cli/chunk-EMMENC4O.js.map +1 -0
  20. package/dist/cli/{chunk-TDHXB2ER.js → chunk-H4CCXMDD.js} +2 -2
  21. package/dist/cli/{chunk-T5A7EY6B.js → chunk-HR5NBKEM.js} +2 -2
  22. package/dist/cli/{chunk-CNG32VAB.js → chunk-I4M5QJNL.js} +2 -2
  23. package/dist/cli/{chunk-5QCB62C4.js → chunk-J2TQAWOM.js} +135 -18
  24. package/dist/cli/{chunk-5QCB62C4.js.map → chunk-J2TQAWOM.js.map} +1 -1
  25. package/dist/cli/{chunk-DN4B5S6Y.js → chunk-JMDE6IO3.js} +2 -2
  26. package/dist/cli/{chunk-4MFCAZ2W.js → chunk-MOJYKO2A.js} +3 -3
  27. package/dist/cli/{chunk-HUILPCYX.js → chunk-MRZG4GBF.js} +3 -3
  28. package/dist/cli/{chunk-GH7DC2Y5.js → chunk-NMQSUNLB.js} +2 -2
  29. package/dist/cli/{chunk-ZXSCAODE.js → chunk-OB4BUJBL.js} +67 -2
  30. package/dist/cli/chunk-OB4BUJBL.js.map +1 -0
  31. package/dist/cli/{chunk-QCFLPSPH.js → chunk-OG5JANQ4.js} +2 -2
  32. package/dist/cli/{chunk-JBH5RM7X.js → chunk-OPYALNTT.js} +326 -55
  33. package/dist/cli/chunk-OPYALNTT.js.map +1 -0
  34. package/dist/cli/{chunk-CCJAP7G3.js → chunk-RUDBUHO4.js} +2 -2
  35. package/dist/cli/{chunk-2XY77LW7.js → chunk-S2RMQULY.js} +56 -24
  36. package/dist/cli/chunk-S2RMQULY.js.map +1 -0
  37. package/dist/cli/{chunk-DWPAKZTY.js → chunk-TE5UIIFL.js} +2 -2
  38. package/dist/cli/{chunk-KVZZ5U75.js → chunk-V4Y732RQ.js} +2 -2
  39. package/dist/cli/{chunk-TRSAHHCL.js → chunk-WZGNXR6E.js} +3 -3
  40. package/dist/cli/chunk-WZGNXR6E.js.map +1 -0
  41. package/dist/cli/{chunk-NRQ5UP5T.js → chunk-YW63N3ZR.js} +116 -28
  42. package/dist/cli/chunk-YW63N3ZR.js.map +1 -0
  43. package/dist/cli/{code-Q4NRVEDG.js → code-PMPJWXEO.js} +30 -31
  44. package/dist/cli/code-PMPJWXEO.js.map +1 -0
  45. package/dist/cli/{commands-4CDI4GFM.js → commands-QS6TG4G3.js} +4 -4
  46. package/dist/cli/{commit-GW7LDQP5.js → commit-XPRSKUBF.js} +3 -3
  47. package/dist/cli/{desktop-EG6P5SF2.js → desktop-562OPWIU.js} +461 -43
  48. package/dist/cli/desktop-562OPWIU.js.map +1 -0
  49. package/dist/cli/{diff-VI2YX4FN.js → diff-I6W4AUWJ.js} +8 -8
  50. package/dist/cli/{doctor-CQTTZP27.js → doctor-6XVZKT4U.js} +9 -9
  51. package/dist/cli/index.js +52 -40
  52. package/dist/cli/index.js.map +1 -1
  53. package/dist/cli/{mcp-J2UCD4RZ.js → mcp-7W7ANO2Y.js} +2 -2
  54. package/dist/cli/{mcp-browse-GSX34JEK.js → mcp-browse-LA4I4YIZ.js} +2 -2
  55. package/dist/cli/{mcp-inspect-RRFYF4ZV.js → mcp-inspect-LWXXU7BY.js} +2 -2
  56. package/dist/cli/{prompt-5TQPIVHV.js → prompt-RKZD4X6Y.js} +3 -3
  57. package/dist/cli/{replay-MJCEMODU.js → replay-2X7MVXOI.js} +8 -8
  58. package/dist/cli/{run-P4D5VDYE.js → run-TPKXIJ27.js} +13 -13
  59. package/dist/cli/{server-C25JNNZV.js → server-NHQ3QXOZ.js} +15 -14
  60. package/dist/cli/{server-C25JNNZV.js.map → server-NHQ3QXOZ.js.map} +1 -1
  61. package/dist/cli/{sessions-QIONZJQ6.js → sessions-2A4DGSHA.js} +12 -12
  62. package/dist/cli/{setup-NLQ6G5G4.js → setup-GOLP7J4C.js} +5 -5
  63. package/dist/cli/{stats-DFZEXHP4.js → stats-CGDAFDKI.js} +6 -6
  64. package/dist/cli/{version-GR3X3MPI.js → version-FIL4ZFOS.js} +12 -12
  65. package/dist/grammars/tree-sitter-go.wasm +0 -0
  66. package/dist/grammars/tree-sitter-java.wasm +0 -0
  67. package/dist/grammars/tree-sitter-javascript.wasm +0 -0
  68. package/dist/grammars/tree-sitter-python.wasm +0 -0
  69. package/dist/grammars/tree-sitter-rust.wasm +0 -0
  70. package/dist/grammars/tree-sitter-tsx.wasm +0 -0
  71. package/dist/grammars/tree-sitter-typescript.wasm +0 -0
  72. package/dist/grammars/web-tree-sitter.wasm +0 -0
  73. package/dist/index.d.ts +38 -10
  74. package/dist/index.js +488 -87
  75. package/dist/index.js.map +1 -1
  76. package/package.json +13 -4
  77. package/dist/cli/chunk-2XY77LW7.js.map +0 -1
  78. package/dist/cli/chunk-6CRPCJAU.js +0 -3141
  79. package/dist/cli/chunk-6CRPCJAU.js.map +0 -1
  80. package/dist/cli/chunk-BQ6HC66J.js.map +0 -1
  81. package/dist/cli/chunk-JBH5RM7X.js.map +0 -1
  82. package/dist/cli/chunk-KYQVQ5X4.js.map +0 -1
  83. package/dist/cli/chunk-NRQ5UP5T.js.map +0 -1
  84. package/dist/cli/chunk-TRSAHHCL.js.map +0 -1
  85. package/dist/cli/chunk-XD6P7AFH.js +0 -375
  86. package/dist/cli/chunk-XD6P7AFH.js.map +0 -1
  87. package/dist/cli/chunk-XMHP7BEE.js.map +0 -1
  88. package/dist/cli/chunk-YFP3MYMY.js +0 -323
  89. package/dist/cli/chunk-YFP3MYMY.js.map +0 -1
  90. package/dist/cli/chunk-ZXSCAODE.js.map +0 -1
  91. package/dist/cli/code-Q4NRVEDG.js.map +0 -1
  92. package/dist/cli/desktop-EG6P5SF2.js.map +0 -1
  93. /package/dist/cli/{acp-GEOAKSTU.js.map → acp-4ROCGYNH.js.map} +0 -0
  94. /package/dist/cli/{chat-YTPATMMG.js.map → chat-GZNB5625.js.map} +0 -0
  95. /package/dist/cli/{chunk-DQ6K5ZQ7.js.map → chunk-3WGTGXO4.js.map} +0 -0
  96. /package/dist/cli/{chunk-6QC5RQLE.js.map → chunk-5OHHAQ4W.js.map} +0 -0
  97. /package/dist/cli/{chunk-TRWHTFG7.js.map → chunk-DOWEOA6E.js.map} +0 -0
  98. /package/dist/cli/{chunk-TDHXB2ER.js.map → chunk-H4CCXMDD.js.map} +0 -0
  99. /package/dist/cli/{chunk-T5A7EY6B.js.map → chunk-HR5NBKEM.js.map} +0 -0
  100. /package/dist/cli/{chunk-CNG32VAB.js.map → chunk-I4M5QJNL.js.map} +0 -0
  101. /package/dist/cli/{chunk-DN4B5S6Y.js.map → chunk-JMDE6IO3.js.map} +0 -0
  102. /package/dist/cli/{chunk-4MFCAZ2W.js.map → chunk-MOJYKO2A.js.map} +0 -0
  103. /package/dist/cli/{chunk-HUILPCYX.js.map → chunk-MRZG4GBF.js.map} +0 -0
  104. /package/dist/cli/{chunk-GH7DC2Y5.js.map → chunk-NMQSUNLB.js.map} +0 -0
  105. /package/dist/cli/{chunk-QCFLPSPH.js.map → chunk-OG5JANQ4.js.map} +0 -0
  106. /package/dist/cli/{chunk-CCJAP7G3.js.map → chunk-RUDBUHO4.js.map} +0 -0
  107. /package/dist/cli/{chunk-DWPAKZTY.js.map → chunk-TE5UIIFL.js.map} +0 -0
  108. /package/dist/cli/{chunk-KVZZ5U75.js.map → chunk-V4Y732RQ.js.map} +0 -0
  109. /package/dist/cli/{commands-4CDI4GFM.js.map → commands-QS6TG4G3.js.map} +0 -0
  110. /package/dist/cli/{commit-GW7LDQP5.js.map → commit-XPRSKUBF.js.map} +0 -0
  111. /package/dist/cli/{diff-VI2YX4FN.js.map → diff-I6W4AUWJ.js.map} +0 -0
  112. /package/dist/cli/{doctor-CQTTZP27.js.map → doctor-6XVZKT4U.js.map} +0 -0
  113. /package/dist/cli/{mcp-J2UCD4RZ.js.map → mcp-7W7ANO2Y.js.map} +0 -0
  114. /package/dist/cli/{mcp-browse-GSX34JEK.js.map → mcp-browse-LA4I4YIZ.js.map} +0 -0
  115. /package/dist/cli/{mcp-inspect-RRFYF4ZV.js.map → mcp-inspect-LWXXU7BY.js.map} +0 -0
  116. /package/dist/cli/{prompt-5TQPIVHV.js.map → prompt-RKZD4X6Y.js.map} +0 -0
  117. /package/dist/cli/{replay-MJCEMODU.js.map → replay-2X7MVXOI.js.map} +0 -0
  118. /package/dist/cli/{run-P4D5VDYE.js.map → run-TPKXIJ27.js.map} +0 -0
  119. /package/dist/cli/{sessions-QIONZJQ6.js.map → sessions-2A4DGSHA.js.map} +0 -0
  120. /package/dist/cli/{setup-NLQ6G5G4.js.map → setup-GOLP7J4C.js.map} +0 -0
  121. /package/dist/cli/{stats-DFZEXHP4.js.map → stats-CGDAFDKI.js.map} +0 -0
  122. /package/dist/cli/{version-GR3X3MPI.js.map → version-FIL4ZFOS.js.map} +0 -0
@@ -8,18 +8,23 @@ import {
8
8
  loadOverlay
9
9
  } from "./chunk-JMBMLOBP.js";
10
10
  import {
11
- createMcpRuntime
12
- } from "./chunk-YFP3MYMY.js";
11
+ QQChannel,
12
+ createMcpRuntime,
13
+ formatQQAccessSummary,
14
+ formatQQModeLabel,
15
+ formatQQSetupPrompt,
16
+ formatQQSetupWaiting
17
+ } from "./chunk-EMMENC4O.js";
13
18
  import {
14
19
  Eventizer,
15
20
  autoResolveVerdict,
16
21
  registerSkillTools,
17
22
  shouldAutoResolveCheckpoint
18
- } from "./chunk-ZXSCAODE.js";
23
+ } from "./chunk-OB4BUJBL.js";
19
24
  import {
20
25
  formatMcpLifecycleEvent,
21
26
  formatMcpSlowToast
22
- } from "./chunk-DQ6K5ZQ7.js";
27
+ } from "./chunk-3WGTGXO4.js";
23
28
  import {
24
29
  buildTransportFromSpec
25
30
  } from "./chunk-EQATK2L2.js";
@@ -31,6 +36,7 @@ import {
31
36
  import {
32
37
  CacheFirstLoop,
33
38
  ImmutablePrefix,
39
+ SHARED_SUBAGENT_SINK,
34
40
  ToolRegistry,
35
41
  applyEditBlocks,
36
42
  detectAtPicker,
@@ -53,27 +59,24 @@ import {
53
59
  toWholeFileEditBlock,
54
60
  walkFilesStream,
55
61
  webFetch
56
- } from "./chunk-JBH5RM7X.js";
62
+ } from "./chunk-OPYALNTT.js";
57
63
  import {
58
64
  openTranscriptFile,
59
65
  recordFromLoopEvent,
60
66
  writeRecord
61
- } from "./chunk-HUILPCYX.js";
67
+ } from "./chunk-MRZG4GBF.js";
62
68
  import {
63
69
  McpClient
64
70
  } from "./chunk-HIYTRCSW.js";
65
71
  import {
66
72
  MemoryStore,
67
73
  effectivePriority
68
- } from "./chunk-BQ6HC66J.js";
69
- import {
70
- wrapper_default
71
- } from "./chunk-FEZK652I.js";
74
+ } from "./chunk-2QSTA2QV.js";
72
75
  import {
73
76
  KeystrokeProvider,
74
77
  SingleSelect,
75
78
  useKeystroke
76
- } from "./chunk-TRWHTFG7.js";
79
+ } from "./chunk-DOWEOA6E.js";
77
80
  import {
78
81
  COLOR,
79
82
  GLYPH,
@@ -81,7 +84,7 @@ import {
81
84
  ThemeProvider,
82
85
  useColor,
83
86
  useThemeTokens
84
- } from "./chunk-CCJAP7G3.js";
87
+ } from "./chunk-RUDBUHO4.js";
85
88
  import {
86
89
  Box_default,
87
90
  Text,
@@ -101,20 +104,20 @@ import {
101
104
  } from "./chunk-LGEKVMMV.js";
102
105
  import {
103
106
  runDoctorChecks
104
- } from "./chunk-2XY77LW7.js";
107
+ } from "./chunk-S2RMQULY.js";
105
108
  import {
106
109
  countTokensBounded
107
110
  } from "./chunk-6OWJV3YW.js";
108
111
  import {
109
112
  DeepSeekClient,
110
113
  pickPrimaryBalance
111
- } from "./chunk-DWPAKZTY.js";
114
+ } from "./chunk-TE5UIIFL.js";
112
115
  import {
113
116
  loadDotenv
114
117
  } from "./chunk-2UQP6H6T.js";
115
118
  import {
116
119
  renderDashboard
117
- } from "./chunk-4MFCAZ2W.js";
120
+ } from "./chunk-MOJYKO2A.js";
118
121
  import {
119
122
  MANUAL_UPDATE_COMMANDS,
120
123
  planUpdate
@@ -140,7 +143,7 @@ import {
140
143
  restoreCheckpoint,
141
144
  savePlanState,
142
145
  suggestSlashCommands
143
- } from "./chunk-KYQVQ5X4.js";
146
+ } from "./chunk-B5CZL2SE.js";
144
147
  import {
145
148
  eventLogPath,
146
149
  openEventSink
@@ -158,7 +161,7 @@ import {
158
161
  pauseGate,
159
162
  runCommand,
160
163
  tildeify
161
- } from "./chunk-TRSAHHCL.js";
164
+ } from "./chunk-WZGNXR6E.js";
162
165
  import {
163
166
  PROJECT_MEMORY_FILE,
164
167
  SkillStore,
@@ -173,7 +176,7 @@ import {
173
176
  loadHooks,
174
177
  projectSettingsPath,
175
178
  runHooks
176
- } from "./chunk-GH7DC2Y5.js";
179
+ } from "./chunk-NMQSUNLB.js";
177
180
  import {
178
181
  deleteSession,
179
182
  detectGitBranch,
@@ -196,12 +199,12 @@ import {
196
199
  appendUsage,
197
200
  defaultUsageLogPath,
198
201
  readUsageLog
199
- } from "./chunk-DN4B5S6Y.js";
202
+ } from "./chunk-JMDE6IO3.js";
200
203
  import {
201
204
  DEEPSEEK_CONTEXT_TOKENS,
202
205
  DEFAULT_CONTEXT_TOKENS,
203
206
  pricingFor
204
- } from "./chunk-QCFLPSPH.js";
207
+ } from "./chunk-OG5JANQ4.js";
205
208
  import {
206
209
  getLanguage,
207
210
  getSupportedLanguages,
@@ -210,7 +213,7 @@ import {
210
213
  setLanguage,
211
214
  t,
212
215
  tObj
213
- } from "./chunk-NRQ5UP5T.js";
216
+ } from "./chunk-YW63N3ZR.js";
214
217
  import {
215
218
  CARD,
216
219
  FG,
@@ -221,9 +224,7 @@ import {
221
224
  addSkillPath,
222
225
  balanceColor,
223
226
  clearProjectShellAllowed,
224
- decideQQAccess,
225
227
  defaultConfigPath,
226
- describeQQAccess,
227
228
  editModeHintShown,
228
229
  formatBalance,
229
230
  formatCost,
@@ -234,6 +235,9 @@ import {
234
235
  loadBaseUrl,
235
236
  loadEditMode,
236
237
  loadEngineeringLifecycleMode,
238
+ loadExaApiKey,
239
+ loadMetasoApiKey,
240
+ loadPerplexityApiKey,
237
241
  loadProjectShellAllowed,
238
242
  loadQQConfig,
239
243
  loadRateLimit,
@@ -241,19 +245,17 @@ import {
241
245
  loadRecentWorkspaces,
242
246
  loadResolvedSkillPaths,
243
247
  loadSkillPaths,
248
+ loadTavilyApiKey,
244
249
  loadTheme,
245
250
  loadWorkspaceDir,
246
251
  markEditModeHintShown,
247
252
  markMouseClipboardHintShown,
248
253
  mouseClipboardHintShown,
249
254
  normalizeMcpConfig,
250
- normalizeQQAllowlist,
251
- normalizeQQOpenId,
252
255
  parseMcpSpec,
253
256
  pushRecentWorkspace,
254
257
  readConfig,
255
258
  redactKey,
256
- redactQQOpenId,
257
259
  removeProjectShellAllowed,
258
260
  removeSkillPath,
259
261
  resolveThemePreference,
@@ -266,7 +268,7 @@ import {
266
268
  webSearchEndpoint,
267
269
  webSearchEngine,
268
270
  writeConfig
269
- } from "./chunk-6CRPCJAU.js";
271
+ } from "./chunk-CDVSFSAK.js";
270
272
  import {
271
273
  VERSION,
272
274
  compareVersions,
@@ -535,7 +537,7 @@ var require_core = __commonJS({
535
537
  return match && match.index === 0;
536
538
  }
537
539
  var BACKREF_RE = /\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./;
538
- function join8(regexps, separator = "|") {
540
+ function join7(regexps, separator = "|") {
539
541
  let numCaptures = 0;
540
542
  return regexps.map((regex) => {
541
543
  numCaptures += 1;
@@ -839,7 +841,7 @@ var require_core = __commonJS({
839
841
  this.exec = () => null;
840
842
  }
841
843
  const terminators = this.regexes.map((el) => el[1]);
842
- this.matcherRe = langRe(join8(terminators), true);
844
+ this.matcherRe = langRe(join7(terminators), true);
843
845
  this.lastIndex = 0;
844
846
  }
845
847
  /** @param {string} s */
@@ -35859,8 +35861,8 @@ var require_tokenizer = __commonJS({
35859
35861
  this.consumedAfterSnapshot--;
35860
35862
  this.preprocessor.retreat();
35861
35863
  }
35862
- _reconsumeInState(state) {
35863
- this.state = state;
35864
+ _reconsumeInState(state2) {
35865
+ this.state = state2;
35864
35866
  this._unconsume();
35865
35867
  }
35866
35868
  _consumeSequenceIfMatch(pattern, startCp, caseSensitive) {
@@ -38482,10 +38484,10 @@ var require_tokenizer_mixin = __commonJS({
38482
38484
  }
38483
38485
  };
38484
38486
  Object.keys(Tokenizer.MODE).forEach((modeName) => {
38485
- const state = Tokenizer.MODE[modeName];
38486
- methods[state] = function(cp) {
38487
+ const state2 = Tokenizer.MODE[modeName];
38488
+ methods[state2] = function(cp) {
38487
38489
  mxn.ctLoc = mxn._getCurrentLocation();
38488
- orig[state].call(this, cp);
38490
+ orig[state2].call(this, cp);
38489
38491
  };
38490
38492
  });
38491
38493
  return methods;
@@ -44320,497 +44322,6 @@ var require_dist = __commonJS({
44320
44322
  // src/cli/commands/chat.tsx
44321
44323
  var import_react95 = __toESM(require_react(), 1);
44322
44324
 
44323
- // src/qq/channel.ts
44324
- import { mkdirSync, readFileSync, unlinkSync, writeFileSync } from "fs";
44325
- import { homedir } from "os";
44326
- import { dirname, join } from "path";
44327
-
44328
- // src/qq/bot.ts
44329
- import { EventEmitter } from "events";
44330
- var TOKEN_URL = "https://bots.qq.com/app/getAppAccessToken";
44331
- var BASE_URL = "https://api.sgroup.qq.com";
44332
- var SANDBOX_URL = "https://sandbox.api.sgroup.qq.com";
44333
- var INTENT_C2C_GROUP = 1 << 25;
44334
- var MIN_HEARTBEAT_INTERVAL_MS = 5e3;
44335
- var MAX_HEARTBEAT_INTERVAL_MS = 6e4;
44336
- var ALLOWED_GATEWAY_HOSTS = ["api.sgroup.qq.com", "sandbox.api.sgroup.qq.com", "qq.com"];
44337
- var QQBot = class extends EventEmitter {
44338
- config;
44339
- token = "";
44340
- tokenExpiresAt = 0;
44341
- ws = null;
44342
- heartbeatTimer = null;
44343
- seq = 0;
44344
- sessionId = "";
44345
- closed = false;
44346
- readyReceived = false;
44347
- constructor(config) {
44348
- super();
44349
- this.config = config;
44350
- }
44351
- get baseUrl() {
44352
- return this.config.sandbox ? SANDBOX_URL : BASE_URL;
44353
- }
44354
- sanitizeHeartbeatInterval(interval) {
44355
- if (typeof interval !== "number" || !Number.isFinite(interval)) {
44356
- return null;
44357
- }
44358
- if (interval < MIN_HEARTBEAT_INTERVAL_MS) {
44359
- return MIN_HEARTBEAT_INTERVAL_MS;
44360
- }
44361
- if (interval > MAX_HEARTBEAT_INTERVAL_MS) {
44362
- return MAX_HEARTBEAT_INTERVAL_MS;
44363
- }
44364
- return Math.trunc(interval);
44365
- }
44366
- validateGatewayUrl(rawUrl) {
44367
- const url = new URL(rawUrl);
44368
- const trustedHost = ALLOWED_GATEWAY_HOSTS.some(
44369
- (host) => url.hostname === host || url.hostname.endsWith(`.${host}`)
44370
- );
44371
- if (url.protocol !== "wss:" || !trustedHost || url.username || url.password || url.search || url.hash) {
44372
- throw new Error(`Unexpected QQ gateway URL: ${rawUrl}`);
44373
- }
44374
- return url.toString();
44375
- }
44376
- async ensureToken() {
44377
- if (this.token && Date.now() < this.tokenExpiresAt - 6e4) {
44378
- return this.token;
44379
- }
44380
- const res = await fetch(TOKEN_URL, {
44381
- method: "POST",
44382
- headers: { "Content-Type": "application/json" },
44383
- body: JSON.stringify({
44384
- appId: this.config.appid,
44385
- clientSecret: this.config.secret
44386
- })
44387
- });
44388
- if (!res.ok) {
44389
- const text = await res.text();
44390
- throw new Error(`Failed to get access token (${res.status}): ${text}`);
44391
- }
44392
- const data = await res.json();
44393
- this.token = data.access_token;
44394
- this.tokenExpiresAt = Date.now() + data.expires_in * 1e3;
44395
- return this.token;
44396
- }
44397
- async getGateway() {
44398
- const token = await this.ensureToken();
44399
- const res = await fetch(`${this.baseUrl}/gateway`, {
44400
- headers: { Authorization: `QQBot ${token}` }
44401
- });
44402
- if (!res.ok) {
44403
- const text = await res.text();
44404
- throw new Error(`Failed to get gateway (${res.status}): ${text}`);
44405
- }
44406
- const data = await res.json();
44407
- return this.validateGatewayUrl(data.url);
44408
- }
44409
- sendOp(op, data) {
44410
- if (!this.ws) return;
44411
- this.ws.send(JSON.stringify({ op, d: data ?? {} }));
44412
- }
44413
- async handlePayload(payload) {
44414
- switch (payload.op) {
44415
- case 10: {
44416
- const d = payload.d;
44417
- this.sendOp(2, {
44418
- token: `QQBot ${await this.ensureToken()}`,
44419
- intents: INTENT_C2C_GROUP,
44420
- shard: [0, 1]
44421
- });
44422
- const heartbeatInterval = this.sanitizeHeartbeatInterval(d?.heartbeat_interval);
44423
- if (heartbeatInterval) {
44424
- this.heartbeatTimer = setInterval(() => {
44425
- this.sendOp(1, this.seq || null);
44426
- }, heartbeatInterval);
44427
- }
44428
- break;
44429
- }
44430
- case 0: {
44431
- if (payload.s) this.seq = payload.s;
44432
- if (payload.t === "READY") {
44433
- const d = payload.d;
44434
- this.sessionId = d.session_id;
44435
- this.readyReceived = true;
44436
- this.emit("online");
44437
- } else if (payload.t === "C2C_MESSAGE_CREATE") {
44438
- this.emit("message.private", payload.d);
44439
- } else if (payload.t === "GROUP_AT_MESSAGE_CREATE") {
44440
- this.emit("message.group", payload.d);
44441
- }
44442
- break;
44443
- }
44444
- case 7: {
44445
- this.reconnect();
44446
- break;
44447
- }
44448
- case 9: {
44449
- this.sessionId = "";
44450
- this.sendOp(2, {
44451
- token: `QQBot ${await this.ensureToken()}`,
44452
- intents: INTENT_C2C_GROUP,
44453
- shard: [0, 1]
44454
- });
44455
- break;
44456
- }
44457
- }
44458
- }
44459
- async reconnect() {
44460
- this.cleanup();
44461
- await this.connect();
44462
- }
44463
- cleanup() {
44464
- if (this.heartbeatTimer) {
44465
- clearInterval(this.heartbeatTimer);
44466
- this.heartbeatTimer = null;
44467
- }
44468
- if (this.ws) {
44469
- this.ws.removeAllListeners();
44470
- this.ws.close();
44471
- this.ws = null;
44472
- }
44473
- }
44474
- async connect() {
44475
- const gatewayUrl = await this.getGateway();
44476
- const token = await this.ensureToken();
44477
- this.ws = new wrapper_default(gatewayUrl, {
44478
- headers: {
44479
- Authorization: `QQBot ${token}`,
44480
- "X-Union-Appid": this.config.appid
44481
- }
44482
- });
44483
- this.ws.on("open", () => {
44484
- if (this.sessionId) {
44485
- this.sendOp(6, {
44486
- token: `QQBot ${this.token}`,
44487
- session_id: this.sessionId,
44488
- seq: this.seq
44489
- });
44490
- }
44491
- });
44492
- this.ws.on("message", (raw) => {
44493
- try {
44494
- const payload = JSON.parse(raw.toString());
44495
- this.handlePayload(payload).catch(() => {
44496
- });
44497
- } catch {
44498
- }
44499
- });
44500
- this.ws.on("close", () => {
44501
- if (!this.closed) {
44502
- if (this.readyReceived) {
44503
- console.error("QQ WebSocket reconnecting...");
44504
- this.cleanup();
44505
- setTimeout(() => this.reconnect(), 3e3);
44506
- } else {
44507
- const msg = "QQ WebSocket closed before authentication completed \u2014 check your appId and appSecret";
44508
- this.emit("bot_error", msg);
44509
- this.closed = true;
44510
- }
44511
- }
44512
- });
44513
- this.ws.on("error", (err) => {
44514
- const msg = `QQ WebSocket error: ${err.message}`;
44515
- console.error(msg);
44516
- this.emit("bot_error", msg);
44517
- });
44518
- }
44519
- async start() {
44520
- this.closed = false;
44521
- this.readyReceived = false;
44522
- await this.connect();
44523
- }
44524
- async stop() {
44525
- this.closed = true;
44526
- this.cleanup();
44527
- }
44528
- async sendPrivateMessage(openid, content, msgId, msgSeq) {
44529
- const token = await this.ensureToken();
44530
- const body = {
44531
- content,
44532
- msg_type: 0
44533
- };
44534
- if (msgId) body.msg_id = msgId;
44535
- if (typeof msgSeq === "number" && Number.isFinite(msgSeq)) body.msg_seq = Math.trunc(msgSeq);
44536
- const res = await fetch(`${this.baseUrl}/v2/users/${encodeURIComponent(openid)}/messages`, {
44537
- method: "POST",
44538
- headers: {
44539
- Authorization: `QQBot ${token}`,
44540
- "Content-Type": "application/json",
44541
- "X-Union-Appid": this.config.appid
44542
- },
44543
- body: JSON.stringify(body)
44544
- });
44545
- if (!res.ok) {
44546
- const text = await res.text();
44547
- const msg = `QQ sendPrivateMessage failed (${res.status}): ${text}`;
44548
- throw new Error(msg);
44549
- }
44550
- }
44551
- };
44552
-
44553
- // src/qq/strings.ts
44554
- function formatQQModeLabel(codeMode) {
44555
- return t(codeMode ? "handlers.qq.modeCode" : "handlers.qq.modeChat");
44556
- }
44557
- function formatQQAccessSummary(config) {
44558
- const ownerOpenId = normalizeQQOpenId(config.ownerOpenId);
44559
- const allowlist = normalizeQQAllowlist(config.allowlist) ?? [];
44560
- const runtimeBoundOpenId = normalizeQQOpenId(config.runtimeBoundOpenId);
44561
- if (ownerOpenId) {
44562
- if (allowlist.length > 0) {
44563
- return t("handlers.qq.accessOwnerWithAllowlist", {
44564
- owner: redactQQOpenId(ownerOpenId),
44565
- count: allowlist.length
44566
- });
44567
- }
44568
- return t("handlers.qq.accessOwner", {
44569
- owner: redactQQOpenId(ownerOpenId)
44570
- });
44571
- }
44572
- if (allowlist.length > 0) {
44573
- return t("handlers.qq.accessAllowlist", { count: allowlist.length });
44574
- }
44575
- if (runtimeBoundOpenId) {
44576
- return t("handlers.qq.accessRuntime", {
44577
- owner: redactQQOpenId(runtimeBoundOpenId)
44578
- });
44579
- }
44580
- return t("handlers.qq.accessOpen");
44581
- }
44582
- function formatQQSetupPrompt(step) {
44583
- return t(step === "appId" ? "handlers.qq.promptAppId" : "handlers.qq.promptAppSecret");
44584
- }
44585
- function formatQQSetupWaiting(step) {
44586
- return t(
44587
- step === "appId" ? "handlers.qq.setupWaitingAppId" : "handlers.qq.setupWaitingAppSecret"
44588
- );
44589
- }
44590
-
44591
- // src/qq/channel.ts
44592
- var QQ_LOCK_FILE = join(homedir(), ".reasonix", "qq-channel.pid");
44593
- var QQ_MAX_CHUNK_BYTES = 1500;
44594
- var NATURAL_SPLIT_MIN_FRACTION = 0.6;
44595
- function fitUtf8Slice(text, maxBytes) {
44596
- let end = 0;
44597
- let bytes = 0;
44598
- for (const char of text) {
44599
- const nextBytes = Buffer.byteLength(char, "utf8");
44600
- if (bytes > 0 && bytes + nextBytes > maxBytes) break;
44601
- end += char.length;
44602
- bytes += nextBytes;
44603
- }
44604
- return end > 0 ? text.slice(0, end) : text.slice(0, 1);
44605
- }
44606
- function pickNaturalSplit(candidate) {
44607
- const minSplit = Math.floor(candidate.length * NATURAL_SPLIT_MIN_FRACTION);
44608
- const splitters = ["\n\n", "\n", " "];
44609
- for (const splitter of splitters) {
44610
- const at = candidate.lastIndexOf(splitter);
44611
- if (at >= minSplit) return at + splitter.length;
44612
- }
44613
- return candidate.length;
44614
- }
44615
- function splitQQMessage(text, maxBytes = QQ_MAX_CHUNK_BYTES) {
44616
- const chunks = [];
44617
- let remaining = text;
44618
- while (remaining.length > 0) {
44619
- if (Buffer.byteLength(remaining, "utf8") <= maxBytes) {
44620
- chunks.push(remaining);
44621
- break;
44622
- }
44623
- const candidate = fitUtf8Slice(remaining, maxBytes);
44624
- const splitAt = pickNaturalSplit(candidate);
44625
- chunks.push(candidate.slice(0, splitAt));
44626
- remaining = remaining.slice(splitAt).trimStart();
44627
- }
44628
- return chunks;
44629
- }
44630
- var QQChannel = class {
44631
- constructor(callbacks) {
44632
- this.callbacks = callbacks;
44633
- }
44634
- callbacks;
44635
- bot = null;
44636
- qqUserId = null;
44637
- qqMessageId = null;
44638
- ownerOpenId;
44639
- allowlist;
44640
- runtimeBoundOpenId = null;
44641
- processedMsgIds = /* @__PURE__ */ new Set();
44642
- processedMsgIdQueue = [];
44643
- lockAcquired = false;
44644
- nextOutboundMsgSeq = 1;
44645
- rememberMessage(id) {
44646
- if (this.processedMsgIds.has(id)) return false;
44647
- this.processedMsgIds.add(id);
44648
- this.processedMsgIdQueue.push(id);
44649
- if (this.processedMsgIdQueue.length > 200) {
44650
- const oldest = this.processedMsgIdQueue.shift();
44651
- if (oldest) this.processedMsgIds.delete(oldest);
44652
- }
44653
- return true;
44654
- }
44655
- acquireLock() {
44656
- try {
44657
- const existing = Number(readFileSync(QQ_LOCK_FILE, "utf8").trim());
44658
- if (Number.isInteger(existing) && existing > 0 && existing !== process.pid) {
44659
- try {
44660
- process.kill(existing, 0);
44661
- throw new Error(t("handlers.qq.lockAlreadyRunning", { pid: existing }));
44662
- } catch (err) {
44663
- const e = err;
44664
- if (e.code !== "ESRCH") throw err;
44665
- }
44666
- }
44667
- } catch (err) {
44668
- const e = err;
44669
- if (e.code !== "ENOENT") throw err;
44670
- }
44671
- mkdirSync(dirname(QQ_LOCK_FILE), { recursive: true });
44672
- writeFileSync(QQ_LOCK_FILE, String(process.pid), "utf8");
44673
- this.lockAcquired = true;
44674
- }
44675
- releaseLock() {
44676
- if (!this.lockAcquired) return;
44677
- try {
44678
- const existing = Number(readFileSync(QQ_LOCK_FILE, "utf8").trim());
44679
- if (existing === process.pid) unlinkSync(QQ_LOCK_FILE);
44680
- } catch {
44681
- }
44682
- this.lockAcquired = false;
44683
- }
44684
- applyAccessConfig(config) {
44685
- this.ownerOpenId = config.ownerOpenId;
44686
- this.allowlist = config.allowlist;
44687
- if (this.ownerOpenId || (this.allowlist?.length ?? 0) > 0) {
44688
- this.runtimeBoundOpenId = null;
44689
- }
44690
- }
44691
- handlePrivateMessage(msg) {
44692
- const text = msg.content?.trim();
44693
- if (!text) return;
44694
- if (!this.rememberMessage(msg.id)) return;
44695
- const openid = msg.author.user_openid;
44696
- const verdict = decideQQAccess(
44697
- {
44698
- ownerOpenId: this.ownerOpenId,
44699
- allowlist: this.allowlist,
44700
- runtimeBoundOpenId: this.runtimeBoundOpenId
44701
- },
44702
- openid
44703
- );
44704
- if (!verdict.accept) {
44705
- this.callbacks.onError?.(
44706
- t("handlers.qq.unauthorizedMessage", {
44707
- openid: redactQQOpenId(openid),
44708
- access: formatQQAccessSummary({
44709
- ownerOpenId: this.ownerOpenId,
44710
- allowlist: this.allowlist,
44711
- runtimeBoundOpenId: this.runtimeBoundOpenId
44712
- })
44713
- })
44714
- );
44715
- return;
44716
- }
44717
- if (verdict.bindRuntime) {
44718
- this.runtimeBoundOpenId = openid;
44719
- this.callbacks.onError?.(
44720
- t("handlers.qq.runtimeBound", {
44721
- openid: redactQQOpenId(openid)
44722
- })
44723
- );
44724
- }
44725
- this.qqUserId = openid;
44726
- this.qqMessageId = msg.id;
44727
- this.callbacks.onSubmitMessage(`[QQ] ${text}`);
44728
- }
44729
- refreshAccessConfig() {
44730
- this.applyAccessConfig(loadQQConfig());
44731
- }
44732
- describeAccess() {
44733
- return describeQQAccess({
44734
- ownerOpenId: this.ownerOpenId,
44735
- allowlist: this.allowlist,
44736
- runtimeBoundOpenId: this.runtimeBoundOpenId
44737
- });
44738
- }
44739
- getRuntimeBoundOpenId() {
44740
- return this.runtimeBoundOpenId;
44741
- }
44742
- async start() {
44743
- loadDotenv();
44744
- this.acquireLock();
44745
- const config = loadQQConfig();
44746
- if (!config.appId) {
44747
- this.releaseLock();
44748
- throw new Error(t("handlers.qq.missingAppId"));
44749
- }
44750
- if (!config.appSecret) {
44751
- this.releaseLock();
44752
- throw new Error(t("handlers.qq.missingAppSecret"));
44753
- }
44754
- this.applyAccessConfig(config);
44755
- const bot = new QQBot({
44756
- appid: config.appId,
44757
- secret: config.appSecret,
44758
- sandbox: config.sandbox ?? false
44759
- });
44760
- bot.on("online", () => {
44761
- process.stderr.write("QQ bot is online!\n");
44762
- });
44763
- bot.on("bot_error", (msg) => {
44764
- this.callbacks.onError?.(msg);
44765
- });
44766
- bot.on("message.private", (msg) => {
44767
- this.handlePrivateMessage(msg);
44768
- });
44769
- this.bot = bot;
44770
- try {
44771
- await bot.start();
44772
- const readyOrError = await Promise.race([
44773
- new Promise((resolve4) => bot.once("online", () => resolve4("ready"))),
44774
- new Promise((resolve4) => bot.once("bot_error", () => resolve4("error"))),
44775
- new Promise((resolve4) => setTimeout(() => resolve4("timeout"), 15e3))
44776
- ]);
44777
- if (readyOrError === "error") {
44778
- throw new Error(t("handlers.qq.authFailed"));
44779
- }
44780
- if (readyOrError === "timeout") {
44781
- throw new Error(t("handlers.qq.readyTimeout"));
44782
- }
44783
- } catch (err) {
44784
- this.releaseLock();
44785
- throw err;
44786
- }
44787
- }
44788
- async sendResponse(text) {
44789
- if (!this.bot || !this.qqUserId) return;
44790
- const chunks = splitQQMessage(text);
44791
- for (let index = 0; index < chunks.length; index++) {
44792
- const chunk = chunks[index];
44793
- if (!chunk) continue;
44794
- try {
44795
- await this.bot.sendPrivateMessage(
44796
- this.qqUserId,
44797
- chunk,
44798
- this.qqMessageId ?? void 0,
44799
- this.nextOutboundMsgSeq++
44800
- );
44801
- } catch (err) {
44802
- const msg = `QQ sendResponse chunk ${index + 1}/${chunks.length} failed: ${err.message}`;
44803
- this.callbacks.onError?.(msg);
44804
- break;
44805
- }
44806
- }
44807
- }
44808
- async stop() {
44809
- await this.bot?.stop();
44810
- this.releaseLock();
44811
- }
44812
- };
44813
-
44814
44325
  // src/cli/ui/App.tsx
44815
44326
  import { statSync as statSync2 } from "fs";
44816
44327
  import { relative as relative2, resolve as resolve3 } from "path";
@@ -44927,6 +44438,27 @@ var EngineeringLifecycleRuntime = class {
44927
44438
  this._completedStepIds.clear();
44928
44439
  this._mutatedSinceLastStep = false;
44929
44440
  }
44441
+ recordPlanRevised(remainingSteps) {
44442
+ if (this._mode === "off") return;
44443
+ const donePrefix = this._planSteps.filter((step) => this._completedStepIds.has(step.id));
44444
+ const merged = [...donePrefix];
44445
+ for (const step of remainingSteps) {
44446
+ if (this._completedStepIds.has(step.id)) continue;
44447
+ merged.push(step);
44448
+ }
44449
+ this._planSteps = merged;
44450
+ if (this._planSteps.length > 0 && this._completedStepIds.size >= this._planSteps.length) {
44451
+ this._state = "complete";
44452
+ } else {
44453
+ this._state = "executing";
44454
+ }
44455
+ }
44456
+ recordCheckpointReached() {
44457
+ if (this._mode === "off") return;
44458
+ if (this._state === "approved" || this._state === "executing") {
44459
+ this._state = "checkpoint";
44460
+ }
44461
+ }
44930
44462
  recordStepCompleted(stepId) {
44931
44463
  if (!stepId) return;
44932
44464
  this._completedStepIds.add(stepId);
@@ -44964,9 +44496,10 @@ var EngineeringLifecycleRuntime = class {
44964
44496
  if (!isHighRiskLifecycleToolCall(name, args)) return null;
44965
44497
  if (this._state !== "approved" && this._state !== "executing") {
44966
44498
  return JSON.stringify({
44967
- error: `${name}: blocked by Engineering Lifecycle \u2014 high-risk engineering work requires an approved structured plan first. Explore with read-only tools, call ask_choice for real forks, then call submit_plan with concrete steps.`,
44499
+ error: `${name}: blocked by Engineering Lifecycle \u2014 submit an approved plan before high-risk mutation.`,
44968
44500
  rejectedReason: "engineering-lifecycle",
44969
- state: this._state
44501
+ state: this._state,
44502
+ nextAction: "submit_plan"
44970
44503
  });
44971
44504
  }
44972
44505
  this._state = "executing";
@@ -44988,9 +44521,10 @@ var EngineeringLifecycleRuntime = class {
44988
44521
  const evidenceRequired = this._mutatedSinceLastStep || step?.risk === "med" || step?.risk === "high" || (step?.verification?.length ?? 0) > 0;
44989
44522
  if (evidenceRequired && evidence.length === 0) {
44990
44523
  return JSON.stringify({
44991
- error: "mark_step_complete: evidence required by Engineering Lifecycle \u2014 include verification, diff, checkpoint, or manual evidence before completing this step.",
44524
+ error: "mark_step_complete: evidence required \u2014 add verification, diff, checkpoint, or manual evidence.",
44992
44525
  rejectedReason: "engineering-lifecycle-evidence",
44993
- stepId
44526
+ stepId,
44527
+ nextAction: "add_evidence"
44994
44528
  });
44995
44529
  }
44996
44530
  return null;
@@ -45096,21 +44630,21 @@ function looksLikePathCheckout(arg) {
45096
44630
  }
45097
44631
 
45098
44632
  // src/code/pending-edits.ts
45099
- import { existsSync, mkdirSync as mkdirSync2, readFileSync as readFileSync2, unlinkSync as unlinkSync2, writeFileSync as writeFileSync2 } from "fs";
45100
- import { dirname as dirname2, join as join2 } from "path";
44633
+ import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "fs";
44634
+ import { dirname, join } from "path";
45101
44635
  function pendingEditsPath(sessionName) {
45102
- return join2(sessionsDir(), `${sanitizeName(sessionName)}.pending.json`);
44636
+ return join(sessionsDir(), `${sanitizeName(sessionName)}.pending.json`);
45103
44637
  }
45104
44638
  function savePendingEdits(sessionName, blocks) {
45105
44639
  if (!sessionName) return;
45106
44640
  const path = pendingEditsPath(sessionName);
45107
44641
  try {
45108
44642
  if (blocks.length === 0) {
45109
- if (existsSync(path)) unlinkSync2(path);
44643
+ if (existsSync(path)) unlinkSync(path);
45110
44644
  return;
45111
44645
  }
45112
- mkdirSync2(dirname2(path), { recursive: true });
45113
- writeFileSync2(path, JSON.stringify(blocks, null, 2), "utf8");
44646
+ mkdirSync(dirname(path), { recursive: true });
44647
+ writeFileSync(path, JSON.stringify(blocks, null, 2), "utf8");
45114
44648
  } catch {
45115
44649
  }
45116
44650
  }
@@ -45120,7 +44654,7 @@ function loadPendingEdits(sessionName) {
45120
44654
  if (!existsSync(path)) return null;
45121
44655
  let raw;
45122
44656
  try {
45123
- raw = readFileSync2(path, "utf8");
44657
+ raw = readFileSync(path, "utf8");
45124
44658
  } catch {
45125
44659
  return null;
45126
44660
  }
@@ -45142,7 +44676,7 @@ function clearPendingEdits(sessionName) {
45142
44676
  if (!sessionName) return;
45143
44677
  const path = pendingEditsPath(sessionName);
45144
44678
  try {
45145
- if (existsSync(path)) unlinkSync2(path);
44679
+ if (existsSync(path)) unlinkSync(path);
45146
44680
  } catch {
45147
44681
  }
45148
44682
  }
@@ -46005,19 +45539,19 @@ function truncateForPrompt(text, max) {
46005
45539
  }
46006
45540
 
46007
45541
  // src/slash-usage.ts
46008
- import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync3, renameSync, writeFileSync as writeFileSync3 } from "fs";
46009
- import { homedir as homedir2 } from "os";
46010
- import { dirname as dirname3, join as join3 } from "path";
45542
+ import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync2, renameSync, writeFileSync as writeFileSync2 } from "fs";
45543
+ import { homedir } from "os";
45544
+ import { dirname as dirname2, join as join2 } from "path";
46011
45545
  function slashUsagePath() {
46012
45546
  const override = process.env.REASONIX_SLASH_USAGE_PATH;
46013
45547
  if (override) return override;
46014
- return join3(homedir2(), ".reasonix", "slash-usage.json");
45548
+ return join2(homedir(), ".reasonix", "slash-usage.json");
46015
45549
  }
46016
45550
  function loadSlashUsage() {
46017
45551
  const path = slashUsagePath();
46018
45552
  if (!existsSync3(path)) return {};
46019
45553
  try {
46020
- const raw = readFileSync3(path, "utf8");
45554
+ const raw = readFileSync2(path, "utf8");
46021
45555
  const parsed = JSON.parse(raw);
46022
45556
  if (!parsed || typeof parsed !== "object") return {};
46023
45557
  const out = {};
@@ -46034,8 +45568,8 @@ function persist(counts) {
46034
45568
  const tmp = `${path}.tmp`;
46035
45569
  const payload = { version: 1, counts };
46036
45570
  try {
46037
- mkdirSync3(dirname3(path), { recursive: true });
46038
- writeFileSync3(tmp, JSON.stringify(payload), "utf8");
45571
+ mkdirSync2(dirname2(path), { recursive: true });
45572
+ writeFileSync2(tmp, JSON.stringify(payload), "utf8");
46039
45573
  renameSync(tmp, path);
46040
45574
  } catch {
46041
45575
  }
@@ -46122,9 +45656,9 @@ function isDirectory(path) {
46122
45656
 
46123
45657
  // src/cli/edit/external-editor.ts
46124
45658
  import { spawn } from "child_process";
46125
- import { mkdtempSync, readFileSync as readFileSync4, rmSync, writeFileSync as writeFileSync4 } from "fs";
45659
+ import { mkdtempSync, readFileSync as readFileSync3, rmSync, writeFileSync as writeFileSync3 } from "fs";
46126
45660
  import { tmpdir } from "os";
46127
- import { join as join4 } from "path";
45661
+ import { join as join3 } from "path";
46128
45662
  function detectEditor(env = process.env) {
46129
45663
  for (const key of ["GIT_EDITOR", "VISUAL", "EDITOR"]) {
46130
45664
  const raw = env[key];
@@ -46141,12 +45675,12 @@ async function openInExternalEditor(initial2) {
46141
45675
  detail: t("composer.editorMissing")
46142
45676
  };
46143
45677
  }
46144
- const dir = mkdtempSync(join4(tmpdir(), "reasonix-compose-"));
46145
- const path = join4(dir, "REASONIX_INPUT.md");
45678
+ const dir = mkdtempSync(join3(tmpdir(), "reasonix-compose-"));
45679
+ const path = join3(dir, "REASONIX_INPUT.md");
46146
45680
  try {
46147
- writeFileSync4(path, initial2, "utf8");
45681
+ writeFileSync3(path, initial2, "utf8");
46148
45682
  await spawnEditor(editor, path);
46149
- const raw = readFileSync4(path, "utf8");
45683
+ const raw = readFileSync3(path, "utf8");
46150
45684
  return { kind: "ok", content: normalizeEditorBuffer(raw) };
46151
45685
  } catch (err) {
46152
45686
  return {
@@ -46416,22 +45950,22 @@ function allocateRows(claims, totalRows) {
46416
45950
  }
46417
45951
  return out;
46418
45952
  }
46419
- function reducer(state, action) {
45953
+ function reducer(state2, action) {
46420
45954
  switch (action.type) {
46421
45955
  case "claim": {
46422
- const next = new Map(state.claims);
45956
+ const next = new Map(state2.claims);
46423
45957
  next.set(action.zone, action.spec);
46424
- return { ...state, claims: next };
45958
+ return { ...state2, claims: next };
46425
45959
  }
46426
45960
  case "release": {
46427
- if (!state.claims.has(action.zone)) return state;
46428
- const next = new Map(state.claims);
45961
+ if (!state2.claims.has(action.zone)) return state2;
45962
+ const next = new Map(state2.claims);
46429
45963
  next.delete(action.zone);
46430
- return { ...state, claims: next };
45964
+ return { ...state2, claims: next };
46431
45965
  }
46432
45966
  case "resize":
46433
- if (action.rows === state.totalRows) return state;
46434
- return { ...state, totalRows: action.rows };
45967
+ if (action.rows === state2.totalRows) return state2;
45968
+ return { ...state2, totalRows: action.rows };
46435
45969
  }
46436
45970
  }
46437
45971
  var BudgetContext = (0, import_react6.createContext)(null);
@@ -46440,7 +45974,7 @@ function ViewportBudgetProvider({
46440
45974
  initialRows
46441
45975
  }) {
46442
45976
  const { stdout } = use_stdout_default();
46443
- const [state, dispatch] = (0, import_react6.useReducer)(reducer, void 0, () => ({
45977
+ const [state2, dispatch] = (0, import_react6.useReducer)(reducer, void 0, () => ({
46444
45978
  claims: /* @__PURE__ */ new Map(),
46445
45979
  totalRows: initialRows ?? stdout?.rows ?? 40
46446
45980
  }));
@@ -46456,19 +45990,19 @@ function ViewportBudgetProvider({
46456
45990
  }, [stdout, initialRows]);
46457
45991
  const allocations = (0, import_react6.useMemo)(() => {
46458
45992
  const list2 = [];
46459
- for (const [zone, spec] of state.claims) {
45993
+ for (const [zone, spec] of state2.claims) {
46460
45994
  list2.push({ zone, priority: ZONE_PRIORITY[zone], ...spec });
46461
45995
  }
46462
- return allocateRows(list2, state.totalRows);
46463
- }, [state.claims, state.totalRows]);
45996
+ return allocateRows(list2, state2.totalRows);
45997
+ }, [state2.claims, state2.totalRows]);
46464
45998
  const value = (0, import_react6.useMemo)(
46465
45999
  () => ({
46466
- totalRows: state.totalRows,
46000
+ totalRows: state2.totalRows,
46467
46001
  allocations,
46468
- claims: state.claims,
46002
+ claims: state2.claims,
46469
46003
  dispatch
46470
46004
  }),
46471
- [state.totalRows, allocations, state.claims]
46005
+ [state2.totalRows, allocations, state2.claims]
46472
46006
  );
46473
46007
  return /* @__PURE__ */ import_react6.default.createElement(BudgetContext.Provider, { value }, children);
46474
46008
  }
@@ -46539,19 +46073,19 @@ var import_react23 = __toESM(require_react(), 1);
46539
46073
  var import_react8 = __toESM(require_react(), 1);
46540
46074
  var ROW_WINDOW = 8;
46541
46075
  function AtMentionSuggestions({
46542
- state,
46076
+ state: state2,
46543
46077
  selectedIndex
46544
46078
  }) {
46545
46079
  const color = useColor();
46546
- if (!state) return null;
46547
- const isBrowse = state.kind === "browse";
46548
- const entries = state.entries;
46080
+ if (!state2) return null;
46081
+ const isBrowse = state2.kind === "browse";
46082
+ const entries = state2.entries;
46549
46083
  const total = entries.length;
46550
46084
  const windowStart = total <= ROW_WINDOW ? 0 : Math.max(0, Math.min(selectedIndex - Math.floor(ROW_WINDOW / 2), total - ROW_WINDOW));
46551
46085
  const shown = entries.slice(windowStart, windowStart + ROW_WINDOW);
46552
46086
  const hiddenAbove = windowStart;
46553
46087
  const hiddenBelow = total - windowStart - shown.length;
46554
- return /* @__PURE__ */ import_react8.default.createElement(Box_default, { flexDirection: "column", paddingX: 1, marginTop: 1 }, /* @__PURE__ */ import_react8.default.createElement(HeaderRow, { state, hiddenAbove }), total === 0 ? /* @__PURE__ */ import_react8.default.createElement(EmptyRow, { state, color }) : null, shown.map((entry, i) => /* @__PURE__ */ import_react8.default.createElement(
46088
+ return /* @__PURE__ */ import_react8.default.createElement(Box_default, { flexDirection: "column", paddingX: 1, marginTop: 1 }, /* @__PURE__ */ import_react8.default.createElement(HeaderRow, { state: state2, hiddenAbove }), total === 0 ? /* @__PURE__ */ import_react8.default.createElement(EmptyRow, { state: state2, color }) : null, shown.map((entry, i) => /* @__PURE__ */ import_react8.default.createElement(
46555
46089
  EntryRow,
46556
46090
  {
46557
46091
  key: `${entry.insertPath}:${entry.isDir ? "d" : "f"}`,
@@ -46561,29 +46095,29 @@ function AtMentionSuggestions({
46561
46095
  )), hiddenBelow > 0 ? /* @__PURE__ */ import_react8.default.createElement(Text, { dimColor: true }, ` \u2193 ${hiddenBelow} below`) : null, /* @__PURE__ */ import_react8.default.createElement(FooterRow, { isBrowse, hasFolder: shown.some((e) => e.isDir) }));
46562
46096
  }
46563
46097
  function HeaderRow({
46564
- state,
46098
+ state: state2,
46565
46099
  hiddenAbove
46566
46100
  }) {
46567
46101
  const color = useColor();
46568
- const total = state.entries.length;
46102
+ const total = state2.entries.length;
46569
46103
  const lead = /* @__PURE__ */ import_react8.default.createElement(Text, { color: color.primary, bold: true }, "@ ");
46570
- if (state.kind === "browse") {
46571
- const where = state.baseDir === "" ? "/" : `${state.baseDir}/`;
46572
- const counter = state.loading ? t("atMentions.loading") : t(total === 1 ? "atMentions.entrySingular" : "atMentions.entryPlural", { count: total });
46104
+ if (state2.kind === "browse") {
46105
+ const where = state2.baseDir === "" ? "/" : `${state2.baseDir}/`;
46106
+ const counter = state2.loading ? t("atMentions.loading") : t(total === 1 ? "atMentions.entrySingular" : "atMentions.entryPlural", { count: total });
46573
46107
  return /* @__PURE__ */ import_react8.default.createElement(Box_default, null, lead, /* @__PURE__ */ import_react8.default.createElement(Text, { dimColor: true }, `${where} ${counter}`), hiddenAbove > 0 ? /* @__PURE__ */ import_react8.default.createElement(Text, { dimColor: true }, ` \u2191 ${hiddenAbove} above`) : null);
46574
46108
  }
46575
- const status2 = state.searching ? `${t("atMentions.searching")} ${state.scanned} ${t("atMentions.scanned")} \xB7 ${total} ${total === 1 ? t("atMentions.match") : t("atMentions.matches")}` : `${total} ${total === 1 ? t("atMentions.match") : t("atMentions.matches")} ${t("atMentions.forFilter", { filter: state.filter })}`;
46109
+ const status2 = state2.searching ? `${t("atMentions.searching")} ${state2.scanned} ${t("atMentions.scanned")} \xB7 ${total} ${total === 1 ? t("atMentions.match") : t("atMentions.matches")}` : `${total} ${total === 1 ? t("atMentions.match") : t("atMentions.matches")} ${t("atMentions.forFilter", { filter: state2.filter })}`;
46576
46110
  return /* @__PURE__ */ import_react8.default.createElement(Box_default, null, lead, /* @__PURE__ */ import_react8.default.createElement(Text, { dimColor: true }, status2), hiddenAbove > 0 ? /* @__PURE__ */ import_react8.default.createElement(Text, { dimColor: true }, ` \u2191 ${hiddenAbove} above`) : null);
46577
46111
  }
46578
- function EmptyRow({ state, color }) {
46579
- if (state.kind === "browse") {
46580
- if (state.loading) return null;
46112
+ function EmptyRow({ state: state2, color }) {
46113
+ if (state2.kind === "browse") {
46114
+ if (state2.loading) return null;
46581
46115
  return /* @__PURE__ */ import_react8.default.createElement(Box_default, null, /* @__PURE__ */ import_react8.default.createElement(Text, { color: color.warn, bold: true }, GLYPH.warn), /* @__PURE__ */ import_react8.default.createElement(Text, null, " "), /* @__PURE__ */ import_react8.default.createElement(Text, { color: color.warn }, t("atMentions.emptyDir")));
46582
46116
  }
46583
- if (state.searching) {
46117
+ if (state2.searching) {
46584
46118
  return /* @__PURE__ */ import_react8.default.createElement(Box_default, null, /* @__PURE__ */ import_react8.default.createElement(Text, { dimColor: true }, t("atMentions.scanning")));
46585
46119
  }
46586
- return /* @__PURE__ */ import_react8.default.createElement(Box_default, null, /* @__PURE__ */ import_react8.default.createElement(Text, { color: color.warn, bold: true }, GLYPH.warn), /* @__PURE__ */ import_react8.default.createElement(Text, null, " "), /* @__PURE__ */ import_react8.default.createElement(Text, { color: color.warn }, t("atMentions.noMatch", { filter: state.filter })));
46120
+ return /* @__PURE__ */ import_react8.default.createElement(Box_default, null, /* @__PURE__ */ import_react8.default.createElement(Text, { color: color.warn, bold: true }, GLYPH.warn), /* @__PURE__ */ import_react8.default.createElement(Text, null, " "), /* @__PURE__ */ import_react8.default.createElement(Text, { color: color.warn }, t("atMentions.noMatch", { filter: state2.filter })));
46587
46121
  }
46588
46122
  function EntryRow({ entry, isSelected }) {
46589
46123
  const color = useColor();
@@ -47913,6 +47447,7 @@ function SubagentRow({ activity }) {
47913
47447
  const last = activity.lastInner;
47914
47448
  const subtitle = activity.skillName ?? truncate(activity.task, 48);
47915
47449
  const modelBadge = activity.model ? modelBadgeFor(activity.model) : null;
47450
+ const streamLine = formatStreamLine(activity);
47916
47451
  return /* @__PURE__ */ import_react18.default.createElement(Card, { tone: CARD.subagent.color }, /* @__PURE__ */ import_react18.default.createElement(
47917
47452
  CardHeader,
47918
47453
  {
@@ -47923,7 +47458,28 @@ function SubagentRow({ activity }) {
47923
47458
  meta: [`iter ${activity.iter}`, `${seconds}s`],
47924
47459
  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 }))
47925
47460
  }
47926
- ), /* @__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));
47461
+ ), /* @__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"))), streamLine ? /* @__PURE__ */ import_react18.default.createElement(Text, { color: FG.faint }, "flow ", /* @__PURE__ */ import_react18.default.createElement(Text, { color: FG.sub }, streamLine)) : null, /* @__PURE__ */ import_react18.default.createElement(Text, { color: TONE.brand }, "\u25B6 ", phase));
47462
+ }
47463
+ function formatBytes(n) {
47464
+ if (n < 1024) return `${n} B`;
47465
+ if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`;
47466
+ return `${(n / (1024 * 1024)).toFixed(2)} MB`;
47467
+ }
47468
+ function formatSubagentBytes(a) {
47469
+ if (a.outputChars + a.reasoningChars + a.toolReadChars === 0) return null;
47470
+ const parts = [];
47471
+ if (a.toolReadChars > 0) parts.push(`\u2193 ${formatBytes(a.toolReadChars)} read`);
47472
+ if (a.outputChars > 0) parts.push(`\u2191 ${formatBytes(a.outputChars)} out`);
47473
+ if (a.reasoningChars > 0) parts.push(`\u25C6 ${formatBytes(a.reasoningChars)} think`);
47474
+ return parts.join(" \xB7 ");
47475
+ }
47476
+ function formatStreamLine(a) {
47477
+ if (a.outputChars + a.reasoningChars + a.toolReadChars === 0) return null;
47478
+ const parts = [];
47479
+ if (a.toolReadChars > 0) parts.push(`\u2193 read ${formatBytes(a.toolReadChars)}`);
47480
+ if (a.outputChars > 0) parts.push(`\u2191 out ${formatBytes(a.outputChars)}`);
47481
+ if (a.reasoningChars > 0) parts.push(`\u25C6 think ${formatBytes(a.reasoningChars)}`);
47482
+ return parts.join(" \xB7 ");
47927
47483
  }
47928
47484
  function SubagentLiveStack({
47929
47485
  activities,
@@ -47966,14 +47522,25 @@ function CompactSubagentLine({
47966
47522
  function truncate(text, max) {
47967
47523
  return text.length > max ? `${text.slice(0, max)}\u2026` : text;
47968
47524
  }
47525
+ var SUBAGENT_WRAPPER_TOOLS = /* @__PURE__ */ new Set([
47526
+ "explore",
47527
+ "research",
47528
+ "review",
47529
+ "security_review",
47530
+ "run_skill"
47531
+ ]);
47969
47532
  function OngoingToolRow({
47970
47533
  tool,
47971
- progress
47534
+ progress,
47535
+ subagentActivities = []
47972
47536
  }) {
47973
47537
  const tick = useTick();
47974
47538
  const elapsed = useElapsedSeconds();
47975
47539
  const summary = summarizeToolArgs(tool.name, tool.args);
47976
- 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);
47540
+ const argsBytes = tool.args ? tool.args.length : 0;
47541
+ const subagentBytes = SUBAGENT_WRAPPER_TOOLS.has(tool.name) ? subagentActivities[subagentActivities.length - 1] : void 0;
47542
+ const subagentBytesLine = subagentBytes ? formatSubagentBytes(subagentBytes) : null;
47543
+ 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`, argsBytes > 0 ? ` \xB7 args ${formatBytes(argsBytes)}` : "")), subagentBytesLine ? /* @__PURE__ */ import_react18.default.createElement(Box_default, { paddingLeft: 3 }, /* @__PURE__ */ import_react18.default.createElement(Text, { color: FG.faint }, subagentBytesLine)) : null, 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);
47977
47544
  }
47978
47545
  function renderProgressLine(p) {
47979
47546
  const msg = p.message ? ` ${p.message}` : "";
@@ -48047,23 +47614,23 @@ function Countdown({
48047
47614
  var import_react20 = __toESM(require_react(), 1);
48048
47615
 
48049
47616
  // src/cli/ui/state/reducer.ts
48050
- function reduce(state, event) {
47617
+ function reduce(state2, event) {
48051
47618
  switch (event.type) {
48052
47619
  case "user.submit":
48053
- return appendCard(state, makeUserCard(event.text));
47620
+ return appendCard(state2, makeUserCard(event.text));
48054
47621
  case "turn.start":
48055
- return { ...state, turnInProgress: true };
47622
+ return { ...state2, turnInProgress: true };
48056
47623
  case "turn.thinking":
48057
47624
  return appendCard(
48058
- state,
48059
- makeLiveCard("thinking", `thinking \xB7 ${state.session.model}`, "brand")
47625
+ state2,
47626
+ makeLiveCard("thinking", `thinking \xB7 ${state2.session.model}`, "brand")
48060
47627
  );
48061
47628
  case "reasoning.start":
48062
- return appendCard(state, makeReasoningCard(event.id, event.model ?? state.session.model));
47629
+ return appendCard(state2, makeReasoningCard(event.id, event.model ?? state2.session.model));
48063
47630
  case "reasoning.chunk":
48064
- return mutateCard(state, event.id, "reasoning", (c) => ({ ...c, text: c.text + event.text }));
47631
+ return mutateCard(state2, event.id, "reasoning", (c) => ({ ...c, text: c.text + event.text }));
48065
47632
  case "reasoning.end":
48066
- return mutateCard(state, event.id, "reasoning", (c) => ({
47633
+ return mutateCard(state2, event.id, "reasoning", (c) => ({
48067
47634
  ...c,
48068
47635
  paragraphs: event.paragraphs,
48069
47636
  tokens: event.tokens,
@@ -48072,24 +47639,24 @@ function reduce(state, event) {
48072
47639
  ...event.aborted ? { aborted: true } : {}
48073
47640
  }));
48074
47641
  case "streaming.start":
48075
- return appendCard(state, makeStreamingCard(event.id, event.model ?? state.session.model));
47642
+ return appendCard(state2, makeStreamingCard(event.id, event.model ?? state2.session.model));
48076
47643
  case "streaming.chunk":
48077
- return mutateCard(state, event.id, "streaming", (c) => ({ ...c, text: c.text + event.text }));
47644
+ return mutateCard(state2, event.id, "streaming", (c) => ({ ...c, text: c.text + event.text }));
48078
47645
  case "streaming.end":
48079
- return mutateCard(state, event.id, "streaming", (c) => ({
47646
+ return mutateCard(state2, event.id, "streaming", (c) => ({
48080
47647
  ...c,
48081
47648
  done: true,
48082
47649
  endedAt: Date.now(),
48083
47650
  ...event.aborted ? { aborted: true } : {}
48084
47651
  }));
48085
47652
  case "tool.start":
48086
- return appendCard(state, makeToolCard(event.id, event.name, event.args));
47653
+ return appendCard(state2, makeToolCard(event.id, event.name, event.args));
48087
47654
  case "tool.chunk":
48088
- return mutateCard(state, event.id, "tool", (c) => ({ ...c, output: c.output + event.text }));
47655
+ return mutateCard(state2, event.id, "tool", (c) => ({ ...c, output: c.output + event.text }));
48089
47656
  case "tool.end": {
48090
47657
  const finalOutput = event.output ?? "";
48091
47658
  const rejected = isPlanModeRejection(finalOutput);
48092
- return mutateCard(state, event.id, "tool", (c) => ({
47659
+ return mutateCard(state2, event.id, "tool", (c) => ({
48093
47660
  ...c,
48094
47661
  done: true,
48095
47662
  output: event.output ?? c.output,
@@ -48100,97 +47667,97 @@ function reduce(state, event) {
48100
47667
  }));
48101
47668
  }
48102
47669
  case "tool.retry":
48103
- return mutateCard(state, event.id, "tool", (c) => ({
47670
+ return mutateCard(state2, event.id, "tool", (c) => ({
48104
47671
  ...c,
48105
47672
  retry: { attempt: event.attempt, max: event.max }
48106
47673
  }));
48107
47674
  case "turn.abort":
48108
47675
  return {
48109
- ...state,
47676
+ ...state2,
48110
47677
  turnInProgress: false,
48111
- composer: { ...state.composer, abortedHint: true }
47678
+ composer: { ...state2.composer, abortedHint: true }
48112
47679
  };
48113
47680
  case "turn.end": {
48114
- const sessionCost = state.status.sessionCost + event.usage.cost;
48115
- const sessionInputTokens = state.status.sessionInputTokens + event.usage.prompt;
48116
- const sessionOutputTokens = state.status.sessionOutputTokens + event.usage.output;
47681
+ const sessionCost = state2.status.sessionCost + event.usage.cost;
47682
+ const sessionInputTokens = state2.status.sessionInputTokens + event.usage.prompt;
47683
+ const sessionOutputTokens = state2.status.sessionOutputTokens + event.usage.output;
48117
47684
  return {
48118
- ...state,
47685
+ ...state2,
48119
47686
  turnInProgress: false,
48120
47687
  status: {
48121
- ...state.status,
47688
+ ...state2.status,
48122
47689
  cost: event.usage.cost,
48123
47690
  sessionCost,
48124
47691
  cacheHit: event.sessionCacheHit ?? event.usage.cacheHit,
48125
47692
  promptTokens: event.usage.prompt,
48126
- promptCap: event.promptCap ?? state.status.promptCap,
47693
+ promptCap: event.promptCap ?? state2.status.promptCap,
48127
47694
  sessionInputTokens,
48128
47695
  sessionOutputTokens,
48129
- lastTurnMs: event.elapsedMs ?? state.status.lastTurnMs
47696
+ lastTurnMs: event.elapsedMs ?? state2.status.lastTurnMs
48130
47697
  }
48131
47698
  };
48132
47699
  }
48133
47700
  case "mode.change":
48134
- return { ...state, status: { ...state.status, mode: event.mode } };
47701
+ return { ...state2, status: { ...state2.status, mode: event.mode } };
48135
47702
  case "network.change":
48136
47703
  return {
48137
- ...state,
48138
- status: { ...state.status, network: event.state, networkDetail: event.detail }
47704
+ ...state2,
47705
+ status: { ...state2.status, network: event.state, networkDetail: event.detail }
48139
47706
  };
48140
47707
  case "language.change":
48141
- return { ...state, lang: event.lang };
47708
+ return { ...state2, lang: event.lang };
48142
47709
  case "session.update":
48143
- return { ...state, status: { ...state.status, ...event.patch } };
47710
+ return { ...state2, status: { ...state2.status, ...event.patch } };
48144
47711
  case "session.model.change":
48145
- return state.session.model === event.model ? state : { ...state, session: { ...state.session, model: event.model } };
47712
+ return state2.session.model === event.model ? state2 : { ...state2, session: { ...state2.session, model: event.model } };
48146
47713
  case "session.preset.change":
48147
- return state.status.preset === event.preset ? state : { ...state, status: { ...state.status, preset: event.preset } };
47714
+ return state2.status.preset === event.preset ? state2 : { ...state2, status: { ...state2.status, preset: event.preset } };
48148
47715
  case "mcp.loading": {
48149
- const current = state.status.mcpLoading;
47716
+ const current = state2.status.mcpLoading;
48150
47717
  if (event.total <= 0) {
48151
- if (!current) return state;
48152
- const { mcpLoading: _drop, ...rest } = state.status;
48153
- return { ...state, status: rest };
47718
+ if (!current) return state2;
47719
+ const { mcpLoading: _drop, ...rest } = state2.status;
47720
+ return { ...state2, status: rest };
48154
47721
  }
48155
- if (current && current.ready === event.ready && current.total === event.total) return state;
47722
+ if (current && current.ready === event.ready && current.total === event.total) return state2;
48156
47723
  return {
48157
- ...state,
48158
- status: { ...state.status, mcpLoading: { ready: event.ready, total: event.total } }
47724
+ ...state2,
47725
+ status: { ...state2.status, mcpLoading: { ready: event.ready, total: event.total } }
48159
47726
  };
48160
47727
  }
48161
47728
  case "focus.move":
48162
47729
  return {
48163
- ...state,
48164
- focusedCardId: moveFocus(state.cards, state.focusedCardId, event.direction)
47730
+ ...state2,
47731
+ focusedCardId: moveFocus(state2.cards, state2.focusedCardId, event.direction)
48165
47732
  };
48166
47733
  case "focus.set":
48167
- return { ...state, focusedCardId: event.cardId };
47734
+ return { ...state2, focusedCardId: event.cardId };
48168
47735
  case "card.toggle":
48169
- return state;
47736
+ return state2;
48170
47737
  case "composer.input":
48171
47738
  return {
48172
- ...state,
47739
+ ...state2,
48173
47740
  composer: {
48174
- ...state.composer,
47741
+ ...state2.composer,
48175
47742
  value: event.value,
48176
47743
  cursor: event.value.length,
48177
47744
  abortedHint: false
48178
47745
  }
48179
47746
  };
48180
47747
  case "composer.cursor":
48181
- return { ...state, composer: { ...state.composer, cursor: event.index } };
47748
+ return { ...state2, composer: { ...state2.composer, cursor: event.index } };
48182
47749
  case "composer.history":
48183
- return state;
47750
+ return state2;
48184
47751
  case "picker.open":
48185
- return { ...state, composer: { ...state.composer, picker: event.kind } };
47752
+ return { ...state2, composer: { ...state2.composer, picker: event.kind } };
48186
47753
  case "picker.close":
48187
- return { ...state, composer: { ...state.composer, picker: null } };
47754
+ return { ...state2, composer: { ...state2.composer, picker: null } };
48188
47755
  case "toast.show":
48189
- return { ...state, toasts: [...state.toasts, makeToast(event)] };
47756
+ return { ...state2, toasts: [...state2.toasts, makeToast(event)] };
48190
47757
  case "toast.hide":
48191
- return { ...state, toasts: state.toasts.filter((t2) => t2.id !== event.id) };
47758
+ return { ...state2, toasts: state2.toasts.filter((t2) => t2.id !== event.id) };
48192
47759
  case "live.show":
48193
- return appendCard(state, {
47760
+ return appendCard(state2, {
48194
47761
  kind: "live",
48195
47762
  id: event.id,
48196
47763
  ts: event.ts,
@@ -48200,7 +47767,7 @@ function reduce(state, event) {
48200
47767
  meta: event.meta
48201
47768
  });
48202
47769
  case "tip.show":
48203
- return appendCard(state, {
47770
+ return appendCard(state2, {
48204
47771
  kind: "tip",
48205
47772
  id: event.id,
48206
47773
  ts: event.ts,
@@ -48211,12 +47778,12 @@ function reduce(state, event) {
48211
47778
  });
48212
47779
  case "session.reset":
48213
47780
  return {
48214
- ...state,
47781
+ ...state2,
48215
47782
  cards: [],
48216
47783
  focusedCardId: null,
48217
47784
  toasts: [],
48218
47785
  status: {
48219
- ...state.status,
47786
+ ...state2.status,
48220
47787
  cost: 0,
48221
47788
  sessionCost: 0,
48222
47789
  cacheHit: 0,
@@ -48225,17 +47792,17 @@ function reduce(state, event) {
48225
47792
  }
48226
47793
  };
48227
47794
  case "session.fork": {
48228
- const idx = state.cards.findIndex((c) => c.id === event.cardId);
48229
- if (idx < 0) return state;
48230
- return { ...state, cards: state.cards.slice(0, idx), focusedCardId: null };
47795
+ const idx = state2.cards.findIndex((c) => c.id === event.cardId);
47796
+ if (idx < 0) return state2;
47797
+ return { ...state2, cards: state2.cards.slice(0, idx), focusedCardId: null };
48231
47798
  }
48232
47799
  case "session.workspace.change":
48233
- return state.session.id === event.id && state.session.workspace === event.workspace ? state : {
48234
- ...state,
48235
- session: { ...state.session, id: event.id, workspace: event.workspace }
47800
+ return state2.session.id === event.id && state2.session.workspace === event.workspace ? state2 : {
47801
+ ...state2,
47802
+ session: { ...state2.session, id: event.id, workspace: event.workspace }
48236
47803
  };
48237
47804
  case "plan.show":
48238
- return appendCard(state, {
47805
+ return appendCard(state2, {
48239
47806
  kind: "plan",
48240
47807
  id: event.id,
48241
47808
  ts: Date.now(),
@@ -48245,20 +47812,20 @@ function reduce(state, event) {
48245
47812
  });
48246
47813
  case "plan.drop": {
48247
47814
  let dropped = false;
48248
- const cards = state.cards.map((c, i) => {
47815
+ const cards = state2.cards.map((c, i) => {
48249
47816
  if (dropped) return c;
48250
47817
  if (c.kind !== "plan" || c.variant !== "active") return c;
48251
- if (state.cards.slice(i + 1).some((cc) => cc.kind === "plan" && cc.variant === "active")) {
47818
+ if (state2.cards.slice(i + 1).some((cc) => cc.kind === "plan" && cc.variant === "active")) {
48252
47819
  return c;
48253
47820
  }
48254
47821
  dropped = true;
48255
47822
  return { ...c, variant: "replay" };
48256
47823
  });
48257
- return dropped ? { ...state, cards } : state;
47824
+ return dropped ? { ...state2, cards } : state2;
48258
47825
  }
48259
47826
  case "plan.step.complete": {
48260
47827
  let changed = false;
48261
- const cards = state.cards.map((c) => {
47828
+ const cards = state2.cards.map((c) => {
48262
47829
  if (c.kind !== "plan") return c;
48263
47830
  let stepChanged = false;
48264
47831
  const next = c.steps.map((s) => {
@@ -48270,10 +47837,10 @@ function reduce(state, event) {
48270
47837
  changed = true;
48271
47838
  return { ...c, steps: next };
48272
47839
  });
48273
- return changed ? { ...state, cards } : state;
47840
+ return changed ? { ...state2, cards } : state2;
48274
47841
  }
48275
47842
  case "ctx.show":
48276
- return appendCard(state, {
47843
+ return appendCard(state2, {
48277
47844
  kind: "ctx",
48278
47845
  id: event.id,
48279
47846
  ts: Date.now(),
@@ -48288,14 +47855,14 @@ function reduce(state, event) {
48288
47855
  topTools: event.topTools
48289
47856
  });
48290
47857
  case "doctor.show":
48291
- return appendCard(state, {
47858
+ return appendCard(state2, {
48292
47859
  kind: "doctor",
48293
47860
  id: event.id,
48294
47861
  ts: Date.now(),
48295
47862
  checks: event.checks
48296
47863
  });
48297
47864
  case "usage.show":
48298
- return appendCard(state, {
47865
+ return appendCard(state2, {
48299
47866
  kind: "usage",
48300
47867
  id: event.id,
48301
47868
  ts: Date.now(),
@@ -48313,34 +47880,65 @@ function reduce(state, event) {
48313
47880
  var RECENT_CARDS_WINDOW = 200;
48314
47881
  var MIN_ELIDE_OUTPUT_LENGTH = 4096;
48315
47882
  var ELIDED_TOOL_OUTPUT_PREFIX = "[elided \u2014 older than the last ";
48316
- function elideOldToolOutputs(cards) {
47883
+ function elidedStub(originalChars) {
47884
+ return `${ELIDED_TOOL_OUTPUT_PREFIX}${RECENT_CARDS_WINDOW} cards; ${originalChars.toLocaleString()} chars dropped to save memory. Full output is on disk in the session log.]`;
47885
+ }
47886
+ function stubHeavyContent(c) {
47887
+ switch (c.kind) {
47888
+ case "tool": {
47889
+ const out = c.output;
47890
+ if (typeof out !== "string") return c;
47891
+ if (out.length <= MIN_ELIDE_OUTPUT_LENGTH) return c;
47892
+ if (out.startsWith(ELIDED_TOOL_OUTPUT_PREFIX)) return c;
47893
+ return { ...c, output: elidedStub(out.length) };
47894
+ }
47895
+ case "reasoning": {
47896
+ const r = c;
47897
+ if (r.streaming) return c;
47898
+ if (r.text.length <= MIN_ELIDE_OUTPUT_LENGTH) return c;
47899
+ if (r.text.startsWith(ELIDED_TOOL_OUTPUT_PREFIX)) return c;
47900
+ return { ...r, text: elidedStub(r.text.length) };
47901
+ }
47902
+ case "streaming": {
47903
+ const s = c;
47904
+ if (!s.done) return c;
47905
+ if (s.text.length <= MIN_ELIDE_OUTPUT_LENGTH) return c;
47906
+ if (s.text.startsWith(ELIDED_TOOL_OUTPUT_PREFIX)) return c;
47907
+ return { ...s, text: elidedStub(s.text.length) };
47908
+ }
47909
+ case "diff": {
47910
+ if (c.hunks.length === 0) return c;
47911
+ let totalChars = 0;
47912
+ for (const h of c.hunks) for (const l of h.lines) totalChars += l.text.length;
47913
+ if (totalChars <= MIN_ELIDE_OUTPUT_LENGTH) return c;
47914
+ return { ...c, hunks: [] };
47915
+ }
47916
+ default:
47917
+ return c;
47918
+ }
47919
+ }
47920
+ function elideOldCardContent(cards) {
48317
47921
  if (cards.length < RECENT_CARDS_WINDOW) return cards;
48318
47922
  const cutoff = cards.length + 1 - RECENT_CARDS_WINDOW;
48319
47923
  let next = null;
48320
47924
  for (let i = 0; i < cutoff; i++) {
48321
47925
  const c = cards[i];
48322
- if (c.kind !== "tool") continue;
48323
- const out = c.output;
48324
- if (typeof out !== "string") continue;
48325
- if (out.length <= MIN_ELIDE_OUTPUT_LENGTH) continue;
48326
- if (out.startsWith(ELIDED_TOOL_OUTPUT_PREFIX)) continue;
47926
+ const stubbed = stubHeavyContent(c);
47927
+ if (stubbed === c) continue;
48327
47928
  if (next === null) next = cards.slice();
48328
- next[i] = {
48329
- ...c,
48330
- output: `${ELIDED_TOOL_OUTPUT_PREFIX}${RECENT_CARDS_WINDOW} cards; ${out.length.toLocaleString()} chars dropped to save memory. Full output is on disk in the session log.]`
48331
- };
47929
+ next[i] = stubbed;
48332
47930
  }
48333
47931
  return next ?? cards;
48334
47932
  }
48335
- function appendCard(state, card) {
48336
- return { ...state, cards: [...elideOldToolOutputs(state.cards), card] };
47933
+ function appendCard(state2, card) {
47934
+ return { ...state2, cards: [...elideOldCardContent(state2.cards), card] };
48337
47935
  }
48338
- function mutateCard(state, id, kind, patch) {
48339
- const idx = state.cards.findIndex((c) => c.id === id && c.kind === kind);
48340
- if (idx < 0) return state;
48341
- const next = state.cards.slice();
48342
- next[idx] = patch(state.cards[idx]);
48343
- return { ...state, cards: next };
47936
+ function mutateCard(state2, id, kind, patch) {
47937
+ const idx = state2.cards.findIndex((c) => c.id === id && c.kind === kind);
47938
+ if (idx < 0) return state2;
47939
+ const next = state2.cards.slice();
47940
+ next[idx] = patch(state2.cards[idx]);
47941
+ return { ...state2, cards: next };
48344
47942
  }
48345
47943
  function moveFocus(cards, current, dir) {
48346
47944
  const last = cards.length - 1;
@@ -48450,15 +48048,15 @@ function initialState(session, cards = []) {
48450
48048
 
48451
48049
  // src/cli/ui/state/store.ts
48452
48050
  function createStore(session, initialCards) {
48453
- let state = initialState(session, initialCards);
48051
+ let state2 = initialState(session, initialCards);
48454
48052
  const stateListeners = /* @__PURE__ */ new Set();
48455
48053
  const eventListeners = /* @__PURE__ */ new Set();
48456
48054
  return {
48457
48055
  getState() {
48458
- return state;
48056
+ return state2;
48459
48057
  },
48460
48058
  dispatch(event) {
48461
- state = reduce(state, event);
48059
+ state2 = reduce(state2, event);
48462
48060
  for (const listener of stateListeners) listener();
48463
48061
  for (const listener of eventListeners) listener(event);
48464
48062
  },
@@ -48651,8 +48249,8 @@ function modeGlyph(mode2) {
48651
48249
  return { glyph: "\xB1", color: TONE.ok };
48652
48250
  }
48653
48251
  }
48654
- function networkDot(state) {
48655
- switch (state) {
48252
+ function networkDot(state2) {
48253
+ switch (state2) {
48656
48254
  case "online":
48657
48255
  return { glyph: "\u25CF", color: TONE.ok };
48658
48256
  case "slow":
@@ -48729,6 +48327,7 @@ var import_react22 = __toESM(require_react(), 1);
48729
48327
  // src/cli/ui/state/chat-scroll-store.ts
48730
48328
  var SCROLL_ARROW_ROWS = 3;
48731
48329
  var SCROLL_PAGE_ROWS = 5;
48330
+ var SCROLL_WHEEL_ROWS = 1;
48732
48331
  var COALESCE_MS = 16;
48733
48332
  var EMPTY_HEIGHTS = /* @__PURE__ */ new Map();
48734
48333
  var initial = {
@@ -48739,29 +48338,29 @@ var initial = {
48739
48338
  cardHeights: EMPTY_HEIGHTS
48740
48339
  };
48741
48340
  function createChatScrollStore() {
48742
- let state = initial;
48341
+ let state2 = initial;
48743
48342
  const listeners = /* @__PURE__ */ new Set();
48744
48343
  let pendingDelta = 0;
48745
48344
  let flushTimer = null;
48746
48345
  let pendingMaxShrink = null;
48747
48346
  let shrinkTimer = null;
48748
48347
  function set(next) {
48749
- const merged = { ...state, ...next };
48750
- if (merged.scrollRows === state.scrollRows && merged.pinned === state.pinned && merged.maxScroll === state.maxScroll && merged.scrollVersion === state.scrollVersion && merged.cardHeights === state.cardHeights) {
48348
+ const merged = { ...state2, ...next };
48349
+ if (merged.scrollRows === state2.scrollRows && merged.pinned === state2.pinned && merged.maxScroll === state2.maxScroll && merged.scrollVersion === state2.scrollVersion && merged.cardHeights === state2.cardHeights) {
48751
48350
  return;
48752
48351
  }
48753
- state = merged;
48352
+ state2 = merged;
48754
48353
  for (const l of listeners) l();
48755
48354
  }
48756
48355
  function applyDelta() {
48757
48356
  const d = pendingDelta;
48758
48357
  pendingDelta = 0;
48759
48358
  if (d === 0) return;
48760
- const next = Math.max(0, Math.min(state.maxScroll, state.scrollRows + d));
48359
+ const next = Math.max(0, Math.min(state2.maxScroll, state2.scrollRows + d));
48761
48360
  set({
48762
48361
  scrollRows: next,
48763
- pinned: d < 0 ? false : next >= state.maxScroll ? true : state.pinned,
48764
- scrollVersion: state.scrollVersion + 1
48362
+ pinned: d < 0 ? false : next >= state2.maxScroll ? true : state2.pinned,
48363
+ scrollVersion: state2.scrollVersion + 1
48765
48364
  });
48766
48365
  }
48767
48366
  function schedule(delta) {
@@ -48784,12 +48383,12 @@ function createChatScrollStore() {
48784
48383
  const target = pendingMaxShrink;
48785
48384
  pendingMaxShrink = null;
48786
48385
  if (target === null) return;
48787
- const nextScrollRows = state.pinned ? target : Math.min(state.scrollRows, target);
48386
+ const nextScrollRows = state2.pinned ? target : Math.min(state2.scrollRows, target);
48788
48387
  set({ maxScroll: target, scrollRows: nextScrollRows });
48789
48388
  }
48790
48389
  return {
48791
48390
  getState() {
48792
- return state;
48391
+ return state2;
48793
48392
  },
48794
48393
  subscribe(listener) {
48795
48394
  listeners.add(listener);
@@ -48801,6 +48400,8 @@ function createChatScrollStore() {
48801
48400
  scrollDown: () => schedule(SCROLL_ARROW_ROWS),
48802
48401
  scrollPageUp: () => schedule(-SCROLL_PAGE_ROWS),
48803
48402
  scrollPageDown: () => schedule(SCROLL_PAGE_ROWS),
48403
+ scrollWheelUp: () => schedule(-SCROLL_WHEEL_ROWS),
48404
+ scrollWheelDown: () => schedule(SCROLL_WHEEL_ROWS),
48804
48405
  jumpToBottom() {
48805
48406
  pendingDelta = 0;
48806
48407
  if (flushTimer !== null) {
@@ -48816,8 +48417,8 @@ function createChatScrollStore() {
48816
48417
  },
48817
48418
  setMaxScroll(rows) {
48818
48419
  const m = rows < 0 ? 0 : rows;
48819
- const currentMax = pendingMaxShrink ?? state.maxScroll;
48820
- if (state.pinned && m < currentMax) {
48420
+ const currentMax = pendingMaxShrink ?? state2.maxScroll;
48421
+ if (state2.pinned && m < currentMax) {
48821
48422
  pendingMaxShrink = m;
48822
48423
  if (shrinkTimer === null) {
48823
48424
  shrinkTimer = setTimeout(() => {
@@ -48828,23 +48429,23 @@ function createChatScrollStore() {
48828
48429
  return;
48829
48430
  }
48830
48431
  if (pendingMaxShrink !== null) flushShrink();
48831
- const nextScrollRows = state.pinned ? m : Math.min(state.scrollRows, m);
48432
+ const nextScrollRows = state2.pinned ? m : Math.min(state2.scrollRows, m);
48832
48433
  set({ maxScroll: m, scrollRows: nextScrollRows });
48833
48434
  },
48834
48435
  setCardHeight(id, rows) {
48835
- if (state.cardHeights.get(id) === rows) return;
48836
- const next = new Map(state.cardHeights);
48436
+ if (state2.cardHeights.get(id) === rows) return;
48437
+ const next = new Map(state2.cardHeights);
48837
48438
  next.set(id, rows);
48838
48439
  set({ cardHeights: next });
48839
48440
  },
48840
48441
  pruneCardHeights(liveIds) {
48841
48442
  let drop = 0;
48842
- for (const id of state.cardHeights.keys()) {
48443
+ for (const id of state2.cardHeights.keys()) {
48843
48444
  if (!liveIds.has(id)) drop++;
48844
48445
  }
48845
48446
  if (drop === 0) return;
48846
48447
  const next = /* @__PURE__ */ new Map();
48847
- for (const [id, h] of state.cardHeights) {
48448
+ for (const [id, h] of state2.cardHeights) {
48848
48449
  if (liveIds.has(id)) next.set(id, h);
48849
48450
  }
48850
48451
  set({ cardHeights: next });
@@ -49530,7 +49131,14 @@ var LiveActivityArea = import_react31.default.memo(
49530
49131
  undoBanner,
49531
49132
  hideUndo
49532
49133
  }) => {
49533
- return /* @__PURE__ */ import_react31.default.createElement(Box_default, { flexDirection: "column", flexShrink: 0, flexWrap: "nowrap" }, noTakeoverOverlay && ongoingTool ? /* @__PURE__ */ import_react31.default.createElement(OngoingToolRow, { tool: ongoingTool, progress: toolProgress }) : null, noTakeoverOverlay && subagentActivities.length > 0 ? /* @__PURE__ */ import_react31.default.createElement(SubagentLiveStack, { activities: subagentActivities, max: 3 }) : null, noTakeoverOverlay && !ongoingTool && statusLine ? /* @__PURE__ */ import_react31.default.createElement(ThinkingRow, { text: statusLine }) : null, undoBanner && !hideUndo ? /* @__PURE__ */ import_react31.default.createElement(UndoBanner, { banner: undoBanner }) : null, noTakeoverOverlay && busy && !isStreaming && !ongoingTool && !statusLine ? /* @__PURE__ */ import_react31.default.createElement(ThinkingRow, { text: activityLabel }) : null, noTakeoverOverlay ? /* @__PURE__ */ import_react31.default.createElement(PlanLiveRow, null) : null, /* @__PURE__ */ import_react31.default.createElement(ToastRail, null));
49134
+ return /* @__PURE__ */ import_react31.default.createElement(Box_default, { flexDirection: "column", flexShrink: 0, flexWrap: "nowrap" }, noTakeoverOverlay && ongoingTool ? /* @__PURE__ */ import_react31.default.createElement(
49135
+ OngoingToolRow,
49136
+ {
49137
+ tool: ongoingTool,
49138
+ progress: toolProgress,
49139
+ subagentActivities
49140
+ }
49141
+ ) : null, noTakeoverOverlay && subagentActivities.length > 0 ? /* @__PURE__ */ import_react31.default.createElement(SubagentLiveStack, { activities: subagentActivities, max: 3 }) : null, noTakeoverOverlay && !ongoingTool && statusLine ? /* @__PURE__ */ import_react31.default.createElement(ThinkingRow, { text: statusLine }) : null, undoBanner && !hideUndo ? /* @__PURE__ */ import_react31.default.createElement(UndoBanner, { banner: undoBanner }) : null, noTakeoverOverlay && busy && !isStreaming && !ongoingTool && !statusLine ? /* @__PURE__ */ import_react31.default.createElement(ThinkingRow, { text: activityLabel }) : null, noTakeoverOverlay ? /* @__PURE__ */ import_react31.default.createElement(PlanLiveRow, null) : null, /* @__PURE__ */ import_react31.default.createElement(ToastRail, null));
49534
49142
  }
49535
49143
  );
49536
49144
  LiveActivityArea.displayName = "LiveActivityArea";
@@ -49865,7 +49473,7 @@ function isInstalled(installedSpecs, entry) {
49865
49473
  }
49866
49474
  }
49867
49475
  function McpMarketplace({ onClose, postInfo, reloadMcp, pickerPorts }) {
49868
- const [state, setState] = (0, import_react33.useState)({
49476
+ const [state2, setState] = (0, import_react33.useState)({
49869
49477
  handle: null,
49870
49478
  loading: true,
49871
49479
  query: "",
@@ -49899,28 +49507,28 @@ function McpMarketplace({ onClose, postInfo, reloadMcp, pickerPorts }) {
49899
49507
  };
49900
49508
  }, []);
49901
49509
  const filtered = (0, import_react33.useMemo)(() => {
49902
- if (!state.handle) return [];
49903
- return rankAndFilter(state.handle.cache.entries, state.query);
49904
- }, [state.handle, state.query]);
49905
- const selected = filtered[state.selected];
49510
+ if (!state2.handle) return [];
49511
+ return rankAndFilter(state2.handle.cache.entries, state2.query);
49512
+ }, [state2.handle, state2.query]);
49513
+ const selected = filtered[state2.selected];
49906
49514
  const fetchMore = (0, import_react33.useCallback)(async () => {
49907
- if (!state.handle || state.loading) return;
49908
- if (state.handle.cache.pagination.nextCursor === null) {
49515
+ if (!state2.handle || state2.loading) return;
49516
+ if (state2.handle.cache.pagination.nextCursor === null) {
49909
49517
  setState((s) => ({ ...s, status: t("mcpMarketplace.allLoaded") }));
49910
49518
  return;
49911
49519
  }
49912
49520
  setState((s) => ({ ...s, loading: true, status: t("mcpMarketplace.loadingMore") }));
49913
49521
  try {
49914
- const r = await loadMorePages(state.handle, { pages: 5 });
49522
+ const r = await loadMorePages(state2.handle, { pages: 5 });
49915
49523
  setState((s) => ({
49916
49524
  ...s,
49917
49525
  loading: false,
49918
- status: `+${r.newEntries} \xB7 ${state.handle?.cache.entries.length ?? 0} total${r.exhausted ? " \xB7 exhausted" : ""}`
49526
+ status: `+${r.newEntries} \xB7 ${state2.handle?.cache.entries.length ?? 0} total${r.exhausted ? " \xB7 exhausted" : ""}`
49919
49527
  }));
49920
49528
  } catch (err) {
49921
49529
  setState((s) => ({ ...s, loading: false, status: `error: ${err.message}` }));
49922
49530
  }
49923
- }, [state.handle, state.loading]);
49531
+ }, [state2.handle, state2.loading]);
49924
49532
  const doUninstall = (0, import_react33.useCallback)(
49925
49533
  async (entry, installed) => {
49926
49534
  const cfg = readConfig();
@@ -50005,21 +49613,21 @@ function McpMarketplace({ onClose, postInfo, reloadMcp, pickerPorts }) {
50005
49613
  );
50006
49614
  const installOrToggle = (0, import_react33.useCallback)(
50007
49615
  async (entry) => {
50008
- const installed = isInstalled(state.installedSpecs, entry);
49616
+ const installed = isInstalled(state2.installedSpecs, entry);
50009
49617
  if (installed) await doUninstall(entry, installed);
50010
49618
  else await doInstall(entry);
50011
49619
  },
50012
- [state.installedSpecs, doInstall, doUninstall]
49620
+ [state2.installedSpecs, doInstall, doUninstall]
50013
49621
  );
50014
49622
  const pickerSnapshot = (0, import_react33.useMemo)(
50015
49623
  () => buildMarketplacePickerSnapshot({
50016
49624
  filtered,
50017
- installedSpecs: state.installedSpecs,
50018
- query: state.query,
50019
- status: state.status,
50020
- hasMore: state.handle?.cache.pagination.nextCursor != null
49625
+ installedSpecs: state2.installedSpecs,
49626
+ query: state2.query,
49627
+ status: state2.status,
49628
+ hasMore: state2.handle?.cache.pagination.nextCursor != null
50021
49629
  }),
50022
- [filtered, state.installedSpecs, state.handle, state.query, state.status]
49630
+ [filtered, state2.installedSpecs, state2.handle, state2.query, state2.status]
50023
49631
  );
50024
49632
  usePickerBroadcast(
50025
49633
  !!pickerPorts,
@@ -50035,9 +49643,9 @@ function McpMarketplace({ onClose, postInfo, reloadMcp, pickerPorts }) {
50035
49643
  return;
50036
49644
  }
50037
49645
  if (res.action === "install") {
50038
- const entry = state.handle?.cache.entries.find((e) => e.name === res.id);
49646
+ const entry = state2.handle?.cache.entries.find((e) => e.name === res.id);
50039
49647
  if (!entry) return;
50040
- if (isInstalled(state.installedSpecs, entry)) {
49648
+ if (isInstalled(state2.installedSpecs, entry)) {
50041
49649
  setState((s) => ({ ...s, status: `already installed: ${entry.name}` }));
50042
49650
  return;
50043
49651
  }
@@ -50045,9 +49653,9 @@ function McpMarketplace({ onClose, postInfo, reloadMcp, pickerPorts }) {
50045
49653
  return;
50046
49654
  }
50047
49655
  if (res.action === "uninstall") {
50048
- const entry = state.handle?.cache.entries.find((e) => e.name === res.id);
49656
+ const entry = state2.handle?.cache.entries.find((e) => e.name === res.id);
50049
49657
  if (!entry) return;
50050
- const installed = isInstalled(state.installedSpecs, entry);
49658
+ const installed = isInstalled(state2.installedSpecs, entry);
50051
49659
  if (!installed) {
50052
49660
  setState((s) => ({ ...s, status: `not installed: ${entry.name}` }));
50053
49661
  return;
@@ -50094,20 +49702,20 @@ function McpMarketplace({ onClose, postInfo, reloadMcp, pickerPorts }) {
50094
49702
  const overlay = (0, import_react33.useMemo)(() => loadOverlay("zh-CN"), []);
50095
49703
  const start = Math.max(
50096
49704
  0,
50097
- Math.min(state.selected - Math.floor(VISIBLE_ROWS / 2), filtered.length - VISIBLE_ROWS)
49705
+ Math.min(state2.selected - Math.floor(VISIBLE_ROWS / 2), filtered.length - VISIBLE_ROWS)
50098
49706
  );
50099
49707
  const window2 = filtered.slice(Math.max(0, start), Math.max(0, start) + VISIBLE_ROWS);
50100
- return /* @__PURE__ */ import_react33.default.createElement(Box_default, { flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ import_react33.default.createElement(Box_default, null, /* @__PURE__ */ import_react33.default.createElement(Text, { bold: true, color: COLOR.brand }, "\u25C8 MCP marketplace"), /* @__PURE__ */ import_react33.default.createElement(Text, { dimColor: true }, ` \xB7 ${state.status}`)), /* @__PURE__ */ import_react33.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react33.default.createElement(Text, null, t("mcpMarketplace.filter")), /* @__PURE__ */ import_react33.default.createElement(Text, null, state.query || t("mcpMarketplace.filterPlaceholder")), /* @__PURE__ */ import_react33.default.createElement(
49708
+ return /* @__PURE__ */ import_react33.default.createElement(Box_default, { flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ import_react33.default.createElement(Box_default, null, /* @__PURE__ */ import_react33.default.createElement(Text, { bold: true, color: COLOR.brand }, "\u25C8 MCP marketplace"), /* @__PURE__ */ import_react33.default.createElement(Text, { dimColor: true }, ` \xB7 ${state2.status}`)), /* @__PURE__ */ import_react33.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react33.default.createElement(Text, null, t("mcpMarketplace.filter")), /* @__PURE__ */ import_react33.default.createElement(Text, null, state2.query || t("mcpMarketplace.filterPlaceholder")), /* @__PURE__ */ import_react33.default.createElement(
50101
49709
  Text,
50102
49710
  {
50103
49711
  dimColor: true
50104
49712
  },
50105
49713
  ` ${t(filtered.length === 1 ? "mcpMarketplace.matchSingular" : "mcpMarketplace.matchPlural", { n: filtered.length })}`
50106
- )), /* @__PURE__ */ import_react33.default.createElement(Box_default, { marginTop: 1, flexDirection: "column" }, window2.length === 0 ? /* @__PURE__ */ import_react33.default.createElement(Text, { dimColor: true }, state.loading ? t("mcpMarketplace.loading") : t("mcpMarketplace.noEntries")) : window2.map((e, i) => {
49714
+ )), /* @__PURE__ */ import_react33.default.createElement(Box_default, { marginTop: 1, flexDirection: "column" }, window2.length === 0 ? /* @__PURE__ */ import_react33.default.createElement(Text, { dimColor: true }, state2.loading ? t("mcpMarketplace.loading") : t("mcpMarketplace.noEntries")) : window2.map((e, i) => {
50107
49715
  const idx = (start || 0) + i;
50108
- const active2 = idx === state.selected;
49716
+ const active2 = idx === state2.selected;
50109
49717
  const tag2 = e.source === "official" ? "[off]" : e.source === "smithery" ? "[smt]" : "[loc]";
50110
- const installedSpec = isInstalled(state.installedSpecs, e);
49718
+ const installedSpec = isInstalled(state2.installedSpecs, e);
50111
49719
  const installedBadge = installedSpec ? " \u2713" : "";
50112
49720
  const pop = e.popularity !== void 0 ? ` \xB7 ${e.popularity.toLocaleString()}` : "";
50113
49721
  return /* @__PURE__ */ import_react33.default.createElement(Box_default, { key: e.name }, /* @__PURE__ */ import_react33.default.createElement(Text, { color: active2 ? COLOR.brand : void 0 }, active2 ? "\u25B8 " : " "), /* @__PURE__ */ import_react33.default.createElement(Text, { bold: active2 }, e.name.padEnd(38).slice(0, 38)), /* @__PURE__ */ import_react33.default.createElement(Text, { dimColor: true }, ` ${tag2}${pop}${installedBadge}`));
@@ -53053,17 +52661,17 @@ function PlanConfirmInner({ plan: plan2, steps, summary, onChoose }) {
53053
52661
  return;
53054
52662
  }
53055
52663
  if (!isDetailScrollKey(ev)) return;
53056
- if (ev.pageUp || ev.mouseScrollUp) {
52664
+ if (ev.pageUp) {
53057
52665
  setDetailOffset((n) => Math.max(0, n - detailViewRows));
53058
- } else if (ev.pageDown || ev.mouseScrollDown) {
52666
+ } else if (ev.pageDown) {
53059
52667
  setDetailOffset((n) => Math.min(maxDetailOffset, n + detailViewRows));
53060
52668
  } else if (ev.home) {
53061
52669
  setDetailOffset(0);
53062
52670
  } else if (ev.end) {
53063
52671
  setDetailOffset(maxDetailOffset);
53064
- } else if (ev.upArrow) {
52672
+ } else if (ev.upArrow || ev.mouseScrollUp) {
53065
52673
  setDetailOffset((n) => Math.max(0, n - 1));
53066
- } else if (ev.downArrow) {
52674
+ } else if (ev.downArrow || ev.mouseScrollDown) {
53067
52675
  setDetailOffset((n) => Math.min(maxDetailOffset, n + 1));
53068
52676
  }
53069
52677
  });
@@ -53601,7 +53209,7 @@ function relativeTime2(date) {
53601
53209
  }
53602
53210
 
53603
53211
  // src/cli/ui/ShellConfirm.tsx
53604
- import { homedir as homedir3 } from "os";
53212
+ import { homedir as homedir2 } from "os";
53605
53213
  var import_react45 = __toESM(require_react(), 1);
53606
53214
  var CHROME_ROWS = 18;
53607
53215
  var MIN_COMMAND_LINES = 3;
@@ -53611,7 +53219,7 @@ function clampCommand(command, max) {
53611
53219
  return { preview: lines.slice(0, max).join("\n"), hidden: lines.length - max };
53612
53220
  }
53613
53221
  function tildeify2(path) {
53614
- const home = homedir3();
53222
+ const home = homedir2();
53615
53223
  if (!home) return path;
53616
53224
  const normalized = home.replace(/[\\/]+$/, "");
53617
53225
  if (path === normalized) return "~";
@@ -53944,13 +53552,13 @@ function wrapToCells(s, maxCells) {
53944
53552
  }
53945
53553
 
53946
53554
  // src/cli/ui/clipboard.ts
53947
- import { mkdtempSync as mkdtempSync2, writeFileSync as writeFileSync5 } from "fs";
53555
+ import { mkdtempSync as mkdtempSync2, writeFileSync as writeFileSync4 } from "fs";
53948
53556
  import { tmpdir as tmpdir2 } from "os";
53949
- import { join as join5 } from "path";
53557
+ import { join as join4 } from "path";
53950
53558
  var OSC_52_LIMIT = 75e3;
53951
53559
  function writeClipboard(text) {
53952
- const dir = mkdtempSync2(join5(tmpdir2(), "reasonix-clip-"));
53953
- const filePath = join5(dir, "clip.txt");
53560
+ const dir = mkdtempSync2(join4(tmpdir2(), "reasonix-clip-"));
53561
+ const filePath = join4(dir, "clip.txt");
53954
53562
  let osc52 = false;
53955
53563
  if (text.length <= OSC_52_LIMIT) {
53956
53564
  const b64 = Buffer.from(text, "utf8").toString("base64");
@@ -53959,7 +53567,7 @@ function writeClipboard(text) {
53959
53567
  }
53960
53568
  let writtenPath = null;
53961
53569
  try {
53962
- writeFileSync5(filePath, text, "utf8");
53570
+ writeFileSync4(filePath, text, "utf8");
53963
53571
  writtenPath = filePath;
53964
53572
  } catch {
53965
53573
  }
@@ -54234,9 +53842,9 @@ function loopEventToDashboard(ev, ctx) {
54234
53842
  }
54235
53843
 
54236
53844
  // src/cli/ui/hash-memory.ts
54237
- import { closeSync, fstatSync, mkdirSync as mkdirSync4, openSync, readSync, writeSync } from "fs";
54238
- import { homedir as homedir4 } from "os";
54239
- import { dirname as dirname4, join as join6 } from "path";
53845
+ import { closeSync, fstatSync, mkdirSync as mkdirSync3, openSync, readSync, writeSync } from "fs";
53846
+ import { homedir as homedir3 } from "os";
53847
+ import { dirname as dirname3, join as join5 } from "path";
54240
53848
  var PROJECT_HEADER = `# Reasonix project memory
54241
53849
 
54242
53850
  Notes the user pinned via the \`#\` prompt prefix. The whole file is
@@ -54272,8 +53880,8 @@ function appendProjectMemory(rootDir, note) {
54272
53880
  }
54273
53881
  var GLOBAL_MEMORY_DIR = ".reasonix";
54274
53882
  var GLOBAL_MEMORY_FILE = "REASONIX.md";
54275
- function globalMemoryPath(homeDir = homedir4()) {
54276
- return join6(homeDir, GLOBAL_MEMORY_DIR, GLOBAL_MEMORY_FILE);
53883
+ function globalMemoryPath(homeDir = homedir3()) {
53884
+ return join5(homeDir, GLOBAL_MEMORY_DIR, GLOBAL_MEMORY_FILE);
54277
53885
  }
54278
53886
  function appendGlobalMemory(note, homeDir) {
54279
53887
  return appendBulletToFile(globalMemoryPath(homeDir), note, GLOBAL_HEADER);
@@ -54283,7 +53891,7 @@ function appendBulletToFile(path, note, newFileHeader) {
54283
53891
  if (!trimmed) throw new Error("note body cannot be empty");
54284
53892
  const bullet2 = `- ${trimmed}
54285
53893
  `;
54286
- mkdirSync4(dirname4(path), { recursive: true });
53894
+ mkdirSync3(dirname3(path), { recursive: true });
54287
53895
  const fd = openSync(path, "a+");
54288
53896
  try {
54289
53897
  const stat = fstatSync(fd);
@@ -54454,16 +54062,22 @@ function handleToolEvent(ev, ctx) {
54454
54062
  const parsed = JSON.parse(ev.content);
54455
54063
  const stepId = parsed.stepId;
54456
54064
  if (parsed.kind === "step_completed" && typeof stepId === "string") {
54065
+ const fullCompletion = ctx.pendingStepCompletionsRef?.current.get(stepId);
54066
+ ctx.pendingStepCompletionsRef?.current.delete(stepId);
54067
+ const completion = fullCompletion ?? parsed;
54457
54068
  ctx.completedStepIdsRef.current.add(stepId);
54458
- ctx.stepCompletionsRef?.current.set(stepId, parsed);
54069
+ ctx.stepCompletionsRef?.current.set(stepId, completion);
54459
54070
  ctx.persistPlanState();
54460
54071
  ctx.log.completePlanStep(stepId);
54461
54072
  ctx.onPlanStepCompleted?.(stepId);
54462
54073
  const total = ctx.planStepsRef.current?.length ?? 0;
54463
54074
  const completed = ctx.completedStepIdsRef.current.size;
54464
54075
  const stepFromPlan = ctx.planStepsRef.current?.find((s) => s.id === stepId);
54465
- const title2 = parsed.title ?? stepFromPlan?.title;
54076
+ const title2 = completion.title ?? parsed.title ?? stepFromPlan?.title;
54466
54077
  if (title2) ctx.log.pushStepProgress(completed, total, title2);
54078
+ const compactEvidenceSummary = typeof parsed.evidenceSummary === "string" && parsed.evidenceSummary.trim() ? `evidence: ${parsed.evidenceSummary.trim()}` : null;
54079
+ const evidenceSummary = formatStepEvidenceSummary(completion.evidence) ?? compactEvidenceSummary;
54080
+ if (evidenceSummary) ctx.log.pushInfo(evidenceSummary, "ghost");
54467
54081
  if (ctx.session && total > 0 && completed >= total) {
54468
54082
  const archive = archivePlanState(ctx.session);
54469
54083
  if (archive) {
@@ -54475,6 +54089,20 @@ function handleToolEvent(ev, ctx) {
54475
54089
  }
54476
54090
  }
54477
54091
  }
54092
+ function formatStepEvidenceSummary(evidence) {
54093
+ if (!evidence || evidence.length === 0) return null;
54094
+ const parts = evidence.map(formatStepEvidenceItem).filter((part) => part.length > 0);
54095
+ if (parts.length === 0) return null;
54096
+ return `evidence: ${parts.join("; ")}`;
54097
+ }
54098
+ function formatStepEvidenceItem(evidence) {
54099
+ const extras = [];
54100
+ if (evidence.command) extras.push(evidence.command);
54101
+ if (evidence.paths && evidence.paths.length > 0)
54102
+ extras.push(evidence.paths.slice(0, 3).join(", "));
54103
+ const suffix = extras.length > 0 ? ` (${extras.join("; ")})` : "";
54104
+ return `${evidence.kind} - ${evidence.summary}${suffix}`;
54105
+ }
54478
54106
 
54479
54107
  // src/cli/ui/hooks/useActivityPhase.ts
54480
54108
  function deriveActivityLabel(cards) {
@@ -56235,7 +55863,7 @@ function headerColorFor(s) {
56235
55863
  function metaTrail(card) {
56236
55864
  const parts = [];
56237
55865
  const inputBytes = largestStringInputBytes(card.args);
56238
- if (inputBytes !== null) parts.push(t("cardLabels.bytesIn", { bytes: formatBytes(inputBytes) }));
55866
+ if (inputBytes !== null) parts.push(t("cardLabels.bytesIn", { bytes: formatBytes2(inputBytes) }));
56239
55867
  if (card.elapsedMs > 0)
56240
55868
  parts.push(t("cardLabels.elapsedSec", { secs: (card.elapsedMs / 1e3).toFixed(2) }));
56241
55869
  if (card.done && !card.rejected && !card.aborted && card.exitCode !== void 0 && card.exitCode !== 0) {
@@ -56270,7 +55898,7 @@ function largestStringInputBytes(args) {
56270
55898
  }
56271
55899
  return max >= INPUT_SIZE_THRESHOLD ? max : null;
56272
55900
  }
56273
- function formatBytes(n) {
55901
+ function formatBytes2(n) {
56274
55902
  if (n < 1024) return `${n} B`;
56275
55903
  if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`;
56276
55904
  return `${(n / (1024 * 1024)).toFixed(1)} MB`;
@@ -56586,9 +56214,9 @@ function formatResourceList(servers) {
56586
56214
  lines.push("");
56587
56215
  }
56588
56216
  if (total === 0) {
56589
- return "No resources on any connected MCP server (or no servers connected). `/mcp` shows the current set.";
56217
+ return t("mcpBrowse.noResources");
56590
56218
  }
56591
- lines.push("Read one: `/resource <uri>` \u2014 or use Tab in the picker.");
56219
+ lines.push(t("mcpBrowse.readOne"));
56592
56220
  return lines.join("\n");
56593
56221
  }
56594
56222
  function formatPromptList(servers) {
@@ -56609,11 +56237,9 @@ function formatPromptList(servers) {
56609
56237
  lines.push("");
56610
56238
  }
56611
56239
  if (total === 0) {
56612
- return "No prompts on any connected MCP server (or no servers connected). `/mcp` shows the current set.";
56240
+ return t("mcpBrowse.noPrompts");
56613
56241
  }
56614
- lines.push(
56615
- "Fetch one: `/prompt <name>` \u2014 args are not supported yet; prompts with required args will surface an error from the server."
56616
- );
56242
+ lines.push(t("mcpBrowse.fetchOne"));
56617
56243
  return lines.join("\n");
56618
56244
  }
56619
56245
  function findServerForResource(servers, uri) {
@@ -56769,7 +56395,7 @@ function formatLongPaste(input, opts = {}) {
56769
56395
  if (originalChars <= charCap && originalLines <= lineCap) {
56770
56396
  return { displayText: input, collapsed: false, originalChars, originalLines };
56771
56397
  }
56772
- const header = `\u25B8 pasted ${formatBytes2(originalChars)} (${originalLines} lines) \u2014 first ${Math.min(headN, originalLines)} shown, full text sent to model`;
56398
+ const header = `\u25B8 pasted ${formatBytes3(originalChars)} (${originalLines} lines) \u2014 first ${Math.min(headN, originalLines)} shown, full text sent to model`;
56773
56399
  const head = lines.slice(0, headN).join("\n");
56774
56400
  const remaining = originalLines - headN;
56775
56401
  const footer = remaining > 0 ? `\u2026 (${remaining} more line${remaining === 1 ? "" : "s"})` : "";
@@ -56779,7 +56405,7 @@ ${footer}` : `${header}
56779
56405
  ${head}`;
56780
56406
  return { displayText, collapsed: true, originalChars, originalLines };
56781
56407
  }
56782
- function formatBytes2(n) {
56408
+ function formatBytes3(n) {
56783
56409
  if (n < 1024) return `${n} B`;
56784
56410
  const kb = n / 1024;
56785
56411
  if (kb < 1024) return `${kb.toFixed(kb >= 10 ? 0 : 1)} KB`;
@@ -56915,6 +56541,9 @@ var handlers = {
56915
56541
  };
56916
56542
 
56917
56543
  // src/cli/ui/slash/handlers/basic.ts
56544
+ var ABOUT_WEBSITE = "https://esengine.github.io/DeepSeek-Reasonix/";
56545
+ var ABOUT_REPO = "https://github.com/esengine/DeepSeek-Reasonix";
56546
+ var ABOUT_LICENSE = "MIT";
56918
56547
  var exit = () => ({ exit: true });
56919
56548
  var resetLog = (_args, loop2) => {
56920
56549
  const { dropped, archived, systemRebuilt } = loop2.clearLog();
@@ -57042,6 +56671,16 @@ var keys = (_args, _loop, ctx) => {
57042
56671
  return {};
57043
56672
  };
57044
56673
  var copy = () => ({ openCopyMode: true });
56674
+ var about = () => {
56675
+ const lines = [
56676
+ t("handlers.basic.aboutHeader", { version: VERSION }),
56677
+ "",
56678
+ ` ${t("handlers.basic.aboutWebsiteLabel")} ${ABOUT_WEBSITE}`,
56679
+ ` ${t("handlers.basic.aboutRepoLabel")} ${ABOUT_REPO}`,
56680
+ ` ${t("handlers.basic.aboutLicenseLabel")} ${ABOUT_LICENSE}`
56681
+ ];
56682
+ return { info: lines.join("\n") };
56683
+ };
57045
56684
  var handlers2 = {
57046
56685
  exit,
57047
56686
  new: resetLog,
@@ -57049,7 +56688,8 @@ var handlers2 = {
57049
56688
  retry,
57050
56689
  loop,
57051
56690
  keys,
57052
- copy
56691
+ copy,
56692
+ about
57053
56693
  };
57054
56694
 
57055
56695
  // src/cli/ui/slash/handlers/dashboard.ts
@@ -57219,7 +56859,7 @@ var plan = (args, _loop, ctx) => {
57219
56859
  if (raw === "on" || raw === "true" || raw === "1" || raw === "strict") target = true;
57220
56860
  else if (raw === "off" || raw === "false" || raw === "0") target = false;
57221
56861
  else target = !currentOn;
57222
- ctx.setPlanMode(target);
56862
+ ctx.setPlanMode(target, "slash");
57223
56863
  if (target) {
57224
56864
  return { info: t("handlers.edits.planOn") };
57225
56865
  }
@@ -58799,7 +58439,7 @@ var handlers17 = {
58799
58439
  var handlers18 = {
58800
58440
  "search-engine": (args, _loop, ctx) => {
58801
58441
  const engine = args[0];
58802
- if (!engine || engine !== "mojeek" && engine !== "searxng" && engine !== "metaso" && engine !== "tavily") {
58442
+ if (!engine || engine !== "mojeek" && engine !== "searxng" && engine !== "metaso" && engine !== "tavily" && engine !== "perplexity" && engine !== "exa") {
58803
58443
  return {
58804
58444
  info: [
58805
58445
  t("handlers.webSearchEngine.currentEngine", { engine: webSearchEngine() }),
@@ -58811,6 +58451,8 @@ var handlers18 = {
58811
58451
  t("handlers.webSearchEngine.usageSearxngUrl"),
58812
58452
  t("handlers.webSearchEngine.usageMetaso"),
58813
58453
  t("handlers.webSearchEngine.usageTavily"),
58454
+ t("handlers.webSearchEngine.usagePerplexity"),
58455
+ t("handlers.webSearchEngine.usageExa"),
58814
58456
  "",
58815
58457
  t("handlers.webSearchEngine.alias"),
58816
58458
  "",
@@ -58820,14 +58462,33 @@ var handlers18 = {
58820
58462
  };
58821
58463
  }
58822
58464
  const cfg = readConfig();
58465
+ const apiKeyEngines = /* @__PURE__ */ new Set(["tavily", "perplexity", "exa", "metaso"]);
58466
+ if (apiKeyEngines.has(engine)) {
58467
+ const loadKey = engine === "tavily" ? loadTavilyApiKey : engine === "perplexity" ? loadPerplexityApiKey : engine === "exa" ? loadExaApiKey : loadMetasoApiKey;
58468
+ if (args[1]) {
58469
+ cfg.webSearchEngine = engine;
58470
+ cfg[`${engine}ApiKey`] = args[1];
58471
+ writeConfig(cfg);
58472
+ return {
58473
+ info: `${t("handlers.webSearchEngine.confirmed", { engine, detail: "" })} ${t("handlers.webSearchEngine.keySaved")}`
58474
+ };
58475
+ }
58476
+ const existingKey = loadKey();
58477
+ if (existingKey) {
58478
+ cfg.webSearchEngine = engine;
58479
+ writeConfig(cfg);
58480
+ return { info: t("handlers.webSearchEngine.confirmed", { engine, detail: "" }) };
58481
+ }
58482
+ const envVar = `${engine.toUpperCase()}_API_KEY`;
58483
+ return { info: t("handlers.webSearchEngine.keyNeeded", { engine, envVar }) };
58484
+ }
58823
58485
  cfg.webSearchEngine = engine;
58824
58486
  if (engine === "searxng" && args[1]) {
58825
58487
  const raw = args[1];
58826
58488
  cfg.webSearchEndpoint = raw.includes("://") ? raw : `http://${raw}`;
58827
58489
  }
58828
58490
  writeConfig(cfg);
58829
- const note = engine === "searxng" ? t("handlers.webSearchEngine.switchedSearxngNote", { endpoint: webSearchEndpoint() }) : engine === "metaso" ? t("handlers.webSearchEngine.switchedMetasoNote") : engine === "tavily" ? t("handlers.webSearchEngine.switchedTavilyNote") : "";
58830
- ctx.postInfo?.(t("handlers.webSearchEngine.switched", { engine, note }));
58491
+ const note = engine === "searxng" ? t("handlers.webSearchEngine.switchedSearxngNote", { endpoint: webSearchEndpoint() }) : engine === "metaso" ? t("handlers.webSearchEngine.switchedMetasoNote") : engine === "tavily" ? t("handlers.webSearchEngine.switchedTavilyNote") : engine === "perplexity" ? t("handlers.webSearchEngine.switchedPerplexityNote") : engine === "exa" ? t("handlers.webSearchEngine.switchedExaNote") : "";
58831
58492
  const detail = engine === "searxng" ? t("handlers.webSearchEngine.confirmedDetail", { endpoint: webSearchEndpoint() }) : "";
58832
58493
  return { info: t("handlers.webSearchEngine.confirmed", { engine, detail }) };
58833
58494
  },
@@ -59662,35 +59323,31 @@ function useEditHistory(codeMode) {
59662
59323
  [codeMode]
59663
59324
  );
59664
59325
  const codeHistory = (0, import_react89.useCallback)(() => {
59665
- if (!codeMode) return "not in code mode";
59326
+ if (!codeMode) return t("app.editHistoryNoCodeMode");
59666
59327
  const entries = editHistory.current;
59667
- if (entries.length === 0) return "no edits recorded this session yet";
59668
- const lines = ["Edit history (oldest first):"];
59328
+ if (entries.length === 0) return t("app.editHistoryNoEdits");
59329
+ const lines = [t("app.editHistoryTitle")];
59669
59330
  for (const e of entries) {
59670
59331
  const when = new Date(e.at).toISOString().replace("T", " ").slice(11, 19);
59671
59332
  const files = new Set(e.blocks.map((b) => b.path));
59672
59333
  const fileList = [...files].join(", ");
59673
59334
  const fileSummary = fileList.length > 60 ? `${fileList.slice(0, 60)}\u2026` : fileList;
59674
59335
  const status2 = entryStatus(e);
59675
- const statusText = status2 === "applied" ? "applied" : status2 === "PARTIAL" ? "PARTIAL" : "UNDONE ";
59336
+ const statusText = status2 === "applied" ? t("app.editHistoryStatusApplied") : status2 === "PARTIAL" ? t("app.editHistoryStatusPartial") : t("app.editHistoryStatusUndone");
59676
59337
  lines.push(
59677
59338
  ` #${String(e.id).padStart(3)} ${when} ${statusText} ${e.source.padEnd(12)} ${files.size} file \xB7 ${e.blocks.length} block ${fileSummary}`
59678
59339
  );
59679
59340
  }
59680
59341
  lines.push("");
59681
- lines.push(
59682
- "/show <id> \u2192 per-file summary \xB7 /show <id> <path> \u2192 full diff of one file"
59683
- );
59684
- lines.push(
59685
- "/undo \u2192 newest non-undone \xB7 /undo <id> [path] \u2192 target a specific batch or file"
59686
- );
59342
+ lines.push(t("app.editHistoryHelpShow"));
59343
+ lines.push(t("app.editHistoryHelpUndo"));
59687
59344
  return lines.join("\n");
59688
59345
  }, [codeMode]);
59689
59346
  const codeShowEdit = (0, import_react89.useCallback)(
59690
59347
  (args = []) => {
59691
- if (!codeMode) return "not in code mode";
59348
+ if (!codeMode) return t("app.editHistoryNoCodeMode");
59692
59349
  const entries = editHistory.current;
59693
- if (entries.length === 0) return "no edits recorded this session \u2014 /history is empty";
59350
+ if (entries.length === 0) return t("app.editHistoryNoEdits2");
59694
59351
  const idArg = args[0];
59695
59352
  const pathArg = args[1];
59696
59353
  let entry;
@@ -59699,23 +59356,27 @@ function useEditHistory(codeMode) {
59699
59356
  } else {
59700
59357
  const id = Number.parseInt(idArg, 10);
59701
59358
  if (!Number.isFinite(id)) {
59702
- return "usage: /show [id] [path] (omit id for newest; path from the per-file summary)";
59359
+ return t("app.editHistoryNoShowId");
59703
59360
  }
59704
59361
  entry = entries.find((e) => e.id === id);
59705
- if (!entry) return `no edit #${id} \u2014 run /history to see valid ids`;
59362
+ if (!entry) return t("app.editHistoryIdNotFound", { id });
59706
59363
  }
59707
- if (!entry) return "unexpected: history lookup failed";
59364
+ if (!entry) return t("app.editHistoryLookupFailed");
59708
59365
  if (pathArg) {
59709
59366
  const fileBlocks = entry.blocks.filter((b) => b.path === pathArg);
59710
59367
  if (fileBlocks.length === 0) {
59711
59368
  const files2 = [...new Set(entry.blocks.map((b) => b.path))];
59712
- return `batch #${entry.id} doesn't include "${pathArg}" \u2014 files in this batch: ${files2.join(", ")}`;
59369
+ return t("app.editHistoryBatchNoFile", {
59370
+ id: entry.id,
59371
+ path: pathArg,
59372
+ files: files2.join(", ")
59373
+ });
59713
59374
  }
59714
59375
  const when2 = new Date(entry.at).toISOString().replace("T", " ").slice(11, 19);
59715
- const state = entry.undoneFiles.has(pathArg) ? "UNDONE" : "applied";
59716
- const header2 = `\u25B8 edit #${entry.id} \xB7 ${when2} \xB7 ${pathArg} \xB7 ${state} \xB7 ${fileBlocks.length} block(s)`;
59376
+ const state2 = entry.undoneFiles.has(pathArg) ? "UNDONE" : "applied";
59377
+ const header2 = `\u25B8 edit #${entry.id} \xB7 ${when2} \xB7 ${pathArg} \xB7 ${state2} \xB7 ${fileBlocks.length} block(s)`;
59717
59378
  const diff = formatAllBlockDiffs(fileBlocks, { maxLines: 60, contextLines: 2 });
59718
- const footer = entry.undoneFiles.has(pathArg) ? "(already reverted \u2014 /history shows the batch-level status)" : `/undo ${entry.id} ${pathArg} \u2192 revert just this file`;
59379
+ const footer = entry.undoneFiles.has(pathArg) ? t("app.editHistoryAlreadyReverted") : t("app.editHistoryRevertFile", { id: entry.id, path: pathArg });
59719
59380
  return [header2, ...diff, "", footer].join("\n");
59720
59381
  }
59721
59382
  const when = new Date(entry.at).toISOString().replace("T", " ").slice(11, 19);
@@ -59731,8 +59392,8 @@ function useEditHistory(codeMode) {
59731
59392
  removed += countLines2(b.search);
59732
59393
  added += countLines2(b.replace);
59733
59394
  }
59734
- const state = entry.undoneFiles.has(path) ? "UNDONE" : "applied";
59735
- return ` ${state.padEnd(7)} -${String(removed).padStart(3)}/+${String(added).padStart(3)} ${path} (${fileBlocks.length} block${fileBlocks.length === 1 ? "" : "s"})`;
59395
+ const state2 = entry.undoneFiles.has(path) ? "UNDONE" : "applied";
59396
+ return ` ${state2.padEnd(7)} -${String(removed).padStart(3)}/+${String(added).padStart(3)} ${path} (${fileBlocks.length} block${fileBlocks.length === 1 ? "" : "s"})`;
59736
59397
  });
59737
59398
  return [
59738
59399
  header,
@@ -59870,6 +59531,18 @@ function reduceSubagentInnerEvent(prev, ev) {
59870
59531
  return { ...a, phase };
59871
59532
  });
59872
59533
  }
59534
+ if (ev.kind === "stream-progress") {
59535
+ return mapMatchingRun(prev, ev.runId, (a) => {
59536
+ const outputChars = ev.outputChars ?? a.outputChars;
59537
+ const reasoningChars = ev.reasoningChars ?? a.reasoningChars;
59538
+ const toolReadChars = ev.toolReadChars ?? a.toolReadChars;
59539
+ const elapsedMs = ev.elapsedMs ?? a.elapsedMs;
59540
+ if (outputChars === a.outputChars && reasoningChars === a.reasoningChars && toolReadChars === a.toolReadChars && elapsedMs === a.elapsedMs) {
59541
+ return a;
59542
+ }
59543
+ return { ...a, outputChars, reasoningChars, toolReadChars, elapsedMs };
59544
+ });
59545
+ }
59873
59546
  return prev;
59874
59547
  }
59875
59548
  function mapMatchingRun(prev, runId, fn) {
@@ -59923,7 +59596,7 @@ function useSubagent({
59923
59596
  getWalletCurrency
59924
59597
  }) {
59925
59598
  const [activities, setActivities] = (0, import_react91.useState)([]);
59926
- const sinkRef = (0, import_react91.useRef)({ current: null });
59599
+ const sinkRef = (0, import_react91.useRef)(SHARED_SUBAGENT_SINK);
59927
59600
  const getWalletCurrencyRef = (0, import_react91.useRef)(getWalletCurrency);
59928
59601
  (0, import_react91.useEffect)(() => {
59929
59602
  getWalletCurrencyRef.current = getWalletCurrency;
@@ -59942,7 +59615,10 @@ function useSubagent({
59942
59615
  skillName: ev.skillName,
59943
59616
  model: ev.model,
59944
59617
  phase: "exploring",
59945
- lastInner: null
59618
+ lastInner: null,
59619
+ outputChars: 0,
59620
+ reasoningChars: 0,
59621
+ toolReadChars: 0
59946
59622
  };
59947
59623
  return [...prev, next];
59948
59624
  });
@@ -60274,6 +59950,7 @@ function AppInner({
60274
59950
  const planStepsRef = (0, import_react92.useRef)(null);
60275
59951
  const completedStepIdsRef = (0, import_react92.useRef)(/* @__PURE__ */ new Set());
60276
59952
  const stepCompletionsRef = (0, import_react92.useRef)(/* @__PURE__ */ new Map());
59953
+ const pendingStepCompletionsRef = (0, import_react92.useRef)(/* @__PURE__ */ new Map());
60277
59954
  const planBodyRef = (0, import_react92.useRef)(null);
60278
59955
  const planSummaryRef = (0, import_react92.useRef)(null);
60279
59956
  const toolStartedAtRef = (0, import_react92.useRef)(null);
@@ -60827,6 +60504,7 @@ run \`reasonix setup\` to remove this entry, or fix the underlying issue (missin
60827
60504
  planStepsRef.current = restoredPlan.steps;
60828
60505
  completedStepIdsRef.current = new Set(restoredPlan.completedStepIds);
60829
60506
  stepCompletionsRef.current = new Map(Object.entries(restoredPlan.stepCompletions ?? {}));
60507
+ pendingStepCompletionsRef.current = /* @__PURE__ */ new Map();
60830
60508
  planBodyRef.current = restoredPlan.body ?? null;
60831
60509
  planSummaryRef.current = restoredPlan.summary ?? null;
60832
60510
  engineeringLifecycleRef.current?.recordPlanApproved(restoredPlan.steps);
@@ -60871,8 +60549,10 @@ run \`reasonix setup\` to remove this entry, or fix the underlying issue (missin
60871
60549
  });
60872
60550
  });
60873
60551
  useKeystroke((ev) => {
60874
- if (ev.pageUp || ev.mouseScrollUp) chatScroll.scrollPageUp();
60875
- else if (ev.pageDown || ev.mouseScrollDown) chatScroll.scrollPageDown();
60552
+ if (ev.pageUp) chatScroll.scrollPageUp();
60553
+ else if (ev.pageDown) chatScroll.scrollPageDown();
60554
+ else if (ev.mouseScrollUp) chatScroll.scrollWheelUp();
60555
+ else if (ev.mouseScrollDown) chatScroll.scrollWheelDown();
60876
60556
  else if (ev.end) chatScroll.jumpToBottom();
60877
60557
  else if (!composerPinned && ev.upArrow) chatScroll.scrollUp();
60878
60558
  else if (!composerPinned && ev.downArrow) chatScroll.scrollDown();
@@ -61096,14 +60776,16 @@ run \`reasonix setup\` to remove this entry, or fix the underlying issue (missin
61096
60776
  const prefixHash = loop2.prefix.fingerprint;
61097
60777
  const writeTranscript = useTranscriptWriter(transcriptRef, model2, prefixHash);
61098
60778
  const togglePlanMode = (0, import_react92.useCallback)(
61099
- (on) => {
60779
+ (on, source) => {
61100
60780
  setPlanMode(on);
61101
60781
  tools?.setPlanMode(on);
61102
60782
  if (on) {
61103
60783
  engineeringLifecycleRef.current?.setMode("strict");
60784
+ } else if (source === "slash") {
60785
+ engineeringLifecycleRef.current?.setMode("off");
61104
60786
  } else {
61105
- const state = engineeringLifecycleRef.current?.snapshot().state;
61106
- if (state === void 0 || state === "idle" || state === "complete" || state === "cancelled") {
60787
+ const state2 = engineeringLifecycleRef.current?.snapshot().state;
60788
+ if (state2 === void 0 || state2 === "idle" || state2 === "complete" || state2 === "cancelled") {
61107
60789
  engineeringLifecycleRef.current?.setMode(engineeringLifecycleBaseModeRef.current);
61108
60790
  }
61109
60791
  }
@@ -61133,7 +60815,7 @@ run \`reasonix setup\` to remove this entry, or fix the underlying issue (missin
61133
60815
  if (dashboardRef.current) return dashboardRef.current.url;
61134
60816
  if (dashboardStartingRef.current) return dashboardStartingRef.current;
61135
60817
  const startup = (async () => {
61136
- const { startDashboardServer } = await import("./server-C25JNNZV.js");
60818
+ const { startDashboardServer } = await import("./server-NHQ3QXOZ.js");
61137
60819
  const handle = await startDashboardServer(
61138
60820
  {
61139
60821
  mode: "attached",
@@ -61155,8 +60837,8 @@ run \`reasonix setup\` to remove this entry, or fix the underlying issue (missin
61155
60837
  saveEditMode(m);
61156
60838
  return m;
61157
60839
  },
61158
- setPlanMode: (on) => {
61159
- if (codeMode) togglePlanMode(on);
60840
+ setPlanMode: (on, source) => {
60841
+ if (codeMode) togglePlanMode(on, source);
61160
60842
  },
61161
60843
  applyPresetLive: (name) => {
61162
60844
  const settings = resolvePreset(name);
@@ -62079,6 +61761,7 @@ ${answer}`, "brand");
62079
61761
  planStepsRef,
62080
61762
  completedStepIdsRef,
62081
61763
  stepCompletionsRef,
61764
+ pendingStepCompletionsRef,
62082
61765
  planBodyRef,
62083
61766
  planSummaryRef,
62084
61767
  persistPlanState,
@@ -62352,6 +62035,7 @@ ${answer}`, "brand");
62352
62035
  if (approvedSteps && approvedSteps.length > 0) {
62353
62036
  completedStepIdsRef.current = /* @__PURE__ */ new Set();
62354
62037
  stepCompletionsRef.current = /* @__PURE__ */ new Map();
62038
+ pendingStepCompletionsRef.current = /* @__PURE__ */ new Map();
62355
62039
  log.showPlan({
62356
62040
  title: planSummaryRef.current ?? "plan",
62357
62041
  steps: approvedSteps.map((s) => ({
@@ -62368,6 +62052,7 @@ ${answer}`, "brand");
62368
62052
  planStepsRef.current = null;
62369
62053
  completedStepIdsRef.current = /* @__PURE__ */ new Set();
62370
62054
  stepCompletionsRef.current = /* @__PURE__ */ new Map();
62055
+ pendingStepCompletionsRef.current = /* @__PURE__ */ new Map();
62371
62056
  planBodyRef.current = null;
62372
62057
  planSummaryRef.current = null;
62373
62058
  persistPlanState();
@@ -62475,17 +62160,22 @@ ${answer}`, "brand");
62475
62160
  planSummaryRef.current = p.summary ?? null;
62476
62161
  planBodyRef.current = p.plan;
62477
62162
  stepCompletionsRef.current = /* @__PURE__ */ new Map();
62163
+ pendingStepCompletionsRef.current = /* @__PURE__ */ new Map();
62478
62164
  engineeringLifecycleRef.current?.recordPlanProposed(p.steps);
62479
62165
  break;
62480
62166
  }
62481
62167
  case "plan_checkpoint": {
62482
62168
  const p = payload;
62169
+ if (p.completion?.kind === "step_completed") {
62170
+ pendingStepCompletionsRef.current.set(p.stepId, p.completion);
62171
+ }
62483
62172
  const total = planStepsRef.current?.length ?? 0;
62484
62173
  const completed = completedCountIncludingStep(
62485
62174
  completedStepIdsRef.current,
62486
62175
  p.stepId,
62487
62176
  total
62488
62177
  );
62178
+ engineeringLifecycleRef.current?.recordCheckpointReached();
62489
62179
  if (shouldAutoResolveCheckpoint(editModeRef.current)) {
62490
62180
  handleAutoCheckpointContinueRef.current(p.stepId, p.title);
62491
62181
  pauseGate.resolve(request.id, { type: "continue" });
@@ -62546,6 +62236,9 @@ ${answer}`, "brand");
62546
62236
  setStagedCheckpointRevise(snap);
62547
62237
  return;
62548
62238
  }
62239
+ if (choice === "stop") {
62240
+ engineeringLifecycleRef.current?.cancel();
62241
+ }
62549
62242
  if (codeMode && choice === "continue") {
62550
62243
  const paths = touchedPaths();
62551
62244
  if (paths.length > 0) {
@@ -62693,10 +62386,7 @@ ${answer}`, "brand");
62693
62386
  merged.push(s);
62694
62387
  }
62695
62388
  planStepsRef.current = merged;
62696
- engineeringLifecycleRef.current?.recordPlanApproved(merged);
62697
- for (const s of merged) {
62698
- if (completed.has(s.id)) engineeringLifecycleRef.current?.recordStepCompleted(s.id);
62699
- }
62389
+ engineeringLifecycleRef.current?.recordPlanRevised(snap.remainingSteps);
62700
62390
  persistPlanState();
62701
62391
  agentStore.dispatch({ type: "plan.drop" });
62702
62392
  log.showPlan({
@@ -63274,6 +62964,39 @@ function disableMouseMode() {
63274
62964
  active = false;
63275
62965
  }
63276
62966
 
62967
+ // src/cli/ui/resize-broadcaster.ts
62968
+ var state = null;
62969
+ function installResizeBroadcaster(stream = process.stdout) {
62970
+ if (state) return;
62971
+ if (typeof stream.on !== "function" || typeof stream.off !== "function") return;
62972
+ const subscribers = /* @__PURE__ */ new Set();
62973
+ const realOn = stream.on.bind(stream);
62974
+ const realOff = stream.off.bind(stream);
62975
+ const broadcast = (...args) => {
62976
+ for (const l of subscribers) l(...args);
62977
+ };
62978
+ realOn("resize", broadcast);
62979
+ const shimOn = (event, listener) => {
62980
+ if (event === "resize") {
62981
+ subscribers.add(listener);
62982
+ return stream;
62983
+ }
62984
+ return realOn(event, listener);
62985
+ };
62986
+ const shimOff = (event, listener) => {
62987
+ if (event === "resize") {
62988
+ subscribers.delete(listener);
62989
+ return stream;
62990
+ }
62991
+ return realOff(event, listener);
62992
+ };
62993
+ stream.on = shimOn;
62994
+ stream.addListener = shimOn;
62995
+ stream.off = shimOff;
62996
+ stream.removeListener = shimOff;
62997
+ state = { stream, subscribers };
62998
+ }
62999
+
63277
63000
  // src/cli/commands/chat.tsx
63278
63001
  function Root({
63279
63002
  initialKey,
@@ -63447,8 +63170,8 @@ async function chatCommand(opts) {
63447
63170
  `);
63448
63171
  }
63449
63172
  }
63450
- process.stdout.setMaxListeners(200);
63451
- if (cfg.mouseTracking !== false) {
63173
+ installResizeBroadcaster();
63174
+ if (!opts.noMouse && cfg.mouseTracking !== false) {
63452
63175
  enableMouseMode();
63453
63176
  process.once("exit", disableMouseMode);
63454
63177
  process.once("SIGINT", () => {
@@ -63494,4 +63217,4 @@ async function chatCommand(opts) {
63494
63217
  export {
63495
63218
  chatCommand
63496
63219
  };
63497
- //# sourceMappingURL=chunk-XMHP7BEE.js.map
63220
+ //# sourceMappingURL=chunk-6MZTZO7A.js.map