Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
f899cc4
feat(codex): add handle-pinned Windows CLI update job store
luvs01 Oct 23, 2026
6a2340f
fix(codex): shard the Windows job-store layout entry and bound the AC…
luvs01 Oct 23, 2026
ebb769e
Merge published CLI plan parent into Windows job store
luvs01 Oct 23, 2026
17c46c9
Merge commit '9fd7f6da4af44c5d9e4ced0a82a9fb6f071d0326' into codex/wi…
luvs01 Oct 23, 2026
9a75d22
test(codex): wait for async job fixture entry
luvs01 Oct 23, 2026
2350f29
docs(codex): clarify ACL timeout reap contract
luvs01 Oct 23, 2026
7769bfc
docs(codex): clarify ACL timeout residual handles
luvs01 Oct 23, 2026
18a5d0e
test(codex): synchronize restart fixture with async owner
luvs01 Oct 23, 2026
a875a43
merge: integrate verified parent into Windows CLI job store
luvs01 Oct 24, 2026
849cfac
Merge 7626 fixture architecture fix
luvs01 Oct 24, 2026
a118bb1
Merge refreshed provenance parent into Windows CLI job store
luvs01 Oct 24, 2026
d06d85e
Merge measured CLI apply weight into PR 7626 candidate
luvs01 Oct 24, 2026
0e91bad
Merge Worker dispatch parent into async Windows job store
luvs01 Oct 24, 2026
cbfa1f3
test(codex): own Windows fixture before async preparation
luvs01 Oct 24, 2026
84930ed
fix(codex): register Windows store handles once
luvs01 Oct 25, 2026
6ad7026
fix(scripts): detect diagnostic spawn timeout via exitedDueToTimeout
luvs01 Oct 25, 2026
66754b0
merge: refresh Windows single-pin parent with runtime timeout flag fix
luvs01 Oct 25, 2026
46f36cd
Merge commit '486768f09490ac49474560c3cb21b32c11318e2f' into codex/76…
luvs01 Oct 25, 2026
0730ebd
Merge commit 'd662a41ed4e97d60d22a48d504921d22643a1237' into codex/76…
luvs01 Oct 25, 2026
70b4e1e
test(codex): assert unsafe-ledger admission refusal for disabled Wind…
Oct 25, 2026
9197113
test(codex): bound the Windows restart-reader wait and surface child …
Oct 25, 2026
0eec93c
test(codex): create the restart-reader engine gate before job dispatch
Oct 25, 2026
0d836ec
test(windows): wait on engine entry for the restart-reader observation
luvs01 Oct 25, 2026
6577d55
test(windows): keep unsettled Node CLI fixtures and name timed-out runs
luvs01 Oct 25, 2026
6a9a3f1
fix(codex): preserve job execution ownership and clean unpublished le…
lidge-jun Oct 26, 2026
c4cf1c6
Merge updated Windows CLI provenance parent
lidge-jun Oct 26, 2026
ac70457
fix(codex): share held canonical path checks with the job store
lidge-jun Oct 26, 2026
5df61b9
Merge Windows provenance updates into CLI job storage
lidge-jun Oct 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions scripts/test-layout/layout-windows-cli-update.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"windows-codex-cli-job-store.test.ts": "windows"
}
4 changes: 2 additions & 2 deletions scripts/test-layout/layout.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"version": 1,
"root": "tests",
"explicitShards": ["layout-clients.json", "layout-codex-collision.json", "layout-agent-assertion.json", "layout-chat.json", "layout-replay.json", "layout-adapters.json", "layout-jev.json", "layout-workbuddy.json", "layout-combos.json"],
"explicitShards": ["layout-clients.json", "layout-codex-collision.json", "layout-agent-assertion.json", "layout-chat.json", "layout-replay.json", "layout-adapters.json", "layout-jev.json", "layout-workbuddy.json", "layout-combos.json", "layout-windows-cli-update.json"],
"explicit": { "combo-description.test.ts": "routing", "combo-description-catalog.test.ts": "codex-integration", "codex-provider-routing.test.ts": "codex-integration", "config-native-reasoning-retention.test.ts": "config", "server-native-reasoning-retention-merge.test.ts": "server", "server-native-reasoning-retention.test.ts": "server", "responses-retained-reasoning-stream-recovery.test.ts": "responses", "openai-native-hosted-search-history.test.ts": "adapters/openai", "responses-native-compact-search-history.test.ts": "responses", "config-hosted-search-projection.test.ts": "config", "gcp-credential-boundary.test.ts": "adapters/google", "gcp-sa-marker.test.ts": "adapters/google", "gcp-sa-adapter.test.ts": "adapters/google", "management-gcp-credential-input.test.ts": "server", "codex-preserve-signed-in.test.ts": "codex-integration", "cli-account-preservation.test.ts": "cli", "cli-provider-list-active.test.ts": "cli", "service-state-isolation.test.ts": "service", "compaction-history-framing.test.ts": "responses", "catalog-native-max-context.test.ts": "codex-integration", "protocol-argon-thought-boundary.test.ts": "responses", "service-log.test.ts": "service", "messages-native-empty-inline.test.ts": "claude-integration", "catalog-auto-review-override.test.ts": "codex-integration", "management-auto-review-settings.test.ts": "server", "management-auto-review-auth.test.ts": "server", "prefer-model-alias-ids.test.ts": "server", "responses-mimo-envelope.test.ts": "responses", "responses-call-id-linkage.test.ts": "responses", "bridge-terminal-refusal.test.ts": "adapters", "loop-terminal-refusal.test.ts": "images", "web-search-terminal-refusal.test.ts": "web-search", "combo-terminal-refusal.test.ts": "routing", "server-terminal-refusal-wiring.test.ts": "server", "incomplete-reason-normalization.test.ts": "responses", "advisor-retention.test.ts": "advisor", "responses-native-key-cooldown.test.ts": "responses", "responses-run-turn-key-readmission.test.ts": "responses", "qoder-spawn-readmission.test.ts": "adapters", "api-key-selection-cooldown.test.ts": "providers", "api-key-auto-pause-distribution.test.ts": "providers", "explicit-key-pause-oauth-boundary.test.ts": "providers", "server-chat-native-key-selection.test.ts": "server", "compact-key-selection.test.ts": "responses", "messages-native-key-selection.test.ts": "claude-integration", "coding-agent-windows-dispatch.test.ts": "adapters", "coding-agent-native-empty-argv.test.ts": "windows",
"service-proxy-env.test.ts": "service", "openai-chat-standalone-bare-block.test.ts": "adapters/openai",
"owner-registry-isolation.test.ts": "config",
Expand Down Expand Up @@ -1995,5 +1995,5 @@
"injection-routing-drift.test.ts": "codex-integration", "injection-routing-healer.test.ts": "codex-integration",
"injection-routing-heal-apply.test.ts": "codex-integration", "cli-start-routing-heal-wiring.test.ts": "cli",
"cli-status-codex-routing-drift.test.ts": "cli", "advisor-settings.test.ts": "advisor", "advisor-context.test.ts": "advisor", "advisor-state.test.ts": "advisor", "advisor-guard.test.ts": "advisor", "advisor-consult.test.ts": "advisor", "advisor-plan.test.ts": "advisor", "advisor-responses-wiring.test.ts": "advisor", "advisor-routes.test.ts": "server", "advisor-internal-authority.test.ts": "advisor", "advisor-core-boundary.test.ts": "advisor", "advisor-continuation-limit.test.ts": "advisor", "advisor-authority-transport.test.ts": "advisor", "advisor-evidence.test.ts": "advisor", "advisor-budget.test.ts": "advisor", "advisor-adaptive.test.ts": "advisor"
}
, "coding-agent-windows-dispatch.test.ts": "adapters", "coding-agent-native-empty-argv.test.ts": "windows"}
}
6 changes: 3 additions & 3 deletions src/cli/codex-cli-update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -310,8 +310,8 @@ export async function handleCodexCliUpdateCommand(
return;
}
if (parsed.action === "status") {
let job: ReturnType<typeof readCodexCliUpdateJob>;
try { job = (deps.readJob ?? readCodexCliUpdateJob)(parsed.jobId); }
let job: Awaited<ReturnType<typeof readCodexCliUpdateJob>>;
try { job = await (deps.readJob ?? readCodexCliUpdateJob)(parsed.jobId); }
catch { unavailableJob(); return; }
if (!job) { unavailableJob(); return; }
printData(job, parsed.json, [`job: ${job.jobId}`, `status: ${job.status}`, `outcome: ${job.outcome ?? "pending"}`,
Expand All @@ -329,7 +329,7 @@ export async function handleCodexCliUpdateCommand(
return;
}
if (parsed.action === "apply") {
const admitted = admitCodexCliUpdateJob({ requestId: parsed.requestId, planId: parsed.planId, confirmed: true });
const admitted = await admitCodexCliUpdateJob({ requestId: parsed.requestId, planId: parsed.planId, confirmed: true });
const apply = deps.applyUpdate
?? ((planId: string) => runCodexCliUpdateApplyInWorker(planId, { jobId: admitted.job.jobId }));
let job: Awaited<ReturnType<typeof runCodexCliUpdateJob>>;
Expand Down
25 changes: 15 additions & 10 deletions src/codex/cli-update-job-execution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ export const CODEX_CLI_JOB_CLEANUP_ERRORS: ReadonlySet<string> = new Set(["lease
export class CodexCliJobStoreBusyError extends Error {
constructor() { super("job_store_busy"); }
}
/** Durable ledger bounds and names shared by the POSIX and Windows store backends. */
export const CODEX_CLI_JOB_STORE_DIR = "codex-cli-update-jobs";
export const CODEX_CLI_JOB_STORE_FILE = "jobs.json";
export const CODEX_CLI_JOB_STORE_LOCK = "admission.lock";
export const CODEX_CLI_JOB_STORE_MAX_BYTES = 256 * 1024;
export class CodexCliJobResultPersistenceError extends Error {
constructor(readonly result: CodexCliApplyResult) { super("job_result_persistence_failed"); }
}
Expand All @@ -29,7 +34,7 @@ export async function retryCodexCliJobStoreOperation<T>(operation: () => T,
delay: (milliseconds: number) => Promise<void> = ms => new Promise(resolve => setTimeout(resolve, ms)),
persistence = false): Promise<T> {
for (let attempt = 0; ; attempt++) {
try { return operation(); }
try { return await operation(); }
catch (error) {
const transientIo = persistence && ["EIO", "ENOSPC", "EBUSY", "EAGAIN", "EINTR", "EMFILE", "ENFILE"]
.includes((error as NodeJS.ErrnoException)?.code ?? "");
Expand All @@ -39,20 +44,20 @@ export async function retryCodexCliJobStoreOperation<T>(operation: () => T,
}
}
interface JobWork {
begin(): number;
finish(revision: number, result: CodexCliApplyResult): CodexCliUpdateJobDto | null;
read(): CodexCliUpdateJobDto | null;
release(): void;
begin(): number | Promise<number>;
finish(revision: number, result: CodexCliApplyResult): CodexCliUpdateJobDto | null | Promise<CodexCliUpdateJobDto | null>;
read(): CodexCliUpdateJobDto | null | Promise<CodexCliUpdateJobDto | null>;
release(): void | Promise<void>;
}
/** Execution and persistence are separate ownership phases. */
export async function runCodexCliUpdateJobWork(run: () => Promise<CodexCliApplyResult>, work: JobWork): Promise<CodexCliUpdateJobDto | null> {
let released = false;
try {
let revision: number;
try { revision = await retryCodexCliJobStoreOperation(() => work.begin()); }
try { revision = await retryCodexCliJobStoreOperation(async () => work.begin()); }
catch {
work.release(); released = true;
try { return work.read(); }
await work.release(); released = true;
try { return await work.read(); }
catch (error) {
const code = error instanceof Error ? error.message : "";
throw new Error(["unsafe_store", "invalid_store", "unsupported_store"].includes(code) ? code : "job_state_unavailable");
Expand All @@ -66,7 +71,7 @@ export async function runCodexCliUpdateJobWork(run: () => Promise<CodexCliApplyR
verificationPid: null, cleanupErrors: [] };
}
try {
return await retryCodexCliJobStoreOperation(() => work.finish(revision, result) ?? work.read(), undefined, true);
return await retryCodexCliJobStoreOperation(async () => (await work.finish(revision, result)) ?? (await work.read()), undefined, true);
} catch { throw new CodexCliJobResultPersistenceError(result); }
} finally { if (!released) work.release(); }
} finally { if (!released) await work.release(); }
}
Loading
Loading