fix(plan): rewrite node_modules/.bin/*.cmd to powershell on Windows#345
fix(plan): rewrite node_modules/.bin/*.cmd to powershell on Windows#345branchseer merged 1 commit intomainfrom
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 |
ea43983 to
24f2a8f
Compare
node_modules/.bin/*.cmd to powershell on Windows
|
@cursor review |
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.
6c3d40c to
a23f585
Compare
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
a23f585 to
09b4dc1
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 09b4dc1. 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.
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.
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.
…inal corruption (#1414) ## Summary Running a `node_modules/.bin/*.cmd` shim on Windows — what `vp run <script>` does when resolving `vite`, `tsc`, etc. — triggers `cmd.exe`'s *"Terminate batch job (Y/N)?"* prompt on Ctrl+C. That prompt leaves the terminal in a corrupt state: backspace prints `^H`, Ctrl+C prints `^C`, input becomes sluggish. Pulls in voidzero-dev/vite-task#345 (merged as `c45e5e72`), which teaches the plan layer to rewrite the invocation at plan time: ``` program_path: <abs path to pwsh.exe or powershell.exe> args: [-NoProfile, -NoLogo, -ExecutionPolicy, Bypass, -File, <.ps1 path relative to task cwd>, ...original_args] ``` PowerShell resolves `-File <relative>` against its own working directory (= the task's cwd) and lands on the correct `.ps1`, so Ctrl+C propagates cleanly without the `cmd.exe` hop. The `.ps1` path is **cwd-relative** so `SpawnFingerprint.args` stays portable — no absolute paths leak into cache keys. The rewrite only fires when **all** of these hold: extension is `.cmd`, path lives inside the workspace root, the two last path components are `.bin` / `node_modules` (case-insensitive), a sibling `.ps1` exists, and `pwsh.exe` / `powershell.exe` is on PATH. Any miss keeps the original `.cmd` path — behavior matches pre-merge. Also includes a previously-pushed CI fix: the musl test job disables `crt-static` so `fspy_preload_unix`'s cdylib build doesn't fail after voidzero-dev/vite-task#344 made that crate an unconditional build-dep. Closes #1176 ## Test plan - [x] `cargo check --workspace` clean on macOS - [x] vite-task CI green on the merged PR (includes new Windows-only plan snapshot verifying the rewrite end-to-end across `cwd` and `--filter` invocations) - [ ] vite-plus CI green - [ ] Manual on Windows: reproduce with https://github.com/Curtion/report-vite-plus-1; Ctrl+C during `vp run dev` should leave the terminal clean - [ ] Manual: confirm `.cmd` fallback on a Windows box with PATH stripped of PowerShell - [ ] Manual: confirm a globally installed `.cmd` outside the workspace is *not* rewritten


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 planning and spawn fingerprints by rewriting certain resolved executables and arguments, which could affect task execution and cache keys on that platform. Scope is constrained to
.cmdshims under workspacenode_modules/.binwith a.ps1sibling and a detectable PowerShell host.Overview
On Windows, planning now rewrites resolved
node_modules/.bin/*.cmdshims inside the workspace to run the sibling.ps1viapwsh.exe/powershell.exe(adding a fixed PowerShell arg prefix and recording the.ps1path relative to the task cwd), so Ctrl+C no longer triggerscmd.exe's "Terminate batch job" prompt and cache fingerprints reflect the actual invocation.This adds a dedicated
ps1_shimmodule (usingpathdiff) and applies it to both normal spawn commands and synthetic plan requests. Snapshot test infrastructure is updated with per-fixtureplatformfiltering plus PowerShell path/name redaction, and a Windows-only plan snapshot fixture is added to validate stable, portable cache keys across invocation styles.Reviewed by Cursor Bugbot for commit 09b4dc1. Configure here.