Skip to content

fix: survive NODE_ENV=production during install - #2650

Open
colonelpanic8 wants to merge 1 commit into
getpaseo:mainfrom
colonelpanic8:postinstall-patch-package
Open

fix: survive NODE_ENV=production during install#2650
colonelpanic8 wants to merge 1 commit into
getpaseo:mainfrom
colonelpanic8:postinstall-patch-package

Conversation

@colonelpanic8

Copy link
Copy Markdown
Contributor

Problem

npm treats an ambient NODE_ENV=production as --omit=dev. When the daemon inherits that from however it was launched (login shell, systemd unit, container image), 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:

postinstall-patches: patch-package failed to spawn: spawnSync patch-package ENOENT
npm error code 1
Worktree setup command failed: npm ci

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.json and docker/base/Dockerfile install with npm ci --include=dev. An explicit --include clears the NODE_ENV-derived omit; both of these installs genuinely need dev dependencies to produce anything usable.
  • scripts/postinstall-patches.mjs resolves patch-package's entrypoint via createRequire and runs it with process.execPath, rather than spawning the bare name off PATH. npm only puts node_modules/.bin on PATH for its own lifecycle scripts, and the bare name otherwise resolves to platform-specific .cmd/.ps1 shims.
  • That script now distinguishes the two ways patch-package can be missing: dev dependencies deliberately omitted (warn, exit 0 — a production install should not die on an absent dev tool) versus genuinely missing (exit 1, with a message naming the NODE_ENV trap).
  • Documented the gotcha in docs/development.md and public-docs/worktrees.md, since it hits any user whose daemon environment carries NODE_ENV=production.

Verification

On a worktree that had failed setup this way:

  • npm ci --include=dev succeeds and all four patches apply.
  • All three postinstall branches exercised directly: omitted-dev skip (exit 0), genuinely-missing failure (exit 1), explicit --include=dev.
  • The rest of the setup array — seed scripts, build:server, expo-two-way-audio — completes.
  • npm run typecheck and npm run lint pass.

🤖 Generated with Claude Code

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>
Comment on lines +89 to +94
if (patchPackageEntry === undefined) {
if (devDependenciesOmitted()) {
console.warn(
"postinstall-patches: skipping patches, dev dependencies were omitted from this install.",
);
process.exit(0);

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.

P1 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.

@greptile-apps

greptile-apps Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR makes development installs resilient to ambient production-mode npm configuration.

  • Explicitly includes development dependencies in worktree and Docker source-package installs.
  • Resolves patch-package through its package entrypoint instead of relying on lifecycle PATH shims.
  • Adds omitted-dependency handling and documents the NODE_ENV installation behavior.

Confidence Score: 4/5

This PR should not merge until production-style source installs stop succeeding with required runtime dependency patches unapplied.

The new omitted-dev branch exits successfully after detecting applicable patches, even though those patches modify production dependencies and prevent concrete runtime failures.

Files Needing Attention: scripts/postinstall-patches.mjs

Important Files Changed

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

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