@openacp/cli 2026.330.3 → 2026.331.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 (145) hide show
  1. package/README.md +17 -0
  2. package/dist/adapter-ELG3VRZ3.js +14 -0
  3. package/dist/{agent-catalog-SZQQERV7.js → agent-catalog-UYD26QDK.js} +3 -3
  4. package/dist/{api-client-XTLRRFPX.js → api-client-PEMHYL5U.js} +2 -2
  5. package/dist/{api-server-JLBDKCU4.js → api-server-DATG2KBR.js} +3 -3
  6. package/dist/api-server-L5Z7XACW.js +7 -0
  7. package/dist/chunk-23SRIVG4.js +50 -0
  8. package/dist/chunk-23SRIVG4.js.map +1 -0
  9. package/dist/{chunk-2HEFALTZ.js → chunk-7GXEMMEV.js} +15 -15
  10. package/dist/{chunk-QWVHCTCA.js → chunk-7U6IZIJP.js} +37 -23
  11. package/dist/chunk-7U6IZIJP.js.map +1 -0
  12. package/dist/{chunk-FCTC7KDT.js → chunk-7YIKTRSM.js} +14 -10
  13. package/dist/chunk-7YIKTRSM.js.map +1 -0
  14. package/dist/{chunk-MITTQMGZ.js → chunk-BYCJQPMN.js} +5 -5
  15. package/dist/chunk-BYCJQPMN.js.map +1 -0
  16. package/dist/{chunk-XBZIHNKV.js → chunk-EWVXSTQK.js} +183 -49
  17. package/dist/chunk-EWVXSTQK.js.map +1 -0
  18. package/dist/{chunk-UWH7KIAA.js → chunk-FPKQYCQS.js} +88 -13
  19. package/dist/chunk-FPKQYCQS.js.map +1 -0
  20. package/dist/{chunk-GEOXPGCO.js → chunk-K6UY5M75.js} +12 -9
  21. package/dist/chunk-K6UY5M75.js.map +1 -0
  22. package/dist/{chunk-KDU3ZEWT.js → chunk-KGAQW6F4.js} +12 -3
  23. package/dist/chunk-KGAQW6F4.js.map +1 -0
  24. package/dist/{chunk-UCIZM5SW.js → chunk-LRV56K2M.js} +205 -16
  25. package/dist/chunk-LRV56K2M.js.map +1 -0
  26. package/dist/{chunk-V2YZWYXT.js → chunk-MDJHCCFS.js} +18 -17
  27. package/dist/chunk-MDJHCCFS.js.map +1 -0
  28. package/dist/chunk-NHD5XDD2.js +686 -0
  29. package/dist/chunk-NHD5XDD2.js.map +1 -0
  30. package/dist/{chunk-APS6UEFU.js → chunk-NJX75BLK.js} +1 -1
  31. package/dist/chunk-NJX75BLK.js.map +1 -0
  32. package/dist/{chunk-5HKQCYOI.js → chunk-NOEAJNTK.js} +14 -3
  33. package/dist/chunk-NOEAJNTK.js.map +1 -0
  34. package/dist/chunk-ON7HB5O7.js +58 -0
  35. package/dist/chunk-ON7HB5O7.js.map +1 -0
  36. package/dist/{chunk-5OCGO27U.js → chunk-OSBZXY2W.js} +2 -1
  37. package/dist/chunk-OSBZXY2W.js.map +1 -0
  38. package/dist/{chunk-PA6MNBG4.js → chunk-P3HHJANC.js} +32 -13
  39. package/dist/chunk-P3HHJANC.js.map +1 -0
  40. package/dist/{chunk-BTJHGSLM.js → chunk-R2YLDQLI.js} +9 -10
  41. package/dist/chunk-R2YLDQLI.js.map +1 -0
  42. package/dist/{chunk-237WYH6H.js → chunk-SSLVNCEA.js} +3 -2
  43. package/dist/chunk-SSLVNCEA.js.map +1 -0
  44. package/dist/{chunk-MPGEHTGE.js → chunk-TGP34LQN.js} +9 -7
  45. package/dist/chunk-TGP34LQN.js.map +1 -0
  46. package/dist/{chunk-TMVTSWVH.js → chunk-VUSCVRJL.js} +2 -1
  47. package/dist/chunk-VUSCVRJL.js.map +1 -0
  48. package/dist/chunk-XRJUS6FE.js +53 -0
  49. package/dist/chunk-XRJUS6FE.js.map +1 -0
  50. package/dist/{chunk-W4LK6WJP.js → chunk-YZCKSNRN.js} +24 -17
  51. package/dist/chunk-YZCKSNRN.js.map +1 -0
  52. package/dist/{chunk-3NAFXVQM.js → chunk-ZIRH6QWW.js} +7 -5
  53. package/dist/chunk-ZIRH6QWW.js.map +1 -0
  54. package/dist/cli.d.ts +11 -0
  55. package/dist/cli.js +334 -140
  56. package/dist/cli.js.map +1 -1
  57. package/dist/config-X4UP7H6R.js +13 -0
  58. package/dist/config-editor-7BENRVG5.js +11 -0
  59. package/dist/{config-registry-ZXAIJNYB.js → config-registry-M3FFWEVM.js} +3 -2
  60. package/dist/context-FVGCU5TI.js +9 -0
  61. package/dist/core-plugins-JSY2I44L.js +25 -0
  62. package/dist/{daemon-XFEMMJSZ.js → daemon-UOSRDEXW.js} +8 -3
  63. package/dist/doctor-6DLACBR4.js +10 -0
  64. package/dist/{file-service-HHB3JQIO.js → file-service-FQQYME7M.js} +2 -2
  65. package/dist/index.d.ts +259 -30
  66. package/dist/index.js +44 -33
  67. package/dist/index.js.map +1 -1
  68. package/dist/{install-cloudflared-JRJ4BSOM.js → install-cloudflared-LNS5L5FR.js} +5 -4
  69. package/dist/install-cloudflared-LNS5L5FR.js.map +1 -0
  70. package/dist/{install-context-EHYV5WRY.js → install-context-KZO5FR4D.js} +4 -3
  71. package/dist/install-context-KZO5FR4D.js.map +1 -0
  72. package/dist/{install-jq-ISTGT263.js → install-jq-SN4IA5K4.js} +3 -3
  73. package/dist/instance-context-FLCE7VZ4.js +13 -0
  74. package/dist/instance-registry-SW5FWKHO.js +7 -0
  75. package/dist/{main-VEJCG5PY.js → main-D7M2AKRM.js} +91 -48
  76. package/dist/main-D7M2AKRM.js.map +1 -0
  77. package/dist/{plugin-create-EHL76ZZG.js → plugin-create-HFKS23JY.js} +4 -2
  78. package/dist/{plugin-create-EHL76ZZG.js.map → plugin-create-HFKS23JY.js.map} +1 -1
  79. package/dist/{post-upgrade-Y26S2ZQ7.js → post-upgrade-F4YPMTUT.js} +6 -6
  80. package/dist/{security-2BA265LN.js → security-O4XGN2CM.js} +2 -2
  81. package/dist/{setup-DISPNDEK.js → setup-44WLBIOT.js} +209 -22
  82. package/dist/setup-44WLBIOT.js.map +1 -0
  83. package/dist/{speech-SG62JYIF.js → speech-GHTSWDAN.js} +2 -2
  84. package/dist/telegram-D7ASLVEB.js +7 -0
  85. package/dist/telegram-D7ASLVEB.js.map +1 -0
  86. package/dist/tunnel-ALJDPFDQ.js +10 -0
  87. package/dist/tunnel-ALJDPFDQ.js.map +1 -0
  88. package/dist/{tunnel-service-ZMO4THKE.js → tunnel-service-TBAHDXMF.js} +41 -547
  89. package/dist/tunnel-service-TBAHDXMF.js.map +1 -0
  90. package/package.json +1 -1
  91. package/dist/adapter-AWSI4GML.js +0 -13
  92. package/dist/api-server-5VNYFWJE.js +0 -7
  93. package/dist/chunk-237WYH6H.js.map +0 -1
  94. package/dist/chunk-3NAFXVQM.js.map +0 -1
  95. package/dist/chunk-4WXALZA3.js +0 -45
  96. package/dist/chunk-4WXALZA3.js.map +0 -1
  97. package/dist/chunk-5HKQCYOI.js.map +0 -1
  98. package/dist/chunk-5OCGO27U.js.map +0 -1
  99. package/dist/chunk-APS6UEFU.js.map +0 -1
  100. package/dist/chunk-BTJHGSLM.js.map +0 -1
  101. package/dist/chunk-FCTC7KDT.js.map +0 -1
  102. package/dist/chunk-GEOXPGCO.js.map +0 -1
  103. package/dist/chunk-KDU3ZEWT.js.map +0 -1
  104. package/dist/chunk-MITTQMGZ.js.map +0 -1
  105. package/dist/chunk-MPGEHTGE.js.map +0 -1
  106. package/dist/chunk-PA6MNBG4.js.map +0 -1
  107. package/dist/chunk-QWVHCTCA.js.map +0 -1
  108. package/dist/chunk-TMVTSWVH.js.map +0 -1
  109. package/dist/chunk-UCIZM5SW.js.map +0 -1
  110. package/dist/chunk-UWH7KIAA.js.map +0 -1
  111. package/dist/chunk-V2YZWYXT.js.map +0 -1
  112. package/dist/chunk-W4LK6WJP.js.map +0 -1
  113. package/dist/chunk-XBZIHNKV.js.map +0 -1
  114. package/dist/config-KN6NKKPF.js +0 -20
  115. package/dist/config-editor-76RVZS4B.js +0 -10
  116. package/dist/context-NXXW62NJ.js +0 -9
  117. package/dist/core-plugins-BPZY7SEB.js +0 -22
  118. package/dist/doctor-AV6AUO22.js +0 -9
  119. package/dist/install-cloudflared-JRJ4BSOM.js.map +0 -1
  120. package/dist/install-context-EHYV5WRY.js.map +0 -1
  121. package/dist/main-VEJCG5PY.js.map +0 -1
  122. package/dist/setup-DISPNDEK.js.map +0 -1
  123. package/dist/telegram-L3YM6SQJ.js +0 -7
  124. package/dist/tunnel-HWJ27WDH.js +0 -7
  125. package/dist/tunnel-service-ZMO4THKE.js.map +0 -1
  126. /package/dist/{adapter-AWSI4GML.js.map → adapter-ELG3VRZ3.js.map} +0 -0
  127. /package/dist/{agent-catalog-SZQQERV7.js.map → agent-catalog-UYD26QDK.js.map} +0 -0
  128. /package/dist/{api-client-XTLRRFPX.js.map → api-client-PEMHYL5U.js.map} +0 -0
  129. /package/dist/{api-server-5VNYFWJE.js.map → api-server-DATG2KBR.js.map} +0 -0
  130. /package/dist/{api-server-JLBDKCU4.js.map → api-server-L5Z7XACW.js.map} +0 -0
  131. /package/dist/{chunk-2HEFALTZ.js.map → chunk-7GXEMMEV.js.map} +0 -0
  132. /package/dist/{config-KN6NKKPF.js.map → config-X4UP7H6R.js.map} +0 -0
  133. /package/dist/{config-editor-76RVZS4B.js.map → config-editor-7BENRVG5.js.map} +0 -0
  134. /package/dist/{config-registry-ZXAIJNYB.js.map → config-registry-M3FFWEVM.js.map} +0 -0
  135. /package/dist/{context-NXXW62NJ.js.map → context-FVGCU5TI.js.map} +0 -0
  136. /package/dist/{core-plugins-BPZY7SEB.js.map → core-plugins-JSY2I44L.js.map} +0 -0
  137. /package/dist/{daemon-XFEMMJSZ.js.map → daemon-UOSRDEXW.js.map} +0 -0
  138. /package/dist/{doctor-AV6AUO22.js.map → doctor-6DLACBR4.js.map} +0 -0
  139. /package/dist/{file-service-HHB3JQIO.js.map → file-service-FQQYME7M.js.map} +0 -0
  140. /package/dist/{install-jq-ISTGT263.js.map → install-jq-SN4IA5K4.js.map} +0 -0
  141. /package/dist/{security-2BA265LN.js.map → instance-context-FLCE7VZ4.js.map} +0 -0
  142. /package/dist/{speech-SG62JYIF.js.map → instance-registry-SW5FWKHO.js.map} +0 -0
  143. /package/dist/{post-upgrade-Y26S2ZQ7.js.map → post-upgrade-F4YPMTUT.js.map} +0 -0
  144. /package/dist/{telegram-L3YM6SQJ.js.map → security-O4XGN2CM.js.map} +0 -0
  145. /package/dist/{tunnel-HWJ27WDH.js.map → speech-GHTSWDAN.js.map} +0 -0
