fix(plan): rewrite node_modules/.bin/*.cmd to powershell on Windows#345
fix(plan): rewrite node_modules/.bin/*.cmd to powershell on Windows#345
node_modules/.bin/*.cmd to powershell on Windows#345Conversation
Address review feedback on #345: - Extract the 5 fixed PowerShell prefix flags to a `const POWERSHELL_PREFIX` - Build `new_args` via iterator chain instead of manual Vec pushes - Drop the no-op `let _ = (&program_path, &args);` on non-Windows
Pulls in voidzero-dev/vite-task#345 which prefers .ps1 shims over .cmd on Windows to avoid the "Terminate batch job (Y/N)?" prompt and terminal corruption on Ctrl+C during `vp run dev`. Closes #1176
This comment was marked as resolved.
This comment was marked as resolved.
Pulls in voidzero-dev/vite-task#345 which prefers .ps1 shims over .cmd on Windows to avoid the "Terminate batch job (Y/N)?" prompt and terminal corruption on Ctrl+C during `vp run dev`. Closes #1176
This comment was marked as resolved.
This comment was marked as resolved.
Picks up the cache-portability fix for voidzero-dev/vite-task#345 (PowerShell rewrite moved from plan layer to spawn layer).
Picks up voidzero-dev/vite-task#345 fix for missing `which` dep on Windows after the module move.
|
@cursor review |
Pulls in voidzero-dev/vite-task#345 which prefers .ps1 shims over .cmd on Windows to avoid the "Terminate batch job (Y/N)?" prompt and terminal corruption on Ctrl+C during `vp run dev`. Closes #1176
Picks up the cache-portability fix for voidzero-dev/vite-task#345 (PowerShell rewrite moved from plan layer to spawn layer).
Picks up voidzero-dev/vite-task#345 fix for missing `which` dep on Windows after the module move.
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 4f14ebe. Configure here.
Address review feedback on #345: - Extract the 5 fixed PowerShell prefix flags to a `const POWERSHELL_PREFIX` - Build `new_args` via iterator chain instead of manual Vec pushes - Drop the no-op `let _ = (&program_path, &args);` on non-Windows
5ce6c62 to
3e1fc38
Compare
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 3e1fc38. Configure here.
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 26021ca. Configure here.
|
@cursor review |
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit be08530. Configure here.
|
@cursor review |
|
@cursor review |
Address review feedback on #345: - Extract the 5 fixed PowerShell prefix flags to a `const POWERSHELL_PREFIX` - Build `new_args` via iterator chain instead of manual Vec pushes - Drop the no-op `let _ = (&program_path, &args);` on non-Windows
ea43983 to
24f2a8f
Compare
node_modules/.bin/*.cmd to powershell on Windows
|
@cursor review |
Running a `node_modules/.bin/*.cmd` shim on Windows triggers `cmd.exe`'s
"Terminate batch job (Y/N)?" prompt on Ctrl+C, which corrupts the
terminal (backspace prints ^H, Ctrl+C prints ^C, input sluggish).
At plan time, when `which()` resolves a `.cmd` shim inside the
workspace and a sibling `.ps1` exists, rewrite the invocation to run
the `.ps1` directly through PowerShell. The spawn layer stays
untouched — it runs whatever the plan records, 1-for-1. Ctrl+C then
propagates cleanly without the intermediate `cmd.exe` hop.
The rewrite records:
program_path: <abs path to pwsh.exe or powershell.exe>
args: [-NoProfile, -NoLogo, -ExecutionPolicy, Bypass, -File,
<.ps1 path relative to task cwd>, ...original_args]
The `.ps1` path is stored relative to the task's cwd (with `/`
separators), so `SpawnFingerprint.args` is portable across machines —
no absolute paths leak into cache keys. PowerShell resolves
`-File <relative>` against its own working directory (the task's
cwd) and lands on the correct file.
The rewrite fires only when all of the following hold:
1. Extension is `.cmd` (case-insensitive) — cmd-shim never emits `.bat`.
2. Path lives inside the workspace root — global shims like
`%AppData%\npm\node_modules\.bin\foo.cmd` are left alone.
3. Path's last two components are `.bin` / `node_modules`
(case-insensitive).
4. A sibling `.ps1` exists.
5. `pwsh.exe` or `powershell.exe` is on PATH.
If any miss, the original `.cmd` is kept — behavior matches pre-PR.
Tests
-----
- 6 cross-platform unit tests in `vite_task_plan::ps1_shim::tests`
cover the pure rewrite logic (root cwd, hoisted monorepo subpackage
with `..` traversal, missing sibling, non-.cmd extensions, outside
`.bin`, outside workspace).
- Windows-only plan snapshot in
`plan_snapshots/fixtures/windows_cmd_shim_rewrite/` — a pnpm
workspace with a sub-package. Two plan cases (`dev_in_subpackage`
via cwd, `dev_filter_from_root` via --filter) produce byte-identical
snapshots, proving the cache key doesn't depend on how the user
navigates to the task. The harness gained a `windows_only: bool`
flag on `SnapshotsFile`; `redact_snapshot` gained a pass that maps
`pwsh` / `powershell` and their absolute host paths to
`<powershell>` so the snapshot doesn't pin a specific runner image.
Closes voidzero-dev/vite-plus#1176
24f2a8f to
892af62
Compare
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 24f2a8f. Configure here.
Pulls in voidzero-dev/vite-task#345 which prefers .ps1 shims over .cmd on Windows to avoid the "Terminate batch job (Y/N)?" prompt and terminal corruption on Ctrl+C during `vp run dev`. Closes #1176
Picks up the cache-portability fix for voidzero-dev/vite-task#345 (PowerShell rewrite moved from plan layer to spawn layer).
Picks up voidzero-dev/vite-task#345 fix for missing `which` dep on Windows after the module move.


Summary
Running a
node_modules/.bin/*.cmdshim on Windows triggerscmd.exe's "Terminate batch job (Y/N)?" prompt on Ctrl+C, which corrupts the terminal. At plan time, whenwhich()resolves such a shim inside the workspace and a sibling.ps1exists, rewrite the invocation to run the.ps1directly through PowerShell — the spawn layer stays untouched and Ctrl+C propagates cleanly.Closes voidzero-dev/vite-plus#1176
What the rewrite does
The
.ps1path is stored relative to the task's cwd (with/separators), soSpawnFingerprint.argsis portable across machines — no absolute paths leak into cache keys. PowerShell resolves-File <relative>against its own working directory (the task's cwd) and lands on the correct file.When it fires
Only when all of the following hold:
.cmd(case-insensitive) — cmd-shim never emits.bat.%AppData%\npm\node_modules\.bin\foo.cmdare left alone..bin/node_modules(case-insensitive)..ps1exists.pwsh.exeorpowershell.exeis on PATH.Any miss and the original
.cmdis kept — behavior matches pre-PR.Tests
vite_task_plan::ps1_shim::testscover the pure rewrite logic: workspace root, hoisted monorepo subpackage (..traversal), missing sibling, non-.cmdextensions,.cmdoutside.bin,.cmdoutside the workspace.plan_snapshots/fixtures/windows_cmd_shim_rewrite/— a pnpm workspace with a sub-package. Two plan cases (dev_in_subpackageviacwd,dev_filter_from_rootvia--filter) produce byte-identical snapshots, proving the cache key doesn't depend on how the user navigates to the task. The harness gained awindows_only: boolflag onSnapshotsFile;redact_snapshotgained a pass that mapspwsh/powershelland their absolute host paths to<powershell>so the snapshot doesn't pin a specific runner image.Test plan
cargo clippy --workspace --all-targets+cargo test --workspacegreen on macOSvp run devleaves terminal clean.cmdfallback on a Windows box with PATH stripped of PowerShell.cmdoutside the workspace is not rewrittenNote
Medium Risk
Changes Windows command resolution and cache fingerprint inputs for spawned tasks, which could affect execution behavior and caching; scope is gated to workspace-local
.cmdshims with.ps1siblings and is covered by targeted tests.Overview
Avoids Windows Ctrl+C terminal corruption by rewriting workspace-local
node_modules/.bin/*.cmdshims (with sibling.ps1) at plan time to run viapwsh.exe/powershell.exe -File <cwd-relative .ps1>; this changes the plannedprogram_path/argsand therefore the cache fingerprint to match what actually executes.Adds
ps1_shimrewrite logic with unit tests, integrates it into both normal spawn planning and synthetic task planning, and extends snapshot testing with a Windows-only fixture plus redaction/harness tweaks (including PowerShell host redaction and allowing fixturenode_modulesin git).Reviewed by Cursor Bugbot for commit 24f2a8f. Configure here.