From c9e715f2dc5abadef3e076f44fab2e53131bb40c Mon Sep 17 00:00:00 2001 From: Stephen Collings Date: Mon, 3 Nov 2025 20:40:12 +0000 Subject: [PATCH 1/5] fix: Provide OPENCODE env var to bash tool Plus generic AGENT var used by eg bun test: https://bun.com/docs/test#environment-variables --- packages/opencode/src/index.ts | 2 -- packages/opencode/src/tool/bash.ts | 5 ++++ packages/opencode/test/tool/bash.test.ts | 32 ++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/packages/opencode/src/index.ts b/packages/opencode/src/index.ts index bfdadff2a74d..f381b0ae39cd 100644 --- a/packages/opencode/src/index.ts +++ b/packages/opencode/src/index.ts @@ -61,8 +61,6 @@ const cli = yargs(hideBin(process.argv)) })(), }) - process.env["OPENCODE"] = "1" - Log.Default.info("opencode", { version: Installation.VERSION, args: process.argv.slice(2), diff --git a/packages/opencode/src/tool/bash.ts b/packages/opencode/src/tool/bash.ts index e7b7d7382468..b875552b3983 100644 --- a/packages/opencode/src/tool/bash.ts +++ b/packages/opencode/src/tool/bash.ts @@ -144,6 +144,11 @@ export const BashTool = Tool.define("bash", { const proc = spawn(params.command, { shell: true, cwd: Instance.directory, + env: { + ...process.env, + AGENT: "1", + OPENCODE: "1", + }, stdio: ["ignore", "pipe", "pipe"], detached: process.platform !== "win32", }) diff --git a/packages/opencode/test/tool/bash.test.ts b/packages/opencode/test/tool/bash.test.ts index 2919ccb0245c..7de32f9b4f72 100644 --- a/packages/opencode/test/tool/bash.test.ts +++ b/packages/opencode/test/tool/bash.test.ts @@ -49,4 +49,36 @@ describe("tool.bash", () => { }, }) }) + + test("provides OPENCODE environment variable", async () => { + await Instance.provide({ + directory: projectRoot, + fn: async () => { + const result = await bash.execute( + { + command: "echo $OPENCODE", + description: "Echo OPENCODE env variable", + }, + ctx, + ) + expect(result.metadata.output).toBe("1\n") + }, + }) + }) + + test("provides AGENT environment variable", async () => { + await Instance.provide({ + directory: projectRoot, + fn: async () => { + const result = await bash.execute( + { + command: "echo $AGENT", + description: "Echo AGENT env variable", + }, + ctx, + ) + expect(result.metadata.output).toBe("1\n") + }, + }) + }) }) From 40b37301e074330f36ba7e22197011a23b783cfc Mon Sep 17 00:00:00 2001 From: Stephen Collings Date: Mon, 3 Nov 2025 22:27:44 +0000 Subject: [PATCH 2/5] fix: Provide AGENT & OPENCODE env vars to shell prompt --- packages/opencode/src/session/prompt.ts | 2 + packages/opencode/test/session/prompt.test.ts | 40 +++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 packages/opencode/test/session/prompt.test.ts diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index 5cbfb8b5afc2..2befc4895328 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -1475,6 +1475,8 @@ export namespace SessionPrompt { stdio: ["ignore", "pipe", "pipe"], env: { ...process.env, + AGENT: "1", + OPENCODE: "1", TERM: "dumb", }, }) diff --git a/packages/opencode/test/session/prompt.test.ts b/packages/opencode/test/session/prompt.test.ts new file mode 100644 index 000000000000..5bbe430a867c --- /dev/null +++ b/packages/opencode/test/session/prompt.test.ts @@ -0,0 +1,40 @@ +import { describe, expect, test } from "bun:test" +import path from "path" +import { Session } from "../../src/session" +import { SessionPrompt } from "../../src/session/prompt" +import { Bus } from "../../src/bus" +import { Log } from "../../src/util/log" +import { Instance } from "../../src/project/instance" + +const projectRoot = path.join(__dirname, "../..") +Log.init({ print: false }) + + +describe("shell", () => { + test("provides AGENT environment variable", () => testShellCommand("echo $AGENT", "1\n")) + test("provides OPENCODE environment variable", () => testShellCommand("echo $OPENCODE", "1\n")) +}) + +const testShellCommand = async (command: string, expectedOutput: string) => { + await Instance.provide({ + directory: projectRoot, + fn: async () => { + const session = await Session.create({}) + const result = await SessionPrompt.shell({ + agent: "build", + sessionID: session.id, + command, + }) + + const output = result.parts.map((part) => { + if (part.state.status === "completed") { + return part.state.output + } + }).filter(Boolean).join("") + + expect(output).toBe(expectedOutput) + }, + }) + + expect.assertions(1) +} From b939a9de62e6410bbf4c406899b7c0721f28eb13 Mon Sep 17 00:00:00 2001 From: Stephen Collings Date: Mon, 3 Nov 2025 22:53:59 +0000 Subject: [PATCH 3/5] fix: Mutate env out of caution This works as-is `opencode run` for not for interactive sessions --- packages/opencode/src/index.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/opencode/src/index.ts b/packages/opencode/src/index.ts index f381b0ae39cd..798a94a95146 100644 --- a/packages/opencode/src/index.ts +++ b/packages/opencode/src/index.ts @@ -61,6 +61,9 @@ const cli = yargs(hideBin(process.argv)) })(), }) + process.env["AGENT"] = "1" + process.env["OPENCODE"] = "1" + Log.Default.info("opencode", { version: Installation.VERSION, args: process.argv.slice(2), From 8e1c00db2da785ba33feb82ebd433e5eb22f8fd6 Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Mon, 3 Nov 2025 19:22:13 -0600 Subject: [PATCH 4/5] tweak: ensure env is passed to worker --- packages/opencode/src/cli/cmd/tui/thread.ts | 8 +++++- packages/opencode/src/index.ts | 4 +-- packages/opencode/src/session/prompt.ts | 2 -- packages/opencode/src/tool/bash.ts | 2 -- packages/opencode/test/tool/bash.test.ts | 32 --------------------- 5 files changed, 9 insertions(+), 39 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/thread.ts b/packages/opencode/src/cli/cmd/tui/thread.ts index 66a22bf9049e..1c2baeff448b 100644 --- a/packages/opencode/src/cli/cmd/tui/thread.ts +++ b/packages/opencode/src/cli/cmd/tui/thread.ts @@ -82,7 +82,13 @@ export const TuiThreadCommand = cmd({ return undefined })() - const worker = new Worker("./src/cli/cmd/tui/worker.ts") + const worker = new Worker("./src/cli/cmd/tui/worker.ts", { + env: Object.fromEntries( + Object.entries(process.env).filter( + (entry): entry is [string, string] => entry[1] !== undefined, + ), + ), + }) worker.onerror = console.error const client = Rpc.client(worker) process.on("uncaughtException", (e) => { diff --git a/packages/opencode/src/index.ts b/packages/opencode/src/index.ts index 798a94a95146..6211e1276954 100644 --- a/packages/opencode/src/index.ts +++ b/packages/opencode/src/index.ts @@ -61,8 +61,8 @@ const cli = yargs(hideBin(process.argv)) })(), }) - process.env["AGENT"] = "1" - process.env["OPENCODE"] = "1" + process.env.AGENT = "1" + process.env.OPENCODE = "1" Log.Default.info("opencode", { version: Installation.VERSION, diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index 2befc4895328..5cbfb8b5afc2 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -1475,8 +1475,6 @@ export namespace SessionPrompt { stdio: ["ignore", "pipe", "pipe"], env: { ...process.env, - AGENT: "1", - OPENCODE: "1", TERM: "dumb", }, }) diff --git a/packages/opencode/src/tool/bash.ts b/packages/opencode/src/tool/bash.ts index b875552b3983..febd253a0c05 100644 --- a/packages/opencode/src/tool/bash.ts +++ b/packages/opencode/src/tool/bash.ts @@ -146,8 +146,6 @@ export const BashTool = Tool.define("bash", { cwd: Instance.directory, env: { ...process.env, - AGENT: "1", - OPENCODE: "1", }, stdio: ["ignore", "pipe", "pipe"], detached: process.platform !== "win32", diff --git a/packages/opencode/test/tool/bash.test.ts b/packages/opencode/test/tool/bash.test.ts index 7de32f9b4f72..2919ccb0245c 100644 --- a/packages/opencode/test/tool/bash.test.ts +++ b/packages/opencode/test/tool/bash.test.ts @@ -49,36 +49,4 @@ describe("tool.bash", () => { }, }) }) - - test("provides OPENCODE environment variable", async () => { - await Instance.provide({ - directory: projectRoot, - fn: async () => { - const result = await bash.execute( - { - command: "echo $OPENCODE", - description: "Echo OPENCODE env variable", - }, - ctx, - ) - expect(result.metadata.output).toBe("1\n") - }, - }) - }) - - test("provides AGENT environment variable", async () => { - await Instance.provide({ - directory: projectRoot, - fn: async () => { - const result = await bash.execute( - { - command: "echo $AGENT", - description: "Echo AGENT env variable", - }, - ctx, - ) - expect(result.metadata.output).toBe("1\n") - }, - }) - }) }) From f3a7575120a8a01fb96e28aed6f45359ab59d14c Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Mon, 3 Nov 2025 19:23:15 -0600 Subject: [PATCH 5/5] rm test --- packages/opencode/test/session/prompt.test.ts | 40 ------------------- 1 file changed, 40 deletions(-) delete mode 100644 packages/opencode/test/session/prompt.test.ts diff --git a/packages/opencode/test/session/prompt.test.ts b/packages/opencode/test/session/prompt.test.ts deleted file mode 100644 index 5bbe430a867c..000000000000 --- a/packages/opencode/test/session/prompt.test.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { describe, expect, test } from "bun:test" -import path from "path" -import { Session } from "../../src/session" -import { SessionPrompt } from "../../src/session/prompt" -import { Bus } from "../../src/bus" -import { Log } from "../../src/util/log" -import { Instance } from "../../src/project/instance" - -const projectRoot = path.join(__dirname, "../..") -Log.init({ print: false }) - - -describe("shell", () => { - test("provides AGENT environment variable", () => testShellCommand("echo $AGENT", "1\n")) - test("provides OPENCODE environment variable", () => testShellCommand("echo $OPENCODE", "1\n")) -}) - -const testShellCommand = async (command: string, expectedOutput: string) => { - await Instance.provide({ - directory: projectRoot, - fn: async () => { - const session = await Session.create({}) - const result = await SessionPrompt.shell({ - agent: "build", - sessionID: session.id, - command, - }) - - const output = result.parts.map((part) => { - if (part.state.status === "completed") { - return part.state.output - } - }).filter(Boolean).join("") - - expect(output).toBe(expectedOutput) - }, - }) - - expect.assertions(1) -}