reasonix 0.43.0 → 0.44.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 (169) hide show
  1. package/README.md +49 -11
  2. package/README.zh-CN.md +35 -7
  3. package/dashboard/app.css +225 -4
  4. package/dashboard/dist/app.js +6441 -6080
  5. package/dashboard/dist/app.js.map +1 -1
  6. package/data/deepseek-tokenizer.json.gz +0 -0
  7. package/dist/cli/{acp-DAGPCVFZ.js → acp-TYZ2CTDL.js} +28 -30
  8. package/dist/cli/acp-TYZ2CTDL.js.map +1 -0
  9. package/dist/cli/chat-TH7VNNCJ.js +51 -0
  10. package/dist/cli/chunk-2425HK6U.js +0 -0
  11. package/dist/cli/chunk-25T6CVUP.js +0 -0
  12. package/dist/cli/chunk-2UQP6H6T.js +0 -0
  13. package/dist/cli/{chunk-3Z6IBU3D.js → chunk-2V6EAEUW.js} +95 -31
  14. package/dist/cli/chunk-2V6EAEUW.js.map +1 -0
  15. package/dist/cli/{chunk-XCGGEJTI.js → chunk-4CTDEJUF.js} +2 -2
  16. package/dist/cli/chunk-4QUNBQQ2.js +0 -0
  17. package/dist/cli/{chunk-74EX7SUH.js → chunk-5QCB62C4.js} +33 -7
  18. package/dist/cli/{chunk-74EX7SUH.js.map → chunk-5QCB62C4.js.map} +1 -1
  19. package/dist/cli/chunk-6OWJV3YW.js +390 -0
  20. package/dist/cli/chunk-6OWJV3YW.js.map +1 -0
  21. package/dist/cli/chunk-6PBZN4VI.js +0 -0
  22. package/dist/cli/{chunk-7O5ALB4C.js → chunk-7CIGMZT3.js} +2 -2
  23. package/dist/cli/{chunk-H6PS7IUE.js → chunk-7UCMM425.js} +7 -3
  24. package/dist/cli/chunk-7UCMM425.js.map +1 -0
  25. package/dist/cli/{chunk-TJX6BFZZ.js → chunk-AB2RED3C.js} +3 -3
  26. package/dist/cli/{chunk-XPDVG52A.js → chunk-AVFXO2EZ.js} +361 -13
  27. package/dist/cli/chunk-AVFXO2EZ.js.map +1 -0
  28. package/dist/cli/{chunk-FHOGSSCH.js → chunk-C53JQES5.js} +3 -3
  29. package/dist/cli/{chunk-RE4RAVFF.js → chunk-CGDR2ELH.js} +92 -30
  30. package/dist/cli/chunk-CGDR2ELH.js.map +1 -0
  31. package/dist/cli/{chunk-OSZC7C6F.js → chunk-CWZKQ5FE.js} +7 -4
  32. package/dist/cli/chunk-CWZKQ5FE.js.map +1 -0
  33. package/dist/cli/{devtools-YECO25QO.js → chunk-FEZK652I.js} +10 -85
  34. package/dist/cli/chunk-FEZK652I.js.map +1 -0
  35. package/dist/cli/{chunk-45U62RI3.js → chunk-HNXDZGC6.js} +104 -2
  36. package/dist/cli/chunk-HNXDZGC6.js.map +1 -0
  37. package/dist/cli/chunk-J5XJHLWM.js +0 -0
  38. package/dist/cli/chunk-JMBMLOBP.js +0 -0
  39. package/dist/cli/{chunk-5JJRUIPA.js → chunk-JNAQYELD.js} +16 -8
  40. package/dist/cli/{chunk-5JJRUIPA.js.map → chunk-JNAQYELD.js.map} +1 -1
  41. package/dist/cli/{chunk-YFGF5NKA.js → chunk-KGBG6M2X.js} +19 -15
  42. package/dist/cli/chunk-KGBG6M2X.js.map +1 -0
  43. package/dist/cli/{chunk-3BXRZFWS.js → chunk-KLQTAZIY.js} +12 -4
  44. package/dist/cli/chunk-KLQTAZIY.js.map +1 -0
  45. package/dist/cli/{chunk-VK5HG73G.js → chunk-KM465GST.js} +9 -9
  46. package/dist/cli/{chunk-DOYHN4KB.js → chunk-LIR2HBQH.js} +2 -2
  47. package/dist/cli/{chunk-YYQAUTTN.js → chunk-MJ6W5UN3.js} +2 -2
  48. package/dist/cli/{chunk-6PZ3CXBP.js → chunk-MRHHQJAQ.js} +5 -4
  49. package/dist/cli/chunk-MRHHQJAQ.js.map +1 -0
  50. package/dist/cli/{chunk-PQXPXJBJ.js → chunk-NVURFF27.js} +16 -5
  51. package/dist/cli/chunk-NVURFF27.js.map +1 -0
  52. package/dist/cli/{chunk-2R4QCDOZ.js → chunk-OPFUUYHL.js} +540 -287
  53. package/dist/cli/chunk-OPFUUYHL.js.map +1 -0
  54. package/dist/cli/chunk-PLHAZOLZ.js +0 -0
  55. package/dist/cli/{chunk-HFEAY5DT.js → chunk-R3CTO2HM.js} +2 -2
  56. package/dist/cli/{chunk-O52OLQL3.js → chunk-RDRC3XDT.js} +136 -38
  57. package/dist/cli/chunk-RDRC3XDT.js.map +1 -0
  58. package/dist/cli/chunk-S4XVGLRW.js +0 -0
  59. package/dist/cli/chunk-SZ5XES2N.js +0 -0
  60. package/dist/cli/{chunk-2K65GZBT.js → chunk-TEUDEGX2.js} +64 -19
  61. package/dist/cli/chunk-TEUDEGX2.js.map +1 -0
  62. package/dist/cli/{chunk-2Z35JOA4.js → chunk-TKVXTQ3T.js} +4 -4
  63. package/dist/cli/{chunk-2Z35JOA4.js.map → chunk-TKVXTQ3T.js.map} +1 -1
  64. package/dist/cli/chunk-TUK7OWJA.js +0 -0
  65. package/dist/cli/{chunk-32TIKD5U.js → chunk-TXJMRPIL.js} +3 -3
  66. package/dist/cli/{chunk-2KDUS647.js → chunk-V26WPN3J.js} +7 -4
  67. package/dist/cli/chunk-V26WPN3J.js.map +1 -0
  68. package/dist/cli/{chunk-F3PXYSNN.js → chunk-WK3UFQY3.js} +2 -2
  69. package/dist/cli/{chunk-6G3CUUFG.js → chunk-X53B3JIX.js} +3 -3
  70. package/dist/cli/{chunk-6G3CUUFG.js.map → chunk-X53B3JIX.js.map} +1 -1
  71. package/dist/cli/chunk-XJXDHAES.js +0 -0
  72. package/dist/cli/{chunk-6AK4EY3D.js → chunk-XSU4QVFW.js} +1 -81
  73. package/dist/cli/chunk-XSU4QVFW.js.map +1 -0
  74. package/dist/cli/chunk-XXC2BYTV.js +0 -0
  75. package/dist/cli/{chunk-P7EKE5ZQ.js → chunk-Z4S7EYXG.js} +4482 -1310
  76. package/dist/cli/chunk-Z4S7EYXG.js.map +1 -0
  77. package/dist/cli/chunk-ZZM6QJ4W.js +0 -0
  78. package/dist/cli/{chunk-YQ6NTIIE.js → chunk-ZZYBBX5N.js} +13 -5
  79. package/dist/cli/chunk-ZZYBBX5N.js.map +1 -0
  80. package/dist/cli/{code-SMKEW6CD.js → code-PSVJ3KEN.js} +48 -36
  81. package/dist/cli/code-PSVJ3KEN.js.map +1 -0
  82. package/dist/cli/{commands-FVVB5FZF.js → commands-OCU42XG4.js} +4 -4
  83. package/dist/cli/{commit-HE4VSPZ7.js → commit-XCQIQCYG.js} +3 -3
  84. package/dist/cli/{desktop-Q7NDXCON.js → desktop-KWGR4BNE.js} +210 -69
  85. package/dist/cli/desktop-KWGR4BNE.js.map +1 -0
  86. package/dist/cli/devtools-HW3WDT3Q.js +91 -0
  87. package/dist/cli/devtools-HW3WDT3Q.js.map +1 -0
  88. package/dist/cli/{diff-435UTPC5.js → diff-NHANTNC3.js} +9 -9
  89. package/dist/cli/{doctor-OT7KH75K.js → doctor-CC5CLOGG.js} +10 -10
  90. package/dist/cli/events-XEFAD5VX.js +0 -0
  91. package/dist/cli/index.js +132 -94
  92. package/dist/cli/index.js.map +1 -1
  93. package/dist/cli/{mcp-WUL2WO75.js → mcp-MPVGBBJF.js} +2 -2
  94. package/dist/cli/{mcp-browse-RR7R4XET.js → mcp-browse-4XOTC3FJ.js} +3 -3
  95. package/dist/cli/{mcp-inspect-REGLYBWT.js → mcp-inspect-CEMGKKAH.js} +14 -9
  96. package/dist/cli/mcp-inspect-CEMGKKAH.js.map +1 -0
  97. package/dist/cli/{prompt-UW6EFLVR.js → prompt-2D7ID24X.js} +4 -4
  98. package/dist/cli/prune-sessions-3RWUBYRS.js +0 -0
  99. package/dist/cli/{replay-YOURXV4C.js → replay-SR44E6RS.js} +10 -10
  100. package/dist/cli/{run-Q6BUXV66.js → run-MDGL27WL.js} +35 -36
  101. package/dist/cli/run-MDGL27WL.js.map +1 -0
  102. package/dist/cli/{server-XGDBRWMB.js → server-27ARQXIZ.js} +67 -24
  103. package/dist/cli/server-27ARQXIZ.js.map +1 -0
  104. package/dist/cli/{sessions-FH7QVYSY.js → sessions-CKQXCYGP.js} +18 -18
  105. package/dist/cli/sessions-CKQXCYGP.js.map +1 -0
  106. package/dist/cli/{setup-VDS6SVEP.js → setup-TPAGSVXO.js} +6 -6
  107. package/dist/cli/{stats-MQVI2XQH.js → stats-DPUBZNVX.js} +6 -4
  108. package/dist/cli/update-6ITLPRDV.js +0 -0
  109. package/dist/cli/{version-DAHGZY5N.js → version-2X3BHVVK.js} +15 -15
  110. package/dist/index.d.ts +181 -53
  111. package/dist/index.js +1322 -533
  112. package/dist/index.js.map +1 -1
  113. package/package.json +21 -8
  114. package/dist/cli/.-3G6VX5S7.js +0 -327
  115. package/dist/cli/.-6YRPB2C7.js +0 -329
  116. package/dist/cli/.-EYSVINK3.js +0 -317
  117. package/dist/cli/acp-DAGPCVFZ.js.map +0 -1
  118. package/dist/cli/chat-7ES4IBNH.js +0 -50
  119. package/dist/cli/chunk-2K65GZBT.js.map +0 -1
  120. package/dist/cli/chunk-2KDUS647.js.map +0 -1
  121. package/dist/cli/chunk-2R4QCDOZ.js.map +0 -1
  122. package/dist/cli/chunk-3BXRZFWS.js.map +0 -1
  123. package/dist/cli/chunk-3Z6IBU3D.js.map +0 -1
  124. package/dist/cli/chunk-45U62RI3.js.map +0 -1
  125. package/dist/cli/chunk-6AK4EY3D.js.map +0 -1
  126. package/dist/cli/chunk-6PZ3CXBP.js.map +0 -1
  127. package/dist/cli/chunk-H6PS7IUE.js.map +0 -1
  128. package/dist/cli/chunk-O52OLQL3.js.map +0 -1
  129. package/dist/cli/chunk-OSZC7C6F.js.map +0 -1
  130. package/dist/cli/chunk-P7EKE5ZQ.js.map +0 -1
  131. package/dist/cli/chunk-PQXPXJBJ.js.map +0 -1
  132. package/dist/cli/chunk-PV55UMTO.js +0 -200
  133. package/dist/cli/chunk-PV55UMTO.js.map +0 -1
  134. package/dist/cli/chunk-RE4RAVFF.js.map +0 -1
  135. package/dist/cli/chunk-XPDVG52A.js.map +0 -1
  136. package/dist/cli/chunk-YFGF5NKA.js.map +0 -1
  137. package/dist/cli/chunk-YQ6NTIIE.js.map +0 -1
  138. package/dist/cli/code-SMKEW6CD.js.map +0 -1
  139. package/dist/cli/desktop-Q7NDXCON.js.map +0 -1
  140. package/dist/cli/devtools-YECO25QO.js.map +0 -1
  141. package/dist/cli/doctor-OT7KH75K.js.map +0 -1
  142. package/dist/cli/mcp-inspect-REGLYBWT.js.map +0 -1
  143. package/dist/cli/prompt-UW6EFLVR.js.map +0 -1
  144. package/dist/cli/run-Q6BUXV66.js.map +0 -1
  145. package/dist/cli/server-XGDBRWMB.js.map +0 -1
  146. package/dist/cli/sessions-FH7QVYSY.js.map +0 -1
  147. package/dist/cli/stats-MQVI2XQH.js.map +0 -1
  148. /package/dist/cli/{.-3G6VX5S7.js.map → chat-TH7VNNCJ.js.map} +0 -0
  149. /package/dist/cli/{chunk-XCGGEJTI.js.map → chunk-4CTDEJUF.js.map} +0 -0
  150. /package/dist/cli/{chunk-7O5ALB4C.js.map → chunk-7CIGMZT3.js.map} +0 -0
  151. /package/dist/cli/{chunk-TJX6BFZZ.js.map → chunk-AB2RED3C.js.map} +0 -0
  152. /package/dist/cli/{chunk-FHOGSSCH.js.map → chunk-C53JQES5.js.map} +0 -0
  153. /package/dist/cli/{chunk-VK5HG73G.js.map → chunk-KM465GST.js.map} +0 -0
  154. /package/dist/cli/{chunk-DOYHN4KB.js.map → chunk-LIR2HBQH.js.map} +0 -0
  155. /package/dist/cli/{chunk-YYQAUTTN.js.map → chunk-MJ6W5UN3.js.map} +0 -0
  156. /package/dist/cli/{chunk-HFEAY5DT.js.map → chunk-R3CTO2HM.js.map} +0 -0
  157. /package/dist/cli/{chunk-32TIKD5U.js.map → chunk-TXJMRPIL.js.map} +0 -0
  158. /package/dist/cli/{chunk-F3PXYSNN.js.map → chunk-WK3UFQY3.js.map} +0 -0
  159. /package/dist/cli/{commands-FVVB5FZF.js.map → commands-OCU42XG4.js.map} +0 -0
  160. /package/dist/cli/{commit-HE4VSPZ7.js.map → commit-XCQIQCYG.js.map} +0 -0
  161. /package/dist/cli/{diff-435UTPC5.js.map → diff-NHANTNC3.js.map} +0 -0
  162. /package/dist/cli/{.-6YRPB2C7.js.map → doctor-CC5CLOGG.js.map} +0 -0
  163. /package/dist/cli/{mcp-WUL2WO75.js.map → mcp-MPVGBBJF.js.map} +0 -0
  164. /package/dist/cli/{mcp-browse-RR7R4XET.js.map → mcp-browse-4XOTC3FJ.js.map} +0 -0
  165. /package/dist/cli/{.-EYSVINK3.js.map → prompt-2D7ID24X.js.map} +0 -0
  166. /package/dist/cli/{replay-YOURXV4C.js.map → replay-SR44E6RS.js.map} +0 -0
  167. /package/dist/cli/{setup-VDS6SVEP.js.map → setup-TPAGSVXO.js.map} +0 -0
  168. /package/dist/cli/{chat-7ES4IBNH.js.map → stats-DPUBZNVX.js.map} +0 -0
  169. /package/dist/cli/{version-DAHGZY5N.js.map → version-2X3BHVVK.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-3Z6IBU3D.js";
5
+ } from "./chunk-2V6EAEUW.js";
6
6
  import {
7
7
  buildCodeToolset
8
- } from "./chunk-YFGF5NKA.js";
8
+ } from "./chunk-KGBG6M2X.js";
9
9
  import {
10
10
  Eventizer,
11
11
  autoResolveVerdict
12
- } from "./chunk-45U62RI3.js";
13
- import "./chunk-H6PS7IUE.js";
14
- import "./chunk-PQXPXJBJ.js";
12
+ } from "./chunk-HNXDZGC6.js";
13
+ import "./chunk-7UCMM425.js";
14
+ import "./chunk-NVURFF27.js";
15
15
  import {
16
16
  CacheFirstLoop,
17
17
  ImmutablePrefix,
@@ -19,41 +19,39 @@ import {
19
19
  listFilesWithStatsAsync,
20
20
  parseAtQuery,
21
21
  rankPickerCandidates
22
- } from "./chunk-2R4QCDOZ.js";
23
- import "./chunk-F3PXYSNN.js";
24
- import "./chunk-FHOGSSCH.js";
25
- import {
26
- parseMcpSpec
27
- } from "./chunk-6AK4EY3D.js";
22
+ } from "./chunk-OPFUUYHL.js";
23
+ import "./chunk-WK3UFQY3.js";
24
+ import "./chunk-C53JQES5.js";
25
+ import "./chunk-XSU4QVFW.js";
28
26
  import {
29
27
  MemoryStore,
30
28
  codeSystemPrompt
31
- } from "./chunk-5JJRUIPA.js";
29
+ } from "./chunk-JNAQYELD.js";
32
30
  import {
33
31
  canonicalPresetName,
34
32
  resolvePreset
35
33
  } from "./chunk-2425HK6U.js";
