orkestrator 2.30.0-beta → 2.32.0-beta

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.
@@ -331,7 +331,7 @@ function createBridgeDiagnostics(bridge, state, metrics) {
331
331
  import { execFile as execFileCallback2 } from "node:child_process";
332
332
  import { randomBytes, timingSafeEqual } from "node:crypto";
333
333
  import { appendFile as appendFile5, mkdir as mkdir8, readFile as readFile7, writeFile as writeFile6 } from "node:fs/promises";
334
- import { join as join15 } from "node:path";
334
+ import { join as join17 } from "node:path";
335
335
  import { promisify as promisify2 } from "node:util";
336
336
 
337
337
  // ../../node_modules/.bun/@hono+node-server@2.1.5+c539cad7f494f5c9/node_modules/@hono/node-server/dist/constants-BLSFu_RU.mjs
@@ -3933,7 +3933,14 @@ var QUESTION_KEYS = new Set([
3933
3933
  "allowFreeText",
3934
3934
  "options"
3935
3935
  ]);
3936
- var OPTION_KEYS = new Set(["id", "label", "providerValue", "description", "amendment"]);
3936
+ var OPTION_KEYS = new Set([
3937
+ "id",
3938
+ "label",
3939
+ "providerValue",
3940
+ "description",
3941
+ "preview",
3942
+ "amendment"
3943
+ ]);
3937
3944
  var AMENDMENT_KEYS = new Set(["kind", "detail"]);
3938
3945
  var ANSWER_KEYS = new Set(["version", "interactionId", "sessionId", "answers"]);
3939
3946
  var QUESTION_ANSWER_KEYS = new Set(["questionId", "optionIds", "freeText"]);
@@ -4060,6 +4067,15 @@ var NATIVE_AGENT_APPROVAL_MODES = Object.freeze({
4060
4067
  }
4061
4068
  ]
4062
4069
  });
4070
+ var CODEX_CONTAINER_APPROVAL_DESCRIPTIONS = Object.freeze({
4071
+ ask: {
4072
+ "on-request": "Codex has no sandbox of its own in a container, so this asks before any command Codex does not trust, like Untrusted"
4073
+ },
4074
+ "auto-approve": {
4075
+ "on-request": "Codex has no sandbox of its own in a container, so this never asks; choose Untrusted to approve commands",
4076
+ "auto-review": "Codex has no sandbox of its own in a container, so the reviewer is never consulted and everything runs"
4077
+ }
4078
+ });
4063
4079
  var NATIVE_AGENT_RETIRED_DISPATCH_TTL_MS = 24 * 60 * 60 * 1000;
