typescript-lsp plugin fails on Windows: spawn ENOENT for npm global binaries
Description
The typescript-lsp plugin fails to start on Windows with the error:
LSP server plugin:typescript-lsp:typescript failed to start: ENOENT: no such file or directory, uv_spawn 'typescript-language-server'
Root Cause
On Windows, npm installs global packages with .cmd wrapper scripts (batch files), not executable binaries. When Claude Code's LSP manager uses Node.js spawn() without shell: true, it cannot find the .cmd files because:
- Node.js
spawn()without shell only looks for actual executables (.exe) - npm creates
typescript-language-server.cmd(batch file), nottypescript-language-server.exe - While cmd.exe respects PATHEXT and finds
.cmdfiles, Node.jsspawn()does not
Reproduction
// This fails on Windows:
const { spawn } = require('child_process');
spawn('typescript-language-server', ['--version']); // ENOENT
// This works:
spawn('typescript-language-server', ['--version'], { shell: true }); // OK
spawn('typescript-language-server', ['--version'], { shell: 'cmd.exe' }); // OK
Environment
- OS: Windows 11 (build 26220)
- Claude Code: 2.1.14
- Node.js: 24.3.0
- typescript-language-server: 5.1.3 (installed globally via npm)
Suggested Fix
The LSP manager should use shell: true (or shell: 'cmd.exe') when spawning language servers on Windows. This allows the shell to resolve .cmd wrapper scripts.
Alternatively, the plugin could explicitly look for the .cmd extension on Windows:
const command = process.platform === 'win32'
? 'typescript-language-server.cmd'
: 'typescript-language-server';
Workaround
Created a .NET shim executable (typescript-language-server.exe) that calls the .cmd file via cmd.exe. This allows Node.js spawn() to find and execute it.
This issue has 14 comments on GitHub. Read the full discussion on GitHub ↗