Skip to content

fix: keep upstream Windows codex app-server for node_repl compatibility#91

Open
siyuan-123 wants to merge 2 commits into
Haleclipse:masterfrom
siyuan-123:codex/fix-windows-node-repl-protocol
Open

fix: keep upstream Windows codex app-server for node_repl compatibility#91
siyuan-123 wants to merge 2 commits into
Haleclipse:masterfrom
siyuan-123:codex/fix-windows-node-repl-protocol

Conversation

@siyuan-123

@siyuan-123 siyuan-123 commented Jun 28, 2026

Copy link
Copy Markdown

Summary

This PR fixes a Windows rebuild compatibility issue where the bundled Desktop app-server can configure node_repl with MCP metadata that newer cua_node/node_repl rejects:

tool call error: tool call failed for `node_repl/js`

Caused by:
    Mcp error: -32602: js: codex/sandbox-state-meta: sandboxCwd must use the file URI scheme

Root cause

The Windows rebuild flow was replacing the upstream MSIX resources/codex.exe with the @cometix/codex CLI. In the failing build this mixed:

  • Desktop/MSIX resources and cua_node/node_repl.exe from a newer upstream package
  • resources/codex.exe from an older / different @cometix/codex app-server build

codex.exe app-server is responsible for writing Desktop MCP configuration and request metadata for node_repl. node_repl validates codex/sandbox-state-meta.sandboxCwd and now requires a file URI. Mixing the app-server binary with a different Desktop bundle can therefore break browser / Node REPL tools even though the rest of the app starts normally.

A local reproduction confirmed the issue disappeared after replacing the rebuilt Windows resources/codex.exe with the upstream MSIX codex.exe from the same package as cua_node/node_repl.exe.

Changes

  • Keep upstream resources/codex.exe for Windows builds instead of replacing it with @cometix/codex.
  • Keep the same behavior in prepare-src.js so forge-style Windows preparation also preserves the upstream app-server binary.
  • Add comments documenting why Windows app-server and bundled node_repl must stay protocol-aligned.
  • Make Windows upstream sync more robust:
    • fallback to PowerShell/.NET ZIP extraction when 7zz / 7z is unavailable
    • extract ASAR contents without failing on unpacked native entries
    • handle MSIX paths where scoped package names are percent-encoded, e.g. %40worklouder
  • Preserve native module unpacking during ASAR repack so native payloads remain outside app.asar.
  • Add a Windows ZIP packaging fallback when 7zz is unavailable.

Validation

Run on Windows:

node -c .\scripts\build-from-upstream.js
node -c .\scripts\prepare-src.js
node -c .\scripts\sync-upstream.js
npm run sync -- --skip-mac
npm run build:win-x64

Observed:

[asar extract] 3087 packed files, 37 unpacked files
[ok] D:\CodexDesktop-Rebuild\out\Codex-win-x64-26.623.42026.zip (619.8 MB)

The generated Windows build keeps upstream:

resources\codex.exe -> codex-cli 0.142.3
SHA256 D0021501D2779B6CD3DAF292308FCECCEE009002E62C9E93977CACE7D4C52535

After swapping that binary into the affected local Desktop rebuild and restarting, node_repl/js succeeded and no longer returned the sandboxCwd must use the file URI scheme error.

Summary by Sourcery

Keep the upstream Windows codex app-server binary to restore compatibility between desktop MCP metadata and bundled node_repl, while hardening the Windows upstream sync and packaging flow.

Enhancements:

  • Improve ASAR extraction to correctly handle unpacked native modules and percent-encoded scoped package paths in Windows MSIX bundles.
  • Adjust ASAR repacking on macOS and Windows to preserve native module unpacking (better-sqlite3, node-pty, @worklouder) and clean up stale app.asar.unpacked directories before repack.
  • Make archive extraction more robust by falling back to PowerShell/.NET ZIP extraction when 7z/7zz is unavailable.
  • Add a cross-platform ZIP creation helper that prefers 7zz but falls back to PowerShell on Windows and zip on other platforms.
  • Update build and pre-build scripts to align platform-specific resource handling, keeping upstream codex.exe on Windows while continuing to vendor @cometix/codex on Linux.
  • Improve path handling in upstream sync by adding case-insensitive resolution for Windows paths.

Build:

  • Refine Windows build-from-upstream and prepare-src flows to ensure upstream codex.exe is preserved and native modules remain correctly unpacked in the distributable.

