Prerequisites
Bug Description
Bug Description
On Windows, the lsp-tools-mcp module's resolveWindowsCommand function incorrectly prioritizes extensionless files over .bat/.cmd scripts when resolving commands from PATH. This causes LSP servers that rely on wrapper scripts (like jdtls) to fail with exit code -4058 (UV_ENOENT - file not found).
Root Cause
In packages/lsp-tools-mcp/src/lsp/process.ts, the getWindowsPathExtensions function returns extensions with an empty string "" at the beginning:
function getWindowsPathExtensions(env: Record<string, string | undefined>): string[] {
const rawExtensions = env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD";
const extensions = rawExtensions
.split(";")
.map((extension) => extension.trim())
.filter(Boolean)
.map((extension) => (extension.startsWith(".") ? extension : `.${extension}`));
return [...new Set(["", ...extensions, ".exe", ".cmd", ".bat"])];
// ^ Empty string first!
}
When resolving jdtls in a directory containing both:
jdtls (extensionless Python script with shebang)
jdtls.bat (wrapper script that sets JAVA_HOME and executes with correct JDK)
The function finds jdtls first (because "" extension is checked before .BAT), returns its full path, and then isWindowsShellShim returns false (since it doesn't end with .bat or .cmd), causing Node.js spawn to execute it directly with shell: false.
The problem: Windows does not support shebang (#!/usr/bin/env python3). An extensionless Python script cannot be executed directly without a shell, resulting in UV_ENOENT error.
Proposed Fix
In packages/lsp-tools-mcp/src/lsp/process.ts, move the empty string "" to the end of the extensions array:
// Before (buggy):
return [...new Set(["", ...extensions, ".exe", ".cmd", ".bat"])];
// After (fixed):
return [...new Set([...extensions, ".exe", ".cmd", ".bat", ""])];
This ensures Windows PATHEXT extensions (.COM, .EXE, .BAT, .CMD) are checked first, matching the behavior of cmd.exe when resolving commands.
Steps to Reproduce
- Install
jdtls (Eclipse JDT Language Server) on Windows
- Configure
jdtls with a wrapper script that sets JAVA_HOME to JDK 21:
jdtls (extensionless Python script with --java-executable pointing to JDK 21)
jdtls.bat (wrapper that sets environment and calls the Python script)
- Ensure JDK 8 is the system default (
JAVA_HOME points to JDK 8)
- Run any LSP operation (e.g.,
lsp_diagnostics on a .java file)
- Observe:
LSP server jdtls exited with code -4058
Expected Behavior
The LSP server should start successfully. The command resolution should follow Windows PATHEXT priority order, matching .BAT/.CMD scripts before extensionless files.
Actual Behavior
The LSP server fails to start because the extensionless Python script is executed directly, which Windows cannot handle without shell involvement.
Doctor Output
Opencode version: 1.15.7
oh-my-openagent version: 4.3.0
Error Logs
Configuration
Additional Context
This bug affects any LSP server on Windows that:
- Has both an extensionless executable and a
.bat/.cmd wrapper
- Relies on the wrapper script for correct environment setup
The current behavior contradicts Windows' native command resolution, where PATHEXT extensions are prioritized over extensionless files.
Operating System
Windows
OpenCode Version
1.15.7
Prerequisites
Bug Description
Bug Description
On Windows, the
lsp-tools-mcpmodule'sresolveWindowsCommandfunction incorrectly prioritizes extensionless files over.bat/.cmdscripts when resolving commands from PATH. This causes LSP servers that rely on wrapper scripts (likejdtls) to fail with exit code-4058(UV_ENOENT - file not found).Root Cause
In
packages/lsp-tools-mcp/src/lsp/process.ts, thegetWindowsPathExtensionsfunction returns extensions with an empty string""at the beginning:When resolving
jdtlsin a directory containing both:jdtls(extensionless Python script with shebang)jdtls.bat(wrapper script that sets JAVA_HOME and executes with correct JDK)The function finds
jdtlsfirst (because""extension is checked before.BAT), returns its full path, and thenisWindowsShellShimreturnsfalse(since it doesn't end with.bator.cmd), causing Node.jsspawnto execute it directly withshell: false.The problem: Windows does not support shebang (
#!/usr/bin/env python3). An extensionless Python script cannot be executed directly without a shell, resulting inUV_ENOENTerror.Proposed Fix
In
packages/lsp-tools-mcp/src/lsp/process.ts, move the empty string""to the end of the extensions array:This ensures Windows
PATHEXTextensions (.COM,.EXE,.BAT,.CMD) are checked first, matching the behavior ofcmd.exewhen resolving commands.Steps to Reproduce
jdtls(Eclipse JDT Language Server) on Windowsjdtlswith a wrapper script that setsJAVA_HOMEto JDK 21:jdtls(extensionless Python script with--java-executablepointing to JDK 21)jdtls.bat(wrapper that sets environment and calls the Python script)JAVA_HOMEpoints to JDK 8)lsp_diagnosticson a.javafile)LSP server jdtls exited with code -4058Expected Behavior
The LSP server should start successfully. The command resolution should follow Windows
PATHEXTpriority order, matching.BAT/.CMDscripts before extensionless files.Actual Behavior
The LSP server fails to start because the extensionless Python script is executed directly, which Windows cannot handle without shell involvement.
Doctor Output
Error Logs
Configuration
Additional Context
This bug affects any LSP server on Windows that:
.bat/.cmdwrapperThe current behavior contradicts Windows' native command resolution, where
PATHEXTextensions are prioritized over extensionless files.Operating System
Windows
OpenCode Version
1.15.7