Skip to content

fix codex wrapper compatibility handling - #353

Closed
ndycode wants to merge 2 commits into
mainfrom
git-split/20260405-pr350-wrapper
Closed

fix codex wrapper compatibility handling#353
ndycode wants to merge 2 commits into
mainfrom
git-split/20260405-pr350-wrapper

Conversation

@ndycode

@ndycode ndycode commented Apr 4, 2026

Copy link
Copy Markdown
Owner

Summary

What Changed

  • Added a dedicated resolver for the real Codex binary and tightened the wrapper fallback path so compatibility staging, shell-guard install, and direct-script resolution behave consistently.
  • Expanded wrapper regression coverage around unsupported reasoning overrides, Windows shell guard setup, and npm-root fallback discovery.

Validation

  • npm run lint
  • npm run typecheck
  • npm test
  • npm test -- test/documentation.test.ts
  • npm run build
  • npm test -- test/codex-bin-wrapper.test.ts

Docs and Governance Checklist

  • No docs updates were needed; this is wrapper/runtime compatibility handling only.

Risk and Rollback

  • Risk level: medium
  • Rollback plan: revert 6c9aea9

Additional Notes

note: greptile review for oc-chatgpt-multi-auth. cite files like lib/foo.ts:123. confirm regression tests + windows concurrency/token redaction coverage.

Greptile Summary

this pr extracts binary resolution into a dedicated codex-bin-resolver.js module with fully injectable dependencies, adds compatibility shadow-home staging that rewrites config.toml reasoning-effort values for mini models and copies auth files with chmod 0o600, and implements retry-with-backoff cleanup via Atomics.wait. it also adds reasoning-effort downgrade in cli args (rewriteReasoningConfigArgs), tightens windows shell-guard installs, and widens test coverage with posix/windows npm-root fallback unit tests, cleanup-failure integration tests, and concurrent-invocation regression tests.

all three issues flagged in prior review threads are resolved:

  • spawnSync timeout: timeout: 5000 is present on both the win32 and posix call sites in codex-bin-resolver.js lines 74–86
  • auth file permissions: chmodSync(dest, 0o600) is applied to every copied file via tightenShadowHomePermissions in codex.js lines 514–519
  • TMPDIR vs TMP/TEMP: TMPDIR: controlledTmp is now included in the cleanup test env (line 423)

key findings:

  • P2 — double rewriteReasoningConfigArgs call: buildForwardArgs rewrites -c model_reasoning_effort=... args, then main() passes its output to createCompatibilityCodexHome which calls rewriteReasoningConfigArgs again. currently harmless (idempotent), but createCompatibilityCodexHome is designed around rawArgs semantics while receiving pre-processed args — a future change that breaks idempotency would silently produce wrong forwarded args
  • posix npm-root unit test is present and complete at line 1131 (asserts command === "npm", args ["root", "-g"], timeout: 5000, and absence of windowsHide)
  • concurrency test at line 1199 runs 10 parallel subprocess invocations and confirms no module-load races

Confidence Score: 5/5

safe to merge — all prior p1 concerns resolved, sole remaining finding is a p2 design smell around double arg-rewrite

the three p1 issues from prior review threads (missing spawnSync timeout, missing chmodSync, wrong tmpdir env var) are all addressed. posix npm-root unit test coverage is complete. the only new finding is the redundant rewriteReasoningConfigArgs call which is currently idempotent and carries no present-tense defect.

no files require special attention; optional follow-up: rename createCompatibilityCodexHome's rawArgs parameter or extract requestedModel to eliminate the double-rewrite pattern

Important Files Changed

