Merge pull request #2991 from GreenPi290/fix/doctor-wsl-binary-detection

fix(doctor): improve opencode binary detection for WSL
This commit is contained in:
YeonGyu-Kim
2026-05-21 00:55:17 +09:00
committed by GitHub
+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 { extractSemverFromOutput } from "../../../shared/extract-semver"
@@ -10,6 +10,15 @@ export { extractSemverFromOutput }
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
@@ -97,15 +106,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(