Skip to content

feat: support claude-code 2.1.245 esm-chunked native format - #336

Merged
bash0816 merged 2 commits into
mainfrom
feature/claude-code-2.1.245-esm-chunked
Aug 27, 2026
Merged

feat: support claude-code 2.1.245 esm-chunked native format#336
bash0816 merged 2 commits into
mainfrom
feature/claude-code-2.1.245-esm-chunked

Conversation

@bash0816

Copy link
Copy Markdown
Owner

Summary

Upstream claude-code 2.1.245 replaced the single CJS-wrapped bundle with Bun code-splitting into ESM chunks (StandaloneModuleGraph container with 1387 modules). This change adds a parallel esm-chunked execution path that:

  • Extracts ESM chunk modules to a process-owned temporary directory
  • Runs them under plain Node.js using a custom ESM loader (bunfs-esm-loader.mjs)
  • Guards against unauthorized child_process/vm access with module wrappers (bunfs-child-process-guard.mjs, bunfs-vm-guard.mjs)
  • Provides a no-op WebSocket stub (bunfs-ws-stub.mjs) and YAML shim (bunfs-yaml-shim.mjs)

The legacy CJS path (single-bundle versions) remains unchanged. Format is auto-detected from the entry module's content signature.

Test plan

  • G1 (Design Review): Go, no blockers
  • G3 (Coding Review): Go, no blockers
  • G4 (Verification Review): Go, no blockers
  • 41 unit tests passing across bunfs-extract, bunfs-esm-loader, child-process-guard, and vm-guard modules
  • E2E integration test (verify-claude-native-e2e.sh) passing with tarball installation and bundle format detection
  • TUI verification complete (auth flow, interactive prompt modes) on end-user device

🤖 Generated by Claude Code

Upstream 2.1.245 switched from a single CJS-wrapped bundle to Bun code-splitting
into ESM chunks (StandaloneModuleGraph container with 1387 modules). Add a
parallel esm-chunked execution path that extracts modules to a process-owned
directory and runs them under plain Node.js via a custom ESM loader
(bunfs-esm-loader.mjs), with guards for child_process/vm access
(bunfs-child-process-guard.mjs, bunfs-vm-guard.mjs) and a ws no-op stub
matching the existing legacy-cjs behavior (bunfs-ws-stub.mjs). The legacy-cjs
path (single-bundle versions) is unchanged; format is auto-detected from the
entry module's content.

Reviewed via G1 (design), G3 (coding review), G4 (verification) — all Go with
no blockers.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 91569eab23

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

const require = createRequire(import.meta.url);
const realChildProcess = require('node:child_process');
const { createGuardedChildProcess } = require('./native-update-guard.js');
const guarded = createGuardedChildProcess(realChildProcess, (v) => process.stderr.write(v));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Preserve Termux URL rewriting in the ESM child-process guard

When the ESM CLI opens a browser during authentication or another URL-opening flow, this guard forwards xdg-open unchanged to the real child-process module, but Termux provides termux-open-url instead. The legacy path explicitly rewrites xdg-open in both spawn and spawnSync, and the launcher still requires termux-open-url; therefore the new esm-chunked path regresses those flows unless the same rewrite is applied before creating the guarded methods.

Useful? React with 👍 / 👎.

const { register } = require('node:module');
const { pathToFileURL } = require('node:url');

const { ownedDir, entryRelPath } = prepareProcessOwnedDir(sourceBin, workdir);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Remove each extracted ESM directory when its process exits

Every ESM invocation creates a new directory containing all extracted non-NAPI modules, but neither bootstrap registers an exit handler to remove ownedDir. The only cleanup occurs on a later invocation, and cleanupStaleOwnedDirs deliberately retains dead-process directories younger than 24 hours, so repeated short-lived calls such as claude -p, --version, or --help accumulate complete extracted bundles and can exhaust the limited storage commonly available in Termux. Register synchronous exit cleanup for the current directory while retaining stale cleanup for crashes.

Useful? React with 👍 / 👎.

- SC2155: Separate local declaration and assignment for cmd_start, cmd_end, stdout_lines, stderr_lines
- SC2034: Remove unused expected_code variable from case statement in report generation loop

Co-Authored-By: Claude Sonnet 5 <[email protected]>
@bash0816
bash0816 merged commit d9b5492 into main Aug 27, 2026
4 checks passed
@bash0816
bash0816 deleted the feature/claude-code-2.1.245-esm-chunked branch August 27, 2026 20:24
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