Exec/ACP: inject OPENCLAW_SHELL into child shell env (#31271)

* exec: mark runtime shell context in exec env

* tests(exec): cover OPENCLAW_SHELL in gateway exec

* tests(exec): cover OPENCLAW_SHELL in pty mode

* acpx: mark runtime shell context for spawned process

* tests(acpx): log OPENCLAW_SHELL in runtime fixture

* tests(acpx): assert OPENCLAW_SHELL in runtime prompt

* docs(env): document OPENCLAW_SHELL runtime markers

* docs(exec): describe OPENCLAW_SHELL exec marker

* docs(acp): document OPENCLAW_SHELL acp marker

* docs(gateway): note OPENCLAW_SHELL for background exec

* tui: tag local shell runs with OPENCLAW_SHELL

* tests(tui): assert OPENCLAW_SHELL in local shell runner

* acp client: tag spawned bridge env with OPENCLAW_SHELL

* tests(acp): cover acp client OPENCLAW_SHELL env helper

* docs(env): include acp-client and tui-local shell markers

* docs(acp): document acp-client OPENCLAW_SHELL marker

* docs(tui): document tui-local OPENCLAW_SHELL marker

* exec: keep shell runtime env string-only for docker args

* changelog: note OPENCLAW_SHELL runtime markers
This commit is contained in:
Vincent Koc
2026-03-01 20:31:06 -08:00
committed by GitHub
parent aeb817353f
commit b7615e0ce3
16 changed files with 145 additions and 7 deletions

View File

@@ -1,6 +1,6 @@
import type { RequestPermissionRequest } from "@agentclientprotocol/sdk";
import { describe, expect, it, vi } from "vitest";
import { resolvePermissionRequest } from "./client.js";
import { resolveAcpClientSpawnEnv, resolvePermissionRequest } from "./client.js";
import { extractAttachmentsFromPrompt, extractTextFromPrompt } from "./event-mapper.js";
function makePermissionRequest(
@@ -28,6 +28,26 @@ function makePermissionRequest(
};
}
describe("resolveAcpClientSpawnEnv", () => {
it("sets OPENCLAW_SHELL marker and preserves existing env values", () => {
const env = resolveAcpClientSpawnEnv({
PATH: "/usr/bin",
USER: "openclaw",
});
expect(env.OPENCLAW_SHELL).toBe("acp-client");
expect(env.PATH).toBe("/usr/bin");
expect(env.USER).toBe("openclaw");
});
it("overrides pre-existing OPENCLAW_SHELL to acp-client", () => {
const env = resolveAcpClientSpawnEnv({
OPENCLAW_SHELL: "wrong",
});
expect(env.OPENCLAW_SHELL).toBe("acp-client");
});
});
describe("resolvePermissionRequest", () => {
it("auto-approves safe tools without prompting", async () => {
const prompt = vi.fn(async () => true);

View File

@@ -342,6 +342,12 @@ function buildServerArgs(opts: AcpClientOptions): string[] {
return args;
}
export function resolveAcpClientSpawnEnv(
baseEnv: NodeJS.ProcessEnv = process.env,
): NodeJS.ProcessEnv {
return { ...baseEnv, OPENCLAW_SHELL: "acp-client" };
}
function resolveSelfEntryPath(): string | null {
// Prefer a path relative to the built module location (dist/acp/client.js -> dist/entry.js).
try {
@@ -413,6 +419,7 @@ export async function createAcpClient(opts: AcpClientOptions = {}): Promise<AcpC
const agent = spawn(serverCommand, effectiveArgs, {
stdio: ["pipe", "pipe", "inherit"],
cwd,
env: resolveAcpClientSpawnEnv(),
});
if (!agent.stdin || !agent.stdout) {