4064
4080
  var SUPPRESSED_COMPOSER_PARAMETERS = Object.freeze({
4065
4081
  claude: Object.freeze(["parameter:thinking", "parameter:context1m"]),
@@ -5925,8 +5941,18 @@ function registerCodexChangeEvidenceRoutes(app, spool) {
5925
5941
 
5926
5942
  // ../../bridges/codex-bridge/src/change-evidence.ts
5927
5943
  import { createHash as createHash5 } from "node:crypto";
5928
- import { existsSync } from "node:fs";
5929
- import { join as join6 } from "node:path";
5944
+ import { existsSync as existsSync2 } from "node:fs";
5945
+ import { basename, join as join8 } from "node:path";
5946
+
5947
+ // ../../bridges/codex-bridge/src/bridge-state-dir.ts
5948
+ import { isAbsolute as isAbsolute2, join as join2 } from "node:path";
5949
+ function codexBridgeStateDir(codexHome, env = process.env) {
5950
+ const override = env.CODEX_BRIDGE_STATE_DIR?.trim();
5951
+ return override && isAbsolute2(override) ? override : codexLoginBridgeDir(codexHome);
5952
+ }
5953
+ function codexLoginBridgeDir(codexHome) {
5954
+ return join2(codexHome, "orkestrator-bridge");
5955
+ }
5930
5956
 
5931
5957
  // ../protocol/src/change-evidence.ts
5932
5958
  var PROVIDER_EVIDENCE_SCHEMA_VERSION = 1;
@@ -6324,7 +6350,7 @@ function workspaceObservationReportIssues(value) {
6324
6350
  import { createHash as createHash4, randomUUID as randomUUID3 } from "node:crypto";
6325
6351
  import { readdirSync, readFileSync } from "node:fs";
6326
6352
  import { appendFile, mkdir, rename, rm as rm2, writeFile } from "node:fs/promises";
6327
- import { join as join2 } from "node:path";
6353
+ import { join as join3 } from "node:path";
6328
6354
  var DEFAULT_EVIDENCE_SPOOL_LIMITS = {
6329
6355
  maxEntries: 2048,
6330
6356
  maxEntryBytes: 256 * 1024,
@@ -6587,7 +6613,7 @@ class ChangeEvidenceSpool {
6587
6613
  const lines = this.pendingLines.splice(0).join("");
6588
6614
  this.enqueueIo(async () => {
6589
6615
  await mkdir(directory, { recursive: true, mode: 448 });
6590
- await appendFile(join2(directory, ENTRIES_FILE), lines, { mode: 384 });
6616
+ await appendFile(join3(directory, ENTRIES_FILE), lines, { mode: 384 });
6591
6617
  });
6592
6618
  }
6593
6619
  persistBody(id, bytes) {
@@ -6595,9 +6621,9 @@ class ChangeEvidenceSpool {
6595
6621
  if (!directory || this.restoring)
6596
6622
  return;
6597
6623
  this.enqueueIo(async () => {
6598
- const bodies = join2(directory, BODY_DIRECTORY);
6624
+ const bodies = join3(directory, BODY_DIRECTORY);
6599
6625
  await mkdir(bodies, { recursive: true, mode: 448 });
6600
- await writeFile(join2(bodies, bodyFileName(id)), bytes, { mode: 384, flag: "wx" }).catch((error) => {
6626
+ await writeFile(join3(bodies, bodyFileName(id)), bytes, { mode: 384, flag: "wx" }).catch((error) => {
6601
6627
  if (error.code !== "EEXIST")
6602
6628
  throw error;
6603
6629
  });
@@ -6607,7 +6633,7 @@ class ChangeEvidenceSpool {
6607
6633
  const directory = this.directory;
6608
6634
  if (!directory)
6609
6635
  return;
6610
- this.enqueueIo(() => rm2(join2(directory, BODY_DIRECTORY, bodyFileName(id)), { force: true }));
6636
+ this.enqueueIo(() => rm2(join3(directory, BODY_DIRECTORY, bodyFileName(id)), { force: true }));
6611
6637
  }
6612
6638
  compactPersisted() {
6613
6639
  const directory = this.directory;
@@ -6618,7 +6644,7 @@ class ChangeEvidenceSpool {
6618
6644
  `);
6619
6645
  this.enqueueIo(async () => {
6620
6646
  await mkdir(directory, { recursive: true, mode: 448 });
6621
- const file = join2(directory, ENTRIES_FILE);
6647
+ const file = join3(directory, ENTRIES_FILE);
6622
6648
  const temp = `${file}.${process.pid}.tmp`;
6623
6649
  await writeFile(temp, body ? `${body}
6624
6650
  ` : "", { mode: 384 });
@@ -6630,10 +6656,10 @@ class ChangeEvidenceSpool {
6630
6656
  await this.io;
6631
6657
  }
6632
6658
  restore(directory) {
6633
- const bodyDirectory = join2(directory, BODY_DIRECTORY);
6659
+ const bodyDirectory = join3(directory, BODY_DIRECTORY);
6634
6660
  try {
6635
6661
  for (const name of readdirSync(bodyDirectory)) {
6636
- const bytes = new Uint8Array(readFileSync(join2(bodyDirectory, name)));
6662
+ const bytes = new Uint8Array(readFileSync(join3(bodyDirectory, name)));
6637
6663
  const id = evidenceBodyId(bytes);
6638
6664
  if (bodyFileName(id) !== name)
6639
6665
  continue;
@@ -6645,7 +6671,7 @@ class ChangeEvidenceSpool {
6645
6671
  } catch {}
6646
6672
  let text = "";
6647
6673
  try {
6648
- text = readFileSync(join2(directory, ENTRIES_FILE), "utf8");
6674
+ text = readFileSync(join3(directory, ENTRIES_FILE), "utf8");
6649
6675
  } catch {
6650
6676
  return;
6651
6677
  }
@@ -6983,7 +7009,7 @@ function canonicalEvidence(evidence) {
6983
7009
  }
6984
7010
 
6985
7011
  // ../../bridges/codex-bridge/src/messages/apply-patch.ts
6986
- import { isAbsolute as isAbsolute2, join as join3 } from "node:path";
7012
+ import { isAbsolute as isAbsolute3, join as join4 } from "node:path";
6987
7013
 
6988
7014
  // ../../bridges/codex-bridge/src/messages/diff-budget.ts
6989
7015
  var MAX_INLINE_FILE_BYTES = 256 * 1024;
@@ -7137,7 +7163,7 @@ function rawPatchTitle(change) {
7137
7163
  }
7138
7164
  function rawApplyPatchParts(value, cwd, state) {
7139
7165
  return parseRawApplyPatchChanges(value).map((change) => {
7140
- const filePath = isAbsolute2(change.targetPath) ? change.targetPath : join3(cwd, change.targetPath);
7166
+ const filePath = isAbsolute3(change.targetPath) ? change.targetPath : join4(cwd, change.targetPath);
7141
7167
  return {
7142
7168
  type: "tool-invocation",
7143
7169
  content: change.targetPath,
@@ -7160,7 +7186,7 @@ function rawApplyPatchParts(value, cwd, state) {
7160
7186
  }
7161
7187
 
7162
7188
  // ../../bridges/codex-bridge/src/messages/file-change-diff.ts
7163
- import { isAbsolute as isAbsolute3, join as join4, relative } from "node:path";
7189
+ import { isAbsolute as isAbsolute4, join as join5, relative } from "node:path";
7164
7190
  var MOVED_TO_SUFFIX = /\n\nMoved to: ([^\n]+)\n?$/;
7165
7191
  var UNIFIED_START = /^(?:@@ -\d+(?:,\d+)? \+\d+(?:,\d+)? @@|--- |diff --git )/;
7166
7192
  function suppliedFileChange(change) {
@@ -7184,7 +7210,7 @@ function suppliedFileChange(change) {
7184
7210
  };
7185
7211
  }
7186
7212
  function headerPath(cwd, path) {
7187
- return isAbsolute3(path) ? relative(cwd, path) || path : path;
7213
+ return isAbsolute4(path) ? relative(cwd, path) || path : path;
7188
7214
  }
7189
7215
  function contentLines(content) {
7190
7216
  if (content.length === 0)
@@ -7223,11 +7249,11 @@ ${supplied.hunks}`;
7223
7249
  `);
7224
7250
  }
7225
7251
  function resolvedChangePath(cwd, path) {
7226
- return isAbsolute3(path) ? path : join4(cwd, path);
7252
+ return isAbsolute4(path) ? path : join5(cwd, path);
7227
7253
  }
7228
7254
 
7229
7255
  // ../../bridges/codex-bridge/src/sessions/command-changes.ts
7230
- import { isAbsolute as isAbsolute4, join as join5 } from "node:path";
7256
+ import { isAbsolute as isAbsolute5, join as join6 } from "node:path";
7231
7257
  import { fileURLToPath } from "node:url";
7232
7258
 
7233
7259
  // ../protocol/src/node/command-change-journal.ts
@@ -7408,7 +7434,7 @@ function journalFileName(threadId) {
7408
7434
  }
7409
7435
  function commandChangeJournalPath(codexHome, threadId) {
7410
7436
  const fileName = journalFileName(threadId);
7411
- return fileName ? join5(codexHome, "orkestrator-bridge", "command-changes", fileName) : undefined;
7437
+ return fileName ? join6(codexBridgeStateDir(codexHome), "command-changes", fileName) : undefined;
7412
7438
  }
7413
7439
  function commandChangeJournalFor(codexHome, threadId) {
7414
7440
  const path = commandChangeJournalPath(codexHome, threadId);
@@ -7433,7 +7459,13 @@ async function readCommandChanges(codexHome, threadId) {
7433
7459
  const journal = commandChangeJournalFor(codexHome, threadId);
7434
7460
  if (!journal)
7435
7461
  return new Map;
7436
- return journal.read().catch(() => new Map);
7462
+ const current = await journal.read().catch(() => new Map);
7463
+ const fileName = journalFileName(threadId);
7464
+ const legacyPath = fileName ? join6(codexLoginBridgeDir(codexHome), "command-changes", fileName) : undefined;
7465
+ if (!legacyPath || legacyPath === commandChangeJournalPath(codexHome, threadId))
7466
+ return current;
7467
+ const legacy = await new CommandChangeJournal(legacyPath).read().catch(() => new Map);
7468
+ return legacy.size === 0 ? current : new Map([...legacy, ...current]);
7437
7469
  }
7438
7470
  function recordCommandChanges(codexHome, threadId, toolUseId, change) {
7439
7471
  if (!hasMeasuredChanges(change))
@@ -7463,7 +7495,7 @@ function commandChangeCwd(item, fallback) {
7463
7495
  return fallback;
7464
7496
  }
7465
7497
  }
7466
- return isAbsolute4(item.cwd) ? item.cwd : fallback;
7498
+ return isAbsolute5(item.cwd) ? item.cwd : fallback;
7467
7499
  }
7468
7500
  function commandDidNotRun(item) {
7469
7501
  return item.type === "command_execution" && item.status === "failed" && item.exit_code === undefined;
@@ -7540,8 +7572,111 @@ async function inheritCommandChanges(codexHome, parentThreadId, forkThreadId, me
7540
7572
  journal?.append(id, change);
7541
7573
  }
7542
7574
 
7575
+ // ../../bridges/codex-bridge/src/change-evidence-migration.ts
7576
+ import { randomUUID as randomUUID4 } from "node:crypto";
7577
+ import {
7578
+ existsSync,
7579
+ mkdirSync,
7580
+ readFileSync as readFileSync2,
7581
+ readdirSync as readdirSync2,
7582
+ renameSync,
7583
+ rmSync as rmSync2,
7584
+ statSync,
7585
+ writeFileSync
7586
+ } from "node:fs";
7587
+ import { join as join7, resolve as resolve2 } from "node:path";
7588
+ import { isDeepStrictEqual } from "node:util";
7589
+ function readBounded(path, limit) {
7590
+ if (statSync(path).size > limit)
7591
+ throw new Error("Evidence migration exceeds storage capacity");
7592
+ const bytes = readFileSync2(path);
7593
+ if (bytes.length > limit)
7594
+ throw new Error("Evidence migration exceeds storage capacity");
7595
+ return bytes;
7596
+ }
7597
+ function publishFile(path, contents) {
7598
+ const temporary = `${path}.${randomUUID4()}.tmp`;
7599
+ try {
7600
+ writeFileSync(temporary, contents, { mode: 384 });
7601
+ renameSync(temporary, path);
7602
+ } finally {
7603
+ rmSync2(temporary, { force: true });
7604
+ }
7605
+ }
7606
+ function migrateCodexChangeEvidence(legacy, shared) {
7607
+ if (resolve2(legacy) === resolve2(shared))
7608
+ return;
7609
+ const legacyFile = join7(legacy, "entries.jsonl");
7610
+ if (!existsSync(legacyFile))
7611
+ return;
7612
+ const entries = new Map;
7613
+ const bodyIds = new Set;
7614
+ for (const directory of [shared, legacy]) {
7615
+ const file = join7(directory, "entries.jsonl");
7616
+ if (!existsSync(file))
7617
+ continue;
7618
+ for (const line of readBounded(file, DEFAULT_EVIDENCE_SPOOL_LIMITS.maxQueuedBytes).toString("utf8").split(`
7619
+ `)) {
7620
+ if (!line)
7621
+ continue;
7622
+ const entry = JSON.parse(line).entry;
7623
+ let identity;
7624
+ if (entry?.type === "frame" && isProviderEvidenceFrame(entry.frame)) {
7625
+ identity = `frame:${entry.frame.frameId}`;
7626
+ for (const id of collectBodyIds(entry.frame))
7627
+ bodyIds.add(id);
7628
+ } else if (entry?.type === "observation" && workspaceObservationReportIssues(entry.report).length === 0) {
7629
+ identity = `observation:${entry.report.reportId}`;
7630
+ } else {
7631
+ throw new Error("Evidence migration encountered an invalid entry");
7632
+ }
7633
+ const normalized = { ...entry, seq: 0 };
7634
+ const existing = entries.get(identity);
7635
+ if (existing && !isDeepStrictEqual(existing, normalized)) {
7636
+ throw new Error("Evidence migration encountered conflicting identities");
7637
+ }
7638
+ entries.set(identity, normalized);
7639
+ }
7640
+ }
7641
+ const lines = [...entries.values()].map((entry, index) => {
7642
+ const serialized = JSON.stringify({ ...entry, seq: index + 1 });
7643
+ if (serialized.length > DEFAULT_EVIDENCE_SPOOL_LIMITS.maxEntryBytes) {
7644
+ throw new Error("Evidence migration exceeds entry capacity");
7645
+ }
7646
+ return JSON.stringify({ entry: { ...entry, seq: index + 1 } });
7647
+ });
7648
+ const contents = lines.length ? `${lines.join(`
7649
+ `)}
7650
+ ` : "";
7651
+ if (entries.size >= DEFAULT_EVIDENCE_SPOOL_LIMITS.maxEntries || Buffer.byteLength(contents) > DEFAULT_EVIDENCE_SPOOL_LIMITS.maxQueuedBytes) {
7652
+ throw new Error("Evidence migration exceeds queue capacity");
7653
+ }
7654
+ mkdirSync(join7(shared, "bodies"), { recursive: true, mode: 448 });
7655
+ let bodyBytes = 0;
7656
+ for (const id of bodyIds) {
7657
+ const name = id.replace(/[^A-Za-z0-9]/g, "_");
7658
+ const target = join7(shared, "bodies", name);
7659
+ const bytes = readBounded(existsSync(target) ? target : join7(legacy, "bodies", name), DEFAULT_EVIDENCE_SPOOL_LIMITS.maxSingleBodyBytes);
7660
+ if (evidenceBodyId(bytes) !== id)
7661
+ throw new Error("Evidence migration body integrity failed");
7662
+ bodyBytes += bytes.length;
7663
+ if (bodyBytes > DEFAULT_EVIDENCE_SPOOL_LIMITS.maxBodyBytes)
7664
+ throw new Error("Evidence migration exceeds body capacity");
7665
+ if (!existsSync(target))
7666
+ publishFile(target, bytes);
7667
+ }
7668
+ const retainedNames = new Set([...bodyIds].map((id) => id.replace(/[^A-Za-z0-9]/g, "_")));
7669
+ for (const name of readdirSync2(join7(shared, "bodies"))) {
7670
+ if (/^sha256_[a-f0-9]{64}$/.test(name) && !retainedNames.has(name)) {
7671
+ rmSync2(join7(shared, "bodies", name));
7672
+ }
7673
+ }
7674
+ publishFile(join7(shared, "entries.jsonl"), contents);
7675
+ rmSync2(legacyFile);
7676
+ }
7677
+
7543
7678
  // ../../bridges/codex-bridge/src/change-evidence.ts
7544
- function detectCaptureExecutor(exists = existsSync) {
7679
+ function detectCaptureExecutor(exists = existsSync2) {
7545
7680
  return exists("/.dockerenv") || exists("/run/.containerenv") ? "container-worker" : "host-worker";
7546
7681
  }
7547
7682
  function codexChangeCapabilities(executor) {
@@ -7777,13 +7912,13 @@ function suppliedMovePath(change) {
7777
7912
  }
7778
7913
  function codexChangeEvidenceDir(codexHome, cwd) {
7779
7914
  const cwdHash = createHash5("sha256").update(cwd).digest("hex").slice(0, 16);
7780
- return join6(codexHome, "orkestrator-bridge", "change-evidence", cwdHash);
7915
+ return join8(codexBridgeStateDir(codexHome), "change-evidence", cwdHash);
7781
7916
  }
7782
7917
  function createCodexChangeEvidence(options) {
7918
+ const directory = codexChangeEvidenceDir(options.codexHome, options.cwd);
7919
+ migrateCodexChangeEvidence(join8(codexLoginBridgeDir(options.codexHome), "change-evidence", basename(directory)), directory);
7783
7920
  return new CodexChangeEvidence({
7784
- spool: new ChangeEvidenceSpool({
7785
- directory: codexChangeEvidenceDir(options.codexHome, options.cwd)
7786
- }),
7921
+ spool: new ChangeEvidenceSpool({ directory }),
7787
7922
  executor: options.executor ?? detectCaptureExecutor()
7788
7923
  });
7789
7924
  }
@@ -7812,7 +7947,7 @@ function codexApprovalConfig(policy, sandbox, mode) {
7812
7947
  import { spawn as spawn2 } from "node:child_process";
7813
7948
  import { appendFile as appendFile3, mkdir as mkdir3, mkdtemp as mkdtemp2, readFile as readFile2, rm as rm4, writeFile as writeFile3 } from "node:fs/promises";
7814
7949
  import { tmpdir as tmpdir2 } from "node:os";
7815
- import { join as join7 } from "node:path";
7950
+ import { join as join9 } from "node:path";
7816
7951
 
7817
7952
  // ../protocol/src/codex-background-task.ts
7818
7953
  var CODEX_BACKGROUND_TASK_MODEL = "gpt-5.6-luna";
@@ -7892,7 +8027,7 @@ async function refreshRuntimeEnvironment(run = execFile2) {
7892
8027
  `if [ -f "$${RUNTIME_ENV_SCRIPT_ENV}" ]; then . "$${RUNTIME_ENV_SCRIPT_ENV}" 2>/dev/null || true; orkestrator_source_runtime_env 2>/dev/null || true; fi; env`
7893
8028
  ], {
7894
8029
  env: {
7895
- ...process.env,
8030
+ ...runtimeEnvironmentSnapshot(),
7896
8031
  [RUNTIME_ENV_SCRIPT_ENV]: runtimeEnvScript
7897
8032
  },
7898
8033
  maxBuffer: 256 * 1024
@@ -7916,7 +8051,9 @@ function fingerprintRuntimeEnvironment(env = process.env) {
7916
8051
  return `sha256:${hash.digest("hex").slice(0, 32)}`;
7917
8052
  }
7918
8053
  function runtimeEnvironmentSnapshot(env = process.env) {
7919
- return { ...env };
8054
+ const snapshot = { ...env };
8055
+ delete snapshot.CODEX_BRIDGE_STATE_DIR;
8056
+ return snapshot;
7920
8057
  }
7921
8058
  function runtimeEnvironmentWithoutCredentials(env = process.env) {
7922
8059
  const snapshot = runtimeEnvironmentSnapshot(env);
@@ -8201,10 +8338,10 @@ async function runCodexTitleCommand(codexPath, args, input, options = {}) {
8201
8338
  });
8202
8339
  }
8203
8340
  async function generateSessionTitleWithCodexExec(codexPath, sourcePrompt, options = {}) {
8204
- const temporaryDirectory = await mkdtemp2(join7(options.temporaryRoot ?? tmpdir2(), "orkestrator-session-title-"));
8205
- const outputPath = join7(temporaryDirectory, "title.txt");
8206
- const modelCatalogPath = join7(temporaryDirectory, "model-catalog.json");
8207
- const outputSchemaPath = join7(temporaryDirectory, "title-schema.json");
8341
+ const temporaryDirectory = await mkdtemp2(join9(options.temporaryRoot ?? tmpdir2(), "orkestrator-session-title-"));
8342
+ const outputPath = join9(temporaryDirectory, "title.txt");
8343
+ const modelCatalogPath = join9(temporaryDirectory, "model-catalog.json");
8344
+ const outputSchemaPath = join9(temporaryDirectory, "title-schema.json");
8208
8345
  const maxOutputBytes = options.maxOutputBytes ?? MAX_COMMAND_OUTPUT_LENGTH;
8209
8346
  try {
8210
8347
  await Promise.all([
@@ -8235,7 +8372,11 @@ async function generateSessionTitleWithCodexExec(codexPath, sourcePrompt, option
8235
8372
  }
8236
8373
  }
8237
8374
  function sessionTitleIndexPath(codexHome) {
8238
- return join7(codexHome, "orkestrator-bridge", SESSION_TITLE_INDEX_FILENAME);
8375
+ return join9(codexBridgeStateDir(codexHome), SESSION_TITLE_INDEX_FILENAME);
8376
+ }
8377
+ function legacySessionTitleIndexPath(codexHome) {
8378
+ const legacy = join9(codexLoginBridgeDir(codexHome), SESSION_TITLE_INDEX_FILENAME);
8379
+ return legacy === sessionTitleIndexPath(codexHome) ? undefined : legacy;
8239
8380
  }
8240
8381
  function persistedSourcePriority(source) {
8241
8382
  if (source === "explicit")
@@ -8245,7 +8386,11 @@ function persistedSourcePriority(source) {
8245
8386
  return 1;
8246
8387
  }
8247
8388
  async function readPersistedSessionTitleEntries(codexHome) {
8248
- const raw = await readFile2(sessionTitleIndexPath(codexHome), "utf8").catch(() => "");
8389
+ const legacyPath = legacySessionTitleIndexPath(codexHome);
8390
+ const legacy = legacyPath ? await readFile2(legacyPath, "utf8").catch(() => "") : "";
8391
+ const current = await readFile2(sessionTitleIndexPath(codexHome), "utf8").catch(() => "");
8392
+ const raw = legacy ? `${legacy}
8393
+ ${current}` : current;
8249
8394
  const selected = new Map;
8250
8395
  for (const [lineIndex, line] of raw.split(`
8251
8396
  `).entries()) {
@@ -8290,7 +8435,7 @@ async function persistSessionTitle(codexHome, threadId, title, options = {}) {
8290
8435
  throw new Error("Session title updatedAt must be a valid date");
8291
8436
  }
8292
8437
  const updatedAt = requestedUpdatedAt.toISOString();
8293
- const directory = join7(codexHome, "orkestrator-bridge");
8438
+ const directory = codexBridgeStateDir(codexHome);
8294
8439
  await mkdir3(directory, { recursive: true });
8295
8440
  await appendFile3(sessionTitleIndexPath(codexHome), `${JSON.stringify({
8296
8441
  threadId: normalizedThreadId,
@@ -10809,7 +10954,7 @@ async function deriveTranscriptSubagentPartsForTurn({
10809
10954
  import { createHash as createHash7 } from "node:crypto";
10810
10955
  import { readFile as readFile4, readdir, stat as stat4 } from "node:fs/promises";
10811
10956
  import { homedir } from "node:os";
10812
- import { basename, join as join8 } from "node:path";
10957
+ import { basename as basename2, join as join10 } from "node:path";
10813
10958
 
10814
10959
  // ../../bridges/codex-bridge/src/sessions/refused-cell-tail.ts
10815
10960
  import { open as open2, stat as stat3 } from "node:fs/promises";
@@ -11005,7 +11150,7 @@ class RefusedCellTail {
11005
11150
  }
11006
11151
 
11007
11152
  // ../../bridges/codex-bridge/src/app-server/item-adapter.ts
11008
- import { isAbsolute as isAbsolute5 } from "node:path";
11153
+ import { isAbsolute as isAbsolute6 } from "node:path";
11009
11154
  function isRecord5(value) {
11010
11155
  return !!value && typeof value === "object" && !Array.isArray(value);
11011
11156
  }
@@ -11027,7 +11172,7 @@ function imageGenerationInputPaths(value) {
11027
11172
  if (paths.size >= MAX_IMAGE_GENERATION_INPUTS)
11028
11173
  break;
11029
11174
  const path = isRecord5(entry) ? str(entry.path) : undefined;
11030
- if (path && isAbsolute5(path))
11175
+ if (path && isAbsolute6(path))
11031
11176
  paths.add(path);
11032
11177
  }
11033
11178
  return [...paths];
@@ -11374,6 +11519,28 @@ function mapTodoArgs(items) {
11374
11519
  };
11375
11520
  }
11376
11521
 
11522
+ // ../../bridges/codex-bridge/src/messages/turn-failure.ts
11523
+ var MAX_TURN_FAILURE_CHARS = 2000;
11524
+ function turnFailureItemId(turnId) {
11525
+ return `turn-error:${turnId}`;
11526
+ }
11527
+ function turnFailureText(message) {
11528
+ const raw = message.trim();
11529
+ let text = raw;
11530
+ if (raw.startsWith("{")) {
11531
+ try {
11532
+ const body = JSON.parse(raw);
11533
+ const nested = body.error && typeof body.error === "object" ? body.error.message : undefined;
11534
+ const candidate = typeof nested === "string" ? nested : body.message;
11535
+ if (typeof candidate === "string" && candidate.trim())
11536
+ text = candidate.trim();
11537
+ } catch {}
11538
+ }
11539
+ if (!text)
11540
+ text = "Codex ended the turn on an error.";
11541
+ return text.length > MAX_TURN_FAILURE_CHARS ? `${text.slice(0, MAX_TURN_FAILURE_CHARS - 1)}…` : text;
11542
+ }
11543
+
11377
11544
  // ../../bridges/codex-bridge/src/sessions/turn-accumulator.ts
11378
11545
  var MAX_ITEM_PROGRESS_CHARS = 200;
11379
11546
  var MODEL_STEP_TOOL_ITEM_TYPES = new Set([
@@ -11695,6 +11862,14 @@ class TurnAccumulator {
11695
11862
  this.touch(accumulator);
11696
11863
  }
11697
11864
  }
11865
+ recordProviderFailure(error) {
11866
+ this.onItemCompleted({
11867
+ id: turnFailureItemId(this.turnId),
11868
+ type: "status",
11869
+ text: turnFailureText(error.message),
11870
+ severity: "error"
11871
+ });
11872
+ }
11698
11873
  interruptOpenAgentMessages(keepId) {
11699
11874
  for (const id of Array.from(this.openAgentMessageIds)) {
11700
11875
  if (id === keepId)
@@ -12332,7 +12507,9 @@ var COORDINATOR_CONTROL_TOOL_NAMES = Object.freeze([
12332
12507
  "adopt_workflow",
12333
12508
  "cancel_build_pipeline",
12334
12509
  "cancel_multi_review",
12510
+ "cancel_schedule",
12335
12511
  "compare_project_files",
12512
+ "create_schedule",
12336
12513
  "create_ticket",
12337
12514
  "get_build_pipeline",
12338
12515
  "get_environment",
@@ -12354,6 +12531,7 @@ var COORDINATOR_CONTROL_TOOL_NAMES = Object.freeze([
12354
12531
  "list_node_environments",
12355
12532
  "list_nodes",
12356
12533
  "list_projects",
12534
+ "list_schedules",
12357
12535
  "list_tabs",
12358
12536
  "list_tickets",
12359
12537
  "list_workflows",
@@ -12393,7 +12571,7 @@ function stripCoordinatorContext(text) {
12393
12571
 
12394
12572
  // ../../bridges/codex-bridge/src/history/rollout.ts
12395
12573
  function getCodexHomeDir() {
12396
- return process.env.CODEX_HOME || join8(homedir(), ".codex");
12574
+ return process.env.CODEX_HOME || join10(homedir(), ".codex");
12397
12575
  }
12398
12576
  function getWorkingDirectory(explicitCwd) {
12399
12577
  return explicitCwd || process.env.CWD || process.cwd();
@@ -12407,7 +12585,7 @@ async function walkJsonlFiles(dir) {
12407
12585
  }
12408
12586
  const files = [];
12409
12587
  for (const entry of entries) {
12410
- const absolutePath = join8(dir, entry.name);
12588
+ const absolutePath = join10(dir, entry.name);
12411
12589
  if (entry.isDirectory()) {
12412
12590
  files.push(...await walkJsonlFiles(absolutePath));
12413
12591
  continue;
@@ -12419,7 +12597,7 @@ async function walkJsonlFiles(dir) {
12419
12597
  return files;
12420
12598
  }
12421
12599
  async function listTranscriptPaths(codexHome = getCodexHomeDir()) {
12422
- const searchRoots = [join8(codexHome, "sessions"), join8(codexHome, "archived_sessions")];
12600
+ const searchRoots = [join10(codexHome, "sessions"), join10(codexHome, "archived_sessions")];
12423
12601
  return (await Promise.all(searchRoots.map((root) => walkJsonlFiles(root)))).flat();
12424
12602
  }
12425
12603
  var cachedTranscriptPaths = new Map;
@@ -12446,7 +12624,7 @@ function rememberTranscriptPath(threadId, path) {
12446
12624
  }
12447
12625
  function selectTranscriptPath(paths, threadId) {
12448
12626
  const anchored = paths.find((file) => {
12449
- const stem = basename(file).replace(/\.jsonl$/, "");
12627
+ const stem = basename2(file).replace(/\.jsonl$/, "");
12450
12628
  return stem === threadId || stem.endsWith(`-${threadId}`);
12451
12629
  });
12452
12630
  return anchored ?? paths.find((file) => file.includes(threadId)) ?? null;
@@ -12562,8 +12740,8 @@ async function buildTranscriptCatalog() {
12562
12740
  const metaByPath = new Map;
12563
12741
  const transcriptPathByThreadId = new Map;
12564
12742
  for (const root of [
12565
- join8(getCodexHomeDir(), "sessions"),
12566
- join8(getCodexHomeDir(), "archived_sessions")
12743
+ join10(getCodexHomeDir(), "sessions"),
12744
+ join10(getCodexHomeDir(), "archived_sessions")
12567
12745
  ]) {
12568
12746
  const files = await walkJsonlFiles(root);
12569
12747
  for (const transcriptPath of files) {
@@ -12573,7 +12751,7 @@ async function buildTranscriptCatalog() {
12573
12751
  }
12574
12752
  metas.push(meta);
12575
12753
  metaByPath.set(transcriptPath, meta);
12576
- const fileThreadId = basename(transcriptPath, ".jsonl");
12754
+ const fileThreadId = basename2(transcriptPath, ".jsonl");
12577
12755
  if (!transcriptPathByThreadId.has(fileThreadId)) {
12578
12756
  transcriptPathByThreadId.set(fileThreadId, transcriptPath);
12579
12757
  }
@@ -12758,7 +12936,7 @@ async function listPersistedSessionsForCwd(cwd, options) {
12758
12936
  return (await listPersistedSessionsWithTitlesForCwd(cwd, options)).sessions;
12759
12937
  }
12760
12938
  async function listPersistedSessionsWithTitlesForCwd(cwd, options) {
12761
- const indexPath = join8(getCodexHomeDir(), "session_index.jsonl");
12939
+ const indexPath = join10(getCodexHomeDir(), "session_index.jsonl");
12762
12940
  const lines = await readTranscriptLines(indexPath);
12763
12941
  const sessions = new Map;
12764
12942
  const transcriptCatalog = await buildTranscriptCatalogCached(options?.mustContainThreadId);
@@ -12807,9 +12985,16 @@ function mergePersistedSessionMeta(sessionsById, meta) {
12807
12985
  indexed.updatedAt = meta.updatedAt;
12808
12986
  }
12809
12987
  }
12988
+ var CODEX_CONTEXT_FRAGMENTS = [
12989
+ ["<environment_context>", "</environment_context>"],
12990
+ ["<skill>", "</skill>"],
12991
+ ["<turn_aborted>", "</turn_aborted>"],
12992
+ ["<subagent_notification>", "</subagent_notification>"],
12993
+ ["<user_shell_command>", "</user_shell_command>"]
12994
+ ];
12810
12995
  function isSyntheticPersistedUserText(text) {
12811
12996
  const trimmed = text.trim();
12812
- return trimmed.startsWith("# AGENTS.md instructions for ") || /^# AGENTS\.md instructions[ \t]*\n\s*<INSTRUCTIONS>/.test(trimmed) || trimmed.startsWith(`<recommended_plugins>
12997
+ return trimmed.startsWith("# AGENTS.md instructions for ") || /^# AGENTS\.md instructions[ \t]*\n\s*<INSTRUCTIONS>/.test(trimmed) || CODEX_CONTEXT_FRAGMENTS.some(([open, close]) => trimmed.startsWith(open) && trimmed.endsWith(close)) || trimmed.startsWith(`<recommended_plugins>
12813
12998
  Here is a list of plugins that are available but not installed.`);
12814
12999
  }
12815
13000
  function extractPersistedMessageContent(content, role) {
@@ -12826,6 +13011,9 @@ function extractPersistedMessageContent(content, role) {
12826
13011
  if (segments.length === 0) {
12827
13012
  return null;
12828
13013
  }
13014
+ if (role === "user" && segments.every((segment) => !segment.trim() || isSyntheticPersistedUserText(segment))) {
13015
+ return null;
13016
+ }
12829
13017
  const joined = segments.join(`
12830
13018
  `).trim();
12831
13019
  if (!joined) {
@@ -12835,7 +13023,7 @@ function extractPersistedMessageContent(content, role) {
12835
13023
  if (!text && parts.length === 0) {
12836
13024
  return null;
12837
13025
  }
12838
- if (role === "user" && isSyntheticPersistedUserText(text)) {
13026
+ if (role === "user" && segments.length === 1 && isSyntheticPersistedUserText(text)) {
12839
13027
  return null;
12840
13028
  }
12841
13029
  return { text, attachments: parts };
@@ -12887,7 +13075,7 @@ function persistedOutputState(payloadType, part, output) {
12887
13075
  return payloadType === "custom_tool_call_output" ? resolveTranscriptToolOutputState(part.toolName, output, part.toolState ?? null) : null;
12888
13076
  }
12889
13077
  async function findSessionIndexEntry(threadId) {
12890
- const lines = await readTranscriptLines(join8(getCodexHomeDir(), "session_index.jsonl"));
13078
+ const lines = await readTranscriptLines(join10(getCodexHomeDir(), "session_index.jsonl"));
12891
13079
  let match = null;
12892
13080
  for (const line of lines) {
12893
13081
  let parsed;
@@ -13219,6 +13407,17 @@ async function replayPersistedRollout(threadId, snapshot, meta, structuredTurns)
13219
13407
  visitCompletedItem(record.payload.item, timestamp);
13220
13408
  return;
13221
13409
  }
13410
+ if (record.type === "event_msg" && record.payload?.type === "task_complete") {
13411
+ const error = record.payload.error;
13412
+ if (error && typeof error === "object" && typeof error.message === "string") {
13413
+ ensureAssistantMessage(timestamp).parts.push({
13414
+ type: "status",
13415
+ severity: "error",
13416
+ content: turnFailureText(error.message)
13417
+ });
13418
+ }
13419
+ return;
13420
+ }
13222
13421
  if (record.type === "token_usage_record" || record.type === "event_msg" && record.payload?.type === "token_count") {
13223
13422
  if (currentRowCalledTool)
13224
13423
  responseCompletedInRow = true;
@@ -14108,7 +14307,7 @@ async function publishAssistantRows(context, state, turn, options) {
14108
14307
  }
14109
14308
 
14110
14309
  // ../../bridges/codex-bridge/src/app-server-runtime-sessions.ts
14111
- import { createHash as createHash10, randomUUID as randomUUID6 } from "node:crypto";
14310
+ import { createHash as createHash10, randomUUID as randomUUID7 } from "node:crypto";
14112
14311
 
14113
14312
  // ../protocol/src/agent-mail.ts
14114
14313
  var AGENT_MAIL_MAX_BODY_BYTES = 32 * 1024;
@@ -14173,11 +14372,11 @@ var ORKESTRATOR_ARTIFACT_MCP_PATH = "/artifact-mcp";
14173
14372
  // ../../bridges/codex-bridge/src/engine/app-server-engine.ts
14174
14373
  import { open as open6 } from "node:fs/promises";
14175
14374
  import { createHash as createHash9 } from "node:crypto";
14176
- import { isAbsolute as isAbsolute7, join as join13 } from "node:path";
14375
+ import { isAbsolute as isAbsolute8, join as join15 } from "node:path";
14177
14376
 
14178
14377
  // ../../bridges/codex-bridge/src/app-server/process-supervisor.ts
14179
14378
  import { execFile as execFile3, spawn as spawn3 } from "node:child_process";
14180
- import { randomUUID as randomUUID4 } from "node:crypto";
14379
+ import { randomUUID as randomUUID5 } from "node:crypto";
14181
14380
  import {
14182
14381
  link,
14183
14382
  mkdir as mkdir5,
@@ -14188,7 +14387,7 @@ import {
14188
14387
  rm as rm5,
14189
14388
  stat as stat5
14190
14389
  } from "node:fs/promises";
14191
- import { join as join10 } from "node:path";
14390
+ import { join as join12 } from "node:path";
14192
14391
 
14193
14392
  // ../../bridges/codex-bridge/src/app-server/errors.ts
14194
14393
  var APP_SERVER_OVERLOAD_CODE = -32001;
@@ -14257,7 +14456,7 @@ class AppServerUnavailableError extends Error {
14257
14456
  class AppServerCircuitOpenError extends Error {
14258
14457
  failures;
14259
14458
  constructor(failures, lastError) {
14260
- super(`app-server failed to start ${failures} times; not retrying${lastError ? ` (last error: ${lastError})` : ""}`);
14459
+ super(`app-server failed to start ${failures} times; not retrying until the cooldown ends${lastError ? ` (last error: ${lastError})` : ""}`);
14261
14460
  this.name = "AppServerCircuitOpenError";
14262
14461
  this.failures = failures;
14263
14462
  }
@@ -14776,7 +14975,7 @@ class SerialQueue {
14776
14975
 
14777
14976
  // ../../bridges/codex-bridge/src/app-server/notification-recorder.ts
14778
14977
  import { appendFile as appendFile4, mkdir as mkdir4 } from "node:fs/promises";
14779
- import { join as join9 } from "node:path";
14978
+ import { join as join11 } from "node:path";
14780
14979
  var DEFAULT_MAX_RECORDING_BYTES = 64 * 1024 * 1024;
14781
14980
  var DEFAULT_FLUSH_INTERVAL_MS = 250;
14782
14981
  var DEFAULT_WARN_INTERVAL_MS = 60000;
@@ -14802,7 +15001,7 @@ class NotificationRecorder {
14802
15001
  stats;
14803
15002
  constructor(options) {
14804
15003
  this.options = options;
14805
- this.path = join9(options.directory, options.fileName);
15004
+ this.path = join11(options.directory, options.fileName);
14806
15005
  this.maxBytes = options.maxBytes ?? DEFAULT_MAX_RECORDING_BYTES;
14807
15006
  this.flushIntervalMs = options.flushIntervalMs ?? DEFAULT_FLUSH_INTERVAL_MS;
14808
15007
  this.warnIntervalMs = options.warnIntervalMs ?? DEFAULT_WARN_INTERVAL_MS;
@@ -14933,6 +15132,8 @@ function isOwnershipContention(error) {
14933
15132
  var DEFAULT_BACKOFF_MS = [250, 500, 1000, 2000, 5000, 1e4];
14934
15133
  var DEFAULT_CIRCUIT_THRESHOLD = 5;
14935
15134
  var DEFAULT_CIRCUIT_WINDOW_MS = 60000;
15135
+ var DEFAULT_CIRCUIT_COOLDOWN_MS = 5 * 60000;
15136
+ var DEFAULT_CIRCUIT_MAX_COOLDOWN_MS = 30 * 60000;
14936
15137
  var DEFAULT_SHUTDOWN_GRACE_MS = 5000;
14937
15138
  var INCOMPLETE_PIDFILE_GRACE_MS = 1000;
14938
15139
  var PID_OWNERSHIP_TTL_MS = 24 * 60 * 60 * 1000;
@@ -14947,6 +15148,8 @@ class AppServerSupervisor {
14947
15148
  backoffSchedule;
14948
15149
  circuitThreshold;
14949
15150
  circuitWindowMs;
15151
+ circuitCooldownMs;
15152
+ circuitMaxCooldownMs;
14950
15153
  shutdownGraceMs;
14951
15154
  fingerprintEnvironment;
14952
15155
  notificationQueue = new SerialQueue;
@@ -14959,6 +15162,9 @@ class AppServerSupervisor {
14959
15162
  restartFailures = [];
14960
15163
  restartCount = 0;
14961
15164
  circuitOpen = false;
15165
+ circuitProbeAt = 0;
15166
+ nextCircuitCooldownMs;
15167
+ stopController = new AbortController;
14962
15168
  lastError;
14963
15169
  lastExitCode = null;
14964
15170
  lastExitSignal = null;
@@ -14966,7 +15172,7 @@ class AppServerSupervisor {
14966
15172
  unknownNotifications = 0;
14967
15173
  unknownServerRequests = 0;
14968
15174
  drainPromise = null;
14969
- pidOwnerToken = randomUUID4();
15175
+ pidOwnerToken = randomUUID5();
14970
15176
  pidOwnershipHeld = false;
14971
15177
  constructor(options) {
14972
15178
  this.options = options;
@@ -14974,6 +15180,9 @@ class AppServerSupervisor {
14974
15180
  this.backoffSchedule = options.backoffScheduleMs ?? DEFAULT_BACKOFF_MS;
14975
15181
  this.circuitThreshold = options.circuitBreakerThreshold ?? DEFAULT_CIRCUIT_THRESHOLD;
14976
15182
  this.circuitWindowMs = options.circuitWindowMs ?? DEFAULT_CIRCUIT_WINDOW_MS;
15183
+ this.circuitCooldownMs = Math.max(0, options.circuitCooldownMs ?? DEFAULT_CIRCUIT_COOLDOWN_MS);
15184
+ this.circuitMaxCooldownMs = Math.max(this.circuitCooldownMs, options.circuitMaxCooldownMs ?? DEFAULT_CIRCUIT_MAX_COOLDOWN_MS);
15185
+ this.nextCircuitCooldownMs = this.circuitCooldownMs;
14977
15186
  this.shutdownGraceMs = options.shutdownGraceMs ?? DEFAULT_SHUTDOWN_GRACE_MS;
14978
15187
  this.fingerprintEnvironment = options.fingerprintEnvironment ?? fingerprintRuntimeEnvironment;
14979
15188
  }
@@ -15026,13 +15235,15 @@ class AppServerSupervisor {
15026
15235
  async ensureStarted() {
15027
15236
  if (this.stopping)
15028
15237
  throw new AppServerUnavailableError("stopped");
15029
- if (this.circuitOpen) {
15238
+ if (this.startPromise)
15239
+ return this.startPromise;
15240
+ if (this.circuitOpen && this.now() < this.circuitProbeAt) {
15030
15241
  throw new AppServerCircuitOpenError(this.restartFailures.length, this.lastError);
15031
15242
  }
15032
15243
  if (this.current && !this.current.client.isClosed() && this.state === "ready") {
15033
15244
  return this.current;
15034
15245
  }
15035
- this.startPromise ??= this.startWithRetry().finally(() => {
15246
+ this.startPromise = this.startWithRetry(this.circuitOpen).finally(() => {
15036
15247
  this.startPromise = null;
15037
15248
  });
15038
15249
  return this.startPromise;
@@ -15069,12 +15280,14 @@ class AppServerSupervisor {
15069
15280
  return;
15070
15281
  await this.current.client.respondWithError(id, code, message);
15071
15282
  }
15072
- async startWithRetry() {
15283
+ async startWithRetry(probe = false) {
15073
15284
  let attempt = 0;
15074
15285
  for (;; ) {
15075
15286
  try {
15076
15287
  const generation = await this.start();
15077
15288
  this.restartFailures = [];
15289
+ this.circuitOpen = false;
15290
+ this.nextCircuitCooldownMs = this.circuitCooldownMs;
15078
15291
  return generation;
15079
15292
  } catch (error) {
15080
15293
  this.lastError = error instanceof Error ? error.message : String(error);
@@ -15084,7 +15297,7 @@ class AppServerSupervisor {
15084
15297
  this.setState("failed", this.lastError);
15085
15298
  throw error;
15086
15299
  }
15087
- this.recordFailure();
15300
+ this.recordFailure(probe);
15088
15301
  if (this.circuitOpen) {
15089
15302
  this.setState("failed", this.lastError);
15090
15303
  throw new AppServerCircuitOpenError(this.restartFailures.length, this.lastError);
@@ -15092,19 +15305,21 @@ class AppServerSupervisor {
15092
15305
  const delay = this.backoffDelay(attempt);
15093
15306
  attempt += 1;
15094
15307
  this.setState("backoff", `retrying in ${delay}ms: ${this.lastError}`);
15095
- await sleep(delay);
15308
+ await sleepUnlessAborted(delay, this.stopController.signal);
15096
15309
  if (this.stopping)
15097
15310
  throw new AppServerUnavailableError("stopped");
15098
15311
  }
15099
15312
  }
15100
15313
  }
15101
- recordFailure() {
15314
+ recordFailure(probe = false) {
15102
15315
  const now = this.now();
15103
15316
  this.restartFailures = this.restartFailures.filter((at) => now - at <= this.circuitWindowMs);
15104
15317
  this.restartFailures.push(now);
15105
- if (this.restartFailures.length >= this.circuitThreshold) {
15106
- this.circuitOpen = true;
15107
- }
15318
+ if (!probe && this.restartFailures.length < this.circuitThreshold)
15319
+ return;
15320
+ this.circuitOpen = true;
15321
+ this.circuitProbeAt = now + this.nextCircuitCooldownMs;
15322
+ this.nextCircuitCooldownMs = Math.min(this.circuitMaxCooldownMs, Math.max(1, this.nextCircuitCooldownMs) * 2);
15108
15323
  }
15109
15324
  backoffDelay(attempt) {
15110
15325
  const base = this.backoffSchedule[Math.min(attempt, this.backoffSchedule.length - 1)] ?? 1000;
@@ -15116,7 +15331,7 @@ class AppServerSupervisor {
15116
15331
  if (this.stopping)
15117
15332
  throw new AppServerUnavailableError("stopped");
15118
15333
  const environmentFingerprint = this.fingerprintEnvironment();
15119
- const instanceId = randomUUID4();
15334
+ const instanceId = randomUUID5();
15120
15335
  const instanceStartedAt = this.now();
15121
15336
  if (this.options.pidFileEnabled !== false && !this.pidOwnershipHeld) {
15122
15337
  const available = await this.acquirePidFileOwnership(instanceId);
@@ -15134,7 +15349,7 @@ class AppServerSupervisor {
15134
15349
  const child = spawnFn(this.options.codexPath, args, {
15135
15350
  cwd: this.options.cwd,
15136
15351
  env: {
15137
- ...process.env,
15352
+ ...runtimeEnvironmentSnapshot(),
15138
15353
  CODEX_HOME: this.options.codexHome,
15139
15354
  LOG_FORMAT: "json",
15140
15355
  ORKESTRATOR_APP_SERVER_INSTANCE_ID: instanceId
@@ -15349,6 +15564,7 @@ class AppServerSupervisor {
15349
15564
  }
15350
15565
  async stop() {
15351
15566
  this.stopping = true;
15567
+ this.stopController.abort();
15352
15568
  this.setState("draining", "bridge shutting down");
15353
15569
  const pendingStart = this.startPromise;
15354
15570
  const startingChild = this.startingChild;
@@ -15409,10 +15625,10 @@ class AppServerSupervisor {
15409
15625
  } catch {}
15410
15626
  }
15411
15627
  pidFileDir() {
15412
- return join10(this.options.codexHome, "orkestrator-bridge");
15628
+ return join12(this.options.codexHome, "orkestrator-bridge");
15413
15629
  }
15414
15630
  pidFilePath() {
15415
- return join10(this.pidFileDir(), `app-server-${hashPath(this.options.cwd)}.pid`);
15631
+ return join12(this.pidFileDir(), `app-server-${hashPath(this.options.cwd)}.pid`);
15416
15632
  }
15417
15633
  async readOwnedPidRecord(path) {
15418
15634
  let raw;
@@ -15670,7 +15886,7 @@ function runPs(args) {
15670
15886
  return new Promise((resolve, reject) => {
15671
15887
  execFile3("/bin/ps", args, {
15672
15888
  maxBuffer: 1024 * 1024,
15673
- env: { ...process.env, LC_ALL: "C", LANG: "C", TZ: process.env.TZ }
15889
+ env: { ...runtimeEnvironmentSnapshot(), LC_ALL: "C", LANG: "C", TZ: process.env.TZ }
15674
15890
  }, (error, stdout) => {
15675
15891
  if (error)
15676
15892
  reject(error);
@@ -15816,6 +16032,20 @@ function sleep(ms) {
15816
16032
  timer.unref?.();
15817
16033
  });
15818
16034
  }
16035
+ function sleepUnlessAborted(ms, signal) {
16036
+ if (signal.aborted)
16037
+ return Promise.resolve();
16038
+ return new Promise((resolve) => {
16039
+ const wake = () => {
16040
+ clearTimeout(timer);
16041
+ signal.removeEventListener("abort", wake);
16042
+ resolve();
16043
+ };
16044
+ const timer = setTimeout(wake, ms);
16045
+ timer.unref?.();
16046
+ signal.addEventListener("abort", wake, { once: true });
16047
+ });
16048
+ }
15819
16049
 
15820
16050
  // ../../bridges/codex-bridge/src/app-server/approvals.ts
15821
16051
  var MAX_APPROVAL_AMENDMENTS = 16;
@@ -17336,10 +17566,10 @@ function redactSecrets(value) {
17336
17566
 
17337
17567
  // ../../bridges/codex-bridge/src/sessions/dispatch-journal.ts
17338
17568
  import { mkdir as mkdir7, open as open4, rename as rename5, rm as rm7, writeFile as writeFile5 } from "node:fs/promises";
17339
- import { join as join12 } from "node:path";
17569
+ import { join as join14 } from "node:path";
17340
17570
 
17341
17571
  // ../../bridges/codex-bridge/src/sessions/persistence.ts
17342
- import { createHash as createHash8, randomUUID as randomUUID5 } from "node:crypto";
17572
+ import { createHash as createHash8, randomUUID as randomUUID6 } from "node:crypto";
17343
17573
  import {
17344
17574
  chmod,
17345
17575
  link as link2,
@@ -17351,7 +17581,7 @@ import {
17351
17581
  stat as stat6,
17352
17582
  writeFile as writeFile4
17353
17583
  } from "node:fs/promises";
17354
- import { join as join11 } from "node:path";
17584
+ import { join as join13 } from "node:path";
17355
17585
  var BRIDGE_SESSION_REGISTRY_VERSION = 2;
17356
17586
  var SESSION_TITLE_SOURCES = new Set([
17357
17587
  "codex",
@@ -17453,19 +17683,23 @@ class BridgeSessionStore {
17453
17683
  this.now = options.now ?? Date.now;
17454
17684
  }
17455
17685
  dir() {
17456
- return join11(this.codexHome, "orkestrator-bridge");
17686
+ return codexBridgeStateDir(this.codexHome);
17457
17687
  }
17458
17688
  path() {
17459
- return join11(this.dir(), `bridge-sessions-${this.cwdHash}.json`);
17689
+ return join13(this.dir(), `bridge-sessions-${this.cwdHash}.json`);
17460
17690
  }
17461
17691
  recordsDir() {
17462
- return join11(this.dir(), `bridge-sessions-${this.cwdHash}`);
17692
+ return join13(this.dir(), `bridge-sessions-${this.cwdHash}`);
17693
+ }
17694
+ loginRecordsDir() {
17695
+ const directory = join13(codexLoginBridgeDir(this.codexHome), `bridge-sessions-${this.cwdHash}`);
17696
+ return directory === this.recordsDir() ? undefined : directory;
17463
17697
  }
17464
17698
  recordKey(bridgeSessionId) {
17465
17699
  return createHash8("sha256").update(bridgeSessionId).digest("hex");
17466
17700
  }
17467
17701
  recordPath(bridgeSessionId) {
17468
- return join11(this.recordsDir(), `${this.recordKey(bridgeSessionId)}.json`);
17702
+ return join13(this.recordsDir(), `${this.recordKey(bridgeSessionId)}.json`);
17469
17703
  }
17470
17704
  async ensurePrivateStorage() {
17471
17705
  await mkdir6(this.dir(), { recursive: true, mode: PRIVATE_DIRECTORY_MODE });
@@ -17484,6 +17718,7 @@ class BridgeSessionStore {
17484
17718
  migrationFailed = true;
17485
17719
  this.warnPersistenceFailure(error);
17486
17720
  });
17721
+ await this.adoptLoginRecords().catch((error) => this.warnPersistenceFailure(error));
17487
17722
  let names;
17488
17723
  try {
17489
17724
  await this.ensurePrivateStorage();
@@ -17492,7 +17727,7 @@ class BridgeSessionStore {
17492
17727
  return legacy;
17493
17728
  }
17494
17729
  const records = await Promise.all(names.map(async (name) => {
17495
- const path = join11(this.recordsDir(), name);
17730
+ const path = join13(this.recordsDir(), name);
17496
17731
  if (name.endsWith(".tmp")) {
17497
17732
  await chmod(path, PRIVATE_FILE_MODE).catch(() => {
17498
17733
  return;
@@ -17575,7 +17810,7 @@ class BridgeSessionStore {
17575
17810
  await this.ensurePrivateStorage();
17576
17811
  await Promise.all(sessions.map(async (session) => {
17577
17812
  const target = this.recordPath(session.bridgeSessionId);
17578
- const temporary = `${target}.${process.pid}.${randomUUID5()}.tmp`;
17813
+ const temporary = `${target}.${process.pid}.${randomUUID6()}.tmp`;
17579
17814
  await writeFile4(temporary, `${JSON.stringify(session, null, 2)}
17580
17815
  `, {
17581
17816
  encoding: "utf8",
@@ -17595,13 +17830,43 @@ class BridgeSessionStore {
17595
17830
  return;
17596
17831
  });
17597
17832
  }
17833
+ async adoptLoginRecords() {
17834
+ const source = this.loginRecordsDir();
17835
+ if (!source)
17836
+ return;
17837
+ const names = (await readdir2(source).catch(() => [])).filter((name) => name.endsWith(".json"));
17838
+ if (names.length === 0)
17839
+ return;
17840
+ await this.ensurePrivateStorage();
17841
+ await Promise.all(names.map(async (name) => {
17842
+ const from = join13(source, name);
17843
+ const target = join13(this.recordsDir(), name);
17844
+ const temporary = `${target}.${process.pid}.${randomUUID6()}.tmp`;
17845
+ await writeFile4(temporary, await readFile6(from), { mode: PRIVATE_FILE_MODE });
17846
+ await chmod(temporary, PRIVATE_FILE_MODE);
17847
+ try {
17848
+ await link2(temporary, target).catch((error) => {
17849
+ if (error.code !== "EEXIST")
17850
+ throw error;
17851
+ });
17852
+ } finally {
17853
+ await rm6(temporary, { force: true }).catch(() => {
17854
+ return;
17855
+ });
17856
+ }
17857
+ await chmod(target, PRIVATE_FILE_MODE);
17858
+ await rm6(from, { force: true }).catch(() => {
17859
+ return;
17860
+ });
17861
+ }));
17862
+ }
17598
17863
  async writeRecordAtomic(session) {
17599
17864
  await this.ensurePrivateStorage();
17600
17865
  await this.writeAtomicPath(this.recordPath(session.bridgeSessionId), `${JSON.stringify(session, null, 2)}
17601
17866
  `);
17602
17867
  }
17603
17868
  async writeAtomicPath(path, payload) {
17604
- const temporary = `${path}.${process.pid}.${randomUUID5()}.tmp`;
17869
+ const temporary = `${path}.${process.pid}.${randomUUID6()}.tmp`;
17605
17870
  await writeFile4(temporary, payload, {
17606
17871
  encoding: "utf8",
17607
17872
  mode: PRIVATE_FILE_MODE
@@ -17693,6 +17958,9 @@ function isPersistedRecord(value) {
17693
17958
  }
17694
17959
  return (record.threadId === null || record.threadId.length > 0) && record.turnId === undefined && record.terminalStatus === undefined;
17695
17960
  }
17961
+ function sameDispatchIdentity(left, right) {
17962
+ return left.bridgeSessionId === right.bridgeSessionId && left.threadId === right.threadId && left.turnId === right.turnId && left.state === right.state && left.terminalStatus === right.terminalStatus && left.quarantined === right.quarantined;
17963
+ }
17696
17964
 
17697
17965
  class DispatchJournal {
17698
17966
  records = new Map;
@@ -17718,7 +17986,7 @@ class DispatchJournal {
17718
17986
  this.persist = options.persist !== false;
17719
17987
  }
17720
17988
  path() {
17721
- return join12(this.codexHome, "orkestrator-bridge", `dispatch-journal-${this.cwdHash}.json`);
17989
+ return join14(codexBridgeStateDir(this.codexHome), `dispatch-journal-${this.cwdHash}.json`);
17722
17990
  }
17723
17991
  async load() {
17724
17992
  if (this.loaded)
@@ -17726,46 +17994,71 @@ class DispatchJournal {
17726
17994
  this.loaded = true;
17727
17995
  if (!this.persist)
17728
17996
  return;
17997
+ const legacy = join14(codexLoginBridgeDir(this.codexHome), `dispatch-journal-${this.cwdHash}.json`);
17729
17998
  try {
17730
- const parsed = JSON.parse(await this.readBounded());
17731
- if (parsed.version !== DISPATCH_JOURNAL_VERSION || !Array.isArray(parsed.records)) {
17732
- this.integrityError = "Dispatch journal has an unsupported or malformed file shape";
17733
- return;
17734
- }
17735
- for (const persisted of parsed.records) {
17736
- const candidate = persisted && typeof persisted === "object" ? persisted : undefined;
17737
- const requestId = typeof candidate?.requestId === "string" ? candidate.requestId : "";
17738
- if (!requestId)
17739
- continue;
17740
- const sequence = Number.isSafeInteger(candidate?.sequence) && Number(candidate?.sequence) > 0 ? Number(candidate.sequence) : this.nextSequence + 1;
17741
- this.nextSequence = Math.max(this.nextSequence, sequence);
17742
- const timestamp = new Date(this.now()).toISOString();
17743
- const record = isPersistedRecord(persisted) ? { ...persisted, sequence } : {
17744
- requestId,
17745
- bridgeSessionId: typeof candidate?.bridgeSessionId === "string" ? candidate.bridgeSessionId : "",
17746
- threadId: typeof candidate?.threadId === "string" || candidate?.threadId === null ? candidate.threadId : null,
17747
- state: "terminal",
17748
- terminalStatus: "failed",
17749
- quarantined: true,
17750
- createdAt: timestamp,
17751
- updatedAt: timestamp,
17752
- sequence
17753
- };
17754
- const existing = this.records.get(requestId);
17755
- if (!existing || compareDispatchRecordsNewestFirst(record, existing) < 0) {
17756
- this.records.set(requestId, record);
17757
- }
17999
+ await this.loadPath(this.path());
18000
+ if (legacy !== this.path() && await this.loadPath(legacy, true)) {
18001
+ this.collectGarbage();
18002
+ this.refreshCapacityError();
18003
+ if (this.capacityError)
18004
+ throw new DispatchJournalCapacityError(this.capacityError);
18005
+ await this.flush({ failClosed: true });
18006
+ await rm7(legacy);
17758
18007
  }
17759
18008
  this.collectGarbage();
17760
18009
  this.refreshCapacityError();
17761
18010
  } catch (error) {
17762
- if (error?.code === "ENOENT")
17763
- return;
17764
18011
  this.integrityError = error instanceof DispatchJournalIntegrityError ? error.message : "Dispatch journal could not be safely decoded";
17765
18012
  }
17766
18013
  }
17767
- async readBounded() {
17768
- const handle = await open4(this.path(), "r");
18014
+ async loadPath(path, merging = false) {
18015
+ let contents;
18016
+ try {
18017
+ contents = await this.readBounded(path);
18018
+ } catch (error) {
18019
+ if (error?.code === "ENOENT")
18020
+ return false;
18021
+ throw error;
18022
+ }
18023
+ const parsed = JSON.parse(contents);
18024
+ if (parsed.version !== DISPATCH_JOURNAL_VERSION || !Array.isArray(parsed.records)) {
18025
+ throw new DispatchJournalIntegrityError("Dispatch journal has an unsupported or malformed file shape");
18026
+ }
18027
+ for (const persisted of parsed.records) {
18028
+ const candidate = persisted && typeof persisted === "object" ? persisted : undefined;
18029
+ const requestId = typeof candidate?.requestId === "string" ? candidate.requestId : "";
18030
+ if (!requestId)
18031
+ continue;
18032
+ const sequence = Number.isSafeInteger(candidate?.sequence) && Number(candidate?.sequence) > 0 ? Number(candidate.sequence) : this.nextSequence + 1;
18033
+ this.nextSequence = Math.max(this.nextSequence, sequence);
18034
+ const timestamp = new Date(this.now()).toISOString();
18035
+ const record = isPersistedRecord(persisted) ? { ...persisted, sequence } : {
18036
+ requestId,
18037
+ bridgeSessionId: typeof candidate?.bridgeSessionId === "string" ? candidate.bridgeSessionId : "",
18038
+ threadId: typeof candidate?.threadId === "string" || candidate?.threadId === null ? candidate.threadId : null,
18039
+ state: "terminal",
18040
+ terminalStatus: "failed",
18041
+ quarantined: true,
18042
+ createdAt: timestamp,
18043
+ updatedAt: timestamp,
18044
+ sequence
18045
+ };
18046
+ const existing = this.records.get(requestId);
18047
+ if (merging && existing && !sameDispatchIdentity(existing, record)) {
18048
+ this.records.set(requestId, {
18049
+ ...existing,
18050
+ state: "terminal",
18051
+ terminalStatus: "failed",
18052
+ quarantined: true
18053
+ });
18054
+ } else if (!existing || !merging && compareDispatchRecordsNewestFirst(record, existing) < 0) {
18055
+ this.records.set(requestId, record);
18056
+ }
18057
+ }
18058
+ return true;
18059
+ }
18060
+ async readBounded(path) {
18061
+ const handle = await open4(path, "r");
17769
18062
  try {
17770
18063
  const metadata = await handle.stat();
17771
18064
  if (!metadata.isFile() || metadata.size > this.maxBytes) {
@@ -17789,6 +18082,9 @@ class DispatchJournal {
17789
18082
  }
17790
18083
  classify(requestId) {
17791
18084
  const record = this.records.get(requestId);
18085
+ if (this.integrityError) {
18086
+ return { duplicate: Boolean(record), action: "blocked", reason: this.integrityError, record };
18087
+ }
17792
18088
  if (!record) {
17793
18089
  const blockedReason = this.integrityError ?? this.capacityError;
17794
18090
  if (blockedReason) {
@@ -17900,6 +18196,13 @@ class DispatchJournal {
17900
18196
  latestForSession(bridgeSessionId) {
17901
18197
  return [...this.records.values()].filter((record) => record.bridgeSessionId === bridgeSessionId).sort(compareDispatchRecordsNewestFirst)[0];
17902
18198
  }
18199
+ requestIdForTurn(turnId) {
18200
+ for (const record of this.records.values()) {
18201
+ if (record.turnId === turnId && !record.quarantined)
18202
+ return record.requestId;
18203
+ }
18204
+ return;
18205
+ }
17903
18206
  async forget(requestId) {
17904
18207
  if (this.integrityError)
17905
18208
  throw new DispatchJournalIntegrityError(this.integrityError);
@@ -17995,7 +18298,7 @@ class DispatchJournal {
17995
18298
  const attempt = this.writeChain.then(async () => {
17996
18299
  try {
17997
18300
  const path = this.path();
17998
- await mkdir7(join12(this.codexHome, "orkestrator-bridge"), { recursive: true });
18301
+ await mkdir7(codexBridgeStateDir(this.codexHome), { recursive: true });
17999
18302
  const temporary = `${path}.${process.pid}.${Math.random().toString(36).slice(2, 8)}.tmp`;
18000
18303
  await writeFile5(temporary, `${JSON.stringify(snapshot, null, 2)}
18001
18304
  `, "utf8");
@@ -18123,7 +18426,7 @@ function coordinatorCapabilityPolicy(mode) {
18123
18426
 
18124
18427
  // ../../bridges/codex-bridge/src/codex-config.ts
18125
18428
  import { realpathSync } from "node:fs";
18126
- import { isAbsolute as isAbsolute6 } from "node:path";
18429
+ import { isAbsolute as isAbsolute7 } from "node:path";
18127
18430
  var CODEX_MAX_CONCURRENT_THREADS_ENV = "CODEX_MAX_CONCURRENT_THREADS_PER_SESSION";
18128
18431
  var DEFAULT_CODEX_MAX_CONCURRENT_THREADS = 5;
18129
18432
  var ORKESTRATOR_AGENT_MCP_URL_ENV = "ORKESTRATOR_AGENT_MCP_URL";
@@ -18143,7 +18446,7 @@ function codexNetworkDeniedConfig(policy) {
18143
18446
  };
18144
18447
  }
18145
18448
  function codexProjectTrustConfig(policy, cwd) {
18146
- if (!policy || policy.projectResources || !cwd || !isAbsolute6(cwd))
18449
+ if (!policy || policy.projectResources || !cwd || !isAbsolute7(cwd))
18147
18450
  return {};
18148
18451
  const roots = new Set([cwd]);
18149
18452
  try {
@@ -18153,6 +18456,11 @@ function codexProjectTrustConfig(policy, cwd) {
18153
18456
  projects: Object.fromEntries([...roots].map((root) => [root, { trust_level: "untrusted" }]))
18154
18457
  };
18155
18458
  }
18459
+ function codexRequestUserInputConfig(policy) {
18460
+ if (!policy || policy.id === "pipeline")
18461
+ return {};
18462
+ return { "features.default_mode_request_user_input": true };
18463
+ }
18156
18464
  var MAX_CODEX_DISABLED_SKILLS = 1024;
18157
18465
  var KEPT_SKILL_SCOPES = new Set(["user", "system", "admin"]);
18158
18466
  function codexProjectSkillsConfig(listed) {
@@ -18166,7 +18474,7 @@ function codexProjectSkillsConfig(listed) {
18166
18474
  const { path, scope, enabled } = skill ?? {};
18167
18475
  if (enabled === true && typeof scope === "string" && KEPT_SKILL_SCOPES.has(scope))
18168
18476
  continue;
18169
- if (typeof path !== "string" || !isAbsolute6(path)) {
18477
+ if (typeof path !== "string" || !isAbsolute7(path)) {
18170
18478
  throw new Error("Codex listed a project skill without a path it can be disabled by");
18171
18479
  }
18172
18480
  disabled.add(path);
@@ -18251,11 +18559,11 @@ function codexAppServerConfigOverrides(env = process.env) {
18251
18559
  const readableRuntimeRoot = env.CODEX_BRIDGE_READABLE_RUNTIME_ROOT?.trim();
18252
18560
  const projectRoot = env.CWD?.trim();
18253
18561
  const attachmentRoot = env[BRIDGE_ATTACHMENT_ROOT_ENV]?.trim();
18254
- if (!permissionProfile || !/^[A-Za-z0-9_-]+$/.test(permissionProfile) || !readableRuntimeRoot || !isAbsolute6(readableRuntimeRoot) || !projectRoot || !isAbsolute6(projectRoot)) {
18562
+ if (!permissionProfile || !/^[A-Za-z0-9_-]+$/.test(permissionProfile) || !readableRuntimeRoot || !isAbsolute7(readableRuntimeRoot) || !projectRoot || !isAbsolute7(projectRoot)) {
18255
18563
  throw new Error("Coordinator Codex permission profile configuration is invalid");
18256
18564
  }
18257
18565
  overrides.default_permissions = JSON.stringify(permissionProfile);
18258
- overrides[`permissions.${permissionProfile}.filesystem`] = `{ ":root" = "deny", ":minimal" = "read", ":tmpdir" = "deny", ` + `":slash_tmp" = "deny", ${JSON.stringify(readableRuntimeRoot)} = "read", ` + (attachmentRoot && isAbsolute6(attachmentRoot) ? `${JSON.stringify(attachmentRoot)} = "read", ` : "") + `":workspace_roots" = { "." = "read" } }`;
18566
+ overrides[`permissions.${permissionProfile}.filesystem`] = `{ ":root" = "deny", ":minimal" = "read", ":tmpdir" = "deny", ` + `":slash_tmp" = "deny", ${JSON.stringify(readableRuntimeRoot)} = "read", ` + (attachmentRoot && isAbsolute7(attachmentRoot) ? `${JSON.stringify(attachmentRoot)} = "read", ` : "") + `":workspace_roots" = { "." = "read" } }`;
18259
18567
  overrides[`permissions.${permissionProfile}.network.enabled`] = "false";
18260
18568
  overrides.web_search = JSON.stringify(codexNetworkDeniedSearchMode(codexCoordinatorPolicy(env)));
18261
18569
  overrides["features.standalone_web_search"] = "false";
@@ -18841,7 +19149,7 @@ function signedOutAccountRead(error) {
18841
19149
  }
18842
19150
  async function readStoredLoginFingerprint(codexHome) {
18843
19151
  try {
18844
- const file = await open6(join13(codexHome, "auth.json"), "r");
19152
+ const file = await open6(join15(codexHome, "auth.json"), "r");
18845
19153
  let raw;
18846
19154
  try {
18847
19155
  const bytes = Buffer.alloc(65537);
@@ -19119,6 +19427,9 @@ class AppServerEngine {
19119
19427
  this.invalidateAccountServing(sequence);
19120
19428
  this.checkAccountSignIn(true);
19121
19429
  }
19430
+ if (notification.method === "account/login/completed" && objectRecord(notification.params).success === true) {
19431
+ this.emit({ kind: "account.signedIn", engineGeneration: generation });
19432
+ }
19122
19433
  const result = reduceNotification(notification, generation);
19123
19434
  if (result.unknownMethod) {
19124
19435
  this.unknownNotificationCount += 1;
@@ -19185,7 +19496,11 @@ class AppServerEngine {
19185
19496
  if (sequence < this.accountAppliedSequence || generation !== this.supervisor.getGeneration())
19186
19497
  return;
19187
19498
  this.accountAppliedSequence = sequence;
19499
+ const wasSignInRequired = this.accountSignInRequired;
19188
19500
  const signedIn = this.recordAccount(response);
19501
+ if (signedIn && wasSignInRequired) {
19502
+ this.emit({ kind: "account.signedIn", engineGeneration: generation });
19503
+ }
19189
19504
  if (!signedIn) {
19190
19505
  await this.requestAccountReloadFromStoredLogin(sequence, generation);
19191
19506
  return;
@@ -19344,6 +19659,7 @@ class AppServerEngine {
19344
19659
  const threadConfig = {
19345
19660
  ...codexNetworkDeniedConfig(config.policy),
19346
19661
  ...codexProjectTrustConfig(config.policy, cwd),
19662
+ ...codexRequestUserInputConfig(config.policy),
19347
19663
  ...extraConfig,
19348
19664
  ...config.agentMcp ? {
19349
19665
  ...config.agentMcp.design ? {
@@ -19380,7 +19696,6 @@ class AppServerEngine {
19380
19696
  sandbox: config.sandbox ?? (config.mode === "plan" ? "read-only" : "danger-full-access")
19381
19697
  },
19382
19698
  ...config.model ? { model: config.model } : {},
19383
- ...config.personality ? { personality: config.personality } : {},
19384
19699
  serviceTier: config.serviceTier ?? null,
19385
19700
  ...Object.keys(threadConfig).length > 0 ? { config: threadConfig } : {}
19386
19701
  };
@@ -19798,7 +20113,7 @@ class AppServerEngine {
19798
20113
  thread.model = confirmedModel.trim();
19799
20114
  }
19800
20115
  if (thread.id) {
19801
- if (typeof raw.path === "string" && isAbsolute7(raw.path)) {
20116
+ if (typeof raw.path === "string" && isAbsolute8(raw.path)) {
19802
20117
  this.rolloutPaths.set(thread.id, raw.path);
19803
20118
  }
19804
20119
  this.bindings.set(thread.id, {
@@ -19913,8 +20228,6 @@ class AppServerEngine {
19913
20228
  ...options.config.model ? { model: options.config.model } : {},
19914
20229
  ...options.config.serviceTier !== undefined ? { serviceTier: options.config.serviceTier } : {},
19915
20230
  ...options.config.reasoningEffort ? { effort: options.config.reasoningEffort } : {},
19916
- ...options.config.reasoningSummary ? { summary: options.config.reasoningSummary } : {},
19917
- ...options.config.personality ? { personality: options.config.personality } : {},
19918
20231
  ...options.config.permissionProfile ? {} : { sandboxPolicy: toSandboxPolicy(options.config) }
19919
20232
  };
19920
20233
  const { result, generation } = await this.supervisor.requestWithGeneration("turn/start", params);
@@ -20406,7 +20719,7 @@ class ThreadRegistry {
20406
20719
 
20407
20720
  // ../../bridges/codex-bridge/src/app-server-runtime-sessions.ts
20408
20721
  var SESSION_CLOSING_ERROR = "Session is closing";
20409
- var ACTIVITY_PROCESS = randomUUID6();
20722
+ var ACTIVITY_PROCESS = randomUUID7();
20410
20723
 
20411
20724
  class CodexRuntimeSessions {
20412
20725
  ctx;
@@ -21213,6 +21526,7 @@ class CodexRuntimeSessions {
21213
21526
  const awaitingRecovery = session.threadId !== null && this.ctx.threadsAwaitingDispatchRecovery.has(session.threadId);
21214
21527
  const phase = context?.phase ?? (awaitingRecovery ? "recovering" : session.restartFailure ? "failed" : "idle");
21215
21528
  const latestDispatch = this.ctx.journal.latestForSession(sessionId);
21529
+ const interruptedRequestId = session.restartFailure ? this.ctx.journal.requestIdForTurn(session.restartFailure.turnId) : undefined;
21216
21530
  const error = context?.error ?? (phase === "failed" && session.restartFailure ? CODEX_RESTARTED_MID_TURN_MESSAGE : undefined);
21217
21531
  return {
21218
21532
  status: phaseToExternalStatus(phase),
@@ -21220,7 +21534,10 @@ class CodexRuntimeSessions {
21220
21534
  phase,
21221
21535
  title: session.title,
21222
21536
  error,
21223
- ...phase === "failed" && session.restartFailure && error === CODEX_RESTARTED_MID_TURN_MESSAGE ? { interruption: "restart" } : {},
21537
+ ...phase === "failed" && session.restartFailure && error === CODEX_RESTARTED_MID_TURN_MESSAGE ? {
21538
+ interruption: "restart",
21539
+ ...interruptedRequestId ? { interruptedRequestId } : {}
21540
+ } : {},
21224
21541
  threadId: session.threadId,
21225
21542
  turnId: context?.activeTurn?.turnId,
21226
21543
  turnStartedAt: context?.turnStartedAt,
@@ -21761,7 +22078,7 @@ function parseCommandToken(text, sigils = ["/"]) {
21761
22078
  // ../../bridges/codex-bridge/src/prompts/template-discovery.ts
21762
22079
  import { createHash as createHash11 } from "node:crypto";
21763
22080
  import { open as open7, readdir as readdir3, stat as stat7 } from "node:fs/promises";
21764
- import { join as join14 } from "node:path";
22081
+ import { join as join16 } from "node:path";
21765
22082
 
21766
22083
  // ../../bridges/codex-bridge/src/prompts/template-format.ts
21767
22084
  var TEMPLATE_DESCRIPTION_MAX_BYTES = 1000;
@@ -21889,8 +22206,8 @@ var RESERVED_TEMPLATE_PREFIXES = ["/skill:", "/prompts:"];
21889
22206
  var TEMPLATE_ID_PREFIX = "codex-template:";
21890
22207
  function templateRoots(cwd, codexHome = getCodexHomeDir()) {
21891
22208
  return [
21892
- { origin: "project", dir: join14(cwd, ".codex", "prompts") },
21893
- { origin: "user", dir: join14(codexHome, "prompts") }
22209
+ { origin: "project", dir: join16(cwd, ".codex", "prompts") },
22210
+ { origin: "user", dir: join16(codexHome, "prompts") }
21894
22211
  ];
21895
22212
  }
21896
22213
  function templateCommandId(origin, relativePath) {
@@ -21914,7 +22231,7 @@ function isReservedName(name) {
21914
22231
  }
21915
22232
  var metadataCache = new Map;
21916
22233
  var METADATA_CACHE_MAX = 1024;
21917
- async function readBounded(absolutePath, maxBytes) {
22234
+ async function readBounded2(absolutePath, maxBytes) {
21918
22235
  const handle = await open7(absolutePath, "r");
21919
22236
  try {
21920
22237
  const info = await handle.stat();
@@ -21995,7 +22312,7 @@ async function scanPromptTemplates(roots, limits = TEMPLATE_LIMITS) {
21995
22312
  return;
21996
22313
  }
21997
22314
  visited += 1;
21998
- const absolutePath = join14(dir, entry.name);
22315
+ const absolutePath = join16(dir, entry.name);
21999
22316
  const relativePath = relative ? `${relative}/${entry.name}` : entry.name;
22000
22317
  if (entry.isDirectory()) {
22001
22318
  if (depth + 1 > limits.maxDepth) {
@@ -22057,7 +22374,7 @@ async function scanPromptTemplates(roots, limits = TEMPLATE_LIMITS) {
22057
22374
  if (candidate.size > limits.maxTemplateBytes)
22058
22375
  return null;
22059
22376
  try {
22060
- const { bytes, oversized } = await readBounded(candidate.absolutePath, limits.maxTemplateBytes);
22377
+ const { bytes, oversized } = await readBounded2(candidate.absolutePath, limits.maxTemplateBytes);
22061
22378
  if (oversized)
22062
22379
  return null;
22063
22380
  if (bytes.length === 0)
@@ -22134,7 +22451,7 @@ async function loadTemplateBody(entry, limits = TEMPLATE_LIMITS) {
22134
22451
  }
22135
22452
  let loaded;
22136
22453
  try {
22137
- loaded = await readBounded(entry.absolutePath, limits.maxTemplateBytes);
22454
+ loaded = await readBounded2(entry.absolutePath, limits.maxTemplateBytes);
22138
22455
  } catch {
22139
22456
  return {
22140
22457
  ok: false,
@@ -22162,7 +22479,7 @@ async function loadTemplateBody(entry, limits = TEMPLATE_LIMITS) {
22162
22479
  }
22163
22480
 
22164
22481
  // ../../bridges/codex-bridge/src/commands/skill-inventory.ts
22165
- import { isAbsolute as isAbsolute8 } from "node:path";
22482
+ import { isAbsolute as isAbsolute9 } from "node:path";
22166
22483
  var SKILL_INVENTORY_LIMITS = Object.freeze({
22167
22484
  maxSkills: 512,
22168
22485
  maxDescriptionBytes: 1000,
@@ -22214,7 +22531,7 @@ function normalizeSkillsList(raw, context) {
22214
22531
  }
22215
22532
  const name = nonEmpty(candidate.name);
22216
22533
  const path = typeof candidate.path === "string" ? candidate.path : undefined;
22217
- if (!name || !usableSkillName(name) || !path || !isAbsolute8(path)) {
22534
+ if (!name || !usableSkillName(name) || !path || !isAbsolute9(path)) {
22218
22535
  truncated = true;
22219
22536
  continue;
22220
22537
  }
@@ -23593,6 +23910,12 @@ class CodexRuntimeLifecycle {
23593
23910
  }
23594
23911
  if (event.kind === "unknown.protocol")
23595
23912
  return;
23913
+ if (event.kind === "account.signedIn") {
23914
+ for (const context of this.ctx.registry.listThreads()) {
23915
+ this.setThreadAuthNotice(context, undefined);
23916
+ }
23917
+ return;
23918
+ }
23596
23919
  if (event.kind === "account.reload.requested") {
23597
23920
  this.ctx.callbacks.reloadStoredAccountLogin().catch((error) => {
23598
23921
  console.warn("[codex-bridge] Reloading the stored account login failed:", error instanceof Error ? error.message : error);
@@ -23878,8 +24201,11 @@ class CodexRuntimeLifecycle {
23878
24201
  this.discardOutlivingCommandWindows(turn);
23879
24202
  if (turn.stoppedByShutdown && event.status === "interrupted")
23880
24203
  this.completeRecoveredTurn(turn, event.status);
23881
- else
24204
+ else {
23882
24205
  turn.complete(event.status, event.error);
24206
+ if (event.status === "failed" && event.error)
24207
+ turn.recordProviderFailure(event.error);
24208
+ }
23883
24209
  this.ctx.options.changeEvidence?.turn(this.evidenceSource(context, turn), event.status);
23884
24210
  const finalize = () => this.runFinalization(context, turn).catch((error) => {
23885
24211
  console.error(`[codex-bridge] Failed to finalize turn ${turn.turnId}:`, error instanceof Error ? error.message : error);
@@ -24626,9 +24952,6 @@ class CodexRuntimeLifecycle {
24626
24952
  const policy = coordinatorReadOnly ? codexCoordinatorPolicy() : requestedPolicy;
24627
24953
  const model = typeof body.model === "string" && body.model.trim().length > 0 ? body.model.trim() : undefined;
24628
24954
  const reasoningEffort = typeof body.modelReasoningEffort === "string" ? body.modelReasoningEffort : undefined;
24629
- const rawParameters = body.parameterValues && typeof body.parameterValues === "object" && !Array.isArray(body.parameterValues) ? body.parameterValues : {};
24630
- const reasoningSummary = ["auto", "concise", "detailed", "none"].includes(String(rawParameters.summary ?? "")) ? rawParameters.summary : undefined;
24631
- const personality = ["none", "friendly", "pragmatic"].includes(String(rawParameters.personality ?? "")) ? rawParameters.personality : undefined;
24632
24955
  const rawAgentMcp = body.agentMcp;
24633
24956
  let agentMcp;
24634
24957
  if (rawAgentMcp && typeof rawAgentMcp === "object" && !Array.isArray(rawAgentMcp)) {
@@ -24652,8 +24975,6 @@ class CodexRuntimeLifecycle {
24652
24975
  mode,
24653
24976
  model,
24654
24977
  reasoningEffort,
24655
- reasoningSummary,
24656
- personality,
24657
24978
  serviceTier: body.fastMode === true ? "fast" : null,
24658
24979
  cwd: this.ctx.options.cwd,
24659
24980
  approvalPolicy: policy?.approvals === "ask" ? "on-request" : policy?.approvals === "deny" ? "never" : "never",
@@ -26701,7 +27022,7 @@ async function writeCodexRawLog(sessionId, entry, logDir = codexRawLogDir) {
26701
27022
  try {
26702
27023
  await mkdir8(logDir, { recursive: true });
26703
27024
  const filename = `${sanitizeLogFileComponent(sessionId)}.jsonl`;
26704
- await appendFile5(join15(logDir, filename), `${JSON.stringify({
27025
+ await appendFile5(join17(logDir, filename), `${JSON.stringify({
26705
27026
  timestamp: new Date().toISOString(),
26706
27027
  sessionId,
26707
27028
  ...entry
@@ -26898,10 +27219,10 @@ function emit(event) {
26898
27219
  }
26899
27220
  }
26900
27221
  function bridgeCacheDir() {
26901
- return join15(getCodexHomeDir(), "orkestrator-bridge");
27222
+ return join17(getCodexHomeDir(), "orkestrator-bridge");
26902
27223
  }
26903
27224
  function bridgeCachePath() {
26904
- return join15(bridgeCacheDir(), "models-cache.json");
27225
+ return join17(bridgeCacheDir(), "models-cache.json");
26905
27226
  }
26906
27227
  var BRIDGE_MODEL_CACHE_VERSION = 2;
26907
27228
  async function readPersistedBridgeCache() {
@@ -26925,7 +27246,7 @@ async function writePersistedBridgeCache(models) {
26925
27246
  }
26926
27247
  async function readCodexCliModelCache() {
26927
27248
  try {
26928
- const raw = await readFile7(join15(getCodexHomeDir(), "models_cache.json"), "utf8");
27249
+ const raw = await readFile7(join17(getCodexHomeDir(), "models_cache.json"), "utf8");
26929
27250
  const models = parseModelCatalog(raw);
26930
27251
  return models.length > 0 ? models : null;
26931
27252
  } catch {
@@ -27358,7 +27679,10 @@ app.get("/session/:id/dispatch", (c) => {
27358
27679
  return c.json({ dispatch: "unknown" });
27359
27680
  const record = appServerRuntime.getJournal().get(requestId);
27360
27681
  const dispatched = record?.bridgeSessionId === c.req.param("id") && (record.state === "accepted" || record.state === "terminal");
27361
- return c.json({ dispatch: dispatched ? "dispatched" : "unknown" });
27682
+ return c.json({
27683
+ dispatch: dispatched ? "dispatched" : "unknown",
27684
+ ...dispatched ? { pending: record.state === "accepted" } : {}
27685
+ });
27362
27686
  });
27363
27687
  app.get("/session/:id/structured-output", (c) => {
27364
27688
  const result = appServerRuntime.getStructuredOutput(c.req.param("id"), c.req.query("requestId")?.trim());
@@ -27678,7 +28002,7 @@ app.get("/session/:id/mcp", async (c) => {
27678
28002
  ...typeof server.pluginId === "string" ? { scope: "plugin" } : {},
27679
28003
  toolCount: tools.length,
27680
28004
  tools,
27681
- ...typeof server.error === "string" ? { error: server.error.slice(0, 1000) } : typeof server.toolsError === "string" ? { error: server.toolsError.slice(0, 1000) } : {},
28005
+ ...typeof server.error === "string" ? { error: redactSecrets(server.error).slice(0, 1000) } : typeof server.toolsError === "string" ? { error: redactSecrets(server.toolsError).slice(0, 1000) } : {},
27682
28006
  actions: status === "needs-auth" ? ["sign-in"] : ["reconnect"]
27683
28007
  }
27684
28008
  ];