@agentclientprotocol/codex-acp 1.11.1-preview.5 → 1.12.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.
Files changed (2) hide show
  1. package/dist/index.js +391 -495
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -24200,6 +24200,305 @@ function mergeRateLimitSnapshot(previous, update) {
24200
24200
  };
24201
24201
  }
24202
24202
 
24203
+ // src/AgentFileChangeReport.ts
24204
+ import fs2 from "node:fs";
24205
+ import path3 from "node:path";
24206
+ var AGENT_FILE_CHANGE_REPORT_VERSION = 1;
24207
+ var AGENT_FILE_CHANGE_REPORT_MAX_PATHS = 1024;
24208
+ var AGENT_FILE_CHANGE_REPORT_MAX_PATH_LENGTH = 4096;
24209
+ var AGENT_FILE_CHANGE_REPORT_MAX_TOTAL_BYTES = 256 * 1024;
24210
+ var AGENT_FILE_CHANGE_REPORT_MAX_DIFF_BYTES = 8 * 1024 * 1024;
24211
+ var TURN_DIFF_UNCERTAINTY = "Codex turn diffs may omit same-content renames and changes made outside apply_patch, including shell commands, version-control commands, generators, and child processes.";
24212
+ function captureAgentFileChangeWorkspace(cwd, additionalDirectories) {
24213
+ const lexicalCwd = parseWorkspaceRoot(cwd);
24214
+ return {
24215
+ cwd,
24216
+ additionalDirectories: [...additionalDirectories],
24217
+ diffRoot: lexicalCwd === null ? cwd : findDiffDisplayRoot(lexicalCwd).value
24218
+ };
24219
+ }
24220
+ function parseAgentFileChangeReportRequest(meta3) {
24221
+ const jetbrains = asRecord2(meta3?.[JETBRAINS_META_KEY]);
24222
+ const air = asRecord2(jetbrains?.[AIR_META_KEY]);
24223
+ const request = asRecord2(air?.[AIR_AGENT_FILE_CHANGE_REPORT_REQUEST_KEY]);
24224
+ if (request === null || !hasOnlyKeys(request, ["version", "requestId"]) || request["version"] !== AGENT_FILE_CHANGE_REPORT_VERSION) {
24225
+ return null;
24226
+ }
24227
+ const requestId = request["requestId"];
24228
+ if (typeof requestId !== "string" || !/^[A-Za-z0-9._:-]{1,128}$/.test(requestId)) {
24229
+ return null;
24230
+ }
24231
+ return { version: AGENT_FILE_CHANGE_REPORT_VERSION, requestId };
24232
+ }
24233
+ function createReportedAgentFileChangeReport(requestId, diff, workspace) {
24234
+ if (Buffer.byteLength(diff, "utf8") > AGENT_FILE_CHANGE_REPORT_MAX_DIFF_BYTES) {
24235
+ throw new AgentFileChangeReportError("invalidOutput", "The turn diff exceeds the parser input limit");
24236
+ }
24237
+ const parsedReport = parseTurnDiff(diff);
24238
+ const normalized = normalizeFileChangeReport(parsedReport, workspace);
24239
+ return fitReportedAgentFileChangeReport({
24240
+ version: AGENT_FILE_CHANGE_REPORT_VERSION,
24241
+ requestId,
24242
+ status: "reported",
24243
+ ...normalized
24244
+ });
24245
+ }
24246
+ function createUnavailableAgentFileChangeReport(requestId, reason) {
24247
+ return {
24248
+ version: AGENT_FILE_CHANGE_REPORT_VERSION,
24249
+ requestId,
24250
+ status: "unavailable",
24251
+ reason
24252
+ };
24253
+ }
24254
+ var AgentFileChangeReportError = class extends Error {
24255
+ reason;
24256
+ constructor(reason, message) {
24257
+ super(message);
24258
+ this.name = "AgentFileChangeReportError";
24259
+ this.reason = reason;
24260
+ }
24261
+ };
24262
+ function parseTurnDiff(diff) {
24263
+ if (diff.trim() === "") {
24264
+ return { paths: [], complete: false, uncertainty: TURN_DIFF_UNCERTAINTY };
24265
+ }
24266
+ let patches;
24267
+ try {
24268
+ patches = parsePatch(diff);
24269
+ } catch (error51) {
24270
+ throw new AgentFileChangeReportError(
24271
+ "invalidOutput",
24272
+ `The turn diff is not valid unified diff: ${error51 instanceof Error ? error51.message : String(error51)}`
24273
+ );
24274
+ }
24275
+ if (patches.length === 0) {
24276
+ throw new AgentFileChangeReportError("invalidOutput", "The turn diff contains no parseable file patches");
24277
+ }
24278
+ const rawFileHeaders = extractRawFileHeaders(diff);
24279
+ const paths = [];
24280
+ for (const [index, patch] of patches.entries()) {
24281
+ const rawHeaders = rawFileHeaders[index];
24282
+ const oldPath = normalizeDiffPath(selectLosslessFileName(rawHeaders?.oldFileName, patch.oldFileName));
24283
+ const newPath = normalizeDiffPath(selectLosslessFileName(rawHeaders?.newFileName, patch.newFileName));
24284
+ if (oldPath === null && newPath === null) {
24285
+ throw new AgentFileChangeReportError("invalidOutput", "The turn diff contains a patch without a file path");
24286
+ }
24287
+ if (oldPath !== null) paths.push(oldPath);
24288
+ if (newPath !== null) paths.push(newPath);
24289
+ }
24290
+ return { paths, complete: false, uncertainty: TURN_DIFF_UNCERTAINTY };
24291
+ }
24292
+ function extractRawFileHeaders(diff) {
24293
+ return diff.split(/(?=^diff --git )/m).filter((section) => section.trim() !== "").map((section) => {
24294
+ const lines = section.split(/\r?\n/);
24295
+ for (let index = 0; index < lines.length; index += 1) {
24296
+ const line = lines[index];
24297
+ if (line?.startsWith("@@ ")) return null;
24298
+ const nextLine = lines[index + 1];
24299
+ if (line?.startsWith("--- ") && nextLine?.startsWith("+++ ")) {
24300
+ return {
24301
+ oldFileName: line.slice(4),
24302
+ newFileName: nextLine.slice(4)
24303
+ };
24304
+ }
24305
+ }
24306
+ return null;
24307
+ });
24308
+ }
24309
+ function selectLosslessFileName(rawFileName, parsedFileName) {
24310
+ return rawFileName === void 0 || rawFileName.startsWith('"') ? parsedFileName : rawFileName;
24311
+ }
24312
+ function normalizeDiffPath(value) {
24313
+ if (value === void 0 || value === "/dev/null") return null;
24314
+ return value.startsWith("a/") || value.startsWith("b/") ? value.slice(2) : value;
24315
+ }
24316
+ function fitReportedAgentFileChangeReport(report) {
24317
+ const paths = [...report.paths];
24318
+ let truncated = report.truncated;
24319
+ let fitted = report;
24320
+ while (Buffer.byteLength(JSON.stringify(fitted), "utf8") > AGENT_FILE_CHANGE_REPORT_MAX_TOTAL_BYTES) {
24321
+ if (paths.length === 0) {
24322
+ throw new AgentFileChangeReportError("invalidOutput", "The audit report exceeds the wire limit");
24323
+ }
24324
+ paths.pop();
24325
+ truncated = true;
24326
+ fitted = {
24327
+ ...report,
24328
+ paths: [...paths],
24329
+ declaredComplete: false,
24330
+ truncated
24331
+ };
24332
+ }
24333
+ return fitted;
24334
+ }
24335
+ function normalizeFileChangeReport(report, workspace) {
24336
+ const lexicalCwd = parseWorkspaceRoot(workspace.cwd);
24337
+ if (lexicalCwd === null) {
24338
+ throw new AgentFileChangeReportError("providerError", "The session working directory is not absolute");
24339
+ }
24340
+ const cwd = canonicalizeWorkspaceRoot(lexicalCwd);
24341
+ const diffRoot = parseWorkspaceRoot(workspace.diffRoot);
24342
+ if (diffRoot === null || diffRoot.flavor !== cwd.flavor) {
24343
+ throw new AgentFileChangeReportError("providerError", "The captured turn-diff root is invalid");
24344
+ }
24345
+ const roots = [cwd, ...workspace.additionalDirectories.flatMap((directory) => {
24346
+ const root = normalizeWorkspaceRoot(directory);
24347
+ return root === null || root.flavor !== cwd.flavor ? [] : [root];
24348
+ })];
24349
+ const paths = [];
24350
+ const seen = /* @__PURE__ */ new Set();
24351
+ let totalBytes = 0;
24352
+ let truncated = false;
24353
+ for (const reportedPath of report.paths) {
24354
+ if (reportedPath.length > AGENT_FILE_CHANGE_REPORT_MAX_PATH_LENGTH) {
24355
+ truncated = true;
24356
+ continue;
24357
+ }
24358
+ const normalized = normalizeReportedPath(reportedPath, diffRoot, roots);
24359
+ if (normalized === null || normalized.value.length > AGENT_FILE_CHANGE_REPORT_MAX_PATH_LENGTH) {
24360
+ truncated = true;
24361
+ continue;
24362
+ }
24363
+ const key = normalized.flavor === "windows" ? normalized.value.toLowerCase() : normalized.value;
24364
+ if (seen.has(key)) {
24365
+ continue;
24366
+ }
24367
+ const bytes = Buffer.byteLength(normalized.value, "utf8");
24368
+ if (paths.length >= AGENT_FILE_CHANGE_REPORT_MAX_PATHS || totalBytes + bytes > AGENT_FILE_CHANGE_REPORT_MAX_TOTAL_BYTES) {
24369
+ truncated = true;
24370
+ continue;
24371
+ }
24372
+ seen.add(key);
24373
+ paths.push(normalized.value);
24374
+ totalBytes += bytes;
24375
+ }
24376
+ return {
24377
+ paths,
24378
+ declaredComplete: report.complete && !truncated,
24379
+ truncated,
24380
+ ...report.uncertainty ? { uncertainty: report.uncertainty } : {}
24381
+ };
24382
+ }
24383
+ function normalizeWorkspaceRoot(value) {
24384
+ const root = parseWorkspaceRoot(value);
24385
+ return root === null ? null : canonicalizeWorkspaceRoot(root);
24386
+ }
24387
+ function parseWorkspaceRoot(value) {
24388
+ const trimmed = value.trim();
24389
+ if (!isValidPathText(trimmed)) {
24390
+ return null;
24391
+ }
24392
+ if (isWindowsAbsolutePath(trimmed)) {
24393
+ return {
24394
+ value: path3.win32.normalize(trimmed.replace(/\//g, "\\")),
24395
+ flavor: "windows"
24396
+ };
24397
+ }
24398
+ if (path3.posix.isAbsolute(trimmed)) {
24399
+ return {
24400
+ value: path3.posix.normalize(trimmed.replace(/\\/g, "/")),
24401
+ flavor: "posix"
24402
+ };
24403
+ }
24404
+ return null;
24405
+ }
24406
+ function normalizeReportedPath(value, relativeRoot, roots) {
24407
+ if (!isValidPathText(value) || /^[A-Za-z]:[^\\/]/.test(value) || /^\\\\[?.]\\/.test(value) || /^(?:\\\\|\/\/)/.test(value) && !isWindowsAbsolutePath(value) || relativeRoot.flavor === "windows" && /^\\(?!\\)/.test(value) || /^[A-Za-z][A-Za-z0-9+.-]*:\/\//.test(value)) {
24408
+ return null;
24409
+ }
24410
+ let candidate;
24411
+ if (isWindowsAbsolutePath(value)) {
24412
+ candidate = { value: path3.win32.normalize(value.replace(/\//g, "\\")), flavor: "windows" };
24413
+ } else if (path3.posix.isAbsolute(value)) {
24414
+ candidate = { value: path3.posix.normalize(value.replace(/\\/g, "/")), flavor: "posix" };
24415
+ } else if (relativeRoot.flavor === "windows") {
24416
+ candidate = {
24417
+ value: path3.win32.resolve(relativeRoot.value, value.replace(/\//g, "\\")),
24418
+ flavor: "windows"
24419
+ };
24420
+ } else {
24421
+ candidate = {
24422
+ value: path3.posix.resolve(relativeRoot.value, value.replace(/\\/g, "/")),
24423
+ flavor: "posix"
24424
+ };
24425
+ }
24426
+ candidate = canonicalizeReportedPath(candidate);
24427
+ return roots.some((root) => pathIsStrictlyInside(root, candidate)) ? candidate : null;
24428
+ }
24429
+ function findDiffDisplayRoot(cwd) {
24430
+ if (!isNativePathFlavor(cwd.flavor)) return cwd;
24431
+ const pathImplementation = cwd.flavor === "windows" ? path3.win32 : path3.posix;
24432
+ let current = cwd.value;
24433
+ while (true) {
24434
+ if (fs2.existsSync(pathImplementation.join(current, ".git"))) {
24435
+ return canonicalizeWorkspaceRoot({ value: current, flavor: cwd.flavor });
24436
+ }
24437
+ const parent = pathImplementation.dirname(current);
24438
+ if (parent === current) return cwd;
24439
+ current = parent;
24440
+ }
24441
+ }
24442
+ function canonicalizeWorkspaceRoot(root) {
24443
+ if (!isNativePathFlavor(root.flavor)) {
24444
+ return root;
24445
+ }
24446
+ return { ...root, value: canonicalizeFromExistingAncestor(root.value) };
24447
+ }
24448
+ function canonicalizeReportedPath(candidate) {
24449
+ if (!isNativePathFlavor(candidate.flavor)) {
24450
+ return candidate;
24451
+ }
24452
+ const parent = canonicalizeFromExistingAncestor(path3.dirname(candidate.value));
24453
+ return { ...candidate, value: path3.resolve(parent, path3.basename(candidate.value)) };
24454
+ }
24455
+ function canonicalizeFromExistingAncestor(value) {
24456
+ const original = path3.resolve(value);
24457
+ let current = original;
24458
+ const missingSegments = [];
24459
+ while (true) {
24460
+ try {
24461
+ const canonical = fs2.realpathSync.native(current);
24462
+ return path3.resolve(canonical, ...missingSegments.reverse());
24463
+ } catch (error51) {
24464
+ if (!isMissingPathError(error51)) return original;
24465
+ }
24466
+ const parent = path3.dirname(current);
24467
+ if (parent === current) return original;
24468
+ missingSegments.push(path3.basename(current));
24469
+ current = parent;
24470
+ }
24471
+ }
24472
+ function isMissingPathError(error51) {
24473
+ if (typeof error51 !== "object" || error51 === null || !("code" in error51)) return false;
24474
+ return error51.code === "ENOENT" || error51.code === "ENOTDIR";
24475
+ }
24476
+ function isNativePathFlavor(flavor) {
24477
+ return process.platform === "win32" ? flavor === "windows" : flavor === "posix";
24478
+ }
24479
+ function pathIsStrictlyInside(root, candidate) {
24480
+ if (root.flavor !== candidate.flavor) {
24481
+ return false;
24482
+ }
24483
+ const pathImplementation = root.flavor === "windows" ? path3.win32 : path3.posix;
24484
+ const relative = pathImplementation.relative(root.value, candidate.value);
24485
+ return relative.length > 0 && !pathImplementation.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${pathImplementation.sep}`);
24486
+ }
24487
+ function isWindowsAbsolutePath(value) {
24488
+ const portable = value.replace(/\\/g, "/");
24489
+ return /^[A-Za-z]:\//.test(portable) || /^\/\/[^/]+\/[^/]+(?:\/|$)/.test(portable);
24490
+ }
24491
+ function isValidPathText(value) {
24492
+ return value.length > 0 && !/[\u0000-\u001F\u007F-\u009F]/.test(value);
24493
+ }
24494
+ function asRecord2(value) {
24495
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
24496
+ }
24497
+ function hasOnlyKeys(value, allowed) {
24498
+ const allowedKeys = new Set(allowed);
24499
+ return Object.keys(value).every((key) => allowedKeys.has(key));
24500
+ }
24501
+
24203
24502
  // src/CodexEventHandler.ts
24204
24503
  var MAX_SESSION_FAILURE_TITLE_LENGTH = 240;
24205
24504
  var SESSION_FAILURE_POLICY = {
@@ -24307,6 +24606,9 @@ var CodexEventHandler = class _CodexEventHandler {
24307
24606
  terminalCommandIds = /* @__PURE__ */ new Set();
24308
24607
  terminalCommandOutputIds = /* @__PURE__ */ new Set();
24309
24608
  agentMessagePhases = /* @__PURE__ */ new Map();
24609
+ turnDiffs = /* @__PURE__ */ new Map();
24610
+ oversizedTurnDiffs = /* @__PURE__ */ new Set();
24611
+ collectTurnDiffs;
24310
24612
  subagents;
24311
24613
  /** Connection-level `authStatus` sink; the app-server account push feeds it. */
24312
24614
  onAccountUpdated;
@@ -24314,7 +24616,7 @@ var CodexEventHandler = class _CodexEventHandler {
24314
24616
  sessionState.sessionId,
24315
24617
  false,
24316
24618
  new ACPSessionConnection(connection, sessionState.sessionId)
24317
- ), onAccountUpdated) {
24619
+ ), onAccountUpdated, collectTurnDiffs = false) {
24318
24620
  this.onAccountUpdated = onAccountUpdated;
24319
24621
  this.sessionState = sessionState;
24320
24622
  this.supportsPlanUpdates = supportsPlanUpdates;
@@ -24322,6 +24624,7 @@ var CodexEventHandler = class _CodexEventHandler {
24322
24624
  this.sessionFailureEpoch = sessionFailureEpoch;
24323
24625
  this.session = new ACPSessionConnection(connection, sessionState.sessionId);
24324
24626
  this.subagents = subagents;
24627
+ this.collectTurnDiffs = collectTurnDiffs;
24325
24628
  if (sessionState.sessionFailure !== void 0) {
24326
24629
  this.failuresById.set(sessionState.sessionFailure.id, sessionState.sessionFailure);
24327
24630
  }
@@ -24329,6 +24632,12 @@ var CodexEventHandler = class _CodexEventHandler {
24329
24632
  getFailure() {
24330
24633
  return this.failure;
24331
24634
  }
24635
+ getTurnDiff(turnId) {
24636
+ return this.turnDiffs.get(turnId) ?? "";
24637
+ }
24638
+ isTurnDiffOversized(turnId) {
24639
+ return this.oversizedTurnDiffs.has(turnId);
24640
+ }
24332
24641
  getTerminalSessionFailureMeta(turnId, allowUnattributed = false) {
24333
24642
  const failure = this.sessionState.sessionFailure;
24334
24643
  if (!this.supportsTypedSessionFailures || failure === void 0 || (this.failureTurnIdById.get(failure.id) === void 0 ? !allowUnattributed : turnId === null || this.failureTurnIdById.get(failure.id) !== turnId)) {
@@ -24488,6 +24797,8 @@ var CodexEventHandler = class _CodexEventHandler {
24488
24797
  this.pendingPlanItemIds.clear();
24489
24798
  this.planDeltaTextByItemId.clear();
24490
24799
  this.lastEmittedPlanTextByItemId.clear();
24800
+ this.turnDiffs.clear();
24801
+ this.oversizedTurnDiffs.clear();
24491
24802
  }
24492
24803
  async createUpdateEvent(notification) {
24493
24804
  switch (notification.method) {
@@ -24506,6 +24817,20 @@ var CodexEventHandler = class _CodexEventHandler {
24506
24817
  case "turn/plan/updated":
24507
24818
  this.completeRetryIncidentOnTurnProgress();
24508
24819
  return await this.updatePlan(notification.params);
24820
+ case "turn/diff/updated":
24821
+ if (notification.params.threadId === this.sessionState.sessionId) {
24822
+ this.completeRetryIncidentOnTurnProgress();
24823
+ if (!this.disposed && this.collectTurnDiffs) {
24824
+ if (Buffer.byteLength(notification.params.diff, "utf8") > AGENT_FILE_CHANGE_REPORT_MAX_DIFF_BYTES) {
24825
+ this.turnDiffs.delete(notification.params.turnId);
24826
+ this.oversizedTurnDiffs.add(notification.params.turnId);
24827
+ } else {
24828
+ this.oversizedTurnDiffs.delete(notification.params.turnId);
24829
+ this.turnDiffs.set(notification.params.turnId, notification.params.diff);
24830
+ }
24831
+ }
24832
+ }
24833
+ return null;
24509
24834
  case "error":
24510
24835
  return await this.createErrorEvent(notification.params);
24511
24836
  case "turn/started":
@@ -24600,7 +24925,6 @@ var CodexEventHandler = class _CodexEventHandler {
24600
24925
  case "command/exec/outputDelta":
24601
24926
  case "hook/started":
24602
24927
  case "hook/completed":
24603
- case "turn/diff/updated":
24604
24928
  case "turn/moderationMetadata":
24605
24929
  case "item/fileChange/outputDelta":
24606
24930
  case "item/fileChange/patchUpdated":
@@ -26652,31 +26976,31 @@ function isCodexAuthRequest(request) {
26652
26976
 
26653
26977
  // node_modules/open/index.js
26654
26978
  import process11 from "node:process";
26655
- import path4 from "node:path";
26979
+ import path5 from "node:path";
26656
26980
  import { fileURLToPath } from "node:url";
26657
26981
  import childProcess4 from "node:child_process";
26658
- import fs6, { constants as fsConstants2 } from "node:fs/promises";
26982
+ import fs7, { constants as fsConstants2 } from "node:fs/promises";
26659
26983
 
26660
26984
  // node_modules/wsl-utils/index.js
26661
- import path3 from "node:path";
26985
+ import path4 from "node:path";
26662
26986
  import { promisify as promisify2 } from "node:util";
26663
26987
  import childProcess2 from "node:child_process";
26664
- import fs5, { constants as fsConstants } from "node:fs/promises";
26988
+ import fs6, { constants as fsConstants } from "node:fs/promises";
26665
26989
 
26666
26990
  // node_modules/is-wsl/index.js
26667
26991
  import process3 from "node:process";
26668
26992
  import os from "node:os";
26669
- import fs4 from "node:fs";
26993
+ import fs5 from "node:fs";
26670
26994
 
26671
26995
  // node_modules/is-inside-container/index.js
26672
- import fs3 from "node:fs";
26996
+ import fs4 from "node:fs";
26673
26997
 
26674
26998
  // node_modules/is-docker/index.js
26675
- import fs2 from "node:fs";
26999
+ import fs3 from "node:fs";
26676
27000
  var isDockerCached;
26677
27001
  function hasDockerEnv() {
26678
27002
  try {
26679
- fs2.statSync("/.dockerenv");
27003
+ fs3.statSync("/.dockerenv");
26680
27004
  return true;
26681
27005
  } catch {
26682
27006
  return false;
@@ -26684,7 +27008,7 @@ function hasDockerEnv() {
26684
27008
  }
26685
27009
  function hasDockerCGroup() {
26686
27010
  try {
26687
- return fs2.readFileSync("/proc/self/cgroup", "utf8").includes("docker");
27011
+ return fs3.readFileSync("/proc/self/cgroup", "utf8").includes("docker");
26688
27012
  } catch {
26689
27013
  return false;
26690
27014
  }
@@ -26700,7 +27024,7 @@ function isDocker() {
26700
27024
  var cachedResult;
26701
27025
  var hasContainerEnv = () => {
26702
27026
  try {
26703
- fs3.statSync("/run/.containerenv");
27027
+ fs4.statSync("/run/.containerenv");
26704
27028
  return true;
26705
27029
  } catch {
26706
27030
  return false;
@@ -26725,12 +27049,12 @@ var isWsl = () => {
26725
27049
  return true;
26726
27050
  }
26727
27051
  try {
26728
- if (fs4.readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft")) {
27052
+ if (fs5.readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft")) {
26729
27053
  return !isInsideContainer();
26730
27054
  }
26731
27055
  } catch {
26732
27056
  }
26733
- if (fs4.existsSync("/proc/sys/fs/binfmt_misc/WSLInterop") || fs4.existsSync("/run/WSL")) {
27057
+ if (fs5.existsSync("/proc/sys/fs/binfmt_misc/WSLInterop") || fs5.existsSync("/run/WSL")) {
26734
27058
  return !isInsideContainer();
26735
27059
  }
26736
27060
  return false;
@@ -26798,14 +27122,14 @@ var wslDrivesMountPoint = /* @__PURE__ */ (() => {
26798
27122
  const configFilePath = "/etc/wsl.conf";
26799
27123
  let isConfigFileExists = false;
26800
27124
  try {
26801
- await fs5.access(configFilePath, fsConstants.F_OK);
27125
+ await fs6.access(configFilePath, fsConstants.F_OK);
26802
27126
  isConfigFileExists = true;
26803
27127
  } catch {
26804
27128
  }
26805
27129
  if (!isConfigFileExists) {
26806
27130
  return defaultMountPoint;
26807
27131
  }
26808
- const configContent = await fs5.readFile(configFilePath, { encoding: "utf8" });
27132
+ const configContent = await fs6.readFile(configFilePath, { encoding: "utf8" });
26809
27133
  const parsedMountPoint = parseMountPointFromConfig(configContent);
26810
27134
  if (parsedMountPoint === void 0) {
26811
27135
  return defaultMountPoint;
@@ -26825,7 +27149,7 @@ var canAccessPowerShell = async () => {
26825
27149
  canAccessPowerShellPromise ??= (async () => {
26826
27150
  try {
26827
27151
  const psPath = await powerShellPath2();
26828
- await fs5.access(psPath, fsConstants.X_OK);
27152
+ await fs6.access(psPath, fsConstants.X_OK);
26829
27153
  return true;
26830
27154
  } catch {
26831
27155
  return false;
@@ -26838,7 +27162,7 @@ var wslDefaultBrowser = async () => {
26838
27162
  const command = String.raw`(Get-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice").ProgId`;
26839
27163
  const { stdout } = await executePowerShell(command, {
26840
27164
  powerShellPath: psPath,
26841
- cwd: path3.dirname(psPath)
27165
+ cwd: path4.dirname(psPath)
26842
27166
  });
26843
27167
  return stdout.trim();
26844
27168
  };
@@ -27044,8 +27368,8 @@ var is_in_ssh_default = isInSsh;
27044
27368
 
27045
27369
  // node_modules/open/index.js
27046
27370
  var fallbackAttemptSymbol = /* @__PURE__ */ Symbol("fallbackAttempt");
27047
- var __dirname = import.meta.url ? path4.dirname(fileURLToPath(import.meta.url)) : "";
27048
- var localXdgOpenPath = path4.join(__dirname, "xdg-open");
27371
+ var __dirname = import.meta.url ? path5.dirname(fileURLToPath(import.meta.url)) : "";
27372
+ var localXdgOpenPath = path5.join(__dirname, "xdg-open");
27049
27373
  var { platform, arch } = process11;
27050
27374
  var tryEachApp = async (apps2, opener) => {
27051
27375
  if (apps2.length === 0) {
@@ -27187,7 +27511,7 @@ var baseOpen = async (options) => {
27187
27511
  childProcessOptions.stdio = "ignore";
27188
27512
  }
27189
27513
  if (is_wsl_default) {
27190
- childProcessOptions.cwd = path4.dirname(command);
27514
+ childProcessOptions.cwd = path5.dirname(command);
27191
27515
  }
27192
27516
  } else {
27193
27517
  if (app) {
@@ -27196,7 +27520,7 @@ var baseOpen = async (options) => {
27196
27520
  const isBundled = !__dirname || __dirname === "/";
27197
27521
  let exeLocalXdgOpen = false;
27198
27522
  try {
27199
- await fs6.access(localXdgOpenPath, fsConstants2.X_OK);
27523
+ await fs7.access(localXdgOpenPath, fsConstants2.X_OK);
27200
27524
  exeLocalXdgOpen = true;
27201
27525
  } catch {
27202
27526
  }
@@ -27484,7 +27808,7 @@ var package_default = {
27484
27808
  publishConfig: {
27485
27809
  access: "public"
27486
27810
  },
27487
- version: "1.11.1-preview.5",
27811
+ version: "1.12.0",
27488
27812
  description: "",
27489
27813
  main: "dist/index.js",
27490
27814
  bin: {
@@ -27591,17 +27915,17 @@ function createCodexCollaborationMode(mode, currentModelId) {
27591
27915
  }
27592
27916
 
27593
27917
  // src/PathUtils.ts
27594
- import path5 from "node:path";
27918
+ import path6 from "node:path";
27595
27919
  function isAbsolutePathLike(value) {
27596
27920
  const trimmed = value.trim();
27597
- return path5.isAbsolute(trimmed) || isWindowsAbsolutePath(trimmed);
27921
+ return path6.isAbsolute(trimmed) || isWindowsAbsolutePath2(trimmed);
27598
27922
  }
27599
27923
  function arePathsEqual(left, right) {
27600
27924
  return normalizePathForComparison(left) === normalizePathForComparison(right);
27601
27925
  }
27602
27926
  function arePathBasenamesEqual(left, right) {
27603
- const leftBase = path5.posix.basename(normalizePathForComparison(left));
27604
- const rightBase = path5.posix.basename(normalizePathForComparison(right));
27927
+ const leftBase = path6.posix.basename(normalizePathForComparison(left));
27928
+ const rightBase = path6.posix.basename(normalizePathForComparison(right));
27605
27929
  if (shouldComparePathCaseInsensitive(left) || shouldComparePathCaseInsensitive(right)) {
27606
27930
  return leftBase.toLowerCase() === rightBase.toLowerCase();
27607
27931
  }
@@ -27612,20 +27936,20 @@ function normalizePathForComparison(value) {
27612
27936
  if (trimmed.length === 0) {
27613
27937
  return "";
27614
27938
  }
27615
- if (isWindowsAbsolutePath(trimmed)) {
27616
- const normalized2 = path5.win32.normalize(trimmed).replace(/\\/g, "/");
27939
+ if (isWindowsAbsolutePath2(trimmed)) {
27940
+ const normalized2 = path6.win32.normalize(trimmed).replace(/\\/g, "/");
27617
27941
  return trimTrailingPathSeparators(normalized2).toLowerCase();
27618
27942
  }
27619
- const pathForComparison = path5.isAbsolute(trimmed) ? trimmed : trimmed.replace(/\\/g, "/");
27620
- const normalized = path5.posix.normalize(pathForComparison);
27943
+ const pathForComparison = path6.isAbsolute(trimmed) ? trimmed : trimmed.replace(/\\/g, "/");
27944
+ const normalized = path6.posix.normalize(pathForComparison);
27621
27945
  return trimTrailingPathSeparators(normalized);
27622
27946
  }
27623
- function isWindowsAbsolutePath(value) {
27947
+ function isWindowsAbsolutePath2(value) {
27624
27948
  const portableValue = value.replace(/\\/g, "/");
27625
27949
  return /^[A-Za-z]:\//.test(portableValue) || /^\/\/[^/]+\/[^/]+/.test(portableValue);
27626
27950
  }
27627
27951
  function shouldComparePathCaseInsensitive(value) {
27628
- return isWindowsAbsolutePath(value) || /^[A-Za-z]:/.test(value) || value.includes("\\");
27952
+ return isWindowsAbsolutePath2(value) || /^[A-Za-z]:/.test(value) || value.includes("\\");
27629
27953
  }
27630
27954
  function trimTrailingPathSeparators(value) {
27631
27955
  let trimmed = value;
@@ -27638,302 +27962,6 @@ function isRootPath(value) {
27638
27962
  return value === "/" || /^[A-Za-z]:\/$/.test(value) || /^\/\/[^/]+\/[^/]+\/$/.test(value);
27639
27963
  }
27640
27964
 
27641
- // src/AgentFileChangeReport.ts
27642
- import fs7 from "node:fs";
27643
- import path6 from "node:path";
27644
- var AGENT_FILE_CHANGE_REPORT_VERSION = 1;
27645
- var AGENT_FILE_CHANGE_REPORT_TIMEOUT_MS = 3e4;
27646
- var AGENT_FILE_CHANGE_REPORT_MAX_PATHS = 1024;
27647
- var AGENT_FILE_CHANGE_REPORT_MAX_PATH_LENGTH = 4096;
27648
- var AGENT_FILE_CHANGE_REPORT_MAX_TOTAL_BYTES = 256 * 1024;
27649
- var AGENT_FILE_CHANGE_REPORT_MAX_UNCERTAINTY_LENGTH = 2e3;
27650
- var AGENT_FILE_CHANGE_REPORT_OUTPUT_SCHEMA = {
27651
- type: "object",
27652
- additionalProperties: false,
27653
- required: ["paths", "complete", "uncertainty"],
27654
- properties: {
27655
- paths: {
27656
- type: "array",
27657
- items: { type: "string" }
27658
- },
27659
- complete: { type: "boolean" },
27660
- uncertainty: {
27661
- anyOf: [{
27662
- type: "string",
27663
- maxLength: AGENT_FILE_CHANGE_REPORT_MAX_UNCERTAINTY_LENGTH
27664
- }, {
27665
- type: "null"
27666
- }]
27667
- }
27668
- }
27669
- };
27670
- var AGENT_FILE_CHANGE_REPORT_DEVELOPER_INSTRUCTIONS = `You are running an internal, read-only file-change audit for the immediately preceding turn.
27671
- Do not modify files, run commands that can modify files, or ask the user questions.
27672
- 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.
27673
- Do not report files that were only read or inspected.
27674
- You may use read-only inspection when needed. If the list may be incomplete, set complete to false and briefly explain why in uncertainty.`;
27675
- function createAgentFileChangeReportPrompt(workspace) {
27676
- return `List the paths changed by the immediately preceding turn.
27677
- Return only the structured result required by the output schema.
27678
- Relative paths are resolved against the working directory.
27679
- Working directory: ${JSON.stringify(workspace.cwd)}
27680
- Additional allowed directories: ${JSON.stringify(workspace.additionalDirectories)}`;
27681
- }
27682
- function parseAgentFileChangeReportRequest(meta3) {
27683
- const jetbrains = asRecord2(meta3?.[JETBRAINS_META_KEY]);
27684
- const air = asRecord2(jetbrains?.[AIR_META_KEY]);
27685
- const request = asRecord2(air?.[AIR_AGENT_FILE_CHANGE_REPORT_REQUEST_KEY]);
27686
- if (request === null || !hasOnlyKeys(request, ["version", "requestId"]) || request["version"] !== AGENT_FILE_CHANGE_REPORT_VERSION) {
27687
- return null;
27688
- }
27689
- const requestId = request["requestId"];
27690
- if (typeof requestId !== "string" || !/^[A-Za-z0-9._:-]{1,128}$/.test(requestId)) {
27691
- return null;
27692
- }
27693
- return { version: AGENT_FILE_CHANGE_REPORT_VERSION, requestId };
27694
- }
27695
- function createReportedAgentFileChangeReport(requestId, turn, workspace) {
27696
- const modelReport = parseModelFileChangeReport(turn);
27697
- const normalized = normalizeModelFileChangeReport(modelReport, workspace);
27698
- return fitReportedAgentFileChangeReport({
27699
- version: AGENT_FILE_CHANGE_REPORT_VERSION,
27700
- requestId,
27701
- status: "reported",
27702
- ...normalized
27703
- });
27704
- }
27705
- function createUnavailableAgentFileChangeReport(requestId, reason) {
27706
- return {
27707
- version: AGENT_FILE_CHANGE_REPORT_VERSION,
27708
- requestId,
27709
- status: "unavailable",
27710
- reason
27711
- };
27712
- }
27713
- var AgentFileChangeReportError = class extends Error {
27714
- reason;
27715
- constructor(reason, message) {
27716
- super(message);
27717
- this.name = "AgentFileChangeReportError";
27718
- this.reason = reason;
27719
- }
27720
- };
27721
- function parseModelFileChangeReport(turn) {
27722
- switch (turn.status) {
27723
- case "interrupted":
27724
- throw new AgentFileChangeReportError("cancelled", "The audit turn was interrupted");
27725
- case "failed":
27726
- throw new AgentFileChangeReportError(
27727
- "providerError",
27728
- `The audit turn failed${turn.error?.message ? `: ${turn.error.message}` : ""}`
27729
- );
27730
- case "inProgress":
27731
- throw new AgentFileChangeReportError("notReported", "The audit turn did not complete");
27732
- case "completed":
27733
- break;
27734
- }
27735
- let text = null;
27736
- for (let index = turn.items.length - 1; index >= 0; index -= 1) {
27737
- const item = turn.items[index];
27738
- if (item?.type === "agentMessage") {
27739
- text = item.text;
27740
- break;
27741
- }
27742
- }
27743
- if (text === null) {
27744
- throw new AgentFileChangeReportError("notReported", "The audit turn returned no agent message");
27745
- }
27746
- let value;
27747
- try {
27748
- value = JSON.parse(text);
27749
- } catch {
27750
- throw new AgentFileChangeReportError("invalidOutput", "The audit turn returned invalid JSON");
27751
- }
27752
- const report = asRecord2(value);
27753
- if (report === null || !hasOnlyKeys(report, ["paths", "complete", "uncertainty"])) {
27754
- throw new AgentFileChangeReportError("invalidOutput", "The audit turn returned an invalid object");
27755
- }
27756
- const paths = report["paths"];
27757
- const complete = report["complete"];
27758
- const uncertainty = report["uncertainty"];
27759
- if (!Array.isArray(paths) || !paths.every((item) => typeof item === "string") || typeof complete !== "boolean" || uncertainty !== void 0 && uncertainty !== null && typeof uncertainty !== "string") {
27760
- throw new AgentFileChangeReportError("invalidOutput", "The audit turn returned invalid fields");
27761
- }
27762
- const normalizedUncertainty = typeof uncertainty === "string" ? uncertainty.trim() : void 0;
27763
- if (normalizedUncertainty !== void 0 && normalizedUncertainty.length > AGENT_FILE_CHANGE_REPORT_MAX_UNCERTAINTY_LENGTH) {
27764
- throw new AgentFileChangeReportError("invalidOutput", "The audit turn returned oversized uncertainty");
27765
- }
27766
- return {
27767
- paths,
27768
- complete,
27769
- ...normalizedUncertainty ? { uncertainty: normalizedUncertainty } : {}
27770
- };
27771
- }
27772
- function fitReportedAgentFileChangeReport(report) {
27773
- const paths = [...report.paths];
27774
- let truncated = report.truncated;
27775
- let fitted = report;
27776
- while (Buffer.byteLength(JSON.stringify(fitted), "utf8") > AGENT_FILE_CHANGE_REPORT_MAX_TOTAL_BYTES) {
27777
- if (paths.length === 0) {
27778
- throw new AgentFileChangeReportError("invalidOutput", "The audit report exceeds the wire limit");
27779
- }
27780
- paths.pop();
27781
- truncated = true;
27782
- fitted = {
27783
- ...report,
27784
- paths: [...paths],
27785
- declaredComplete: false,
27786
- truncated
27787
- };
27788
- }
27789
- return fitted;
27790
- }
27791
- function normalizeModelFileChangeReport(report, workspace) {
27792
- const cwd = normalizeWorkspaceRoot(workspace.cwd);
27793
- if (cwd === null) {
27794
- throw new AgentFileChangeReportError("providerError", "The session working directory is not absolute");
27795
- }
27796
- const roots = [cwd, ...workspace.additionalDirectories.flatMap((directory) => {
27797
- const root = normalizeWorkspaceRoot(directory);
27798
- return root === null || root.flavor !== cwd.flavor ? [] : [root];
27799
- })];
27800
- const paths = [];
27801
- const seen = /* @__PURE__ */ new Set();
27802
- let totalBytes = 0;
27803
- let truncated = false;
27804
- for (const reportedPath of report.paths) {
27805
- if (reportedPath.length > AGENT_FILE_CHANGE_REPORT_MAX_PATH_LENGTH) {
27806
- truncated = true;
27807
- continue;
27808
- }
27809
- const normalized = normalizeReportedPath(reportedPath, cwd, roots);
27810
- if (normalized === null || normalized.value.length > AGENT_FILE_CHANGE_REPORT_MAX_PATH_LENGTH) {
27811
- truncated = true;
27812
- continue;
27813
- }
27814
- const key = normalized.flavor === "windows" ? normalized.value.toLowerCase() : normalized.value;
27815
- if (seen.has(key)) {
27816
- continue;
27817
- }
27818
- const bytes = Buffer.byteLength(normalized.value, "utf8");
27819
- if (paths.length >= AGENT_FILE_CHANGE_REPORT_MAX_PATHS || totalBytes + bytes > AGENT_FILE_CHANGE_REPORT_MAX_TOTAL_BYTES) {
27820
- truncated = true;
27821
- continue;
27822
- }
27823
- seen.add(key);
27824
- paths.push(normalized.value);
27825
- totalBytes += bytes;
27826
- }
27827
- return {
27828
- paths,
27829
- declaredComplete: report.complete && !truncated,
27830
- truncated,
27831
- ...report.uncertainty ? { uncertainty: report.uncertainty } : {}
27832
- };
27833
- }
27834
- function normalizeWorkspaceRoot(value) {
27835
- const trimmed = value.trim();
27836
- if (!isValidPathText(trimmed)) {
27837
- return null;
27838
- }
27839
- if (isWindowsAbsolutePath2(trimmed)) {
27840
- return canonicalizeWorkspaceRoot({
27841
- value: path6.win32.normalize(trimmed.replace(/\//g, "\\")),
27842
- flavor: "windows"
27843
- });
27844
- }
27845
- if (path6.posix.isAbsolute(trimmed)) {
27846
- return canonicalizeWorkspaceRoot({
27847
- value: path6.posix.normalize(trimmed.replace(/\\/g, "/")),
27848
- flavor: "posix"
27849
- });
27850
- }
27851
- return null;
27852
- }
27853
- function normalizeReportedPath(value, cwd, roots) {
27854
- const trimmed = value.trim();
27855
- 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)) {
27856
- return null;
27857
- }
27858
- let candidate;
27859
- if (isWindowsAbsolutePath2(trimmed)) {
27860
- candidate = { value: path6.win32.normalize(trimmed.replace(/\//g, "\\")), flavor: "windows" };
27861
- } else if (path6.posix.isAbsolute(trimmed)) {
27862
- candidate = { value: path6.posix.normalize(trimmed.replace(/\\/g, "/")), flavor: "posix" };
27863
- } else if (cwd.flavor === "windows") {
27864
- candidate = {
27865
- value: path6.win32.resolve(cwd.value, trimmed.replace(/\//g, "\\")),
27866
- flavor: "windows"
27867
- };
27868
- } else {
27869
- candidate = {
27870
- value: path6.posix.resolve(cwd.value, trimmed.replace(/\\/g, "/")),
27871
- flavor: "posix"
27872
- };
27873
- }
27874
- candidate = canonicalizeReportedPath(candidate);
27875
- return roots.some((root) => pathIsStrictlyInside(root, candidate)) ? candidate : null;
27876
- }
27877
- function canonicalizeWorkspaceRoot(root) {
27878
- if (!isNativePathFlavor(root.flavor)) {
27879
- return root;
27880
- }
27881
- return { ...root, value: canonicalizeFromExistingAncestor(root.value) };
27882
- }
27883
- function canonicalizeReportedPath(candidate) {
27884
- if (!isNativePathFlavor(candidate.flavor)) {
27885
- return candidate;
27886
- }
27887
- const parent = canonicalizeFromExistingAncestor(path6.dirname(candidate.value));
27888
- return { ...candidate, value: path6.resolve(parent, path6.basename(candidate.value)) };
27889
- }
27890
- function canonicalizeFromExistingAncestor(value) {
27891
- const original = path6.resolve(value);
27892
- let current = original;
27893
- const missingSegments = [];
27894
- while (true) {
27895
- try {
27896
- const canonical = fs7.realpathSync.native(current);
27897
- return path6.resolve(canonical, ...missingSegments.reverse());
27898
- } catch (error51) {
27899
- if (!isMissingPathError(error51)) return original;
27900
- }
27901
- const parent = path6.dirname(current);
27902
- if (parent === current) return original;
27903
- missingSegments.push(path6.basename(current));
27904
- current = parent;
27905
- }
27906
- }
27907
- function isMissingPathError(error51) {
27908
- if (typeof error51 !== "object" || error51 === null || !("code" in error51)) return false;
27909
- return error51.code === "ENOENT" || error51.code === "ENOTDIR";
27910
- }
27911
- function isNativePathFlavor(flavor) {
27912
- return process.platform === "win32" ? flavor === "windows" : flavor === "posix";
27913
- }
27914
- function pathIsStrictlyInside(root, candidate) {
27915
- if (root.flavor !== candidate.flavor) {
27916
- return false;
27917
- }
27918
- const pathImplementation = root.flavor === "windows" ? path6.win32 : path6.posix;
27919
- const relative = pathImplementation.relative(root.value, candidate.value);
27920
- return relative.length > 0 && !pathImplementation.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${pathImplementation.sep}`);
27921
- }
27922
- function isWindowsAbsolutePath2(value) {
27923
- const portable = value.replace(/\\/g, "/");
27924
- return /^[A-Za-z]:\//.test(portable) || /^\/\/[^/]+\/[^/]+(?:\/|$)/.test(portable);
27925
- }
27926
- function isValidPathText(value) {
27927
- return value.length > 0 && !/[\u0000-\u001F\u007F-\u009F]/.test(value);
27928
- }
27929
- function asRecord2(value) {
27930
- return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
27931
- }
27932
- function hasOnlyKeys(value, allowed) {
27933
- const allowedKeys = new Set(allowed);
27934
- return Object.keys(value).every((key) => allowedKeys.has(key));
27935
- }
27936
-
27937
27965
  // src/subagents/CodexSubagentSubscriptions.ts
27938
27966
  var CodexSubagentSubscriptions = class {
27939
27967
  constructor(client) {
@@ -28673,7 +28701,7 @@ var CodexAcpClient = class {
28673
28701
  baseUrl: activeProvider.baseUrl
28674
28702
  });
28675
28703
  const mergedConfig = {
28676
- ...mergeGatewayConfig(this.config, this.gatewayConfig),
28704
+ ...forceGitRootTurnDiffPaths(mergeGatewayConfig(this.config, this.gatewayConfig)),
28677
28705
  projects: Object.fromEntries(sessionRoots.map((root) => [root, {
28678
28706
  trust_level: "trusted"
28679
28707
  }]))
@@ -28833,101 +28861,6 @@ var CodexAcpClient = class {
28833
28861
  serviceTier
28834
28862
  }, onTurnStarted);
28835
28863
  }
28836
- async runAgentFileChangeReport(params) {
28837
- if (params.signal?.aborted) {
28838
- return createUnavailableAgentFileChangeReport(params.requestId, "cancelled");
28839
- }
28840
- const budget = new AgentFileChangeReportBudget(params.signal);
28841
- let forkThreadId = null;
28842
- let auditTurnId = null;
28843
- let auditTurnCompleted = false;
28844
- let lateStopReason = null;
28845
- try {
28846
- const forkPromise = this.codexClient.threadFork({
28847
- excludeTurns: true,
28848
- threadId: params.sessionId,
28849
- lastTurnId: params.turnId,
28850
- cwd: params.workspace.cwd,
28851
- approvalPolicy: "never",
28852
- sandbox: "read-only",
28853
- developerInstructions: AGENT_FILE_CHANGE_REPORT_DEVELOPER_INSTRUCTIONS,
28854
- ephemeral: true
28855
- });
28856
- void forkPromise.then((fork2) => {
28857
- if (lateStopReason !== null && forkThreadId === null) {
28858
- void this.unsubscribeAgentFileChangeReportThread(fork2.thread.id, budget);
28859
- }
28860
- }, () => {
28861
- });
28862
- const fork = await budget.wait(forkPromise);
28863
- forkThreadId = fork.thread.id;
28864
- const turnPromise = this.codexClient.runTurn({
28865
- threadId: forkThreadId,
28866
- input: [{
28867
- type: "text",
28868
- text: createAgentFileChangeReportPrompt(params.workspace),
28869
- text_elements: []
28870
- }],
28871
- cwd: params.workspace.cwd,
28872
- approvalPolicy: "never",
28873
- sandboxPolicy: { type: "readOnly", networkAccess: false },
28874
- summary: "none",
28875
- outputSchema: AGENT_FILE_CHANGE_REPORT_OUTPUT_SCHEMA
28876
- }, (turnId) => {
28877
- auditTurnId = turnId;
28878
- if (lateStopReason !== null && forkThreadId !== null) {
28879
- void this.interruptAgentFileChangeReport(forkThreadId, turnId, lateStopReason, budget);
28880
- }
28881
- });
28882
- const outcome = await budget.wait(turnPromise);
28883
- auditTurnCompleted = true;
28884
- return createReportedAgentFileChangeReport(
28885
- params.requestId,
28886
- outcome.turn,
28887
- params.workspace
28888
- );
28889
- } catch (error51) {
28890
- if (error51 instanceof AgentFileChangeReportBudgetError) {
28891
- lateStopReason = error51.reason;
28892
- if (!auditTurnCompleted && forkThreadId !== null && auditTurnId !== null) {
28893
- await this.interruptAgentFileChangeReport(
28894
- forkThreadId,
28895
- auditTurnId,
28896
- error51.reason,
28897
- budget
28898
- );
28899
- }
28900
- return createUnavailableAgentFileChangeReport(params.requestId, error51.reason);
28901
- }
28902
- if (error51 instanceof AgentFileChangeReportError) {
28903
- logger.error("Agent file-change report unavailable", error51);
28904
- return createUnavailableAgentFileChangeReport(params.requestId, error51.reason);
28905
- }
28906
- logger.error("Agent file-change report failed", error51);
28907
- return createUnavailableAgentFileChangeReport(params.requestId, "providerError");
28908
- } finally {
28909
- if (forkThreadId !== null) {
28910
- await this.unsubscribeAgentFileChangeReportThread(forkThreadId, budget);
28911
- }
28912
- }
28913
- }
28914
- async interruptAgentFileChangeReport(threadId, turnId, reason, budget) {
28915
- this.codexClient.markTurnStale(threadId, turnId);
28916
- try {
28917
- await budget.wait(this.codexClient.turnInterrupt({ threadId, turnId }));
28918
- } catch (error51) {
28919
- logger.error(`Failed to interrupt ${reason} agent file-change report`, error51);
28920
- } finally {
28921
- this.codexClient.resolveTurnInterrupted(threadId, turnId);
28922
- }
28923
- }
28924
- async unsubscribeAgentFileChangeReportThread(threadId, budget) {
28925
- try {
28926
- await budget.wait(this.codexClient.threadUnsubscribe({ threadId }));
28927
- } catch (error51) {
28928
- logger.error("Failed to unsubscribe the agent file-change report thread", error51);
28929
- }
28930
- }
28931
28864
  async setCollaborationMode(sessionId, mode, currentModelId) {
28932
28865
  await this.codexClient.threadSettingsUpdate({
28933
28866
  threadId: sessionId,
@@ -29084,58 +29017,6 @@ var CodexAcpClient = class {
29084
29017
  };
29085
29018
  }
29086
29019
  };
29087
- var AgentFileChangeReportBudgetError = class extends Error {
29088
- constructor(reason) {
29089
- super(`Agent file-change report ${reason}`);
29090
- this.reason = reason;
29091
- this.name = "AgentFileChangeReportBudgetError";
29092
- }
29093
- reason;
29094
- };
29095
- var AgentFileChangeReportBudget = class {
29096
- constructor(signal) {
29097
- this.signal = signal;
29098
- }
29099
- signal;
29100
- deadline = Date.now() + AGENT_FILE_CHANGE_REPORT_TIMEOUT_MS;
29101
- async wait(operation) {
29102
- void operation.catch(() => {
29103
- });
29104
- const immediateReason = this.stopReason();
29105
- if (immediateReason !== null) {
29106
- throw new AgentFileChangeReportBudgetError(immediateReason);
29107
- }
29108
- return await new Promise((resolve, reject) => {
29109
- let settled = false;
29110
- const finish = (action) => {
29111
- if (settled) return;
29112
- settled = true;
29113
- clearTimeout(timeout);
29114
- this.signal?.removeEventListener("abort", onAbort);
29115
- action();
29116
- };
29117
- const onAbort = () => finish(() => reject(new AgentFileChangeReportBudgetError("cancelled")));
29118
- const timeout = setTimeout(
29119
- () => finish(() => reject(new AgentFileChangeReportBudgetError("timeout"))),
29120
- Math.max(1, this.deadline - Date.now())
29121
- );
29122
- timeout.unref();
29123
- this.signal?.addEventListener("abort", onAbort, { once: true });
29124
- if (this.signal?.aborted) {
29125
- onAbort();
29126
- }
29127
- void operation.then(
29128
- (value) => finish(() => resolve(value)),
29129
- (error51) => finish(() => reject(error51))
29130
- );
29131
- });
29132
- }
29133
- stopReason() {
29134
- if (this.signal?.aborted) return "cancelled";
29135
- if (Date.now() >= this.deadline) return "timeout";
29136
- return null;
29137
- }
29138
- };
29139
29020
  function buildPromptItems(prompt) {
29140
29021
  return prompt.map((block) => {
29141
29022
  switch (block.type) {
@@ -29250,6 +29131,16 @@ function mergeSandboxWorkspaceWriteRoots(config2, roots) {
29250
29131
  }
29251
29132
  };
29252
29133
  }
29134
+ function forceGitRootTurnDiffPaths(config2) {
29135
+ const features = isJsonObject(config2["features"]) ? config2["features"] : {};
29136
+ return {
29137
+ ...config2,
29138
+ features: {
29139
+ ...features,
29140
+ cwd_relative_turn_diffs: false
29141
+ }
29142
+ };
29143
+ }
29253
29144
  function addAdditionalDirectoriesToSandboxPolicy(sandboxPolicy, additionalDirectories) {
29254
29145
  if (additionalDirectories.length === 0 || sandboxPolicy.type !== "workspaceWrite") {
29255
29146
  return sandboxPolicy;
@@ -34004,24 +33895,19 @@ Check ${configPath} and project .codex directories, especially their config.toml
34004
33895
  title
34005
33896
  });
34006
33897
  }
34007
- async publishAgentFileChangeReport(sessionState, turnId, request, unavailableReason, signal) {
33898
+ async publishAgentFileChangeReport(sessionState, turnId, request, unavailableReason, turnDiff, workspace) {
34008
33899
  let report;
34009
33900
  try {
34010
- report = turnId === null ? createUnavailableAgentFileChangeReport(request.requestId, unavailableReason) : await this.codexAcpClient.runAgentFileChangeReport({
34011
- sessionId: sessionState.sessionId,
34012
- turnId,
34013
- // The client owns request-id correlation and duplicate suppression. The wrapper
34014
- // stays stateless so a retried ACP prompt still receives a terminal report.
34015
- requestId: request.requestId,
34016
- workspace: {
34017
- cwd: sessionState.cwd,
34018
- additionalDirectories: sessionState.additionalDirectories
34019
- },
34020
- signal
34021
- });
33901
+ report = turnId === null ? createUnavailableAgentFileChangeReport(request.requestId, unavailableReason) : createReportedAgentFileChangeReport(request.requestId, turnDiff, workspace);
34022
33902
  } catch (error51) {
34023
- logger.error("Agent file-change report failed unexpectedly", error51);
34024
- report = createUnavailableAgentFileChangeReport(request.requestId, "providerError");
33903
+ logger.error(
33904
+ error51 instanceof AgentFileChangeReportError ? "Agent file-change report unavailable" : "Agent file-change report failed unexpectedly",
33905
+ error51
33906
+ );
33907
+ report = createUnavailableAgentFileChangeReport(
33908
+ request.requestId,
33909
+ error51 instanceof AgentFileChangeReportError ? error51.reason : "providerError"
33910
+ );
34025
33911
  }
34026
33912
  try {
34027
33913
  const session = new ACPSessionConnection(this.connection, sessionState.sessionId);
@@ -34491,6 +34377,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
34491
34377
  });
34492
34378
  const sessionState = this.getSessionState(params.sessionId);
34493
34379
  const agentFileChangeReportRequest = clientSupportsAgentFileChangeReports(this.clientCapabilities) ? parseAgentFileChangeReportRequest(params._meta) : null;
34380
+ const agentFileChangeWorkspace = agentFileChangeReportRequest === null ? null : captureAgentFileChangeWorkspace(sessionState.cwd, sessionState.additionalDirectories);
34494
34381
  let agentFileChangeReportTurnId = null;
34495
34382
  let agentFileChangeReportUnavailableReason = "providerError";
34496
34383
  let promptWasCancelled = false;
@@ -34529,7 +34416,8 @@ Check ${configPath} and project .codex directories, especially their config.toml
34529
34416
  clientSupportsTypedSessionFailures(this.clientCapabilities),
34530
34417
  this.sessionFailureEpoch,
34531
34418
  sessionState.subagents,
34532
- (accountUpdated) => this.handleAccountUpdated(accountUpdated)
34419
+ (accountUpdated) => this.handleAccountUpdated(accountUpdated),
34420
+ agentFileChangeReportRequest !== null
34533
34421
  );
34534
34422
  eventHandler = promptEventHandler;
34535
34423
  const permissionLifecycle = this.permissionLifecycleContext(sessionState);
@@ -34881,13 +34769,21 @@ Check ${configPath} and project .codex directories, especially their config.toml
34881
34769
  } catch (error51) {
34882
34770
  logger.error("Failed to publish terminal subagent state during prompt cleanup", error51);
34883
34771
  }
34884
- if (agentFileChangeReportRequest !== null) {
34772
+ if (agentFileChangeReportRequest !== null && agentFileChangeWorkspace !== null) {
34773
+ if (promptWasCancelled || activePrompt.signal.aborted || this.sessionIsClosing(params.sessionId)) {
34774
+ agentFileChangeReportTurnId = null;
34775
+ agentFileChangeReportUnavailableReason = "cancelled";
34776
+ } else if (agentFileChangeReportTurnId !== null && eventHandler?.isTurnDiffOversized(agentFileChangeReportTurnId)) {
34777
+ agentFileChangeReportTurnId = null;
34778
+ agentFileChangeReportUnavailableReason = "invalidOutput";
34779
+ }
34885
34780
  await this.publishAgentFileChangeReport(
34886
34781
  sessionState,
34887
34782
  agentFileChangeReportTurnId,
34888
34783
  agentFileChangeReportRequest,
34889
34784
  agentFileChangeReportUnavailableReason,
34890
- activePrompt.signal
34785
+ agentFileChangeReportTurnId === null || eventHandler === null ? "" : eventHandler.getTurnDiff(agentFileChangeReportTurnId),
34786
+ agentFileChangeWorkspace
34891
34787
  );
34892
34788
  }
34893
34789
  logger.log("Prompt completed", { sessionId: params.sessionId });
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.11.1-preview.5",
6
+ "version": "1.12.0",
7
7
  "description": "",
8
8
  "main": "dist/index.js",
9
9
  "bin": {