@agentclientprotocol/codex-acp 1.9.0 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -0
- package/dist/index.js +501 -44
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -13,6 +13,7 @@ Use [OpenAI Codex](https://github.com/openai/codex) from [Agent Client Protocol]
|
|
|
13
13
|
- Text prompts, embedded context, images, resource links, and additional workspace directories.
|
|
14
14
|
- Shell command, file change, [permission request](docs/permission-extension.md), MCP tool call, terminal output, reasoning, plan, web search, image generation, image view, token usage, and review events.
|
|
15
15
|
- [Native ACP subagent sessions](docs/subagent-sessions.md) (after capability negotiation) with separate child histories and root-routed permissions; a legacy tool-call fallback otherwise.
|
|
16
|
+
- [Background terminal tasks](docs/async-tasks.md) in AIR, with task status and targeted stop support after capability negotiation.
|
|
16
17
|
- Session-scoped long-running goals through the provider-neutral [goal extension](docs/goal-extension.md).
|
|
17
18
|
- A per-turn [agent file-change report](docs/agent-file-change-report.md) after capability negotiation.
|
|
18
19
|
- Client-provided MCP servers over command-based stdio config and HTTP transport.
|
|
@@ -82,6 +83,12 @@ Subagent sessions follow the draft [ACP subagent RFD](https://github.com/agentcl
|
|
|
82
83
|
|
|
83
84
|
See [docs/subagent-sessions.md](docs/subagent-sessions.md) for the negotiation, lifecycle events, `session/load` reconstruction, and legacy fallback details.
|
|
84
85
|
|
|
86
|
+
### Background terminal tasks
|
|
87
|
+
|
|
88
|
+
Codex can keep a shell command running after a turn continues. AIR clients can show this work in the Async Tasks panel and stop one command.
|
|
89
|
+
|
|
90
|
+
See [docs/async-tasks.md](docs/async-tasks.md) for the capability, lifecycle events, and stop request.
|
|
91
|
+
|
|
85
92
|
## License
|
|
86
93
|
|
|
87
94
|
By contributing, you agree that your contributions will be licensed under the Apache 2.0 License.
|
package/dist/index.js
CHANGED
|
@@ -22131,32 +22131,7 @@ function attachLogs(proc) {
|
|
|
22131
22131
|
});
|
|
22132
22132
|
}
|
|
22133
22133
|
|
|
22134
|
-
// src/
|
|
22135
|
-
var JETBRAINS_META_KEY = "jetbrains";
|
|
22136
|
-
var AIR_META_KEY = "air";
|
|
22137
|
-
var AIR_EXTENSION_VERSION_KEY = "version";
|
|
22138
|
-
var AIR_EXTENSION_CAPABILITIES_KEY = "capabilities";
|
|
22139
|
-
var AIR_SESSION_FAILURE_KEY = "sessionFailure";
|
|
22140
|
-
var AIR_AGENT_FILE_CHANGE_REPORT_KEY = "agentFileChangeReport";
|
|
22141
|
-
var AIR_NATIVE_SUBAGENT_SESSIONS_KEY = "nativeSubagentSessions";
|
|
22142
|
-
var AIR_AGENT_FILE_CHANGE_REPORT_REQUEST_KEY = "agentFileChangeReportRequest";
|
|
22143
|
-
var AIR_EXTENSION_VERSION = 1;
|
|
22144
|
-
function clientSupportsAirCapability(capabilities, capability) {
|
|
22145
|
-
const jetbrains = capabilities?._meta?.[JETBRAINS_META_KEY];
|
|
22146
|
-
const air = jetbrains?.[AIR_META_KEY];
|
|
22147
|
-
const version2 = air?.[AIR_EXTENSION_VERSION_KEY];
|
|
22148
|
-
const supported = air?.[AIR_EXTENSION_CAPABILITIES_KEY];
|
|
22149
|
-
return typeof version2 === "number" && Number.isInteger(version2) && version2 >= AIR_EXTENSION_VERSION && Array.isArray(supported) && supported.includes(capability);
|
|
22150
|
-
}
|
|
22151
|
-
|
|
22152
|
-
// src/subagents/AcpSubagents.ts
|
|
22153
|
-
function clientSupportsSubagents(capabilities) {
|
|
22154
|
-
const subagents = capabilities?.subagents;
|
|
22155
|
-
if (typeof subagents === "object" && subagents !== null && !Array.isArray(subagents)) {
|
|
22156
|
-
return true;
|
|
22157
|
-
}
|
|
22158
|
-
return clientSupportsAirCapability(capabilities, AIR_NATIVE_SUBAGENT_SESSIONS_KEY);
|
|
22159
|
-
}
|
|
22134
|
+
// src/AcpSessionExtensions.ts
|
|
22160
22135
|
function asSdkSessionNotification(notification) {
|
|
22161
22136
|
return notification;
|
|
22162
22137
|
}
|
|
@@ -23676,6 +23651,26 @@ function sameThreadGoalSnapshot(left, right) {
|
|
|
23676
23651
|
// src/CodexEventHandler.ts
|
|
23677
23652
|
import { randomUUID } from "node:crypto";
|
|
23678
23653
|
|
|
23654
|
+
// src/AirExtension.ts
|
|
23655
|
+
var JETBRAINS_META_KEY = "jetbrains";
|
|
23656
|
+
var AIR_META_KEY = "air";
|
|
23657
|
+
var AIR_EXTENSION_VERSION_KEY = "version";
|
|
23658
|
+
var AIR_EXTENSION_CAPABILITIES_KEY = "capabilities";
|
|
23659
|
+
var AIR_SESSION_FAILURE_KEY = "sessionFailure";
|
|
23660
|
+
var AIR_AGENT_FILE_CHANGE_REPORT_KEY = "agentFileChangeReport";
|
|
23661
|
+
var AIR_NATIVE_SUBAGENT_SESSIONS_KEY = "nativeSubagentSessions";
|
|
23662
|
+
var AIR_ASYNC_TASKS_KEY = "asyncTasks";
|
|
23663
|
+
var AIR_ASYNC_TASKS_BACKGROUNDED_KEY = "backgrounded";
|
|
23664
|
+
var AIR_AGENT_FILE_CHANGE_REPORT_REQUEST_KEY = "agentFileChangeReportRequest";
|
|
23665
|
+
var AIR_EXTENSION_VERSION = 1;
|
|
23666
|
+
function clientSupportsAirCapability(capabilities, capability) {
|
|
23667
|
+
const jetbrains = capabilities?._meta?.[JETBRAINS_META_KEY];
|
|
23668
|
+
const air = jetbrains?.[AIR_META_KEY];
|
|
23669
|
+
const version2 = air?.[AIR_EXTENSION_VERSION_KEY];
|
|
23670
|
+
const supported = air?.[AIR_EXTENSION_CAPABILITIES_KEY];
|
|
23671
|
+
return typeof version2 === "number" && Number.isInteger(version2) && version2 >= AIR_EXTENSION_VERSION && Array.isArray(supported) && supported.includes(capability);
|
|
23672
|
+
}
|
|
23673
|
+
|
|
23679
23674
|
// src/subagents/CodexAgentPath.ts
|
|
23680
23675
|
function normalizeAgentPath(path9) {
|
|
23681
23676
|
const normalized = path9.trim().replace(/\/+$/, "");
|
|
@@ -23731,14 +23726,14 @@ var CodexSubagentEventRouter = class _CodexSubagentEventRouter {
|
|
|
23731
23726
|
}
|
|
23732
23727
|
return childTurn;
|
|
23733
23728
|
}
|
|
23734
|
-
const
|
|
23735
|
-
if (typeof
|
|
23736
|
-
const pending = this.pendingSpawns.get(
|
|
23729
|
+
const notificationThreadId2 = notification.params.threadId;
|
|
23730
|
+
if (typeof notificationThreadId2 === "string" && this.pendingSpawns.has(notificationThreadId2)) {
|
|
23731
|
+
const pending = this.pendingSpawns.get(notificationThreadId2);
|
|
23737
23732
|
if (pending.buffered.length === _CodexSubagentEventRouter.MAX_PENDING_NOTIFICATIONS) {
|
|
23738
23733
|
pending.buffered.shift();
|
|
23739
23734
|
pending.droppedBufferedNotifications += 1;
|
|
23740
23735
|
if (pending.droppedBufferedNotifications === 1) {
|
|
23741
|
-
logger.log(`Pending subagent ${
|
|
23736
|
+
logger.log(`Pending subagent ${notificationThreadId2} exceeded the notification buffer; dropping oldest updates`);
|
|
23742
23737
|
}
|
|
23743
23738
|
}
|
|
23744
23739
|
pending.buffered.push(notification);
|
|
@@ -23823,6 +23818,25 @@ var CodexSubagentEventRouter = class _CodexSubagentEventRouter {
|
|
|
23823
23818
|
const threadId = notification.params.threadId;
|
|
23824
23819
|
return typeof threadId === "string" && this.children.has(threadId) ? this.children.get(threadId).sessionId : this.rootSessionId;
|
|
23825
23820
|
}
|
|
23821
|
+
closingChildSessions(notification) {
|
|
23822
|
+
if (!this.supported) return [];
|
|
23823
|
+
if (notification.method === "turn/completed") {
|
|
23824
|
+
if (terminalStateFromTurn(notification.params.turn.status) === void 0) return [];
|
|
23825
|
+
return this.closingChildSession(notification.params.threadId);
|
|
23826
|
+
}
|
|
23827
|
+
if (notification.method !== "item/started" && notification.method !== "item/completed") return [];
|
|
23828
|
+
const item = notification.params.item;
|
|
23829
|
+
if (item.type === "subAgentActivity") {
|
|
23830
|
+
return item.kind === "interrupted" ? this.closingChildSession(item.agentThreadId) : [];
|
|
23831
|
+
}
|
|
23832
|
+
if (item.type !== "collabAgentToolCall") return [];
|
|
23833
|
+
const closing = /* @__PURE__ */ new Map();
|
|
23834
|
+
for (const [threadId, state] of Object.entries(item.agentsStates)) {
|
|
23835
|
+
if (!state || terminalStateOf(state.status) === void 0) continue;
|
|
23836
|
+
for (const child of this.closingChildSession(threadId)) closing.set(threadId, child);
|
|
23837
|
+
}
|
|
23838
|
+
return [...closing.values()];
|
|
23839
|
+
}
|
|
23826
23840
|
takeBufferedNotifications() {
|
|
23827
23841
|
return this.replayQueue.splice(0);
|
|
23828
23842
|
}
|
|
@@ -23898,6 +23912,10 @@ var CodexSubagentEventRouter = class _CodexSubagentEventRouter {
|
|
|
23898
23912
|
isKnownChild(threadId) {
|
|
23899
23913
|
return threadId !== this.rootSessionId && (this.children.has(threadId) || this.pendingSpawns.has(threadId) || this.terminalPendingSpawns.has(threadId));
|
|
23900
23914
|
}
|
|
23915
|
+
closingChildSession(threadId) {
|
|
23916
|
+
const child = this.children.get(threadId);
|
|
23917
|
+
return child && child.terminalState === void 0 ? [{ threadId, sessionId: child.sessionId }] : [];
|
|
23918
|
+
}
|
|
23901
23919
|
async materialize(childSessionId, path9) {
|
|
23902
23920
|
if (this.children.has(childSessionId)) return;
|
|
23903
23921
|
const pending = this.pendingSpawns.get(childSessionId);
|
|
@@ -24306,17 +24324,29 @@ var CodexEventHandler = class _CodexEventHandler {
|
|
|
24306
24324
|
}
|
|
24307
24325
|
async handleNotification(notification) {
|
|
24308
24326
|
await this.flushPendingErrors();
|
|
24327
|
+
const closingChildren = this.subagents.closingChildSessions(notification);
|
|
24328
|
+
for (const child of closingChildren) {
|
|
24329
|
+
await this.sessionState.asyncTasks.reconcile(child.threadId, child.sessionId);
|
|
24330
|
+
}
|
|
24309
24331
|
const handledBySubagents = await this.subagents.handle(notification);
|
|
24310
24332
|
for (const buffered of this.subagents.takeBufferedNotifications()) {
|
|
24311
24333
|
await this.handleNotification(buffered);
|
|
24312
24334
|
}
|
|
24313
|
-
|
|
24314
|
-
|
|
24335
|
+
const ignoredBySubagents = !handledBySubagents && this.subagents.shouldIgnore(notification);
|
|
24336
|
+
let updateEvent;
|
|
24337
|
+
if (!handledBySubagents && !ignoredBySubagents && notification.method === "item/started" && notification.params.item.type === "commandExecution") {
|
|
24338
|
+
updateEvent = await this.createUpdateEvent(notification);
|
|
24315
24339
|
}
|
|
24316
|
-
if (
|
|
24317
|
-
|
|
24340
|
+
if (!handledBySubagents) {
|
|
24341
|
+
await this.sessionState.asyncTasks.handleNotification(
|
|
24342
|
+
notification,
|
|
24343
|
+
this.subagents.notificationSessionId(notification),
|
|
24344
|
+
toolCallTitle(updateEvent)
|
|
24345
|
+
);
|
|
24318
24346
|
}
|
|
24319
|
-
|
|
24347
|
+
if (handledBySubagents) return;
|
|
24348
|
+
if (ignoredBySubagents) return;
|
|
24349
|
+
if (updateEvent === void 0) updateEvent = await this.createUpdateEvent(notification);
|
|
24320
24350
|
if (updateEvent) {
|
|
24321
24351
|
await this.session.update(updateEvent, this.subagents.notificationSessionId(notification));
|
|
24322
24352
|
}
|
|
@@ -25153,6 +25183,10 @@ ${event.stdin}
|
|
|
25153
25183
|
return createGuardianApprovalReviewToolCall(params);
|
|
25154
25184
|
}
|
|
25155
25185
|
};
|
|
25186
|
+
function toolCallTitle(update) {
|
|
25187
|
+
if (update?.sessionUpdate !== "tool_call") return void 0;
|
|
25188
|
+
return update.title;
|
|
25189
|
+
}
|
|
25156
25190
|
|
|
25157
25191
|
// src/permissions/option-ids.ts
|
|
25158
25192
|
var ApprovalOptionId = {
|
|
@@ -27285,7 +27319,7 @@ var package_default = {
|
|
|
27285
27319
|
publishConfig: {
|
|
27286
27320
|
access: "public"
|
|
27287
27321
|
},
|
|
27288
|
-
version: "1.
|
|
27322
|
+
version: "1.10.0",
|
|
27289
27323
|
description: "",
|
|
27290
27324
|
main: "dist/index.js",
|
|
27291
27325
|
bin: {
|
|
@@ -27348,7 +27382,7 @@ var package_default = {
|
|
|
27348
27382
|
},
|
|
27349
27383
|
dependencies: {
|
|
27350
27384
|
"@agentclientprotocol/sdk": "^1.4.0",
|
|
27351
|
-
"@openai/codex": "^0.153.
|
|
27385
|
+
"@openai/codex": "^0.153.3",
|
|
27352
27386
|
diff: "^9.0.0",
|
|
27353
27387
|
open: "^11.0.1",
|
|
27354
27388
|
"vscode-jsonrpc": "^9.0.1",
|
|
@@ -29491,6 +29525,12 @@ var CodexAppServerClient = class {
|
|
|
29491
29525
|
async threadCompactStart(params) {
|
|
29492
29526
|
return await this.sendRequest({ method: "thread/compact/start", params });
|
|
29493
29527
|
}
|
|
29528
|
+
async threadBackgroundTerminalsList(params) {
|
|
29529
|
+
return await this.sendRequest({ method: "thread/backgroundTerminals/list", params });
|
|
29530
|
+
}
|
|
29531
|
+
async threadBackgroundTerminalsTerminate(params) {
|
|
29532
|
+
return await this.sendRequest({ method: "thread/backgroundTerminals/terminate", params });
|
|
29533
|
+
}
|
|
29494
29534
|
async threadGoalSet(params) {
|
|
29495
29535
|
return await this.sendRequest({ method: "thread/goal/set", params });
|
|
29496
29536
|
}
|
|
@@ -31462,6 +31502,9 @@ function numberValue(value) {
|
|
|
31462
31502
|
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
31463
31503
|
}
|
|
31464
31504
|
|
|
31505
|
+
// src/async-tasks/AsyncTaskExtension.ts
|
|
31506
|
+
var ASYNC_TASK_STOP_METHOD = "_session/async_task/stop";
|
|
31507
|
+
|
|
31465
31508
|
// src/AuthStatusMeta.ts
|
|
31466
31509
|
var AUTH_STATUS_UPDATE_METHOD = "_auth/status_update";
|
|
31467
31510
|
var AUTH_STATUS_META_KEY = "authStatus";
|
|
@@ -31599,7 +31642,7 @@ function sameAuthStatus(previous, next) {
|
|
|
31599
31642
|
var LEGACY_SET_SESSION_MODEL_METHOD = "session/set_model";
|
|
31600
31643
|
var SESSION_STEERING_METHOD = "_session/steering";
|
|
31601
31644
|
function isExtMethodRequest(request) {
|
|
31602
|
-
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;
|
|
31645
|
+
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;
|
|
31603
31646
|
}
|
|
31604
31647
|
|
|
31605
31648
|
// src/FastModeConfig.ts
|
|
@@ -31666,6 +31709,15 @@ function clientSupportsPlanUpdates(clientCapabilities) {
|
|
|
31666
31709
|
return clientCapabilities?.plan != null;
|
|
31667
31710
|
}
|
|
31668
31711
|
|
|
31712
|
+
// src/subagents/AcpSubagents.ts
|
|
31713
|
+
function clientSupportsSubagents(capabilities) {
|
|
31714
|
+
const subagents = capabilities?.subagents;
|
|
31715
|
+
if (typeof subagents === "object" && subagents !== null && !Array.isArray(subagents)) {
|
|
31716
|
+
return true;
|
|
31717
|
+
}
|
|
31718
|
+
return clientSupportsAirCapability(capabilities, AIR_NATIVE_SUBAGENT_SESSIONS_KEY);
|
|
31719
|
+
}
|
|
31720
|
+
|
|
31669
31721
|
// src/CodexAcpServer.ts
|
|
31670
31722
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
31671
31723
|
|
|
@@ -31754,6 +31806,332 @@ function extractTitle(turn) {
|
|
|
31754
31806
|
|
|
31755
31807
|
// src/CodexAcpServer.ts
|
|
31756
31808
|
import { once } from "node:events";
|
|
31809
|
+
|
|
31810
|
+
// src/async-tasks/CodexBackgroundTerminalTasks.ts
|
|
31811
|
+
var CodexBackgroundTerminalTasks = class {
|
|
31812
|
+
constructor(enabled, rootSessionId, appServer, session) {
|
|
31813
|
+
this.enabled = enabled;
|
|
31814
|
+
this.rootSessionId = rootSessionId;
|
|
31815
|
+
this.appServer = appServer;
|
|
31816
|
+
this.session = session;
|
|
31817
|
+
}
|
|
31818
|
+
enabled;
|
|
31819
|
+
rootSessionId;
|
|
31820
|
+
appServer;
|
|
31821
|
+
session;
|
|
31822
|
+
tasks = /* @__PURE__ */ new Map();
|
|
31823
|
+
syncs = /* @__PURE__ */ new Map();
|
|
31824
|
+
appServerGeneration = 0;
|
|
31825
|
+
appServerQueriesEnabled = true;
|
|
31826
|
+
disposed = false;
|
|
31827
|
+
async handleNotification(notification, sessionId, commandTitle2) {
|
|
31828
|
+
if (!this.isActive()) return;
|
|
31829
|
+
const threadId = notificationThreadId(notification);
|
|
31830
|
+
if (threadId === null) return;
|
|
31831
|
+
if (notification.method === "item/started" && notification.params.item.type === "commandExecution") {
|
|
31832
|
+
this.observeCommandStarted(notification.params.item, threadId, sessionId, commandTitle2);
|
|
31833
|
+
return;
|
|
31834
|
+
}
|
|
31835
|
+
if (notification.method === "item/completed" && notification.params.item.type === "commandExecution") {
|
|
31836
|
+
await this.observeCommandCompleted(notification.params.item, threadId);
|
|
31837
|
+
return;
|
|
31838
|
+
}
|
|
31839
|
+
if (notification.method === "turn/completed") {
|
|
31840
|
+
await this.reconcile(threadId, sessionId);
|
|
31841
|
+
return;
|
|
31842
|
+
}
|
|
31843
|
+
if (notification.method === "item/started") {
|
|
31844
|
+
this.refresh(threadId, sessionId);
|
|
31845
|
+
}
|
|
31846
|
+
}
|
|
31847
|
+
observeCommandStarted(item, threadId, sessionId, commandTitle2) {
|
|
31848
|
+
if (!this.isActive() || item.processId === null) return;
|
|
31849
|
+
this.remember(threadId, sessionId, {
|
|
31850
|
+
itemId: item.id,
|
|
31851
|
+
processId: item.processId,
|
|
31852
|
+
command: item.command
|
|
31853
|
+
}, commandTitle2);
|
|
31854
|
+
}
|
|
31855
|
+
async observeCommandCompleted(item, threadId) {
|
|
31856
|
+
if (!this.isActive()) return;
|
|
31857
|
+
const task = this.tasks.get(wireTaskId(this.rootSessionId, threadId, item.id));
|
|
31858
|
+
if (task) await this.finish(task, item.status === "completed" ? "completed" : "failed");
|
|
31859
|
+
}
|
|
31860
|
+
refresh(threadId = this.rootSessionId, sessionId = this.rootSessionId) {
|
|
31861
|
+
void this.reconcile(threadId, sessionId);
|
|
31862
|
+
}
|
|
31863
|
+
async reconcile(threadId = this.rootSessionId, sessionId = this.rootSessionId) {
|
|
31864
|
+
try {
|
|
31865
|
+
await this.sync(threadId, sessionId);
|
|
31866
|
+
} catch (error51) {
|
|
31867
|
+
if (this.isActive()) logger.error(`Failed to list background terminals for ${threadId}`, error51);
|
|
31868
|
+
}
|
|
31869
|
+
}
|
|
31870
|
+
setAppServer(appServer) {
|
|
31871
|
+
this.appServer = appServer;
|
|
31872
|
+
this.appServerGeneration += 1;
|
|
31873
|
+
this.appServerQueriesEnabled = true;
|
|
31874
|
+
}
|
|
31875
|
+
prepareForAppServerReplacement() {
|
|
31876
|
+
this.appServerGeneration += 1;
|
|
31877
|
+
this.appServerQueriesEnabled = false;
|
|
31878
|
+
}
|
|
31879
|
+
async recover(threadId, sessionId, itemIds) {
|
|
31880
|
+
if (!this.canQueryAppServer() || itemIds.size === 0) return;
|
|
31881
|
+
const snapshot = await this.listAll(threadId);
|
|
31882
|
+
if (snapshot === null) return;
|
|
31883
|
+
for (const terminal of snapshot.terminals) {
|
|
31884
|
+
if (!this.queryIsCurrent(snapshot.generation)) return;
|
|
31885
|
+
if (!itemIds.has(terminal.itemId)) continue;
|
|
31886
|
+
const task = this.remember(threadId, sessionId, terminal);
|
|
31887
|
+
if (task.publication === "unpublished" && task.state === "running") await this.announce(task);
|
|
31888
|
+
}
|
|
31889
|
+
}
|
|
31890
|
+
async finishAll(state) {
|
|
31891
|
+
if (!this.isActive()) return;
|
|
31892
|
+
const errors = [];
|
|
31893
|
+
for (const task of this.tasks.values()) {
|
|
31894
|
+
try {
|
|
31895
|
+
await this.finish(task, state);
|
|
31896
|
+
} catch (error51) {
|
|
31897
|
+
errors.push(error51);
|
|
31898
|
+
}
|
|
31899
|
+
}
|
|
31900
|
+
if (errors.length > 0) {
|
|
31901
|
+
throw new AggregateError(errors, `Failed to finish ${errors.length} background terminal task(s)`);
|
|
31902
|
+
}
|
|
31903
|
+
}
|
|
31904
|
+
async sync(threadId = this.rootSessionId, sessionId = this.rootSessionId) {
|
|
31905
|
+
if (!this.canQueryAppServer()) return;
|
|
31906
|
+
const current = this.syncs.get(threadId);
|
|
31907
|
+
if (current) {
|
|
31908
|
+
current.requested = true;
|
|
31909
|
+
current.sessionId = sessionId;
|
|
31910
|
+
return await current.promise;
|
|
31911
|
+
}
|
|
31912
|
+
const pending = {
|
|
31913
|
+
requested: false,
|
|
31914
|
+
sessionId,
|
|
31915
|
+
promise: Promise.resolve()
|
|
31916
|
+
};
|
|
31917
|
+
pending.promise = this.syncUntilCurrent(threadId, pending).finally(() => {
|
|
31918
|
+
if (this.syncs.get(threadId) === pending) this.syncs.delete(threadId);
|
|
31919
|
+
});
|
|
31920
|
+
this.syncs.set(threadId, pending);
|
|
31921
|
+
await pending.promise;
|
|
31922
|
+
}
|
|
31923
|
+
async stop(taskId) {
|
|
31924
|
+
if (!this.isActive()) return false;
|
|
31925
|
+
const task = this.tasks.get(taskId);
|
|
31926
|
+
if (!task || task.publication !== "published") return false;
|
|
31927
|
+
if (task.state === "stopped" && !task.terminalPublished) {
|
|
31928
|
+
await this.publishTerminalState(task);
|
|
31929
|
+
return true;
|
|
31930
|
+
}
|
|
31931
|
+
if (task.state !== "running") return false;
|
|
31932
|
+
task.state = "stopping";
|
|
31933
|
+
try {
|
|
31934
|
+
const response = await this.appServer.threadBackgroundTerminalsTerminate({
|
|
31935
|
+
threadId: task.threadId,
|
|
31936
|
+
processId: task.processId
|
|
31937
|
+
});
|
|
31938
|
+
if (!response.terminated) {
|
|
31939
|
+
if (task.state === "stopping") task.state = "running";
|
|
31940
|
+
return false;
|
|
31941
|
+
}
|
|
31942
|
+
await this.finish(task, "stopped");
|
|
31943
|
+
return true;
|
|
31944
|
+
} catch (error51) {
|
|
31945
|
+
if (task.state === "stopping") task.state = "running";
|
|
31946
|
+
throw error51;
|
|
31947
|
+
}
|
|
31948
|
+
}
|
|
31949
|
+
clear() {
|
|
31950
|
+
this.disposed = true;
|
|
31951
|
+
this.appServerGeneration += 1;
|
|
31952
|
+
this.appServerQueriesEnabled = false;
|
|
31953
|
+
this.tasks.clear();
|
|
31954
|
+
this.syncs.clear();
|
|
31955
|
+
}
|
|
31956
|
+
async syncThread(threadId, sessionId) {
|
|
31957
|
+
const snapshot = await this.listAll(threadId);
|
|
31958
|
+
if (snapshot === null || !this.queryIsCurrent(snapshot.generation)) return;
|
|
31959
|
+
const liveTaskIds = /* @__PURE__ */ new Set();
|
|
31960
|
+
for (const terminal of snapshot.terminals) {
|
|
31961
|
+
if (!this.queryIsCurrent(snapshot.generation)) return;
|
|
31962
|
+
liveTaskIds.add(terminal.itemId);
|
|
31963
|
+
const task = this.remember(threadId, sessionId, terminal);
|
|
31964
|
+
if (task.publication === "unpublished" && task.state === "running") await this.announce(task);
|
|
31965
|
+
}
|
|
31966
|
+
for (const task of this.tasks.values()) {
|
|
31967
|
+
if (!this.queryIsCurrent(snapshot.generation)) return;
|
|
31968
|
+
if (task.threadId === threadId && task.publication === "published" && (task.state === "running" || task.state === "stopping") && !liveTaskIds.has(task.itemId)) {
|
|
31969
|
+
await this.finish(task, "stopped");
|
|
31970
|
+
}
|
|
31971
|
+
}
|
|
31972
|
+
}
|
|
31973
|
+
async syncUntilCurrent(threadId, pending) {
|
|
31974
|
+
let hasFailure = false;
|
|
31975
|
+
let failure;
|
|
31976
|
+
do {
|
|
31977
|
+
pending.requested = false;
|
|
31978
|
+
try {
|
|
31979
|
+
await this.syncThread(threadId, pending.sessionId);
|
|
31980
|
+
hasFailure = false;
|
|
31981
|
+
} catch (error51) {
|
|
31982
|
+
hasFailure = true;
|
|
31983
|
+
failure = error51;
|
|
31984
|
+
}
|
|
31985
|
+
} while (pending.requested && this.canQueryAppServer());
|
|
31986
|
+
if (hasFailure) throw failure;
|
|
31987
|
+
}
|
|
31988
|
+
async announce(task) {
|
|
31989
|
+
if (task.publication === "published") return;
|
|
31990
|
+
if (task.announcement !== null) {
|
|
31991
|
+
await task.announcement;
|
|
31992
|
+
return;
|
|
31993
|
+
}
|
|
31994
|
+
task.publication = "publishing";
|
|
31995
|
+
const announcement = this.publishAnnouncement(task);
|
|
31996
|
+
task.announcement = announcement;
|
|
31997
|
+
try {
|
|
31998
|
+
await announcement;
|
|
31999
|
+
} finally {
|
|
32000
|
+
if (task.announcement === announcement) task.announcement = null;
|
|
32001
|
+
}
|
|
32002
|
+
if (isTerminalState(task.state)) await this.publishTerminalState(task);
|
|
32003
|
+
}
|
|
32004
|
+
async publishAnnouncement(task) {
|
|
32005
|
+
try {
|
|
32006
|
+
await this.publishSpawn(task);
|
|
32007
|
+
task.publication = "published";
|
|
32008
|
+
} catch (error51) {
|
|
32009
|
+
task.publication = "unpublished";
|
|
32010
|
+
throw error51;
|
|
32011
|
+
}
|
|
32012
|
+
}
|
|
32013
|
+
async publishSpawn(task) {
|
|
32014
|
+
await this.session.update({
|
|
32015
|
+
sessionUpdate: "tool_call_update",
|
|
32016
|
+
toolCallId: task.itemId,
|
|
32017
|
+
_meta: {
|
|
32018
|
+
[JETBRAINS_META_KEY]: {
|
|
32019
|
+
[AIR_META_KEY]: {
|
|
32020
|
+
[AIR_ASYNC_TASKS_KEY]: {
|
|
32021
|
+
[AIR_ASYNC_TASKS_BACKGROUNDED_KEY]: true
|
|
32022
|
+
}
|
|
32023
|
+
}
|
|
32024
|
+
}
|
|
32025
|
+
}
|
|
32026
|
+
}, task.sessionId);
|
|
32027
|
+
await this.session.update({
|
|
32028
|
+
sessionUpdate: "async_task_spawned",
|
|
32029
|
+
asyncTaskId: task.asyncTaskId,
|
|
32030
|
+
name: task.name,
|
|
32031
|
+
taskType: "shell",
|
|
32032
|
+
showInTranscript: false,
|
|
32033
|
+
canStop: true,
|
|
32034
|
+
toolCallId: task.itemId
|
|
32035
|
+
}, task.sessionId);
|
|
32036
|
+
}
|
|
32037
|
+
remember(threadId, sessionId, terminal, commandTitle2) {
|
|
32038
|
+
const asyncTaskId = wireTaskId(this.rootSessionId, threadId, terminal.itemId);
|
|
32039
|
+
const existing = this.tasks.get(asyncTaskId);
|
|
32040
|
+
if (existing) {
|
|
32041
|
+
existing.processId = terminal.processId;
|
|
32042
|
+
if (commandTitle2 !== void 0) existing.name = commandTitle2;
|
|
32043
|
+
return existing;
|
|
32044
|
+
}
|
|
32045
|
+
const task = {
|
|
32046
|
+
threadId,
|
|
32047
|
+
sessionId,
|
|
32048
|
+
asyncTaskId,
|
|
32049
|
+
processId: terminal.processId,
|
|
32050
|
+
itemId: terminal.itemId,
|
|
32051
|
+
name: commandTitle2 ?? terminal.command,
|
|
32052
|
+
publication: "unpublished",
|
|
32053
|
+
announcement: null,
|
|
32054
|
+
terminalUpdate: null,
|
|
32055
|
+
terminalPublished: false,
|
|
32056
|
+
state: "running"
|
|
32057
|
+
};
|
|
32058
|
+
this.tasks.set(asyncTaskId, task);
|
|
32059
|
+
return task;
|
|
32060
|
+
}
|
|
32061
|
+
async finish(task, state) {
|
|
32062
|
+
if (task.state === "running" || task.state === "stopping") {
|
|
32063
|
+
task.state = state;
|
|
32064
|
+
} else if (task.state !== state) {
|
|
32065
|
+
return;
|
|
32066
|
+
}
|
|
32067
|
+
if (task.announcement !== null) await task.announcement;
|
|
32068
|
+
if (task.publication === "published") await this.publishTerminalState(task);
|
|
32069
|
+
}
|
|
32070
|
+
async publishTerminalState(task) {
|
|
32071
|
+
if (!isTerminalState(task.state) || task.terminalPublished) return;
|
|
32072
|
+
if (task.terminalUpdate !== null) {
|
|
32073
|
+
await task.terminalUpdate;
|
|
32074
|
+
return;
|
|
32075
|
+
}
|
|
32076
|
+
const terminalUpdate = this.session.update({
|
|
32077
|
+
sessionUpdate: "async_task_state_update",
|
|
32078
|
+
asyncTaskId: task.asyncTaskId,
|
|
32079
|
+
state: task.state,
|
|
32080
|
+
toolCallId: task.itemId
|
|
32081
|
+
}, task.sessionId);
|
|
32082
|
+
task.terminalUpdate = terminalUpdate;
|
|
32083
|
+
try {
|
|
32084
|
+
await terminalUpdate;
|
|
32085
|
+
task.terminalPublished = true;
|
|
32086
|
+
} finally {
|
|
32087
|
+
if (task.terminalUpdate === terminalUpdate) task.terminalUpdate = null;
|
|
32088
|
+
}
|
|
32089
|
+
}
|
|
32090
|
+
async listAll(threadId) {
|
|
32091
|
+
const appServer = this.appServer;
|
|
32092
|
+
const generation = this.appServerGeneration;
|
|
32093
|
+
const terminals = [];
|
|
32094
|
+
const seenCursors = /* @__PURE__ */ new Set();
|
|
32095
|
+
let cursor = null;
|
|
32096
|
+
do {
|
|
32097
|
+
const response = await appServer.threadBackgroundTerminalsList({
|
|
32098
|
+
threadId,
|
|
32099
|
+
cursor
|
|
32100
|
+
});
|
|
32101
|
+
if (!this.queryIsCurrent(generation)) return null;
|
|
32102
|
+
terminals.push(...response.data);
|
|
32103
|
+
cursor = response.nextCursor;
|
|
32104
|
+
if (cursor !== null) {
|
|
32105
|
+
if (seenCursors.has(cursor)) {
|
|
32106
|
+
throw new Error("Codex returned a repeated background terminal cursor");
|
|
32107
|
+
}
|
|
32108
|
+
seenCursors.add(cursor);
|
|
32109
|
+
}
|
|
32110
|
+
} while (cursor !== null);
|
|
32111
|
+
return { generation, terminals };
|
|
32112
|
+
}
|
|
32113
|
+
isActive() {
|
|
32114
|
+
return this.enabled && !this.disposed;
|
|
32115
|
+
}
|
|
32116
|
+
canQueryAppServer() {
|
|
32117
|
+
return this.isActive() && this.appServerQueriesEnabled;
|
|
32118
|
+
}
|
|
32119
|
+
queryIsCurrent(generation) {
|
|
32120
|
+
return this.canQueryAppServer() && generation === this.appServerGeneration;
|
|
32121
|
+
}
|
|
32122
|
+
};
|
|
32123
|
+
function isTerminalState(state) {
|
|
32124
|
+
return state === "completed" || state === "failed" || state === "stopped";
|
|
32125
|
+
}
|
|
32126
|
+
function wireTaskId(rootSessionId, threadId, itemId) {
|
|
32127
|
+
return threadId === rootSessionId ? itemId : `${threadId}:${itemId}`;
|
|
32128
|
+
}
|
|
32129
|
+
function notificationThreadId(notification) {
|
|
32130
|
+
const threadId = notification.params.threadId;
|
|
32131
|
+
return typeof threadId === "string" ? threadId : null;
|
|
32132
|
+
}
|
|
32133
|
+
|
|
32134
|
+
// src/CodexAcpServer.ts
|
|
31757
32135
|
var CODEX_PROCESS_EXITED_ERROR_CODE = 1001;
|
|
31758
32136
|
function clientSupportsTypedSessionFailures(capabilities) {
|
|
31759
32137
|
return clientSupportsAirCapability(capabilities, AIR_SESSION_FAILURE_KEY);
|
|
@@ -31791,6 +32169,7 @@ var CodexAcpServer = class _CodexAcpServer {
|
|
|
31791
32169
|
goalControlGenerations;
|
|
31792
32170
|
permissionLifecycleContexts;
|
|
31793
32171
|
codexProcessState;
|
|
32172
|
+
codexProcessGeneration = 0;
|
|
31794
32173
|
initializeRequest = null;
|
|
31795
32174
|
providerUpdate = null;
|
|
31796
32175
|
constructor(connection, codexAcpClient, defaultAuthRequest, getExitCode, getRecentStderr, codexProcessState) {
|
|
@@ -31818,6 +32197,7 @@ var CodexAcpServer = class _CodexAcpServer {
|
|
|
31818
32197
|
this.booleanConfigOptionsSupported = false;
|
|
31819
32198
|
this.currentAuthStatus = null;
|
|
31820
32199
|
this.availableCommands = this.createAvailableCommands(codexAcpClient);
|
|
32200
|
+
this.observeCodexProcess();
|
|
31821
32201
|
}
|
|
31822
32202
|
createAvailableCommands(client) {
|
|
31823
32203
|
return new CodexCommands(
|
|
@@ -31890,7 +32270,8 @@ var CodexAcpServer = class _CodexAcpServer {
|
|
|
31890
32270
|
[AIR_EXTENSION_CAPABILITIES_KEY]: [
|
|
31891
32271
|
AIR_SESSION_FAILURE_KEY,
|
|
31892
32272
|
AIR_AGENT_FILE_CHANGE_REPORT_KEY,
|
|
31893
|
-
AIR_NATIVE_SUBAGENT_SESSIONS_KEY
|
|
32273
|
+
AIR_NATIVE_SUBAGENT_SESSIONS_KEY,
|
|
32274
|
+
AIR_ASYNC_TASKS_KEY
|
|
31894
32275
|
]
|
|
31895
32276
|
}
|
|
31896
32277
|
}
|
|
@@ -31913,6 +32294,18 @@ var CodexAcpServer = class _CodexAcpServer {
|
|
|
31913
32294
|
return await this.unstable_setSessionModel(this.parseLegacySetSessionModelParams(methodRequest.params));
|
|
31914
32295
|
case SESSION_STEERING_METHOD:
|
|
31915
32296
|
return await this.executeOrQueueSteeringRequest(this.parseSessionSteerParams(methodRequest.params));
|
|
32297
|
+
case ASYNC_TASK_STOP_METHOD: {
|
|
32298
|
+
if (this.providerUpdate !== null) {
|
|
32299
|
+
await this.providerUpdate;
|
|
32300
|
+
}
|
|
32301
|
+
const sessionState = this.sessions.get(methodRequest.params.sessionId);
|
|
32302
|
+
if (!sessionState) return { stopped: false };
|
|
32303
|
+
return {
|
|
32304
|
+
stopped: await this.runWithProcessCheck(
|
|
32305
|
+
() => sessionState.asyncTasks.stop(methodRequest.params.asyncTaskId)
|
|
32306
|
+
)
|
|
32307
|
+
};
|
|
32308
|
+
}
|
|
31916
32309
|
case GOAL_CONTROL_METHOD:
|
|
31917
32310
|
case LEGACY_GOAL_CONTROL_METHOD: {
|
|
31918
32311
|
const sessionState = this.sessions.get(methodRequest.params.sessionId);
|
|
@@ -32154,7 +32547,8 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
32154
32547
|
sessionId,
|
|
32155
32548
|
clientSupportsSubagents(this.clientCapabilities),
|
|
32156
32549
|
new ACPSessionConnection(this.connection, sessionId)
|
|
32157
|
-
)
|
|
32550
|
+
),
|
|
32551
|
+
asyncTasks: this.createAsyncTasks(sessionId)
|
|
32158
32552
|
};
|
|
32159
32553
|
sessionState.titleGen = new TitleGenerator(
|
|
32160
32554
|
this.codexAcpClient.appServerClient,
|
|
@@ -32162,7 +32556,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
32162
32556
|
sessionState.cwd,
|
|
32163
32557
|
() => sessionState.sessionTitleSource
|
|
32164
32558
|
);
|
|
32165
|
-
this.
|
|
32559
|
+
this.installSessionState(sessionState);
|
|
32166
32560
|
resumeSubscribed = false;
|
|
32167
32561
|
const canPublishSessionUpdates = operation !== "fork";
|
|
32168
32562
|
if (canPublishSessionUpdates && requestedMcpServers.length > 0 && mcpServerStartupVersion !== null) {
|
|
@@ -32177,6 +32571,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
32177
32571
|
}
|
|
32178
32572
|
if (operation === "resume") {
|
|
32179
32573
|
this.publishCurrentGoalAsync(sessionState, sessionGeneration);
|
|
32574
|
+
this.publishAsyncTasksAsync(sessionState, sessionGeneration);
|
|
32180
32575
|
}
|
|
32181
32576
|
const sessionModelState = this.createModelState(models, currentModelId);
|
|
32182
32577
|
const sessionModeState = sessionState.agentMode.toSessionModeState();
|
|
@@ -32206,6 +32601,18 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
32206
32601
|
}
|
|
32207
32602
|
return a === b;
|
|
32208
32603
|
}
|
|
32604
|
+
createAsyncTasks(sessionId) {
|
|
32605
|
+
return new CodexBackgroundTerminalTasks(
|
|
32606
|
+
clientSupportsAirCapability(this.clientCapabilities, AIR_ASYNC_TASKS_KEY),
|
|
32607
|
+
sessionId,
|
|
32608
|
+
this.codexAcpClient.appServerClient,
|
|
32609
|
+
new ACPSessionConnection(this.connection, sessionId)
|
|
32610
|
+
);
|
|
32611
|
+
}
|
|
32612
|
+
installSessionState(sessionState) {
|
|
32613
|
+
this.sessions.get(sessionState.sessionId)?.asyncTasks.clear();
|
|
32614
|
+
this.sessions.set(sessionState.sessionId, sessionState);
|
|
32615
|
+
}
|
|
32209
32616
|
getAuthProviderForAuthenticateRequest(request) {
|
|
32210
32617
|
if (isCodexAuthRequest(request) && request.methodId === "gateway") {
|
|
32211
32618
|
return "custom-gateway";
|
|
@@ -32224,6 +32631,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
32224
32631
|
thread
|
|
32225
32632
|
} = await this.getOrCreateSessionWithHistory(params);
|
|
32226
32633
|
await this.streamThreadHistory(sessionId, thread);
|
|
32634
|
+
await this.getSessionState(sessionId).asyncTasks.reconcile();
|
|
32227
32635
|
logger.log("Session loaded", {
|
|
32228
32636
|
sessionId,
|
|
32229
32637
|
modelId: modelState.currentModelId,
|
|
@@ -32297,6 +32705,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
32297
32705
|
try {
|
|
32298
32706
|
if (sessionState) {
|
|
32299
32707
|
await this.interruptSessionTurn(sessionState, "Close", true);
|
|
32708
|
+
sessionState.asyncTasks.clear();
|
|
32300
32709
|
} else {
|
|
32301
32710
|
logger.log("Close request received for unknown local session", { sessionId: params.sessionId });
|
|
32302
32711
|
}
|
|
@@ -32432,6 +32841,10 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
32432
32841
|
await Promise.all(activePrompts);
|
|
32433
32842
|
}
|
|
32434
32843
|
logger.log("Restarting Codex app-server for provider update", { sessionCount: this.sessions.size });
|
|
32844
|
+
for (const session of this.sessions.values()) {
|
|
32845
|
+
session.asyncTasks.prepareForAppServerReplacement();
|
|
32846
|
+
}
|
|
32847
|
+
await this.finishAllAsyncTasks("stopped", "before the provider restart");
|
|
32435
32848
|
const replacement = await this.restartCodexClient();
|
|
32436
32849
|
apply(replacement);
|
|
32437
32850
|
if (this.initializeRequest === null) {
|
|
@@ -32442,6 +32855,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
32442
32855
|
this.availableCommands = this.createAvailableCommands(replacement);
|
|
32443
32856
|
const resumeErrors = [];
|
|
32444
32857
|
for (const session of this.sessions.values()) {
|
|
32858
|
+
session.asyncTasks.setAppServer(replacement.appServerClient);
|
|
32445
32859
|
try {
|
|
32446
32860
|
await replacement.resumeSession({
|
|
32447
32861
|
sessionId: session.sessionId,
|
|
@@ -32450,6 +32864,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
32450
32864
|
mcpServers: session.mcpServers ?? []
|
|
32451
32865
|
});
|
|
32452
32866
|
session.authProvider = replacement.getModelProvider();
|
|
32867
|
+
session.asyncTasks.refresh();
|
|
32453
32868
|
logger.log("Resumed session after provider restart", { sessionId: session.sessionId });
|
|
32454
32869
|
} catch (error51) {
|
|
32455
32870
|
resumeErrors.push(error51);
|
|
@@ -32479,12 +32894,22 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
32479
32894
|
state.stderr = (state.stderr + data.toString()).slice(-2 * 1024);
|
|
32480
32895
|
});
|
|
32481
32896
|
}
|
|
32897
|
+
observeCodexProcess() {
|
|
32898
|
+
const process12 = this.codexProcessState?.connection.process;
|
|
32899
|
+
if (!process12) return;
|
|
32900
|
+
const generation = ++this.codexProcessGeneration;
|
|
32901
|
+
process12.once("exit", () => {
|
|
32902
|
+
if (generation !== this.codexProcessGeneration) return;
|
|
32903
|
+
void this.finishAllAsyncTasks("failed", "after the Codex process exited");
|
|
32904
|
+
});
|
|
32905
|
+
}
|
|
32482
32906
|
async restartCodexClient() {
|
|
32483
32907
|
const state = this.codexProcessState;
|
|
32484
32908
|
if (state === null) {
|
|
32485
32909
|
throw new Error("Codex process state is unavailable");
|
|
32486
32910
|
}
|
|
32487
32911
|
const previous = state.connection;
|
|
32912
|
+
this.codexProcessGeneration += 1;
|
|
32488
32913
|
const exited = previous.process.exitCode === null ? once(previous.process, "exit") : Promise.resolve();
|
|
32489
32914
|
previous.process.stdin.end();
|
|
32490
32915
|
const forceKill = setTimeout(() => {
|
|
@@ -32498,6 +32923,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
32498
32923
|
state.stderr = "";
|
|
32499
32924
|
state.connection = startCodexConnection(state.codexPath);
|
|
32500
32925
|
this.captureStderr();
|
|
32926
|
+
this.observeCodexProcess();
|
|
32501
32927
|
return new CodexAcpClient(
|
|
32502
32928
|
new CodexAppServerClient(state.connection.connection),
|
|
32503
32929
|
state.config,
|
|
@@ -33047,6 +33473,10 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
33047
33473
|
publishCurrentGoalAsync(sessionState, sessionGeneration) {
|
|
33048
33474
|
void this.publishCurrentGoalBestEffort(sessionState, sessionGeneration, true);
|
|
33049
33475
|
}
|
|
33476
|
+
publishAsyncTasksAsync(sessionState, sessionGeneration) {
|
|
33477
|
+
if (!this.sessionPublishIsCurrent(sessionState, sessionGeneration)) return;
|
|
33478
|
+
sessionState.asyncTasks.refresh();
|
|
33479
|
+
}
|
|
33050
33480
|
async publishCurrentGoalBestEffort(sessionState, sessionGeneration, force) {
|
|
33051
33481
|
try {
|
|
33052
33482
|
await this.publishCurrentGoal(sessionState, sessionGeneration, force);
|
|
@@ -33170,7 +33600,8 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
33170
33600
|
sessionId,
|
|
33171
33601
|
clientSupportsSubagents(this.clientCapabilities),
|
|
33172
33602
|
new ACPSessionConnection(this.connection, sessionId)
|
|
33173
|
-
)
|
|
33603
|
+
),
|
|
33604
|
+
asyncTasks: this.createAsyncTasks(sessionId)
|
|
33174
33605
|
};
|
|
33175
33606
|
sessionState.titleGen = new TitleGenerator(
|
|
33176
33607
|
this.codexAcpClient.appServerClient,
|
|
@@ -33178,7 +33609,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
33178
33609
|
sessionState.cwd,
|
|
33179
33610
|
() => sessionState.sessionTitleSource
|
|
33180
33611
|
);
|
|
33181
|
-
this.
|
|
33612
|
+
this.installSessionState(sessionState);
|
|
33182
33613
|
subscribed = false;
|
|
33183
33614
|
if (requestedMcpServers.length > 0 && mcpServerStartupVersion !== null) {
|
|
33184
33615
|
this.pendingMcpStartupSessions.set(sessionId, {
|
|
@@ -33270,6 +33701,15 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
33270
33701
|
/* @__PURE__ */ new Set([...ancestry, item.agentThreadId]),
|
|
33271
33702
|
threadCache
|
|
33272
33703
|
);
|
|
33704
|
+
try {
|
|
33705
|
+
await sessionState.asyncTasks.recover(
|
|
33706
|
+
item.agentThreadId,
|
|
33707
|
+
childSessionId,
|
|
33708
|
+
commandItemIds(childTurn.items)
|
|
33709
|
+
);
|
|
33710
|
+
} catch (error51) {
|
|
33711
|
+
logger.error(`Failed to restore background terminals for ${item.agentThreadId}`, error51);
|
|
33712
|
+
}
|
|
33273
33713
|
}
|
|
33274
33714
|
}
|
|
33275
33715
|
} else if (activityKind === "completed" || activityKind === "interrupted") {
|
|
@@ -34320,6 +34760,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
34320
34760
|
throw new RequestError(requestErrorCode, `VC++ redistributable should be installed`);
|
|
34321
34761
|
}
|
|
34322
34762
|
if (exitCode !== null) {
|
|
34763
|
+
await this.finishAllAsyncTasks("failed", "after the Codex process exited");
|
|
34323
34764
|
const stderr = this.getRecentStderr().trim();
|
|
34324
34765
|
const detail = stderr ? `:
|
|
34325
34766
|
${stderr}` : "";
|
|
@@ -34328,6 +34769,15 @@ ${stderr}` : "";
|
|
|
34328
34769
|
throw err;
|
|
34329
34770
|
}
|
|
34330
34771
|
}
|
|
34772
|
+
async finishAllAsyncTasks(state, reason) {
|
|
34773
|
+
for (const session of this.sessions.values()) {
|
|
34774
|
+
try {
|
|
34775
|
+
await session.asyncTasks.finishAll(state);
|
|
34776
|
+
} catch (error51) {
|
|
34777
|
+
logger.error(`Failed to finish background terminal tasks ${reason}`, error51);
|
|
34778
|
+
}
|
|
34779
|
+
}
|
|
34780
|
+
}
|
|
34331
34781
|
async cancel(params) {
|
|
34332
34782
|
const sessionState = this.sessions.get(params.sessionId);
|
|
34333
34783
|
if (!sessionState) {
|
|
@@ -34377,6 +34827,9 @@ function mergeHistoryUpdates(responseItemFallbackUpdates, threadUpdates) {
|
|
|
34377
34827
|
}
|
|
34378
34828
|
return merged;
|
|
34379
34829
|
}
|
|
34830
|
+
function commandItemIds(items) {
|
|
34831
|
+
return new Set(items.filter((item) => item.type === "commandExecution").map((item) => item.id));
|
|
34832
|
+
}
|
|
34380
34833
|
function historyUpdateKey(update) {
|
|
34381
34834
|
switch (update.sessionUpdate) {
|
|
34382
34835
|
case "user_message_chunk":
|
|
@@ -34560,6 +35013,10 @@ var goalControlParamsParser = external_exports.discriminatedUnion("action", [
|
|
|
34560
35013
|
action: external_exports.enum(["pause", "resume", "clear"])
|
|
34561
35014
|
}).passthrough()
|
|
34562
35015
|
]);
|
|
35016
|
+
var asyncTaskStopParamsParser = external_exports.object({
|
|
35017
|
+
sessionId: external_exports.string().trim().min(1),
|
|
35018
|
+
asyncTaskId: external_exports.string().trim().min(1)
|
|
35019
|
+
}).passthrough();
|
|
34563
35020
|
if (process.argv.includes("--version")) {
|
|
34564
35021
|
console.log(`${package_default.name} ${package_default.version}`);
|
|
34565
35022
|
process.exit(0);
|
|
@@ -34640,5 +35097,5 @@ function startAcpServer() {
|
|
|
34640
35097
|
codexAcpServer = null;
|
|
34641
35098
|
}
|
|
34642
35099
|
});
|
|
34643
|
-
}).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);
|
|
35100
|
+
}).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);
|
|
34644
35101
|
}
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.
|
|
6
|
+
"version": "1.10.0",
|
|
7
7
|
"description": "",
|
|
8
8
|
"main": "dist/index.js",
|
|
9
9
|
"bin": {
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
},
|
|
67
67
|
"dependencies": {
|
|
68
68
|
"@agentclientprotocol/sdk": "^1.4.0",
|
|
69
|
-
"@openai/codex": "^0.153.
|
|
69
|
+
"@openai/codex": "^0.153.3",
|
|
70
70
|
"diff": "^9.0.0",
|
|
71
71
|
"open": "^11.0.1",
|
|
72
72
|
"vscode-jsonrpc": "^9.0.1",
|