From 576b660d3837e5dc50555cb0e58d3bac00e11e07 Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Fri, 10 Jul 2026 00:51:24 +0000 Subject: [PATCH] fix(core): mark user processes as opencode agents --- packages/core/src/pty.ts | 2 ++ packages/core/src/shell.ts | 2 ++ packages/core/test/pty/pty-session.test.ts | 8 +++++++ packages/core/test/tool-shell.test.ts | 26 ++++++++++++++++++++++ 4 files changed, 38 insertions(+) diff --git a/packages/core/src/pty.ts b/packages/core/src/pty.ts index 4111aaa31a..13a73ffbed 100644 --- a/packages/core/src/pty.ts +++ b/packages/core/src/pty.ts @@ -170,6 +170,8 @@ const layer = Layer.effect( const env = { ...process.env, ...input.env, + AGENT: "1", + OPENCODE: "1", TERM: "xterm-256color", OPENCODE_TERMINAL: "1", } as Record diff --git a/packages/core/src/shell.ts b/packages/core/src/shell.ts index a62fef8107..36210d910d 100644 --- a/packages/core/src/shell.ts +++ b/packages/core/src/shell.ts @@ -173,6 +173,8 @@ export const layer = Layer.effect( const file = path.join(outputDir, `${id}.out`) const env = { ...process.env, + AGENT: "1", + OPENCODE: "1", TERM: "xterm-256color", OPENCODE_TERMINAL: "1", } as Record diff --git a/packages/core/test/pty/pty-session.test.ts b/packages/core/test/pty/pty-session.test.ts index 6d049b49ae..0744c2e031 100644 --- a/packages/core/test/pty/pty-session.test.ts +++ b/packages/core/test/pty/pty-session.test.ts @@ -153,6 +153,14 @@ describe("pty", () => { }), ) + ptyTest("marks terminal sessions as running under opencode", () => + Effect.gen(function* () { + const info = yield* createPty("sh", ["-c", 'printf "%s|%s" "$AGENT" "$OPENCODE"; sleep 1']) + const attached = yield* attachCollecting(info.id) + expect(yield* waitForOutput(attached.output, "1|1")).toContain("1|1") + }), + ) + ptyTest("stops delivering output after detach", () => Effect.gen(function* () { const pty = yield* Pty.Service diff --git a/packages/core/test/tool-shell.test.ts b/packages/core/test/tool-shell.test.ts index 6a6a53e171..ccf43347d9 100644 --- a/packages/core/test/tool-shell.test.ts +++ b/packages/core/test/tool-shell.test.ts @@ -162,6 +162,9 @@ const idleCommand = isWindows ? "Start-Sleep -Seconds 60" : "sleep 60" const bodyExitCommand = isWindows ? "[Console]::Out.Write('body'); Start-Sleep -Milliseconds 100; exit 7" : "printf body && exit 7" +const agentEnvCommand = isWindows + ? '[Console]::Out.Write("$env:AGENT|$env:OPENCODE"); Start-Sleep -Milliseconds 100' + : 'printf "%s|%s" "$AGENT" "$OPENCODE"' const overflowCommand = (bytes: number) => isWindows ? `[Console]::Out.Write(('x' * ${bytes})); Start-Sleep -Milliseconds 100` @@ -265,6 +268,29 @@ describe("ShellTool", () => { ), ) + it.live("marks shell commands as running under opencode", () => + Effect.acquireUseRelease( + Effect.promise(() => tmpdir()), + (tmp) => { + reset() + return withSession(tmp.path, (registry) => + settleTool(registry, call({ command: agentEnvCommand }, "call-agent-env")), + ).pipe( + Effect.andThen((settled) => + Effect.sync(() => { + expect(settled.output?.structured).toMatchObject({ exit: 0, truncated: false }) + const output = settled.output?.content[0]?.type === "text" ? settled.output.content[0].text : "" + const parts = output.split("|") + expect(parts[0]).toBe("1") + expect(parts[1]).toBe("1") + }), + ), + ) + }, + (tmp) => Effect.promise(() => tmp[Symbol.asyncDispose]().then(() => undefined)), + ), + ) + it.live("rejects a workdir that stops being a directory during approval", () => Effect.acquireUseRelease( Effect.promise(() => tmpdir()),