From 1db6bd1770d01caa51b73521eba7573a2c0a82a3 Mon Sep 17 00:00:00 2001 From: Terada Kousuke Date: Fri, 3 Apr 2026 19:31:27 +0900 Subject: [PATCH 1/2] fix: preserve original CWD when bun spawns opencode subprocess (#22) When opencode falls back to running via bun (no prebuilt binary found), the bun() function in bin/opencode sets cwd to the package directory so that the relative ./src/index.ts path resolves correctly. This causes process.cwd() in the spawned process to return the opencode package path instead of the user's project directory. Pass the original working directory as OPENCODE_ORIGINAL_CWD env var to the bun subprocess, and resolve it centrally in bootstrap() so all CLI commands (run, export, debug, session, etc.) use the correct directory. Also fix file path resolution in the run command's --file handler. Co-Authored-By: Claude Opus 4.6 (1M context) --- packages/opencode/bin/opencode | 4 ++++ packages/opencode/src/cli/bootstrap.ts | 3 ++- packages/opencode/src/cli/cmd/run.ts | 4 +++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/opencode/bin/opencode b/packages/opencode/bin/opencode index 2526b0f76a05..d6801adb1b6b 100755 --- a/packages/opencode/bin/opencode +++ b/packages/opencode/bin/opencode @@ -25,6 +25,10 @@ function bun(dir) { { stdio: "inherit", cwd: dir, + env: { + ...process.env, + OPENCODE_ORIGINAL_CWD: process.cwd(), + }, }, ) if (result.error) { diff --git a/packages/opencode/src/cli/bootstrap.ts b/packages/opencode/src/cli/bootstrap.ts index 984d5723d44d..4d27a15269f4 100644 --- a/packages/opencode/src/cli/bootstrap.ts +++ b/packages/opencode/src/cli/bootstrap.ts @@ -2,8 +2,9 @@ import { InstanceBootstrap } from "../project/bootstrap" import { Instance } from "../project/instance" export async function bootstrap(directory: string, cb: () => Promise) { + const resolvedDirectory = process.env.OPENCODE_ORIGINAL_CWD || directory return Instance.provide({ - directory, + directory: resolvedDirectory, init: InstanceBootstrap, fn: async () => { try { diff --git a/packages/opencode/src/cli/cmd/run.ts b/packages/opencode/src/cli/cmd/run.ts index 0aeb864e8679..8e049f53ffba 100644 --- a/packages/opencode/src/cli/cmd/run.ts +++ b/packages/opencode/src/cli/cmd/run.ts @@ -304,6 +304,8 @@ export const RunCommand = cmd({ }) }, handler: async (args) => { + const effectiveCwd = process.env.OPENCODE_ORIGINAL_CWD || process.cwd() + let message = [...args.message, ...(args["--"] || [])] .map((arg) => (arg.includes(" ") ? `"${arg.replace(/"/g, '\\"')}"` : arg)) .join(" ") @@ -325,7 +327,7 @@ export const RunCommand = cmd({ const list = Array.isArray(args.file) ? args.file : [args.file] for (const filePath of list) { - const resolvedPath = path.resolve(process.cwd(), filePath) + const resolvedPath = path.resolve(effectiveCwd, filePath) if (!(await Filesystem.exists(resolvedPath))) { UI.error(`File not found: ${filePath}`) process.exit(1) From cbbf8af492a1d5cc043a9e416fc143048256ed8e Mon Sep 17 00:00:00 2001 From: Terada Kousuke Date: Fri, 3 Apr 2026 19:35:21 +0900 Subject: [PATCH 2/2] fix: restore CWD via process.chdir in index.ts instead of per-caller resolution (#22) The previous approach of resolving OPENCODE_ORIGINAL_CWD in bootstrap() would silently override the --dir flag. Instead, restore the original CWD at process startup in index.ts via process.chdir(). This fixes all code paths globally and preserves --dir behavior since process.chdir(args.dir) runs later in the handler. Reverts bootstrap.ts and run.ts to their original state. Co-Authored-By: Claude Opus 4.6 (1M context) --- packages/opencode/src/cli/bootstrap.ts | 3 +-- packages/opencode/src/cli/cmd/run.ts | 4 +--- packages/opencode/src/index.ts | 8 ++++++++ 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/packages/opencode/src/cli/bootstrap.ts b/packages/opencode/src/cli/bootstrap.ts index 4d27a15269f4..984d5723d44d 100644 --- a/packages/opencode/src/cli/bootstrap.ts +++ b/packages/opencode/src/cli/bootstrap.ts @@ -2,9 +2,8 @@ import { InstanceBootstrap } from "../project/bootstrap" import { Instance } from "../project/instance" export async function bootstrap(directory: string, cb: () => Promise) { - const resolvedDirectory = process.env.OPENCODE_ORIGINAL_CWD || directory return Instance.provide({ - directory: resolvedDirectory, + directory, init: InstanceBootstrap, fn: async () => { try { diff --git a/packages/opencode/src/cli/cmd/run.ts b/packages/opencode/src/cli/cmd/run.ts index 8e049f53ffba..0aeb864e8679 100644 --- a/packages/opencode/src/cli/cmd/run.ts +++ b/packages/opencode/src/cli/cmd/run.ts @@ -304,8 +304,6 @@ export const RunCommand = cmd({ }) }, handler: async (args) => { - const effectiveCwd = process.env.OPENCODE_ORIGINAL_CWD || process.cwd() - let message = [...args.message, ...(args["--"] || [])] .map((arg) => (arg.includes(" ") ? `"${arg.replace(/"/g, '\\"')}"` : arg)) .join(" ") @@ -327,7 +325,7 @@ export const RunCommand = cmd({ const list = Array.isArray(args.file) ? args.file : [args.file] for (const filePath of list) { - const resolvedPath = path.resolve(effectiveCwd, filePath) + const resolvedPath = path.resolve(process.cwd(), filePath) if (!(await Filesystem.exists(resolvedPath))) { UI.error(`File not found: ${filePath}`) process.exit(1) diff --git a/packages/opencode/src/index.ts b/packages/opencode/src/index.ts index 1fa027abf904..8820416bad2d 100644 --- a/packages/opencode/src/index.ts +++ b/packages/opencode/src/index.ts @@ -37,6 +37,14 @@ import { errorMessage } from "./util/error" import { PluginCommand } from "./cli/cmd/plug" import { Heap } from "./cli/heap" +// When launched via the bun fallback in bin/opencode, the subprocess CWD is set +// to the opencode package directory (so ./src/index.ts resolves). The original +// user CWD is passed via OPENCODE_ORIGINAL_CWD. Restore it early so all code +// paths (including process.cwd() calls in CLI handlers) see the correct directory. +if (process.env.OPENCODE_ORIGINAL_CWD) { + process.chdir(process.env.OPENCODE_ORIGINAL_CWD) +} + process.on("unhandledRejection", (e) => { Log.Default.error("rejection", { e: errorMessage(e),