reasonix 0.46.1 → 0.47.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 (139) hide show
  1. package/README.md +62 -13
  2. package/README.zh-CN.md +52 -10
  3. package/dashboard/dist/app.js +217 -60
  4. package/dashboard/dist/app.js.map +1 -1
  5. package/dist/cli/{acp-LKJU5DZX.js → acp-GEOAKSTU.js} +26 -54
  6. package/dist/cli/acp-GEOAKSTU.js.map +1 -0
  7. package/dist/cli/chat-YTPATMMG.js +51 -0
  8. package/dist/cli/{chunk-R2ASNSEO.js → chunk-2XY77LW7.js} +8 -8
  9. package/dist/cli/{chunk-SE7C5ZSI.js → chunk-4MFCAZ2W.js} +3 -3
  10. package/dist/cli/{chunk-DGA5QYFM.js → chunk-6CRPCJAU.js} +55 -13
  11. package/dist/cli/chunk-6CRPCJAU.js.map +1 -0
  12. package/dist/cli/{chunk-TDSBASOF.js → chunk-6QC5RQLE.js} +2 -2
  13. package/dist/cli/chunk-BQ6HC66J.js +530 -0
  14. package/dist/cli/chunk-BQ6HC66J.js.map +1 -0
  15. package/dist/cli/{chunk-7SGGXNB2.js → chunk-CCJAP7G3.js} +2 -2
  16. package/dist/cli/{chunk-3AAG2CUT.js → chunk-CNG32VAB.js} +2 -2
  17. package/dist/cli/{chunk-WRONKNIH.js → chunk-DN4B5S6Y.js} +2 -2
  18. package/dist/cli/{chunk-NCBP5D6E.js → chunk-DQ6K5ZQ7.js} +2 -2
  19. package/dist/cli/{chunk-MIIZJD5O.js → chunk-DWPAKZTY.js} +14 -3
  20. package/dist/cli/chunk-DWPAKZTY.js.map +1 -0
  21. package/dist/cli/{chunk-IYQ325V7.js → chunk-E5WCLUIU.js} +2 -2
  22. package/dist/cli/{chunk-YRLC2EDF.js → chunk-EQATK2L2.js} +2 -2
  23. package/dist/cli/{chunk-TEUDEGX2.js → chunk-FY4S7TJZ.js} +19 -5
  24. package/dist/cli/chunk-FY4S7TJZ.js.map +1 -0
  25. package/dist/cli/{chunk-C72TNHDE.js → chunk-GH7DC2Y5.js} +2 -2
  26. package/dist/cli/{chunk-WQ6ZRDQM.js → chunk-HIYTRCSW.js} +16 -12
  27. package/dist/cli/chunk-HIYTRCSW.js.map +1 -0
  28. package/dist/cli/{chunk-EAOL43HB.js → chunk-HUILPCYX.js} +3 -3
  29. package/dist/cli/{chunk-ZOQHVQON.js → chunk-JBH5RM7X.js} +473 -87
  30. package/dist/cli/chunk-JBH5RM7X.js.map +1 -0
  31. package/dist/cli/{chunk-XPAUNFOL.js → chunk-KVZZ5U75.js} +3 -2
  32. package/dist/cli/chunk-KVZZ5U75.js.map +1 -0
  33. package/dist/cli/{chunk-2AASOSD5.js → chunk-KYQVQ5X4.js} +85 -10
  34. package/dist/cli/chunk-KYQVQ5X4.js.map +1 -0
  35. package/dist/cli/{chunk-2425HK6U.js → chunk-LGEKVMMV.js} +7 -2
  36. package/dist/cli/{chunk-2425HK6U.js.map → chunk-LGEKVMMV.js.map} +1 -1
  37. package/dist/cli/{chunk-6VANO7KB.js → chunk-NRQ5UP5T.js} +165 -24
  38. package/dist/cli/chunk-NRQ5UP5T.js.map +1 -0
  39. package/dist/cli/{chunk-M4E5JK6S.js → chunk-QCFLPSPH.js} +2 -2
  40. package/dist/cli/{chunk-E7TAHQ4A.js → chunk-RRXUIPWG.js} +19 -18
  41. package/dist/cli/chunk-RRXUIPWG.js.map +1 -0
  42. package/dist/cli/{chunk-JLQDNLZF.js → chunk-T5A7EY6B.js} +26 -14
  43. package/dist/cli/chunk-T5A7EY6B.js.map +1 -0
  44. package/dist/cli/{chunk-7LOJS3LV.js → chunk-TDHXB2ER.js} +2 -2
  45. package/dist/cli/{chunk-CXVWUPA3.js → chunk-TKVXTQ3T.js} +26 -26
  46. package/dist/cli/chunk-TKVXTQ3T.js.map +1 -0
  47. package/dist/cli/{chunk-JVFEJAJX.js → chunk-TRSAHHCL.js} +107 -11
  48. package/dist/cli/chunk-TRSAHHCL.js.map +1 -0
  49. package/dist/cli/{chunk-K3AIFMI6.js → chunk-TRWHTFG7.js} +2 -2
  50. package/dist/cli/{chunk-7YW6TPXK.js → chunk-XD6P7AFH.js} +28 -31
  51. package/dist/cli/chunk-XD6P7AFH.js.map +1 -0
  52. package/dist/cli/{chunk-SPXN5JIT.js → chunk-XMHP7BEE.js} +1787 -1081
  53. package/dist/cli/chunk-XMHP7BEE.js.map +1 -0
  54. package/dist/cli/{chunk-JVQT5IYP.js → chunk-YFP3MYMY.js} +19 -9
  55. package/dist/cli/chunk-YFP3MYMY.js.map +1 -0
  56. package/dist/cli/{chunk-HNXDZGC6.js → chunk-ZXSCAODE.js} +9 -9
  57. package/dist/cli/{chunk-HNXDZGC6.js.map → chunk-ZXSCAODE.js.map} +1 -1
  58. package/dist/cli/{code-2JIHL5M2.js → code-Q4NRVEDG.js} +42 -35
  59. package/dist/cli/code-Q4NRVEDG.js.map +1 -0
  60. package/dist/cli/{commands-OPT5AJNH.js → commands-4CDI4GFM.js} +4 -4
  61. package/dist/cli/{commit-KA37H6GM.js → commit-GW7LDQP5.js} +3 -3
  62. package/dist/cli/{desktop-5ONTRU3C.js → desktop-EG6P5SF2.js} +321 -36
  63. package/dist/cli/desktop-EG6P5SF2.js.map +1 -0
  64. package/dist/cli/{diff-SOIA7AKH.js → diff-VI2YX4FN.js} +8 -8
  65. package/dist/cli/{doctor-RCUP4XRV.js → doctor-CQTTZP27.js} +9 -9
  66. package/dist/cli/{events-6KHITNX4.js → events-VRYXOSKI.js} +3 -3
  67. package/dist/cli/index.js +94 -45
  68. package/dist/cli/index.js.map +1 -1
  69. package/dist/cli/{mcp-JP5OWD6R.js → mcp-J2UCD4RZ.js} +2 -2
  70. package/dist/cli/{mcp-browse-ONCJJPJN.js → mcp-browse-GSX34JEK.js} +2 -2
  71. package/dist/cli/{mcp-inspect-TPLHW5JA.js → mcp-inspect-RRFYF4ZV.js} +4 -4
  72. package/dist/cli/{prompt-RJDNCQAP.js → prompt-5TQPIVHV.js} +4 -4
  73. package/dist/cli/{prune-sessions-MKEATRVL.js → prune-sessions-SEWX7GP6.js} +2 -2
  74. package/dist/cli/{replay-4NILJG4U.js → replay-MJCEMODU.js} +9 -9
  75. package/dist/cli/{run-WFGXB4SB.js → run-P4D5VDYE.js} +17 -17
  76. package/dist/cli/{server-5VFQP3PV.js → server-C25JNNZV.js} +82 -34
  77. package/dist/cli/server-C25JNNZV.js.map +1 -0
  78. package/dist/cli/{sessions-5XDJDALO.js → sessions-QIONZJQ6.js} +15 -15
  79. package/dist/cli/{setup-F6XSWLRA.js → setup-NLQ6G5G4.js} +7 -7
  80. package/dist/cli/setup-NLQ6G5G4.js.map +1 -0
  81. package/dist/cli/{stats-ALHBZICE.js → stats-DFZEXHP4.js} +6 -6
  82. package/dist/cli/{version-JVRAHBMM.js → version-GR3X3MPI.js} +15 -15
  83. package/dist/index.d.ts +69 -56
  84. package/dist/index.js +791 -303
  85. package/dist/index.js.map +1 -1
  86. package/package.json +3 -1
  87. package/dist/cli/acp-LKJU5DZX.js.map +0 -1
  88. package/dist/cli/chat-W7LAWEN6.js +0 -51
  89. package/dist/cli/chunk-2AASOSD5.js.map +0 -1
  90. package/dist/cli/chunk-6VANO7KB.js.map +0 -1
  91. package/dist/cli/chunk-7YW6TPXK.js.map +0 -1
  92. package/dist/cli/chunk-CXVWUPA3.js.map +0 -1
  93. package/dist/cli/chunk-DGA5QYFM.js.map +0 -1
  94. package/dist/cli/chunk-DHRVZJ2D.js +0 -642
  95. package/dist/cli/chunk-DHRVZJ2D.js.map +0 -1
  96. package/dist/cli/chunk-E7TAHQ4A.js.map +0 -1
  97. package/dist/cli/chunk-JLQDNLZF.js.map +0 -1
  98. package/dist/cli/chunk-JVFEJAJX.js.map +0 -1
  99. package/dist/cli/chunk-JVQT5IYP.js.map +0 -1
  100. package/dist/cli/chunk-MIIZJD5O.js.map +0 -1
  101. package/dist/cli/chunk-SPXN5JIT.js.map +0 -1
  102. package/dist/cli/chunk-TEUDEGX2.js.map +0 -1
  103. package/dist/cli/chunk-WQ6ZRDQM.js.map +0 -1
  104. package/dist/cli/chunk-XPAUNFOL.js.map +0 -1
  105. package/dist/cli/chunk-ZOQHVQON.js.map +0 -1
  106. package/dist/cli/code-2JIHL5M2.js.map +0 -1
  107. package/dist/cli/desktop-5ONTRU3C.js.map +0 -1
  108. package/dist/cli/server-5VFQP3PV.js.map +0 -1
  109. package/dist/cli/setup-F6XSWLRA.js.map +0 -1
  110. /package/dist/cli/{chat-W7LAWEN6.js.map → chat-YTPATMMG.js.map} +0 -0
  111. /package/dist/cli/{chunk-R2ASNSEO.js.map → chunk-2XY77LW7.js.map} +0 -0
  112. /package/dist/cli/{chunk-SE7C5ZSI.js.map → chunk-4MFCAZ2W.js.map} +0 -0
  113. /package/dist/cli/{chunk-TDSBASOF.js.map → chunk-6QC5RQLE.js.map} +0 -0
  114. /package/dist/cli/{chunk-7SGGXNB2.js.map → chunk-CCJAP7G3.js.map} +0 -0
  115. /package/dist/cli/{chunk-3AAG2CUT.js.map → chunk-CNG32VAB.js.map} +0 -0
  116. /package/dist/cli/{chunk-WRONKNIH.js.map → chunk-DN4B5S6Y.js.map} +0 -0
  117. /package/dist/cli/{chunk-NCBP5D6E.js.map → chunk-DQ6K5ZQ7.js.map} +0 -0
  118. /package/dist/cli/{chunk-IYQ325V7.js.map → chunk-E5WCLUIU.js.map} +0 -0
  119. /package/dist/cli/{chunk-YRLC2EDF.js.map → chunk-EQATK2L2.js.map} +0 -0
  120. /package/dist/cli/{chunk-C72TNHDE.js.map → chunk-GH7DC2Y5.js.map} +0 -0
  121. /package/dist/cli/{chunk-EAOL43HB.js.map → chunk-HUILPCYX.js.map} +0 -0
  122. /package/dist/cli/{chunk-M4E5JK6S.js.map → chunk-QCFLPSPH.js.map} +0 -0
  123. /package/dist/cli/{chunk-7LOJS3LV.js.map → chunk-TDHXB2ER.js.map} +0 -0
  124. /package/dist/cli/{chunk-K3AIFMI6.js.map → chunk-TRWHTFG7.js.map} +0 -0
  125. /package/dist/cli/{commands-OPT5AJNH.js.map → commands-4CDI4GFM.js.map} +0 -0
  126. /package/dist/cli/{commit-KA37H6GM.js.map → commit-GW7LDQP5.js.map} +0 -0
  127. /package/dist/cli/{diff-SOIA7AKH.js.map → diff-VI2YX4FN.js.map} +0 -0
  128. /package/dist/cli/{doctor-RCUP4XRV.js.map → doctor-CQTTZP27.js.map} +0 -0
  129. /package/dist/cli/{events-6KHITNX4.js.map → events-VRYXOSKI.js.map} +0 -0
  130. /package/dist/cli/{mcp-JP5OWD6R.js.map → mcp-J2UCD4RZ.js.map} +0 -0
  131. /package/dist/cli/{mcp-browse-ONCJJPJN.js.map → mcp-browse-GSX34JEK.js.map} +0 -0
  132. /package/dist/cli/{mcp-inspect-TPLHW5JA.js.map → mcp-inspect-RRFYF4ZV.js.map} +0 -0
  133. /package/dist/cli/{prompt-RJDNCQAP.js.map → prompt-5TQPIVHV.js.map} +0 -0
  134. /package/dist/cli/{prune-sessions-MKEATRVL.js.map → prune-sessions-SEWX7GP6.js.map} +0 -0
  135. /package/dist/cli/{replay-4NILJG4U.js.map → replay-MJCEMODU.js.map} +0 -0
  136. /package/dist/cli/{run-WFGXB4SB.js.map → run-P4D5VDYE.js.map} +0 -0
  137. /package/dist/cli/{sessions-5XDJDALO.js.map → sessions-QIONZJQ6.js.map} +0 -0
  138. /package/dist/cli/{stats-ALHBZICE.js.map → stats-DFZEXHP4.js.map} +0 -0
  139. /package/dist/cli/{version-JVRAHBMM.js.map → version-GR3X3MPI.js.map} +0 -0
