Skip to content

feat(exec): replace the npm process with the command instead of waiting for it - #10166

Open
Finomosec wants to merge 1 commit into
npm:latestfrom
Finomosec:exec-replace-process
Open

Finomosec wants to merge 1 commit into
npm:latestfrom
Finomosec:exec-replace-process

Conversation

@Finomosec

Copy link
Copy Markdown

Closes #10165.

npx <pkg> / npm exec -- <pkg> now replaces the npm process with the command instead of spawning it and waiting:

before                          after
npm exec <pkg>                  <pkg>
└─ sh -c '<pkg>'
   └─ <pkg>
  • lib/commands/exec.js asks for this only for a single command; --workspaces keeps running one child per workspace.
  • libnpmexec passes it on to @npmcli/run-script, except in interactive mode (no command).
    For a plain bin call with the default sh it also prefixes the script with exec, so the shell is replaced as well; --call scripts and custom script-shells are left as they are.
  • On Windows, and until the dependencies below are released, everything behaves as before.

Besides the memory of the idle npm process, this also fixes orphaned processes: today npm only forwards SIGINT and SIGTERM, and the shell in between does not forward anything, so a SIGKILL (or a SIGTERM that reaches only the shell) leaves the actual program running with PPID 1.
MCP clients run into this a lot, because MCP servers are typically configured as npx -y <pkg> (see anthropics/claude-code#76306 and anthropics/claude-code#1935).
With this change the program is the process the caller started, so signals reach it directly.

Things that no longer happen after the handover, because npm is gone: the update notice and npm's own "command failed" messages on a non-zero exit.
The exit code is the program's own.

Depends on npm/promise-spawn#175 and npm/run-script#283; they need to be released and bundled for this to take effect.
The workaround for nodejs/node#66824 lives in promise-spawn.

Tested:

  • test/lib/commands/exec.js and libnpmexec at 100 % coverage on Node.js 22, 24 and 26.
  • End-to-end with the bundled dependencies patched, on Node.js 22, 24 and 26: no npm or shell process left in the tree, blocking stdio, large output into a slow pipe, exit code and argument quoting unchanged, SIGTERM/SIGKILL leave no orphans, first-time install prompt/warning still shown, --call, interactive mode and --workspaces unchanged.

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.

[BUG] npx keeps an idle npm process alive for the whole lifetime of the command it runs

1 participant