reasonix 0.47.2 → 0.48.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. package/README.md +14 -26
  2. package/README.zh-CN.md +5 -26
  3. package/dist/cli/{acp-GEOAKSTU.js → acp-QJGGHQLA.js} +52 -135
  4. package/dist/cli/acp-QJGGHQLA.js.map +1 -0
  5. package/dist/cli/{chat-YTPATMMG.js → chat-ZXF227MP.js} +25 -25
  6. package/dist/cli/{chunk-DN4B5S6Y.js → chunk-3FULTFRB.js} +2 -2
  7. package/dist/cli/chunk-43ROGEX2.js +5190 -0
  8. package/dist/cli/chunk-43ROGEX2.js.map +1 -0
  9. package/dist/cli/{chunk-DQ6K5ZQ7.js → chunk-4E2BHJU4.js} +4 -4
  10. package/dist/cli/chunk-4E2BHJU4.js.map +1 -0
  11. package/dist/cli/{chunk-T5A7EY6B.js → chunk-5AW6NIHU.js} +2 -2
  12. package/dist/cli/{chunk-DWPAKZTY.js → chunk-5U5LMMFF.js} +2 -2
  13. package/dist/cli/{chunk-TRSAHHCL.js → chunk-6FRNXWDZ.js} +321 -76
  14. package/dist/cli/chunk-6FRNXWDZ.js.map +1 -0
  15. package/dist/cli/{chunk-KYQVQ5X4.js → chunk-B5CZL2SE.js} +9 -4
  16. package/dist/cli/chunk-B5CZL2SE.js.map +1 -0
  17. package/dist/cli/{chunk-XMHP7BEE.js → chunk-DABAOQSV.js} +2273 -2517
  18. package/dist/cli/chunk-DABAOQSV.js.map +1 -0
  19. package/dist/cli/chunk-EO6RPTJG.js +831 -0
  20. package/dist/cli/chunk-EO6RPTJG.js.map +1 -0
  21. package/dist/cli/{chunk-BQ6HC66J.js → chunk-FD7SNDWW.js} +4 -14
  22. package/dist/cli/chunk-FD7SNDWW.js.map +1 -0
  23. package/dist/cli/chunk-FPME5QOO.js +17747 -0
  24. package/dist/cli/chunk-FPME5QOO.js.map +1 -0
  25. package/dist/cli/{chunk-6QC5RQLE.js → chunk-H2F4LDNH.js} +2 -2
  26. package/dist/cli/{chunk-QCFLPSPH.js → chunk-IKSYVBBZ.js} +2 -2
  27. package/dist/cli/{chunk-5QCB62C4.js → chunk-J2TQAWOM.js} +135 -18
  28. package/dist/cli/{chunk-5QCB62C4.js.map → chunk-J2TQAWOM.js.map} +1 -1
  29. package/dist/cli/{chunk-JBH5RM7X.js → chunk-JFBGSWQB.js} +395 -85
  30. package/dist/cli/chunk-JFBGSWQB.js.map +1 -0
  31. package/dist/cli/{chunk-CCJAP7G3.js → chunk-KH5JIJJD.js} +2 -2
  32. package/dist/cli/{chunk-TDHXB2ER.js → chunk-NQZ5U37J.js} +2 -2
  33. package/dist/cli/{chunk-CNG32VAB.js → chunk-O3AGYTG2.js} +2 -2
  34. package/dist/cli/{chunk-NRQ5UP5T.js → chunk-PIC5HJRD.js} +234 -40
  35. package/dist/cli/chunk-PIC5HJRD.js.map +1 -0
  36. package/dist/cli/{chunk-GH7DC2Y5.js → chunk-PJIQIYTV.js} +6 -3
  37. package/dist/cli/chunk-PJIQIYTV.js.map +1 -0
  38. package/dist/cli/{chunk-KVZZ5U75.js → chunk-R7U44O3Y.js} +2 -2
  39. package/dist/cli/{chunk-ZXSCAODE.js → chunk-RCLS63KE.js} +71 -3
  40. package/dist/cli/chunk-RCLS63KE.js.map +1 -0
  41. package/dist/cli/{chunk-FY4S7TJZ.js → chunk-SLAFMXAZ.js} +10 -2
  42. package/dist/cli/chunk-SLAFMXAZ.js.map +1 -0
  43. package/dist/cli/{chunk-TRWHTFG7.js → chunk-SWUMD2LX.js} +2 -2
  44. package/dist/cli/{chunk-2XY77LW7.js → chunk-TIJ4ZHD6.js} +56 -24
  45. package/dist/cli/chunk-TIJ4ZHD6.js.map +1 -0
  46. package/dist/cli/{chunk-4MFCAZ2W.js → chunk-WKOXKCF3.js} +3 -3
  47. package/dist/cli/{chunk-HUILPCYX.js → chunk-XMR2VCGT.js} +3 -3
  48. package/dist/cli/{code-Q4NRVEDG.js → code-OKA5YPOH.js} +31 -32
  49. package/dist/cli/code-OKA5YPOH.js.map +1 -0
  50. package/dist/cli/{commands-4CDI4GFM.js → commands-3U6PUVSS.js} +4 -4
  51. package/dist/cli/{commit-GW7LDQP5.js → commit-HFB7SRBU.js} +3 -3
  52. package/dist/cli/{desktop-EG6P5SF2.js → desktop-G7UMW3CJ.js} +503 -48
  53. package/dist/cli/desktop-G7UMW3CJ.js.map +1 -0
  54. package/dist/cli/{diff-VI2YX4FN.js → diff-PGXW4YZD.js} +8 -8
  55. package/dist/cli/{doctor-CQTTZP27.js → doctor-WWJFLVCB.js} +9 -9
  56. package/dist/cli/index.js +53 -41
  57. package/dist/cli/index.js.map +1 -1
  58. package/dist/cli/{mcp-J2UCD4RZ.js → mcp-Y3VKIK3T.js} +2 -2
  59. package/dist/cli/{mcp-browse-GSX34JEK.js → mcp-browse-4IN2QIFR.js} +2 -2
  60. package/dist/cli/{mcp-inspect-RRFYF4ZV.js → mcp-inspect-BUXFXDHB.js} +2 -2
  61. package/dist/cli/{prompt-5TQPIVHV.js → prompt-US57R6BA.js} +5 -4
  62. package/dist/cli/{replay-MJCEMODU.js → replay-EQJMZRB3.js} +8 -8
  63. package/dist/cli/{run-P4D5VDYE.js → run-KVEI66TR.js} +14 -14
  64. package/dist/cli/{server-C25JNNZV.js → server-D6C4GHWN.js} +18 -15
  65. package/dist/cli/server-D6C4GHWN.js.map +1 -0
  66. package/dist/cli/{sessions-QIONZJQ6.js → sessions-TGVS2RQZ.js} +13 -13
  67. package/dist/cli/{setup-NLQ6G5G4.js → setup-WLKX6GGG.js} +5 -5
  68. package/dist/cli/{stats-DFZEXHP4.js → stats-TCD7Q6MB.js} +6 -6
  69. package/dist/cli/{version-GR3X3MPI.js → version-BCWWS2OU.js} +13 -13
  70. package/dist/grammars/tree-sitter-go.wasm +0 -0
  71. package/dist/grammars/tree-sitter-java.wasm +0 -0
  72. package/dist/grammars/tree-sitter-javascript.wasm +0 -0
  73. package/dist/grammars/tree-sitter-python.wasm +0 -0
  74. package/dist/grammars/tree-sitter-rust.wasm +0 -0
  75. package/dist/grammars/tree-sitter-tsx.wasm +0 -0
  76. package/dist/grammars/tree-sitter-typescript.wasm +0 -0
  77. package/dist/grammars/web-tree-sitter.wasm +0 -0
  78. package/dist/index.d.ts +46 -12
  79. package/dist/index.js +684 -129
  80. package/dist/index.js.map +1 -1
  81. package/package.json +16 -4
  82. package/dist/cli/acp-GEOAKSTU.js.map +0 -1
  83. package/dist/cli/chunk-2XY77LW7.js.map +0 -1
  84. package/dist/cli/chunk-6CRPCJAU.js +0 -3141
  85. package/dist/cli/chunk-6CRPCJAU.js.map +0 -1
  86. package/dist/cli/chunk-BQ6HC66J.js.map +0 -1
  87. package/dist/cli/chunk-DQ6K5ZQ7.js.map +0 -1
  88. package/dist/cli/chunk-FY4S7TJZ.js.map +0 -1
  89. package/dist/cli/chunk-GH7DC2Y5.js.map +0 -1
  90. package/dist/cli/chunk-JBH5RM7X.js.map +0 -1
  91. package/dist/cli/chunk-KYQVQ5X4.js.map +0 -1
  92. package/dist/cli/chunk-NRQ5UP5T.js.map +0 -1
  93. package/dist/cli/chunk-TRSAHHCL.js.map +0 -1
  94. package/dist/cli/chunk-XD6P7AFH.js +0 -375
  95. package/dist/cli/chunk-XD6P7AFH.js.map +0 -1
  96. package/dist/cli/chunk-XMHP7BEE.js.map +0 -1
  97. package/dist/cli/chunk-YFP3MYMY.js +0 -323
  98. package/dist/cli/chunk-YFP3MYMY.js.map +0 -1
  99. package/dist/cli/chunk-ZXSCAODE.js.map +0 -1
  100. package/dist/cli/code-Q4NRVEDG.js.map +0 -1
  101. package/dist/cli/desktop-EG6P5SF2.js.map +0 -1
  102. package/dist/cli/server-C25JNNZV.js.map +0 -1
  103. /package/dist/cli/{chat-YTPATMMG.js.map → chat-ZXF227MP.js.map} +0 -0
  104. /package/dist/cli/{chunk-DN4B5S6Y.js.map → chunk-3FULTFRB.js.map} +0 -0
  105. /package/dist/cli/{chunk-T5A7EY6B.js.map → chunk-5AW6NIHU.js.map} +0 -0
  106. /package/dist/cli/{chunk-DWPAKZTY.js.map → chunk-5U5LMMFF.js.map} +0 -0
  107. /package/dist/cli/{chunk-6QC5RQLE.js.map → chunk-H2F4LDNH.js.map} +0 -0
  108. /package/dist/cli/{chunk-QCFLPSPH.js.map → chunk-IKSYVBBZ.js.map} +0 -0
  109. /package/dist/cli/{chunk-CCJAP7G3.js.map → chunk-KH5JIJJD.js.map} +0 -0
  110. /package/dist/cli/{chunk-TDHXB2ER.js.map → chunk-NQZ5U37J.js.map} +0 -0
  111. /package/dist/cli/{chunk-CNG32VAB.js.map → chunk-O3AGYTG2.js.map} +0 -0
  112. /package/dist/cli/{chunk-KVZZ5U75.js.map → chunk-R7U44O3Y.js.map} +0 -0
  113. /package/dist/cli/{chunk-TRWHTFG7.js.map → chunk-SWUMD2LX.js.map} +0 -0
  114. /package/dist/cli/{chunk-4MFCAZ2W.js.map → chunk-WKOXKCF3.js.map} +0 -0
  115. /package/dist/cli/{chunk-HUILPCYX.js.map → chunk-XMR2VCGT.js.map} +0 -0
  116. /package/dist/cli/{commands-4CDI4GFM.js.map → commands-3U6PUVSS.js.map} +0 -0
  117. /package/dist/cli/{commit-GW7LDQP5.js.map → commit-HFB7SRBU.js.map} +0 -0
  118. /package/dist/cli/{diff-VI2YX4FN.js.map → diff-PGXW4YZD.js.map} +0 -0
  119. /package/dist/cli/{doctor-CQTTZP27.js.map → doctor-WWJFLVCB.js.map} +0 -0
  120. /package/dist/cli/{mcp-J2UCD4RZ.js.map → mcp-Y3VKIK3T.js.map} +0 -0
  121. /package/dist/cli/{mcp-browse-GSX34JEK.js.map → mcp-browse-4IN2QIFR.js.map} +0 -0
  122. /package/dist/cli/{mcp-inspect-RRFYF4ZV.js.map → mcp-inspect-BUXFXDHB.js.map} +0 -0
  123. /package/dist/cli/{prompt-5TQPIVHV.js.map → prompt-US57R6BA.js.map} +0 -0
  124. /package/dist/cli/{replay-MJCEMODU.js.map → replay-EQJMZRB3.js.map} +0 -0
  125. /package/dist/cli/{run-P4D5VDYE.js.map → run-KVEI66TR.js.map} +0 -0
  126. /package/dist/cli/{sessions-QIONZJQ6.js.map → sessions-TGVS2RQZ.js.map} +0 -0
  127. /package/dist/cli/{setup-NLQ6G5G4.js.map → setup-WLKX6GGG.js.map} +0 -0
  128. /package/dist/cli/{stats-DFZEXHP4.js.map → stats-TCD7Q6MB.js.map} +0 -0
  129. /package/dist/cli/{version-GR3X3MPI.js.map → version-BCWWS2OU.js.map} +0 -0