@@ -1,9 +1,6 @@
1
1
  import {
2
2
  AgentCatalog
3
- } from "./chunk-V2YZWYXT.js";
4
- import {
5
- getAgentCapabilities
6
- } from "./chunk-ZSLHHQPQ.js";
3
+ } from "./chunk-MDJHCCFS.js";
7
4
  import {
8
5
  readTextFileWithRange
9
6
  } from "./chunk-OYSAN7UX.js";
@@ -12,6 +9,9 @@ import {
12
9
  createChildLogger,
13
10
  createSessionLogger
14
11
  } from "./chunk-R6KZYF7D.js";
12
+ import {
13
+ getAgentCapabilities
14
+ } from "./chunk-ZSLHHQPQ.js";
15
15
 
16
16
  // src/core/utils/streams.ts
17
17
  function nodeToWebWritable(nodeStream) {
@@ -1084,6 +1084,8 @@ var Session = class extends TypedEmitter {
1084
1084
  agentCapabilities;
1085
1085
  archiving = false;
1086
1086
  promptCount = 0;
1087
+ firstAgent;
1088
+ agentSwitchHistory = [];
1087
1089
  log;
1088
1090
  middlewareChain;
1089
1091
  permissionGate = new PermissionGate();
@@ -1095,6 +1097,7 @@ var Session = class extends TypedEmitter {
1095
1097
  this.id = opts.id || nanoid(12);
1096
1098
  this.channelId = opts.channelId;
1097
1099
  this.agentName = opts.agentName;
1100
+ this.firstAgent = opts.agentName;
1098
1101
  this.workingDirectory = opts.workingDirectory;
1099
1102
  this.agentInstance = opts.agentInstance;
1100
1103
  this.speechService = opts.speechService;
@@ -1176,6 +1179,7 @@ var Session = class extends TypedEmitter {
1176
1179
  }
1177
1180
  if (this._status === "finished") return;
1178
1181
  this.promptCount++;
1182
+ this.emit("prompt_count_changed", this.promptCount);
1179
1183
  if (this._status === "initializing" || this._status === "cancelled" || this._status === "error") {
1180
1184
  this.activate();
1181
1185
  }
@@ -1422,6 +1426,44 @@ ${result.text}` : result.text;
1422
1426
  this.log.info("Prompt aborted");
1423
1427
  await this.agentInstance.cancel();
1424
1428
  }
1429
+ /** Search backward through agentSwitchHistory for the last entry matching agentName */
1430
+ findLastSwitchEntry(agentName) {
1431
+ for (let i = this.agentSwitchHistory.length - 1; i >= 0; i--) {
1432
+ if (this.agentSwitchHistory[i].agentName === agentName) {
1433
+ return this.agentSwitchHistory[i];
1434
+ }
1435
+ }
1436
+ return void 0;
1437
+ }
1438
+ /** Switch the agent instance in-place, preserving session identity */
1439
+ async switchAgent(agentName, createAgent) {
1440
+ if (agentName === this.agentName) {
1441
+ throw new Error(`Already using ${agentName}`);
1442
+ }
1443
+ this.agentSwitchHistory.push({
1444
+ agentName: this.agentName,
1445
+ agentSessionId: this.agentSessionId,
1446
+ switchedAt: (/* @__PURE__ */ new Date()).toISOString(),
1447
+ promptCount: this.promptCount
1448
+ });
1449
+ this.queue.clear();
1450
+ if (this.permissionGate.isPending) {
1451
+ this.permissionGate.reject("Agent switched");
1452
+ }
1453
+ await this.agentInstance.destroy();
1454
+ const newAgent = await createAgent();
1455
+ this.agentInstance = newAgent;
1456
+ this.agentName = agentName;
1457
+ this.agentSessionId = newAgent.sessionId;
1458
+ this.promptCount = 0;
1459
+ this.agentCapabilities = void 0;
1460
+ this.currentMode = void 0;
1461
+ this.availableModes = [];
1462
+ this.currentModel = void 0;
1463
+ this.availableModels = [];
1464
+ this.configOptions = [];
1465
+ this.log.info({ from: this.agentSwitchHistory.at(-1).agentName, to: agentName }, "Agent switched");
1466
+ }
1425
1467
  async destroy() {
1426
1468
  this.log.info("Session destroyed");
1427
1469
  if (this.permissionGate.isPending) {
@@ -1609,6 +1651,7 @@ var SessionBridge = class {
1609
1651
  sessionEventHandler;
1610
1652
  statusChangeHandler;
1611
1653
  namedHandler;
1654
+ promptCountHandler;
1612
1655
  get tracer() {
1613
1656
  return this.session.agentInstance.debugTracer ?? null;
1614
1657
  }
@@ -1657,6 +1700,9 @@ var SessionBridge = class {
1657
1700
  if (this.namedHandler) {
1658
1701
  this.session.off("named", this.namedHandler);
1659
1702
  }
1703
+ if (this.promptCountHandler) {
1704
+ this.session.off("prompt_count_changed", this.promptCountHandler);
1705
+ }
1660
1706
  this.session.agentInstance.onPermissionRequest = async () => "";
1661
1707
  }
1662
1708
  wireAgentToSession() {
@@ -1941,6 +1987,10 @@ var SessionBridge = class {
1941
1987
  this.adapter.renameSessionThread(this.session.id, name);
1942
1988
  };
1943
1989
  this.session.on("named", this.namedHandler);
1990
+ this.promptCountHandler = (count) => {
1991
+ this.deps.sessionManager.patchRecord(this.session.id, { currentPromptCount: count });
1992
+ };
1993
+ this.session.on("prompt_count_changed", this.promptCountHandler);
1944
1994
  }
1945
1995
  };
1946
1996
 
@@ -2422,8 +2472,8 @@ var EventBus = class extends TypedEmitter {
2422
2472
  };
2423
2473
 
2424
2474
  // src/core/core.ts
2425
- import path5 from "path";
2426
- import os from "os";
2475
+ import path6 from "path";
2476
+ import os2 from "os";
2427
2477
 
2428
2478
  // src/core/sessions/session-store.ts
2429
2479
  import fs4 from "fs";
@@ -2467,9 +2517,15 @@ var JsonFileSessionStore = class {
2467
2517
  return void 0;
2468
2518
  }
2469
2519
  findByAgentSessionId(agentSessionId) {
2470
- return [...this.records.values()].find(
2471
- (r) => r.agentSessionId === agentSessionId || r.originalAgentSessionId === agentSessionId
2472
- );
2520
+ for (const record of this.records.values()) {
2521
+ if (record.agentSessionId === agentSessionId || record.originalAgentSessionId === agentSessionId) {
2522
+ return record;
2523
+ }
2524
+ if (record.agentSwitchHistory?.some((e) => e.agentSessionId === agentSessionId)) {
2525
+ return record;
2526
+ }
2527
+ }
2528
+ return void 0;
2473
2529
  }
2474
2530
  list(channelId) {
2475
2531
  const all = [...this.records.values()];
@@ -2796,6 +2852,10 @@ var ErrorTracker = class {
2796
2852
  }
2797
2853
  };
2798
2854
 
2855
+ // src/core/plugin/plugin-context.ts
2856
+ import path5 from "path";
2857
+ import os from "os";
2858
+
2799
2859
  // src/core/plugin/plugin-storage.ts
2800
2860
  import fs5 from "fs";
2801
2861
  import path4 from "path";
@@ -2867,6 +2927,7 @@ function createPluginContext(opts) {
2867
2927
  config,
2868
2928
  core
2869
2929
  } = opts;
2930
+ const instanceRoot = opts.instanceRoot ?? path5.join(os.homedir(), ".openacp");
2870
2931
  const registeredListeners = [];
2871
2932
  const registeredCommands = [];
2872
2933
  const noopLog = {
@@ -2975,6 +3036,7 @@ function createPluginContext(opts) {
2975
3036
  requirePermission(permissions, "kernel:access", "core");
2976
3037
  return core;
2977
3038
  },
3039
+ instanceRoot,
2978
3040
  cleanup() {
2979
3041
  for (const { event, handler } of registeredListeners) {
2980
3042
  eventBus.off(event, handler);
@@ -3049,6 +3111,7 @@ var LifecycleManager = class {
3049
3111
  log;
3050
3112
  settingsManager;
3051
3113
  pluginRegistry;
3114
+ instanceRoot;
3052
3115
  contexts = /* @__PURE__ */ new Map();
3053
3116
  loadOrder = [];
3054
3117
  _loaded = /* @__PURE__ */ new Set();
@@ -3081,6 +3144,7 @@ var LifecycleManager = class {
3081
3144
  this.log = opts?.log;
3082
3145
  this.settingsManager = opts?.settingsManager;
3083
3146
  this.pluginRegistry = opts?.pluginRegistry;
3147
+ this.instanceRoot = opts?.instanceRoot;
3084
3148
  }
3085
3149
  getPluginLogger(pluginName) {
3086
3150
  if (this.log && typeof this.log.child === "function") {
@@ -3190,7 +3254,8 @@ var LifecycleManager = class {
3190
3254
  sessions: this.sessions,
3191
3255
  config: this.config,
3192
3256
  core: this.core,
3193
- log: this.log
3257
+ log: this.log,
3258
+ instanceRoot: this.instanceRoot
3194
3259
  });
3195
3260
  try {
3196
3261
  await withTimeout(plugin.setup(ctx), SETUP_TIMEOUT_MS, `${plugin.name}.setup()`);
@@ -3255,14 +3320,18 @@ var OpenACPCore = class {
3255
3320
  sessionManager;
3256
3321
  messageTransformer;
3257
3322
  adapters = /* @__PURE__ */ new Map();
3323
+ /** sessionId → SessionBridge — tracks active bridges for disconnect/reconnect during agent switch */
3324
+ bridges = /* @__PURE__ */ new Map();
3258
3325
  /** Set by main.ts — triggers graceful shutdown with restart exit code */
3259
3326
  requestRestart = null;
3260
3327
  _tunnelService;
3261
3328
  sessionStore = null;
3262
3329
  resumeLocks = /* @__PURE__ */ new Map();
3330
+ switchingLocks = /* @__PURE__ */ new Set();
3263
3331
  eventBus;
3264
3332
  sessionFactory;
3265
3333
  lifecycleManager;
3334
+ instanceContext;
3266
3335
  // --- Lazy getters: resolve from ServiceRegistry (populated by plugins during boot) ---
3267
3336
  getService(name) {
3268
3337
  const svc = this.lifecycleManager.serviceRegistry.get(name);
@@ -3284,13 +3353,14 @@ var OpenACPCore = class {
3284
3353
  get contextManager() {
3285
3354
  return this.getService("context");
3286
3355
  }
3287
- constructor(configManager) {
3356
+ constructor(configManager, ctx) {
3288
3357
  this.configManager = configManager;
3358
+ this.instanceContext = ctx;
3289
3359
  const config = configManager.get();
3290
3360
  this.agentCatalog = new AgentCatalog();
3291
3361
  this.agentCatalog.load();
3292
3362
  this.agentManager = new AgentManager(this.agentCatalog);
3293
- const storePath = path5.join(os.homedir(), ".openacp", "sessions.json");
3363
+ const storePath = ctx?.paths.sessions ?? path6.join(os2.homedir(), ".openacp", "sessions.json");
3294
3364
  this.sessionStore = new JsonFileSessionStore(
3295
3365
  storePath,
3296
3366
  config.sessionStore.ttlDays
@@ -3313,7 +3383,7 @@ var OpenACPCore = class {
3313
3383
  sessions: this.sessionManager,
3314
3384
  config: this.configManager,
3315
3385
  core: this,
3316
- storagePath: path5.join(os.homedir(), ".openacp", "plugins", "data"),
3386
+ storagePath: ctx?.paths.pluginsData ?? path6.join(os2.homedir(), ".openacp", "plugins", "data"),
3317
3387
  log: createChildLogger({ module: "plugin" })
3318
3388
  });
3319
3389
  this.sessionFactory.middlewareChain = this.lifecycleManager.middlewareChain;
@@ -3502,7 +3572,10 @@ var OpenACPCore = class {
3502
3572
  createdAt: session.createdAt.toISOString(),
3503
3573
  lastActiveAt: (/* @__PURE__ */ new Date()).toISOString(),
3504
3574
  name: session.name,
3505
- platform
3575
+ platform,
3576
+ firstAgent: session.firstAgent,
3577
+ currentPromptCount: session.promptCount,
3578
+ agentSwitchHistory: session.agentSwitchHistory
3506
3579
  });
3507
3580
  log6.info(
3508
3581
  { sessionId: session.id, agentName: params.agentName },
@@ -3675,6 +3748,117 @@ var OpenACPCore = class {
3675
3748
  }
3676
3749
  return { session, contextResult };
3677
3750
  }
3751
+ // --- Agent Switch ---
3752
+ async switchSessionAgent(sessionId, toAgent) {
3753
+ if (this.switchingLocks.has(sessionId)) {
3754
+ throw new Error("Switch already in progress");
3755
+ }
3756
+ this.switchingLocks.add(sessionId);
3757
+ try {
3758
+ return await this._doSwitchSessionAgent(sessionId, toAgent);
3759
+ } finally {
3760
+ this.switchingLocks.delete(sessionId);
3761
+ }
3762
+ }
3763
+ async _doSwitchSessionAgent(sessionId, toAgent) {
3764
+ const session = this.sessionManager.getSession(sessionId);
3765
+ if (!session) throw new Error(`Session ${sessionId} not found`);
3766
+ const agentDef = this.agentManager.getAgent(toAgent);
3767
+ if (!agentDef) throw new Error(`Agent "${toAgent}" is not installed`);
3768
+ const fromAgent = session.agentName;
3769
+ const middlewareChain = this.lifecycleManager.middlewareChain;
3770
+ const result = await middlewareChain.execute("agent:beforeSwitch", {
3771
+ sessionId,
3772
+ fromAgent,
3773
+ toAgent
3774
+ }, async (payload) => payload);
3775
+ if (!result) throw new Error("Agent switch blocked by middleware");
3776
+ const lastEntry = session.findLastSwitchEntry(toAgent);
3777
+ const caps = getAgentCapabilities(toAgent);
3778
+ const canResume = !!(lastEntry && caps.supportsResume && lastEntry.promptCount === 0);
3779
+ const resumed = canResume;
3780
+ const bridge = this.bridges.get(sessionId);
3781
+ if (bridge) bridge.disconnect();
3782
+ const switchAdapter = this.adapters.get(session.channelId);
3783
+ if (switchAdapter?.sendSkillCommands) {
3784
+ await switchAdapter.sendSkillCommands(session.id, []);
3785
+ }
3786
+ if (switchAdapter?.cleanupSessionState) {
3787
+ await switchAdapter.cleanupSessionState(session.id);
3788
+ }
3789
+ const fromAgentSessionId = session.agentSessionId;
3790
+ try {
3791
+ await session.switchAgent(toAgent, async () => {
3792
+ if (canResume) {
3793
+ return this.agentManager.resume(toAgent, session.workingDirectory, lastEntry.agentSessionId);
3794
+ } else {
3795
+ const instance = await this.agentManager.spawn(toAgent, session.workingDirectory);
3796
+ try {
3797
+ const contextService = this.lifecycleManager.serviceRegistry.get("context");
3798
+ if (contextService) {
3799
+ const config = this.configManager.get();
3800
+ const labelAgent = config.agentSwitch?.labelHistory ?? true;
3801
+ const contextResult = await contextService.buildContext(
3802
+ { type: "session", value: sessionId, repoPath: session.workingDirectory },
3803
+ { labelAgent }
3804
+ );
3805
+ if (contextResult?.markdown) {
3806
+ session.setContext(contextResult.markdown);
3807
+ }
3808
+ }
3809
+ } catch {
3810
+ }
3811
+ return instance;
3812
+ }
3813
+ });
3814
+ } catch (err) {
3815
+ try {
3816
+ let rollbackInstance;
3817
+ try {
3818
+ rollbackInstance = await this.agentManager.resume(fromAgent, session.workingDirectory, fromAgentSessionId);
3819
+ } catch {
3820
+ rollbackInstance = await this.agentManager.spawn(fromAgent, session.workingDirectory);
3821
+ }
3822
+ const oldInstance = rollbackInstance;
3823
+ session.agentSwitchHistory.pop();
3824
+ session.agentInstance = oldInstance;
3825
+ session.agentName = fromAgent;
3826
+ session.agentSessionId = oldInstance.sessionId;
3827
+ const adapter = this.adapters.get(session.channelId);
3828
+ if (adapter) {
3829
+ const rollbackBridge = this.createBridge(session, adapter);
3830
+ rollbackBridge.connect();
3831
+ }
3832
+ log6.warn({ sessionId, fromAgent, toAgent, err }, "Agent switch failed, rolled back to previous agent");
3833
+ } catch (rollbackErr) {
3834
+ session.fail(`Switch failed and rollback failed: ${rollbackErr instanceof Error ? rollbackErr.message : String(rollbackErr)}`);
3835
+ log6.error({ sessionId, fromAgent, toAgent, err, rollbackErr }, "Agent switch failed and rollback also failed");
3836
+ }
3837
+ throw err;
3838
+ }
3839
+ if (bridge) {
3840
+ const adapter = this.adapters.get(session.channelId);
3841
+ if (adapter) {
3842
+ const newBridge = this.createBridge(session, adapter);
3843
+ newBridge.connect();
3844
+ }
3845
+ }
3846
+ await this.sessionManager.patchRecord(sessionId, {
3847
+ agentName: toAgent,
3848
+ agentSessionId: session.agentSessionId,
3849
+ firstAgent: session.firstAgent,
3850
+ currentPromptCount: 0,
3851
+ agentSwitchHistory: session.agentSwitchHistory
3852
+ });
3853
+ middlewareChain.execute("agent:afterSwitch", {
3854
+ sessionId,
3855
+ fromAgent,
3856
+ toAgent,
3857
+ resumed
3858
+ }, async (p) => p).catch(() => {
3859
+ });
3860
+ return { resumed };
3861
+ }
3678
3862
  // --- Lazy Resume ---
3679
3863
  /**
3680
3864
  * Get active session by thread, or attempt lazy resume from store.
@@ -3734,6 +3918,9 @@ var OpenACPCore = class {
3734
3918
  });
3735
3919
  session.activate();
3736
3920
  session.dangerousMode = record.dangerousMode ?? false;
3921
+ if (record.firstAgent) session.firstAgent = record.firstAgent;
3922
+ if (record.agentSwitchHistory) session.agentSwitchHistory = record.agentSwitchHistory;
3923
+ if (record.currentPromptCount != null) session.promptCount = record.currentPromptCount;
3737
3924
  log6.info(
3738
3925
  { sessionId: session.id, threadId: message.threadId },
3739
3926
  "Lazy resume successful"
@@ -3762,7 +3949,7 @@ var OpenACPCore = class {
3762
3949
  // --- Event Wiring ---
3763
3950
  /** Create a SessionBridge for the given session and adapter */
3764
3951
  createBridge(session, adapter) {
3765
- return new SessionBridge(session, adapter, {
3952
+ const bridge = new SessionBridge(session, adapter, {
3766
3953
  messageTransformer: this.messageTransformer,
3767
3954
  notificationManager: this.notificationManager,
3768
3955
  sessionManager: this.sessionManager,
@@ -3770,6 +3957,8 @@ var OpenACPCore = class {
3770
3957
  fileService: this.fileService,
3771
3958
  middlewareChain: this.lifecycleManager?.middlewareChain
3772
3959
  });
3960
+ this.bridges.set(session.id, bridge);
3961
+ return bridge;
3773
3962
  }
3774
3963
  };
3775
3964
 
@@ -3914,4 +4103,4 @@ export {
3914
4103
  OpenACPCore,
3915
4104
  CommandRegistry
3916
4105
  };
3917
- //# sourceMappingURL=chunk-UCIZM5SW.js.map
4106
+ //# sourceMappingURL=chunk-LRV56K2M.js.map