fix: survive NODE_ENV=production during install - #2650
Conversation
npm reads an ambient NODE_ENV=production as --omit=dev. When the daemon inherits that from its launch environment, every worktree setup runs `npm ci` without dev dependencies: typescript, oxlint and patch-package never install, and the root postinstall then dies trying to spawn patch-package, failing the whole setup array with a misleading ENOENT. Pin worktree and Docker installs to `npm ci --include=dev`; an explicit --include clears the NODE_ENV-derived omit. Make the postinstall script honest about the two cases it can hit. It now resolves patch-package's entrypoint through createRequire and runs it with process.execPath instead of spawning a bare name off PATH, which npm only populates for its own lifecycle scripts and which resolves to platform-specific shims. When patch-package is genuinely absent it skips quietly if dev dependencies were deliberately omitted, and otherwise fails with a message naming the NODE_ENV trap. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
| if (patchPackageEntry === undefined) { | ||
| if (devDependenciesOmitted()) { | ||
| console.warn( | ||
| "postinstall-patches: skipping patches, dev dependencies were omitted from this install.", | ||
| ); | ||
| process.exit(0); |
There was a problem hiding this comment.
Production patches are silently skipped
When a source-based production install omits dev dependencies, this branch exits successfully after detecting applicable patches, leaving runtime dependencies unpatched and exposing known failures such as pointer-capture exceptions and unhandled SDK cancellation rejections.
|
| Filename | Overview |
|---|---|
| scripts/postinstall-patches.mjs | Adds portable patch-package resolution, but permits successful production installs with required runtime dependency patches unapplied. |
| paseo.json | Explicitly includes development dependencies during worktree setup so inherited production mode cannot omit required build tools. |
| docker/base/Dockerfile | Explicitly includes development dependencies in the source packaging stage. |
| docs/development.md | Documents the ambient NODE_ENV npm behavior and the required worktree setup override. |
| public-docs/worktrees.md | Adds user-facing guidance to pin development dependency installation in setup commands. |
Reviews (1): Last reviewed commit: "fix: survive NODE_ENV=production during ..." | Re-trigger Greptile
Problem
npm treats an ambient
NODE_ENV=productionas--omit=dev. When the daemon inherits that from however it was launched (login shell, systemd unit, container image), every worktree setup runsnpm ciwithout dev dependencies.typescript,oxlintandpatch-packagenever install, and the rootpostinstallthen dies trying to spawnpatch-package:The ENOENT is a symptom. The install had already silently dropped every dev dependency, so the remaining setup steps (
npm run build:server, etc.) could not have worked either.Changes
paseo.jsonanddocker/base/Dockerfileinstall withnpm ci --include=dev. An explicit--includeclears theNODE_ENV-derived omit; both of these installs genuinely need dev dependencies to produce anything usable.scripts/postinstall-patches.mjsresolves patch-package's entrypoint viacreateRequireand runs it withprocess.execPath, rather than spawning the bare name offPATH. npm only putsnode_modules/.binonPATHfor its own lifecycle scripts, and the bare name otherwise resolves to platform-specific.cmd/.ps1shims.NODE_ENVtrap).docs/development.mdandpublic-docs/worktrees.md, since it hits any user whose daemon environment carriesNODE_ENV=production.Verification
On a worktree that had failed setup this way:
npm ci --include=devsucceeds and all four patches apply.--include=dev.build:server, expo-two-way-audio — completes.npm run typecheckandnpm run lintpass.🤖 Generated with Claude Code