Skip to content

fix(hooks): detect the Vercel CLI on Windows - #163

Open
ohad6k wants to merge 1 commit into
vercel:mainfrom
ohad6k:fix/windows-cmd-shim-detection
Open

fix(hooks): detect the Vercel CLI on Windows#163
ohad6k wants to merge 1 commit into
vercel:mainfrom
ohad6k:fix/windows-cmd-shim-detection

Conversation

@ohad6k

@ohad6k ohad6k commented Aug 29, 2026

Copy link
Copy Markdown

Fixes #140.

On Windows the SessionStart hook reports the Vercel CLI as not installed even
when it is, so the model is told a capability is unavailable and avoids
vercel env pull, vercel deploy and vercel logs.

Two independent failures, either of which alone breaks detection.

Candidate ordering. npm installs three shims for a global CLI on Windows: an
extensionless POSIX sh script for Git Bash, a .cmd and a .ps1.
getBinaryPathCandidates returned the bare name first, and accessSync(X_OK)
cannot rule it out because Node treats X_OK as F_OK on win32, so any existing
file passes. Resolution therefore always returned the one shim Windows cannot
execute. Extensions now come first and the bare name last.

Executing the shim. Since CVE-2024-27980 Node refuses to spawn a .cmd or .bat
through execFile, so the version check failed even when resolution was correct.
Both call sites now go through one execBinarySync helper.

The helper uses spawnSync with windowsVerbatimArguments, not shell: true.
shell: true alongside an args array emits DEP0190, and invoking ComSpec
without verbatim arguments does not work either: Node applies its Windows
argument escaping, cmd.exe receives "C:\path\to\vercel.CMD" and reports the
whole quoted path as an unrecognised command. windowsVerbatimArguments is
typed on the spawn options and not on execFileSync's, which is why the helper
uses spawnSync.

The npm call site had the same bug and is fixed with it, so a stale-version
check no longer fails silently on Windows.

Verified on Windows 11 (26200), Node v24.12.0, against a real npm-installed
global CLI:

before resolved ...\npm\claude execFileSync -> ENOENT
after resolved ...\npm\claude.CMD execBinarySync -> OK

Adds the regression test the issue asks for: on win32 an executable extension
must sort ahead of the bare name.

Fixes vercel#140.

On Windows the SessionStart hook reports the Vercel CLI as not installed even
when it is, so the model is told a capability is unavailable and avoids
`vercel env pull`, `vercel deploy` and `vercel logs`.

Two independent failures, either of which alone breaks detection.

Candidate ordering. npm installs three shims for a global CLI on Windows: an
extensionless POSIX sh script for Git Bash, a .cmd and a .ps1.
`getBinaryPathCandidates` returned the bare name first, and `accessSync(X_OK)`
cannot rule it out because Node treats X_OK as F_OK on win32, so any existing
file passes. Resolution therefore always returned the one shim Windows cannot
execute. Extensions now come first and the bare name last.

Executing the shim. Since CVE-2024-27980 Node refuses to spawn a .cmd or .bat
through execFile, so the version check failed even when resolution was correct.
Both call sites now go through one `execBinarySync` helper.

The helper uses spawnSync with `windowsVerbatimArguments`, not `shell: true`.
`shell: true` alongside an args array emits DEP0190, and invoking ComSpec
without verbatim arguments does not work either: Node applies its Windows
argument escaping, cmd.exe receives \"C:\path\to\vercel.CMD\" and reports the
whole quoted path as an unrecognised command. `windowsVerbatimArguments` is
typed on the spawn options and not on execFileSync's, which is why the helper
uses spawnSync.

The npm call site had the same bug and is fixed with it, so a stale-version
check no longer fails silently on Windows.

Verified on Windows 11 (26200), Node v24.12.0, against a real npm-installed
global CLI:

  before  resolved ...\npm\claude       execFileSync -> ENOENT
  after   resolved ...\npm\claude.CMD   execBinarySync -> OK

Adds the regression test the issue asks for: on win32 an executable extension
must sort ahead of the bare name.
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.

Vercel CLI detection always reports "not installed" on Windows (session-start-profiler)

1 participant