From ccab4f49dfe6bc94f7080e4ad82e6b2161ad583d Mon Sep 17 00:00:00 2001 From: Bohdan Triapitsyn Date: Tue, 28 Apr 2026 01:19:12 +0300 Subject: [PATCH] fix: preserve shell PATH for managed OpenCode Restores shell-first PATH resolution for desktop-launched OpenCode Keeps app PATH entries as fallback Adds coverage for managed OpenCode PATH merging --- packages/web/server/lib/opencode/env-runtime.js | 9 +++++---- .../web/server/lib/opencode/server-utils-runtime.js | 5 ----- .../server/lib/opencode/server-utils-runtime.test.js | 11 +++++++++-- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/packages/web/server/lib/opencode/env-runtime.js b/packages/web/server/lib/opencode/env-runtime.js index b76cdff7..970bc8e6 100644 --- a/packages/web/server/lib/opencode/env-runtime.js +++ b/packages/web/server/lib/opencode/env-runtime.js @@ -2,7 +2,7 @@ import { spawnSync } from 'node:child_process'; import fs from 'node:fs'; import os from 'node:os'; import path from 'node:path'; -import { pathLooksUserConfigured, mergePathValues } from './path-utils.js'; +import { mergePathValues } from './path-utils.js'; export const createOpenCodeEnvRuntime = (deps) => { const { @@ -183,10 +183,11 @@ export const createOpenCodeEnvRuntime = (deps) => { const currentPath = process.env.PATH || ''; const shellPath = snapshot.PATH || ''; - const home = os.homedir(); - if (!pathLooksUserConfigured(currentPath, home, path.delimiter) && shellPath) { - process.env.PATH = mergePathValues(shellPath, currentPath, path.delimiter); + if (!shellPath) { + return; } + + process.env.PATH = mergePathValues(shellPath, currentPath, path.delimiter); }; const isWslExecutableValue = (value) => { diff --git a/packages/web/server/lib/opencode/server-utils-runtime.js b/packages/web/server/lib/opencode/server-utils-runtime.js index 267e6962..dc4584ec 100644 --- a/packages/web/server/lib/opencode/server-utils-runtime.js +++ b/packages/web/server/lib/opencode/server-utils-runtime.js @@ -76,11 +76,6 @@ export const createServerUtilsRuntime = (dependencies) => { const buildManagedOpenCodePath = () => { const currentPath = process.env.PATH || ''; const loginShellPath = getLoginShellPath(); - const home = os.homedir(); - - if (pathLooksUserConfigured(currentPath, home, path.delimiter)) { - return currentPath; - } return mergePathValues(loginShellPath || '', currentPath, path.delimiter); }; diff --git a/packages/web/server/lib/opencode/server-utils-runtime.test.js b/packages/web/server/lib/opencode/server-utils-runtime.test.js index bf34aacb..6e79e37c 100644 --- a/packages/web/server/lib/opencode/server-utils-runtime.test.js +++ b/packages/web/server/lib/opencode/server-utils-runtime.test.js @@ -32,7 +32,7 @@ const createRuntime = (loginShellPath) => createServerUtilsRuntime({ }); describe('server utils runtime', () => { - it('keeps managed OpenCode PATH literal when process PATH is user-configured', () => { + it('prefers shell PATH for managed OpenCode before appending process-only entries', () => { const home = os.homedir(); const currentPath = [ path.join(home, '.opencode', 'bin'), @@ -51,7 +51,14 @@ describe('server utils runtime', () => { path.join(home, '.cargo', 'bin'), ].join(path.delimiter)); - expect(runtime.buildManagedOpenCodePath()).toBe(currentPath); + expect(runtime.buildManagedOpenCodePath()).toBe([ + path.join(home, '.opencode', 'bin'), + path.join(home, '.bun', 'bin'), + '/opt/homebrew/bin', + '/usr/bin', + path.join(home, '.cargo', 'bin'), + path.join(home, 'Library', 'pnpm'), + ].join(path.delimiter)); }); it('uses login shell PATH for managed OpenCode when process PATH is minimal', () => {