@@ -1,16 +1,17 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire as __cr } from 'node:module'; if (typeof globalThis.require === 'undefined') { globalThis.require = __cr(import.meta.url); }
3
3
  import {
4
+ QQChannel,
4
5
  createMcpRuntime
5
- } from "./chunk-YFP3MYMY.js";
6
+ } from "./chunk-EO6RPTJG.js";
6
7
  import {
7
8
  buildCodeToolset
8
- } from "./chunk-XD6P7AFH.js";
9
+ } from "./chunk-43ROGEX2.js";
9
10
  import {
10
11
  Eventizer,
11
12
  autoResolveVerdict
12
- } from "./chunk-ZXSCAODE.js";
13
- import "./chunk-DQ6K5ZQ7.js";
13
+ } from "./chunk-RCLS63KE.js";
14
+ import "./chunk-4E2BHJU4.js";
14
15
  import "./chunk-EQATK2L2.js";
15
16
  import {
16
17
  CacheFirstLoop,
@@ -19,14 +20,15 @@ import {
19
20
  listFilesWithStatsAsync,
20
21
  parseAtQuery,
21
22
  rankPickerCandidates
22
- } from "./chunk-JBH5RM7X.js";
23
- import "./chunk-6QC5RQLE.js";
24
- import "./chunk-HUILPCYX.js";
23
+ } from "./chunk-JFBGSWQB.js";
24
+ import "./chunk-H2F4LDNH.js";
25
+ import "./chunk-XMR2VCGT.js";
25
26
  import "./chunk-HIYTRCSW.js";