36
34
  import {
37
- countTokens
38
- } from "./chunk-PV55UMTO.js";
35
+ countTokensBounded
36
+ } from "./chunk-6OWJV3YW.js";
39
37
  import {
40
38
  DeepSeekClient,
41
39
  pickPrimaryBalance
42
- } from "./chunk-2KDUS647.js";
40
+ } from "./chunk-V26WPN3J.js";
43
41
  import "./chunk-25T6CVUP.js";
44
42
  import {
45
43
  loadDotenv
46
44
  } from "./chunk-2UQP6H6T.js";
47
- import "./chunk-YYQAUTTN.js";
45
+ import "./chunk-MJ6W5UN3.js";
48
46
  import {
49
47
  pauseGate
50
- } from "./chunk-O52OLQL3.js";
48
+ } from "./chunk-RDRC3XDT.js";
51
49
  import {
52
50
  SkillStore
53
- } from "./chunk-2K65GZBT.js";
51
+ } from "./chunk-TEUDEGX2.js";
54
52
  import "./chunk-PLHAZOLZ.js";
55
- import "./chunk-XCGGEJTI.js";
56
- import "./chunk-7O5ALB4C.js";
53
+ import "./chunk-4CTDEJUF.js";
54
+ import "./chunk-7CIGMZT3.js";
57
55
  import "./chunk-S4XVGLRW.js";
