@openacp/cli 2026.403.7 → 2026.404.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.
package/dist/index.js CHANGED
@@ -1078,7 +1078,7 @@ var BYPASS_KEYWORDS;
1078
1078
  var init_bypass_detection = __esm({
1079
1079
  "src/core/utils/bypass-detection.ts"() {
1080
1080
  "use strict";
1081
- BYPASS_KEYWORDS = ["bypass", "dangerous", "auto_accept"];
1081
+ BYPASS_KEYWORDS = ["bypass", "dangerous", "auto_accept", "yolo"];
1082
1082
  }
1083
1083
  });
1084
1084
 
@@ -8362,7 +8362,7 @@ var init_commands = __esm({
8362
8362
 
8363
8363
  // src/plugins/telegram/permissions.ts
8364
8364
  import { InlineKeyboard as InlineKeyboard11 } from "grammy";
8365
- import { nanoid as nanoid2 } from "nanoid";
8365
+ import { nanoid as nanoid3 } from "nanoid";
8366
8366
  var log30, PermissionHandler;
8367
8367
  var init_permissions = __esm({
8368
8368
  "src/plugins/telegram/permissions.ts"() {
@@ -8381,7 +8381,7 @@ var init_permissions = __esm({
8381
8381
  pending = /* @__PURE__ */ new Map();
8382
8382
  async sendPermissionRequest(session, request) {
8383
8383
  const threadId = Number(session.threadId);
8384
- const callbackKey = nanoid2(8);
8384
+ const callbackKey = nanoid3(8);
8385
8385
  this.pending.set(callbackKey, {
8386
8386
  sessionId: session.id,
8387
8387
  requestId: request.id,
@@ -11182,6 +11182,7 @@ var AgentInstance = class _AgentInstance extends TypedEmitter {
11182
11182
  { sessionId: this.sessionId, exitCode: code, signal },
11183
11183
  "Agent process exited"
11184
11184
  );
11185
+ if (signal === "SIGINT" || signal === "SIGTERM") return;
11185
11186
  if (code !== 0 && code !== null || signal) {
11186
11187
  const stderr = this.stderrCapture.getLastLines();
11187
11188
  this.emit("agent_event", {
@@ -11211,12 +11212,18 @@ ${stderr}`
11211
11212
  cwd: workingDirectory,
11212
11213
  mcpServers: resolvedMcp
11213
11214
  });
11215
+ log4.info(response, "newSession response");
11214
11216
  instance.sessionId = response.sessionId;
11215
11217
  instance.initialSessionResponse = response;
11216
11218
  instance.debugTracer = createDebugTracer(response.sessionId, workingDirectory);
11217
11219
  instance.setupCrashDetection();
11218
11220
  log4.info(
11219
- { sessionId: response.sessionId, durationMs: Date.now() - spawnStart },
11221
+ {
11222
+ sessionId: response.sessionId,
11223
+ durationMs: Date.now() - spawnStart,
11224
+ configOptions: response.configOptions ?? [],
11225
+ agentCapabilities: instance.agentCapabilities ?? null
11226
+ },
11220
11227
  "Agent spawn complete"
11221
11228
  );
11222
11229
  return instance;
@@ -11228,24 +11235,47 @@ ${stderr}`
11228
11235
  agentDef,
11229
11236
  workingDirectory
11230
11237
  );
11238
+ const resolvedMcp = _AgentInstance.mcpManager.resolve(mcpServers);
11231
11239
  try {
11232
- const response = await instance.connection.unstable_resumeSession({
11233
- sessionId: agentSessionId,
11234
- cwd: workingDirectory
11235
- });
11236
- instance.sessionId = response.sessionId;
11237
- instance.initialSessionResponse = response;
11238
- instance.debugTracer = createDebugTracer(response.sessionId, workingDirectory);
11239
- log4.info(
11240
- { sessionId: response.sessionId, durationMs: Date.now() - spawnStart },
11241
- "Agent resume complete"
11242
- );
11240
+ if (instance.agentCapabilities?.loadSession) {
11241
+ const response = await instance.connection.loadSession({
11242
+ sessionId: agentSessionId,
11243
+ cwd: workingDirectory,
11244
+ mcpServers: resolvedMcp
11245
+ });
11246
+ instance.sessionId = agentSessionId;
11247
+ instance.initialSessionResponse = response;
11248
+ instance.debugTracer = createDebugTracer(agentSessionId, workingDirectory);
11249
+ log4.info(
11250
+ {
11251
+ sessionId: agentSessionId,
11252
+ durationMs: Date.now() - spawnStart,
11253
+ agentCapabilities: instance.agentCapabilities ?? null
11254
+ },
11255
+ "Agent load complete"
11256
+ );
11257
+ } else {
11258
+ const response = await instance.connection.unstable_resumeSession({
11259
+ sessionId: agentSessionId,
11260
+ cwd: workingDirectory
11261
+ });
11262
+ instance.sessionId = response.sessionId;
11263
+ instance.initialSessionResponse = response;
11264
+ instance.debugTracer = createDebugTracer(response.sessionId, workingDirectory);
11265
+ log4.info(
11266
+ {
11267
+ sessionId: response.sessionId,
11268
+ durationMs: Date.now() - spawnStart,
11269
+ agentCapabilities: instance.agentCapabilities ?? null
11270
+ },
11271
+ "Agent resume complete"
11272
+ );
11273
+ }
11243
11274
  } catch (err) {
11244
11275
  log4.warn(
11245
11276
  { err, agentSessionId },
11246
11277
  "Resume failed, falling back to new session"
11247
11278
  );
11248
- const resolvedMcp = _AgentInstance.mcpManager.resolve(mcpServers);
11249
11279
  const response = await instance.connection.newSession({
11250
11280
  cwd: workingDirectory,
11251
11281
  mcpServers: resolvedMcp
@@ -11476,11 +11506,31 @@ ${stderr}`
11476
11506
  }
11477
11507
  // ── New ACP methods ──────────────────────────────────────────────────
11478
11508
  async setConfigOption(configId, value) {
11479
- return await this.connection.setSessionConfigOption({
11480
- sessionId: this.sessionId,
11481
- configId,
11482
- ...value
11483
- });
11509
+ try {
11510
+ return await this.connection.setSessionConfigOption({
11511
+ sessionId: this.sessionId,
11512
+ configId,
11513
+ ...value
11514
+ });
11515
+ } catch (err) {
11516
+ if (typeof err === "object" && err !== null && err.code === -32601) {
11517
+ if (configId === "mode" && value.type === "select") {
11518
+ await this.connection.setSessionMode({
11519
+ sessionId: this.sessionId,
11520
+ modeId: value.value
11521
+ });
11522
+ return { configOptions: [] };
11523
+ }
11524
+ if (configId === "model" && value.type === "select") {
11525
+ await this.connection.unstable_setSessionModel({
11526
+ sessionId: this.sessionId,
11527
+ modelId: value.value
11528
+ });
11529
+ return { configOptions: [] };
11530
+ }
11531
+ }
11532
+ throw err;
11533
+ }
11484
11534
  }
11485
11535
  async listSessions(cwd, cursor) {
11486
11536
  return await this.connection.listSessions({
@@ -11608,7 +11658,7 @@ var AgentManager = class {
11608
11658
  };
11609
11659
 
11610
11660
  // src/core/sessions/session.ts
11611
- import { nanoid } from "nanoid";
11661
+ import { nanoid as nanoid2 } from "nanoid";
11612
11662
 
11613
11663
  // src/core/sessions/prompt-queue.ts
11614
11664
  var PromptQueue = class {
@@ -11619,21 +11669,21 @@ var PromptQueue = class {
11619
11669
  queue = [];
11620
11670
  processing = false;
11621
11671
  abortController = null;
11622
- async enqueue(text3, attachments) {
11672
+ async enqueue(text3, attachments, routing) {
11623
11673
  if (this.processing) {
11624
11674
  return new Promise((resolve6) => {
11625
- this.queue.push({ text: text3, attachments, resolve: resolve6 });
11675
+ this.queue.push({ text: text3, attachments, routing, resolve: resolve6 });
11626
11676
  });
11627
11677
  }
11628
- await this.process(text3, attachments);
11678
+ await this.process(text3, attachments, routing);
11629
11679
  }
11630
- async process(text3, attachments) {
11680
+ async process(text3, attachments, routing) {
11631
11681
  this.processing = true;
11632
11682
  this.abortController = new AbortController();
11633
11683
  const { signal } = this.abortController;
11634
11684
  try {
11635
11685
  await Promise.race([
11636
- this.processor(text3, attachments),
11686
+ this.processor(text3, attachments, routing),
11637
11687
  new Promise((_, reject) => {
11638
11688
  signal.addEventListener("abort", () => reject(new Error("Prompt aborted")), { once: true });
11639
11689
  })
@@ -11651,7 +11701,7 @@ var PromptQueue = class {
11651
11701
  drainNext() {
11652
11702
  const next = this.queue.shift();
11653
11703
  if (next) {
11654
- this.process(next.text, next.attachments).then(next.resolve);
11704
+ this.process(next.text, next.attachments, next.routing).then(next.resolve);
11655
11705
  }
11656
11706
  }
11657
11707
  clear() {
@@ -11741,6 +11791,33 @@ var PermissionGate = class {
11741
11791
  // src/core/sessions/session.ts
11742
11792
  init_log();
11743
11793
  import * as fs10 from "fs";
11794
+
11795
+ // src/core/sessions/turn-context.ts
11796
+ import { nanoid } from "nanoid";
11797
+ function createTurnContext(sourceAdapterId, responseAdapterId) {
11798
+ return {
11799
+ turnId: nanoid(8),
11800
+ sourceAdapterId,
11801
+ responseAdapterId
11802
+ };
11803
+ }
11804
+ function getEffectiveTarget(ctx) {
11805
+ if (ctx.responseAdapterId === null) return null;
11806
+ return ctx.responseAdapterId ?? ctx.sourceAdapterId;
11807
+ }
11808
+ var SYSTEM_EVENT_TYPES = /* @__PURE__ */ new Set([
11809
+ "session_end",
11810
+ "system_message",
11811
+ "session_info_update",
11812
+ "config_option_update",
11813
+ "commands_update",
11814
+ "tts_strip"
11815
+ ]);
11816
+ function isSystemEvent(event) {
11817
+ return SYSTEM_EVENT_TYPES.has(event.type);
11818
+ }
11819
+
11820
+ // src/core/sessions/session.ts
11744
11821
  var moduleLog = createChildLogger({ module: "session" });
11745
11822
  var TTS_PROMPT_INSTRUCTION = `
11746
11823
 
@@ -11758,7 +11835,15 @@ var VALID_TRANSITIONS = {
11758
11835
  var Session = class extends TypedEmitter {
11759
11836
  id;
11760
11837
  channelId;
11761
- threadId = "";
11838
+ /** @deprecated Use threadIds map directly. Getter returns primary adapter's threadId. */
11839
+ get threadId() {
11840
+ return this.threadIds.get(this.channelId) ?? "";
11841
+ }
11842
+ set threadId(value) {
11843
+ if (value) {
11844
+ this.threadIds.set(this.channelId, value);
11845
+ }
11846
+ }
11762
11847
  agentName;
11763
11848
  workingDirectory;
11764
11849
  agentInstance;
@@ -11779,14 +11864,21 @@ var Session = class extends TypedEmitter {
11779
11864
  middlewareChain;
11780
11865
  /** Latest commands emitted by the agent — buffered before bridge connects so they're not lost */
11781
11866
  latestCommands = null;
11867
+ /** Adapters currently attached to this session (including primary) */
11868
+ attachedAdapters = [];
11869
+ /** Per-adapter thread IDs: adapterId → threadId */
11870
+ threadIds = /* @__PURE__ */ new Map();
11871
+ /** Active turn context — sealed on prompt dequeue, cleared on turn end */
11872
+ activeTurnContext = null;
11782
11873
  permissionGate = new PermissionGate();
11783
11874
  queue;
11784
11875
  speechService;
11785
11876
  pendingContext = null;
11786
11877
  constructor(opts) {
11787
11878
  super();
11788
- this.id = opts.id || nanoid(12);
11879
+ this.id = opts.id || nanoid2(12);
11789
11880
  this.channelId = opts.channelId;
11881
+ this.attachedAdapters = [opts.channelId];
11790
11882
  this.agentName = opts.agentName;
11791
11883
  this.firstAgent = opts.agentName;
11792
11884
  this.workingDirectory = opts.workingDirectory;
@@ -11796,18 +11888,28 @@ var Session = class extends TypedEmitter {
11796
11888
  this.log = createSessionLogger(this.id, moduleLog);
11797
11889
  this.log.info({ agentName: this.agentName }, "Session created");
11798
11890
  this.queue = new PromptQueue(
11799
- (text3, attachments) => this.processPrompt(text3, attachments),
11891
+ (text3, attachments, routing) => this.processPrompt(text3, attachments, routing),
11800
11892
  (err) => {
11801
11893
  this.log.error({ err }, "Prompt execution failed");
11802
11894
  const message = err instanceof Error ? err.message : String(err);
11895
+ this.fail(message);
11803
11896
  this.emit("agent_event", { type: "error", message: `Prompt execution failed: ${message}` });
11804
11897
  }
11805
11898
  );
11806
- this.agentInstance.on("agent_event", (event) => {
11899
+ this.wireCommandsBuffer();
11900
+ }
11901
+ /** Wire a listener on the current agentInstance to buffer commands_update events.
11902
+ * Must be called after every agentInstance replacement (constructor + switchAgent). */
11903
+ commandsBufferCleanup;
11904
+ wireCommandsBuffer() {
11905
+ this.commandsBufferCleanup?.();
11906
+ const handler = (event) => {
11807
11907
  if (event.type === "commands_update") {
11808
11908
  this.latestCommands = event.commands;
11809
11909
  }
11810
- });
11910
+ };
11911
+ this.agentInstance.on("agent_event", handler);
11912
+ this.commandsBufferCleanup = () => this.agentInstance.off("agent_event", handler);
11811
11913
  }
11812
11914
  // --- State Machine ---
11813
11915
  get status() {
@@ -11861,7 +11963,7 @@ var Session = class extends TypedEmitter {
11861
11963
  this.log.info({ voiceMode: mode }, "TTS mode changed");
11862
11964
  }
11863
11965
  // --- Public API ---
11864
- async enqueuePrompt(text3, attachments) {
11966
+ async enqueuePrompt(text3, attachments, routing) {
11865
11967
  if (this.middlewareChain) {
11866
11968
  const payload = { text: text3, attachments, sessionId: this.id };
11867
11969
  const result = await this.middlewareChain.execute("agent:beforePrompt", payload, async (p) => p);
@@ -11869,10 +11971,14 @@ var Session = class extends TypedEmitter {
11869
11971
  text3 = result.text;
11870
11972
  attachments = result.attachments;
11871
11973
  }
11872
- await this.queue.enqueue(text3, attachments);
11974
+ await this.queue.enqueue(text3, attachments, routing);
11873
11975
  }
11874
- async processPrompt(text3, attachments) {
11976
+ async processPrompt(text3, attachments, routing) {
11875
11977
  if (this._status === "finished") return;
11978
+ this.activeTurnContext = createTurnContext(
11979
+ routing?.sourceAdapterId ?? this.channelId,
11980
+ routing?.responseAdapterId
11981
+ );
11876
11982
  this.promptCount++;
11877
11983
  this.emit("prompt_count_changed", this.promptCount);
11878
11984
  if (this._status === "initializing" || this._status === "cancelled" || this._status === "error") {
@@ -11939,6 +12045,7 @@ ${text3}`;
11939
12045
  this.log.warn({ err }, "TTS post-processing failed");
11940
12046
  });
11941
12047
  }
12048
+ this.activeTurnContext = null;
11942
12049
  if (!this.name) {
11943
12050
  await this.autoName();
11944
12051
  }
@@ -12054,6 +12161,42 @@ ${result.text}` : result.text;
12054
12161
  setAgentCapabilities(caps) {
12055
12162
  this.agentCapabilities = caps;
12056
12163
  }
12164
+ /**
12165
+ * Hydrate configOptions and agentCapabilities from a spawn response.
12166
+ * Handles both the native configOptions format and legacy modes/models fields.
12167
+ */
12168
+ applySpawnResponse(resp, caps) {
12169
+ if (caps) this.agentCapabilities = caps;
12170
+ if (!resp) return;
12171
+ if (resp.configOptions) {
12172
+ this.configOptions = resp.configOptions;
12173
+ return;
12174
+ }
12175
+ const legacyOptions = [];
12176
+ if (resp.modes) {
12177
+ const m = resp.modes;
12178
+ legacyOptions.push({
12179
+ id: "mode",
12180
+ name: "Mode",
12181
+ category: "mode",
12182
+ type: "select",
12183
+ currentValue: m.currentModeId,
12184
+ options: m.availableModes.map((x) => ({ value: x.id, name: x.name, description: x.description }))
12185
+ });
12186
+ }
12187
+ if (resp.models) {
12188
+ const m = resp.models;
12189
+ legacyOptions.push({
12190
+ id: "model",
12191
+ name: "Model",
12192
+ category: "model",
12193
+ type: "select",
12194
+ currentValue: m.currentModelId,
12195
+ options: m.availableModels.map((x) => ({ value: x.modelId ?? x.id, name: x.name, description: x.description }))
12196
+ });
12197
+ }
12198
+ if (legacyOptions.length > 0) this.configOptions = legacyOptions;
12199
+ }
12057
12200
  getConfigOption(id) {
12058
12201
  return this.configOptions.find((o) => o.id === id);
12059
12202
  }
@@ -12073,8 +12216,13 @@ ${result.text}` : result.text;
12073
12216
  /** Send a config option change to the agent and update local state from the response. */
12074
12217
  async setConfigOption(configId, value) {
12075
12218
  const response = await this.agentInstance.setConfigOption(configId, value);
12076
- if (response.configOptions) {
12219
+ if (response.configOptions && response.configOptions.length > 0) {
12077
12220
  await this.updateConfigOptions(response.configOptions);
12221
+ } else if (value.type === "select") {
12222
+ const updated = this.configOptions.map(
12223
+ (o) => o.id === configId && o.type === "select" ? { ...o, currentValue: value.value } : o
12224
+ );
12225
+ await this.updateConfigOptions(updated);
12078
12226
  }
12079
12227
  }
12080
12228
  async updateConfigOptions(options) {
@@ -12138,6 +12286,9 @@ ${result.text}` : result.text;
12138
12286
  this.promptCount = 0;
12139
12287
  this.agentCapabilities = void 0;
12140
12288
  this.configOptions = [];
12289
+ this.latestCommands = null;
12290
+ this.applySpawnResponse(newAgent.initialSessionResponse, newAgent.agentCapabilities);
12291
+ this.wireCommandsBuffer();
12141
12292
  this.log.info({ from: this.agentSwitchHistory.at(-1).agentName, to: agentName }, "Agent switched");
12142
12293
  }
12143
12294
  async destroy() {
@@ -12605,6 +12756,8 @@ var SessionManager = class {
12605
12756
  }
12606
12757
  getSessionByThread(channelId, threadId) {
12607
12758
  for (const session of this.sessions.values()) {
12759
+ const adapterThread = session.threadIds.get(channelId);
12760
+ if (adapterThread === threadId) return session;
12608
12761
  if (session.channelId === channelId && session.threadId === threadId) {
12609
12762
  return session;
12610
12763
  }
@@ -12672,6 +12825,67 @@ var SessionManager = class {
12672
12825
  if (channelId) return all.filter((s) => s.channelId === channelId);
12673
12826
  return all;
12674
12827
  }
12828
+ listAllSessions(channelId) {
12829
+ if (this.store) {
12830
+ let records = this.store.list();
12831
+ if (channelId) records = records.filter((r) => r.channelId === channelId);
12832
+ return records.map((record) => {
12833
+ const live2 = this.sessions.get(record.sessionId);
12834
+ if (live2) {
12835
+ return {
12836
+ id: live2.id,
12837
+ agent: live2.agentName,
12838
+ status: live2.status,
12839
+ name: live2.name ?? null,
12840
+ workspace: live2.workingDirectory,
12841
+ channelId: live2.channelId,
12842
+ createdAt: live2.createdAt.toISOString(),
12843
+ lastActiveAt: record.lastActiveAt ?? null,
12844
+ dangerousMode: live2.clientOverrides.bypassPermissions ?? false,
12845
+ queueDepth: live2.queueDepth,
12846
+ promptRunning: live2.promptRunning,
12847
+ configOptions: live2.configOptions?.length ? live2.configOptions : void 0,
12848
+ capabilities: live2.agentCapabilities ?? null,
12849
+ isLive: true
12850
+ };
12851
+ }
12852
+ return {
12853
+ id: record.sessionId,
12854
+ agent: record.agentName,
12855
+ status: record.status,
12856
+ name: record.name ?? null,
12857
+ workspace: record.workingDir,
12858
+ channelId: record.channelId,
12859
+ createdAt: record.createdAt,
12860
+ lastActiveAt: record.lastActiveAt ?? null,
12861
+ dangerousMode: record.clientOverrides?.bypassPermissions ?? false,
12862
+ queueDepth: 0,
12863
+ promptRunning: false,
12864
+ configOptions: record.acpState?.configOptions,
12865
+ capabilities: record.acpState?.agentCapabilities ?? null,
12866
+ isLive: false
12867
+ };
12868
+ });
12869
+ }
12870
+ let live = Array.from(this.sessions.values());
12871
+ if (channelId) live = live.filter((s) => s.channelId === channelId);
12872
+ return live.map((s) => ({
12873
+ id: s.id,
12874
+ agent: s.agentName,
12875
+ status: s.status,
12876
+ name: s.name ?? null,
12877
+ workspace: s.workingDirectory,
12878
+ channelId: s.channelId,
12879
+ createdAt: s.createdAt.toISOString(),
12880
+ lastActiveAt: null,
12881
+ dangerousMode: s.clientOverrides.bypassPermissions ?? false,
12882
+ queueDepth: s.queueDepth,
12883
+ promptRunning: s.promptRunning,
12884
+ configOptions: s.configOptions?.length ? s.configOptions : void 0,
12885
+ capabilities: s.agentCapabilities ?? null,
12886
+ isLive: true
12887
+ }));
12888
+ }
12675
12889
  listRecords(filter) {
12676
12890
  if (!this.store) return [];
12677
12891
  let records = this.store.list();
@@ -12694,7 +12908,14 @@ var SessionManager = class {
12694
12908
  for (const session of this.sessions.values()) {
12695
12909
  const record = this.store.get(session.id);
12696
12910
  if (record) {
12697
- await this.store.save({ ...record, status: "finished" });
12911
+ await this.store.save({
12912
+ ...record,
12913
+ status: "finished",
12914
+ acpState: session.toAcpStateSnapshot(),
12915
+ clientOverrides: session.clientOverrides,
12916
+ currentPromptCount: session.promptCount,
12917
+ agentSwitchHistory: session.agentSwitchHistory
12918
+ });
12698
12919
  }
12699
12920
  }
12700
12921
  this.store.flush();
@@ -12704,6 +12925,8 @@ var SessionManager = class {
12704
12925
  /**
12705
12926
  * Forcefully destroy all sessions (kill agent subprocesses).
12706
12927
  * Use only when sessions must be fully torn down (e.g. archive).
12928
+ * Unlike shutdownAll(), this does NOT snapshot live session state (acpState, etc.)
12929
+ * because destroyed sessions are terminal and will not be resumed.
12707
12930
  */
12708
12931
  async destroyAll() {
12709
12932
  if (this.store) {
@@ -12734,13 +12957,15 @@ init_log();
12734
12957
  init_bypass_detection();
12735
12958
  var log6 = createChildLogger({ module: "session-bridge" });
12736
12959
  var SessionBridge = class {
12737
- constructor(session, adapter, deps) {
12960
+ constructor(session, adapter, deps, adapterId) {
12738
12961
  this.session = session;
12739
12962
  this.adapter = adapter;
12740
12963
  this.deps = deps;
12964
+ this.adapterId = adapterId ?? adapter.name;
12741
12965
  }
12742
12966
  connected = false;
12743
12967
  cleanupFns = [];
12968
+ adapterId;
12744
12969
  get tracer() {
12745
12970
  return this.session.agentInstance.debugTracer ?? null;
12746
12971
  }
@@ -12771,6 +12996,15 @@ var SessionBridge = class {
12771
12996
  log6.error({ err, sessionId }, "Error in sendMessage middleware");
12772
12997
  }
12773
12998
  }
12999
+ /** Determine if this bridge should forward the given event based on turn routing. */
13000
+ shouldForward(event) {
13001
+ if (isSystemEvent(event)) return true;
13002
+ const ctx = this.session.activeTurnContext;
13003
+ if (!ctx) return true;
13004
+ const target = getEffectiveTarget(ctx);
13005
+ if (target === null) return false;
13006
+ return this.adapterId === target;
13007
+ }
12774
13008
  connect() {
12775
13009
  if (this.connected) return;
12776
13010
  this.connected = true;
@@ -12778,11 +13012,29 @@ var SessionBridge = class {
12778
13012
  this.session.emit("agent_event", event);
12779
13013
  });
12780
13014
  this.listen(this.session, "agent_event", (event) => {
12781
- this.dispatchAgentEvent(event);
13015
+ if (this.shouldForward(event)) {
13016
+ this.dispatchAgentEvent(event);
13017
+ } else {
13018
+ this.deps.eventBus?.emit("agent:event", { sessionId: this.session.id, event });
13019
+ }
13020
+ });
13021
+ if (!this.session.agentInstance.onPermissionRequest || this.session.agentInstance.onPermissionRequest.__bridgeId === void 0) {
13022
+ const handler = async (request) => {
13023
+ return this.resolvePermission(request);
13024
+ };
13025
+ handler.__bridgeId = this.adapterId;
13026
+ this.session.agentInstance.onPermissionRequest = handler;
13027
+ }
13028
+ this.listen(this.session, "permission_request", async (request) => {
13029
+ const current = this.session.agentInstance.onPermissionRequest;
13030
+ if (current?.__bridgeId === this.adapterId) return;
13031
+ if (!this.session.permissionGate.isPending) return;
13032
+ try {
13033
+ await this.adapter.sendPermissionRequest(this.session.id, request);
13034
+ } catch (err) {
13035
+ log6.error({ err, sessionId: this.session.id, adapterId: this.adapterId }, "Failed to send permission request to adapter");
13036
+ }
12782
13037
  });
12783
- this.session.agentInstance.onPermissionRequest = async (request) => {
12784
- return this.resolvePermission(request);
12785
- };
12786
13038
  this.listen(this.session, "status_change", (from, to) => {
12787
13039
  this.deps.sessionManager.patchRecord(this.session.id, {
12788
13040
  status: to,
@@ -12814,13 +13066,19 @@ var SessionBridge = class {
12814
13066
  if (this.session.latestCommands !== null) {
12815
13067
  this.session.emit("agent_event", { type: "commands_update", commands: this.session.latestCommands });
12816
13068
  }
13069
+ if (this.session.configOptions.length > 0) {
13070
+ this.session.emit("agent_event", { type: "config_option_update", options: this.session.configOptions });
13071
+ }
12817
13072
  }
12818
13073
  disconnect() {
12819
13074
  if (!this.connected) return;
12820
13075
  this.connected = false;
12821
13076
  this.cleanupFns.forEach((fn) => fn());
12822
13077
  this.cleanupFns = [];
12823
- this.session.agentInstance.onPermissionRequest = async () => "";
13078
+ const current = this.session.agentInstance.onPermissionRequest;
13079
+ if (current?.__bridgeId === this.adapterId) {
13080
+ this.session.agentInstance.onPermissionRequest = async () => "";
13081
+ }
12824
13082
  }
12825
13083
  /** Dispatch an agent event through middleware and to the adapter */
12826
13084
  async dispatchAgentEvent(event) {
@@ -12951,8 +13209,10 @@ var SessionBridge = class {
12951
13209
  this.sendMessage(this.session.id, outgoing);
12952
13210
  break;
12953
13211
  case "config_option_update":
12954
- this.session.updateConfigOptions(event.options);
12955
- this.persistAcpState();
13212
+ this.session.updateConfigOptions(event.options).then(() => {
13213
+ this.persistAcpState();
13214
+ }).catch(() => {
13215
+ });
12956
13216
  outgoing = this.deps.messageTransformer.transform(event);
12957
13217
  this.sendMessage(this.session.id, outgoing);
12958
13218
  break;
@@ -12996,19 +13256,27 @@ var SessionBridge = class {
12996
13256
  return result.autoResolve;
12997
13257
  }
12998
13258
  }
12999
- this.session.emit("permission_request", permReq);
13000
13259
  this.deps.eventBus?.emit("permission:request", {
13001
13260
  sessionId: this.session.id,
13002
13261
  permission: permReq
13003
13262
  });
13004
13263
  const autoDecision = this.checkAutoApprove(permReq);
13005
13264
  if (autoDecision) {
13265
+ this.session.emit("permission_request", permReq);
13006
13266
  this.emitAfterResolve(mw, permReq.id, autoDecision, "system", startTime);
13007
13267
  return autoDecision;
13008
13268
  }
13009
13269
  const promise = this.session.permissionGate.setPending(permReq);
13270
+ this.session.emit("permission_request", permReq);
13010
13271
  await this.adapter.sendPermissionRequest(this.session.id, permReq);
13011
13272
  const optionId = await promise;
13273
+ this.deps.eventBus?.emit("permission:resolved", {
13274
+ sessionId: this.session.id,
13275
+ requestId: permReq.id,
13276
+ decision: optionId,
13277
+ optionId,
13278
+ resolvedBy: this.adapterId
13279
+ });
13012
13280
  this.emitAfterResolve(mw, permReq.id, optionId, "user", startTime);
13013
13281
  return optionId;
13014
13282
  }
@@ -13184,17 +13452,7 @@ var SessionFactory = class {
13184
13452
  if (createParams.initialName) {
13185
13453
  session.name = createParams.initialName;
13186
13454
  }
13187
- const resp = agentInstance.initialSessionResponse;
13188
- if (resp) {
13189
- if (resp.configOptions) {
13190
- session.setInitialConfigOptions(resp.configOptions);
13191
- }
13192
- if (agentInstance.agentCapabilities) {
13193
- session.setAgentCapabilities(agentInstance.agentCapabilities);
13194
- }
13195
- } else if (agentInstance.agentCapabilities) {
13196
- session.setAgentCapabilities(agentInstance.agentCapabilities);
13197
- }
13455
+ session.applySpawnResponse(agentInstance.initialSessionResponse, agentInstance.agentCapabilities);
13198
13456
  this.sessionManager.registerSession(session);
13199
13457
  this.eventBus.emit("session:created", {
13200
13458
  sessionId: session.id,
@@ -13212,6 +13470,65 @@ var SessionFactory = class {
13212
13470
  if (session) return session;
13213
13471
  return this.lazyResume(channelId, threadId);
13214
13472
  }
13473
+ async getOrResumeById(sessionId) {
13474
+ const live = this.sessionManager.getSession(sessionId);
13475
+ if (live) return live;
13476
+ if (!this.sessionStore || !this.createFullSession) return null;
13477
+ const record = this.sessionStore.get(sessionId);
13478
+ if (!record) return null;
13479
+ if (record.status === "error" || record.status === "cancelled") return null;
13480
+ const existing = this.resumeLocks.get(sessionId);
13481
+ if (existing) return existing;
13482
+ const resumePromise = (async () => {
13483
+ try {
13484
+ const p = record.platform;
13485
+ const existingThreadId = p?.topicId ? String(p.topicId) : p?.threadId;
13486
+ const session = await this.createFullSession({
13487
+ channelId: record.channelId,
13488
+ agentName: record.agentName,
13489
+ workingDirectory: record.workingDir,
13490
+ resumeAgentSessionId: record.agentSessionId,
13491
+ existingSessionId: record.sessionId,
13492
+ initialName: record.name,
13493
+ threadId: existingThreadId
13494
+ });
13495
+ session.activate();
13496
+ if (record.clientOverrides) {
13497
+ session.clientOverrides = record.clientOverrides;
13498
+ } else if (record.dangerousMode) {
13499
+ session.clientOverrides = { bypassPermissions: true };
13500
+ }
13501
+ if (record.firstAgent) session.firstAgent = record.firstAgent;
13502
+ if (record.agentSwitchHistory) session.agentSwitchHistory = record.agentSwitchHistory;
13503
+ if (record.currentPromptCount != null) session.promptCount = record.currentPromptCount;
13504
+ if (record.attachedAdapters) session.attachedAdapters = record.attachedAdapters;
13505
+ if (record.platforms) {
13506
+ for (const [adapterId, platformData] of Object.entries(record.platforms)) {
13507
+ const data = platformData;
13508
+ const tid = adapterId === "telegram" ? String(data.topicId ?? "") : String(data.threadId ?? "");
13509
+ if (tid) session.threadIds.set(adapterId, tid);
13510
+ }
13511
+ }
13512
+ if (record.acpState) {
13513
+ if (record.acpState.configOptions && session.configOptions.length === 0) {
13514
+ session.setInitialConfigOptions(record.acpState.configOptions);
13515
+ }
13516
+ if (record.acpState.agentCapabilities && !session.agentCapabilities) {
13517
+ session.setAgentCapabilities(record.acpState.agentCapabilities);
13518
+ }
13519
+ }
13520
+ log7.info({ sessionId }, "Lazy resume by ID successful");
13521
+ return session;
13522
+ } catch (err) {
13523
+ log7.error({ err, sessionId }, "Lazy resume by ID failed");
13524
+ return null;
13525
+ } finally {
13526
+ this.resumeLocks.delete(sessionId);
13527
+ }
13528
+ })();
13529
+ this.resumeLocks.set(sessionId, resumePromise);
13530
+ return resumePromise;
13531
+ }
13215
13532
  async lazyResume(channelId, threadId) {
13216
13533
  const store = this.sessionStore;
13217
13534
  if (!store || !this.createFullSession) return null;
@@ -13220,7 +13537,7 @@ var SessionFactory = class {
13220
13537
  if (existing) return existing;
13221
13538
  const record = store.findByPlatform(
13222
13539
  channelId,
13223
- (p) => String(p.topicId) === threadId
13540
+ (p) => String(p.topicId) === threadId || String(p.threadId ?? "") === threadId
13224
13541
  );
13225
13542
  if (!record) {
13226
13543
  log7.debug({ threadId, channelId }, "No session record found for thread");
@@ -13255,11 +13572,21 @@ var SessionFactory = class {
13255
13572
  if (record.firstAgent) session.firstAgent = record.firstAgent;
13256
13573
  if (record.agentSwitchHistory) session.agentSwitchHistory = record.agentSwitchHistory;
13257
13574
  if (record.currentPromptCount != null) session.promptCount = record.currentPromptCount;
13575
+ if (record.attachedAdapters) {
13576
+ session.attachedAdapters = record.attachedAdapters;
13577
+ }
13578
+ if (record.platforms) {
13579
+ for (const [adapterId, platformData] of Object.entries(record.platforms)) {
13580
+ const data = platformData;
13581
+ const tid = adapterId === "telegram" ? String(data.topicId ?? "") : String(data.threadId ?? "");
13582
+ if (tid) session.threadIds.set(adapterId, tid);
13583
+ }
13584
+ }
13258
13585
  if (record.acpState) {
13259
- if (record.acpState.configOptions) {
13586
+ if (record.acpState.configOptions && session.configOptions.length === 0) {
13260
13587
  session.setInitialConfigOptions(record.acpState.configOptions);
13261
13588
  }
13262
- if (record.acpState.agentCapabilities) {
13589
+ if (record.acpState.agentCapabilities && !session.agentCapabilities) {
13263
13590
  session.setAgentCapabilities(record.acpState.agentCapabilities);
13264
13591
  }
13265
13592
  }
@@ -13426,6 +13753,9 @@ var JsonFileSessionStore = class {
13426
13753
  }
13427
13754
  findByPlatform(channelId, predicate) {
13428
13755
  for (const record of this.records.values()) {
13756
+ if (record.platforms?.[channelId]) {
13757
+ if (predicate(record.platforms[channelId])) return record;
13758
+ }
13429
13759
  if (record.channelId === channelId && predicate(record.platform)) {
13430
13760
  return record;
13431
13761
  }
@@ -13492,7 +13822,7 @@ var JsonFileSessionStore = class {
13492
13822
  return;
13493
13823
  }
13494
13824
  for (const [id, record] of Object.entries(raw.sessions)) {
13495
- this.records.set(id, record);
13825
+ this.records.set(id, this.migrateRecord(record));
13496
13826
  }
13497
13827
  log8.debug({ count: this.records.size }, "Loaded session records");
13498
13828
  } catch (err) {
@@ -13503,6 +13833,19 @@ var JsonFileSessionStore = class {
13503
13833
  }
13504
13834
  }
13505
13835
  }
13836
+ /** Migrate old SessionRecord format to new multi-adapter format. */
13837
+ migrateRecord(record) {
13838
+ if (!record.platforms && record.platform && typeof record.platform === "object") {
13839
+ const platformData = record.platform;
13840
+ if (Object.keys(platformData).length > 0) {
13841
+ record.platforms = { [record.channelId]: platformData };
13842
+ }
13843
+ }
13844
+ if (!record.attachedAdapters) {
13845
+ record.attachedAdapters = [record.channelId];
13846
+ }
13847
+ return record;
13848
+ }
13506
13849
  cleanup() {
13507
13850
  const cutoff = Date.now() - this.ttlDays * 24 * 60 * 60 * 1e3;
13508
13851
  let removed = 0;
@@ -13581,8 +13924,15 @@ var AgentSwitchHandler = class {
13581
13924
  toAgent,
13582
13925
  status: "starting"
13583
13926
  });
13584
- const bridge = bridges.get(sessionId);
13585
- if (bridge) bridge.disconnect();
13927
+ const sessionBridgeKeys = this.deps.getSessionBridgeKeys(sessionId);
13928
+ const hadBridges = sessionBridgeKeys.length > 0;
13929
+ for (const key of sessionBridgeKeys) {
13930
+ const bridge = bridges.get(key);
13931
+ if (bridge) {
13932
+ bridges.delete(key);
13933
+ bridge.disconnect();
13934
+ }
13935
+ }
13586
13936
  const switchAdapter = adapters.get(session.channelId);
13587
13937
  if (switchAdapter?.sendSkillCommands) {
13588
13938
  await switchAdapter.sendSkillCommands(session.id, []);
@@ -13659,9 +14009,11 @@ var AgentSwitchHandler = class {
13659
14009
  session.agentInstance = oldInstance;
13660
14010
  session.agentName = fromAgent;
13661
14011
  session.agentSessionId = oldInstance.sessionId;
13662
- const adapter = adapters.get(session.channelId);
13663
- if (adapter) {
13664
- createBridge(session, adapter).connect();
14012
+ for (const adapterId of session.attachedAdapters) {
14013
+ const adapter = adapters.get(adapterId);
14014
+ if (adapter) {
14015
+ createBridge(session, adapter, adapterId).connect();
14016
+ }
13665
14017
  }
13666
14018
  log9.warn({ sessionId, fromAgent, toAgent, err }, "Agent switch failed, rolled back to previous agent");
13667
14019
  } catch (rollbackErr) {
@@ -13670,10 +14022,14 @@ var AgentSwitchHandler = class {
13670
14022
  }
13671
14023
  throw err;
13672
14024
  }
13673
- if (bridge) {
13674
- const adapter = adapters.get(session.channelId);
13675
- if (adapter) {
13676
- createBridge(session, adapter).connect();
14025
+ if (hadBridges) {
14026
+ for (const adapterId of session.attachedAdapters) {
14027
+ const adapter = adapters.get(adapterId);
14028
+ if (adapter) {
14029
+ createBridge(session, adapter, adapterId).connect();
14030
+ } else {
14031
+ log9.warn({ sessionId, adapterId }, "Adapter not available during switch reconnect, skipping bridge");
14032
+ }
13677
14033
  }
13678
14034
  }
13679
14035
  await sessionManager.patchRecord(sessionId, {
@@ -15126,7 +15482,7 @@ var OpenACPCore = class {
15126
15482
  sessionManager;
15127
15483
  messageTransformer;
15128
15484
  adapters = /* @__PURE__ */ new Map();
15129
- /** sessionId → SessionBridge — tracks active bridges for disconnect/reconnect during agent switch */
15485
+ /** "adapterId:sessionId" → SessionBridge — tracks active bridges for disconnect/reconnect */
15130
15486
  bridges = /* @__PURE__ */ new Map();
15131
15487
  /** Set by main.ts — triggers graceful shutdown with restart exit code */
15132
15488
  requestRestart = null;
@@ -15222,7 +15578,8 @@ var OpenACPCore = class {
15222
15578
  eventBus: this.eventBus,
15223
15579
  adapters: this.adapters,
15224
15580
  bridges: this.bridges,
15225
- createBridge: (session, adapter) => this.createBridge(session, adapter),
15581
+ createBridge: (session, adapter, adapterId) => this.createBridge(session, adapter, adapterId),
15582
+ getSessionBridgeKeys: (sessionId) => this.getSessionBridgeKeys(sessionId),
15226
15583
  getMiddlewareChain: () => this.lifecycleManager?.middlewareChain,
15227
15584
  getService: (name) => this.lifecycleManager.serviceRegistry.get(name)
15228
15585
  });
@@ -15402,7 +15759,7 @@ User message:
15402
15759
  ${text3}`;
15403
15760
  }
15404
15761
  }
15405
- await session.enqueuePrompt(text3, message.attachments);
15762
+ await session.enqueuePrompt(text3, message.attachments, message.routing);
15406
15763
  }
15407
15764
  // --- Unified Session Creation Pipeline ---
15408
15765
  async createSession(params) {
@@ -15429,6 +15786,12 @@ ${text3}`;
15429
15786
  platform2.threadId = session.threadId;
15430
15787
  }
15431
15788
  }
15789
+ const platforms = {
15790
+ ...existingRecord?.platforms ?? {}
15791
+ };
15792
+ if (session.threadId) {
15793
+ platforms[params.channelId] = params.channelId === "telegram" ? { topicId: Number(session.threadId) || session.threadId } : { threadId: session.threadId };
15794
+ }
15432
15795
  await this.sessionManager.patchRecord(session.id, {
15433
15796
  sessionId: session.id,
15434
15797
  agentSessionId: session.agentSessionId,
@@ -15440,6 +15803,7 @@ ${text3}`;
15440
15803
  lastActiveAt: (/* @__PURE__ */ new Date()).toISOString(),
15441
15804
  name: session.name,
15442
15805
  platform: platform2,
15806
+ platforms,
15443
15807
  firstAgent: session.firstAgent,
15444
15808
  currentPromptCount: session.promptCount,
15445
15809
  agentSwitchHistory: session.agentSwitchHistory,
@@ -15447,7 +15811,7 @@ ${text3}`;
15447
15811
  acpState: session.toAcpStateSnapshot()
15448
15812
  }, { immediate: true });
15449
15813
  if (adapter) {
15450
- const bridge = this.createBridge(session, adapter);
15814
+ const bridge = this.createBridge(session, adapter, session.channelId);
15451
15815
  bridge.connect();
15452
15816
  adapter.flushPendingSkillCommands?.(session.id).catch((err) => {
15453
15817
  log16.warn({ err, sessionId: session.id }, "Failed to flush pending skill commands");
@@ -15586,9 +15950,14 @@ ${text3}`;
15586
15950
  } else {
15587
15951
  adoptPlatform.threadId = session.threadId;
15588
15952
  }
15953
+ const adoptPlatforms = {};
15954
+ if (session.threadId) {
15955
+ adoptPlatforms[adapterChannelId] = adapterChannelId === "telegram" ? { topicId: Number(session.threadId) || session.threadId } : { threadId: session.threadId };
15956
+ }
15589
15957
  await this.sessionManager.patchRecord(session.id, {
15590
15958
  originalAgentSessionId: agentSessionId,
15591
- platform: adoptPlatform
15959
+ platform: adoptPlatform,
15960
+ platforms: adoptPlatforms
15592
15961
  });
15593
15962
  return {
15594
15963
  ok: true,
@@ -15610,18 +15979,101 @@ ${text3}`;
15610
15979
  async getOrResumeSession(channelId, threadId) {
15611
15980
  return this.sessionFactory.getOrResume(channelId, threadId);
15612
15981
  }
15982
+ async getOrResumeSessionById(sessionId) {
15983
+ return this.sessionFactory.getOrResumeById(sessionId);
15984
+ }
15985
+ async attachAdapter(sessionId, adapterId) {
15986
+ const session = this.sessionManager.getSession(sessionId);
15987
+ if (!session) throw new Error(`Session ${sessionId} not found`);
15988
+ const adapter = this.adapters.get(adapterId);
15989
+ if (!adapter) throw new Error(`Adapter "${adapterId}" not found or not running`);
15990
+ if (session.attachedAdapters.includes(adapterId)) {
15991
+ const existingThread = session.threadIds.get(adapterId) ?? session.id;
15992
+ return { threadId: existingThread };
15993
+ }
15994
+ const threadId = await adapter.createSessionThread(
15995
+ session.id,
15996
+ session.name ?? `Session ${session.id.slice(0, 6)}`
15997
+ );
15998
+ session.threadIds.set(adapterId, threadId);
15999
+ session.attachedAdapters.push(adapterId);
16000
+ const bridge = this.createBridge(session, adapter, adapterId);
16001
+ bridge.connect();
16002
+ await this.sessionManager.patchRecord(session.id, {
16003
+ attachedAdapters: session.attachedAdapters,
16004
+ platforms: this.buildPlatformsFromSession(session)
16005
+ });
16006
+ return { threadId };
16007
+ }
16008
+ async detachAdapter(sessionId, adapterId) {
16009
+ const session = this.sessionManager.getSession(sessionId);
16010
+ if (!session) throw new Error(`Session ${sessionId} not found`);
16011
+ if (adapterId === session.channelId) {
16012
+ throw new Error("Cannot detach primary adapter (channelId)");
16013
+ }
16014
+ if (!session.attachedAdapters.includes(adapterId)) {
16015
+ return;
16016
+ }
16017
+ const adapter = this.adapters.get(adapterId);
16018
+ if (adapter) {
16019
+ try {
16020
+ await adapter.sendMessage(session.id, {
16021
+ type: "system_message",
16022
+ text: "Session detached from this adapter."
16023
+ });
16024
+ } catch {
16025
+ }
16026
+ }
16027
+ const key = this.bridgeKey(adapterId, session.id);
16028
+ const bridge = this.bridges.get(key);
16029
+ if (bridge) {
16030
+ bridge.disconnect();
16031
+ this.bridges.delete(key);
16032
+ }
16033
+ session.attachedAdapters = session.attachedAdapters.filter((a) => a !== adapterId);
16034
+ session.threadIds.delete(adapterId);
16035
+ await this.sessionManager.patchRecord(session.id, {
16036
+ attachedAdapters: session.attachedAdapters,
16037
+ platforms: this.buildPlatformsFromSession(session)
16038
+ });
16039
+ }
16040
+ buildPlatformsFromSession(session) {
16041
+ const platforms = {};
16042
+ for (const [adapterId, threadId] of session.threadIds) {
16043
+ if (adapterId === "telegram") {
16044
+ platforms.telegram = { topicId: Number(threadId) || threadId };
16045
+ } else {
16046
+ platforms[adapterId] = { threadId };
16047
+ }
16048
+ }
16049
+ return platforms;
16050
+ }
15613
16051
  // --- Event Wiring ---
16052
+ /** Composite bridge key: "adapterId:sessionId" */
16053
+ bridgeKey(adapterId, sessionId) {
16054
+ return `${adapterId}:${sessionId}`;
16055
+ }
16056
+ /** Get all bridge keys for a session (regardless of adapter) */
16057
+ getSessionBridgeKeys(sessionId) {
16058
+ const keys = [];
16059
+ for (const key of this.bridges.keys()) {
16060
+ if (key.endsWith(`:${sessionId}`)) keys.push(key);
16061
+ }
16062
+ return keys;
16063
+ }
15614
16064
  /** Connect a session bridge for the given session (used by AssistantManager) */
15615
16065
  connectSessionBridge(session) {
15616
16066
  const adapter = this.adapters.get(session.channelId);
15617
16067
  if (!adapter) return;
15618
- const bridge = this.createBridge(session, adapter);
16068
+ const bridge = this.createBridge(session, adapter, session.channelId);
15619
16069
  bridge.connect();
15620
16070
  }
15621
16071
  /** Create a SessionBridge for the given session and adapter.
15622
- * Disconnects any existing bridge for the same session first. */
15623
- createBridge(session, adapter) {
15624
- const existing = this.bridges.get(session.id);
16072
+ * Disconnects any existing bridge for the same adapter+session first. */
16073
+ createBridge(session, adapter, adapterId) {
16074
+ const id = adapterId ?? adapter.name;
16075
+ const key = this.bridgeKey(id, session.id);
16076
+ const existing = this.bridges.get(key);
15625
16077
  if (existing) {
15626
16078
  existing.disconnect();
15627
16079
  }
@@ -15632,8 +16084,8 @@ ${text3}`;
15632
16084
  eventBus: this.eventBus,
15633
16085
  fileService: this.fileService,
15634
16086
  middlewareChain: this.lifecycleManager?.middlewareChain
15635
- });
15636
- this.bridges.set(session.id, bridge);
16087
+ }, id);
16088
+ this.bridges.set(key, bridge);
15637
16089
  return bridge;
15638
16090
  }
15639
16091
  };
@@ -17668,12 +18120,14 @@ export {
17668
18120
  createApiServerService,
17669
18121
  createChildLogger,
17670
18122
  createSessionLogger,
18123
+ createTurnContext,
17671
18124
  expandHome3 as expandHome,
17672
18125
  extractContentText,
17673
18126
  formatTokens,
17674
18127
  formatToolSummary,
17675
18128
  formatToolTitle,
17676
18129
  getConfigValue,
18130
+ getEffectiveTarget,
17677
18131
  getFieldDef,
17678
18132
  getPidPath,
17679
18133
  getSafeFields,
@@ -17683,6 +18137,7 @@ export {
17683
18137
  isAutoStartInstalled,
17684
18138
  isAutoStartSupported,
17685
18139
  isHotReloadable,
18140
+ isSystemEvent,
17686
18141
  log,
17687
18142
  nodeToWebReadable,
17688
18143
  nodeToWebWritable,