diff --git a/packages/core/src/tool/plugin/shell.ts b/packages/core/src/tool/plugin/shell.ts index 87be4c9d165..7f7154a671c 100644 --- a/packages/core/src/tool/plugin/shell.ts +++ b/packages/core/src/tool/plugin/shell.ts @@ -207,6 +207,10 @@ export const Plugin = { }, (invocation) => Effect.gen(function* () { + invocation.env.AGENT = "1" + invocation.env.OPENCODE = "1" + invocation.env.AI_AGENT ||= "opencode" + invocation.env.OPENCODE_SESSION_ID = context.sessionID finalTimeout = yield* prepare(invocation, context) }), ) diff --git a/packages/core/test/tool-shell.test.ts b/packages/core/test/tool-shell.test.ts index 226c716b190..e706d9b0efd 100644 --- a/packages/core/test/tool-shell.test.ts +++ b/packages/core/test/tool-shell.test.ts @@ -956,6 +956,59 @@ describe("ShellTool", () => { { timeout: 15_000 }, ) + productionIt.live( + "identifies agent shell commands without inheriting a stale session ID", + () => + Effect.acquireUseRelease( + Effect.promise(() => tmpdir()), + (tmp) => { + reset() + return withSession(tmp.path, (registry) => + Effect.gen(function* () { + const sessions = yield* Session.Service + yield* sessions.environment({ + sessionID, + variables: { AGENT: "0", OPENCODE: "0", AI_AGENT: "", OPENCODE_SESSION_ID: "stale" }, + }) + const command = isWindows + ? '[Console]::Out.Write("$env:AGENT|$env:OPENCODE|$env:AI_AGENT|$env:OPENCODE_SESSION_ID")' + : 'printf %s "$AGENT|$OPENCODE|$AI_AGENT|$OPENCODE_SESSION_ID"' + const settled = yield* executeTool(registry, call({ command })) + + expect(settled.status).toBe("completed") + expect(settled.content?.[0]).toEqual({ type: "text", text: `1|1|opencode|${sessionID}` }) + }), + ) + }, + (tmp) => Effect.promise(() => tmp[Symbol.asyncDispose]().then(() => undefined)), + ), + { timeout: 15_000 }, + ) + + productionIt.live( + "preserves an outer AI_AGENT marker in agent shell commands", + () => + Effect.acquireUseRelease( + Effect.promise(() => tmpdir()), + (tmp) => { + reset() + return withSession(tmp.path, (registry) => + Effect.gen(function* () { + const sessions = yield* Session.Service + yield* sessions.environment({ sessionID, variables: { AI_AGENT: "outer-agent" } }) + const command = isWindows ? '[Console]::Out.Write($env:AI_AGENT)' : 'printf %s "$AI_AGENT"' + const settled = yield* executeTool(registry, call({ command })) + + expect(settled.status).toBe("completed") + expect(settled.content?.[0]).toEqual({ type: "text", text: "outer-agent" }) + }), + ) + }, + (tmp) => Effect.promise(() => tmp[Symbol.asyncDispose]().then(() => undefined)), + ), + { timeout: 15_000 }, + ) + it.live("resolves a relative workdir from the active Location", () => Effect.acquireUseRelease( Effect.promise(() => tmpdir()),