Documentation:

  • Document the requirement that the Windows app-server (codex.exe) and bundled cua_node/node_repl stay protocol-aligned to avoid MCP metadata compatibility issues.

@sourcery-ai

sourcery-ai Bot commented Jun 28, 2026

Copy link
Copy Markdown

Reviewer's Guide

Windows builds now retain the upstream codex.exe app-server to stay MCP protocol-aligned with bundled cua_node/node_repl, while upstream sync, ASAR handling, and ZIP/archive workflows are hardened and made more resilient across platforms.

File-Level Changes

Change Details Files
Make archive extraction resilient on Windows by adding a PowerShell/.NET ZIP/MSIX fallback and improving recursive copy behavior.
  • Extend child_process usage to include execFileSync for PowerShell-based extraction.
  • Add a PowerShell/.NET ZipFile::ExtractToDirectory fallback when 7z/7zz is unavailable for MSIX/ZIP archives on Windows.
  • Introduce case-insensitive path resolution when copying files from extracted archives to handle Windows store path quirks.
scripts/sync-upstream.js
Implement custom ASAR extraction for patching that preserves unpacked native modules, safely handles links, and surfaces missing unpacked files without failing the build.
  • Replace npx asar extract with a bespoke extractAsarForPatching routine based on @electron/asar headers.
  • Add logic to copy unpacked native files from app.asar.unpacked, including handling percent-encoded scoped package folders (e.g. %40worklouder).
  • Ensure symlink targets stay within the output tree and mark executable files with appropriate permissions.
  • Log packed/unpacked file counts and stub missing unpacked files while keeping the tree structurally complete.
scripts/sync-upstream.js
Adjust ASAR repacking for macOS, Windows, and forge prep to keep native modules unpacked and clear stale unpacked content before repack.
  • Add clearExistingAsarUnpacked helper to remove any existing app.asar.unpacked before repacking.
  • Update macOS build to pass asar --unpack-dir and --unpack patterns for better-sqlite3, node-pty, and native payloads.
  • Update Windows build and prepare-src flow to keep better-sqlite3, node-pty, and @worklouder modules unpacked.
  • Make prepare-src choose platform-specific asar pack arguments, with Linux using a simple pack and macOS/Windows using targeted unpack directives.
scripts/build-from-upstream.js
scripts/prepare-src.js
Ensure Windows keeps the upstream codex.exe app-server while continuing to inject @cometix/codex on non-Windows platforms.
  • Change sync-upstream comments to reflect that Windows retains the upstream codex.exe while Linux uses @cometix/codex.
  • Add keepUpstreamCodex helper to explicitly log and preserve the upstream codex.exe for Windows builds.
  • Modify build-from-upstream Windows flow to call keepUpstreamCodex instead of replaceCodex.
  • Update prepare-src to skip vendor codex replacement on Windows, logging that upstream codex.exe is kept, while retaining vendor replacement on Linux.
scripts/sync-upstream.js
scripts/build-from-upstream.js
scripts/prepare-src.js
Strengthen ZIP packaging by introducing a cross-platform createZip helper with fallbacks when 7zz is missing.
  • Replace direct 7zz ZIP invocation with a createZip helper in build-from-upstream Windows flow.
  • Provide a Windows PowerShell/.NET ZipFile::CreateFromDirectory fallback when 7zz is unavailable.
  • Fallback to the zip CLI on non-Windows platforms when 7zz is not present.
scripts/build-from-upstream.js

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@siyuan-123
siyuan-123 marked this pull request as ready for review June 28, 2026 06:04

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - I've found 4 security issues, and left some high level feedback:

Security issues:

  • Detected calls to child_process from a function argument platform. This could lead to a command injection if the input is user controllable. Try to avoid calls to child_process, and if it is needed ensure user input is correctly sanitized or sandboxed. (link)
  • Detected calls to child_process from a function argument platform. This could lead to a command injection if the input is user controllable. Try to avoid calls to child_process, and if it is needed ensure user input is correctly sanitized or sandboxed. (link)
  • Detected calls to child_process from a function argument zipPath. This could lead to a command injection if the input is user controllable. Try to avoid calls to child_process, and if it is needed ensure user input is correctly sanitized or sandboxed. (link)
  • Detected calls to child_process from a function argument zipPath. This could lead to a command injection if the input is user controllable. Try to avoid calls to child_process, and if it is needed ensure user input is correctly sanitized or sandboxed. (link)

