Session-start hook reports "The Vercel CLI is not installed" on Windows — execFileSync on vercel.cmd throws EINVAL
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 287
- Forks
- 58
- Avg merge
- 1d 1h
- Merged PRs (30d)
- 17
Description
What happened
On Windows the session-start hook always injects this into the agent's context:
IMPORTANT: The Vercel CLI is not installed.
Strongly recommend the user install it withnpm i -g vercelto unlock agentic features likevercel env pull,vercel deploy, andvercel logs.
The CLI is installed and authenticated:
$ vercel --version
Vercel CLI 56.5.0
$ vercel whoami
<my username>
The practical cost is not the wrong line, it's what the agent does with it: it takes the statement at face value and avoids vercel ls / vercel inspect for the rest of the session, so it can't check its own deployments.
Environment
- Plugin:
vercel0.48.0 (installed fromanthropics/claude-plugins-official) - OS: Windows 11
- Node: v24.13.0
vercelinstalled globally with npm, so it resolves to%APPDATA%\npm\vercel.cmd
Cause
In hooks/src/session-start-profiler.mts (and identically in the compiled hooks/session-start-profiler.mjs that actually runs):
checkVercelCli()(~line 416) resolves the binary correctly.resolveBinaryFromPathdoes append the Windows executable extensions and findsvercel.cmd, so this part is not the bug.- It then calls
execFileSync(vercelBinary, ["--version"])at ~line 425 withoutshell: true. - Since Node 18.20 / 20.12 (the CVE-2024-27980 hardening), spawning a
.cmdor.batwithout a shell throwsEINVAL. - The
catchat ~line 433 swallows it and returns{ installed: false }— which is what produces the message.
So the hook finds the CLI and then concludes it does not exist.
Minimal repro
node -e "const{execFileSync}=require('child_process');const p=require('path').join(process.env.APPDATA,'npm','vercel.cmd');try{execFileSync(p,['--version'],{stdio:['ignore','pipe','ignore']});console.log('ok')}catch(e){console.log(e.code)}"
Prints EINVAL. Adding shell: true (with the path quoted) makes it print ok.
Blast radius
- The
npm viewcall at ~line 449 has exactly the same shape and would fail the same way, but it is unreachable: thecatchon the first call returns before it. - The "CLI is outdated (x → y)" branch lives in the
elseofinstalled, so on Windows it can never fire. Windows users don't get a false statement there — they get no upgrade notice at all. - Any npm-installed CLI on Windows resolves to a
.cmdshim, so the pattern isn't specific tovercel.
Suggested fix
Spawn through a shell on Windows when the resolved path ends in .cmd / .bat, or resolve to the JS entry point behind the shim instead of the shim itself. A bare shell: true needs care with argument escaping, so quoting the resolved path explicitly is probably the safer form.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in hooks/src/session-start-profiler.mts at checkVercelCli and compare it with the compiled hooks/session-start-profiler.mjs that runs. Run the Windows minimal reproduction and inspect the nearby npm view call for the same spawning pattern. Done means Windows npm-installed .cmd and .bat CLIs are detected and the session-start hook no longer reports an installed CLI as missing.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- node.js, typescript
- Domain
- tooling
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100