fix(lsp): remove unreliable Windows binary availability check
The isBinaryAvailableOnWindows() function used spawnSync("where")
which fails even when the binary IS on PATH, causing false negatives.
Removed the redundant pre-check and let nodeSpawn handle binary
resolution naturally with proper OS-level error messages.
Fixes #1805
This commit is contained in:
37
src/tools/lsp/lsp-process.test.ts
Normal file
37
src/tools/lsp/lsp-process.test.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { mkdtempSync, rmSync } from "node:fs"
|
||||
import { tmpdir } from "node:os"
|
||||
import { join } from "node:path"
|
||||
|
||||
import { describe, expect, it, spyOn } from "bun:test"
|
||||
|
||||
describe("spawnProcess", () => {
|
||||
it("proceeds to node spawn on Windows when command is available", async () => {
|
||||
// #given
|
||||
const originalPlatform = process.platform
|
||||
const rootDir = mkdtempSync(join(tmpdir(), "lsp-process-test-"))
|
||||
const childProcess = await import("node:child_process")
|
||||
const nodeSpawnSpy = spyOn(childProcess, "spawn")
|
||||
|
||||
try {
|
||||
Object.defineProperty(process, "platform", { value: "win32" })
|
||||
const { spawnProcess } = await import("./lsp-process")
|
||||
|
||||
// #when
|
||||
let result: ReturnType<typeof spawnProcess> | null = null
|
||||
expect(() => {
|
||||
result = spawnProcess(["node", "--version"], {
|
||||
cwd: rootDir,
|
||||
env: process.env,
|
||||
})
|
||||
}).not.toThrow(/Binary 'node' not found/)
|
||||
|
||||
// #then
|
||||
expect(nodeSpawnSpy).toHaveBeenCalled()
|
||||
expect(result).not.toBeNull()
|
||||
} finally {
|
||||
Object.defineProperty(process, "platform", { value: originalPlatform })
|
||||
nodeSpawnSpy.mockRestore()
|
||||
rmSync(rootDir, { recursive: true, force: true })
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -1,5 +1,5 @@
|
||||
import { spawn as bunSpawn } from "bun"
|
||||
import { spawn as nodeSpawn, spawnSync, type ChildProcess } from "node:child_process"
|
||||
import { spawn as nodeSpawn, type ChildProcess } from "node:child_process"
|
||||
import { existsSync, statSync } from "fs"
|
||||
import { log } from "../../shared/logger"
|
||||
// Bun spawn segfaults on Windows (oven-sh/bun#25798) — unfixed as of v1.3.8+
|
||||
@@ -21,24 +21,6 @@ export function validateCwd(cwd: string): { valid: boolean; error?: string } {
|
||||
return { valid: false, error: `Cannot access working directory: ${cwd} (${err instanceof Error ? err.message : String(err)})` }
|
||||
}
|
||||
}
|
||||
function isBinaryAvailableOnWindows(command: string): boolean {
|
||||
if (process.platform !== "win32") return true
|
||||
|
||||
if (command.includes("/") || command.includes("\\")) {
|
||||
return existsSync(command)
|
||||
}
|
||||
|
||||
try {
|
||||
const result = spawnSync("where", [command], {
|
||||
shell: true,
|
||||
windowsHide: true,
|
||||
timeout: 5000,
|
||||
})
|
||||
return result.status === 0
|
||||
} catch {
|
||||
return true
|
||||
}
|
||||
}
|
||||
interface StreamReader {
|
||||
read(): Promise<{ done: boolean; value: Uint8Array | undefined }>
|
||||
}
|
||||
@@ -158,13 +140,6 @@ export function spawnProcess(
|
||||
}
|
||||
if (shouldUseNodeSpawn()) {
|
||||
const [cmd, ...args] = command
|
||||
if (!isBinaryAvailableOnWindows(cmd)) {
|
||||
throw new Error(
|
||||
`[LSP] Binary '${cmd}' not found on Windows. ` +
|
||||
`Ensure the LSP server is installed and available in PATH. ` +
|
||||
`For npm packages, try: npm install -g ${cmd}`
|
||||
)
|
||||
}
|
||||
log("[LSP] Using Node.js child_process on Windows to avoid Bun spawn segfault")
|
||||
const proc = nodeSpawn(cmd, args, {
|
||||
cwd: options.cwd,
|
||||
|
||||
Reference in New Issue
Block a user