General comments:

  • In encodeScopedPackagePath, replacing all '@' characters with '%40' may over-encode non-scoped segments; consider limiting the replacement to leading '@' in path parts that are actually package scopes.
  • createZip falls back to the bare zip CLI on non-Windows platforms without checking availability or handling errors; you might want to detect its presence or surface a clearer failure when zip is not installed.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In encodeScopedPackagePath, replacing all '@' characters with '%40' may over-encode non-scoped segments; consider limiting the replacement to leading '@' in path parts that are actually package scopes.
- createZip falls back to the bare `zip` CLI on non-Windows platforms without checking availability or handling errors; you might want to detect its presence or surface a clearer failure when `zip` is not installed.

## Individual Comments

### Comment 1
<location path="scripts/build-from-upstream.js" line_range="161" />
<code_context>
  execSync(`npx asar pack "${asarDir}" "${asarPath}" --unpack-dir "{node_modules/better-sqlite3,node_modules/node-pty}" --unpack "{**/*.node,**/node-pty/build/Release/*.exe}"`);
</code_context>
<issue_to_address>
**security (javascript.lang.security.detect-child-process):** Detected calls to child_process from a function argument `platform`. This could lead to a command injection if the input is user controllable. Try to avoid calls to child_process, and if it is needed ensure user input is correctly sanitized or sandboxed.

*Source: opengrep*
</issue_to_address>

### Comment 2
<location path="scripts/build-from-upstream.js" line_range="234" />
<code_context>
  execSync(`npx asar pack "${asarDir}" "${asarPath}" --unpack-dir "{node_modules/better-sqlite3,node_modules/node-pty,node_modules/@worklouder}"`);
</code_context>
<issue_to_address>
**security (javascript.lang.security.detect-child-process):** Detected calls to child_process from a function argument `platform`. This could lead to a command injection if the input is user controllable. Try to avoid calls to child_process, and if it is needed ensure user input is correctly sanitized or sandboxed.

*Source: opengrep*
</issue_to_address>

### Comment 3
<location path="scripts/build-from-upstream.js" line_range="329" />
<code_context>
    execSync(`7zz a -tzip -mx=5 "${zipPath}" .`, { cwd, stdio: "pipe" });
</code_context>
<issue_to_address>
**security (javascript.lang.security.detect-child-process):** Detected calls to child_process from a function argument `zipPath`. This could lead to a command injection if the input is user controllable. Try to avoid calls to child_process, and if it is needed ensure user input is correctly sanitized or sandboxed.

*Source: opengrep*
</issue_to_address>

### Comment 4
<location path="scripts/build-from-upstream.js" line_range="349" />
<code_context>
  execSync(`zip -r "${zipPath}" .`, { cwd, stdio: "pipe" });
</code_context>
<issue_to_address>
**security (javascript.lang.security.detect-child-process):** Detected calls to child_process from a function argument `zipPath`. This could lead to a command injection if the input is user controllable. Try to avoid calls to child_process, and if it is needed ensure user input is correctly sanitized or sandboxed.

*Source: opengrep*
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread scripts/build-from-upstream.js Outdated
Comment thread scripts/build-from-upstream.js Outdated
Comment thread scripts/build-from-upstream.js Outdated
Comment thread scripts/build-from-upstream.js Outdated
@siyuan-123

Copy link
Copy Markdown
Author

Addressed the Sourcery feedback in a follow-up commit:

  • Replaced the newly added shell-string npx asar pack, 7zz, and zip calls with execFileSync argument arrays.
  • Avoided the Windows npx.cmd spawn edge case by invoking the local @electron/asar/bin/asar.mjs through process.execPath.
  • Kept the PowerShell ZIP fallback parameterized through param($src, $zip) and now surfaces clearer fallback errors.
  • Limited scoped package path encoding to path parts that start with @, so non-scope @ characters are not over-encoded.
  • Applied the same ASAR pack helper in prepare-src.js to keep the build scripts consistent.

Validation:

node -c scripts/build-from-upstream.js
node -c scripts/prepare-src.js
node -c scripts/sync-upstream.js
npm run build:win-x64

The Windows build completed successfully and still keeps the upstream resources/codex.exe.

@sourcery-ai review

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