orkestrator 2.31.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.
- package/dist/client.js +4 -2
- package/dist/main.js +4063 -3091
- package/package.json +3 -3
- package/resources/claude-bridge/dist/index.js +262 -27
- package/resources/codex-bridge/dist/index.js +406 -130
|
@@ -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
|
|
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
|
|
@@ -5941,8 +5941,18 @@ function registerCodexChangeEvidenceRoutes(app, spool) {
|
|
|
5941
5941
|
|
|
5942
5942
|
// ../../bridges/codex-bridge/src/change-evidence.ts
|
|
5943
5943
|
import { createHash as createHash5 } from "node:crypto";
|
|
5944
|
-
import { existsSync } from "node:fs";
|
|
5945
|
-
import { join as
|
|
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
|
+
}
|
|
5946
5956
|
|
|
5947
5957
|
// ../protocol/src/change-evidence.ts
|
|
5948
5958
|
var PROVIDER_EVIDENCE_SCHEMA_VERSION = 1;
|
|
@@ -6340,7 +6350,7 @@ function workspaceObservationReportIssues(value) {
|
|
|
6340
6350
|
import { createHash as createHash4, randomUUID as randomUUID3 } from "node:crypto";
|
|
6341
6351
|
import { readdirSync, readFileSync } from "node:fs";
|
|
6342
6352
|
import { appendFile, mkdir, rename, rm as rm2, writeFile } from "node:fs/promises";
|
|
6343
|
-
import { join as
|
|
6353
|
+
import { join as join3 } from "node:path";
|
|
6344
6354
|
var DEFAULT_EVIDENCE_SPOOL_LIMITS = {
|
|
6345
6355
|
maxEntries: 2048,
|
|
6346
6356
|
maxEntryBytes: 256 * 1024,
|
|
@@ -6603,7 +6613,7 @@ class ChangeEvidenceSpool {
|
|
|
6603
6613
|
const lines = this.pendingLines.splice(0).join("");
|
|
6604
6614
|
this.enqueueIo(async () => {
|
|
6605
6615
|
await mkdir(directory, { recursive: true, mode: 448 });
|
|
6606
|
-
await appendFile(
|
|
6616
|
+
await appendFile(join3(directory, ENTRIES_FILE), lines, { mode: 384 });
|
|
6607
6617
|
});
|
|
6608
6618
|
}
|
|
6609
6619
|
persistBody(id, bytes) {
|
|
@@ -6611,9 +6621,9 @@ class ChangeEvidenceSpool {
|
|
|
6611
6621
|
if (!directory || this.restoring)
|
|
6612
6622
|
return;
|
|
6613
6623
|
this.enqueueIo(async () => {
|
|
6614
|
-
const bodies =
|
|
6624
|
+
const bodies = join3(directory, BODY_DIRECTORY);
|
|
6615
6625
|
await mkdir(bodies, { recursive: true, mode: 448 });
|
|
6616
|
-
await writeFile(
|
|
6626
|
+
await writeFile(join3(bodies, bodyFileName(id)), bytes, { mode: 384, flag: "wx" }).catch((error) => {
|
|
6617
6627
|
if (error.code !== "EEXIST")
|
|
6618
6628
|
throw error;
|
|
6619
6629
|
});
|
|
@@ -6623,7 +6633,7 @@ class ChangeEvidenceSpool {
|
|
|
6623
6633
|
const directory = this.directory;
|
|
6624
6634
|
if (!directory)
|
|
6625
6635
|
return;
|
|
6626
|
-
this.enqueueIo(() => rm2(
|
|
6636
|
+
this.enqueueIo(() => rm2(join3(directory, BODY_DIRECTORY, bodyFileName(id)), { force: true }));
|
|
6627
6637
|
}
|
|
6628
6638
|
compactPersisted() {
|
|
6629
6639
|
const directory = this.directory;
|
|
@@ -6634,7 +6644,7 @@ class ChangeEvidenceSpool {
|
|
|
6634
6644
|
`);
|
|
6635
6645
|
this.enqueueIo(async () => {
|
|
6636
6646
|
await mkdir(directory, { recursive: true, mode: 448 });
|
|
6637
|
-
const file =
|
|
6647
|
+
const file = join3(directory, ENTRIES_FILE);
|
|
6638
6648
|
const temp = `${file}.${process.pid}.tmp`;
|
|
6639
6649
|
await writeFile(temp, body ? `${body}
|
|
6640
6650
|
` : "", { mode: 384 });
|
|
@@ -6646,10 +6656,10 @@ class ChangeEvidenceSpool {
|
|
|
6646
6656
|
await this.io;
|
|
6647
6657
|
}
|
|
6648
6658
|
restore(directory) {
|
|
6649
|
-
const bodyDirectory =
|
|
6659
|
+
const bodyDirectory = join3(directory, BODY_DIRECTORY);
|
|
6650
6660
|
try {
|
|
6651
6661
|
for (const name of readdirSync(bodyDirectory)) {
|
|
6652
|
-
const bytes = new Uint8Array(readFileSync(
|
|
6662
|
+
const bytes = new Uint8Array(readFileSync(join3(bodyDirectory, name)));
|
|
6653
6663
|
const id = evidenceBodyId(bytes);
|
|
6654
6664
|
if (bodyFileName(id) !== name)
|
|
6655
6665
|
continue;
|
|
@@ -6661,7 +6671,7 @@ class ChangeEvidenceSpool {
|
|
|
6661
6671
|
} catch {}
|
|
6662
6672
|
let text = "";
|
|
6663
6673
|
try {
|
|
6664
|
-
text = readFileSync(
|
|
6674
|
+
text = readFileSync(join3(directory, ENTRIES_FILE), "utf8");
|
|
6665
6675
|
} catch {
|
|
6666
6676
|
return;
|
|
6667
6677
|
}
|
|
@@ -6999,7 +7009,7 @@ function canonicalEvidence(evidence) {
|
|
|
6999
7009
|
}
|
|
7000
7010
|
|
|
7001
7011
|
// ../../bridges/codex-bridge/src/messages/apply-patch.ts
|
|
7002
|
-
import { isAbsolute as
|
|
7012
|
+
import { isAbsolute as isAbsolute3, join as join4 } from "node:path";
|
|
7003
7013
|
|
|
7004
7014
|
// ../../bridges/codex-bridge/src/messages/diff-budget.ts
|
|
7005
7015
|
var MAX_INLINE_FILE_BYTES = 256 * 1024;
|
|
@@ -7153,7 +7163,7 @@ function rawPatchTitle(change) {
|
|
|
7153
7163
|
}
|
|
7154
7164
|
function rawApplyPatchParts(value, cwd, state) {
|
|
7155
7165
|
return parseRawApplyPatchChanges(value).map((change) => {
|
|
7156
|
-
const filePath =
|
|
7166
|
+
const filePath = isAbsolute3(change.targetPath) ? change.targetPath : join4(cwd, change.targetPath);
|
|
7157
7167
|
return {
|
|
7158
7168
|
type: "tool-invocation",
|
|
7159
7169
|
content: change.targetPath,
|
|
@@ -7176,7 +7186,7 @@ function rawApplyPatchParts(value, cwd, state) {
|
|
|
7176
7186
|
}
|
|
7177
7187
|
|
|
7178
7188
|
// ../../bridges/codex-bridge/src/messages/file-change-diff.ts
|
|
7179
|
-
import { isAbsolute as
|
|
7189
|
+
import { isAbsolute as isAbsolute4, join as join5, relative } from "node:path";
|
|
7180
7190
|
var MOVED_TO_SUFFIX = /\n\nMoved to: ([^\n]+)\n?$/;
|
|
7181
7191
|
var UNIFIED_START = /^(?:@@ -\d+(?:,\d+)? \+\d+(?:,\d+)? @@|--- |diff --git )/;
|
|
7182
7192
|
function suppliedFileChange(change) {
|
|
@@ -7200,7 +7210,7 @@ function suppliedFileChange(change) {
|
|
|
7200
7210
|
};
|
|
7201
7211
|
}
|
|
7202
7212
|
function headerPath(cwd, path) {
|
|
7203
|
-
return
|
|
7213
|
+
return isAbsolute4(path) ? relative(cwd, path) || path : path;
|
|
7204
7214
|
}
|
|
7205
7215
|
function contentLines(content) {
|
|
7206
7216
|
if (content.length === 0)
|
|
@@ -7239,11 +7249,11 @@ ${supplied.hunks}`;
|
|
|
7239
7249
|
`);
|
|
7240
7250
|
}
|
|
7241
7251
|
function resolvedChangePath(cwd, path) {
|
|
7242
|
-
return
|
|
7252
|
+
return isAbsolute4(path) ? path : join5(cwd, path);
|
|
7243
7253
|
}
|
|
7244
7254
|
|
|
7245
7255
|
// ../../bridges/codex-bridge/src/sessions/command-changes.ts
|
|
7246
|
-
import { isAbsolute as
|
|
7256
|
+
import { isAbsolute as isAbsolute5, join as join6 } from "node:path";
|
|
7247
7257
|
import { fileURLToPath } from "node:url";
|
|
7248
7258
|
|
|
7249
7259
|
// ../protocol/src/node/command-change-journal.ts
|
|
@@ -7424,7 +7434,7 @@ function journalFileName(threadId) {
|
|
|
7424
7434
|
}
|
|
7425
7435
|
function commandChangeJournalPath(codexHome, threadId) {
|
|
7426
7436
|
const fileName = journalFileName(threadId);
|
|
7427
|
-
return fileName ?
|
|
7437
|
+
return fileName ? join6(codexBridgeStateDir(codexHome), "command-changes", fileName) : undefined;
|
|
7428
7438
|
}
|
|
7429
7439
|
function commandChangeJournalFor(codexHome, threadId) {
|
|
7430
7440
|
const path = commandChangeJournalPath(codexHome, threadId);
|
|
@@ -7449,7 +7459,13 @@ async function readCommandChanges(codexHome, threadId) {
|
|
|
7449
7459
|
const journal = commandChangeJournalFor(codexHome, threadId);
|
|
7450
7460
|
if (!journal)
|
|
7451
7461
|
return new Map;
|
|
7452
|
-
|
|
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]);
|
|
7453
7469
|
}
|
|
7454
7470
|
function recordCommandChanges(codexHome, threadId, toolUseId, change) {
|
|
7455
7471
|
if (!hasMeasuredChanges(change))
|
|
@@ -7479,7 +7495,7 @@ function commandChangeCwd(item, fallback) {
|
|
|
7479
7495
|
return fallback;
|
|
7480
7496
|
}
|
|
7481
7497
|
}
|
|
7482
|
-
return
|
|
7498
|
+
return isAbsolute5(item.cwd) ? item.cwd : fallback;
|
|
7483
7499
|
}
|
|
7484
7500
|
function commandDidNotRun(item) {
|
|
7485
7501
|
return item.type === "command_execution" && item.status === "failed" && item.exit_code === undefined;
|
|
@@ -7556,8 +7572,111 @@ async function inheritCommandChanges(codexHome, parentThreadId, forkThreadId, me
|
|
|
7556
7572
|
journal?.append(id, change);
|
|
7557
7573
|
}
|
|
7558
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
|
+
|
|
7559
7678
|
// ../../bridges/codex-bridge/src/change-evidence.ts
|
|
7560
|
-
function detectCaptureExecutor(exists =
|
|
7679
|
+
function detectCaptureExecutor(exists = existsSync2) {
|
|
7561
7680
|
return exists("/.dockerenv") || exists("/run/.containerenv") ? "container-worker" : "host-worker";
|
|
7562
7681
|
}
|
|
7563
7682
|
function codexChangeCapabilities(executor) {
|
|
@@ -7793,13 +7912,13 @@ function suppliedMovePath(change) {
|
|
|
7793
7912
|
}
|
|
7794
7913
|
function codexChangeEvidenceDir(codexHome, cwd) {
|
|
7795
7914
|
const cwdHash = createHash5("sha256").update(cwd).digest("hex").slice(0, 16);
|
|
7796
|
-
return
|
|
7915
|
+
return join8(codexBridgeStateDir(codexHome), "change-evidence", cwdHash);
|
|
7797
7916
|
}
|
|
7798
7917
|
function createCodexChangeEvidence(options) {
|
|
7918
|
+
const directory = codexChangeEvidenceDir(options.codexHome, options.cwd);
|
|
7919
|
+
migrateCodexChangeEvidence(join8(codexLoginBridgeDir(options.codexHome), "change-evidence", basename(directory)), directory);
|
|
7799
7920
|
return new CodexChangeEvidence({
|
|
7800
|
-
spool: new ChangeEvidenceSpool({
|
|
7801
|
-
directory: codexChangeEvidenceDir(options.codexHome, options.cwd)
|
|
7802
|
-
}),
|
|
7921
|
+
spool: new ChangeEvidenceSpool({ directory }),
|
|
7803
7922
|
executor: options.executor ?? detectCaptureExecutor()
|
|
7804
7923
|
});
|
|
7805
7924
|
}
|
|
@@ -7828,7 +7947,7 @@ function codexApprovalConfig(policy, sandbox, mode) {
|
|
|
7828
7947
|
import { spawn as spawn2 } from "node:child_process";
|
|
7829
7948
|
import { appendFile as appendFile3, mkdir as mkdir3, mkdtemp as mkdtemp2, readFile as readFile2, rm as rm4, writeFile as writeFile3 } from "node:fs/promises";
|
|
7830
7949
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
7831
|
-
import { join as
|
|
7950
|
+
import { join as join9 } from "node:path";
|
|
7832
7951
|
|
|
7833
7952
|
// ../protocol/src/codex-background-task.ts
|
|
7834
7953
|
var CODEX_BACKGROUND_TASK_MODEL = "gpt-5.6-luna";
|
|
@@ -7908,7 +8027,7 @@ async function refreshRuntimeEnvironment(run = execFile2) {
|
|
|
7908
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`
|
|
7909
8028
|
], {
|
|
7910
8029
|
env: {
|
|
7911
|
-
...
|
|
8030
|
+
...runtimeEnvironmentSnapshot(),
|
|
7912
8031
|
[RUNTIME_ENV_SCRIPT_ENV]: runtimeEnvScript
|
|
7913
8032
|
},
|
|
7914
8033
|
maxBuffer: 256 * 1024
|
|
@@ -7932,7 +8051,9 @@ function fingerprintRuntimeEnvironment(env = process.env) {
|
|
|
7932
8051
|
return `sha256:${hash.digest("hex").slice(0, 32)}`;
|
|
7933
8052
|
}
|
|
7934
8053
|
function runtimeEnvironmentSnapshot(env = process.env) {
|
|
7935
|
-
|
|
8054
|
+
const snapshot = { ...env };
|
|
8055
|
+
delete snapshot.CODEX_BRIDGE_STATE_DIR;
|
|
8056
|
+
return snapshot;
|
|
7936
8057
|
}
|
|
7937
8058
|
function runtimeEnvironmentWithoutCredentials(env = process.env) {
|
|
7938
8059
|
const snapshot = runtimeEnvironmentSnapshot(env);
|
|
@@ -8217,10 +8338,10 @@ async function runCodexTitleCommand(codexPath, args, input, options = {}) {
|
|
|
8217
8338
|
});
|
|
8218
8339
|
}
|
|
8219
8340
|
async function generateSessionTitleWithCodexExec(codexPath, sourcePrompt, options = {}) {
|
|
8220
|
-
const temporaryDirectory = await mkdtemp2(
|
|
8221
|
-
const outputPath =
|
|
8222
|
-
const modelCatalogPath =
|
|
8223
|
-
const outputSchemaPath =
|
|
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");
|
|
8224
8345
|
const maxOutputBytes = options.maxOutputBytes ?? MAX_COMMAND_OUTPUT_LENGTH;
|
|
8225
8346
|
try {
|
|
8226
8347
|
await Promise.all([
|
|
@@ -8251,7 +8372,11 @@ async function generateSessionTitleWithCodexExec(codexPath, sourcePrompt, option
|
|
|
8251
8372
|
}
|
|
8252
8373
|
}
|
|
8253
8374
|
function sessionTitleIndexPath(codexHome) {
|
|
8254
|
-
return
|
|
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;
|
|
8255
8380
|
}
|
|
8256
8381
|
function persistedSourcePriority(source) {
|
|
8257
8382
|
if (source === "explicit")
|
|
@@ -8261,7 +8386,11 @@ function persistedSourcePriority(source) {
|
|
|
8261
8386
|
return 1;
|
|
8262
8387
|
}
|
|
8263
8388
|
async function readPersistedSessionTitleEntries(codexHome) {
|
|
8264
|
-
const
|
|
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;
|
|
8265
8394
|
const selected = new Map;
|
|
8266
8395
|
for (const [lineIndex, line] of raw.split(`
|
|
8267
8396
|
`).entries()) {
|
|
@@ -8306,7 +8435,7 @@ async function persistSessionTitle(codexHome, threadId, title, options = {}) {
|
|
|
8306
8435
|
throw new Error("Session title updatedAt must be a valid date");
|
|
8307
8436
|
}
|
|
8308
8437
|
const updatedAt = requestedUpdatedAt.toISOString();
|
|
8309
|
-
const directory =
|
|
8438
|
+
const directory = codexBridgeStateDir(codexHome);
|
|
8310
8439
|
await mkdir3(directory, { recursive: true });
|
|
8311
8440
|
await appendFile3(sessionTitleIndexPath(codexHome), `${JSON.stringify({
|
|
8312
8441
|
threadId: normalizedThreadId,
|
|
@@ -10825,7 +10954,7 @@ async function deriveTranscriptSubagentPartsForTurn({
|
|
|
10825
10954
|
import { createHash as createHash7 } from "node:crypto";
|
|
10826
10955
|
import { readFile as readFile4, readdir, stat as stat4 } from "node:fs/promises";
|
|
10827
10956
|
import { homedir } from "node:os";
|
|
10828
|
-
import { basename, join as
|
|
10957
|
+
import { basename as basename2, join as join10 } from "node:path";
|
|
10829
10958
|
|
|
10830
10959
|
// ../../bridges/codex-bridge/src/sessions/refused-cell-tail.ts
|
|
10831
10960
|
import { open as open2, stat as stat3 } from "node:fs/promises";
|
|
@@ -11021,7 +11150,7 @@ class RefusedCellTail {
|
|
|
11021
11150
|
}
|
|
11022
11151
|
|
|
11023
11152
|
// ../../bridges/codex-bridge/src/app-server/item-adapter.ts
|
|
11024
|
-
import { isAbsolute as
|
|
11153
|
+
import { isAbsolute as isAbsolute6 } from "node:path";
|
|
11025
11154
|
function isRecord5(value) {
|
|
11026
11155
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
11027
11156
|
}
|
|
@@ -11043,7 +11172,7 @@ function imageGenerationInputPaths(value) {
|
|
|
11043
11172
|
if (paths.size >= MAX_IMAGE_GENERATION_INPUTS)
|
|
11044
11173
|
break;
|
|
11045
11174
|
const path = isRecord5(entry) ? str(entry.path) : undefined;
|
|
11046
|
-
if (path &&
|
|
11175
|
+
if (path && isAbsolute6(path))
|
|
11047
11176
|
paths.add(path);
|
|
11048
11177
|
}
|
|
11049
11178
|
return [...paths];
|
|
@@ -11390,6 +11519,28 @@ function mapTodoArgs(items) {
|
|
|
11390
11519
|
};
|
|
11391
11520
|
}
|
|
11392
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
|
+
|
|
11393
11544
|
// ../../bridges/codex-bridge/src/sessions/turn-accumulator.ts
|
|
11394
11545
|
var MAX_ITEM_PROGRESS_CHARS = 200;
|
|
11395
11546
|
var MODEL_STEP_TOOL_ITEM_TYPES = new Set([
|
|
@@ -11711,6 +11862,14 @@ class TurnAccumulator {
|
|
|
11711
11862
|
this.touch(accumulator);
|
|
11712
11863
|
}
|
|
11713
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
|
+
}
|
|
11714
11873
|
interruptOpenAgentMessages(keepId) {
|
|
11715
11874
|
for (const id of Array.from(this.openAgentMessageIds)) {
|
|
11716
11875
|
if (id === keepId)
|
|
@@ -12412,7 +12571,7 @@ function stripCoordinatorContext(text) {
|
|
|
12412
12571
|
|
|
12413
12572
|
// ../../bridges/codex-bridge/src/history/rollout.ts
|
|
12414
12573
|
function getCodexHomeDir() {
|
|
12415
|
-
return process.env.CODEX_HOME ||
|
|
12574
|
+
return process.env.CODEX_HOME || join10(homedir(), ".codex");
|
|
12416
12575
|
}
|
|
12417
12576
|
function getWorkingDirectory(explicitCwd) {
|
|
12418
12577
|
return explicitCwd || process.env.CWD || process.cwd();
|
|
@@ -12426,7 +12585,7 @@ async function walkJsonlFiles(dir) {
|
|
|
12426
12585
|
}
|
|
12427
12586
|
const files = [];
|
|
12428
12587
|
for (const entry of entries) {
|
|
12429
|
-
const absolutePath =
|
|
12588
|
+
const absolutePath = join10(dir, entry.name);
|
|
12430
12589
|
if (entry.isDirectory()) {
|
|
12431
12590
|
files.push(...await walkJsonlFiles(absolutePath));
|
|
12432
12591
|
continue;
|
|
@@ -12438,7 +12597,7 @@ async function walkJsonlFiles(dir) {
|
|
|
12438
12597
|
return files;
|
|
12439
12598
|
}
|
|
12440
12599
|
async function listTranscriptPaths(codexHome = getCodexHomeDir()) {
|
|
12441
|
-
const searchRoots = [
|
|
12600
|
+
const searchRoots = [join10(codexHome, "sessions"), join10(codexHome, "archived_sessions")];
|
|
12442
12601
|
return (await Promise.all(searchRoots.map((root) => walkJsonlFiles(root)))).flat();
|
|
12443
12602
|
}
|
|
12444
12603
|
var cachedTranscriptPaths = new Map;
|
|
@@ -12465,7 +12624,7 @@ function rememberTranscriptPath(threadId, path) {
|
|
|
12465
12624
|
}
|
|
12466
12625
|
function selectTranscriptPath(paths, threadId) {
|
|
12467
12626
|
const anchored = paths.find((file) => {
|
|
12468
|
-
const stem =
|
|
12627
|
+
const stem = basename2(file).replace(/\.jsonl$/, "");
|
|
12469
12628
|
return stem === threadId || stem.endsWith(`-${threadId}`);
|
|
12470
12629
|
});
|
|
12471
12630
|
return anchored ?? paths.find((file) => file.includes(threadId)) ?? null;
|
|
@@ -12581,8 +12740,8 @@ async function buildTranscriptCatalog() {
|
|
|
12581
12740
|
const metaByPath = new Map;
|
|
12582
12741
|
const transcriptPathByThreadId = new Map;
|
|
12583
12742
|
for (const root of [
|
|
12584
|
-
|
|
12585
|
-
|
|
12743
|
+
join10(getCodexHomeDir(), "sessions"),
|
|
12744
|
+
join10(getCodexHomeDir(), "archived_sessions")
|
|
12586
12745
|
]) {
|
|
12587
12746
|
const files = await walkJsonlFiles(root);
|
|
12588
12747
|
for (const transcriptPath of files) {
|
|
@@ -12592,7 +12751,7 @@ async function buildTranscriptCatalog() {
|
|
|
12592
12751
|
}
|
|
12593
12752
|
metas.push(meta);
|
|
12594
12753
|
metaByPath.set(transcriptPath, meta);
|
|
12595
|
-
const fileThreadId =
|
|
12754
|
+
const fileThreadId = basename2(transcriptPath, ".jsonl");
|
|
12596
12755
|
if (!transcriptPathByThreadId.has(fileThreadId)) {
|
|
12597
12756
|
transcriptPathByThreadId.set(fileThreadId, transcriptPath);
|
|
12598
12757
|
}
|
|
@@ -12777,7 +12936,7 @@ async function listPersistedSessionsForCwd(cwd, options) {
|
|
|
12777
12936
|
return (await listPersistedSessionsWithTitlesForCwd(cwd, options)).sessions;
|
|
12778
12937
|
}
|
|
12779
12938
|
async function listPersistedSessionsWithTitlesForCwd(cwd, options) {
|
|
12780
|
-
const indexPath =
|
|
12939
|
+
const indexPath = join10(getCodexHomeDir(), "session_index.jsonl");
|
|
12781
12940
|
const lines = await readTranscriptLines(indexPath);
|
|
12782
12941
|
const sessions = new Map;
|
|
12783
12942
|
const transcriptCatalog = await buildTranscriptCatalogCached(options?.mustContainThreadId);
|
|
@@ -12826,9 +12985,16 @@ function mergePersistedSessionMeta(sessionsById, meta) {
|
|
|
12826
12985
|
indexed.updatedAt = meta.updatedAt;
|
|
12827
12986
|
}
|
|
12828
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
|
+
];
|
|
12829
12995
|
function isSyntheticPersistedUserText(text) {
|
|
12830
12996
|
const trimmed = text.trim();
|
|
12831
|
-
return trimmed.startsWith("# AGENTS.md instructions for ") || /^# AGENTS\.md instructions[ \t]*\n\s*<INSTRUCTIONS>/.test(trimmed) || trimmed.startsWith(
|
|
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>
|
|
12832
12998
|
Here is a list of plugins that are available but not installed.`);
|
|
12833
12999
|
}
|
|
12834
13000
|
function extractPersistedMessageContent(content, role) {
|
|
@@ -12845,6 +13011,9 @@ function extractPersistedMessageContent(content, role) {
|
|
|
12845
13011
|
if (segments.length === 0) {
|
|
12846
13012
|
return null;
|
|
12847
13013
|
}
|
|
13014
|
+
if (role === "user" && segments.every((segment) => !segment.trim() || isSyntheticPersistedUserText(segment))) {
|
|
13015
|
+
return null;
|
|
13016
|
+
}
|
|
12848
13017
|
const joined = segments.join(`
|
|
12849
13018
|
`).trim();
|
|
12850
13019
|
if (!joined) {
|
|
@@ -12854,7 +13023,7 @@ function extractPersistedMessageContent(content, role) {
|
|
|
12854
13023
|
if (!text && parts.length === 0) {
|
|
12855
13024
|
return null;
|
|
12856
13025
|
}
|
|
12857
|
-
if (role === "user" && isSyntheticPersistedUserText(text)) {
|
|
13026
|
+
if (role === "user" && segments.length === 1 && isSyntheticPersistedUserText(text)) {
|
|
12858
13027
|
return null;
|
|
12859
13028
|
}
|
|
12860
13029
|
return { text, attachments: parts };
|
|
@@ -12906,7 +13075,7 @@ function persistedOutputState(payloadType, part, output) {
|
|
|
12906
13075
|
return payloadType === "custom_tool_call_output" ? resolveTranscriptToolOutputState(part.toolName, output, part.toolState ?? null) : null;
|
|
12907
13076
|
}
|
|
12908
13077
|
async function findSessionIndexEntry(threadId) {
|
|
12909
|
-
const lines = await readTranscriptLines(
|
|
13078
|
+
const lines = await readTranscriptLines(join10(getCodexHomeDir(), "session_index.jsonl"));
|
|
12910
13079
|
let match = null;
|
|
12911
13080
|
for (const line of lines) {
|
|
12912
13081
|
let parsed;
|
|
@@ -13238,6 +13407,17 @@ async function replayPersistedRollout(threadId, snapshot, meta, structuredTurns)
|
|
|
13238
13407
|
visitCompletedItem(record.payload.item, timestamp);
|
|
13239
13408
|
return;
|
|
13240
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
|
+
}
|
|
13241
13421
|
if (record.type === "token_usage_record" || record.type === "event_msg" && record.payload?.type === "token_count") {
|
|
13242
13422
|
if (currentRowCalledTool)
|
|
13243
13423
|
responseCompletedInRow = true;
|
|
@@ -14127,7 +14307,7 @@ async function publishAssistantRows(context, state, turn, options) {
|
|
|
14127
14307
|
}
|
|
14128
14308
|
|
|
14129
14309
|
// ../../bridges/codex-bridge/src/app-server-runtime-sessions.ts
|
|
14130
|
-
import { createHash as createHash10, randomUUID as
|
|
14310
|
+
import { createHash as createHash10, randomUUID as randomUUID7 } from "node:crypto";
|
|
14131
14311
|
|
|
14132
14312
|
// ../protocol/src/agent-mail.ts
|
|
14133
14313
|
var AGENT_MAIL_MAX_BODY_BYTES = 32 * 1024;
|
|
@@ -14192,11 +14372,11 @@ var ORKESTRATOR_ARTIFACT_MCP_PATH = "/artifact-mcp";
|
|
|
14192
14372
|
// ../../bridges/codex-bridge/src/engine/app-server-engine.ts
|
|
14193
14373
|
import { open as open6 } from "node:fs/promises";
|
|
14194
14374
|
import { createHash as createHash9 } from "node:crypto";
|
|
14195
|
-
import { isAbsolute as
|
|
14375
|
+
import { isAbsolute as isAbsolute8, join as join15 } from "node:path";
|
|
14196
14376
|
|
|
14197
14377
|
// ../../bridges/codex-bridge/src/app-server/process-supervisor.ts
|
|
14198
14378
|
import { execFile as execFile3, spawn as spawn3 } from "node:child_process";
|
|
14199
|
-
import { randomUUID as
|
|
14379
|
+
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
14200
14380
|
import {
|
|
14201
14381
|
link,
|
|
14202
14382
|
mkdir as mkdir5,
|
|
@@ -14207,7 +14387,7 @@ import {
|
|
|
14207
14387
|
rm as rm5,
|
|
14208
14388
|
stat as stat5
|
|
14209
14389
|
} from "node:fs/promises";
|
|
14210
|
-
import { join as
|
|
14390
|
+
import { join as join12 } from "node:path";
|
|
14211
14391
|
|
|
14212
14392
|
// ../../bridges/codex-bridge/src/app-server/errors.ts
|
|
14213
14393
|
var APP_SERVER_OVERLOAD_CODE = -32001;
|
|
@@ -14795,7 +14975,7 @@ class SerialQueue {
|
|
|
14795
14975
|
|
|
14796
14976
|
// ../../bridges/codex-bridge/src/app-server/notification-recorder.ts
|
|
14797
14977
|
import { appendFile as appendFile4, mkdir as mkdir4 } from "node:fs/promises";
|
|
14798
|
-
import { join as
|
|
14978
|
+
import { join as join11 } from "node:path";
|
|
14799
14979
|
var DEFAULT_MAX_RECORDING_BYTES = 64 * 1024 * 1024;
|
|
14800
14980
|
var DEFAULT_FLUSH_INTERVAL_MS = 250;
|
|
14801
14981
|
var DEFAULT_WARN_INTERVAL_MS = 60000;
|
|
@@ -14821,7 +15001,7 @@ class NotificationRecorder {
|
|
|
14821
15001
|
stats;
|
|
14822
15002
|
constructor(options) {
|
|
14823
15003
|
this.options = options;
|
|
14824
|
-
this.path =
|
|
15004
|
+
this.path = join11(options.directory, options.fileName);
|
|
14825
15005
|
this.maxBytes = options.maxBytes ?? DEFAULT_MAX_RECORDING_BYTES;
|
|
14826
15006
|
this.flushIntervalMs = options.flushIntervalMs ?? DEFAULT_FLUSH_INTERVAL_MS;
|
|
14827
15007
|
this.warnIntervalMs = options.warnIntervalMs ?? DEFAULT_WARN_INTERVAL_MS;
|
|
@@ -14992,7 +15172,7 @@ class AppServerSupervisor {
|
|
|
14992
15172
|
unknownNotifications = 0;
|
|
14993
15173
|
unknownServerRequests = 0;
|
|
14994
15174
|
drainPromise = null;
|
|
14995
|
-
pidOwnerToken =
|
|
15175
|
+
pidOwnerToken = randomUUID5();
|
|
14996
15176
|
pidOwnershipHeld = false;
|
|
14997
15177
|
constructor(options) {
|
|
14998
15178
|
this.options = options;
|
|
@@ -15151,7 +15331,7 @@ class AppServerSupervisor {
|
|
|
15151
15331
|
if (this.stopping)
|
|
15152
15332
|
throw new AppServerUnavailableError("stopped");
|
|
15153
15333
|
const environmentFingerprint = this.fingerprintEnvironment();
|
|
15154
|
-
const instanceId =
|
|
15334
|
+
const instanceId = randomUUID5();
|
|
15155
15335
|
const instanceStartedAt = this.now();
|
|
15156
15336
|
if (this.options.pidFileEnabled !== false && !this.pidOwnershipHeld) {
|
|
15157
15337
|
const available = await this.acquirePidFileOwnership(instanceId);
|
|
@@ -15169,7 +15349,7 @@ class AppServerSupervisor {
|
|
|
15169
15349
|
const child = spawnFn(this.options.codexPath, args, {
|
|
15170
15350
|
cwd: this.options.cwd,
|
|
15171
15351
|
env: {
|
|
15172
|
-
...
|
|
15352
|
+
...runtimeEnvironmentSnapshot(),
|
|
15173
15353
|
CODEX_HOME: this.options.codexHome,
|
|
15174
15354
|
LOG_FORMAT: "json",
|
|
15175
15355
|
ORKESTRATOR_APP_SERVER_INSTANCE_ID: instanceId
|
|
@@ -15445,10 +15625,10 @@ class AppServerSupervisor {
|
|
|
15445
15625
|
} catch {}
|
|
15446
15626
|
}
|
|
15447
15627
|
pidFileDir() {
|
|
15448
|
-
return
|
|
15628
|
+
return join12(this.options.codexHome, "orkestrator-bridge");
|
|
15449
15629
|
}
|
|
15450
15630
|
pidFilePath() {
|
|
15451
|
-
return
|
|
15631
|
+
return join12(this.pidFileDir(), `app-server-${hashPath(this.options.cwd)}.pid`);
|
|
15452
15632
|
}
|
|
15453
15633
|
async readOwnedPidRecord(path) {
|
|
15454
15634
|
let raw;
|
|
@@ -15706,7 +15886,7 @@ function runPs(args) {
|
|
|
15706
15886
|
return new Promise((resolve, reject) => {
|
|
15707
15887
|
execFile3("/bin/ps", args, {
|
|
15708
15888
|
maxBuffer: 1024 * 1024,
|
|
15709
|
-
env: { ...
|
|
15889
|
+
env: { ...runtimeEnvironmentSnapshot(), LC_ALL: "C", LANG: "C", TZ: process.env.TZ }
|
|
15710
15890
|
}, (error, stdout) => {
|
|
15711
15891
|
if (error)
|
|
15712
15892
|
reject(error);
|
|
@@ -17386,10 +17566,10 @@ function redactSecrets(value) {
|
|
|
17386
17566
|
|
|
17387
17567
|
// ../../bridges/codex-bridge/src/sessions/dispatch-journal.ts
|
|
17388
17568
|
import { mkdir as mkdir7, open as open4, rename as rename5, rm as rm7, writeFile as writeFile5 } from "node:fs/promises";
|
|
17389
|
-
import { join as
|
|
17569
|
+
import { join as join14 } from "node:path";
|
|
17390
17570
|
|
|
17391
17571
|
// ../../bridges/codex-bridge/src/sessions/persistence.ts
|
|
17392
|
-
import { createHash as createHash8, randomUUID as
|
|
17572
|
+
import { createHash as createHash8, randomUUID as randomUUID6 } from "node:crypto";
|
|
17393
17573
|
import {
|
|
17394
17574
|
chmod,
|
|
17395
17575
|
link as link2,
|
|
@@ -17401,7 +17581,7 @@ import {
|
|
|
17401
17581
|
stat as stat6,
|
|
17402
17582
|
writeFile as writeFile4
|
|
17403
17583
|
} from "node:fs/promises";
|
|
17404
|
-
import { join as
|
|
17584
|
+
import { join as join13 } from "node:path";
|
|
17405
17585
|
var BRIDGE_SESSION_REGISTRY_VERSION = 2;
|
|
17406
17586
|
var SESSION_TITLE_SOURCES = new Set([
|
|
17407
17587
|
"codex",
|
|
@@ -17503,19 +17683,23 @@ class BridgeSessionStore {
|
|
|
17503
17683
|
this.now = options.now ?? Date.now;
|
|
17504
17684
|
}
|
|
17505
17685
|
dir() {
|
|
17506
|
-
return
|
|
17686
|
+
return codexBridgeStateDir(this.codexHome);
|
|
17507
17687
|
}
|
|
17508
17688
|
path() {
|
|
17509
|
-
return
|
|
17689
|
+
return join13(this.dir(), `bridge-sessions-${this.cwdHash}.json`);
|
|
17510
17690
|
}
|
|
17511
17691
|
recordsDir() {
|
|
17512
|
-
return
|
|
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;
|
|
17513
17697
|
}
|
|
17514
17698
|
recordKey(bridgeSessionId) {
|
|
17515
17699
|
return createHash8("sha256").update(bridgeSessionId).digest("hex");
|
|
17516
17700
|
}
|
|
17517
17701
|
recordPath(bridgeSessionId) {
|
|
17518
|
-
return
|
|
17702
|
+
return join13(this.recordsDir(), `${this.recordKey(bridgeSessionId)}.json`);
|
|
17519
17703
|
}
|
|
17520
17704
|
async ensurePrivateStorage() {
|
|
17521
17705
|
await mkdir6(this.dir(), { recursive: true, mode: PRIVATE_DIRECTORY_MODE });
|
|
@@ -17534,6 +17718,7 @@ class BridgeSessionStore {
|
|
|
17534
17718
|
migrationFailed = true;
|
|
17535
17719
|
this.warnPersistenceFailure(error);
|
|
17536
17720
|
});
|
|
17721
|
+
await this.adoptLoginRecords().catch((error) => this.warnPersistenceFailure(error));
|
|
17537
17722
|
let names;
|
|
17538
17723
|
try {
|
|
17539
17724
|
await this.ensurePrivateStorage();
|
|
@@ -17542,7 +17727,7 @@ class BridgeSessionStore {
|
|
|
17542
17727
|
return legacy;
|
|
17543
17728
|
}
|
|
17544
17729
|
const records = await Promise.all(names.map(async (name) => {
|
|
17545
|
-
const path =
|
|
17730
|
+
const path = join13(this.recordsDir(), name);
|
|
17546
17731
|
if (name.endsWith(".tmp")) {
|
|
17547
17732
|
await chmod(path, PRIVATE_FILE_MODE).catch(() => {
|
|
17548
17733
|
return;
|
|
@@ -17625,7 +17810,7 @@ class BridgeSessionStore {
|
|
|
17625
17810
|
await this.ensurePrivateStorage();
|
|
17626
17811
|
await Promise.all(sessions.map(async (session) => {
|
|
17627
17812
|
const target = this.recordPath(session.bridgeSessionId);
|
|
17628
|
-
const temporary = `${target}.${process.pid}.${
|
|
17813
|
+
const temporary = `${target}.${process.pid}.${randomUUID6()}.tmp`;
|
|
17629
17814
|
await writeFile4(temporary, `${JSON.stringify(session, null, 2)}
|
|
17630
17815
|
`, {
|
|
17631
17816
|
encoding: "utf8",
|
|
@@ -17645,13 +17830,43 @@ class BridgeSessionStore {
|
|
|
17645
17830
|
return;
|
|
17646
17831
|
});
|
|
17647
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
|
+
}
|
|
17648
17863
|
async writeRecordAtomic(session) {
|
|
17649
17864
|
await this.ensurePrivateStorage();
|
|
17650
17865
|
await this.writeAtomicPath(this.recordPath(session.bridgeSessionId), `${JSON.stringify(session, null, 2)}
|
|
17651
17866
|
`);
|
|
17652
17867
|
}
|
|
17653
17868
|
async writeAtomicPath(path, payload) {
|
|
17654
|
-
const temporary = `${path}.${process.pid}.${
|
|
17869
|
+
const temporary = `${path}.${process.pid}.${randomUUID6()}.tmp`;
|
|
17655
17870
|
await writeFile4(temporary, payload, {
|
|
17656
17871
|
encoding: "utf8",
|
|
17657
17872
|
mode: PRIVATE_FILE_MODE
|
|
@@ -17743,6 +17958,9 @@ function isPersistedRecord(value) {
|
|
|
17743
17958
|
}
|
|
17744
17959
|
return (record.threadId === null || record.threadId.length > 0) && record.turnId === undefined && record.terminalStatus === undefined;
|
|
17745
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
|
+
}
|
|
17746
17964
|
|
|
17747
17965
|
class DispatchJournal {
|
|
17748
17966
|
records = new Map;
|
|
@@ -17768,7 +17986,7 @@ class DispatchJournal {
|
|
|
17768
17986
|
this.persist = options.persist !== false;
|
|
17769
17987
|
}
|
|
17770
17988
|
path() {
|
|
17771
|
-
return
|
|
17989
|
+
return join14(codexBridgeStateDir(this.codexHome), `dispatch-journal-${this.cwdHash}.json`);
|
|
17772
17990
|
}
|
|
17773
17991
|
async load() {
|
|
17774
17992
|
if (this.loaded)
|
|
@@ -17776,46 +17994,71 @@ class DispatchJournal {
|
|
|
17776
17994
|
this.loaded = true;
|
|
17777
17995
|
if (!this.persist)
|
|
17778
17996
|
return;
|
|
17997
|
+
const legacy = join14(codexLoginBridgeDir(this.codexHome), `dispatch-journal-${this.cwdHash}.json`);
|
|
17779
17998
|
try {
|
|
17780
|
-
|
|
17781
|
-
if (
|
|
17782
|
-
this.
|
|
17783
|
-
|
|
17784
|
-
|
|
17785
|
-
|
|
17786
|
-
|
|
17787
|
-
|
|
17788
|
-
if (!requestId)
|
|
17789
|
-
continue;
|
|
17790
|
-
const sequence = Number.isSafeInteger(candidate?.sequence) && Number(candidate?.sequence) > 0 ? Number(candidate.sequence) : this.nextSequence + 1;
|
|
17791
|
-
this.nextSequence = Math.max(this.nextSequence, sequence);
|
|
17792
|
-
const timestamp = new Date(this.now()).toISOString();
|
|
17793
|
-
const record = isPersistedRecord(persisted) ? { ...persisted, sequence } : {
|
|
17794
|
-
requestId,
|
|
17795
|
-
bridgeSessionId: typeof candidate?.bridgeSessionId === "string" ? candidate.bridgeSessionId : "",
|
|
17796
|
-
threadId: typeof candidate?.threadId === "string" || candidate?.threadId === null ? candidate.threadId : null,
|
|
17797
|
-
state: "terminal",
|
|
17798
|
-
terminalStatus: "failed",
|
|
17799
|
-
quarantined: true,
|
|
17800
|
-
createdAt: timestamp,
|
|
17801
|
-
updatedAt: timestamp,
|
|
17802
|
-
sequence
|
|
17803
|
-
};
|
|
17804
|
-
const existing = this.records.get(requestId);
|
|
17805
|
-
if (!existing || compareDispatchRecordsNewestFirst(record, existing) < 0) {
|
|
17806
|
-
this.records.set(requestId, record);
|
|
17807
|
-
}
|
|
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);
|
|
17808
18007
|
}
|
|
17809
18008
|
this.collectGarbage();
|
|
17810
18009
|
this.refreshCapacityError();
|
|
17811
18010
|
} catch (error) {
|
|
17812
|
-
if (error?.code === "ENOENT")
|
|
17813
|
-
return;
|
|
17814
18011
|
this.integrityError = error instanceof DispatchJournalIntegrityError ? error.message : "Dispatch journal could not be safely decoded";
|
|
17815
18012
|
}
|
|
17816
18013
|
}
|
|
17817
|
-
async
|
|
17818
|
-
|
|
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");
|
|
17819
18062
|
try {
|
|
17820
18063
|
const metadata = await handle.stat();
|
|
17821
18064
|
if (!metadata.isFile() || metadata.size > this.maxBytes) {
|
|
@@ -17839,6 +18082,9 @@ class DispatchJournal {
|
|
|
17839
18082
|
}
|
|
17840
18083
|
classify(requestId) {
|
|
17841
18084
|
const record = this.records.get(requestId);
|
|
18085
|
+
if (this.integrityError) {
|
|
18086
|
+
return { duplicate: Boolean(record), action: "blocked", reason: this.integrityError, record };
|
|
18087
|
+
}
|
|
17842
18088
|
if (!record) {
|
|
17843
18089
|
const blockedReason = this.integrityError ?? this.capacityError;
|
|
17844
18090
|
if (blockedReason) {
|
|
@@ -17950,6 +18196,13 @@ class DispatchJournal {
|
|
|
17950
18196
|
latestForSession(bridgeSessionId) {
|
|
17951
18197
|
return [...this.records.values()].filter((record) => record.bridgeSessionId === bridgeSessionId).sort(compareDispatchRecordsNewestFirst)[0];
|
|
17952
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
|
+
}
|
|
17953
18206
|
async forget(requestId) {
|
|
17954
18207
|
if (this.integrityError)
|
|
17955
18208
|
throw new DispatchJournalIntegrityError(this.integrityError);
|
|
@@ -18045,7 +18298,7 @@ class DispatchJournal {
|
|
|
18045
18298
|
const attempt = this.writeChain.then(async () => {
|
|
18046
18299
|
try {
|
|
18047
18300
|
const path = this.path();
|
|
18048
|
-
await mkdir7(
|
|
18301
|
+
await mkdir7(codexBridgeStateDir(this.codexHome), { recursive: true });
|
|
18049
18302
|
const temporary = `${path}.${process.pid}.${Math.random().toString(36).slice(2, 8)}.tmp`;
|
|
18050
18303
|
await writeFile5(temporary, `${JSON.stringify(snapshot, null, 2)}
|
|
18051
18304
|
`, "utf8");
|
|
@@ -18173,7 +18426,7 @@ function coordinatorCapabilityPolicy(mode) {
|
|
|
18173
18426
|
|
|
18174
18427
|
// ../../bridges/codex-bridge/src/codex-config.ts
|
|
18175
18428
|
import { realpathSync } from "node:fs";
|
|
18176
|
-
import { isAbsolute as
|
|
18429
|
+
import { isAbsolute as isAbsolute7 } from "node:path";
|
|
18177
18430
|
var CODEX_MAX_CONCURRENT_THREADS_ENV = "CODEX_MAX_CONCURRENT_THREADS_PER_SESSION";
|
|
18178
18431
|
var DEFAULT_CODEX_MAX_CONCURRENT_THREADS = 5;
|
|
18179
18432
|
var ORKESTRATOR_AGENT_MCP_URL_ENV = "ORKESTRATOR_AGENT_MCP_URL";
|
|
@@ -18193,7 +18446,7 @@ function codexNetworkDeniedConfig(policy) {
|
|
|
18193
18446
|
};
|
|
18194
18447
|
}
|
|
18195
18448
|
function codexProjectTrustConfig(policy, cwd) {
|
|
18196
|
-
if (!policy || policy.projectResources || !cwd || !
|
|
18449
|
+
if (!policy || policy.projectResources || !cwd || !isAbsolute7(cwd))
|
|
18197
18450
|
return {};
|
|
18198
18451
|
const roots = new Set([cwd]);
|
|
18199
18452
|
try {
|
|
@@ -18221,7 +18474,7 @@ function codexProjectSkillsConfig(listed) {
|
|
|
18221
18474
|
const { path, scope, enabled } = skill ?? {};
|
|
18222
18475
|
if (enabled === true && typeof scope === "string" && KEPT_SKILL_SCOPES.has(scope))
|
|
18223
18476
|
continue;
|
|
18224
|
-
if (typeof path !== "string" || !
|
|
18477
|
+
if (typeof path !== "string" || !isAbsolute7(path)) {
|
|
18225
18478
|
throw new Error("Codex listed a project skill without a path it can be disabled by");
|
|
18226
18479
|
}
|
|
18227
18480
|
disabled.add(path);
|
|
@@ -18306,11 +18559,11 @@ function codexAppServerConfigOverrides(env = process.env) {
|
|
|
18306
18559
|
const readableRuntimeRoot = env.CODEX_BRIDGE_READABLE_RUNTIME_ROOT?.trim();
|
|
18307
18560
|
const projectRoot = env.CWD?.trim();
|
|
18308
18561
|
const attachmentRoot = env[BRIDGE_ATTACHMENT_ROOT_ENV]?.trim();
|
|
18309
|
-
if (!permissionProfile || !/^[A-Za-z0-9_-]+$/.test(permissionProfile) || !readableRuntimeRoot || !
|
|
18562
|
+
if (!permissionProfile || !/^[A-Za-z0-9_-]+$/.test(permissionProfile) || !readableRuntimeRoot || !isAbsolute7(readableRuntimeRoot) || !projectRoot || !isAbsolute7(projectRoot)) {
|
|
18310
18563
|
throw new Error("Coordinator Codex permission profile configuration is invalid");
|
|
18311
18564
|
}
|
|
18312
18565
|
overrides.default_permissions = JSON.stringify(permissionProfile);
|
|
18313
|
-
overrides[`permissions.${permissionProfile}.filesystem`] = `{ ":root" = "deny", ":minimal" = "read", ":tmpdir" = "deny", ` + `":slash_tmp" = "deny", ${JSON.stringify(readableRuntimeRoot)} = "read", ` + (attachmentRoot &&
|
|
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" } }`;
|
|
18314
18567
|
overrides[`permissions.${permissionProfile}.network.enabled`] = "false";
|
|
18315
18568
|
overrides.web_search = JSON.stringify(codexNetworkDeniedSearchMode(codexCoordinatorPolicy(env)));
|
|
18316
18569
|
overrides["features.standalone_web_search"] = "false";
|
|
@@ -18896,7 +19149,7 @@ function signedOutAccountRead(error) {
|
|
|
18896
19149
|
}
|
|
18897
19150
|
async function readStoredLoginFingerprint(codexHome) {
|
|
18898
19151
|
try {
|
|
18899
|
-
const file = await open6(
|
|
19152
|
+
const file = await open6(join15(codexHome, "auth.json"), "r");
|
|
18900
19153
|
let raw;
|
|
18901
19154
|
try {
|
|
18902
19155
|
const bytes = Buffer.alloc(65537);
|
|
@@ -19174,6 +19427,9 @@ class AppServerEngine {
|
|
|
19174
19427
|
this.invalidateAccountServing(sequence);
|
|
19175
19428
|
this.checkAccountSignIn(true);
|
|
19176
19429
|
}
|
|
19430
|
+
if (notification.method === "account/login/completed" && objectRecord(notification.params).success === true) {
|
|
19431
|
+
this.emit({ kind: "account.signedIn", engineGeneration: generation });
|
|
19432
|
+
}
|
|
19177
19433
|
const result = reduceNotification(notification, generation);
|
|
19178
19434
|
if (result.unknownMethod) {
|
|
19179
19435
|
this.unknownNotificationCount += 1;
|
|
@@ -19240,7 +19496,11 @@ class AppServerEngine {
|
|
|
19240
19496
|
if (sequence < this.accountAppliedSequence || generation !== this.supervisor.getGeneration())
|
|
19241
19497
|
return;
|
|
19242
19498
|
this.accountAppliedSequence = sequence;
|
|
19499
|
+
const wasSignInRequired = this.accountSignInRequired;
|
|
19243
19500
|
const signedIn = this.recordAccount(response);
|
|
19501
|
+
if (signedIn && wasSignInRequired) {
|
|
19502
|
+
this.emit({ kind: "account.signedIn", engineGeneration: generation });
|
|
19503
|
+
}
|
|
19244
19504
|
if (!signedIn) {
|
|
19245
19505
|
await this.requestAccountReloadFromStoredLogin(sequence, generation);
|
|
19246
19506
|
return;
|
|
@@ -19853,7 +20113,7 @@ class AppServerEngine {
|
|
|
19853
20113
|
thread.model = confirmedModel.trim();
|
|
19854
20114
|
}
|
|
19855
20115
|
if (thread.id) {
|
|
19856
|
-
if (typeof raw.path === "string" &&
|
|
20116
|
+
if (typeof raw.path === "string" && isAbsolute8(raw.path)) {
|
|
19857
20117
|
this.rolloutPaths.set(thread.id, raw.path);
|
|
19858
20118
|
}
|
|
19859
20119
|
this.bindings.set(thread.id, {
|
|
@@ -20459,7 +20719,7 @@ class ThreadRegistry {
|
|
|
20459
20719
|
|
|
20460
20720
|
// ../../bridges/codex-bridge/src/app-server-runtime-sessions.ts
|
|
20461
20721
|
var SESSION_CLOSING_ERROR = "Session is closing";
|
|
20462
|
-
var ACTIVITY_PROCESS =
|
|
20722
|
+
var ACTIVITY_PROCESS = randomUUID7();
|
|
20463
20723
|
|
|
20464
20724
|
class CodexRuntimeSessions {
|
|
20465
20725
|
ctx;
|
|
@@ -21266,6 +21526,7 @@ class CodexRuntimeSessions {
|
|
|
21266
21526
|
const awaitingRecovery = session.threadId !== null && this.ctx.threadsAwaitingDispatchRecovery.has(session.threadId);
|
|
21267
21527
|
const phase = context?.phase ?? (awaitingRecovery ? "recovering" : session.restartFailure ? "failed" : "idle");
|
|
21268
21528
|
const latestDispatch = this.ctx.journal.latestForSession(sessionId);
|
|
21529
|
+
const interruptedRequestId = session.restartFailure ? this.ctx.journal.requestIdForTurn(session.restartFailure.turnId) : undefined;
|
|
21269
21530
|
const error = context?.error ?? (phase === "failed" && session.restartFailure ? CODEX_RESTARTED_MID_TURN_MESSAGE : undefined);
|
|
21270
21531
|
return {
|
|
21271
21532
|
status: phaseToExternalStatus(phase),
|
|
@@ -21273,7 +21534,10 @@ class CodexRuntimeSessions {
|
|
|
21273
21534
|
phase,
|
|
21274
21535
|
title: session.title,
|
|
21275
21536
|
error,
|
|
21276
|
-
...phase === "failed" && session.restartFailure && error === CODEX_RESTARTED_MID_TURN_MESSAGE ? {
|
|
21537
|
+
...phase === "failed" && session.restartFailure && error === CODEX_RESTARTED_MID_TURN_MESSAGE ? {
|
|
21538
|
+
interruption: "restart",
|
|
21539
|
+
...interruptedRequestId ? { interruptedRequestId } : {}
|
|
21540
|
+
} : {},
|
|
21277
21541
|
threadId: session.threadId,
|
|
21278
21542
|
turnId: context?.activeTurn?.turnId,
|
|
21279
21543
|
turnStartedAt: context?.turnStartedAt,
|
|
@@ -21814,7 +22078,7 @@ function parseCommandToken(text, sigils = ["/"]) {
|
|
|
21814
22078
|
// ../../bridges/codex-bridge/src/prompts/template-discovery.ts
|
|
21815
22079
|
import { createHash as createHash11 } from "node:crypto";
|
|
21816
22080
|
import { open as open7, readdir as readdir3, stat as stat7 } from "node:fs/promises";
|
|
21817
|
-
import { join as
|
|
22081
|
+
import { join as join16 } from "node:path";
|
|
21818
22082
|
|
|
21819
22083
|
// ../../bridges/codex-bridge/src/prompts/template-format.ts
|
|
21820
22084
|
var TEMPLATE_DESCRIPTION_MAX_BYTES = 1000;
|
|
@@ -21942,8 +22206,8 @@ var RESERVED_TEMPLATE_PREFIXES = ["/skill:", "/prompts:"];
|
|
|
21942
22206
|
var TEMPLATE_ID_PREFIX = "codex-template:";
|
|
21943
22207
|
function templateRoots(cwd, codexHome = getCodexHomeDir()) {
|
|
21944
22208
|
return [
|
|
21945
|
-
{ origin: "project", dir:
|
|
21946
|
-
{ origin: "user", dir:
|
|
22209
|
+
{ origin: "project", dir: join16(cwd, ".codex", "prompts") },
|
|
22210
|
+
{ origin: "user", dir: join16(codexHome, "prompts") }
|
|
21947
22211
|
];
|
|
21948
22212
|
}
|
|
21949
22213
|
function templateCommandId(origin, relativePath) {
|
|
@@ -21967,7 +22231,7 @@ function isReservedName(name) {
|
|
|
21967
22231
|
}
|
|
21968
22232
|
var metadataCache = new Map;
|
|
21969
22233
|
var METADATA_CACHE_MAX = 1024;
|
|
21970
|
-
async function
|
|
22234
|
+
async function readBounded2(absolutePath, maxBytes) {
|
|
21971
22235
|
const handle = await open7(absolutePath, "r");
|
|
21972
22236
|
try {
|
|
21973
22237
|
const info = await handle.stat();
|
|
@@ -22048,7 +22312,7 @@ async function scanPromptTemplates(roots, limits = TEMPLATE_LIMITS) {
|
|
|
22048
22312
|
return;
|
|
22049
22313
|
}
|
|
22050
22314
|
visited += 1;
|
|
22051
|
-
const absolutePath =
|
|
22315
|
+
const absolutePath = join16(dir, entry.name);
|
|
22052
22316
|
const relativePath = relative ? `${relative}/${entry.name}` : entry.name;
|
|
22053
22317
|
if (entry.isDirectory()) {
|
|
22054
22318
|
if (depth + 1 > limits.maxDepth) {
|
|
@@ -22110,7 +22374,7 @@ async function scanPromptTemplates(roots, limits = TEMPLATE_LIMITS) {
|
|
|
22110
22374
|
if (candidate.size > limits.maxTemplateBytes)
|
|
22111
22375
|
return null;
|
|
22112
22376
|
try {
|
|
22113
|
-
const { bytes, oversized } = await
|
|
22377
|
+
const { bytes, oversized } = await readBounded2(candidate.absolutePath, limits.maxTemplateBytes);
|
|
22114
22378
|
if (oversized)
|
|
22115
22379
|
return null;
|
|
22116
22380
|
if (bytes.length === 0)
|
|
@@ -22187,7 +22451,7 @@ async function loadTemplateBody(entry, limits = TEMPLATE_LIMITS) {
|
|
|
22187
22451
|
}
|
|
22188
22452
|
let loaded;
|
|
22189
22453
|
try {
|
|
22190
|
-
loaded = await
|
|
22454
|
+
loaded = await readBounded2(entry.absolutePath, limits.maxTemplateBytes);
|
|
22191
22455
|
} catch {
|
|
22192
22456
|
return {
|
|
22193
22457
|
ok: false,
|
|
@@ -22215,7 +22479,7 @@ async function loadTemplateBody(entry, limits = TEMPLATE_LIMITS) {
|
|
|
22215
22479
|
}
|
|
22216
22480
|
|
|
22217
22481
|
// ../../bridges/codex-bridge/src/commands/skill-inventory.ts
|
|
22218
|
-
import { isAbsolute as
|
|
22482
|
+
import { isAbsolute as isAbsolute9 } from "node:path";
|
|
22219
22483
|
var SKILL_INVENTORY_LIMITS = Object.freeze({
|
|
22220
22484
|
maxSkills: 512,
|
|
22221
22485
|
maxDescriptionBytes: 1000,
|
|
@@ -22267,7 +22531,7 @@ function normalizeSkillsList(raw, context) {
|
|
|
22267
22531
|
}
|
|
22268
22532
|
const name = nonEmpty(candidate.name);
|
|
22269
22533
|
const path = typeof candidate.path === "string" ? candidate.path : undefined;
|
|
22270
|
-
if (!name || !usableSkillName(name) || !path || !
|
|
22534
|
+
if (!name || !usableSkillName(name) || !path || !isAbsolute9(path)) {
|
|
22271
22535
|
truncated = true;
|
|
22272
22536
|
continue;
|
|
22273
22537
|
}
|
|
@@ -23646,6 +23910,12 @@ class CodexRuntimeLifecycle {
|
|
|
23646
23910
|
}
|
|
23647
23911
|
if (event.kind === "unknown.protocol")
|
|
23648
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
|
+
}
|
|
23649
23919
|
if (event.kind === "account.reload.requested") {
|
|
23650
23920
|
this.ctx.callbacks.reloadStoredAccountLogin().catch((error) => {
|
|
23651
23921
|
console.warn("[codex-bridge] Reloading the stored account login failed:", error instanceof Error ? error.message : error);
|
|
@@ -23931,8 +24201,11 @@ class CodexRuntimeLifecycle {
|
|
|
23931
24201
|
this.discardOutlivingCommandWindows(turn);
|
|
23932
24202
|
if (turn.stoppedByShutdown && event.status === "interrupted")
|
|
23933
24203
|
this.completeRecoveredTurn(turn, event.status);
|
|
23934
|
-
else
|
|
24204
|
+
else {
|
|
23935
24205
|
turn.complete(event.status, event.error);
|
|
24206
|
+
if (event.status === "failed" && event.error)
|
|
24207
|
+
turn.recordProviderFailure(event.error);
|
|
24208
|
+
}
|
|
23936
24209
|
this.ctx.options.changeEvidence?.turn(this.evidenceSource(context, turn), event.status);
|
|
23937
24210
|
const finalize = () => this.runFinalization(context, turn).catch((error) => {
|
|
23938
24211
|
console.error(`[codex-bridge] Failed to finalize turn ${turn.turnId}:`, error instanceof Error ? error.message : error);
|
|
@@ -26749,7 +27022,7 @@ async function writeCodexRawLog(sessionId, entry, logDir = codexRawLogDir) {
|
|
|
26749
27022
|
try {
|
|
26750
27023
|
await mkdir8(logDir, { recursive: true });
|
|
26751
27024
|
const filename = `${sanitizeLogFileComponent(sessionId)}.jsonl`;
|
|
26752
|
-
await appendFile5(
|
|
27025
|
+
await appendFile5(join17(logDir, filename), `${JSON.stringify({
|
|
26753
27026
|
timestamp: new Date().toISOString(),
|
|
26754
27027
|
sessionId,
|
|
26755
27028
|
...entry
|
|
@@ -26946,10 +27219,10 @@ function emit(event) {
|
|
|
26946
27219
|
}
|
|
26947
27220
|
}
|
|
26948
27221
|
function bridgeCacheDir() {
|
|
26949
|
-
return
|
|
27222
|
+
return join17(getCodexHomeDir(), "orkestrator-bridge");
|
|
26950
27223
|
}
|
|
26951
27224
|
function bridgeCachePath() {
|
|
26952
|
-
return
|
|
27225
|
+
return join17(bridgeCacheDir(), "models-cache.json");
|
|
26953
27226
|
}
|
|
26954
27227
|
var BRIDGE_MODEL_CACHE_VERSION = 2;
|
|
26955
27228
|
async function readPersistedBridgeCache() {
|
|
@@ -26973,7 +27246,7 @@ async function writePersistedBridgeCache(models) {
|
|
|
26973
27246
|
}
|
|
26974
27247
|
async function readCodexCliModelCache() {
|
|
26975
27248
|
try {
|
|
26976
|
-
const raw = await readFile7(
|
|
27249
|
+
const raw = await readFile7(join17(getCodexHomeDir(), "models_cache.json"), "utf8");
|
|
26977
27250
|
const models = parseModelCatalog(raw);
|
|
26978
27251
|
return models.length > 0 ? models : null;
|
|
26979
27252
|
} catch {
|
|
@@ -27406,7 +27679,10 @@ app.get("/session/:id/dispatch", (c) => {
|
|
|
27406
27679
|
return c.json({ dispatch: "unknown" });
|
|
27407
27680
|
const record = appServerRuntime.getJournal().get(requestId);
|
|
27408
27681
|
const dispatched = record?.bridgeSessionId === c.req.param("id") && (record.state === "accepted" || record.state === "terminal");
|
|
27409
|
-
return c.json({
|
|
27682
|
+
return c.json({
|
|
27683
|
+
dispatch: dispatched ? "dispatched" : "unknown",
|
|
27684
|
+
...dispatched ? { pending: record.state === "accepted" } : {}
|
|
27685
|
+
});
|
|
27410
27686
|
});
|
|
27411
27687
|
app.get("/session/:id/structured-output", (c) => {
|
|
27412
27688
|
const result = appServerRuntime.getStructuredOutput(c.req.param("id"), c.req.query("requestId")?.trim());
|