Filename Overview
scripts/codex-bin-resolver.js new injectable resolver: override env → require.resolve → sibling search → npm-prefix → npm root -g with timeout:5000 on both posix and win32 paths; windows cmd.exe derivation from ComSpec/COMSPEC/SystemRoot fully unit-tested
scripts/codex.js adds shadow-home compat staging with chmod 0o600, atomics-based retry cleanup, reasoning-effort downgrade in args and config.toml, and windows shim guard install; delegates binary resolution to new module; all prior token-safety and timeout concerns addressed
test/codex-bin-wrapper.test.ts comprehensive new coverage: shadow home creation and cleanup-on-failure, posix and windows npm-root spawnSyncImpl unit tests, reasoning rewrite (quoted and unquoted toml), windows shell guard installs, and 10-way concurrent invocation regression

Fix All in Codex

Prompt To Fix All With AI
This is a comment left during a code review.
Path: scripts/codex.js
Line: 554-565

Comment:
**redundant `rewriteReasoningConfigArgs` double-call**

`buildForwardArgs` calls `rewriteReasoningConfigArgs(rawArgs)` internally and returns the rewritten args. `main()` then passes that output directly into `createCompatibilityCodexHome`, which calls `rewriteReasoningConfigArgs` again. the rewrite is idempotent today so there is no present bug, but `createCompatibilityCodexHome` parameter is named `rawArgs` and its logic assumes unprocessed input. if the rewrite ever becomes non-idempotent, `compatibility.args` would silently diverge from `forwardArgs` with no test to catch it.

consider extracting model detection so `createCompatibilityCodexHome` receives the resolved model directly, or at minimum rename the parameter from `rawArgs` to `processedArgs` to accurately signal the contract.

How can I resolve this? If you propose a fix, please make it concise.

Greploops — Automatically fix all review issues by running /greploops in Claude Code. It iterates: fix, push, re-review, repeat until 5/5 confidence.
Use the Greptile plugin for Claude Code to query reviews, search comments, and manage custom context directly from your terminal.

Reviews (2): Last reviewed commit: "fix: harden codex wrapper fallbacks" | Re-trigger Greptile

Context used:

  • Context used - speak in lowercase, concise sentences. act like th... (source)

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Credits must be used to enable repository wide code reviews.

@coderabbitai

coderabbitai Bot commented Apr 4, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

introduces bin resolution refactoring to delegate codex binary discovery to a new module with dependency injection support. adds reasoning-effort compatibility rewriting that maps unsupported model/effort combinations to supported defaults, creates temporary shadow CODEX_HOME directories with modified config when needed, and implements retryable cleanup for those shadow directories.

Changes

Cohort / File(s) Summary
Bin Resolution
scripts/codex-bin-resolver.js
New module exporting resolveRealCodexBin(options = {}) with multi-stage fallback resolution: checks CODEX_MULTI_AUTH_REAL_CODEX_BIN env var, attempts package-based resolution via require.resolve, searches multiple roots (script dir, invoked script parent, npm prefix locations), and falls back to global npm root lookup with Windows-specific cmd.exe path derivation.
Codex Script Core Updates
scripts/codex.js
Delegates bin resolution to resolveRealCodexBinFromEnvironment({ moduleUrl }); refactored forwardToRealCodex to accept optional env and cleanup params with best-effort cleanup on process completion. adds reasoning-effort compatibility rewriting: parses requested model, coercively maps model_reasoning_effort to model-supported values, rewrites -c/--config assignments, and updates buildForwardArgs to apply rewriting before appending auth config.
Compatibility Shadow Homes
scripts/codex.js
Introduces "compatibility Codex home" behavior: when model/reasoning effort compatibility requires changes, creates temporary shadow CODEX_HOME directory, writes modified config.toml, copies auth/global state files, tightens permissions (best-effort), forwards updated environment including CODEX_MULTI_AUTH_DIR, and returns cleanup function. implements retryable cleanup with backoff retries on EBUSY, EPERM, ENOTEMPTY via rmSync with recursive/force semantics.
Test Coverage Expansion
test/codex-bin-wrapper.test.ts
Extended fixture setup to copy scripts/codex-bin-resolver.js; added helper functions (buildWrapperEnv, createFakeGlobalCodexInstall, createSpawnSyncSuccess, injectShadowCleanupBusyFailures). new test cases: compatibility shadow home creation/config rewriting/auth file copying with permission checks; shadow home cleanup on staging failure with simulated EBUSY; reasoning-effort rewriting and downgrading for mini models; resolver tests validating npm root fallback on Windows (cmd.exe derivation from SYSTEMROOT, COMSPEC casing) and POSIX platforms.

