From 9d0b56d375aeaf1841f32f1a9d1c37d86820a75a Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Thu, 12 Mar 2026 01:44:06 +0900 Subject: [PATCH 1/2] fix: unify LSP server PATH resolution between detection and spawn (#2431) --- src/tools/lsp/lsp-client-transport.ts | 20 ++++++++++++++++---- src/tools/lsp/server-installation.ts | 19 ++++--------------- src/tools/lsp/server-path-bases.ts | 15 +++++++++++++++ 3 files changed, 35 insertions(+), 19 deletions(-) create mode 100644 src/tools/lsp/server-path-bases.ts diff --git a/src/tools/lsp/lsp-client-transport.ts b/src/tools/lsp/lsp-client-transport.ts index d4590262b..6031e8574 100644 --- a/src/tools/lsp/lsp-client-transport.ts +++ b/src/tools/lsp/lsp-client-transport.ts @@ -1,4 +1,5 @@ import { Readable, Writable } from "node:stream" +import { delimiter } from "path" import { createMessageConnection, StreamMessageReader, @@ -7,6 +8,7 @@ import { } from "vscode-jsonrpc/node" import type { Diagnostic, ResolvedServer } from "./types" import { spawnProcess, type UnifiedProcess } from "./lsp-process" +import { getLspServerAdditionalPathBases } from "./server-path-bases" import { log } from "../../shared/logger" export class LSPClientTransport { protected proc: UnifiedProcess | null = null @@ -18,12 +20,22 @@ export class LSPClientTransport { constructor(protected root: string, protected server: ResolvedServer) {} async start(): Promise { + const env = { + ...process.env, + ...this.server.env, + } + const pathValue = process.platform === "win32" ? env.PATH ?? env.Path ?? "" : env.PATH ?? "" + const spawnPath = [pathValue, ...getLspServerAdditionalPathBases(this.root)] + .filter(Boolean) + .join(delimiter) + if (process.platform === "win32" && env.Path !== undefined) { + env.Path = spawnPath + } + env.PATH = spawnPath + this.proc = spawnProcess(this.server.command, { cwd: this.root, - env: { - ...process.env, - ...this.server.env, - }, + env, }) if (!this.proc) { throw new Error(`Failed to spawn LSP server: ${this.server.command.join(" ")}`) diff --git a/src/tools/lsp/server-installation.ts b/src/tools/lsp/server-installation.ts index e3a834c8a..9e26eee7a 100644 --- a/src/tools/lsp/server-installation.ts +++ b/src/tools/lsp/server-installation.ts @@ -1,7 +1,7 @@ import { existsSync } from "fs" -import { join } from "path" +import { delimiter, join } from "path" -import { getOpenCodeConfigDir, getDataDir } from "../../shared" +import { getLspServerAdditionalPathBases } from "./server-path-bases" export function isServerInstalled(command: string[]): boolean { if (command.length === 0) return false @@ -31,8 +31,7 @@ export function isServerInstalled(command: string[]): boolean { pathEnv = process.env.Path || "" } - const pathSeparator = isWindows ? ";" : ":" - const paths = pathEnv.split(pathSeparator) + const paths = pathEnv.split(delimiter) for (const p of paths) { for (const suffix of exts) { @@ -42,17 +41,7 @@ export function isServerInstalled(command: string[]): boolean { } } - const cwd = process.cwd() - const configDir = getOpenCodeConfigDir({ binary: "opencode" }) - const dataDir = join(getDataDir(), "opencode") - const additionalBases = [ - join(cwd, "node_modules", ".bin"), - join(configDir, "bin"), - join(configDir, "node_modules", ".bin"), - join(dataDir, "bin"), - ] - - for (const base of additionalBases) { + for (const base of getLspServerAdditionalPathBases(process.cwd())) { for (const suffix of exts) { if (existsSync(join(base, cmd + suffix))) { return true diff --git a/src/tools/lsp/server-path-bases.ts b/src/tools/lsp/server-path-bases.ts new file mode 100644 index 000000000..ae0070ff3 --- /dev/null +++ b/src/tools/lsp/server-path-bases.ts @@ -0,0 +1,15 @@ +import { join } from "path" + +import { getDataDir, getOpenCodeConfigDir } from "../../shared" + +export function getLspServerAdditionalPathBases(workingDirectory: string): string[] { + const configDir = getOpenCodeConfigDir({ binary: "opencode" }) + const dataDir = join(getDataDir(), "opencode") + + return [ + join(workingDirectory, "node_modules", ".bin"), + join(configDir, "bin"), + join(configDir, "node_modules", ".bin"), + join(dataDir, "bin"), + ] +} From 6014f03ed26bd366f1124d0e389a3c892c3c261b Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Thu, 12 Mar 2026 11:04:43 +0900 Subject: [PATCH 2/2] fix: address Cubic finding for LSP server npm bin path Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/tools/lsp/server-path-bases.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/lsp/server-path-bases.ts b/src/tools/lsp/server-path-bases.ts index ae0070ff3..7f6b00490 100644 --- a/src/tools/lsp/server-path-bases.ts +++ b/src/tools/lsp/server-path-bases.ts @@ -11,5 +11,6 @@ export function getLspServerAdditionalPathBases(workingDirectory: string): strin join(configDir, "bin"), join(configDir, "node_modules", ".bin"), join(dataDir, "bin"), + join(dataDir, "bin", "node_modules", ".bin"), ] }