@openacp/cli 2026.327.5 → 2026.328.2

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 (178) hide show
  1. package/README.md +13 -13
  2. package/dist/adapter-HGJENQCN.js +13 -0
  3. package/dist/agent-catalog-SZQQERV7.js +10 -0
  4. package/dist/{agent-dependencies-WS7Z2DFW.js → agent-dependencies-ED2ZTUHG.js} +1 -2
  5. package/dist/{agent-registry-5LZT7CUB.js → agent-registry-YOGP656W.js} +1 -2
  6. package/dist/agent-store-5UHZH2XI.js +8 -0
  7. package/dist/{api-client-AQPNKXI2.js → api-client-XTLRRFPX.js} +1 -2
  8. package/dist/api-server-DSUW637I.js +7 -0
  9. package/dist/api-server-WFB5K6FP.js +10 -0
  10. package/dist/{autostart-6JS565RY.js → autostart-CUPZMKKC.js} +3 -4
  11. package/dist/{chunk-WIIZNPCR.js → chunk-2KT6TROD.js} +12 -33
  12. package/dist/chunk-2KT6TROD.js.map +1 -0
  13. package/dist/{chunk-PPSMUECX.js → chunk-2R5XM3ES.js} +2 -2
  14. package/dist/{chunk-SNPYTMPR.js → chunk-3EWTPOF7.js} +2 -2
  15. package/dist/{chunk-YEULD3SG.js → chunk-3NAFXVQM.js} +7 -2
  16. package/dist/{chunk-YEULD3SG.js.map → chunk-3NAFXVQM.js.map} +1 -1
  17. package/dist/{chunk-QAQDGPB4.js → chunk-43JVXFYP.js} +3 -3
  18. package/dist/{chunk-KMMEFXIE.js → chunk-4B6PCWQP.js} +37 -9
  19. package/dist/chunk-4B6PCWQP.js.map +1 -0
  20. package/dist/{chunk-A6Y4GZM3.js → chunk-566W6INH.js} +2 -2
  21. package/dist/{chunk-ODUM3D6X.js → chunk-5HKQCYOI.js} +1 -39
  22. package/dist/chunk-5HKQCYOI.js.map +1 -0
  23. package/dist/{chunk-P2G275VD.js → chunk-5TCXYDLR.js} +3 -3
  24. package/dist/{chunk-XIBG7LSL.js → chunk-6VR4GWOO.js} +238 -108
  25. package/dist/chunk-6VR4GWOO.js.map +1 -0
  26. package/dist/{chunk-WXVT3AOY.js → chunk-7ZCQF6QM.js} +8 -3
  27. package/dist/chunk-7ZCQF6QM.js.map +1 -0
  28. package/dist/{chunk-S3ZGPPXY.js → chunk-E2SLHZAC.js} +8 -12
  29. package/dist/{chunk-S3ZGPPXY.js.map → chunk-E2SLHZAC.js.map} +1 -1
  30. package/dist/{chunk-RBYBSSGO.js → chunk-FCTC7KDT.js} +2 -2
  31. package/dist/{plugin-installer-QVJP6VKV.js → chunk-I53NEV3S.js} +6 -3
  32. package/dist/chunk-I53NEV3S.js.map +1 -0
  33. package/dist/{chunk-2YCW3QDV.js → chunk-IXMIC4GQ.js} +8 -7
  34. package/dist/chunk-IXMIC4GQ.js.map +1 -0
  35. package/dist/{chunk-BLQUXO7S.js → chunk-IZ5UEZF7.js} +27 -2
  36. package/dist/chunk-IZ5UEZF7.js.map +1 -0
  37. package/dist/{chunk-QVMEF6FB.js → chunk-JOMDPFQ2.js} +10 -24
  38. package/dist/chunk-JOMDPFQ2.js.map +1 -0
  39. package/dist/{chunk-4GMLGCF2.js → chunk-JUFN4XMB.js} +2 -2
  40. package/dist/{chunk-AD3X6DGK.js → chunk-NT6FYV27.js} +75 -13
  41. package/dist/chunk-NT6FYV27.js.map +1 -0
  42. package/dist/{chunk-HRKAXFWR.js → chunk-QBEQJFGL.js} +9 -9
  43. package/dist/{chunk-XMMAGAT4.js → chunk-R6KZYF7D.js} +8 -1
  44. package/dist/{chunk-XMMAGAT4.js.map → chunk-R6KZYF7D.js.map} +1 -1
  45. package/dist/{chunk-XWDW3XBE.js → chunk-RXMWJHWH.js} +687 -99
  46. package/dist/chunk-RXMWJHWH.js.map +1 -0
  47. package/dist/{chunk-SHTGQGAU.js → chunk-V2YZWYXT.js} +3 -3
  48. package/dist/{chunk-BQ6FR32N.js → chunk-VD3QSMVY.js} +2 -2
  49. package/dist/cli.js +103 -97
  50. package/dist/cli.js.map +1 -1
  51. package/dist/{config-I4FMCJGZ.js → config-UCAFCS5W.js} +3 -4
  52. package/dist/config-editor-OU6PUY66.js +10 -0
  53. package/dist/{config-registry-CUMNXFGK.js → config-registry-ZXAIJNYB.js} +2 -3
  54. package/dist/{context-XM6E22LM.js → context-7MPU7RL5.js} +1 -2
  55. package/dist/core-plugins-R2EVZAJV.js +22 -0
  56. package/dist/{daemon-PXO5QPCR.js → daemon-DTA6KYYY.js} +4 -5
  57. package/dist/{dev-loader-DRU3R7ZM.js → dev-loader-7P3HZCIA.js} +1 -3
  58. package/dist/{dev-loader-DRU3R7ZM.js.map → dev-loader-7P3HZCIA.js.map} +1 -1
  59. package/dist/doctor-D723IB2I.js +9 -0
  60. package/dist/file-service-HHB3JQIO.js +8 -0
  61. package/dist/index.d.ts +37 -145
  62. package/dist/index.js +32 -28
  63. package/dist/index.js.map +1 -1
  64. package/dist/{install-cloudflared-AN24L4DP.js → install-cloudflared-JRJ4BSOM.js} +3 -4
  65. package/dist/{install-cloudflared-AN24L4DP.js.map → install-cloudflared-JRJ4BSOM.js.map} +1 -1
  66. package/dist/{install-context-XPWTFT3J.js → install-context-EHYV5WRY.js} +2 -3
  67. package/dist/{install-context-XPWTFT3J.js.map → install-context-EHYV5WRY.js.map} +1 -1
  68. package/dist/{install-jq-CRVDJGF3.js → install-jq-ISTGT263.js} +3 -4
  69. package/dist/{install-jq-CRVDJGF3.js.map → install-jq-ISTGT263.js.map} +1 -1
  70. package/dist/{integrate-G6CVXTGT.js → integrate-JIEZYDOR.js} +1 -2
  71. package/dist/{integrate-G6CVXTGT.js.map → integrate-JIEZYDOR.js.map} +1 -1
  72. package/dist/{log-LZ7FTRKG.js → log-YZ243M5G.js} +4 -3
  73. package/dist/{main-3GF3EQTE.js → main-RRSX5SRL.js} +117 -40
  74. package/dist/main-RRSX5SRL.js.map +1 -0
  75. package/dist/{menu-YDQ2LWAR.js → menu-ALFN37IR.js} +1 -2
  76. package/dist/notifications-MO23S7S3.js +8 -0
  77. package/dist/{plugin-create-5HQRF2ID.js → plugin-create-EHL76ZZG.js} +1 -2
  78. package/dist/{plugin-create-5HQRF2ID.js.map → plugin-create-EHL76ZZG.js.map} +1 -1
  79. package/dist/plugin-installer-5XHORMLS.js +9 -0
  80. package/dist/{plugin-registry-WB3DR67H.js → plugin-registry-6J3YSFHF.js} +1 -2
  81. package/dist/{plugin-search-HQ4WQKOF.js → plugin-search-MGKAL5JM.js} +1 -2
  82. package/dist/{plugin-search-HQ4WQKOF.js.map → plugin-search-MGKAL5JM.js.map} +1 -1
  83. package/dist/{post-upgrade-3ADZRMYJ.js → post-upgrade-Y26S2ZQ7.js} +6 -7
  84. package/dist/{post-upgrade-3ADZRMYJ.js.map → post-upgrade-Y26S2ZQ7.js.map} +1 -1
  85. package/dist/{read-text-file-IRZM3QLM.js → read-text-file-DJBTITIB.js} +1 -2
  86. package/dist/{registry-client-AVGRE4CF.js → registry-client-GTBWLXYU.js} +1 -2
  87. package/dist/{security-YNRBW6S7.js → security-2BA265LN.js} +1 -2
  88. package/dist/{settings-manager-MD2U4ZV2.js → settings-manager-B4UN2LAC.js} +1 -2
  89. package/dist/{setup-A7VPW46C.js → setup-OI6A3OXW.js} +109 -82
  90. package/dist/setup-OI6A3OXW.js.map +1 -0
  91. package/dist/speech-GB7PHVQZ.js +9 -0
  92. package/dist/{suggest-7D6B542M.js → suggest-RST5VOHB.js} +1 -3
  93. package/dist/{suggest-7D6B542M.js.map → suggest-RST5VOHB.js.map} +1 -1
  94. package/dist/telegram-UVIAXADE.js +7 -0
  95. package/dist/tunnel-4WNFC7GO.js +7 -0
  96. package/dist/{tunnel-service-QJPUYEKU.js → tunnel-service-I2NFUX3V.js} +3 -4
  97. package/dist/{tunnel-service-QJPUYEKU.js.map → tunnel-service-I2NFUX3V.js.map} +1 -1
  98. package/dist/{validators-WSTBNKRW.js → validators-GITLOFXC.js} +1 -2
  99. package/dist/{version-NQZBM5M7.js → version-AXXV6IV2.js} +1 -2
  100. package/package.json +1 -3
  101. package/dist/adapter-JQFQ3JAO.js +0 -15
  102. package/dist/adapter-UORRGHNH.js +0 -1030
  103. package/dist/adapter-UORRGHNH.js.map +0 -1
  104. package/dist/agent-catalog-YHBFERYO.js +0 -11
  105. package/dist/agent-store-VSHNY5GT.js +0 -9
  106. package/dist/api-server-7G3ZUZRM.js +0 -8
  107. package/dist/api-server-CAYNPUF2.js +0 -11
  108. package/dist/chunk-2YCW3QDV.js.map +0 -1
  109. package/dist/chunk-32LVIEPW.js +0 -477
  110. package/dist/chunk-32LVIEPW.js.map +0 -1
  111. package/dist/chunk-AD3X6DGK.js.map +0 -1
  112. package/dist/chunk-BLQUXO7S.js.map +0 -1
  113. package/dist/chunk-KMMEFXIE.js.map +0 -1
  114. package/dist/chunk-ODUM3D6X.js.map +0 -1
  115. package/dist/chunk-QVMEF6FB.js.map +0 -1
  116. package/dist/chunk-VUNV25KB.js +0 -16
  117. package/dist/chunk-WIIZNPCR.js.map +0 -1
  118. package/dist/chunk-WXVT3AOY.js.map +0 -1
  119. package/dist/chunk-XIBG7LSL.js.map +0 -1
  120. package/dist/chunk-XWDW3XBE.js.map +0 -1
  121. package/dist/chunk-ZNSO2QVC.js +0 -124
  122. package/dist/chunk-ZNSO2QVC.js.map +0 -1
  123. package/dist/config-editor-7PKW42GZ.js +0 -11
  124. package/dist/core-plugins-Y5US6RED.js +0 -23
  125. package/dist/dist-UHQK5CXN.js +0 -21151
  126. package/dist/dist-UHQK5CXN.js.map +0 -1
  127. package/dist/doctor-QZQAP46W.js +0 -10
  128. package/dist/file-service-EUODJAIT.js +0 -9
  129. package/dist/main-3GF3EQTE.js.map +0 -1
  130. package/dist/notifications-D5BRDNSU.js +0 -9
  131. package/dist/plugin-installer-QVJP6VKV.js.map +0 -1
  132. package/dist/setup-A7VPW46C.js.map +0 -1
  133. package/dist/slack-2XNWBOWH.js +0 -8
  134. package/dist/speech-2GHQNRIO.js +0 -9
  135. package/dist/telegram-E65IWFBW.js +0 -8
  136. package/dist/tunnel-45HA72MB.js +0 -8
  137. package/dist/version-NQZBM5M7.js.map +0 -1
  138. /package/dist/{adapter-JQFQ3JAO.js.map → adapter-HGJENQCN.js.map} +0 -0
  139. /package/dist/{agent-catalog-YHBFERYO.js.map → agent-catalog-SZQQERV7.js.map} +0 -0
  140. /package/dist/{agent-dependencies-WS7Z2DFW.js.map → agent-dependencies-ED2ZTUHG.js.map} +0 -0
  141. /package/dist/{agent-registry-5LZT7CUB.js.map → agent-registry-YOGP656W.js.map} +0 -0
  142. /package/dist/{agent-store-VSHNY5GT.js.map → agent-store-5UHZH2XI.js.map} +0 -0
  143. /package/dist/{api-client-AQPNKXI2.js.map → api-client-XTLRRFPX.js.map} +0 -0
  144. /package/dist/{api-server-7G3ZUZRM.js.map → api-server-DSUW637I.js.map} +0 -0
  145. /package/dist/{api-server-CAYNPUF2.js.map → api-server-WFB5K6FP.js.map} +0 -0
  146. /package/dist/{autostart-6JS565RY.js.map → autostart-CUPZMKKC.js.map} +0 -0
  147. /package/dist/{chunk-PPSMUECX.js.map → chunk-2R5XM3ES.js.map} +0 -0
  148. /package/dist/{chunk-SNPYTMPR.js.map → chunk-3EWTPOF7.js.map} +0 -0
  149. /package/dist/{chunk-QAQDGPB4.js.map → chunk-43JVXFYP.js.map} +0 -0
  150. /package/dist/{chunk-A6Y4GZM3.js.map → chunk-566W6INH.js.map} +0 -0
  151. /package/dist/{chunk-P2G275VD.js.map → chunk-5TCXYDLR.js.map} +0 -0
  152. /package/dist/{chunk-RBYBSSGO.js.map → chunk-FCTC7KDT.js.map} +0 -0
  153. /package/dist/{chunk-4GMLGCF2.js.map → chunk-JUFN4XMB.js.map} +0 -0
  154. /package/dist/{chunk-HRKAXFWR.js.map → chunk-QBEQJFGL.js.map} +0 -0
  155. /package/dist/{chunk-SHTGQGAU.js.map → chunk-V2YZWYXT.js.map} +0 -0
  156. /package/dist/{chunk-BQ6FR32N.js.map → chunk-VD3QSMVY.js.map} +0 -0
  157. /package/dist/{chunk-VUNV25KB.js.map → config-UCAFCS5W.js.map} +0 -0
  158. /package/dist/{config-I4FMCJGZ.js.map → config-editor-OU6PUY66.js.map} +0 -0
  159. /package/dist/{config-editor-7PKW42GZ.js.map → config-registry-ZXAIJNYB.js.map} +0 -0
  160. /package/dist/{config-registry-CUMNXFGK.js.map → context-7MPU7RL5.js.map} +0 -0
  161. /package/dist/{context-XM6E22LM.js.map → core-plugins-R2EVZAJV.js.map} +0 -0
  162. /package/dist/{core-plugins-Y5US6RED.js.map → daemon-DTA6KYYY.js.map} +0 -0
  163. /package/dist/{daemon-PXO5QPCR.js.map → doctor-D723IB2I.js.map} +0 -0
  164. /package/dist/{doctor-QZQAP46W.js.map → file-service-HHB3JQIO.js.map} +0 -0
  165. /package/dist/{file-service-EUODJAIT.js.map → log-YZ243M5G.js.map} +0 -0
  166. /package/dist/{log-LZ7FTRKG.js.map → menu-ALFN37IR.js.map} +0 -0
  167. /package/dist/{menu-YDQ2LWAR.js.map → notifications-MO23S7S3.js.map} +0 -0
  168. /package/dist/{notifications-D5BRDNSU.js.map → plugin-installer-5XHORMLS.js.map} +0 -0
  169. /package/dist/{plugin-registry-WB3DR67H.js.map → plugin-registry-6J3YSFHF.js.map} +0 -0
  170. /package/dist/{read-text-file-IRZM3QLM.js.map → read-text-file-DJBTITIB.js.map} +0 -0
  171. /package/dist/{registry-client-AVGRE4CF.js.map → registry-client-GTBWLXYU.js.map} +0 -0
  172. /package/dist/{security-YNRBW6S7.js.map → security-2BA265LN.js.map} +0 -0
  173. /package/dist/{settings-manager-MD2U4ZV2.js.map → settings-manager-B4UN2LAC.js.map} +0 -0
  174. /package/dist/{slack-2XNWBOWH.js.map → speech-GB7PHVQZ.js.map} +0 -0
  175. /package/dist/{speech-2GHQNRIO.js.map → telegram-UVIAXADE.js.map} +0 -0
  176. /package/dist/{telegram-E65IWFBW.js.map → tunnel-4WNFC7GO.js.map} +0 -0
  177. /package/dist/{tunnel-45HA72MB.js.map → validators-GITLOFXC.js.map} +0 -0
  178. /package/dist/{validators-WSTBNKRW.js.map → version-AXXV6IV2.js.map} +0 -0
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  AgentCatalog
3
- } from "./chunk-SHTGQGAU.js";
3
+ } from "./chunk-V2YZWYXT.js";
4
4
  import {
5
5
  getAgentCapabilities
6
6
  } from "./chunk-ZSLHHQPQ.js";
