@agentconnect.md/codex-acp 1.8.0-agentconnect.1 → 1.10.0-agentconnect.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 (3) hide show
  1. package/README.md +7 -0
  2. package/dist/index.js +1011 -108
  3. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -22132,32 +22132,7 @@ function attachLogs(proc) {
22132
22132
  });
22133
22133
  }
22134
22134
 
22135
- // src/AirExtension.ts
22136
- var JETBRAINS_META_KEY = "jetbrains";
22137
- var AIR_META_KEY = "air";
22138
- var AIR_EXTENSION_VERSION_KEY = "version";
22139
- var AIR_EXTENSION_CAPABILITIES_KEY = "capabilities";
22140
- var AIR_SESSION_FAILURE_KEY = "sessionFailure";
22141
- var AIR_AGENT_FILE_CHANGE_REPORT_KEY = "agentFileChangeReport";
22142
- var AIR_NATIVE_SUBAGENT_SESSIONS_KEY = "nativeSubagentSessions";
22143
- var AIR_AGENT_FILE_CHANGE_REPORT_REQUEST_KEY = "agentFileChangeReportRequest";
22144
- var AIR_EXTENSION_VERSION = 1;
22145
- function clientSupportsAirCapability(capabilities, capability) {
22146
- const jetbrains = capabilities?._meta?.[JETBRAINS_META_KEY];
22147
- const air = jetbrains?.[AIR_META_KEY];
22148
- const version2 = air?.[AIR_EXTENSION_VERSION_KEY];
22149
- const supported = air?.[AIR_EXTENSION_CAPABILITIES_KEY];
22150
- return typeof version2 === "number" && Number.isInteger(version2) && version2 >= AIR_EXTENSION_VERSION && Array.isArray(supported) && supported.includes(capability);
22151
- }
22152
-
22153
- // src/subagents/AcpSubagents.ts
22154
- function clientSupportsSubagents(capabilities) {
22155
- const subagents = capabilities?.subagents;
22156
- if (typeof subagents === "object" && subagents !== null && !Array.isArray(subagents)) {
22157
- return true;
22158
- }
22159
- return clientSupportsAirCapability(capabilities, AIR_NATIVE_SUBAGENT_SESSIONS_KEY);
22160
- }
22135
+ // src/AcpSessionExtensions.ts
22161
22136
  function asSdkSessionNotification(notification) {
22162
22137
  return notification;
22163
22138
  }