Sequence Diagram

sequenceDiagram
    participant CLI as CLI Invocation
    participant Codex as scripts/codex.js
    participant Resolver as codex-bin-resolver
    participant ShadowHome as Shadow CODEX_HOME
    participant RealCodex as Real Codex Binary

    CLI->>Codex: --model mini --model-reasoning-effort xhigh
    
    Codex->>Codex: parse model & reasoning-effort from args
    
    Codex->>Codex: check if effort unsupported by model
    alt Incompatible (xhigh unsupported for mini)
        Codex->>ShadowHome: create temp CODEX_HOME
        Codex->>ShadowHome: write modified config.toml<br/>(effort→high)
        Codex->>ShadowHome: copy auth/global files
        Codex->>ShadowHome: tighten permissions
    end
    
    Codex->>Resolver: resolveRealCodexBinFromEnvironment({ moduleUrl })
    Resolver->>Resolver: check CODEX_MULTI_AUTH_REAL_CODEX_BIN
    alt Env override exists & valid
        Resolver-->>Codex: return override path
    else
        Resolver->>Resolver: attempt package-based resolution
        alt Package resolution succeeds
            Resolver-->>Codex: return resolved path
        else
            Resolver->>Resolver: search multiple roots<br/>(script dir, argv[1] parent, npm prefix)
            alt Found in local roots
                Resolver-->>Codex: return found path
            else
                Resolver->>Resolver: spawn npm root -g<br/>(Windows: cmd.exe /c npm root -g)
                Resolver-->>Codex: return global root path or null
            end
        end
    end
    
    Codex->>RealCodex: spawn with rewritten args<br/>+ compatibility env/shadow home
    RealCodex-->>Codex: exit code
    
    Codex->>ShadowHome: cleanup with retries<br/>(EBUSY/EPERM/ENOTEMPTY backoff)
    ShadowHome-->>Codex: cleanup complete
    
    Codex-->>CLI: exit code
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~55 minutes

notes on review focus:

  • scripts/codex-bin-resolver.js: verify the multi-stage fallback ordering and the windows-specific cmd.exe derivation logic (process.env.SystemRoot casing sensitivity, fallback to bare cmd.exe). confirm that require.resolve derivation from moduleUrl correctly handles relative module resolution.
  • scripts/codex.js: the compatibility rewriting logic is dense. trace through the reasoning-effort mapping, config.toml rewriting, and shadow home creation flow. verify that the buildWrapperEnv call surfaces CODEX_MULTI_AUTH_DIR correctly when set. check that cleanup retries handle the specified error codes and that the cleanup function is always invoked (even on spawn errors). flag: no concurrency protection on shadow home creation if multiple codex instances run simultaneously with the same temporary directory target.
  • test/codex-bin-wrapper.test.ts: the new tests are comprehensive but verify that windows-specific edge cases like COMSPEC casing variations and SystemRoot presence/absence are covered. check that the injectShadowCleanupBusyFailures helper correctly simulates EBUSY during cleanup. flag: missing explicit regression test for cross-platform permission enforcement on shadow config files (test checks permissions but only asserts on mode bits; verify this works on windows where file mode semantics differ).

Suggested labels