@@ -8,31 +8,42 @@ import {
8
8
  readTextFileWithRange
9
9
  } from "./chunk-OYSAN7UX.js";
10
10
  import {
11
+ closeSessionLogger,
11
12
  createChildLogger,
12
13
  createSessionLogger
13
- } from "./chunk-XMMAGAT4.js";
14
+ } from "./chunk-R6KZYF7D.js";
14
15
 
15
16
  // src/core/utils/streams.ts
16
17
  function nodeToWebWritable(nodeStream) {
17
18
  return new WritableStream({
18
19
  write(chunk) {
19
20
  return new Promise((resolve, reject) => {
20
- nodeStream.write(Buffer.from(chunk), (err) => {
21
- if (err) reject(err);
22
- else resolve();
23
- });
21
+ const ok = nodeStream.write(chunk);
22
+ if (ok) {
23
+ resolve();
24
+ return;
25
+ }
26
+ nodeStream.once("drain", resolve);
27
+ nodeStream.once("error", reject);
24
28
  });
29
+ },
30
+ close() {
31
+ nodeStream.end();
32
+ },
33
+ abort(reason) {
34
+ nodeStream.destroy(reason instanceof Error ? reason : new Error(String(reason)));
25
35
  }
26
36
  });
27
37
  }
28
38
  function nodeToWebReadable(nodeStream) {
29
39
  return new ReadableStream({
30
40
  start(controller) {
31
- nodeStream.on("data", (chunk) => {
32
- controller.enqueue(new Uint8Array(chunk));
33
- });
41
+ nodeStream.on("data", (chunk) => controller.enqueue(new Uint8Array(chunk)));
34
42
  nodeStream.on("end", () => controller.close());
35
43
  nodeStream.on("error", (err) => controller.error(err));
44
+ },
45
+ cancel() {
46
+ nodeStream.destroy();
36
47
  }
37
48
  });
38
49
  }