58
56
  import {
59
57
  deleteSession,
@@ -63,30 +61,34 @@ import {
63
61
  patchSessionMeta,
64
62
  timestampSuffix
65
63
  } from "./chunk-6PBZN4VI.js";
66
- import "./chunk-RE4RAVFF.js";
64
+ import "./chunk-R3CTO2HM.js";
65
+ import "./chunk-ZZYBBX5N.js";
66
+ import "./chunk-CGDR2ELH.js";
67
67
  import {
68
68
  isPlausibleKey,
69
69
  loadApiKey,
70
70
  loadBaseUrl,
71
+ loadDesktopOpenTabs,
71
72
  loadEditMode,
72
73
  loadEditor,
73
74
  loadPreset,
74
75
  loadReasoningEffort,
75
76
  loadRecentWorkspaces,
77
+ loadResolvedSkillPaths,
76
78
  loadWorkspaceDir,
79
+ parseMcpSpec,
77
80
  pushRecentWorkspace,
78
81
  readConfig,
79
82
  saveApiKey,
80
83
  saveBaseUrl,
84
+ saveDesktopOpenTabs,
81
85
  saveEditMode,
82
86
  saveEditor,
83
87
  savePreset,
84
88
  saveReasoningEffort,
85
89
  saveWorkspaceDir,
86
90
  writeConfig
87
- } from "./chunk-XPDVG52A.js";
88
- import "./chunk-HFEAY5DT.js";
89
- import "./chunk-YQ6NTIIE.js";
91
+ } from "./chunk-AVFXO2EZ.js";
90
92
  import {
91
93
  VERSION
92
94
  } from "./chunk-XXC2BYTV.js";
