Skip to content

Spawn vp-managed package managers via node <pm>.cjs directly to remove the Windows .cmd/.ps1 shim hazards #1971

Description

@fengmk2

Summary

Proposal: invoke vp-managed package managers (and npm/npx) by spawning the real JS entry with the managed Node directly (node <pm>.cjs <args>), instead of resolving to the Windows .cmd shim and then routing through PowerShell. This removes the root cause behind both the Ctrl+C terminal corruption and the CI stdin hang in every stdio configuration, and drops the PowerShell dependency.

Background

Why the current approach has structural limits

  • It couples two unrelated concerns through a heuristic: terminal Ctrl+C corruption is a console property, but it is gated on stdin TTY-ness.
  • It keeps a hard dependency on PowerShell being present plus -ExecutionPolicy Bypass for the interactive path.
  • It still leaves the cmd.exe corruption in place for non-TTY-but-console cases (e.g. vp install < input.txt from a real terminal).

Proposal: bypass the shims for vp-managed binaries

vp already has everything needed to skip the shim layer for the binaries it manages:

  • The installer writes the real JS entry next to the shims (crates/vite_install/src/package_manager.rs, crates/vite_install/src/shim.rs): <pm>.cjs, <pm>.cmd, and <pm>.ps1 all just run node <pm>.cjs, e.g. $VP_HOME/package_manager/pnpm/<ver>/pnpm/bin/pnpm.cjs.
  • vp ships its own Node: $VP_HOME/js_runtime/node/<ver>/node(.exe).

So for the managed scope, spawn:

$VP_HOME/js_runtime/node/<ver>/node(.exe)   .../pnpm/bin/pnpm.cjs   <args>

This is byte-for-byte what the shims do internally, minus the wrapper.

Benefits:

  • No cmd.exe, so no Ctrl+C "Terminate batch job (Y/N)?" corruption, in every stdio config.
  • No .ps1, so no $MyInvocation.ExpectingInput stdin hang, in every stdio config.
  • No PowerShell dependency or execution-policy concerns.
  • Removes the TTY heuristic for this path; identical behavior in CI and interactive. vp keeps full control of stdio inheritance and signal handling (execute_with_terminal_guard, fix_stdio_streams).

Scope and fallback

Apply this only to what vp owns (the $VP_HOME managed shims: package managers plus npm/npx under js_runtime), where the .cjs target is known. For arbitrary third-party node_modules/.bin/*.cmd, parsing the shim to find the node target is more involved, so the existing TTY-gated PowerShell rewrite in ps1_shim.rs can stay as the fallback there. Net result: the highest-value path (the package-manager invocation that caused the CI hang) becomes bulletproof, and the general case keeps today's behavior.

Implementation sketch

  • In crates/vite_command/src/lib.rs resolve_program (or a layer above it): when the resolved bin is a vp-managed PM / npm / npx shim, resolve to the sibling <name>.cjs plus the managed node, and return (node_path, [cjs_path, ...args]) instead of the .cmd / PowerShell rewrite.
  • Keep ps1_shim::rewrite_cmd_to_powershell for the node_modules/.bin/* fallback.

Notes

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Priority

None yet

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions