Compare commits

...

1 Commits

Author SHA1 Message Date
Aiden Cline 576b660d38 fix(core): mark user processes as opencode agents 2026-07-10 00:57:25 +00:00
4 changed files with 38 additions and 0 deletions
+2
View File
@@ -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<string, string>
+2
View File
@@ -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<string, string>
@@ -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
+26
View File
@@ -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()),