26
27
  import {
27
28
  MemoryStore,
28
29
  codeSystemPrompt
29
- } from "./chunk-BQ6HC66J.js";
30
+ } from "./chunk-FD7SNDWW.js";
31
+ import "./chunk-FEZK652I.js";
30
32
  import {
31
33
  canonicalPresetName,
32
34
  resolvePreset
@@ -37,21 +39,22 @@ import {
37
39
  import {
38
40
  DeepSeekClient,
39
41
  pickPrimaryBalance
40
- } from "./chunk-DWPAKZTY.js";
42
+ } from "./chunk-5U5LMMFF.js";
41
43
  import "./chunk-25T6CVUP.js";
42
44
  import {
43
45
  loadDotenv
44
46
  } from "./chunk-2UQP6H6T.js";
45
- import "./chunk-KVZZ5U75.js";
47
+ import "./chunk-R7U44O3Y.js";
46
48
  import {
47
- pauseGate
48
- } from "./chunk-TRSAHHCL.js";
49
+ pauseGate,
50
+ toApprovalPrompt
51
+ } from "./chunk-6FRNXWDZ.js";
49
52
  import {
50
53
  SkillStore
51
- } from "./chunk-FY4S7TJZ.js";
54
+ } from "./chunk-SLAFMXAZ.js";
52
55
  import "./chunk-PLHAZOLZ.js";
53
- import "./chunk-T5A7EY6B.js";
54
- import "./chunk-GH7DC2Y5.js";
56
+ import "./chunk-5AW6NIHU.js";
57
+ import "./chunk-PJIQIYTV.js";
55
58
  import "./chunk-S4XVGLRW.js";
