diff --git a/packages/core/src/tool/bash.ts b/packages/core/src/tool/bash.ts index 22423764bc..386755d94a 100644 --- a/packages/core/src/tool/bash.ts +++ b/packages/core/src/tool/bash.ts @@ -158,6 +158,8 @@ const layer = Layer.effectDiscard( const command = ChildProcess.make(input.command, [], { cwd: target.canonical, shell, + env: { OPENCODE: "1", AGENT: "1" }, + extendEnv: true, stdin: "ignore", detached: process.platform !== "win32", forceKillAfter: Duration.seconds(3), diff --git a/packages/core/test/tool-bash.test.ts b/packages/core/test/tool-bash.test.ts index 1e67abe2ba..05e80ca46a 100644 --- a/packages/core/test/tool-bash.test.ts +++ b/packages/core/test/tool-bash.test.ts @@ -28,6 +28,8 @@ const runs: Array<{ readonly command: string readonly cwd?: string readonly shell?: string | boolean + readonly env?: Record + readonly extendEnv?: boolean readonly options?: AppProcess.RunOptions }> = [] let denyAction: string | undefined @@ -67,7 +69,14 @@ const appProcess = Layer.succeed( run: (command: ChildProcess.Command, options?: AppProcess.RunOptions) => Effect.suspend(() => { if (command._tag !== "StandardCommand") throw new Error("expected standard command") - runs.push({ command: command.command, cwd: command.options.cwd, shell: command.options.shell, options }) + runs.push({ + command: command.command, + cwd: command.options.cwd, + shell: command.options.shell, + env: command.options.env, + extendEnv: command.options.extendEnv, + options, + }) return runFailure ? Effect.fail(runFailure) : Effect.succeed(result) }), } as unknown as AppProcess.Interface), @@ -168,6 +177,7 @@ describe("BashTool", () => { }, }) expect(runs).toMatchObject([{ command: "pwd", cwd: realpathSync(tmp.path) }]) + expect(runs[0]).toMatchObject({ env: { OPENCODE: "1", AGENT: "1" }, extendEnv: true }) expect(runs[0]?.options).toMatchObject({ combineOutput: true, maxOutputBytes: BashTool.MAX_CAPTURE_BYTES, diff --git a/packages/opencode/src/tool/shell.ts b/packages/opencode/src/tool/shell.ts index 1e4423e017..e7ef8381c6 100644 --- a/packages/opencode/src/tool/shell.ts +++ b/packages/opencode/src/tool/shell.ts @@ -422,6 +422,8 @@ export const ShellTool = Tool.define( return { ...process.env, ...extra.env, + OPENCODE: "1", + AGENT: "1", } }) diff --git a/packages/opencode/test/tool/shell.test.ts b/packages/opencode/test/tool/shell.test.ts index a970f85d46..a755aeb769 100644 --- a/packages/opencode/test/tool/shell.test.ts +++ b/packages/opencode/test/tool/shell.test.ts @@ -194,6 +194,19 @@ describe("tool.shell", () => { ), ) + each("identifies commands as running under opencode", () => + runIn( + projectRoot, + Effect.gen(function* () { + const code = "process.stdout.write([process.env.OPENCODE,process.env.AGENT].join(String.fromCharCode(44)))" + const command = `${PS.has(sh()) ? "& " : ""}${bin} -e ${evalarg(code)}` + const result = yield* run({ command }) + expect(result.metadata.exit).toBe(0) + expect(result.output).toContain("1,1") + }), + ), + ) + it.live("falls back from terminal-only configured shell", () => Effect.gen(function* () { const tmp = yield* tmpdirScoped({ config: { shell: "fish" } })