@@ -2,16 +2,16 @@
2
2
  import { createRequire as __cr } from 'node:module'; if (typeof globalThis.require === 'undefined') { globalThis.require = __cr(import.meta.url); }
3
3
  import {
4
4
  createMcpRuntime
5
- } from "./chunk-JVQT5IYP.js";
5
+ } from "./chunk-YFP3MYMY.js";
6
6
  import {
7
7
  buildCodeToolset
8
- } from "./chunk-7YW6TPXK.js";
8
+ } from "./chunk-XD6P7AFH.js";
9
9
  import {
10
10
  Eventizer,
11
11
  autoResolveVerdict
12
- } from "./chunk-HNXDZGC6.js";
13
- import "./chunk-NCBP5D6E.js";
14
- import "./chunk-YRLC2EDF.js";
12
+ } from "./chunk-ZXSCAODE.js";
13
+ import "./chunk-DQ6K5ZQ7.js";
14
+ import "./chunk-EQATK2L2.js";
15
15
  import {
16
16
  CacheFirstLoop,
17
17
  ImmutablePrefix,
@@ -19,39 +19,39 @@ import {
19
19
  listFilesWithStatsAsync,
20
20
  parseAtQuery,
21
21
  rankPickerCandidates
22
- } from "./chunk-ZOQHVQON.js";
23
- import "./chunk-TDSBASOF.js";
24
- import "./chunk-EAOL43HB.js";
25
- import "./chunk-WQ6ZRDQM.js";
22
+ } from "./chunk-JBH5RM7X.js";
23
+ import "./chunk-6QC5RQLE.js";
24
+ import "./chunk-HUILPCYX.js";
25
+ import "./chunk-HIYTRCSW.js";
26
26
  import {
27
27
  MemoryStore,
28
28
  codeSystemPrompt
29
- } from "./chunk-DHRVZJ2D.js";
29
+ } from "./chunk-BQ6HC66J.js";
30
30
  import {
31
31
  canonicalPresetName,
32
32
  resolvePreset
33
- } from "./chunk-2425HK6U.js";
33
+ } from "./chunk-LGEKVMMV.js";
34
34
  import {
35
35
  countTokensBounded
36
36
  } from "./chunk-6OWJV3YW.js";