bug

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title follows conventional commit format with type 'fix' and lowercase imperative summary well under 72 chars, directly describing the main change.
Description check ✅ Passed PR description covers summary, changes, validation status, docs checklist, risk/rollback, and notes. Structure aligns with template requirements.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch git-split/20260405-pr350-wrapper
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch git-split/20260405-pr350-wrapper

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Comment thread scripts/codex-bin-resolver.js
Comment thread scripts/codex.js
Comment thread test/codex-bin-wrapper.test.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@scripts/codex.js`:
- Around line 507-550: The shadow home currently discards refreshed auth/state
files; update cleanup() to sync auth/state back to the real home before removing
the shadow. Specifically, in cleanup() (and in the try/catch error path) copy
any present files named "auth.json", "accounts.json", and
".codex-global-state.json" from shadowCodexHome to originalCodexHome (use
existsSync + copyFileSync and preserve permissions via
tightenShadowHomePermissions/chmodSync), but do so safely (best-effort with
try/catch around each copy and avoid clobbering newer originals by checking
mtimes or skipping if original is newer). After syncing, call
removeDirectoryWithRetry(shadowCodexHome) as before and keep the existing
best-effort behavior on failure.
- Around line 486-489: The early-return that checks xhighCompatEffort (computed
by coerceReasoningEffortForModel(requestedModel, "xhigh")) incorrectly
short-circuits config rewriting for models that accept "xhigh" but reject other
efforts; remove or change this guard so we don't return immediately when
xhighCompatEffort === "xhigh" and instead let the existing config-rewrite logic
run to validate/downgrade other efforts (use coerceReasoningEffortForModel for
the specific requested effort levels and only return early when all required
effort levels are compatible). Update the branch around xhighCompatEffort,
nextArgs, baseEnv, cleanup to continue through the normal rewrite flow unless
full compatibility is verified for the requested model and specific configured
effort.

In `@test/codex-bin-wrapper.test.ts`:
- Around line 89-116: The test helper injectShadowCleanupBusyFailures mutates
scripts/codex.js by string-matching literals, which breaks on formatting
refactors; instead, modify scripts/codex.js to call a configurable cleanup hook
(e.g., export or call globalThis.__shadowCleanupHook || defaultCleanup) and
update injectShadowCleanupBusyFailures to set globalThis.__shadowCleanupHook to
a function that simulates EBUSY failures (decrementing failuresBeforeSuccess
then throwing an error with code "EBUSY" before delegating to the real rmSync),
so tests inject failures via the hook rather than by patching source text.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: f69007d6-3360-470f-a24d-b6b3b7df0106

📥 Commits

Reviewing files that changed from the base of the PR and between cbce5f5 and 24f503f.

📒 Files selected for processing (3)
  • scripts/codex-bin-resolver.js
  • scripts/codex.js
  • test/codex-bin-wrapper.test.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Greptile Review
🧰 Additional context used
📓 Path-based instructions (1)
test/**

⚙️ CodeRabbit configuration file

tests must stay deterministic and use vitest. demand regression cases that reproduce concurrency bugs, token refresh races, and windows filesystem behavior. reject changes that mock real secrets or skip assertions.

Files:

  • test/codex-bin-wrapper.test.ts
🔇 Additional comments (1)
scripts/codex-bin-resolver.js (1)

71-86: good timeout on the global npm-root probe.

this closes the only external-call hang risk in the resolver fallback path, and test/codex-bin-wrapper.test.ts:905-1176 covers both windows and posix branches.

Comment thread scripts/codex.js
Comment on lines +486 to +489
const xhighCompatEffort = coerceReasoningEffortForModel(requestedModel, "xhigh");
if (xhighCompatEffort === "xhigh") {
return { args: nextArgs, env: baseEnv, cleanup: undefined };
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

do not short-circuit config rewriting on xhigh support.

this guard misses models that allow xhigh but still reject other efforts. gpt-5-codex, gpt-5.1-codex-max, gpt-5.2-pro, and gpt-5.4-pro all support xhigh but not none and/or minimal per lib/request/helpers/model-map.ts:86-155. with --model gpt-5.4-pro plus model_reasoning_effort = "none" in config.toml, the wrapper returns the original CODEX_HOME unchanged and the real cli still sees an unsupported config. current coverage in test/codex-bin-wrapper.test.ts:338-573 only exercises xhigh downgrades.

proposed fix
 function createCompatibilityCodexHome(rawArgs, baseEnv = process.env) {
 	const { args: nextArgs, requestedModel } = rewriteReasoningConfigArgs(rawArgs);
 	if (!requestedModel) {
 		return { args: nextArgs, env: baseEnv, cleanup: undefined };
 	}
-
-	const xhighCompatEffort = coerceReasoningEffortForModel(requestedModel, "xhigh");
-	if (xhighCompatEffort === "xhigh") {
-		return { args: nextArgs, env: baseEnv, cleanup: undefined };
-	}
 
 	const originalCodexHome = resolveCodexHomeDir(baseEnv);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/codex.js` around lines 486 - 489, The early-return that checks
