From cd1e23183c2354385542a5e42de5f5267adae7a9 Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Fri, 24 Apr 2026 17:44:54 -0400 Subject: [PATCH 1/2] fix(session): preserve shell cwd after startup --- packages/opencode/src/session/prompt.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index 5f3530bcefa7..dab6f8626da7 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -787,6 +787,7 @@ NOTE: At any point in time through this workflow you should feel free to ask the const shellName = ( process.platform === "win32" ? path.win32.basename(sh, ".exe") : path.basename(sh) ).toLowerCase() + const cwd = ctx.directory const invocations: Record = { nu: { args: ["-c", input.command] }, fish: { args: ["-c", input.command] }, @@ -795,10 +796,9 @@ NOTE: At any point in time through this workflow you should feel free to ask the "-l", "-c", ` - __oc_cwd=$PWD [[ -f ~/.zshenv ]] && source ~/.zshenv >/dev/null 2>&1 || true [[ -f "\${ZDOTDIR:-$HOME}/.zshrc" ]] && source "\${ZDOTDIR:-$HOME}/.zshrc" >/dev/null 2>&1 || true - cd "$__oc_cwd" + cd "$OPENCODE_CWD" eval ${JSON.stringify(input.command)} `, ], @@ -808,10 +808,9 @@ NOTE: At any point in time through this workflow you should feel free to ask the "-l", "-c", ` - __oc_cwd=$PWD shopt -s expand_aliases [[ -f ~/.bashrc ]] && source ~/.bashrc >/dev/null 2>&1 || true - cd "$__oc_cwd" + cd "$OPENCODE_CWD" eval ${JSON.stringify(input.command)} `, ], @@ -823,7 +822,6 @@ NOTE: At any point in time through this workflow you should feel free to ask the } const args = (invocations[shellName] ?? invocations[""]).args - const cwd = ctx.directory const shellEnv = yield* plugin.trigger( "shell.env", { cwd, sessionID: input.sessionID, callID: part.callID }, @@ -833,7 +831,7 @@ NOTE: At any point in time through this workflow you should feel free to ask the const cmd = ChildProcess.make(sh, args, { cwd, extendEnv: true, - env: { ...shellEnv.env, TERM: "dumb" }, + env: { ...shellEnv.env, OPENCODE_CWD: cwd, TERM: "dumb" }, stdin: "ignore", forceKillAfter: "3 seconds", }) From de375ff5c43e6466bca652420ea3c4d2b032ad57 Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Fri, 24 Apr 2026 18:01:13 -0400 Subject: [PATCH 2/2] test(session): cover shell cwd changes --- packages/opencode/src/session/prompt.ts | 10 +++++--- packages/opencode/test/session/prompt.test.ts | 24 +++++++++++++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index dab6f8626da7..3d07a96ecdc5 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -798,9 +798,11 @@ NOTE: At any point in time through this workflow you should feel free to ask the ` [[ -f ~/.zshenv ]] && source ~/.zshenv >/dev/null 2>&1 || true [[ -f "\${ZDOTDIR:-$HOME}/.zshrc" ]] && source "\${ZDOTDIR:-$HOME}/.zshrc" >/dev/null 2>&1 || true - cd "$OPENCODE_CWD" + cd -- "$1" eval ${JSON.stringify(input.command)} `, + "opencode", + cwd, ], }, bash: { @@ -810,9 +812,11 @@ NOTE: At any point in time through this workflow you should feel free to ask the ` shopt -s expand_aliases [[ -f ~/.bashrc ]] && source ~/.bashrc >/dev/null 2>&1 || true - cd "$OPENCODE_CWD" + cd -- "$1" eval ${JSON.stringify(input.command)} `, + "opencode", + cwd, ], }, cmd: { args: ["/c", input.command] }, @@ -831,7 +835,7 @@ NOTE: At any point in time through this workflow you should feel free to ask the const cmd = ChildProcess.make(sh, args, { cwd, extendEnv: true, - env: { ...shellEnv.env, OPENCODE_CWD: cwd, TERM: "dumb" }, + env: { ...shellEnv.env, TERM: "dumb" }, stdin: "ignore", forceKillAfter: "3 seconds", }) diff --git a/packages/opencode/test/session/prompt.test.ts b/packages/opencode/test/session/prompt.test.ts index 8ffb20f15419..911cb4415553 100644 --- a/packages/opencode/test/session/prompt.test.ts +++ b/packages/opencode/test/session/prompt.test.ts @@ -1078,6 +1078,30 @@ unix("shell completes a fast command on the preferred shell", () => ), ) +unix("shell commands can change directory after startup", () => + provideTmpdirInstance( + (dir) => + Effect.gen(function* () { + const { prompt, run, chat } = yield* boot() + const parent = path.dirname(dir) + const result = yield* prompt.shell({ + sessionID: chat.id, + agent: "build", + command: "cd .. && pwd", + }) + + expect(result.info.role).toBe("assistant") + const tool = completedTool(result.parts) + if (!tool) return + + expect(tool.state.output).toContain(parent) + expect(tool.state.metadata.output).toContain(parent) + yield* run.assertNotBusy(chat.id) + }), + { git: true, config: cfg }, + ), +) + unix("shell lists files from the project directory", () => provideTmpdirInstance( (dir) =>