37
37
  import {
38
38
  DeepSeekClient,
39
39
  pickPrimaryBalance
40
- } from "./chunk-MIIZJD5O.js";
40
+ } from "./chunk-DWPAKZTY.js";
41
41
  import "./chunk-25T6CVUP.js";
42
42
  import {
43
43
  loadDotenv
44
44
  } from "./chunk-2UQP6H6T.js";
45
- import "./chunk-XPAUNFOL.js";
45
+ import "./chunk-KVZZ5U75.js";
46
46
  import {
47
47
  pauseGate
48
- } from "./chunk-JVFEJAJX.js";
48
+ } from "./chunk-TRSAHHCL.js";
49
49
  import {
50
50
  SkillStore
51
- } from "./chunk-TEUDEGX2.js";
51
+ } from "./chunk-FY4S7TJZ.js";
52
52
  import "./chunk-PLHAZOLZ.js";
53
- import "./chunk-JLQDNLZF.js";
54
- import "./chunk-C72TNHDE.js";
53
+ import "./chunk-T5A7EY6B.js";
54
+ import "./chunk-GH7DC2Y5.js";
55
55
  import "./chunk-S4XVGLRW.js";
56
56
  import {
57
57
  deleteSession,
@@ -59,12 +59,14 @@ import {
59
59
  loadSessionMessages,
60
60
  loadSessionMeta,
61
61
  patchSessionMeta,
62
+ sessionPath,
62
63
  timestampSuffix
63
- } from "./chunk-E7TAHQ4A.js";
64
- import "./chunk-WRONKNIH.js";
65
- import "./chunk-M4E5JK6S.js";
66
- import "./chunk-6VANO7KB.js";
64
+ } from "./chunk-RRXUIPWG.js";
65
+ import "./chunk-DN4B5S6Y.js";
66
+ import "./chunk-QCFLPSPH.js";
67
+ import "./chunk-NRQ5UP5T.js";
67
68
  import {
69
+ describeQQAccess,
68
70
  isPlausibleKey,
69
71
  loadApiKey,
70
72
  loadBaseUrl,
@@ -72,6 +74,7 @@ import {
72
74
  loadEditMode,
73
75
  loadEditor,
74
76
  loadPreset,
77
+ loadQQConfig,
75
78
  loadReasoningEffort,
76
79
  loadRecentWorkspaces,
77
80
  loadResolvedSkillPaths,
@@ -85,10 +88,11 @@ import {
85
88
  saveEditMode,
86
89
  saveEditor,
87
90
  savePreset,
91
+ saveQQConfig,
88
92
  saveReasoningEffort,
89
93
  saveWorkspaceDir,
90
94
  writeConfig
91
- } from "./chunk-DGA5QYFM.js";
95
+ } from "./chunk-6CRPCJAU.js";
92
96
  import {
93
97
  VERSION
94
98
  } from "./chunk-XXC2BYTV.js";
@@ -101,6 +105,109 @@ import { readFile } from "fs/promises";
101
105
  import { isAbsolute, join, resolve } from "path";
102
106
  import { stdin } from "process";
103
107
  import { createInterface } from "readline";
108
+
109
+ // src/desktop/login-shell-path.ts
110
+ import { spawnSync } from "child_process";
111
+ var cached;
112
+ function resolveLoginShellPath(opts = {}) {
113
+ if (cached !== void 0) return cached.value;
114
+ cached = { value: null };
115
+ if (process.platform === "win32") return null;
116
+ const shell = process.env.SHELL || "/bin/bash";
117
+ const marker = "__REASONIX_PATH__=";
118
+ try {
119
+ const result = spawnSync(shell, ["-ilc", `printf '${marker}%s\\n' "$PATH"`], {
120
+ encoding: "utf8",
121
+ timeout: opts.timeoutMs ?? 2e3,
122
+ stdio: ["ignore", "pipe", "ignore"]
123
+ });
124
+ if (result.status !== 0 && result.signal === null) return null;
125
+ const stdout = result.stdout ?? "";
126
+ const idx = stdout.lastIndexOf(marker);
127
+ if (idx < 0) return null;
128
+ const tail = stdout.slice(idx + marker.length);
129
+ const newline = tail.indexOf("\n");
130
+ const path = (newline >= 0 ? tail.slice(0, newline) : tail).trim();
131
+ if (!path || !path.includes("/")) return null;
132
+ cached.value = path;
133
+ return path;
134
+ } catch {
135
+ return null;
136
+ }
137
+ }
138
+ function augmentProcessPath() {
139
+ const loginPath = resolveLoginShellPath();
140
+ if (!loginPath) return { added: [] };
141
+ const current = process.env.PATH ?? "";
142
+ const seen = new Set(
143
+ current.split(":").map((s) => s.trim()).filter(Boolean)
144
+ );
145
+ const additions = [];
146
+ for (const entry of loginPath.split(":")) {
147
+ const t = entry.trim();
148
+ if (!t || seen.has(t)) continue;
149
+ seen.add(t);
150
+ additions.push(t);
151
+ }
152
+ if (additions.length === 0) return { added: [] };
153
+ process.env.PATH = additions.concat(current ? [current] : []).join(":");
154
+ return { added: additions };
155
+ }
156
+
157
+ // src/desktop/qq-settings.ts
158
+ function trimOptional(value) {
159
+ const trimmed = value?.trim();
160
+ return trimmed ? trimmed : void 0;
161
+ }
162
+ function toPreview(appId) {
163
+ if (!appId) return void 0;
164
+ return appId.length > 6 ? `${appId.slice(0, 6)}...` : appId;
165
+ }
166
+ function toAccess(config) {
167
+ return describeQQAccess({
168
+ ownerOpenId: config.ownerOpenId,
169
+ allowlist: config.allowlist
170
+ });
171
+ }
172
+ function loadDesktopQQState(path) {
173
+ const config = loadQQConfig(path);
174
+ const configured = Boolean(config.appId && config.appSecret);
175
+ const enabled = config.enabled === true;
176
+ return {
177
+ ...config,
178
+ sandbox: config.sandbox ?? false,
179
+ enabled,
180
+ configured,
181
+ // Never true — the desktop process doesn't host a QQChannel (#1317).
182
+ connected: false,
183
+ enabledForCli: configured && enabled,
184
+ appIdPreview: toPreview(config.appId),
185
+ access: toAccess(config)
186
+ };
187
+ }
188
+ function saveDesktopQQSettings(patch, path) {
189
+ const existing = loadQQConfig(path);
190
+ saveQQConfig(
191
+ {
192
+ ...existing,
193
+ appId: trimOptional(patch.appId),
194
+ appSecret: trimOptional(patch.appSecret),
195
+ sandbox: patch.sandbox
196
+ },
197
+ path
198
+ );
199
+ return loadDesktopQQState(path);
200
+ }
201
+ function setDesktopQQEnabled(enabled, path) {
202
+ const existing = loadQQConfig(path);
203
+ if (enabled && !(existing.appId && existing.appSecret)) {
204
+ throw new Error("QQ App ID and App Secret are required.");
205
+ }
206
+ saveQQConfig({ ...existing, enabled }, path);
207
+ return loadDesktopQQState(path);
208
+ }
209
+
210
+ // src/cli/commands/desktop.ts
104
211
  function emit(ev, tabId) {
105
212
  const payload = tabId ? { ...ev, tabId } : ev;
106
213
  writeSync(1, Buffer.from(`${JSON.stringify(payload)}
@@ -179,6 +286,9 @@ function emitSettings(tab) {
179
286
  tab.id
180
287
  );
181
288
  }
289
+ function emitQQSettings(tab) {
290
+ emit({ type: "$qq_settings", ...loadDesktopQQState() }, tab.id);
291
+ }
182
292
  async function emitBalance(tab) {
183
293
  if (!tab.runtime) return;
184
294
  const bal = await tab.runtime.loop.client.getBalance().catch(() => null);
@@ -415,9 +525,17 @@ function installDesktopCrashGuards(stderr = process.stderr) {
415
525
  }
416
526
  async function desktopCommand(opts) {
417
527
  loadDotenv();
528
+ const augmented = augmentProcessPath();
529
+ if (augmented.added.length > 0) {
530
+ process.stderr.write(
531
+ `[desktop] augmented PATH with ${augmented.added.length} login-shell entries
532
+ `
533
+ );
534
+ }
418
535
  installDesktopCrashGuards();
419
536
  const tabs = /* @__PURE__ */ new Map();
420
537
  const tabContext = new AsyncLocalStorage();
538
+ let lastActiveTabId = "";
421
539
  function activeRunningTab() {
422
540
  const id = tabContext.getStore();
423
541
  return id ? tabs.get(id) : void 0;
@@ -519,7 +637,13 @@ async function desktopCommand(opts) {
519
637
  }
520
638
  function persistOpenTabs() {
521
639
  try {
522
- saveDesktopOpenTabs(Array.from(tabs.values()).map((t) => t.rootDir));
640
+ saveDesktopOpenTabs(
641
+ Array.from(tabs.values()).map((t) => ({
642
+ dir: t.rootDir,
643
+ session: t.currentSession || void 0,
644
+ active: t.id === lastActiveTabId
645
+ }))
646
+ );
523
647
  } catch {
524
648
  }
525
649
  }
@@ -622,6 +746,7 @@ async function desktopCommand(opts) {
622
746
  emitSessions(tab);
623
747
  emitSettings(tab);
624
748
  emitSkills(tab);
749
+ persistOpenTabs();
625
750
  }
626
751
  function forgetGate(id) {
627
752
  for (const t of tabs.values()) {
@@ -849,14 +974,44 @@ async function desktopCommand(opts) {
849
974
  if (tab) tab.pendingGateIds.delete(req.id);
850
975
  pauseGate.cancel(req.id);
851
976
  });
852
- function bootstrapTab(initialDir) {
977
+ function bootstrapTab(initialDir, restore) {
853
978
  const tab = createTabSkeleton(initialDir);
854
- emit({ type: "$tab_opened", workspaceDir: tab.rootDir }, tab.id);
979
+ let restoredMessages;
980
+ if (restore?.session) {
981
+ try {
982
+ if (existsSync(sessionPath(restore.session))) {
983
+ const msgs = buildLoadedMessages(loadSessionMessages(restore.session));
984
+ if (msgs.length > 0) {
985
+ tab.currentSession = restore.session;
986
+ restoredMessages = msgs;
987
+ }
988
+ }
989
+ } catch {
990
+ }
991
+ }
992
+ emit({ type: "$tab_opened", workspaceDir: tab.rootDir, active: restore?.active }, tab.id);
855
993
  emitSessions(tab);
856
994
  emitSettings(tab);
857
995
  emitMcpSpecs(tab);
858
996
  emitSkills(tab);
859
997
  emitMemory(tab);
998
+ emitQQSettings(tab);
999
+ if (restoredMessages) {
1000
+ const meta = loadSessionMeta(tab.currentSession);
1001
+ emit(
1002
+ {
1003
+ type: "$session_loaded",
1004
+ name: tab.currentSession,
1005
+ messages: restoredMessages,
1006
+ carryover: {
1007
+ totalCostUsd: meta.totalCostUsd ?? 0,
1008
+ cacheHitTokens: meta.cacheHitTokens ?? 0,
1009
+ cacheMissTokens: meta.cacheMissTokens ?? 0
1010
+ }
1011
+ },
1012
+ tab.id
1013
+ );
1014
+ }
860
1015
  if (!loadApiKey()) emit({ type: "$needs_setup", reason: "no_api_key" }, tab.id);
861
1016
  void emitBalance(tab);
862
1017
  void initTabToolset(tab).then(() => {
@@ -867,18 +1022,18 @@ async function desktopCommand(opts) {
867
1022
  });
868
1023
  return tab;
869
1024
  }
870
- const savedTabDirs = opts.dir ? [] : loadDesktopOpenTabs().filter((d) => {
1025
+ const savedTabs = opts.dir ? [] : loadDesktopOpenTabs().filter((t) => {
871
1026
  try {
872
- return existsSync(d) && statSync(d).isDirectory();
1027
+ return existsSync(t.dir) && statSync(t.dir).isDirectory();
873
1028
  } catch {
874
1029
  return false;
875
1030
  }
876
1031
  });
877
- first = bootstrapTab(savedTabDirs[0]);
878
- for (const d of savedTabDirs.slice(1)) {
879
- if (resolve(d) === first.rootDir) continue;
880
- bootstrapTab(d);
881
- }
1032
+ first = bootstrapTab(savedTabs[0]?.dir, savedTabs[0]);
1033
+ const restored = [first];
1034
+ for (const t of savedTabs.slice(1)) restored.push(bootstrapTab(t.dir, t));
1035
+ const activeIdx = savedTabs.findIndex((t) => t.active);
1036
+ lastActiveTabId = ((activeIdx >= 0 ? restored[activeIdx] : first) ?? first).id;
882
1037
  persistOpenTabs();
883
1038
  const rl = createInterface({ input: stdin });
884
1039
  rl.on("line", (line) => {
@@ -893,13 +1048,21 @@ async function desktopCommand(opts) {
893
1048
  }
894
1049
  if (msg.cmd === "tab_open") {
895
1050
  try {
896
- bootstrapTab(msg.workspaceDir);
1051
+ const opened = bootstrapTab(msg.workspaceDir, { active: true });
1052
+ lastActiveTabId = opened.id;
897
1053
  persistOpenTabs();
898
1054
  } catch (err) {
899
1055
  emit({ type: "$error", message: `tab_open failed: ${err.message}` });
900
1056
  }
901
1057
  return;
902
1058
  }
1059
+ if (msg.cmd === "tab_activate") {
1060
+ if (tabs.has(msg.tabId)) {
1061
+ lastActiveTabId = msg.tabId;
1062
+ persistOpenTabs();
1063
+ }
1064
+ return;
1065
+ }
903
1066
  if (msg.cmd === "confirm_response") {
904
1067
  forgetGate(msg.id);
905
1068
  pauseGate.resolve(msg.id, msg.response);
@@ -977,7 +1140,10 @@ async function desktopCommand(opts) {
977
1140
  }
978
1141
  const tab = msg.tabId ? tabs.get(msg.tabId) : first;
979
1142
  if (!tab) {
980
- emit({ type: "$error", message: `unknown tab: ${msg.tabId}` });
1143
+ process.stderr.write(
1144
+ `rpc dispatch: unknown tabId=${msg.tabId} for cmd=${msg.cmd} \u2014 dropping
1145
+ `
1146
+ );
981
1147
  return;
982
1148
  }
983
1149
  if (msg.cmd === "abort") {
@@ -1088,12 +1254,26 @@ ${found.body}${argsLine}`;
1088
1254
  abortTurn(tab);
1089
1255
  cancelPendingGates(tab);
1090
1256
  tab.currentSession = msg.name;
1257
+ persistOpenTabs();
1091
1258
  if (tab.runtime) tab.runtime = buildRuntimeFor(tab);
1259
+ const loadedMessages = buildLoadedMessages(records);
1260
+ if (loadedMessages.length === 0) {
1261
+ let sizeBytes = 0;
1262
+ try {
1263
+ sizeBytes = statSync(sessionPath(msg.name)).size;
1264
+ } catch {
1265
+ }
1266
+ process.stderr.write(
1267
+ `session_load: "${msg.name}" returned 0 messages (file size=${sizeBytes}B) \u2014 empty or unreadable jsonl
1268
+ `
1269
+ );
1270
+ emit({ type: "$session_empty", name: msg.name, sizeBytes }, tab.id);
1271
+ }
1092
1272
  emit(
1093
1273
  {
1094
1274
  type: "$session_loaded",
1095
1275
  name: msg.name,
1096
- messages: buildLoadedMessages(records),
1276
+ messages: loadedMessages,
1097
1277
  carryover: {
1098
1278
  totalCostUsd: meta.totalCostUsd ?? 0,
1099
1279
  cacheHitTokens: meta.cacheHitTokens ?? 0,
@@ -1103,6 +1283,8 @@ ${found.body}${argsLine}`;
1103
1283
  tab.id
1104
1284
  );
1105
1285
  } catch (err) {
1286
+ process.stderr.write(`session_load: "${msg.name}" threw \u2014 ${err.message}
1287
+ `);
1106
1288
  emit({ type: "$error", message: `session_load failed: ${err.message}` }, tab.id);
1107
1289
  }
1108
1290
  return;
@@ -1111,6 +1293,7 @@ ${found.body}${argsLine}`;
1111
1293
  abortTurn(tab);
1112
1294
  cancelPendingGates(tab);
1113
1295
  tab.currentSession = mintSessionFor(tab.rootDir);
1296
+ persistOpenTabs();
1114
1297
  if (tab.runtime) tab.runtime = buildRuntimeFor(tab);
1115
1298
  emitSessions(tab);
1116
1299
  return;
@@ -1119,6 +1302,10 @@ ${found.body}${argsLine}`;
1119
1302
  emitSettings(tab);
1120
1303
  return;
1121
1304
  }
1305
+ if (msg.cmd === "qq_status_get") {
1306
+ emitQQSettings(tab);
1307
+ return;
1308
+ }
1122
1309
  if (msg.cmd === "settings_save") {
1123
1310
  try {
1124
1311
  if (msg.reasoningEffort !== void 0) {
@@ -1158,6 +1345,68 @@ ${found.body}${argsLine}`;
1158
1345
  }
1159
1346
  return;
1160
1347
  }
1348
+ if (msg.cmd === "qq_config_save") {
1349
+ try {
1350
+ saveDesktopQQSettings(
1351
+ {
1352
+ appId: msg.appId,
1353
+ appSecret: msg.appSecret,
1354
+ sandbox: msg.sandbox
1355
+ },
1356
+ void 0
1357
+ );
1358
+ emitQQSettings(tab);
1359
+ } catch (err) {
1360
+ emit(
1361
+ { type: "$error", message: `qq_config_save failed: ${err.message}` },
1362
+ tab.id
1363
+ );
1364
+ }
1365
+ return;
1366
+ }
1367
+ if (msg.cmd === "qq_connect") {
1368
+ try {
1369
+ const current = loadQQConfig();
1370
+ setDesktopQQEnabled(true);
1371
+ emit(
1372
+ {
1373
+ type: "status",
1374
+ id: Date.now(),
1375
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
1376
+ turn: 0,
1377
+ text: `QQ enabled for CLI (${current.sandbox ? "sandbox" : "production"}) \u2014 start the bot by running \`reasonix\` in a terminal`
1378
+ },
1379
+ tab.id
1380
+ );
1381
+ emitQQSettings(tab);
1382
+ } catch (err) {
1383
+ emit({ type: "$error", message: `qq_connect failed: ${err.message}` }, tab.id);
1384
+ emitQQSettings(tab);
1385
+ }
1386
+ return;
1387
+ }
1388
+ if (msg.cmd === "qq_disconnect") {
1389
+ 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)"
1398
+ },
1399
+ tab.id
1400
+ );
1401
+ emitQQSettings(tab);
1402
+ } catch (err) {
1403
+ emit(
1404
+ { type: "$error", message: `qq_disconnect failed: ${err.message}` },
1405
+ tab.id
1406
+ );
1407
+ }
1408
+ return;
1409
+ }
1161
1410
  if (msg.cmd === "mention_query") {
1162
1411
  const nonce = msg.nonce;
1163
1412
  const query = msg.query;
@@ -1230,6 +1479,42 @@ ${found.body}${argsLine}`;
1230
1479
  });
1231
1480
  return;
1232
1481
  }
1482
+ if (msg.cmd === "compact_history") {
1483
+ if (!tab.runtime) return;
1484
+ void tab.runtime.loop.compactHistory().catch((err) => {
1485
+ emit({ type: "$error", message: `/compact failed: ${err.message}` }, tab.id);
1486
+ });
1487
+ return;
1488
+ }
1489
+ if (msg.cmd === "retry") {
1490
+ if (!tab.runtime) return;
1491
+ const prev = tab.runtime.loop.retryLastUser();
1492
+ if (prev) {
1493
+ emit({ type: "$retry_result", text: prev }, tab.id);
1494
+ }
1495
+ return;
1496
+ }
1497
+ if (msg.cmd === "btw") {
1498
+ if (!tab.runtime) return;
1499
+ const question = msg.text.trim();
1500
+ if (!question) return;
1501
+ void (async () => {
1502
+ try {
1503
+ const reply = await tab.runtime.loop.client.chat({
1504
+ model: tab.currentModel,
1505
+ messages: [
1506
+ { role: "system", content: tab.system },
1507
+ { role: "user", content: question }
1508
+ ]
1509
+ });
1510
+ const answer = (typeof reply.content === "string" ? reply.content.trim() : "") || "(no answer)";
1511
+ emit({ type: "$btw_result", question, answer }, tab.id);
1512
+ } catch (err) {
1513
+ emit({ type: "$error", message: `/btw failed: ${err.message}` }, tab.id);
1514
+ }
1515
+ })();
1516
+ return;
1517
+ }
1233
1518
  if (msg.cmd === "user_input") {
1234
1519
  if (!tab.runtime) {
1235
1520
  emit(
@@ -1252,4 +1537,4 @@ export {
1252
1537
  desktopCommand,
1253
1538
  installDesktopCrashGuards
1254
1539
  };
1255
- //# sourceMappingURL=desktop-5ONTRU3C.js.map
1540
+ //# sourceMappingURL=desktop-EG6P5SF2.js.map