56
59
  import {
57
60
  deleteSession,
@@ -62,9 +65,9 @@ import {
62
65
  sessionPath,
63
66
  timestampSuffix
64
67
  } from "./chunk-RRXUIPWG.js";
65
- import "./chunk-DN4B5S6Y.js";
66
- import "./chunk-QCFLPSPH.js";
67
- import "./chunk-NRQ5UP5T.js";
68
+ import "./chunk-3FULTFRB.js";
69
+ import "./chunk-IKSYVBBZ.js";
70
+ import "./chunk-PIC5HJRD.js";
68
71
  import {
69
72
  describeQQAccess,
70
73
  isPlausibleKey,
@@ -92,7 +95,7 @@ import {
92
95
  saveReasoningEffort,
93
96
  saveWorkspaceDir,
94
97
  writeConfig
95
- } from "./chunk-6CRPCJAU.js";
98
+ } from "./chunk-FPME5QOO.js";
96
99
  import {
97
100
  VERSION
98
101
  } from "./chunk-XXC2BYTV.js";
@@ -172,15 +175,12 @@ function toAccess(config) {
172
175
  function loadDesktopQQState(path) {
173
176
  const config = loadQQConfig(path);
174
177
  const configured = Boolean(config.appId && config.appSecret);
175
- const enabled = config.enabled === true;
176
178
  return {
177
179
  ...config,
178
180
  sandbox: config.sandbox ?? false,
179
- enabled,
181
+ enabled: config.enabled === true,
180
182
  configured,
181
- // Never true — the desktop process doesn't host a QQChannel (#1317).
182
- connected: false,
183
- enabledForCli: configured && enabled,
183
+ runtimeState: "disconnected",
184
184
  appIdPreview: toPreview(config.appId),
185
185
  access: toAccess(config)
186
186
  };
@@ -208,9 +208,36 @@ function setDesktopQQEnabled(enabled, path) {
208
208
  }
209
209
 
210
210
  // src/cli/commands/desktop.ts
211
+ var desktopQqRuntimeSnapshot = {
212
+ runtimeState: "disconnected"
213
+ };
214
+ var STDOUT_BACKPRESSURE_WAIT = new Int32Array(new SharedArrayBuffer(4));
215
+ var SESSION_TITLE_MAX_CHARS = 200;
216
+ function normalizeSessionTitle(raw) {
217
+ return raw.replace(/\s+/g, " ").trim().slice(0, SESSION_TITLE_MAX_CHARS);
218
+ }
219
+ function writeAllSync(fd, buffer, opts = {}) {
220
+ const write = opts.write ?? writeSync;
221
+ const wait = opts.wait ?? (() => Atomics.wait(STDOUT_BACKPRESSURE_WAIT, 0, 0, 5));
222
+ let offset = 0;
223
+ while (offset < buffer.length) {
224
+ let written;
225
+ try {
226
+ written = write(fd, buffer, offset, buffer.length - offset);
227
+ } catch (err) {
228
+ if (err.code === "EAGAIN") {
229
+ wait();
230
+ continue;
231
+ }
232
+ throw err;
233
+ }
234
+ if (written <= 0) throw new Error("stdout write returned 0 bytes");
235
+ offset += written;
236
+ }
237
+ }
211
238
  function emit(ev, tabId) {
212
239
  const payload = tabId ? { ...ev, tabId } : ev;
213
- writeSync(1, Buffer.from(`${JSON.stringify(payload)}
240
+ writeAllSync(1, Buffer.from(`${JSON.stringify(payload)}
214
241
  `, "utf8"));
215
242
  }
216
243
  function tailLines(s, n) {
@@ -287,7 +314,16 @@ function emitSettings(tab) {
287
314
  );
288
315
  }
289
316
  function emitQQSettings(tab) {
290
- emit({ type: "$qq_settings", ...loadDesktopQQState() }, tab.id);
317
+ const base = loadDesktopQQState();
318
+ emit(
319
+ {
320
+ type: "$qq_settings",
321
+ ...base,
322
+ runtimeState: desktopQqRuntimeSnapshot.runtimeState,
323
+ lastError: desktopQqRuntimeSnapshot.lastError
324
+ },
325
+ tab.id
326
+ );
291
327
  }
292
328
  async function emitBalance(tab) {
293
329
  if (!tab.runtime) return;
@@ -379,7 +415,8 @@ function emitCtxBreakdown(tab) {
379
415
  try {
380
416
  const sys = countTokensBounded(tab.runtime.loop.prefix.system);
381
417
  const tools = countTokensBounded(JSON.stringify(tab.runtime.loop.prefix.toolSpecs));
382
- emit({ type: "$ctx_breakdown", reservedTokens: sys + tools }, tab.id);
418
+ const logTokens = tab.runtime.loop.getCurrentLogTokens();
419
+ emit({ type: "$ctx_breakdown", reservedTokens: sys + tools, logTokens }, tab.id);
383
420
  } catch {
384
421
  }
385
422
  }
@@ -540,6 +577,319 @@ async function desktopCommand(opts) {
540
577
  const id = tabContext.getStore();
541
578
  return id ? tabs.get(id) : void 0;
542
579
  }
580
+ let first;
581
+ const qqRuntime = {
582
+ channel: null,
583
+ runtimeState: "disconnected",
584
+ lastError: void 0,
585
+ pendingGateId: null,
586
+ interaction: { kind: null, payload: null },
587
+ replyThisTurn: false
588
+ };
589
+ function currentQqSettings() {
590
+ const base = loadDesktopQQState();
591
+ return {
592
+ type: "$qq_settings",
593
+ ...base,
594
+ runtimeState: qqRuntime.runtimeState,
595
+ lastError: qqRuntime.lastError
596
+ };
597
+ }
598
+ function activeDesktopTab() {
599
+ return (lastActiveTabId ? tabs.get(lastActiveTabId) : void 0) ?? first;
600
+ }
601
+ function broadcastQQSettings() {
602
+ for (const tab of tabs.values()) emit(currentQqSettings(), tab.id);
603
+ }
604
+ function setQQRuntimeState(runtimeState, lastError) {
605
+ qqRuntime.runtimeState = runtimeState;
606
+ qqRuntime.lastError = lastError;
607
+ desktopQqRuntimeSnapshot.runtimeState = runtimeState;
608
+ desktopQqRuntimeSnapshot.lastError = lastError;
609
+ broadcastQQSettings();
610
+ }
611
+ function sendQQInfo(message) {
612
+ const tab = activeDesktopTab();
613
+ if (tab) {
614
+ emit(
615
+ {
616
+ type: "status",
617
+ id: Date.now(),
618
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
619
+ turn: 0,
620
+ text: message
621
+ },
622
+ tab.id
623
+ );
624
+ }
625
+ void qqRuntime.channel?.sendResponse(message).catch((err) => {
626
+ const active = activeDesktopTab();
627
+ if (active) {
628
+ emit({ type: "$error", message: `qq send failed: ${err.message}` }, active.id);
629
+ }
630
+ });
631
+ }
632
+ function parseIndexedChoice(text) {
633
+ const rawIndex = text.match(/^(\d+)/)?.[1];
634
+ return rawIndex ? Number.parseInt(rawIndex, 10) - 1 : -1;
635
+ }
636
+ function parseRunPermissionChoice(text) {
637
+ const lower = text.toLowerCase();
638
+ if (lower.includes("1") || lower.includes("run")) return "run_once";
639
+ if (lower.includes("2") || lower.includes("always")) return "always_allow";
640
+ return "deny";
641
+ }
642
+ function parsePlanChoice(text) {
643
+ const lower = text.toLowerCase();
644
+ if (lower.includes("1") || lower.includes("approve")) return "approve";
645
+ if (lower.includes("2") || lower.includes("refine")) return "refine";
646
+ return "cancel";
647
+ }
648
+ function parseCheckpointChoice(text) {
649
+ const lower = text.toLowerCase();
650
+ if (lower.includes("1") || lower.includes("continue")) return "continue";
651
+ if (lower.includes("2") || lower.includes("revise")) return "revise";
652
+ return "stop";
653
+ }
654
+ function parseRevisionChoice(text) {
655
+ const lower = text.toLowerCase();
656
+ if (lower.includes("1") || lower.includes("accept")) return "accept";
657
+ if (lower.includes("2") || lower.includes("reject")) return "reject";
658
+ return "cancel";
659
+ }
660
+ function stripFollowupPrefix(text) {
661
+ return text.replace(
662
+ /^(?:\d+\s*|approve\s*|refine\s*|cancel\s*|continue\s*|revise\s*|stop\s*|accept\s*|reject\s*|run\s*|always\s*|deny\s*)/iu,
663
+ ""
664
+ ).trim();
665
+ }
666
+ function handleQQPauseReply(text) {
667
+ if (qqRuntime.interaction.kind === null || qqRuntime.pendingGateId === null) return false;
668
+ qqRuntime.replyThisTurn = true;
669
+ const followup = stripFollowupPrefix(text);
670
+ const interaction = qqRuntime.interaction;
671
+ qqRuntime.interaction = { kind: null, payload: null };
672
+ const gateId = qqRuntime.pendingGateId;
673
+ qqRuntime.pendingGateId = null;
674
+ switch (interaction.kind) {
675
+ case "run_command":
676
+ case "run_background":
677
+ case "path_access":
678
+ pauseGate.resolve(gateId, parseRunPermissionChoice(text));
679
+ return true;
680
+ case "plan_proposed": {
681
+ const payload = interaction.payload ?? {};
682
+ const choice = parsePlanChoice(text);
683
+ if (choice === "cancel") {
684
+ pauseGate.cancel(gateId);
685
+ } else {
686
+ pauseGate.resolve(gateId, {
687
+ type: choice === "approve" ? "approve" : "refine",
688
+ feedback: followup,
689
+ override: {
690
+ plan: payload.plan ?? "",
691
+ mode: choice === "approve" ? "approve" : "refine"
692
+ }
693
+ });
694
+ }
695
+ return true;
696
+ }
697
+ case "plan_checkpoint": {
698
+ const payload = interaction.payload ?? {};
699
+ const choice = parseCheckpointChoice(text);
700
+ if (choice === "revise") {
701
+ pauseGate.resolve(gateId, {
702
+ type: "revise",
703
+ feedback: followup,
704
+ checkpoint: { stepId: payload.stepId ?? "", title: payload.title }
705
+ });
706
+ } else {
707
+ pauseGate.resolve(gateId, { type: choice });
708
+ }
709
+ return true;
710
+ }
711
+ case "plan_revision":
712
+ pauseGate.resolve(gateId, parseRevisionChoice(text));
713
+ return true;
714
+ case "choice": {
715
+ const payload = interaction.payload ?? {};
716
+ const options = payload.options ?? [];
717
+ const pickedIndex = parseIndexedChoice(text);
718
+ if (pickedIndex >= 0 && pickedIndex < options.length) {
719
+ const selected = options[pickedIndex];
720
+ if (selected) pauseGate.resolve(gateId, { type: "pick", optionId: selected.id });
721
+ return true;
722
+ }
723
+ for (const option of options) {
724
+ if (text.toLowerCase().includes(option.title.toLowerCase())) {
725
+ pauseGate.resolve(gateId, { type: "pick", optionId: option.id });
726
+ return true;
727
+ }
728
+ }
729
+ pauseGate.resolve(
730
+ gateId,
731
+ payload.allowCustom ? { type: "text", text } : { type: "cancel" }
732
+ );
733
+ return true;
734
+ }
735
+ default:
736
+ return false;
737
+ }
738
+ }
739
+ function handleQQPauseRequest(tab, kind, payload) {
740
+ if (!qqRuntime.channel) return;
741
+ qqRuntime.interaction = { kind, payload };
742
+ let qqMessage = "";
743
+ switch (kind) {
744
+ case "run_command":
745
+ case "run_background": {
746
+ const p = payload;
747
+ qqMessage = `Need confirmation
748
+
749
+ Command: \`${p.command}\`
750
+
751
+ Reply with:
752
+ 1. Run once
753
+ 2. Always allow
754
+ 3. Deny`;
755
+ break;
756
+ }
757
+ case "path_access": {
758
+ const p = payload;
759
+ const intentText = p.intent === "read" ? "Read" : "Write";
760
+ qqMessage = `Need file access confirmation
761
+
762
+ Action: ${intentText}
763
+ Path: ${p.path}
764
+ Tool: ${p.toolName}
765
+
766
+ Reply with:
767
+ 1. Run once
768
+ 2. Always allow
769
+ 3. Deny`;
770
+ break;
771
+ }
772
+ case "plan_proposed": {
773
+ const p = payload;
774
+ qqMessage = `Plan confirmation
775
+
776
+ ${p.plan}
777
+
778
+ Reply with:
779
+ 1. Approve
780
+ 2. Refine
781
+ 3. Cancel`;
782
+ break;
783
+ }
784
+ case "plan_checkpoint": {
785
+ const p = payload;
786
+ qqMessage = `Step complete (${tab.completedStepIds.size}/${tab.planTotalSteps})
787
+
788
+ ${p.title ? `Step: ${p.title}
789
+ ` : ""}Result: ${p.result}
790
+
791
+ Reply with:
792
+ 1. Continue
793
+ 2. Revise
794
+ 3. Stop`;
795
+ break;
796
+ }
797
+ case "plan_revision": {
798
+ const p = payload;
799
+ qqMessage = `Plan revision proposed
800
+
801
+ ${p.reason}
802
+
803
+ Reply with:
804
+ 1. Accept
805
+ 2. Reject
806
+ 3. Cancel`;
807
+ break;
808
+ }
809
+ case "choice": {
810
+ const p = payload;
811
+ const optionsList = p.options.map((opt, idx) => `${idx + 1}. ${opt.title}`).join("\n");
812
+ qqMessage = `Please choose
813
+
814
+ ${p.question}
815
+
816
+ Options:
817
+ ${optionsList}${p.allowCustom ? "\n\n(You can also reply with custom text.)" : ""}`;
818
+ break;
819
+ }
820
+ }
821
+ if (qqMessage) {
822
+ void qqRuntime.channel.sendResponse(qqMessage).catch((err) => {
823
+ emit({ type: "$error", message: `qq send failed: ${err.message}` }, tab.id);
824
+ });
825
+ }
826
+ }
827
+ async function startDesktopQQ(shouldPersistEnabled = true) {
828
+ const current = loadQQConfig();
829
+ if (!(current.appId && current.appSecret)) {
830
+ throw new Error("QQ App ID and App Secret are required.");
831
+ }
832
+ if (qqRuntime.channel) {
833
+ qqRuntime.channel.refreshAccessConfig();
834
+ setQQRuntimeState("connected");
835
+ return;
836
+ }
837
+ setQQRuntimeState("connecting");
838
+ const channel = new QQChannel({
839
+ onSubmitMessage: (text) => {
840
+ const tab = activeDesktopTab();
841
+ if (!tab) return;
842
+ const trimmed = text.trim();
843
+ if (!trimmed) return;
844
+ emit(
845
+ {
846
+ type: "user.message",
847
+ id: Date.now(),
848
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
849
+ turn: 0,
850
+ text: trimmed
851
+ },
852
+ tab.id
853
+ );
854
+ if (handleQQPauseReply(trimmed)) return;
855
+ if (tab.aborter) {
856
+ void channel.sendResponse(
857
+ "Session is busy. Wait for the current turn or reply to the pending prompt."
858
+ ).catch(() => void 0);
859
+ return;
860
+ }
861
+ qqRuntime.replyThisTurn = true;
862
+ void runTurn(tab, trimmed, true);
863
+ },
864
+ onError: (message) => {
865
+ const tab = activeDesktopTab();
866
+ setQQRuntimeState("failed", message);
867
+ if (tab) emit({ type: "$error", message: `QQ: ${message}` }, tab.id);
868
+ }
869
+ });
870
+ try {
871
+ await channel.start();
872
+ qqRuntime.channel = channel;
873
+ if (shouldPersistEnabled) setDesktopQQEnabled(true);
874
+ setQQRuntimeState("connected");
875
+ } catch (err) {
876
+ await channel.stop().catch(() => void 0);
877
+ qqRuntime.channel = null;
878
+ if (shouldPersistEnabled) setDesktopQQEnabled(false);
879
+ setQQRuntimeState("failed", err.message);
880
+ throw err;
881
+ }
882
+ }
883
+ async function stopDesktopQQ(shouldDisable = true) {
884
+ const channel = qqRuntime.channel;
885
+ qqRuntime.channel = null;
886
+ qqRuntime.interaction = { kind: null, payload: null };
887
+ qqRuntime.pendingGateId = null;
888
+ qqRuntime.replyThisTurn = false;
889
+ if (channel) await channel.stop();
890
+ if (shouldDisable) setDesktopQQEnabled(false);
891
+ setQQRuntimeState("disconnected");
892
+ }
543
893
  function createTabSkeleton(initialDir) {
544
894
  const dir = resolve(initialDir ?? opts.dir ?? loadWorkspaceDir() ?? process.cwd());
545
895
  pushRecentWorkspace(dir);
@@ -667,10 +1017,12 @@ async function desktopCommand(opts) {
667
1017
  persistOpenTabs();
668
1018
  emit({ type: "$tab_closed" }, tab.id);
669
1019
  }
670
- async function runTurn(tab, text) {
1020
+ async function runTurn(tab, text, fromQQ = false) {
671
1021
  if (!tab.runtime) return;
672
1022
  const rt = tab.runtime;
673
1023
  tab.aborter = new AbortController();
1024
+ qqRuntime.replyThisTurn = fromQQ;
1025
+ let lastAssistantText = "";
674
1026
  if (tab.currentSession) {
675
1027
  const existing = loadSessionMeta(tab.currentSession).summary;
676
1028
  if (!existing || !existing.trim()) {
@@ -686,6 +1038,9 @@ async function desktopCommand(opts) {
686
1038
  await tabContext.run(tab.id, async () => {
687
1039
  try {
688
1040
  for await (const ev of rt.loop.step(text)) {
1041
+ if (ev.role === "assistant_final" && ev.content) {
1042
+ lastAssistantText = ev.content;
1043
+ }
689
1044
  for (const kev of rt.eventizer.consume(ev, rt.ctx)) emit(kev, tab.id);
690
1045
  if (ev.role === "tool" && (ev.toolName === "remember" || ev.toolName === "forget")) {
691
1046
  emitMemory(tab);
@@ -696,6 +1051,12 @@ async function desktopCommand(opts) {
696
1051
  emit({ type: "$error", message: err.message }, tab.id);
697
1052
  } finally {
698
1053
  tab.aborter = null;
1054
+ if (fromQQ && lastAssistantText && qqRuntime.channel && qqRuntime.replyThisTurn) {
1055
+ await qqRuntime.channel.sendResponse(lastAssistantText).catch((err) => {
1056
+ emit({ type: "$error", message: `qq send failed: ${err.message}` }, tab.id);
1057
+ });
1058
+ }
1059
+ qqRuntime.replyThisTurn = false;
699
1060
  emit({ type: "$turn_complete" }, tab.id);
700
1061
  if (tab.planTotalSteps > 0 && tab.completedStepIds.size >= tab.planTotalSteps) {
701
1062
  tab.completedStepIds.clear();
@@ -828,11 +1189,11 @@ async function desktopCommand(opts) {
828
1189
  emit({ type: "$plan_cleared" }, tab.id);
829
1190
  }
830
1191
  }
831
- let first;
832
1192
  let shuttingDown = false;
833
1193
  async function gracefulShutdown() {
834
1194
  if (shuttingDown) return;
835
1195
  shuttingDown = true;
1196
+ await stopDesktopQQ(false).catch(() => void 0);
836
1197
  await Promise.allSettled(
837
1198
  [...tabs.values()].map((t) => t.toolset?.jobs.shutdown(1500) ?? Promise.resolve())
838
1199
  );
@@ -848,6 +1209,7 @@ async function desktopCommand(opts) {
848
1209
  const tab = activeRunningTab();
849
1210
  const tabId = tab?.id;
850
1211
  if (tab) tab.pendingGateIds.add(req.id);
1212
+ qqRuntime.pendingGateId = req.id;
851
1213
  const auto = autoResolveVerdict(req, loadEditMode());
852
1214
  if (auto !== null) {
853
1215
  if (req.kind === "plan_checkpoint") {
@@ -871,9 +1233,20 @@ async function desktopCommand(opts) {
871
1233
  if (req.kind === "run_command" || req.kind === "run_background") {
872
1234
  const payload = req.payload;
873
1235
  emit(
874
- { type: "$confirm_required", id: req.id, kind: req.kind, command: payload.command ?? "" },
1236
+ {
1237
+ type: "$confirm_required",
1238
+ id: req.id,
1239
+ kind: req.kind,
1240
+ command: payload.command ?? "",
1241
+ prompt: toApprovalPrompt({
1242
+ id: req.id,
1243
+ kind: req.kind,
1244
+ payload
1245
+ })
1246
+ },
875
1247
  tabId
876
1248
  );
1249
+ if (tab) handleQQPauseRequest(tab, req.kind, payload);
877
1250
  return;
878
1251
  }
879
1252
  if (req.kind === "path_access") {
@@ -886,10 +1259,16 @@ async function desktopCommand(opts) {
886
1259
  intent: payload.intent,
887
1260
  toolName: payload.toolName,
888
1261
  sandboxRoot: payload.sandboxRoot,
889
- allowPrefix: payload.allowPrefix
1262
+ allowPrefix: payload.allowPrefix,
1263
+ prompt: toApprovalPrompt({
1264
+ id: req.id,
1265
+ kind: req.kind,
1266
+ payload
1267
+ })
890
1268
  },
891
1269
  tabId
892
1270
  );
1271
+ if (tab) handleQQPauseRequest(tab, req.kind, payload);
893
1272
  return;
894
1273
  }
895
1274
  if (req.kind === "choice") {
@@ -904,6 +1283,7 @@ async function desktopCommand(opts) {
904
1283
  },
905
1284
  tabId
906
1285
  );
1286
+ if (tab) handleQQPauseRequest(tab, req.kind, payload);
907
1287
  return;
908
1288
  }
909
1289
  if (req.kind === "plan_proposed") {
@@ -922,6 +1302,7 @@ async function desktopCommand(opts) {
922
1302
  },
923
1303
  tabId
924
1304
  );
1305
+ if (tab) handleQQPauseRequest(tab, req.kind, payload);
925
1306
  return;
926
1307
  }
927
1308
  if (req.kind === "plan_checkpoint") {
@@ -950,6 +1331,7 @@ async function desktopCommand(opts) {
950
1331
  },
951
1332
  tabId
952
1333
  );
1334
+ if (tab) handleQQPauseRequest(tab, req.kind, payload);
953
1335
  return;
954
1336
  }
955
1337
  if (req.kind === "plan_revision") {
@@ -964,6 +1346,7 @@ async function desktopCommand(opts) {
964
1346
  },
965
1347
  tabId
966
1348
  );
1349
+ if (tab) handleQQPauseRequest(tab, req.kind, payload);
967
1350
  return;
968
1351
  }
969
1352
  const exhaustive = req.kind;
@@ -1035,6 +1418,12 @@ async function desktopCommand(opts) {
1035
1418
  const activeIdx = savedTabs.findIndex((t) => t.active);
1036
1419
  lastActiveTabId = ((activeIdx >= 0 ? restored[activeIdx] : first) ?? first).id;
1037
1420
  persistOpenTabs();
1421
+ const qqConfig = loadQQConfig();
1422
+ if (qqConfig.enabled && qqConfig.appId && qqConfig.appSecret) {
1423
+ void startDesktopQQ(false).catch(() => void 0);
1424
+ } else {
1425
+ broadcastQQSettings();
1426
+ }
1038
1427
  const rl = createInterface({ input: stdin });
1039
1428
  rl.on("line", (line) => {
1040
1429
  const trimmed = line.trim();
@@ -1126,6 +1515,25 @@ async function desktopCommand(opts) {
1126
1515
  }
1127
1516
  return;
1128
1517
  }
1518
+ if (msg.cmd === "desktop_resync") {
1519
+ const hasKey = !!loadApiKey();
1520
+ for (const t of tabs.values()) {
1521
+ emit(
1522
+ { type: "$tab_opened", workspaceDir: t.rootDir, active: t.id === lastActiveTabId },
1523
+ t.id
1524
+ );
1525
+ emitSessions(t);
1526
+ emitSettings(t);
1527
+ emitMcpSpecs(t);
1528
+ emitSkills(t);
1529
+ emitMemory(t);
1530
+ emitQQSettings(t);
1531
+ if (!hasKey) emit({ type: "$needs_setup", reason: "no_api_key" }, t.id);
1532
+ else if (t.toolset) emit({ type: "$ready" }, t.id);
1533
+ void emitBalance(t);
1534
+ }
1535
+ return;
1536
+ }
1129
1537
  if (msg.cmd === "jobs_list") {
1130
1538
  emitJobs();
1131
1539
  return;
@@ -1247,6 +1655,19 @@ ${found.body}${argsLine}`;
1247
1655
  emitSessions(tab);
1248
1656
  return;
1249
1657
  }
1658
+ if (msg.cmd === "session_rename") {
1659
+ try {
1660
+ const trimmed2 = normalizeSessionTitle(msg.title);
1661
+ patchSessionMeta(msg.name, { summary: trimmed2 || void 0 });
1662
+ emitSessions(tab);
1663
+ } catch (err) {
1664
+ emit(
1665
+ { type: "$error", message: `session_rename failed: ${err.message}` },
1666
+ tab.id
1667
+ );
1668
+ }
1669
+ return;
1670
+ }
1250
1671
  if (msg.cmd === "session_load") {
1251
1672
  try {
1252
1673
  const records = loadSessionMessages(msg.name);
@@ -1367,18 +1788,38 @@ ${found.body}${argsLine}`;
1367
1788
  if (msg.cmd === "qq_connect") {
1368
1789
  try {
1369
1790
  const current = loadQQConfig();
1370
- setDesktopQQEnabled(true);
1371
1791
  emit(
1372
1792
  {
1373
1793
  type: "status",
1374
1794
  id: Date.now(),
1375
1795
  ts: (/* @__PURE__ */ new Date()).toISOString(),
1376
1796
  turn: 0,
1377
- text: `QQ enabled for CLI (${current.sandbox ? "sandbox" : "production"}) \u2014 start the bot by running \`reasonix\` in a terminal`
1797
+ text: `QQ connecting (${current.sandbox ? "sandbox" : "production"})`
1378
1798
  },
1379
1799
  tab.id
1380
1800
  );
1381
- emitQQSettings(tab);
1801
+ void startDesktopQQ(true).then(
1802
+ () => {
1803
+ emit(
1804
+ {
1805
+ type: "status",
1806
+ id: Date.now(),
1807
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
1808
+ turn: 0,
1809
+ text: `QQ connected (${current.sandbox ? "sandbox" : "production"})`
1810
+ },
1811
+ tab.id
1812
+ );
1813
+ emitQQSettings(tab);
1814
+ },
1815
+ (err) => {
1816
+ emit(
1817
+ { type: "$error", message: `qq_connect failed: ${err.message}` },
1818
+ tab.id
1819
+ );
1820
+ emitQQSettings(tab);
1821
+ }
1822
+ );
1382
1823
  } catch (err) {
1383
1824
  emit({ type: "$error", message: `qq_connect failed: ${err.message}` }, tab.id);
1384
1825
  emitQQSettings(tab);
@@ -1387,18 +1828,27 @@ ${found.body}${argsLine}`;
1387
1828
  }
1388
1829
  if (msg.cmd === "qq_disconnect") {
1389
1830
  try {
1390
- setDesktopQQEnabled(false);
1391
- emit(
1392
- {
1393
- type: "status",
1394
- id: Date.now(),
1395
- ts: (/* @__PURE__ */ new Date()).toISOString(),
1396
- turn: 0,
1397
- text: "QQ disabled for CLI (next `reasonix` terminal session won't auto-start the bot)"
1831
+ void stopDesktopQQ(true).then(
1832
+ () => {
1833
+ emit(
1834
+ {
1835
+ type: "status",
1836
+ id: Date.now(),
1837
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
1838
+ turn: 0,
1839
+ text: "QQ disabled"
1840
+ },
1841
+ tab.id
1842
+ );
1843
+ emitQQSettings(tab);
1398
1844
  },
1399
- tab.id
1845
+ (err) => {
1846
+ emit(
1847
+ { type: "$error", message: `qq_disconnect failed: ${err.message}` },
1848
+ tab.id
1849
+ );
1850
+ }
1400
1851
  );
1401
- emitQQSettings(tab);
1402
1852
  } catch (err) {
1403
1853
  emit(
1404
1854
  { type: "$error", message: `qq_disconnect failed: ${err.message}` },
@@ -1481,7 +1931,7 @@ ${found.body}${argsLine}`;
1481
1931
  }
1482
1932
  if (msg.cmd === "compact_history") {
1483
1933
  if (!tab.runtime) return;
1484
- void tab.runtime.loop.compactHistory().catch((err) => {
1934
+ void tab.runtime.loop.compactHistory().then(() => emitCtxBreakdown(tab)).catch((err) => {
1485
1935
  emit({ type: "$error", message: `/compact failed: ${err.message}` }, tab.id);
1486
1936
  });
1487
1937
  return;
@@ -1503,7 +1953,10 @@ ${found.body}${argsLine}`;
1503
1953
  const reply = await tab.runtime.loop.client.chat({
1504
1954
  model: tab.currentModel,
1505
1955
  messages: [
1506
- { role: "system", content: tab.system },
1956
+ {
1957
+ role: "system",
1958
+ content: "You are answering a side question that is unrelated to the current coding conversation. Answer concisely (1-3 sentences) in plain prose. Do not call tools, do not ask clarifying questions, and do not reference any prior turns."
1959
+ },
1507
1960
  { role: "user", content: question }
1508
1961
  ]
1509
1962
  });
@@ -1535,6 +1988,8 @@ ${found.body}${argsLine}`;
1535
1988
  }
1536
1989
  export {
1537
1990
  desktopCommand,
1538
- installDesktopCrashGuards
1991
+ installDesktopCrashGuards,
1992
+ normalizeSessionTitle,
1993
+ writeAllSync
1539
1994
  };
1540
- //# sourceMappingURL=desktop-EG6P5SF2.js.map
1995
+ //# sourceMappingURL=desktop-G7UMW3CJ.js.map