@@ -349,6 +360,7 @@ var AgentInstance = class _AgentInstance extends TypedEmitter {
349
360
  stderrCapture;
350
361
  terminalManager = new TerminalManager();
351
362
  static mcpManager = new McpManager();
363
+ _destroying = false;
352
364
  sessionId;
353
365
  agentName;
354
366
  promptCapabilities;
@@ -442,15 +454,17 @@ var AgentInstance = class _AgentInstance extends TypedEmitter {
442
454
  }
443
455
  setupCrashDetection() {
444
456
  this.child.on("exit", (code, signal) => {
457
+ if (this._destroying) return;
445
458
  log.info(
446
459
  { sessionId: this.sessionId, exitCode: code, signal },
447
460
  "Agent process exited"
448
461
  );
449
- if (code !== 0 && code !== null) {
462
+ if (code !== 0 && code !== null || signal) {
450
463
  const stderr = this.stderrCapture.getLastLines();
451
464
  this.emit("agent_event", {
452
465
  type: "error",
453
- message: `Agent crashed (exit code ${code})
466
+ message: signal ? `Agent killed by signal ${signal}
467
+ ${stderr}` : `Agent crashed (exit code ${code})
454
468
  ${stderr}`
455
469
  });
456
470
  }
@@ -810,11 +824,23 @@ ${stderr}`
810
824
  await this.connection.cancel({ sessionId: this.sessionId });
811
825
  }
812
826
  async destroy() {
827
+ this._destroying = true;
813
828
  this.terminalManager.destroyAll();
814
- this.child.kill("SIGTERM");
815
- setTimeout(() => {
816
- if (!this.child.killed) this.child.kill("SIGKILL");
817
- }, 1e4);
829
+ if (this.child.exitCode !== null) return;
830
+ await new Promise((resolve) => {
831
+ this.child.on("exit", () => {
832
+ clearTimeout(forceKillTimer);
833
+ resolve();
834
+ });
835
+ this.child.kill("SIGTERM");
836
+ const forceKillTimer = setTimeout(() => {
837
+ if (this.child.exitCode === null) this.child.kill("SIGKILL");
838
+ resolve();
839
+ }, 1e4);
840
+ if (typeof forceKillTimer === "object" && forceKillTimer !== null && "unref" in forceKillTimer) {
841
+ forceKillTimer.unref();
842
+ }
843
+ });
818
844
  }
819
845
  };
820
846
 
@@ -921,6 +947,9 @@ var PermissionGate = class {
921
947
  this.timeoutMs = timeoutMs ?? DEFAULT_TIMEOUT_MS;
922
948
  }
923
949
  setPending(request) {
950
+ if (!this.settled && this.rejectFn) {
951
+ this.rejectFn(new Error("Superseded by new permission request"));
952
+ }
924
953
  this.request = request;
925
954
  this.settled = false;
926
955
  this.clearTimeout();
@@ -930,6 +959,9 @@ var PermissionGate = class {
930
959
  this.timeoutTimer = setTimeout(() => {
931
960
  this.reject("Permission request timed out (no response received)");
932
961
  }, this.timeoutMs);
962
+ if (typeof this.timeoutTimer === "object" && "unref" in this.timeoutTimer) {
963
+ this.timeoutTimer.unref();
964
+ }
933
965
  });
934
966
  }
935
967
  resolve(optionId) {
@@ -982,7 +1014,7 @@ var TTS_TIMEOUT_MS = 3e4;
982
1014
  var VALID_TRANSITIONS = {
983
1015
  initializing: /* @__PURE__ */ new Set(["active", "error"]),
984
1016
  active: /* @__PURE__ */ new Set(["error", "finished", "cancelled"]),
985
- error: /* @__PURE__ */ new Set(["active"]),
1017
+ error: /* @__PURE__ */ new Set(["active", "cancelled"]),
986
1018
  cancelled: /* @__PURE__ */ new Set(["active"]),
987
1019
  finished: /* @__PURE__ */ new Set()
988
1020
  };
@@ -1097,30 +1129,28 @@ var Session = class extends TypedEmitter {
1097
1129
  await this.runWarmup();
1098
1130
  return;
1099
1131
  }
1132
+ if (this._status === "finished") return;
1100
1133
  this.promptCount++;
1101
- if (this._status === "initializing") {
1134
+ if (this._status === "initializing" || this._status === "cancelled" || this._status === "error") {
1102
1135
  this.activate();
1103
1136
  }
1104
1137
  const promptStart = Date.now();
1105
1138
  this.log.debug("Prompt execution started");
1106
- if (this.pendingContext) {
1139
+ const contextUsed = this.pendingContext;
1140
+ if (contextUsed) {
1107
1141
  text = `[CONVERSATION HISTORY - This is context from previous sessions, not current conversation]
1108
1142
 
1109
- ${this.pendingContext}
1143
+ ${contextUsed}
1110
1144
 
1111
1145
  [END CONVERSATION HISTORY]
1112
1146
 
1113
1147
  ${text}`;
1114
- this.pendingContext = null;
1115
1148
  this.log.debug("Context injected into prompt");
1116
1149
  }
1117
1150
  const processed = await this.maybeTranscribeAudio(text, attachments);
1118
1151
  const ttsActive = this.voiceMode !== "off" && !!this.speechService?.isTTSAvailable();
1119
1152
  if (ttsActive) {
1120
1153
  processed.text += TTS_PROMPT_INSTRUCTION;
1121
- if (this.voiceMode === "next") {
1122
- this.voiceMode = "off";
1123
- }
1124
1154
  }
1125
1155
  let accumulatedText = "";
1126
1156
  const accumulatorListener = ttsActive ? (event) => {
@@ -1141,6 +1171,12 @@ ${text}`;
1141
1171
  if (response && typeof response === "object" && "stopReason" in response) {
1142
1172
  stopReason = response.stopReason ?? "end_turn";
1143
1173
  }
1174
+ if (contextUsed) {
1175
+ this.pendingContext = null;
1176
+ }
1177
+ if (ttsActive && this.voiceMode === "next") {
1178
+ this.voiceMode = "off";
1179
+ }
1144
1180
  } finally {
1145
1181
  if (accumulatorListener) {
1146
1182
  this.off("agent_event", accumulatorListener);
@@ -1220,20 +1256,26 @@ ${result.text}` : result.text;
1220
1256
  ttsText = ttsText.slice(0, TTS_MAX_LENGTH);
1221
1257
  }
1222
1258
  try {
1223
- const timeoutPromise = new Promise(
1224
- (_, reject) => setTimeout(() => reject(new Error("TTS synthesis timed out")), TTS_TIMEOUT_MS)
1225
- );
1226
- const result = await Promise.race([
1227
- this.speechService.synthesize(ttsText),
1228
- timeoutPromise
1229
- ]);
1230
- const base64 = result.audioBuffer.toString("base64");
1231
- this.emit("agent_event", {
1232
- type: "audio_content",
1233
- data: base64,
1234
- mimeType: result.mimeType
1259
+ let ttsTimer;
1260
+ const timeoutPromise = new Promise((_, reject) => {
1261
+ ttsTimer = setTimeout(() => reject(new Error("TTS synthesis timed out")), TTS_TIMEOUT_MS);
1235
1262
  });
1236
- this.log.info("TTS synthesis completed");
1263
+ try {
1264
+ const result = await Promise.race([
1265
+ this.speechService.synthesize(ttsText),
1266
+ timeoutPromise
1267
+ ]);
1268
+ const base64 = result.audioBuffer.toString("base64");
1269
+ this.emit("agent_event", {
1270
+ type: "audio_content",
1271
+ data: base64,
1272
+ mimeType: result.mimeType
1273
+ });
1274
+ this.emit("agent_event", { type: "tts_strip" });
1275
+ this.log.info("TTS synthesis completed");
1276
+ } finally {
1277
+ clearTimeout(ttsTimer);
1278
+ }
1237
1279
  } catch (err) {
1238
1280
  this.log.warn({ err }, "TTS synthesis failed, skipping");
1239
1281
  }
@@ -1337,7 +1379,12 @@ ${result.text}` : result.text;
1337
1379
  }
1338
1380
  async destroy() {
1339
1381
  this.log.info("Session destroyed");
1382
+ if (this.permissionGate.isPending) {
1383
+ this.permissionGate.reject("Session destroyed");
1384
+ }
1385
+ this.queue.clear();
1340
1386
  await this.agentInstance.destroy();
1387
+ closeSessionLogger(this.log);
1341
1388
  }
1342
1389
  };
1343
1390
 
@@ -1426,8 +1473,12 @@ var SessionManager = class {
1426
1473
  async cancelSession(sessionId) {
1427
1474
  const session = this.sessions.get(sessionId);
1428
1475
  if (session) {
1429
- await session.abortPrompt();
1476
+ try {
1477
+ await session.abortPrompt();
1478
+ } catch {
1479
+ }
1430
1480
  session.markCancelled();
1481
+ this.sessions.delete(sessionId);
1431
1482
  }
1432
1483
  if (this.store) {
1433
1484
  const record = this.store.get(sessionId);
@@ -1458,6 +1509,25 @@ var SessionManager = class {
1458
1509
  await this.store.remove(sessionId);
1459
1510
  this.eventBus?.emit("session:deleted", { sessionId });
1460
1511
  }
1512
+ /**
1513
+ * Graceful shutdown: persist session state without killing agent subprocesses.
1514
+ * Agent processes will exit naturally when the parent process terminates.
1515
+ */
1516
+ async shutdownAll() {
1517
+ if (this.store) {
1518
+ for (const session of this.sessions.values()) {
1519
+ const record = this.store.get(session.id);
1520
+ if (record) {
1521
+ await this.store.save({ ...record, status: "finished" });
1522
+ }
1523
+ }
1524
+ }
1525
+ this.sessions.clear();
1526
+ }
1527
+ /**
1528
+ * Forcefully destroy all sessions (kill agent subprocesses).
1529
+ * Use only when sessions must be fully torn down (e.g. archive).
1530
+ */
1461
1531
  async destroyAll() {
1462
1532
  if (this.store) {
1463
1533
  for (const session of this.sessions.values()) {
@@ -1496,13 +1566,21 @@ var SessionBridge = class {
1496
1566
  namedHandler;
1497
1567
  /** Send message to adapter, optionally running through message:outgoing middleware */
1498
1568
  async sendMessage(sessionId, message) {
1499
- const mw = this.deps.middlewareChain;
1500
- if (mw) {
1501
- const result = await mw.execute("message:outgoing", { sessionId, message }, async (m) => m);
1502
- if (!result) return;
1503
- this.adapter.sendMessage(sessionId, result.message);
1504
- } else {
1505
- this.adapter.sendMessage(sessionId, message);
1569
+ try {
1570
+ const mw = this.deps.middlewareChain;
1571
+ if (mw) {
1572
+ const result = await mw.execute("message:outgoing", { sessionId, message }, async (m) => m);
1573
+ if (!result) return;
1574
+ this.adapter.sendMessage(sessionId, result.message).catch((err) => {
1575
+ log2.error({ err, sessionId }, "Failed to send message to adapter");
1576
+ });
1577
+ } else {
1578
+ this.adapter.sendMessage(sessionId, message).catch((err) => {
1579
+ log2.error({ err, sessionId }, "Failed to send message to adapter");
1580
+ });
1581
+ }
1582
+ } catch (err) {
1583
+ log2.error({ err, sessionId }, "Error in sendMessage middleware");
1506
1584
  }
1507
1585
  }
1508
1586
  connect() {
@@ -1542,19 +1620,31 @@ var SessionBridge = class {
1542
1620
  if (mw) {
1543
1621
  mw.execute("agent:beforeEvent", { sessionId: this.session.id, event }, async (e) => e).then((result) => {
1544
1622
  if (!result) return;
1545
- const transformedEvent = result.event;
1546
- const outgoing = this.handleAgentEvent(transformedEvent);
1547
- mw.execute("agent:afterEvent", {
1548
- sessionId: this.session.id,
1549
- event: transformedEvent,
1550
- outgoingMessage: outgoing ?? { type: "text", text: "" }
1551
- }, async (e) => e).catch(() => {
1552
- });
1623
+ try {
1624
+ const transformedEvent = result.event;
1625
+ const outgoing = this.handleAgentEvent(transformedEvent);
1626
+ mw.execute("agent:afterEvent", {
1627
+ sessionId: this.session.id,
1628
+ event: transformedEvent,
1629
+ outgoingMessage: outgoing ?? { type: "text", text: "" }
1630
+ }, async (e) => e).catch(() => {
1631
+ });
1632
+ } catch (err) {
1633
+ log2.error({ err, sessionId: this.session.id }, "Error handling agent event after middleware");
1634
+ }
1553
1635
  }).catch(() => {
1554
- this.handleAgentEvent(event);
1636
+ try {
1637
+ this.handleAgentEvent(event);
1638
+ } catch (err) {
1639
+ log2.error({ err, sessionId: this.session.id }, "Error handling agent event (middleware fallback)");
1640
+ }
1555
1641
  });
1556
1642
  } else {
1557
- this.handleAgentEvent(event);
1643
+ try {
1644
+ this.handleAgentEvent(event);
1645
+ } catch (err) {
1646
+ log2.error({ err, sessionId: this.session.id }, "Error handling agent event");
1647
+ }
1558
1648
  }
1559
1649
  };
1560
1650
  this.session.on("agent_event", this.sessionEventHandler);
@@ -1678,6 +1768,9 @@ var SessionBridge = class {
1678
1768
  outgoing = this.deps.messageTransformer.transform(event);
1679
1769
  this.sendMessage(this.session.id, outgoing);
1680
1770
  break;
1771
+ case "tts_strip":
1772
+ this.adapter.stripTTSBlock?.(this.session.id);
1773
+ break;
1681
1774
  }
1682
1775
  this.deps.eventBus?.emit("agent:event", {
1683
1776
  sessionId: this.session.id,
@@ -1780,7 +1873,7 @@ var SessionBridge = class {
1780
1873
  sessionId: this.session.id,
1781
1874
  status: to
1782
1875
  });
1783
- if (to === "finished" || to === "cancelled") {
1876
+ if (to === "finished") {
1784
1877
  queueMicrotask(() => this.disconnect());
1785
1878
  }
1786
1879
  };
@@ -1947,7 +2040,7 @@ var MessageTransformer = class {
1947
2040
  metadata: {
1948
2041
  tokensUsed: event.tokensUsed,
1949
2042
  contextSize: event.contextSize,
1950
- cost: event.cost
2043
+ cost: event.cost?.amount
1951
2044
  }
1952
2045
  };
1953
2046
  case "session_end":
@@ -2251,7 +2344,11 @@ var JsonFileSessionStore = class {
2251
2344
  }
2252
2345
  log5.debug({ count: this.records.size }, "Loaded session records");
2253
2346
  } catch (err) {
2254
- log5.error({ err }, "Failed to load session store");
2347
+ log5.error({ err }, "Failed to load session store, backing up corrupt file");
2348
+ try {
2349
+ fs3.renameSync(this.filePath, `${this.filePath}.bak`);
2350
+ } catch {
2351
+ }
2255
2352
  }
2256
2353
  }
2257
2354
  cleanup() {
@@ -2392,6 +2489,7 @@ var MiddlewareChain = class {
2392
2489
  const existing = this.chains.get(hook);
2393
2490
  if (existing) {
2394
2491
  existing.push(entry);
2492
+ existing.sort((a, b) => a.priority - b.priority);
2395
2493
  } else {
2396
2494
  this.chains.set(hook, [entry]);
2397
2495
  }
@@ -2401,7 +2499,7 @@ var MiddlewareChain = class {
2401
2499
  if (!handlers || handlers.length === 0) {
2402
2500
  return coreHandler(payload);
2403
2501
  }
2404
- const sorted = [...handlers].sort((a, b) => a.priority - b.priority);
2502
+ const sorted = handlers;
2405
2503
  let cachedResult = void 0;
2406
2504
  const buildNext = (index, currentPayload) => {
2407
2505
  return async () => {
@@ -2431,15 +2529,16 @@ var MiddlewareChain = class {
2431
2529
  return nextResult;
2432
2530
  };
2433
2531
  let handlerResult;
2532
+ let timeoutTimer;
2434
2533
  try {
2435
2534
  const timeoutPromise = new Promise((_, reject) => {
2436
- const timer = setTimeout(
2535
+ timeoutTimer = setTimeout(
2437
2536
  () => reject(new Error(`Middleware timeout: ${entry.pluginName} on hook ${hook}`)),
2438
2537
  MIDDLEWARE_TIMEOUT_MS
2439
2538
  );
2440
- if (typeof timer === "object" && timer !== null && "unref" in timer) {
2539
+ if (typeof timeoutTimer === "object" && timeoutTimer !== null && "unref" in timeoutTimer) {
2441
2540
  ;
2442
- timer.unref();
2541
+ timeoutTimer.unref();
2443
2542
  }
2444
2543
  });
2445
2544
  handlerResult = await Promise.race([
@@ -2452,6 +2551,8 @@ var MiddlewareChain = class {
2452
2551
  }
2453
2552
  this.errorTracker?.increment(entry.pluginName);
2454
2553
  return nextFn();
2554
+ } finally {
2555
+ clearTimeout(timeoutTimer);
2455
2556
  }
2456
2557
  if (handlerResult === null) {
2457
2558
  return null;
@@ -2528,6 +2629,7 @@ var PluginStorageImpl = class {
2528
2629
  constructor(baseDir) {
2529
2630
  this.dataDir = path3.join(baseDir, "data");
2530
2631
  this.kvPath = path3.join(baseDir, "kv.json");
2632
+ fs4.mkdirSync(baseDir, { recursive: true });
2531
2633
  }
2532
2634
  readKv() {
2533
2635
  try {
@@ -2780,6 +2882,9 @@ var LifecycleManager = class {
2780
2882
  get failedPlugins() {
2781
2883
  return [...this._failed];
2782
2884
  }
2885
+ get registry() {
2886
+ return this.pluginRegistry;
2887
+ }
2783
2888
  constructor(opts) {
2784
2889
  this.serviceRegistry = opts?.serviceRegistry ?? new ServiceRegistry();
2785
2890
  this.middlewareChain = opts?.middlewareChain ?? new MiddlewareChain();
@@ -2821,6 +2926,8 @@ var LifecycleManager = class {
2821
2926
  try {
2822
2927
  sorted = resolveLoadOrder(allForResolution);
2823
2928
  } catch (err) {
2929
+ const error = err instanceof Error ? err : new Error(String(err));
2930
+ this.log?.error(`Plugin dependency resolution failed: ${error.message}`);
2824
2931
  for (const p of plugins) {
2825
2932
  this._failed.add(p.name);
2826
2933
  }
@@ -2859,7 +2966,11 @@ var LifecycleManager = class {
2859
2966
  settings: this.settingsManager.createAPI(plugin.name),
2860
2967
  log: pluginLog
2861
2968
  };
2862
- const newSettings = await plugin.migrate(migrateCtx, oldSettings, registryEntry.version);
2969
+ const newSettings = await withTimeout(
2970
+ plugin.migrate(migrateCtx, oldSettings, registryEntry.version),
2971
+ SETUP_TIMEOUT_MS,
2972
+ `${plugin.name}.migrate()`
2973
+ );
2863
2974
  if (newSettings && typeof newSettings === "object") {
2864
2975
  await migrateCtx.settings.setAll(newSettings);
2865
2976
  }
@@ -2872,11 +2983,23 @@ var LifecycleManager = class {
2872
2983
  let pluginConfig;
2873
2984
  if (this.settingsManager) {
2874
2985
  pluginConfig = await this.settingsManager.loadSettings(plugin.name);
2986
+ const settingsPath = this.settingsManager.getSettingsPath(plugin.name);
2987
+ this.getPluginLogger(plugin.name).debug(`Settings loaded from ${settingsPath}: ${Object.keys(pluginConfig).length} keys`);
2875
2988
  if (Object.keys(pluginConfig).length === 0) {
2876
2989
  pluginConfig = resolvePluginConfig(plugin.name, this.config);
2877
2990
  }
2878
2991
  } else {
2879
2992
  pluginConfig = resolvePluginConfig(plugin.name, this.config);
2993
+ this.getPluginLogger(plugin.name).debug("No settingsManager, using legacy config");
2994
+ }
2995
+ if (plugin.settingsSchema && this.settingsManager) {
2996
+ const validation = this.settingsManager.validateSettings(plugin.name, pluginConfig, plugin.settingsSchema);
2997
+ if (!validation.valid) {
2998
+ this._failed.add(plugin.name);
2999
+ this.getPluginLogger(plugin.name).error(`Settings validation failed: ${validation.errors?.join("; ")}`);
3000
+ this.eventBus?.emit("plugin:failed", { name: plugin.name, error: `Settings validation failed: ${validation.errors?.join("; ")}` });
3001
+ continue;
3002
+ }
2880
3003
  }
2881
3004
  const ctx = createPluginContext({
2882
3005
  pluginName: plugin.name,
@@ -2964,20 +3087,25 @@ var OpenACPCore = class {
2964
3087
  sessionFactory;
2965
3088
  lifecycleManager;
2966
3089
  // --- Lazy getters: resolve from ServiceRegistry (populated by plugins during boot) ---
3090
+ getService(name) {
3091
+ const svc = this.lifecycleManager.serviceRegistry.get(name);
3092
+ if (!svc) throw new Error(`Service '${name}' not registered \u2014 is the ${name} plugin loaded?`);
3093
+ return svc;
3094
+ }
2967
3095
  get securityGuard() {
2968
- return this.lifecycleManager.serviceRegistry.get("security");
3096
+ return this.getService("security");
2969
3097
  }
2970
3098
  get notificationManager() {
2971
- return this.lifecycleManager.serviceRegistry.get("notifications");
3099
+ return this.getService("notifications");
2972
3100
  }
2973
3101
  get fileService() {
2974
- return this.lifecycleManager.serviceRegistry.get("file-service");
3102
+ return this.getService("file-service");
2975
3103
  }
2976
3104
  get speechService() {
2977
- return this.lifecycleManager.serviceRegistry.get("speech");
3105
+ return this.getService("speech");
2978
3106
  }
2979
3107
  get contextManager() {
2980
- return this.lifecycleManager.serviceRegistry.get("context");
3108
+ return this.getService("context");
2981
3109
  }
2982
3110
  constructor(configManager) {
2983
3111
  this.configManager = configManager;
@@ -3017,7 +3145,7 @@ var OpenACPCore = class {
3017
3145
  "config:changed",
3018
3146
  async ({ path: configPath, value }) => {
3019
3147
  if (configPath === "logging.level" && typeof value === "string") {
3020
- const { setLogLevel } = await import("./log-LZ7FTRKG.js");
3148
+ const { setLogLevel } = await import("./log-YZ243M5G.js");
3021
3149
  setLogLevel(value);
3022
3150
  log6.info({ level: value }, "Log level changed at runtime");
3023
3151
  }
@@ -3056,14 +3184,17 @@ var OpenACPCore = class {
3056
3184
  }
3057
3185
  async stop() {
3058
3186
  try {
3059
- await this.notificationManager.notifyAll({
3060
- sessionId: "system",
3061
- type: "error",
3062
- summary: "OpenACP is shutting down"
3063
- });
3187
+ const nm = this.lifecycleManager.serviceRegistry.get("notifications");
3188
+ if (nm) {
3189
+ await nm.notifyAll({
3190
+ sessionId: "system",
3191
+ type: "error",
3192
+ summary: "OpenACP is shutting down"
3193
+ });
3194
+ }
3064
3195
  } catch {
3065
3196
  }
3066
- await this.sessionManager.destroyAll();
3197
+ await this.sessionManager.shutdownAll();
3067
3198
  for (const adapter of this.adapters.values()) {
3068
3199
  await adapter.stop();
3069
3200
  }
@@ -3071,30 +3202,30 @@ var OpenACPCore = class {
3071
3202
  // --- Archive ---
3072
3203
  async archiveSession(sessionId) {
3073
3204
  const session = this.sessionManager.getSession(sessionId);
3074
- const record = this.sessionManager.getSessionRecord(sessionId);
3075
- if (!session && !record) return { ok: false, error: "Session not found" };
3076
- const channelId = session?.channelId ?? record?.channelId;
3077
- if (!channelId) return { ok: false, error: "No channel for session" };
3078
- const adapter = this.adapters.get(channelId);
3205
+ if (!session) return { ok: false, error: "Session not found (must be in memory)" };
3206
+ if (session.status !== "active" && session.status !== "cancelled" && session.status !== "error") {
3207
+ return { ok: false, error: `Cannot archive session in '${session.status}' state` };
3208
+ }
3209
+ const adapter = this.adapters.get(session.channelId);
3079
3210
  if (!adapter) return { ok: false, error: "Adapter not found for session" };
3211
+ if (!adapter.archiveSessionTopic) return { ok: false, error: "Adapter does not support topic archiving" };
3080
3212
  try {
3081
- if (session) {
3082
- await adapter.archiveSessionTopic?.(session.id);
3083
- } else {
3084
- await adapter.deleteSessionThread?.(sessionId);
3085
- }
3086
- if (session) {
3087
- try {
3088
- await this.sessionManager.cancelSession(sessionId);
3089
- } catch {
3090
- } finally {
3091
- session.archiving = false;
3213
+ const newThreadId = await adapter.archiveSessionTopic(session.id);
3214
+ session.threadId = newThreadId;
3215
+ try {
3216
+ const platform = {};
3217
+ if (session.channelId === "telegram") {
3218
+ platform.topicId = Number(newThreadId);
3219
+ } else {
3220
+ platform.threadId = newThreadId;
3092
3221
  }
3222
+ await this.sessionManager.patchRecord(sessionId, { platform });
3223
+ } catch (patchErr) {
3224
+ log6.warn({ err: patchErr, sessionId }, "Failed to update session record after archive \u2014 session will work but may not survive restart");
3093
3225
  }
3094
- await this.sessionManager.removeRecord(sessionId);
3095
- return { ok: true };
3226
+ return { ok: true, newThreadId };
3096
3227
  } catch (err) {
3097
- if (session) session.archiving = false;
3228
+ session.archiving = false;
3098
3229
  return { ok: false, error: err.message };
3099
3230
  }
3100
3231
  }
@@ -3153,6 +3284,9 @@ var OpenACPCore = class {
3153
3284
  // --- Unified Session Creation Pipeline ---
3154
3285
  async createSession(params) {
3155
3286
  const session = await this.sessionFactory.create(params);
3287
+ if (params.threadId) {
3288
+ session.threadId = params.threadId;
3289
+ }
3156
3290
  const adapter = this.adapters.get(params.channelId);
3157
3291
  if (params.createThread && adapter) {
3158
3292
  const threadId = await adapter.createSessionThread(
@@ -3391,7 +3525,7 @@ var OpenACPCore = class {
3391
3525
  );
3392
3526
  return null;
3393
3527
  }
3394
- if (record.status === "error") {
3528
+ if (record.status === "error" || record.status === "cancelled") {
3395
3529
  log6.debug(
3396
3530
  {
3397
3531
  threadId: message.threadId,
@@ -3418,9 +3552,9 @@ var OpenACPCore = class {
3418
3552
  workingDirectory: record.workingDir,
3419
3553
  resumeAgentSessionId: record.agentSessionId,
3420
3554
  existingSessionId: record.sessionId,
3421
- initialName: record.name
3555
+ initialName: record.name,
3556
+ threadId: message.threadId
3422
3557
  });
3423
- session.threadId = message.threadId;
3424
3558
  session.activate();
3425
3559
  session.dangerousMode = record.dangerousMode ?? false;
3426
3560
  log6.info(
@@ -3468,7 +3602,7 @@ var CommandRegistry = class _CommandRegistry {
3468
3602
  commands = /* @__PURE__ */ new Map();
3469
3603
  /** Adapter-specific overrides: `channelId:commandName` → RegisteredCommand */
3470
3604
  overrides = /* @__PURE__ */ new Map();
3471
- static ADAPTER_SCOPES = /* @__PURE__ */ new Set(["telegram", "discord", "slack"]);
3605
+ static ADAPTER_SCOPES = /* @__PURE__ */ new Set(["telegram", "discord"]);
3472
3606
  /**
3473
3607
  * Register a command definition.
3474
3608
  * @param def - Command definition
@@ -3503,22 +3637,18 @@ var CommandRegistry = class _CommandRegistry {
3503
3637
  get(name) {
3504
3638
  return this.commands.get(name);
3505
3639
  }
3506
- /** Remove a command by short name. Also removes its qualified name entry. */
3640
+ /** Remove a command by name (short or qualified). Also removes its qualified name entry. */
3507
3641
  unregister(name) {
3508
3642
  const cmd = this.commands.get(name);
3509
- if (cmd) {
3510
- this.commands.delete(name);
3511
- if (cmd.scope) {
3512
- this.commands.delete(`${cmd.scope}:${name}`);
3513
- }
3514
- }
3515
- if (!cmd) {
3516
- this.commands.delete(name);
3643
+ if (!cmd) return;
3644
+ this.commands.delete(name);
3645
+ if (cmd.scope) {
3646
+ this.commands.delete(`${cmd.scope}:${cmd.name}`);
3647
+ this.commands.delete(cmd.name);
3517
3648
  }
3518
3649
  }
3519
3650
  /** Remove all commands registered by a given plugin. */
3520
3651
  unregisterByPlugin(pluginName) {
3521
- const scope = _CommandRegistry.extractScope(pluginName);
3522
3652
  const toDelete = [];
3523
3653
  for (const [key, cmd] of this.commands) {
3524
3654
  if (cmd.pluginName === pluginName) {
@@ -3607,4 +3737,4 @@ export {
3607
3737
  OpenACPCore,
3608
3738
  CommandRegistry
3609
3739
  };
3610
- //# sourceMappingURL=chunk-XIBG7LSL.js.map
3740
+ //# sourceMappingURL=chunk-6VR4GWOO.js.map