fix(doctor): improve opencode binary detection for WSL

- Add manual PATH directory search as fallback for WSL
- Add isExecutable() to verify binary is actually executable
- Reuse WINDOWS_EXECUTABLE_EXTS constant

Fixes cubic-dev-ai review comments on PR #2991
This commit is contained in:
GreenPi290
2026-04-01 15:52:47 +09:00
parent a3f9eb1337
commit c507ce7c56
+41 -4
View File
@@ -1,4 +1,4 @@
import { existsSync } from "node:fs"
import { existsSync, accessSync, constants } from "node:fs"
import { homedir } from "node:os"
import { join } from "node:path"
import { spawnWithWindowsHide } from "../../../shared/spawn-with-windows-hide"
@@ -7,6 +7,15 @@ import { OPENCODE_BINARIES } from "../constants"
const WINDOWS_EXECUTABLE_EXTS = [".exe", ".cmd", ".bat", ".ps1"]
function isExecutable(path: string): boolean {
try {
accessSync(path, constants.X_OK)
return true
} catch {
return false
}
}
export interface OpenCodeBinaryInfo {
binary: string
path: string
@@ -94,15 +103,43 @@ export function findDesktopBinary(
return null
}
export async function findOpenCodeBinary(): Promise<OpenCodeBinaryInfo | null> {
export async function findOpenCodeBinary(
platform: NodeJS.Platform = process.platform,
checkExists: (path: string) => boolean = existsSync,
): Promise<OpenCodeBinaryInfo | null> {
// 1) Try Bun.which first
for (const binary of OPENCODE_BINARIES) {
const path = Bun.which(binary)
if (path) {
if (path && checkExists(path)) {
return { binary, path }
}
}
return findDesktopBinary()
// 2) Manually search through PATH directories (robust for WSL/mixed environments)
const pathEnv = process.env.PATH ?? ""
const delimiter = platform === "win32" ? ";" : ":"
const candidates = getCommandCandidates(platform)
for (const entry of pathEnv.split(delimiter).filter(Boolean)) {
for (const command of candidates) {
const fullPath = join(entry, command)
if (checkExists(fullPath) && isExecutable(fullPath)) {
return { binary: command, path: fullPath }
}
}
}
// 3) Fall back to desktop app paths
return findDesktopBinary(platform, checkExists)
}
function getCommandCandidates(platform: NodeJS.Platform): string[] {
if (platform !== "win32") return [...OPENCODE_BINARIES]
const WINDOWS_SUFFIXES = ["", ...WINDOWS_EXECUTABLE_EXTS] as const
return OPENCODE_BINARIES.flatMap((command) =>
WINDOWS_SUFFIXES.map((suffix) => `${command}${suffix}`),
)
}
export async function getOpenCodeVersion(