




















@@ -27,6 +27,23 @@ function restoreEnv(name: keyof typeof previousEnv): void {
2727}
2828}
292930+function generatedCodexPaths(stateDir: string): {
31+configPath: string;
32+wrapperPath: string;
33+} {
34+const baseDir = path.join(stateDir, "acpx");
35+const codexHome = path.join(baseDir, "codex-home");
36+return {
37+configPath: path.join(codexHome, "config.toml"),
38+wrapperPath: path.join(baseDir, "codex-acp-wrapper.mjs"),
39+};
40+}
41+42+function expectCodexWrapperCommand(command: string | undefined, wrapperPath: string): void {
43+expect(command).toContain(process.execPath);
44+expect(command).toContain(wrapperPath);
45+}
46+3047afterEach(async () => {
3148restoreEnv("CODEX_HOME");
3249restoreEnv("OPENCLAW_AGENT_DIR");
@@ -37,10 +54,11 @@ afterEach(async () => {
3754});
38553956describe("prepareAcpxCodexAuthConfig", () => {
40-it("does not synthesize a Codex ACP auth home from canonical OpenClaw OAuth", async () => {
57+it("installs an isolated Codex ACP wrapper without synthesizing auth from canonical OpenClaw OAuth", async () => {
4158const root = await makeTempDir();
4259const agentDir = path.join(root, "agent");
4360const stateDir = path.join(root, "state");
61+const generated = generatedCodexPaths(stateDir);
4462process.env.OPENCLAW_AGENT_DIR = agentDir;
4563delete process.env.PI_CODING_AGENT_DIR;
4664@@ -53,10 +71,10 @@ describe("prepareAcpxCodexAuthConfig", () => {
5371 stateDir,
5472});
557356-expect(resolved.agents.codex).toBeUndefined();
57-await expect(
58- fs.access(path.join(stateDir, "acpx", "codex-acp-wrapper.mjs")),
59-).rejects.toMatchObject({ code: "ENOENT" });
74+expectCodexWrapperCommand(resolved.agents.codex, generated.wrapperPath);
75+await expect(fs.access(generated.wrapperPath)).resolves.toBeUndefined();
76+const wrapper = await fs.readFile(generated.wrapperPath, "utf8");
77+expect(wrapper).toContain('"--", "codex-acp"');
6078await expect(
6179fs.access(path.join(agentDir, "acp-auth", "codex", "auth.json")),
6280).rejects.toMatchObject({ code: "ENOENT" });
@@ -66,11 +84,17 @@ describe("prepareAcpxCodexAuthConfig", () => {
6684const root = await makeTempDir();
6785const sourceCodexHome = path.join(root, "source-codex");
6886const agentDir = path.join(root, "agent");
87+const stateDir = path.join(root, "state");
88+const generated = generatedCodexPaths(stateDir);
6989await fs.mkdir(sourceCodexHome, { recursive: true });
7090await fs.writeFile(
7191path.join(sourceCodexHome, "auth.json"),
7292`${JSON.stringify({ auth_mode: "apikey", OPENAI_API_KEY: "test-api-key" }, null, 2)}\n`,
7393);
94+await fs.writeFile(
95+path.join(sourceCodexHome, "config.toml"),
96+'notify = ["SkyComputerUseClient", "turn-ended"]\n',
97+);
7498process.env.CODEX_HOME = sourceCodexHome;
7599process.env.OPENCLAW_AGENT_DIR = agentDir;
76100delete process.env.PI_CODING_AGENT_DIR;
@@ -81,10 +105,16 @@ describe("prepareAcpxCodexAuthConfig", () => {
81105});
82106const resolved = await prepareAcpxCodexAuthConfig({
83107 pluginConfig,
84-stateDir: path.join(root, "state"),
108+ stateDir,
85109});
8611087-expect(resolved.agents.codex).toBeUndefined();
111+expectCodexWrapperCommand(resolved.agents.codex, generated.wrapperPath);
112+const isolatedConfig = await fs.readFile(generated.configPath, "utf8");
113+expect(isolatedConfig).not.toContain("notify");
114+expect(isolatedConfig).not.toContain("SkyComputerUseClient");
115+const wrapper = await fs.readFile(generated.wrapperPath, "utf8");
116+expect(wrapper).toContain("CODEX_HOME: codexHome");
117+expect(wrapper).not.toContain(sourceCodexHome);
88118await expect(
89119fs.access(path.join(agentDir, "acp-auth", "codex-source", "auth.json")),
90120).rejects.toMatchObject({ code: "ENOENT" });
@@ -93,13 +123,22 @@ describe("prepareAcpxCodexAuthConfig", () => {
93123).rejects.toMatchObject({ code: "ENOENT" });
94124});
9512596-it("does not override an explicitly configured Codex agent command", async () => {
126+it("wraps an explicitly configured Codex agent command with isolated CODEX_HOME", async () => {
97127const root = await makeTempDir();
128+const sourceCodexHome = path.join(root, "source-codex");
129+const stateDir = path.join(root, "state");
130+const generated = generatedCodexPaths(stateDir);
131+await fs.mkdir(sourceCodexHome, { recursive: true });
132+await fs.writeFile(
133+path.join(sourceCodexHome, "config.toml"),
134+'notify = ["SkyComputerUseClient", "turn-ended"]\n',
135+);
136+process.env.CODEX_HOME = sourceCodexHome;
98137const pluginConfig = resolveAcpxPluginConfig({
99138rawConfig: {
100139agents: {
101140codex: {
102-command: "custom-codex-acp",
141+command: "npx @zed-industries/codex-acp@^0.11.1 -c 'model=\"gpt-5.4\"'",
103142},
104143},
105144},
@@ -108,9 +147,18 @@ describe("prepareAcpxCodexAuthConfig", () => {
108147109148const resolved = await prepareAcpxCodexAuthConfig({
110149 pluginConfig,
111-stateDir: path.join(root, "state"),
150+ stateDir,
112151});
113152114-expect(resolved.agents.codex).toBe("custom-codex-acp");
153+expectCodexWrapperCommand(resolved.agents.codex, generated.wrapperPath);
154+expect(resolved.agents.codex).toContain("npx @zed-industries/codex-acp@^0.11.1");
155+expect(resolved.agents.codex).toContain("-c 'model=\"gpt-5.4\"'");
156+const isolatedConfig = await fs.readFile(generated.configPath, "utf8");
157+expect(isolatedConfig).not.toContain("notify");
158+expect(isolatedConfig).not.toContain("SkyComputerUseClient");
159+const wrapper = await fs.readFile(generated.wrapperPath, "utf8");
160+expect(wrapper).toContain("process.argv.slice(2)");
161+expect(wrapper).toContain("CODEX_HOME: codexHome");
162+expect(wrapper).not.toContain(sourceCodexHome);
115163});
116164});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。