xhighCompatEffort (computed by coerceReasoningEffortForModel(requestedModel,
"xhigh")) incorrectly short-circuits config rewriting for models that accept
"xhigh" but reject other efforts; remove or change this guard so we don't return
immediately when xhighCompatEffort === "xhigh" and instead let the existing
config-rewrite logic run to validate/downgrade other efforts (use
coerceReasoningEffortForModel for the specific requested effort levels and only
return early when all required effort levels are compatible). Update the branch
around xhighCompatEffort, nextArgs, baseEnv, cleanup to continue through the
normal rewrite flow unless full compatibility is verified for the requested
model and specific configured effort.

Comment thread scripts/codex.js
Comment on lines +507 to +550
const cleanup = () => {
try {
removeDirectoryWithRetry(shadowCodexHome);
} catch {
// Best-effort cleanup only.
}
};
const tightenShadowHomePermissions = (path) => {
try {
chmodSync(path, 0o600);
} catch {
// Best-effort only; permission semantics vary by platform.
}
};
try {
const compatConfigPath = join(shadowCodexHome, "config.toml");
writeFileSync(compatConfigPath, compatConfig, "utf8");
tightenShadowHomePermissions(compatConfigPath);
for (const name of ["auth.json", "accounts.json", ".codex-global-state.json"]) {
const sourcePath = join(originalCodexHome, name);
if (existsSync(sourcePath)) {
const destinationPath = join(shadowCodexHome, name);
copyFileSync(sourcePath, destinationPath);
tightenShadowHomePermissions(destinationPath);
}
}
} catch (error) {
cleanup();
throw error;
}

const forwardedEnv = {
...baseEnv,
CODEX_HOME: shadowCodexHome,
};
const originalMultiAuthDir = resolveOriginalMultiAuthDir(baseEnv);
if (originalMultiAuthDir) {
forwardedEnv.CODEX_MULTI_AUTH_DIR = originalMultiAuthDir;
}

