From bd4f0475119f76a598369f09ff8bfdfe9ba05f98 Mon Sep 17 00:00:00 2001 From: js0ny Date: Tue, 12 May 2026 16:16:20 +0100 Subject: [PATCH] fix(tui): preserve multiline shell input --- packages/opencode/src/shell/shell.ts | 6 ++-- packages/opencode/test/session/prompt.test.ts | 31 +++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/packages/opencode/src/shell/shell.ts b/packages/opencode/src/shell/shell.ts index 516a5bf23ff9..c8b6b2011e11 100644 --- a/packages/opencode/src/shell/shell.ts +++ b/packages/opencode/src/shell/shell.ts @@ -167,10 +167,11 @@ export function args(file: string, command: string, cwd: string) { [[ -f ~/.zshenv ]] && source ~/.zshenv >/dev/null 2>&1 || true [[ -f "\${ZDOTDIR:-$HOME}/.zshrc" ]] && source "\${ZDOTDIR:-$HOME}/.zshrc" >/dev/null 2>&1 || true cd -- "$1" - eval ${JSON.stringify(command)} + eval "$2" `, "opencode", cwd, + command, ] } if (n === "bash") { @@ -181,10 +182,11 @@ export function args(file: string, command: string, cwd: string) { shopt -s expand_aliases [[ -f ~/.bashrc ]] && source ~/.bashrc >/dev/null 2>&1 || true cd -- "$1" - eval ${JSON.stringify(command)} + eval "$2" `, "opencode", cwd, + command, ] } if (n === "cmd") return ["/c", command] diff --git a/packages/opencode/test/session/prompt.test.ts b/packages/opencode/test/session/prompt.test.ts index 3821954945f5..922ff6818175 100644 --- a/packages/opencode/test/session/prompt.test.ts +++ b/packages/opencode/test/session/prompt.test.ts @@ -1225,6 +1225,37 @@ unix("shell commands can change directory after startup", () => ), ) +unix( + "shell preserves newlines with configured bash", + () => + withSh(() => + provideTmpdirInstance( + (_dir) => + Effect.gen(function* () { + if (!Bun.which("bash")) return + + const { prompt, run, chat } = yield* boot() + const result = yield* prompt.shell({ + sessionID: chat.id, + agent: "build", + command: "printf first\nprintf second", + }) + + expect(result.info.role).toBe("assistant") + const tool = completedTool(result.parts) + if (!tool) return + + expect(tool.state.input.command).toBe("printf first\nprintf second") + expect(tool.state.output).toContain("firstsecond") + expect(tool.state.output).not.toContain("firstnprintf") + yield* run.assertNotBusy(chat.id) + }), + { git: true, config: { ...cfg, shell: "bash" } }, + ), + ), + 30_000, +) + unix("shell lists files from the project directory", () => provideTmpdirInstance( (dir) =>