@agentclientprotocol/codex-acp 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +607 -82
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3453,9 +3453,9 @@ 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 path8 = __importStar(__require("path"));
|
|
3457
3457
|
var os2 = __importStar(__require("os"));
|
|
3458
|
-
var
|
|
3458
|
+
var fs8 = __importStar(__require("fs"));
|
|
3459
3459
|
var crypto_1 = __require("crypto");
|
|
3460
3460
|
var net_1 = __require("net");
|
|
3461
3461
|
var api_1 = require_api();
|
|
@@ -3596,7 +3596,7 @@ var require_main = __commonJS({
|
|
|
3596
3596
|
}
|
|
3597
3597
|
let randomLength = 32;
|
|
3598
3598
|
const fixedLength = "/lsp-.sock".length;
|
|
3599
|
-
const tmpDir =
|
|
3599
|
+
const tmpDir = fs8.realpathSync(XDG_RUNTIME_DIR ?? os2.tmpdir());
|
|
3600
3600
|
const limit = safeIpcPathLengths.get(process.platform);
|
|
3601
3601
|
if (limit !== void 0) {
|
|
3602
3602
|
randomLength = Math.min(limit - tmpDir.length - fixedLength, randomLength);
|
|
@@ -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 path8.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, path8) {
|
|
4513
|
+
if (!path8)
|
|
4514
4514
|
return obj;
|
|
4515
|
-
return
|
|
4515
|
+
return path8.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(path8, 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(path8);
|
|
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, path8 = []) => {
|
|
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 }, [...path8, ...issue2.path]));
|
|
5079
5079
|
} else if (issue2.code === "invalid_key") {
|
|
5080
|
-
processError({ issues: issue2.issues }, [...
|
|
5080
|
+
processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
|
|
5081
5081
|
} else if (issue2.code === "invalid_element") {
|
|
5082
|
-
processError({ issues: issue2.issues }, [...
|
|
5082
|
+
processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
|
|
5083
5083
|
} else {
|
|
5084
|
-
const fullpath = [...
|
|
5084
|
+
const fullpath = [...path8, ...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, path8 = []) => {
|
|
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 }, [...path8, ...issue2.path]));
|
|
5116
5116
|
} else if (issue2.code === "invalid_key") {
|
|
5117
|
-
processError({ issues: issue2.issues }, [...
|
|
5117
|
+
processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
|
|
5118
5118
|
} else if (issue2.code === "invalid_element") {
|
|
5119
|
-
processError({ issues: issue2.issues }, [...
|
|
5119
|
+
processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
|
|
5120
5120
|
} else {
|
|
5121
|
-
const fullpath = [...
|
|
5121
|
+
const fullpath = [...path8, ...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 path8 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
5154
|
+
for (const seg of path8) {
|
|
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 path8 = ref.slice(1).split("/").filter(Boolean);
|
|
17847
|
+
if (path8.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 (path8[0] === defsKey) {
|
|
17852
|
+
const key = path8[1];
|
|
17853
17853
|
if (!key || !ctx.defs[key]) {
|
|
17854
17854
|
throw new Error(`Reference not found: ${ref}`);
|
|
17855
17855
|
}
|
|
@@ -23247,13 +23247,13 @@ function createTerminalCommandEvent(event, terminalId, cwd) {
|
|
|
23247
23247
|
}
|
|
23248
23248
|
};
|
|
23249
23249
|
}
|
|
23250
|
-
function createSearchTitle(query,
|
|
23251
|
-
if (query &&
|
|
23252
|
-
return `Search for '${query}' in ${
|
|
23250
|
+
function createSearchTitle(query, path8) {
|
|
23251
|
+
if (query && path8) {
|
|
23252
|
+
return `Search for '${query}' in ${path8}`;
|
|
23253
23253
|
} else if (query) {
|
|
23254
23254
|
return `Search for '${query}'`;
|
|
23255
|
-
} else if (
|
|
23256
|
-
return `Search in '${
|
|
23255
|
+
} else if (path8) {
|
|
23256
|
+
return `Search in '${path8}'`;
|
|
23257
23257
|
}
|
|
23258
23258
|
return "Search";
|
|
23259
23259
|
}
|
|
@@ -23479,12 +23479,12 @@ function revertPatch(unifiedDiff) {
|
|
|
23479
23479
|
if (!patch) return null;
|
|
23480
23480
|
return reversePatch(patch);
|
|
23481
23481
|
}
|
|
23482
|
-
function createUpdateDiffContent(
|
|
23482
|
+
function createUpdateDiffContent(path8, oldText, newText) {
|
|
23483
23483
|
return {
|
|
23484
23484
|
type: "diff",
|
|
23485
23485
|
oldText,
|
|
23486
23486
|
newText,
|
|
23487
|
-
path:
|
|
23487
|
+
path: path8,
|
|
23488
23488
|
_meta: {
|
|
23489
23489
|
kind: "update"
|
|
23490
23490
|
}
|
|
@@ -23617,6 +23617,8 @@ var AIR_META_KEY = "air";
|
|
|
23617
23617
|
var AIR_EXTENSION_VERSION_KEY = "version";
|
|
23618
23618
|
var AIR_EXTENSION_CAPABILITIES_KEY = "capabilities";
|
|
23619
23619
|
var AIR_SESSION_FAILURE_KEY = "sessionFailure";
|
|
23620
|
+
var AIR_AGENT_FILE_CHANGE_REPORT_KEY = "agentFileChangeReport";
|
|
23621
|
+
var AIR_AGENT_FILE_CHANGE_REPORT_REQUEST_KEY = "agentFileChangeReportRequest";
|
|
23620
23622
|
var AIR_EXTENSION_VERSION = 1;
|
|
23621
23623
|
|
|
23622
23624
|
// src/CodexEventHandler.ts
|
|
@@ -25007,11 +25009,11 @@ var CodexApprovalHandler = class {
|
|
|
25007
25009
|
});
|
|
25008
25010
|
}
|
|
25009
25011
|
const fileSystem = permissions.fileSystem;
|
|
25010
|
-
for (const
|
|
25011
|
-
changes.push(this.fileSystemGrantChange(
|
|
25012
|
+
for (const path8 of fileSystem?.read ?? []) {
|
|
25013
|
+
changes.push(this.fileSystemGrantChange(path8, "read", lifetime, suffix));
|
|
25012
25014
|
}
|
|
25013
|
-
for (const
|
|
25014
|
-
changes.push(this.fileSystemGrantChange(
|
|
25015
|
+
for (const path8 of fileSystem?.write ?? []) {
|
|
25016
|
+
changes.push(this.fileSystemGrantChange(path8, "write", lifetime, suffix));
|
|
25015
25017
|
}
|
|
25016
25018
|
for (const entry of fileSystem?.entries ?? []) {
|
|
25017
25019
|
const matcher = (() => {
|
|
@@ -25040,16 +25042,16 @@ var CodexApprovalHandler = class {
|
|
|
25040
25042
|
}
|
|
25041
25043
|
return changes.length > 0 ? { version: 1, changes } : void 0;
|
|
25042
25044
|
}
|
|
25043
|
-
fileSystemGrantChange(
|
|
25045
|
+
fileSystemGrantChange(path8, access, lifetime, suffix) {
|
|
25044
25046
|
return {
|
|
25045
25047
|
type: "grant",
|
|
25046
25048
|
operation: "grant",
|
|
25047
|
-
description: `Allow ${access} access to ${
|
|
25049
|
+
description: `Allow ${access} access to ${path8}${suffix}`,
|
|
25048
25050
|
lifetime,
|
|
25049
25051
|
targets: [{
|
|
25050
25052
|
type: "filesystem",
|
|
25051
25053
|
access: [access],
|
|
25052
|
-
matcher: { type: "exact_path", path:
|
|
25054
|
+
matcher: { type: "exact_path", path: path8 }
|
|
25053
25055
|
}]
|
|
25054
25056
|
};
|
|
25055
25057
|
}
|
|
@@ -25959,15 +25961,15 @@ var wslDefaultBrowser = async () => {
|
|
|
25959
25961
|
const { stdout } = await executePowerShell(command, { powerShellPath: psPath });
|
|
25960
25962
|
return stdout.trim();
|
|
25961
25963
|
};
|
|
25962
|
-
var convertWslPathToWindows = async (
|
|
25963
|
-
if (/^[a-z]+:\/\//i.test(
|
|
25964
|
-
return
|
|
25964
|
+
var convertWslPathToWindows = async (path8) => {
|
|
25965
|
+
if (/^[a-z]+:\/\//i.test(path8)) {
|
|
25966
|
+
return path8;
|
|
25965
25967
|
}
|
|
25966
25968
|
try {
|
|
25967
|
-
const { stdout } = await execFile2("wslpath", ["-aw",
|
|
25969
|
+
const { stdout } = await execFile2("wslpath", ["-aw", path8], { encoding: "utf8" });
|
|
25968
25970
|
return stdout.trim();
|
|
25969
25971
|
} catch {
|
|
25970
|
-
return
|
|
25972
|
+
return path8;
|
|
25971
25973
|
}
|
|
25972
25974
|
};
|
|
25973
25975
|
|
|
@@ -26517,7 +26519,7 @@ var AgentMode = class _AgentMode {
|
|
|
26517
26519
|
};
|
|
26518
26520
|
|
|
26519
26521
|
// src/CodexAcpClient.ts
|
|
26520
|
-
import
|
|
26522
|
+
import path6 from "node:path";
|
|
26521
26523
|
|
|
26522
26524
|
// src/McpServerName.ts
|
|
26523
26525
|
var MCP_SERVER_NAME_WHITESPACE = /\p{White_Space}/gu;
|
|
@@ -26531,7 +26533,7 @@ var package_default = {
|
|
|
26531
26533
|
publishConfig: {
|
|
26532
26534
|
access: "public"
|
|
26533
26535
|
},
|
|
26534
|
-
version: "1.
|
|
26536
|
+
version: "1.4.0",
|
|
26535
26537
|
description: "",
|
|
26536
26538
|
main: "dist/index.js",
|
|
26537
26539
|
bin: {
|
|
@@ -26684,6 +26686,295 @@ function isRootPath(value) {
|
|
|
26684
26686
|
return value === "/" || /^[A-Za-z]:\/$/.test(value) || /^\/\/[^/]+\/[^/]+\/$/.test(value);
|
|
26685
26687
|
}
|
|
26686
26688
|
|
|
26689
|
+
// src/AgentFileChangeReport.ts
|
|
26690
|
+
import fs7 from "node:fs";
|
|
26691
|
+
import path5 from "node:path";
|
|
26692
|
+
var AGENT_FILE_CHANGE_REPORT_VERSION = 1;
|
|
26693
|
+
var AGENT_FILE_CHANGE_REPORT_TIMEOUT_MS = 3e4;
|
|
26694
|
+
var AGENT_FILE_CHANGE_REPORT_MAX_PATHS = 1024;
|
|
26695
|
+
var AGENT_FILE_CHANGE_REPORT_MAX_PATH_LENGTH = 4096;
|
|
26696
|
+
var AGENT_FILE_CHANGE_REPORT_MAX_TOTAL_BYTES = 256 * 1024;
|
|
26697
|
+
var AGENT_FILE_CHANGE_REPORT_MAX_UNCERTAINTY_LENGTH = 2e3;
|
|
26698
|
+
var AGENT_FILE_CHANGE_REPORT_OUTPUT_SCHEMA = {
|
|
26699
|
+
type: "object",
|
|
26700
|
+
additionalProperties: false,
|
|
26701
|
+
required: ["paths", "complete"],
|
|
26702
|
+
properties: {
|
|
26703
|
+
paths: {
|
|
26704
|
+
type: "array",
|
|
26705
|
+
items: { type: "string" }
|
|
26706
|
+
},
|
|
26707
|
+
complete: { type: "boolean" },
|
|
26708
|
+
uncertainty: {
|
|
26709
|
+
type: "string",
|
|
26710
|
+
maxLength: AGENT_FILE_CHANGE_REPORT_MAX_UNCERTAINTY_LENGTH
|
|
26711
|
+
}
|
|
26712
|
+
}
|
|
26713
|
+
};
|
|
26714
|
+
var AGENT_FILE_CHANGE_REPORT_DEVELOPER_INSTRUCTIONS = `You are running an internal, read-only file-change audit for the immediately preceding turn.
|
|
26715
|
+
Do not modify files, run commands that can modify files, or ask the user questions.
|
|
26716
|
+
Report files that the preceding turn causally created, modified, deleted, or moved, including changes made by shell commands, version-control commands, generators, and child processes.
|
|
26717
|
+
Do not report files that were only read or inspected.
|
|
26718
|
+
You may use read-only inspection when needed. If the list may be incomplete, set complete to false and briefly explain why in uncertainty.`;
|
|
26719
|
+
function createAgentFileChangeReportPrompt(workspace) {
|
|
26720
|
+
return `List the paths changed by the immediately preceding turn.
|
|
26721
|
+
Return only the structured result required by the output schema.
|
|
26722
|
+
Relative paths are resolved against the working directory.
|
|
26723
|
+
Working directory: ${JSON.stringify(workspace.cwd)}
|
|
26724
|
+
Additional allowed directories: ${JSON.stringify(workspace.additionalDirectories)}`;
|
|
26725
|
+
}
|
|
26726
|
+
function parseAgentFileChangeReportRequest(meta3) {
|
|
26727
|
+
const jetbrains = asRecord(meta3?.[JETBRAINS_META_KEY]);
|
|
26728
|
+
const air = asRecord(jetbrains?.[AIR_META_KEY]);
|
|
26729
|
+
const request = asRecord(air?.[AIR_AGENT_FILE_CHANGE_REPORT_REQUEST_KEY]);
|
|
26730
|
+
if (request === null || !hasOnlyKeys(request, ["version", "requestId"]) || request["version"] !== AGENT_FILE_CHANGE_REPORT_VERSION) {
|
|
26731
|
+
return null;
|
|
26732
|
+
}
|
|
26733
|
+
const requestId = request["requestId"];
|
|
26734
|
+
if (typeof requestId !== "string" || !/^[A-Za-z0-9._:-]{1,128}$/.test(requestId)) {
|
|
26735
|
+
return null;
|
|
26736
|
+
}
|
|
26737
|
+
return { version: AGENT_FILE_CHANGE_REPORT_VERSION, requestId };
|
|
26738
|
+
}
|
|
26739
|
+
function createReportedAgentFileChangeReport(requestId, turn, workspace) {
|
|
26740
|
+
const modelReport = parseModelFileChangeReport(turn);
|
|
26741
|
+
const normalized = normalizeModelFileChangeReport(modelReport, workspace);
|
|
26742
|
+
return fitReportedAgentFileChangeReport({
|
|
26743
|
+
version: AGENT_FILE_CHANGE_REPORT_VERSION,
|
|
26744
|
+
requestId,
|
|
26745
|
+
status: "reported",
|
|
26746
|
+
...normalized
|
|
26747
|
+
});
|
|
26748
|
+
}
|
|
26749
|
+
function createUnavailableAgentFileChangeReport(requestId, reason) {
|
|
26750
|
+
return {
|
|
26751
|
+
version: AGENT_FILE_CHANGE_REPORT_VERSION,
|
|
26752
|
+
requestId,
|
|
26753
|
+
status: "unavailable",
|
|
26754
|
+
reason
|
|
26755
|
+
};
|
|
26756
|
+
}
|
|
26757
|
+
var AgentFileChangeReportError = class extends Error {
|
|
26758
|
+
reason;
|
|
26759
|
+
constructor(reason, message) {
|
|
26760
|
+
super(message);
|
|
26761
|
+
this.name = "AgentFileChangeReportError";
|
|
26762
|
+
this.reason = reason;
|
|
26763
|
+
}
|
|
26764
|
+
};
|
|
26765
|
+
function parseModelFileChangeReport(turn) {
|
|
26766
|
+
switch (turn.status) {
|
|
26767
|
+
case "interrupted":
|
|
26768
|
+
throw new AgentFileChangeReportError("cancelled", "The audit turn was interrupted");
|
|
26769
|
+
case "failed":
|
|
26770
|
+
throw new AgentFileChangeReportError("providerError", "The audit turn failed");
|
|
26771
|
+
case "inProgress":
|
|
26772
|
+
throw new AgentFileChangeReportError("notReported", "The audit turn did not complete");
|
|
26773
|
+
case "completed":
|
|
26774
|
+
break;
|
|
26775
|
+
}
|
|
26776
|
+
let text = null;
|
|
26777
|
+
for (let index = turn.items.length - 1; index >= 0; index -= 1) {
|
|
26778
|
+
const item = turn.items[index];
|
|
26779
|
+
if (item?.type === "agentMessage") {
|
|
26780
|
+
text = item.text;
|
|
26781
|
+
break;
|
|
26782
|
+
}
|
|
26783
|
+
}
|
|
26784
|
+
if (text === null) {
|
|
26785
|
+
throw new AgentFileChangeReportError("notReported", "The audit turn returned no agent message");
|
|
26786
|
+
}
|
|
26787
|
+
let value;
|
|
26788
|
+
try {
|
|
26789
|
+
value = JSON.parse(text);
|
|
26790
|
+
} catch {
|
|
26791
|
+
throw new AgentFileChangeReportError("invalidOutput", "The audit turn returned invalid JSON");
|
|
26792
|
+
}
|
|
26793
|
+
const report = asRecord(value);
|
|
26794
|
+
if (report === null || !hasOnlyKeys(report, ["paths", "complete", "uncertainty"])) {
|
|
26795
|
+
throw new AgentFileChangeReportError("invalidOutput", "The audit turn returned an invalid object");
|
|
26796
|
+
}
|
|
26797
|
+
const paths = report["paths"];
|
|
26798
|
+
const complete = report["complete"];
|
|
26799
|
+
const uncertainty = report["uncertainty"];
|
|
26800
|
+
if (!Array.isArray(paths) || !paths.every((item) => typeof item === "string") || typeof complete !== "boolean" || uncertainty !== void 0 && typeof uncertainty !== "string") {
|
|
26801
|
+
throw new AgentFileChangeReportError("invalidOutput", "The audit turn returned invalid fields");
|
|
26802
|
+
}
|
|
26803
|
+
const normalizedUncertainty = uncertainty?.trim();
|
|
26804
|
+
if (normalizedUncertainty !== void 0 && normalizedUncertainty.length > AGENT_FILE_CHANGE_REPORT_MAX_UNCERTAINTY_LENGTH) {
|
|
26805
|
+
throw new AgentFileChangeReportError("invalidOutput", "The audit turn returned oversized uncertainty");
|
|
26806
|
+
}
|
|
26807
|
+
return {
|
|
26808
|
+
paths,
|
|
26809
|
+
complete,
|
|
26810
|
+
...normalizedUncertainty ? { uncertainty: normalizedUncertainty } : {}
|
|
26811
|
+
};
|
|
26812
|
+
}
|
|
26813
|
+
function fitReportedAgentFileChangeReport(report) {
|
|
26814
|
+
const paths = [...report.paths];
|
|
26815
|
+
let truncated = report.truncated;
|
|
26816
|
+
let fitted = report;
|
|
26817
|
+
while (Buffer.byteLength(JSON.stringify(fitted), "utf8") > AGENT_FILE_CHANGE_REPORT_MAX_TOTAL_BYTES) {
|
|
26818
|
+
if (paths.length === 0) {
|
|
26819
|
+
throw new AgentFileChangeReportError("invalidOutput", "The audit report exceeds the wire limit");
|
|
26820
|
+
}
|
|
26821
|
+
paths.pop();
|
|
26822
|
+
truncated = true;
|
|
26823
|
+
fitted = {
|
|
26824
|
+
...report,
|
|
26825
|
+
paths: [...paths],
|
|
26826
|
+
declaredComplete: false,
|
|
26827
|
+
truncated
|
|
26828
|
+
};
|
|
26829
|
+
}
|
|
26830
|
+
return fitted;
|
|
26831
|
+
}
|
|
26832
|
+
function normalizeModelFileChangeReport(report, workspace) {
|
|
26833
|
+
const cwd = normalizeWorkspaceRoot(workspace.cwd);
|
|
26834
|
+
if (cwd === null) {
|
|
26835
|
+
throw new AgentFileChangeReportError("providerError", "The session working directory is not absolute");
|
|
26836
|
+
}
|
|
26837
|
+
const roots = [cwd, ...workspace.additionalDirectories.flatMap((directory) => {
|
|
26838
|
+
const root = normalizeWorkspaceRoot(directory);
|
|
26839
|
+
return root === null || root.flavor !== cwd.flavor ? [] : [root];
|
|
26840
|
+
})];
|
|
26841
|
+
const paths = [];
|
|
26842
|
+
const seen = /* @__PURE__ */ new Set();
|
|
26843
|
+
let totalBytes = 0;
|
|
26844
|
+
let truncated = false;
|
|
26845
|
+
for (const reportedPath of report.paths) {
|
|
26846
|
+
if (reportedPath.length > AGENT_FILE_CHANGE_REPORT_MAX_PATH_LENGTH) {
|
|
26847
|
+
truncated = true;
|
|
26848
|
+
continue;
|
|
26849
|
+
}
|
|
26850
|
+
const normalized = normalizeReportedPath(reportedPath, cwd, roots);
|
|
26851
|
+
if (normalized === null || normalized.value.length > AGENT_FILE_CHANGE_REPORT_MAX_PATH_LENGTH) {
|
|
26852
|
+
truncated = true;
|
|
26853
|
+
continue;
|
|
26854
|
+
}
|
|
26855
|
+
const key = normalized.flavor === "windows" ? normalized.value.toLowerCase() : normalized.value;
|
|
26856
|
+
if (seen.has(key)) {
|
|
26857
|
+
continue;
|
|
26858
|
+
}
|
|
26859
|
+
const bytes = Buffer.byteLength(normalized.value, "utf8");
|
|
26860
|
+
if (paths.length >= AGENT_FILE_CHANGE_REPORT_MAX_PATHS || totalBytes + bytes > AGENT_FILE_CHANGE_REPORT_MAX_TOTAL_BYTES) {
|
|
26861
|
+
truncated = true;
|
|
26862
|
+
continue;
|
|
26863
|
+
}
|
|
26864
|
+
seen.add(key);
|
|
26865
|
+
paths.push(normalized.value);
|
|
26866
|
+
totalBytes += bytes;
|
|
26867
|
+
}
|
|
26868
|
+
return {
|
|
26869
|
+
paths,
|
|
26870
|
+
declaredComplete: report.complete && !truncated,
|
|
26871
|
+
truncated,
|
|
26872
|
+
...report.uncertainty ? { uncertainty: report.uncertainty } : {}
|
|
26873
|
+
};
|
|
26874
|
+
}
|
|
26875
|
+
function normalizeWorkspaceRoot(value) {
|
|
26876
|
+
const trimmed = value.trim();
|
|
26877
|
+
if (!isValidPathText(trimmed)) {
|
|
26878
|
+
return null;
|
|
26879
|
+
}
|
|
26880
|
+
if (isWindowsAbsolutePath2(trimmed)) {
|
|
26881
|
+
return canonicalizeWorkspaceRoot({
|
|
26882
|
+
value: path5.win32.normalize(trimmed.replace(/\//g, "\\")),
|
|
26883
|
+
flavor: "windows"
|
|
26884
|
+
});
|
|
26885
|
+
}
|
|
26886
|
+
if (path5.posix.isAbsolute(trimmed)) {
|
|
26887
|
+
return canonicalizeWorkspaceRoot({
|
|
26888
|
+
value: path5.posix.normalize(trimmed.replace(/\\/g, "/")),
|
|
26889
|
+
flavor: "posix"
|
|
26890
|
+
});
|
|
26891
|
+
}
|
|
26892
|
+
return null;
|
|
26893
|
+
}
|
|
26894
|
+
function normalizeReportedPath(value, cwd, roots) {
|
|
26895
|
+
const trimmed = value.trim();
|
|
26896
|
+
if (!isValidPathText(trimmed) || /^[A-Za-z]:[^\\/]/.test(trimmed) || /^\\\\[?.]\\/.test(trimmed) || /^(?:\\\\|\/\/)/.test(trimmed) && !isWindowsAbsolutePath2(trimmed) || cwd.flavor === "windows" && /^\\(?!\\)/.test(trimmed) || /^[A-Za-z][A-Za-z0-9+.-]*:\/\//.test(trimmed)) {
|
|
26897
|
+
return null;
|
|
26898
|
+
}
|
|
26899
|
+
let candidate;
|
|
26900
|
+
if (isWindowsAbsolutePath2(trimmed)) {
|
|
26901
|
+
candidate = { value: path5.win32.normalize(trimmed.replace(/\//g, "\\")), flavor: "windows" };
|
|
26902
|
+
} else if (path5.posix.isAbsolute(trimmed)) {
|
|
26903
|
+
candidate = { value: path5.posix.normalize(trimmed.replace(/\\/g, "/")), flavor: "posix" };
|
|
26904
|
+
} else if (cwd.flavor === "windows") {
|
|
26905
|
+
candidate = {
|
|
26906
|
+
value: path5.win32.resolve(cwd.value, trimmed.replace(/\//g, "\\")),
|
|
26907
|
+
flavor: "windows"
|
|
26908
|
+
};
|
|
26909
|
+
} else {
|
|
26910
|
+
candidate = {
|
|
26911
|
+
value: path5.posix.resolve(cwd.value, trimmed.replace(/\\/g, "/")),
|
|
26912
|
+
flavor: "posix"
|
|
26913
|
+
};
|
|
26914
|
+
}
|
|
26915
|
+
candidate = canonicalizeReportedPath(candidate);
|
|
26916
|
+
return roots.some((root) => pathIsStrictlyInside(root, candidate)) ? candidate : null;
|
|
26917
|
+
}
|
|
26918
|
+
function canonicalizeWorkspaceRoot(root) {
|
|
26919
|
+
if (!isNativePathFlavor(root.flavor)) {
|
|
26920
|
+
return root;
|
|
26921
|
+
}
|
|
26922
|
+
return { ...root, value: canonicalizeFromExistingAncestor(root.value) };
|
|
26923
|
+
}
|
|
26924
|
+
function canonicalizeReportedPath(candidate) {
|
|
26925
|
+
if (!isNativePathFlavor(candidate.flavor)) {
|
|
26926
|
+
return candidate;
|
|
26927
|
+
}
|
|
26928
|
+
const parent = canonicalizeFromExistingAncestor(path5.dirname(candidate.value));
|
|
26929
|
+
return { ...candidate, value: path5.resolve(parent, path5.basename(candidate.value)) };
|
|
26930
|
+
}
|
|
26931
|
+
function canonicalizeFromExistingAncestor(value) {
|
|
26932
|
+
const original = path5.resolve(value);
|
|
26933
|
+
let current = original;
|
|
26934
|
+
const missingSegments = [];
|
|
26935
|
+
while (true) {
|
|
26936
|
+
try {
|
|
26937
|
+
const canonical = fs7.realpathSync.native(current);
|
|
26938
|
+
return path5.resolve(canonical, ...missingSegments.reverse());
|
|
26939
|
+
} catch (error51) {
|
|
26940
|
+
if (!isMissingPathError(error51)) return original;
|
|
26941
|
+
}
|
|
26942
|
+
const parent = path5.dirname(current);
|
|
26943
|
+
if (parent === current) return original;
|
|
26944
|
+
missingSegments.push(path5.basename(current));
|
|
26945
|
+
current = parent;
|
|
26946
|
+
}
|
|
26947
|
+
}
|
|
26948
|
+
function isMissingPathError(error51) {
|
|
26949
|
+
if (typeof error51 !== "object" || error51 === null || !("code" in error51)) return false;
|
|
26950
|
+
return error51.code === "ENOENT" || error51.code === "ENOTDIR";
|
|
26951
|
+
}
|
|
26952
|
+
function isNativePathFlavor(flavor) {
|
|
26953
|
+
return process.platform === "win32" ? flavor === "windows" : flavor === "posix";
|
|
26954
|
+
}
|
|
26955
|
+
function pathIsStrictlyInside(root, candidate) {
|
|
26956
|
+
if (root.flavor !== candidate.flavor) {
|
|
26957
|
+
return false;
|
|
26958
|
+
}
|
|
26959
|
+
const pathImplementation = root.flavor === "windows" ? path5.win32 : path5.posix;
|
|
26960
|
+
const relative = pathImplementation.relative(root.value, candidate.value);
|
|
26961
|
+
return relative.length > 0 && !pathImplementation.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${pathImplementation.sep}`);
|
|
26962
|
+
}
|
|
26963
|
+
function isWindowsAbsolutePath2(value) {
|
|
26964
|
+
const portable = value.replace(/\\/g, "/");
|
|
26965
|
+
return /^[A-Za-z]:\//.test(portable) || /^\/\/[^/]+\/[^/]+(?:\/|$)/.test(portable);
|
|
26966
|
+
}
|
|
26967
|
+
function isValidPathText(value) {
|
|
26968
|
+
return value.length > 0 && !/[\u0000-\u001F\u007F-\u009F]/.test(value);
|
|
26969
|
+
}
|
|
26970
|
+
function asRecord(value) {
|
|
26971
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
|
|
26972
|
+
}
|
|
26973
|
+
function hasOnlyKeys(value, allowed) {
|
|
26974
|
+
const allowedKeys = new Set(allowed);
|
|
26975
|
+
return Object.keys(value).every((key) => allowedKeys.has(key));
|
|
26976
|
+
}
|
|
26977
|
+
|
|
26687
26978
|
// src/CodexAcpClient.ts
|
|
26688
26979
|
var CUSTOM_GATEWAY_PROVIDER_ID = "custom-gateway";
|
|
26689
26980
|
var OPENAI_PROVIDER_ID = "openai";
|
|
@@ -27153,7 +27444,7 @@ var CodexAcpClient = class {
|
|
|
27153
27444
|
if (!cwd) {
|
|
27154
27445
|
return;
|
|
27155
27446
|
}
|
|
27156
|
-
const skillExtraRoots = additionalRoots.map((root) =>
|
|
27447
|
+
const skillExtraRoots = additionalRoots.map((root) => path6.join(root, ".agents", "skills"));
|
|
27157
27448
|
if (!arraysEqual(this.skillExtraRoots, skillExtraRoots)) {
|
|
27158
27449
|
await this.codexClient.skillsExtraRootsSet({ extraRoots: skillExtraRoots });
|
|
27159
27450
|
this.skillExtraRoots = skillExtraRoots;
|
|
@@ -27275,6 +27566,113 @@ var CodexAcpClient = class {
|
|
|
27275
27566
|
serviceTier
|
|
27276
27567
|
}, onTurnStarted);
|
|
27277
27568
|
}
|
|
27569
|
+
async runAgentFileChangeReport(params) {
|
|
27570
|
+
if (params.signal?.aborted) {
|
|
27571
|
+
return createUnavailableAgentFileChangeReport(params.requestId, "cancelled");
|
|
27572
|
+
}
|
|
27573
|
+
const budget = new AgentFileChangeReportBudget(params.signal);
|
|
27574
|
+
let forkThreadId = null;
|
|
27575
|
+
let auditTurnId = null;
|
|
27576
|
+
let auditTurnCompleted = false;
|
|
27577
|
+
let lateStopReason = null;
|
|
27578
|
+
try {
|
|
27579
|
+
const forkPromise = this.codexClient.threadFork({
|
|
27580
|
+
threadId: params.sessionId,
|
|
27581
|
+
lastTurnId: params.turnId,
|
|
27582
|
+
cwd: params.workspace.cwd,
|
|
27583
|
+
approvalPolicy: "never",
|
|
27584
|
+
sandbox: "read-only",
|
|
27585
|
+
developerInstructions: AGENT_FILE_CHANGE_REPORT_DEVELOPER_INSTRUCTIONS,
|
|
27586
|
+
ephemeral: true
|
|
27587
|
+
});
|
|
27588
|
+
void forkPromise.then((fork2) => {
|
|
27589
|
+
if (lateStopReason !== null && forkThreadId === null) {
|
|
27590
|
+
void this.unsubscribeAgentFileChangeReportThread(fork2.thread.id, budget);
|
|
27591
|
+
}
|
|
27592
|
+
}, () => {
|
|
27593
|
+
});
|
|
27594
|
+
const fork = await budget.wait(forkPromise);
|
|
27595
|
+
forkThreadId = fork.thread.id;
|
|
27596
|
+
const turnPromise = this.codexClient.runTurn({
|
|
27597
|
+
threadId: forkThreadId,
|
|
27598
|
+
input: [{
|
|
27599
|
+
type: "text",
|
|
27600
|
+
text: createAgentFileChangeReportPrompt(params.workspace),
|
|
27601
|
+
text_elements: []
|
|
27602
|
+
}],
|
|
27603
|
+
cwd: params.workspace.cwd,
|
|
27604
|
+
approvalPolicy: "never",
|
|
27605
|
+
sandboxPolicy: { type: "readOnly", networkAccess: false },
|
|
27606
|
+
summary: "none",
|
|
27607
|
+
outputSchema: AGENT_FILE_CHANGE_REPORT_OUTPUT_SCHEMA
|
|
27608
|
+
}, (turnId) => {
|
|
27609
|
+
auditTurnId = turnId;
|
|
27610
|
+
if (lateStopReason !== null && forkThreadId !== null) {
|
|
27611
|
+
void this.interruptAgentFileChangeReport(forkThreadId, turnId, lateStopReason, budget);
|
|
27612
|
+
}
|
|
27613
|
+
});
|
|
27614
|
+
const outcome = await budget.wait(turnPromise);
|
|
27615
|
+
auditTurnCompleted = true;
|
|
27616
|
+
const thread = await budget.wait(this.codexClient.threadRead({
|
|
27617
|
+
threadId: forkThreadId,
|
|
27618
|
+
includeTurns: true
|
|
27619
|
+
}));
|
|
27620
|
+
const completedTurn = thread.thread.turns.find(
|
|
27621
|
+
(turn) => turn.id === outcome.turn.id
|
|
27622
|
+
);
|
|
27623
|
+
if (completedTurn === void 0) {
|
|
27624
|
+
throw new AgentFileChangeReportError(
|
|
27625
|
+
"notReported",
|
|
27626
|
+
"The completed audit turn was not present in thread history"
|
|
27627
|
+
);
|
|
27628
|
+
}
|
|
27629
|
+
return createReportedAgentFileChangeReport(
|
|
27630
|
+
params.requestId,
|
|
27631
|
+
completedTurn,
|
|
27632
|
+
params.workspace
|
|
27633
|
+
);
|
|
27634
|
+
} catch (error51) {
|
|
27635
|
+
if (error51 instanceof AgentFileChangeReportBudgetError) {
|
|
27636
|
+
lateStopReason = error51.reason;
|
|
27637
|
+
if (!auditTurnCompleted && forkThreadId !== null && auditTurnId !== null) {
|
|
27638
|
+
await this.interruptAgentFileChangeReport(
|
|
27639
|
+
forkThreadId,
|
|
27640
|
+
auditTurnId,
|
|
27641
|
+
error51.reason,
|
|
27642
|
+
budget
|
|
27643
|
+
);
|
|
27644
|
+
}
|
|
27645
|
+
return createUnavailableAgentFileChangeReport(params.requestId, error51.reason);
|
|
27646
|
+
}
|
|
27647
|
+
if (error51 instanceof AgentFileChangeReportError) {
|
|
27648
|
+
logger.log("Agent file-change report unavailable", { reason: error51.reason });
|
|
27649
|
+
return createUnavailableAgentFileChangeReport(params.requestId, error51.reason);
|
|
27650
|
+
}
|
|
27651
|
+
logger.error("Agent file-change report failed", error51);
|
|
27652
|
+
return createUnavailableAgentFileChangeReport(params.requestId, "providerError");
|
|
27653
|
+
} finally {
|
|
27654
|
+
if (forkThreadId !== null) {
|
|
27655
|
+
await this.unsubscribeAgentFileChangeReportThread(forkThreadId, budget);
|
|
27656
|
+
}
|
|
27657
|
+
}
|
|
27658
|
+
}
|
|
27659
|
+
async interruptAgentFileChangeReport(threadId, turnId, reason, budget) {
|
|
27660
|
+
this.codexClient.markTurnStale(threadId, turnId);
|
|
27661
|
+
try {
|
|
27662
|
+
await budget.wait(this.codexClient.turnInterrupt({ threadId, turnId }));
|
|
27663
|
+
} catch (error51) {
|
|
27664
|
+
logger.error(`Failed to interrupt ${reason} agent file-change report`, error51);
|
|
27665
|
+
} finally {
|
|
27666
|
+
this.codexClient.resolveTurnInterrupted(threadId, turnId);
|
|
27667
|
+
}
|
|
27668
|
+
}
|
|
27669
|
+
async unsubscribeAgentFileChangeReportThread(threadId, budget) {
|
|
27670
|
+
try {
|
|
27671
|
+
await budget.wait(this.codexClient.threadUnsubscribe({ threadId }));
|
|
27672
|
+
} catch (error51) {
|
|
27673
|
+
logger.error("Failed to unsubscribe the agent file-change report thread", error51);
|
|
27674
|
+
}
|
|
27675
|
+
}
|
|
27278
27676
|
async setCollaborationMode(sessionId, mode, currentModelId) {
|
|
27279
27677
|
await this.codexClient.threadSettingsUpdate({
|
|
27280
27678
|
threadId: sessionId,
|
|
@@ -27425,6 +27823,58 @@ var CodexAcpClient = class {
|
|
|
27425
27823
|
};
|
|
27426
27824
|
}
|
|
27427
27825
|
};
|
|
27826
|
+
var AgentFileChangeReportBudgetError = class extends Error {
|
|
27827
|
+
constructor(reason) {
|
|
27828
|
+
super(`Agent file-change report ${reason}`);
|
|
27829
|
+
this.reason = reason;
|
|
27830
|
+
this.name = "AgentFileChangeReportBudgetError";
|
|
27831
|
+
}
|
|
27832
|
+
reason;
|
|
27833
|
+
};
|
|
27834
|
+
var AgentFileChangeReportBudget = class {
|
|
27835
|
+
constructor(signal) {
|
|
27836
|
+
this.signal = signal;
|
|
27837
|
+
}
|
|
27838
|
+
signal;
|
|
27839
|
+
deadline = Date.now() + AGENT_FILE_CHANGE_REPORT_TIMEOUT_MS;
|
|
27840
|
+
async wait(operation) {
|
|
27841
|
+
void operation.catch(() => {
|
|
27842
|
+
});
|
|
27843
|
+
const immediateReason = this.stopReason();
|
|
27844
|
+
if (immediateReason !== null) {
|
|
27845
|
+
throw new AgentFileChangeReportBudgetError(immediateReason);
|
|
27846
|
+
}
|
|
27847
|
+
return await new Promise((resolve, reject) => {
|
|
27848
|
+
let settled = false;
|
|
27849
|
+
const finish = (action) => {
|
|
27850
|
+
if (settled) return;
|
|
27851
|
+
settled = true;
|
|
27852
|
+
clearTimeout(timeout);
|
|
27853
|
+
this.signal?.removeEventListener("abort", onAbort);
|
|
27854
|
+
action();
|
|
27855
|
+
};
|
|
27856
|
+
const onAbort = () => finish(() => reject(new AgentFileChangeReportBudgetError("cancelled")));
|
|
27857
|
+
const timeout = setTimeout(
|
|
27858
|
+
() => finish(() => reject(new AgentFileChangeReportBudgetError("timeout"))),
|
|
27859
|
+
Math.max(1, this.deadline - Date.now())
|
|
27860
|
+
);
|
|
27861
|
+
timeout.unref();
|
|
27862
|
+
this.signal?.addEventListener("abort", onAbort, { once: true });
|
|
27863
|
+
if (this.signal?.aborted) {
|
|
27864
|
+
onAbort();
|
|
27865
|
+
}
|
|
27866
|
+
void operation.then(
|
|
27867
|
+
(value) => finish(() => resolve(value)),
|
|
27868
|
+
(error51) => finish(() => reject(error51))
|
|
27869
|
+
);
|
|
27870
|
+
});
|
|
27871
|
+
}
|
|
27872
|
+
stopReason() {
|
|
27873
|
+
if (this.signal?.aborted) return "cancelled";
|
|
27874
|
+
if (Date.now() >= this.deadline) return "timeout";
|
|
27875
|
+
return null;
|
|
27876
|
+
}
|
|
27877
|
+
};
|
|
27428
27878
|
function buildPromptItems(prompt) {
|
|
27429
27879
|
return prompt.map((block) => {
|
|
27430
27880
|
switch (block.type) {
|
|
@@ -27484,8 +27934,8 @@ function formatUriAsLink(name, uri) {
|
|
|
27484
27934
|
return `[@${name}](${uri})`;
|
|
27485
27935
|
}
|
|
27486
27936
|
if (uri.startsWith("file://")) {
|
|
27487
|
-
const
|
|
27488
|
-
const fileName =
|
|
27937
|
+
const path8 = uri.replace("file://", "");
|
|
27938
|
+
const fileName = path8.split("/").pop() ?? path8;
|
|
27489
27939
|
return `[@${fileName}](${uri})`;
|
|
27490
27940
|
}
|
|
27491
27941
|
return uri;
|
|
@@ -27515,7 +27965,7 @@ function readAdditionalDirectories(cwd, additionalDirectories, meta3) {
|
|
|
27515
27965
|
if (directory.length === 0) {
|
|
27516
27966
|
throw RequestError.invalidParams(void 0, "additionalDirectories entries must not be empty");
|
|
27517
27967
|
}
|
|
27518
|
-
if (!
|
|
27968
|
+
if (!path6.isAbsolute(directory)) {
|
|
27519
27969
|
throw RequestError.invalidParams(void 0, "additionalDirectories entries must be absolute paths");
|
|
27520
27970
|
}
|
|
27521
27971
|
if (!seen.has(directory)) {
|
|
@@ -28118,7 +28568,7 @@ var SteeringQueue = class {
|
|
|
28118
28568
|
|
|
28119
28569
|
// src/ResponseItemHistoryFallback.ts
|
|
28120
28570
|
import { readFile as readFile2 } from "node:fs/promises";
|
|
28121
|
-
import
|
|
28571
|
+
import path7 from "node:path";
|
|
28122
28572
|
function historyFallbackUpdateKey(update) {
|
|
28123
28573
|
switch (update.sessionUpdate) {
|
|
28124
28574
|
case "user_message_chunk":
|
|
@@ -28272,14 +28722,14 @@ function parseJsonRecord(line) {
|
|
|
28272
28722
|
}
|
|
28273
28723
|
try {
|
|
28274
28724
|
const value = JSON.parse(line);
|
|
28275
|
-
return
|
|
28725
|
+
return asRecord2(value);
|
|
28276
28726
|
} catch {
|
|
28277
28727
|
return null;
|
|
28278
28728
|
}
|
|
28279
28729
|
}
|
|
28280
28730
|
function extractResponseItem(record2) {
|
|
28281
28731
|
if (record2["type"] === "response_item") {
|
|
28282
|
-
return
|
|
28732
|
+
return asRecord2(record2["payload"]);
|
|
28283
28733
|
}
|
|
28284
28734
|
const itemType = record2["type"];
|
|
28285
28735
|
if (typeof itemType === "string" && isLegacyResponseItemType(itemType)) {
|
|
@@ -28313,7 +28763,7 @@ function createEventMsgUpdates(record2) {
|
|
|
28313
28763
|
if (record2["type"] !== "event_msg") {
|
|
28314
28764
|
return null;
|
|
28315
28765
|
}
|
|
28316
|
-
const payload =
|
|
28766
|
+
const payload = asRecord2(record2["payload"]);
|
|
28317
28767
|
if (!payload) {
|
|
28318
28768
|
return [];
|
|
28319
28769
|
}
|
|
@@ -28357,9 +28807,9 @@ function imageBlocks(images) {
|
|
|
28357
28807
|
if (typeof image === "string") {
|
|
28358
28808
|
return [{ type: "text", text: `[@image](${image})` }];
|
|
28359
28809
|
}
|
|
28360
|
-
const record2 =
|
|
28361
|
-
const
|
|
28362
|
-
return
|
|
28810
|
+
const record2 = asRecord2(image);
|
|
28811
|
+
const path8 = record2 ? stringValue(record2["path"]) ?? stringValue(record2["url"]) : null;
|
|
28812
|
+
return path8 ? [{ type: "text", text: `[@image](${path8})` }] : [];
|
|
28363
28813
|
});
|
|
28364
28814
|
}
|
|
28365
28815
|
function contentBlocksFromResponseContent(content) {
|
|
@@ -28367,7 +28817,7 @@ function contentBlocksFromResponseContent(content) {
|
|
|
28367
28817
|
return [];
|
|
28368
28818
|
}
|
|
28369
28819
|
return content.flatMap((entry) => {
|
|
28370
|
-
const record2 =
|
|
28820
|
+
const record2 = asRecord2(entry);
|
|
28371
28821
|
if (!record2) {
|
|
28372
28822
|
return [];
|
|
28373
28823
|
}
|
|
@@ -28400,7 +28850,7 @@ function textParts(value) {
|
|
|
28400
28850
|
if (typeof entry === "string") {
|
|
28401
28851
|
return entry.length > 0 ? [entry] : [];
|
|
28402
28852
|
}
|
|
28403
|
-
const record2 =
|
|
28853
|
+
const record2 = asRecord2(entry);
|
|
28404
28854
|
if (!record2) {
|
|
28405
28855
|
return [];
|
|
28406
28856
|
}
|
|
@@ -28492,7 +28942,7 @@ function parseFunctionArguments(value) {
|
|
|
28492
28942
|
}
|
|
28493
28943
|
function rawInputForFunctionCall(name, args) {
|
|
28494
28944
|
if (name === "exec_command") {
|
|
28495
|
-
const record2 =
|
|
28945
|
+
const record2 = asRecord2(args);
|
|
28496
28946
|
if (record2) {
|
|
28497
28947
|
return {
|
|
28498
28948
|
command: stringValue(record2["cmd"]) ?? stringValue(record2["command"]),
|
|
@@ -28539,14 +28989,14 @@ function functionCallUsesTerminal(item) {
|
|
|
28539
28989
|
return item["name"] === "exec_command";
|
|
28540
28990
|
}
|
|
28541
28991
|
function commandFromFunctionArguments(args) {
|
|
28542
|
-
const record2 =
|
|
28992
|
+
const record2 = asRecord2(args);
|
|
28543
28993
|
if (!record2) {
|
|
28544
28994
|
return null;
|
|
28545
28995
|
}
|
|
28546
28996
|
return stringValue(record2["cmd"]) ?? stringValue(record2["command"]);
|
|
28547
28997
|
}
|
|
28548
28998
|
function cwdFromFunctionArguments(args) {
|
|
28549
|
-
const record2 =
|
|
28999
|
+
const record2 = asRecord2(args);
|
|
28550
29000
|
if (!record2) {
|
|
28551
29001
|
return "";
|
|
28552
29002
|
}
|
|
@@ -28991,10 +29441,10 @@ function baseCommandName(commandName) {
|
|
|
28991
29441
|
return commandName.split(/[\\/]/).pop() ?? commandName;
|
|
28992
29442
|
}
|
|
28993
29443
|
function absolutizePath(cwd, targetPath) {
|
|
28994
|
-
if (
|
|
29444
|
+
if (path7.isAbsolute(targetPath) || cwd.length === 0) {
|
|
28995
29445
|
return targetPath;
|
|
28996
29446
|
}
|
|
28997
|
-
return
|
|
29447
|
+
return path7.join(cwd, targetPath);
|
|
28998
29448
|
}
|
|
28999
29449
|
function withTerminalContent(event, terminalId, cwd) {
|
|
29000
29450
|
const { rawInput, ...eventWithoutRawInput } = event;
|
|
@@ -29018,7 +29468,7 @@ function outputText(output) {
|
|
|
29018
29468
|
return "";
|
|
29019
29469
|
}
|
|
29020
29470
|
return output.flatMap((entry) => {
|
|
29021
|
-
const record2 =
|
|
29471
|
+
const record2 = asRecord2(entry);
|
|
29022
29472
|
if (!record2) {
|
|
29023
29473
|
return [];
|
|
29024
29474
|
}
|
|
@@ -29034,7 +29484,7 @@ function outputText(output) {
|
|
|
29034
29484
|
}).join("\n");
|
|
29035
29485
|
}
|
|
29036
29486
|
function parseExitCode(rawOutput, output) {
|
|
29037
|
-
const record2 =
|
|
29487
|
+
const record2 = asRecord2(rawOutput);
|
|
29038
29488
|
if (record2) {
|
|
29039
29489
|
const exitCode2 = numberValue(record2["exit_code"]) ?? numberValue(record2["exitCode"]);
|
|
29040
29490
|
if (exitCode2 !== null) {
|
|
@@ -29065,7 +29515,7 @@ function looksLikeCommandFailure(output) {
|
|
|
29065
29515
|
}
|
|
29066
29516
|
return /(^|\n)(Error|Failed|Command failed|Sandbox error|No such file or directory|Permission denied|Operation not permitted|ENOENT|EACCES)(:|\b)/i.test(trimmed);
|
|
29067
29517
|
}
|
|
29068
|
-
function
|
|
29518
|
+
function asRecord2(value) {
|
|
29069
29519
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
29070
29520
|
return null;
|
|
29071
29521
|
}
|
|
@@ -29154,12 +29604,18 @@ import { randomUUID as randomUUID2 } from "node:crypto";
|
|
|
29154
29604
|
var IMPLEMENT_PLAN_OPTION_ID = "implement_plan";
|
|
29155
29605
|
var REVISE_PLAN_OPTION_ID = "revise_plan";
|
|
29156
29606
|
var CODEX_PROCESS_EXITED_ERROR_CODE = 1001;
|
|
29157
|
-
function
|
|
29607
|
+
function clientSupportsAirCapability(capabilities, capability) {
|
|
29158
29608
|
const jetbrains = capabilities?._meta?.[JETBRAINS_META_KEY];
|
|
29159
29609
|
const air = jetbrains?.[AIR_META_KEY];
|
|
29160
29610
|
const version2 = air?.[AIR_EXTENSION_VERSION_KEY];
|
|
29161
29611
|
const supported = air?.[AIR_EXTENSION_CAPABILITIES_KEY];
|
|
29162
|
-
return typeof version2 === "number" && Number.isInteger(version2) && version2 >= AIR_EXTENSION_VERSION && Array.isArray(supported) && supported.includes(
|
|
29612
|
+
return typeof version2 === "number" && Number.isInteger(version2) && version2 >= AIR_EXTENSION_VERSION && Array.isArray(supported) && supported.includes(capability);
|
|
29613
|
+
}
|
|
29614
|
+
function clientSupportsTypedSessionFailures(capabilities) {
|
|
29615
|
+
return clientSupportsAirCapability(capabilities, AIR_SESSION_FAILURE_KEY);
|
|
29616
|
+
}
|
|
29617
|
+
function clientSupportsAgentFileChangeReports(capabilities) {
|
|
29618
|
+
return clientSupportsAirCapability(capabilities, AIR_AGENT_FILE_CHANGE_REPORT_KEY);
|
|
29163
29619
|
}
|
|
29164
29620
|
var CodexAcpServer = class _CodexAcpServer {
|
|
29165
29621
|
static MODEL_NAME_TOKEN_OVERRIDES = {
|
|
@@ -29264,7 +29720,10 @@ var CodexAcpServer = class _CodexAcpServer {
|
|
|
29264
29720
|
[JETBRAINS_META_KEY]: {
|
|
29265
29721
|
[AIR_META_KEY]: {
|
|
29266
29722
|
[AIR_EXTENSION_VERSION_KEY]: AIR_EXTENSION_VERSION,
|
|
29267
|
-
[AIR_EXTENSION_CAPABILITIES_KEY]: [
|
|
29723
|
+
[AIR_EXTENSION_CAPABILITIES_KEY]: [
|
|
29724
|
+
AIR_SESSION_FAILURE_KEY,
|
|
29725
|
+
AIR_AGENT_FILE_CHANGE_REPORT_KEY
|
|
29726
|
+
]
|
|
29268
29727
|
}
|
|
29269
29728
|
}
|
|
29270
29729
|
}
|
|
@@ -30315,6 +30774,42 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30315
30774
|
title
|
|
30316
30775
|
});
|
|
30317
30776
|
}
|
|
30777
|
+
async publishAgentFileChangeReport(sessionState, turnId, request, unavailableReason, signal) {
|
|
30778
|
+
let report;
|
|
30779
|
+
try {
|
|
30780
|
+
report = turnId === null ? createUnavailableAgentFileChangeReport(request.requestId, unavailableReason) : await this.codexAcpClient.runAgentFileChangeReport({
|
|
30781
|
+
sessionId: sessionState.sessionId,
|
|
30782
|
+
turnId,
|
|
30783
|
+
// The client owns request-id correlation and duplicate suppression. The wrapper
|
|
30784
|
+
// stays stateless so a retried ACP prompt still receives a terminal report.
|
|
30785
|
+
requestId: request.requestId,
|
|
30786
|
+
workspace: {
|
|
30787
|
+
cwd: sessionState.cwd,
|
|
30788
|
+
additionalDirectories: sessionState.additionalDirectories
|
|
30789
|
+
},
|
|
30790
|
+
signal
|
|
30791
|
+
});
|
|
30792
|
+
} catch (error51) {
|
|
30793
|
+
logger.error("Agent file-change report failed unexpectedly", error51);
|
|
30794
|
+
report = createUnavailableAgentFileChangeReport(request.requestId, "providerError");
|
|
30795
|
+
}
|
|
30796
|
+
try {
|
|
30797
|
+
const session = new ACPSessionConnection(this.connection, sessionState.sessionId);
|
|
30798
|
+
await session.update({
|
|
30799
|
+
sessionUpdate: "session_info_update",
|
|
30800
|
+
_meta: {
|
|
30801
|
+
[JETBRAINS_META_KEY]: {
|
|
30802
|
+
[AIR_META_KEY]: {
|
|
30803
|
+
[AIR_EXTENSION_VERSION_KEY]: AIR_EXTENSION_VERSION,
|
|
30804
|
+
[AIR_AGENT_FILE_CHANGE_REPORT_KEY]: report
|
|
30805
|
+
}
|
|
30806
|
+
}
|
|
30807
|
+
}
|
|
30808
|
+
});
|
|
30809
|
+
} catch (error51) {
|
|
30810
|
+
logger.error("Failed to publish agent file-change report", error51);
|
|
30811
|
+
}
|
|
30812
|
+
}
|
|
30318
30813
|
createPromptFallbackTitle(prompt) {
|
|
30319
30814
|
return this.normalizeSessionTitle(prompt.filter((block) => block.type === "text").map((block) => block.text).join(" "));
|
|
30320
30815
|
}
|
|
@@ -30449,8 +30944,8 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30449
30944
|
return `[@${name}](${uri})`;
|
|
30450
30945
|
}
|
|
30451
30946
|
if (uri.startsWith("file://")) {
|
|
30452
|
-
const
|
|
30453
|
-
const fileName =
|
|
30947
|
+
const path8 = uri.replace("file://", "");
|
|
30948
|
+
const fileName = path8.split("/").pop() ?? path8;
|
|
30454
30949
|
return `[@${fileName}](${uri})`;
|
|
30455
30950
|
}
|
|
30456
30951
|
return uri;
|
|
@@ -30703,6 +31198,9 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30703
31198
|
prompt: params.prompt
|
|
30704
31199
|
});
|
|
30705
31200
|
const sessionState = this.getSessionState(params.sessionId);
|
|
31201
|
+
const agentFileChangeReportRequest = clientSupportsAgentFileChangeReports(this.clientCapabilities) ? parseAgentFileChangeReportRequest(params._meta) : null;
|
|
31202
|
+
let agentFileChangeReportTurnId = null;
|
|
31203
|
+
let agentFileChangeReportUnavailableReason = "providerError";
|
|
30706
31204
|
let recoverableSessionFailure = sessionState.sessionFailure;
|
|
30707
31205
|
sessionState.currentTurnId = null;
|
|
30708
31206
|
sessionState.lastTokenUsage = null;
|
|
@@ -30725,6 +31223,11 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30725
31223
|
await handler.clearSessionFailure();
|
|
30726
31224
|
}
|
|
30727
31225
|
};
|
|
31226
|
+
const cancelledPromptResponse = () => {
|
|
31227
|
+
agentFileChangeReportTurnId = null;
|
|
31228
|
+
agentFileChangeReportUnavailableReason = "cancelled";
|
|
31229
|
+
return this.cancelledPromptResponse(sessionState);
|
|
31230
|
+
};
|
|
30728
31231
|
try {
|
|
30729
31232
|
const promptEventHandler = new CodexEventHandler(
|
|
30730
31233
|
this.connection,
|
|
@@ -30759,7 +31262,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30759
31262
|
elicitationHandler
|
|
30760
31263
|
);
|
|
30761
31264
|
if (activePrompt.signal.aborted) {
|
|
30762
|
-
return
|
|
31265
|
+
return cancelledPromptResponse();
|
|
30763
31266
|
}
|
|
30764
31267
|
const commandPromise = this.availableCommands.tryHandleCommand(params.prompt, sessionState, {
|
|
30765
31268
|
onTurnStartPending: () => {
|
|
@@ -30800,7 +31303,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30800
31303
|
this.cancelBeforeTurnStarted(activePrompt)
|
|
30801
31304
|
]);
|
|
30802
31305
|
if (commandResult === null) {
|
|
30803
|
-
return
|
|
31306
|
+
return cancelledPromptResponse();
|
|
30804
31307
|
}
|
|
30805
31308
|
if (commandResult.handled) {
|
|
30806
31309
|
promptNotificationsActive = false;
|
|
@@ -30812,7 +31315,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30812
31315
|
await eventHandler.handleFailedTurn(commandResult.turnCompleted.turn);
|
|
30813
31316
|
}
|
|
30814
31317
|
if (commandResult.turnCompleted?.turn.status === "interrupted") {
|
|
30815
|
-
return
|
|
31318
|
+
return cancelledPromptResponse();
|
|
30816
31319
|
}
|
|
30817
31320
|
const error52 = eventHandler.getFailure();
|
|
30818
31321
|
if (error52) {
|
|
@@ -30826,6 +31329,11 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30826
31329
|
if (terminalFailure2) {
|
|
30827
31330
|
return terminalFailure2;
|
|
30828
31331
|
}
|
|
31332
|
+
if (commandResult.turnCompleted?.turn.status === "completed") {
|
|
31333
|
+
agentFileChangeReportTurnId = commandResult.turnCompleted.turn.id;
|
|
31334
|
+
} else if (commandResult.turnCompleted === void 0) {
|
|
31335
|
+
agentFileChangeReportUnavailableReason = "notReported";
|
|
31336
|
+
}
|
|
30829
31337
|
await clearRecoveredSessionFailure(eventHandler);
|
|
30830
31338
|
return {
|
|
30831
31339
|
stopReason: "end_turn",
|
|
@@ -30835,7 +31343,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30835
31343
|
}
|
|
30836
31344
|
const effectiveParams = commandResult.prompt === void 0 ? params : { ...params, prompt: commandResult.prompt };
|
|
30837
31345
|
if (this.sessionIsClosing(params.sessionId)) {
|
|
30838
|
-
return
|
|
31346
|
+
return cancelledPromptResponse();
|
|
30839
31347
|
}
|
|
30840
31348
|
const modelId = ModelId.fromString(sessionState.currentModelId);
|
|
30841
31349
|
const modelLacksReasoning = sessionState.supportedReasoningEfforts.length > 0 && sessionState.supportedReasoningEfforts.every((e) => e.reasoningEffort === "none");
|
|
@@ -30889,7 +31397,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30889
31397
|
this.cancelBeforeTurnStarted(activePrompt)
|
|
30890
31398
|
]);
|
|
30891
31399
|
if (turnCompleted === null) {
|
|
30892
|
-
return
|
|
31400
|
+
return cancelledPromptResponse();
|
|
30893
31401
|
}
|
|
30894
31402
|
await this.codexAcpClient.waitForSessionNotifications(params.sessionId);
|
|
30895
31403
|
await eventHandler.flushPendingErrors();
|
|
@@ -30897,7 +31405,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30897
31405
|
promptNotificationsActive = false;
|
|
30898
31406
|
if (turnCompleted.turn.status === "interrupted") {
|
|
30899
31407
|
await eventHandler.flushPendingPlanUpdates();
|
|
30900
|
-
return
|
|
31408
|
+
return cancelledPromptResponse();
|
|
30901
31409
|
}
|
|
30902
31410
|
const error51 = eventHandler.getFailure();
|
|
30903
31411
|
if (error51) {
|
|
@@ -30920,7 +31428,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30920
31428
|
activePrompt.signal
|
|
30921
31429
|
);
|
|
30922
31430
|
if (this.promptShouldStop(params.sessionId, activePrompt)) {
|
|
30923
|
-
return
|
|
31431
|
+
return cancelledPromptResponse();
|
|
30924
31432
|
}
|
|
30925
31433
|
if (approved && !this.promptShouldStop(params.sessionId, activePrompt)) {
|
|
30926
31434
|
await this.applyCollaborationModeChange(sessionState, DEFAULT_COLLABORATION_MODE);
|
|
@@ -30969,7 +31477,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30969
31477
|
this.cancelBeforeTurnStarted(activePrompt)
|
|
30970
31478
|
]);
|
|
30971
31479
|
if (turnCompleted === null) {
|
|
30972
|
-
return
|
|
31480
|
+
return cancelledPromptResponse();
|
|
30973
31481
|
}
|
|
30974
31482
|
await this.codexAcpClient.waitForSessionNotifications(params.sessionId);
|
|
30975
31483
|
await eventHandler.flushPendingErrors();
|
|
@@ -30977,7 +31485,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30977
31485
|
promptNotificationsActive = false;
|
|
30978
31486
|
if (turnCompleted.turn.status === "interrupted") {
|
|
30979
31487
|
await eventHandler.flushPendingPlanUpdates();
|
|
30980
|
-
return
|
|
31488
|
+
return cancelledPromptResponse();
|
|
30981
31489
|
}
|
|
30982
31490
|
const implementationError = eventHandler.getFailure();
|
|
30983
31491
|
if (implementationError) {
|
|
@@ -30993,6 +31501,9 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30993
31501
|
}
|
|
30994
31502
|
}
|
|
30995
31503
|
}
|
|
31504
|
+
if (turnCompleted.turn.status === "completed") {
|
|
31505
|
+
agentFileChangeReportTurnId = turnCompleted.turn.id;
|
|
31506
|
+
}
|
|
30996
31507
|
await clearRecoveredSessionFailure(eventHandler);
|
|
30997
31508
|
await this.publishFallbackSessionTitle(
|
|
30998
31509
|
sessionState,
|
|
@@ -31006,8 +31517,10 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
31006
31517
|
} catch (err) {
|
|
31007
31518
|
logger.error(`Prompt for session ${params.sessionId} failed`, err);
|
|
31008
31519
|
if (activePrompt.signal.aborted || this.sessionIsClosing(params.sessionId)) {
|
|
31009
|
-
return
|
|
31520
|
+
return cancelledPromptResponse();
|
|
31010
31521
|
}
|
|
31522
|
+
agentFileChangeReportTurnId = null;
|
|
31523
|
+
agentFileChangeReportUnavailableReason = "providerError";
|
|
31011
31524
|
const isProcessExit = err instanceof RequestError && err.code === CODEX_PROCESS_EXITED_ERROR_CODE;
|
|
31012
31525
|
const isUnexpectedFailure = !(err instanceof RequestError);
|
|
31013
31526
|
if (eventHandler !== null && clientSupportsTypedSessionFailures(this.clientCapabilities) && (isProcessExit || isUnexpectedFailure)) {
|
|
@@ -31028,6 +31541,15 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
31028
31541
|
throw err;
|
|
31029
31542
|
} finally {
|
|
31030
31543
|
promptNotificationsActive = false;
|
|
31544
|
+
if (agentFileChangeReportRequest !== null) {
|
|
31545
|
+
await this.publishAgentFileChangeReport(
|
|
31546
|
+
sessionState,
|
|
31547
|
+
agentFileChangeReportTurnId,
|
|
31548
|
+
agentFileChangeReportRequest,
|
|
31549
|
+
agentFileChangeReportUnavailableReason,
|
|
31550
|
+
activePrompt.signal
|
|
31551
|
+
);
|
|
31552
|
+
}
|
|
31031
31553
|
logger.log("Prompt completed", { sessionId: params.sessionId });
|
|
31032
31554
|
await eventHandler?.dispose();
|
|
31033
31555
|
disposePromptRequestCancellation();
|
|
@@ -31590,6 +32112,9 @@ var CodexAppServerClient = class {
|
|
|
31590
32112
|
async threadResume(params) {
|
|
31591
32113
|
return await this.sendRequest({ method: "thread/resume", params });
|
|
31592
32114
|
}
|
|
32115
|
+
async threadFork(params) {
|
|
32116
|
+
return await this.sendRequest({ method: "thread/fork", params });
|
|
32117
|
+
}
|
|
31593
32118
|
getThreadSettings(threadId) {
|
|
31594
32119
|
return this.threadSettings.get(threadId);
|
|
31595
32120
|
}
|