Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
06eefbe
docs(codex-cloud): retire xhigh prompt marker gate and clarify raw-en…
BigSimmo Oct 16, 2026
85793dc
docs(ledger): record review for codex/cloud-policy-clarity
BigSimmo Oct 16, 2026
627f034
fix: Clarify Cloud setting refresh behavior
qodo-code-review[bot] Oct 16, 2026
bdb0cea
chore(cloud): remove all remaining xhigh marker references and scrub …
BigSimmo Oct 16, 2026
b0b486e
docs(ledger): record review for bdb0cea521 on codex/cloud-policy-clarity
BigSimmo Oct 16, 2026
9c3c473
Merge remote-tracking branch 'origin/main' into gb-3581-work-2232
BigSimmo Oct 16, 2026
111fede
docs(codex-cloud): address review threads on raw-env exit semantics a…
BigSimmo Oct 16, 2026
1e3f1a0
fix(codex-cloud): harden shell profile sourcing, command shims, and o…
BigSimmo Oct 16, 2026
ce6c8a8
Merge remote-tracking branch 'origin/codex/cloud-policy-clarity' into…
BigSimmo Oct 16, 2026
953409c
docs(ledger): record review for ce6c8a8e19 on codex/cloud-policy-clarity
BigSimmo Oct 16, 2026
51e6077
fix(codex-cloud): add JSDoc env type annotations to shouldAutoSourceC…
BigSimmo Oct 16, 2026
d8a5a26
docs(ledger): record review for 51e6077ab9 on codex/cloud-policy-clarity
BigSimmo Oct 16, 2026
90c5f13
docs(ledger): record review for d8a5a2675e on codex/cloud-policy-clarity
BigSimmo Oct 16, 2026
3e0876f
chore(cloud): remove xhighConfirmed from RAG phase receipt schemas an…
BigSimmo Oct 16, 2026
db82acc
docs(ledger): record review for 3e0876f6e8 on codex/cloud-policy-clarity
BigSimmo Oct 16, 2026
59c030d
fix: Relocate existing Cloud profile blocks
qodo-code-review[bot] Oct 16, 2026
fc2164c
fix: 3 findings — Validate Node version before creating shims; Allow PAT
qodo-code-review[bot] Oct 16, 2026
a24ecb8
fix: Report Cloud profile re-exec failures
qodo-code-review[bot] Oct 16, 2026
b9d688c
fix(codex-cloud): unbreak CI and close open review findings on #3587 …
BigSimmo Oct 16, 2026
adf52ea
fix(codex-cloud): align the policy-only harness test with profile pre…
claude Oct 16, 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
8 changes: 8 additions & 0 deletions data/repo-awareness-snapshot.json
Original file line number Diff line number Diff line change
Expand Up @@ -21556,6 +21556,14 @@
"outcome": "2 Codex P2 → skip placeholders in compactBestUseTitle; gate subtitle compaction to services mode; threads unreplied (API 403)",
"checks": "vitest services-catalog+document-search-record-fault 20 passed; no provider-backed checks"
},
{
"date": "2026-10-16",
"ref": "codex/cloud-policy-clarity",
"head": "bdb0cea521800eb85f47fa3a0de3ce7869082a4c",
"scope": "Codex Cloud reasoning-effort and raw-env policy overhaul",
"outcome": "PASS (0 blocking findings; removed all xhigh prompt-marker references across policies/skills/RAG launch checks, added GH_TOKEN to known launcher scrub path, clarified activation guidance)",
"checks": "check:codex-cloud, vitest (tests/codex-cloud-setup.test.ts, tests/rag-local-agent-policy.test.ts, tests/rag-plan-package-parity.test.ts, tests/organisation-decisions.test.ts: 150 passed), docs:maintain, check:instructions, check:decisions, check:organisation"
Comment thread
BigSimmo marked this conversation as resolved.
Resolved
},
{
"date": "2026-07-20",
"ref": "cursor/documents-search-header-3eab / PR #936",
Expand Down
7 changes: 4 additions & 3 deletions docs/branch-review-index.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ Retention and rotation: [`branch-review-archival-policy.md`](branch-review-archi

## Summary

- Records: 702
- Records: 703
- Distinct ref cells: 452
- Distinct reviewed heads: 684
- Distinct reviewed heads: 685
- Date range: `2026-08-12` to `2026-10-16`

Records per date, newest first:

- `2026-10-16` — 3 records
- `2026-10-16` — 4 records
- `2026-10-15` — 3 records
- `2026-10-14` — 1 record
- `2026-10-13` — 2 records
Expand Down Expand Up @@ -80,6 +80,7 @@ Scope and outcome are truncated; follow the record link for the full six-cell ro
| --- | --- | --- | --- | --- |
| 2026-10-16 | fix/adversarial-remediation-20261016 | Adversarial assessment + parallel fix swarm + post-fix adversarial review across calculato… | All P0/P1/P2 findings fixed and verified; zero RAG files touched | [2a6b6200](branch-review-records/2a6b620065f5371039438fdbff73be97da6baf6c40dace3596e26c7bad0047dd.record.md) |
| 2026-10-16 | codex/cloud-policy-clarity | Codex Cloud reasoning-effort and raw-env policy overhaul | PASS (0 blocking findings; removed all xhigh prompt-marker references… | [3dd0e7e3](branch-review-records/3dd0e7e32634c00735102bf22ba9883745ad72dc5db730b1dce2c33f03e699f0.record.md) |
| 2026-10-16 | codex/cloud-policy-clarity | Codex Cloud environment script and shell-profile hardening | PASS (0 blocking findings; hardened .bashrc prepend, command-shim fall… | [7f059fca](branch-review-records/7f059fca46aac02223aa9f81e3d88a1a08f2b8a4844646d3a8eaa2cabd493c33.record.md) |
| 2026-10-16 | feat/backlog-remediation-20261016 | prlanded | PR #3571 squash-merged cleanly into main (e526f8a4d5ad00ad05c5b780262b… | [ad2c45bc](branch-review-records/ad2c45bc2f3c606a7847421acc887ddf4861ab0563a5b96b4c6315b066837d90.record.md) |
| 2026-10-15 | codex/ingestion-rag-pilot-handover-20261014 | Uncommitted admin pilot shared announcement correction; file SHA256 0f76deaa4d8d9ad46139d0… | Independent frontend source review ACCEPT; visible message and polite… | [263f1f06](branch-review-records/263f1f0680e9d5cda1bed9bb2a62853d3a34b78b5ad60054971520fdc884cf1c.record.md) |
| 2026-10-15 | codex/ingestion-rag-pilot-handover-20261014 | Uncommitted native-PDF layout v5 producer 352d178978ef9086df1df708aa71266538076a2f5050a526… | Independent technical P1/P2 closure and qualified representative-sourc… | [6d2fd2e8](branch-review-records/6d2fd2e81761e17d32bb56bd41261efe8f9239ef266cf85a512c1021f889dd4b.record.md) |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
| 2026-10-16 | codex/cloud-policy-clarity | 3e0876f6e81d765f6d3695c74385d5b5a91b7951 | Codex Cloud environment script and shell-profile hardening | PASS (0 blocking findings; hardened .bashrc prepend, command-shim fallback, check-codex-cloud auto-profile load, Node 24.15.0 diagnostic floor, offline provider env scrubbing, and receipt schema cleanup) | check:codex-cloud, vitest (tests/codex-cloud-diagnose.test.ts, tests/codex-cloud-setup.test.ts: 50 passed), docs:maintain, check-format-changed, typecheck |
19 changes: 11 additions & 8 deletions docs/codex-cloud.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,14 +119,17 @@ The generated shell profile removes known OpenAI, Supabase, Railway, GitHub/GitL
database, CI-trigger, test-user, and emergency-PAT variables. This prevents an unrelated
Cloud task from silently becoming provider-backed.

Set all five offline values in the environment UI. The setup also writes the generated
profile to `.bashrc`, `.profile`, and `.bash_profile`. Covering `.bash_profile` is required:
Bash stops login-profile discovery at the first matching file, so an existing `.bash_profile`
can otherwise prevent `.profile` from running. Offline mode values are forced after inherited
platform values so stale `auto`/`false` settings cannot outrank the repository contract.
Do not manually source the profile as an acceptance workaround: start a fresh task and invoke
the direct `npm run check:codex-cloud` commands below. The tracked command shims make those
ordinary Node commands load the profile themselves.
Set all five offline values in the environment UI. The setup also prepends the generated
profile to the top of `.bashrc`, `.profile`, and `.bash_profile` (ahead of Ubuntu's
non-interactive `return` guard in `.bashrc`) and runs `scripts/install-codex-cloud-command-shims.sh`.
Comment thread
codeant-ai[bot] marked this conversation as resolved.
Resolved
Covering `.bash_profile` is required: Bash stops login-profile discovery at the first matching
file, so an existing `.bash_profile` can otherwise prevent `.profile` from running. Offline mode
values are forced after inherited platform values so stale `auto`/`false` settings cannot outrank
the repository contract. Do not manually source the profile as an acceptance workaround: start a
fresh task and invoke the direct `npm run check:codex-cloud` commands below. Both the tracked
command shims and `scripts/check-codex-cloud-setup.mjs` itself automatically load
`$HOME/.clinical-kb-codex-cloud.sh` when invoked in a Cloud shell (including raw `bash -c`
invocations where `/root/.nvm/versions/node/.../bin` precedes `$HOME/.local/bin` on `PATH`).

### Connected (explicit opt-in)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
"programmeImplementationBase",
"branch",
"launchProfile",
"xhighConfirmed",
"controllerRouting",
"capabilityEvidence",
"phaseStartSha",
Expand Down Expand Up @@ -45,7 +44,6 @@
"programmeImplementationBase": { "$ref": "#/$defs/gitSha" },
"branch": { "type": "string", "minLength": 1 },
"launchProfile": { "enum": ["high", "xhigh"] },
"xhighConfirmed": { "type": "boolean" },
"controllerRouting": { "$ref": "#/$defs/agentRouting" },
"capabilityEvidence": {
"type": "array",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
"programmeImplementationBase": "f3d1a3cce2c943ad3083425ed9c7c46dbef23087",
"branch": "codex/rag-upgrade-p00",
"launchProfile": "high",
"xhighConfirmed": false,
"controllerRouting": {
"agentId": "controller-p00",
"runtimeHost": "codex-cloud",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
"programmeImplementationBase",
"branch",
"launchProfile",
"xhighConfirmed",
"controllerRouting",
"capabilityEvidence",
"phaseStartSha",
Expand Down Expand Up @@ -45,7 +44,6 @@
"programmeImplementationBase": { "$ref": "#/$defs/gitSha" },
"branch": { "type": "string", "minLength": 1 },
"launchProfile": { "enum": ["high", "xhigh"] },
"xhighConfirmed": { "type": "boolean" },
"controllerRouting": { "$ref": "#/$defs/agentRouting" },
"capabilityEvidence": {
"type": "array",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
"programmeImplementationBase": "f3d1a3cce2c943ad3083425ed9c7c46dbef23087",
"branch": "codex/rag-upgrade-p00",
"launchProfile": "high",
"xhighConfirmed": false,
"controllerRouting": {
"agentId": "controller-p00",
"runtimeHost": "codex-cloud",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
"programmeImplementationBase",
"branch",
"launchProfile",
"xhighConfirmed",
"controllerRouting",
"capabilityEvidence",
"phaseStartSha",
Expand Down Expand Up @@ -45,7 +44,6 @@
"programmeImplementationBase": { "$ref": "#/$defs/gitSha" },
"branch": { "type": "string", "minLength": 1 },
"launchProfile": { "enum": ["high", "xhigh"] },
"xhighConfirmed": { "type": "boolean" },
"controllerRouting": { "$ref": "#/$defs/agentRouting" },
"capabilityEvidence": {
"type": "array",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
"programmeImplementationBase": "f3d1a3cce2c943ad3083425ed9c7c46dbef23087",
"branch": "codex/rag-upgrade-p00",
"launchProfile": "high",
"xhighConfirmed": false,
"controllerRouting": {
"agentId": "controller-p00",
"runtimeHost": "codex-cloud",
Expand Down
8 changes: 6 additions & 2 deletions scripts/check-codex-cloud-raw-env.sh
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,12 @@ printf '[Codex Cloud Raw Env] FAIL-KNOWN: inherited documented launcher defect n
printf '[Codex Cloud Raw Env] CONTINUE-RESTRICTED: use only the generated profile and command shims; raw boundary remains failed.\n' >&2
for name in "${known[@]}"; do
case "$name" in
OPENAI_BASE_URL) printf '[Codex Cloud Raw Env] CONTINUE-RESTRICTED: OPENAI_BASE_URL can redirect OpenAI-bound traffic; never invoke OpenAI clients from the raw parent or any binary that bypasses the profile/shim scrub.\n' >&2 ;;
GH_TOKEN) printf '[Codex Cloud Raw Env] CONTINUE-RESTRICTED: GH_TOKEN carries host GitHub credentials; never invoke gh/GitHub clients from the raw parent or any binary that bypasses the profile/shim scrub.\n' >&2 ;;
OPENAI_BASE_URL)
printf '[Codex Cloud Raw Env] CONTINUE-RESTRICTED: OPENAI_BASE_URL can redirect OpenAI-bound traffic; never invoke OpenAI clients from the raw parent or any binary that bypasses the profile/shim scrub.\n' >&2
;;
GH_TOKEN)
printf '[Codex Cloud Raw Env] CONTINUE-RESTRICTED: GH_TOKEN carries host GitHub credentials; never invoke gh, git credential helpers, or network clients from the raw parent or any binary that bypasses the profile/shim scrub.\n' >&2
;;
esac
done
exit 2
159 changes: 107 additions & 52 deletions scripts/check-codex-cloud-setup.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -364,24 +364,26 @@ export function validateHostedAppInventory(appNames) {
}

export const providerCredentialVariables = Object.freeze([
...providerEnvironmentKeys,
"RAILWAY_API_TOKEN",
"RAILWAY_TOKEN",
"GH_TOKEN",
"GITHUB_TOKEN",
"CODEX_CLOUD_GITHUB_PAT",
"GITLAB_TOKEN",
"GLAB_TOKEN",
"CODEX_TRIGGER_TOKEN",
"HEALTH_DEEP_PROBE_SECRET",
"INDEXING_V3_AGENT_SECRET",
"CROSS_TENANT_SERVICE_ROLE_KEY",
"FIGMA_CLIENT_ID",
"FIGMA_CLIENT_SECRET",
"FIGMA_ACCESS_TOKEN",
"FIGMA_PERSONAL_ACCESS_TOKEN",
"FIGMA_TOKEN",
"FIGMA_NPM_TOKEN",
...new Set([
...providerEnvironmentKeys,
"RAILWAY_API_TOKEN",
"RAILWAY_TOKEN",
"GH_TOKEN",
"GITHUB_TOKEN",
"CODEX_CLOUD_GITHUB_PAT",
"GITLAB_TOKEN",
"GLAB_TOKEN",
"CODEX_TRIGGER_TOKEN",
"HEALTH_DEEP_PROBE_SECRET",
"INDEXING_V3_AGENT_SECRET",
"CROSS_TENANT_SERVICE_ROLE_KEY",
"FIGMA_CLIENT_ID",
"FIGMA_CLIENT_SECRET",
"FIGMA_ACCESS_TOKEN",
"FIGMA_PERSONAL_ACCESS_TOKEN",
"FIGMA_TOKEN",
"FIGMA_NPM_TOKEN",
]),
]);

function read(relativePath) {
Expand Down Expand Up @@ -1079,13 +1081,16 @@ function validateMaintenanceAndCommandShims(sources, errors) {
}
for (const [pattern, message] of [
[/nvm version/, "Cloud command shims must resolve the selected Node version without following their own wrappers."],
[/clean_path=.*\.local.*bin/, "Cloud command shims must remove their directory before running child npm scripts."],
[
/\[\[ "\\\$path_entry" == "\\\$HOME\/\.local\/bin" \]\] && continue[\s\S]*clean_path\+="\\\$path_entry"/,
"Cloud command shims must remove their directory before running child npm scripts.",
],
[/mkdir -p "\$HOME\/\.local\/bin"/, "Cloud command shims must create their destination directory."],
[/\.clinical-kb-codex-cloud\.sh/, "Cloud command shims must load the generated profile."],
]) {
requireMatch(errors, commandShims, pattern, message);
}
if (!commandShims.includes('exec "$node_bin/$command_name" "\\$@"')) {
if (!commandShims.includes('exec "$command_path" "\\$@"')) {
errors.push("Cloud command shims must execute absolute Node commands.");
}
}
Expand Down Expand Up @@ -1328,40 +1333,90 @@ export async function validateCodexCloudRuntime(env = process.env) {
return errors;
}

/** @param {NodeJS.ProcessEnv | Record<string, string | undefined>} [env] */
function readableRuntimeProfile(env = process.env) {
if (!env.HOME) return null;
const profilePath = path.join(env.HOME, ".clinical-kb-codex-cloud.sh");
try {
return statSync(profilePath).isFile() && (accessSync(profilePath, constants.R_OK), profilePath);
} catch {
return null;
}
}

/** @param {NodeJS.ProcessEnv | Record<string, string | undefined>} [env] */
export function shouldAutoSourceCloudProfile(env = process.env) {
return (
env.CODEX_CLOUD === "1" &&
env.NODE_ENV !== "test" &&
env.CODEX_CLOUD_PROFILE_LOADED !== "1" &&
Boolean(readableRuntimeProfile(env))
);
}

if (isDirectEntrypoint(import.meta.url)) {
const errors = validateCodexCloudSetup();
const commandArguments = process.argv.slice(2);
const hostedAppArgumentErrors = validateHostedAppInventoryArguments(commandArguments);
const hostedAppInventory = parseHostedAppInventoryArgument(commandArguments);
const hostedAppInventoryErrors = validateHostedAppInventory(hostedAppInventory);
const hostedAppInputErrors = [...hostedAppArgumentErrors, ...hostedAppInventoryErrors];
errors.push(...hostedAppInputErrors);
const runtime = process.argv.includes("--runtime");
const environment = runtime || process.env.CODEX_CLOUD === "1" || process.argv.includes("--environment");
if (runtime) errors.push(...(await validateCodexCloudRuntime()));
else if (environment) errors.push(...validateCodexCloudEnvironment());
if (
runtime &&
process.env.CODEX_CLOUD_PROVISIONING === "1" &&
gitCheckoutFreshness(repoRoot).freshness === "unverified"
) {
console.warn(
"[Codex Cloud Check] WARN: checkout freshness is unverified during provisioning; run explicit acceptance with CODEX_CLOUD_EXPECTED_BASE_SHA.",
const runtimeProfilePath = shouldAutoSourceCloudProfile(process.env) ? readableRuntimeProfile(process.env) : null;
if (runtimeProfilePath) {
const bashExecutable =
process.platform === "win32"
? path.join(process.env.ProgramFiles || "C:\\Program Files", "Git/bin/bash.exe")
: "bash";
const reexec = spawnSync(
bashExecutable,
[
"-c",
'profile_path="$1"; node_exec="$2"; script_path="$3"; shift 3; saved_args=("$@"); set --; . "$profile_path" && export CODEX_CLOUD_PROFILE_LOADED=1 && exec "$node_exec" "$script_path" "${saved_args[@]}"',
"codex-cloud-check",
runtimeProfilePath.replaceAll("\\", "/"),
process.execPath,
fileURLToPath(import.meta.url),
...process.argv.slice(2),
],
{ cwd: repoRoot, stdio: "inherit" },
);
}
if (environment && hostedAppInputErrors.length === 0) {
console.log("[Codex Cloud Environment] sanitized effective modes and capabilities:");
for (const line of sanitizedCloudCapabilityLines(process.env, { hostedAppInventory })) console.log(` ${line}`);
}
if (errors.length > 0) {
for (const error of errors) console.error(`[Codex Cloud Check] FAIL: ${error}`);
process.exitCode = 1;
if (reexec.error) {
console.error(
`[Codex Cloud Check] FAIL: could not re-exec through bash to load ${runtimeProfilePath}: ${reexec.error.message}`,
);
} else if (reexec.signal) {
console.error(`[Codex Cloud Check] FAIL: bash re-exec was terminated by signal ${reexec.signal}.`);
}
process.exitCode = reexec.status ?? 1;
} else {
const scope = codexCloudValidationScope({
runtime,
environment,
browserInstallSkipped: process.env.CODEX_CLOUD_SKIP_BROWSER_INSTALL === "1",
});
console.log(`[Codex Cloud Check] PASS: ${scope} Cloud contracts match.`);
const errors = validateCodexCloudSetup();
const commandArguments = process.argv.slice(2);
const hostedAppArgumentErrors = validateHostedAppInventoryArguments(commandArguments);
const hostedAppInventory = parseHostedAppInventoryArgument(commandArguments);
const hostedAppInventoryErrors = validateHostedAppInventory(hostedAppInventory);
const hostedAppInputErrors = [...hostedAppArgumentErrors, ...hostedAppInventoryErrors];
errors.push(...hostedAppInputErrors);
const runtime = process.argv.includes("--runtime");
const environment = runtime || process.env.CODEX_CLOUD === "1" || process.argv.includes("--environment");
if (runtime) errors.push(...(await validateCodexCloudRuntime()));
else if (environment) errors.push(...validateCodexCloudEnvironment());
if (
runtime &&
process.env.CODEX_CLOUD_PROVISIONING === "1" &&
gitCheckoutFreshness(repoRoot).freshness === "unverified"
) {
console.warn(
"[Codex Cloud Check] WARN: checkout freshness is unverified during provisioning; run explicit acceptance with CODEX_CLOUD_EXPECTED_BASE_SHA.",
);
}
if (environment && hostedAppInputErrors.length === 0) {
console.log("[Codex Cloud Environment] sanitized effective modes and capabilities:");
for (const line of sanitizedCloudCapabilityLines(process.env, { hostedAppInventory })) console.log(` ${line}`);
}
if (errors.length > 0) {
for (const error of errors) console.error(`[Codex Cloud Check] FAIL: ${error}`);
process.exitCode = 1;
} else {
const scope = codexCloudValidationScope({
runtime,
environment,
browserInstallSkipped: process.env.CODEX_CLOUD_SKIP_BROWSER_INSTALL === "1",
});
console.log(`[Codex Cloud Check] PASS: ${scope} Cloud contracts match.`);
}
}
}
3 changes: 0 additions & 3 deletions scripts/check-rag-phase-receipts.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -408,9 +408,6 @@ function validateCapabilityEvidence(items, label, errors, requireTracked) {
function validateModelRouting(receipt, phase, errors, requireTracked) {
const controllerReasoning = manifest.adaptiveEffortPolicy.highLaunchPhases.includes(phase.id) ? "high" : "xhigh";
if (receipt.launchProfile !== controllerReasoning) errors.push(`launchProfile must be ${controllerReasoning}`);
if (receipt.xhighConfirmed !== (controllerReasoning === "xhigh")) {
errors.push(`xhighConfirmed must be ${controllerReasoning === "xhigh"}`);
}
validateAgentRouting(
receipt.controllerRouting,
{ model: manifest.defaultAgentPolicy.controllerModel, reasoning: controllerReasoning },
Expand Down
22 changes: 19 additions & 3 deletions scripts/diagnose-codex-cloud.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,26 @@ import { isDirectEntrypoint } from "./lib/is-entrypoint.mjs";

import { lockPythonVersion, workerPythonLockTargets } from "./worker-python-lock-config.mjs";

const NODE_MINIMUM_VERSION = "24.15.0";

function major(version) {
return version?.match(/\d+/)?.[0] ?? null;
}

function isSupportedNodeVersion(version) {
if (!version || major(version) !== "24") return false;
const parts = version
.match(/^\d+(?:\.\d+){1,2}/)?.[0]
?.split(".")
.map(Number);
if (!parts || parts.length < 3 || parts.some((part) => !Number.isFinite(part))) return false;
const required = NODE_MINIMUM_VERSION.split(".").map(Number);
for (let index = 0; index < 3; index += 1) {
if (parts[index] !== required[index]) return parts[index] > required[index];
}
return true;
}

export function diagnoseCodexCloud({
nodeVersion,
npmVersion,
Expand All @@ -19,11 +35,11 @@ export function diagnoseCodexCloud({
setupExitCode,
}) {
const issues = [];
if (major(nodeVersion) !== "24") {
if (!isSupportedNodeVersion(nodeVersion)) {
issues.push({
code: "NODE_RUNTIME",
issue: `Node 24.x is required; detected ${nodeVersion || "unavailable"}.`,
fix: "Select Node 24 in the Cloud environment or rerun setup with nvm available.",
issue: `Node >=${NODE_MINIMUM_VERSION} <25 is required; detected ${nodeVersion || "unavailable"}.`,
fix: "Select Node 24 (>=24.15.0) in the Cloud environment or rerun setup with nvm available.",
});
}
if (major(npmVersion) !== "11") {
Expand Down
Loading
Loading