@agentconnect.md/codex-acp 1.6.2-agentconnect.1 → 1.7.0-agentconnect.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -3
- package/dist/index.js +1946 -1043
- package/package.json +6 -6
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;
|
|
@@ -22103,6 +22132,36 @@ function attachLogs(proc) {
|
|
|
22103
22132
|
});
|
|
22104
22133
|
}
|
|
22105
22134
|
|
|
22135
|
+
// src/AirExtension.ts
|
|
22136
|
+
var JETBRAINS_META_KEY = "jetbrains";
|
|
22137
|
+
var AIR_META_KEY = "air";
|
|
22138
|
+
var AIR_EXTENSION_VERSION_KEY = "version";
|
|
22139
|
+
var AIR_EXTENSION_CAPABILITIES_KEY = "capabilities";
|
|
22140
|
+
var AIR_SESSION_FAILURE_KEY = "sessionFailure";
|
|
22141
|
+
var AIR_AGENT_FILE_CHANGE_REPORT_KEY = "agentFileChangeReport";
|
|
22142
|
+
var AIR_NATIVE_SUBAGENT_SESSIONS_KEY = "nativeSubagentSessions";
|
|
22143
|
+
var AIR_AGENT_FILE_CHANGE_REPORT_REQUEST_KEY = "agentFileChangeReportRequest";
|
|
22144
|
+
var AIR_EXTENSION_VERSION = 1;
|
|
22145
|
+
function clientSupportsAirCapability(capabilities, capability) {
|
|
22146
|
+
const jetbrains = capabilities?._meta?.[JETBRAINS_META_KEY];
|
|
22147
|
+
const air = jetbrains?.[AIR_META_KEY];
|
|
22148
|
+
const version2 = air?.[AIR_EXTENSION_VERSION_KEY];
|
|
22149
|
+
const supported = air?.[AIR_EXTENSION_CAPABILITIES_KEY];
|
|
22150
|
+
return typeof version2 === "number" && Number.isInteger(version2) && version2 >= AIR_EXTENSION_VERSION && Array.isArray(supported) && supported.includes(capability);
|
|
22151
|
+
}
|
|
22152
|
+
|
|
22153
|
+
// src/subagents/AcpSubagents.ts
|
|
22154
|
+
function clientSupportsSubagents(capabilities) {
|
|
22155
|
+
const subagents = capabilities?.subagents;
|
|
22156
|
+
if (typeof subagents === "object" && subagents !== null && !Array.isArray(subagents)) {
|
|
22157
|
+
return true;
|
|
22158
|
+
}
|
|
22159
|
+
return clientSupportsAirCapability(capabilities, AIR_NATIVE_SUBAGENT_SESSIONS_KEY);
|
|
22160
|
+
}
|
|
22161
|
+
function asSdkSessionNotification(notification) {
|
|
22162
|
+
return notification;
|
|
22163
|
+
}
|
|
22164
|
+
|
|
22106
22165
|
// src/ACPSessionConnection.ts
|
|
22107
22166
|
var ACPSessionConnection = class {
|
|
22108
22167
|
connection;
|
|
@@ -22111,11 +22170,11 @@ var ACPSessionConnection = class {
|
|
|
22111
22170
|
this.connection = connection;
|
|
22112
22171
|
this.sessionId = sessionId;
|
|
22113
22172
|
}
|
|
22114
|
-
async update(update) {
|
|
22115
|
-
await this.connection.notify(methods.client.session.update, {
|
|
22116
|
-
sessionId
|
|
22173
|
+
async update(update, sessionId = this.sessionId) {
|
|
22174
|
+
await this.connection.notify(methods.client.session.update, asSdkSessionNotification({
|
|
22175
|
+
sessionId,
|
|
22117
22176
|
update
|
|
22118
|
-
});
|
|
22177
|
+
}));
|
|
22119
22178
|
}
|
|
22120
22179
|
};
|
|
22121
22180
|
|
|
@@ -23258,13 +23317,13 @@ function createTerminalCommandEvent(event, terminalId, cwd) {
|
|
|
23258
23317
|
}
|
|
23259
23318
|
};
|
|
23260
23319
|
}
|
|
23261
|
-
function createSearchTitle(query,
|
|
23262
|
-
if (query &&
|
|
23263
|
-
return `Search for '${query}' in ${
|
|
23320
|
+
function createSearchTitle(query, path9) {
|
|
23321
|
+
if (query && path9) {
|
|
23322
|
+
return `Search for '${query}' in ${path9}`;
|
|
23264
23323
|
} else if (query) {
|
|
23265
23324
|
return `Search for '${query}'`;
|
|
23266
|
-
} else if (
|
|
23267
|
-
return `Search in '${
|
|
23325
|
+
} else if (path9) {
|
|
23326
|
+
return `Search in '${path9}'`;
|
|
23268
23327
|
}
|
|
23269
23328
|
return "Search";
|
|
23270
23329
|
}
|
|
@@ -23490,12 +23549,12 @@ function revertPatch(unifiedDiff) {
|
|
|
23490
23549
|
if (!patch) return null;
|
|
23491
23550
|
return reversePatch(patch);
|
|
23492
23551
|
}
|
|
23493
|
-
function createUpdateDiffContent(
|
|
23552
|
+
function createUpdateDiffContent(path9, oldText, newText) {
|
|
23494
23553
|
return {
|
|
23495
23554
|
type: "diff",
|
|
23496
23555
|
oldText,
|
|
23497
23556
|
newText,
|
|
23498
|
-
path:
|
|
23557
|
+
path: path9,
|
|
23499
23558
|
_meta: {
|
|
23500
23559
|
kind: "update"
|
|
23501
23560
|
}
|
|
@@ -23622,15 +23681,380 @@ function sameThreadGoalSnapshot(left, right) {
|
|
|
23622
23681
|
// src/CodexEventHandler.ts
|
|
23623
23682
|
import { randomUUID } from "node:crypto";
|
|
23624
23683
|
|
|
23625
|
-
// src/
|
|
23626
|
-
|
|
23627
|
-
|
|
23628
|
-
|
|
23629
|
-
|
|
23630
|
-
|
|
23631
|
-
|
|
23632
|
-
|
|
23633
|
-
|
|
23684
|
+
// src/subagents/CodexAgentPath.ts
|
|
23685
|
+
function normalizeAgentPath(path9) {
|
|
23686
|
+
const normalized = path9.trim().replace(/\/+$/, "");
|
|
23687
|
+
return normalized || "/root";
|
|
23688
|
+
}
|
|
23689
|
+
function isRootAgentPath(path9) {
|
|
23690
|
+
const normalized = normalizeAgentPath(path9);
|
|
23691
|
+
return normalized === "/root" || normalized === "root";
|
|
23692
|
+
}
|
|
23693
|
+
function nameFromAgentPath(path9, fallback) {
|
|
23694
|
+
const normalized = normalizeAgentPath(path9);
|
|
23695
|
+
const name = normalized.slice(normalized.lastIndexOf("/") + 1).trim();
|
|
23696
|
+
if (!name) return fallback;
|
|
23697
|
+
const words = name.replace(/[_-]+/g, " ").replace(/\s+/g, " ").trim();
|
|
23698
|
+
return words ? words.charAt(0).toUpperCase() + words.slice(1) : fallback;
|
|
23699
|
+
}
|
|
23700
|
+
|
|
23701
|
+
// src/subagents/CodexSubagentEventRouter.ts
|
|
23702
|
+
var CodexSubagentEventRouter = class _CodexSubagentEventRouter {
|
|
23703
|
+
constructor(rootSessionId, supported, session) {
|
|
23704
|
+
this.rootSessionId = rootSessionId;
|
|
23705
|
+
this.supported = supported;
|
|
23706
|
+
this.session = session;
|
|
23707
|
+
}
|
|
23708
|
+
rootSessionId;
|
|
23709
|
+
supported;
|
|
23710
|
+
session;
|
|
23711
|
+
static DEFAULT_WAIT_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
23712
|
+
static MAX_PENDING_NOTIFICATIONS = 256;
|
|
23713
|
+
children = /* @__PURE__ */ new Map();
|
|
23714
|
+
pendingSpawns = /* @__PURE__ */ new Map();
|
|
23715
|
+
terminalPendingSpawns = /* @__PURE__ */ new Map();
|
|
23716
|
+
waiters = /* @__PURE__ */ new Set();
|
|
23717
|
+
materializationWaiters = /* @__PURE__ */ new Map();
|
|
23718
|
+
replayQueue = [];
|
|
23719
|
+
activeLegacyActivities = /* @__PURE__ */ new Set();
|
|
23720
|
+
async handle(notification) {
|
|
23721
|
+
if (notification.method === "turn/started") {
|
|
23722
|
+
return this.isKnownChild(notification.params.threadId);
|
|
23723
|
+
}
|
|
23724
|
+
if (notification.method === "turn/completed") {
|
|
23725
|
+
const childTurn = this.isKnownChild(notification.params.threadId);
|
|
23726
|
+
const state = terminalStateFromTurn(notification.params.turn.status);
|
|
23727
|
+
if (!state) return childTurn;
|
|
23728
|
+
if (notification.params.threadId === this.rootSessionId) {
|
|
23729
|
+
if (state !== "completed") await this.finishOutstanding(state);
|
|
23730
|
+
} else {
|
|
23731
|
+
if (this.pendingSpawns.has(notification.params.threadId)) {
|
|
23732
|
+
this.finishPending(notification.params.threadId);
|
|
23733
|
+
} else {
|
|
23734
|
+
await this.finish(notification.params.threadId, state);
|
|
23735
|
+
}
|
|
23736
|
+
}
|
|
23737
|
+
return childTurn;
|
|
23738
|
+
}
|
|
23739
|
+
const notificationThreadId = notification.params.threadId;
|
|
23740
|
+
if (typeof notificationThreadId === "string" && this.pendingSpawns.has(notificationThreadId)) {
|
|
23741
|
+
const pending = this.pendingSpawns.get(notificationThreadId);
|
|
23742
|
+
if (pending.buffered.length === _CodexSubagentEventRouter.MAX_PENDING_NOTIFICATIONS) {
|
|
23743
|
+
pending.buffered.shift();
|
|
23744
|
+
pending.droppedBufferedNotifications += 1;
|
|
23745
|
+
if (pending.droppedBufferedNotifications === 1) {
|
|
23746
|
+
logger.log(`Pending subagent ${notificationThreadId} exceeded the notification buffer; dropping oldest updates`);
|
|
23747
|
+
}
|
|
23748
|
+
}
|
|
23749
|
+
pending.buffered.push(notification);
|
|
23750
|
+
return true;
|
|
23751
|
+
}
|
|
23752
|
+
if (notification.method !== "item/started" && notification.method !== "item/completed") {
|
|
23753
|
+
return false;
|
|
23754
|
+
}
|
|
23755
|
+
const item = notification.params.item;
|
|
23756
|
+
if (!this.supported) {
|
|
23757
|
+
return false;
|
|
23758
|
+
}
|
|
23759
|
+
if (item.type === "subAgentActivity") {
|
|
23760
|
+
if (isRootAgentPath(item.agentPath)) return true;
|
|
23761
|
+
if (this.terminalPendingSpawns.has(item.agentThreadId)) return true;
|
|
23762
|
+
let hasNativeRepresentation = this.children.has(item.agentThreadId);
|
|
23763
|
+
if (!hasNativeRepresentation) {
|
|
23764
|
+
await this.materialize(item.agentThreadId, item.agentPath);
|
|
23765
|
+
hasNativeRepresentation = this.children.has(item.agentThreadId);
|
|
23766
|
+
}
|
|
23767
|
+
if (hasNativeRepresentation && item.kind === "interrupted") {
|
|
23768
|
+
await this.finish(item.agentThreadId, "cancelled");
|
|
23769
|
+
}
|
|
23770
|
+
return hasNativeRepresentation;
|
|
23771
|
+
}
|
|
23772
|
+
if (item.type !== "collabAgentToolCall") return false;
|
|
23773
|
+
if (item.tool === "resumeAgent" || item.tool === "sendInput") {
|
|
23774
|
+
for (const [childThreadId, state] of Object.entries(item.agentsStates)) {
|
|
23775
|
+
if (state?.status === "running" || state?.status === "pendingInit") {
|
|
23776
|
+
await this.reopen(childThreadId);
|
|
23777
|
+
}
|
|
23778
|
+
}
|
|
23779
|
+
}
|
|
23780
|
+
let representedSpawn = false;
|
|
23781
|
+
if (item.tool === "spawnAgent") {
|
|
23782
|
+
const parent = this.children.get(item.senderThreadId);
|
|
23783
|
+
const parentThreadId = parent ? item.senderThreadId : this.rootSessionId;
|
|
23784
|
+
const parentSessionId = parent?.sessionId ?? this.rootSessionId;
|
|
23785
|
+
for (const childSessionId of item.receiverThreadIds) {
|
|
23786
|
+
if (childSessionId.trim().length === 0) {
|
|
23787
|
+
logger.log("Ignoring spawned subagent with an empty thread id");
|
|
23788
|
+
continue;
|
|
23789
|
+
}
|
|
23790
|
+
if (childSessionId === parentSessionId || childSessionId === this.rootSessionId) {
|
|
23791
|
+
logger.log(`Ignoring self-referential spawned subagent ${childSessionId}`);
|
|
23792
|
+
continue;
|
|
23793
|
+
}
|
|
23794
|
+
if (this.children.has(childSessionId) || this.pendingSpawns.has(childSessionId) || this.terminalPendingSpawns.has(childSessionId)) {
|
|
23795
|
+
representedSpawn = true;
|
|
23796
|
+
continue;
|
|
23797
|
+
}
|
|
23798
|
+
this.pendingSpawns.set(childSessionId, {
|
|
23799
|
+
parentThreadId,
|
|
23800
|
+
parentSessionId,
|
|
23801
|
+
task: item.prompt?.trim() || "Delegated task",
|
|
23802
|
+
buffered: [],
|
|
23803
|
+
droppedBufferedNotifications: 0
|
|
23804
|
+
});
|
|
23805
|
+
representedSpawn = true;
|
|
23806
|
+
}
|
|
23807
|
+
}
|
|
23808
|
+
for (const [childSessionId, state] of Object.entries(item.agentsStates)) {
|
|
23809
|
+
const terminalState = state && terminalStateOf(state.status);
|
|
23810
|
+
if (!terminalState) continue;
|
|
23811
|
+
if (this.children.has(childSessionId)) await this.finish(childSessionId, terminalState);
|
|
23812
|
+
else if (this.pendingSpawns.has(childSessionId)) this.finishPending(childSessionId);
|
|
23813
|
+
}
|
|
23814
|
+
if (item.tool === "spawnAgent" && item.status === "failed") {
|
|
23815
|
+
for (const childSessionId of item.receiverThreadIds) {
|
|
23816
|
+
if (this.pendingSpawns.has(childSessionId)) this.finishPending(childSessionId);
|
|
23817
|
+
}
|
|
23818
|
+
}
|
|
23819
|
+
return item.tool === "spawnAgent" && representedSpawn;
|
|
23820
|
+
}
|
|
23821
|
+
shouldIgnore(notification) {
|
|
23822
|
+
const threadId = notification.params.threadId;
|
|
23823
|
+
const ignored = typeof threadId === "string" && (this.children.get(threadId)?.terminalState !== void 0 || this.terminalPendingSpawns.has(threadId));
|
|
23824
|
+
if (ignored) logger.log(`Ignoring update for terminal subagent ${threadId}`);
|
|
23825
|
+
return ignored;
|
|
23826
|
+
}
|
|
23827
|
+
notificationSessionId(notification) {
|
|
23828
|
+
const threadId = notification.params.threadId;
|
|
23829
|
+
return typeof threadId === "string" && this.children.has(threadId) ? this.children.get(threadId).sessionId : this.rootSessionId;
|
|
23830
|
+
}
|
|
23831
|
+
takeBufferedNotifications() {
|
|
23832
|
+
return this.replayQueue.splice(0);
|
|
23833
|
+
}
|
|
23834
|
+
async waitForMaterializedSession(childThreadId) {
|
|
23835
|
+
const child = this.children.get(childThreadId);
|
|
23836
|
+
if (child) return child.terminalState === void 0 ? child.sessionId : null;
|
|
23837
|
+
if (this.terminalPendingSpawns.has(childThreadId)) return null;
|
|
23838
|
+
if (!this.pendingSpawns.has(childThreadId)) return null;
|
|
23839
|
+
return await new Promise((resolve) => {
|
|
23840
|
+
const waiters = this.materializationWaiters.get(childThreadId) ?? /* @__PURE__ */ new Set();
|
|
23841
|
+
waiters.add(resolve);
|
|
23842
|
+
this.materializationWaiters.set(childThreadId, waiters);
|
|
23843
|
+
});
|
|
23844
|
+
}
|
|
23845
|
+
legacyActivityStarted(item) {
|
|
23846
|
+
this.activeLegacyActivities.add(item.id);
|
|
23847
|
+
return createSubAgentActivityUpdate(item, "in_progress", "tool_call");
|
|
23848
|
+
}
|
|
23849
|
+
legacyCollaborationStarted(item) {
|
|
23850
|
+
return createCollabAgentToolCallUpdate(item);
|
|
23851
|
+
}
|
|
23852
|
+
legacyCollaborationCompleted(item) {
|
|
23853
|
+
return createCollabAgentToolCallCompleteUpdate(item);
|
|
23854
|
+
}
|
|
23855
|
+
legacyActivityCompleted(item) {
|
|
23856
|
+
const sessionUpdate = this.activeLegacyActivities.delete(item.id) ? "tool_call_update" : "tool_call";
|
|
23857
|
+
return createSubAgentActivityUpdate(item, "completed", sessionUpdate);
|
|
23858
|
+
}
|
|
23859
|
+
async wait(signal, timeoutMs = _CodexSubagentEventRouter.DEFAULT_WAIT_TIMEOUT_MS) {
|
|
23860
|
+
const deadline = Date.now() + timeoutMs;
|
|
23861
|
+
while (this.hasOutstanding()) {
|
|
23862
|
+
if (signal.aborted) return;
|
|
23863
|
+
const remainingMs = deadline - Date.now();
|
|
23864
|
+
if (remainingMs <= 0) {
|
|
23865
|
+
logger.log(`Timed out waiting for subagents in session ${this.rootSessionId}; marking them failed`);
|
|
23866
|
+
await this.finishOutstanding("failed");
|
|
23867
|
+
return;
|
|
23868
|
+
}
|
|
23869
|
+
const changed = await new Promise((resolve) => {
|
|
23870
|
+
const timeout = setTimeout(() => {
|
|
23871
|
+
this.waiters.delete(onChange);
|
|
23872
|
+
signal.removeEventListener("abort", onAbort);
|
|
23873
|
+
resolve(false);
|
|
23874
|
+
}, remainingMs);
|
|
23875
|
+
const onAbort = () => {
|
|
23876
|
+
clearTimeout(timeout);
|
|
23877
|
+
this.waiters.delete(onChange);
|
|
23878
|
+
resolve(true);
|
|
23879
|
+
};
|
|
23880
|
+
const onChange = () => {
|
|
23881
|
+
clearTimeout(timeout);
|
|
23882
|
+
signal.removeEventListener("abort", onAbort);
|
|
23883
|
+
resolve(true);
|
|
23884
|
+
};
|
|
23885
|
+
this.waiters.add(onChange);
|
|
23886
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
23887
|
+
});
|
|
23888
|
+
if (!changed) {
|
|
23889
|
+
logger.log(`Timed out waiting for subagents in session ${this.rootSessionId}; marking them failed`);
|
|
23890
|
+
await this.finishOutstanding("failed");
|
|
23891
|
+
return;
|
|
23892
|
+
}
|
|
23893
|
+
}
|
|
23894
|
+
}
|
|
23895
|
+
async finishOutstanding(state) {
|
|
23896
|
+
for (const childSessionId of [...this.pendingSpawns.keys()]) {
|
|
23897
|
+
this.finishPending(childSessionId);
|
|
23898
|
+
}
|
|
23899
|
+
for (const childSessionId of [...this.children.keys()].reverse()) {
|
|
23900
|
+
await this.finish(childSessionId, state);
|
|
23901
|
+
}
|
|
23902
|
+
}
|
|
23903
|
+
isKnownChild(threadId) {
|
|
23904
|
+
return threadId !== this.rootSessionId && (this.children.has(threadId) || this.pendingSpawns.has(threadId) || this.terminalPendingSpawns.has(threadId));
|
|
23905
|
+
}
|
|
23906
|
+
async materialize(childSessionId, path9) {
|
|
23907
|
+
if (this.children.has(childSessionId)) return;
|
|
23908
|
+
const pending = this.pendingSpawns.get(childSessionId);
|
|
23909
|
+
const name = nameFromAgentPath(path9, fallbackName(childSessionId));
|
|
23910
|
+
const inferredParent = this.parentForPath(path9);
|
|
23911
|
+
const parentThreadId = pending?.parentThreadId ?? inferredParent.threadId;
|
|
23912
|
+
const parentSessionId = pending?.parentSessionId ?? inferredParent.sessionId;
|
|
23913
|
+
const task = pending?.task ?? `Delegated task for ${name}`;
|
|
23914
|
+
await this.session.update({
|
|
23915
|
+
sessionUpdate: "subagent_spawned",
|
|
23916
|
+
subagentSessionId: childSessionId,
|
|
23917
|
+
name,
|
|
23918
|
+
task,
|
|
23919
|
+
capabilities: {}
|
|
23920
|
+
}, parentSessionId);
|
|
23921
|
+
this.children.set(childSessionId, {
|
|
23922
|
+
parentThreadId,
|
|
23923
|
+
parentSessionId,
|
|
23924
|
+
sessionId: childSessionId,
|
|
23925
|
+
name,
|
|
23926
|
+
task,
|
|
23927
|
+
path: normalizeAgentPath(path9),
|
|
23928
|
+
generation: 1
|
|
23929
|
+
});
|
|
23930
|
+
this.pendingSpawns.delete(childSessionId);
|
|
23931
|
+
this.replayQueue.push(...pending?.buffered ?? []);
|
|
23932
|
+
this.resolveMaterialization(childSessionId, childSessionId);
|
|
23933
|
+
}
|
|
23934
|
+
finishPending(childSessionId) {
|
|
23935
|
+
const pending = this.pendingSpawns.get(childSessionId);
|
|
23936
|
+
if (!pending) return;
|
|
23937
|
+
this.pendingSpawns.delete(childSessionId);
|
|
23938
|
+
this.terminalPendingSpawns.set(childSessionId, pending);
|
|
23939
|
+
this.resolveMaterialization(childSessionId, null);
|
|
23940
|
+
this.notifyWaiters();
|
|
23941
|
+
}
|
|
23942
|
+
async finish(childSessionId, state) {
|
|
23943
|
+
const child = this.children.get(childSessionId);
|
|
23944
|
+
if (!child || child.terminalState !== void 0) return;
|
|
23945
|
+
child.terminalState = state;
|
|
23946
|
+
try {
|
|
23947
|
+
await this.session.update({
|
|
23948
|
+
sessionUpdate: "subagent_state_update",
|
|
23949
|
+
subagentSessionId: child.sessionId,
|
|
23950
|
+
state
|
|
23951
|
+
}, child.parentSessionId);
|
|
23952
|
+
} catch (error51) {
|
|
23953
|
+
if (child.terminalState === state) delete child.terminalState;
|
|
23954
|
+
throw error51;
|
|
23955
|
+
}
|
|
23956
|
+
this.notifyWaiters();
|
|
23957
|
+
}
|
|
23958
|
+
async reopen(childThreadId) {
|
|
23959
|
+
const child = this.children.get(childThreadId);
|
|
23960
|
+
if (!child) {
|
|
23961
|
+
const pending = this.terminalPendingSpawns.get(childThreadId);
|
|
23962
|
+
if (!pending) return;
|
|
23963
|
+
const parentSessionId = this.children.get(pending.parentThreadId)?.sessionId ?? this.rootSessionId;
|
|
23964
|
+
const reopened = {
|
|
23965
|
+
parentThreadId: pending.parentThreadId,
|
|
23966
|
+
parentSessionId,
|
|
23967
|
+
sessionId: `${childThreadId}:generation:2`,
|
|
23968
|
+
name: fallbackName(childThreadId),
|
|
23969
|
+
task: pending.task,
|
|
23970
|
+
generation: 2
|
|
23971
|
+
};
|
|
23972
|
+
await this.session.update({
|
|
23973
|
+
sessionUpdate: "subagent_spawned",
|
|
23974
|
+
subagentSessionId: reopened.sessionId,
|
|
23975
|
+
name: reopened.name,
|
|
23976
|
+
task: reopened.task,
|
|
23977
|
+
capabilities: {}
|
|
23978
|
+
}, parentSessionId);
|
|
23979
|
+
this.children.set(childThreadId, reopened);
|
|
23980
|
+
this.terminalPendingSpawns.delete(childThreadId);
|
|
23981
|
+
return;
|
|
23982
|
+
}
|
|
23983
|
+
if (!child.terminalState) return;
|
|
23984
|
+
const previousSessionId = child.sessionId;
|
|
23985
|
+
const previousParentSessionId = child.parentSessionId;
|
|
23986
|
+
const previousState = child.terminalState;
|
|
23987
|
+
child.parentSessionId = this.children.get(child.parentThreadId)?.sessionId ?? this.rootSessionId;
|
|
23988
|
+
child.generation += 1;
|
|
23989
|
+
child.sessionId = `${childThreadId}:generation:${child.generation}`;
|
|
23990
|
+
delete child.terminalState;
|
|
23991
|
+
try {
|
|
23992
|
+
await this.session.update({
|
|
23993
|
+
sessionUpdate: "subagent_spawned",
|
|
23994
|
+
subagentSessionId: child.sessionId,
|
|
23995
|
+
name: child.name,
|
|
23996
|
+
task: child.task,
|
|
23997
|
+
capabilities: {}
|
|
23998
|
+
}, child.parentSessionId);
|
|
23999
|
+
} catch (error51) {
|
|
24000
|
+
child.generation -= 1;
|
|
24001
|
+
child.sessionId = previousSessionId;
|
|
24002
|
+
child.parentSessionId = previousParentSessionId;
|
|
24003
|
+
child.terminalState = previousState;
|
|
24004
|
+
throw error51;
|
|
24005
|
+
}
|
|
24006
|
+
}
|
|
24007
|
+
resolveMaterialization(childThreadId, sessionId) {
|
|
24008
|
+
for (const resolve of this.materializationWaiters.get(childThreadId) ?? []) resolve(sessionId);
|
|
24009
|
+
this.materializationWaiters.delete(childThreadId);
|
|
24010
|
+
}
|
|
24011
|
+
hasOutstanding() {
|
|
24012
|
+
return this.pendingSpawns.size > 0 || [...this.children.values()].some((child) => child.terminalState === void 0);
|
|
24013
|
+
}
|
|
24014
|
+
notifyWaiters() {
|
|
24015
|
+
for (const waiter of this.waiters) waiter();
|
|
24016
|
+
this.waiters.clear();
|
|
24017
|
+
}
|
|
24018
|
+
parentForPath(path9) {
|
|
24019
|
+
const normalized = normalizeAgentPath(path9);
|
|
24020
|
+
const separator = normalized.lastIndexOf("/");
|
|
24021
|
+
if (separator <= 0) return { threadId: this.rootSessionId, sessionId: this.rootSessionId };
|
|
24022
|
+
const parentPath = normalized.slice(0, separator);
|
|
24023
|
+
const parent = [...this.children.entries()].find(([, child]) => child.path === parentPath);
|
|
24024
|
+
return parent ? { threadId: parent[0], sessionId: parent[1].sessionId } : { threadId: this.rootSessionId, sessionId: this.rootSessionId };
|
|
24025
|
+
}
|
|
24026
|
+
};
|
|
24027
|
+
function terminalStateOf(status) {
|
|
24028
|
+
switch (status) {
|
|
24029
|
+
case "completed":
|
|
24030
|
+
return "completed";
|
|
24031
|
+
case "interrupted":
|
|
24032
|
+
return "cancelled";
|
|
24033
|
+
case "errored":
|
|
24034
|
+
case "shutdown":
|
|
24035
|
+
case "notFound":
|
|
24036
|
+
return "failed";
|
|
24037
|
+
case "pendingInit":
|
|
24038
|
+
case "running":
|
|
24039
|
+
return void 0;
|
|
24040
|
+
}
|
|
24041
|
+
}
|
|
24042
|
+
function terminalStateFromTurn(status) {
|
|
24043
|
+
switch (status) {
|
|
24044
|
+
case "completed":
|
|
24045
|
+
return "completed";
|
|
24046
|
+
case "interrupted":
|
|
24047
|
+
return "cancelled";
|
|
24048
|
+
case "failed":
|
|
24049
|
+
return "failed";
|
|
24050
|
+
case "inProgress":
|
|
24051
|
+
return void 0;
|
|
24052
|
+
}
|
|
24053
|
+
}
|
|
24054
|
+
function fallbackName(sessionId) {
|
|
24055
|
+
const suffix = sessionId.length > 8 ? sessionId.slice(-8) : sessionId;
|
|
24056
|
+
return `Agent ${suffix}`;
|
|
24057
|
+
}
|
|
23634
24058
|
|
|
23635
24059
|
// src/CodexEventHandler.ts
|
|
23636
24060
|
var MAX_SESSION_FAILURE_TITLE_LENGTH = 240;
|
|
@@ -23738,13 +24162,18 @@ var CodexEventHandler = class _CodexEventHandler {
|
|
|
23738
24162
|
terminalCommandIds = /* @__PURE__ */ new Set();
|
|
23739
24163
|
terminalCommandOutputIds = /* @__PURE__ */ new Set();
|
|
23740
24164
|
agentMessagePhases = /* @__PURE__ */ new Map();
|
|
23741
|
-
|
|
23742
|
-
constructor(connection, sessionState, supportsPlanUpdates = false, supportsTypedSessionFailures = false, sessionFailureEpoch = randomUUID()
|
|
24165
|
+
subagents;
|
|
24166
|
+
constructor(connection, sessionState, supportsPlanUpdates = false, supportsTypedSessionFailures = false, sessionFailureEpoch = randomUUID(), subagents = new CodexSubagentEventRouter(
|
|
24167
|
+
sessionState.sessionId,
|
|
24168
|
+
false,
|
|
24169
|
+
new ACPSessionConnection(connection, sessionState.sessionId)
|
|
24170
|
+
)) {
|
|
23743
24171
|
this.sessionState = sessionState;
|
|
23744
24172
|
this.supportsPlanUpdates = supportsPlanUpdates;
|
|
23745
24173
|
this.supportsTypedSessionFailures = supportsTypedSessionFailures;
|
|
23746
24174
|
this.sessionFailureEpoch = sessionFailureEpoch;
|
|
23747
24175
|
this.session = new ACPSessionConnection(connection, sessionState.sessionId);
|
|
24176
|
+
this.subagents = subagents;
|
|
23748
24177
|
if (sessionState.sessionFailure !== void 0) {
|
|
23749
24178
|
this.failuresById.set(sessionState.sessionFailure.id, sessionState.sessionFailure);
|
|
23750
24179
|
}
|
|
@@ -23846,11 +24275,30 @@ var CodexEventHandler = class _CodexEventHandler {
|
|
|
23846
24275
|
}
|
|
23847
24276
|
async handleNotification(notification) {
|
|
23848
24277
|
await this.flushPendingErrors();
|
|
24278
|
+
const handledBySubagents = await this.subagents.handle(notification);
|
|
24279
|
+
for (const buffered of this.subagents.takeBufferedNotifications()) {
|
|
24280
|
+
await this.handleNotification(buffered);
|
|
24281
|
+
}
|
|
24282
|
+
if (handledBySubagents) {
|
|
24283
|
+
return;
|
|
24284
|
+
}
|
|
24285
|
+
if (this.subagents.shouldIgnore(notification)) {
|
|
24286
|
+
return;
|
|
24287
|
+
}
|
|
23849
24288
|
const updateEvent = await this.createUpdateEvent(notification);
|
|
23850
24289
|
if (updateEvent) {
|
|
23851
|
-
await this.session.update(updateEvent);
|
|
24290
|
+
await this.session.update(updateEvent, this.subagents.notificationSessionId(notification));
|
|
23852
24291
|
}
|
|
23853
24292
|
}
|
|
24293
|
+
async waitForNativeSubagentSession(childThreadId) {
|
|
24294
|
+
return await this.subagents.waitForMaterializedSession(childThreadId);
|
|
24295
|
+
}
|
|
24296
|
+
async waitForNativeSubagents(signal) {
|
|
24297
|
+
await this.subagents.wait(signal);
|
|
24298
|
+
}
|
|
24299
|
+
async finishOutstandingNativeSubagents(state) {
|
|
24300
|
+
await this.subagents.finishOutstanding(state);
|
|
24301
|
+
}
|
|
23854
24302
|
async flushPendingPlanUpdates() {
|
|
23855
24303
|
this.cancelPlanUpdateTimer();
|
|
23856
24304
|
do {
|
|
@@ -24142,15 +24590,14 @@ ${event.details}` : event.summary;
|
|
|
24142
24590
|
this.activeImageGenerationItems.add(event.item.id);
|
|
24143
24591
|
return createImageGenerationStartUpdate(event.item);
|
|
24144
24592
|
case "collabAgentToolCall":
|
|
24145
|
-
return
|
|
24593
|
+
return this.subagents.legacyCollaborationStarted(event.item);
|
|
24146
24594
|
case "agentMessage":
|
|
24147
24595
|
this.rememberAgentMessagePhase(event.item);
|
|
24148
24596
|
return null;
|
|
24149
24597
|
case "contextCompaction":
|
|
24150
24598
|
return createContextCompactionStartUpdate(event.item);
|
|
24151
24599
|
case "subAgentActivity":
|
|
24152
|
-
this.
|
|
24153
|
-
return createSubAgentActivityUpdate(event.item, "in_progress", "tool_call");
|
|
24600
|
+
return this.subagents.legacyActivityStarted(event.item);
|
|
24154
24601
|
case "sleep":
|
|
24155
24602
|
case "userMessage":
|
|
24156
24603
|
case "hookPrompt":
|
|
@@ -24198,7 +24645,7 @@ ${event.details}` : event.summary;
|
|
|
24198
24645
|
case "webSearch":
|
|
24199
24646
|
return createWebSearchCompleteUpdate(event.item);
|
|
24200
24647
|
case "collabAgentToolCall":
|
|
24201
|
-
return
|
|
24648
|
+
return this.subagents.legacyCollaborationCompleted(event.item);
|
|
24202
24649
|
case "agentMessage":
|
|
24203
24650
|
this.rememberAgentMessagePhase(event.item);
|
|
24204
24651
|
return null;
|
|
@@ -24211,10 +24658,8 @@ ${event.details}` : event.summary;
|
|
|
24211
24658
|
case "contextCompaction":
|
|
24212
24659
|
return createContextCompactionCompleteUpdate(event.item);
|
|
24213
24660
|
//ignored types
|
|
24214
|
-
case "subAgentActivity":
|
|
24215
|
-
|
|
24216
|
-
return createSubAgentActivityUpdate(event.item, "completed", sessionUpdate);
|
|
24217
|
-
}
|
|
24661
|
+
case "subAgentActivity":
|
|
24662
|
+
return this.subagents.legacyActivityCompleted(event.item);
|
|
24218
24663
|
case "sleep":
|
|
24219
24664
|
case "userMessage":
|
|
24220
24665
|
case "hookPrompt":
|
|
@@ -24663,343 +25108,545 @@ ${event.stdin}
|
|
|
24663
25108
|
}
|
|
24664
25109
|
};
|
|
24665
25110
|
|
|
24666
|
-
// src/
|
|
25111
|
+
// src/permissions/option-ids.ts
|
|
24667
25112
|
var ApprovalOptionId = {
|
|
24668
25113
|
AllowOnce: "allow_once",
|
|
24669
|
-
|
|
24670
|
-
|
|
25114
|
+
AllowForSession: "allow_for_session",
|
|
25115
|
+
Decline: "decline",
|
|
25116
|
+
Cancel: "cancel",
|
|
24671
25117
|
AcceptWithExecpolicyAmendment: "accept_execpolicy_amendment",
|
|
24672
25118
|
ApplyNetworkPolicyAmendment: "apply_network_policy_amendment",
|
|
24673
25119
|
AllowPermissionsForTurn: "allow_permissions_turn",
|
|
25120
|
+
AllowPermissionsForTurnWithStrictAutoReview: "allow_permissions_turn_strict_auto_review",
|
|
24674
25121
|
AllowPermissionsForSession: "allow_permissions_session",
|
|
24675
25122
|
RejectPermissions: "reject_permissions"
|
|
24676
25123
|
};
|
|
25124
|
+
var McpApprovalOptionId = {
|
|
25125
|
+
AllowOnce: "allow_once",
|
|
25126
|
+
AllowSession: "allow_session",
|
|
25127
|
+
AllowAlways: "allow_always",
|
|
25128
|
+
Decline: "decline",
|
|
25129
|
+
Cancel: "cancel"
|
|
25130
|
+
};
|
|
24677
25131
|
|
|
24678
|
-
// src/
|
|
24679
|
-
function
|
|
24680
|
-
return
|
|
24681
|
-
optionId,
|
|
24682
|
-
name,
|
|
24683
|
-
kind,
|
|
24684
|
-
...codexMeta || permission ? {
|
|
24685
|
-
_meta: {
|
|
24686
|
-
...permission ? { permission } : {},
|
|
24687
|
-
...codexMeta ? { codex: codexMeta } : {}
|
|
24688
|
-
}
|
|
24689
|
-
} : {}
|
|
24690
|
-
};
|
|
25132
|
+
// src/permissions/json.ts
|
|
25133
|
+
function isRecord2(value) {
|
|
25134
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
24691
25135
|
}
|
|
24692
|
-
|
|
24693
|
-
|
|
24694
|
-
|
|
24695
|
-
|
|
24696
|
-
|
|
24697
|
-
|
|
24698
|
-
|
|
24699
|
-
|
|
25136
|
+
function recordOrNull(value) {
|
|
25137
|
+
return isRecord2(value) ? value : null;
|
|
25138
|
+
}
|
|
25139
|
+
function normalizeJsonValue(value) {
|
|
25140
|
+
if (value === null || value === void 0) return null;
|
|
25141
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return value;
|
|
25142
|
+
if (typeof value === "bigint") return Number(value);
|
|
25143
|
+
if (Array.isArray(value)) return value.map(normalizeJsonValue);
|
|
25144
|
+
if (typeof value === "object") {
|
|
25145
|
+
return Object.fromEntries(
|
|
25146
|
+
Object.entries(value).filter(([, nested]) => nested !== void 0).map(([key, nested]) => [key, normalizeJsonValue(nested)])
|
|
25147
|
+
);
|
|
24700
25148
|
}
|
|
24701
|
-
|
|
24702
|
-
|
|
24703
|
-
|
|
24704
|
-
|
|
24705
|
-
|
|
24706
|
-
|
|
24707
|
-
|
|
24708
|
-
|
|
24709
|
-
|
|
24710
|
-
|
|
24711
|
-
|
|
24712
|
-
|
|
24713
|
-
|
|
24714
|
-
|
|
25149
|
+
return String(value);
|
|
25150
|
+
}
|
|
25151
|
+
function normalizeJsonObject(value) {
|
|
25152
|
+
return Object.fromEntries(
|
|
25153
|
+
Object.entries(value).filter(([, nested]) => nested !== void 0).map(([key, nested]) => [key, normalizeJsonValue(nested)])
|
|
25154
|
+
);
|
|
25155
|
+
}
|
|
25156
|
+
|
|
25157
|
+
// src/permissions/command-decision-contract.ts
|
|
25158
|
+
function parseAvailableCommandDecisions(params) {
|
|
25159
|
+
if (params.availableDecisions === void 0 || params.availableDecisions === null) {
|
|
25160
|
+
return defaultCommandDecisions(params);
|
|
25161
|
+
}
|
|
25162
|
+
if (!Array.isArray(params.availableDecisions) || params.availableDecisions.length === 0) return void 0;
|
|
25163
|
+
const decisions = [];
|
|
25164
|
+
for (const candidate of params.availableDecisions) {
|
|
25165
|
+
const decision = parseCommandDecision(candidate, params);
|
|
25166
|
+
if (!decision) return void 0;
|
|
25167
|
+
decisions.push(decision);
|
|
25168
|
+
}
|
|
25169
|
+
return decisions;
|
|
25170
|
+
}
|
|
25171
|
+
function defaultCommandDecisions(params) {
|
|
25172
|
+
if (params.networkApprovalContext) {
|
|
25173
|
+
const decisions2 = ["accept", "acceptForSession"];
|
|
25174
|
+
for (const amendment of params.proposedNetworkPolicyAmendments ?? []) {
|
|
25175
|
+
decisions2.push({ applyNetworkPolicyAmendment: { network_policy_amendment: amendment } });
|
|
25176
|
+
}
|
|
25177
|
+
decisions2.push("decline", "cancel");
|
|
25178
|
+
return decisions2;
|
|
25179
|
+
}
|
|
25180
|
+
if (params.additionalPermissions) return ["accept", "cancel"];
|
|
25181
|
+
const decisions = ["accept", "acceptForSession"];
|
|
25182
|
+
if (params.proposedExecpolicyAmendment && params.proposedExecpolicyAmendment.length > 0) {
|
|
25183
|
+
decisions.push({
|
|
25184
|
+
acceptWithExecpolicyAmendment: { execpolicy_amendment: params.proposedExecpolicyAmendment }
|
|
25185
|
+
});
|
|
24715
25186
|
}
|
|
24716
|
-
|
|
24717
|
-
|
|
24718
|
-
|
|
24719
|
-
|
|
24720
|
-
|
|
24721
|
-
|
|
24722
|
-
|
|
24723
|
-
|
|
24724
|
-
|
|
24725
|
-
|
|
24726
|
-
|
|
24727
|
-
|
|
24728
|
-
|
|
25187
|
+
decisions.push("decline", "cancel");
|
|
25188
|
+
return decisions;
|
|
25189
|
+
}
|
|
25190
|
+
function parseCommandDecision(candidate, params) {
|
|
25191
|
+
if (candidate === "accept" || candidate === "acceptForSession" || candidate === "decline" || candidate === "cancel") {
|
|
25192
|
+
return candidate;
|
|
25193
|
+
}
|
|
25194
|
+
if (!isRecord2(candidate)) return void 0;
|
|
25195
|
+
if ("acceptWithExecpolicyAmendment" in candidate) {
|
|
25196
|
+
const value = candidate["acceptWithExecpolicyAmendment"];
|
|
25197
|
+
if (!isRecord2(value)) return void 0;
|
|
25198
|
+
const amendment = value["execpolicy_amendment"];
|
|
25199
|
+
if (!isStringArray(amendment) || amendment.length === 0) return void 0;
|
|
25200
|
+
if (!sameStrings(amendment, params.proposedExecpolicyAmendment)) return void 0;
|
|
25201
|
+
return { acceptWithExecpolicyAmendment: { execpolicy_amendment: [...amendment] } };
|
|
25202
|
+
}
|
|
25203
|
+
if ("applyNetworkPolicyAmendment" in candidate) {
|
|
25204
|
+
const value = candidate["applyNetworkPolicyAmendment"];
|
|
25205
|
+
if (!isRecord2(value)) return void 0;
|
|
25206
|
+
const amendment = parseNetworkAmendment(value["network_policy_amendment"]);
|
|
25207
|
+
if (!amendment || !params.networkApprovalContext) return void 0;
|
|
25208
|
+
if (amendment.host !== params.networkApprovalContext.host) return void 0;
|
|
25209
|
+
if (!(params.proposedNetworkPolicyAmendments ?? []).some((proposed) => sameNetworkAmendment(proposed, amendment))) {
|
|
25210
|
+
return void 0;
|
|
24729
25211
|
}
|
|
25212
|
+
return { applyNetworkPolicyAmendment: { network_policy_amendment: amendment } };
|
|
24730
25213
|
}
|
|
24731
|
-
|
|
24732
|
-
|
|
24733
|
-
|
|
24734
|
-
|
|
24735
|
-
|
|
24736
|
-
|
|
24737
|
-
|
|
24738
|
-
|
|
24739
|
-
|
|
24740
|
-
|
|
24741
|
-
|
|
24742
|
-
|
|
24743
|
-
|
|
25214
|
+
return void 0;
|
|
25215
|
+
}
|
|
25216
|
+
function parseNetworkAmendment(value) {
|
|
25217
|
+
if (!isRecord2(value) || typeof value["host"] !== "string") return void 0;
|
|
25218
|
+
const action = value["action"];
|
|
25219
|
+
if (action !== "allow" && action !== "deny") return void 0;
|
|
25220
|
+
return { host: value["host"], action };
|
|
25221
|
+
}
|
|
25222
|
+
function isStringArray(value) {
|
|
25223
|
+
return Array.isArray(value) && value.every((entry) => typeof entry === "string");
|
|
25224
|
+
}
|
|
25225
|
+
function sameStrings(left, right) {
|
|
25226
|
+
return !!right && left.length === right.length && left.every((value, index) => value === right[index]);
|
|
25227
|
+
}
|
|
25228
|
+
function sameNetworkAmendment(left, right) {
|
|
25229
|
+
return left.host === right.host && left.action === right.action;
|
|
25230
|
+
}
|
|
25231
|
+
|
|
25232
|
+
// src/permissions/options.ts
|
|
25233
|
+
function commandDecisionOptions(params) {
|
|
25234
|
+
const decisions = parseAvailableCommandDecisions(params);
|
|
25235
|
+
if (!decisions) return void 0;
|
|
25236
|
+
const options = [];
|
|
25237
|
+
let networkIndex = 0;
|
|
25238
|
+
for (const decision of decisions) {
|
|
25239
|
+
if (decision === "accept") {
|
|
25240
|
+
options.push(decisionOption(
|
|
25241
|
+
ApprovalOptionId.AllowOnce,
|
|
25242
|
+
params.networkApprovalContext ? "Yes, just this once" : "Yes, proceed",
|
|
25243
|
+
"allow_once",
|
|
25244
|
+
decision
|
|
25245
|
+
));
|
|
25246
|
+
} else if (decision === "acceptForSession") {
|
|
25247
|
+
options.push(decisionOption(
|
|
25248
|
+
ApprovalOptionId.AllowForSession,
|
|
25249
|
+
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",
|
|
25250
|
+
"allow_always",
|
|
25251
|
+
decision
|
|
25252
|
+
));
|
|
25253
|
+
} else if (decision === "decline") {
|
|
25254
|
+
options.push(decisionOption(
|
|
25255
|
+
ApprovalOptionId.Decline,
|
|
25256
|
+
"No, continue without running it",
|
|
25257
|
+
"reject_once",
|
|
25258
|
+
decision
|
|
25259
|
+
));
|
|
25260
|
+
} else if (decision === "cancel") {
|
|
25261
|
+
options.push(decisionOption(
|
|
25262
|
+
ApprovalOptionId.Cancel,
|
|
25263
|
+
"No, and tell Codex what to do differently",
|
|
25264
|
+
"reject_once",
|
|
25265
|
+
decision
|
|
25266
|
+
));
|
|
25267
|
+
} else if ("acceptWithExecpolicyAmendment" in decision) {
|
|
25268
|
+
const prefix = renderExecPolicyPrefix(decision.acceptWithExecpolicyAmendment.execpolicy_amendment);
|
|
25269
|
+
if (prefix.includes("\n") || prefix.includes("\r")) continue;
|
|
25270
|
+
options.push(decisionOption(
|
|
25271
|
+
ApprovalOptionId.AcceptWithExecpolicyAmendment,
|
|
25272
|
+
`Yes, and don't ask again for commands that start with \`${prefix}\``,
|
|
25273
|
+
"allow_always",
|
|
25274
|
+
decision
|
|
25275
|
+
));
|
|
25276
|
+
} else {
|
|
25277
|
+
const amendment = decision.applyNetworkPolicyAmendment.network_policy_amendment;
|
|
25278
|
+
options.push(decisionOption(
|
|
25279
|
+
`${ApprovalOptionId.ApplyNetworkPolicyAmendment}:${networkIndex++}`,
|
|
25280
|
+
amendment.action === "allow" ? "Yes, and allow this host in the future" : "No, and block this host in the future",
|
|
25281
|
+
amendment.action === "allow" ? "allow_always" : "reject_always",
|
|
25282
|
+
decision
|
|
25283
|
+
));
|
|
24744
25284
|
}
|
|
24745
25285
|
}
|
|
24746
|
-
|
|
24747
|
-
|
|
25286
|
+
const orderedOptions = [...options].sort(
|
|
25287
|
+
(left, right) => permissionOptionOrder(left.option) - permissionOptionOrder(right.option)
|
|
25288
|
+
);
|
|
25289
|
+
const hasAllow = orderedOptions.some(({ option }) => option.kind === "allow_once" || option.kind === "allow_always");
|
|
25290
|
+
const hasReject = orderedOptions.some(({ option }) => option.kind === "reject_once" || option.kind === "reject_always");
|
|
25291
|
+
const optionIds = orderedOptions.map(({ option }) => option.optionId);
|
|
25292
|
+
const hasUniqueOptionIds = new Set(optionIds).size === optionIds.length;
|
|
25293
|
+
return hasAllow && hasReject && hasUniqueOptionIds ? orderedOptions : void 0;
|
|
25294
|
+
}
|
|
25295
|
+
function permissionOptionOrder(option) {
|
|
25296
|
+
if (option.kind === "allow_once") return 0;
|
|
25297
|
+
if (option.kind === "allow_always") return 1;
|
|
25298
|
+
return 2;
|
|
25299
|
+
}
|
|
25300
|
+
function fileChangeDecisionOptions() {
|
|
25301
|
+
return [
|
|
25302
|
+
decisionOption(ApprovalOptionId.AllowOnce, "Yes, proceed", "allow_once", "accept"),
|
|
25303
|
+
decisionOption(
|
|
25304
|
+
ApprovalOptionId.AllowForSession,
|
|
25305
|
+
"Yes, and don't ask again for these files",
|
|
25306
|
+
"allow_always",
|
|
25307
|
+
"acceptForSession"
|
|
25308
|
+
),
|
|
25309
|
+
decisionOption(
|
|
25310
|
+
ApprovalOptionId.Cancel,
|
|
25311
|
+
"No, and tell Codex what to do differently",
|
|
25312
|
+
"reject_once",
|
|
25313
|
+
"cancel"
|
|
25314
|
+
)
|
|
25315
|
+
];
|
|
25316
|
+
}
|
|
25317
|
+
function permissionProfileOptions() {
|
|
25318
|
+
return [
|
|
25319
|
+
permissionOption(
|
|
25320
|
+
ApprovalOptionId.AllowPermissionsForTurn,
|
|
25321
|
+
"Yes, grant these permissions for this turn",
|
|
25322
|
+
"allow_once"
|
|
25323
|
+
),
|
|
25324
|
+
permissionOption(
|
|
25325
|
+
ApprovalOptionId.AllowPermissionsForTurnWithStrictAutoReview,
|
|
25326
|
+
"Yes, grant for this turn with strict auto review",
|
|
25327
|
+
"allow_once"
|
|
25328
|
+
),
|
|
25329
|
+
permissionOption(
|
|
25330
|
+
ApprovalOptionId.AllowPermissionsForSession,
|
|
25331
|
+
"Yes, grant these permissions for this session",
|
|
25332
|
+
"allow_always"
|
|
25333
|
+
),
|
|
25334
|
+
permissionOption(
|
|
25335
|
+
ApprovalOptionId.RejectPermissions,
|
|
25336
|
+
"No, continue without permissions",
|
|
25337
|
+
"reject_once"
|
|
25338
|
+
)
|
|
25339
|
+
];
|
|
25340
|
+
}
|
|
25341
|
+
function decisionOption(optionId, name, kind, decision) {
|
|
25342
|
+
return { option: permissionOption(optionId, name, kind), decision };
|
|
25343
|
+
}
|
|
25344
|
+
function permissionOption(optionId, name, kind) {
|
|
25345
|
+
return { optionId, name, kind };
|
|
25346
|
+
}
|
|
25347
|
+
function renderExecPolicyPrefix(command) {
|
|
25348
|
+
const script = extractWrappedScript(command);
|
|
25349
|
+
if (script !== void 0) return script;
|
|
25350
|
+
if (command.some((value) => value.includes("\0"))) return command.join(" ");
|
|
25351
|
+
return command.map(shlexQuote).join(" ");
|
|
25352
|
+
}
|
|
25353
|
+
function extractWrappedScript(command) {
|
|
25354
|
+
const executable = executableName(command[0]);
|
|
25355
|
+
if ((executable === "bash" || executable === "zsh" || executable === "sh") && command.length === 3 && (command[1] === "-lc" || command[1] === "-c")) {
|
|
25356
|
+
return command[2];
|
|
24748
25357
|
}
|
|
24749
|
-
|
|
24750
|
-
|
|
24751
|
-
|
|
24752
|
-
|
|
24753
|
-
|
|
24754
|
-
|
|
24755
|
-
kind: "execute",
|
|
24756
|
-
status: "pending",
|
|
24757
|
-
rawInput: params.command ? { command: stripShellPrefix(params.command), cwd: params.cwd } : null
|
|
24758
|
-
},
|
|
24759
|
-
options,
|
|
24760
|
-
_meta: { codex: { params } }
|
|
24761
|
-
};
|
|
25358
|
+
if (executable !== "pwsh" && executable !== "powershell") return void 0;
|
|
25359
|
+
const allowedFlags = /* @__PURE__ */ new Set(["-nologo", "-noprofile", "-command", "-c"]);
|
|
25360
|
+
for (let index = 1; index + 1 < command.length; index++) {
|
|
25361
|
+
const flag = command[index]?.toLowerCase();
|
|
25362
|
+
if (flag === void 0 || !allowedFlags.has(flag)) return void 0;
|
|
25363
|
+
if (flag === "-command" || flag === "-c") return command[index + 1];
|
|
24762
25364
|
}
|
|
24763
|
-
|
|
24764
|
-
|
|
24765
|
-
|
|
24766
|
-
|
|
24767
|
-
|
|
24768
|
-
|
|
24769
|
-
|
|
24770
|
-
|
|
24771
|
-
|
|
24772
|
-
options,
|
|
24773
|
-
_meta: { codex: { params } }
|
|
24774
|
-
};
|
|
25365
|
+
return void 0;
|
|
25366
|
+
}
|
|
25367
|
+
function executableName(command) {
|
|
25368
|
+
let filename = command?.replaceAll("\\", "/").split("/").at(-1);
|
|
25369
|
+
while (filename !== void 0) {
|
|
25370
|
+
if (["bash", "zsh", "sh", "pwsh", "powershell"].includes(filename)) return filename;
|
|
25371
|
+
const dot = filename.lastIndexOf(".");
|
|
25372
|
+
if (dot <= 0) return void 0;
|
|
25373
|
+
filename = filename.slice(0, dot);
|
|
24775
25374
|
}
|
|
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
|
-
|
|
24805
|
-
|
|
24806
|
-
|
|
24807
|
-
|
|
24808
|
-
"Reject",
|
|
24809
|
-
"reject_once",
|
|
24810
|
-
{ decision: "rejectPermissions" }
|
|
24811
|
-
)
|
|
24812
|
-
],
|
|
24813
|
-
_meta: { codex: { params } }
|
|
24814
|
-
};
|
|
25375
|
+
return void 0;
|
|
25376
|
+
}
|
|
25377
|
+
function shlexQuote(value) {
|
|
25378
|
+
if (value.length === 0) return "''";
|
|
25379
|
+
const UNQUOTED = 1;
|
|
25380
|
+
const SINGLE_QUOTED = 2;
|
|
25381
|
+
const DOUBLE_QUOTED = 4;
|
|
25382
|
+
let offset = 0;
|
|
25383
|
+
let result = "";
|
|
25384
|
+
while (offset < value.length) {
|
|
25385
|
+
const start = offset;
|
|
25386
|
+
let allowed = UNQUOTED | SINGLE_QUOTED | DOUBLE_QUOTED;
|
|
25387
|
+
if (value[offset] === "^") {
|
|
25388
|
+
allowed = SINGLE_QUOTED;
|
|
25389
|
+
offset++;
|
|
25390
|
+
}
|
|
25391
|
+
while (offset < value.length) {
|
|
25392
|
+
const character = value[offset];
|
|
25393
|
+
let nextAllowed = allowed;
|
|
25394
|
+
if (!isShlexUnquoted(character)) nextAllowed &= ~UNQUOTED;
|
|
25395
|
+
if (character === "'" || character === "^" || character === "\\") nextAllowed &= ~SINGLE_QUOTED;
|
|
25396
|
+
if (character === "`" || character === "$" || character === "!" || character === "^") {
|
|
25397
|
+
nextAllowed &= ~DOUBLE_QUOTED;
|
|
25398
|
+
}
|
|
25399
|
+
if (nextAllowed === 0) break;
|
|
25400
|
+
allowed = nextAllowed;
|
|
25401
|
+
offset++;
|
|
25402
|
+
}
|
|
25403
|
+
const chunk = value.slice(start, offset);
|
|
25404
|
+
if ((allowed & UNQUOTED) !== 0) result += chunk;
|
|
25405
|
+
else if ((allowed & SINGLE_QUOTED) !== 0) result += `'${chunk}'`;
|
|
25406
|
+
else result += `"${chunk.replace(/["\\]/g, "\\$&")}"`;
|
|
24815
25407
|
}
|
|
24816
|
-
|
|
24817
|
-
|
|
25408
|
+
return result;
|
|
25409
|
+
}
|
|
25410
|
+
function isShlexUnquoted(character) {
|
|
25411
|
+
return /^[0-9A-Za-z]$/.test(character) || "+-./:@]_".includes(character);
|
|
25412
|
+
}
|
|
25413
|
+
|
|
25414
|
+
// src/permissions/metadata.ts
|
|
25415
|
+
var CODEX_COMMAND_PERMISSION_TITLE = "Run command?";
|
|
25416
|
+
var CODEX_NETWORK_PERMISSION_TITLE = "Allow network access?";
|
|
25417
|
+
var CODEX_FILE_CHANGE_PERMISSION_TITLE = "Make edits?";
|
|
25418
|
+
var CODEX_ADDITIONAL_PERMISSIONS_TITLE = "Grant permissions?";
|
|
25419
|
+
function requestPermissionMeta(title, reason) {
|
|
25420
|
+
const description = nonBlank(reason);
|
|
25421
|
+
const permission = {
|
|
25422
|
+
version: 1,
|
|
25423
|
+
title,
|
|
25424
|
+
...description ? { description } : {}
|
|
25425
|
+
};
|
|
25426
|
+
return { permission };
|
|
25427
|
+
}
|
|
25428
|
+
function optionPermissionMeta(description) {
|
|
25429
|
+
const normalized = nonBlank(description);
|
|
25430
|
+
if (!normalized) return void 0;
|
|
25431
|
+
const permission = { version: 1, description: normalized };
|
|
25432
|
+
return { permission };
|
|
25433
|
+
}
|
|
25434
|
+
function nonBlank(value) {
|
|
25435
|
+
const normalized = value?.trim();
|
|
25436
|
+
return normalized ? normalized : void 0;
|
|
25437
|
+
}
|
|
25438
|
+
|
|
25439
|
+
// src/permissions/presentation.ts
|
|
25440
|
+
function commandToolCall(params) {
|
|
25441
|
+
const network = params.networkApprovalContext;
|
|
25442
|
+
const rawInput = {
|
|
25443
|
+
...params.command ? { command: stripShellPrefix(params.command) } : {},
|
|
25444
|
+
...params.cwd ? { cwd: params.cwd } : {},
|
|
25445
|
+
...network?.protocol === "http" || network?.protocol === "https" ? { url: `${network.protocol}://${network.host}` } : {},
|
|
25446
|
+
...params.additionalPermissions ? { additionalPermissions: params.additionalPermissions } : {}
|
|
25447
|
+
};
|
|
25448
|
+
const additionalPermissionContent = params.additionalPermissions ? permissionProfileContent(params.additionalPermissions) : [];
|
|
25449
|
+
return {
|
|
25450
|
+
toolCallId: params.itemId,
|
|
25451
|
+
kind: "execute",
|
|
25452
|
+
status: "pending",
|
|
25453
|
+
title: network ? `${network.protocol} network access to ${network.host}` : commandTitle(params.commandActions),
|
|
25454
|
+
...Object.keys(rawInput).length > 0 ? { rawInput } : {},
|
|
25455
|
+
...locationsField(unique([
|
|
25456
|
+
...commandActionPaths(params.commandActions),
|
|
25457
|
+
...permissionProfilePaths(params.additionalPermissions)
|
|
25458
|
+
])),
|
|
25459
|
+
...network ? { content: [textContent(`${network.protocol} access to ${network.host}`), ...additionalPermissionContent] } : additionalPermissionContent.length > 0 ? { content: additionalPermissionContent } : {}
|
|
25460
|
+
};
|
|
25461
|
+
}
|
|
25462
|
+
function fileChangeToolCall(params, permissionContext) {
|
|
25463
|
+
const item = permissionContext.fileChange(params.threadId, params.itemId);
|
|
25464
|
+
return {
|
|
25465
|
+
toolCallId: params.itemId,
|
|
25466
|
+
kind: "edit",
|
|
25467
|
+
status: "pending",
|
|
25468
|
+
title: "Edit files",
|
|
25469
|
+
...locationsField(fileChangePaths(item))
|
|
25470
|
+
};
|
|
25471
|
+
}
|
|
25472
|
+
function additionalPermissionsToolCall(itemId, cwd, environmentId, permissions) {
|
|
25473
|
+
const content = permissionProfileContent(permissions);
|
|
25474
|
+
return {
|
|
25475
|
+
toolCallId: itemId,
|
|
25476
|
+
kind: "other",
|
|
25477
|
+
status: "pending",
|
|
25478
|
+
title: "Additional sandbox permissions",
|
|
25479
|
+
rawInput: { permissions, cwd, environmentId },
|
|
25480
|
+
...locationsField(permissionProfilePaths(permissions)),
|
|
25481
|
+
...content.length > 0 ? { content } : {}
|
|
25482
|
+
};
|
|
25483
|
+
}
|
|
25484
|
+
function commandTitle(actions) {
|
|
25485
|
+
const first = actions?.[0];
|
|
25486
|
+
if (!first) return "Run command";
|
|
25487
|
+
switch (first.type) {
|
|
25488
|
+
case "read":
|
|
25489
|
+
return actions?.length === 1 ? "Read file" : "Run command with file reads";
|
|
25490
|
+
case "listFiles":
|
|
25491
|
+
return "List files";
|
|
25492
|
+
case "search":
|
|
25493
|
+
return "Search files";
|
|
25494
|
+
case "unknown":
|
|
25495
|
+
return "Run command";
|
|
25496
|
+
}
|
|
25497
|
+
}
|
|
25498
|
+
function commandActionPaths(actions) {
|
|
25499
|
+
return unique((actions ?? []).flatMap((action) => {
|
|
25500
|
+
switch (action.type) {
|
|
25501
|
+
case "read":
|
|
25502
|
+
return [action.path];
|
|
25503
|
+
case "listFiles":
|
|
25504
|
+
case "search":
|
|
25505
|
+
return action.path ? [action.path] : [];
|
|
25506
|
+
case "unknown":
|
|
25507
|
+
return [];
|
|
25508
|
+
}
|
|
25509
|
+
}));
|
|
25510
|
+
}
|
|
25511
|
+
function fileChangePaths(item) {
|
|
25512
|
+
return unique(item?.changes.map((change) => change.path) ?? []);
|
|
25513
|
+
}
|
|
25514
|
+
function permissionProfilePaths(permissions) {
|
|
25515
|
+
const fileSystem = permissions?.fileSystem;
|
|
25516
|
+
return unique([
|
|
25517
|
+
...fileSystem?.read ?? [],
|
|
25518
|
+
...fileSystem?.write ?? [],
|
|
25519
|
+
...(fileSystem?.entries ?? []).flatMap((entry) => entry.path.type === "path" ? [entry.path.path] : [])
|
|
25520
|
+
]);
|
|
25521
|
+
}
|
|
25522
|
+
function permissionProfileContent(permissions) {
|
|
25523
|
+
const lines = [];
|
|
25524
|
+
const networkEnabled = permissions.network?.enabled;
|
|
25525
|
+
if (networkEnabled !== null && networkEnabled !== void 0) {
|
|
25526
|
+
lines.push(networkEnabled ? "Enable network access" : "Disable network access");
|
|
25527
|
+
}
|
|
25528
|
+
for (const entry of permissions.fileSystem?.entries ?? []) {
|
|
25529
|
+
switch (entry.path.type) {
|
|
25530
|
+
case "glob_pattern":
|
|
25531
|
+
lines.push(`${entry.access} filesystem pattern ${entry.path.pattern}`);
|
|
25532
|
+
break;
|
|
25533
|
+
case "special":
|
|
25534
|
+
lines.push(`${entry.access} Codex filesystem scope ${JSON.stringify(entry.path.value)}`);
|
|
25535
|
+
break;
|
|
25536
|
+
case "path":
|
|
25537
|
+
break;
|
|
25538
|
+
}
|
|
25539
|
+
}
|
|
25540
|
+
return lines.length > 0 ? [textContent(lines.join("\n"))] : [];
|
|
25541
|
+
}
|
|
25542
|
+
function locationsField(paths) {
|
|
25543
|
+
return paths.length > 0 ? { locations: paths.map((path9) => ({ path: path9 })) } : {};
|
|
25544
|
+
}
|
|
25545
|
+
function textContent(text) {
|
|
25546
|
+
return { type: "content", content: { type: "text", text } };
|
|
25547
|
+
}
|
|
25548
|
+
function unique(values) {
|
|
25549
|
+
return [...new Set(values)];
|
|
25550
|
+
}
|
|
25551
|
+
|
|
25552
|
+
// src/permissions/CodexApprovalHandler.ts
|
|
25553
|
+
var CodexApprovalHandler = class {
|
|
25554
|
+
constructor(connection, permissionContext, cancellationSignal) {
|
|
25555
|
+
this.connection = connection;
|
|
25556
|
+
this.permissionContext = permissionContext;
|
|
25557
|
+
this.cancellationSignal = cancellationSignal;
|
|
25558
|
+
}
|
|
25559
|
+
connection;
|
|
25560
|
+
permissionContext;
|
|
25561
|
+
cancellationSignal;
|
|
25562
|
+
async handleCommandExecution(params) {
|
|
25563
|
+
const authoritativeParams = params;
|
|
25564
|
+
const decisions = commandDecisionOptions(authoritativeParams);
|
|
25565
|
+
if (!decisions) {
|
|
25566
|
+
logger.error("Cancelling command approval without a complete authoritative decision set", void 0);
|
|
25567
|
+
return { decision: "cancel" };
|
|
25568
|
+
}
|
|
25569
|
+
try {
|
|
25570
|
+
const response = await this.requestPermission({
|
|
25571
|
+
sessionId: params.threadId,
|
|
25572
|
+
toolCall: commandToolCall(authoritativeParams),
|
|
25573
|
+
options: decisions.map(({ option }) => option),
|
|
25574
|
+
_meta: requestPermissionMeta(
|
|
25575
|
+
params.networkApprovalContext ? CODEX_NETWORK_PERMISSION_TITLE : CODEX_COMMAND_PERMISSION_TITLE,
|
|
25576
|
+
params.reason
|
|
25577
|
+
)
|
|
25578
|
+
});
|
|
25579
|
+
return { decision: this.selectedDecision(response, decisions) ?? "cancel" };
|
|
25580
|
+
} catch (error51) {
|
|
25581
|
+
logger.error("Error requesting command execution permission", error51);
|
|
24818
25582
|
return { decision: "cancel" };
|
|
24819
25583
|
}
|
|
24820
|
-
const optionId = response.outcome.optionId;
|
|
24821
|
-
const decision = this.buildCommandOptions(params).find(({ option }) => option.optionId === optionId)?.decision;
|
|
24822
|
-
return { decision: decision ?? "decline" };
|
|
24823
25584
|
}
|
|
24824
|
-
|
|
24825
|
-
|
|
25585
|
+
async handleFileChange(params) {
|
|
25586
|
+
const decisions = fileChangeDecisionOptions();
|
|
25587
|
+
try {
|
|
25588
|
+
const response = await this.requestPermission({
|
|
25589
|
+
sessionId: params.threadId,
|
|
25590
|
+
toolCall: fileChangeToolCall(params, this.permissionContext),
|
|
25591
|
+
options: decisions.map(({ option }) => option),
|
|
25592
|
+
_meta: requestPermissionMeta(CODEX_FILE_CHANGE_PERMISSION_TITLE, params.reason)
|
|
25593
|
+
});
|
|
25594
|
+
return { decision: this.selectedDecision(response, decisions) ?? "cancel" };
|
|
25595
|
+
} catch (error51) {
|
|
25596
|
+
logger.error("Error requesting file change permission", error51);
|
|
24826
25597
|
return { decision: "cancel" };
|
|
24827
25598
|
}
|
|
24828
|
-
const optionId = response.outcome.optionId;
|
|
24829
|
-
const decision = this.buildFileChangeOptions(params).find(({ option }) => option.optionId === optionId)?.decision;
|
|
24830
|
-
return { decision: decision ?? "decline" };
|
|
24831
25599
|
}
|
|
24832
|
-
|
|
24833
|
-
|
|
25600
|
+
async handlePermissionsRequest(params) {
|
|
25601
|
+
try {
|
|
25602
|
+
const response = await this.requestPermission({
|
|
25603
|
+
sessionId: params.threadId,
|
|
25604
|
+
toolCall: additionalPermissionsToolCall(
|
|
25605
|
+
params.itemId,
|
|
25606
|
+
params.cwd,
|
|
25607
|
+
params.environmentId,
|
|
25608
|
+
params.permissions
|
|
25609
|
+
),
|
|
25610
|
+
options: permissionProfileOptions(),
|
|
25611
|
+
_meta: requestPermissionMeta(CODEX_ADDITIONAL_PERMISSIONS_TITLE, params.reason)
|
|
25612
|
+
});
|
|
25613
|
+
return this.permissionsResponse(params.permissions, response);
|
|
25614
|
+
} catch (error51) {
|
|
25615
|
+
logger.error("Error requesting permissions", error51);
|
|
24834
25616
|
return this.rejectPermissionsResponse();
|
|
24835
25617
|
}
|
|
25618
|
+
}
|
|
25619
|
+
requestPermission(request) {
|
|
25620
|
+
return this.connection.request(
|
|
25621
|
+
methods.client.session.requestPermission,
|
|
25622
|
+
request,
|
|
25623
|
+
this.cancellationSignal ? { cancellationSignal: this.cancellationSignal } : void 0
|
|
25624
|
+
);
|
|
25625
|
+
}
|
|
25626
|
+
selectedDecision(response, decisions) {
|
|
25627
|
+
if (response.outcome.outcome === "cancelled") return void 0;
|
|
25628
|
+
const optionId = response.outcome.optionId;
|
|
25629
|
+
return decisions.find(({ option }) => option.optionId === optionId)?.decision;
|
|
25630
|
+
}
|
|
25631
|
+
permissionsResponse(permissions, response) {
|
|
25632
|
+
if (response.outcome.outcome === "cancelled") return this.rejectPermissionsResponse();
|
|
24836
25633
|
switch (response.outcome.optionId) {
|
|
24837
|
-
case ApprovalOptionId.AllowPermissionsForSession:
|
|
24838
|
-
case ApprovalOptionId.AllowAlways:
|
|
24839
|
-
return {
|
|
24840
|
-
permissions: this.grantedPermissions(params.permissions),
|
|
24841
|
-
scope: "session",
|
|
24842
|
-
strictAutoReview: false
|
|
24843
|
-
};
|
|
24844
25634
|
case ApprovalOptionId.AllowPermissionsForTurn:
|
|
24845
|
-
|
|
24846
|
-
|
|
24847
|
-
|
|
24848
|
-
|
|
24849
|
-
|
|
24850
|
-
|
|
25635
|
+
return this.grantedPermissionsResponse(permissions, "turn", false);
|
|
25636
|
+
case ApprovalOptionId.AllowPermissionsForTurnWithStrictAutoReview:
|
|
25637
|
+
return this.grantedPermissionsResponse(permissions, "turn", true);
|
|
25638
|
+
case ApprovalOptionId.AllowPermissionsForSession:
|
|
25639
|
+
return this.grantedPermissionsResponse(permissions, "session", false);
|
|
25640
|
+
case ApprovalOptionId.RejectPermissions:
|
|
24851
25641
|
default:
|
|
24852
25642
|
return this.rejectPermissionsResponse();
|
|
24853
25643
|
}
|
|
24854
25644
|
}
|
|
24855
|
-
|
|
24856
|
-
|
|
24857
|
-
{
|
|
24858
|
-
option: permissionOption(ApprovalOptionId.AllowOnce, "Allow Once", "allow_once", { decision: "accept" }),
|
|
24859
|
-
decision: "accept"
|
|
24860
|
-
},
|
|
24861
|
-
{
|
|
24862
|
-
option: permissionOption(
|
|
24863
|
-
ApprovalOptionId.AllowAlways,
|
|
24864
|
-
params.networkApprovalContext ? "Allow Host for Session" : "Allow for Session",
|
|
24865
|
-
"allow_always",
|
|
24866
|
-
{ decision: "acceptForSession" },
|
|
24867
|
-
params.networkApprovalContext ? {
|
|
24868
|
-
version: 1,
|
|
24869
|
-
changes: [{
|
|
24870
|
-
type: "grant",
|
|
24871
|
-
operation: "grant",
|
|
24872
|
-
description: `Allow access to ${params.networkApprovalContext.host} for this session`,
|
|
24873
|
-
lifetime: { scope: "session" },
|
|
24874
|
-
targets: [{
|
|
24875
|
-
type: "network",
|
|
24876
|
-
matcher: {
|
|
24877
|
-
type: "host",
|
|
24878
|
-
host: params.networkApprovalContext.host,
|
|
24879
|
-
protocol: params.networkApprovalContext.protocol
|
|
24880
|
-
}
|
|
24881
|
-
}]
|
|
24882
|
-
}]
|
|
24883
|
-
} : void 0
|
|
24884
|
-
),
|
|
24885
|
-
decision: "acceptForSession"
|
|
24886
|
-
}
|
|
24887
|
-
];
|
|
24888
|
-
if (params.proposedExecpolicyAmendment && params.proposedExecpolicyAmendment.length > 0) {
|
|
24889
|
-
options.push({
|
|
24890
|
-
option: permissionOption(
|
|
24891
|
-
ApprovalOptionId.AcceptWithExecpolicyAmendment,
|
|
24892
|
-
this.execpolicyAmendmentLabel(params.proposedExecpolicyAmendment),
|
|
24893
|
-
"allow_always",
|
|
24894
|
-
{
|
|
24895
|
-
decision: "acceptWithExecpolicyAmendment",
|
|
24896
|
-
execpolicyAmendment: params.proposedExecpolicyAmendment
|
|
24897
|
-
},
|
|
24898
|
-
{
|
|
24899
|
-
version: 1,
|
|
24900
|
-
changes: [{
|
|
24901
|
-
type: "policy_rule",
|
|
24902
|
-
operation: "add",
|
|
24903
|
-
ruleBehavior: "allow",
|
|
24904
|
-
description: `Allow commands starting with ${params.proposedExecpolicyAmendment.join(" ")}`,
|
|
24905
|
-
targets: [{
|
|
24906
|
-
type: "command",
|
|
24907
|
-
matcher: {
|
|
24908
|
-
type: "argv_prefix",
|
|
24909
|
-
argv: params.proposedExecpolicyAmendment
|
|
24910
|
-
}
|
|
24911
|
-
}]
|
|
24912
|
-
}]
|
|
24913
|
-
}
|
|
24914
|
-
),
|
|
24915
|
-
decision: {
|
|
24916
|
-
acceptWithExecpolicyAmendment: {
|
|
24917
|
-
execpolicy_amendment: params.proposedExecpolicyAmendment
|
|
24918
|
-
}
|
|
24919
|
-
}
|
|
24920
|
-
});
|
|
24921
|
-
}
|
|
24922
|
-
params.proposedNetworkPolicyAmendments?.forEach((amendment, index) => {
|
|
24923
|
-
options.push({
|
|
24924
|
-
option: permissionOption(
|
|
24925
|
-
this.networkPolicyAmendmentOptionId(index),
|
|
24926
|
-
this.networkPolicyAmendmentLabel(amendment),
|
|
24927
|
-
amendment.action === "allow" ? "allow_always" : "reject_always",
|
|
24928
|
-
{
|
|
24929
|
-
decision: "applyNetworkPolicyAmendment",
|
|
24930
|
-
networkPolicyAmendment: amendment
|
|
24931
|
-
},
|
|
24932
|
-
{
|
|
24933
|
-
version: 1,
|
|
24934
|
-
changes: [{
|
|
24935
|
-
type: "policy_rule",
|
|
24936
|
-
operation: "add",
|
|
24937
|
-
ruleBehavior: amendment.action,
|
|
24938
|
-
description: amendment.action === "allow" ? `Allow access to ${amendment.host}` : `Block access to ${amendment.host}`,
|
|
24939
|
-
targets: [{
|
|
24940
|
-
type: "network",
|
|
24941
|
-
matcher: {
|
|
24942
|
-
type: "host",
|
|
24943
|
-
host: amendment.host
|
|
24944
|
-
}
|
|
24945
|
-
}]
|
|
24946
|
-
}]
|
|
24947
|
-
}
|
|
24948
|
-
),
|
|
24949
|
-
decision: {
|
|
24950
|
-
applyNetworkPolicyAmendment: {
|
|
24951
|
-
network_policy_amendment: amendment
|
|
24952
|
-
}
|
|
24953
|
-
}
|
|
24954
|
-
});
|
|
24955
|
-
});
|
|
24956
|
-
options.push({
|
|
24957
|
-
option: permissionOption(ApprovalOptionId.RejectOnce, "Reject", "reject_once", { decision: "decline" }),
|
|
24958
|
-
decision: "decline"
|
|
24959
|
-
});
|
|
24960
|
-
return options;
|
|
24961
|
-
}
|
|
24962
|
-
buildFileChangeOptions(params) {
|
|
24963
|
-
return [
|
|
24964
|
-
{
|
|
24965
|
-
option: permissionOption(ApprovalOptionId.AllowOnce, "Allow Once", "allow_once", { decision: "accept" }),
|
|
24966
|
-
decision: "accept"
|
|
24967
|
-
},
|
|
24968
|
-
{
|
|
24969
|
-
option: permissionOption(
|
|
24970
|
-
ApprovalOptionId.AllowAlways,
|
|
24971
|
-
params.grantRoot ? "Allow Root for Session" : "Allow for Session",
|
|
24972
|
-
"allow_always",
|
|
24973
|
-
{ decision: "acceptForSession", grantRoot: params.grantRoot ?? null },
|
|
24974
|
-
params.grantRoot ? {
|
|
24975
|
-
version: 1,
|
|
24976
|
-
changes: [{
|
|
24977
|
-
type: "grant",
|
|
24978
|
-
operation: "grant",
|
|
24979
|
-
description: `Allow writes under ${params.grantRoot} for this session`,
|
|
24980
|
-
lifetime: { scope: "session" },
|
|
24981
|
-
targets: [{
|
|
24982
|
-
type: "filesystem",
|
|
24983
|
-
access: ["write"],
|
|
24984
|
-
matcher: { type: "directory", path: params.grantRoot }
|
|
24985
|
-
}]
|
|
24986
|
-
}]
|
|
24987
|
-
} : void 0
|
|
24988
|
-
),
|
|
24989
|
-
decision: "acceptForSession"
|
|
24990
|
-
},
|
|
24991
|
-
{
|
|
24992
|
-
option: permissionOption(ApprovalOptionId.RejectOnce, "Reject", "reject_once", { decision: "decline" }),
|
|
24993
|
-
decision: "decline"
|
|
24994
|
-
}
|
|
24995
|
-
];
|
|
25645
|
+
grantedPermissionsResponse(permissions, scope, strictAutoReview) {
|
|
25646
|
+
return { permissions: this.grantedPermissions(permissions), scope, strictAutoReview };
|
|
24996
25647
|
}
|
|
24997
25648
|
rejectPermissionsResponse() {
|
|
24998
|
-
return {
|
|
24999
|
-
permissions: {},
|
|
25000
|
-
scope: "turn",
|
|
25001
|
-
strictAutoReview: true
|
|
25002
|
-
};
|
|
25649
|
+
return { permissions: {}, scope: "turn", strictAutoReview: false };
|
|
25003
25650
|
}
|
|
25004
25651
|
grantedPermissions(permissions) {
|
|
25005
25652
|
return {
|
|
@@ -25007,117 +25654,131 @@ var CodexApprovalHandler = class {
|
|
|
25007
25654
|
...permissions.fileSystem ? { fileSystem: permissions.fileSystem } : {}
|
|
25008
25655
|
};
|
|
25009
25656
|
}
|
|
25010
|
-
|
|
25011
|
-
|
|
25012
|
-
|
|
25013
|
-
|
|
25014
|
-
|
|
25015
|
-
|
|
25016
|
-
changes.push({
|
|
25017
|
-
type: allowed ? "grant" : "policy_rule",
|
|
25018
|
-
operation: allowed ? "grant" : "add",
|
|
25019
|
-
...allowed ? {} : { ruleBehavior: "deny" },
|
|
25020
|
-
description: `${allowed ? "Allow" : "Deny"} network access${suffix}`,
|
|
25021
|
-
lifetime,
|
|
25022
|
-
targets: [{ type: "network", matcher: { type: "any" } }]
|
|
25023
|
-
});
|
|
25024
|
-
}
|
|
25025
|
-
const fileSystem = permissions.fileSystem;
|
|
25026
|
-
for (const path8 of fileSystem?.read ?? []) {
|
|
25027
|
-
changes.push(this.fileSystemGrantChange(path8, "read", lifetime, suffix));
|
|
25028
|
-
}
|
|
25029
|
-
for (const path8 of fileSystem?.write ?? []) {
|
|
25030
|
-
changes.push(this.fileSystemGrantChange(path8, "write", lifetime, suffix));
|
|
25031
|
-
}
|
|
25032
|
-
for (const entry of fileSystem?.entries ?? []) {
|
|
25033
|
-
const matcher = (() => {
|
|
25034
|
-
switch (entry.path.type) {
|
|
25035
|
-
case "path":
|
|
25036
|
-
return { type: "exact_path", path: entry.path.path };
|
|
25037
|
-
case "glob_pattern":
|
|
25038
|
-
return { type: "glob", pattern: entry.path.pattern };
|
|
25039
|
-
case "special":
|
|
25040
|
-
return { type: "special", provider: "codex", value: entry.path.value };
|
|
25041
|
-
}
|
|
25042
|
-
})();
|
|
25043
|
-
const pathDescription = entry.path.type === "path" ? entry.path.path : entry.path.type === "glob_pattern" ? entry.path.pattern : JSON.stringify(entry.path.value);
|
|
25044
|
-
changes.push({
|
|
25045
|
-
type: entry.access === "deny" ? "policy_rule" : "grant",
|
|
25046
|
-
operation: entry.access === "deny" ? "add" : "grant",
|
|
25047
|
-
...entry.access === "deny" ? { ruleBehavior: "deny" } : {},
|
|
25048
|
-
description: entry.access === "deny" ? `Deny filesystem access to ${pathDescription}${suffix}` : `Allow ${entry.access} access to ${pathDescription}${suffix}`,
|
|
25049
|
-
lifetime,
|
|
25050
|
-
targets: [{
|
|
25051
|
-
type: "filesystem",
|
|
25052
|
-
...entry.access === "deny" ? {} : { access: [entry.access] },
|
|
25053
|
-
matcher
|
|
25054
|
-
}]
|
|
25055
|
-
});
|
|
25056
|
-
}
|
|
25057
|
-
return changes.length > 0 ? { version: 1, changes } : void 0;
|
|
25657
|
+
};
|
|
25658
|
+
|
|
25659
|
+
// src/permissions/lifecycle.ts
|
|
25660
|
+
var PermissionLifecycleContext = class {
|
|
25661
|
+
constructor(session) {
|
|
25662
|
+
this.session = session;
|
|
25058
25663
|
}
|
|
25059
|
-
|
|
25060
|
-
|
|
25061
|
-
|
|
25062
|
-
|
|
25063
|
-
|
|
25064
|
-
|
|
25065
|
-
|
|
25066
|
-
|
|
25067
|
-
access: [access],
|
|
25068
|
-
matcher: { type: "exact_path", path: path8 }
|
|
25069
|
-
}]
|
|
25070
|
-
};
|
|
25664
|
+
session;
|
|
25665
|
+
permissionRequestSequence = 0;
|
|
25666
|
+
beginPrompt() {
|
|
25667
|
+
return new PermissionPromptContext((serverName) => this.nextStandaloneMcpToolCallId(serverName));
|
|
25668
|
+
}
|
|
25669
|
+
nextStandaloneMcpToolCallId(serverName) {
|
|
25670
|
+
this.permissionRequestSequence += 1;
|
|
25671
|
+
return ["elicitation", this.session.sessionId, serverName, this.permissionRequestSequence].join(":");
|
|
25071
25672
|
}
|
|
25072
|
-
|
|
25073
|
-
|
|
25673
|
+
};
|
|
25674
|
+
var PermissionPromptContext = class {
|
|
25675
|
+
constructor(nextStandaloneId) {
|
|
25676
|
+
this.nextStandaloneId = nextStandaloneId;
|
|
25074
25677
|
}
|
|
25075
|
-
|
|
25076
|
-
|
|
25077
|
-
|
|
25078
|
-
|
|
25678
|
+
nextStandaloneId;
|
|
25679
|
+
fileChanges = /* @__PURE__ */ new Map();
|
|
25680
|
+
pendingMcpApprovals = /* @__PURE__ */ new Map();
|
|
25681
|
+
handleNotification(notification) {
|
|
25682
|
+
switch (notification.method) {
|
|
25683
|
+
case "item/started":
|
|
25684
|
+
this.handleItemStarted(notification.params.threadId, notification.params.item);
|
|
25685
|
+
return;
|
|
25686
|
+
case "item/completed":
|
|
25687
|
+
this.handleItemCompleted(notification.params.threadId, notification.params.item);
|
|
25688
|
+
return;
|
|
25689
|
+
case "turn/completed":
|
|
25690
|
+
this.clearTransientState(notification.params.threadId);
|
|
25691
|
+
return;
|
|
25692
|
+
case "serverRequest/resolved":
|
|
25693
|
+
this.pendingMcpApprovals.delete(notification.params.threadId);
|
|
25694
|
+
return;
|
|
25695
|
+
default:
|
|
25696
|
+
return;
|
|
25079
25697
|
}
|
|
25080
|
-
return `Allow Commands Starting With \`${commandPrefix}\``;
|
|
25081
25698
|
}
|
|
25082
|
-
|
|
25083
|
-
return
|
|
25699
|
+
fileChange(threadId, itemId) {
|
|
25700
|
+
return this.fileChanges.get(threadId)?.get(itemId);
|
|
25084
25701
|
}
|
|
25085
|
-
|
|
25086
|
-
const
|
|
25087
|
-
if (
|
|
25088
|
-
|
|
25089
|
-
|
|
25090
|
-
|
|
25091
|
-
|
|
25092
|
-
|
|
25093
|
-
|
|
25094
|
-
|
|
25702
|
+
popPendingMcpApproval(threadId, serverName) {
|
|
25703
|
+
const byServer = this.pendingMcpApprovals.get(threadId);
|
|
25704
|
+
if (!byServer) return void 0;
|
|
25705
|
+
const pending = byServer.get(serverName);
|
|
25706
|
+
if (pending?.length !== 1) return void 0;
|
|
25707
|
+
const callId = pending[0];
|
|
25708
|
+
byServer.delete(serverName);
|
|
25709
|
+
if (byServer.size === 0) this.pendingMcpApprovals.delete(threadId);
|
|
25710
|
+
return callId;
|
|
25711
|
+
}
|
|
25712
|
+
nextStandaloneMcpToolCallId(serverName) {
|
|
25713
|
+
return this.nextStandaloneId(serverName);
|
|
25714
|
+
}
|
|
25715
|
+
handleItemStarted(threadId, item) {
|
|
25716
|
+
if (item.type === "fileChange") {
|
|
25717
|
+
const byItem = this.fileChanges.get(threadId) ?? /* @__PURE__ */ new Map();
|
|
25718
|
+
byItem.set(item.id, item);
|
|
25719
|
+
this.fileChanges.set(threadId, byItem);
|
|
25720
|
+
return;
|
|
25095
25721
|
}
|
|
25096
|
-
if (
|
|
25097
|
-
|
|
25722
|
+
if (item.type !== "mcpToolCall") return;
|
|
25723
|
+
const byServer = this.pendingMcpApprovals.get(threadId) ?? /* @__PURE__ */ new Map();
|
|
25724
|
+
const pending = byServer.get(item.server);
|
|
25725
|
+
if (pending) pending.push(item.id);
|
|
25726
|
+
else byServer.set(item.server, [item.id]);
|
|
25727
|
+
this.pendingMcpApprovals.set(threadId, byServer);
|
|
25728
|
+
}
|
|
25729
|
+
handleItemCompleted(threadId, item) {
|
|
25730
|
+
if (item.type === "fileChange") {
|
|
25731
|
+
const byItem = this.fileChanges.get(threadId);
|
|
25732
|
+
byItem?.delete(item.id);
|
|
25733
|
+
if (byItem?.size === 0) this.fileChanges.delete(threadId);
|
|
25734
|
+
return;
|
|
25098
25735
|
}
|
|
25099
|
-
|
|
25736
|
+
if (item.type !== "mcpToolCall") return;
|
|
25737
|
+
const byServer = this.pendingMcpApprovals.get(threadId);
|
|
25738
|
+
if (!byServer) return;
|
|
25739
|
+
const pending = byServer.get(item.server);
|
|
25740
|
+
if (!pending) return;
|
|
25741
|
+
const index = pending.indexOf(item.id);
|
|
25742
|
+
if (index >= 0) pending.splice(index, 1);
|
|
25743
|
+
if (pending.length === 0) byServer.delete(item.server);
|
|
25744
|
+
if (byServer.size === 0) this.pendingMcpApprovals.delete(threadId);
|
|
25100
25745
|
}
|
|
25101
|
-
|
|
25102
|
-
|
|
25103
|
-
|
|
25104
|
-
return [{
|
|
25105
|
-
type: "content",
|
|
25106
|
-
content: {
|
|
25107
|
-
type: "text",
|
|
25108
|
-
text
|
|
25109
|
-
}
|
|
25110
|
-
}];
|
|
25746
|
+
clearTransientState(threadId) {
|
|
25747
|
+
this.fileChanges.delete(threadId);
|
|
25748
|
+
this.pendingMcpApprovals.delete(threadId);
|
|
25111
25749
|
}
|
|
25112
25750
|
};
|
|
25113
25751
|
|
|
25114
|
-
// src/
|
|
25115
|
-
var
|
|
25116
|
-
|
|
25117
|
-
|
|
25118
|
-
|
|
25119
|
-
|
|
25120
|
-
|
|
25752
|
+
// src/permissions/plan-review.ts
|
|
25753
|
+
var IMPLEMENT_PLAN_OPTION_ID = "implement_plan";
|
|
25754
|
+
var REVISE_PLAN_OPTION_ID = "revise_plan";
|
|
25755
|
+
function planImplementationPermissionRequest(sessionId, plan) {
|
|
25756
|
+
return {
|
|
25757
|
+
sessionId,
|
|
25758
|
+
toolCall: {
|
|
25759
|
+
toolCallId: planImplementationToolCallId(plan),
|
|
25760
|
+
title: "Implement this plan?",
|
|
25761
|
+
kind: "switch_mode",
|
|
25762
|
+
status: "pending",
|
|
25763
|
+
rawInput: { plan: plan.text }
|
|
25764
|
+
},
|
|
25765
|
+
options: [
|
|
25766
|
+
{ optionId: IMPLEMENT_PLAN_OPTION_ID, name: "Yes, implement this plan", kind: "allow_once" },
|
|
25767
|
+
{
|
|
25768
|
+
optionId: REVISE_PLAN_OPTION_ID,
|
|
25769
|
+
name: "No, and tell Codex what to do differently",
|
|
25770
|
+
kind: "reject_once"
|
|
25771
|
+
}
|
|
25772
|
+
],
|
|
25773
|
+
_meta: { codex: { kind: "plan_review", planItemId: plan.itemId } }
|
|
25774
|
+
};
|
|
25775
|
+
}
|
|
25776
|
+
function planImplementationApproved(response) {
|
|
25777
|
+
return response.outcome.outcome === "selected" && response.outcome.optionId === IMPLEMENT_PLAN_OPTION_ID;
|
|
25778
|
+
}
|
|
25779
|
+
function planImplementationToolCallId(plan) {
|
|
25780
|
+
return `plan-review:${plan.itemId}`;
|
|
25781
|
+
}
|
|
25121
25782
|
|
|
25122
25783
|
// src/ElicitationCapabilities.ts
|
|
25123
25784
|
function clientSupportsFormElicitation(clientCapabilities) {
|
|
@@ -25127,57 +25788,146 @@ function clientSupportsUrlElicitation(clientCapabilities) {
|
|
|
25127
25788
|
return clientCapabilities?.elicitation?.url != null;
|
|
25128
25789
|
}
|
|
25129
25790
|
|
|
25130
|
-
// src/
|
|
25131
|
-
var ELICITATION_OPTIONS = [
|
|
25132
|
-
{ optionId: "accept", name: "Accept", kind: "allow_once" },
|
|
25133
|
-
{ optionId: "decline", name: "Decline", kind: "reject_once" }
|
|
25134
|
-
];
|
|
25135
|
-
var USER_INPUT_OTHER_FIELD_SUFFIX = "__other";
|
|
25791
|
+
// src/permissions/mcp.ts
|
|
25136
25792
|
function parsePersistOptions(meta3) {
|
|
25137
25793
|
const result = /* @__PURE__ */ new Set();
|
|
25138
|
-
if (!meta3
|
|
25794
|
+
if (!isRecord2(meta3)) return result;
|
|
25139
25795
|
const persist = meta3["persist"];
|
|
25140
|
-
if (persist === "session")
|
|
25141
|
-
|
|
25142
|
-
|
|
25143
|
-
result.add("always");
|
|
25144
|
-
} else if (Array.isArray(persist)) {
|
|
25796
|
+
if (persist === "session") result.add("session");
|
|
25797
|
+
else if (persist === "always") result.add("always");
|
|
25798
|
+
else if (Array.isArray(persist)) {
|
|
25145
25799
|
if (persist.includes("session")) result.add("session");
|
|
25146
25800
|
if (persist.includes("always")) result.add("always");
|
|
25147
25801
|
}
|
|
25148
25802
|
return result;
|
|
25149
25803
|
}
|
|
25150
25804
|
function isMcpToolCallApproval(meta3) {
|
|
25151
|
-
return meta3
|
|
25152
|
-
}
|
|
25153
|
-
function
|
|
25154
|
-
|
|
25155
|
-
|
|
25156
|
-
|
|
25157
|
-
|
|
25158
|
-
|
|
25805
|
+
return isRecord2(meta3) && meta3["codex_approval_kind"] === "mcp_tool_call";
|
|
25806
|
+
}
|
|
25807
|
+
function buildMcpPermissionOptions(isToolApproval, persistOptions) {
|
|
25808
|
+
const options = [permissionOption2(
|
|
25809
|
+
isToolApproval ? McpApprovalOptionId.AllowOnce : "accept",
|
|
25810
|
+
"Allow",
|
|
25811
|
+
"allow_once",
|
|
25812
|
+
isToolApproval ? "Run the tool and continue." : "Allow this request and continue."
|
|
25813
|
+
)];
|
|
25814
|
+
if (persistOptions.has("session")) {
|
|
25815
|
+
options.push(permissionOption2(
|
|
25816
|
+
McpApprovalOptionId.AllowSession,
|
|
25817
|
+
"Allow for this session",
|
|
25818
|
+
"allow_always",
|
|
25819
|
+
isToolApproval ? "Run the tool and remember this choice for this session." : "Allow this request and remember this choice for this session."
|
|
25820
|
+
));
|
|
25159
25821
|
}
|
|
25160
|
-
if (
|
|
25161
|
-
|
|
25822
|
+
if (persistOptions.has("always")) {
|
|
25823
|
+
options.push(permissionOption2(
|
|
25824
|
+
McpApprovalOptionId.AllowAlways,
|
|
25825
|
+
"Always allow",
|
|
25826
|
+
"allow_always",
|
|
25827
|
+
isToolApproval ? "Run the tool and remember this choice for future tool calls." : "Allow this request and remember this choice for future requests."
|
|
25828
|
+
));
|
|
25162
25829
|
}
|
|
25163
|
-
if (
|
|
25164
|
-
|
|
25830
|
+
if (isToolApproval) {
|
|
25831
|
+
options.push(permissionOption2(
|
|
25832
|
+
McpApprovalOptionId.Cancel,
|
|
25833
|
+
"Cancel",
|
|
25834
|
+
"reject_once",
|
|
25835
|
+
"Cancel this tool call"
|
|
25836
|
+
));
|
|
25837
|
+
} else {
|
|
25838
|
+
options.push(
|
|
25839
|
+
permissionOption2(
|
|
25840
|
+
McpApprovalOptionId.Decline,
|
|
25841
|
+
"Deny",
|
|
25842
|
+
"reject_once",
|
|
25843
|
+
"Decline this request and continue."
|
|
25844
|
+
),
|
|
25845
|
+
permissionOption2(McpApprovalOptionId.Cancel, "Cancel", "reject_once", "Cancel this request")
|
|
25846
|
+
);
|
|
25165
25847
|
}
|
|
25166
|
-
|
|
25167
|
-
|
|
25848
|
+
return options;
|
|
25849
|
+
}
|
|
25850
|
+
function buildMcpPermissionRequest(sessionId, params, context, nextStandaloneToolCallId) {
|
|
25851
|
+
const messageContent = {
|
|
25852
|
+
type: "content",
|
|
25853
|
+
content: { type: "text", text: params.message }
|
|
25854
|
+
};
|
|
25855
|
+
const options = buildMcpPermissionOptions(context.isToolApproval, context.persistOptions);
|
|
25856
|
+
if (params.mode === "form" || params.mode === "openai/form") {
|
|
25857
|
+
if (context.correlatedCallId !== void 0) {
|
|
25858
|
+
return {
|
|
25859
|
+
request: {
|
|
25860
|
+
sessionId,
|
|
25861
|
+
toolCall: {
|
|
25862
|
+
toolCallId: context.correlatedCallId,
|
|
25863
|
+
kind: "execute",
|
|
25864
|
+
status: "pending"
|
|
25865
|
+
},
|
|
25866
|
+
_meta: { is_mcp_tool_approval: true },
|
|
25867
|
+
options
|
|
25868
|
+
},
|
|
25869
|
+
correlatedCallId: context.correlatedCallId
|
|
25870
|
+
};
|
|
25871
|
+
}
|
|
25872
|
+
return {
|
|
25873
|
+
request: {
|
|
25874
|
+
sessionId,
|
|
25875
|
+
toolCall: {
|
|
25876
|
+
toolCallId: nextStandaloneToolCallId(),
|
|
25877
|
+
kind: context.isToolApproval ? "execute" : "other",
|
|
25878
|
+
status: "pending",
|
|
25879
|
+
content: [messageContent],
|
|
25880
|
+
rawInput: { serverName: params.serverName, schema: params.requestedSchema }
|
|
25881
|
+
},
|
|
25882
|
+
...context.isToolApproval ? { _meta: { is_mcp_tool_approval: true } } : {},
|
|
25883
|
+
options
|
|
25884
|
+
},
|
|
25885
|
+
correlatedCallId: void 0
|
|
25886
|
+
};
|
|
25168
25887
|
}
|
|
25169
|
-
|
|
25170
|
-
|
|
25171
|
-
|
|
25172
|
-
|
|
25888
|
+
return {
|
|
25889
|
+
request: {
|
|
25890
|
+
sessionId,
|
|
25891
|
+
toolCall: {
|
|
25892
|
+
toolCallId: `elicitation-${params.elicitationId}`,
|
|
25893
|
+
kind: "fetch",
|
|
25894
|
+
status: "pending",
|
|
25895
|
+
content: [messageContent],
|
|
25896
|
+
rawInput: { serverName: params.serverName, url: params.url }
|
|
25897
|
+
},
|
|
25898
|
+
options
|
|
25899
|
+
},
|
|
25900
|
+
correlatedCallId: void 0
|
|
25901
|
+
};
|
|
25902
|
+
}
|
|
25903
|
+
function convertMcpPermissionResponse(response, isToolApproval, persistOptions) {
|
|
25904
|
+
if (response.outcome.outcome === "cancelled") return cancelledResponse();
|
|
25905
|
+
switch (response.outcome.optionId) {
|
|
25906
|
+
case McpApprovalOptionId.AllowSession:
|
|
25907
|
+
return persistOptions.has("session") ? { action: "accept", content: null, _meta: { persist: "session" } } : cancelledResponse();
|
|
25908
|
+
case McpApprovalOptionId.AllowAlways:
|
|
25909
|
+
return persistOptions.has("always") ? { action: "accept", content: null, _meta: { persist: "always" } } : cancelledResponse();
|
|
25910
|
+
case McpApprovalOptionId.AllowOnce:
|
|
25911
|
+
return isToolApproval ? { action: "accept", content: null, _meta: null } : cancelledResponse();
|
|
25912
|
+
case "accept":
|
|
25913
|
+
return !isToolApproval ? { action: "accept", content: null, _meta: null } : cancelledResponse();
|
|
25914
|
+
case McpApprovalOptionId.Decline:
|
|
25915
|
+
return !isToolApproval ? { action: "decline", content: null, _meta: null } : cancelledResponse();
|
|
25916
|
+
case McpApprovalOptionId.Cancel:
|
|
25917
|
+
default:
|
|
25918
|
+
return cancelledResponse();
|
|
25173
25919
|
}
|
|
25174
|
-
return String(value);
|
|
25175
25920
|
}
|
|
25176
|
-
function
|
|
25177
|
-
|
|
25178
|
-
|
|
25179
|
-
|
|
25921
|
+
function permissionOption2(optionId, name, kind, description) {
|
|
25922
|
+
const meta3 = optionPermissionMeta(description);
|
|
25923
|
+
return { optionId, name, kind, ...meta3 ? { _meta: meta3 } : {} };
|
|
25924
|
+
}
|
|
25925
|
+
function cancelledResponse() {
|
|
25926
|
+
return { action: "cancel", content: null, _meta: null };
|
|
25180
25927
|
}
|
|
25928
|
+
|
|
25929
|
+
// src/CodexElicitationHandler.ts
|
|
25930
|
+
var USER_INPUT_OTHER_FIELD_SUFFIX = "__other";
|
|
25181
25931
|
function normalizeElicitationSchema(value) {
|
|
25182
25932
|
const normalized = normalizeElicitationSchemaValue(value);
|
|
25183
25933
|
if (!isRecord2(normalized)) {
|
|
@@ -25213,40 +25963,6 @@ function normalizeElicitationSchemaValue(value) {
|
|
|
25213
25963
|
}
|
|
25214
25964
|
return result;
|
|
25215
25965
|
}
|
|
25216
|
-
function metaRecord(meta3) {
|
|
25217
|
-
return isRecord2(meta3) ? meta3 : null;
|
|
25218
|
-
}
|
|
25219
|
-
function persistChoiceOption(value) {
|
|
25220
|
-
switch (value) {
|
|
25221
|
-
case "once":
|
|
25222
|
-
return { const: "once", title: "Allow once" };
|
|
25223
|
-
case "session":
|
|
25224
|
-
return { const: "session", title: "Allow for this session" };
|
|
25225
|
-
case "always":
|
|
25226
|
-
return { const: "always", title: "Allow and don't ask again" };
|
|
25227
|
-
}
|
|
25228
|
-
}
|
|
25229
|
-
function addPersistChoiceToSchema(schema, persistOptions) {
|
|
25230
|
-
if (persistOptions.size === 0) {
|
|
25231
|
-
return schema;
|
|
25232
|
-
}
|
|
25233
|
-
const choices = ["once"];
|
|
25234
|
-
if (persistOptions.has("session")) choices.push("session");
|
|
25235
|
-
if (persistOptions.has("always")) choices.push("always");
|
|
25236
|
-
return {
|
|
25237
|
-
...schema,
|
|
25238
|
-
properties: {
|
|
25239
|
-
...schema.properties,
|
|
25240
|
-
persist: {
|
|
25241
|
-
type: "string",
|
|
25242
|
-
title: "Approval scope",
|
|
25243
|
-
oneOf: choices.map(persistChoiceOption),
|
|
25244
|
-
default: "once"
|
|
25245
|
-
}
|
|
25246
|
-
},
|
|
25247
|
-
required: Array.from(/* @__PURE__ */ new Set([...schema.required ?? [], "persist"]))
|
|
25248
|
-
};
|
|
25249
|
-
}
|
|
25250
25966
|
function contentRecord(content) {
|
|
25251
25967
|
return isRecord2(content) ? content : {};
|
|
25252
25968
|
}
|
|
@@ -25258,7 +25974,7 @@ function jsonObjectOrNull(content) {
|
|
|
25258
25974
|
return Object.fromEntries(entries.map(([key, value]) => [key, normalizeJsonValue(value)]));
|
|
25259
25975
|
}
|
|
25260
25976
|
function elicitationResponseMeta(response, context, persist = void 0) {
|
|
25261
|
-
const responseMeta =
|
|
25977
|
+
const responseMeta = recordOrNull(response._meta);
|
|
25262
25978
|
const meta3 = responseMeta ? normalizeJsonObject(responseMeta) : {};
|
|
25263
25979
|
if (context.isToolApproval) {
|
|
25264
25980
|
delete meta3["persist"];
|
|
@@ -25289,22 +26005,9 @@ function userInputResponseValue(content, fieldId) {
|
|
|
25289
26005
|
}
|
|
25290
26006
|
return value;
|
|
25291
26007
|
}
|
|
25292
|
-
function buildToolApprovalOptions(persistOptions) {
|
|
25293
|
-
const options = [
|
|
25294
|
-
{ optionId: McpApprovalOptionId.AllowOnce, name: "Allow", kind: "allow_once" }
|
|
25295
|
-
];
|
|
25296
|
-
if (persistOptions.has("session")) {
|
|
25297
|
-
options.push({ optionId: McpApprovalOptionId.AllowSession, name: "Allow for This Session", kind: "allow_always" });
|
|
25298
|
-
}
|
|
25299
|
-
if (persistOptions.has("always")) {
|
|
25300
|
-
options.push({ optionId: McpApprovalOptionId.AllowAlways, name: "Allow and Don't Ask Again", kind: "allow_always" });
|
|
25301
|
-
}
|
|
25302
|
-
options.push({ optionId: McpApprovalOptionId.Decline, name: "Decline", kind: "reject_once" });
|
|
25303
|
-
return options;
|
|
25304
|
-
}
|
|
25305
26008
|
var CodexElicitationHandler = class {
|
|
25306
26009
|
connection;
|
|
25307
|
-
|
|
26010
|
+
permissionContext;
|
|
25308
26011
|
clientCapabilities;
|
|
25309
26012
|
cancellationSignal;
|
|
25310
26013
|
// In Rust, the MCP elicitation handler receives ElicitationRequestEvent directly from the MCP
|
|
@@ -25316,32 +26019,21 @@ var CodexElicitationHandler = class {
|
|
|
25316
26019
|
// reaches the client.
|
|
25317
26020
|
//
|
|
25318
26021
|
// Workaround: before requesting approval, Codex emits an item/started notification with an
|
|
25319
|
-
// mcpToolCall item carrying the call id and server name.
|
|
25320
|
-
//
|
|
26022
|
+
// mcpToolCall item carrying the call id and server name. The shared permission lifecycle stores
|
|
26023
|
+
// (threadId, serverName) → callId so this request can correlate to the rendered tool call item.
|
|
25321
26024
|
//
|
|
25322
|
-
// Multiple calls are safe because Codex requests approval synchronously — it blocks on one tool
|
|
25323
|
-
// call's elicitation before starting the next, so there is at most one pending approval per
|
|
25324
|
-
// (threadId, serverName).
|
|
25325
|
-
pendingMcpApprovals = /* @__PURE__ */ new Map();
|
|
25326
26025
|
// The app-server handler exposes URL elicitationId, while serverRequest/resolved only exposes
|
|
25327
26026
|
// threadId here, so accepted URL elicitations are completed at thread scope.
|
|
25328
26027
|
pendingUrlElicitations = /* @__PURE__ */ new Map();
|
|
25329
|
-
constructor(connection,
|
|
26028
|
+
constructor(connection, permissionContext, clientCapabilities = null, cancellationSignal) {
|
|
25330
26029
|
this.connection = connection;
|
|
25331
|
-
this.
|
|
26030
|
+
this.permissionContext = permissionContext;
|
|
25332
26031
|
this.clientCapabilities = clientCapabilities;
|
|
25333
26032
|
this.cancellationSignal = cancellationSignal;
|
|
25334
26033
|
}
|
|
25335
26034
|
async handleNotification(notification) {
|
|
25336
26035
|
switch (notification.method) {
|
|
25337
|
-
case "item/started":
|
|
25338
|
-
this.handleItemStarted(notification.params);
|
|
25339
|
-
return;
|
|
25340
|
-
case "item/completed":
|
|
25341
|
-
this.handleItemCompleted(notification.params);
|
|
25342
|
-
return;
|
|
25343
26036
|
case "serverRequest/resolved":
|
|
25344
|
-
this.clearThread(notification.params.threadId);
|
|
25345
26037
|
await this.completeUrlElicitations(notification.params.threadId);
|
|
25346
26038
|
return;
|
|
25347
26039
|
default:
|
|
@@ -25357,29 +26049,39 @@ var CodexElicitationHandler = class {
|
|
|
25357
26049
|
this.buildElicitationRequest(params, context),
|
|
25358
26050
|
this.requestOptions()
|
|
25359
26051
|
);
|
|
25360
|
-
const
|
|
25361
|
-
if (params.mode === "url" &&
|
|
26052
|
+
const result2 = this.convertElicitationResponse(response2, context);
|
|
26053
|
+
if (params.mode === "url" && result2.action === "accept") {
|
|
25362
26054
|
this.trackUrlElicitation(params.threadId, params.elicitationId);
|
|
25363
26055
|
}
|
|
25364
|
-
await this.publishAcceptedMcpToolApproval(context,
|
|
25365
|
-
return
|
|
26056
|
+
await this.publishAcceptedMcpToolApproval(params.threadId, context, result2.action === "accept");
|
|
26057
|
+
return result2;
|
|
25366
26058
|
}
|
|
25367
|
-
|
|
26059
|
+
if (!this.canUsePermissionFallback(params)) {
|
|
26060
|
+
return { action: "cancel", content: null, _meta: null };
|
|
26061
|
+
}
|
|
26062
|
+
const { request, correlatedCallId } = buildMcpPermissionRequest(
|
|
26063
|
+
params.threadId,
|
|
26064
|
+
params,
|
|
26065
|
+
context,
|
|
26066
|
+
() => this.permissionContext.nextStandaloneMcpToolCallId(params.serverName)
|
|
26067
|
+
);
|
|
25368
26068
|
const response = await this.connection.request(
|
|
25369
26069
|
methods.client.session.requestPermission,
|
|
25370
26070
|
request,
|
|
25371
26071
|
this.requestOptions()
|
|
25372
26072
|
);
|
|
25373
|
-
|
|
25374
|
-
|
|
25375
|
-
|
|
25376
|
-
|
|
25377
|
-
|
|
25378
|
-
|
|
25379
|
-
|
|
25380
|
-
|
|
26073
|
+
const result = convertMcpPermissionResponse(
|
|
26074
|
+
response,
|
|
26075
|
+
context.isToolApproval,
|
|
26076
|
+
context.persistOptions
|
|
26077
|
+
);
|
|
26078
|
+
if (correlatedCallId !== void 0 && result.action === "accept") {
|
|
26079
|
+
await this.connection.notify(methods.client.session.update, {
|
|
26080
|
+
sessionId: params.threadId,
|
|
26081
|
+
update: { sessionUpdate: "tool_call_update", toolCallId: correlatedCallId, status: "in_progress" }
|
|
26082
|
+
});
|
|
25381
26083
|
}
|
|
25382
|
-
return
|
|
26084
|
+
return result;
|
|
25383
26085
|
} catch (error51) {
|
|
25384
26086
|
logger.error("Error handling MCP elicitation request", error51);
|
|
25385
26087
|
return { action: "cancel", content: null, _meta: null };
|
|
@@ -25449,12 +26151,17 @@ var CodexElicitationHandler = class {
|
|
|
25449
26151
|
}
|
|
25450
26152
|
}
|
|
25451
26153
|
createMcpElicitationContext(params) {
|
|
25452
|
-
const isToolApproval = isMcpToolCallApproval(params._meta);
|
|
26154
|
+
const isToolApproval = isMcpToolCallApproval(params._meta) && this.isMessageOnlyForm(params);
|
|
25453
26155
|
const persistOptions = parsePersistOptions(params._meta);
|
|
25454
|
-
const correlatedCallId = isToolApproval
|
|
25455
|
-
return {
|
|
26156
|
+
const correlatedCallId = isToolApproval ? this.permissionContext.popPendingMcpApproval(params.threadId, params.serverName) : void 0;
|
|
26157
|
+
return {
|
|
26158
|
+
isToolApproval,
|
|
26159
|
+
persistOptions,
|
|
26160
|
+
correlatedCallId
|
|
26161
|
+
};
|
|
25456
26162
|
}
|
|
25457
26163
|
shouldUseAcpElicitation(params) {
|
|
26164
|
+
if (this.isMessageOnlyForm(params)) return false;
|
|
25458
26165
|
switch (params.mode) {
|
|
25459
26166
|
case "form":
|
|
25460
26167
|
return clientSupportsFormElicitation(this.clientCapabilities);
|
|
@@ -25464,23 +26171,28 @@ var CodexElicitationHandler = class {
|
|
|
25464
26171
|
return false;
|
|
25465
26172
|
}
|
|
25466
26173
|
}
|
|
26174
|
+
canUsePermissionFallback(params) {
|
|
26175
|
+
return params.mode === "url" || this.isMessageOnlyForm(params);
|
|
26176
|
+
}
|
|
26177
|
+
isMessageOnlyForm(params) {
|
|
26178
|
+
if (params.mode !== "form" && params.mode !== "openai/form") return false;
|
|
26179
|
+
if (params.requestedSchema === null) return true;
|
|
26180
|
+
if (!isRecord2(params.requestedSchema)) return false;
|
|
26181
|
+
return params.requestedSchema["type"] === "object" && isRecord2(params.requestedSchema["properties"]) && Object.keys(params.requestedSchema["properties"]).length === 0;
|
|
26182
|
+
}
|
|
25467
26183
|
buildElicitationRequest(params, context) {
|
|
25468
26184
|
const base = {
|
|
25469
|
-
sessionId:
|
|
26185
|
+
sessionId: params.threadId,
|
|
25470
26186
|
...context.correlatedCallId ? { toolCallId: context.correlatedCallId } : {},
|
|
25471
26187
|
message: params.message,
|
|
25472
|
-
_meta:
|
|
26188
|
+
_meta: recordOrNull(params._meta)
|
|
25473
26189
|
};
|
|
25474
26190
|
switch (params.mode) {
|
|
25475
26191
|
case "form": {
|
|
25476
|
-
const requestedSchema = context.isToolApproval ? addPersistChoiceToSchema(
|
|
25477
|
-
normalizeElicitationSchema(params.requestedSchema),
|
|
25478
|
-
context.persistOptions
|
|
25479
|
-
) : normalizeElicitationSchema(params.requestedSchema);
|
|
25480
26192
|
return {
|
|
25481
26193
|
...base,
|
|
25482
26194
|
mode: "form",
|
|
25483
|
-
requestedSchema
|
|
26195
|
+
requestedSchema: normalizeElicitationSchema(params.requestedSchema)
|
|
25484
26196
|
};
|
|
25485
26197
|
}
|
|
25486
26198
|
case "url":
|
|
@@ -25542,7 +26254,7 @@ var CodexElicitationHandler = class {
|
|
|
25542
26254
|
}
|
|
25543
26255
|
const firstQuestion = params.questions[0];
|
|
25544
26256
|
return {
|
|
25545
|
-
sessionId:
|
|
26257
|
+
sessionId: params.threadId,
|
|
25546
26258
|
toolCallId: params.itemId,
|
|
25547
26259
|
mode: "form",
|
|
25548
26260
|
message: params.questions.length === 1 && firstQuestion ? firstQuestion.question : "Input requested",
|
|
@@ -25551,90 +26263,20 @@ var CodexElicitationHandler = class {
|
|
|
25551
26263
|
properties,
|
|
25552
26264
|
required: required2
|
|
25553
26265
|
},
|
|
25554
|
-
_meta: {
|
|
25555
|
-
codex: {
|
|
25556
|
-
autoResolutionMs: params.autoResolutionMs
|
|
25557
|
-
}
|
|
25558
|
-
}
|
|
25559
|
-
};
|
|
25560
|
-
}
|
|
25561
|
-
buildPermissionRequest(params, context) {
|
|
25562
|
-
const sessionId = this.sessionState.sessionId;
|
|
25563
|
-
const messageContent = {
|
|
25564
|
-
type: "content",
|
|
25565
|
-
content: { type: "text", text: params.message }
|
|
25566
|
-
};
|
|
25567
|
-
const options = context.isToolApproval ? buildToolApprovalOptions(context.persistOptions) : ELICITATION_OPTIONS;
|
|
25568
|
-
if (params.mode === "form" || params.mode === "openai/form") {
|
|
25569
|
-
if (context.correlatedCallId !== void 0) {
|
|
25570
|
-
return {
|
|
25571
|
-
request: {
|
|
25572
|
-
sessionId,
|
|
25573
|
-
toolCall: {
|
|
25574
|
-
toolCallId: context.correlatedCallId,
|
|
25575
|
-
kind: "execute",
|
|
25576
|
-
status: "pending"
|
|
25577
|
-
// content: [messageContent], — omitted: already rendered via item/started
|
|
25578
|
-
// rawInput: { ... } — omitted: same reason
|
|
25579
|
-
},
|
|
25580
|
-
_meta: { is_mcp_tool_approval: true },
|
|
25581
|
-
options
|
|
25582
|
-
},
|
|
25583
|
-
correlatedCallId: context.correlatedCallId
|
|
25584
|
-
};
|
|
25585
|
-
}
|
|
25586
|
-
return {
|
|
25587
|
-
request: {
|
|
25588
|
-
sessionId,
|
|
25589
|
-
toolCall: {
|
|
25590
|
-
toolCallId: `elicitation-${params.serverName}`,
|
|
25591
|
-
kind: context.isToolApproval ? "execute" : "other",
|
|
25592
|
-
status: "pending",
|
|
25593
|
-
content: [messageContent],
|
|
25594
|
-
rawInput: { serverName: params.serverName, schema: params.requestedSchema }
|
|
25595
|
-
},
|
|
25596
|
-
...context.isToolApproval ? { _meta: { is_mcp_tool_approval: true } } : {},
|
|
25597
|
-
options
|
|
25598
|
-
},
|
|
25599
|
-
correlatedCallId: void 0
|
|
25600
|
-
};
|
|
25601
|
-
} else {
|
|
25602
|
-
return {
|
|
25603
|
-
request: {
|
|
25604
|
-
sessionId,
|
|
25605
|
-
toolCall: {
|
|
25606
|
-
toolCallId: `elicitation-${params.elicitationId}`,
|
|
25607
|
-
kind: "fetch",
|
|
25608
|
-
status: "pending",
|
|
25609
|
-
content: [messageContent],
|
|
25610
|
-
rawInput: { serverName: params.serverName, url: params.url }
|
|
25611
|
-
},
|
|
25612
|
-
options
|
|
25613
|
-
},
|
|
25614
|
-
correlatedCallId: void 0
|
|
25615
|
-
};
|
|
25616
|
-
}
|
|
25617
|
-
}
|
|
25618
|
-
convertPermissionResponse(response) {
|
|
25619
|
-
if (response.outcome.outcome === "cancelled") {
|
|
25620
|
-
return { action: "cancel", content: null, _meta: null };
|
|
25621
|
-
}
|
|
25622
|
-
const optionId = response.outcome.optionId;
|
|
25623
|
-
if (optionId === McpApprovalOptionId.AllowSession) {
|
|
25624
|
-
return { action: "accept", content: null, _meta: { persist: "session" } };
|
|
25625
|
-
}
|
|
25626
|
-
if (optionId === McpApprovalOptionId.AllowAlways) {
|
|
25627
|
-
return { action: "accept", content: null, _meta: { persist: "always" } };
|
|
25628
|
-
}
|
|
25629
|
-
if (optionId === McpApprovalOptionId.AllowOnce || optionId === "accept") {
|
|
25630
|
-
return { action: "accept", content: null, _meta: null };
|
|
25631
|
-
}
|
|
25632
|
-
return { action: "decline", content: null, _meta: null };
|
|
26266
|
+
_meta: {
|
|
26267
|
+
codex: {
|
|
26268
|
+
autoResolutionMs: params.autoResolutionMs
|
|
26269
|
+
}
|
|
26270
|
+
}
|
|
26271
|
+
};
|
|
25633
26272
|
}
|
|
25634
26273
|
convertElicitationResponse(response, context) {
|
|
25635
26274
|
if (CreateElicitationResponse.isAccept(response)) {
|
|
25636
26275
|
const content = contentRecord(response.content);
|
|
25637
26276
|
const persist = context.isToolApproval ? content["persist"] : void 0;
|
|
26277
|
+
if (context.isToolApproval && !this.isAllowedToolApprovalPersist(persist, context.persistOptions)) {
|
|
26278
|
+
return { action: "cancel", content: null, _meta: null };
|
|
26279
|
+
}
|
|
25638
26280
|
if (persist === "session" || persist === "always" || persist === "once") {
|
|
25639
26281
|
delete content["persist"];
|
|
25640
26282
|
}
|
|
@@ -25645,7 +26287,7 @@ var CodexElicitationHandler = class {
|
|
|
25645
26287
|
};
|
|
25646
26288
|
}
|
|
25647
26289
|
if (CreateElicitationResponse.isDecline(response)) {
|
|
25648
|
-
return { action: "decline", content: null, _meta: elicitationResponseMeta(response, context) };
|
|
26290
|
+
return context.isToolApproval ? { action: "cancel", content: null, _meta: elicitationResponseMeta(response, context) } : { action: "decline", content: null, _meta: elicitationResponseMeta(response, context) };
|
|
25649
26291
|
}
|
|
25650
26292
|
if (CreateElicitationResponse.isCancel(response)) {
|
|
25651
26293
|
return { action: "cancel", content: null, _meta: elicitationResponseMeta(response, context) };
|
|
@@ -25655,6 +26297,9 @@ var CodexElicitationHandler = class {
|
|
|
25655
26297
|
}
|
|
25656
26298
|
return { action: "cancel", content: null, _meta: null };
|
|
25657
26299
|
}
|
|
26300
|
+
isAllowedToolApprovalPersist(persist, persistOptions) {
|
|
26301
|
+
return persist === void 0 || persist === "once" || persist === "session" && persistOptions.has("session") || persist === "always" && persistOptions.has("always");
|
|
26302
|
+
}
|
|
25658
26303
|
convertUserInputResponse(response, params) {
|
|
25659
26304
|
if (!CreateElicitationResponse.isAccept(response)) {
|
|
25660
26305
|
return { answers: {} };
|
|
@@ -25673,12 +26318,12 @@ var CodexElicitationHandler = class {
|
|
|
25673
26318
|
}
|
|
25674
26319
|
return { answers };
|
|
25675
26320
|
}
|
|
25676
|
-
async publishAcceptedMcpToolApproval(context, accepted) {
|
|
26321
|
+
async publishAcceptedMcpToolApproval(sessionId, context, accepted) {
|
|
25677
26322
|
if (!accepted || context.correlatedCallId === void 0) {
|
|
25678
26323
|
return;
|
|
25679
26324
|
}
|
|
25680
26325
|
await this.connection.notify(methods.client.session.update, {
|
|
25681
|
-
sessionId
|
|
26326
|
+
sessionId,
|
|
25682
26327
|
update: { sessionUpdate: "tool_call_update", toolCallId: context.correlatedCallId, status: "in_progress" }
|
|
25683
26328
|
});
|
|
25684
26329
|
}
|
|
@@ -25702,37 +26347,6 @@ var CodexElicitationHandler = class {
|
|
|
25702
26347
|
});
|
|
25703
26348
|
}
|
|
25704
26349
|
}
|
|
25705
|
-
handleItemStarted(event) {
|
|
25706
|
-
if (event.item.type !== "mcpToolCall") {
|
|
25707
|
-
return;
|
|
25708
|
-
}
|
|
25709
|
-
this.pendingMcpApprovals.set(this.key(event.threadId, event.item.server), event.item.id);
|
|
25710
|
-
}
|
|
25711
|
-
handleItemCompleted(event) {
|
|
25712
|
-
if (event.item.type !== "mcpToolCall") {
|
|
25713
|
-
return;
|
|
25714
|
-
}
|
|
25715
|
-
this.popPendingApproval(event.threadId, event.item.server);
|
|
25716
|
-
}
|
|
25717
|
-
popPendingApproval(threadId, serverName) {
|
|
25718
|
-
const key = this.key(threadId, serverName);
|
|
25719
|
-
const callId = this.pendingMcpApprovals.get(key);
|
|
25720
|
-
this.pendingMcpApprovals.delete(key);
|
|
25721
|
-
return callId;
|
|
25722
|
-
}
|
|
25723
|
-
clearThread(threadId) {
|
|
25724
|
-
for (const key of this.pendingMcpApprovals.keys()) {
|
|
25725
|
-
if (this.belongsToThread(key, threadId)) {
|
|
25726
|
-
this.pendingMcpApprovals.delete(key);
|
|
25727
|
-
}
|
|
25728
|
-
}
|
|
25729
|
-
}
|
|
25730
|
-
key(threadId, serverName) {
|
|
25731
|
-
return `${threadId}:${serverName}`;
|
|
25732
|
-
}
|
|
25733
|
-
belongsToThread(key, threadId) {
|
|
25734
|
-
return key.startsWith(`${threadId}:`);
|
|
25735
|
-
}
|
|
25736
26350
|
};
|
|
25737
26351
|
|
|
25738
26352
|
// src/CodexAuthMethod.ts
|
|
@@ -25788,13 +26402,14 @@ function isCodexAuthRequest(request) {
|
|
|
25788
26402
|
}
|
|
25789
26403
|
|
|
25790
26404
|
// node_modules/open/index.js
|
|
25791
|
-
import
|
|
25792
|
-
import
|
|
26405
|
+
import process11 from "node:process";
|
|
26406
|
+
import path4 from "node:path";
|
|
25793
26407
|
import { fileURLToPath } from "node:url";
|
|
25794
|
-
import
|
|
26408
|
+
import childProcess4 from "node:child_process";
|
|
25795
26409
|
import fs6, { constants as fsConstants2 } from "node:fs/promises";
|
|
25796
26410
|
|
|
25797
26411
|
// node_modules/wsl-utils/index.js
|
|
26412
|
+
import path3 from "node:path";
|
|
25798
26413
|
import { promisify as promisify2 } from "node:util";
|
|
25799
26414
|
import childProcess2 from "node:child_process";
|
|
25800
26415
|
import fs5, { constants as fsConstants } from "node:fs/promises";
|
|
@@ -25873,7 +26488,7 @@ var isWsl = () => {
|
|
|
25873
26488
|
};
|
|
25874
26489
|
var is_wsl_default = process3.env.__IS_WSL_TEST__ ? isWsl : isWsl();
|
|
25875
26490
|
|
|
25876
|
-
// node_modules/powershell-utils/index.js
|
|
26491
|
+
// node_modules/wsl-utils/node_modules/powershell-utils/index.js
|
|
25877
26492
|
import process4 from "node:process";
|
|
25878
26493
|
import { Buffer as Buffer2 } from "node:buffer";
|
|
25879
26494
|
import { promisify } from "node:util";
|
|
@@ -25972,20 +26587,73 @@ var canAccessPowerShell = async () => {
|
|
|
25972
26587
|
var wslDefaultBrowser = async () => {
|
|
25973
26588
|
const psPath = await powerShellPath2();
|
|
25974
26589
|
const command = String.raw`(Get-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice").ProgId`;
|
|
25975
|
-
const { stdout } = await executePowerShell(command, {
|
|
26590
|
+
const { stdout } = await executePowerShell(command, {
|
|
26591
|
+
powerShellPath: psPath,
|
|
26592
|
+
cwd: path3.dirname(psPath)
|
|
26593
|
+
});
|
|
25976
26594
|
return stdout.trim();
|
|
25977
26595
|
};
|
|
25978
|
-
var
|
|
25979
|
-
|
|
25980
|
-
|
|
25981
|
-
|
|
25982
|
-
|
|
25983
|
-
|
|
25984
|
-
|
|
25985
|
-
|
|
25986
|
-
|
|
26596
|
+
var isUrl = (path9) => /^[a-z]+:\/\//i.test(path9);
|
|
26597
|
+
var convertWslPathToWindows = async (paths) => {
|
|
26598
|
+
const isBatch = Array.isArray(paths);
|
|
26599
|
+
const pathArray = isBatch ? paths : [paths];
|
|
26600
|
+
const indicesToConvert = [];
|
|
26601
|
+
const pathsToConvert = [];
|
|
26602
|
+
for (const [index, path9] of pathArray.entries()) {
|
|
26603
|
+
if (!isUrl(path9)) {
|
|
26604
|
+
indicesToConvert.push(index);
|
|
26605
|
+
pathsToConvert.push(path9);
|
|
26606
|
+
}
|
|
26607
|
+
}
|
|
26608
|
+
const results = [...pathArray];
|
|
26609
|
+
if (pathsToConvert.length > 0) {
|
|
26610
|
+
try {
|
|
26611
|
+
const { stdout } = await execFile2("wslpath", ["-aw", ...pathsToConvert], { encoding: "utf8" });
|
|
26612
|
+
const convertedPaths = stdout.split(/\r?\n/).filter(Boolean);
|
|
26613
|
+
for (const [index, originalIndex] of indicesToConvert.entries()) {
|
|
26614
|
+
results[originalIndex] = convertedPaths[index] ?? pathArray[originalIndex];
|
|
26615
|
+
}
|
|
26616
|
+
} catch {
|
|
26617
|
+
}
|
|
25987
26618
|
}
|
|
26619
|
+
return isBatch ? results : results[0];
|
|
26620
|
+
};
|
|
26621
|
+
|
|
26622
|
+
// node_modules/powershell-utils/index.js
|
|
26623
|
+
import process5 from "node:process";
|
|
26624
|
+
import { Buffer as Buffer3 } from "node:buffer";
|
|
26625
|
+
import { promisify as promisify3 } from "node:util";
|
|
26626
|
+
import childProcess3 from "node:child_process";
|
|
26627
|
+
var execFile3 = promisify3(childProcess3.execFile);
|
|
26628
|
+
var powerShellPath3 = () => `${process5.env.SYSTEMROOT || process5.env.windir || String.raw`C:\Windows`}\\System32\\WindowsPowerShell\\v1.0\\powershell.exe`;
|
|
26629
|
+
var argumentsPrefix = [
|
|
26630
|
+
"-NoProfile",
|
|
26631
|
+
"-NonInteractive",
|
|
26632
|
+
"-ExecutionPolicy",
|
|
26633
|
+
"Bypass",
|
|
26634
|
+
"-EncodedCommand"
|
|
26635
|
+
];
|
|
26636
|
+
var encodeCommand = (command) => Buffer3.from(command, "utf16le").toString("base64");
|
|
26637
|
+
var escapeArgument = (value) => `'${String(value).replaceAll("'", "''")}'`;
|
|
26638
|
+
var createArguments = (command) => [...argumentsPrefix, encodeCommand(command)];
|
|
26639
|
+
var executePowerShell2 = async (command, options = {}) => {
|
|
26640
|
+
const {
|
|
26641
|
+
powerShellPath: psPath,
|
|
26642
|
+
...execFileOptions
|
|
26643
|
+
} = options;
|
|
26644
|
+
return execFile3(
|
|
26645
|
+
psPath ?? powerShellPath3(),
|
|
26646
|
+
createArguments(command),
|
|
26647
|
+
{
|
|
26648
|
+
encoding: "utf8",
|
|
26649
|
+
...execFileOptions
|
|
26650
|
+
}
|
|
26651
|
+
);
|
|
25988
26652
|
};
|
|
26653
|
+
executePowerShell2.argumentsPrefix = argumentsPrefix;
|
|
26654
|
+
executePowerShell2.encodeCommand = encodeCommand;
|
|
26655
|
+
executePowerShell2.escapeArgument = escapeArgument;
|
|
26656
|
+
executePowerShell2.createArguments = createArguments;
|
|
25989
26657
|
|
|
25990
26658
|
// node_modules/define-lazy-prop/index.js
|
|
25991
26659
|
function defineLazyProperty(object2, propertyName, valueGetter) {
|
|
@@ -26006,17 +26674,17 @@ function defineLazyProperty(object2, propertyName, valueGetter) {
|
|
|
26006
26674
|
}
|
|
26007
26675
|
|
|
26008
26676
|
// node_modules/default-browser/index.js
|
|
26009
|
-
import { promisify as
|
|
26010
|
-
import
|
|
26011
|
-
import { execFile as
|
|
26677
|
+
import { promisify as promisify7 } from "node:util";
|
|
26678
|
+
import process9 from "node:process";
|
|
26679
|
+
import { execFile as execFile7 } from "node:child_process";
|
|
26012
26680
|
|
|
26013
26681
|
// node_modules/default-browser-id/index.js
|
|
26014
|
-
import { promisify as
|
|
26015
|
-
import
|
|
26016
|
-
import { execFile as
|
|
26017
|
-
var execFileAsync =
|
|
26682
|
+
import { promisify as promisify4 } from "node:util";
|
|
26683
|
+
import process6 from "node:process";
|
|
26684
|
+
import { execFile as execFile4 } from "node:child_process";
|
|
26685
|
+
var execFileAsync = promisify4(execFile4);
|
|
26018
26686
|
async function defaultBrowserId() {
|
|
26019
|
-
if (
|
|
26687
|
+
if (process6.platform !== "darwin") {
|
|
26020
26688
|
throw new Error("macOS only");
|
|
26021
26689
|
}
|
|
26022
26690
|
const { stdout } = await execFileAsync("defaults", ["read", "com.apple.LaunchServices/com.apple.launchservices.secure", "LSHandlers"]);
|
|
@@ -26029,12 +26697,12 @@ async function defaultBrowserId() {
|
|
|
26029
26697
|
}
|
|
26030
26698
|
|
|
26031
26699
|
// node_modules/run-applescript/index.js
|
|
26032
|
-
import
|
|
26033
|
-
import { promisify as
|
|
26034
|
-
import { execFile as
|
|
26035
|
-
var execFileAsync2 =
|
|
26700
|
+
import process7 from "node:process";
|
|
26701
|
+
import { promisify as promisify5 } from "node:util";
|
|
26702
|
+
import { execFile as execFile5, execFileSync } from "node:child_process";
|
|
26703
|
+
var execFileAsync2 = promisify5(execFile5);
|
|
26036
26704
|
async function runAppleScript(script, { humanReadableOutput = true, signal } = {}) {
|
|
26037
|
-
if (
|
|
26705
|
+
if (process7.platform !== "darwin") {
|
|
26038
26706
|
throw new Error("macOS only");
|
|
26039
26707
|
}
|
|
26040
26708
|
const outputArguments = humanReadableOutput ? [] : ["-ss"];
|
|
@@ -26053,9 +26721,10 @@ tell application "System Events" to get value of property list item "CFBundleNam
|
|
|
26053
26721
|
}
|
|
26054
26722
|
|
|
26055
26723
|
// node_modules/default-browser/windows.js
|
|
26056
|
-
import
|
|
26057
|
-
import {
|
|
26058
|
-
|
|
26724
|
+
import process8 from "node:process";
|
|
26725
|
+
import { promisify as promisify6 } from "node:util";
|
|
26726
|
+
import { execFile as execFile6 } from "node:child_process";
|
|
26727
|
+
var execFileAsync3 = promisify6(execFile6);
|
|
26059
26728
|
var windowsBrowserProgIds = {
|
|
26060
26729
|
MSEdgeHTM: { name: "Edge", id: "com.microsoft.edge" },
|
|
26061
26730
|
// The missing `L` is correct.
|
|
@@ -26079,7 +26748,8 @@ var _windowsBrowserProgIdMap = new Map(Object.entries(windowsBrowserProgIds));
|
|
|
26079
26748
|
var UnknownBrowserError = class extends Error {
|
|
26080
26749
|
};
|
|
26081
26750
|
async function defaultBrowser(_execFileAsync = execFileAsync3) {
|
|
26082
|
-
const {
|
|
26751
|
+
const regPath = `${process8.env.SYSTEMROOT ?? process8.env.windir ?? "C:\\Windows"}\\System32\\reg.exe`;
|
|
26752
|
+
const { stdout } = await _execFileAsync(regPath, [
|
|
26083
26753
|
"QUERY",
|
|
26084
26754
|
" HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\http\\UserChoice",
|
|
26085
26755
|
"/v",
|
|
@@ -26098,36 +26768,36 @@ async function defaultBrowser(_execFileAsync = execFileAsync3) {
|
|
|
26098
26768
|
}
|
|
26099
26769
|
|
|
26100
26770
|
// node_modules/default-browser/index.js
|
|
26101
|
-
var execFileAsync4 =
|
|
26771
|
+
var execFileAsync4 = promisify7(execFile7);
|
|
26102
26772
|
var titleize = (string4) => string4.toLowerCase().replaceAll(/(?:^|\s|-)\S/g, (x) => x.toUpperCase());
|
|
26103
26773
|
async function defaultBrowser2() {
|
|
26104
|
-
if (
|
|
26774
|
+
if (process9.platform === "darwin") {
|
|
26105
26775
|
const id = await defaultBrowserId();
|
|
26106
26776
|
const name = await bundleName(id);
|
|
26107
26777
|
return { name, id };
|
|
26108
26778
|
}
|
|
26109
|
-
if (
|
|
26779
|
+
if (process9.platform === "linux") {
|
|
26110
26780
|
const { stdout } = await execFileAsync4("xdg-mime", ["query", "default", "x-scheme-handler/http"]);
|
|
26111
26781
|
const id = stdout.trim();
|
|
26112
26782
|
const name = titleize(id.replace(/.desktop$/, "").replace("-", " "));
|
|
26113
26783
|
return { name, id };
|
|
26114
26784
|
}
|
|
26115
|
-
if (
|
|
26785
|
+
if (process9.platform === "win32") {
|
|
26116
26786
|
return defaultBrowser();
|
|
26117
26787
|
}
|
|
26118
26788
|
throw new Error("Only macOS, Linux, and Windows are supported");
|
|
26119
26789
|
}
|
|
26120
26790
|
|
|
26121
26791
|
// node_modules/is-in-ssh/index.js
|
|
26122
|
-
import
|
|
26123
|
-
var isInSsh = Boolean(
|
|
26792
|
+
import process10 from "node:process";
|
|
26793
|
+
var isInSsh = Boolean(process10.env.SSH_CONNECTION || process10.env.SSH_CLIENT || process10.env.SSH_TTY);
|
|
26124
26794
|
var is_in_ssh_default = isInSsh;
|
|
26125
26795
|
|
|
26126
26796
|
// node_modules/open/index.js
|
|
26127
26797
|
var fallbackAttemptSymbol = /* @__PURE__ */ Symbol("fallbackAttempt");
|
|
26128
|
-
var __dirname = import.meta.url ?
|
|
26129
|
-
var localXdgOpenPath =
|
|
26130
|
-
var { platform, arch } =
|
|
26798
|
+
var __dirname = import.meta.url ? path4.dirname(fileURLToPath(import.meta.url)) : "";
|
|
26799
|
+
var localXdgOpenPath = path4.join(__dirname, "xdg-open");
|
|
26800
|
+
var { platform, arch } = process11;
|
|
26131
26801
|
var tryEachApp = async (apps2, opener) => {
|
|
26132
26802
|
if (apps2.length === 0) {
|
|
26133
26803
|
return;
|
|
@@ -26240,7 +26910,7 @@ var baseOpen = async (options) => {
|
|
|
26240
26910
|
}
|
|
26241
26911
|
} else if (platform === "win32" || shouldUseWindowsInWsl) {
|
|
26242
26912
|
command = await powerShellPath2();
|
|
26243
|
-
cliArguments.push(...
|
|
26913
|
+
cliArguments.push(...executePowerShell2.argumentsPrefix);
|
|
26244
26914
|
if (!is_wsl_default) {
|
|
26245
26915
|
childProcessOptions.windowsVerbatimArguments = true;
|
|
26246
26916
|
}
|
|
@@ -26252,21 +26922,24 @@ var baseOpen = async (options) => {
|
|
|
26252
26922
|
encodedArguments.push("-Wait");
|
|
26253
26923
|
}
|
|
26254
26924
|
if (app) {
|
|
26255
|
-
encodedArguments.push(
|
|
26925
|
+
encodedArguments.push(executePowerShell2.escapeArgument(app));
|
|
26256
26926
|
if (options.target) {
|
|
26257
26927
|
appArguments.push(options.target);
|
|
26258
26928
|
}
|
|
26259
26929
|
} else if (options.target) {
|
|
26260
|
-
encodedArguments.push(
|
|
26930
|
+
encodedArguments.push(executePowerShell2.escapeArgument(options.target));
|
|
26261
26931
|
}
|
|
26262
26932
|
if (appArguments.length > 0) {
|
|
26263
|
-
appArguments = appArguments.map((argument) =>
|
|
26933
|
+
appArguments = appArguments.map((argument) => executePowerShell2.escapeArgument(argument));
|
|
26264
26934
|
encodedArguments.push("-ArgumentList", appArguments.join(","));
|
|
26265
26935
|
}
|
|
26266
|
-
options.target =
|
|
26936
|
+
options.target = executePowerShell2.encodeCommand(encodedArguments.join(" "));
|
|
26267
26937
|
if (!options.wait) {
|
|
26268
26938
|
childProcessOptions.stdio = "ignore";
|
|
26269
26939
|
}
|
|
26940
|
+
if (is_wsl_default) {
|
|
26941
|
+
childProcessOptions.cwd = path4.dirname(command);
|
|
26942
|
+
}
|
|
26270
26943
|
} else {
|
|
26271
26944
|
if (app) {
|
|
26272
26945
|
command = app;
|
|
@@ -26278,7 +26951,7 @@ var baseOpen = async (options) => {
|
|
|
26278
26951
|
exeLocalXdgOpen = true;
|
|
26279
26952
|
} catch {
|
|
26280
26953
|
}
|
|
26281
|
-
const useSystemXdgOpen =
|
|
26954
|
+
const useSystemXdgOpen = process11.versions.electron ?? (platform === "android" || isBundled || !exeLocalXdgOpen);
|
|
26282
26955
|
command = useSystemXdgOpen ? "xdg-open" : localXdgOpenPath;
|
|
26283
26956
|
}
|
|
26284
26957
|
if (appArguments.length > 0) {
|
|
@@ -26295,7 +26968,7 @@ var baseOpen = async (options) => {
|
|
|
26295
26968
|
if (options.target) {
|
|
26296
26969
|
cliArguments.push(options.target);
|
|
26297
26970
|
}
|
|
26298
|
-
const subprocess =
|
|
26971
|
+
const subprocess = childProcess4.spawn(command, cliArguments, childProcessOptions);
|
|
26299
26972
|
if (options.wait) {
|
|
26300
26973
|
return new Promise((resolve, reject) => {
|
|
26301
26974
|
subprocess.once("error", reject);
|
|
@@ -26442,33 +27115,44 @@ var AgentMode = class _AgentMode {
|
|
|
26442
27115
|
id;
|
|
26443
27116
|
name;
|
|
26444
27117
|
description;
|
|
27118
|
+
kind;
|
|
26445
27119
|
approvalPolicy;
|
|
27120
|
+
approvalsReviewer;
|
|
26446
27121
|
sandboxPolicy;
|
|
26447
27122
|
sandboxMode;
|
|
26448
|
-
constructor(id, name, description,
|
|
27123
|
+
constructor(id, name, description, kind, approvalPolicy, approvalsReviewer, sandboxPolicy, sandboxMode) {
|
|
26449
27124
|
this.id = id;
|
|
26450
27125
|
this.name = name;
|
|
26451
27126
|
this.description = description;
|
|
26452
|
-
this.
|
|
26453
|
-
this.
|
|
27127
|
+
this.kind = kind;
|
|
27128
|
+
this.approvalPolicy = approvalPolicy;
|
|
27129
|
+
this.approvalsReviewer = approvalsReviewer;
|
|
27130
|
+
this.sandboxPolicy = sandboxPolicy;
|
|
26454
27131
|
this.sandboxMode = sandboxMode;
|
|
26455
27132
|
}
|
|
26456
27133
|
static ReadOnly = new _AgentMode(
|
|
26457
27134
|
"read-only",
|
|
26458
|
-
"
|
|
26459
|
-
"
|
|
27135
|
+
"Ask for approval",
|
|
27136
|
+
"Always ask to edit external files and use the internet",
|
|
27137
|
+
"standard",
|
|
26460
27138
|
"on-request",
|
|
27139
|
+
"user",
|
|
26461
27140
|
{
|
|
26462
|
-
|
|
26463
|
-
|
|
27141
|
+
type: "workspaceWrite",
|
|
27142
|
+
writableRoots: [],
|
|
27143
|
+
networkAccess: false,
|
|
27144
|
+
excludeTmpdirEnvVar: false,
|
|
27145
|
+
excludeSlashTmp: false
|
|
26464
27146
|
},
|
|
26465
|
-
"
|
|
27147
|
+
"workspace-write"
|
|
26466
27148
|
);
|
|
26467
27149
|
static Agent = new _AgentMode(
|
|
26468
27150
|
"agent",
|
|
26469
|
-
"
|
|
26470
|
-
"
|
|
27151
|
+
"Approve for me",
|
|
27152
|
+
"Only ask for actions detected as potentially unsafe",
|
|
27153
|
+
"auto_review",
|
|
26471
27154
|
"on-request",
|
|
27155
|
+
"auto_review",
|
|
26472
27156
|
{
|
|
26473
27157
|
type: "workspaceWrite",
|
|
26474
27158
|
writableRoots: [],
|
|
@@ -26480,9 +27164,11 @@ var AgentMode = class _AgentMode {
|
|
|
26480
27164
|
);
|
|
26481
27165
|
static AgentFullAccess = new _AgentMode(
|
|
26482
27166
|
"agent-full-access",
|
|
26483
|
-
"
|
|
26484
|
-
"
|
|
27167
|
+
"Full access",
|
|
27168
|
+
"Unrestricted access to the internet and any file on your computer",
|
|
27169
|
+
"full_access",
|
|
26485
27170
|
"never",
|
|
27171
|
+
"user",
|
|
26486
27172
|
{ "type": "dangerFullAccess" },
|
|
26487
27173
|
"danger-full-access"
|
|
26488
27174
|
);
|
|
@@ -26491,7 +27177,8 @@ var AgentMode = class _AgentMode {
|
|
|
26491
27177
|
return {
|
|
26492
27178
|
id: this.id,
|
|
26493
27179
|
name: this.name,
|
|
26494
|
-
description: this.description
|
|
27180
|
+
description: this.description,
|
|
27181
|
+
_meta: { kind: this.kind }
|
|
26495
27182
|
};
|
|
26496
27183
|
}
|
|
26497
27184
|
toSessionModeState() {
|
|
@@ -26511,7 +27198,8 @@ var AgentMode = class _AgentMode {
|
|
|
26511
27198
|
options: _AgentMode.all().map((mode) => ({
|
|
26512
27199
|
value: mode.id,
|
|
26513
27200
|
name: mode.name,
|
|
26514
|
-
description: mode.description
|
|
27201
|
+
description: mode.description,
|
|
27202
|
+
_meta: { kind: mode.kind }
|
|
26515
27203
|
}))
|
|
26516
27204
|
};
|
|
26517
27205
|
}
|
|
@@ -26533,7 +27221,7 @@ var AgentMode = class _AgentMode {
|
|
|
26533
27221
|
};
|
|
26534
27222
|
|
|
26535
27223
|
// src/CodexAcpClient.ts
|
|
26536
|
-
import
|
|
27224
|
+
import path7 from "node:path";
|
|
26537
27225
|
|
|
26538
27226
|
// src/McpServerName.ts
|
|
26539
27227
|
var MCP_SERVER_NAME_WHITESPACE = /\p{White_Space}/gu;
|
|
@@ -26547,7 +27235,7 @@ var package_default = {
|
|
|
26547
27235
|
publishConfig: {
|
|
26548
27236
|
access: "public"
|
|
26549
27237
|
},
|
|
26550
|
-
version: "1.
|
|
27238
|
+
version: "1.7.0-agentconnect.2",
|
|
26551
27239
|
description: "",
|
|
26552
27240
|
main: "dist/index.js",
|
|
26553
27241
|
bin: {
|
|
@@ -26600,17 +27288,17 @@ var package_default = {
|
|
|
26600
27288
|
type: "module",
|
|
26601
27289
|
devDependencies: {
|
|
26602
27290
|
"@types/node": "^26.1.0",
|
|
26603
|
-
esbuild: "^0.28.
|
|
27291
|
+
esbuild: "^0.28.2",
|
|
26604
27292
|
"mcp-hello-world": "^1.1.2",
|
|
26605
|
-
tsx: "^4.23.
|
|
27293
|
+
tsx: "^4.23.12",
|
|
26606
27294
|
typescript: "^7.0.2",
|
|
26607
|
-
vitest: "^4.1.
|
|
27295
|
+
vitest: "^4.1.11"
|
|
26608
27296
|
},
|
|
26609
27297
|
dependencies: {
|
|
26610
|
-
"@agentclientprotocol/sdk": "^1.
|
|
27298
|
+
"@agentclientprotocol/sdk": "^1.4.0",
|
|
26611
27299
|
"@openai/codex": "^0.148.0",
|
|
26612
27300
|
diff: "^9.0.0",
|
|
26613
|
-
open: "^11.0.
|
|
27301
|
+
open: "^11.0.1",
|
|
26614
27302
|
"vscode-jsonrpc": "^9.0.1",
|
|
26615
27303
|
zod: "^4.0.0"
|
|
26616
27304
|
}
|
|
@@ -26652,17 +27340,17 @@ function createCodexCollaborationMode(mode, currentModelId) {
|
|
|
26652
27340
|
}
|
|
26653
27341
|
|
|
26654
27342
|
// src/PathUtils.ts
|
|
26655
|
-
import
|
|
27343
|
+
import path5 from "node:path";
|
|
26656
27344
|
function isAbsolutePathLike(value) {
|
|
26657
27345
|
const trimmed = value.trim();
|
|
26658
|
-
return
|
|
27346
|
+
return path5.isAbsolute(trimmed) || isWindowsAbsolutePath(trimmed);
|
|
26659
27347
|
}
|
|
26660
27348
|
function arePathsEqual(left, right) {
|
|
26661
27349
|
return normalizePathForComparison(left) === normalizePathForComparison(right);
|
|
26662
27350
|
}
|
|
26663
27351
|
function arePathBasenamesEqual(left, right) {
|
|
26664
|
-
const leftBase =
|
|
26665
|
-
const rightBase =
|
|
27352
|
+
const leftBase = path5.posix.basename(normalizePathForComparison(left));
|
|
27353
|
+
const rightBase = path5.posix.basename(normalizePathForComparison(right));
|
|
26666
27354
|
if (shouldComparePathCaseInsensitive(left) || shouldComparePathCaseInsensitive(right)) {
|
|
26667
27355
|
return leftBase.toLowerCase() === rightBase.toLowerCase();
|
|
26668
27356
|
}
|
|
@@ -26674,11 +27362,11 @@ function normalizePathForComparison(value) {
|
|
|
26674
27362
|
return "";
|
|
26675
27363
|
}
|
|
26676
27364
|
if (isWindowsAbsolutePath(trimmed)) {
|
|
26677
|
-
const normalized2 =
|
|
27365
|
+
const normalized2 = path5.win32.normalize(trimmed).replace(/\\/g, "/");
|
|
26678
27366
|
return trimTrailingPathSeparators(normalized2).toLowerCase();
|
|
26679
27367
|
}
|
|
26680
|
-
const pathForComparison =
|
|
26681
|
-
const normalized =
|
|
27368
|
+
const pathForComparison = path5.isAbsolute(trimmed) ? trimmed : trimmed.replace(/\\/g, "/");
|
|
27369
|
+
const normalized = path5.posix.normalize(pathForComparison);
|
|
26682
27370
|
return trimTrailingPathSeparators(normalized);
|
|
26683
27371
|
}
|
|
26684
27372
|
function isWindowsAbsolutePath(value) {
|
|
@@ -26701,7 +27389,7 @@ function isRootPath(value) {
|
|
|
26701
27389
|
|
|
26702
27390
|
// src/AgentFileChangeReport.ts
|
|
26703
27391
|
import fs7 from "node:fs";
|
|
26704
|
-
import
|
|
27392
|
+
import path6 from "node:path";
|
|
26705
27393
|
var AGENT_FILE_CHANGE_REPORT_VERSION = 1;
|
|
26706
27394
|
var AGENT_FILE_CHANGE_REPORT_TIMEOUT_MS = 3e4;
|
|
26707
27395
|
var AGENT_FILE_CHANGE_REPORT_MAX_PATHS = 1024;
|
|
@@ -26711,7 +27399,7 @@ var AGENT_FILE_CHANGE_REPORT_MAX_UNCERTAINTY_LENGTH = 2e3;
|
|
|
26711
27399
|
var AGENT_FILE_CHANGE_REPORT_OUTPUT_SCHEMA = {
|
|
26712
27400
|
type: "object",
|
|
26713
27401
|
additionalProperties: false,
|
|
26714
|
-
required: ["paths", "complete"],
|
|
27402
|
+
required: ["paths", "complete", "uncertainty"],
|
|
26715
27403
|
properties: {
|
|
26716
27404
|
paths: {
|
|
26717
27405
|
type: "array",
|
|
@@ -26719,8 +27407,12 @@ var AGENT_FILE_CHANGE_REPORT_OUTPUT_SCHEMA = {
|
|
|
26719
27407
|
},
|
|
26720
27408
|
complete: { type: "boolean" },
|
|
26721
27409
|
uncertainty: {
|
|
26722
|
-
|
|
26723
|
-
|
|
27410
|
+
anyOf: [{
|
|
27411
|
+
type: "string",
|
|
27412
|
+
maxLength: AGENT_FILE_CHANGE_REPORT_MAX_UNCERTAINTY_LENGTH
|
|
27413
|
+
}, {
|
|
27414
|
+
type: "null"
|
|
27415
|
+
}]
|
|
26724
27416
|
}
|
|
26725
27417
|
}
|
|
26726
27418
|
};
|
|
@@ -26780,7 +27472,10 @@ function parseModelFileChangeReport(turn) {
|
|
|
26780
27472
|
case "interrupted":
|
|
26781
27473
|
throw new AgentFileChangeReportError("cancelled", "The audit turn was interrupted");
|
|
26782
27474
|
case "failed":
|
|
26783
|
-
throw new AgentFileChangeReportError(
|
|
27475
|
+
throw new AgentFileChangeReportError(
|
|
27476
|
+
"providerError",
|
|
27477
|
+
`The audit turn failed${turn.error?.message ? `: ${turn.error.message}` : ""}`
|
|
27478
|
+
);
|
|
26784
27479
|
case "inProgress":
|
|
26785
27480
|
throw new AgentFileChangeReportError("notReported", "The audit turn did not complete");
|
|
26786
27481
|
case "completed":
|
|
@@ -26810,10 +27505,10 @@ function parseModelFileChangeReport(turn) {
|
|
|
26810
27505
|
const paths = report["paths"];
|
|
26811
27506
|
const complete = report["complete"];
|
|
26812
27507
|
const uncertainty = report["uncertainty"];
|
|
26813
|
-
if (!Array.isArray(paths) || !paths.every((item) => typeof item === "string") || typeof complete !== "boolean" || uncertainty !== void 0 && typeof uncertainty !== "string") {
|
|
27508
|
+
if (!Array.isArray(paths) || !paths.every((item) => typeof item === "string") || typeof complete !== "boolean" || uncertainty !== void 0 && uncertainty !== null && typeof uncertainty !== "string") {
|
|
26814
27509
|
throw new AgentFileChangeReportError("invalidOutput", "The audit turn returned invalid fields");
|
|
26815
27510
|
}
|
|
26816
|
-
const normalizedUncertainty = uncertainty
|
|
27511
|
+
const normalizedUncertainty = typeof uncertainty === "string" ? uncertainty.trim() : void 0;
|
|
26817
27512
|
if (normalizedUncertainty !== void 0 && normalizedUncertainty.length > AGENT_FILE_CHANGE_REPORT_MAX_UNCERTAINTY_LENGTH) {
|
|
26818
27513
|
throw new AgentFileChangeReportError("invalidOutput", "The audit turn returned oversized uncertainty");
|
|
26819
27514
|
}
|
|
@@ -26892,13 +27587,13 @@ function normalizeWorkspaceRoot(value) {
|
|
|
26892
27587
|
}
|
|
26893
27588
|
if (isWindowsAbsolutePath2(trimmed)) {
|
|
26894
27589
|
return canonicalizeWorkspaceRoot({
|
|
26895
|
-
value:
|
|
27590
|
+
value: path6.win32.normalize(trimmed.replace(/\//g, "\\")),
|
|
26896
27591
|
flavor: "windows"
|
|
26897
27592
|
});
|
|
26898
27593
|
}
|
|
26899
|
-
if (
|
|
27594
|
+
if (path6.posix.isAbsolute(trimmed)) {
|
|
26900
27595
|
return canonicalizeWorkspaceRoot({
|
|
26901
|
-
value:
|
|
27596
|
+
value: path6.posix.normalize(trimmed.replace(/\\/g, "/")),
|
|
26902
27597
|
flavor: "posix"
|
|
26903
27598
|
});
|
|
26904
27599
|
}
|
|
@@ -26911,17 +27606,17 @@ function normalizeReportedPath(value, cwd, roots) {
|
|
|
26911
27606
|
}
|
|
26912
27607
|
let candidate;
|
|
26913
27608
|
if (isWindowsAbsolutePath2(trimmed)) {
|
|
26914
|
-
candidate = { value:
|
|
26915
|
-
} else if (
|
|
26916
|
-
candidate = { value:
|
|
27609
|
+
candidate = { value: path6.win32.normalize(trimmed.replace(/\//g, "\\")), flavor: "windows" };
|
|
27610
|
+
} else if (path6.posix.isAbsolute(trimmed)) {
|
|
27611
|
+
candidate = { value: path6.posix.normalize(trimmed.replace(/\\/g, "/")), flavor: "posix" };
|
|
26917
27612
|
} else if (cwd.flavor === "windows") {
|
|
26918
27613
|
candidate = {
|
|
26919
|
-
value:
|
|
27614
|
+
value: path6.win32.resolve(cwd.value, trimmed.replace(/\//g, "\\")),
|
|
26920
27615
|
flavor: "windows"
|
|
26921
27616
|
};
|
|
26922
27617
|
} else {
|
|
26923
27618
|
candidate = {
|
|
26924
|
-
value:
|
|
27619
|
+
value: path6.posix.resolve(cwd.value, trimmed.replace(/\\/g, "/")),
|
|
26925
27620
|
flavor: "posix"
|
|
26926
27621
|
};
|
|
26927
27622
|
}
|
|
@@ -26938,23 +27633,23 @@ function canonicalizeReportedPath(candidate) {
|
|
|
26938
27633
|
if (!isNativePathFlavor(candidate.flavor)) {
|
|
26939
27634
|
return candidate;
|
|
26940
27635
|
}
|
|
26941
|
-
const parent = canonicalizeFromExistingAncestor(
|
|
26942
|
-
return { ...candidate, value:
|
|
27636
|
+
const parent = canonicalizeFromExistingAncestor(path6.dirname(candidate.value));
|
|
27637
|
+
return { ...candidate, value: path6.resolve(parent, path6.basename(candidate.value)) };
|
|
26943
27638
|
}
|
|
26944
27639
|
function canonicalizeFromExistingAncestor(value) {
|
|
26945
|
-
const original =
|
|
27640
|
+
const original = path6.resolve(value);
|
|
26946
27641
|
let current = original;
|
|
26947
27642
|
const missingSegments = [];
|
|
26948
27643
|
while (true) {
|
|
26949
27644
|
try {
|
|
26950
27645
|
const canonical = fs7.realpathSync.native(current);
|
|
26951
|
-
return
|
|
27646
|
+
return path6.resolve(canonical, ...missingSegments.reverse());
|
|
26952
27647
|
} catch (error51) {
|
|
26953
27648
|
if (!isMissingPathError(error51)) return original;
|
|
26954
27649
|
}
|
|
26955
|
-
const parent =
|
|
27650
|
+
const parent = path6.dirname(current);
|
|
26956
27651
|
if (parent === current) return original;
|
|
26957
|
-
missingSegments.push(
|
|
27652
|
+
missingSegments.push(path6.basename(current));
|
|
26958
27653
|
current = parent;
|
|
26959
27654
|
}
|
|
26960
27655
|
}
|
|
@@ -26969,7 +27664,7 @@ function pathIsStrictlyInside(root, candidate) {
|
|
|
26969
27664
|
if (root.flavor !== candidate.flavor) {
|
|
26970
27665
|
return false;
|
|
26971
27666
|
}
|
|
26972
|
-
const pathImplementation = root.flavor === "windows" ?
|
|
27667
|
+
const pathImplementation = root.flavor === "windows" ? path6.win32 : path6.posix;
|
|
26973
27668
|
const relative = pathImplementation.relative(root.value, candidate.value);
|
|
26974
27669
|
return relative.length > 0 && !pathImplementation.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${pathImplementation.sep}`);
|
|
26975
27670
|
}
|
|
@@ -26988,40 +27683,119 @@ function hasOnlyKeys(value, allowed) {
|
|
|
26988
27683
|
return Object.keys(value).every((key) => allowedKeys.has(key));
|
|
26989
27684
|
}
|
|
26990
27685
|
|
|
26991
|
-
// src/
|
|
26992
|
-
var
|
|
26993
|
-
|
|
26994
|
-
|
|
26995
|
-
|
|
26996
|
-
|
|
26997
|
-
|
|
26998
|
-
|
|
26999
|
-
|
|
27000
|
-
|
|
27001
|
-
|
|
27002
|
-
|
|
27003
|
-
|
|
27004
|
-
|
|
27005
|
-
|
|
27006
|
-
|
|
27007
|
-
|
|
27686
|
+
// src/subagents/CodexSubagentSubscriptions.ts
|
|
27687
|
+
var CodexSubagentSubscriptions = class {
|
|
27688
|
+
constructor(client) {
|
|
27689
|
+
this.client = client;
|
|
27690
|
+
}
|
|
27691
|
+
client;
|
|
27692
|
+
sessions = /* @__PURE__ */ new Map();
|
|
27693
|
+
subscribe(subscription) {
|
|
27694
|
+
const existing = this.sessions.get(subscription.rootSessionId);
|
|
27695
|
+
if (existing) {
|
|
27696
|
+
existing.current = subscription;
|
|
27697
|
+
return;
|
|
27698
|
+
}
|
|
27699
|
+
const session = { current: subscription, children: /* @__PURE__ */ new Set() };
|
|
27700
|
+
this.sessions.set(subscription.rootSessionId, session);
|
|
27701
|
+
this.client.onServerNotification(subscription.rootSessionId, (event) => {
|
|
27702
|
+
this.discover(session, event);
|
|
27703
|
+
session.current.dispatch(event);
|
|
27704
|
+
});
|
|
27705
|
+
this.registerInteractiveHandlers(session, subscription.rootSessionId);
|
|
27706
|
+
}
|
|
27707
|
+
clear(rootSessionId) {
|
|
27708
|
+
for (const childSessionId of this.sessions.get(rootSessionId)?.children ?? []) {
|
|
27709
|
+
this.client.clearThreadHandlers(childSessionId);
|
|
27710
|
+
}
|
|
27711
|
+
this.sessions.delete(rootSessionId);
|
|
27712
|
+
}
|
|
27713
|
+
discover(session, event) {
|
|
27714
|
+
if (event.method !== "item/started" && event.method !== "item/completed") {
|
|
27715
|
+
return;
|
|
27716
|
+
}
|
|
27717
|
+
const item = event.params.item;
|
|
27718
|
+
const childSessionIds = item.type === "collabAgentToolCall" && item.tool === "spawnAgent" ? item.receiverThreadIds : item.type === "subAgentActivity" && item.kind !== "interrupted" && !isRootAgentPath(item.agentPath) ? [item.agentThreadId] : [];
|
|
27719
|
+
for (const childSessionId of childSessionIds) {
|
|
27720
|
+
if (childSessionId.trim() === "") continue;
|
|
27721
|
+
if (childSessionId === session.current.rootSessionId || childSessionId === event.params.threadId || session.children.has(childSessionId)) {
|
|
27722
|
+
continue;
|
|
27723
|
+
}
|
|
27724
|
+
session.children.add(childSessionId);
|
|
27725
|
+
this.client.onServerNotification(childSessionId, (childEvent) => {
|
|
27726
|
+
const eventThreadId = childEvent.params.threadId;
|
|
27727
|
+
if (eventThreadId !== childSessionId) return;
|
|
27728
|
+
this.discover(session, childEvent);
|
|
27729
|
+
if (session.current.supportsSubagents) session.current.dispatch(childEvent);
|
|
27730
|
+
else session.current.enqueueInteraction(this.rootAttributed(childEvent, session.current.rootSessionId));
|
|
27731
|
+
});
|
|
27732
|
+
this.registerInteractiveHandlers(session, childSessionId);
|
|
27733
|
+
}
|
|
27734
|
+
}
|
|
27735
|
+
registerInteractiveHandlers(session, targetSessionId) {
|
|
27736
|
+
this.client.onApprovalRequest(targetSessionId, {
|
|
27737
|
+
handleCommandExecution: 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.handleCommandExecution(
|
|
27743
|
+
{ ...params, threadId: sessionId }
|
|
27744
|
+
);
|
|
27008
27745
|
},
|
|
27009
|
-
{
|
|
27010
|
-
|
|
27011
|
-
|
|
27012
|
-
|
|
27746
|
+
handleFileChange: async (params) => {
|
|
27747
|
+
const current = session.current;
|
|
27748
|
+
await current.waitForRootNotifications();
|
|
27749
|
+
const sessionId = await this.interactionSessionId(current, targetSessionId);
|
|
27750
|
+
if (sessionId === null) return { decision: "cancel" };
|
|
27751
|
+
return await current.approvalHandler.handleFileChange(
|
|
27752
|
+
{ ...params, threadId: sessionId }
|
|
27753
|
+
);
|
|
27754
|
+
},
|
|
27755
|
+
handlePermissionsRequest: async (params) => {
|
|
27756
|
+
const current = session.current;
|
|
27757
|
+
await current.waitForRootNotifications();
|
|
27758
|
+
const sessionId = await this.interactionSessionId(current, targetSessionId);
|
|
27759
|
+
if (sessionId === null) return { permissions: {}, scope: "turn", strictAutoReview: false };
|
|
27760
|
+
return await current.approvalHandler.handlePermissionsRequest(
|
|
27761
|
+
{ ...params, threadId: sessionId }
|
|
27762
|
+
);
|
|
27013
27763
|
}
|
|
27014
|
-
|
|
27015
|
-
|
|
27016
|
-
|
|
27017
|
-
|
|
27018
|
-
|
|
27019
|
-
|
|
27020
|
-
|
|
27021
|
-
|
|
27022
|
-
|
|
27023
|
-
|
|
27024
|
-
}
|
|
27764
|
+
});
|
|
27765
|
+
this.client.onElicitationRequest(targetSessionId, {
|
|
27766
|
+
handleElicitation: async (params) => {
|
|
27767
|
+
const current = session.current;
|
|
27768
|
+
await current.waitForRootNotifications();
|
|
27769
|
+
const sessionId = await this.interactionSessionId(current, targetSessionId);
|
|
27770
|
+
if (sessionId === null) return { action: "cancel", content: null, _meta: null };
|
|
27771
|
+
return await current.elicitationHandler.handleElicitation(
|
|
27772
|
+
{ ...params, threadId: sessionId }
|
|
27773
|
+
);
|
|
27774
|
+
},
|
|
27775
|
+
handleUserInput: async (params) => {
|
|
27776
|
+
const current = session.current;
|
|
27777
|
+
await current.waitForRootNotifications();
|
|
27778
|
+
const sessionId = await this.interactionSessionId(current, targetSessionId);
|
|
27779
|
+
if (sessionId === null) return { answers: {} };
|
|
27780
|
+
return await current.elicitationHandler.handleUserInput(
|
|
27781
|
+
{ ...params, threadId: sessionId }
|
|
27782
|
+
);
|
|
27783
|
+
}
|
|
27784
|
+
});
|
|
27785
|
+
}
|
|
27786
|
+
async interactionSessionId(subscription, targetSessionId) {
|
|
27787
|
+
if (targetSessionId === subscription.rootSessionId) return targetSessionId;
|
|
27788
|
+
if (!subscription.supportsSubagents) return subscription.rootSessionId;
|
|
27789
|
+
return await subscription.waitForChildSession(targetSessionId);
|
|
27790
|
+
}
|
|
27791
|
+
rootAttributed(event, rootSessionId) {
|
|
27792
|
+
if (typeof event.params.threadId !== "string") return event;
|
|
27793
|
+
return {
|
|
27794
|
+
...event,
|
|
27795
|
+
params: { ...event.params, threadId: rootSessionId }
|
|
27796
|
+
};
|
|
27797
|
+
}
|
|
27798
|
+
};
|
|
27025
27799
|
|
|
27026
27800
|
// src/PermissionProfileConfig.ts
|
|
27027
27801
|
var PERMISSION_PROFILE_CONFIG_ENV = "CODEX_ACP_PERMISSION_PROFILE_CONFIG";
|
|
@@ -27066,6 +27840,7 @@ var CodexAcpClient = class {
|
|
|
27066
27840
|
pendingLoginCompleted = null;
|
|
27067
27841
|
pendingAccountUpdated = null;
|
|
27068
27842
|
sessionNotificationQueues = /* @__PURE__ */ new Map();
|
|
27843
|
+
subagents;
|
|
27069
27844
|
skillExtraRoots = [];
|
|
27070
27845
|
configPath = null;
|
|
27071
27846
|
constructor(codexClient, codexConfig, modelProvider, permissionProfileConfig) {
|
|
@@ -27074,6 +27849,7 @@ var CodexAcpClient = class {
|
|
|
27074
27849
|
this.modelProvider = modelProvider ?? null;
|
|
27075
27850
|
this.permissionProfileConfig = permissionProfileConfig;
|
|
27076
27851
|
this.gatewayConfig = null;
|
|
27852
|
+
this.subagents = new CodexSubagentSubscriptions(codexClient);
|
|
27077
27853
|
}
|
|
27078
27854
|
defaultClientInfo = {
|
|
27079
27855
|
name: `${package_default.name}`,
|
|
@@ -27149,16 +27925,31 @@ var CodexAcpClient = class {
|
|
|
27149
27925
|
if (loginResponse.type !== "chatgptDeviceCode") {
|
|
27150
27926
|
return false;
|
|
27151
27927
|
}
|
|
27152
|
-
const
|
|
27928
|
+
const elicitationResponsePromise = Promise.resolve(urlElicitationRequester.elicitUrl({
|
|
27153
27929
|
url: loginResponse.verificationUrl,
|
|
27154
27930
|
message: `Sign in to ChatGPT and enter this code: ${loginResponse.userCode}`,
|
|
27155
27931
|
elicitationId: loginResponse.loginId
|
|
27156
|
-
});
|
|
27157
|
-
|
|
27932
|
+
}));
|
|
27933
|
+
const first = await Promise.race([
|
|
27934
|
+
loginCompletedPromise.then((result2) => ({
|
|
27935
|
+
type: "loginCompleted",
|
|
27936
|
+
result: result2
|
|
27937
|
+
})),
|
|
27938
|
+
elicitationResponsePromise.then((response) => ({
|
|
27939
|
+
type: "elicitationResponse",
|
|
27940
|
+
response
|
|
27941
|
+
}))
|
|
27942
|
+
]);
|
|
27943
|
+
if (first.type === "loginCompleted") {
|
|
27944
|
+
await urlElicitationRequester.completeElicitation();
|
|
27945
|
+
return first.result.success;
|
|
27946
|
+
}
|
|
27947
|
+
if (!CreateElicitationResponse.isAccept(first.response)) {
|
|
27158
27948
|
await this.codexClient.accountLoginCancel({ loginId: loginResponse.loginId });
|
|
27159
27949
|
return false;
|
|
27160
27950
|
}
|
|
27161
27951
|
const result = await loginCompletedPromise;
|
|
27952
|
+
await urlElicitationRequester.completeElicitation();
|
|
27162
27953
|
return result.success;
|
|
27163
27954
|
}
|
|
27164
27955
|
authenticateWithGateway(authRequest) {
|
|
@@ -27374,7 +28165,6 @@ var CodexAcpClient = class {
|
|
|
27374
28165
|
currentModelId,
|
|
27375
28166
|
models: codexModels,
|
|
27376
28167
|
collaborationMode: this.getCollaborationMode(response.thread.id),
|
|
27377
|
-
approvalsReviewer: normalizeApprovalsReviewer(response.approvalsReviewer),
|
|
27378
28168
|
modelProvider: response.modelProvider,
|
|
27379
28169
|
currentServiceTier: response.serviceTier ?? null,
|
|
27380
28170
|
additionalDirectories
|
|
@@ -27403,13 +28193,18 @@ var CodexAcpClient = class {
|
|
|
27403
28193
|
currentModelId,
|
|
27404
28194
|
models: codexModels,
|
|
27405
28195
|
collaborationMode: this.getCollaborationMode(response.thread.id),
|
|
27406
|
-
approvalsReviewer: normalizeApprovalsReviewer(response.approvalsReviewer),
|
|
27407
28196
|
modelProvider: response.modelProvider,
|
|
27408
28197
|
currentServiceTier: response.serviceTier ?? null,
|
|
27409
28198
|
thread: historyResponse.thread,
|
|
27410
28199
|
additionalDirectories
|
|
27411
28200
|
};
|
|
27412
28201
|
}
|
|
28202
|
+
async readSessionThread(sessionId) {
|
|
28203
|
+
return (await this.codexClient.threadRead({
|
|
28204
|
+
threadId: sessionId,
|
|
28205
|
+
includeTurns: true
|
|
28206
|
+
})).thread;
|
|
28207
|
+
}
|
|
27413
28208
|
async newSession(request) {
|
|
27414
28209
|
const additionalDirectories = readAdditionalDirectories(request.cwd, request.additionalDirectories, request._meta);
|
|
27415
28210
|
const initialAgentMode = AgentMode.getInitialAgentMode();
|
|
@@ -27430,7 +28225,6 @@ var CodexAcpClient = class {
|
|
|
27430
28225
|
currentModelId,
|
|
27431
28226
|
models: codexModels,
|
|
27432
28227
|
collaborationMode: this.getCollaborationMode(response.thread.id),
|
|
27433
|
-
approvalsReviewer: normalizeApprovalsReviewer(response.approvalsReviewer),
|
|
27434
28228
|
modelProvider: response.modelProvider,
|
|
27435
28229
|
currentServiceTier: response.serviceTier ?? null,
|
|
27436
28230
|
additionalDirectories
|
|
@@ -27441,6 +28235,7 @@ var CodexAcpClient = class {
|
|
|
27441
28235
|
await this.codexClient.threadUnsubscribe({ threadId: sessionId });
|
|
27442
28236
|
} finally {
|
|
27443
28237
|
this.codexClient.clearThreadHandlers(sessionId);
|
|
28238
|
+
this.subagents.clear(sessionId);
|
|
27444
28239
|
}
|
|
27445
28240
|
}
|
|
27446
28241
|
permissionProfileSelection(agentMode, cwd, additionalDirectories) {
|
|
@@ -27575,7 +28370,7 @@ var CodexAcpClient = class {
|
|
|
27575
28370
|
if (!cwd) {
|
|
27576
28371
|
return;
|
|
27577
28372
|
}
|
|
27578
|
-
const skillExtraRoots = additionalRoots.map((root) =>
|
|
28373
|
+
const skillExtraRoots = additionalRoots.map((root) => path7.join(root, ".agents", "skills"));
|
|
27579
28374
|
if (!arraysEqual(this.skillExtraRoots, skillExtraRoots)) {
|
|
27580
28375
|
await this.codexClient.skillsExtraRootsSet({ extraRoots: skillExtraRoots });
|
|
27581
28376
|
this.skillExtraRoots = skillExtraRoots;
|
|
@@ -27626,33 +28421,21 @@ var CodexAcpClient = class {
|
|
|
27626
28421
|
}
|
|
27627
28422
|
return ModelId.create(defaultModel.id, reasoningEffort ?? defaultModel.defaultReasoningEffort);
|
|
27628
28423
|
}
|
|
27629
|
-
async subscribeToSessionEvents(sessionId, eventHandler, approvalHandler, elicitationHandler) {
|
|
27630
|
-
|
|
28424
|
+
async subscribeToSessionEvents(sessionId, eventHandler, approvalHandler, elicitationHandler, supportsSubagents, observeInteraction, waitForChildSession) {
|
|
28425
|
+
const dispatch = (event) => {
|
|
27631
28426
|
this.enqueueSessionNotification(sessionId, () => eventHandler(event));
|
|
27632
|
-
}
|
|
27633
|
-
this.
|
|
27634
|
-
|
|
27635
|
-
|
|
27636
|
-
|
|
27637
|
-
|
|
27638
|
-
|
|
27639
|
-
await this.waitForSessionNotifications(sessionId);
|
|
27640
|
-
return await approvalHandler.handleFileChange(params);
|
|
27641
|
-
},
|
|
27642
|
-
handlePermissionsRequest: async (params) => {
|
|
27643
|
-
await this.waitForSessionNotifications(sessionId);
|
|
27644
|
-
return await approvalHandler.handlePermissionsRequest(params);
|
|
27645
|
-
}
|
|
27646
|
-
});
|
|
27647
|
-
this.codexClient.onElicitationRequest(sessionId, {
|
|
27648
|
-
handleElicitation: async (params) => {
|
|
27649
|
-
await this.waitForSessionNotifications(sessionId);
|
|
27650
|
-
return await elicitationHandler.handleElicitation(params);
|
|
28427
|
+
};
|
|
28428
|
+
this.subagents.subscribe({
|
|
28429
|
+
rootSessionId: sessionId,
|
|
28430
|
+
supportsSubagents,
|
|
28431
|
+
dispatch,
|
|
28432
|
+
enqueueInteraction: (event) => {
|
|
28433
|
+
this.enqueueSessionNotification(sessionId, () => observeInteraction(event));
|
|
27651
28434
|
},
|
|
27652
|
-
|
|
27653
|
-
|
|
27654
|
-
|
|
27655
|
-
|
|
28435
|
+
approvalHandler,
|
|
28436
|
+
elicitationHandler,
|
|
28437
|
+
waitForRootNotifications: () => this.waitForSessionNotifications(sessionId),
|
|
28438
|
+
waitForChildSession
|
|
27656
28439
|
});
|
|
27657
28440
|
}
|
|
27658
28441
|
async waitForSessionNotifications(sessionId) {
|
|
@@ -27679,7 +28462,7 @@ var CodexAcpClient = class {
|
|
|
27679
28462
|
}
|
|
27680
28463
|
});
|
|
27681
28464
|
}
|
|
27682
|
-
async sendPrompt(request, agentMode,
|
|
28465
|
+
async sendPrompt(request, agentMode, modelId, serviceTier, disableSummary, cwd, additionalDirectories, onTurnStarted, shouldCancel) {
|
|
27683
28466
|
const input = buildPromptItems(request.prompt);
|
|
27684
28467
|
const effort = modelId.effort;
|
|
27685
28468
|
await this.refreshSkills(cwd, additionalDirectories);
|
|
@@ -27695,7 +28478,7 @@ var CodexAcpClient = class {
|
|
|
27695
28478
|
threadId: request.sessionId,
|
|
27696
28479
|
input,
|
|
27697
28480
|
approvalPolicy: agentMode.approvalPolicy,
|
|
27698
|
-
approvalsReviewer,
|
|
28481
|
+
approvalsReviewer: agentMode.approvalsReviewer,
|
|
27699
28482
|
...sandboxSelection,
|
|
27700
28483
|
summary: disableSummary ? "none" : "auto",
|
|
27701
28484
|
effort,
|
|
@@ -27750,22 +28533,9 @@ var CodexAcpClient = class {
|
|
|
27750
28533
|
});
|
|
27751
28534
|
const outcome = await budget.wait(turnPromise);
|
|
27752
28535
|
auditTurnCompleted = true;
|
|
27753
|
-
const thread = await budget.wait(this.codexClient.threadRead({
|
|
27754
|
-
threadId: forkThreadId,
|
|
27755
|
-
includeTurns: true
|
|
27756
|
-
}));
|
|
27757
|
-
const completedTurn = thread.thread.turns.find(
|
|
27758
|
-
(turn) => turn.id === outcome.turn.id
|
|
27759
|
-
);
|
|
27760
|
-
if (completedTurn === void 0) {
|
|
27761
|
-
throw new AgentFileChangeReportError(
|
|
27762
|
-
"notReported",
|
|
27763
|
-
"The completed audit turn was not present in thread history"
|
|
27764
|
-
);
|
|
27765
|
-
}
|
|
27766
28536
|
return createReportedAgentFileChangeReport(
|
|
27767
28537
|
params.requestId,
|
|
27768
|
-
|
|
28538
|
+
outcome.turn,
|
|
27769
28539
|
params.workspace
|
|
27770
28540
|
);
|
|
27771
28541
|
} catch (error51) {
|
|
@@ -27782,7 +28552,7 @@ var CodexAcpClient = class {
|
|
|
27782
28552
|
return createUnavailableAgentFileChangeReport(params.requestId, error51.reason);
|
|
27783
28553
|
}
|
|
27784
28554
|
if (error51 instanceof AgentFileChangeReportError) {
|
|
27785
|
-
logger.
|
|
28555
|
+
logger.error("Agent file-change report unavailable", error51);
|
|
27786
28556
|
return createUnavailableAgentFileChangeReport(params.requestId, error51.reason);
|
|
27787
28557
|
}
|
|
27788
28558
|
logger.error("Agent file-change report failed", error51);
|
|
@@ -28080,8 +28850,8 @@ function formatUriAsLink(name, uri) {
|
|
|
28080
28850
|
return `[@${name}](${uri})`;
|
|
28081
28851
|
}
|
|
28082
28852
|
if (uri.startsWith("file://")) {
|
|
28083
|
-
const
|
|
28084
|
-
const fileName =
|
|
28853
|
+
const path9 = uri.replace("file://", "");
|
|
28854
|
+
const fileName = path9.split("/").pop() ?? path9;
|
|
28085
28855
|
return `[@${fileName}](${uri})`;
|
|
28086
28856
|
}
|
|
28087
28857
|
return uri;
|
|
@@ -28111,7 +28881,7 @@ function readAdditionalDirectories(cwd, additionalDirectories, meta3) {
|
|
|
28111
28881
|
if (directory.length === 0) {
|
|
28112
28882
|
throw RequestError.invalidParams(void 0, "additionalDirectories entries must not be empty");
|
|
28113
28883
|
}
|
|
28114
|
-
if (!
|
|
28884
|
+
if (!path7.isAbsolute(directory)) {
|
|
28115
28885
|
throw RequestError.invalidParams(void 0, "additionalDirectories entries must be absolute paths");
|
|
28116
28886
|
}
|
|
28117
28887
|
if (!seen.has(directory)) {
|
|
@@ -28269,11 +29039,11 @@ var CodexAppServerClient = class {
|
|
|
28269
29039
|
});
|
|
28270
29040
|
this.connection.onRequest(PermissionsApprovalRequest, async (params) => {
|
|
28271
29041
|
if (this.isStaleTurn(params.threadId, params.turnId)) {
|
|
28272
|
-
return { permissions: {}, scope: "turn", strictAutoReview:
|
|
29042
|
+
return { permissions: {}, scope: "turn", strictAutoReview: false };
|
|
28273
29043
|
}
|
|
28274
29044
|
const handler = this.approvalHandlers.get(params.threadId);
|
|
28275
29045
|
if (!handler) {
|
|
28276
|
-
return { permissions: {}, scope: "turn", strictAutoReview:
|
|
29046
|
+
return { permissions: {}, scope: "turn", strictAutoReview: false };
|
|
28277
29047
|
}
|
|
28278
29048
|
return await handler.handlePermissionsRequest(params);
|
|
28279
29049
|
});
|
|
@@ -29036,11 +29806,14 @@ var CodexCommands = class {
|
|
|
29036
29806
|
this.runWithProcessCheck = runWithProcessCheck;
|
|
29037
29807
|
this.onLogout = onLogout;
|
|
29038
29808
|
}
|
|
29039
|
-
async publish(sessionState) {
|
|
29809
|
+
async publish(sessionState, shouldPublish = () => true) {
|
|
29040
29810
|
try {
|
|
29811
|
+
if (!shouldPublish()) {
|
|
29812
|
+
return;
|
|
29813
|
+
}
|
|
29041
29814
|
const skillsResponse = await this.runWithProcessCheck(() => this.codexAcpClient.listSkills(this.createSkillsListParams(sessionState)));
|
|
29042
29815
|
const availableCommands = this.buildAvailableCommands(skillsResponse?.data ?? []);
|
|
29043
|
-
if (availableCommands.length === 0) {
|
|
29816
|
+
if (availableCommands.length === 0 || !shouldPublish()) {
|
|
29044
29817
|
return;
|
|
29045
29818
|
}
|
|
29046
29819
|
const session = new ACPSessionConnection(this.connection, sessionState.sessionId);
|
|
@@ -29049,7 +29822,9 @@ var CodexCommands = class {
|
|
|
29049
29822
|
availableCommands
|
|
29050
29823
|
});
|
|
29051
29824
|
} catch (err) {
|
|
29052
|
-
|
|
29825
|
+
if (shouldPublish()) {
|
|
29826
|
+
logger.error(`Failed to publish available commands for session ${sessionState.sessionId}`, err);
|
|
29827
|
+
}
|
|
29053
29828
|
}
|
|
29054
29829
|
}
|
|
29055
29830
|
createSkillsListParams(sessionState) {
|
|
@@ -29508,7 +30283,7 @@ var SteeringQueue = class {
|
|
|
29508
30283
|
|
|
29509
30284
|
// src/ResponseItemHistoryFallback.ts
|
|
29510
30285
|
import { readFile as readFile2 } from "node:fs/promises";
|
|
29511
|
-
import
|
|
30286
|
+
import path8 from "node:path";
|
|
29512
30287
|
function historyFallbackUpdateKey(update) {
|
|
29513
30288
|
switch (update.sessionUpdate) {
|
|
29514
30289
|
case "user_message_chunk":
|
|
@@ -29748,8 +30523,8 @@ function imageBlocks(images) {
|
|
|
29748
30523
|
return [{ type: "text", text: `[@image](${image})` }];
|
|
29749
30524
|
}
|
|
29750
30525
|
const record2 = asRecord2(image);
|
|
29751
|
-
const
|
|
29752
|
-
return
|
|
30526
|
+
const path9 = record2 ? stringValue(record2["path"]) ?? stringValue(record2["url"]) : null;
|
|
30527
|
+
return path9 ? [{ type: "text", text: `[@image](${path9})` }] : [];
|
|
29753
30528
|
});
|
|
29754
30529
|
}
|
|
29755
30530
|
function contentBlocksFromResponseContent(content) {
|
|
@@ -30381,10 +31156,10 @@ function baseCommandName(commandName) {
|
|
|
30381
31156
|
return commandName.split(/[\\/]/).pop() ?? commandName;
|
|
30382
31157
|
}
|
|
30383
31158
|
function absolutizePath(cwd, targetPath) {
|
|
30384
|
-
if (
|
|
31159
|
+
if (path8.isAbsolute(targetPath) || cwd.length === 0) {
|
|
30385
31160
|
return targetPath;
|
|
30386
31161
|
}
|
|
30387
|
-
return
|
|
31162
|
+
return path8.join(cwd, targetPath);
|
|
30388
31163
|
}
|
|
30389
31164
|
function withTerminalContent(event, terminalId, cwd) {
|
|
30390
31165
|
const { rawInput, ...eventWithoutRawInput } = event;
|
|
@@ -30542,16 +31317,7 @@ function clientSupportsPlanUpdates(clientCapabilities) {
|
|
|
30542
31317
|
// src/CodexAcpServer.ts
|
|
30543
31318
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
30544
31319
|
import { once } from "node:events";
|
|
30545
|
-
var IMPLEMENT_PLAN_OPTION_ID = "implement_plan";
|
|
30546
|
-
var REVISE_PLAN_OPTION_ID = "revise_plan";
|
|
30547
31320
|
var CODEX_PROCESS_EXITED_ERROR_CODE = 1001;
|
|
30548
|
-
function clientSupportsAirCapability(capabilities, capability) {
|
|
30549
|
-
const jetbrains = capabilities?._meta?.[JETBRAINS_META_KEY];
|
|
30550
|
-
const air = jetbrains?.[AIR_META_KEY];
|
|
30551
|
-
const version2 = air?.[AIR_EXTENSION_VERSION_KEY];
|
|
30552
|
-
const supported = air?.[AIR_EXTENSION_CAPABILITIES_KEY];
|
|
30553
|
-
return typeof version2 === "number" && Number.isInteger(version2) && version2 >= AIR_EXTENSION_VERSION && Array.isArray(supported) && supported.includes(capability);
|
|
30554
|
-
}
|
|
30555
31321
|
function clientSupportsTypedSessionFailures(capabilities) {
|
|
30556
31322
|
return clientSupportsAirCapability(capabilities, AIR_SESSION_FAILURE_KEY);
|
|
30557
31323
|
}
|
|
@@ -30584,6 +31350,7 @@ var CodexAcpServer = class _CodexAcpServer {
|
|
|
30584
31350
|
sessionGenerations;
|
|
30585
31351
|
sessionOpenGenerations;
|
|
30586
31352
|
goalControlGenerations;
|
|
31353
|
+
permissionLifecycleContexts;
|
|
30587
31354
|
codexProcessState;
|
|
30588
31355
|
initializeRequest = null;
|
|
30589
31356
|
providerUpdate = null;
|
|
@@ -30597,6 +31364,7 @@ var CodexAcpServer = class _CodexAcpServer {
|
|
|
30597
31364
|
this.sessionGenerations = /* @__PURE__ */ new Map();
|
|
30598
31365
|
this.sessionOpenGenerations = /* @__PURE__ */ new Map();
|
|
30599
31366
|
this.goalControlGenerations = /* @__PURE__ */ new Map();
|
|
31367
|
+
this.permissionLifecycleContexts = /* @__PURE__ */ new WeakMap();
|
|
30600
31368
|
this.connection = connection;
|
|
30601
31369
|
this.codexAcpClient = codexAcpClient;
|
|
30602
31370
|
this.defaultAuthRequest = defaultAuthRequest ?? null;
|
|
@@ -30627,6 +31395,14 @@ var CodexAcpServer = class _CodexAcpServer {
|
|
|
30627
31395
|
this.terminalOutputMode = resolveTerminalOutputMode(_params.clientCapabilities);
|
|
30628
31396
|
this.booleanConfigOptionsSupported = clientSupportsBooleanConfigOptions(_params.clientCapabilities);
|
|
30629
31397
|
await this.runWithProcessCheck(() => this.codexAcpClient.initialize(_params));
|
|
31398
|
+
const sessionCapabilities = {
|
|
31399
|
+
resume: {},
|
|
31400
|
+
list: {},
|
|
31401
|
+
close: {},
|
|
31402
|
+
delete: {},
|
|
31403
|
+
additionalDirectories: {},
|
|
31404
|
+
subagents: {}
|
|
31405
|
+
};
|
|
30630
31406
|
return {
|
|
30631
31407
|
protocolVersion: PROTOCOL_VERSION,
|
|
30632
31408
|
agentInfo: {
|
|
@@ -30644,13 +31420,7 @@ var CodexAcpServer = class _CodexAcpServer {
|
|
|
30644
31420
|
embeddedContext: true,
|
|
30645
31421
|
image: true
|
|
30646
31422
|
},
|
|
30647
|
-
sessionCapabilities
|
|
30648
|
-
resume: {},
|
|
30649
|
-
list: {},
|
|
30650
|
-
close: {},
|
|
30651
|
-
delete: {},
|
|
30652
|
-
additionalDirectories: {}
|
|
30653
|
-
},
|
|
31423
|
+
sessionCapabilities,
|
|
30654
31424
|
mcpCapabilities: {
|
|
30655
31425
|
acp: false,
|
|
30656
31426
|
http: true,
|
|
@@ -30672,7 +31442,8 @@ var CodexAcpServer = class _CodexAcpServer {
|
|
|
30672
31442
|
[AIR_EXTENSION_VERSION_KEY]: AIR_EXTENSION_VERSION,
|
|
30673
31443
|
[AIR_EXTENSION_CAPABILITIES_KEY]: [
|
|
30674
31444
|
AIR_SESSION_FAILURE_KEY,
|
|
30675
|
-
AIR_AGENT_FILE_CHANGE_REPORT_KEY
|
|
31445
|
+
AIR_AGENT_FILE_CHANGE_REPORT_KEY,
|
|
31446
|
+
AIR_NATIVE_SUBAGENT_SESSIONS_KEY
|
|
30676
31447
|
]
|
|
30677
31448
|
}
|
|
30678
31449
|
}
|
|
@@ -30724,7 +31495,7 @@ var CodexAcpServer = class _CodexAcpServer {
|
|
|
30724
31495
|
}
|
|
30725
31496
|
} else if (methodRequest.params.action === "pause") {
|
|
30726
31497
|
const goal = await this.runWithProcessCheck(() => this.codexAcpClient.setGoalStatus(sessionState.sessionId, "paused"));
|
|
30727
|
-
if (this.
|
|
31498
|
+
if (this.sessionPublishIsCurrent(sessionState, sessionGeneration)) {
|
|
30728
31499
|
await this.publishGoalSnapshot(sessionState, toThreadGoalSnapshot(goal), false);
|
|
30729
31500
|
}
|
|
30730
31501
|
} else if (methodRequest.params.action === "resume") {
|
|
@@ -30736,7 +31507,7 @@ var CodexAcpServer = class _CodexAcpServer {
|
|
|
30736
31507
|
updatedGoal = goal;
|
|
30737
31508
|
}
|
|
30738
31509
|
));
|
|
30739
|
-
if (updatedGoal !== null && this.
|
|
31510
|
+
if (updatedGoal !== null && this.sessionPublishIsCurrent(sessionState, sessionGeneration)) {
|
|
30740
31511
|
await this.publishGoalSnapshot(sessionState, toThreadGoalSnapshot(updatedGoal), false);
|
|
30741
31512
|
}
|
|
30742
31513
|
if (turnCompleted === null && updatedGoal !== null) {
|
|
@@ -30749,7 +31520,7 @@ var CodexAcpServer = class _CodexAcpServer {
|
|
|
30749
31520
|
}
|
|
30750
31521
|
} else if (methodRequest.params.action === "clear") {
|
|
30751
31522
|
await this.runWithProcessCheck(() => this.codexAcpClient.clearGoal(sessionState.sessionId));
|
|
30752
|
-
if (this.
|
|
31523
|
+
if (this.sessionPublishIsCurrent(sessionState, sessionGeneration)) {
|
|
30753
31524
|
await this.publishGoalSnapshot(sessionState, null, false);
|
|
30754
31525
|
}
|
|
30755
31526
|
}
|
|
@@ -30907,7 +31678,6 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30907
31678
|
supportedReasoningEfforts: currentModel?.supportedReasoningEfforts ?? [],
|
|
30908
31679
|
supportedInputModalities: currentModel?.inputModalities ?? ["text", "image"],
|
|
30909
31680
|
agentMode: AgentMode.getInitialAgentMode(),
|
|
30910
|
-
approvalsReviewer: sessionMetadata.approvalsReviewer,
|
|
30911
31681
|
collaborationMode: sessionMetadata.collaborationMode,
|
|
30912
31682
|
currentTurnId: null,
|
|
30913
31683
|
lastTokenUsage: null,
|
|
@@ -30926,7 +31696,12 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30926
31696
|
terminalOutputMode: this.terminalOutputMode,
|
|
30927
31697
|
goalRevision: 0,
|
|
30928
31698
|
sessionTitle: null,
|
|
30929
|
-
sessionTitleSource: "sessionId" in request ? "unknown" : "unset"
|
|
31699
|
+
sessionTitleSource: "sessionId" in request ? "unknown" : "unset",
|
|
31700
|
+
subagents: new CodexSubagentEventRouter(
|
|
31701
|
+
sessionId,
|
|
31702
|
+
clientSupportsSubagents(this.clientCapabilities),
|
|
31703
|
+
new ACPSessionConnection(this.connection, sessionId)
|
|
31704
|
+
)
|
|
30930
31705
|
};
|
|
30931
31706
|
this.sessions.set(sessionId, sessionState);
|
|
30932
31707
|
resumeSubscribed = false;
|
|
@@ -30937,7 +31712,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30937
31712
|
});
|
|
30938
31713
|
this.publishMcpStartupStatusAsync(sessionId);
|
|
30939
31714
|
}
|
|
30940
|
-
this.publishAvailableCommandsAsync(sessionState);
|
|
31715
|
+
this.publishAvailableCommandsAsync(sessionState, sessionGeneration);
|
|
30941
31716
|
if ("sessionId" in request) {
|
|
30942
31717
|
this.publishCurrentGoalAsync(sessionState, sessionGeneration);
|
|
30943
31718
|
}
|
|
@@ -31120,12 +31895,24 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
31120
31895
|
if (requestId == null || !clientSupportsUrlElicitation(this.clientCapabilities)) {
|
|
31121
31896
|
return void 0;
|
|
31122
31897
|
}
|
|
31898
|
+
let elicitationId = null;
|
|
31123
31899
|
return {
|
|
31124
|
-
elicitUrl: (request) =>
|
|
31125
|
-
|
|
31126
|
-
|
|
31127
|
-
|
|
31128
|
-
|
|
31900
|
+
elicitUrl: (request) => {
|
|
31901
|
+
elicitationId = request.elicitationId;
|
|
31902
|
+
return this.connection.request(methods.client.elicitation.create, {
|
|
31903
|
+
mode: "url",
|
|
31904
|
+
requestId,
|
|
31905
|
+
...request
|
|
31906
|
+
});
|
|
31907
|
+
},
|
|
31908
|
+
completeElicitation: async () => {
|
|
31909
|
+
if (elicitationId === null) {
|
|
31910
|
+
return;
|
|
31911
|
+
}
|
|
31912
|
+
await this.connection.notify(methods.client.elicitation.complete, {
|
|
31913
|
+
elicitationId
|
|
31914
|
+
});
|
|
31915
|
+
}
|
|
31129
31916
|
};
|
|
31130
31917
|
}
|
|
31131
31918
|
async logout(_params) {
|
|
@@ -31279,9 +32066,6 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
31279
32066
|
case MODE_CONFIG_ID:
|
|
31280
32067
|
await this.applyModeChange(sessionState, this.stringConfigValue(params));
|
|
31281
32068
|
break;
|
|
31282
|
-
case APPROVALS_REVIEWER_CONFIG_ID:
|
|
31283
|
-
this.applyApprovalsReviewerChange(sessionState, this.stringConfigValue(params));
|
|
31284
|
-
break;
|
|
31285
32069
|
case COLLABORATION_MODE_CONFIG_ID:
|
|
31286
32070
|
await this.applyCollaborationModeChange(sessionState, this.stringConfigValue(params));
|
|
31287
32071
|
break;
|
|
@@ -31323,13 +32107,6 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
31323
32107
|
);
|
|
31324
32108
|
sessionState.agentMode = newMode;
|
|
31325
32109
|
}
|
|
31326
|
-
applyApprovalsReviewerChange(sessionState, value) {
|
|
31327
|
-
const approvalsReviewer = parseApprovalsReviewer(value);
|
|
31328
|
-
if (approvalsReviewer === null) {
|
|
31329
|
-
throw RequestError.invalidParams();
|
|
31330
|
-
}
|
|
31331
|
-
sessionState.approvalsReviewer = approvalsReviewer;
|
|
31332
|
-
}
|
|
31333
32110
|
async applyCollaborationModeChange(sessionState, value) {
|
|
31334
32111
|
const mode = parseCollaborationMode(value);
|
|
31335
32112
|
if (mode === null) {
|
|
@@ -31533,7 +32310,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
31533
32310
|
sessionId: sessionState.sessionId,
|
|
31534
32311
|
prompt: GOAL_CONTINUATION_PROMPT
|
|
31535
32312
|
}, "Goal continuation", async () => {
|
|
31536
|
-
if (!this.
|
|
32313
|
+
if (!this.sessionPublishIsCurrent(sessionState, sessionGeneration) || this.goalControlGenerations.get(sessionState.sessionId) !== goalControlGeneration) {
|
|
31537
32314
|
return false;
|
|
31538
32315
|
}
|
|
31539
32316
|
const currentGoal = await this.runWithProcessCheck(() => this.codexAcpClient.getGoal(sessionState.sessionId));
|
|
@@ -31617,7 +32394,6 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
31617
32394
|
const currentModelId = ModelId.fromString(sessionState.currentModelId);
|
|
31618
32395
|
const configOptions = [
|
|
31619
32396
|
sessionState.agentMode.toConfigOption(),
|
|
31620
|
-
createApprovalsReviewerConfigOption(sessionState.approvalsReviewer),
|
|
31621
32397
|
createCollaborationModeConfigOption(sessionState.collaborationMode),
|
|
31622
32398
|
createModelConfigOption(sessionState.availableModels, currentModelId.model)
|
|
31623
32399
|
];
|
|
@@ -31645,8 +32421,14 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
31645
32421
|
isSessionConfigEnabled() {
|
|
31646
32422
|
return !isJetBrains2026_1Client(this.clientInfo);
|
|
31647
32423
|
}
|
|
31648
|
-
publishAvailableCommandsAsync(sessionState) {
|
|
31649
|
-
void this.
|
|
32424
|
+
publishAvailableCommandsAsync(sessionState, sessionGeneration) {
|
|
32425
|
+
void this.publishAvailableCommands(sessionState, sessionGeneration);
|
|
32426
|
+
}
|
|
32427
|
+
async publishAvailableCommands(sessionState, sessionGeneration) {
|
|
32428
|
+
await this.availableCommands.publish(
|
|
32429
|
+
sessionState,
|
|
32430
|
+
() => this.sessionPublishIsCurrent(sessionState, sessionGeneration)
|
|
32431
|
+
);
|
|
31650
32432
|
}
|
|
31651
32433
|
publishCurrentGoalAsync(sessionState, sessionGeneration) {
|
|
31652
32434
|
void this.publishCurrentGoalBestEffort(sessionState, sessionGeneration, true);
|
|
@@ -31662,12 +32444,12 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
31662
32444
|
const requestRevision = ++sessionState.goalRevision;
|
|
31663
32445
|
const goal = await this.runWithProcessCheck(() => this.codexAcpClient.getGoal(sessionState.sessionId));
|
|
31664
32446
|
const snapshot = goal === null ? null : toThreadGoalSnapshot(goal);
|
|
31665
|
-
if (!this.
|
|
32447
|
+
if (!this.sessionPublishIsCurrent(sessionState, sessionGeneration) || sessionState.goalRevision !== requestRevision) {
|
|
31666
32448
|
return;
|
|
31667
32449
|
}
|
|
31668
32450
|
await this.publishGoalSnapshot(sessionState, snapshot, force, false);
|
|
31669
32451
|
}
|
|
31670
|
-
|
|
32452
|
+
sessionPublishIsCurrent(sessionState, sessionGeneration) {
|
|
31671
32453
|
return this.sessions.get(sessionState.sessionId) === sessionState && this.getSessionGeneration(sessionState.sessionId) === sessionGeneration && !this.sessionIsClosing(sessionState.sessionId);
|
|
31672
32454
|
}
|
|
31673
32455
|
async publishGoalSnapshot(sessionState, snapshot, force, incrementRevision = true) {
|
|
@@ -31751,7 +32533,6 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
31751
32533
|
supportedReasoningEfforts: currentModel?.supportedReasoningEfforts ?? [],
|
|
31752
32534
|
supportedInputModalities: currentModel?.inputModalities ?? ["text", "image"],
|
|
31753
32535
|
agentMode: AgentMode.getInitialAgentMode(),
|
|
31754
|
-
approvalsReviewer: sessionMetadata.approvalsReviewer,
|
|
31755
32536
|
collaborationMode: sessionMetadata.collaborationMode,
|
|
31756
32537
|
currentTurnId: null,
|
|
31757
32538
|
lastTokenUsage: null,
|
|
@@ -31770,7 +32551,12 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
31770
32551
|
terminalOutputMode: this.terminalOutputMode,
|
|
31771
32552
|
goalRevision: 0,
|
|
31772
32553
|
sessionTitle: null,
|
|
31773
|
-
sessionTitleSource: "unset"
|
|
32554
|
+
sessionTitleSource: "unset",
|
|
32555
|
+
subagents: new CodexSubagentEventRouter(
|
|
32556
|
+
sessionId,
|
|
32557
|
+
clientSupportsSubagents(this.clientCapabilities),
|
|
32558
|
+
new ACPSessionConnection(this.connection, sessionId)
|
|
32559
|
+
)
|
|
31774
32560
|
};
|
|
31775
32561
|
this.sessions.set(sessionId, sessionState);
|
|
31776
32562
|
subscribed = false;
|
|
@@ -31781,7 +32567,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
31781
32567
|
});
|
|
31782
32568
|
this.publishMcpStartupStatusAsync(sessionId);
|
|
31783
32569
|
}
|
|
31784
|
-
await this.
|
|
32570
|
+
await this.publishAvailableCommands(sessionState, requestedSessionGeneration);
|
|
31785
32571
|
await this.publishCurrentGoalBestEffort(sessionState, requestedSessionGeneration, true);
|
|
31786
32572
|
const sessionModelState = this.createModelState(models, currentModelId);
|
|
31787
32573
|
const sessionModeState = sessionState.agentMode.toSessionModeState();
|
|
@@ -31796,6 +32582,16 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
31796
32582
|
const session = new ACPSessionConnection(this.connection, sessionId);
|
|
31797
32583
|
const sessionState = this.getSessionState(sessionId);
|
|
31798
32584
|
await this.publishThreadHistoryTitle(session, sessionState, thread);
|
|
32585
|
+
if (clientSupportsSubagents(this.clientCapabilities)) {
|
|
32586
|
+
await this.streamNativeThreadHistory(
|
|
32587
|
+
sessionId,
|
|
32588
|
+
thread,
|
|
32589
|
+
sessionState,
|
|
32590
|
+
/* @__PURE__ */ new Set([sessionId]),
|
|
32591
|
+
/* @__PURE__ */ new Map([[sessionId, thread]])
|
|
32592
|
+
);
|
|
32593
|
+
return;
|
|
32594
|
+
}
|
|
31799
32595
|
const responseItemFallbackUpdates = await createResponseItemHistoryFallbackUpdates(
|
|
31800
32596
|
thread,
|
|
31801
32597
|
sessionState.terminalOutputMode
|
|
@@ -31812,6 +32608,93 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
31812
32608
|
await session.update(update);
|
|
31813
32609
|
}
|
|
31814
32610
|
}
|
|
32611
|
+
async streamNativeThreadHistory(sessionId, thread, sessionState, ancestry, threadCache) {
|
|
32612
|
+
const session = new ACPSessionConnection(this.connection, sessionId);
|
|
32613
|
+
const announced = /* @__PURE__ */ new Map();
|
|
32614
|
+
for (const turn of thread.turns) {
|
|
32615
|
+
for (const item of turn.items) {
|
|
32616
|
+
if (item.type === "subAgentActivity") {
|
|
32617
|
+
const activityKind = item.kind;
|
|
32618
|
+
if (activityKind === "started") {
|
|
32619
|
+
const previous = announced.get(item.agentThreadId);
|
|
32620
|
+
if (previous && !previous.terminal) continue;
|
|
32621
|
+
const generation = (previous?.generation ?? 0) + 1;
|
|
32622
|
+
const childSessionId = generation === 1 ? item.agentThreadId : `${item.agentThreadId}:generation:${generation}`;
|
|
32623
|
+
const name = nameFromAgentPath(item.agentPath, `Agent ${item.agentThreadId.slice(-8)}`);
|
|
32624
|
+
await session.update({
|
|
32625
|
+
sessionUpdate: "subagent_spawned",
|
|
32626
|
+
subagentSessionId: childSessionId,
|
|
32627
|
+
name,
|
|
32628
|
+
task: `Delegated task for ${name}`,
|
|
32629
|
+
capabilities: {}
|
|
32630
|
+
});
|
|
32631
|
+
announced.set(item.agentThreadId, { generation, sessionId: childSessionId, terminal: false });
|
|
32632
|
+
if (!ancestry.has(item.agentThreadId)) {
|
|
32633
|
+
let child = threadCache.get(item.agentThreadId);
|
|
32634
|
+
if (child === void 0) {
|
|
32635
|
+
try {
|
|
32636
|
+
child = await this.codexAcpClient.readSessionThread(item.agentThreadId);
|
|
32637
|
+
threadCache.set(item.agentThreadId, child);
|
|
32638
|
+
} catch (error51) {
|
|
32639
|
+
threadCache.set(item.agentThreadId, null);
|
|
32640
|
+
logger.error(`Failed to read subagent history ${item.agentThreadId}`, error51);
|
|
32641
|
+
child = null;
|
|
32642
|
+
}
|
|
32643
|
+
}
|
|
32644
|
+
const childTurn = child?.turns[generation - 1];
|
|
32645
|
+
if (child && childTurn) {
|
|
32646
|
+
await this.streamNativeThreadHistory(
|
|
32647
|
+
childSessionId,
|
|
32648
|
+
{ ...child, turns: [childTurn] },
|
|
32649
|
+
sessionState,
|
|
32650
|
+
/* @__PURE__ */ new Set([...ancestry, item.agentThreadId]),
|
|
32651
|
+
threadCache
|
|
32652
|
+
);
|
|
32653
|
+
}
|
|
32654
|
+
}
|
|
32655
|
+
} else if (activityKind === "completed" || activityKind === "interrupted") {
|
|
32656
|
+
const child = announced.get(item.agentThreadId);
|
|
32657
|
+
if (!child) {
|
|
32658
|
+
const name = nameFromAgentPath(item.agentPath, `Agent ${item.agentThreadId.slice(-8)}`);
|
|
32659
|
+
await session.update({
|
|
32660
|
+
sessionUpdate: "subagent_spawned",
|
|
32661
|
+
subagentSessionId: item.agentThreadId,
|
|
32662
|
+
name,
|
|
32663
|
+
task: `Delegated task for ${name}`,
|
|
32664
|
+
capabilities: {}
|
|
32665
|
+
});
|
|
32666
|
+
announced.set(item.agentThreadId, {
|
|
32667
|
+
generation: 1,
|
|
32668
|
+
sessionId: item.agentThreadId,
|
|
32669
|
+
terminal: false
|
|
32670
|
+
});
|
|
32671
|
+
continue;
|
|
32672
|
+
}
|
|
32673
|
+
if (child.terminal) continue;
|
|
32674
|
+
await session.update({
|
|
32675
|
+
sessionUpdate: "subagent_state_update",
|
|
32676
|
+
subagentSessionId: child.sessionId,
|
|
32677
|
+
state: activityKind === "completed" ? "completed" : "cancelled"
|
|
32678
|
+
});
|
|
32679
|
+
child.terminal = true;
|
|
32680
|
+
}
|
|
32681
|
+
continue;
|
|
32682
|
+
}
|
|
32683
|
+
if (item.type === "collabAgentToolCall") continue;
|
|
32684
|
+
for (const update of await this.createHistoryUpdates(item, sessionState)) {
|
|
32685
|
+
await session.update(update);
|
|
32686
|
+
}
|
|
32687
|
+
}
|
|
32688
|
+
}
|
|
32689
|
+
for (const child of announced.values()) {
|
|
32690
|
+
if (child.terminal) continue;
|
|
32691
|
+
await session.update({
|
|
32692
|
+
sessionUpdate: "subagent_state_update",
|
|
32693
|
+
subagentSessionId: child.sessionId,
|
|
32694
|
+
state: "disconnected"
|
|
32695
|
+
});
|
|
32696
|
+
}
|
|
32697
|
+
}
|
|
31815
32698
|
async publishThreadHistoryTitle(session, sessionState, thread) {
|
|
31816
32699
|
const explicitTitle = this.normalizeSessionTitle(thread.name);
|
|
31817
32700
|
if (explicitTitle) {
|
|
@@ -32016,8 +32899,8 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
32016
32899
|
return `[@${name}](${uri})`;
|
|
32017
32900
|
}
|
|
32018
32901
|
if (uri.startsWith("file://")) {
|
|
32019
|
-
const
|
|
32020
|
-
const fileName =
|
|
32902
|
+
const path9 = uri.replace("file://", "");
|
|
32903
|
+
const fileName = path9.split("/").pop() ?? path9;
|
|
32021
32904
|
return `[@${fileName}](${uri})`;
|
|
32022
32905
|
}
|
|
32023
32906
|
return uri;
|
|
@@ -32029,6 +32912,13 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
32029
32912
|
}
|
|
32030
32913
|
return sessionState;
|
|
32031
32914
|
}
|
|
32915
|
+
permissionLifecycleContext(sessionState) {
|
|
32916
|
+
const existing = this.permissionLifecycleContexts.get(sessionState);
|
|
32917
|
+
if (existing) return existing;
|
|
32918
|
+
const context = new PermissionLifecycleContext(sessionState);
|
|
32919
|
+
this.permissionLifecycleContexts.set(sessionState, context);
|
|
32920
|
+
return context;
|
|
32921
|
+
}
|
|
32032
32922
|
resolveSessionMcpServers(mcpServers, recoverFromStartup) {
|
|
32033
32923
|
const requestedServerNames = getRequestedMcpServerNames(mcpServers);
|
|
32034
32924
|
if (requestedServerNames.length > 0) {
|
|
@@ -32276,6 +33166,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
32276
33166
|
const agentFileChangeReportRequest = clientSupportsAgentFileChangeReports(this.clientCapabilities) ? parseAgentFileChangeReportRequest(params._meta) : null;
|
|
32277
33167
|
let agentFileChangeReportTurnId = null;
|
|
32278
33168
|
let agentFileChangeReportUnavailableReason = "providerError";
|
|
33169
|
+
let promptWasCancelled = false;
|
|
32279
33170
|
let recoverableSessionFailure = sessionState.sessionFailure;
|
|
32280
33171
|
const promptStartTotalTokenUsage = sessionState.totalTokenUsage;
|
|
32281
33172
|
sessionState.currentTurnId = null;
|
|
@@ -32300,6 +33191,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
32300
33191
|
}
|
|
32301
33192
|
};
|
|
32302
33193
|
const cancelledPromptResponse = () => {
|
|
33194
|
+
promptWasCancelled = true;
|
|
32303
33195
|
agentFileChangeReportTurnId = null;
|
|
32304
33196
|
agentFileChangeReportUnavailableReason = "cancelled";
|
|
32305
33197
|
return this.cancelledPromptResponse(sessionState, promptStartTotalTokenUsage);
|
|
@@ -32310,32 +33202,46 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
32310
33202
|
sessionState,
|
|
32311
33203
|
clientSupportsPlanUpdates(this.clientCapabilities),
|
|
32312
33204
|
clientSupportsTypedSessionFailures(this.clientCapabilities),
|
|
32313
|
-
this.sessionFailureEpoch
|
|
33205
|
+
this.sessionFailureEpoch,
|
|
33206
|
+
sessionState.subagents
|
|
32314
33207
|
);
|
|
32315
33208
|
eventHandler = promptEventHandler;
|
|
32316
|
-
const
|
|
33209
|
+
const permissionLifecycle = this.permissionLifecycleContext(sessionState);
|
|
33210
|
+
const permissionContext = permissionLifecycle.beginPrompt();
|
|
33211
|
+
const approvalHandler = new CodexApprovalHandler(
|
|
33212
|
+
this.connection,
|
|
33213
|
+
permissionContext,
|
|
33214
|
+
activePrompt.signal
|
|
33215
|
+
);
|
|
32317
33216
|
const elicitationHandler = new CodexElicitationHandler(
|
|
32318
33217
|
this.connection,
|
|
32319
|
-
|
|
33218
|
+
permissionContext,
|
|
32320
33219
|
this.clientCapabilities,
|
|
32321
33220
|
activePrompt.signal
|
|
32322
33221
|
);
|
|
33222
|
+
const observeInteraction = async (event) => {
|
|
33223
|
+
permissionContext.handleNotification(event);
|
|
33224
|
+
await elicitationHandler.handleNotification(event);
|
|
33225
|
+
};
|
|
32323
33226
|
await this.codexAcpClient.subscribeToSessionEvents(
|
|
32324
33227
|
params.sessionId,
|
|
32325
33228
|
async (event) => {
|
|
33229
|
+
await observeInteraction(event);
|
|
32326
33230
|
if (!promptNotificationsActive) {
|
|
32327
33231
|
await promptEventHandler.handleSessionScopedNotification(event);
|
|
32328
33232
|
return;
|
|
32329
33233
|
}
|
|
32330
|
-
const completesActiveTurn = event.method === "turn/completed" && event.params.turn.id === sessionState.currentTurnId;
|
|
32331
|
-
await elicitationHandler.handleNotification(event);
|
|
33234
|
+
const completesActiveTurn = event.method === "turn/completed" && event.params.threadId === sessionState.sessionId && event.params.turn.id === sessionState.currentTurnId;
|
|
32332
33235
|
await promptEventHandler.handleNotification(event);
|
|
32333
33236
|
if (completesActiveTurn) {
|
|
32334
33237
|
promptNotificationsActive = false;
|
|
32335
33238
|
}
|
|
32336
33239
|
},
|
|
32337
33240
|
approvalHandler,
|
|
32338
|
-
elicitationHandler
|
|
33241
|
+
elicitationHandler,
|
|
33242
|
+
clientSupportsSubagents(this.clientCapabilities),
|
|
33243
|
+
observeInteraction,
|
|
33244
|
+
(childThreadId) => promptEventHandler.waitForNativeSubagentSession(childThreadId)
|
|
32339
33245
|
);
|
|
32340
33246
|
if (activePrompt.signal.aborted) {
|
|
32341
33247
|
return cancelledPromptResponse();
|
|
@@ -32444,7 +33350,6 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
32444
33350
|
() => this.codexAcpClient.sendPrompt(
|
|
32445
33351
|
effectiveParams,
|
|
32446
33352
|
agentMode,
|
|
32447
|
-
sessionState.approvalsReviewer,
|
|
32448
33353
|
modelId,
|
|
32449
33354
|
serviceTier,
|
|
32450
33355
|
disableSummary,
|
|
@@ -32478,6 +33383,15 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
32478
33383
|
return cancelledPromptResponse();
|
|
32479
33384
|
}
|
|
32480
33385
|
await this.codexAcpClient.waitForSessionNotifications(params.sessionId);
|
|
33386
|
+
if (turnCompleted.turn.status === "completed") {
|
|
33387
|
+
await eventHandler.waitForNativeSubagents(activePrompt.signal);
|
|
33388
|
+
if (activePrompt.signal.aborted) return cancelledPromptResponse();
|
|
33389
|
+
await this.codexAcpClient.waitForSessionNotifications(params.sessionId);
|
|
33390
|
+
} else {
|
|
33391
|
+
await eventHandler.finishOutstandingNativeSubagents(
|
|
33392
|
+
turnCompleted.turn.status === "interrupted" ? "cancelled" : "failed"
|
|
33393
|
+
);
|
|
33394
|
+
}
|
|
32481
33395
|
await eventHandler.flushPendingErrors();
|
|
32482
33396
|
await eventHandler.handleFailedTurn(turnCompleted.turn);
|
|
32483
33397
|
promptNotificationsActive = false;
|
|
@@ -32526,7 +33440,6 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
32526
33440
|
() => this.codexAcpClient.sendPrompt(
|
|
32527
33441
|
implementationRequest,
|
|
32528
33442
|
agentMode,
|
|
32529
|
-
sessionState.approvalsReviewer,
|
|
32530
33443
|
modelId,
|
|
32531
33444
|
serviceTier,
|
|
32532
33445
|
disableSummary,
|
|
@@ -32560,6 +33473,15 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
32560
33473
|
return cancelledPromptResponse();
|
|
32561
33474
|
}
|
|
32562
33475
|
await this.codexAcpClient.waitForSessionNotifications(params.sessionId);
|
|
33476
|
+
if (turnCompleted.turn.status === "completed") {
|
|
33477
|
+
await eventHandler.waitForNativeSubagents(activePrompt.signal);
|
|
33478
|
+
if (activePrompt.signal.aborted) return cancelledPromptResponse();
|
|
33479
|
+
await this.codexAcpClient.waitForSessionNotifications(params.sessionId);
|
|
33480
|
+
} else {
|
|
33481
|
+
await eventHandler.finishOutstandingNativeSubagents(
|
|
33482
|
+
turnCompleted.turn.status === "interrupted" ? "cancelled" : "failed"
|
|
33483
|
+
);
|
|
33484
|
+
}
|
|
32563
33485
|
await eventHandler.flushPendingErrors();
|
|
32564
33486
|
await eventHandler.handleFailedTurn(turnCompleted.turn);
|
|
32565
33487
|
promptNotificationsActive = false;
|
|
@@ -32623,6 +33545,14 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
32623
33545
|
throw err;
|
|
32624
33546
|
} finally {
|
|
32625
33547
|
promptNotificationsActive = false;
|
|
33548
|
+
try {
|
|
33549
|
+
await this.codexAcpClient.waitForSessionNotifications(params.sessionId);
|
|
33550
|
+
await eventHandler?.finishOutstandingNativeSubagents(
|
|
33551
|
+
promptWasCancelled || activePrompt.signal.aborted || this.sessionIsClosing(params.sessionId) ? "cancelled" : "failed"
|
|
33552
|
+
);
|
|
33553
|
+
} catch (error51) {
|
|
33554
|
+
logger.error("Failed to publish terminal subagent state during prompt cleanup", error51);
|
|
33555
|
+
}
|
|
32626
33556
|
if (agentFileChangeReportRequest !== null) {
|
|
32627
33557
|
await this.publishAgentFileChangeReport(
|
|
32628
33558
|
sessionState,
|
|
@@ -32645,41 +33575,14 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
32645
33575
|
}
|
|
32646
33576
|
}
|
|
32647
33577
|
async requestPlanImplementationPermission(sessionState, plan, cancellationSignal) {
|
|
32648
|
-
const toolCallId =
|
|
33578
|
+
const toolCallId = planImplementationToolCallId(plan);
|
|
32649
33579
|
try {
|
|
32650
33580
|
const response = await this.connection.request(
|
|
32651
33581
|
methods.client.session.requestPermission,
|
|
32652
|
-
|
|
32653
|
-
sessionId: sessionState.sessionId,
|
|
32654
|
-
toolCall: {
|
|
32655
|
-
toolCallId,
|
|
32656
|
-
title: "Implement this plan?",
|
|
32657
|
-
kind: "switch_mode",
|
|
32658
|
-
status: "pending",
|
|
32659
|
-
rawInput: { plan: plan.text }
|
|
32660
|
-
},
|
|
32661
|
-
options: [
|
|
32662
|
-
{
|
|
32663
|
-
optionId: IMPLEMENT_PLAN_OPTION_ID,
|
|
32664
|
-
name: "Yes, implement this plan",
|
|
32665
|
-
kind: "allow_once"
|
|
32666
|
-
},
|
|
32667
|
-
{
|
|
32668
|
-
optionId: REVISE_PLAN_OPTION_ID,
|
|
32669
|
-
name: "No, and tell Codex what to do differently",
|
|
32670
|
-
kind: "reject_once"
|
|
32671
|
-
}
|
|
32672
|
-
],
|
|
32673
|
-
_meta: {
|
|
32674
|
-
codex: {
|
|
32675
|
-
kind: "plan_review",
|
|
32676
|
-
planItemId: plan.itemId
|
|
32677
|
-
}
|
|
32678
|
-
}
|
|
32679
|
-
},
|
|
33582
|
+
planImplementationPermissionRequest(sessionState.sessionId, plan),
|
|
32680
33583
|
{ cancellationSignal }
|
|
32681
33584
|
);
|
|
32682
|
-
const approved = response
|
|
33585
|
+
const approved = planImplementationApproved(response);
|
|
32683
33586
|
await this.connection.notify(methods.client.session.update, {
|
|
32684
33587
|
sessionId: sessionState.sessionId,
|
|
32685
33588
|
update: {
|