@agentclientprotocol/codex-acp 1.6.0 → 1.7.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 +9 -2
- package/dist/index.js +1962 -1005
- package/package.json +7 -7
package/dist/index.js
CHANGED
|
@@ -3453,7 +3453,7 @@ var require_main = __commonJS({
|
|
|
3453
3453
|
exports.createMessageConnection = createMessageConnection2;
|
|
3454
3454
|
var ril_1 = __importDefault(require_ril());
|
|
3455
3455
|
ril_1.default.install();
|
|
3456
|
-
var
|
|
3456
|
+
var path9 = __importStar(__require("path"));
|
|
3457
3457
|
var os2 = __importStar(__require("os"));
|
|
3458
3458
|
var fs8 = __importStar(__require("fs"));
|
|
3459
3459
|
var crypto_1 = __require("crypto");
|
|
@@ -3462,9 +3462,9 @@ var require_main = __commonJS({
|
|
|
3462
3462
|
__exportStar(require_api(), exports);
|
|
3463
3463
|
var IPCMessageReader = class extends api_1.AbstractMessageReader {
|
|
3464
3464
|
process;
|
|
3465
|
-
constructor(
|
|
3465
|
+
constructor(process12) {
|
|
3466
3466
|
super();
|
|
3467
|
-
this.process =
|
|
3467
|
+
this.process = process12;
|
|
3468
3468
|
const eventEmitter = this.process;
|
|
3469
3469
|
eventEmitter.on("error", (error51) => this.fireError(error51));
|
|
3470
3470
|
eventEmitter.on("close", () => this.fireClose());
|
|
@@ -3478,9 +3478,9 @@ var require_main = __commonJS({
|
|
|
3478
3478
|
var IPCMessageWriter = class extends api_1.AbstractMessageWriter {
|
|
3479
3479
|
process;
|
|
3480
3480
|
errorCount;
|
|
3481
|
-
constructor(
|
|
3481
|
+
constructor(process12) {
|
|
3482
3482
|
super();
|
|
3483
|
-
this.process =
|
|
3483
|
+
this.process = process12;
|
|
3484
3484
|
this.errorCount = 0;
|
|
3485
3485
|
const eventEmitter = this.process;
|
|
3486
3486
|
eventEmitter.on("error", (error51) => this.fireError(error51));
|
|
@@ -3605,7 +3605,7 @@ var require_main = __commonJS({
|
|
|
3605
3605
|
throw new Error(`Unable to generate a random pipe name with ${randomLength} characters.`);
|
|
3606
3606
|
}
|
|
3607
3607
|
const randomSuffix = (0, crypto_1.randomBytes)(Math.floor(randomLength / 2)).toString("hex");
|
|
3608
|
-
return
|
|
3608
|
+
return path9.join(tmpDir, `lsp-${randomSuffix}.sock`);
|
|
3609
3609
|
}
|
|
3610
3610
|
function createClientPipeTransport(pipeName, encoding = "utf-8") {
|
|
3611
3611
|
let connectResolve;
|
|
@@ -4509,10 +4509,10 @@ function mergeDefs(...defs) {
|
|
|
4509
4509
|
function cloneDef(schema) {
|
|
4510
4510
|
return mergeDefs(schema._zod.def);
|
|
4511
4511
|
}
|
|
4512
|
-
function getElementAtPath(obj,
|
|
4513
|
-
if (!
|
|
4512
|
+
function getElementAtPath(obj, path9) {
|
|
4513
|
+
if (!path9)
|
|
4514
4514
|
return obj;
|
|
4515
|
-
return
|
|
4515
|
+
return path9.reduce((acc, key) => acc?.[key], obj);
|
|
4516
4516
|
}
|
|
4517
4517
|
function promiseAllObject(promisesObj) {
|
|
4518
4518
|
const keys = Object.keys(promisesObj);
|
|
@@ -4921,11 +4921,11 @@ function explicitlyAborted(x, startIndex = 0) {
|
|
|
4921
4921
|
}
|
|
4922
4922
|
return false;
|
|
4923
4923
|
}
|
|
4924
|
-
function prefixIssues(
|
|
4924
|
+
function prefixIssues(path9, issues) {
|
|
4925
4925
|
return issues.map((iss) => {
|
|
4926
4926
|
var _a3;
|
|
4927
4927
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
4928
|
-
iss.path.unshift(
|
|
4928
|
+
iss.path.unshift(path9);
|
|
4929
4929
|
return iss;
|
|
4930
4930
|
});
|
|
4931
4931
|
}
|
|
@@ -5072,16 +5072,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
|
|
|
5072
5072
|
}
|
|
5073
5073
|
function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
5074
5074
|
const fieldErrors = { _errors: [] };
|
|
5075
|
-
const processError = (error52,
|
|
5075
|
+
const processError = (error52, path9 = []) => {
|
|
5076
5076
|
for (const issue2 of error52.issues) {
|
|
5077
5077
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
5078
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
5078
|
+
issue2.errors.map((issues) => processError({ issues }, [...path9, ...issue2.path]));
|
|
5079
5079
|
} else if (issue2.code === "invalid_key") {
|
|
5080
|
-
processError({ issues: issue2.issues }, [...
|
|
5080
|
+
processError({ issues: issue2.issues }, [...path9, ...issue2.path]);
|
|
5081
5081
|
} else if (issue2.code === "invalid_element") {
|
|
5082
|
-
processError({ issues: issue2.issues }, [...
|
|
5082
|
+
processError({ issues: issue2.issues }, [...path9, ...issue2.path]);
|
|
5083
5083
|
} else {
|
|
5084
|
-
const fullpath = [...
|
|
5084
|
+
const fullpath = [...path9, ...issue2.path];
|
|
5085
5085
|
if (fullpath.length === 0) {
|
|
5086
5086
|
fieldErrors._errors.push(mapper(issue2));
|
|
5087
5087
|
} else {
|
|
@@ -5108,17 +5108,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
|
5108
5108
|
}
|
|
5109
5109
|
function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
5110
5110
|
const result = { errors: [] };
|
|
5111
|
-
const processError = (error52,
|
|
5111
|
+
const processError = (error52, path9 = []) => {
|
|
5112
5112
|
var _a3, _b;
|
|
5113
5113
|
for (const issue2 of error52.issues) {
|
|
5114
5114
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
5115
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
5115
|
+
issue2.errors.map((issues) => processError({ issues }, [...path9, ...issue2.path]));
|
|
5116
5116
|
} else if (issue2.code === "invalid_key") {
|
|
5117
|
-
processError({ issues: issue2.issues }, [...
|
|
5117
|
+
processError({ issues: issue2.issues }, [...path9, ...issue2.path]);
|
|
5118
5118
|
} else if (issue2.code === "invalid_element") {
|
|
5119
|
-
processError({ issues: issue2.issues }, [...
|
|
5119
|
+
processError({ issues: issue2.issues }, [...path9, ...issue2.path]);
|
|
5120
5120
|
} else {
|
|
5121
|
-
const fullpath = [...
|
|
5121
|
+
const fullpath = [...path9, ...issue2.path];
|
|
5122
5122
|
if (fullpath.length === 0) {
|
|
5123
5123
|
result.errors.push(mapper(issue2));
|
|
5124
5124
|
continue;
|
|
@@ -5150,8 +5150,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
|
5150
5150
|
}
|
|
5151
5151
|
function toDotPath(_path) {
|
|
5152
5152
|
const segs = [];
|
|
5153
|
-
const
|
|
5154
|
-
for (const seg of
|
|
5153
|
+
const path9 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
5154
|
+
for (const seg of path9) {
|
|
5155
5155
|
if (typeof seg === "number")
|
|
5156
5156
|
segs.push(`[${seg}]`);
|
|
5157
5157
|
else if (typeof seg === "symbol")
|
|
@@ -17843,13 +17843,13 @@ function resolveRef(ref, ctx) {
|
|
|
17843
17843
|
if (!ref.startsWith("#")) {
|
|
17844
17844
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
17845
17845
|
}
|
|
17846
|
-
const
|
|
17847
|
-
if (
|
|
17846
|
+
const path9 = ref.slice(1).split("/").filter(Boolean);
|
|
17847
|
+
if (path9.length === 0) {
|
|
17848
17848
|
return ctx.rootSchema;
|
|
17849
17849
|
}
|
|
17850
17850
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
17851
|
-
if (
|
|
17852
|
-
const key =
|
|
17851
|
+
if (path9[0] === defsKey) {
|
|
17852
|
+
const key = path9[1];
|
|
17853
17853
|
if (!key || !ctx.defs[key]) {
|
|
17854
17854
|
throw new Error(`Reference not found: ${ref}`);
|
|
17855
17855
|
}
|
|
@@ -18856,21 +18856,6 @@ var zAgentCapabilities = object({
|
|
|
18856
18856
|
_meta: defaultOnError(record(string2(), unknown()).nullish(), () => void 0)
|
|
18857
18857
|
});
|
|
18858
18858
|
var zAuthMethodId = string2();
|
|
18859
|
-
var zAuthEnvVar = object({
|
|
18860
|
-
name: string2(),
|
|
18861
|
-
label: defaultOnError(string2().nullish(), () => void 0),
|
|
18862
|
-
secret: defaultOnError(boolean2().optional().default(true), () => true),
|
|
18863
|
-
optional: defaultOnError(boolean2().optional().default(false), () => false),
|
|
18864
|
-
_meta: defaultOnError(record(string2(), unknown()).nullish(), () => void 0)
|
|
18865
|
-
});
|
|
18866
|
-
var zAuthMethodEnvVar = object({
|
|
18867
|
-
id: zAuthMethodId,
|
|
18868
|
-
name: string2(),
|
|
18869
|
-
description: defaultOnError(string2().nullish(), () => void 0),
|
|
18870
|
-
vars: requiredDefaultOnError(vecSkipError(zAuthEnvVar), () => []),
|
|
18871
|
-
link: defaultOnError(string2().nullish(), () => void 0),
|
|
18872
|
-
_meta: defaultOnError(record(string2(), unknown()).nullish(), () => void 0)
|
|
18873
|
-
});
|
|
18874
18859
|
var zAuthMethodTerminal = object({
|
|
18875
18860
|
id: zAuthMethodId,
|
|
18876
18861
|
name: string2(),
|
|
@@ -18886,9 +18871,6 @@ var zAuthMethodAgent = object({
|
|
|
18886
18871
|
_meta: defaultOnError(record(string2(), unknown()).nullish(), () => void 0)
|
|
18887
18872
|
});
|
|
18888
18873
|
var zAuthMethod = union([
|
|
18889
|
-
zAuthMethodEnvVar.and(object({
|
|
18890
|
-
type: literal("env_var")
|
|
18891
|
-
})),
|
|
18892
18874
|
zAuthMethodTerminal.and(object({
|
|
18893
18875
|
type: literal("terminal")
|
|
18894
18876
|
})),
|
|
@@ -19339,6 +19321,26 @@ var zUsageUpdate = object({
|
|
|
19339
19321
|
cost: defaultOnError(zCost.nullish(), () => void 0),
|
|
19340
19322
|
_meta: defaultOnError(record(string2(), unknown()).nullish(), () => void 0)
|
|
19341
19323
|
});
|
|
19324
|
+
var zCompactionId = string2();
|
|
19325
|
+
var zCompactionStatus = union([
|
|
19326
|
+
literal("in_progress"),
|
|
19327
|
+
literal("completed"),
|
|
19328
|
+
literal("failed"),
|
|
19329
|
+
literal("cancelled"),
|
|
19330
|
+
string2()
|
|
19331
|
+
]);
|
|
19332
|
+
var zCompactionUpdate = object({
|
|
19333
|
+
compactionId: zCompactionId,
|
|
19334
|
+
status: zCompactionStatus,
|
|
19335
|
+
summary: defaultOnError(vecSkipError(zContentBlock).nullish(), () => void 0),
|
|
19336
|
+
error: defaultOnError(string2().nullish(), () => void 0),
|
|
19337
|
+
_meta: defaultOnError(record(string2(), unknown()).nullish(), () => void 0)
|
|
19338
|
+
});
|
|
19339
|
+
var zCompactionSummaryChunk = object({
|
|
19340
|
+
compactionId: zCompactionId,
|
|
19341
|
+
content: zContentBlock,
|
|
19342
|
+
_meta: defaultOnError(record(string2(), unknown()).nullish(), () => void 0)
|
|
19343
|
+
});
|
|
19342
19344
|
var zSessionUpdate = union([
|
|
19343
19345
|
zContentChunk.and(object({
|
|
19344
19346
|
sessionUpdate: literal("user_message_chunk")
|
|
@@ -19378,6 +19380,12 @@ var zSessionUpdate = union([
|
|
|
19378
19380
|
})),
|
|
19379
19381
|
zUsageUpdate.and(object({
|
|
19380
19382
|
sessionUpdate: literal("usage_update")
|
|
19383
|
+
})),
|
|
19384
|
+
zCompactionUpdate.and(object({
|
|
19385
|
+
sessionUpdate: literal("compaction_update")
|
|
19386
|
+
})),
|
|
19387
|
+
zCompactionSummaryChunk.and(object({
|
|
19388
|
+
sessionUpdate: literal("compaction_summary_chunk")
|
|
19381
19389
|
}))
|
|
19382
19390
|
]);
|
|
19383
19391
|
var zSessionNotification = object({
|
|
@@ -19410,6 +19418,7 @@ var zFileSystemCapabilities = object({
|
|
|
19410
19418
|
writeTextFile: defaultOnError(boolean2().optional().default(false), () => false),
|
|
19411
19419
|
_meta: defaultOnError(record(string2(), unknown()).nullish(), () => void 0)
|
|
19412
19420
|
});
|
|
19421
|
+
var zCompactionCapabilities = record(string2(), unknown());
|
|
19413
19422
|
var zBooleanConfigOptionCapabilities = object({
|
|
19414
19423
|
_meta: defaultOnError(record(string2(), unknown()).nullish(), () => void 0)
|
|
19415
19424
|
});
|
|
@@ -19418,6 +19427,7 @@ var zSessionConfigOptionsCapabilities = object({
|
|
|
19418
19427
|
_meta: defaultOnError(record(string2(), unknown()).nullish(), () => void 0)
|
|
19419
19428
|
});
|
|
19420
19429
|
var zClientSessionCapabilities = object({
|
|
19430
|
+
compaction: defaultOnError(zCompactionCapabilities.nullish(), () => void 0),
|
|
19421
19431
|
configOptions: defaultOnError(zSessionConfigOptionsCapabilities.nullish(), () => void 0),
|
|
19422
19432
|
_meta: defaultOnError(record(string2(), unknown()).nullish(), () => void 0)
|
|
19423
19433
|
});
|
|
@@ -20096,6 +20106,7 @@ var RequestResponder = class {
|
|
|
20096
20106
|
});
|
|
20097
20107
|
}
|
|
20098
20108
|
};
|
|
20109
|
+
var requestBatchSizes = /* @__PURE__ */ new WeakMap();
|
|
20099
20110
|
var HandlerRegistration = class {
|
|
20100
20111
|
disposeHandler;
|
|
20101
20112
|
active = true;
|
|
@@ -20446,9 +20457,6 @@ var Connection = class {
|
|
|
20446
20457
|
if (done) {
|
|
20447
20458
|
break;
|
|
20448
20459
|
}
|
|
20449
|
-
if (!message) {
|
|
20450
|
-
continue;
|
|
20451
|
-
}
|
|
20452
20460
|
this.receiveWireMessage(message);
|
|
20453
20461
|
}
|
|
20454
20462
|
} finally {
|
|
@@ -20472,19 +20480,16 @@ var Connection = class {
|
|
|
20472
20480
|
this.receiveBatch(message);
|
|
20473
20481
|
return;
|
|
20474
20482
|
}
|
|
20475
|
-
if (!
|
|
20476
|
-
|
|
20483
|
+
if (!isRequestMessage(message) && !isNotificationMessage(message) && !isResponseShapedMessage(message)) {
|
|
20484
|
+
void this.sendWireMessage(protocolErrorResponse(RequestError.invalidRequest(message))).catch(() => {
|
|
20485
|
+
});
|
|
20477
20486
|
return;
|
|
20478
20487
|
}
|
|
20479
20488
|
this.receiveMessage(message);
|
|
20480
20489
|
}
|
|
20481
20490
|
receiveBatch(batch) {
|
|
20482
20491
|
if (batch.length === 0) {
|
|
20483
|
-
void this.sendWireMessage({
|
|
20484
|
-
jsonrpc: "2.0",
|
|
20485
|
-
id: null,
|
|
20486
|
-
error: RequestError.invalidRequest(batch).toErrorResponse()
|
|
20487
|
-
}).catch(() => {
|
|
20492
|
+
void this.sendWireMessage(protocolErrorResponse(RequestError.invalidRequest(batch))).catch(() => {
|
|
20488
20493
|
});
|
|
20489
20494
|
return;
|
|
20490
20495
|
}
|
|
@@ -20514,15 +20519,11 @@ var Connection = class {
|
|
|
20514
20519
|
continue;
|
|
20515
20520
|
}
|
|
20516
20521
|
if (!isRequestMessage(message) && !isNotificationMessage(message)) {
|
|
20517
|
-
void collectResponse({
|
|
20518
|
-
jsonrpc: "2.0",
|
|
20519
|
-
id: null,
|
|
20520
|
-
error: RequestError.invalidRequest(message).toErrorResponse()
|
|
20521
|
-
}).catch(() => {
|
|
20522
|
+
void collectResponse(protocolErrorResponse(RequestError.invalidRequest(message))).catch(() => {
|
|
20522
20523
|
});
|
|
20523
20524
|
continue;
|
|
20524
20525
|
}
|
|
20525
|
-
const processing = this.receiveMessage(message, isRequestMessage(message) ? collectResponse : void 0);
|
|
20526
|
+
const processing = this.receiveMessage(message, isRequestMessage(message) ? collectResponse : void 0, batch.length);
|
|
20526
20527
|
if (isNotificationMessage(message)) {
|
|
20527
20528
|
void processing.finally(() => {
|
|
20528
20529
|
remainingNotifications -= 1;
|
|
@@ -20531,7 +20532,7 @@ var Connection = class {
|
|
|
20531
20532
|
}
|
|
20532
20533
|
}
|
|
20533
20534
|
}
|
|
20534
|
-
receiveMessage(message, sendResponse) {
|
|
20535
|
+
receiveMessage(message, sendResponse, batchSize) {
|
|
20535
20536
|
if (this.abortController.signal.aborted) {
|
|
20536
20537
|
return Promise.resolve();
|
|
20537
20538
|
}
|
|
@@ -20543,7 +20544,7 @@ var Connection = class {
|
|
|
20543
20544
|
if (!("id" in message)) {
|
|
20544
20545
|
this.handleProtocolNotification(message);
|
|
20545
20546
|
}
|
|
20546
|
-
return this.processIncomingMessage(this.toIncomingMessage(message, sendResponse)).catch((error51) => this.close(error51));
|
|
20547
|
+
return this.processIncomingMessage(this.toIncomingMessage(message, sendResponse, batchSize)).catch((error51) => this.close(error51));
|
|
20547
20548
|
} else if ("id" in message) {
|
|
20548
20549
|
this.handleResponse(message);
|
|
20549
20550
|
} else {
|
|
@@ -20593,7 +20594,7 @@ var Connection = class {
|
|
|
20593
20594
|
}
|
|
20594
20595
|
}
|
|
20595
20596
|
}
|
|
20596
|
-
toIncomingMessage(message, sendResponse) {
|
|
20597
|
+
toIncomingMessage(message, sendResponse, batchSize) {
|
|
20597
20598
|
if ("id" in message) {
|
|
20598
20599
|
const abortController = new AbortController();
|
|
20599
20600
|
this.incomingRequests.set(message.id, abortController);
|
|
@@ -20602,20 +20603,24 @@ var Connection = class {
|
|
|
20602
20603
|
this.incomingRequests.delete(message.id);
|
|
20603
20604
|
}
|
|
20604
20605
|
};
|
|
20606
|
+
const responder = new RequestResponder(message.id, (result) => {
|
|
20607
|
+
const response = {
|
|
20608
|
+
jsonrpc: "2.0",
|
|
20609
|
+
id: message.id,
|
|
20610
|
+
...result
|
|
20611
|
+
};
|
|
20612
|
+
return sendResponse ? sendResponse(response) : this.sendWireMessage(response);
|
|
20613
|
+
}, abortController.signal, finishRequest);
|
|
20614
|
+
if (batchSize !== void 0) {
|
|
20615
|
+
requestBatchSizes.set(responder, batchSize);
|
|
20616
|
+
}
|
|
20605
20617
|
return {
|
|
20606
20618
|
kind: "request",
|
|
20607
20619
|
method: message.method,
|
|
20608
20620
|
params: message.params,
|
|
20609
20621
|
raw: message,
|
|
20610
20622
|
signal: abortController.signal,
|
|
20611
|
-
responder
|
|
20612
|
-
const response = {
|
|
20613
|
-
jsonrpc: "2.0",
|
|
20614
|
-
id: message.id,
|
|
20615
|
-
...result
|
|
20616
|
-
};
|
|
20617
|
-
return sendResponse ? sendResponse(response) : this.sendWireMessage(response);
|
|
20618
|
-
}, abortController.signal, finishRequest)
|
|
20623
|
+
responder
|
|
20619
20624
|
};
|
|
20620
20625
|
}
|
|
20621
20626
|
return {
|
|
@@ -20837,6 +20842,13 @@ var RequestError = class _RequestError extends Error {
|
|
|
20837
20842
|
};
|
|
20838
20843
|
}
|
|
20839
20844
|
};
|
|
20845
|
+
function protocolErrorResponse(error51) {
|
|
20846
|
+
return {
|
|
20847
|
+
jsonrpc: "2.0",
|
|
20848
|
+
id: null,
|
|
20849
|
+
error: error51.toErrorResponse()
|
|
20850
|
+
};
|
|
20851
|
+
}
|
|
20840
20852
|
|
|
20841
20853
|
// node_modules/@agentclientprotocol/sdk/dist/line-buffer.js
|
|
20842
20854
|
var newline = 10;
|
|
@@ -20897,22 +20909,40 @@ function ndJsonStream(output, input) {
|
|
|
20897
20909
|
const textDecoder = new TextDecoder();
|
|
20898
20910
|
let cancelled = false;
|
|
20899
20911
|
let inputReader;
|
|
20912
|
+
let outputWrite = Promise.resolve();
|
|
20913
|
+
const writeJson = (message) => {
|
|
20914
|
+
const content = JSON.stringify(message) + "\n";
|
|
20915
|
+
const write = outputWrite.then(async () => {
|
|
20916
|
+
const writer = output.getWriter();
|
|
20917
|
+
try {
|
|
20918
|
+
await writer.write(textEncoder.encode(content));
|
|
20919
|
+
} finally {
|
|
20920
|
+
writer.releaseLock();
|
|
20921
|
+
}
|
|
20922
|
+
});
|
|
20923
|
+
outputWrite = write.catch(() => {
|
|
20924
|
+
});
|
|
20925
|
+
return write;
|
|
20926
|
+
};
|
|
20900
20927
|
const readable = new ReadableStream({
|
|
20901
20928
|
async start(controller) {
|
|
20902
20929
|
const lines = new LineBuffer();
|
|
20903
|
-
const enqueueLine = (lineBytes) => {
|
|
20930
|
+
const enqueueLine = async (lineBytes) => {
|
|
20904
20931
|
const trimmedLine = textDecoder.decode(lineBytes).trim();
|
|
20905
|
-
if (trimmedLine) {
|
|
20906
|
-
|
|
20907
|
-
|
|
20908
|
-
|
|
20909
|
-
|
|
20910
|
-
|
|
20911
|
-
|
|
20912
|
-
|
|
20913
|
-
|
|
20914
|
-
|
|
20915
|
-
|
|
20932
|
+
if (!trimmedLine) {
|
|
20933
|
+
return;
|
|
20934
|
+
}
|
|
20935
|
+
let message;
|
|
20936
|
+
try {
|
|
20937
|
+
message = JSON.parse(trimmedLine);
|
|
20938
|
+
} catch {
|
|
20939
|
+
await writeJson(protocolErrorResponse(RequestError.parseError()));
|
|
20940
|
+
return;
|
|
20941
|
+
}
|
|
20942
|
+
if (isRecord(message) || Array.isArray(message)) {
|
|
20943
|
+
controller.enqueue(message);
|
|
20944
|
+
} else {
|
|
20945
|
+
await writeJson(protocolErrorResponse(RequestError.invalidRequest(message)));
|
|
20916
20946
|
}
|
|
20917
20947
|
};
|
|
20918
20948
|
const reader = input.getReader();
|
|
@@ -20930,7 +20960,7 @@ function ndJsonStream(output, input) {
|
|
|
20930
20960
|
continue;
|
|
20931
20961
|
}
|
|
20932
20962
|
for (const line of lines.push(value)) {
|
|
20933
|
-
enqueueLine(line);
|
|
20963
|
+
await enqueueLine(line);
|
|
20934
20964
|
if (cancelled) {
|
|
20935
20965
|
return;
|
|
20936
20966
|
}
|
|
@@ -20941,7 +20971,7 @@ function ndJsonStream(output, input) {
|
|
|
20941
20971
|
}
|
|
20942
20972
|
const lastLine = lines.flush();
|
|
20943
20973
|
if (lastLine) {
|
|
20944
|
-
enqueueLine(lastLine);
|
|
20974
|
+
await enqueueLine(lastLine);
|
|
20945
20975
|
}
|
|
20946
20976
|
} catch (err) {
|
|
20947
20977
|
if (cancelled) {
|
|
@@ -20966,14 +20996,8 @@ function ndJsonStream(output, input) {
|
|
|
20966
20996
|
}
|
|
20967
20997
|
});
|
|
20968
20998
|
const writable = new WritableStream({
|
|
20969
|
-
|
|
20970
|
-
|
|
20971
|
-
const writer = output.getWriter();
|
|
20972
|
-
try {
|
|
20973
|
-
await writer.write(textEncoder.encode(content));
|
|
20974
|
-
} finally {
|
|
20975
|
-
writer.releaseLock();
|
|
20976
|
-
}
|
|
20999
|
+
write(message) {
|
|
21000
|
+
return writeJson(message);
|
|
20977
21001
|
}
|
|
20978
21002
|
});
|
|
20979
21003
|
return { readable, writable };
|
|
@@ -21592,11 +21616,11 @@ var clientRequestSpecs = {
|
|
|
21592
21616
|
releaseTerminal: requestSpec(CLIENT_METHODS.terminal_release, zReleaseTerminalRequest, emptyObjectResponse),
|
|
21593
21617
|
waitForTerminalExit: requestSpec(CLIENT_METHODS.terminal_wait_for_exit, zWaitForTerminalExitRequest),
|
|
21594
21618
|
killTerminal: requestSpec(CLIENT_METHODS.terminal_kill, zKillTerminalRequest, emptyObjectResponse),
|
|
21595
|
-
|
|
21619
|
+
createElicitation: requestSpec(CLIENT_METHODS.elicitation_create, zCreateElicitationRequest)
|
|
21596
21620
|
};
|
|
21597
21621
|
var clientNotificationSpecs = {
|
|
21598
21622
|
sessionUpdate: notificationSpec(CLIENT_METHODS.session_update, zSessionNotification),
|
|
21599
|
-
|
|
21623
|
+
completeElicitation: notificationSpec(CLIENT_METHODS.elicitation_complete, zCompleteElicitationNotification)
|
|
21600
21624
|
};
|
|
21601
21625
|
var agentRequestSpecsByMethod = specsByMethod(agentRequestSpecs);
|
|
21602
21626
|
var agentNotificationSpecsByMethod = specsByMethod(agentNotificationSpecs);
|
|
@@ -22021,7 +22045,12 @@ var Logger = class {
|
|
|
22021
22045
|
}
|
|
22022
22046
|
}
|
|
22023
22047
|
error(message, err) {
|
|
22024
|
-
|
|
22048
|
+
const formattedError = this.formatError(err);
|
|
22049
|
+
if (!this.logFilePath) {
|
|
22050
|
+
console.error(`[SYSTEM_ERROR] ${message}: ${formattedError}`);
|
|
22051
|
+
return;
|
|
22052
|
+
}
|
|
22053
|
+
this.log(`[SYSTEM_ERROR] ${message}`, { exception: formattedError });
|
|
22025
22054
|
}
|
|
22026
22055
|
log(message, context) {
|
|
22027
22056
|
if (!this.logFilePath) return;
|
|
@@ -22102,6 +22131,36 @@ function attachLogs(proc) {
|
|
|
22102
22131
|
});
|
|
22103
22132
|
}
|
|
22104
22133
|
|
|
22134
|
+
// src/AirExtension.ts
|
|
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
|
+
}
|
|
22160
|
+
function asSdkSessionNotification(notification) {
|
|
22161
|
+
return notification;
|
|
22162
|
+
}
|
|
22163
|
+
|
|
22105
22164
|
// src/ACPSessionConnection.ts
|
|
22106
22165
|
var ACPSessionConnection = class {
|
|
22107
22166
|
connection;
|
|
@@ -22110,11 +22169,11 @@ var ACPSessionConnection = class {
|
|
|
22110
22169
|
this.connection = connection;
|
|
22111
22170
|
this.sessionId = sessionId;
|
|
22112
22171
|
}
|
|
22113
|
-
async update(update) {
|
|
22114
|
-
await this.connection.notify(methods.client.session.update, {
|
|
22115
|
-
sessionId
|
|
22172
|
+
async update(update, sessionId = this.sessionId) {
|
|
22173
|
+
await this.connection.notify(methods.client.session.update, asSdkSessionNotification({
|
|
22174
|
+
sessionId,
|
|
22116
22175
|
update
|
|
22117
|
-
});
|
|
22176
|
+
}));
|
|
22118
22177
|
}
|
|
22119
22178
|
};
|
|
22120
22179
|
|
|
@@ -23248,13 +23307,13 @@ function createTerminalCommandEvent(event, terminalId, cwd) {
|
|
|
23248
23307
|
}
|
|
23249
23308
|
};
|
|
23250
23309
|
}
|
|
23251
|
-
function createSearchTitle(query,
|
|
23252
|
-
if (query &&
|
|
23253
|
-
return `Search for '${query}' in ${
|
|
23310
|
+
function createSearchTitle(query, path9) {
|
|
23311
|
+
if (query && path9) {
|
|
23312
|
+
return `Search for '${query}' in ${path9}`;
|
|
23254
23313
|
} else if (query) {
|
|
23255
23314
|
return `Search for '${query}'`;
|
|
23256
|
-
} else if (
|
|
23257
|
-
return `Search in '${
|
|
23315
|
+
} else if (path9) {
|
|
23316
|
+
return `Search in '${path9}'`;
|
|
23258
23317
|
}
|
|
23259
23318
|
return "Search";
|
|
23260
23319
|
}
|
|
@@ -23480,12 +23539,12 @@ function revertPatch(unifiedDiff) {
|
|
|
23480
23539
|
if (!patch) return null;
|
|
23481
23540
|
return reversePatch(patch);
|
|
23482
23541
|
}
|
|
23483
|
-
function createUpdateDiffContent(
|
|
23542
|
+
function createUpdateDiffContent(path9, oldText, newText) {
|
|
23484
23543
|
return {
|
|
23485
23544
|
type: "diff",
|
|
23486
23545
|
oldText,
|
|
23487
23546
|
newText,
|
|
23488
|
-
path:
|
|
23547
|
+
path: path9,
|
|
23489
23548
|
_meta: {
|
|
23490
23549
|
kind: "update"
|
|
23491
23550
|
}
|
|
@@ -23612,15 +23671,380 @@ function sameThreadGoalSnapshot(left, right) {
|
|
|
23612
23671
|
// src/CodexEventHandler.ts
|
|
23613
23672
|
import { randomUUID } from "node:crypto";
|
|
23614
23673
|
|
|
23615
|
-
// src/
|
|
23616
|
-
|
|
23617
|
-
|
|
23618
|
-
|
|
23619
|
-
|
|
23620
|
-
|
|
23621
|
-
|
|
23622
|
-
|
|
23623
|
-
|
|
23674
|
+
// src/subagents/CodexAgentPath.ts
|
|
23675
|
+
function normalizeAgentPath(path9) {
|
|
23676
|
+
const normalized = path9.trim().replace(/\/+$/, "");
|
|
23677
|
+
return normalized || "/root";
|
|
23678
|
+
}
|
|
23679
|
+
function isRootAgentPath(path9) {
|
|
23680
|
+
const normalized = normalizeAgentPath(path9);
|
|
23681
|
+
return normalized === "/root" || normalized === "root";
|
|
23682
|
+
}
|
|
23683
|
+
function nameFromAgentPath(path9, fallback) {
|
|
23684
|
+
const normalized = normalizeAgentPath(path9);
|
|
23685
|
+
const name = normalized.slice(normalized.lastIndexOf("/") + 1).trim();
|
|
23686
|
+
if (!name) return fallback;
|
|
23687
|
+
const words = name.replace(/[_-]+/g, " ").replace(/\s+/g, " ").trim();
|
|
23688
|
+
return words ? words.charAt(0).toUpperCase() + words.slice(1) : fallback;
|
|
23689
|
+
}
|
|
23690
|
+
|
|
23691
|
+
// src/subagents/CodexSubagentEventRouter.ts
|
|
23692
|
+
var CodexSubagentEventRouter = class _CodexSubagentEventRouter {
|
|
23693
|
+
constructor(rootSessionId, supported, session) {
|
|
23694
|
+
this.rootSessionId = rootSessionId;
|
|
23695
|
+
this.supported = supported;
|
|
23696
|
+
this.session = session;
|
|
23697
|
+
}
|
|
23698
|
+
rootSessionId;
|
|
23699
|
+
supported;
|
|
23700
|
+
session;
|
|
23701
|
+
static DEFAULT_WAIT_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
23702
|
+
static MAX_PENDING_NOTIFICATIONS = 256;
|
|
23703
|
+
children = /* @__PURE__ */ new Map();
|
|
23704
|
+
pendingSpawns = /* @__PURE__ */ new Map();
|
|
23705
|
+
terminalPendingSpawns = /* @__PURE__ */ new Map();
|
|
23706
|
+
waiters = /* @__PURE__ */ new Set();
|
|
23707
|
+
materializationWaiters = /* @__PURE__ */ new Map();
|
|
23708
|
+
replayQueue = [];
|
|
23709
|
+
activeLegacyActivities = /* @__PURE__ */ new Set();
|
|
23710
|
+
async handle(notification) {
|
|
23711
|
+
if (notification.method === "turn/started") {
|
|
23712
|
+
return this.isKnownChild(notification.params.threadId);
|
|
23713
|
+
}
|
|
23714
|
+
if (notification.method === "turn/completed") {
|
|
23715
|
+
const childTurn = this.isKnownChild(notification.params.threadId);
|
|
23716
|
+
const state = terminalStateFromTurn(notification.params.turn.status);
|
|
23717
|
+
if (!state) return childTurn;
|
|
23718
|
+
if (notification.params.threadId === this.rootSessionId) {
|
|
23719
|
+
if (state !== "completed") await this.finishOutstanding(state);
|
|
23720
|
+
} else {
|
|
23721
|
+
if (this.pendingSpawns.has(notification.params.threadId)) {
|
|
23722
|
+
this.finishPending(notification.params.threadId);
|
|
23723
|
+
} else {
|
|
23724
|
+
await this.finish(notification.params.threadId, state);
|
|
23725
|
+
}
|
|
23726
|
+
}
|
|
23727
|
+
return childTurn;
|
|
23728
|
+
}
|
|
23729
|
+
const notificationThreadId = notification.params.threadId;
|
|
23730
|
+
if (typeof notificationThreadId === "string" && this.pendingSpawns.has(notificationThreadId)) {
|
|
23731
|
+
const pending = this.pendingSpawns.get(notificationThreadId);
|
|
23732
|
+
if (pending.buffered.length === _CodexSubagentEventRouter.MAX_PENDING_NOTIFICATIONS) {
|
|
23733
|
+
pending.buffered.shift();
|
|
23734
|
+
pending.droppedBufferedNotifications += 1;
|
|
23735
|
+
if (pending.droppedBufferedNotifications === 1) {
|
|
23736
|
+
logger.log(`Pending subagent ${notificationThreadId} exceeded the notification buffer; dropping oldest updates`);
|
|
23737
|
+
}
|
|
23738
|
+
}
|
|
23739
|
+
pending.buffered.push(notification);
|
|
23740
|
+
return true;
|
|
23741
|
+
}
|
|
23742
|
+
if (notification.method !== "item/started" && notification.method !== "item/completed") {
|
|
23743
|
+
return false;
|
|
23744
|
+
}
|
|
23745
|
+
const item = notification.params.item;
|
|
23746
|
+
if (!this.supported) {
|
|
23747
|
+
return false;
|
|
23748
|
+
}
|
|
23749
|
+
if (item.type === "subAgentActivity") {
|
|
23750
|
+
if (isRootAgentPath(item.agentPath)) return true;
|
|
23751
|
+
if (this.terminalPendingSpawns.has(item.agentThreadId)) return true;
|
|
23752
|
+
let hasNativeRepresentation = this.children.has(item.agentThreadId);
|
|
23753
|
+
if (!hasNativeRepresentation) {
|
|
23754
|
+
await this.materialize(item.agentThreadId, item.agentPath);
|
|
23755
|
+
hasNativeRepresentation = this.children.has(item.agentThreadId);
|
|
23756
|
+
}
|
|
23757
|
+
if (hasNativeRepresentation && item.kind === "interrupted") {
|
|
23758
|
+
await this.finish(item.agentThreadId, "cancelled");
|
|
23759
|
+
}
|
|
23760
|
+
return hasNativeRepresentation;
|
|
23761
|
+
}
|
|
23762
|
+
if (item.type !== "collabAgentToolCall") return false;
|
|
23763
|
+
if (item.tool === "resumeAgent" || item.tool === "sendInput") {
|
|
23764
|
+
for (const [childThreadId, state] of Object.entries(item.agentsStates)) {
|
|
23765
|
+
if (state?.status === "running" || state?.status === "pendingInit") {
|
|
23766
|
+
await this.reopen(childThreadId);
|
|
23767
|
+
}
|
|
23768
|
+
}
|
|
23769
|
+
}
|
|
23770
|
+
let representedSpawn = false;
|
|
23771
|
+
if (item.tool === "spawnAgent") {
|
|
23772
|
+
const parent = this.children.get(item.senderThreadId);
|
|
23773
|
+
const parentThreadId = parent ? item.senderThreadId : this.rootSessionId;
|
|
23774
|
+
const parentSessionId = parent?.sessionId ?? this.rootSessionId;
|
|
23775
|
+
for (const childSessionId of item.receiverThreadIds) {
|
|
23776
|
+
if (childSessionId.trim().length === 0) {
|
|
23777
|
+
logger.log("Ignoring spawned subagent with an empty thread id");
|
|
23778
|
+
continue;
|
|
23779
|
+
}
|
|
23780
|
+
if (childSessionId === parentSessionId || childSessionId === this.rootSessionId) {
|
|
23781
|
+
logger.log(`Ignoring self-referential spawned subagent ${childSessionId}`);
|
|
23782
|
+
continue;
|
|
23783
|
+
}
|
|
23784
|
+
if (this.children.has(childSessionId) || this.pendingSpawns.has(childSessionId) || this.terminalPendingSpawns.has(childSessionId)) {
|
|
23785
|
+
representedSpawn = true;
|
|
23786
|
+
continue;
|
|
23787
|
+
}
|
|
23788
|
+
this.pendingSpawns.set(childSessionId, {
|
|
23789
|
+
parentThreadId,
|
|
23790
|
+
parentSessionId,
|
|
23791
|
+
task: item.prompt?.trim() || "Delegated task",
|
|
23792
|
+
buffered: [],
|
|
23793
|
+
droppedBufferedNotifications: 0
|
|
23794
|
+
});
|
|
23795
|
+
representedSpawn = true;
|
|
23796
|
+
}
|
|
23797
|
+
}
|
|
23798
|
+
for (const [childSessionId, state] of Object.entries(item.agentsStates)) {
|
|
23799
|
+
const terminalState = state && terminalStateOf(state.status);
|
|
23800
|
+
if (!terminalState) continue;
|
|
23801
|
+
if (this.children.has(childSessionId)) await this.finish(childSessionId, terminalState);
|
|
23802
|
+
else if (this.pendingSpawns.has(childSessionId)) this.finishPending(childSessionId);
|
|
23803
|
+
}
|
|
23804
|
+
if (item.tool === "spawnAgent" && item.status === "failed") {
|
|
23805
|
+
for (const childSessionId of item.receiverThreadIds) {
|
|
23806
|
+
if (this.pendingSpawns.has(childSessionId)) this.finishPending(childSessionId);
|
|
23807
|
+
}
|
|
23808
|
+
}
|
|
23809
|
+
return item.tool === "spawnAgent" && representedSpawn;
|
|
23810
|
+
}
|
|
23811
|
+
shouldIgnore(notification) {
|
|
23812
|
+
const threadId = notification.params.threadId;
|
|
23813
|
+
const ignored = typeof threadId === "string" && (this.children.get(threadId)?.terminalState !== void 0 || this.terminalPendingSpawns.has(threadId));
|
|
23814
|
+
if (ignored) logger.log(`Ignoring update for terminal subagent ${threadId}`);
|
|
23815
|
+
return ignored;
|
|
23816
|
+
}
|
|
23817
|
+
notificationSessionId(notification) {
|
|
23818
|
+
const threadId = notification.params.threadId;
|
|
23819
|
+
return typeof threadId === "string" && this.children.has(threadId) ? this.children.get(threadId).sessionId : this.rootSessionId;
|
|
23820
|
+
}
|
|
23821
|
+
takeBufferedNotifications() {
|
|
23822
|
+
return this.replayQueue.splice(0);
|
|
23823
|
+
}
|
|
23824
|
+
async waitForMaterializedSession(childThreadId) {
|
|
23825
|
+
const child = this.children.get(childThreadId);
|
|
23826
|
+
if (child) return child.terminalState === void 0 ? child.sessionId : null;
|
|
23827
|
+
if (this.terminalPendingSpawns.has(childThreadId)) return null;
|
|
23828
|
+
if (!this.pendingSpawns.has(childThreadId)) return null;
|
|
23829
|
+
return await new Promise((resolve) => {
|
|
23830
|
+
const waiters = this.materializationWaiters.get(childThreadId) ?? /* @__PURE__ */ new Set();
|
|
23831
|
+
waiters.add(resolve);
|
|
23832
|
+
this.materializationWaiters.set(childThreadId, waiters);
|
|
23833
|
+
});
|
|
23834
|
+
}
|
|
23835
|
+
legacyActivityStarted(item) {
|
|
23836
|
+
this.activeLegacyActivities.add(item.id);
|
|
23837
|
+
return createSubAgentActivityUpdate(item, "in_progress", "tool_call");
|
|
23838
|
+
}
|
|
23839
|
+
legacyCollaborationStarted(item) {
|
|
23840
|
+
return createCollabAgentToolCallUpdate(item);
|
|
23841
|
+
}
|
|
23842
|
+
legacyCollaborationCompleted(item) {
|
|
23843
|
+
return createCollabAgentToolCallCompleteUpdate(item);
|
|
23844
|
+
}
|
|
23845
|
+
legacyActivityCompleted(item) {
|
|
23846
|
+
const sessionUpdate = this.activeLegacyActivities.delete(item.id) ? "tool_call_update" : "tool_call";
|
|
23847
|
+
return createSubAgentActivityUpdate(item, "completed", sessionUpdate);
|
|
23848
|
+
}
|
|
23849
|
+
async wait(signal, timeoutMs = _CodexSubagentEventRouter.DEFAULT_WAIT_TIMEOUT_MS) {
|
|
23850
|
+
const deadline = Date.now() + timeoutMs;
|
|
23851
|
+
while (this.hasOutstanding()) {
|
|
23852
|
+
if (signal.aborted) return;
|
|
23853
|
+
const remainingMs = deadline - Date.now();
|
|
23854
|
+
if (remainingMs <= 0) {
|
|
23855
|
+
logger.log(`Timed out waiting for subagents in session ${this.rootSessionId}; marking them failed`);
|
|
23856
|
+
await this.finishOutstanding("failed");
|
|
23857
|
+
return;
|
|
23858
|
+
}
|
|
23859
|
+
const changed = await new Promise((resolve) => {
|
|
23860
|
+
const timeout = setTimeout(() => {
|
|
23861
|
+
this.waiters.delete(onChange);
|
|
23862
|
+
signal.removeEventListener("abort", onAbort);
|
|
23863
|
+
resolve(false);
|
|
23864
|
+
}, remainingMs);
|
|
23865
|
+
const onAbort = () => {
|
|
23866
|
+
clearTimeout(timeout);
|
|
23867
|
+
this.waiters.delete(onChange);
|
|
23868
|
+
resolve(true);
|
|
23869
|
+
};
|
|
23870
|
+
const onChange = () => {
|
|
23871
|
+
clearTimeout(timeout);
|
|
23872
|
+
signal.removeEventListener("abort", onAbort);
|
|
23873
|
+
resolve(true);
|
|
23874
|
+
};
|
|
23875
|
+
this.waiters.add(onChange);
|
|
23876
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
23877
|
+
});
|
|
23878
|
+
if (!changed) {
|
|
23879
|
+
logger.log(`Timed out waiting for subagents in session ${this.rootSessionId}; marking them failed`);
|
|
23880
|
+
await this.finishOutstanding("failed");
|
|
23881
|
+
return;
|
|
23882
|
+
}
|
|
23883
|
+
}
|
|
23884
|
+
}
|
|
23885
|
+
async finishOutstanding(state) {
|
|
23886
|
+
for (const childSessionId of [...this.pendingSpawns.keys()]) {
|
|
23887
|
+
this.finishPending(childSessionId);
|
|
23888
|
+
}
|
|
23889
|
+
for (const childSessionId of [...this.children.keys()].reverse()) {
|
|
23890
|
+
await this.finish(childSessionId, state);
|
|
23891
|
+
}
|
|
23892
|
+
}
|
|
23893
|
+
isKnownChild(threadId) {
|
|
23894
|
+
return threadId !== this.rootSessionId && (this.children.has(threadId) || this.pendingSpawns.has(threadId) || this.terminalPendingSpawns.has(threadId));
|
|
23895
|
+
}
|
|
23896
|
+
async materialize(childSessionId, path9) {
|
|
23897
|
+
if (this.children.has(childSessionId)) return;
|
|
23898
|
+
const pending = this.pendingSpawns.get(childSessionId);
|
|
23899
|
+
const name = nameFromAgentPath(path9, fallbackName(childSessionId));
|
|
23900
|
+
const inferredParent = this.parentForPath(path9);
|
|
23901
|
+
const parentThreadId = pending?.parentThreadId ?? inferredParent.threadId;
|
|
23902
|
+
const parentSessionId = pending?.parentSessionId ?? inferredParent.sessionId;
|
|
23903
|
+
const task = pending?.task ?? `Delegated task for ${name}`;
|
|
23904
|
+
await this.session.update({
|
|
23905
|
+
sessionUpdate: "subagent_spawned",
|
|
23906
|
+
subagentSessionId: childSessionId,
|
|
23907
|
+
name,
|
|
23908
|
+
task,
|
|
23909
|
+
capabilities: {}
|
|
23910
|
+
}, parentSessionId);
|
|
23911
|
+
this.children.set(childSessionId, {
|
|
23912
|
+
parentThreadId,
|
|
23913
|
+
parentSessionId,
|
|
23914
|
+
sessionId: childSessionId,
|
|
23915
|
+
name,
|
|
23916
|
+
task,
|
|
23917
|
+
path: normalizeAgentPath(path9),
|
|
23918
|
+
generation: 1
|
|
23919
|
+
});
|
|
23920
|
+
this.pendingSpawns.delete(childSessionId);
|
|
23921
|
+
this.replayQueue.push(...pending?.buffered ?? []);
|
|
23922
|
+
this.resolveMaterialization(childSessionId, childSessionId);
|
|
23923
|
+
}
|
|
23924
|
+
finishPending(childSessionId) {
|
|
23925
|
+
const pending = this.pendingSpawns.get(childSessionId);
|
|
23926
|
+
if (!pending) return;
|
|
23927
|
+
this.pendingSpawns.delete(childSessionId);
|
|
23928
|
+
this.terminalPendingSpawns.set(childSessionId, pending);
|
|
23929
|
+
this.resolveMaterialization(childSessionId, null);
|
|
23930
|
+
this.notifyWaiters();
|
|
23931
|
+
}
|
|
23932
|
+
async finish(childSessionId, state) {
|
|
23933
|
+
const child = this.children.get(childSessionId);
|
|
23934
|
+
if (!child || child.terminalState !== void 0) return;
|
|
23935
|
+
child.terminalState = state;
|
|
23936
|
+
try {
|
|
23937
|
+
await this.session.update({
|
|
23938
|
+
sessionUpdate: "subagent_state_update",
|
|
23939
|
+
subagentSessionId: child.sessionId,
|
|
23940
|
+
state
|
|
23941
|
+
}, child.parentSessionId);
|
|
23942
|
+
} catch (error51) {
|
|
23943
|
+
if (child.terminalState === state) delete child.terminalState;
|
|
23944
|
+
throw error51;
|
|
23945
|
+
}
|
|
23946
|
+
this.notifyWaiters();
|
|
23947
|
+
}
|
|
23948
|
+
async reopen(childThreadId) {
|
|
23949
|
+
const child = this.children.get(childThreadId);
|
|
23950
|
+
if (!child) {
|
|
23951
|
+
const pending = this.terminalPendingSpawns.get(childThreadId);
|
|
23952
|
+
if (!pending) return;
|
|
23953
|
+
const parentSessionId = this.children.get(pending.parentThreadId)?.sessionId ?? this.rootSessionId;
|
|
23954
|
+
const reopened = {
|
|
23955
|
+
parentThreadId: pending.parentThreadId,
|
|
23956
|
+
parentSessionId,
|
|
23957
|
+
sessionId: `${childThreadId}:generation:2`,
|
|
23958
|
+
name: fallbackName(childThreadId),
|
|
23959
|
+
task: pending.task,
|
|
23960
|
+
generation: 2
|
|
23961
|
+
};
|
|
23962
|
+
await this.session.update({
|
|
23963
|
+
sessionUpdate: "subagent_spawned",
|
|
23964
|
+
subagentSessionId: reopened.sessionId,
|
|
23965
|
+
name: reopened.name,
|
|
23966
|
+
task: reopened.task,
|
|
23967
|
+
capabilities: {}
|
|
23968
|
+
}, parentSessionId);
|
|
23969
|
+
this.children.set(childThreadId, reopened);
|
|
23970
|
+
this.terminalPendingSpawns.delete(childThreadId);
|
|
23971
|
+
return;
|
|
23972
|
+
}
|
|
23973
|
+
if (!child.terminalState) return;
|
|
23974
|
+
const previousSessionId = child.sessionId;
|
|
23975
|
+
const previousParentSessionId = child.parentSessionId;
|
|
23976
|
+
const previousState = child.terminalState;
|
|
23977
|
+
child.parentSessionId = this.children.get(child.parentThreadId)?.sessionId ?? this.rootSessionId;
|
|
23978
|
+
child.generation += 1;
|
|
23979
|
+
child.sessionId = `${childThreadId}:generation:${child.generation}`;
|
|
23980
|
+
delete child.terminalState;
|
|
23981
|
+
try {
|
|
23982
|
+
await this.session.update({
|
|
23983
|
+
sessionUpdate: "subagent_spawned",
|
|
23984
|
+
subagentSessionId: child.sessionId,
|
|
23985
|
+
name: child.name,
|
|
23986
|
+
task: child.task,
|
|
23987
|
+
capabilities: {}
|
|
23988
|
+
}, child.parentSessionId);
|
|
23989
|
+
} catch (error51) {
|
|
23990
|
+
child.generation -= 1;
|
|
23991
|
+
child.sessionId = previousSessionId;
|
|
23992
|
+
child.parentSessionId = previousParentSessionId;
|
|
23993
|
+
child.terminalState = previousState;
|
|
23994
|
+
throw error51;
|
|
23995
|
+
}
|
|
23996
|
+
}
|
|
23997
|
+
resolveMaterialization(childThreadId, sessionId) {
|
|
23998
|
+
for (const resolve of this.materializationWaiters.get(childThreadId) ?? []) resolve(sessionId);
|
|
23999
|
+
this.materializationWaiters.delete(childThreadId);
|
|
24000
|
+
}
|
|
24001
|
+
hasOutstanding() {
|
|
24002
|
+
return this.pendingSpawns.size > 0 || [...this.children.values()].some((child) => child.terminalState === void 0);
|
|
24003
|
+
}
|
|
24004
|
+
notifyWaiters() {
|
|
24005
|
+
for (const waiter of this.waiters) waiter();
|
|
24006
|
+
this.waiters.clear();
|
|
24007
|
+
}
|
|
24008
|
+
parentForPath(path9) {
|
|
24009
|
+
const normalized = normalizeAgentPath(path9);
|
|
24010
|
+
const separator = normalized.lastIndexOf("/");
|
|
24011
|
+
if (separator <= 0) return { threadId: this.rootSessionId, sessionId: this.rootSessionId };
|
|
24012
|
+
const parentPath = normalized.slice(0, separator);
|
|
24013
|
+
const parent = [...this.children.entries()].find(([, child]) => child.path === parentPath);
|
|
24014
|
+
return parent ? { threadId: parent[0], sessionId: parent[1].sessionId } : { threadId: this.rootSessionId, sessionId: this.rootSessionId };
|
|
24015
|
+
}
|
|
24016
|
+
};
|
|
24017
|
+
function terminalStateOf(status) {
|
|
24018
|
+
switch (status) {
|
|
24019
|
+
case "completed":
|
|
24020
|
+
return "completed";
|
|
24021
|
+
case "interrupted":
|
|
24022
|
+
return "cancelled";
|
|
24023
|
+
case "errored":
|
|
24024
|
+
case "shutdown":
|
|
24025
|
+
case "notFound":
|
|
24026
|
+
return "failed";
|
|
24027
|
+
case "pendingInit":
|
|
24028
|
+
case "running":
|
|
24029
|
+
return void 0;
|
|
24030
|
+
}
|
|
24031
|
+
}
|
|
24032
|
+
function terminalStateFromTurn(status) {
|
|
24033
|
+
switch (status) {
|
|
24034
|
+
case "completed":
|
|
24035
|
+
return "completed";
|
|
24036
|
+
case "interrupted":
|
|
24037
|
+
return "cancelled";
|
|
24038
|
+
case "failed":
|
|
24039
|
+
return "failed";
|
|
24040
|
+
case "inProgress":
|
|
24041
|
+
return void 0;
|
|
24042
|
+
}
|
|
24043
|
+
}
|
|
24044
|
+
function fallbackName(sessionId) {
|
|
24045
|
+
const suffix = sessionId.length > 8 ? sessionId.slice(-8) : sessionId;
|
|
24046
|
+
return `Agent ${suffix}`;
|
|
24047
|
+
}
|
|
23624
24048
|
|
|
23625
24049
|
// src/CodexEventHandler.ts
|
|
23626
24050
|
var MAX_SESSION_FAILURE_TITLE_LENGTH = 240;
|
|
@@ -23728,13 +24152,18 @@ var CodexEventHandler = class _CodexEventHandler {
|
|
|
23728
24152
|
terminalCommandIds = /* @__PURE__ */ new Set();
|
|
23729
24153
|
terminalCommandOutputIds = /* @__PURE__ */ new Set();
|
|
23730
24154
|
agentMessagePhases = /* @__PURE__ */ new Map();
|
|
23731
|
-
|
|
23732
|
-
constructor(connection, sessionState, supportsPlanUpdates = false, supportsTypedSessionFailures = false, sessionFailureEpoch = randomUUID()
|
|
24155
|
+
subagents;
|
|
24156
|
+
constructor(connection, sessionState, supportsPlanUpdates = false, supportsTypedSessionFailures = false, sessionFailureEpoch = randomUUID(), subagents = new CodexSubagentEventRouter(
|
|
24157
|
+
sessionState.sessionId,
|
|
24158
|
+
false,
|
|
24159
|
+
new ACPSessionConnection(connection, sessionState.sessionId)
|
|
24160
|
+
)) {
|
|
23733
24161
|
this.sessionState = sessionState;
|
|
23734
24162
|
this.supportsPlanUpdates = supportsPlanUpdates;
|
|
23735
24163
|
this.supportsTypedSessionFailures = supportsTypedSessionFailures;
|
|
23736
24164
|
this.sessionFailureEpoch = sessionFailureEpoch;
|
|
23737
24165
|
this.session = new ACPSessionConnection(connection, sessionState.sessionId);
|
|
24166
|
+
this.subagents = subagents;
|
|
23738
24167
|
if (sessionState.sessionFailure !== void 0) {
|
|
23739
24168
|
this.failuresById.set(sessionState.sessionFailure.id, sessionState.sessionFailure);
|
|
23740
24169
|
}
|
|
@@ -23836,11 +24265,30 @@ var CodexEventHandler = class _CodexEventHandler {
|
|
|
23836
24265
|
}
|
|
23837
24266
|
async handleNotification(notification) {
|
|
23838
24267
|
await this.flushPendingErrors();
|
|
24268
|
+
const handledBySubagents = await this.subagents.handle(notification);
|
|
24269
|
+
for (const buffered of this.subagents.takeBufferedNotifications()) {
|
|
24270
|
+
await this.handleNotification(buffered);
|
|
24271
|
+
}
|
|
24272
|
+
if (handledBySubagents) {
|
|
24273
|
+
return;
|
|
24274
|
+
}
|
|
24275
|
+
if (this.subagents.shouldIgnore(notification)) {
|
|
24276
|
+
return;
|
|
24277
|
+
}
|
|
23839
24278
|
const updateEvent = await this.createUpdateEvent(notification);
|
|
23840
24279
|
if (updateEvent) {
|
|
23841
|
-
await this.session.update(updateEvent);
|
|
24280
|
+
await this.session.update(updateEvent, this.subagents.notificationSessionId(notification));
|
|
23842
24281
|
}
|
|
23843
24282
|
}
|
|
24283
|
+
async waitForNativeSubagentSession(childThreadId) {
|
|
24284
|
+
return await this.subagents.waitForMaterializedSession(childThreadId);
|
|
24285
|
+
}
|
|
24286
|
+
async waitForNativeSubagents(signal) {
|
|
24287
|
+
await this.subagents.wait(signal);
|
|
24288
|
+
}
|
|
24289
|
+
async finishOutstandingNativeSubagents(state) {
|
|
24290
|
+
await this.subagents.finishOutstanding(state);
|
|
24291
|
+
}
|
|
23844
24292
|
async flushPendingPlanUpdates() {
|
|
23845
24293
|
this.cancelPlanUpdateTimer();
|
|
23846
24294
|
do {
|
|
@@ -24132,15 +24580,14 @@ ${event.details}` : event.summary;
|
|
|
24132
24580
|
this.activeImageGenerationItems.add(event.item.id);
|
|
24133
24581
|
return createImageGenerationStartUpdate(event.item);
|
|
24134
24582
|
case "collabAgentToolCall":
|
|
24135
|
-
return
|
|
24583
|
+
return this.subagents.legacyCollaborationStarted(event.item);
|
|
24136
24584
|
case "agentMessage":
|
|
24137
24585
|
this.rememberAgentMessagePhase(event.item);
|
|
24138
24586
|
return null;
|
|
24139
24587
|
case "contextCompaction":
|
|
24140
24588
|
return createContextCompactionStartUpdate(event.item);
|
|
24141
24589
|
case "subAgentActivity":
|
|
24142
|
-
this.
|
|
24143
|
-
return createSubAgentActivityUpdate(event.item, "in_progress", "tool_call");
|
|
24590
|
+
return this.subagents.legacyActivityStarted(event.item);
|
|
24144
24591
|
case "sleep":
|
|
24145
24592
|
case "userMessage":
|
|
24146
24593
|
case "hookPrompt":
|
|
@@ -24188,7 +24635,7 @@ ${event.details}` : event.summary;
|
|
|
24188
24635
|
case "webSearch":
|
|
24189
24636
|
return createWebSearchCompleteUpdate(event.item);
|
|
24190
24637
|
case "collabAgentToolCall":
|
|
24191
|
-
return
|
|
24638
|
+
return this.subagents.legacyCollaborationCompleted(event.item);
|
|
24192
24639
|
case "agentMessage":
|
|
24193
24640
|
this.rememberAgentMessagePhase(event.item);
|
|
24194
24641
|
return null;
|
|
@@ -24201,10 +24648,8 @@ ${event.details}` : event.summary;
|
|
|
24201
24648
|
case "contextCompaction":
|
|
24202
24649
|
return createContextCompactionCompleteUpdate(event.item);
|
|
24203
24650
|
//ignored types
|
|
24204
|
-
case "subAgentActivity":
|
|
24205
|
-
|
|
24206
|
-
return createSubAgentActivityUpdate(event.item, "completed", sessionUpdate);
|
|
24207
|
-
}
|
|
24651
|
+
case "subAgentActivity":
|
|
24652
|
+
return this.subagents.legacyActivityCompleted(event.item);
|
|
24208
24653
|
case "sleep":
|
|
24209
24654
|
case "userMessage":
|
|
24210
24655
|
case "hookPrompt":
|
|
@@ -24653,343 +25098,545 @@ ${event.stdin}
|
|
|
24653
25098
|
}
|
|
24654
25099
|
};
|
|
24655
25100
|
|
|
24656
|
-
// src/
|
|
25101
|
+
// src/permissions/option-ids.ts
|
|
24657
25102
|
var ApprovalOptionId = {
|
|
24658
25103
|
AllowOnce: "allow_once",
|
|
24659
|
-
|
|
24660
|
-
|
|
25104
|
+
AllowForSession: "allow_for_session",
|
|
25105
|
+
Decline: "decline",
|
|
25106
|
+
Cancel: "cancel",
|
|
24661
25107
|
AcceptWithExecpolicyAmendment: "accept_execpolicy_amendment",
|
|
24662
25108
|
ApplyNetworkPolicyAmendment: "apply_network_policy_amendment",
|
|
24663
25109
|
AllowPermissionsForTurn: "allow_permissions_turn",
|
|
25110
|
+
AllowPermissionsForTurnWithStrictAutoReview: "allow_permissions_turn_strict_auto_review",
|
|
24664
25111
|
AllowPermissionsForSession: "allow_permissions_session",
|
|
24665
25112
|
RejectPermissions: "reject_permissions"
|
|
24666
25113
|
};
|
|
25114
|
+
var McpApprovalOptionId = {
|
|
25115
|
+
AllowOnce: "allow_once",
|
|
25116
|
+
AllowSession: "allow_session",
|
|
25117
|
+
AllowAlways: "allow_always",
|
|
25118
|
+
Decline: "decline",
|
|
25119
|
+
Cancel: "cancel"
|
|
25120
|
+
};
|
|
24667
25121
|
|
|
24668
|
-
// src/
|
|
24669
|
-
function
|
|
24670
|
-
return
|
|
24671
|
-
optionId,
|
|
24672
|
-
name,
|
|
24673
|
-
kind,
|
|
24674
|
-
...codexMeta || permission ? {
|
|
24675
|
-
_meta: {
|
|
24676
|
-
...permission ? { permission } : {},
|
|
24677
|
-
...codexMeta ? { codex: codexMeta } : {}
|
|
24678
|
-
}
|
|
24679
|
-
} : {}
|
|
24680
|
-
};
|
|
25122
|
+
// src/permissions/json.ts
|
|
25123
|
+
function isRecord2(value) {
|
|
25124
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
24681
25125
|
}
|
|
24682
|
-
|
|
24683
|
-
|
|
24684
|
-
|
|
24685
|
-
|
|
24686
|
-
|
|
24687
|
-
|
|
24688
|
-
|
|
24689
|
-
|
|
25126
|
+
function recordOrNull(value) {
|
|
25127
|
+
return isRecord2(value) ? value : null;
|
|
25128
|
+
}
|
|
25129
|
+
function normalizeJsonValue(value) {
|
|
25130
|
+
if (value === null || value === void 0) return null;
|
|
25131
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return value;
|
|
25132
|
+
if (typeof value === "bigint") return Number(value);
|
|
25133
|
+
if (Array.isArray(value)) return value.map(normalizeJsonValue);
|
|
25134
|
+
if (typeof value === "object") {
|
|
25135
|
+
return Object.fromEntries(
|
|
25136
|
+
Object.entries(value).filter(([, nested]) => nested !== void 0).map(([key, nested]) => [key, normalizeJsonValue(nested)])
|
|
25137
|
+
);
|
|
24690
25138
|
}
|
|
24691
|
-
|
|
24692
|
-
|
|
24693
|
-
|
|
24694
|
-
|
|
24695
|
-
|
|
24696
|
-
|
|
24697
|
-
|
|
24698
|
-
|
|
24699
|
-
|
|
24700
|
-
|
|
24701
|
-
|
|
24702
|
-
|
|
24703
|
-
|
|
24704
|
-
|
|
25139
|
+
return String(value);
|
|
25140
|
+
}
|
|
25141
|
+
function normalizeJsonObject(value) {
|
|
25142
|
+
return Object.fromEntries(
|
|
25143
|
+
Object.entries(value).filter(([, nested]) => nested !== void 0).map(([key, nested]) => [key, normalizeJsonValue(nested)])
|
|
25144
|
+
);
|
|
25145
|
+
}
|
|
25146
|
+
|
|
25147
|
+
// src/permissions/command-decision-contract.ts
|
|
25148
|
+
function parseAvailableCommandDecisions(params) {
|
|
25149
|
+
if (params.availableDecisions === void 0 || params.availableDecisions === null) {
|
|
25150
|
+
return defaultCommandDecisions(params);
|
|
25151
|
+
}
|
|
25152
|
+
if (!Array.isArray(params.availableDecisions) || params.availableDecisions.length === 0) return void 0;
|
|
25153
|
+
const decisions = [];
|
|
25154
|
+
for (const candidate of params.availableDecisions) {
|
|
25155
|
+
const decision = parseCommandDecision(candidate, params);
|
|
25156
|
+
if (!decision) return void 0;
|
|
25157
|
+
decisions.push(decision);
|
|
25158
|
+
}
|
|
25159
|
+
return decisions;
|
|
25160
|
+
}
|
|
25161
|
+
function defaultCommandDecisions(params) {
|
|
25162
|
+
if (params.networkApprovalContext) {
|
|
25163
|
+
const decisions2 = ["accept", "acceptForSession"];
|
|
25164
|
+
for (const amendment of params.proposedNetworkPolicyAmendments ?? []) {
|
|
25165
|
+
decisions2.push({ applyNetworkPolicyAmendment: { network_policy_amendment: amendment } });
|
|
25166
|
+
}
|
|
25167
|
+
decisions2.push("decline", "cancel");
|
|
25168
|
+
return decisions2;
|
|
25169
|
+
}
|
|
25170
|
+
if (params.additionalPermissions) return ["accept", "cancel"];
|
|
25171
|
+
const decisions = ["accept", "acceptForSession"];
|
|
25172
|
+
if (params.proposedExecpolicyAmendment && params.proposedExecpolicyAmendment.length > 0) {
|
|
25173
|
+
decisions.push({
|
|
25174
|
+
acceptWithExecpolicyAmendment: { execpolicy_amendment: params.proposedExecpolicyAmendment }
|
|
25175
|
+
});
|
|
24705
25176
|
}
|
|
24706
|
-
|
|
24707
|
-
|
|
24708
|
-
|
|
24709
|
-
|
|
24710
|
-
|
|
24711
|
-
|
|
24712
|
-
|
|
24713
|
-
|
|
24714
|
-
|
|
24715
|
-
|
|
24716
|
-
|
|
24717
|
-
|
|
24718
|
-
|
|
25177
|
+
decisions.push("decline", "cancel");
|
|
25178
|
+
return decisions;
|
|
25179
|
+
}
|
|
25180
|
+
function parseCommandDecision(candidate, params) {
|
|
25181
|
+
if (candidate === "accept" || candidate === "acceptForSession" || candidate === "decline" || candidate === "cancel") {
|
|
25182
|
+
return candidate;
|
|
25183
|
+
}
|
|
25184
|
+
if (!isRecord2(candidate)) return void 0;
|
|
25185
|
+
if ("acceptWithExecpolicyAmendment" in candidate) {
|
|
25186
|
+
const value = candidate["acceptWithExecpolicyAmendment"];
|
|
25187
|
+
if (!isRecord2(value)) return void 0;
|
|
25188
|
+
const amendment = value["execpolicy_amendment"];
|
|
25189
|
+
if (!isStringArray(amendment) || amendment.length === 0) return void 0;
|
|
25190
|
+
if (!sameStrings(amendment, params.proposedExecpolicyAmendment)) return void 0;
|
|
25191
|
+
return { acceptWithExecpolicyAmendment: { execpolicy_amendment: [...amendment] } };
|
|
25192
|
+
}
|
|
25193
|
+
if ("applyNetworkPolicyAmendment" in candidate) {
|
|
25194
|
+
const value = candidate["applyNetworkPolicyAmendment"];
|
|
25195
|
+
if (!isRecord2(value)) return void 0;
|
|
25196
|
+
const amendment = parseNetworkAmendment(value["network_policy_amendment"]);
|
|
25197
|
+
if (!amendment || !params.networkApprovalContext) return void 0;
|
|
25198
|
+
if (amendment.host !== params.networkApprovalContext.host) return void 0;
|
|
25199
|
+
if (!(params.proposedNetworkPolicyAmendments ?? []).some((proposed) => sameNetworkAmendment(proposed, amendment))) {
|
|
25200
|
+
return void 0;
|
|
24719
25201
|
}
|
|
25202
|
+
return { applyNetworkPolicyAmendment: { network_policy_amendment: amendment } };
|
|
24720
25203
|
}
|
|
24721
|
-
|
|
24722
|
-
|
|
24723
|
-
|
|
24724
|
-
|
|
24725
|
-
|
|
24726
|
-
|
|
24727
|
-
|
|
24728
|
-
|
|
24729
|
-
|
|
24730
|
-
|
|
24731
|
-
|
|
24732
|
-
|
|
24733
|
-
|
|
25204
|
+
return void 0;
|
|
25205
|
+
}
|
|
25206
|
+
function parseNetworkAmendment(value) {
|
|
25207
|
+
if (!isRecord2(value) || typeof value["host"] !== "string") return void 0;
|
|
25208
|
+
const action = value["action"];
|
|
25209
|
+
if (action !== "allow" && action !== "deny") return void 0;
|
|
25210
|
+
return { host: value["host"], action };
|
|
25211
|
+
}
|
|
25212
|
+
function isStringArray(value) {
|
|
25213
|
+
return Array.isArray(value) && value.every((entry) => typeof entry === "string");
|
|
25214
|
+
}
|
|
25215
|
+
function sameStrings(left, right) {
|
|
25216
|
+
return !!right && left.length === right.length && left.every((value, index) => value === right[index]);
|
|
25217
|
+
}
|
|
25218
|
+
function sameNetworkAmendment(left, right) {
|
|
25219
|
+
return left.host === right.host && left.action === right.action;
|
|
25220
|
+
}
|
|
25221
|
+
|
|
25222
|
+
// src/permissions/options.ts
|
|
25223
|
+
function commandDecisionOptions(params) {
|
|
25224
|
+
const decisions = parseAvailableCommandDecisions(params);
|
|
25225
|
+
if (!decisions) return void 0;
|
|
25226
|
+
const options = [];
|
|
25227
|
+
let networkIndex = 0;
|
|
25228
|
+
for (const decision of decisions) {
|
|
25229
|
+
if (decision === "accept") {
|
|
25230
|
+
options.push(decisionOption(
|
|
25231
|
+
ApprovalOptionId.AllowOnce,
|
|
25232
|
+
params.networkApprovalContext ? "Yes, just this once" : "Yes, proceed",
|
|
25233
|
+
"allow_once",
|
|
25234
|
+
decision
|
|
25235
|
+
));
|
|
25236
|
+
} else if (decision === "acceptForSession") {
|
|
25237
|
+
options.push(decisionOption(
|
|
25238
|
+
ApprovalOptionId.AllowForSession,
|
|
25239
|
+
params.networkApprovalContext ? "Yes, and allow this host for this conversation" : params.additionalPermissions ? "Yes, and allow these permissions for this session" : "Yes, and don't ask again for this command in this session",
|
|
25240
|
+
"allow_always",
|
|
25241
|
+
decision
|
|
25242
|
+
));
|
|
25243
|
+
} else if (decision === "decline") {
|
|
25244
|
+
options.push(decisionOption(
|
|
25245
|
+
ApprovalOptionId.Decline,
|
|
25246
|
+
"No, continue without running it",
|
|
25247
|
+
"reject_once",
|
|
25248
|
+
decision
|
|
25249
|
+
));
|
|
25250
|
+
} else if (decision === "cancel") {
|
|
25251
|
+
options.push(decisionOption(
|
|
25252
|
+
ApprovalOptionId.Cancel,
|
|
25253
|
+
"No, and tell Codex what to do differently",
|
|
25254
|
+
"reject_once",
|
|
25255
|
+
decision
|
|
25256
|
+
));
|
|
25257
|
+
} else if ("acceptWithExecpolicyAmendment" in decision) {
|
|
25258
|
+
const prefix = renderExecPolicyPrefix(decision.acceptWithExecpolicyAmendment.execpolicy_amendment);
|
|
25259
|
+
if (prefix.includes("\n") || prefix.includes("\r")) continue;
|
|
25260
|
+
options.push(decisionOption(
|
|
25261
|
+
ApprovalOptionId.AcceptWithExecpolicyAmendment,
|
|
25262
|
+
`Yes, and don't ask again for commands that start with \`${prefix}\``,
|
|
25263
|
+
"allow_always",
|
|
25264
|
+
decision
|
|
25265
|
+
));
|
|
25266
|
+
} else {
|
|
25267
|
+
const amendment = decision.applyNetworkPolicyAmendment.network_policy_amendment;
|
|
25268
|
+
options.push(decisionOption(
|
|
25269
|
+
`${ApprovalOptionId.ApplyNetworkPolicyAmendment}:${networkIndex++}`,
|
|
25270
|
+
amendment.action === "allow" ? "Yes, and allow this host in the future" : "No, and block this host in the future",
|
|
25271
|
+
amendment.action === "allow" ? "allow_always" : "reject_always",
|
|
25272
|
+
decision
|
|
25273
|
+
));
|
|
24734
25274
|
}
|
|
24735
25275
|
}
|
|
24736
|
-
|
|
24737
|
-
|
|
25276
|
+
const orderedOptions = [...options].sort(
|
|
25277
|
+
(left, right) => permissionOptionOrder(left.option) - permissionOptionOrder(right.option)
|
|
25278
|
+
);
|
|
25279
|
+
const hasAllow = orderedOptions.some(({ option }) => option.kind === "allow_once" || option.kind === "allow_always");
|
|
25280
|
+
const hasReject = orderedOptions.some(({ option }) => option.kind === "reject_once" || option.kind === "reject_always");
|
|
25281
|
+
const optionIds = orderedOptions.map(({ option }) => option.optionId);
|
|
25282
|
+
const hasUniqueOptionIds = new Set(optionIds).size === optionIds.length;
|
|
25283
|
+
return hasAllow && hasReject && hasUniqueOptionIds ? orderedOptions : void 0;
|
|
25284
|
+
}
|
|
25285
|
+
function permissionOptionOrder(option) {
|
|
25286
|
+
if (option.kind === "allow_once") return 0;
|
|
25287
|
+
if (option.kind === "allow_always") return 1;
|
|
25288
|
+
return 2;
|
|
25289
|
+
}
|
|
25290
|
+
function fileChangeDecisionOptions() {
|
|
25291
|
+
return [
|
|
25292
|
+
decisionOption(ApprovalOptionId.AllowOnce, "Yes, proceed", "allow_once", "accept"),
|
|
25293
|
+
decisionOption(
|
|
25294
|
+
ApprovalOptionId.AllowForSession,
|
|
25295
|
+
"Yes, and don't ask again for these files",
|
|
25296
|
+
"allow_always",
|
|
25297
|
+
"acceptForSession"
|
|
25298
|
+
),
|
|
25299
|
+
decisionOption(
|
|
25300
|
+
ApprovalOptionId.Cancel,
|
|
25301
|
+
"No, and tell Codex what to do differently",
|
|
25302
|
+
"reject_once",
|
|
25303
|
+
"cancel"
|
|
25304
|
+
)
|
|
25305
|
+
];
|
|
25306
|
+
}
|
|
25307
|
+
function permissionProfileOptions() {
|
|
25308
|
+
return [
|
|
25309
|
+
permissionOption(
|
|
25310
|
+
ApprovalOptionId.AllowPermissionsForTurn,
|
|
25311
|
+
"Yes, grant these permissions for this turn",
|
|
25312
|
+
"allow_once"
|
|
25313
|
+
),
|
|
25314
|
+
permissionOption(
|
|
25315
|
+
ApprovalOptionId.AllowPermissionsForTurnWithStrictAutoReview,
|
|
25316
|
+
"Yes, grant for this turn with strict auto review",
|
|
25317
|
+
"allow_once"
|
|
25318
|
+
),
|
|
25319
|
+
permissionOption(
|
|
25320
|
+
ApprovalOptionId.AllowPermissionsForSession,
|
|
25321
|
+
"Yes, grant these permissions for this session",
|
|
25322
|
+
"allow_always"
|
|
25323
|
+
),
|
|
25324
|
+
permissionOption(
|
|
25325
|
+
ApprovalOptionId.RejectPermissions,
|
|
25326
|
+
"No, continue without permissions",
|
|
25327
|
+
"reject_once"
|
|
25328
|
+
)
|
|
25329
|
+
];
|
|
25330
|
+
}
|
|
25331
|
+
function decisionOption(optionId, name, kind, decision) {
|
|
25332
|
+
return { option: permissionOption(optionId, name, kind), decision };
|
|
25333
|
+
}
|
|
25334
|
+
function permissionOption(optionId, name, kind) {
|
|
25335
|
+
return { optionId, name, kind };
|
|
25336
|
+
}
|
|
25337
|
+
function renderExecPolicyPrefix(command) {
|
|
25338
|
+
const script = extractWrappedScript(command);
|
|
25339
|
+
if (script !== void 0) return script;
|
|
25340
|
+
if (command.some((value) => value.includes("\0"))) return command.join(" ");
|
|
25341
|
+
return command.map(shlexQuote).join(" ");
|
|
25342
|
+
}
|
|
25343
|
+
function extractWrappedScript(command) {
|
|
25344
|
+
const executable = executableName(command[0]);
|
|
25345
|
+
if ((executable === "bash" || executable === "zsh" || executable === "sh") && command.length === 3 && (command[1] === "-lc" || command[1] === "-c")) {
|
|
25346
|
+
return command[2];
|
|
24738
25347
|
}
|
|
24739
|
-
|
|
24740
|
-
|
|
24741
|
-
|
|
24742
|
-
|
|
24743
|
-
|
|
24744
|
-
|
|
24745
|
-
kind: "execute",
|
|
24746
|
-
status: "pending",
|
|
24747
|
-
rawInput: params.command ? { command: stripShellPrefix(params.command), cwd: params.cwd } : null
|
|
24748
|
-
},
|
|
24749
|
-
options,
|
|
24750
|
-
_meta: { codex: { params } }
|
|
24751
|
-
};
|
|
25348
|
+
if (executable !== "pwsh" && executable !== "powershell") return void 0;
|
|
25349
|
+
const allowedFlags = /* @__PURE__ */ new Set(["-nologo", "-noprofile", "-command", "-c"]);
|
|
25350
|
+
for (let index = 1; index + 1 < command.length; index++) {
|
|
25351
|
+
const flag = command[index]?.toLowerCase();
|
|
25352
|
+
if (flag === void 0 || !allowedFlags.has(flag)) return void 0;
|
|
25353
|
+
if (flag === "-command" || flag === "-c") return command[index + 1];
|
|
24752
25354
|
}
|
|
24753
|
-
|
|
24754
|
-
|
|
24755
|
-
|
|
24756
|
-
|
|
24757
|
-
|
|
24758
|
-
|
|
24759
|
-
|
|
24760
|
-
|
|
24761
|
-
|
|
24762
|
-
options,
|
|
24763
|
-
_meta: { codex: { params } }
|
|
24764
|
-
};
|
|
25355
|
+
return void 0;
|
|
25356
|
+
}
|
|
25357
|
+
function executableName(command) {
|
|
25358
|
+
let filename = command?.replaceAll("\\", "/").split("/").at(-1);
|
|
25359
|
+
while (filename !== void 0) {
|
|
25360
|
+
if (["bash", "zsh", "sh", "pwsh", "powershell"].includes(filename)) return filename;
|
|
25361
|
+
const dot = filename.lastIndexOf(".");
|
|
25362
|
+
if (dot <= 0) return void 0;
|
|
25363
|
+
filename = filename.slice(0, dot);
|
|
24765
25364
|
}
|
|
24766
|
-
|
|
24767
|
-
|
|
24768
|
-
|
|
24769
|
-
|
|
24770
|
-
|
|
24771
|
-
|
|
24772
|
-
|
|
24773
|
-
|
|
24774
|
-
|
|
24775
|
-
|
|
24776
|
-
|
|
24777
|
-
|
|
24778
|
-
|
|
24779
|
-
|
|
24780
|
-
|
|
24781
|
-
|
|
24782
|
-
|
|
24783
|
-
|
|
24784
|
-
|
|
24785
|
-
|
|
24786
|
-
|
|
24787
|
-
|
|
24788
|
-
|
|
24789
|
-
|
|
24790
|
-
|
|
24791
|
-
|
|
24792
|
-
|
|
24793
|
-
|
|
24794
|
-
|
|
24795
|
-
|
|
24796
|
-
|
|
24797
|
-
|
|
24798
|
-
|
|
24799
|
-
|
|
24800
|
-
|
|
24801
|
-
|
|
24802
|
-
|
|
24803
|
-
|
|
24804
|
-
|
|
25365
|
+
return void 0;
|
|
25366
|
+
}
|
|
25367
|
+
function shlexQuote(value) {
|
|
25368
|
+
if (value.length === 0) return "''";
|
|
25369
|
+
const UNQUOTED = 1;
|
|
25370
|
+
const SINGLE_QUOTED = 2;
|
|
25371
|
+
const DOUBLE_QUOTED = 4;
|
|
25372
|
+
let offset = 0;
|
|
25373
|
+
let result = "";
|
|
25374
|
+
while (offset < value.length) {
|
|
25375
|
+
const start = offset;
|
|
25376
|
+
let allowed = UNQUOTED | SINGLE_QUOTED | DOUBLE_QUOTED;
|
|
25377
|
+
if (value[offset] === "^") {
|
|
25378
|
+
allowed = SINGLE_QUOTED;
|
|
25379
|
+
offset++;
|
|
25380
|
+
}
|
|
25381
|
+
while (offset < value.length) {
|
|
25382
|
+
const character = value[offset];
|
|
25383
|
+
let nextAllowed = allowed;
|
|
25384
|
+
if (!isShlexUnquoted(character)) nextAllowed &= ~UNQUOTED;
|
|
25385
|
+
if (character === "'" || character === "^" || character === "\\") nextAllowed &= ~SINGLE_QUOTED;
|
|
25386
|
+
if (character === "`" || character === "$" || character === "!" || character === "^") {
|
|
25387
|
+
nextAllowed &= ~DOUBLE_QUOTED;
|
|
25388
|
+
}
|
|
25389
|
+
if (nextAllowed === 0) break;
|
|
25390
|
+
allowed = nextAllowed;
|
|
25391
|
+
offset++;
|
|
25392
|
+
}
|
|
25393
|
+
const chunk = value.slice(start, offset);
|
|
25394
|
+
if ((allowed & UNQUOTED) !== 0) result += chunk;
|
|
25395
|
+
else if ((allowed & SINGLE_QUOTED) !== 0) result += `'${chunk}'`;
|
|
25396
|
+
else result += `"${chunk.replace(/["\\]/g, "\\$&")}"`;
|
|
25397
|
+
}
|
|
25398
|
+
return result;
|
|
25399
|
+
}
|
|
25400
|
+
function isShlexUnquoted(character) {
|
|
25401
|
+
return /^[0-9A-Za-z]$/.test(character) || "+-./:@]_".includes(character);
|
|
25402
|
+
}
|
|
25403
|
+
|
|
25404
|
+
// src/permissions/metadata.ts
|
|
25405
|
+
var CODEX_COMMAND_PERMISSION_TITLE = "Run command?";
|
|
25406
|
+
var CODEX_NETWORK_PERMISSION_TITLE = "Allow network access?";
|
|
25407
|
+
var CODEX_FILE_CHANGE_PERMISSION_TITLE = "Make edits?";
|
|
25408
|
+
var CODEX_ADDITIONAL_PERMISSIONS_TITLE = "Grant permissions?";
|
|
25409
|
+
function requestPermissionMeta(title, reason) {
|
|
25410
|
+
const description = nonBlank(reason);
|
|
25411
|
+
const permission = {
|
|
25412
|
+
version: 1,
|
|
25413
|
+
title,
|
|
25414
|
+
...description ? { description } : {}
|
|
25415
|
+
};
|
|
25416
|
+
return { permission };
|
|
25417
|
+
}
|
|
25418
|
+
function optionPermissionMeta(description) {
|
|
25419
|
+
const normalized = nonBlank(description);
|
|
25420
|
+
if (!normalized) return void 0;
|
|
25421
|
+
const permission = { version: 1, description: normalized };
|
|
25422
|
+
return { permission };
|
|
25423
|
+
}
|
|
25424
|
+
function nonBlank(value) {
|
|
25425
|
+
const normalized = value?.trim();
|
|
25426
|
+
return normalized ? normalized : void 0;
|
|
25427
|
+
}
|
|
25428
|
+
|
|
25429
|
+
// src/permissions/presentation.ts
|
|
25430
|
+
function commandToolCall(params) {
|
|
25431
|
+
const network = params.networkApprovalContext;
|
|
25432
|
+
const rawInput = {
|
|
25433
|
+
...params.command ? { command: stripShellPrefix(params.command) } : {},
|
|
25434
|
+
...params.cwd ? { cwd: params.cwd } : {},
|
|
25435
|
+
...network?.protocol === "http" || network?.protocol === "https" ? { url: `${network.protocol}://${network.host}` } : {},
|
|
25436
|
+
...params.additionalPermissions ? { additionalPermissions: params.additionalPermissions } : {}
|
|
25437
|
+
};
|
|
25438
|
+
const additionalPermissionContent = params.additionalPermissions ? permissionProfileContent(params.additionalPermissions) : [];
|
|
25439
|
+
return {
|
|
25440
|
+
toolCallId: params.itemId,
|
|
25441
|
+
kind: "execute",
|
|
25442
|
+
status: "pending",
|
|
25443
|
+
title: network ? `${network.protocol} network access to ${network.host}` : commandTitle(params.commandActions),
|
|
25444
|
+
...Object.keys(rawInput).length > 0 ? { rawInput } : {},
|
|
25445
|
+
...locationsField(unique([
|
|
25446
|
+
...commandActionPaths(params.commandActions),
|
|
25447
|
+
...permissionProfilePaths(params.additionalPermissions)
|
|
25448
|
+
])),
|
|
25449
|
+
...network ? { content: [textContent(`${network.protocol} access to ${network.host}`), ...additionalPermissionContent] } : additionalPermissionContent.length > 0 ? { content: additionalPermissionContent } : {}
|
|
25450
|
+
};
|
|
25451
|
+
}
|
|
25452
|
+
function fileChangeToolCall(params, permissionContext) {
|
|
25453
|
+
const item = permissionContext.fileChange(params.threadId, params.itemId);
|
|
25454
|
+
return {
|
|
25455
|
+
toolCallId: params.itemId,
|
|
25456
|
+
kind: "edit",
|
|
25457
|
+
status: "pending",
|
|
25458
|
+
title: "Edit files",
|
|
25459
|
+
...locationsField(fileChangePaths(item))
|
|
25460
|
+
};
|
|
25461
|
+
}
|
|
25462
|
+
function additionalPermissionsToolCall(itemId, cwd, environmentId, permissions) {
|
|
25463
|
+
const content = permissionProfileContent(permissions);
|
|
25464
|
+
return {
|
|
25465
|
+
toolCallId: itemId,
|
|
25466
|
+
kind: "other",
|
|
25467
|
+
status: "pending",
|
|
25468
|
+
title: "Additional sandbox permissions",
|
|
25469
|
+
rawInput: { permissions, cwd, environmentId },
|
|
25470
|
+
...locationsField(permissionProfilePaths(permissions)),
|
|
25471
|
+
...content.length > 0 ? { content } : {}
|
|
25472
|
+
};
|
|
25473
|
+
}
|
|
25474
|
+
function commandTitle(actions) {
|
|
25475
|
+
const first = actions?.[0];
|
|
25476
|
+
if (!first) return "Run command";
|
|
25477
|
+
switch (first.type) {
|
|
25478
|
+
case "read":
|
|
25479
|
+
return actions?.length === 1 ? "Read file" : "Run command with file reads";
|
|
25480
|
+
case "listFiles":
|
|
25481
|
+
return "List files";
|
|
25482
|
+
case "search":
|
|
25483
|
+
return "Search files";
|
|
25484
|
+
case "unknown":
|
|
25485
|
+
return "Run command";
|
|
25486
|
+
}
|
|
25487
|
+
}
|
|
25488
|
+
function commandActionPaths(actions) {
|
|
25489
|
+
return unique((actions ?? []).flatMap((action) => {
|
|
25490
|
+
switch (action.type) {
|
|
25491
|
+
case "read":
|
|
25492
|
+
return [action.path];
|
|
25493
|
+
case "listFiles":
|
|
25494
|
+
case "search":
|
|
25495
|
+
return action.path ? [action.path] : [];
|
|
25496
|
+
case "unknown":
|
|
25497
|
+
return [];
|
|
25498
|
+
}
|
|
25499
|
+
}));
|
|
25500
|
+
}
|
|
25501
|
+
function fileChangePaths(item) {
|
|
25502
|
+
return unique(item?.changes.map((change) => change.path) ?? []);
|
|
25503
|
+
}
|
|
25504
|
+
function permissionProfilePaths(permissions) {
|
|
25505
|
+
const fileSystem = permissions?.fileSystem;
|
|
25506
|
+
return unique([
|
|
25507
|
+
...fileSystem?.read ?? [],
|
|
25508
|
+
...fileSystem?.write ?? [],
|
|
25509
|
+
...(fileSystem?.entries ?? []).flatMap((entry) => entry.path.type === "path" ? [entry.path.path] : [])
|
|
25510
|
+
]);
|
|
25511
|
+
}
|
|
25512
|
+
function permissionProfileContent(permissions) {
|
|
25513
|
+
const lines = [];
|
|
25514
|
+
const networkEnabled = permissions.network?.enabled;
|
|
25515
|
+
if (networkEnabled !== null && networkEnabled !== void 0) {
|
|
25516
|
+
lines.push(networkEnabled ? "Enable network access" : "Disable network access");
|
|
25517
|
+
}
|
|
25518
|
+
for (const entry of permissions.fileSystem?.entries ?? []) {
|
|
25519
|
+
switch (entry.path.type) {
|
|
25520
|
+
case "glob_pattern":
|
|
25521
|
+
lines.push(`${entry.access} filesystem pattern ${entry.path.pattern}`);
|
|
25522
|
+
break;
|
|
25523
|
+
case "special":
|
|
25524
|
+
lines.push(`${entry.access} Codex filesystem scope ${JSON.stringify(entry.path.value)}`);
|
|
25525
|
+
break;
|
|
25526
|
+
case "path":
|
|
25527
|
+
break;
|
|
25528
|
+
}
|
|
25529
|
+
}
|
|
25530
|
+
return lines.length > 0 ? [textContent(lines.join("\n"))] : [];
|
|
25531
|
+
}
|
|
25532
|
+
function locationsField(paths) {
|
|
25533
|
+
return paths.length > 0 ? { locations: paths.map((path9) => ({ path: path9 })) } : {};
|
|
25534
|
+
}
|
|
25535
|
+
function textContent(text) {
|
|
25536
|
+
return { type: "content", content: { type: "text", text } };
|
|
25537
|
+
}
|
|
25538
|
+
function unique(values) {
|
|
25539
|
+
return [...new Set(values)];
|
|
25540
|
+
}
|
|
25541
|
+
|
|
25542
|
+
// src/permissions/CodexApprovalHandler.ts
|
|
25543
|
+
var CodexApprovalHandler = class {
|
|
25544
|
+
constructor(connection, permissionContext, cancellationSignal) {
|
|
25545
|
+
this.connection = connection;
|
|
25546
|
+
this.permissionContext = permissionContext;
|
|
25547
|
+
this.cancellationSignal = cancellationSignal;
|
|
24805
25548
|
}
|
|
24806
|
-
|
|
24807
|
-
|
|
25549
|
+
connection;
|
|
25550
|
+
permissionContext;
|
|
25551
|
+
cancellationSignal;
|
|
25552
|
+
async handleCommandExecution(params) {
|
|
25553
|
+
const authoritativeParams = params;
|
|
25554
|
+
const decisions = commandDecisionOptions(authoritativeParams);
|
|
25555
|
+
if (!decisions) {
|
|
25556
|
+
logger.error("Cancelling command approval without a complete authoritative decision set", void 0);
|
|
25557
|
+
return { decision: "cancel" };
|
|
25558
|
+
}
|
|
25559
|
+
try {
|
|
25560
|
+
const response = await this.requestPermission({
|
|
25561
|
+
sessionId: params.threadId,
|
|
25562
|
+
toolCall: commandToolCall(authoritativeParams),
|
|
25563
|
+
options: decisions.map(({ option }) => option),
|
|
25564
|
+
_meta: requestPermissionMeta(
|
|
25565
|
+
params.networkApprovalContext ? CODEX_NETWORK_PERMISSION_TITLE : CODEX_COMMAND_PERMISSION_TITLE,
|
|
25566
|
+
params.reason
|
|
25567
|
+
)
|
|
25568
|
+
});
|
|
25569
|
+
return { decision: this.selectedDecision(response, decisions) ?? "cancel" };
|
|
25570
|
+
} catch (error51) {
|
|
25571
|
+
logger.error("Error requesting command execution permission", error51);
|
|
24808
25572
|
return { decision: "cancel" };
|
|
24809
25573
|
}
|
|
24810
|
-
const optionId = response.outcome.optionId;
|
|
24811
|
-
const decision = this.buildCommandOptions(params).find(({ option }) => option.optionId === optionId)?.decision;
|
|
24812
|
-
return { decision: decision ?? "decline" };
|
|
24813
25574
|
}
|
|
24814
|
-
|
|
24815
|
-
|
|
25575
|
+
async handleFileChange(params) {
|
|
25576
|
+
const decisions = fileChangeDecisionOptions();
|
|
25577
|
+
try {
|
|
25578
|
+
const response = await this.requestPermission({
|
|
25579
|
+
sessionId: params.threadId,
|
|
25580
|
+
toolCall: fileChangeToolCall(params, this.permissionContext),
|
|
25581
|
+
options: decisions.map(({ option }) => option),
|
|
25582
|
+
_meta: requestPermissionMeta(CODEX_FILE_CHANGE_PERMISSION_TITLE, params.reason)
|
|
25583
|
+
});
|
|
25584
|
+
return { decision: this.selectedDecision(response, decisions) ?? "cancel" };
|
|
25585
|
+
} catch (error51) {
|
|
25586
|
+
logger.error("Error requesting file change permission", error51);
|
|
24816
25587
|
return { decision: "cancel" };
|
|
24817
25588
|
}
|
|
24818
|
-
const optionId = response.outcome.optionId;
|
|
24819
|
-
const decision = this.buildFileChangeOptions(params).find(({ option }) => option.optionId === optionId)?.decision;
|
|
24820
|
-
return { decision: decision ?? "decline" };
|
|
24821
25589
|
}
|
|
24822
|
-
|
|
24823
|
-
|
|
25590
|
+
async handlePermissionsRequest(params) {
|
|
25591
|
+
try {
|
|
25592
|
+
const response = await this.requestPermission({
|
|
25593
|
+
sessionId: params.threadId,
|
|
25594
|
+
toolCall: additionalPermissionsToolCall(
|
|
25595
|
+
params.itemId,
|
|
25596
|
+
params.cwd,
|
|
25597
|
+
params.environmentId,
|
|
25598
|
+
params.permissions
|
|
25599
|
+
),
|
|
25600
|
+
options: permissionProfileOptions(),
|
|
25601
|
+
_meta: requestPermissionMeta(CODEX_ADDITIONAL_PERMISSIONS_TITLE, params.reason)
|
|
25602
|
+
});
|
|
25603
|
+
return this.permissionsResponse(params.permissions, response);
|
|
25604
|
+
} catch (error51) {
|
|
25605
|
+
logger.error("Error requesting permissions", error51);
|
|
24824
25606
|
return this.rejectPermissionsResponse();
|
|
24825
25607
|
}
|
|
25608
|
+
}
|
|
25609
|
+
requestPermission(request) {
|
|
25610
|
+
return this.connection.request(
|
|
25611
|
+
methods.client.session.requestPermission,
|
|
25612
|
+
request,
|
|
25613
|
+
this.cancellationSignal ? { cancellationSignal: this.cancellationSignal } : void 0
|
|
25614
|
+
);
|
|
25615
|
+
}
|
|
25616
|
+
selectedDecision(response, decisions) {
|
|
25617
|
+
if (response.outcome.outcome === "cancelled") return void 0;
|
|
25618
|
+
const optionId = response.outcome.optionId;
|
|
25619
|
+
return decisions.find(({ option }) => option.optionId === optionId)?.decision;
|
|
25620
|
+
}
|
|
25621
|
+
permissionsResponse(permissions, response) {
|
|
25622
|
+
if (response.outcome.outcome === "cancelled") return this.rejectPermissionsResponse();
|
|
24826
25623
|
switch (response.outcome.optionId) {
|
|
24827
|
-
case ApprovalOptionId.AllowPermissionsForSession:
|
|
24828
|
-
case ApprovalOptionId.AllowAlways:
|
|
24829
|
-
return {
|
|
24830
|
-
permissions: this.grantedPermissions(params.permissions),
|
|
24831
|
-
scope: "session",
|
|
24832
|
-
strictAutoReview: false
|
|
24833
|
-
};
|
|
24834
25624
|
case ApprovalOptionId.AllowPermissionsForTurn:
|
|
24835
|
-
|
|
24836
|
-
|
|
24837
|
-
|
|
24838
|
-
|
|
24839
|
-
|
|
24840
|
-
|
|
25625
|
+
return this.grantedPermissionsResponse(permissions, "turn", false);
|
|
25626
|
+
case ApprovalOptionId.AllowPermissionsForTurnWithStrictAutoReview:
|
|
25627
|
+
return this.grantedPermissionsResponse(permissions, "turn", true);
|
|
25628
|
+
case ApprovalOptionId.AllowPermissionsForSession:
|
|
25629
|
+
return this.grantedPermissionsResponse(permissions, "session", false);
|
|
25630
|
+
case ApprovalOptionId.RejectPermissions:
|
|
24841
25631
|
default:
|
|
24842
25632
|
return this.rejectPermissionsResponse();
|
|
24843
25633
|
}
|
|
24844
25634
|
}
|
|
24845
|
-
|
|
24846
|
-
|
|
24847
|
-
{
|
|
24848
|
-
option: permissionOption(ApprovalOptionId.AllowOnce, "Allow Once", "allow_once", { decision: "accept" }),
|
|
24849
|
-
decision: "accept"
|
|
24850
|
-
},
|
|
24851
|
-
{
|
|
24852
|
-
option: permissionOption(
|
|
24853
|
-
ApprovalOptionId.AllowAlways,
|
|
24854
|
-
params.networkApprovalContext ? "Allow Host for Session" : "Allow for Session",
|
|
24855
|
-
"allow_always",
|
|
24856
|
-
{ decision: "acceptForSession" },
|
|
24857
|
-
params.networkApprovalContext ? {
|
|
24858
|
-
version: 1,
|
|
24859
|
-
changes: [{
|
|
24860
|
-
type: "grant",
|
|
24861
|
-
operation: "grant",
|
|
24862
|
-
description: `Allow access to ${params.networkApprovalContext.host} for this session`,
|
|
24863
|
-
lifetime: { scope: "session" },
|
|
24864
|
-
targets: [{
|
|
24865
|
-
type: "network",
|
|
24866
|
-
matcher: {
|
|
24867
|
-
type: "host",
|
|
24868
|
-
host: params.networkApprovalContext.host,
|
|
24869
|
-
protocol: params.networkApprovalContext.protocol
|
|
24870
|
-
}
|
|
24871
|
-
}]
|
|
24872
|
-
}]
|
|
24873
|
-
} : void 0
|
|
24874
|
-
),
|
|
24875
|
-
decision: "acceptForSession"
|
|
24876
|
-
}
|
|
24877
|
-
];
|
|
24878
|
-
if (params.proposedExecpolicyAmendment && params.proposedExecpolicyAmendment.length > 0) {
|
|
24879
|
-
options.push({
|
|
24880
|
-
option: permissionOption(
|
|
24881
|
-
ApprovalOptionId.AcceptWithExecpolicyAmendment,
|
|
24882
|
-
this.execpolicyAmendmentLabel(params.proposedExecpolicyAmendment),
|
|
24883
|
-
"allow_always",
|
|
24884
|
-
{
|
|
24885
|
-
decision: "acceptWithExecpolicyAmendment",
|
|
24886
|
-
execpolicyAmendment: params.proposedExecpolicyAmendment
|
|
24887
|
-
},
|
|
24888
|
-
{
|
|
24889
|
-
version: 1,
|
|
24890
|
-
changes: [{
|
|
24891
|
-
type: "policy_rule",
|
|
24892
|
-
operation: "add",
|
|
24893
|
-
ruleBehavior: "allow",
|
|
24894
|
-
description: `Allow commands starting with ${params.proposedExecpolicyAmendment.join(" ")}`,
|
|
24895
|
-
targets: [{
|
|
24896
|
-
type: "command",
|
|
24897
|
-
matcher: {
|
|
24898
|
-
type: "argv_prefix",
|
|
24899
|
-
argv: params.proposedExecpolicyAmendment
|
|
24900
|
-
}
|
|
24901
|
-
}]
|
|
24902
|
-
}]
|
|
24903
|
-
}
|
|
24904
|
-
),
|
|
24905
|
-
decision: {
|
|
24906
|
-
acceptWithExecpolicyAmendment: {
|
|
24907
|
-
execpolicy_amendment: params.proposedExecpolicyAmendment
|
|
24908
|
-
}
|
|
24909
|
-
}
|
|
24910
|
-
});
|
|
24911
|
-
}
|
|
24912
|
-
params.proposedNetworkPolicyAmendments?.forEach((amendment, index) => {
|
|
24913
|
-
options.push({
|
|
24914
|
-
option: permissionOption(
|
|
24915
|
-
this.networkPolicyAmendmentOptionId(index),
|
|
24916
|
-
this.networkPolicyAmendmentLabel(amendment),
|
|
24917
|
-
amendment.action === "allow" ? "allow_always" : "reject_always",
|
|
24918
|
-
{
|
|
24919
|
-
decision: "applyNetworkPolicyAmendment",
|
|
24920
|
-
networkPolicyAmendment: amendment
|
|
24921
|
-
},
|
|
24922
|
-
{
|
|
24923
|
-
version: 1,
|
|
24924
|
-
changes: [{
|
|
24925
|
-
type: "policy_rule",
|
|
24926
|
-
operation: "add",
|
|
24927
|
-
ruleBehavior: amendment.action,
|
|
24928
|
-
description: amendment.action === "allow" ? `Allow access to ${amendment.host}` : `Block access to ${amendment.host}`,
|
|
24929
|
-
targets: [{
|
|
24930
|
-
type: "network",
|
|
24931
|
-
matcher: {
|
|
24932
|
-
type: "host",
|
|
24933
|
-
host: amendment.host
|
|
24934
|
-
}
|
|
24935
|
-
}]
|
|
24936
|
-
}]
|
|
24937
|
-
}
|
|
24938
|
-
),
|
|
24939
|
-
decision: {
|
|
24940
|
-
applyNetworkPolicyAmendment: {
|
|
24941
|
-
network_policy_amendment: amendment
|
|
24942
|
-
}
|
|
24943
|
-
}
|
|
24944
|
-
});
|
|
24945
|
-
});
|
|
24946
|
-
options.push({
|
|
24947
|
-
option: permissionOption(ApprovalOptionId.RejectOnce, "Reject", "reject_once", { decision: "decline" }),
|
|
24948
|
-
decision: "decline"
|
|
24949
|
-
});
|
|
24950
|
-
return options;
|
|
24951
|
-
}
|
|
24952
|
-
buildFileChangeOptions(params) {
|
|
24953
|
-
return [
|
|
24954
|
-
{
|
|
24955
|
-
option: permissionOption(ApprovalOptionId.AllowOnce, "Allow Once", "allow_once", { decision: "accept" }),
|
|
24956
|
-
decision: "accept"
|
|
24957
|
-
},
|
|
24958
|
-
{
|
|
24959
|
-
option: permissionOption(
|
|
24960
|
-
ApprovalOptionId.AllowAlways,
|
|
24961
|
-
params.grantRoot ? "Allow Root for Session" : "Allow for Session",
|
|
24962
|
-
"allow_always",
|
|
24963
|
-
{ decision: "acceptForSession", grantRoot: params.grantRoot ?? null },
|
|
24964
|
-
params.grantRoot ? {
|
|
24965
|
-
version: 1,
|
|
24966
|
-
changes: [{
|
|
24967
|
-
type: "grant",
|
|
24968
|
-
operation: "grant",
|
|
24969
|
-
description: `Allow writes under ${params.grantRoot} for this session`,
|
|
24970
|
-
lifetime: { scope: "session" },
|
|
24971
|
-
targets: [{
|
|
24972
|
-
type: "filesystem",
|
|
24973
|
-
access: ["write"],
|
|
24974
|
-
matcher: { type: "directory", path: params.grantRoot }
|
|
24975
|
-
}]
|
|
24976
|
-
}]
|
|
24977
|
-
} : void 0
|
|
24978
|
-
),
|
|
24979
|
-
decision: "acceptForSession"
|
|
24980
|
-
},
|
|
24981
|
-
{
|
|
24982
|
-
option: permissionOption(ApprovalOptionId.RejectOnce, "Reject", "reject_once", { decision: "decline" }),
|
|
24983
|
-
decision: "decline"
|
|
24984
|
-
}
|
|
24985
|
-
];
|
|
25635
|
+
grantedPermissionsResponse(permissions, scope, strictAutoReview) {
|
|
25636
|
+
return { permissions: this.grantedPermissions(permissions), scope, strictAutoReview };
|
|
24986
25637
|
}
|
|
24987
25638
|
rejectPermissionsResponse() {
|
|
24988
|
-
return {
|
|
24989
|
-
permissions: {},
|
|
24990
|
-
scope: "turn",
|
|
24991
|
-
strictAutoReview: true
|
|
24992
|
-
};
|
|
25639
|
+
return { permissions: {}, scope: "turn", strictAutoReview: false };
|
|
24993
25640
|
}
|
|
24994
25641
|
grantedPermissions(permissions) {
|
|
24995
25642
|
return {
|
|
@@ -24997,117 +25644,131 @@ var CodexApprovalHandler = class {
|
|
|
24997
25644
|
...permissions.fileSystem ? { fileSystem: permissions.fileSystem } : {}
|
|
24998
25645
|
};
|
|
24999
25646
|
}
|
|
25000
|
-
|
|
25001
|
-
|
|
25002
|
-
|
|
25003
|
-
|
|
25004
|
-
|
|
25005
|
-
|
|
25006
|
-
changes.push({
|
|
25007
|
-
type: allowed ? "grant" : "policy_rule",
|
|
25008
|
-
operation: allowed ? "grant" : "add",
|
|
25009
|
-
...allowed ? {} : { ruleBehavior: "deny" },
|
|
25010
|
-
description: `${allowed ? "Allow" : "Deny"} network access${suffix}`,
|
|
25011
|
-
lifetime,
|
|
25012
|
-
targets: [{ type: "network", matcher: { type: "any" } }]
|
|
25013
|
-
});
|
|
25014
|
-
}
|
|
25015
|
-
const fileSystem = permissions.fileSystem;
|
|
25016
|
-
for (const path8 of fileSystem?.read ?? []) {
|
|
25017
|
-
changes.push(this.fileSystemGrantChange(path8, "read", lifetime, suffix));
|
|
25018
|
-
}
|
|
25019
|
-
for (const path8 of fileSystem?.write ?? []) {
|
|
25020
|
-
changes.push(this.fileSystemGrantChange(path8, "write", lifetime, suffix));
|
|
25021
|
-
}
|
|
25022
|
-
for (const entry of fileSystem?.entries ?? []) {
|
|
25023
|
-
const matcher = (() => {
|
|
25024
|
-
switch (entry.path.type) {
|
|
25025
|
-
case "path":
|
|
25026
|
-
return { type: "exact_path", path: entry.path.path };
|
|
25027
|
-
case "glob_pattern":
|
|
25028
|
-
return { type: "glob", pattern: entry.path.pattern };
|
|
25029
|
-
case "special":
|
|
25030
|
-
return { type: "special", provider: "codex", value: entry.path.value };
|
|
25031
|
-
}
|
|
25032
|
-
})();
|
|
25033
|
-
const pathDescription = entry.path.type === "path" ? entry.path.path : entry.path.type === "glob_pattern" ? entry.path.pattern : JSON.stringify(entry.path.value);
|
|
25034
|
-
changes.push({
|
|
25035
|
-
type: entry.access === "deny" ? "policy_rule" : "grant",
|
|
25036
|
-
operation: entry.access === "deny" ? "add" : "grant",
|
|
25037
|
-
...entry.access === "deny" ? { ruleBehavior: "deny" } : {},
|
|
25038
|
-
description: entry.access === "deny" ? `Deny filesystem access to ${pathDescription}${suffix}` : `Allow ${entry.access} access to ${pathDescription}${suffix}`,
|
|
25039
|
-
lifetime,
|
|
25040
|
-
targets: [{
|
|
25041
|
-
type: "filesystem",
|
|
25042
|
-
...entry.access === "deny" ? {} : { access: [entry.access] },
|
|
25043
|
-
matcher
|
|
25044
|
-
}]
|
|
25045
|
-
});
|
|
25046
|
-
}
|
|
25047
|
-
return changes.length > 0 ? { version: 1, changes } : void 0;
|
|
25647
|
+
};
|
|
25648
|
+
|
|
25649
|
+
// src/permissions/lifecycle.ts
|
|
25650
|
+
var PermissionLifecycleContext = class {
|
|
25651
|
+
constructor(session) {
|
|
25652
|
+
this.session = session;
|
|
25048
25653
|
}
|
|
25049
|
-
|
|
25050
|
-
|
|
25051
|
-
|
|
25052
|
-
|
|
25053
|
-
description: `Allow ${access} access to ${path8}${suffix}`,
|
|
25054
|
-
lifetime,
|
|
25055
|
-
targets: [{
|
|
25056
|
-
type: "filesystem",
|
|
25057
|
-
access: [access],
|
|
25058
|
-
matcher: { type: "exact_path", path: path8 }
|
|
25059
|
-
}]
|
|
25060
|
-
};
|
|
25654
|
+
session;
|
|
25655
|
+
permissionRequestSequence = 0;
|
|
25656
|
+
beginPrompt() {
|
|
25657
|
+
return new PermissionPromptContext((serverName) => this.nextStandaloneMcpToolCallId(serverName));
|
|
25061
25658
|
}
|
|
25062
|
-
|
|
25063
|
-
|
|
25659
|
+
nextStandaloneMcpToolCallId(serverName) {
|
|
25660
|
+
this.permissionRequestSequence += 1;
|
|
25661
|
+
return ["elicitation", this.session.sessionId, serverName, this.permissionRequestSequence].join(":");
|
|
25064
25662
|
}
|
|
25065
|
-
|
|
25066
|
-
|
|
25067
|
-
|
|
25068
|
-
|
|
25663
|
+
};
|
|
25664
|
+
var PermissionPromptContext = class {
|
|
25665
|
+
constructor(nextStandaloneId) {
|
|
25666
|
+
this.nextStandaloneId = nextStandaloneId;
|
|
25667
|
+
}
|
|
25668
|
+
nextStandaloneId;
|
|
25669
|
+
fileChanges = /* @__PURE__ */ new Map();
|
|
25670
|
+
pendingMcpApprovals = /* @__PURE__ */ new Map();
|
|
25671
|
+
handleNotification(notification) {
|
|
25672
|
+
switch (notification.method) {
|
|
25673
|
+
case "item/started":
|
|
25674
|
+
this.handleItemStarted(notification.params.threadId, notification.params.item);
|
|
25675
|
+
return;
|
|
25676
|
+
case "item/completed":
|
|
25677
|
+
this.handleItemCompleted(notification.params.threadId, notification.params.item);
|
|
25678
|
+
return;
|
|
25679
|
+
case "turn/completed":
|
|
25680
|
+
this.clearTransientState(notification.params.threadId);
|
|
25681
|
+
return;
|
|
25682
|
+
case "serverRequest/resolved":
|
|
25683
|
+
this.pendingMcpApprovals.delete(notification.params.threadId);
|
|
25684
|
+
return;
|
|
25685
|
+
default:
|
|
25686
|
+
return;
|
|
25069
25687
|
}
|
|
25070
|
-
return `Allow Commands Starting With \`${commandPrefix}\``;
|
|
25071
25688
|
}
|
|
25072
|
-
|
|
25073
|
-
return
|
|
25689
|
+
fileChange(threadId, itemId) {
|
|
25690
|
+
return this.fileChanges.get(threadId)?.get(itemId);
|
|
25074
25691
|
}
|
|
25075
|
-
|
|
25076
|
-
const
|
|
25077
|
-
if (
|
|
25078
|
-
|
|
25079
|
-
|
|
25080
|
-
|
|
25081
|
-
|
|
25082
|
-
|
|
25083
|
-
|
|
25084
|
-
|
|
25692
|
+
popPendingMcpApproval(threadId, serverName) {
|
|
25693
|
+
const byServer = this.pendingMcpApprovals.get(threadId);
|
|
25694
|
+
if (!byServer) return void 0;
|
|
25695
|
+
const pending = byServer.get(serverName);
|
|
25696
|
+
if (pending?.length !== 1) return void 0;
|
|
25697
|
+
const callId = pending[0];
|
|
25698
|
+
byServer.delete(serverName);
|
|
25699
|
+
if (byServer.size === 0) this.pendingMcpApprovals.delete(threadId);
|
|
25700
|
+
return callId;
|
|
25701
|
+
}
|
|
25702
|
+
nextStandaloneMcpToolCallId(serverName) {
|
|
25703
|
+
return this.nextStandaloneId(serverName);
|
|
25704
|
+
}
|
|
25705
|
+
handleItemStarted(threadId, item) {
|
|
25706
|
+
if (item.type === "fileChange") {
|
|
25707
|
+
const byItem = this.fileChanges.get(threadId) ?? /* @__PURE__ */ new Map();
|
|
25708
|
+
byItem.set(item.id, item);
|
|
25709
|
+
this.fileChanges.set(threadId, byItem);
|
|
25710
|
+
return;
|
|
25085
25711
|
}
|
|
25086
|
-
if (
|
|
25087
|
-
|
|
25712
|
+
if (item.type !== "mcpToolCall") return;
|
|
25713
|
+
const byServer = this.pendingMcpApprovals.get(threadId) ?? /* @__PURE__ */ new Map();
|
|
25714
|
+
const pending = byServer.get(item.server);
|
|
25715
|
+
if (pending) pending.push(item.id);
|
|
25716
|
+
else byServer.set(item.server, [item.id]);
|
|
25717
|
+
this.pendingMcpApprovals.set(threadId, byServer);
|
|
25718
|
+
}
|
|
25719
|
+
handleItemCompleted(threadId, item) {
|
|
25720
|
+
if (item.type === "fileChange") {
|
|
25721
|
+
const byItem = this.fileChanges.get(threadId);
|
|
25722
|
+
byItem?.delete(item.id);
|
|
25723
|
+
if (byItem?.size === 0) this.fileChanges.delete(threadId);
|
|
25724
|
+
return;
|
|
25088
25725
|
}
|
|
25089
|
-
|
|
25726
|
+
if (item.type !== "mcpToolCall") return;
|
|
25727
|
+
const byServer = this.pendingMcpApprovals.get(threadId);
|
|
25728
|
+
if (!byServer) return;
|
|
25729
|
+
const pending = byServer.get(item.server);
|
|
25730
|
+
if (!pending) return;
|
|
25731
|
+
const index = pending.indexOf(item.id);
|
|
25732
|
+
if (index >= 0) pending.splice(index, 1);
|
|
25733
|
+
if (pending.length === 0) byServer.delete(item.server);
|
|
25734
|
+
if (byServer.size === 0) this.pendingMcpApprovals.delete(threadId);
|
|
25090
25735
|
}
|
|
25091
|
-
|
|
25092
|
-
|
|
25093
|
-
|
|
25094
|
-
return [{
|
|
25095
|
-
type: "content",
|
|
25096
|
-
content: {
|
|
25097
|
-
type: "text",
|
|
25098
|
-
text
|
|
25099
|
-
}
|
|
25100
|
-
}];
|
|
25736
|
+
clearTransientState(threadId) {
|
|
25737
|
+
this.fileChanges.delete(threadId);
|
|
25738
|
+
this.pendingMcpApprovals.delete(threadId);
|
|
25101
25739
|
}
|
|
25102
25740
|
};
|
|
25103
25741
|
|
|
25104
|
-
// src/
|
|
25105
|
-
var
|
|
25106
|
-
|
|
25107
|
-
|
|
25108
|
-
|
|
25109
|
-
|
|
25110
|
-
|
|
25742
|
+
// src/permissions/plan-review.ts
|
|
25743
|
+
var IMPLEMENT_PLAN_OPTION_ID = "implement_plan";
|
|
25744
|
+
var REVISE_PLAN_OPTION_ID = "revise_plan";
|
|
25745
|
+
function planImplementationPermissionRequest(sessionId, plan) {
|
|
25746
|
+
return {
|
|
25747
|
+
sessionId,
|
|
25748
|
+
toolCall: {
|
|
25749
|
+
toolCallId: planImplementationToolCallId(plan),
|
|
25750
|
+
title: "Implement this plan?",
|
|
25751
|
+
kind: "switch_mode",
|
|
25752
|
+
status: "pending",
|
|
25753
|
+
rawInput: { plan: plan.text }
|
|
25754
|
+
},
|
|
25755
|
+
options: [
|
|
25756
|
+
{ optionId: IMPLEMENT_PLAN_OPTION_ID, name: "Yes, implement this plan", kind: "allow_once" },
|
|
25757
|
+
{
|
|
25758
|
+
optionId: REVISE_PLAN_OPTION_ID,
|
|
25759
|
+
name: "No, and tell Codex what to do differently",
|
|
25760
|
+
kind: "reject_once"
|
|
25761
|
+
}
|
|
25762
|
+
],
|
|
25763
|
+
_meta: { codex: { kind: "plan_review", planItemId: plan.itemId } }
|
|
25764
|
+
};
|
|
25765
|
+
}
|
|
25766
|
+
function planImplementationApproved(response) {
|
|
25767
|
+
return response.outcome.outcome === "selected" && response.outcome.optionId === IMPLEMENT_PLAN_OPTION_ID;
|
|
25768
|
+
}
|
|
25769
|
+
function planImplementationToolCallId(plan) {
|
|
25770
|
+
return `plan-review:${plan.itemId}`;
|
|
25771
|
+
}
|
|
25111
25772
|
|
|
25112
25773
|
// src/ElicitationCapabilities.ts
|
|
25113
25774
|
function clientSupportsFormElicitation(clientCapabilities) {
|
|
@@ -25117,57 +25778,146 @@ function clientSupportsUrlElicitation(clientCapabilities) {
|
|
|
25117
25778
|
return clientCapabilities?.elicitation?.url != null;
|
|
25118
25779
|
}
|
|
25119
25780
|
|
|
25120
|
-
// src/
|
|
25121
|
-
var ELICITATION_OPTIONS = [
|
|
25122
|
-
{ optionId: "accept", name: "Accept", kind: "allow_once" },
|
|
25123
|
-
{ optionId: "decline", name: "Decline", kind: "reject_once" }
|
|
25124
|
-
];
|
|
25125
|
-
var USER_INPUT_OTHER_FIELD_SUFFIX = "__other";
|
|
25781
|
+
// src/permissions/mcp.ts
|
|
25126
25782
|
function parsePersistOptions(meta3) {
|
|
25127
25783
|
const result = /* @__PURE__ */ new Set();
|
|
25128
|
-
if (!meta3
|
|
25784
|
+
if (!isRecord2(meta3)) return result;
|
|
25129
25785
|
const persist = meta3["persist"];
|
|
25130
|
-
if (persist === "session")
|
|
25131
|
-
|
|
25132
|
-
|
|
25133
|
-
result.add("always");
|
|
25134
|
-
} else if (Array.isArray(persist)) {
|
|
25786
|
+
if (persist === "session") result.add("session");
|
|
25787
|
+
else if (persist === "always") result.add("always");
|
|
25788
|
+
else if (Array.isArray(persist)) {
|
|
25135
25789
|
if (persist.includes("session")) result.add("session");
|
|
25136
25790
|
if (persist.includes("always")) result.add("always");
|
|
25137
25791
|
}
|
|
25138
25792
|
return result;
|
|
25139
25793
|
}
|
|
25140
25794
|
function isMcpToolCallApproval(meta3) {
|
|
25141
|
-
return meta3
|
|
25142
|
-
}
|
|
25143
|
-
function
|
|
25144
|
-
|
|
25145
|
-
|
|
25146
|
-
|
|
25147
|
-
|
|
25148
|
-
|
|
25795
|
+
return isRecord2(meta3) && meta3["codex_approval_kind"] === "mcp_tool_call";
|
|
25796
|
+
}
|
|
25797
|
+
function buildMcpPermissionOptions(isToolApproval, persistOptions) {
|
|
25798
|
+
const options = [permissionOption2(
|
|
25799
|
+
isToolApproval ? McpApprovalOptionId.AllowOnce : "accept",
|
|
25800
|
+
"Allow",
|
|
25801
|
+
"allow_once",
|
|
25802
|
+
isToolApproval ? "Run the tool and continue." : "Allow this request and continue."
|
|
25803
|
+
)];
|
|
25804
|
+
if (persistOptions.has("session")) {
|
|
25805
|
+
options.push(permissionOption2(
|
|
25806
|
+
McpApprovalOptionId.AllowSession,
|
|
25807
|
+
"Allow for this session",
|
|
25808
|
+
"allow_always",
|
|
25809
|
+
isToolApproval ? "Run the tool and remember this choice for this session." : "Allow this request and remember this choice for this session."
|
|
25810
|
+
));
|
|
25149
25811
|
}
|
|
25150
|
-
if (
|
|
25151
|
-
|
|
25812
|
+
if (persistOptions.has("always")) {
|
|
25813
|
+
options.push(permissionOption2(
|
|
25814
|
+
McpApprovalOptionId.AllowAlways,
|
|
25815
|
+
"Always allow",
|
|
25816
|
+
"allow_always",
|
|
25817
|
+
isToolApproval ? "Run the tool and remember this choice for future tool calls." : "Allow this request and remember this choice for future requests."
|
|
25818
|
+
));
|
|
25152
25819
|
}
|
|
25153
|
-
if (
|
|
25154
|
-
|
|
25820
|
+
if (isToolApproval) {
|
|
25821
|
+
options.push(permissionOption2(
|
|
25822
|
+
McpApprovalOptionId.Cancel,
|
|
25823
|
+
"Cancel",
|
|
25824
|
+
"reject_once",
|
|
25825
|
+
"Cancel this tool call"
|
|
25826
|
+
));
|
|
25827
|
+
} else {
|
|
25828
|
+
options.push(
|
|
25829
|
+
permissionOption2(
|
|
25830
|
+
McpApprovalOptionId.Decline,
|
|
25831
|
+
"Deny",
|
|
25832
|
+
"reject_once",
|
|
25833
|
+
"Decline this request and continue."
|
|
25834
|
+
),
|
|
25835
|
+
permissionOption2(McpApprovalOptionId.Cancel, "Cancel", "reject_once", "Cancel this request")
|
|
25836
|
+
);
|
|
25155
25837
|
}
|
|
25156
|
-
|
|
25157
|
-
|
|
25838
|
+
return options;
|
|
25839
|
+
}
|
|
25840
|
+
function buildMcpPermissionRequest(sessionId, params, context, nextStandaloneToolCallId) {
|
|
25841
|
+
const messageContent = {
|
|
25842
|
+
type: "content",
|
|
25843
|
+
content: { type: "text", text: params.message }
|
|
25844
|
+
};
|
|
25845
|
+
const options = buildMcpPermissionOptions(context.isToolApproval, context.persistOptions);
|
|
25846
|
+
if (params.mode === "form" || params.mode === "openai/form") {
|
|
25847
|
+
if (context.correlatedCallId !== void 0) {
|
|
25848
|
+
return {
|
|
25849
|
+
request: {
|
|
25850
|
+
sessionId,
|
|
25851
|
+
toolCall: {
|
|
25852
|
+
toolCallId: context.correlatedCallId,
|
|
25853
|
+
kind: "execute",
|
|
25854
|
+
status: "pending"
|
|
25855
|
+
},
|
|
25856
|
+
_meta: { is_mcp_tool_approval: true },
|
|
25857
|
+
options
|
|
25858
|
+
},
|
|
25859
|
+
correlatedCallId: context.correlatedCallId
|
|
25860
|
+
};
|
|
25861
|
+
}
|
|
25862
|
+
return {
|
|
25863
|
+
request: {
|
|
25864
|
+
sessionId,
|
|
25865
|
+
toolCall: {
|
|
25866
|
+
toolCallId: nextStandaloneToolCallId(),
|
|
25867
|
+
kind: context.isToolApproval ? "execute" : "other",
|
|
25868
|
+
status: "pending",
|
|
25869
|
+
content: [messageContent],
|
|
25870
|
+
rawInput: { serverName: params.serverName, schema: params.requestedSchema }
|
|
25871
|
+
},
|
|
25872
|
+
...context.isToolApproval ? { _meta: { is_mcp_tool_approval: true } } : {},
|
|
25873
|
+
options
|
|
25874
|
+
},
|
|
25875
|
+
correlatedCallId: void 0
|
|
25876
|
+
};
|
|
25158
25877
|
}
|
|
25159
|
-
|
|
25160
|
-
|
|
25161
|
-
|
|
25162
|
-
|
|
25878
|
+
return {
|
|
25879
|
+
request: {
|
|
25880
|
+
sessionId,
|
|
25881
|
+
toolCall: {
|
|
25882
|
+
toolCallId: `elicitation-${params.elicitationId}`,
|
|
25883
|
+
kind: "fetch",
|
|
25884
|
+
status: "pending",
|
|
25885
|
+
content: [messageContent],
|
|
25886
|
+
rawInput: { serverName: params.serverName, url: params.url }
|
|
25887
|
+
},
|
|
25888
|
+
options
|
|
25889
|
+
},
|
|
25890
|
+
correlatedCallId: void 0
|
|
25891
|
+
};
|
|
25892
|
+
}
|
|
25893
|
+
function convertMcpPermissionResponse(response, isToolApproval, persistOptions) {
|
|
25894
|
+
if (response.outcome.outcome === "cancelled") return cancelledResponse();
|
|
25895
|
+
switch (response.outcome.optionId) {
|
|
25896
|
+
case McpApprovalOptionId.AllowSession:
|
|
25897
|
+
return persistOptions.has("session") ? { action: "accept", content: null, _meta: { persist: "session" } } : cancelledResponse();
|
|
25898
|
+
case McpApprovalOptionId.AllowAlways:
|
|
25899
|
+
return persistOptions.has("always") ? { action: "accept", content: null, _meta: { persist: "always" } } : cancelledResponse();
|
|
25900
|
+
case McpApprovalOptionId.AllowOnce:
|
|
25901
|
+
return isToolApproval ? { action: "accept", content: null, _meta: null } : cancelledResponse();
|
|
25902
|
+
case "accept":
|
|
25903
|
+
return !isToolApproval ? { action: "accept", content: null, _meta: null } : cancelledResponse();
|
|
25904
|
+
case McpApprovalOptionId.Decline:
|
|
25905
|
+
return !isToolApproval ? { action: "decline", content: null, _meta: null } : cancelledResponse();
|
|
25906
|
+
case McpApprovalOptionId.Cancel:
|
|
25907
|
+
default:
|
|
25908
|
+
return cancelledResponse();
|
|
25163
25909
|
}
|
|
25164
|
-
return String(value);
|
|
25165
25910
|
}
|
|
25166
|
-
function
|
|
25167
|
-
|
|
25168
|
-
|
|
25169
|
-
|
|
25911
|
+
function permissionOption2(optionId, name, kind, description) {
|
|
25912
|
+
const meta3 = optionPermissionMeta(description);
|
|
25913
|
+
return { optionId, name, kind, ...meta3 ? { _meta: meta3 } : {} };
|
|
25914
|
+
}
|
|
25915
|
+
function cancelledResponse() {
|
|
25916
|
+
return { action: "cancel", content: null, _meta: null };
|
|
25170
25917
|
}
|
|
25918
|
+
|
|
25919
|
+
// src/CodexElicitationHandler.ts
|
|
25920
|
+
var USER_INPUT_OTHER_FIELD_SUFFIX = "__other";
|
|
25171
25921
|
function normalizeElicitationSchema(value) {
|
|
25172
25922
|
const normalized = normalizeElicitationSchemaValue(value);
|
|
25173
25923
|
if (!isRecord2(normalized)) {
|
|
@@ -25203,40 +25953,6 @@ function normalizeElicitationSchemaValue(value) {
|
|
|
25203
25953
|
}
|
|
25204
25954
|
return result;
|
|
25205
25955
|
}
|
|
25206
|
-
function metaRecord(meta3) {
|
|
25207
|
-
return isRecord2(meta3) ? meta3 : null;
|
|
25208
|
-
}
|
|
25209
|
-
function persistChoiceOption(value) {
|
|
25210
|
-
switch (value) {
|
|
25211
|
-
case "once":
|
|
25212
|
-
return { const: "once", title: "Allow once" };
|
|
25213
|
-
case "session":
|
|
25214
|
-
return { const: "session", title: "Allow for this session" };
|
|
25215
|
-
case "always":
|
|
25216
|
-
return { const: "always", title: "Allow and don't ask again" };
|
|
25217
|
-
}
|
|
25218
|
-
}
|
|
25219
|
-
function addPersistChoiceToSchema(schema, persistOptions) {
|
|
25220
|
-
if (persistOptions.size === 0) {
|
|
25221
|
-
return schema;
|
|
25222
|
-
}
|
|
25223
|
-
const choices = ["once"];
|
|
25224
|
-
if (persistOptions.has("session")) choices.push("session");
|
|
25225
|
-
if (persistOptions.has("always")) choices.push("always");
|
|
25226
|
-
return {
|
|
25227
|
-
...schema,
|
|
25228
|
-
properties: {
|
|
25229
|
-
...schema.properties,
|
|
25230
|
-
persist: {
|
|
25231
|
-
type: "string",
|
|
25232
|
-
title: "Approval scope",
|
|
25233
|
-
oneOf: choices.map(persistChoiceOption),
|
|
25234
|
-
default: "once"
|
|
25235
|
-
}
|
|
25236
|
-
},
|
|
25237
|
-
required: Array.from(/* @__PURE__ */ new Set([...schema.required ?? [], "persist"]))
|
|
25238
|
-
};
|
|
25239
|
-
}
|
|
25240
25956
|
function contentRecord(content) {
|
|
25241
25957
|
return isRecord2(content) ? content : {};
|
|
25242
25958
|
}
|
|
@@ -25248,7 +25964,7 @@ function jsonObjectOrNull(content) {
|
|
|
25248
25964
|
return Object.fromEntries(entries.map(([key, value]) => [key, normalizeJsonValue(value)]));
|
|
25249
25965
|
}
|
|
25250
25966
|
function elicitationResponseMeta(response, context, persist = void 0) {
|
|
25251
|
-
const responseMeta =
|
|
25967
|
+
const responseMeta = recordOrNull(response._meta);
|
|
25252
25968
|
const meta3 = responseMeta ? normalizeJsonObject(responseMeta) : {};
|
|
25253
25969
|
if (context.isToolApproval) {
|
|
25254
25970
|
delete meta3["persist"];
|
|
@@ -25279,22 +25995,9 @@ function userInputResponseValue(content, fieldId) {
|
|
|
25279
25995
|
}
|
|
25280
25996
|
return value;
|
|
25281
25997
|
}
|
|
25282
|
-
function buildToolApprovalOptions(persistOptions) {
|
|
25283
|
-
const options = [
|
|
25284
|
-
{ optionId: McpApprovalOptionId.AllowOnce, name: "Allow", kind: "allow_once" }
|
|
25285
|
-
];
|
|
25286
|
-
if (persistOptions.has("session")) {
|
|
25287
|
-
options.push({ optionId: McpApprovalOptionId.AllowSession, name: "Allow for This Session", kind: "allow_always" });
|
|
25288
|
-
}
|
|
25289
|
-
if (persistOptions.has("always")) {
|
|
25290
|
-
options.push({ optionId: McpApprovalOptionId.AllowAlways, name: "Allow and Don't Ask Again", kind: "allow_always" });
|
|
25291
|
-
}
|
|
25292
|
-
options.push({ optionId: McpApprovalOptionId.Decline, name: "Decline", kind: "reject_once" });
|
|
25293
|
-
return options;
|
|
25294
|
-
}
|
|
25295
25998
|
var CodexElicitationHandler = class {
|
|
25296
25999
|
connection;
|
|
25297
|
-
|
|
26000
|
+
permissionContext;
|
|
25298
26001
|
clientCapabilities;
|
|
25299
26002
|
cancellationSignal;
|
|
25300
26003
|
// In Rust, the MCP elicitation handler receives ElicitationRequestEvent directly from the MCP
|
|
@@ -25306,32 +26009,21 @@ var CodexElicitationHandler = class {
|
|
|
25306
26009
|
// reaches the client.
|
|
25307
26010
|
//
|
|
25308
26011
|
// Workaround: before requesting approval, Codex emits an item/started notification with an
|
|
25309
|
-
// mcpToolCall item carrying the call id and server name.
|
|
25310
|
-
//
|
|
26012
|
+
// mcpToolCall item carrying the call id and server name. The shared permission lifecycle stores
|
|
26013
|
+
// (threadId, serverName) → callId so this request can correlate to the rendered tool call item.
|
|
25311
26014
|
//
|
|
25312
|
-
// Multiple calls are safe because Codex requests approval synchronously — it blocks on one tool
|
|
25313
|
-
// call's elicitation before starting the next, so there is at most one pending approval per
|
|
25314
|
-
// (threadId, serverName).
|
|
25315
|
-
pendingMcpApprovals = /* @__PURE__ */ new Map();
|
|
25316
26015
|
// The app-server handler exposes URL elicitationId, while serverRequest/resolved only exposes
|
|
25317
26016
|
// threadId here, so accepted URL elicitations are completed at thread scope.
|
|
25318
26017
|
pendingUrlElicitations = /* @__PURE__ */ new Map();
|
|
25319
|
-
constructor(connection,
|
|
26018
|
+
constructor(connection, permissionContext, clientCapabilities = null, cancellationSignal) {
|
|
25320
26019
|
this.connection = connection;
|
|
25321
|
-
this.
|
|
26020
|
+
this.permissionContext = permissionContext;
|
|
25322
26021
|
this.clientCapabilities = clientCapabilities;
|
|
25323
26022
|
this.cancellationSignal = cancellationSignal;
|
|
25324
26023
|
}
|
|
25325
26024
|
async handleNotification(notification) {
|
|
25326
26025
|
switch (notification.method) {
|
|
25327
|
-
case "item/started":
|
|
25328
|
-
this.handleItemStarted(notification.params);
|
|
25329
|
-
return;
|
|
25330
|
-
case "item/completed":
|
|
25331
|
-
this.handleItemCompleted(notification.params);
|
|
25332
|
-
return;
|
|
25333
26026
|
case "serverRequest/resolved":
|
|
25334
|
-
this.clearThread(notification.params.threadId);
|
|
25335
26027
|
await this.completeUrlElicitations(notification.params.threadId);
|
|
25336
26028
|
return;
|
|
25337
26029
|
default:
|
|
@@ -25347,29 +26039,39 @@ var CodexElicitationHandler = class {
|
|
|
25347
26039
|
this.buildElicitationRequest(params, context),
|
|
25348
26040
|
this.requestOptions()
|
|
25349
26041
|
);
|
|
25350
|
-
const
|
|
25351
|
-
if (params.mode === "url" &&
|
|
26042
|
+
const result2 = this.convertElicitationResponse(response2, context);
|
|
26043
|
+
if (params.mode === "url" && result2.action === "accept") {
|
|
25352
26044
|
this.trackUrlElicitation(params.threadId, params.elicitationId);
|
|
25353
26045
|
}
|
|
25354
|
-
await this.publishAcceptedMcpToolApproval(context,
|
|
25355
|
-
return
|
|
26046
|
+
await this.publishAcceptedMcpToolApproval(params.threadId, context, result2.action === "accept");
|
|
26047
|
+
return result2;
|
|
25356
26048
|
}
|
|
25357
|
-
|
|
26049
|
+
if (!this.canUsePermissionFallback(params)) {
|
|
26050
|
+
return { action: "cancel", content: null, _meta: null };
|
|
26051
|
+
}
|
|
26052
|
+
const { request, correlatedCallId } = buildMcpPermissionRequest(
|
|
26053
|
+
params.threadId,
|
|
26054
|
+
params,
|
|
26055
|
+
context,
|
|
26056
|
+
() => this.permissionContext.nextStandaloneMcpToolCallId(params.serverName)
|
|
26057
|
+
);
|
|
25358
26058
|
const response = await this.connection.request(
|
|
25359
26059
|
methods.client.session.requestPermission,
|
|
25360
26060
|
request,
|
|
25361
26061
|
this.requestOptions()
|
|
25362
26062
|
);
|
|
25363
|
-
|
|
25364
|
-
|
|
25365
|
-
|
|
25366
|
-
|
|
25367
|
-
|
|
25368
|
-
|
|
25369
|
-
|
|
25370
|
-
|
|
26063
|
+
const result = convertMcpPermissionResponse(
|
|
26064
|
+
response,
|
|
26065
|
+
context.isToolApproval,
|
|
26066
|
+
context.persistOptions
|
|
26067
|
+
);
|
|
26068
|
+
if (correlatedCallId !== void 0 && result.action === "accept") {
|
|
26069
|
+
await this.connection.notify(methods.client.session.update, {
|
|
26070
|
+
sessionId: params.threadId,
|
|
26071
|
+
update: { sessionUpdate: "tool_call_update", toolCallId: correlatedCallId, status: "in_progress" }
|
|
26072
|
+
});
|
|
25371
26073
|
}
|
|
25372
|
-
return
|
|
26074
|
+
return result;
|
|
25373
26075
|
} catch (error51) {
|
|
25374
26076
|
logger.error("Error handling MCP elicitation request", error51);
|
|
25375
26077
|
return { action: "cancel", content: null, _meta: null };
|
|
@@ -25439,12 +26141,17 @@ var CodexElicitationHandler = class {
|
|
|
25439
26141
|
}
|
|
25440
26142
|
}
|
|
25441
26143
|
createMcpElicitationContext(params) {
|
|
25442
|
-
const isToolApproval = isMcpToolCallApproval(params._meta);
|
|
26144
|
+
const isToolApproval = isMcpToolCallApproval(params._meta) && this.isMessageOnlyForm(params);
|
|
25443
26145
|
const persistOptions = parsePersistOptions(params._meta);
|
|
25444
|
-
const correlatedCallId = isToolApproval
|
|
25445
|
-
return {
|
|
26146
|
+
const correlatedCallId = isToolApproval ? this.permissionContext.popPendingMcpApproval(params.threadId, params.serverName) : void 0;
|
|
26147
|
+
return {
|
|
26148
|
+
isToolApproval,
|
|
26149
|
+
persistOptions,
|
|
26150
|
+
correlatedCallId
|
|
26151
|
+
};
|
|
25446
26152
|
}
|
|
25447
26153
|
shouldUseAcpElicitation(params) {
|
|
26154
|
+
if (this.isMessageOnlyForm(params)) return false;
|
|
25448
26155
|
switch (params.mode) {
|
|
25449
26156
|
case "form":
|
|
25450
26157
|
return clientSupportsFormElicitation(this.clientCapabilities);
|
|
@@ -25454,23 +26161,28 @@ var CodexElicitationHandler = class {
|
|
|
25454
26161
|
return false;
|
|
25455
26162
|
}
|
|
25456
26163
|
}
|
|
26164
|
+
canUsePermissionFallback(params) {
|
|
26165
|
+
return params.mode === "url" || this.isMessageOnlyForm(params);
|
|
26166
|
+
}
|
|
26167
|
+
isMessageOnlyForm(params) {
|
|
26168
|
+
if (params.mode !== "form" && params.mode !== "openai/form") return false;
|
|
26169
|
+
if (params.requestedSchema === null) return true;
|
|
26170
|
+
if (!isRecord2(params.requestedSchema)) return false;
|
|
26171
|
+
return params.requestedSchema["type"] === "object" && isRecord2(params.requestedSchema["properties"]) && Object.keys(params.requestedSchema["properties"]).length === 0;
|
|
26172
|
+
}
|
|
25457
26173
|
buildElicitationRequest(params, context) {
|
|
25458
26174
|
const base = {
|
|
25459
|
-
sessionId:
|
|
26175
|
+
sessionId: params.threadId,
|
|
25460
26176
|
...context.correlatedCallId ? { toolCallId: context.correlatedCallId } : {},
|
|
25461
26177
|
message: params.message,
|
|
25462
|
-
_meta:
|
|
26178
|
+
_meta: recordOrNull(params._meta)
|
|
25463
26179
|
};
|
|
25464
26180
|
switch (params.mode) {
|
|
25465
26181
|
case "form": {
|
|
25466
|
-
const requestedSchema = context.isToolApproval ? addPersistChoiceToSchema(
|
|
25467
|
-
normalizeElicitationSchema(params.requestedSchema),
|
|
25468
|
-
context.persistOptions
|
|
25469
|
-
) : normalizeElicitationSchema(params.requestedSchema);
|
|
25470
26182
|
return {
|
|
25471
26183
|
...base,
|
|
25472
26184
|
mode: "form",
|
|
25473
|
-
requestedSchema
|
|
26185
|
+
requestedSchema: normalizeElicitationSchema(params.requestedSchema)
|
|
25474
26186
|
};
|
|
25475
26187
|
}
|
|
25476
26188
|
case "url":
|
|
@@ -25526,105 +26238,35 @@ var CodexElicitationHandler = class {
|
|
|
25526
26238
|
isOtherAnswer: true,
|
|
25527
26239
|
isSecret: question.isSecret
|
|
25528
26240
|
}
|
|
25529
|
-
}
|
|
25530
|
-
};
|
|
25531
|
-
}
|
|
25532
|
-
}
|
|
25533
|
-
const firstQuestion = params.questions[0];
|
|
25534
|
-
return {
|
|
25535
|
-
sessionId: this.sessionState.sessionId,
|
|
25536
|
-
toolCallId: params.itemId,
|
|
25537
|
-
mode: "form",
|
|
25538
|
-
message: params.questions.length === 1 && firstQuestion ? firstQuestion.question : "Input requested",
|
|
25539
|
-
requestedSchema: {
|
|
25540
|
-
type: "object",
|
|
25541
|
-
properties,
|
|
25542
|
-
required: required2
|
|
25543
|
-
},
|
|
25544
|
-
_meta: {
|
|
25545
|
-
codex: {
|
|
25546
|
-
autoResolutionMs: params.autoResolutionMs
|
|
25547
|
-
}
|
|
25548
|
-
}
|
|
25549
|
-
};
|
|
25550
|
-
}
|
|
25551
|
-
buildPermissionRequest(params, context) {
|
|
25552
|
-
const sessionId = this.sessionState.sessionId;
|
|
25553
|
-
const messageContent = {
|
|
25554
|
-
type: "content",
|
|
25555
|
-
content: { type: "text", text: params.message }
|
|
25556
|
-
};
|
|
25557
|
-
const options = context.isToolApproval ? buildToolApprovalOptions(context.persistOptions) : ELICITATION_OPTIONS;
|
|
25558
|
-
if (params.mode === "form" || params.mode === "openai/form") {
|
|
25559
|
-
if (context.correlatedCallId !== void 0) {
|
|
25560
|
-
return {
|
|
25561
|
-
request: {
|
|
25562
|
-
sessionId,
|
|
25563
|
-
toolCall: {
|
|
25564
|
-
toolCallId: context.correlatedCallId,
|
|
25565
|
-
kind: "execute",
|
|
25566
|
-
status: "pending"
|
|
25567
|
-
// content: [messageContent], — omitted: already rendered via item/started
|
|
25568
|
-
// rawInput: { ... } — omitted: same reason
|
|
25569
|
-
},
|
|
25570
|
-
_meta: { is_mcp_tool_approval: true },
|
|
25571
|
-
options
|
|
25572
|
-
},
|
|
25573
|
-
correlatedCallId: context.correlatedCallId
|
|
25574
|
-
};
|
|
25575
|
-
}
|
|
25576
|
-
return {
|
|
25577
|
-
request: {
|
|
25578
|
-
sessionId,
|
|
25579
|
-
toolCall: {
|
|
25580
|
-
toolCallId: `elicitation-${params.serverName}`,
|
|
25581
|
-
kind: context.isToolApproval ? "execute" : "other",
|
|
25582
|
-
status: "pending",
|
|
25583
|
-
content: [messageContent],
|
|
25584
|
-
rawInput: { serverName: params.serverName, schema: params.requestedSchema }
|
|
25585
|
-
},
|
|
25586
|
-
...context.isToolApproval ? { _meta: { is_mcp_tool_approval: true } } : {},
|
|
25587
|
-
options
|
|
25588
|
-
},
|
|
25589
|
-
correlatedCallId: void 0
|
|
25590
|
-
};
|
|
25591
|
-
} else {
|
|
25592
|
-
return {
|
|
25593
|
-
request: {
|
|
25594
|
-
sessionId,
|
|
25595
|
-
toolCall: {
|
|
25596
|
-
toolCallId: `elicitation-${params.elicitationId}`,
|
|
25597
|
-
kind: "fetch",
|
|
25598
|
-
status: "pending",
|
|
25599
|
-
content: [messageContent],
|
|
25600
|
-
rawInput: { serverName: params.serverName, url: params.url }
|
|
25601
|
-
},
|
|
25602
|
-
options
|
|
25603
|
-
},
|
|
25604
|
-
correlatedCallId: void 0
|
|
25605
|
-
};
|
|
25606
|
-
}
|
|
25607
|
-
}
|
|
25608
|
-
convertPermissionResponse(response) {
|
|
25609
|
-
if (response.outcome.outcome === "cancelled") {
|
|
25610
|
-
return { action: "cancel", content: null, _meta: null };
|
|
25611
|
-
}
|
|
25612
|
-
const optionId = response.outcome.optionId;
|
|
25613
|
-
if (optionId === McpApprovalOptionId.AllowSession) {
|
|
25614
|
-
return { action: "accept", content: null, _meta: { persist: "session" } };
|
|
25615
|
-
}
|
|
25616
|
-
if (optionId === McpApprovalOptionId.AllowAlways) {
|
|
25617
|
-
return { action: "accept", content: null, _meta: { persist: "always" } };
|
|
25618
|
-
}
|
|
25619
|
-
if (optionId === McpApprovalOptionId.AllowOnce || optionId === "accept") {
|
|
25620
|
-
return { action: "accept", content: null, _meta: null };
|
|
26241
|
+
}
|
|
26242
|
+
};
|
|
26243
|
+
}
|
|
25621
26244
|
}
|
|
25622
|
-
|
|
26245
|
+
const firstQuestion = params.questions[0];
|
|
26246
|
+
return {
|
|
26247
|
+
sessionId: params.threadId,
|
|
26248
|
+
toolCallId: params.itemId,
|
|
26249
|
+
mode: "form",
|
|
26250
|
+
message: params.questions.length === 1 && firstQuestion ? firstQuestion.question : "Input requested",
|
|
26251
|
+
requestedSchema: {
|
|
26252
|
+
type: "object",
|
|
26253
|
+
properties,
|
|
26254
|
+
required: required2
|
|
26255
|
+
},
|
|
26256
|
+
_meta: {
|
|
26257
|
+
codex: {
|
|
26258
|
+
autoResolutionMs: params.autoResolutionMs
|
|
26259
|
+
}
|
|
26260
|
+
}
|
|
26261
|
+
};
|
|
25623
26262
|
}
|
|
25624
26263
|
convertElicitationResponse(response, context) {
|
|
25625
26264
|
if (CreateElicitationResponse.isAccept(response)) {
|
|
25626
26265
|
const content = contentRecord(response.content);
|
|
25627
26266
|
const persist = context.isToolApproval ? content["persist"] : void 0;
|
|
26267
|
+
if (context.isToolApproval && !this.isAllowedToolApprovalPersist(persist, context.persistOptions)) {
|
|
26268
|
+
return { action: "cancel", content: null, _meta: null };
|
|
26269
|
+
}
|
|
25628
26270
|
if (persist === "session" || persist === "always" || persist === "once") {
|
|
25629
26271
|
delete content["persist"];
|
|
25630
26272
|
}
|
|
@@ -25635,7 +26277,7 @@ var CodexElicitationHandler = class {
|
|
|
25635
26277
|
};
|
|
25636
26278
|
}
|
|
25637
26279
|
if (CreateElicitationResponse.isDecline(response)) {
|
|
25638
|
-
return { action: "decline", content: null, _meta: elicitationResponseMeta(response, context) };
|
|
26280
|
+
return context.isToolApproval ? { action: "cancel", content: null, _meta: elicitationResponseMeta(response, context) } : { action: "decline", content: null, _meta: elicitationResponseMeta(response, context) };
|
|
25639
26281
|
}
|
|
25640
26282
|
if (CreateElicitationResponse.isCancel(response)) {
|
|
25641
26283
|
return { action: "cancel", content: null, _meta: elicitationResponseMeta(response, context) };
|
|
@@ -25645,6 +26287,9 @@ var CodexElicitationHandler = class {
|
|
|
25645
26287
|
}
|
|
25646
26288
|
return { action: "cancel", content: null, _meta: null };
|
|
25647
26289
|
}
|
|
26290
|
+
isAllowedToolApprovalPersist(persist, persistOptions) {
|
|
26291
|
+
return persist === void 0 || persist === "once" || persist === "session" && persistOptions.has("session") || persist === "always" && persistOptions.has("always");
|
|
26292
|
+
}
|
|
25648
26293
|
convertUserInputResponse(response, params) {
|
|
25649
26294
|
if (!CreateElicitationResponse.isAccept(response)) {
|
|
25650
26295
|
return { answers: {} };
|
|
@@ -25663,12 +26308,12 @@ var CodexElicitationHandler = class {
|
|
|
25663
26308
|
}
|
|
25664
26309
|
return { answers };
|
|
25665
26310
|
}
|
|
25666
|
-
async publishAcceptedMcpToolApproval(context, accepted) {
|
|
26311
|
+
async publishAcceptedMcpToolApproval(sessionId, context, accepted) {
|
|
25667
26312
|
if (!accepted || context.correlatedCallId === void 0) {
|
|
25668
26313
|
return;
|
|
25669
26314
|
}
|
|
25670
26315
|
await this.connection.notify(methods.client.session.update, {
|
|
25671
|
-
sessionId
|
|
26316
|
+
sessionId,
|
|
25672
26317
|
update: { sessionUpdate: "tool_call_update", toolCallId: context.correlatedCallId, status: "in_progress" }
|
|
25673
26318
|
});
|
|
25674
26319
|
}
|
|
@@ -25692,37 +26337,6 @@ var CodexElicitationHandler = class {
|
|
|
25692
26337
|
});
|
|
25693
26338
|
}
|
|
25694
26339
|
}
|
|
25695
|
-
handleItemStarted(event) {
|
|
25696
|
-
if (event.item.type !== "mcpToolCall") {
|
|
25697
|
-
return;
|
|
25698
|
-
}
|
|
25699
|
-
this.pendingMcpApprovals.set(this.key(event.threadId, event.item.server), event.item.id);
|
|
25700
|
-
}
|
|
25701
|
-
handleItemCompleted(event) {
|
|
25702
|
-
if (event.item.type !== "mcpToolCall") {
|
|
25703
|
-
return;
|
|
25704
|
-
}
|
|
25705
|
-
this.popPendingApproval(event.threadId, event.item.server);
|
|
25706
|
-
}
|
|
25707
|
-
popPendingApproval(threadId, serverName) {
|
|
25708
|
-
const key = this.key(threadId, serverName);
|
|
25709
|
-
const callId = this.pendingMcpApprovals.get(key);
|
|
25710
|
-
this.pendingMcpApprovals.delete(key);
|
|
25711
|
-
return callId;
|
|
25712
|
-
}
|
|
25713
|
-
clearThread(threadId) {
|
|
25714
|
-
for (const key of this.pendingMcpApprovals.keys()) {
|
|
25715
|
-
if (this.belongsToThread(key, threadId)) {
|
|
25716
|
-
this.pendingMcpApprovals.delete(key);
|
|
25717
|
-
}
|
|
25718
|
-
}
|
|
25719
|
-
}
|
|
25720
|
-
key(threadId, serverName) {
|
|
25721
|
-
return `${threadId}:${serverName}`;
|
|
25722
|
-
}
|
|
25723
|
-
belongsToThread(key, threadId) {
|
|
25724
|
-
return key.startsWith(`${threadId}:`);
|
|
25725
|
-
}
|
|
25726
26340
|
};
|
|
25727
26341
|
|
|
25728
26342
|
// src/CodexAuthMethod.ts
|
|
@@ -25778,13 +26392,14 @@ function isCodexAuthRequest(request) {
|
|
|
25778
26392
|
}
|
|
25779
26393
|
|
|
25780
26394
|
// node_modules/open/index.js
|
|
25781
|
-
import
|
|
25782
|
-
import
|
|
26395
|
+
import process11 from "node:process";
|
|
26396
|
+
import path4 from "node:path";
|
|
25783
26397
|
import { fileURLToPath } from "node:url";
|
|
25784
|
-
import
|
|
26398
|
+
import childProcess4 from "node:child_process";
|
|
25785
26399
|
import fs6, { constants as fsConstants2 } from "node:fs/promises";
|
|
25786
26400
|
|
|
25787
26401
|
// node_modules/wsl-utils/index.js
|
|
26402
|
+
import path3 from "node:path";
|
|
25788
26403
|
import { promisify as promisify2 } from "node:util";
|
|
25789
26404
|
import childProcess2 from "node:child_process";
|
|
25790
26405
|
import fs5, { constants as fsConstants } from "node:fs/promises";
|
|
@@ -25863,7 +26478,7 @@ var isWsl = () => {
|
|
|
25863
26478
|
};
|
|
25864
26479
|
var is_wsl_default = process3.env.__IS_WSL_TEST__ ? isWsl : isWsl();
|
|
25865
26480
|
|
|
25866
|
-
// node_modules/powershell-utils/index.js
|
|
26481
|
+
// node_modules/wsl-utils/node_modules/powershell-utils/index.js
|
|
25867
26482
|
import process4 from "node:process";
|
|
25868
26483
|
import { Buffer as Buffer2 } from "node:buffer";
|
|
25869
26484
|
import { promisify } from "node:util";
|
|
@@ -25962,20 +26577,73 @@ var canAccessPowerShell = async () => {
|
|
|
25962
26577
|
var wslDefaultBrowser = async () => {
|
|
25963
26578
|
const psPath = await powerShellPath2();
|
|
25964
26579
|
const command = String.raw`(Get-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice").ProgId`;
|
|
25965
|
-
const { stdout } = await executePowerShell(command, {
|
|
26580
|
+
const { stdout } = await executePowerShell(command, {
|
|
26581
|
+
powerShellPath: psPath,
|
|
26582
|
+
cwd: path3.dirname(psPath)
|
|
26583
|
+
});
|
|
25966
26584
|
return stdout.trim();
|
|
25967
26585
|
};
|
|
25968
|
-
var
|
|
25969
|
-
|
|
25970
|
-
|
|
25971
|
-
|
|
25972
|
-
|
|
25973
|
-
|
|
25974
|
-
|
|
25975
|
-
|
|
25976
|
-
|
|
26586
|
+
var isUrl = (path9) => /^[a-z]+:\/\//i.test(path9);
|
|
26587
|
+
var convertWslPathToWindows = async (paths) => {
|
|
26588
|
+
const isBatch = Array.isArray(paths);
|
|
26589
|
+
const pathArray = isBatch ? paths : [paths];
|
|
26590
|
+
const indicesToConvert = [];
|
|
26591
|
+
const pathsToConvert = [];
|
|
26592
|
+
for (const [index, path9] of pathArray.entries()) {
|
|
26593
|
+
if (!isUrl(path9)) {
|
|
26594
|
+
indicesToConvert.push(index);
|
|
26595
|
+
pathsToConvert.push(path9);
|
|
26596
|
+
}
|
|
26597
|
+
}
|
|
26598
|
+
const results = [...pathArray];
|
|
26599
|
+
if (pathsToConvert.length > 0) {
|
|
26600
|
+
try {
|
|
26601
|
+
const { stdout } = await execFile2("wslpath", ["-aw", ...pathsToConvert], { encoding: "utf8" });
|
|
26602
|
+
const convertedPaths = stdout.split(/\r?\n/).filter(Boolean);
|
|
26603
|
+
for (const [index, originalIndex] of indicesToConvert.entries()) {
|
|
26604
|
+
results[originalIndex] = convertedPaths[index] ?? pathArray[originalIndex];
|
|
26605
|
+
}
|
|
26606
|
+
} catch {
|
|
26607
|
+
}
|
|
25977
26608
|
}
|
|
26609
|
+
return isBatch ? results : results[0];
|
|
26610
|
+
};
|
|
26611
|
+
|
|
26612
|
+
// node_modules/powershell-utils/index.js
|
|
26613
|
+
import process5 from "node:process";
|
|
26614
|
+
import { Buffer as Buffer3 } from "node:buffer";
|
|
26615
|
+
import { promisify as promisify3 } from "node:util";
|
|
26616
|
+
import childProcess3 from "node:child_process";
|
|
26617
|
+
var execFile3 = promisify3(childProcess3.execFile);
|
|
26618
|
+
var powerShellPath3 = () => `${process5.env.SYSTEMROOT || process5.env.windir || String.raw`C:\Windows`}\\System32\\WindowsPowerShell\\v1.0\\powershell.exe`;
|
|
26619
|
+
var argumentsPrefix = [
|
|
26620
|
+
"-NoProfile",
|
|
26621
|
+
"-NonInteractive",
|
|
26622
|
+
"-ExecutionPolicy",
|
|
26623
|
+
"Bypass",
|
|
26624
|
+
"-EncodedCommand"
|
|
26625
|
+
];
|
|
26626
|
+
var encodeCommand = (command) => Buffer3.from(command, "utf16le").toString("base64");
|
|
26627
|
+
var escapeArgument = (value) => `'${String(value).replaceAll("'", "''")}'`;
|
|
26628
|
+
var createArguments = (command) => [...argumentsPrefix, encodeCommand(command)];
|
|
26629
|
+
var executePowerShell2 = async (command, options = {}) => {
|
|
26630
|
+
const {
|
|
26631
|
+
powerShellPath: psPath,
|
|
26632
|
+
...execFileOptions
|
|
26633
|
+
} = options;
|
|
26634
|
+
return execFile3(
|
|
26635
|
+
psPath ?? powerShellPath3(),
|
|
26636
|
+
createArguments(command),
|
|
26637
|
+
{
|
|
26638
|
+
encoding: "utf8",
|
|
26639
|
+
...execFileOptions
|
|
26640
|
+
}
|
|
26641
|
+
);
|
|
25978
26642
|
};
|
|
26643
|
+
executePowerShell2.argumentsPrefix = argumentsPrefix;
|
|
26644
|
+
executePowerShell2.encodeCommand = encodeCommand;
|
|
26645
|
+
executePowerShell2.escapeArgument = escapeArgument;
|
|
26646
|
+
executePowerShell2.createArguments = createArguments;
|
|
25979
26647
|
|
|
25980
26648
|
// node_modules/define-lazy-prop/index.js
|
|
25981
26649
|
function defineLazyProperty(object2, propertyName, valueGetter) {
|
|
@@ -25996,17 +26664,17 @@ function defineLazyProperty(object2, propertyName, valueGetter) {
|
|
|
25996
26664
|
}
|
|
25997
26665
|
|
|
25998
26666
|
// node_modules/default-browser/index.js
|
|
25999
|
-
import { promisify as
|
|
26000
|
-
import
|
|
26001
|
-
import { execFile as
|
|
26667
|
+
import { promisify as promisify7 } from "node:util";
|
|
26668
|
+
import process9 from "node:process";
|
|
26669
|
+
import { execFile as execFile7 } from "node:child_process";
|
|
26002
26670
|
|
|
26003
26671
|
// node_modules/default-browser-id/index.js
|
|
26004
|
-
import { promisify as
|
|
26005
|
-
import
|
|
26006
|
-
import { execFile as
|
|
26007
|
-
var execFileAsync =
|
|
26672
|
+
import { promisify as promisify4 } from "node:util";
|
|
26673
|
+
import process6 from "node:process";
|
|
26674
|
+
import { execFile as execFile4 } from "node:child_process";
|
|
26675
|
+
var execFileAsync = promisify4(execFile4);
|
|
26008
26676
|
async function defaultBrowserId() {
|
|
26009
|
-
if (
|
|
26677
|
+
if (process6.platform !== "darwin") {
|
|
26010
26678
|
throw new Error("macOS only");
|
|
26011
26679
|
}
|
|
26012
26680
|
const { stdout } = await execFileAsync("defaults", ["read", "com.apple.LaunchServices/com.apple.launchservices.secure", "LSHandlers"]);
|
|
@@ -26019,12 +26687,12 @@ async function defaultBrowserId() {
|
|
|
26019
26687
|
}
|
|
26020
26688
|
|
|
26021
26689
|
// node_modules/run-applescript/index.js
|
|
26022
|
-
import
|
|
26023
|
-
import { promisify as
|
|
26024
|
-
import { execFile as
|
|
26025
|
-
var execFileAsync2 =
|
|
26690
|
+
import process7 from "node:process";
|
|
26691
|
+
import { promisify as promisify5 } from "node:util";
|
|
26692
|
+
import { execFile as execFile5, execFileSync } from "node:child_process";
|
|
26693
|
+
var execFileAsync2 = promisify5(execFile5);
|
|
26026
26694
|
async function runAppleScript(script, { humanReadableOutput = true, signal } = {}) {
|
|
26027
|
-
if (
|
|
26695
|
+
if (process7.platform !== "darwin") {
|
|
26028
26696
|
throw new Error("macOS only");
|
|
26029
26697
|
}
|
|
26030
26698
|
const outputArguments = humanReadableOutput ? [] : ["-ss"];
|
|
@@ -26043,9 +26711,10 @@ tell application "System Events" to get value of property list item "CFBundleNam
|
|
|
26043
26711
|
}
|
|
26044
26712
|
|
|
26045
26713
|
// node_modules/default-browser/windows.js
|
|
26046
|
-
import
|
|
26047
|
-
import {
|
|
26048
|
-
|
|
26714
|
+
import process8 from "node:process";
|
|
26715
|
+
import { promisify as promisify6 } from "node:util";
|
|
26716
|
+
import { execFile as execFile6 } from "node:child_process";
|
|
26717
|
+
var execFileAsync3 = promisify6(execFile6);
|
|
26049
26718
|
var windowsBrowserProgIds = {
|
|
26050
26719
|
MSEdgeHTM: { name: "Edge", id: "com.microsoft.edge" },
|
|
26051
26720
|
// The missing `L` is correct.
|
|
@@ -26069,7 +26738,8 @@ var _windowsBrowserProgIdMap = new Map(Object.entries(windowsBrowserProgIds));
|
|
|
26069
26738
|
var UnknownBrowserError = class extends Error {
|
|
26070
26739
|
};
|
|
26071
26740
|
async function defaultBrowser(_execFileAsync = execFileAsync3) {
|
|
26072
|
-
const {
|
|
26741
|
+
const regPath = `${process8.env.SYSTEMROOT ?? process8.env.windir ?? "C:\\Windows"}\\System32\\reg.exe`;
|
|
26742
|
+
const { stdout } = await _execFileAsync(regPath, [
|
|
26073
26743
|
"QUERY",
|
|
26074
26744
|
" HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\http\\UserChoice",
|
|
26075
26745
|
"/v",
|
|
@@ -26088,36 +26758,36 @@ async function defaultBrowser(_execFileAsync = execFileAsync3) {
|
|
|
26088
26758
|
}
|
|
26089
26759
|
|
|
26090
26760
|
// node_modules/default-browser/index.js
|
|
26091
|
-
var execFileAsync4 =
|
|
26761
|
+
var execFileAsync4 = promisify7(execFile7);
|
|
26092
26762
|
var titleize = (string4) => string4.toLowerCase().replaceAll(/(?:^|\s|-)\S/g, (x) => x.toUpperCase());
|
|
26093
26763
|
async function defaultBrowser2() {
|
|
26094
|
-
if (
|
|
26764
|
+
if (process9.platform === "darwin") {
|
|
26095
26765
|
const id = await defaultBrowserId();
|
|
26096
26766
|
const name = await bundleName(id);
|
|
26097
26767
|
return { name, id };
|
|
26098
26768
|
}
|
|
26099
|
-
if (
|
|
26769
|
+
if (process9.platform === "linux") {
|
|
26100
26770
|
const { stdout } = await execFileAsync4("xdg-mime", ["query", "default", "x-scheme-handler/http"]);
|
|
26101
26771
|
const id = stdout.trim();
|
|
26102
26772
|
const name = titleize(id.replace(/.desktop$/, "").replace("-", " "));
|
|
26103
26773
|
return { name, id };
|
|
26104
26774
|
}
|
|
26105
|
-
if (
|
|
26775
|
+
if (process9.platform === "win32") {
|
|
26106
26776
|
return defaultBrowser();
|
|
26107
26777
|
}
|
|
26108
26778
|
throw new Error("Only macOS, Linux, and Windows are supported");
|
|
26109
26779
|
}
|
|
26110
26780
|
|
|
26111
26781
|
// node_modules/is-in-ssh/index.js
|
|
26112
|
-
import
|
|
26113
|
-
var isInSsh = Boolean(
|
|
26782
|
+
import process10 from "node:process";
|
|
26783
|
+
var isInSsh = Boolean(process10.env.SSH_CONNECTION || process10.env.SSH_CLIENT || process10.env.SSH_TTY);
|
|
26114
26784
|
var is_in_ssh_default = isInSsh;
|
|
26115
26785
|
|
|
26116
26786
|
// node_modules/open/index.js
|
|
26117
26787
|
var fallbackAttemptSymbol = /* @__PURE__ */ Symbol("fallbackAttempt");
|
|
26118
|
-
var __dirname = import.meta.url ?
|
|
26119
|
-
var localXdgOpenPath =
|
|
26120
|
-
var { platform, arch } =
|
|
26788
|
+
var __dirname = import.meta.url ? path4.dirname(fileURLToPath(import.meta.url)) : "";
|
|
26789
|
+
var localXdgOpenPath = path4.join(__dirname, "xdg-open");
|
|
26790
|
+
var { platform, arch } = process11;
|
|
26121
26791
|
var tryEachApp = async (apps2, opener) => {
|
|
26122
26792
|
if (apps2.length === 0) {
|
|
26123
26793
|
return;
|
|
@@ -26230,7 +26900,7 @@ var baseOpen = async (options) => {
|
|
|
26230
26900
|
}
|
|
26231
26901
|
} else if (platform === "win32" || shouldUseWindowsInWsl) {
|
|
26232
26902
|
command = await powerShellPath2();
|
|
26233
|
-
cliArguments.push(...
|
|
26903
|
+
cliArguments.push(...executePowerShell2.argumentsPrefix);
|
|
26234
26904
|
if (!is_wsl_default) {
|
|
26235
26905
|
childProcessOptions.windowsVerbatimArguments = true;
|
|
26236
26906
|
}
|
|
@@ -26242,21 +26912,24 @@ var baseOpen = async (options) => {
|
|
|
26242
26912
|
encodedArguments.push("-Wait");
|
|
26243
26913
|
}
|
|
26244
26914
|
if (app) {
|
|
26245
|
-
encodedArguments.push(
|
|
26915
|
+
encodedArguments.push(executePowerShell2.escapeArgument(app));
|
|
26246
26916
|
if (options.target) {
|
|
26247
26917
|
appArguments.push(options.target);
|
|
26248
26918
|
}
|
|
26249
26919
|
} else if (options.target) {
|
|
26250
|
-
encodedArguments.push(
|
|
26920
|
+
encodedArguments.push(executePowerShell2.escapeArgument(options.target));
|
|
26251
26921
|
}
|
|
26252
26922
|
if (appArguments.length > 0) {
|
|
26253
|
-
appArguments = appArguments.map((argument) =>
|
|
26923
|
+
appArguments = appArguments.map((argument) => executePowerShell2.escapeArgument(argument));
|
|
26254
26924
|
encodedArguments.push("-ArgumentList", appArguments.join(","));
|
|
26255
26925
|
}
|
|
26256
|
-
options.target =
|
|
26926
|
+
options.target = executePowerShell2.encodeCommand(encodedArguments.join(" "));
|
|
26257
26927
|
if (!options.wait) {
|
|
26258
26928
|
childProcessOptions.stdio = "ignore";
|
|
26259
26929
|
}
|
|
26930
|
+
if (is_wsl_default) {
|
|
26931
|
+
childProcessOptions.cwd = path4.dirname(command);
|
|
26932
|
+
}
|
|
26260
26933
|
} else {
|
|
26261
26934
|
if (app) {
|
|
26262
26935
|
command = app;
|
|
@@ -26268,7 +26941,7 @@ var baseOpen = async (options) => {
|
|
|
26268
26941
|
exeLocalXdgOpen = true;
|
|
26269
26942
|
} catch {
|
|
26270
26943
|
}
|
|
26271
|
-
const useSystemXdgOpen =
|
|
26944
|
+
const useSystemXdgOpen = process11.versions.electron ?? (platform === "android" || isBundled || !exeLocalXdgOpen);
|
|
26272
26945
|
command = useSystemXdgOpen ? "xdg-open" : localXdgOpenPath;
|
|
26273
26946
|
}
|
|
26274
26947
|
if (appArguments.length > 0) {
|
|
@@ -26285,7 +26958,7 @@ var baseOpen = async (options) => {
|
|
|
26285
26958
|
if (options.target) {
|
|
26286
26959
|
cliArguments.push(options.target);
|
|
26287
26960
|
}
|
|
26288
|
-
const subprocess =
|
|
26961
|
+
const subprocess = childProcess4.spawn(command, cliArguments, childProcessOptions);
|
|
26289
26962
|
if (options.wait) {
|
|
26290
26963
|
return new Promise((resolve, reject) => {
|
|
26291
26964
|
subprocess.once("error", reject);
|
|
@@ -26432,33 +27105,44 @@ var AgentMode = class _AgentMode {
|
|
|
26432
27105
|
id;
|
|
26433
27106
|
name;
|
|
26434
27107
|
description;
|
|
27108
|
+
kind;
|
|
26435
27109
|
approvalPolicy;
|
|
27110
|
+
approvalsReviewer;
|
|
26436
27111
|
sandboxPolicy;
|
|
26437
27112
|
sandboxMode;
|
|
26438
|
-
constructor(id, name, description,
|
|
27113
|
+
constructor(id, name, description, kind, approvalPolicy, approvalsReviewer, sandboxPolicy, sandboxMode) {
|
|
26439
27114
|
this.id = id;
|
|
26440
27115
|
this.name = name;
|
|
26441
27116
|
this.description = description;
|
|
26442
|
-
this.
|
|
26443
|
-
this.
|
|
27117
|
+
this.kind = kind;
|
|
27118
|
+
this.approvalPolicy = approvalPolicy;
|
|
27119
|
+
this.approvalsReviewer = approvalsReviewer;
|
|
27120
|
+
this.sandboxPolicy = sandboxPolicy;
|
|
26444
27121
|
this.sandboxMode = sandboxMode;
|
|
26445
27122
|
}
|
|
26446
27123
|
static ReadOnly = new _AgentMode(
|
|
26447
27124
|
"read-only",
|
|
26448
|
-
"
|
|
26449
|
-
"
|
|
27125
|
+
"Ask for approval",
|
|
27126
|
+
"Always ask to edit external files and use the internet",
|
|
27127
|
+
"standard",
|
|
26450
27128
|
"on-request",
|
|
27129
|
+
"user",
|
|
26451
27130
|
{
|
|
26452
|
-
|
|
26453
|
-
|
|
27131
|
+
type: "workspaceWrite",
|
|
27132
|
+
writableRoots: [],
|
|
27133
|
+
networkAccess: false,
|
|
27134
|
+
excludeTmpdirEnvVar: false,
|
|
27135
|
+
excludeSlashTmp: false
|
|
26454
27136
|
},
|
|
26455
|
-
"
|
|
27137
|
+
"workspace-write"
|
|
26456
27138
|
);
|
|
26457
27139
|
static Agent = new _AgentMode(
|
|
26458
27140
|
"agent",
|
|
26459
|
-
"
|
|
26460
|
-
"
|
|
27141
|
+
"Approve for me",
|
|
27142
|
+
"Only ask for actions detected as potentially unsafe",
|
|
27143
|
+
"auto_review",
|
|
26461
27144
|
"on-request",
|
|
27145
|
+
"auto_review",
|
|
26462
27146
|
{
|
|
26463
27147
|
type: "workspaceWrite",
|
|
26464
27148
|
writableRoots: [],
|
|
@@ -26470,9 +27154,11 @@ var AgentMode = class _AgentMode {
|
|
|
26470
27154
|
);
|
|
26471
27155
|
static AgentFullAccess = new _AgentMode(
|
|
26472
27156
|
"agent-full-access",
|
|
26473
|
-
"
|
|
26474
|
-
"
|
|
27157
|
+
"Full access",
|
|
27158
|
+
"Unrestricted access to the internet and any file on your computer",
|
|
27159
|
+
"full_access",
|
|
26475
27160
|
"never",
|
|
27161
|
+
"user",
|
|
26476
27162
|
{ "type": "dangerFullAccess" },
|
|
26477
27163
|
"danger-full-access"
|
|
26478
27164
|
);
|
|
@@ -26481,7 +27167,8 @@ var AgentMode = class _AgentMode {
|
|
|
26481
27167
|
return {
|
|
26482
27168
|
id: this.id,
|
|
26483
27169
|
name: this.name,
|
|
26484
|
-
description: this.description
|
|
27170
|
+
description: this.description,
|
|
27171
|
+
_meta: { kind: this.kind }
|
|
26485
27172
|
};
|
|
26486
27173
|
}
|
|
26487
27174
|
toSessionModeState() {
|
|
@@ -26501,7 +27188,8 @@ var AgentMode = class _AgentMode {
|
|
|
26501
27188
|
options: _AgentMode.all().map((mode) => ({
|
|
26502
27189
|
value: mode.id,
|
|
26503
27190
|
name: mode.name,
|
|
26504
|
-
description: mode.description
|
|
27191
|
+
description: mode.description,
|
|
27192
|
+
_meta: { kind: mode.kind }
|
|
26505
27193
|
}))
|
|
26506
27194
|
};
|
|
26507
27195
|
}
|
|
@@ -26523,7 +27211,7 @@ var AgentMode = class _AgentMode {
|
|
|
26523
27211
|
};
|
|
26524
27212
|
|
|
26525
27213
|
// src/CodexAcpClient.ts
|
|
26526
|
-
import
|
|
27214
|
+
import path7 from "node:path";
|
|
26527
27215
|
|
|
26528
27216
|
// src/McpServerName.ts
|
|
26529
27217
|
var MCP_SERVER_NAME_WHITESPACE = /\p{White_Space}/gu;
|
|
@@ -26537,7 +27225,7 @@ var package_default = {
|
|
|
26537
27225
|
publishConfig: {
|
|
26538
27226
|
access: "public"
|
|
26539
27227
|
},
|
|
26540
|
-
version: "1.
|
|
27228
|
+
version: "1.7.0",
|
|
26541
27229
|
description: "",
|
|
26542
27230
|
main: "dist/index.js",
|
|
26543
27231
|
bin: {
|
|
@@ -26571,7 +27259,7 @@ var package_default = {
|
|
|
26571
27259
|
"example:steering:multistep": "node --import tsx examples/steering.ts",
|
|
26572
27260
|
"generate-types": "./node_modules/.bin/codex app-server generate-ts --out src/app-server",
|
|
26573
27261
|
"release:preflight": "bash scripts/release-preflight.sh",
|
|
26574
|
-
test: "vitest run",
|
|
27262
|
+
test: "vitest run --no-file-parallelism --retry=2",
|
|
26575
27263
|
"test:e2e": "npm run build && RUN_E2E_TESTS=true vitest run --no-file-parallelism --retry=2 src/__tests__/CodexACPAgent/e2e",
|
|
26576
27264
|
"test:watch": "vitest",
|
|
26577
27265
|
typecheck: "tsc --noEmit && tsc --noEmit -p examples/tsconfig.json",
|
|
@@ -26591,17 +27279,17 @@ var package_default = {
|
|
|
26591
27279
|
type: "module",
|
|
26592
27280
|
devDependencies: {
|
|
26593
27281
|
"@types/node": "^26.1.0",
|
|
26594
|
-
esbuild: "^0.28.
|
|
27282
|
+
esbuild: "^0.28.2",
|
|
26595
27283
|
"mcp-hello-world": "^1.1.2",
|
|
26596
|
-
tsx: "^4.23.
|
|
27284
|
+
tsx: "^4.23.12",
|
|
26597
27285
|
typescript: "^7.0.2",
|
|
26598
|
-
vitest: "^4.1.
|
|
27286
|
+
vitest: "^4.1.11"
|
|
26599
27287
|
},
|
|
26600
27288
|
dependencies: {
|
|
26601
|
-
"@agentclientprotocol/sdk": "^1.
|
|
27289
|
+
"@agentclientprotocol/sdk": "^1.4.0",
|
|
26602
27290
|
"@openai/codex": "^0.148.0",
|
|
26603
27291
|
diff: "^9.0.0",
|
|
26604
|
-
open: "^11.0.
|
|
27292
|
+
open: "^11.0.1",
|
|
26605
27293
|
"vscode-jsonrpc": "^9.0.1",
|
|
26606
27294
|
zod: "^4.0.0"
|
|
26607
27295
|
}
|
|
@@ -26643,17 +27331,17 @@ function createCodexCollaborationMode(mode, currentModelId) {
|
|
|
26643
27331
|
}
|
|
26644
27332
|
|
|
26645
27333
|
// src/PathUtils.ts
|
|
26646
|
-
import
|
|
27334
|
+
import path5 from "node:path";
|
|
26647
27335
|
function isAbsolutePathLike(value) {
|
|
26648
27336
|
const trimmed = value.trim();
|
|
26649
|
-
return
|
|
27337
|
+
return path5.isAbsolute(trimmed) || isWindowsAbsolutePath(trimmed);
|
|
26650
27338
|
}
|
|
26651
27339
|
function arePathsEqual(left, right) {
|
|
26652
27340
|
return normalizePathForComparison(left) === normalizePathForComparison(right);
|
|
26653
27341
|
}
|
|
26654
27342
|
function arePathBasenamesEqual(left, right) {
|
|
26655
|
-
const leftBase =
|
|
26656
|
-
const rightBase =
|
|
27343
|
+
const leftBase = path5.posix.basename(normalizePathForComparison(left));
|
|
27344
|
+
const rightBase = path5.posix.basename(normalizePathForComparison(right));
|
|
26657
27345
|
if (shouldComparePathCaseInsensitive(left) || shouldComparePathCaseInsensitive(right)) {
|
|
26658
27346
|
return leftBase.toLowerCase() === rightBase.toLowerCase();
|
|
26659
27347
|
}
|
|
@@ -26665,11 +27353,11 @@ function normalizePathForComparison(value) {
|
|
|
26665
27353
|
return "";
|
|
26666
27354
|
}
|
|
26667
27355
|
if (isWindowsAbsolutePath(trimmed)) {
|
|
26668
|
-
const normalized2 =
|
|
27356
|
+
const normalized2 = path5.win32.normalize(trimmed).replace(/\\/g, "/");
|
|
26669
27357
|
return trimTrailingPathSeparators(normalized2).toLowerCase();
|
|
26670
27358
|
}
|
|
26671
|
-
const pathForComparison =
|
|
26672
|
-
const normalized =
|
|
27359
|
+
const pathForComparison = path5.isAbsolute(trimmed) ? trimmed : trimmed.replace(/\\/g, "/");
|
|
27360
|
+
const normalized = path5.posix.normalize(pathForComparison);
|
|
26673
27361
|
return trimTrailingPathSeparators(normalized);
|
|
26674
27362
|
}
|
|
26675
27363
|
function isWindowsAbsolutePath(value) {
|
|
@@ -26692,7 +27380,7 @@ function isRootPath(value) {
|
|
|
26692
27380
|
|
|
26693
27381
|
// src/AgentFileChangeReport.ts
|
|
26694
27382
|
import fs7 from "node:fs";
|
|
26695
|
-
import
|
|
27383
|
+
import path6 from "node:path";
|
|
26696
27384
|
var AGENT_FILE_CHANGE_REPORT_VERSION = 1;
|
|
26697
27385
|
var AGENT_FILE_CHANGE_REPORT_TIMEOUT_MS = 3e4;
|
|
26698
27386
|
var AGENT_FILE_CHANGE_REPORT_MAX_PATHS = 1024;
|
|
@@ -26702,7 +27390,7 @@ var AGENT_FILE_CHANGE_REPORT_MAX_UNCERTAINTY_LENGTH = 2e3;
|
|
|
26702
27390
|
var AGENT_FILE_CHANGE_REPORT_OUTPUT_SCHEMA = {
|
|
26703
27391
|
type: "object",
|
|
26704
27392
|
additionalProperties: false,
|
|
26705
|
-
required: ["paths", "complete"],
|
|
27393
|
+
required: ["paths", "complete", "uncertainty"],
|
|
26706
27394
|
properties: {
|
|
26707
27395
|
paths: {
|
|
26708
27396
|
type: "array",
|
|
@@ -26710,8 +27398,12 @@ var AGENT_FILE_CHANGE_REPORT_OUTPUT_SCHEMA = {
|
|
|
26710
27398
|
},
|
|
26711
27399
|
complete: { type: "boolean" },
|
|
26712
27400
|
uncertainty: {
|
|
26713
|
-
|
|
26714
|
-
|
|
27401
|
+
anyOf: [{
|
|
27402
|
+
type: "string",
|
|
27403
|
+
maxLength: AGENT_FILE_CHANGE_REPORT_MAX_UNCERTAINTY_LENGTH
|
|
27404
|
+
}, {
|
|
27405
|
+
type: "null"
|
|
27406
|
+
}]
|
|
26715
27407
|
}
|
|
26716
27408
|
}
|
|
26717
27409
|
};
|
|
@@ -26771,7 +27463,10 @@ function parseModelFileChangeReport(turn) {
|
|
|
26771
27463
|
case "interrupted":
|
|
26772
27464
|
throw new AgentFileChangeReportError("cancelled", "The audit turn was interrupted");
|
|
26773
27465
|
case "failed":
|
|
26774
|
-
throw new AgentFileChangeReportError(
|
|
27466
|
+
throw new AgentFileChangeReportError(
|
|
27467
|
+
"providerError",
|
|
27468
|
+
`The audit turn failed${turn.error?.message ? `: ${turn.error.message}` : ""}`
|
|
27469
|
+
);
|
|
26775
27470
|
case "inProgress":
|
|
26776
27471
|
throw new AgentFileChangeReportError("notReported", "The audit turn did not complete");
|
|
26777
27472
|
case "completed":
|
|
@@ -26801,10 +27496,10 @@ function parseModelFileChangeReport(turn) {
|
|
|
26801
27496
|
const paths = report["paths"];
|
|
26802
27497
|
const complete = report["complete"];
|
|
26803
27498
|
const uncertainty = report["uncertainty"];
|
|
26804
|
-
if (!Array.isArray(paths) || !paths.every((item) => typeof item === "string") || typeof complete !== "boolean" || uncertainty !== void 0 && typeof uncertainty !== "string") {
|
|
27499
|
+
if (!Array.isArray(paths) || !paths.every((item) => typeof item === "string") || typeof complete !== "boolean" || uncertainty !== void 0 && uncertainty !== null && typeof uncertainty !== "string") {
|
|
26805
27500
|
throw new AgentFileChangeReportError("invalidOutput", "The audit turn returned invalid fields");
|
|
26806
27501
|
}
|
|
26807
|
-
const normalizedUncertainty = uncertainty
|
|
27502
|
+
const normalizedUncertainty = typeof uncertainty === "string" ? uncertainty.trim() : void 0;
|
|
26808
27503
|
if (normalizedUncertainty !== void 0 && normalizedUncertainty.length > AGENT_FILE_CHANGE_REPORT_MAX_UNCERTAINTY_LENGTH) {
|
|
26809
27504
|
throw new AgentFileChangeReportError("invalidOutput", "The audit turn returned oversized uncertainty");
|
|
26810
27505
|
}
|
|
@@ -26883,13 +27578,13 @@ function normalizeWorkspaceRoot(value) {
|
|
|
26883
27578
|
}
|
|
26884
27579
|
if (isWindowsAbsolutePath2(trimmed)) {
|
|
26885
27580
|
return canonicalizeWorkspaceRoot({
|
|
26886
|
-
value:
|
|
27581
|
+
value: path6.win32.normalize(trimmed.replace(/\//g, "\\")),
|
|
26887
27582
|
flavor: "windows"
|
|
26888
27583
|
});
|
|
26889
27584
|
}
|
|
26890
|
-
if (
|
|
27585
|
+
if (path6.posix.isAbsolute(trimmed)) {
|
|
26891
27586
|
return canonicalizeWorkspaceRoot({
|
|
26892
|
-
value:
|
|
27587
|
+
value: path6.posix.normalize(trimmed.replace(/\\/g, "/")),
|
|
26893
27588
|
flavor: "posix"
|
|
26894
27589
|
});
|
|
26895
27590
|
}
|
|
@@ -26902,17 +27597,17 @@ function normalizeReportedPath(value, cwd, roots) {
|
|
|
26902
27597
|
}
|
|
26903
27598
|
let candidate;
|
|
26904
27599
|
if (isWindowsAbsolutePath2(trimmed)) {
|
|
26905
|
-
candidate = { value:
|
|
26906
|
-
} else if (
|
|
26907
|
-
candidate = { value:
|
|
27600
|
+
candidate = { value: path6.win32.normalize(trimmed.replace(/\//g, "\\")), flavor: "windows" };
|
|
27601
|
+
} else if (path6.posix.isAbsolute(trimmed)) {
|
|
27602
|
+
candidate = { value: path6.posix.normalize(trimmed.replace(/\\/g, "/")), flavor: "posix" };
|
|
26908
27603
|
} else if (cwd.flavor === "windows") {
|
|
26909
27604
|
candidate = {
|
|
26910
|
-
value:
|
|
27605
|
+
value: path6.win32.resolve(cwd.value, trimmed.replace(/\//g, "\\")),
|
|
26911
27606
|
flavor: "windows"
|
|
26912
27607
|
};
|
|
26913
27608
|
} else {
|
|
26914
27609
|
candidate = {
|
|
26915
|
-
value:
|
|
27610
|
+
value: path6.posix.resolve(cwd.value, trimmed.replace(/\\/g, "/")),
|
|
26916
27611
|
flavor: "posix"
|
|
26917
27612
|
};
|
|
26918
27613
|
}
|
|
@@ -26929,23 +27624,23 @@ function canonicalizeReportedPath(candidate) {
|
|
|
26929
27624
|
if (!isNativePathFlavor(candidate.flavor)) {
|
|
26930
27625
|
return candidate;
|
|
26931
27626
|
}
|
|
26932
|
-
const parent = canonicalizeFromExistingAncestor(
|
|
26933
|
-
return { ...candidate, value:
|
|
27627
|
+
const parent = canonicalizeFromExistingAncestor(path6.dirname(candidate.value));
|
|
27628
|
+
return { ...candidate, value: path6.resolve(parent, path6.basename(candidate.value)) };
|
|
26934
27629
|
}
|
|
26935
27630
|
function canonicalizeFromExistingAncestor(value) {
|
|
26936
|
-
const original =
|
|
27631
|
+
const original = path6.resolve(value);
|
|
26937
27632
|
let current = original;
|
|
26938
27633
|
const missingSegments = [];
|
|
26939
27634
|
while (true) {
|
|
26940
27635
|
try {
|
|
26941
27636
|
const canonical = fs7.realpathSync.native(current);
|
|
26942
|
-
return
|
|
27637
|
+
return path6.resolve(canonical, ...missingSegments.reverse());
|
|
26943
27638
|
} catch (error51) {
|
|
26944
27639
|
if (!isMissingPathError(error51)) return original;
|
|
26945
27640
|
}
|
|
26946
|
-
const parent =
|
|
27641
|
+
const parent = path6.dirname(current);
|
|
26947
27642
|
if (parent === current) return original;
|
|
26948
|
-
missingSegments.push(
|
|
27643
|
+
missingSegments.push(path6.basename(current));
|
|
26949
27644
|
current = parent;
|
|
26950
27645
|
}
|
|
26951
27646
|
}
|
|
@@ -26960,7 +27655,7 @@ function pathIsStrictlyInside(root, candidate) {
|
|
|
26960
27655
|
if (root.flavor !== candidate.flavor) {
|
|
26961
27656
|
return false;
|
|
26962
27657
|
}
|
|
26963
|
-
const pathImplementation = root.flavor === "windows" ?
|
|
27658
|
+
const pathImplementation = root.flavor === "windows" ? path6.win32 : path6.posix;
|
|
26964
27659
|
const relative = pathImplementation.relative(root.value, candidate.value);
|
|
26965
27660
|
return relative.length > 0 && !pathImplementation.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${pathImplementation.sep}`);
|
|
26966
27661
|
}
|
|
@@ -26979,6 +27674,120 @@ function hasOnlyKeys(value, allowed) {
|
|
|
26979
27674
|
return Object.keys(value).every((key) => allowedKeys.has(key));
|
|
26980
27675
|
}
|
|
26981
27676
|
|
|
27677
|
+
// src/subagents/CodexSubagentSubscriptions.ts
|
|
27678
|
+
var CodexSubagentSubscriptions = class {
|
|
27679
|
+
constructor(client) {
|
|
27680
|
+
this.client = client;
|
|
27681
|
+
}
|
|
27682
|
+
client;
|
|
27683
|
+
sessions = /* @__PURE__ */ new Map();
|
|
27684
|
+
subscribe(subscription) {
|
|
27685
|
+
const existing = this.sessions.get(subscription.rootSessionId);
|
|
27686
|
+
if (existing) {
|
|
27687
|
+
existing.current = subscription;
|
|
27688
|
+
return;
|
|
27689
|
+
}
|
|
27690
|
+
const session = { current: subscription, children: /* @__PURE__ */ new Set() };
|
|
27691
|
+
this.sessions.set(subscription.rootSessionId, session);
|
|
27692
|
+
this.client.onServerNotification(subscription.rootSessionId, (event) => {
|
|
27693
|
+
this.discover(session, event);
|
|
27694
|
+
session.current.dispatch(event);
|
|
27695
|
+
});
|
|
27696
|
+
this.registerInteractiveHandlers(session, subscription.rootSessionId);
|
|
27697
|
+
}
|
|
27698
|
+
clear(rootSessionId) {
|
|
27699
|
+
for (const childSessionId of this.sessions.get(rootSessionId)?.children ?? []) {
|
|
27700
|
+
this.client.clearThreadHandlers(childSessionId);
|
|
27701
|
+
}
|
|
27702
|
+
this.sessions.delete(rootSessionId);
|
|
27703
|
+
}
|
|
27704
|
+
discover(session, event) {
|
|
27705
|
+
if (event.method !== "item/started" && event.method !== "item/completed") {
|
|
27706
|
+
return;
|
|
27707
|
+
}
|
|
27708
|
+
const item = event.params.item;
|
|
27709
|
+
const childSessionIds = item.type === "collabAgentToolCall" && item.tool === "spawnAgent" ? item.receiverThreadIds : item.type === "subAgentActivity" && item.kind !== "interrupted" && !isRootAgentPath(item.agentPath) ? [item.agentThreadId] : [];
|
|
27710
|
+
for (const childSessionId of childSessionIds) {
|
|
27711
|
+
if (childSessionId.trim() === "") continue;
|
|
27712
|
+
if (childSessionId === session.current.rootSessionId || childSessionId === event.params.threadId || session.children.has(childSessionId)) {
|
|
27713
|
+
continue;
|
|
27714
|
+
}
|
|
27715
|
+
session.children.add(childSessionId);
|
|
27716
|
+
this.client.onServerNotification(childSessionId, (childEvent) => {
|
|
27717
|
+
const eventThreadId = childEvent.params.threadId;
|
|
27718
|
+
if (eventThreadId !== childSessionId) return;
|
|
27719
|
+
this.discover(session, childEvent);
|
|
27720
|
+
if (session.current.supportsSubagents) session.current.dispatch(childEvent);
|
|
27721
|
+
else session.current.enqueueInteraction(this.rootAttributed(childEvent, session.current.rootSessionId));
|
|
27722
|
+
});
|
|
27723
|
+
this.registerInteractiveHandlers(session, childSessionId);
|
|
27724
|
+
}
|
|
27725
|
+
}
|
|
27726
|
+
registerInteractiveHandlers(session, targetSessionId) {
|
|
27727
|
+
this.client.onApprovalRequest(targetSessionId, {
|
|
27728
|
+
handleCommandExecution: async (params) => {
|
|
27729
|
+
const current = session.current;
|
|
27730
|
+
await current.waitForRootNotifications();
|
|
27731
|
+
const sessionId = await this.interactionSessionId(current, targetSessionId);
|
|
27732
|
+
if (sessionId === null) return { decision: "cancel" };
|
|
27733
|
+
return await current.approvalHandler.handleCommandExecution(
|
|
27734
|
+
{ ...params, threadId: sessionId }
|
|
27735
|
+
);
|
|
27736
|
+
},
|
|
27737
|
+
handleFileChange: async (params) => {
|
|
27738
|
+
const current = session.current;
|
|
27739
|
+
await current.waitForRootNotifications();
|
|
27740
|
+
const sessionId = await this.interactionSessionId(current, targetSessionId);
|
|
27741
|
+
if (sessionId === null) return { decision: "cancel" };
|
|
27742
|
+
return await current.approvalHandler.handleFileChange(
|
|
27743
|
+
{ ...params, threadId: sessionId }
|
|
27744
|
+
);
|
|
27745
|
+
},
|
|
27746
|
+
handlePermissionsRequest: async (params) => {
|
|
27747
|
+
const current = session.current;
|
|
27748
|
+
await current.waitForRootNotifications();
|
|
27749
|
+
const sessionId = await this.interactionSessionId(current, targetSessionId);
|
|
27750
|
+
if (sessionId === null) return { permissions: {}, scope: "turn", strictAutoReview: false };
|
|
27751
|
+
return await current.approvalHandler.handlePermissionsRequest(
|
|
27752
|
+
{ ...params, threadId: sessionId }
|
|
27753
|
+
);
|
|
27754
|
+
}
|
|
27755
|
+
});
|
|
27756
|
+
this.client.onElicitationRequest(targetSessionId, {
|
|
27757
|
+
handleElicitation: async (params) => {
|
|
27758
|
+
const current = session.current;
|
|
27759
|
+
await current.waitForRootNotifications();
|
|
27760
|
+
const sessionId = await this.interactionSessionId(current, targetSessionId);
|
|
27761
|
+
if (sessionId === null) return { action: "cancel", content: null, _meta: null };
|
|
27762
|
+
return await current.elicitationHandler.handleElicitation(
|
|
27763
|
+
{ ...params, threadId: sessionId }
|
|
27764
|
+
);
|
|
27765
|
+
},
|
|
27766
|
+
handleUserInput: async (params) => {
|
|
27767
|
+
const current = session.current;
|
|
27768
|
+
await current.waitForRootNotifications();
|
|
27769
|
+
const sessionId = await this.interactionSessionId(current, targetSessionId);
|
|
27770
|
+
if (sessionId === null) return { answers: {} };
|
|
27771
|
+
return await current.elicitationHandler.handleUserInput(
|
|
27772
|
+
{ ...params, threadId: sessionId }
|
|
27773
|
+
);
|
|
27774
|
+
}
|
|
27775
|
+
});
|
|
27776
|
+
}
|
|
27777
|
+
async interactionSessionId(subscription, targetSessionId) {
|
|
27778
|
+
if (targetSessionId === subscription.rootSessionId) return targetSessionId;
|
|
27779
|
+
if (!subscription.supportsSubagents) return subscription.rootSessionId;
|
|
27780
|
+
return await subscription.waitForChildSession(targetSessionId);
|
|
27781
|
+
}
|
|
27782
|
+
rootAttributed(event, rootSessionId) {
|
|
27783
|
+
if (typeof event.params.threadId !== "string") return event;
|
|
27784
|
+
return {
|
|
27785
|
+
...event,
|
|
27786
|
+
params: { ...event.params, threadId: rootSessionId }
|
|
27787
|
+
};
|
|
27788
|
+
}
|
|
27789
|
+
};
|
|
27790
|
+
|
|
26982
27791
|
// src/CodexAcpClient.ts
|
|
26983
27792
|
var CUSTOM_GATEWAY_PROVIDER_ID = "custom-gateway";
|
|
26984
27793
|
var OPENAI_PROVIDER_ID = "openai";
|
|
@@ -26994,6 +27803,7 @@ var CodexAcpClient = class {
|
|
|
26994
27803
|
pendingLoginCompleted = null;
|
|
26995
27804
|
pendingAccountUpdated = null;
|
|
26996
27805
|
sessionNotificationQueues = /* @__PURE__ */ new Map();
|
|
27806
|
+
subagents;
|
|
26997
27807
|
skillExtraRoots = [];
|
|
26998
27808
|
configPath = null;
|
|
26999
27809
|
constructor(codexClient, codexConfig, modelProvider) {
|
|
@@ -27001,6 +27811,7 @@ var CodexAcpClient = class {
|
|
|
27001
27811
|
this.config = codexConfig ?? {};
|
|
27002
27812
|
this.modelProvider = modelProvider ?? null;
|
|
27003
27813
|
this.gatewayConfig = null;
|
|
27814
|
+
this.subagents = new CodexSubagentSubscriptions(codexClient);
|
|
27004
27815
|
}
|
|
27005
27816
|
defaultClientInfo = {
|
|
27006
27817
|
name: `${package_default.name}`,
|
|
@@ -27076,16 +27887,31 @@ var CodexAcpClient = class {
|
|
|
27076
27887
|
if (loginResponse.type !== "chatgptDeviceCode") {
|
|
27077
27888
|
return false;
|
|
27078
27889
|
}
|
|
27079
|
-
const
|
|
27890
|
+
const elicitationResponsePromise = Promise.resolve(urlElicitationRequester.elicitUrl({
|
|
27080
27891
|
url: loginResponse.verificationUrl,
|
|
27081
27892
|
message: `Sign in to ChatGPT and enter this code: ${loginResponse.userCode}`,
|
|
27082
27893
|
elicitationId: loginResponse.loginId
|
|
27083
|
-
});
|
|
27084
|
-
|
|
27894
|
+
}));
|
|
27895
|
+
const first = await Promise.race([
|
|
27896
|
+
loginCompletedPromise.then((result2) => ({
|
|
27897
|
+
type: "loginCompleted",
|
|
27898
|
+
result: result2
|
|
27899
|
+
})),
|
|
27900
|
+
elicitationResponsePromise.then((response) => ({
|
|
27901
|
+
type: "elicitationResponse",
|
|
27902
|
+
response
|
|
27903
|
+
}))
|
|
27904
|
+
]);
|
|
27905
|
+
if (first.type === "loginCompleted") {
|
|
27906
|
+
await urlElicitationRequester.completeElicitation();
|
|
27907
|
+
return first.result.success;
|
|
27908
|
+
}
|
|
27909
|
+
if (!CreateElicitationResponse.isAccept(first.response)) {
|
|
27085
27910
|
await this.codexClient.accountLoginCancel({ loginId: loginResponse.loginId });
|
|
27086
27911
|
return false;
|
|
27087
27912
|
}
|
|
27088
27913
|
const result = await loginCompletedPromise;
|
|
27914
|
+
await urlElicitationRequester.completeElicitation();
|
|
27089
27915
|
return result.success;
|
|
27090
27916
|
}
|
|
27091
27917
|
authenticateWithGateway(authRequest) {
|
|
@@ -27331,6 +28157,12 @@ var CodexAcpClient = class {
|
|
|
27331
28157
|
additionalDirectories
|
|
27332
28158
|
};
|
|
27333
28159
|
}
|
|
28160
|
+
async readSessionThread(sessionId) {
|
|
28161
|
+
return (await this.codexClient.threadRead({
|
|
28162
|
+
threadId: sessionId,
|
|
28163
|
+
includeTurns: true
|
|
28164
|
+
})).thread;
|
|
28165
|
+
}
|
|
27334
28166
|
async newSession(request) {
|
|
27335
28167
|
const additionalDirectories = readAdditionalDirectories(request.cwd, request.additionalDirectories, request._meta);
|
|
27336
28168
|
await this.refreshSkills(request.cwd, additionalDirectories);
|
|
@@ -27359,6 +28191,7 @@ var CodexAcpClient = class {
|
|
|
27359
28191
|
await this.codexClient.threadUnsubscribe({ threadId: sessionId });
|
|
27360
28192
|
} finally {
|
|
27361
28193
|
this.codexClient.clearThreadHandlers(sessionId);
|
|
28194
|
+
this.subagents.clear(sessionId);
|
|
27362
28195
|
}
|
|
27363
28196
|
}
|
|
27364
28197
|
async deleteSession(sessionId) {
|
|
@@ -27484,7 +28317,7 @@ var CodexAcpClient = class {
|
|
|
27484
28317
|
if (!cwd) {
|
|
27485
28318
|
return;
|
|
27486
28319
|
}
|
|
27487
|
-
const skillExtraRoots = additionalRoots.map((root) =>
|
|
28320
|
+
const skillExtraRoots = additionalRoots.map((root) => path7.join(root, ".agents", "skills"));
|
|
27488
28321
|
if (!arraysEqual(this.skillExtraRoots, skillExtraRoots)) {
|
|
27489
28322
|
await this.codexClient.skillsExtraRootsSet({ extraRoots: skillExtraRoots });
|
|
27490
28323
|
this.skillExtraRoots = skillExtraRoots;
|
|
@@ -27535,33 +28368,21 @@ var CodexAcpClient = class {
|
|
|
27535
28368
|
}
|
|
27536
28369
|
return ModelId.create(defaultModel.id, reasoningEffort ?? defaultModel.defaultReasoningEffort);
|
|
27537
28370
|
}
|
|
27538
|
-
async subscribeToSessionEvents(sessionId, eventHandler, approvalHandler, elicitationHandler) {
|
|
27539
|
-
|
|
28371
|
+
async subscribeToSessionEvents(sessionId, eventHandler, approvalHandler, elicitationHandler, supportsSubagents, observeInteraction, waitForChildSession) {
|
|
28372
|
+
const dispatch = (event) => {
|
|
27540
28373
|
this.enqueueSessionNotification(sessionId, () => eventHandler(event));
|
|
27541
|
-
}
|
|
27542
|
-
this.
|
|
27543
|
-
|
|
27544
|
-
|
|
27545
|
-
|
|
27546
|
-
|
|
27547
|
-
|
|
27548
|
-
await this.waitForSessionNotifications(sessionId);
|
|
27549
|
-
return await approvalHandler.handleFileChange(params);
|
|
27550
|
-
},
|
|
27551
|
-
handlePermissionsRequest: async (params) => {
|
|
27552
|
-
await this.waitForSessionNotifications(sessionId);
|
|
27553
|
-
return await approvalHandler.handlePermissionsRequest(params);
|
|
27554
|
-
}
|
|
27555
|
-
});
|
|
27556
|
-
this.codexClient.onElicitationRequest(sessionId, {
|
|
27557
|
-
handleElicitation: async (params) => {
|
|
27558
|
-
await this.waitForSessionNotifications(sessionId);
|
|
27559
|
-
return await elicitationHandler.handleElicitation(params);
|
|
28374
|
+
};
|
|
28375
|
+
this.subagents.subscribe({
|
|
28376
|
+
rootSessionId: sessionId,
|
|
28377
|
+
supportsSubagents,
|
|
28378
|
+
dispatch,
|
|
28379
|
+
enqueueInteraction: (event) => {
|
|
28380
|
+
this.enqueueSessionNotification(sessionId, () => observeInteraction(event));
|
|
27560
28381
|
},
|
|
27561
|
-
|
|
27562
|
-
|
|
27563
|
-
|
|
27564
|
-
|
|
28382
|
+
approvalHandler,
|
|
28383
|
+
elicitationHandler,
|
|
28384
|
+
waitForRootNotifications: () => this.waitForSessionNotifications(sessionId),
|
|
28385
|
+
waitForChildSession
|
|
27565
28386
|
});
|
|
27566
28387
|
}
|
|
27567
28388
|
async waitForSessionNotifications(sessionId) {
|
|
@@ -27599,6 +28420,7 @@ var CodexAcpClient = class {
|
|
|
27599
28420
|
threadId: request.sessionId,
|
|
27600
28421
|
input,
|
|
27601
28422
|
approvalPolicy: agentMode.approvalPolicy,
|
|
28423
|
+
approvalsReviewer: agentMode.approvalsReviewer,
|
|
27602
28424
|
sandboxPolicy: addAdditionalDirectoriesToSandboxPolicy(agentMode.sandboxPolicy, additionalDirectories),
|
|
27603
28425
|
summary: disableSummary ? "none" : "auto",
|
|
27604
28426
|
effort,
|
|
@@ -27653,22 +28475,9 @@ var CodexAcpClient = class {
|
|
|
27653
28475
|
});
|
|
27654
28476
|
const outcome = await budget.wait(turnPromise);
|
|
27655
28477
|
auditTurnCompleted = true;
|
|
27656
|
-
const thread = await budget.wait(this.codexClient.threadRead({
|
|
27657
|
-
threadId: forkThreadId,
|
|
27658
|
-
includeTurns: true
|
|
27659
|
-
}));
|
|
27660
|
-
const completedTurn = thread.thread.turns.find(
|
|
27661
|
-
(turn) => turn.id === outcome.turn.id
|
|
27662
|
-
);
|
|
27663
|
-
if (completedTurn === void 0) {
|
|
27664
|
-
throw new AgentFileChangeReportError(
|
|
27665
|
-
"notReported",
|
|
27666
|
-
"The completed audit turn was not present in thread history"
|
|
27667
|
-
);
|
|
27668
|
-
}
|
|
27669
28478
|
return createReportedAgentFileChangeReport(
|
|
27670
28479
|
params.requestId,
|
|
27671
|
-
|
|
28480
|
+
outcome.turn,
|
|
27672
28481
|
params.workspace
|
|
27673
28482
|
);
|
|
27674
28483
|
} catch (error51) {
|
|
@@ -27685,7 +28494,7 @@ var CodexAcpClient = class {
|
|
|
27685
28494
|
return createUnavailableAgentFileChangeReport(params.requestId, error51.reason);
|
|
27686
28495
|
}
|
|
27687
28496
|
if (error51 instanceof AgentFileChangeReportError) {
|
|
27688
|
-
logger.
|
|
28497
|
+
logger.error("Agent file-change report unavailable", error51);
|
|
27689
28498
|
return createUnavailableAgentFileChangeReport(params.requestId, error51.reason);
|
|
27690
28499
|
}
|
|
27691
28500
|
logger.error("Agent file-change report failed", error51);
|
|
@@ -27974,8 +28783,8 @@ function formatUriAsLink(name, uri) {
|
|
|
27974
28783
|
return `[@${name}](${uri})`;
|
|
27975
28784
|
}
|
|
27976
28785
|
if (uri.startsWith("file://")) {
|
|
27977
|
-
const
|
|
27978
|
-
const fileName =
|
|
28786
|
+
const path9 = uri.replace("file://", "");
|
|
28787
|
+
const fileName = path9.split("/").pop() ?? path9;
|
|
27979
28788
|
return `[@${fileName}](${uri})`;
|
|
27980
28789
|
}
|
|
27981
28790
|
return uri;
|
|
@@ -28005,7 +28814,7 @@ function readAdditionalDirectories(cwd, additionalDirectories, meta3) {
|
|
|
28005
28814
|
if (directory.length === 0) {
|
|
28006
28815
|
throw RequestError.invalidParams(void 0, "additionalDirectories entries must not be empty");
|
|
28007
28816
|
}
|
|
28008
|
-
if (!
|
|
28817
|
+
if (!path7.isAbsolute(directory)) {
|
|
28009
28818
|
throw RequestError.invalidParams(void 0, "additionalDirectories entries must be absolute paths");
|
|
28010
28819
|
}
|
|
28011
28820
|
if (!seen.has(directory)) {
|
|
@@ -28160,11 +28969,11 @@ var CodexAppServerClient = class {
|
|
|
28160
28969
|
});
|
|
28161
28970
|
this.connection.onRequest(PermissionsApprovalRequest, async (params) => {
|
|
28162
28971
|
if (this.isStaleTurn(params.threadId, params.turnId)) {
|
|
28163
|
-
return { permissions: {}, scope: "turn", strictAutoReview:
|
|
28972
|
+
return { permissions: {}, scope: "turn", strictAutoReview: false };
|
|
28164
28973
|
}
|
|
28165
28974
|
const handler = this.approvalHandlers.get(params.threadId);
|
|
28166
28975
|
if (!handler) {
|
|
28167
|
-
return { permissions: {}, scope: "turn", strictAutoReview:
|
|
28976
|
+
return { permissions: {}, scope: "turn", strictAutoReview: false };
|
|
28168
28977
|
}
|
|
28169
28978
|
return await handler.handlePermissionsRequest(params);
|
|
28170
28979
|
});
|
|
@@ -28927,11 +29736,14 @@ var CodexCommands = class {
|
|
|
28927
29736
|
this.runWithProcessCheck = runWithProcessCheck;
|
|
28928
29737
|
this.onLogout = onLogout;
|
|
28929
29738
|
}
|
|
28930
|
-
async publish(sessionState) {
|
|
29739
|
+
async publish(sessionState, shouldPublish = () => true) {
|
|
28931
29740
|
try {
|
|
29741
|
+
if (!shouldPublish()) {
|
|
29742
|
+
return;
|
|
29743
|
+
}
|
|
28932
29744
|
const skillsResponse = await this.runWithProcessCheck(() => this.codexAcpClient.listSkills(this.createSkillsListParams(sessionState)));
|
|
28933
29745
|
const availableCommands = this.buildAvailableCommands(skillsResponse?.data ?? []);
|
|
28934
|
-
if (availableCommands.length === 0) {
|
|
29746
|
+
if (availableCommands.length === 0 || !shouldPublish()) {
|
|
28935
29747
|
return;
|
|
28936
29748
|
}
|
|
28937
29749
|
const session = new ACPSessionConnection(this.connection, sessionState.sessionId);
|
|
@@ -28940,7 +29752,9 @@ var CodexCommands = class {
|
|
|
28940
29752
|
availableCommands
|
|
28941
29753
|
});
|
|
28942
29754
|
} catch (err) {
|
|
28943
|
-
|
|
29755
|
+
if (shouldPublish()) {
|
|
29756
|
+
logger.error(`Failed to publish available commands for session ${sessionState.sessionId}`, err);
|
|
29757
|
+
}
|
|
28944
29758
|
}
|
|
28945
29759
|
}
|
|
28946
29760
|
createSkillsListParams(sessionState) {
|
|
@@ -29399,7 +30213,7 @@ var SteeringQueue = class {
|
|
|
29399
30213
|
|
|
29400
30214
|
// src/ResponseItemHistoryFallback.ts
|
|
29401
30215
|
import { readFile as readFile2 } from "node:fs/promises";
|
|
29402
|
-
import
|
|
30216
|
+
import path8 from "node:path";
|
|
29403
30217
|
function historyFallbackUpdateKey(update) {
|
|
29404
30218
|
switch (update.sessionUpdate) {
|
|
29405
30219
|
case "user_message_chunk":
|
|
@@ -29639,8 +30453,8 @@ function imageBlocks(images) {
|
|
|
29639
30453
|
return [{ type: "text", text: `[@image](${image})` }];
|
|
29640
30454
|
}
|
|
29641
30455
|
const record2 = asRecord2(image);
|
|
29642
|
-
const
|
|
29643
|
-
return
|
|
30456
|
+
const path9 = record2 ? stringValue(record2["path"]) ?? stringValue(record2["url"]) : null;
|
|
30457
|
+
return path9 ? [{ type: "text", text: `[@image](${path9})` }] : [];
|
|
29644
30458
|
});
|
|
29645
30459
|
}
|
|
29646
30460
|
function contentBlocksFromResponseContent(content) {
|
|
@@ -30272,10 +31086,10 @@ function baseCommandName(commandName) {
|
|
|
30272
31086
|
return commandName.split(/[\\/]/).pop() ?? commandName;
|
|
30273
31087
|
}
|
|
30274
31088
|
function absolutizePath(cwd, targetPath) {
|
|
30275
|
-
if (
|
|
31089
|
+
if (path8.isAbsolute(targetPath) || cwd.length === 0) {
|
|
30276
31090
|
return targetPath;
|
|
30277
31091
|
}
|
|
30278
|
-
return
|
|
31092
|
+
return path8.join(cwd, targetPath);
|
|
30279
31093
|
}
|
|
30280
31094
|
function withTerminalContent(event, terminalId, cwd) {
|
|
30281
31095
|
const { rawInput, ...eventWithoutRawInput } = event;
|
|
@@ -30433,16 +31247,7 @@ function clientSupportsPlanUpdates(clientCapabilities) {
|
|
|
30433
31247
|
// src/CodexAcpServer.ts
|
|
30434
31248
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
30435
31249
|
import { once } from "node:events";
|
|
30436
|
-
var IMPLEMENT_PLAN_OPTION_ID = "implement_plan";
|
|
30437
|
-
var REVISE_PLAN_OPTION_ID = "revise_plan";
|
|
30438
31250
|
var CODEX_PROCESS_EXITED_ERROR_CODE = 1001;
|
|
30439
|
-
function clientSupportsAirCapability(capabilities, capability) {
|
|
30440
|
-
const jetbrains = capabilities?._meta?.[JETBRAINS_META_KEY];
|
|
30441
|
-
const air = jetbrains?.[AIR_META_KEY];
|
|
30442
|
-
const version2 = air?.[AIR_EXTENSION_VERSION_KEY];
|
|
30443
|
-
const supported = air?.[AIR_EXTENSION_CAPABILITIES_KEY];
|
|
30444
|
-
return typeof version2 === "number" && Number.isInteger(version2) && version2 >= AIR_EXTENSION_VERSION && Array.isArray(supported) && supported.includes(capability);
|
|
30445
|
-
}
|
|
30446
31251
|
function clientSupportsTypedSessionFailures(capabilities) {
|
|
30447
31252
|
return clientSupportsAirCapability(capabilities, AIR_SESSION_FAILURE_KEY);
|
|
30448
31253
|
}
|
|
@@ -30475,6 +31280,7 @@ var CodexAcpServer = class _CodexAcpServer {
|
|
|
30475
31280
|
sessionGenerations;
|
|
30476
31281
|
sessionOpenGenerations;
|
|
30477
31282
|
goalControlGenerations;
|
|
31283
|
+
permissionLifecycleContexts;
|
|
30478
31284
|
codexProcessState;
|
|
30479
31285
|
initializeRequest = null;
|
|
30480
31286
|
providerUpdate = null;
|
|
@@ -30488,6 +31294,7 @@ var CodexAcpServer = class _CodexAcpServer {
|
|
|
30488
31294
|
this.sessionGenerations = /* @__PURE__ */ new Map();
|
|
30489
31295
|
this.sessionOpenGenerations = /* @__PURE__ */ new Map();
|
|
30490
31296
|
this.goalControlGenerations = /* @__PURE__ */ new Map();
|
|
31297
|
+
this.permissionLifecycleContexts = /* @__PURE__ */ new WeakMap();
|
|
30491
31298
|
this.connection = connection;
|
|
30492
31299
|
this.codexAcpClient = codexAcpClient;
|
|
30493
31300
|
this.defaultAuthRequest = defaultAuthRequest ?? null;
|
|
@@ -30518,6 +31325,14 @@ var CodexAcpServer = class _CodexAcpServer {
|
|
|
30518
31325
|
this.terminalOutputMode = resolveTerminalOutputMode(_params.clientCapabilities);
|
|
30519
31326
|
this.booleanConfigOptionsSupported = clientSupportsBooleanConfigOptions(_params.clientCapabilities);
|
|
30520
31327
|
await this.runWithProcessCheck(() => this.codexAcpClient.initialize(_params));
|
|
31328
|
+
const sessionCapabilities = {
|
|
31329
|
+
resume: {},
|
|
31330
|
+
list: {},
|
|
31331
|
+
close: {},
|
|
31332
|
+
delete: {},
|
|
31333
|
+
additionalDirectories: {},
|
|
31334
|
+
subagents: {}
|
|
31335
|
+
};
|
|
30521
31336
|
return {
|
|
30522
31337
|
protocolVersion: PROTOCOL_VERSION,
|
|
30523
31338
|
agentInfo: {
|
|
@@ -30535,13 +31350,7 @@ var CodexAcpServer = class _CodexAcpServer {
|
|
|
30535
31350
|
embeddedContext: true,
|
|
30536
31351
|
image: true
|
|
30537
31352
|
},
|
|
30538
|
-
sessionCapabilities
|
|
30539
|
-
resume: {},
|
|
30540
|
-
list: {},
|
|
30541
|
-
close: {},
|
|
30542
|
-
delete: {},
|
|
30543
|
-
additionalDirectories: {}
|
|
30544
|
-
},
|
|
31353
|
+
sessionCapabilities,
|
|
30545
31354
|
mcpCapabilities: {
|
|
30546
31355
|
acp: false,
|
|
30547
31356
|
http: true,
|
|
@@ -30563,7 +31372,8 @@ var CodexAcpServer = class _CodexAcpServer {
|
|
|
30563
31372
|
[AIR_EXTENSION_VERSION_KEY]: AIR_EXTENSION_VERSION,
|
|
30564
31373
|
[AIR_EXTENSION_CAPABILITIES_KEY]: [
|
|
30565
31374
|
AIR_SESSION_FAILURE_KEY,
|
|
30566
|
-
AIR_AGENT_FILE_CHANGE_REPORT_KEY
|
|
31375
|
+
AIR_AGENT_FILE_CHANGE_REPORT_KEY,
|
|
31376
|
+
AIR_NATIVE_SUBAGENT_SESSIONS_KEY
|
|
30567
31377
|
]
|
|
30568
31378
|
}
|
|
30569
31379
|
}
|
|
@@ -30615,7 +31425,7 @@ var CodexAcpServer = class _CodexAcpServer {
|
|
|
30615
31425
|
}
|
|
30616
31426
|
} else if (methodRequest.params.action === "pause") {
|
|
30617
31427
|
const goal = await this.runWithProcessCheck(() => this.codexAcpClient.setGoalStatus(sessionState.sessionId, "paused"));
|
|
30618
|
-
if (this.
|
|
31428
|
+
if (this.sessionPublishIsCurrent(sessionState, sessionGeneration)) {
|
|
30619
31429
|
await this.publishGoalSnapshot(sessionState, toThreadGoalSnapshot(goal), false);
|
|
30620
31430
|
}
|
|
30621
31431
|
} else if (methodRequest.params.action === "resume") {
|
|
@@ -30627,7 +31437,7 @@ var CodexAcpServer = class _CodexAcpServer {
|
|
|
30627
31437
|
updatedGoal = goal;
|
|
30628
31438
|
}
|
|
30629
31439
|
));
|
|
30630
|
-
if (updatedGoal !== null && this.
|
|
31440
|
+
if (updatedGoal !== null && this.sessionPublishIsCurrent(sessionState, sessionGeneration)) {
|
|
30631
31441
|
await this.publishGoalSnapshot(sessionState, toThreadGoalSnapshot(updatedGoal), false);
|
|
30632
31442
|
}
|
|
30633
31443
|
if (turnCompleted === null && updatedGoal !== null) {
|
|
@@ -30640,7 +31450,7 @@ var CodexAcpServer = class _CodexAcpServer {
|
|
|
30640
31450
|
}
|
|
30641
31451
|
} else if (methodRequest.params.action === "clear") {
|
|
30642
31452
|
await this.runWithProcessCheck(() => this.codexAcpClient.clearGoal(sessionState.sessionId));
|
|
30643
|
-
if (this.
|
|
31453
|
+
if (this.sessionPublishIsCurrent(sessionState, sessionGeneration)) {
|
|
30644
31454
|
await this.publishGoalSnapshot(sessionState, null, false);
|
|
30645
31455
|
}
|
|
30646
31456
|
}
|
|
@@ -30816,7 +31626,12 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30816
31626
|
terminalOutputMode: this.terminalOutputMode,
|
|
30817
31627
|
goalRevision: 0,
|
|
30818
31628
|
sessionTitle: null,
|
|
30819
|
-
sessionTitleSource: "sessionId" in request ? "unknown" : "unset"
|
|
31629
|
+
sessionTitleSource: "sessionId" in request ? "unknown" : "unset",
|
|
31630
|
+
subagents: new CodexSubagentEventRouter(
|
|
31631
|
+
sessionId,
|
|
31632
|
+
clientSupportsSubagents(this.clientCapabilities),
|
|
31633
|
+
new ACPSessionConnection(this.connection, sessionId)
|
|
31634
|
+
)
|
|
30820
31635
|
};
|
|
30821
31636
|
this.sessions.set(sessionId, sessionState);
|
|
30822
31637
|
resumeSubscribed = false;
|
|
@@ -30827,7 +31642,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30827
31642
|
});
|
|
30828
31643
|
this.publishMcpStartupStatusAsync(sessionId);
|
|
30829
31644
|
}
|
|
30830
|
-
this.publishAvailableCommandsAsync(sessionState);
|
|
31645
|
+
this.publishAvailableCommandsAsync(sessionState, sessionGeneration);
|
|
30831
31646
|
if ("sessionId" in request) {
|
|
30832
31647
|
this.publishCurrentGoalAsync(sessionState, sessionGeneration);
|
|
30833
31648
|
}
|
|
@@ -31010,12 +31825,24 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
31010
31825
|
if (requestId == null || !clientSupportsUrlElicitation(this.clientCapabilities)) {
|
|
31011
31826
|
return void 0;
|
|
31012
31827
|
}
|
|
31828
|
+
let elicitationId = null;
|
|
31013
31829
|
return {
|
|
31014
|
-
elicitUrl: (request) =>
|
|
31015
|
-
|
|
31016
|
-
|
|
31017
|
-
|
|
31018
|
-
|
|
31830
|
+
elicitUrl: (request) => {
|
|
31831
|
+
elicitationId = request.elicitationId;
|
|
31832
|
+
return this.connection.request(methods.client.elicitation.create, {
|
|
31833
|
+
mode: "url",
|
|
31834
|
+
requestId,
|
|
31835
|
+
...request
|
|
31836
|
+
});
|
|
31837
|
+
},
|
|
31838
|
+
completeElicitation: async () => {
|
|
31839
|
+
if (elicitationId === null) {
|
|
31840
|
+
return;
|
|
31841
|
+
}
|
|
31842
|
+
await this.connection.notify(methods.client.elicitation.complete, {
|
|
31843
|
+
elicitationId
|
|
31844
|
+
});
|
|
31845
|
+
}
|
|
31019
31846
|
};
|
|
31020
31847
|
}
|
|
31021
31848
|
async logout(_params) {
|
|
@@ -31404,7 +32231,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
31404
32231
|
sessionId: sessionState.sessionId,
|
|
31405
32232
|
prompt: GOAL_CONTINUATION_PROMPT
|
|
31406
32233
|
}, "Goal continuation", async () => {
|
|
31407
|
-
if (!this.
|
|
32234
|
+
if (!this.sessionPublishIsCurrent(sessionState, sessionGeneration) || this.goalControlGenerations.get(sessionState.sessionId) !== goalControlGeneration) {
|
|
31408
32235
|
return false;
|
|
31409
32236
|
}
|
|
31410
32237
|
const currentGoal = await this.runWithProcessCheck(() => this.codexAcpClient.getGoal(sessionState.sessionId));
|
|
@@ -31515,8 +32342,14 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
31515
32342
|
isSessionConfigEnabled() {
|
|
31516
32343
|
return !isJetBrains2026_1Client(this.clientInfo);
|
|
31517
32344
|
}
|
|
31518
|
-
publishAvailableCommandsAsync(sessionState) {
|
|
31519
|
-
void this.
|
|
32345
|
+
publishAvailableCommandsAsync(sessionState, sessionGeneration) {
|
|
32346
|
+
void this.publishAvailableCommands(sessionState, sessionGeneration);
|
|
32347
|
+
}
|
|
32348
|
+
async publishAvailableCommands(sessionState, sessionGeneration) {
|
|
32349
|
+
await this.availableCommands.publish(
|
|
32350
|
+
sessionState,
|
|
32351
|
+
() => this.sessionPublishIsCurrent(sessionState, sessionGeneration)
|
|
32352
|
+
);
|
|
31520
32353
|
}
|
|
31521
32354
|
publishCurrentGoalAsync(sessionState, sessionGeneration) {
|
|
31522
32355
|
void this.publishCurrentGoalBestEffort(sessionState, sessionGeneration, true);
|
|
@@ -31532,12 +32365,12 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
31532
32365
|
const requestRevision = ++sessionState.goalRevision;
|
|
31533
32366
|
const goal = await this.runWithProcessCheck(() => this.codexAcpClient.getGoal(sessionState.sessionId));
|
|
31534
32367
|
const snapshot = goal === null ? null : toThreadGoalSnapshot(goal);
|
|
31535
|
-
if (!this.
|
|
32368
|
+
if (!this.sessionPublishIsCurrent(sessionState, sessionGeneration) || sessionState.goalRevision !== requestRevision) {
|
|
31536
32369
|
return;
|
|
31537
32370
|
}
|
|
31538
32371
|
await this.publishGoalSnapshot(sessionState, snapshot, force, false);
|
|
31539
32372
|
}
|
|
31540
|
-
|
|
32373
|
+
sessionPublishIsCurrent(sessionState, sessionGeneration) {
|
|
31541
32374
|
return this.sessions.get(sessionState.sessionId) === sessionState && this.getSessionGeneration(sessionState.sessionId) === sessionGeneration && !this.sessionIsClosing(sessionState.sessionId);
|
|
31542
32375
|
}
|
|
31543
32376
|
async publishGoalSnapshot(sessionState, snapshot, force, incrementRevision = true) {
|
|
@@ -31639,7 +32472,12 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
31639
32472
|
terminalOutputMode: this.terminalOutputMode,
|
|
31640
32473
|
goalRevision: 0,
|
|
31641
32474
|
sessionTitle: null,
|
|
31642
|
-
sessionTitleSource: "unset"
|
|
32475
|
+
sessionTitleSource: "unset",
|
|
32476
|
+
subagents: new CodexSubagentEventRouter(
|
|
32477
|
+
sessionId,
|
|
32478
|
+
clientSupportsSubagents(this.clientCapabilities),
|
|
32479
|
+
new ACPSessionConnection(this.connection, sessionId)
|
|
32480
|
+
)
|
|
31643
32481
|
};
|
|
31644
32482
|
this.sessions.set(sessionId, sessionState);
|
|
31645
32483
|
subscribed = false;
|
|
@@ -31650,7 +32488,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
31650
32488
|
});
|
|
31651
32489
|
this.publishMcpStartupStatusAsync(sessionId);
|
|
31652
32490
|
}
|
|
31653
|
-
await this.
|
|
32491
|
+
await this.publishAvailableCommands(sessionState, requestedSessionGeneration);
|
|
31654
32492
|
await this.publishCurrentGoalBestEffort(sessionState, requestedSessionGeneration, true);
|
|
31655
32493
|
const sessionModelState = this.createModelState(models, currentModelId);
|
|
31656
32494
|
const sessionModeState = sessionState.agentMode.toSessionModeState();
|
|
@@ -31665,6 +32503,16 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
31665
32503
|
const session = new ACPSessionConnection(this.connection, sessionId);
|
|
31666
32504
|
const sessionState = this.getSessionState(sessionId);
|
|
31667
32505
|
await this.publishThreadHistoryTitle(session, sessionState, thread);
|
|
32506
|
+
if (clientSupportsSubagents(this.clientCapabilities)) {
|
|
32507
|
+
await this.streamNativeThreadHistory(
|
|
32508
|
+
sessionId,
|
|
32509
|
+
thread,
|
|
32510
|
+
sessionState,
|
|
32511
|
+
/* @__PURE__ */ new Set([sessionId]),
|
|
32512
|
+
/* @__PURE__ */ new Map([[sessionId, thread]])
|
|
32513
|
+
);
|
|
32514
|
+
return;
|
|
32515
|
+
}
|
|
31668
32516
|
const responseItemFallbackUpdates = await createResponseItemHistoryFallbackUpdates(
|
|
31669
32517
|
thread,
|
|
31670
32518
|
sessionState.terminalOutputMode
|
|
@@ -31681,6 +32529,93 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
31681
32529
|
await session.update(update);
|
|
31682
32530
|
}
|
|
31683
32531
|
}
|
|
32532
|
+
async streamNativeThreadHistory(sessionId, thread, sessionState, ancestry, threadCache) {
|
|
32533
|
+
const session = new ACPSessionConnection(this.connection, sessionId);
|
|
32534
|
+
const announced = /* @__PURE__ */ new Map();
|
|
32535
|
+
for (const turn of thread.turns) {
|
|
32536
|
+
for (const item of turn.items) {
|
|
32537
|
+
if (item.type === "subAgentActivity") {
|
|
32538
|
+
const activityKind = item.kind;
|
|
32539
|
+
if (activityKind === "started") {
|
|
32540
|
+
const previous = announced.get(item.agentThreadId);
|
|
32541
|
+
if (previous && !previous.terminal) continue;
|
|
32542
|
+
const generation = (previous?.generation ?? 0) + 1;
|
|
32543
|
+
const childSessionId = generation === 1 ? item.agentThreadId : `${item.agentThreadId}:generation:${generation}`;
|
|
32544
|
+
const name = nameFromAgentPath(item.agentPath, `Agent ${item.agentThreadId.slice(-8)}`);
|
|
32545
|
+
await session.update({
|
|
32546
|
+
sessionUpdate: "subagent_spawned",
|
|
32547
|
+
subagentSessionId: childSessionId,
|
|
32548
|
+
name,
|
|
32549
|
+
task: `Delegated task for ${name}`,
|
|
32550
|
+
capabilities: {}
|
|
32551
|
+
});
|
|
32552
|
+
announced.set(item.agentThreadId, { generation, sessionId: childSessionId, terminal: false });
|
|
32553
|
+
if (!ancestry.has(item.agentThreadId)) {
|
|
32554
|
+
let child = threadCache.get(item.agentThreadId);
|
|
32555
|
+
if (child === void 0) {
|
|
32556
|
+
try {
|
|
32557
|
+
child = await this.codexAcpClient.readSessionThread(item.agentThreadId);
|
|
32558
|
+
threadCache.set(item.agentThreadId, child);
|
|
32559
|
+
} catch (error51) {
|
|
32560
|
+
threadCache.set(item.agentThreadId, null);
|
|
32561
|
+
logger.error(`Failed to read subagent history ${item.agentThreadId}`, error51);
|
|
32562
|
+
child = null;
|
|
32563
|
+
}
|
|
32564
|
+
}
|
|
32565
|
+
const childTurn = child?.turns[generation - 1];
|
|
32566
|
+
if (child && childTurn) {
|
|
32567
|
+
await this.streamNativeThreadHistory(
|
|
32568
|
+
childSessionId,
|
|
32569
|
+
{ ...child, turns: [childTurn] },
|
|
32570
|
+
sessionState,
|
|
32571
|
+
/* @__PURE__ */ new Set([...ancestry, item.agentThreadId]),
|
|
32572
|
+
threadCache
|
|
32573
|
+
);
|
|
32574
|
+
}
|
|
32575
|
+
}
|
|
32576
|
+
} else if (activityKind === "completed" || activityKind === "interrupted") {
|
|
32577
|
+
const child = announced.get(item.agentThreadId);
|
|
32578
|
+
if (!child) {
|
|
32579
|
+
const name = nameFromAgentPath(item.agentPath, `Agent ${item.agentThreadId.slice(-8)}`);
|
|
32580
|
+
await session.update({
|
|
32581
|
+
sessionUpdate: "subagent_spawned",
|
|
32582
|
+
subagentSessionId: item.agentThreadId,
|
|
32583
|
+
name,
|
|
32584
|
+
task: `Delegated task for ${name}`,
|
|
32585
|
+
capabilities: {}
|
|
32586
|
+
});
|
|
32587
|
+
announced.set(item.agentThreadId, {
|
|
32588
|
+
generation: 1,
|
|
32589
|
+
sessionId: item.agentThreadId,
|
|
32590
|
+
terminal: false
|
|
32591
|
+
});
|
|
32592
|
+
continue;
|
|
32593
|
+
}
|
|
32594
|
+
if (child.terminal) continue;
|
|
32595
|
+
await session.update({
|
|
32596
|
+
sessionUpdate: "subagent_state_update",
|
|
32597
|
+
subagentSessionId: child.sessionId,
|
|
32598
|
+
state: activityKind === "completed" ? "completed" : "cancelled"
|
|
32599
|
+
});
|
|
32600
|
+
child.terminal = true;
|
|
32601
|
+
}
|
|
32602
|
+
continue;
|
|
32603
|
+
}
|
|
32604
|
+
if (item.type === "collabAgentToolCall") continue;
|
|
32605
|
+
for (const update of await this.createHistoryUpdates(item, sessionState)) {
|
|
32606
|
+
await session.update(update);
|
|
32607
|
+
}
|
|
32608
|
+
}
|
|
32609
|
+
}
|
|
32610
|
+
for (const child of announced.values()) {
|
|
32611
|
+
if (child.terminal) continue;
|
|
32612
|
+
await session.update({
|
|
32613
|
+
sessionUpdate: "subagent_state_update",
|
|
32614
|
+
subagentSessionId: child.sessionId,
|
|
32615
|
+
state: "disconnected"
|
|
32616
|
+
});
|
|
32617
|
+
}
|
|
32618
|
+
}
|
|
31684
32619
|
async publishThreadHistoryTitle(session, sessionState, thread) {
|
|
31685
32620
|
const explicitTitle = this.normalizeSessionTitle(thread.name);
|
|
31686
32621
|
if (explicitTitle) {
|
|
@@ -31885,8 +32820,8 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
31885
32820
|
return `[@${name}](${uri})`;
|
|
31886
32821
|
}
|
|
31887
32822
|
if (uri.startsWith("file://")) {
|
|
31888
|
-
const
|
|
31889
|
-
const fileName =
|
|
32823
|
+
const path9 = uri.replace("file://", "");
|
|
32824
|
+
const fileName = path9.split("/").pop() ?? path9;
|
|
31890
32825
|
return `[@${fileName}](${uri})`;
|
|
31891
32826
|
}
|
|
31892
32827
|
return uri;
|
|
@@ -31898,6 +32833,13 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
31898
32833
|
}
|
|
31899
32834
|
return sessionState;
|
|
31900
32835
|
}
|
|
32836
|
+
permissionLifecycleContext(sessionState) {
|
|
32837
|
+
const existing = this.permissionLifecycleContexts.get(sessionState);
|
|
32838
|
+
if (existing) return existing;
|
|
32839
|
+
const context = new PermissionLifecycleContext(sessionState);
|
|
32840
|
+
this.permissionLifecycleContexts.set(sessionState, context);
|
|
32841
|
+
return context;
|
|
32842
|
+
}
|
|
31901
32843
|
resolveSessionMcpServers(mcpServers, recoverFromStartup) {
|
|
31902
32844
|
const requestedServerNames = getRequestedMcpServerNames(mcpServers);
|
|
31903
32845
|
if (requestedServerNames.length > 0) {
|
|
@@ -32145,6 +33087,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
32145
33087
|
const agentFileChangeReportRequest = clientSupportsAgentFileChangeReports(this.clientCapabilities) ? parseAgentFileChangeReportRequest(params._meta) : null;
|
|
32146
33088
|
let agentFileChangeReportTurnId = null;
|
|
32147
33089
|
let agentFileChangeReportUnavailableReason = "providerError";
|
|
33090
|
+
let promptWasCancelled = false;
|
|
32148
33091
|
let recoverableSessionFailure = sessionState.sessionFailure;
|
|
32149
33092
|
sessionState.currentTurnId = null;
|
|
32150
33093
|
sessionState.lastTokenUsage = null;
|
|
@@ -32168,6 +33111,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
32168
33111
|
}
|
|
32169
33112
|
};
|
|
32170
33113
|
const cancelledPromptResponse = () => {
|
|
33114
|
+
promptWasCancelled = true;
|
|
32171
33115
|
agentFileChangeReportTurnId = null;
|
|
32172
33116
|
agentFileChangeReportUnavailableReason = "cancelled";
|
|
32173
33117
|
return this.cancelledPromptResponse(sessionState);
|
|
@@ -32178,32 +33122,46 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
32178
33122
|
sessionState,
|
|
32179
33123
|
clientSupportsPlanUpdates(this.clientCapabilities),
|
|
32180
33124
|
clientSupportsTypedSessionFailures(this.clientCapabilities),
|
|
32181
|
-
this.sessionFailureEpoch
|
|
33125
|
+
this.sessionFailureEpoch,
|
|
33126
|
+
sessionState.subagents
|
|
32182
33127
|
);
|
|
32183
33128
|
eventHandler = promptEventHandler;
|
|
32184
|
-
const
|
|
33129
|
+
const permissionLifecycle = this.permissionLifecycleContext(sessionState);
|
|
33130
|
+
const permissionContext = permissionLifecycle.beginPrompt();
|
|
33131
|
+
const approvalHandler = new CodexApprovalHandler(
|
|
33132
|
+
this.connection,
|
|
33133
|
+
permissionContext,
|
|
33134
|
+
activePrompt.signal
|
|
33135
|
+
);
|
|
32185
33136
|
const elicitationHandler = new CodexElicitationHandler(
|
|
32186
33137
|
this.connection,
|
|
32187
|
-
|
|
33138
|
+
permissionContext,
|
|
32188
33139
|
this.clientCapabilities,
|
|
32189
33140
|
activePrompt.signal
|
|
32190
33141
|
);
|
|
33142
|
+
const observeInteraction = async (event) => {
|
|
33143
|
+
permissionContext.handleNotification(event);
|
|
33144
|
+
await elicitationHandler.handleNotification(event);
|
|
33145
|
+
};
|
|
32191
33146
|
await this.codexAcpClient.subscribeToSessionEvents(
|
|
32192
33147
|
params.sessionId,
|
|
32193
33148
|
async (event) => {
|
|
33149
|
+
await observeInteraction(event);
|
|
32194
33150
|
if (!promptNotificationsActive) {
|
|
32195
33151
|
await promptEventHandler.handleSessionScopedNotification(event);
|
|
32196
33152
|
return;
|
|
32197
33153
|
}
|
|
32198
|
-
const completesActiveTurn = event.method === "turn/completed" && event.params.turn.id === sessionState.currentTurnId;
|
|
32199
|
-
await elicitationHandler.handleNotification(event);
|
|
33154
|
+
const completesActiveTurn = event.method === "turn/completed" && event.params.threadId === sessionState.sessionId && event.params.turn.id === sessionState.currentTurnId;
|
|
32200
33155
|
await promptEventHandler.handleNotification(event);
|
|
32201
33156
|
if (completesActiveTurn) {
|
|
32202
33157
|
promptNotificationsActive = false;
|
|
32203
33158
|
}
|
|
32204
33159
|
},
|
|
32205
33160
|
approvalHandler,
|
|
32206
|
-
elicitationHandler
|
|
33161
|
+
elicitationHandler,
|
|
33162
|
+
clientSupportsSubagents(this.clientCapabilities),
|
|
33163
|
+
observeInteraction,
|
|
33164
|
+
(childThreadId) => promptEventHandler.waitForNativeSubagentSession(childThreadId)
|
|
32207
33165
|
);
|
|
32208
33166
|
if (activePrompt.signal.aborted) {
|
|
32209
33167
|
return cancelledPromptResponse();
|
|
@@ -32344,6 +33302,15 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
32344
33302
|
return cancelledPromptResponse();
|
|
32345
33303
|
}
|
|
32346
33304
|
await this.codexAcpClient.waitForSessionNotifications(params.sessionId);
|
|
33305
|
+
if (turnCompleted.turn.status === "completed") {
|
|
33306
|
+
await eventHandler.waitForNativeSubagents(activePrompt.signal);
|
|
33307
|
+
if (activePrompt.signal.aborted) return cancelledPromptResponse();
|
|
33308
|
+
await this.codexAcpClient.waitForSessionNotifications(params.sessionId);
|
|
33309
|
+
} else {
|
|
33310
|
+
await eventHandler.finishOutstandingNativeSubagents(
|
|
33311
|
+
turnCompleted.turn.status === "interrupted" ? "cancelled" : "failed"
|
|
33312
|
+
);
|
|
33313
|
+
}
|
|
32347
33314
|
await eventHandler.flushPendingErrors();
|
|
32348
33315
|
await eventHandler.handleFailedTurn(turnCompleted.turn);
|
|
32349
33316
|
promptNotificationsActive = false;
|
|
@@ -32424,6 +33391,15 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
32424
33391
|
return cancelledPromptResponse();
|
|
32425
33392
|
}
|
|
32426
33393
|
await this.codexAcpClient.waitForSessionNotifications(params.sessionId);
|
|
33394
|
+
if (turnCompleted.turn.status === "completed") {
|
|
33395
|
+
await eventHandler.waitForNativeSubagents(activePrompt.signal);
|
|
33396
|
+
if (activePrompt.signal.aborted) return cancelledPromptResponse();
|
|
33397
|
+
await this.codexAcpClient.waitForSessionNotifications(params.sessionId);
|
|
33398
|
+
} else {
|
|
33399
|
+
await eventHandler.finishOutstandingNativeSubagents(
|
|
33400
|
+
turnCompleted.turn.status === "interrupted" ? "cancelled" : "failed"
|
|
33401
|
+
);
|
|
33402
|
+
}
|
|
32427
33403
|
await eventHandler.flushPendingErrors();
|
|
32428
33404
|
await eventHandler.handleFailedTurn(turnCompleted.turn);
|
|
32429
33405
|
promptNotificationsActive = false;
|
|
@@ -32485,6 +33461,14 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
32485
33461
|
throw err;
|
|
32486
33462
|
} finally {
|
|
32487
33463
|
promptNotificationsActive = false;
|
|
33464
|
+
try {
|
|
33465
|
+
await this.codexAcpClient.waitForSessionNotifications(params.sessionId);
|
|
33466
|
+
await eventHandler?.finishOutstandingNativeSubagents(
|
|
33467
|
+
promptWasCancelled || activePrompt.signal.aborted || this.sessionIsClosing(params.sessionId) ? "cancelled" : "failed"
|
|
33468
|
+
);
|
|
33469
|
+
} catch (error51) {
|
|
33470
|
+
logger.error("Failed to publish terminal subagent state during prompt cleanup", error51);
|
|
33471
|
+
}
|
|
32488
33472
|
if (agentFileChangeReportRequest !== null) {
|
|
32489
33473
|
await this.publishAgentFileChangeReport(
|
|
32490
33474
|
sessionState,
|
|
@@ -32507,41 +33491,14 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
32507
33491
|
}
|
|
32508
33492
|
}
|
|
32509
33493
|
async requestPlanImplementationPermission(sessionState, plan, cancellationSignal) {
|
|
32510
|
-
const toolCallId =
|
|
33494
|
+
const toolCallId = planImplementationToolCallId(plan);
|
|
32511
33495
|
try {
|
|
32512
33496
|
const response = await this.connection.request(
|
|
32513
33497
|
methods.client.session.requestPermission,
|
|
32514
|
-
|
|
32515
|
-
sessionId: sessionState.sessionId,
|
|
32516
|
-
toolCall: {
|
|
32517
|
-
toolCallId,
|
|
32518
|
-
title: "Implement this plan?",
|
|
32519
|
-
kind: "switch_mode",
|
|
32520
|
-
status: "pending",
|
|
32521
|
-
rawInput: { plan: plan.text }
|
|
32522
|
-
},
|
|
32523
|
-
options: [
|
|
32524
|
-
{
|
|
32525
|
-
optionId: IMPLEMENT_PLAN_OPTION_ID,
|
|
32526
|
-
name: "Yes, implement this plan",
|
|
32527
|
-
kind: "allow_once"
|
|
32528
|
-
},
|
|
32529
|
-
{
|
|
32530
|
-
optionId: REVISE_PLAN_OPTION_ID,
|
|
32531
|
-
name: "No, and tell Codex what to do differently",
|
|
32532
|
-
kind: "reject_once"
|
|
32533
|
-
}
|
|
32534
|
-
],
|
|
32535
|
-
_meta: {
|
|
32536
|
-
codex: {
|
|
32537
|
-
kind: "plan_review",
|
|
32538
|
-
planItemId: plan.itemId
|
|
32539
|
-
}
|
|
32540
|
-
}
|
|
32541
|
-
},
|
|
33498
|
+
planImplementationPermissionRequest(sessionState.sessionId, plan),
|
|
32542
33499
|
{ cancellationSignal }
|
|
32543
33500
|
);
|
|
32544
|
-
const approved = response
|
|
33501
|
+
const approved = planImplementationApproved(response);
|
|
32545
33502
|
await this.connection.notify(methods.client.session.update, {
|
|
32546
33503
|
sessionId: sessionState.sessionId,
|
|
32547
33504
|
update: {
|