@@ -104,6 +106,11 @@ function emit(ev, tabId) {
104
106
  writeSync(1, Buffer.from(`${JSON.stringify(payload)}
105
107
  `, "utf8"));
106
108
  }
109
+ function tailLines(s, n) {
110
+ if (!s) return "";
111
+ const lines = s.split(/\r?\n/);
112
+ return lines.slice(-n).join("\n");
113
+ }
107
114
  function buildLoadedMessages(records) {
108
115
  const out = [];
109
116
  let turn = 0;
@@ -260,15 +267,18 @@ function emitMemory(tab) {
260
267
  function emitCtxBreakdown(tab) {
261
268
  if (!tab.runtime) return;
262
269
  try {
263
- const sys = countTokens(tab.runtime.loop.prefix.system);
264
- const tools = countTokens(JSON.stringify(tab.runtime.loop.prefix.toolSpecs));
270
+ const sys = countTokensBounded(tab.runtime.loop.prefix.system);
271
+ const tools = countTokensBounded(JSON.stringify(tab.runtime.loop.prefix.toolSpecs));
265
272
  emit({ type: "$ctx_breakdown", reservedTokens: sys + tools }, tab.id);
266
273
  } catch {
267
274
  }
268
275
  }
269
276
  function emitSkills(tab) {
270
277
  try {
271
- const store = new SkillStore({ projectRoot: tab.rootDir });
278
+ const store = new SkillStore({
279
+ projectRoot: tab.rootDir,
280
+ customSkillPaths: loadResolvedSkillPaths(tab.rootDir)
281
+ });
272
282
  const items = store.list().map((s) => ({
273
283
  name: s.name,
274
284
  description: s.description,
@@ -392,8 +402,20 @@ function pushMentionRecent(tab, path) {
392
402
  tab.recentMentions.unshift(path);
393
403
  if (tab.recentMentions.length > MAX) tab.recentMentions.length = MAX;
394
404
  }
405
+ function installDesktopCrashGuards(stderr = process.stderr) {
406
+ process.on("unhandledRejection", (reason) => {
407
+ const err = reason instanceof Error ? reason : new Error(String(reason));
408
+ stderr.write(`[desktop] unhandledRejection: ${err.stack ?? err.message}
409
+ `);
410
+ });
411
+ process.on("uncaughtException", (err) => {
412
+ stderr.write(`[desktop] uncaughtException: ${err.stack ?? err.message}
413
+ `);
414
+ });
415
+ }
395
416
  async function desktopCommand(opts) {
396
417
  loadDotenv();
418
+ installDesktopCrashGuards();
397
419
  const tabs = /* @__PURE__ */ new Map();
398
420
  const tabContext = new AsyncLocalStorage();
399
421
  function activeRunningTab() {
@@ -434,7 +456,11 @@ async function desktopCommand(opts) {
434
456
  return tab;
435
457
  }
436
458
  async function initTabToolset(tab) {
437
- const toolset = await buildCodeToolset({ rootDir: tab.rootDir });
459
+ const toolset = await buildCodeToolset({
460
+ rootDir: tab.rootDir,
461
+ onSkillInstalled: () => emitSkills(tab),
462
+ onJobsChanged: () => emitJobs()
463
+ });
438
464
  tab.toolset = toolset;
439
465
  tab.system = codeSystemPrompt(tab.rootDir, {
440
466
  hasSemanticSearch: toolset.semantic.enabled,
@@ -491,8 +517,14 @@ async function desktopCommand(opts) {
491
517
  emit({ type: "$error", message: `mcp bridge failed: ${err.message}` }, tab.id);
492
518
  });
493
519
  }
520
+ function persistOpenTabs() {
521
+ try {
522
+ saveDesktopOpenTabs(Array.from(tabs.values()).map((t) => t.rootDir));
523
+ } catch {
524
+ }
525
+ }
494
526
  async function closeTab(tab) {
495
- tab.aborter?.abort();
527
+ abortTurn(tab);
496
528
  try {
497
529
  await tab.toolset?.jobs.shutdown();
498
530
  } catch {
@@ -504,6 +536,11 @@ async function desktopCommand(opts) {
504
536
  }
505
537
  }
506
538
  tabs.delete(tab.id);
539
+ if (first && first.id === tab.id) {
540
+ const next = tabs.values().next().value;
541
+ if (next) first = next;
542
+ }
543
+ persistOpenTabs();
507
544
  emit({ type: "$tab_closed" }, tab.id);
508
545
  }
509
546
  async function runTurn(tab, text) {
@@ -557,7 +594,7 @@ async function desktopCommand(opts) {
557
594
  emitSettings(tab);
558
595
  return;
559
596
  }
560
- tab.aborter?.abort();
597
+ abortTurn(tab);
561
598
  try {
562
599
  await tab.toolset?.jobs.shutdown();
563
600
  } catch {
@@ -572,7 +609,11 @@ async function desktopCommand(opts) {
572
609
  tab.symbolBuilding = null;
573
610
  tab.recentMentions.length = 0;
574
611
  tab.currentSession = mintSessionFor(target);
575
- tab.toolset = await buildCodeToolset({ rootDir: target });
612
+ tab.toolset = await buildCodeToolset({
613
+ rootDir: target,
614
+ onSkillInstalled: () => emitSkills(tab),
615
+ onJobsChanged: () => emitJobs()
616
+ });
576
617
  tab.system = codeSystemPrompt(target, {
577
618
  hasSemanticSearch: tab.toolset.semantic.enabled,
578
619
  modelId: tab.currentModel
@@ -588,6 +629,69 @@ async function desktopCommand(opts) {
588
629
  }
589
630
  return void 0;
590
631
  }
632
+ function abortTurn(tab) {
633
+ tab.aborter?.abort();
634
+ tab.runtime?.loop.abort();
635
+ }
636
+ function tabSessionLabel(tab) {
637
+ if (tab.currentSession) {
638
+ try {
639
+ const summary = loadSessionMeta(tab.currentSession).summary?.trim();
640
+ if (summary) return summary;
641
+ } catch {
642
+ }
643
+ }
644
+ return tab.rootDir.split(/[\\/]/).filter(Boolean).pop() ?? tab.rootDir;
645
+ }
646
+ function emitJobs() {
647
+ const items = [];
648
+ for (const t of tabs.values()) {
649
+ const reg = t.toolset?.jobs;
650
+ if (!reg) continue;
651
+ const label = tabSessionLabel(t);
652
+ for (const j of reg.list()) {
653
+ items.push({
654
+ id: j.id,
655
+ tabId: t.id,
656
+ sessionLabel: label,
657
+ command: j.command,
658
+ pid: j.pid,
659
+ running: j.running,
660
+ exitCode: j.exitCode,
661
+ startedAt: j.startedAt,
662
+ outputTail: tailLines(j.output, 8),
663
+ spawnError: j.spawnError
664
+ });
665
+ }
666
+ }
667
+ items.sort((a, b) => {
668
+ if (a.running !== b.running) return a.running ? -1 : 1;
669
+ return b.startedAt - a.startedAt;
670
+ });
671
+ emit({ type: "$jobs", items });
672
+ }
673
+ async function stopJob(jobId) {
674
+ for (const t of tabs.values()) {
675
+ const reg = t.toolset?.jobs;
676
+ if (!reg) continue;
677
+ const hit = reg.list().find((j) => j.id === jobId);
678
+ if (!hit) continue;
679
+ await reg.stop(jobId);
680
+ return true;
681
+ }
682
+ return false;
683
+ }
684
+ async function stopAllJobs() {
685
+ const ops = [];
686
+ for (const t of tabs.values()) {
687
+ const reg = t.toolset?.jobs;
688
+ if (!reg) continue;
689
+ for (const j of reg.list()) {
690
+ if (j.running) ops.push(reg.stop(j.id));
691
+ }
692
+ }
693
+ await Promise.allSettled(ops);
694
+ }
591
695
  function cancelPendingGates(tab) {
592
696
  const hadActivePlan = tab.planTotalSteps > 0 || tab.completedStepIds.size > 0;
593
697
  const ids = [...tab.pendingGateIds];
@@ -599,9 +703,21 @@ async function desktopCommand(opts) {
599
703
  emit({ type: "$plan_cleared" }, tab.id);
600
704
  }
601
705
  }
602
- const first = createTabSkeleton();
603
- process.once("exit", () => {
604
- for (const t of tabs.values()) void t.toolset?.jobs.shutdown();
706
+ let first;
707
+ let shuttingDown = false;
708
+ async function gracefulShutdown() {
709
+ if (shuttingDown) return;
710
+ shuttingDown = true;
711
+ await Promise.allSettled(
712
+ [...tabs.values()].map((t) => t.toolset?.jobs.shutdown(1500) ?? Promise.resolve())
713
+ );
714
+ process.exit(0);
715
+ }
716
+ process.on("SIGTERM", () => {
717
+ void gracefulShutdown();
718
+ });
719
+ process.on("SIGINT", () => {
720
+ void gracefulShutdown();
605
721
  });
606
722
  pauseGate.on((req) => {
607
723
  const tab = activeRunningTab();
@@ -733,20 +849,37 @@ async function desktopCommand(opts) {
733
849
  if (tab) tab.pendingGateIds.delete(req.id);
734
850
  pauseGate.cancel(req.id);
735
851
  });
736
- emit({ type: "$tab_opened", workspaceDir: first.rootDir }, first.id);
737
- emitSessions(first);
738
- emitSettings(first);
739
- emitMcpSpecs(first);
740
- emitSkills(first);
741
- emitMemory(first);
742
- if (!loadApiKey()) emit({ type: "$needs_setup", reason: "no_api_key" }, first.id);
743
- void emitBalance(first);
744
- void initTabToolset(first).then(() => {
745
- if (loadApiKey()) emit({ type: "$ready" }, first.id);
746
- emitCtxBreakdown(first);
747
- }).catch((err) => {
748
- emit({ type: "$error", message: `init failed: ${err.message}` }, first.id);
852
+ function bootstrapTab(initialDir) {
853
+ const tab = createTabSkeleton(initialDir);
854
+ emit({ type: "$tab_opened", workspaceDir: tab.rootDir }, tab.id);
855
+ emitSessions(tab);
856
+ emitSettings(tab);
857
+ emitMcpSpecs(tab);
858
+ emitSkills(tab);
859
+ emitMemory(tab);
860
+ if (!loadApiKey()) emit({ type: "$needs_setup", reason: "no_api_key" }, tab.id);
861
+ void emitBalance(tab);
862
+ void initTabToolset(tab).then(() => {
863
+ if (loadApiKey()) emit({ type: "$ready" }, tab.id);
864
+ emitCtxBreakdown(tab);
865
+ }).catch((err) => {
866
+ emit({ type: "$error", message: `init failed: ${err.message}` }, tab.id);
867
+ });
868
+ return tab;
869
+ }
870
+ const savedTabDirs = opts.dir ? [] : loadDesktopOpenTabs().filter((d) => {
871
+ try {
872
+ return existsSync(d) && statSync(d).isDirectory();
873
+ } catch {
874
+ return false;
875
+ }
749
876
  });
877
+ first = bootstrapTab(savedTabDirs[0]);
878
+ for (const d of savedTabDirs.slice(1)) {
879
+ if (resolve(d) === first.rootDir) continue;
880
+ bootstrapTab(d);
881
+ }
882
+ persistOpenTabs();
750
883
  const rl = createInterface({ input: stdin });
751
884
  rl.on("line", (line) => {
752
885
  const trimmed = line.trim();
@@ -760,21 +893,8 @@ async function desktopCommand(opts) {
760
893
  }
761
894
  if (msg.cmd === "tab_open") {
762
895
  try {
763
- const tab2 = createTabSkeleton(msg.workspaceDir);
764
- emit({ type: "$tab_opened", workspaceDir: tab2.rootDir }, tab2.id);
765
- emitSessions(tab2);
766
- emitSettings(tab2);
767
- emitMcpSpecs(tab2);
768
- emitSkills(tab2);
769
- emitMemory(tab2);
770
- if (!loadApiKey()) emit({ type: "$needs_setup", reason: "no_api_key" }, tab2.id);
771
- void emitBalance(tab2);
772
- void initTabToolset(tab2).then(() => {
773
- if (loadApiKey()) emit({ type: "$ready" }, tab2.id);
774
- emitCtxBreakdown(tab2);
775
- }).catch((err) => {
776
- emit({ type: "$error", message: `init failed: ${err.message}` }, tab2.id);
777
- });
896
+ bootstrapTab(msg.workspaceDir);
897
+ persistOpenTabs();
778
898
  } catch (err) {
779
899
  emit({ type: "$error", message: `tab_open failed: ${err.message}` });
780
900
  }
@@ -843,13 +963,25 @@ async function desktopCommand(opts) {
843
963
  }
844
964
  return;
845
965
  }
966
+ if (msg.cmd === "jobs_list") {
967
+ emitJobs();
968
+ return;
969
+ }
970
+ if (msg.cmd === "jobs_stop") {
971
+ void stopJob(msg.jobId).finally(() => emitJobs());
972
+ return;
973
+ }
974
+ if (msg.cmd === "jobs_stop_all") {
975
+ void stopAllJobs().finally(() => emitJobs());
976
+ return;
977
+ }
846
978
  const tab = msg.tabId ? tabs.get(msg.tabId) : first;
847
979
  if (!tab) {
848
980
  emit({ type: "$error", message: `unknown tab: ${msg.tabId}` });
849
981
  return;
850
982
  }
851
983
  if (msg.cmd === "abort") {
852
- tab.aborter?.abort();
984
+ abortTurn(tab);
853
985
  cancelPendingGates(tab);
854
986
  return;
855
987
  }
@@ -916,7 +1048,10 @@ async function desktopCommand(opts) {
916
1048
  return;
917
1049
  }
918
1050
  try {
919
- const store = new SkillStore({ projectRoot: tab.rootDir });
1051
+ const store = new SkillStore({
1052
+ projectRoot: tab.rootDir,
1053
+ customSkillPaths: loadResolvedSkillPaths(tab.rootDir)
1054
+ });
920
1055
  const found = store.read(msg.name);
921
1056
  if (!found) {
922
1057
  emit({ type: "$error", message: `skill not found: ${msg.name}` }, tab.id);
@@ -950,7 +1085,7 @@ ${found.body}${argsLine}`;
950
1085
  try {
951
1086
  const records = loadSessionMessages(msg.name);
952
1087
  const meta = loadSessionMeta(msg.name);
953
- tab.aborter?.abort();
1088
+ abortTurn(tab);
954
1089
  cancelPendingGates(tab);
955
1090
  tab.currentSession = msg.name;
956
1091
  if (tab.runtime) tab.runtime = buildRuntimeFor(tab);
@@ -973,7 +1108,7 @@ ${found.body}${argsLine}`;
973
1108
  return;
974
1109
  }
975
1110
  if (msg.cmd === "new_chat") {
976
- tab.aborter?.abort();
1111
+ abortTurn(tab);
977
1112
  cancelPendingGates(tab);
978
1113
  tab.currentSession = mintSessionFor(tab.rootDir);
979
1114
  if (tab.runtime) tab.runtime = buildRuntimeFor(tab);
@@ -1106,9 +1241,15 @@ ${found.body}${argsLine}`;
1106
1241
  void runTurn(tab, msg.text);
1107
1242
  }
1108
1243
  });
1109
- await new Promise((resolve2) => rl.on("close", resolve2));
1244
+ await new Promise((resolve2) => {
1245
+ rl.on("close", () => {
1246
+ void gracefulShutdown();
1247
+ resolve2();
1248
+ });
1249
+ });
1110
1250
  }
1111
1251
  export {
1112
- desktopCommand
1252
+ desktopCommand,
1253
+ installDesktopCrashGuards
1113
1254
  };
1114
- //# sourceMappingURL=desktop-Q7NDXCON.js.map
1255
+ //# sourceMappingURL=desktop-KWGR4BNE.js.map