From df44b41aaa06b0a0c54a008740c11896708d9727 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Fri, 20 Mar 2026 10:33:53 -0400 Subject: [PATCH] fix: handle undefined from Npm.which in all callers Npm.which now returns undefined instead of throwing when binary not found. Update all callers to check for undefined and return early. Avoid explicit union types by using a resolved variable pattern. --- packages/opencode/src/format/formatter.ts | 8 +++-- packages/opencode/src/lsp/server.ts | 37 +++++++++++++++++------ packages/opencode/src/npm/index.ts | 2 +- 3 files changed, 35 insertions(+), 12 deletions(-) diff --git a/packages/opencode/src/format/formatter.ts b/packages/opencode/src/format/formatter.ts index cdb4f09be..d26a0f994 100644 --- a/packages/opencode/src/format/formatter.ts +++ b/packages/opencode/src/format/formatter.ts @@ -92,7 +92,9 @@ export const oxfmt: Info = { devDependencies?: Record }>(item) if (json.dependencies?.oxfmt || json.devDependencies?.oxfmt) { - return [await Npm.which("oxfmt"), "$FILE"] + const bin = await Npm.which("oxfmt") + if (!bin) return false + return [bin, "$FILE"] } } return false @@ -134,7 +136,9 @@ export const biome: Info = { for (const config of configs) { const found = await Filesystem.findUp(config, Instance.directory, Instance.worktree) if (found.length > 0) { - return [await Npm.which("@biomejs/biome"), "check", "--write", "$FILE"] + const bin = await Npm.which("@biomejs/biome") + if (!bin) return false + return [bin, "check", "--write", "$FILE"] } } return false diff --git a/packages/opencode/src/lsp/server.ts b/packages/opencode/src/lsp/server.ts index e822642b0..aa9bc884a 100644 --- a/packages/opencode/src/lsp/server.ts +++ b/packages/opencode/src/lsp/server.ts @@ -103,7 +103,9 @@ export namespace LSPServer { const tsserver = Module.resolve("typescript/lib/tsserver.js", Instance.directory) log.info("typescript server", { tsserver }) if (!tsserver) return - const proc = spawn(await Npm.which("typescript-language-server"), ["--stdio"], { + const bin = await Npm.which("typescript-language-server") + if (!bin) return + const proc = spawn(bin, ["--stdio"], { cwd: root, env: { ...process.env, @@ -129,7 +131,9 @@ export namespace LSPServer { const args: string[] = [] if (!binary) { if (Flag.OPENCODE_DISABLE_LSP_DOWNLOAD) return - binary = await Npm.which("@vue/language-server") + const resolved = await Npm.which("@vue/language-server") + if (!resolved) return + binary = resolved } args.push("--stdio") const proc = spawn(binary, args, { @@ -322,6 +326,7 @@ export namespace LSPServer { const resolved = Module.resolve("biome", root) if (!resolved) return bin = await Npm.which("biome") + if (!bin) return args = ["lsp-proxy", "--stdio"] } @@ -488,7 +493,9 @@ export namespace LSPServer { const args = [] if (!binary) { if (Flag.OPENCODE_DISABLE_LSP_DOWNLOAD) return - binary = await Npm.which("pyright") + const resolved = await Npm.which("pyright") + if (!resolved) return + binary = resolved } args.push("--stdio") @@ -1003,7 +1010,9 @@ export namespace LSPServer { const args: string[] = [] if (!binary) { if (Flag.OPENCODE_DISABLE_LSP_DOWNLOAD) return - binary = await Npm.which("svelte-language-server") + const resolved = await Npm.which("svelte-language-server") + if (!resolved) return + binary = resolved } args.push("--stdio") const proc = spawn(binary, args, { @@ -1035,7 +1044,9 @@ export namespace LSPServer { const args: string[] = [] if (!binary) { if (Flag.OPENCODE_DISABLE_LSP_DOWNLOAD) return - binary = await Npm.which("@astrojs/language-server") + const resolved = await Npm.which("@astrojs/language-server") + if (!resolved) return + binary = resolved } args.push("--stdio") const proc = spawn(binary, args, { @@ -1284,7 +1295,9 @@ export namespace LSPServer { const args: string[] = [] if (!binary) { if (Flag.OPENCODE_DISABLE_LSP_DOWNLOAD) return - binary = await Npm.which("yaml-language-server") + const resolved = await Npm.which("yaml-language-server") + if (!resolved) return + binary = resolved } args.push("--stdio") const proc = spawn(binary, args, { @@ -1449,7 +1462,9 @@ export namespace LSPServer { const args: string[] = [] if (!binary) { if (Flag.OPENCODE_DISABLE_LSP_DOWNLOAD) return - binary = await Npm.which("intelephense") + const resolved = await Npm.which("intelephense") + if (!resolved) return + binary = resolved } args.push("--stdio") const proc = spawn(binary, args, { @@ -1531,7 +1546,9 @@ export namespace LSPServer { const args: string[] = [] if (!binary) { if (Flag.OPENCODE_DISABLE_LSP_DOWNLOAD) return - binary = await Npm.which("bash-language-server") + const resolved = await Npm.which("bash-language-server") + if (!resolved) return + binary = resolved } args.push("start") const proc = spawn(binary, args, { @@ -1724,7 +1741,9 @@ export namespace LSPServer { const args: string[] = [] if (!binary) { if (Flag.OPENCODE_DISABLE_LSP_DOWNLOAD) return - binary = await Npm.which("dockerfile-language-server-nodejs") + const resolved = await Npm.which("dockerfile-language-server-nodejs") + if (!resolved) return + binary = resolved } args.push("--stdio") const proc = spawn(binary, args, { diff --git a/packages/opencode/src/npm/index.ts b/packages/opencode/src/npm/index.ts index 90e135367..db95c6e1d 100644 --- a/packages/opencode/src/npm/index.ts +++ b/packages/opencode/src/npm/index.ts @@ -175,7 +175,7 @@ export namespace Npm { await rm(path.join(dir, "package-lock.json"), { force: true }) await add(pkg) const resolved = await pick() - if (!resolved) throw new Error(`No binary found for package "${pkg}" after install`) + if (!resolved) return return path.join(binDir, resolved) } }