@@ -23686,6 +23661,26 @@ function sameThreadGoalSnapshot(left, right) {
23686
23661
  // src/CodexEventHandler.ts
23687
23662
  import { randomUUID } from "node:crypto";
23688
23663
 
23664
+ // src/AirExtension.ts
23665
+ var JETBRAINS_META_KEY = "jetbrains";
23666
+ var AIR_META_KEY = "air";
23667
+ var AIR_EXTENSION_VERSION_KEY = "version";
23668
+ var AIR_EXTENSION_CAPABILITIES_KEY = "capabilities";
23669
+ var AIR_SESSION_FAILURE_KEY = "sessionFailure";
23670
+ var AIR_AGENT_FILE_CHANGE_REPORT_KEY = "agentFileChangeReport";
23671
+ var AIR_NATIVE_SUBAGENT_SESSIONS_KEY = "nativeSubagentSessions";
23672
+ var AIR_ASYNC_TASKS_KEY = "asyncTasks";
23673
+ var AIR_ASYNC_TASKS_BACKGROUNDED_KEY = "backgrounded";
23674
+ var AIR_AGENT_FILE_CHANGE_REPORT_REQUEST_KEY = "agentFileChangeReportRequest";
23675
+ var AIR_EXTENSION_VERSION = 1;
23676
+ function clientSupportsAirCapability(capabilities, capability) {
23677
+ const jetbrains = capabilities?._meta?.[JETBRAINS_META_KEY];
23678
+ const air = jetbrains?.[AIR_META_KEY];
23679
+ const version2 = air?.[AIR_EXTENSION_VERSION_KEY];
23680
+ const supported = air?.[AIR_EXTENSION_CAPABILITIES_KEY];
23681
+ return typeof version2 === "number" && Number.isInteger(version2) && version2 >= AIR_EXTENSION_VERSION && Array.isArray(supported) && supported.includes(capability);
23682
+ }
23683
+
23689
23684
  // src/subagents/CodexAgentPath.ts
23690
23685
  function normalizeAgentPath(path9) {
23691
23686
  const normalized = path9.trim().replace(/\/+$/, "");
@@ -23741,14 +23736,14 @@ var CodexSubagentEventRouter = class _CodexSubagentEventRouter {
23741
23736
  }
23742
23737
  return childTurn;
23743
23738
  }
23744
- const notificationThreadId = notification.params.threadId;
23745
- if (typeof notificationThreadId === "string" && this.pendingSpawns.has(notificationThreadId)) {
23746
- const pending = this.pendingSpawns.get(notificationThreadId);
23739
+ const notificationThreadId2 = notification.params.threadId;
23740
+ if (typeof notificationThreadId2 === "string" && this.pendingSpawns.has(notificationThreadId2)) {
23741
+ const pending = this.pendingSpawns.get(notificationThreadId2);
23747
23742
  if (pending.buffered.length === _CodexSubagentEventRouter.MAX_PENDING_NOTIFICATIONS) {
23748
23743
  pending.buffered.shift();
23749
23744
  pending.droppedBufferedNotifications += 1;
23750
23745
  if (pending.droppedBufferedNotifications === 1) {
23751
- logger.log(`Pending subagent ${notificationThreadId} exceeded the notification buffer; dropping oldest updates`);
23746
+ logger.log(`Pending subagent ${notificationThreadId2} exceeded the notification buffer; dropping oldest updates`);
23752
23747
  }
23753
23748
  }
23754
23749
  pending.buffered.push(notification);
@@ -23833,6 +23828,25 @@ var CodexSubagentEventRouter = class _CodexSubagentEventRouter {
23833
23828
  const threadId = notification.params.threadId;
23834
23829
  return typeof threadId === "string" && this.children.has(threadId) ? this.children.get(threadId).sessionId : this.rootSessionId;
23835
23830
  }
23831
+ closingChildSessions(notification) {
23832
+ if (!this.supported) return [];
23833
+ if (notification.method === "turn/completed") {
23834
+ if (terminalStateFromTurn(notification.params.turn.status) === void 0) return [];
23835
+ return this.closingChildSession(notification.params.threadId);
23836
+ }
23837
+ if (notification.method !== "item/started" && notification.method !== "item/completed") return [];
23838
+ const item = notification.params.item;
23839
+ if (item.type === "subAgentActivity") {
23840
+ return item.kind === "interrupted" ? this.closingChildSession(item.agentThreadId) : [];
23841
+ }
23842
+ if (item.type !== "collabAgentToolCall") return [];
23843
+ const closing = /* @__PURE__ */ new Map();
23844
+ for (const [threadId, state] of Object.entries(item.agentsStates)) {
23845
+ if (!state || terminalStateOf(state.status) === void 0) continue;
23846
+ for (const child of this.closingChildSession(threadId)) closing.set(threadId, child);
23847
+ }
23848
+ return [...closing.values()];
23849
+ }
23836
23850
  takeBufferedNotifications() {
23837
23851
  return this.replayQueue.splice(0);
23838
23852
  }
@@ -23908,6 +23922,10 @@ var CodexSubagentEventRouter = class _CodexSubagentEventRouter {
23908
23922
  isKnownChild(threadId) {
23909
23923
  return threadId !== this.rootSessionId && (this.children.has(threadId) || this.pendingSpawns.has(threadId) || this.terminalPendingSpawns.has(threadId));
23910
23924
  }
23925
+ closingChildSession(threadId) {
23926
+ const child = this.children.get(threadId);
23927
+ return child && child.terminalState === void 0 ? [{ threadId, sessionId: child.sessionId }] : [];
23928
+ }
23911
23929
  async materialize(childSessionId, path9) {
23912
23930
  if (this.children.has(childSessionId)) return;
23913
23931
  const pending = this.pendingSpawns.get(childSessionId);
@@ -24061,6 +24079,37 @@ function fallbackName(sessionId) {
24061
24079
  return `Agent ${suffix}`;
24062
24080
  }
24063
24081
 
24082
+ // src/RateLimitsMap.ts
24083
+ function rateLimitId(snapshot, fallback = "codex") {
24084
+ return snapshot.limitId ?? fallback;
24085
+ }
24086
+ function createRateLimitsMap(response) {
24087
+ const result = /* @__PURE__ */ new Map();
24088
+ const snapshots = Object.entries(response.rateLimitsByLimitId ?? {}).filter((entry) => entry[1] !== void 0);
24089
+ if (snapshots.length === 0) {
24090
+ snapshots.push([rateLimitId(response.rateLimits), response.rateLimits]);
24091
+ }
24092
+ for (const [fallbackId, snapshot] of snapshots) {
24093
+ const limitId = rateLimitId(snapshot, fallbackId);
24094
+ result.set(limitId, {
24095
+ limitId,
24096
+ limitName: snapshot.limitName ?? limitId,
24097
+ snapshot
24098
+ });
24099
+ }
24100
+ return result;
24101
+ }
24102
+ function mergeRateLimitSnapshot(previous, update) {
24103
+ return {
24104
+ ...update,
24105
+ limitId: update.limitId ?? "codex",
24106
+ credits: update.credits ?? previous.credits,
24107
+ individualLimit: update.individualLimit ?? previous.individualLimit,
24108
+ spendControlReached: update.spendControlReached ?? previous.spendControlReached,
24109
+ planType: update.planType ?? previous.planType
24110
+ };
24111
+ }
24112
+
24064
24113
  // src/CodexEventHandler.ts
24065
24114
  var MAX_SESSION_FAILURE_TITLE_LENGTH = 240;
24066
24115
  var SESSION_FAILURE_POLICY = {
@@ -24169,11 +24218,14 @@ var CodexEventHandler = class _CodexEventHandler {
24169
24218
  terminalCommandOutputIds = /* @__PURE__ */ new Set();
24170
24219
  agentMessagePhases = /* @__PURE__ */ new Map();
24171
24220
  subagents;
24221
+ /** Connection-level `authStatus` sink; the app-server account push feeds it. */
24222
+ onAccountUpdated;
24172
24223
  constructor(connection, sessionState, supportsPlanUpdates = false, supportsTypedSessionFailures = false, sessionFailureEpoch = randomUUID(), subagents = new CodexSubagentEventRouter(
24173
24224
  sessionState.sessionId,
24174
24225
  false,
24175
24226
  new ACPSessionConnection(connection, sessionState.sessionId)
24176
- )) {
24227
+ ), onAccountUpdated) {
24228
+ this.onAccountUpdated = onAccountUpdated;
24177
24229
  this.sessionState = sessionState;
24178
24230
  this.supportsPlanUpdates = supportsPlanUpdates;
24179
24231
  this.supportsTypedSessionFailures = supportsTypedSessionFailures;
@@ -24282,17 +24334,29 @@ var CodexEventHandler = class _CodexEventHandler {
24282
24334
  }
24283
24335
  async handleNotification(notification) {
24284
24336
  await this.flushPendingErrors();
24337
+ const closingChildren = this.subagents.closingChildSessions(notification);
24338
+ for (const child of closingChildren) {
24339
+ await this.sessionState.asyncTasks.reconcile(child.threadId, child.sessionId);
24340
+ }
24285
24341
  const handledBySubagents = await this.subagents.handle(notification);
24286
24342
  for (const buffered of this.subagents.takeBufferedNotifications()) {
24287
24343
  await this.handleNotification(buffered);
24288
24344
  }
24289
- if (handledBySubagents) {
24290
- return;
24345
+ const ignoredBySubagents = !handledBySubagents && this.subagents.shouldIgnore(notification);
24346
+ let updateEvent;
24347
+ if (!handledBySubagents && !ignoredBySubagents && notification.method === "item/started" && notification.params.item.type === "commandExecution") {
24348
+ updateEvent = await this.createUpdateEvent(notification);
24291
24349
  }
24292
- if (this.subagents.shouldIgnore(notification)) {
24293
- return;
24350
+ if (!handledBySubagents) {
24351
+ await this.sessionState.asyncTasks.handleNotification(
24352
+ notification,
24353
+ this.subagents.notificationSessionId(notification),
24354
+ toolCallTitle(updateEvent)
24355
+ );
24294
24356
  }
24295
- const updateEvent = await this.createUpdateEvent(notification);
24357
+ if (handledBySubagents) return;
24358
+ if (ignoredBySubagents) return;
24359
+ if (updateEvent === void 0) updateEvent = await this.createUpdateEvent(notification);
24296
24360
  if (updateEvent) {
24297
24361
  await this.session.update(updateEvent, this.subagents.notificationSessionId(notification));
24298
24362
  }
@@ -24397,6 +24461,9 @@ var CodexEventHandler = class _CodexEventHandler {
24397
24461
  case "account/rateLimits/updated":
24398
24462
  this.handleRateLimitsUpdated(notification.params);
24399
24463
  return null;
24464
+ case "account/updated":
24465
+ this.onAccountUpdated?.(notification.params);
24466
+ return null;
24400
24467
  case "configWarning":
24401
24468
  return await this.createConfigWarningEvent(notification.params);
24402
24469
  case "warning":
@@ -24447,7 +24514,6 @@ var CodexEventHandler = class _CodexEventHandler {
24447
24514
  case "turn/moderationMetadata":
24448
24515
  case "item/fileChange/outputDelta":
24449
24516
  case "item/fileChange/patchUpdated":
24450
- case "account/updated":
24451
24517
  case "fs/changed":
24452
24518
  case "mcpServer/startupStatus/updated":
24453
24519
  case "mcpServer/event/stream/notification":
@@ -25093,11 +25159,13 @@ ${event.stdin}
25093
25159
  if (!this.sessionState.rateLimits) {
25094
25160
  this.sessionState.rateLimits = /* @__PURE__ */ new Map();
25095
25161
  }
25096
- const limitId = params.rateLimits.limitId ?? params.rateLimits.limitName ?? "unknown";
25162
+ const limitId = params.rateLimits.limitId ?? "codex";
25163
+ const existingEntry = this.sessionState.rateLimits.get(limitId);
25164
+ const snapshot = existingEntry ? mergeRateLimitSnapshot(existingEntry.snapshot, params.rateLimits) : { ...params.rateLimits, limitId };
25097
25165
  this.sessionState.rateLimits.set(limitId, {
25098
25166
  limitId,
25099
- limitName: params.rateLimits.limitName ?? limitId,
25100
- snapshot: params.rateLimits
25167
+ limitName: snapshot.limitName ?? existingEntry?.limitName ?? limitId,
25168
+ snapshot
25101
25169
  });
25102
25170
  }
25103
25171
  handleFuzzyFileSearchSessionUpdated(params) {
@@ -25125,6 +25193,10 @@ ${event.stdin}
25125
25193
  return createGuardianApprovalReviewToolCall(params);
25126
25194
  }
25127
25195
  };
25196
+ function toolCallTitle(update) {
25197
+ if (update?.sessionUpdate !== "tool_call") return void 0;
25198
+ return update.title;
25199
+ }
25128
25200
 
25129
25201
  // src/permissions/option-ids.ts
25130
25202
  var ApprovalOptionId = {
@@ -25569,14 +25641,16 @@ function unique(values) {
25569
25641
 
25570
25642
  // src/permissions/CodexApprovalHandler.ts
25571
25643
  var CodexApprovalHandler = class {
25572
- constructor(connection, permissionContext, cancellationSignal) {
25644
+ constructor(connection, permissionContext, cancellationSignal, denyRequests) {
25573
25645
  this.connection = connection;
25574
25646
  this.permissionContext = permissionContext;
25575
25647
  this.cancellationSignal = cancellationSignal;
25648
+ this.denyRequests = denyRequests;
25576
25649
  }
25577
25650
  connection;
25578
25651
  permissionContext;
25579
25652
  cancellationSignal;
25653
+ denyRequests;
25580
25654
  async handleCommandExecution(params) {
25581
25655
  const authoritativeParams = params;
25582
25656
  const decisions = commandDecisionOptions(authoritativeParams);
@@ -25635,6 +25709,7 @@ var CodexApprovalHandler = class {
25635
25709
  }
25636
25710
  }
25637
25711
  requestPermission(request) {
25712
+ if (this.denyRequests?.()) return Promise.resolve({ outcome: { outcome: "cancelled" } });
25638
25713
  return this.connection.request(
25639
25714
  methods.client.session.requestPermission,
25640
25715
  request,
@@ -26027,31 +26102,20 @@ function userInputResponseValue(content, fieldId) {
26027
26102
  return value;
26028
26103
  }
26029
26104
  var CodexElicitationHandler = class {
26030
- connection;
26031
- permissionContext;
26032
- clientCapabilities;
26033
- cancellationSignal;
26034
- // In Rust, the MCP elicitation handler receives ElicitationRequestEvent directly from the MCP
26035
- // protocol layer, where id is set to "mcp_tool_call_approval_<call_id>" — the call ID is extracted
26036
- // by stripping that prefix.
26037
- //
26038
- // In TypeScript, Codex speaks the app-server JSON-RPC protocol (v2), where
26039
- // McpServerElicitationRequestParams omits elicitationId for form mode, so the MCP-level ID never
26040
- // reaches the client.
26041
- //
26042
- // Workaround: before requesting approval, Codex emits an item/started notification with an
26043
- // mcpToolCall item carrying the call id and server name. The shared permission lifecycle stores
26044
- // (threadId, serverName) → callId so this request can correlate to the rendered tool call item.
26045
- //
26046
- // The app-server handler exposes URL elicitationId, while serverRequest/resolved only exposes
26047
- // threadId here, so accepted URL elicitations are completed at thread scope.
26048
- pendingUrlElicitations = /* @__PURE__ */ new Map();
26049
- constructor(connection, permissionContext, clientCapabilities = null, cancellationSignal) {
26105
+ constructor(connection, permissionContext, clientCapabilities = null, cancellationSignal, fullAccessHttpServers) {
26106
+ this.fullAccessHttpServers = fullAccessHttpServers;
26050
26107
  this.connection = connection;
26051
26108
  this.permissionContext = permissionContext;
26052
26109
  this.clientCapabilities = clientCapabilities;
26053
26110
  this.cancellationSignal = cancellationSignal;
26054
26111
  }
26112
+ fullAccessHttpServers;
26113
+ connection;
26114
+ permissionContext;
26115
+ clientCapabilities;
26116
+ cancellationSignal;
26117
+ // App-server omits form elicitation IDs, so item/started correlates MCP approvals to tool calls.
26118
+ pendingUrlElicitations = /* @__PURE__ */ new Map();
26055
26119
  async handleNotification(notification) {
26056
26120
  switch (notification.method) {
26057
26121
  case "serverRequest/resolved":
@@ -26064,6 +26128,12 @@ var CodexElicitationHandler = class {
26064
26128
  async handleElicitation(params) {
26065
26129
  try {
26066
26130
  const context = this.createMcpElicitationContext(params);
26131
+ const httpServers = this.fullAccessHttpServers?.(params);
26132
+ if (httpServers !== void 0) {
26133
+ const accepted = !this.cancellationSignal?.aborted && params.mode === "form" && context.isToolApproval && context.persistOptions.has("session") && httpServers.has(params.serverName);
26134
+ await this.publishAcceptedMcpToolApproval(params.threadId, context, accepted);
26135
+ return { action: accepted ? "accept" : "cancel", content: accepted ? {} : null, _meta: null };
26136
+ }
26067
26137
  if (this.shouldUseAcpElicitation(params)) {
26068
26138
  const response2 = await this.connection.request(
26069
26139
  methods.client.elicitation.create,
@@ -26109,6 +26179,9 @@ var CodexElicitationHandler = class {
26109
26179
  }
26110
26180
  }
26111
26181
  async handleUserInput(params) {
26182
+ if (this.fullAccessHttpServers?.(params) !== void 0 && params.itemId === `mcp-deps-${params.turnId}` && params.questions.some((question) => question.id === "skill_mcp_dependency_install")) {
26183
+ return { answers: {} };
26184
+ }
26112
26185
  if (!clientSupportsFormElicitation(this.clientCapabilities)) {
26113
26186
  return { answers: {} };
26114
26187
  }
@@ -27257,7 +27330,7 @@ var package_default = {
27257
27330
  publishConfig: {
27258
27331
  access: "public"
27259
27332
  },
27260
- version: "1.8.0-agentconnect.1",
27333
+ version: "1.10.0-agentconnect.2",
27261
27334
  description: "",
27262
27335
  main: "dist/index.js",
27263
27336
  bin: {
@@ -27319,7 +27392,7 @@ var package_default = {
27319
27392
  },
27320
27393
  dependencies: {
27321
27394
  "@agentclientprotocol/sdk": "^1.4.0",
27322
- "@openai/codex": "^0.152.0",
27395
+ "@openai/codex": "^0.153.3",
27323
27396
  diff: "^9.0.0",
27324
27397
  open: "^11.0.1",
27325
27398
  "vscode-jsonrpc": "^9.0.1",
@@ -27825,12 +27898,9 @@ import { createHash } from "node:crypto";
27825
27898
  async function forkSession(request, additionalDirectories, dependencies) {
27826
27899
  await dependencies.refreshSkills(request.cwd, additionalDirectories);
27827
27900
  const lastTurnId = await resolveForkTurnId(request, dependencies.codexClient);
27901
+ const prepared = await dependencies.createSessionConfig(request.cwd, additionalDirectories, request.mcpServers ?? []);
27828
27902
  const response = await dependencies.codexClient.threadFork({
27829
- config: await dependencies.createSessionConfig(
27830
- request.cwd,
27831
- additionalDirectories,
27832
- request.mcpServers ?? []
27833
- ),
27903
+ config: prepared.config,
27834
27904
  cwd: request.cwd,
27835
27905
  ...lastTurnId !== void 0 && { lastTurnId },
27836
27906
  modelProvider: await dependencies.getResumeModelProvider(),
@@ -27845,7 +27915,8 @@ async function forkSession(request, additionalDirectories, dependencies) {
27845
27915
  collaborationMode: dependencies.getCollaborationMode(response.thread.id),
27846
27916
  modelProvider: response.modelProvider,
27847
27917
  currentServiceTier: response.serviceTier ?? null,
27848
- additionalDirectories
27918
+ additionalDirectories,
27919
+ fullAccessHttpMcpServers: prepared.fullAccessHttpMcpServers
27849
27920
  };
27850
27921
  }
27851
27922
  async function resolveForkTurnId(request, codexClient) {
@@ -27945,6 +28016,12 @@ var CodexAcpClient = class {
27945
28016
  modelProvider;
27946
28017
  permissionProfileConfig;
27947
28018
  gatewayConfig;
28019
+ /**
28020
+ * Where the stored gateway routing came from: the `gateway` auth method
28021
+ * (agent-owned authentication) or the ACP `providers/*` API (client-driven
28022
+ * routing). `authStatus` reports only the agent-owned one.
28023
+ */
28024
+ gatewayConfigSource;
27948
28025
  pendingLoginCompleted = null;
27949
28026
  pendingAccountUpdated = null;
27950
28027
  sessionNotificationQueues = /* @__PURE__ */ new Map();
@@ -27957,6 +28034,7 @@ var CodexAcpClient = class {
27957
28034
  this.modelProvider = modelProvider ?? null;
27958
28035
  this.permissionProfileConfig = permissionProfileConfig;
27959
28036
  this.gatewayConfig = null;
28037
+ this.gatewayConfigSource = null;
27960
28038
  this.subagents = new CodexSubagentSubscriptions(codexClient);
27961
28039
  }
27962
28040
  get appServerClient() {
@@ -27989,6 +28067,7 @@ var CodexAcpClient = class {
27989
28067
  throw RequestError.invalidRequest();
27990
28068
  }
27991
28069
  this.gatewayConfig = null;
28070
+ this.gatewayConfigSource = null;
27992
28071
  switch (authRequest.methodId) {
27993
28072
  case "api-key":
27994
28073
  return await this.authenticateWithApiKey(authRequest);
@@ -28072,7 +28151,7 @@ var CodexAcpClient = class {
28072
28151
  apiType: GatewayAuthMethod._meta.gateway.protocol,
28073
28152
  headers: gatewaySettings.headers,
28074
28153
  providerName: gatewaySettings.providerName
28075
- });
28154
+ }, "authentication");
28076
28155
  return true;
28077
28156
  }
28078
28157
  readApiKeyFromEnv() {
@@ -28118,6 +28197,11 @@ var CodexAcpClient = class {
28118
28197
  };
28119
28198
  }
28120
28199
  }
28200
+ /**
28201
+ * The provider that actually serves requests, ACP-configured gateway
28202
+ * routing included. Use {@link getAgentConfiguredModelProvider} instead
28203
+ * when asking what the agent itself is configured with (`authStatus`).
28204
+ */
28121
28205
  async getCurrentModelProvider() {
28122
28206
  const sessionModelProvider = this.getModelProvider();
28123
28207
  if (sessionModelProvider !== null) {
@@ -28143,7 +28227,7 @@ var CodexAcpClient = class {
28143
28227
  * method and the ACP `providers/set` method. Throws `invalid_params` for an
28144
28228
  * unsupported protocol or a malformed base URL.
28145
28229
  */
28146
- applyGatewayConfig(params) {
28230
+ applyGatewayConfig(params, source) {
28147
28231
  const apiType = params.apiType;
28148
28232
  const wireApi = SUPPORTED_GATEWAY_PROTOCOLS[apiType];
28149
28233
  if (!wireApi) {
@@ -28160,6 +28244,7 @@ var CodexAcpClient = class {
28160
28244
  "X-Client-Feature-ID": "codex",
28161
28245
  ...params.headers
28162
28246
  };
28247
+ this.gatewayConfigSource = source;
28163
28248
  this.gatewayConfig = {
28164
28249
  modelProvider: CUSTOM_GATEWAY_PROVIDER_ID,
28165
28250
  config: {
@@ -28224,7 +28309,7 @@ var CodexAcpClient = class {
28224
28309
  apiType: request.apiType,
28225
28310
  baseUrl: request.baseUrl,
28226
28311
  headers: request.headers
28227
- });
28312
+ }, "acpProviders");
28228
28313
  logger.log("providers/set applied", {
28229
28314
  providerId: request.providerId,
28230
28315
  apiType: request.apiType,
@@ -28240,6 +28325,7 @@ var CodexAcpClient = class {
28240
28325
  const overrideWasActive = this.gatewayConfig !== null;
28241
28326
  if (request.providerId === OPENAI_PROVIDER_ID) {
28242
28327
  this.gatewayConfig = null;
28328
+ this.gatewayConfigSource = null;
28243
28329
  }
28244
28330
  const current = this.gatewayConfig ? {
28245
28331
  apiType: gatewayApiTypeFromConfig(this.gatewayConfig),
@@ -28257,12 +28343,44 @@ var CodexAcpClient = class {
28257
28343
  async getAccount() {
28258
28344
  return this.codexClient.accountRead({ refreshToken: false });
28259
28345
  }
28346
+ async getRateLimits() {
28347
+ return this.codexClient.accountRateLimitsRead();
28348
+ }
28349
+ /**
28350
+ * Presentable name of the gateway the agent itself authenticated against
28351
+ * (the `gateway` auth method), or `null`. Routing that the client
28352
+ * configured through `providers/set` is deliberately not reported here:
28353
+ * `authStatus` describes the agent-owned login only.
28354
+ */
28355
+ getAuthGatewayProviderName() {
28356
+ return this.gatewayConfigSource === "authentication" ? this.gatewayConfig?.config.name ?? null : null;
28357
+ }
28358
+ /** Whether this provider id is client-driven routing set through `providers/set`. */
28359
+ isClientConfiguredProvider(providerId) {
28360
+ return providerId === CUSTOM_GATEWAY_PROVIDER_ID && this.gatewayConfigSource === "acpProviders";
28361
+ }
28362
+ /**
28363
+ * The model provider the agent itself is configured with (launch option or
28364
+ * Codex config), ignoring any ACP-configured gateway routing. The
28365
+ * routing-aware counterpart is {@link getCurrentModelProvider}.
28366
+ */
28367
+ async getAgentConfiguredModelProvider() {
28368
+ const provider = this.getModelProvider();
28369
+ const agentProvider = this.isClientConfiguredProvider(provider) ? this.modelProvider : provider;
28370
+ if (agentProvider !== null) {
28371
+ return agentProvider;
28372
+ }
28373
+ const settingsModelProvider = await this.codexClient.configRead({ includeLayers: false });
28374
+ return settingsModelProvider?.config?.model_provider ?? null;
28375
+ }
28260
28376
  async resumeSession(request, onSubscribed) {
28261
28377
  const additionalDirectories = readAdditionalDirectories(request.cwd, request.additionalDirectories, request._meta);
28262
28378
  const initialAgentMode = AgentMode.getInitialAgentMode();
28263
28379
  await this.refreshSkills(request.cwd, additionalDirectories);
28380
+ const prepared = await this.createSessionConfig(request.cwd, additionalDirectories, request.mcpServers ?? []);
28381
+ await this.restrictResumedHttpMcpServers(request.sessionId, prepared);
28264
28382
  const response = await this.codexClient.threadResume({
28265
- config: await this.createSessionConfig(request.cwd, additionalDirectories, request.mcpServers ?? []),
28383
+ config: prepared.config,
28266
28384
  cwd: request.cwd,
28267
28385
  modelProvider: await this.getResumeModelProvider(),
28268
28386
  threadId: request.sessionId,
@@ -28278,7 +28396,8 @@ var CodexAcpClient = class {
28278
28396
  collaborationMode: this.getCollaborationMode(response.thread.id),
28279
28397
  modelProvider: response.modelProvider,
28280
28398
  currentServiceTier: response.serviceTier ?? null,
28281
- additionalDirectories
28399
+ additionalDirectories,
28400
+ fullAccessHttpMcpServers: prepared.fullAccessHttpMcpServers
28282
28401
  };
28283
28402
  }
28284
28403
  async forkSession(request) {
@@ -28297,8 +28416,10 @@ var CodexAcpClient = class {
28297
28416
  const additionalDirectories = readAdditionalDirectories(request.cwd, request.additionalDirectories, request._meta);
28298
28417
  const initialAgentMode = AgentMode.getInitialAgentMode();
28299
28418
  await this.refreshSkills(request.cwd, additionalDirectories);
28419
+ const prepared = await this.createSessionConfig(request.cwd, additionalDirectories, request.mcpServers ?? []);
28420
+ await this.restrictResumedHttpMcpServers(request.sessionId, prepared);
28300
28421
  const response = await this.codexClient.threadResume({
28301
- config: await this.createSessionConfig(request.cwd, additionalDirectories, request.mcpServers ?? []),
28422
+ config: prepared.config,
28302
28423
  cwd: request.cwd,
28303
28424
  modelProvider: await this.getResumeModelProvider(),
28304
28425
  threadId: request.sessionId,
@@ -28319,7 +28440,8 @@ var CodexAcpClient = class {
28319
28440
  modelProvider: response.modelProvider,
28320
28441
  currentServiceTier: response.serviceTier ?? null,
28321
28442
  thread: historyResponse.thread,
28322
- additionalDirectories
28443
+ additionalDirectories,
28444
+ fullAccessHttpMcpServers: prepared.fullAccessHttpMcpServers
28323
28445
  };
28324
28446
  }
28325
28447
  async readSessionThread(sessionId) {
@@ -28332,8 +28454,9 @@ var CodexAcpClient = class {
28332
28454
  const additionalDirectories = readAdditionalDirectories(request.cwd, request.additionalDirectories, request._meta);
28333
28455
  const initialAgentMode = AgentMode.getInitialAgentMode();
28334
28456
  await this.refreshSkills(request.cwd, additionalDirectories);
28457
+ const prepared = await this.createSessionConfig(request.cwd, additionalDirectories, request.mcpServers);
28335
28458
  const response = await this.codexClient.threadStart({
28336
- config: await this.createSessionConfig(request.cwd, additionalDirectories, request.mcpServers),
28459
+ config: prepared.config,
28337
28460
  modelProvider: this.getModelProvider(),
28338
28461
  cwd: request.cwd,
28339
28462
  ...this.permissionProfileSelection(initialAgentMode, request.cwd, additionalDirectories)
@@ -28350,7 +28473,8 @@ var CodexAcpClient = class {
28350
28473
  collaborationMode: this.getCollaborationMode(response.thread.id),
28351
28474
  modelProvider: response.modelProvider,
28352
28475
  currentServiceTier: response.serviceTier ?? null,
28353
- additionalDirectories
28476
+ additionalDirectories,
28477
+ fullAccessHttpMcpServers: prepared.fullAccessHttpMcpServers
28354
28478
  };
28355
28479
  }
28356
28480
  async closeSession(sessionId) {
@@ -28365,11 +28489,23 @@ var CodexAcpClient = class {
28365
28489
  const config2 = this.permissionProfileConfig;
28366
28490
  if (!config2) return {};
28367
28491
  return {
28368
- approvalPolicy: agentMode.approvalPolicy,
28492
+ approvalPolicy: this.approvalPolicyForMode(agentMode),
28369
28493
  permissions: permissionProfileForMode(config2, agentMode.id),
28370
28494
  runtimeWorkspaceRoots: sessionRoots(cwd, additionalDirectories)
28371
28495
  };
28372
28496
  }
28497
+ isProtectedFullAccess(agentMode) {
28498
+ return this.permissionProfileConfig !== void 0 && agentMode.kind === "full_access";
28499
+ }
28500
+ approvalPolicyForMode(agentMode) {
28501
+ if (!this.isProtectedFullAccess(agentMode)) return agentMode.approvalPolicy;
28502
+ return { granular: { sandbox_approval: false, rules: false, skill_approval: false, request_permissions: false, mcp_elicitations: false } };
28503
+ }
28504
+ async restrictResumedHttpMcpServers(sessionId, prepared) {
28505
+ if (prepared.fullAccessHttpMcpServers.length === 0) return;
28506
+ const loaded = await this.codexClient.threadLoadedList({});
28507
+ if (loaded.data.includes(sessionId) || loaded.nextCursor !== null) prepared.fullAccessHttpMcpServers = [];
28508
+ }
28373
28509
  async deleteSession(sessionId) {
28374
28510
  await this.codexClient.threadArchive({ threadId: sessionId });
28375
28511
  }
@@ -28454,23 +28590,25 @@ var CodexAcpClient = class {
28454
28590
  };
28455
28591
  const configWithWorkspaceRoots = mergeSandboxWorkspaceWriteRoots(mergedConfig, additionalDirectories);
28456
28592
  if (mcpServers.length === 0) {
28457
- return configWithWorkspaceRoots;
28593
+ return { config: configWithWorkspaceRoots, fullAccessHttpMcpServers: [] };
28458
28594
  }
28459
28595
  const requestedServers = mcpServers.map((mcp) => ({
28460
28596
  name: sanitizeMcpServerName(mcp.name),
28461
28597
  server: mcp
28462
28598
  }));
28463
28599
  let serversToConfigure = requestedServers;
28600
+ const existingNames = shouldDeduplicateMcpConflicts() || this.permissionProfileConfig ? await this.getConfigMcpServerNames(projectPath) : /* @__PURE__ */ new Set();
28464
28601
  if (shouldDeduplicateMcpConflicts()) {
28465
- const existingNames = await this.getConfigMcpServerNames(projectPath);
28466
28602
  serversToConfigure = requestedServers.filter((mcp) => !existingNames.has(mcp.name));
28467
28603
  }
28468
28604
  if (serversToConfigure.length === 0) {
28469
- return configWithWorkspaceRoots;
28605
+ return { config: configWithWorkspaceRoots, fullAccessHttpMcpServers: [] };
28470
28606
  }
28607
+ const configuredServers = Object.fromEntries(serversToConfigure.map((mcp) => [mcp.name, this.createMcpSeverConfig(mcp.server)]));
28608
+ const inheritedServers = isJsonObject(this.config["mcp_servers"]) ? this.config["mcp_servers"] : {};
28471
28609
  return {
28472
- ...configWithWorkspaceRoots,
28473
- "mcp_servers": Object.fromEntries(serversToConfigure.map((mcp) => [mcp.name, this.createMcpSeverConfig(mcp.server)]))
28610
+ config: { ...configWithWorkspaceRoots, mcp_servers: configuredServers },
28611
+ fullAccessHttpMcpServers: this.permissionProfileConfig ? Object.entries(configuredServers).filter(([name, server]) => typeof server["url"] === "string" && !existingNames.has(name) && !Object.hasOwn(inheritedServers, name)).map(([name]) => name) : []
28474
28612
  };
28475
28613
  }
28476
28614
  async getConfigMcpServerNames(projectPath) {
@@ -28603,7 +28741,7 @@ var CodexAcpClient = class {
28603
28741
  return await this.codexClient.runTurn({
28604
28742
  threadId: request.sessionId,
28605
28743
  input,
28606
- approvalPolicy: agentMode.approvalPolicy,
28744
+ approvalPolicy: this.approvalPolicyForMode(agentMode),
28607
28745
  approvalsReviewer: agentMode.approvalsReviewer,
28608
28746
  ...sandboxSelection,
28609
28747
  summary: disableSummary ? "none" : "auto",
@@ -28711,7 +28849,7 @@ var CodexAcpClient = class {
28711
28849
  if (!config2) return;
28712
28850
  await this.codexClient.threadSettingsUpdate({
28713
28851
  threadId: sessionId,
28714
- approvalPolicy: agentMode.approvalPolicy,
28852
+ approvalPolicy: this.approvalPolicyForMode(agentMode),
28715
28853
  permissions: permissionProfileForMode(config2, agentMode.id)
28716
28854
  });
28717
28855
  }
@@ -29478,6 +29616,12 @@ var CodexAppServerClient = class {
29478
29616
  async threadCompactStart(params) {
29479
29617
  return await this.sendRequest({ method: "thread/compact/start", params });
29480
29618
  }
29619
+ async threadBackgroundTerminalsList(params) {
29620
+ return await this.sendRequest({ method: "thread/backgroundTerminals/list", params });
29621
+ }
29622
+ async threadBackgroundTerminalsTerminate(params) {
29623
+ return await this.sendRequest({ method: "thread/backgroundTerminals/terminate", params });
29624
+ }
29481
29625
  async threadGoalSet(params) {
29482
29626
  return await this.sendRequest({ method: "thread/goal/set", params });
29483
29627
  }
@@ -29543,6 +29687,9 @@ var CodexAppServerClient = class {
29543
29687
  async accountRead(params) {
29544
29688
  return await this.sendRequest({ method: "account/read", params });
29545
29689
  }
29690
+ async accountRateLimitsRead() {
29691
+ return await this.sendRequest({ method: "account/rateLimits/read", params: void 0 });
29692
+ }
29546
29693
  //TODO create type-safe helper
29547
29694
  async awaitTurnCompleted(threadId, turnId) {
29548
29695
  return await new Promise((resolve) => {
@@ -30149,6 +30296,7 @@ var CodexCommands = class {
30149
30296
  return { handled: true, turnCompleted };
30150
30297
  }
30151
30298
  case "status": {
30299
+ await this.refreshRateLimits(sessionState);
30152
30300
  const session = new ACPSessionConnection(this.connection, sessionId);
30153
30301
  const message = this.buildStatusMessage(sessionState);
30154
30302
  await session.update(createAgentTextMessageChunk(message));
@@ -30297,6 +30445,16 @@ var CodexCommands = class {
30297
30445
  ];
30298
30446
  return lines.join(" \n");
30299
30447
  }
30448
+ async refreshRateLimits(sessionState) {
30449
+ try {
30450
+ const response = await this.runWithProcessCheck(() => this.codexAcpClient.getRateLimits());
30451
+ if (response) {
30452
+ sessionState.rateLimits = createRateLimitsMap(response);
30453
+ }
30454
+ } catch (err) {
30455
+ logger.error(`Failed to refresh rate limits for session ${sessionState.sessionId}`, err);
30456
+ }
30457
+ }
30300
30458
  formatAccountInfo(account) {
30301
30459
  if (!account) {
30302
30460
  return "not logged in";
@@ -30327,10 +30485,10 @@ var CodexCommands = class {
30327
30485
  return "data not available yet";
30328
30486
  }
30329
30487
  const used = usage.totalTokens;
30330
- const percentLeft = Math.round((contextWindow - used) / contextWindow * 100);
30488
+ const percentUsed = Math.round(used / contextWindow * 100);
30331
30489
  const usedFormatted = this.formatTokenCount(used);
30332
30490
  const totalFormatted = this.formatTokenCount(contextWindow);
30333
- return `${percentLeft}% left (${usedFormatted} used / ${totalFormatted})`;
30491
+ return `${percentUsed}% used (${usedFormatted} used / ${totalFormatted})`;
30334
30492
  }
30335
30493
  formatRateLimitLines(rateLimits) {
30336
30494
  if (!rateLimits || rateLimits.size === 0) {
@@ -30364,8 +30522,31 @@ var CodexCommands = class {
30364
30522
  lines.push(`**${prefix}Credits:** ${rateLimits.credits.balance}`);
30365
30523
  }
30366
30524
  }
30525
+ if (rateLimits.individualLimit) {
30526
+ const limit = rateLimits.individualLimit;
30527
+ const used = this.formatCreditAmount(limit.used);
30528
+ const total = this.formatCreditAmount(limit.limit);
30529
+ if (used !== null && total !== null) {
30530
+ const percentLeft = Math.round(Math.min(100, Math.max(0, limit.remainingPercent)));
30531
+ const resetDate = new Date(limit.resetsAt * 1e3).toLocaleDateString("en-US", { month: "short", day: "numeric" });
30532
+ lines.push(
30533
+ `**${prefix}individual spend limit:** ${percentLeft}% left (${used} of ${total} credits used; resets ${resetDate})`
30534
+ );
30535
+ }
30536
+ }
30367
30537
  return lines;
30368
30538
  }
30539
+ formatCreditAmount(raw) {
30540
+ const trimmed = raw.trim();
30541
+ if (trimmed.length === 0) {
30542
+ return null;
30543
+ }
30544
+ const value = Number(trimmed);
30545
+ if (!Number.isFinite(value) || value < 0) {
30546
+ return null;
30547
+ }
30548
+ return Math.round(value).toLocaleString("en-US");
30549
+ }
30369
30550
  formatWindowLabel(windowDurationMins) {
30370
30551
  if (windowDurationMins === null) {
30371
30552
  return "Limit";
@@ -31412,11 +31593,147 @@ function numberValue(value) {
31412
31593
  return typeof value === "number" && Number.isFinite(value) ? value : null;
31413
31594
  }
31414
31595
 
31596
+ // src/async-tasks/AsyncTaskExtension.ts
31597
+ var ASYNC_TASK_STOP_METHOD = "_session/async_task/stop";
31598
+
31599
+ // src/AuthStatusMeta.ts
31600
+ var AUTH_STATUS_UPDATE_METHOD = "_auth/status_update";
31601
+ var AUTH_STATUS_META_KEY = "authStatus";
31602
+ function authStatusCapability() {
31603
+ return {};
31604
+ }
31605
+ var NOT_LOGGED_IN_LABEL = "Not logged in";
31606
+ var DEFAULT_GATEWAY_LABEL = "Custom model gateway";
31607
+ var PLAN_DISPLAY_NAMES = {
31608
+ free: "Free",
31609
+ go: "Go",
31610
+ plus: "Plus",
31611
+ pro: "Pro",
31612
+ team: "Team",
31613
+ business: "Business",
31614
+ enterprise: "Enterprise",
31615
+ edu: "Edu"
31616
+ };
31617
+ function planTypePresentable(planType) {
31618
+ if (!planType || planType === "unknown") {
31619
+ return null;
31620
+ }
31621
+ return PLAN_DISPLAY_NAMES[planType] ?? capitalize2(planType);
31622
+ }
31623
+ function capitalize2(value) {
31624
+ return value.charAt(0).toUpperCase() + value.slice(1);
31625
+ }
31626
+ function chatGptLabel(planType) {
31627
+ const plan = planTypePresentable(planType);
31628
+ return plan === null ? "ChatGPT" : `ChatGPT ${plan}`;
31629
+ }
31630
+ function gatewayStatus(providerName) {
31631
+ const detail = typeof providerName === "string" && providerName.trim().length > 0 ? providerName.trim() : void 0;
31632
+ return {
31633
+ kind: "gateway",
31634
+ label: DEFAULT_GATEWAY_LABEL,
31635
+ ...detail === void 0 ? {} : { detail }
31636
+ };
31637
+ }
31638
+ function unauthenticatedStatus() {
31639
+ return {
31640
+ kind: "none",
31641
+ label: NOT_LOGGED_IN_LABEL
31642
+ };
31643
+ }
31644
+ function fromAccount(account) {
31645
+ if (account === null) {
31646
+ return unauthenticatedStatus();
31647
+ }
31648
+ switch (account.type) {
31649
+ case "chatgpt": {
31650
+ const accountInfo = {};
31651
+ if (account.email) {
31652
+ accountInfo.email = account.email;
31653
+ }
31654
+ if (account.planType) {
31655
+ accountInfo.plan = account.planType;
31656
+ }
31657
+ return {
31658
+ kind: "account",
31659
+ label: chatGptLabel(account.planType),
31660
+ ...Object.keys(accountInfo).length > 0 ? { account: accountInfo } : {}
31661
+ };
31662
+ }
31663
+ case "apiKey":
31664
+ return {
31665
+ kind: "api_key",
31666
+ label: "OpenAI API key"
31667
+ };
31668
+ case "amazonBedrock":
31669
+ return {
31670
+ kind: "external",
31671
+ label: "AWS Bedrock"
31672
+ };
31673
+ }
31674
+ }
31675
+ function fromAccountUpdated(notification, previous) {
31676
+ const authMode = notification.authMode;
31677
+ if (authMode === null) {
31678
+ return unauthenticatedStatus();
31679
+ }
31680
+ switch (authMode) {
31681
+ case "chatgpt":
31682
+ case "chatgptAuthTokens": {
31683
+ const status = {
31684
+ kind: "account",
31685
+ label: chatGptLabel(notification.planType)
31686
+ };
31687
+ const accountInfo = {};
31688
+ const previousEmail = previous?.kind === "account" ? previous.account?.email : void 0;
31689
+ if (previousEmail) {
31690
+ accountInfo.email = previousEmail;
31691
+ }
31692
+ if (notification.planType) {
31693
+ accountInfo.plan = notification.planType;
31694
+ }
31695
+ if (Object.keys(accountInfo).length > 0) {
31696
+ status.account = accountInfo;
31697
+ }
31698
+ return status;
31699
+ }
31700
+ case "apikey":
31701
+ return {
31702
+ kind: "api_key",
31703
+ label: "OpenAI API key"
31704
+ };
31705
+ case "personalAccessToken":
31706
+ return {
31707
+ kind: "api_key",
31708
+ label: "OpenAI personal access token"
31709
+ };
31710
+ case "bedrockApiKey":
31711
+ case "bedrockAccessKeys":
31712
+ return {
31713
+ kind: "external",
31714
+ label: "AWS Bedrock"
31715
+ };
31716
+ case "agentIdentity":
31717
+ return {
31718
+ kind: "external",
31719
+ label: "Agent identity"
31720
+ };
31721
+ case "headers":
31722
+ return gatewayStatus();
31723
+ }
31724
+ }
31725
+ function sameAuthStatus(previous, next) {
31726
+ if (!previous) {
31727
+ return false;
31728
+ }
31729
+ return previous.kind === next.kind && previous.label === next.label && previous.detail === next.detail && previous.account?.email === next.account?.email && previous.account?.organization === next.account?.organization && previous.account?.plan === next.account?.plan && JSON.stringify(previous.vendor) === JSON.stringify(next.vendor);
31730
+ }
31731
+
31415
31732
  // src/AcpExtensions.ts
31416
31733
  var LEGACY_SET_SESSION_MODEL_METHOD = "session/set_model";
31417
31734
  var SESSION_STEERING_METHOD = "_session/steering";
31418
31735
  function isExtMethodRequest(request) {
31419
- return request.method === "authentication/status" || request.method === "authentication/logout" || request.method === LEGACY_SET_SESSION_MODEL_METHOD || request.method === GOAL_CONTROL_METHOD || request.method === LEGACY_GOAL_CONTROL_METHOD || request.method === SESSION_STEERING_METHOD;
31736
+ return request.method === "authentication/status" || request.method === "authentication/logout" || request.method === LEGACY_SET_SESSION_MODEL_METHOD || request.method === GOAL_CONTROL_METHOD || request.method === LEGACY_GOAL_CONTROL_METHOD || request.method === SESSION_STEERING_METHOD || request.method === ASYNC_TASK_STOP_METHOD;
31420
31737
  }
31421
31738
 
31422
31739
  // src/FastModeConfig.ts
@@ -31483,6 +31800,15 @@ function clientSupportsPlanUpdates(clientCapabilities) {
31483
31800
  return clientCapabilities?.plan != null;
31484
31801
  }
31485
31802
 
31803
+ // src/subagents/AcpSubagents.ts
31804
+ function clientSupportsSubagents(capabilities) {
31805
+ const subagents = capabilities?.subagents;
31806
+ if (typeof subagents === "object" && subagents !== null && !Array.isArray(subagents)) {
31807
+ return true;
31808
+ }
31809
+ return clientSupportsAirCapability(capabilities, AIR_NATIVE_SUBAGENT_SESSIONS_KEY);
31810
+ }
31811
+
31486
31812
  // src/CodexAcpServer.ts
31487
31813
  import { randomUUID as randomUUID2 } from "node:crypto";
31488
31814
 
@@ -31571,6 +31897,332 @@ function extractTitle(turn) {
31571
31897
 
31572
31898
  // src/CodexAcpServer.ts
31573
31899
  import { once } from "node:events";
31900
+
31901
+ // src/async-tasks/CodexBackgroundTerminalTasks.ts
31902
+ var CodexBackgroundTerminalTasks = class {
31903
+ constructor(enabled, rootSessionId, appServer, session) {
31904
+ this.enabled = enabled;
31905
+ this.rootSessionId = rootSessionId;
31906
+ this.appServer = appServer;
31907
+ this.session = session;
31908
+ }
31909
+ enabled;
31910
+ rootSessionId;
31911
+ appServer;
31912
+ session;
31913
+ tasks = /* @__PURE__ */ new Map();
31914
+ syncs = /* @__PURE__ */ new Map();
31915
+ appServerGeneration = 0;
31916
+ appServerQueriesEnabled = true;
31917
+ disposed = false;
31918
+ async handleNotification(notification, sessionId, commandTitle2) {
31919
+ if (!this.isActive()) return;
31920
+ const threadId = notificationThreadId(notification);
31921
+ if (threadId === null) return;
31922
+ if (notification.method === "item/started" && notification.params.item.type === "commandExecution") {
31923
+ this.observeCommandStarted(notification.params.item, threadId, sessionId, commandTitle2);
31924
+ return;
31925
+ }
31926
+ if (notification.method === "item/completed" && notification.params.item.type === "commandExecution") {
31927
+ await this.observeCommandCompleted(notification.params.item, threadId);
31928
+ return;
31929
+ }
31930
+ if (notification.method === "turn/completed") {
31931
+ await this.reconcile(threadId, sessionId);
31932
+ return;
31933
+ }
31934
+ if (notification.method === "item/started") {
31935
+ this.refresh(threadId, sessionId);
31936
+ }
31937
+ }
31938
+ observeCommandStarted(item, threadId, sessionId, commandTitle2) {
31939
+ if (!this.isActive() || item.processId === null) return;
31940
+ this.remember(threadId, sessionId, {
31941
+ itemId: item.id,
31942
+ processId: item.processId,
31943
+ command: item.command
31944
+ }, commandTitle2);
31945
+ }
31946
+ async observeCommandCompleted(item, threadId) {
31947
+ if (!this.isActive()) return;
31948
+ const task = this.tasks.get(wireTaskId(this.rootSessionId, threadId, item.id));
31949
+ if (task) await this.finish(task, item.status === "completed" ? "completed" : "failed");
31950
+ }
31951
+ refresh(threadId = this.rootSessionId, sessionId = this.rootSessionId) {
31952
+ void this.reconcile(threadId, sessionId);
31953
+ }
31954
+ async reconcile(threadId = this.rootSessionId, sessionId = this.rootSessionId) {
31955
+ try {
31956
+ await this.sync(threadId, sessionId);
31957
+ } catch (error51) {
31958
+ if (this.isActive()) logger.error(`Failed to list background terminals for ${threadId}`, error51);
31959
+ }
31960
+ }
31961
+ setAppServer(appServer) {
31962
+ this.appServer = appServer;
31963
+ this.appServerGeneration += 1;
31964
+ this.appServerQueriesEnabled = true;
31965
+ }
31966
+ prepareForAppServerReplacement() {
31967
+ this.appServerGeneration += 1;
31968
+ this.appServerQueriesEnabled = false;
31969
+ }
31970
+ async recover(threadId, sessionId, itemIds) {
31971
+ if (!this.canQueryAppServer() || itemIds.size === 0) return;
31972
+ const snapshot = await this.listAll(threadId);
31973
+ if (snapshot === null) return;
31974
+ for (const terminal of snapshot.terminals) {
31975
+ if (!this.queryIsCurrent(snapshot.generation)) return;
31976
+ if (!itemIds.has(terminal.itemId)) continue;
31977
+ const task = this.remember(threadId, sessionId, terminal);
31978
+ if (task.publication === "unpublished" && task.state === "running") await this.announce(task);
31979
+ }
31980
+ }
31981
+ async finishAll(state) {
31982
+ if (!this.isActive()) return;
31983
+ const errors = [];
31984
+ for (const task of this.tasks.values()) {
31985
+ try {
31986
+ await this.finish(task, state);
31987
+ } catch (error51) {
31988
+ errors.push(error51);
31989
+ }
31990
+ }
31991
+ if (errors.length > 0) {
31992
+ throw new AggregateError(errors, `Failed to finish ${errors.length} background terminal task(s)`);
31993
+ }
31994
+ }
31995
+ async sync(threadId = this.rootSessionId, sessionId = this.rootSessionId) {
31996
+ if (!this.canQueryAppServer()) return;
31997
+ const current = this.syncs.get(threadId);
31998
+ if (current) {
31999
+ current.requested = true;
32000
+ current.sessionId = sessionId;
32001
+ return await current.promise;
32002
+ }
32003
+ const pending = {
32004
+ requested: false,
32005
+ sessionId,
32006
+ promise: Promise.resolve()
32007
+ };
32008
+ pending.promise = this.syncUntilCurrent(threadId, pending).finally(() => {
32009
+ if (this.syncs.get(threadId) === pending) this.syncs.delete(threadId);
32010
+ });
32011
+ this.syncs.set(threadId, pending);
32012
+ await pending.promise;
32013
+ }
32014
+ async stop(taskId) {
32015
+ if (!this.isActive()) return false;
32016
+ const task = this.tasks.get(taskId);
32017
+ if (!task || task.publication !== "published") return false;
32018
+ if (task.state === "stopped" && !task.terminalPublished) {
32019
+ await this.publishTerminalState(task);
32020
+ return true;
32021
+ }
32022
+ if (task.state !== "running") return false;
32023
+ task.state = "stopping";
32024
+ try {
32025
+ const response = await this.appServer.threadBackgroundTerminalsTerminate({
32026
+ threadId: task.threadId,
32027
+ processId: task.processId
32028
+ });
32029
+ if (!response.terminated) {
32030
+ if (task.state === "stopping") task.state = "running";
32031
+ return false;
32032
+ }
32033
+ await this.finish(task, "stopped");
32034
+ return true;
32035
+ } catch (error51) {
32036
+ if (task.state === "stopping") task.state = "running";
32037
+ throw error51;
32038
+ }
32039
+ }
32040
+ clear() {
32041
+ this.disposed = true;
32042
+ this.appServerGeneration += 1;
32043
+ this.appServerQueriesEnabled = false;
32044
+ this.tasks.clear();
32045
+ this.syncs.clear();
32046
+ }
32047
+ async syncThread(threadId, sessionId) {
32048
+ const snapshot = await this.listAll(threadId);
32049
+ if (snapshot === null || !this.queryIsCurrent(snapshot.generation)) return;
32050
+ const liveTaskIds = /* @__PURE__ */ new Set();
32051
+ for (const terminal of snapshot.terminals) {
32052
+ if (!this.queryIsCurrent(snapshot.generation)) return;
32053
+ liveTaskIds.add(terminal.itemId);
32054
+ const task = this.remember(threadId, sessionId, terminal);
32055
+ if (task.publication === "unpublished" && task.state === "running") await this.announce(task);
32056
+ }
32057
+ for (const task of this.tasks.values()) {
32058
+ if (!this.queryIsCurrent(snapshot.generation)) return;
32059
+ if (task.threadId === threadId && task.publication === "published" && (task.state === "running" || task.state === "stopping") && !liveTaskIds.has(task.itemId)) {
32060
+ await this.finish(task, "stopped");
32061
+ }
32062
+ }
32063
+ }
32064
+ async syncUntilCurrent(threadId, pending) {
32065
+ let hasFailure = false;
32066
+ let failure;
32067
+ do {
32068
+ pending.requested = false;
32069
+ try {
32070
+ await this.syncThread(threadId, pending.sessionId);
32071
+ hasFailure = false;
32072
+ } catch (error51) {
32073
+ hasFailure = true;
32074
+ failure = error51;
32075
+ }
32076
+ } while (pending.requested && this.canQueryAppServer());
32077
+ if (hasFailure) throw failure;
32078
+ }
32079
+ async announce(task) {
32080
+ if (task.publication === "published") return;
32081
+ if (task.announcement !== null) {
32082
+ await task.announcement;
32083
+ return;
32084
+ }
32085
+ task.publication = "publishing";
32086
+ const announcement = this.publishAnnouncement(task);
32087
+ task.announcement = announcement;
32088
+ try {
32089
+ await announcement;
32090
+ } finally {
32091
+ if (task.announcement === announcement) task.announcement = null;
32092
+ }
32093
+ if (isTerminalState(task.state)) await this.publishTerminalState(task);
32094
+ }
32095
+ async publishAnnouncement(task) {
32096
+ try {
32097
+ await this.publishSpawn(task);
32098
+ task.publication = "published";
32099
+ } catch (error51) {
32100
+ task.publication = "unpublished";
32101
+ throw error51;
32102
+ }
32103
+ }
32104
+ async publishSpawn(task) {
32105
+ await this.session.update({
32106
+ sessionUpdate: "tool_call_update",
32107
+ toolCallId: task.itemId,
32108
+ _meta: {
32109
+ [JETBRAINS_META_KEY]: {
32110
+ [AIR_META_KEY]: {
32111
+ [AIR_ASYNC_TASKS_KEY]: {
32112
+ [AIR_ASYNC_TASKS_BACKGROUNDED_KEY]: true
32113
+ }
32114
+ }
32115
+ }
32116
+ }
32117
+ }, task.sessionId);
32118
+ await this.session.update({
32119
+ sessionUpdate: "async_task_spawned",
32120
+ asyncTaskId: task.asyncTaskId,
32121
+ name: task.name,
32122
+ taskType: "shell",
32123
+ showInTranscript: false,
32124
+ canStop: true,
32125
+ toolCallId: task.itemId
32126
+ }, task.sessionId);
32127
+ }
32128
+ remember(threadId, sessionId, terminal, commandTitle2) {
32129
+ const asyncTaskId = wireTaskId(this.rootSessionId, threadId, terminal.itemId);
32130
+ const existing = this.tasks.get(asyncTaskId);
32131
+ if (existing) {
32132
+ existing.processId = terminal.processId;
32133
+ if (commandTitle2 !== void 0) existing.name = commandTitle2;
32134
+ return existing;
32135
+ }
32136
+ const task = {
32137
+ threadId,
32138
+ sessionId,
32139
+ asyncTaskId,
32140
+ processId: terminal.processId,
32141
+ itemId: terminal.itemId,
32142
+ name: commandTitle2 ?? terminal.command,
32143
+ publication: "unpublished",
32144
+ announcement: null,
32145
+ terminalUpdate: null,
32146
+ terminalPublished: false,
32147
+ state: "running"
32148
+ };
32149
+ this.tasks.set(asyncTaskId, task);
32150
+ return task;
32151
+ }
32152
+ async finish(task, state) {
32153
+ if (task.state === "running" || task.state === "stopping") {
32154
+ task.state = state;
32155
+ } else if (task.state !== state) {
32156
+ return;
32157
+ }
32158
+ if (task.announcement !== null) await task.announcement;
32159
+ if (task.publication === "published") await this.publishTerminalState(task);
32160
+ }
32161
+ async publishTerminalState(task) {
32162
+ if (!isTerminalState(task.state) || task.terminalPublished) return;
32163
+ if (task.terminalUpdate !== null) {
32164
+ await task.terminalUpdate;
32165
+ return;
32166
+ }
32167
+ const terminalUpdate = this.session.update({
32168
+ sessionUpdate: "async_task_state_update",
32169
+ asyncTaskId: task.asyncTaskId,
32170
+ state: task.state,
32171
+ toolCallId: task.itemId
32172
+ }, task.sessionId);
32173
+ task.terminalUpdate = terminalUpdate;
32174
+ try {
32175
+ await terminalUpdate;
32176
+ task.terminalPublished = true;
32177
+ } finally {
32178
+ if (task.terminalUpdate === terminalUpdate) task.terminalUpdate = null;
32179
+ }
32180
+ }
32181
+ async listAll(threadId) {
32182
+ const appServer = this.appServer;
32183
+ const generation = this.appServerGeneration;
32184
+ const terminals = [];
32185
+ const seenCursors = /* @__PURE__ */ new Set();
32186
+ let cursor = null;
32187
+ do {
32188
+ const response = await appServer.threadBackgroundTerminalsList({
32189
+ threadId,
32190
+ cursor
32191
+ });
32192
+ if (!this.queryIsCurrent(generation)) return null;
32193
+ terminals.push(...response.data);
32194
+ cursor = response.nextCursor;
32195
+ if (cursor !== null) {
32196
+ if (seenCursors.has(cursor)) {
32197
+ throw new Error("Codex returned a repeated background terminal cursor");
32198
+ }
32199
+ seenCursors.add(cursor);
32200
+ }
32201
+ } while (cursor !== null);
32202
+ return { generation, terminals };
32203
+ }
32204
+ isActive() {
32205
+ return this.enabled && !this.disposed;
32206
+ }
32207
+ canQueryAppServer() {
32208
+ return this.isActive() && this.appServerQueriesEnabled;
32209
+ }
32210
+ queryIsCurrent(generation) {
32211
+ return this.canQueryAppServer() && generation === this.appServerGeneration;
32212
+ }
32213
+ };
32214
+ function isTerminalState(state) {
32215
+ return state === "completed" || state === "failed" || state === "stopped";
32216
+ }
32217
+ function wireTaskId(rootSessionId, threadId, itemId) {
32218
+ return threadId === rootSessionId ? itemId : `${threadId}:${itemId}`;
32219
+ }
32220
+ function notificationThreadId(notification) {
32221
+ const threadId = notification.params.threadId;
32222
+ return typeof threadId === "string" ? threadId : null;
32223
+ }
32224
+
32225
+ // src/CodexAcpServer.ts
31574
32226
  var CODEX_PROCESS_EXITED_ERROR_CODE = 1001;
31575
32227
  function clientSupportsTypedSessionFailures(capabilities) {
31576
32228
  return clientSupportsAirCapability(capabilities, AIR_SESSION_FAILURE_KEY);
@@ -31595,6 +32247,8 @@ var CodexAcpServer = class _CodexAcpServer {
31595
32247
  clientCapabilities;
31596
32248
  terminalOutputMode;
31597
32249
  booleanConfigOptionsSupported;
32250
+ /** Last `authStatus` pushed to the client; used to suppress duplicates. */
32251
+ currentAuthStatus;
31598
32252
  sessions;
31599
32253
  pendingMcpStartupSessions;
31600
32254
  pendingTurnStarts;
@@ -31606,6 +32260,7 @@ var CodexAcpServer = class _CodexAcpServer {
31606
32260
  goalControlGenerations;
31607
32261
  permissionLifecycleContexts;
31608
32262
  codexProcessState;
32263
+ codexProcessGeneration = 0;
31609
32264
  initializeRequest = null;
31610
32265
  providerUpdate = null;
31611
32266
  constructor(connection, codexAcpClient, defaultAuthRequest, getExitCode, getRecentStderr, codexProcessState) {
@@ -31631,14 +32286,16 @@ var CodexAcpServer = class _CodexAcpServer {
31631
32286
  this.clientCapabilities = null;
31632
32287
  this.terminalOutputMode = "terminal_output_delta";
31633
32288
  this.booleanConfigOptionsSupported = false;
32289
+ this.currentAuthStatus = null;
31634
32290
  this.availableCommands = this.createAvailableCommands(codexAcpClient);
32291
+ this.observeCodexProcess();
31635
32292
  }
31636
32293
  createAvailableCommands(client) {
31637
32294
  return new CodexCommands(
31638
32295
  this.connection,
31639
32296
  client,
31640
32297
  (operation) => this.runWithProcessCheck(operation),
31641
- () => this.refreshSessionsAuthState(null)
32298
+ () => this.refreshAuthState(null)
31642
32299
  );
31643
32300
  }
31644
32301
  async initialize(_params) {
@@ -31649,6 +32306,7 @@ var CodexAcpServer = class _CodexAcpServer {
31649
32306
  this.terminalOutputMode = resolveTerminalOutputMode(_params.clientCapabilities);
31650
32307
  this.booleanConfigOptionsSupported = clientSupportsBooleanConfigOptions(_params.clientCapabilities);
31651
32308
  await this.runWithProcessCheck(() => this.codexAcpClient.initialize(_params));
32309
+ this.publishFirstAuthStatusAfterResponse();
31652
32310
  const sessionCapabilities = {
31653
32311
  resume: {},
31654
32312
  list: {},
@@ -31680,6 +32338,11 @@ var CodexAcpServer = class _CodexAcpServer {
31680
32338
  acp: false,
31681
32339
  http: true,
31682
32340
  sse: false
32341
+ },
32342
+ _meta: {
32343
+ // Presence means "this agent pushes `_auth/status_update`". It
32344
+ // never carries a payload, and the client never asks for one.
32345
+ [AUTH_STATUS_META_KEY]: authStatusCapability()
31683
32346
  }
31684
32347
  },
31685
32348
  authMethods: getCodexAuthMethods(_params.clientCapabilities),
@@ -31698,7 +32361,8 @@ var CodexAcpServer = class _CodexAcpServer {
31698
32361
  [AIR_EXTENSION_CAPABILITIES_KEY]: [
31699
32362
  AIR_SESSION_FAILURE_KEY,
31700
32363
  AIR_AGENT_FILE_CHANGE_REPORT_KEY,
31701
- AIR_NATIVE_SUBAGENT_SESSIONS_KEY
32364
+ AIR_NATIVE_SUBAGENT_SESSIONS_KEY,
32365
+ AIR_ASYNC_TASKS_KEY
31702
32366
  ]
31703
32367
  }
31704
32368
  }
@@ -31721,6 +32385,18 @@ var CodexAcpServer = class _CodexAcpServer {
31721
32385
  return await this.unstable_setSessionModel(this.parseLegacySetSessionModelParams(methodRequest.params));
31722
32386
  case SESSION_STEERING_METHOD:
31723
32387
  return await this.executeOrQueueSteeringRequest(this.parseSessionSteerParams(methodRequest.params));
32388
+ case ASYNC_TASK_STOP_METHOD: {
32389
+ if (this.providerUpdate !== null) {
32390
+ await this.providerUpdate;
32391
+ }
32392
+ const sessionState = this.sessions.get(methodRequest.params.sessionId);
32393
+ if (!sessionState) return { stopped: false };
32394
+ return {
32395
+ stopped: await this.runWithProcessCheck(
32396
+ () => sessionState.asyncTasks.stop(methodRequest.params.asyncTaskId)
32397
+ )
32398
+ };
32399
+ }
31724
32400
  case GOAL_CONTROL_METHOD:
31725
32401
  case LEGACY_GOAL_CONTROL_METHOD: {
31726
32402
  const sessionState = this.sessions.get(methodRequest.params.sessionId);
@@ -31811,7 +32487,7 @@ var CodexAcpServer = class _CodexAcpServer {
31811
32487
  async handleError(e) {
31812
32488
  if (e.message.includes("log out") || e.message.includes("cloud requirements")) {
31813
32489
  await this.runWithProcessCheck(() => this.codexAcpClient.logout());
31814
- await this.refreshSessionsAuthState(null);
32490
+ await this.refreshAuthState(null);
31815
32491
  throw RequestError.internalError(`${e.message}
31816
32492
 
31817
32493
  You have been logged out. Please try again.`);
@@ -31939,6 +32615,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
31939
32615
  supportedReasoningEfforts: currentModel?.supportedReasoningEfforts ?? [],
31940
32616
  supportedInputModalities: currentModel?.inputModalities ?? ["text", "image"],
31941
32617
  agentMode: AgentMode.getInitialAgentMode(),
32618
+ fullAccessHttpMcpServers: sessionMetadata.fullAccessHttpMcpServers ?? [],
31942
32619
  collaborationMode: sessionMetadata.collaborationMode,
31943
32620
  currentTurnId: null,
31944
32621
  lastTokenUsage: null,
@@ -31962,7 +32639,8 @@ Check ${configPath} and project .codex directories, especially their config.toml
31962
32639
  sessionId,
31963
32640
  clientSupportsSubagents(this.clientCapabilities),
31964
32641
  new ACPSessionConnection(this.connection, sessionId)
31965
- )
32642
+ ),
32643
+ asyncTasks: this.createAsyncTasks(sessionId)
31966
32644
  };
31967
32645
  sessionState.titleGen = new TitleGenerator(
31968
32646
  this.codexAcpClient.appServerClient,
@@ -31970,7 +32648,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
31970
32648
  sessionState.cwd,
31971
32649
  () => sessionState.sessionTitleSource
31972
32650
  );
31973
- this.sessions.set(sessionId, sessionState);
32651
+ this.installSessionState(sessionState);
31974
32652
  resumeSubscribed = false;
31975
32653
  const canPublishSessionUpdates = operation !== "fork";
31976
32654
  if (canPublishSessionUpdates && requestedMcpServers.length > 0 && mcpServerStartupVersion !== null) {
@@ -31985,6 +32663,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
31985
32663
  }
31986
32664
  if (operation === "resume") {
31987
32665
  this.publishCurrentGoalAsync(sessionState, sessionGeneration);
32666
+ this.publishAsyncTasksAsync(sessionState, sessionGeneration);
31988
32667
  }
31989
32668
  const sessionModelState = this.createModelState(models, currentModelId);
31990
32669
  const sessionModeState = sessionState.agentMode.toSessionModeState();
@@ -31992,12 +32671,14 @@ Check ${configPath} and project .codex directories, especially their config.toml
31992
32671
  }
31993
32672
  async getAuthStateForProvider(authProvider) {
31994
32673
  if (!this.authProviderUsesOpenAiAccount(authProvider)) {
32674
+ await this.publishAuthStatus(authProvider, null);
31995
32675
  return {
31996
32676
  account: null,
31997
32677
  authConfigured: true
31998
32678
  };
31999
32679
  }
32000
32680
  const accountResponse = await this.runWithProcessCheck(() => this.codexAcpClient.getAccount());
32681
+ await this.publishAuthStatus(authProvider, accountResponse.account);
32001
32682
  return {
32002
32683
  account: accountResponse.account,
32003
32684
  authConfigured: accountResponse.account !== null || !accountResponse.requiresOpenaiAuth
@@ -32012,6 +32693,18 @@ Check ${configPath} and project .codex directories, especially their config.toml
32012
32693
  }
32013
32694
  return a === b;
32014
32695
  }
32696
+ createAsyncTasks(sessionId) {
32697
+ return new CodexBackgroundTerminalTasks(
32698
+ clientSupportsAirCapability(this.clientCapabilities, AIR_ASYNC_TASKS_KEY),
32699
+ sessionId,
32700
+ this.codexAcpClient.appServerClient,
32701
+ new ACPSessionConnection(this.connection, sessionId)
32702
+ );
32703
+ }
32704
+ installSessionState(sessionState) {
32705
+ this.sessions.get(sessionState.sessionId)?.asyncTasks.clear();
32706
+ this.sessions.set(sessionState.sessionId, sessionState);
32707
+ }
32015
32708
  getAuthProviderForAuthenticateRequest(request) {
32016
32709
  if (isCodexAuthRequest(request) && request.methodId === "gateway") {
32017
32710
  return "custom-gateway";
@@ -32030,6 +32723,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
32030
32723
  thread
32031
32724
  } = await this.getOrCreateSessionWithHistory(params);
32032
32725
  await this.streamThreadHistory(sessionId, thread);
32726
+ await this.getSessionState(sessionId).asyncTasks.reconcile();
32033
32727
  logger.log("Session loaded", {
32034
32728
  sessionId,
32035
32729
  modelId: modelState.currentModelId,
@@ -32103,6 +32797,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
32103
32797
  try {
32104
32798
  if (sessionState) {
32105
32799
  await this.interruptSessionTurn(sessionState, "Close", true);
32800
+ sessionState.asyncTasks.clear();
32106
32801
  } else {
32107
32802
  logger.log("Close request received for unknown local session", { sessionId: params.sessionId });
32108
32803
  }
@@ -32176,7 +32871,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
32176
32871
  logger.log("Authenticate request failed");
32177
32872
  throw RequestError.invalidParams();
32178
32873
  }
32179
- await this.refreshSessionsAuthState(this.getAuthProviderForAuthenticateRequest(_params));
32874
+ await this.refreshAuthState(this.getAuthProviderForAuthenticateRequest(_params));
32180
32875
  logger.log("Authenticate request completed");
32181
32876
  return {};
32182
32877
  }
@@ -32207,7 +32902,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
32207
32902
  async logout(_params) {
32208
32903
  logger.log("Logout request received");
32209
32904
  await this.runWithProcessCheck(() => this.codexAcpClient.logout());
32210
- await this.refreshSessionsAuthState(null);
32905
+ await this.refreshAuthState(null);
32211
32906
  logger.log("Logout request completed");
32212
32907
  }
32213
32908
  listProviders(_params) {
@@ -32238,6 +32933,10 @@ Check ${configPath} and project .codex directories, especially their config.toml
32238
32933
  await Promise.all(activePrompts);
32239
32934
  }
32240
32935
  logger.log("Restarting Codex app-server for provider update", { sessionCount: this.sessions.size });
32936
+ for (const session of this.sessions.values()) {
32937
+ session.asyncTasks.prepareForAppServerReplacement();
32938
+ }
32939
+ await this.finishAllAsyncTasks("stopped", "before the provider restart");
32241
32940
  const replacement = await this.restartCodexClient();
32242
32941
  apply(replacement);
32243
32942
  if (this.initializeRequest === null) {
@@ -32248,14 +32947,17 @@ Check ${configPath} and project .codex directories, especially their config.toml
32248
32947
  this.availableCommands = this.createAvailableCommands(replacement);
32249
32948
  const resumeErrors = [];
32250
32949
  for (const session of this.sessions.values()) {
32950
+ session.asyncTasks.setAppServer(replacement.appServerClient);
32251
32951
  try {
32252
- await replacement.resumeSession({
32952
+ const metadata = await replacement.resumeSession({
32253
32953
  sessionId: session.sessionId,
32254
32954
  cwd: session.cwd,
32255
32955
  additionalDirectories: session.additionalDirectories,
32256
32956
  mcpServers: session.mcpServers ?? []
32257
32957
  });
32958
+ session.fullAccessHttpMcpServers = metadata.fullAccessHttpMcpServers ?? [];
32258
32959
  session.authProvider = replacement.getModelProvider();
32960
+ session.asyncTasks.refresh();
32259
32961
  logger.log("Resumed session after provider restart", { sessionId: session.sessionId });
32260
32962
  } catch (error51) {
32261
32963
  resumeErrors.push(error51);
@@ -32285,12 +32987,22 @@ Check ${configPath} and project .codex directories, especially their config.toml
32285
32987
  state.stderr = (state.stderr + data.toString()).slice(-2 * 1024);
32286
32988
  });
32287
32989
  }
32990
+ observeCodexProcess() {
32991
+ const process12 = this.codexProcessState?.connection.process;
32992
+ if (!process12) return;
32993
+ const generation = ++this.codexProcessGeneration;
32994
+ process12.once("exit", () => {
32995
+ if (generation !== this.codexProcessGeneration) return;
32996
+ void this.finishAllAsyncTasks("failed", "after the Codex process exited");
32997
+ });
32998
+ }
32288
32999
  async restartCodexClient() {
32289
33000
  const state = this.codexProcessState;
32290
33001
  if (state === null) {
32291
33002
  throw new Error("Codex process state is unavailable");
32292
33003
  }
32293
33004
  const previous = state.connection;
33005
+ this.codexProcessGeneration += 1;
32294
33006
  const exited = previous.process.exitCode === null ? once(previous.process, "exit") : Promise.resolve();
32295
33007
  previous.process.stdin.end();
32296
33008
  const forceKill = setTimeout(() => {
@@ -32308,6 +33020,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
32308
33020
  state.permissionProfileConfig?.configOverrides
32309
33021
  );
32310
33022
  this.captureStderr();
33023
+ this.observeCodexProcess();
32311
33024
  return new CodexAcpClient(
32312
33025
  new CodexAppServerClient(state.connection.connection),
32313
33026
  state.config,
@@ -32315,15 +33028,155 @@ Check ${configPath} and project .codex directories, especially their config.toml
32315
33028
  state.permissionProfileConfig
32316
33029
  );
32317
33030
  }
33031
+ /** Returns whether the auth state was read (and thus the auth status pushed). */
32318
33032
  async refreshSessionsAuthState(authProvider) {
32319
- if (this.sessions.size === 0) return;
33033
+ if (this.sessions.size === 0) return false;
32320
33034
  const sessionsToRefresh = [...this.sessions.values()].filter((sessionState) => this.authProvidersMatch(sessionState.authProvider, authProvider));
32321
- if (sessionsToRefresh.length === 0) return;
33035
+ if (sessionsToRefresh.length === 0) return false;
32322
33036
  const authState = await this.getAuthStateForProvider(authProvider);
32323
33037
  for (const sessionState of sessionsToRefresh) {
32324
33038
  sessionState.account = authState.account;
32325
33039
  sessionState.authConfigured = authState.authConfigured;
32326
33040
  }
33041
+ return true;
33042
+ }
33043
+ /**
33044
+ * Refreshes the sessions of a provider and makes sure the connection-level
33045
+ * `authStatus` is pushed even when no session matched (the empty-screen
33046
+ * login case). Reuses the session refresh read; never adds a second one.
33047
+ */
33048
+ async refreshAuthState(authProvider) {
33049
+ const refreshed = await this.refreshSessionsAuthState(authProvider);
33050
+ if (refreshed) return;
33051
+ try {
33052
+ await this.getAuthStateForProvider(authProvider ?? this.codexAcpClient.getModelProvider());
33053
+ } catch (error51) {
33054
+ logger.log("Failed to refresh auth status", { error: String(error51) });
33055
+ }
33056
+ }
33057
+ /**
33058
+ * Schedules the connection's first `_auth/status_update`: one account read,
33059
+ * pushed whatever it says, including `none`.
33060
+ *
33061
+ * The push must not overtake the `initialize` response. The JSON-RPC layer
33062
+ * writes that response in the microtask that resolves {@link initialize}, so
33063
+ * the read starts from a check-phase callback, which always runs after it.
33064
+ * `initialize` itself never waits for the read.
33065
+ *
33066
+ * "Unconditional" costs nothing extra here: nothing has been pushed yet on
33067
+ * this connection, so {@link setAuthStatus} cannot suppress this one.
33068
+ */
33069
+ publishFirstAuthStatusAfterResponse() {
33070
+ setImmediate(() => void this.publishAuthStatusRead());
33071
+ }
33072
+ /**
33073
+ * Reads the agent-owned identity and pushes it.
33074
+ *
33075
+ * Never rejects: an unreadable source means "nothing to report", not an
33076
+ * error. The client then keeps showing the last pushed value, or "not
33077
+ * reported" when there was none.
33078
+ */
33079
+ async publishAuthStatusRead() {
33080
+ let authStatus;
33081
+ try {
33082
+ authStatus = await this.readAgentAuthIdentity();
33083
+ } catch (error51) {
33084
+ logger.log("Cannot determine auth status", { error: String(error51) });
33085
+ return;
33086
+ }
33087
+ await this.setAuthStatus(authStatus);
33088
+ }
33089
+ /**
33090
+ * Builds the agent-owned auth identity. Routing the client configured
33091
+ * through the ACP `providers/*` API is invisible here: the reported state
33092
+ * is what the agent itself is logged in with. `gateway` stays reserved for
33093
+ * agent-owned gateway state — the `gateway` auth method, or a provider the
33094
+ * user configured in Codex's own config.
33095
+ */
33096
+ async readAgentAuthIdentity() {
33097
+ const authGatewayName = this.codexAcpClient.getAuthGatewayProviderName();
33098
+ if (authGatewayName !== null) {
33099
+ return gatewayStatus(authGatewayName);
33100
+ }
33101
+ const modelProvider = await this.runWithProcessCheck(() => this.codexAcpClient.getAgentConfiguredModelProvider());
33102
+ if (!this.authProviderUsesOpenAiAccount(modelProvider)) {
33103
+ return gatewayStatus(modelProvider);
33104
+ }
33105
+ const accountResponse = await this.runWithProcessCheck(() => this.codexAcpClient.getAccount());
33106
+ return fromAccount(accountResponse.account);
33107
+ }
33108
+ /**
33109
+ * Pushes `_auth/status_update` for the freshly read account of a provider.
33110
+ * Agent-owned gateway authentication wins; a client-driven provider
33111
+ * override is ignored and the agent-owned login is reported instead.
33112
+ */
33113
+ async publishAuthStatus(authProvider, account) {
33114
+ const authGatewayName = this.codexAcpClient.getAuthGatewayProviderName();
33115
+ if (authGatewayName !== null) {
33116
+ await this.setAuthStatus(gatewayStatus(authGatewayName));
33117
+ return;
33118
+ }
33119
+ if (this.authProviderUsesOpenAiAccount(authProvider)) {
33120
+ await this.setAuthStatus(fromAccount(account));
33121
+ return;
33122
+ }
33123
+ if (this.codexAcpClient.isClientConfiguredProvider(authProvider)) {
33124
+ await this.publishAuthStatusRead();
33125
+ return;
33126
+ }
33127
+ await this.setAuthStatus(gatewayStatus(authProvider));
33128
+ }
33129
+ /**
33130
+ * Handles the app-server `account/updated` push: the free freshness channel
33131
+ * for logins and logouts happening outside this connection.
33132
+ */
33133
+ handleAccountUpdated(notification) {
33134
+ void this.applyAccountUpdated(notification);
33135
+ }
33136
+ /**
33137
+ * `account/updated` describes the Codex account only. It must never
33138
+ * overwrite an agent-owned gateway status, which no account event can
33139
+ * invalidate; only a gateway logout or a provider change does.
33140
+ */
33141
+ async applyAccountUpdated(notification) {
33142
+ try {
33143
+ if (this.codexAcpClient.getAuthGatewayProviderName() !== null) {
33144
+ return;
33145
+ }
33146
+ if (this.currentAuthStatus === null) {
33147
+ await this.publishAuthStatusRead();
33148
+ return;
33149
+ }
33150
+ if (this.currentAuthStatus.kind === "gateway") {
33151
+ return;
33152
+ }
33153
+ await this.setAuthStatus(fromAccountUpdated(notification, this.currentAuthStatus));
33154
+ } catch (error51) {
33155
+ logger.log("Failed to apply account update to auth status", { error: String(error51) });
33156
+ }
33157
+ }
33158
+ /**
33159
+ * Stores `next` and pushes `_auth/status_update`.
33160
+ *
33161
+ * A push goes out only when the payload changed. The identity is read on
33162
+ * many occasions — `initialize`, each session create, each `account/updated`
33163
+ * — and almost all of them see the login already reported.
33164
+ * Clients replace their whole state on each update and tolerate duplicates,
33165
+ * so a repeat is harmless, but it is pure noise all the same.
33166
+ *
33167
+ * The first push of a connection always goes out: nothing was reported yet,
33168
+ * so no payload can equal it.
33169
+ */
33170
+ async setAuthStatus(next) {
33171
+ if (sameAuthStatus(this.currentAuthStatus, next)) {
33172
+ return;
33173
+ }
33174
+ this.currentAuthStatus = next;
33175
+ try {
33176
+ await this.connection.notify(AUTH_STATUS_UPDATE_METHOD, { authStatus: next });
33177
+ } catch (error51) {
33178
+ logger.log("Failed to send auth status update", { error: String(error51) });
33179
+ }
32327
33180
  }
32328
33181
  async setSessionMode(_params) {
32329
33182
  logger.log("Set session mode requested", {
@@ -32390,6 +33243,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
32390
33243
  if (!newMode) {
32391
33244
  throw RequestError.invalidParams();
32392
33245
  }
33246
+ sessionState.permissionModeRevision = (sessionState.permissionModeRevision ?? 0) + 1;
32393
33247
  await this.codexAcpClient.setAgentMode(
32394
33248
  sessionState.sessionId,
32395
33249
  newMode
@@ -32722,6 +33576,10 @@ Check ${configPath} and project .codex directories, especially their config.toml
32722
33576
  publishCurrentGoalAsync(sessionState, sessionGeneration) {
32723
33577
  void this.publishCurrentGoalBestEffort(sessionState, sessionGeneration, true);
32724
33578
  }
33579
+ publishAsyncTasksAsync(sessionState, sessionGeneration) {
33580
+ if (!this.sessionPublishIsCurrent(sessionState, sessionGeneration)) return;
33581
+ sessionState.asyncTasks.refresh();
33582
+ }
32725
33583
  async publishCurrentGoalBestEffort(sessionState, sessionGeneration, force) {
32726
33584
  try {
32727
33585
  await this.publishCurrentGoal(sessionState, sessionGeneration, force);
@@ -32822,6 +33680,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
32822
33680
  supportedReasoningEfforts: currentModel?.supportedReasoningEfforts ?? [],
32823
33681
  supportedInputModalities: currentModel?.inputModalities ?? ["text", "image"],
32824
33682
  agentMode: AgentMode.getInitialAgentMode(),
33683
+ fullAccessHttpMcpServers: sessionMetadata.fullAccessHttpMcpServers ?? [],
32825
33684
  collaborationMode: sessionMetadata.collaborationMode,
32826
33685
  currentTurnId: null,
32827
33686
  lastTokenUsage: null,
@@ -32845,7 +33704,8 @@ Check ${configPath} and project .codex directories, especially their config.toml
32845
33704
  sessionId,
32846
33705
  clientSupportsSubagents(this.clientCapabilities),
32847
33706
  new ACPSessionConnection(this.connection, sessionId)
32848
- )
33707
+ ),
33708
+ asyncTasks: this.createAsyncTasks(sessionId)
32849
33709
  };
32850
33710
  sessionState.titleGen = new TitleGenerator(
32851
33711
  this.codexAcpClient.appServerClient,
@@ -32853,7 +33713,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
32853
33713
  sessionState.cwd,
32854
33714
  () => sessionState.sessionTitleSource
32855
33715
  );
32856
- this.sessions.set(sessionId, sessionState);
33716
+ this.installSessionState(sessionState);
32857
33717
  subscribed = false;
32858
33718
  if (requestedMcpServers.length > 0 && mcpServerStartupVersion !== null) {
32859
33719
  this.pendingMcpStartupSessions.set(sessionId, {
@@ -32945,6 +33805,15 @@ Check ${configPath} and project .codex directories, especially their config.toml
32945
33805
  /* @__PURE__ */ new Set([...ancestry, item.agentThreadId]),
32946
33806
  threadCache
32947
33807
  );
33808
+ try {
33809
+ await sessionState.asyncTasks.recover(
33810
+ item.agentThreadId,
33811
+ childSessionId,
33812
+ commandItemIds(childTurn.items)
33813
+ );
33814
+ } catch (error51) {
33815
+ logger.error(`Failed to restore background terminals for ${item.agentThreadId}`, error51);
33816
+ }
32948
33817
  }
32949
33818
  }
32950
33819
  } else if (activityKind === "completed" || activityKind === "interrupted") {
@@ -33518,7 +34387,6 @@ Check ${configPath} and project .codex directories, especially their config.toml
33518
34387
  let recoverableSessionFailure = sessionState.sessionFailure;
33519
34388
  const promptStartTotalTokenUsage = sessionState.totalTokenUsage;
33520
34389
  sessionState.currentTurnId = null;
33521
- sessionState.lastTokenUsage = null;
33522
34390
  const activePrompt = this.trackActivePrompt(params.sessionId);
33523
34391
  let pendingTurnStart = null;
33524
34392
  const ensurePendingTurnStart = () => {
@@ -33551,21 +34419,33 @@ Check ${configPath} and project .codex directories, especially their config.toml
33551
34419
  clientSupportsPlanUpdates(this.clientCapabilities),
33552
34420
  clientSupportsTypedSessionFailures(this.clientCapabilities),
33553
34421
  this.sessionFailureEpoch,
33554
- sessionState.subagents
34422
+ sessionState.subagents,
34423
+ (accountUpdated) => this.handleAccountUpdated(accountUpdated)
33555
34424
  );
33556
34425
  eventHandler = promptEventHandler;
33557
34426
  const permissionLifecycle = this.permissionLifecycleContext(sessionState);
33558
34427
  const permissionContext = permissionLifecycle.beginPrompt();
34428
+ let promptAgentMode;
34429
+ let permissionModeRevision;
34430
+ const httpServers = new Set(sessionState.fullAccessHttpMcpServers);
34431
+ const noHttpServers = /* @__PURE__ */ new Set();
34432
+ let mcpApprovalTurnId = null;
34433
+ const isProtectedFullAccess = () => this.codexAcpClient.isProtectedFullAccess(promptAgentMode ?? sessionState.agentMode);
33559
34434
  const approvalHandler = new CodexApprovalHandler(
33560
34435
  this.connection,
33561
34436
  permissionContext,
33562
- activePrompt.signal
34437
+ activePrompt.signal,
34438
+ isProtectedFullAccess
33563
34439
  );
33564
34440
  const elicitationHandler = new CodexElicitationHandler(
33565
34441
  this.connection,
33566
34442
  permissionContext,
33567
34443
  this.clientCapabilities,
33568
- activePrompt.signal
34444
+ activePrompt.signal,
34445
+ (request) => {
34446
+ if (!isProtectedFullAccess()) return void 0;
34447
+ return mcpApprovalTurnId !== null && request.turnId === mcpApprovalTurnId && sessionState.agentMode.kind === "full_access" && sessionState.permissionModeRevision === permissionModeRevision ? httpServers : noHttpServers;
34448
+ }
33569
34449
  );
33570
34450
  const observeInteraction = async (event) => {
33571
34451
  permissionContext.handleNotification(event);
@@ -33596,6 +34476,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
33596
34476
  }
33597
34477
  const commandPromise = this.availableCommands.tryHandleCommand(params.prompt, sessionState, {
33598
34478
  onTurnStartPending: () => {
34479
+ sessionState.lastTokenUsage = null;
33599
34480
  ensurePendingTurnStart();
33600
34481
  },
33601
34482
  onTurnStarted: (turnId, threadId) => {
@@ -33689,10 +34570,13 @@ Check ${configPath} and project .codex directories, especially their config.toml
33689
34570
  throw RequestError.invalidRequest("The current model does not support image input");
33690
34571
  }
33691
34572
  const agentMode = sessionState.agentMode;
34573
+ promptAgentMode = agentMode;
34574
+ permissionModeRevision = sessionState.permissionModeRevision;
33692
34575
  const serviceTier = resolveFastServiceTier(
33693
34576
  sessionState.fastModeEnabled,
33694
34577
  sessionState.currentModelSupportsFast
33695
34578
  );
34579
+ sessionState.lastTokenUsage = null;
33696
34580
  ensurePendingTurnStart();
33697
34581
  const sendPromptPromise = this.runWithProcessCheck(
33698
34582
  () => this.codexAcpClient.sendPrompt(
@@ -33704,6 +34588,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
33704
34588
  sessionState.cwd,
33705
34589
  sessionState.additionalDirectories,
33706
34590
  (turnId) => {
34591
+ mcpApprovalTurnId = turnId;
33707
34592
  const turn = { threadId: params.sessionId, turnId };
33708
34593
  activePrompt.currentTurn = turn;
33709
34594
  if (this.promptShouldStop(params.sessionId, activePrompt)) {
@@ -33714,7 +34599,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
33714
34599
  pendingTurnStart?.resolve(turnId);
33715
34600
  onTurnStarted?.();
33716
34601
  },
33717
- () => this.promptShouldStop(params.sessionId, activePrompt)
34602
+ () => this.promptShouldStop(params.sessionId, activePrompt) || sessionState.permissionModeRevision !== permissionModeRevision
33718
34603
  )
33719
34604
  );
33720
34605
  void sendPromptPromise.catch((err) => {
@@ -33794,6 +34679,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
33794
34679
  sessionState.cwd,
33795
34680
  sessionState.additionalDirectories,
33796
34681
  (turnId) => {
34682
+ mcpApprovalTurnId = turnId;
33797
34683
  const turn = { threadId: params.sessionId, turnId };
33798
34684
  activePrompt.currentTurn = turn;
33799
34685
  if (this.promptShouldStop(params.sessionId, activePrompt)) {
@@ -33804,7 +34690,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
33804
34690
  recoverableSessionFailure = sessionState.sessionFailure;
33805
34691
  promptNotificationsActive = true;
33806
34692
  },
33807
- () => this.promptShouldStop(params.sessionId, activePrompt)
34693
+ () => this.promptShouldStop(params.sessionId, activePrompt) || sessionState.permissionModeRevision !== permissionModeRevision
33808
34694
  )
33809
34695
  );
33810
34696
  void implementationPromise.catch((err) => {
@@ -33999,6 +34885,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
33999
34885
  throw new RequestError(requestErrorCode, `VC++ redistributable should be installed`);
34000
34886
  }
34001
34887
  if (exitCode !== null) {
34888
+ await this.finishAllAsyncTasks("failed", "after the Codex process exited");
34002
34889
  const stderr = this.getRecentStderr().trim();
34003
34890
  const detail = stderr ? `:
34004
34891
  ${stderr}` : "";
@@ -34007,6 +34894,15 @@ ${stderr}` : "";
34007
34894
  throw err;
34008
34895
  }
34009
34896
  }
34897
+ async finishAllAsyncTasks(state, reason) {
34898
+ for (const session of this.sessions.values()) {
34899
+ try {
34900
+ await session.asyncTasks.finishAll(state);
34901
+ } catch (error51) {
34902
+ logger.error(`Failed to finish background terminal tasks ${reason}`, error51);
34903
+ }
34904
+ }
34905
+ }
34010
34906
  async cancel(params) {
34011
34907
  const sessionState = this.sessions.get(params.sessionId);
34012
34908
  if (!sessionState) {
@@ -34056,6 +34952,9 @@ function mergeHistoryUpdates(responseItemFallbackUpdates, threadUpdates) {
34056
34952
  }
34057
34953
  return merged;
34058
34954
  }
34955
+ function commandItemIds(items) {
34956
+ return new Set(items.filter((item) => item.type === "commandExecution").map((item) => item.id));
34957
+ }
34059
34958
  function historyUpdateKey(update) {
34060
34959
  switch (update.sessionUpdate) {
34061
34960
  case "user_message_chunk":
@@ -34239,6 +35138,10 @@ var goalControlParamsParser = external_exports.discriminatedUnion("action", [
34239
35138
  action: external_exports.enum(["pause", "resume", "clear"])
34240
35139
  }).passthrough()
34241
35140
  ]);
35141
+ var asyncTaskStopParamsParser = external_exports.object({
35142
+ sessionId: external_exports.string().trim().min(1),
35143
+ asyncTaskId: external_exports.string().trim().min(1)
35144
+ }).passthrough();
34242
35145
  if (process.argv.includes("--version")) {
34243
35146
  console.log(`${package_default.name} ${package_default.version}`);
34244
35147
  process.exit(0);
@@ -34333,5 +35236,5 @@ function startAcpServer() {
34333
35236
  codexAcpServer = null;
34334
35237
  }
34335
35238
  });
34336
- }).onRequest(methods.agent.initialize, (ctx) => getAgent().initialize(ctx.params)).onRequest(methods.agent.session.new, (ctx) => getAgent().newSession(ctx.params)).onRequest(methods.agent.session.load, (ctx) => getAgent().loadSession(ctx.params)).onRequest(methods.agent.session.fork, (ctx) => getAgent().forkSession(ctx.params)).onRequest(methods.agent.session.list, (ctx) => getAgent().listSessions(ctx.params)).onRequest(methods.agent.session.delete, (ctx) => getAgent().deleteSession(ctx.params)).onRequest(methods.agent.session.resume, (ctx) => getAgent().resumeSession(ctx.params)).onRequest(methods.agent.session.close, (ctx) => getAgent().closeSession(ctx.params)).onRequest(methods.agent.session.setMode, (ctx) => getAgent().setSessionMode(ctx.params)).onRequest(methods.agent.session.setConfigOption, (ctx) => getAgent().setSessionConfigOption(ctx.params)).onRequest(methods.agent.authenticate, (ctx) => getAgent().authenticate(ctx.params, ctx.requestId)).onRequest(methods.agent.logout, (ctx) => getAgent().logout(ctx.params)).onRequest(methods.agent.providers.list, (ctx) => getAgent().listProviders(ctx.params)).onRequest(methods.agent.providers.set, (ctx) => getAgent().setProvider(ctx.params)).onRequest(methods.agent.providers.disable, (ctx) => getAgent().disableProvider(ctx.params)).onRequest(methods.agent.session.prompt, (ctx) => getAgent().prompt(ctx.params, ctx.signal)).onNotification(methods.agent.session.cancel, (ctx) => getAgent().cancel(ctx.params)).onRequest("authentication/status", emptyExtensionParamsParser, (ctx) => getAgent().extMethod("authentication/status", ctx.params)).onRequest("authentication/logout", emptyExtensionParamsParser, (ctx) => getAgent().extMethod("authentication/logout", ctx.params)).onRequest(LEGACY_SET_SESSION_MODEL_METHOD, legacySetSessionModelParamsParser, (ctx) => getAgent().extMethod(LEGACY_SET_SESSION_MODEL_METHOD, ctx.params)).onRequest(SESSION_STEERING_METHOD, sessionSteerParamsParser, (ctx) => getAgent().extMethod(SESSION_STEERING_METHOD, ctx.params)).onRequest(GOAL_CONTROL_METHOD, goalControlParamsParser, (ctx) => getAgent().extMethod(GOAL_CONTROL_METHOD, ctx.params)).connect(acpJsonStream);
35239
+ }).onRequest(methods.agent.initialize, (ctx) => getAgent().initialize(ctx.params)).onRequest(methods.agent.session.new, (ctx) => getAgent().newSession(ctx.params)).onRequest(methods.agent.session.load, (ctx) => getAgent().loadSession(ctx.params)).onRequest(methods.agent.session.fork, (ctx) => getAgent().forkSession(ctx.params)).onRequest(methods.agent.session.list, (ctx) => getAgent().listSessions(ctx.params)).onRequest(methods.agent.session.delete, (ctx) => getAgent().deleteSession(ctx.params)).onRequest(methods.agent.session.resume, (ctx) => getAgent().resumeSession(ctx.params)).onRequest(methods.agent.session.close, (ctx) => getAgent().closeSession(ctx.params)).onRequest(methods.agent.session.setMode, (ctx) => getAgent().setSessionMode(ctx.params)).onRequest(methods.agent.session.setConfigOption, (ctx) => getAgent().setSessionConfigOption(ctx.params)).onRequest(methods.agent.authenticate, (ctx) => getAgent().authenticate(ctx.params, ctx.requestId)).onRequest(methods.agent.logout, (ctx) => getAgent().logout(ctx.params)).onRequest(methods.agent.providers.list, (ctx) => getAgent().listProviders(ctx.params)).onRequest(methods.agent.providers.set, (ctx) => getAgent().setProvider(ctx.params)).onRequest(methods.agent.providers.disable, (ctx) => getAgent().disableProvider(ctx.params)).onRequest(methods.agent.session.prompt, (ctx) => getAgent().prompt(ctx.params, ctx.signal)).onNotification(methods.agent.session.cancel, (ctx) => getAgent().cancel(ctx.params)).onRequest("authentication/status", emptyExtensionParamsParser, (ctx) => getAgent().extMethod("authentication/status", ctx.params)).onRequest("authentication/logout", emptyExtensionParamsParser, (ctx) => getAgent().extMethod("authentication/logout", ctx.params)).onRequest(LEGACY_SET_SESSION_MODEL_METHOD, legacySetSessionModelParamsParser, (ctx) => getAgent().extMethod(LEGACY_SET_SESSION_MODEL_METHOD, ctx.params)).onRequest(SESSION_STEERING_METHOD, sessionSteerParamsParser, (ctx) => getAgent().extMethod(SESSION_STEERING_METHOD, ctx.params)).onRequest(ASYNC_TASK_STOP_METHOD, asyncTaskStopParamsParser, (ctx) => getAgent().extMethod(ASYNC_TASK_STOP_METHOD, ctx.params)).onRequest(GOAL_CONTROL_METHOD, goalControlParamsParser, (ctx) => getAgent().extMethod(GOAL_CONTROL_METHOD, ctx.params)).connect(acpJsonStream);
34337
35240
  }