return {
args: nextArgs,
env: forwardedEnv,
cleanup,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

the shadow home currently drops refreshed auth state.

during compatibility runs the real cli is forced onto the file auth store (test/codex-bin-wrapper.test.ts:275-336), so any token refresh or account-state write lands in the temp CODEX_HOME created here. cleanup() then removes that directory without syncing auth.json, accounts.json, or .codex-global-state.json back to the original home, which makes those updates disappear after exit. this also opens a token-refresh race with non-shadowed invocations, because the shadow copy can diverge from the real home and then be thrown away. test/codex-bin-wrapper.test.ts:338-433 only checks creation and cleanup, not state persistence. please either sync those files back before deletion or avoid shadowing auth/state files at all.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/codex.js` around lines 507 - 550, The shadow home currently discards
refreshed auth/state files; update cleanup() to sync auth/state back to the real
home before removing the shadow. Specifically, in cleanup() (and in the
try/catch error path) copy any present files named "auth.json", "accounts.json",
and ".codex-global-state.json" from shadowCodexHome to originalCodexHome (use
existsSync + copyFileSync and preserve permissions via
tightenShadowHomePermissions/chmodSync), but do so safely (best-effort with
try/catch around each copy and avoid clobbering newer originals by checking
mtimes or skipping if original is newer). After syncing, call
removeDirectoryWithRetry(shadowCodexHome) as before and keep the existing
best-effort behavior on failure.

Comment on lines +89 to +116
function injectShadowCleanupBusyFailures(
fixtureRoot: string,
failuresBeforeSuccess = 2,
): void {
const wrapperPath = join(fixtureRoot, "scripts", "codex.js");
const originalSource = readFileSync(wrapperPath, "utf8");
const instrumentedSource = originalSource
.replace(
'const SHADOW_HOME_CLEANUP_BACKOFF_MS = [20, 60, 120];',
[
'const SHADOW_HOME_CLEANUP_BACKOFF_MS = [20, 60, 120];',
`globalThis.__cleanupBusyFailuresRemaining = ${failuresBeforeSuccess};`,
].join("\n"),
)
.replace(
"rmSync(targetPath, { recursive: true, force: true });",
[
"if (globalThis.__cleanupBusyFailuresRemaining > 0) {",
"\tglobalThis.__cleanupBusyFailuresRemaining -= 1;",
'\tconst error = new Error("simulated busy cleanup");',
'\terror.code = "EBUSY";',
"\tthrow error;",
"}",
"rmSync(targetPath, { recursive: true, force: true });",
].join("\n"),
);
writeFileSync(wrapperPath, instrumentedSource, "utf8");
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -n -C2 'SHADOW_HOME_CLEANUP_BACKOFF_MS = \[20, 60, 120\];|rmSync\(targetPath, \{ recursive: true, force: true \}\);' scripts/codex.js test/codex-bin-wrapper.test.ts

Repository: ndycode/codex-multi-auth

Length of output: 1775


🏁 Script executed:

# Check the test that uses this helper
sed -n '399,433p' test/codex-bin-wrapper.test.ts

Repository: ndycode/codex-multi-auth

Length of output: 1162


🏁 Script executed:

# Look at the cleanup function structure in scripts/codex.js
sed -n '20,55p' scripts/codex.js

Repository: ndycode/codex-multi-auth

Length of output: 1152


🏁 Script executed:

# Check if there's an export or module interface in scripts/codex.js that could be used for injection
rg -n 'module\.exports|export' scripts/codex.js

Repository: ndycode/codex-multi-auth

Length of output: 152


avoid string-patching for cleanup failure injection in test/codex-bin-wrapper.test.ts:89-116.

the injectShadowCleanupBusyFailures helper rewrites scripts/codex.js by finding exact string literals at lines 23 and 40. a formatting refactor—renaming the backoff array or reformatting the rmSync call—silently disables the injected EBUSY path while test/codex-bin-wrapper.test.ts:399-433 still passes. this loses the regression case.

refactor scripts/codex.js to accept an injectable cleanup function or expose a globalThis hook for testing. this lets test/codex-bin-wrapper.test.ts inject failures without source text coupling.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/codex-bin-wrapper.test.ts` around lines 89 - 116, The test helper
injectShadowCleanupBusyFailures mutates scripts/codex.js by string-matching
literals, which breaks on formatting refactors; instead, modify scripts/codex.js
to call a configurable cleanup hook (e.g., export or call
globalThis.__shadowCleanupHook || defaultCleanup) and update
injectShadowCleanupBusyFailures to set globalThis.__shadowCleanupHook to a
function that simulates EBUSY failures (decrementing failuresBeforeSuccess then
throwing an error with code "EBUSY" before delegating to the real rmSync), so
tests inject failures via the hook rather than by patching source text.

@ndycode

ndycode commented Apr 5, 2026

Copy link
Copy Markdown
Owner Author

Superseded by merged rebuild #355 and the follow-up release work now on main.

@ndycode ndycode closed this Apr 5, 2026
@ndycode
ndycode deleted the git-split/20260405-pr350-wrapper branch April 12, 2026 06:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant