@openclaw/acpx 2026.5.2-beta.2 → 2026.5.3-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +14 -0
- package/dist/register.runtime.js +108 -0
- package/dist/runtime-B3LWev_t.js +357 -0
- package/dist/runtime-api.js +4 -0
- package/dist/service-YhcC786_.js +665 -0
- package/dist/setup-api.js +16 -0
- package/package.json +33 -3
- package/AGENTS.md +0 -54
- package/index.test.ts +0 -119
- package/index.ts +0 -19
- package/register.runtime.ts +0 -154
- package/runtime-api.ts +0 -46
- package/setup-api.ts +0 -18
- package/src/acpx-runtime-compat.d.ts +0 -62
- package/src/claude-agent-acp-completion.test.ts +0 -129
- package/src/codex-auth-bridge.test.ts +0 -448
- package/src/codex-auth-bridge.ts +0 -385
- package/src/config-schema.ts +0 -117
- package/src/config.test.ts +0 -144
- package/src/config.ts +0 -273
- package/src/manifest.test.ts +0 -20
- package/src/runtime-internals/mcp-command-line.test.ts +0 -59
- package/src/runtime-internals/mcp-proxy.test.ts +0 -114
- package/src/runtime.test.ts +0 -816
- package/src/runtime.ts +0 -613
- package/src/service.test.ts +0 -401
- package/src/service.ts +0 -278
- package/tsconfig.json +0 -16
- /package/{src/runtime-internals → dist}/error-format.mjs +0 -0
- /package/{src/runtime-internals → dist}/mcp-command-line.mjs +0 -0
- /package/{src/runtime-internals → dist}/mcp-proxy.mjs +0 -0
|
@@ -1,448 +0,0 @@
|
|
|
1
|
-
import { execFile } from "node:child_process";
|
|
2
|
-
import fs from "node:fs/promises";
|
|
3
|
-
import os from "node:os";
|
|
4
|
-
import path from "node:path";
|
|
5
|
-
import { promisify } from "node:util";
|
|
6
|
-
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
7
|
-
import { prepareAcpxCodexAuthConfig } from "./codex-auth-bridge.js";
|
|
8
|
-
import { resolveAcpxPluginConfig } from "./config.js";
|
|
9
|
-
|
|
10
|
-
const execFileAsync = promisify(execFile);
|
|
11
|
-
const tempDirs: string[] = [];
|
|
12
|
-
const previousEnv = {
|
|
13
|
-
CODEX_HOME: process.env.CODEX_HOME,
|
|
14
|
-
OPENCLAW_AGENT_DIR: process.env.OPENCLAW_AGENT_DIR,
|
|
15
|
-
PI_CODING_AGENT_DIR: process.env.PI_CODING_AGENT_DIR,
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
async function makeTempDir(): Promise<string> {
|
|
19
|
-
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-acpx-codex-auth-"));
|
|
20
|
-
tempDirs.push(dir);
|
|
21
|
-
return dir;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function quoteArg(value: string): string {
|
|
25
|
-
return JSON.stringify(value);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function restoreEnv(name: keyof typeof previousEnv): void {
|
|
29
|
-
const value = previousEnv[name];
|
|
30
|
-
if (value === undefined) {
|
|
31
|
-
delete process.env[name];
|
|
32
|
-
} else {
|
|
33
|
-
process.env[name] = value;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function generatedCodexPaths(stateDir: string): {
|
|
38
|
-
configPath: string;
|
|
39
|
-
wrapperPath: string;
|
|
40
|
-
} {
|
|
41
|
-
const baseDir = path.join(stateDir, "acpx");
|
|
42
|
-
const codexHome = path.join(baseDir, "codex-home");
|
|
43
|
-
return {
|
|
44
|
-
configPath: path.join(codexHome, "config.toml"),
|
|
45
|
-
wrapperPath: path.join(baseDir, "codex-acp-wrapper.mjs"),
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function generatedClaudePaths(stateDir: string): {
|
|
50
|
-
wrapperPath: string;
|
|
51
|
-
} {
|
|
52
|
-
const baseDir = path.join(stateDir, "acpx");
|
|
53
|
-
return {
|
|
54
|
-
wrapperPath: path.join(baseDir, "claude-agent-acp-wrapper.mjs"),
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function expectCodexWrapperCommand(command: string | undefined, wrapperPath: string): void {
|
|
59
|
-
expect(command).toContain(process.execPath);
|
|
60
|
-
expect(command).toContain(wrapperPath);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
function expectClaudeWrapperCommand(command: string | undefined, wrapperPath: string): void {
|
|
64
|
-
expect(command).toContain(process.execPath);
|
|
65
|
-
expect(command).toContain(wrapperPath);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
afterEach(async () => {
|
|
69
|
-
vi.restoreAllMocks();
|
|
70
|
-
restoreEnv("CODEX_HOME");
|
|
71
|
-
restoreEnv("OPENCLAW_AGENT_DIR");
|
|
72
|
-
restoreEnv("PI_CODING_AGENT_DIR");
|
|
73
|
-
for (const dir of tempDirs.splice(0)) {
|
|
74
|
-
await fs.rm(dir, { recursive: true, force: true });
|
|
75
|
-
}
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
describe("prepareAcpxCodexAuthConfig", () => {
|
|
79
|
-
it("installs an isolated Codex ACP wrapper without synthesizing auth from canonical OpenClaw OAuth", async () => {
|
|
80
|
-
const root = await makeTempDir();
|
|
81
|
-
const agentDir = path.join(root, "agent");
|
|
82
|
-
const stateDir = path.join(root, "state");
|
|
83
|
-
const generated = generatedCodexPaths(stateDir);
|
|
84
|
-
const generatedClaude = generatedClaudePaths(stateDir);
|
|
85
|
-
const installedBinPath = path.join(
|
|
86
|
-
root,
|
|
87
|
-
"node_modules",
|
|
88
|
-
"@zed-industries",
|
|
89
|
-
"codex-acp",
|
|
90
|
-
"bin",
|
|
91
|
-
"codex-acp.js",
|
|
92
|
-
);
|
|
93
|
-
process.env.OPENCLAW_AGENT_DIR = agentDir;
|
|
94
|
-
delete process.env.PI_CODING_AGENT_DIR;
|
|
95
|
-
|
|
96
|
-
const pluginConfig = resolveAcpxPluginConfig({
|
|
97
|
-
rawConfig: {},
|
|
98
|
-
workspaceDir: root,
|
|
99
|
-
});
|
|
100
|
-
const resolved = await prepareAcpxCodexAuthConfig({
|
|
101
|
-
pluginConfig,
|
|
102
|
-
stateDir,
|
|
103
|
-
resolveInstalledCodexAcpBinPath: async () => installedBinPath,
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
expectCodexWrapperCommand(resolved.agents.codex, generated.wrapperPath);
|
|
107
|
-
expectClaudeWrapperCommand(resolved.agents.claude, generatedClaude.wrapperPath);
|
|
108
|
-
await expect(fs.access(generated.wrapperPath)).resolves.toBeUndefined();
|
|
109
|
-
await expect(fs.access(generatedClaude.wrapperPath)).resolves.toBeUndefined();
|
|
110
|
-
const wrapper = await fs.readFile(generated.wrapperPath, "utf8");
|
|
111
|
-
expect(wrapper).toContain(JSON.stringify(installedBinPath));
|
|
112
|
-
expect(wrapper).toContain("defaultArgs = [installedBinPath]");
|
|
113
|
-
await expect(
|
|
114
|
-
fs.access(path.join(agentDir, "acp-auth", "codex", "auth.json")),
|
|
115
|
-
).rejects.toMatchObject({ code: "ENOENT" });
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
it("keeps generated wrappers usable when chmod is rejected by the state filesystem", async () => {
|
|
119
|
-
const root = await makeTempDir();
|
|
120
|
-
const stateDir = path.join(root, "state");
|
|
121
|
-
const generatedCodex = generatedCodexPaths(stateDir);
|
|
122
|
-
const generatedClaude = generatedClaudePaths(stateDir);
|
|
123
|
-
const chmodError = Object.assign(new Error("operation not permitted"), { code: "EPERM" });
|
|
124
|
-
const chmodSpy = vi.spyOn(fs, "chmod").mockRejectedValue(chmodError);
|
|
125
|
-
const pluginConfig = resolveAcpxPluginConfig({
|
|
126
|
-
rawConfig: {},
|
|
127
|
-
workspaceDir: root,
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
const resolved = await prepareAcpxCodexAuthConfig({
|
|
131
|
-
pluginConfig,
|
|
132
|
-
stateDir,
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
expect(chmodSpy).toHaveBeenCalledWith(generatedCodex.wrapperPath, 0o755);
|
|
136
|
-
expect(chmodSpy).toHaveBeenCalledWith(generatedClaude.wrapperPath, 0o755);
|
|
137
|
-
expectCodexWrapperCommand(resolved.agents.codex, generatedCodex.wrapperPath);
|
|
138
|
-
expectClaudeWrapperCommand(resolved.agents.claude, generatedClaude.wrapperPath);
|
|
139
|
-
await expect(fs.access(generatedCodex.wrapperPath)).resolves.toBeUndefined();
|
|
140
|
-
await expect(fs.access(generatedClaude.wrapperPath)).resolves.toBeUndefined();
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
it("falls back to the current Codex ACP package range when the local adapter is unavailable", async () => {
|
|
144
|
-
const root = await makeTempDir();
|
|
145
|
-
const stateDir = path.join(root, "state");
|
|
146
|
-
const generated = generatedCodexPaths(stateDir);
|
|
147
|
-
const pluginConfig = resolveAcpxPluginConfig({
|
|
148
|
-
rawConfig: {},
|
|
149
|
-
workspaceDir: root,
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
await prepareAcpxCodexAuthConfig({
|
|
153
|
-
pluginConfig,
|
|
154
|
-
stateDir,
|
|
155
|
-
resolveInstalledCodexAcpBinPath: async () => undefined,
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
const wrapper = await fs.readFile(generated.wrapperPath, "utf8");
|
|
159
|
-
expect(wrapper).toContain('"@zed-industries/codex-acp@^0.12.0"');
|
|
160
|
-
expect(wrapper).toContain('"--", "codex-acp"');
|
|
161
|
-
expect(wrapper).not.toContain("@zed-industries/codex-acp@^0.11.1");
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
it("falls back to the patched Claude ACP package when the local adapter is unavailable", async () => {
|
|
165
|
-
const root = await makeTempDir();
|
|
166
|
-
const stateDir = path.join(root, "state");
|
|
167
|
-
const generated = generatedClaudePaths(stateDir);
|
|
168
|
-
const pluginConfig = resolveAcpxPluginConfig({
|
|
169
|
-
rawConfig: {},
|
|
170
|
-
workspaceDir: root,
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
await prepareAcpxCodexAuthConfig({
|
|
174
|
-
pluginConfig,
|
|
175
|
-
stateDir,
|
|
176
|
-
resolveInstalledClaudeAcpBinPath: async () => undefined,
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
const wrapper = await fs.readFile(generated.wrapperPath, "utf8");
|
|
180
|
-
expect(wrapper).toContain('"@agentclientprotocol/claude-agent-acp@0.31.4"');
|
|
181
|
-
expect(wrapper).toContain('"--", "claude-agent-acp"');
|
|
182
|
-
expect(wrapper).not.toContain("@agentclientprotocol/claude-agent-acp@^0.31.0");
|
|
183
|
-
expect(wrapper).not.toContain("@agentclientprotocol/claude-agent-acp@0.31.0");
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
it("uses the bundled Codex ACP dependency by default when it is installed", async () => {
|
|
187
|
-
const root = await makeTempDir();
|
|
188
|
-
const stateDir = path.join(root, "state");
|
|
189
|
-
const generated = generatedCodexPaths(stateDir);
|
|
190
|
-
const pluginConfig = resolveAcpxPluginConfig({
|
|
191
|
-
rawConfig: {},
|
|
192
|
-
workspaceDir: root,
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
await prepareAcpxCodexAuthConfig({
|
|
196
|
-
pluginConfig,
|
|
197
|
-
stateDir,
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
const wrapper = await fs.readFile(generated.wrapperPath, "utf8");
|
|
201
|
-
expect(wrapper).toContain("@zed-industries/codex-acp");
|
|
202
|
-
expect(wrapper).toContain("bin/codex-acp.js");
|
|
203
|
-
expect(wrapper).toContain("defaultArgs = [installedBinPath]");
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
it("uses the bundled Claude ACP dependency by default when it is installed", async () => {
|
|
207
|
-
const root = await makeTempDir();
|
|
208
|
-
const stateDir = path.join(root, "state");
|
|
209
|
-
const generated = generatedClaudePaths(stateDir);
|
|
210
|
-
const pluginConfig = resolveAcpxPluginConfig({
|
|
211
|
-
rawConfig: {},
|
|
212
|
-
workspaceDir: root,
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
await prepareAcpxCodexAuthConfig({
|
|
216
|
-
pluginConfig,
|
|
217
|
-
stateDir,
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
const wrapper = await fs.readFile(generated.wrapperPath, "utf8");
|
|
221
|
-
expect(wrapper).toContain("@agentclientprotocol/claude-agent-acp");
|
|
222
|
-
expect(wrapper).toContain("dist/index.js");
|
|
223
|
-
expect(wrapper).toContain("defaultArgs = [installedBinPath]");
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
it("launches the locally installed Codex ACP bin with isolated CODEX_HOME", async () => {
|
|
227
|
-
const root = await makeTempDir();
|
|
228
|
-
const stateDir = path.join(root, "state");
|
|
229
|
-
const generated = generatedCodexPaths(stateDir);
|
|
230
|
-
const installedBinPath = path.join(root, "codex-acp-bin.js");
|
|
231
|
-
await fs.writeFile(
|
|
232
|
-
installedBinPath,
|
|
233
|
-
"console.log(JSON.stringify({ argv: process.argv.slice(2), codexHome: process.env.CODEX_HOME }));\n",
|
|
234
|
-
"utf8",
|
|
235
|
-
);
|
|
236
|
-
const pluginConfig = resolveAcpxPluginConfig({
|
|
237
|
-
rawConfig: {},
|
|
238
|
-
workspaceDir: root,
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
await prepareAcpxCodexAuthConfig({
|
|
242
|
-
pluginConfig,
|
|
243
|
-
stateDir,
|
|
244
|
-
resolveInstalledCodexAcpBinPath: async () => installedBinPath,
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
const { stdout } = await execFileAsync(process.execPath, [generated.wrapperPath], {
|
|
248
|
-
cwd: root,
|
|
249
|
-
});
|
|
250
|
-
const launched = JSON.parse(stdout.trim()) as { argv?: unknown; codexHome?: unknown };
|
|
251
|
-
expect(launched.argv).toEqual([]);
|
|
252
|
-
const expectedCodexHome = await fs.realpath(path.join(stateDir, "acpx", "codex-home"));
|
|
253
|
-
expect(path.resolve(String(launched.codexHome))).toBe(expectedCodexHome);
|
|
254
|
-
});
|
|
255
|
-
|
|
256
|
-
it("launches the locally installed Claude ACP bin without going through npm", async () => {
|
|
257
|
-
const root = await makeTempDir();
|
|
258
|
-
const stateDir = path.join(root, "state");
|
|
259
|
-
const generated = generatedClaudePaths(stateDir);
|
|
260
|
-
const installedBinPath = path.join(root, "claude-agent-acp-bin.js");
|
|
261
|
-
await fs.writeFile(
|
|
262
|
-
installedBinPath,
|
|
263
|
-
"console.log(JSON.stringify({ argv: process.argv.slice(2), codexHome: process.env.CODEX_HOME ?? null }));\n",
|
|
264
|
-
"utf8",
|
|
265
|
-
);
|
|
266
|
-
const pluginConfig = resolveAcpxPluginConfig({
|
|
267
|
-
rawConfig: {},
|
|
268
|
-
workspaceDir: root,
|
|
269
|
-
});
|
|
270
|
-
|
|
271
|
-
await prepareAcpxCodexAuthConfig({
|
|
272
|
-
pluginConfig,
|
|
273
|
-
stateDir,
|
|
274
|
-
resolveInstalledClaudeAcpBinPath: async () => installedBinPath,
|
|
275
|
-
});
|
|
276
|
-
|
|
277
|
-
const { stdout } = await execFileAsync(
|
|
278
|
-
process.execPath,
|
|
279
|
-
[generated.wrapperPath, "--permission-mode", "bypass"],
|
|
280
|
-
{
|
|
281
|
-
cwd: root,
|
|
282
|
-
},
|
|
283
|
-
);
|
|
284
|
-
const launched = JSON.parse(stdout.trim()) as { argv?: unknown; codexHome?: unknown };
|
|
285
|
-
expect(launched.argv).toEqual(["--permission-mode", "bypass"]);
|
|
286
|
-
expect(launched.codexHome).toBeNull();
|
|
287
|
-
});
|
|
288
|
-
|
|
289
|
-
it("does not copy source Codex auth", async () => {
|
|
290
|
-
const root = await makeTempDir();
|
|
291
|
-
const sourceCodexHome = path.join(root, "source-codex");
|
|
292
|
-
const agentDir = path.join(root, "agent");
|
|
293
|
-
const stateDir = path.join(root, "state");
|
|
294
|
-
const generated = generatedCodexPaths(stateDir);
|
|
295
|
-
await fs.mkdir(sourceCodexHome, { recursive: true });
|
|
296
|
-
await fs.writeFile(
|
|
297
|
-
path.join(sourceCodexHome, "auth.json"),
|
|
298
|
-
`${JSON.stringify({ auth_mode: "apikey", OPENAI_API_KEY: "test-api-key" }, null, 2)}\n`,
|
|
299
|
-
);
|
|
300
|
-
await fs.writeFile(
|
|
301
|
-
path.join(sourceCodexHome, "config.toml"),
|
|
302
|
-
'notify = ["SkyComputerUseClient", "turn-ended"]\n',
|
|
303
|
-
);
|
|
304
|
-
process.env.CODEX_HOME = sourceCodexHome;
|
|
305
|
-
process.env.OPENCLAW_AGENT_DIR = agentDir;
|
|
306
|
-
delete process.env.PI_CODING_AGENT_DIR;
|
|
307
|
-
|
|
308
|
-
const pluginConfig = resolveAcpxPluginConfig({
|
|
309
|
-
rawConfig: {},
|
|
310
|
-
workspaceDir: root,
|
|
311
|
-
});
|
|
312
|
-
const resolved = await prepareAcpxCodexAuthConfig({
|
|
313
|
-
pluginConfig,
|
|
314
|
-
stateDir,
|
|
315
|
-
resolveInstalledCodexAcpBinPath: async () => undefined,
|
|
316
|
-
});
|
|
317
|
-
|
|
318
|
-
expectCodexWrapperCommand(resolved.agents.codex, generated.wrapperPath);
|
|
319
|
-
const isolatedConfig = await fs.readFile(generated.configPath, "utf8");
|
|
320
|
-
expect(isolatedConfig).not.toContain("notify");
|
|
321
|
-
expect(isolatedConfig).not.toContain("SkyComputerUseClient");
|
|
322
|
-
const wrapper = await fs.readFile(generated.wrapperPath, "utf8");
|
|
323
|
-
expect(wrapper).toContain("CODEX_HOME: codexHome");
|
|
324
|
-
expect(wrapper).not.toContain(sourceCodexHome);
|
|
325
|
-
await expect(
|
|
326
|
-
fs.access(path.join(agentDir, "acp-auth", "codex-source", "auth.json")),
|
|
327
|
-
).rejects.toMatchObject({ code: "ENOENT" });
|
|
328
|
-
await expect(
|
|
329
|
-
fs.access(path.join(agentDir, "acp-auth", "codex", "auth.json")),
|
|
330
|
-
).rejects.toMatchObject({ code: "ENOENT" });
|
|
331
|
-
});
|
|
332
|
-
|
|
333
|
-
it("normalizes an explicitly configured Codex ACP command to the local wrapper", async () => {
|
|
334
|
-
const root = await makeTempDir();
|
|
335
|
-
const sourceCodexHome = path.join(root, "source-codex");
|
|
336
|
-
const stateDir = path.join(root, "state");
|
|
337
|
-
const generated = generatedCodexPaths(stateDir);
|
|
338
|
-
await fs.mkdir(sourceCodexHome, { recursive: true });
|
|
339
|
-
await fs.writeFile(
|
|
340
|
-
path.join(sourceCodexHome, "config.toml"),
|
|
341
|
-
'notify = ["SkyComputerUseClient", "turn-ended"]\n',
|
|
342
|
-
);
|
|
343
|
-
process.env.CODEX_HOME = sourceCodexHome;
|
|
344
|
-
const pluginConfig = resolveAcpxPluginConfig({
|
|
345
|
-
rawConfig: {
|
|
346
|
-
agents: {
|
|
347
|
-
codex: {
|
|
348
|
-
command: "npx @zed-industries/codex-acp@0.12.0 -c 'model=\"gpt-5.4\"'",
|
|
349
|
-
},
|
|
350
|
-
},
|
|
351
|
-
},
|
|
352
|
-
workspaceDir: root,
|
|
353
|
-
});
|
|
354
|
-
|
|
355
|
-
const resolved = await prepareAcpxCodexAuthConfig({
|
|
356
|
-
pluginConfig,
|
|
357
|
-
stateDir,
|
|
358
|
-
resolveInstalledCodexAcpBinPath: async () => path.join(root, "codex-acp.js"),
|
|
359
|
-
});
|
|
360
|
-
|
|
361
|
-
expectCodexWrapperCommand(resolved.agents.codex, generated.wrapperPath);
|
|
362
|
-
expect(resolved.agents.codex).not.toContain("npx @zed-industries/codex-acp@0.12.0");
|
|
363
|
-
expect(resolved.agents.codex).toContain(quoteArg("-c"));
|
|
364
|
-
expect(resolved.agents.codex).toContain(quoteArg('model="gpt-5.4"'));
|
|
365
|
-
const isolatedConfig = await fs.readFile(generated.configPath, "utf8");
|
|
366
|
-
expect(isolatedConfig).not.toContain("notify");
|
|
367
|
-
expect(isolatedConfig).not.toContain("SkyComputerUseClient");
|
|
368
|
-
const wrapper = await fs.readFile(generated.wrapperPath, "utf8");
|
|
369
|
-
expect(wrapper).toContain("process.argv.slice(2)");
|
|
370
|
-
expect(wrapper).toContain("CODEX_HOME: codexHome");
|
|
371
|
-
expect(wrapper).not.toContain(sourceCodexHome);
|
|
372
|
-
});
|
|
373
|
-
|
|
374
|
-
it("normalizes an explicitly configured Claude ACP npx command to the local wrapper", async () => {
|
|
375
|
-
const root = await makeTempDir();
|
|
376
|
-
const stateDir = path.join(root, "state");
|
|
377
|
-
const generated = generatedClaudePaths(stateDir);
|
|
378
|
-
const pluginConfig = resolveAcpxPluginConfig({
|
|
379
|
-
rawConfig: {
|
|
380
|
-
agents: {
|
|
381
|
-
claude: {
|
|
382
|
-
command: "npx -y @agentclientprotocol/claude-agent-acp@0.31.4 --permission-mode bypass",
|
|
383
|
-
},
|
|
384
|
-
},
|
|
385
|
-
},
|
|
386
|
-
workspaceDir: root,
|
|
387
|
-
});
|
|
388
|
-
|
|
389
|
-
const resolved = await prepareAcpxCodexAuthConfig({
|
|
390
|
-
pluginConfig,
|
|
391
|
-
stateDir,
|
|
392
|
-
resolveInstalledClaudeAcpBinPath: async () => path.join(root, "claude-agent-acp.js"),
|
|
393
|
-
});
|
|
394
|
-
|
|
395
|
-
expectClaudeWrapperCommand(resolved.agents.claude, generated.wrapperPath);
|
|
396
|
-
expect(resolved.agents.claude).not.toContain("npx -y @agentclientprotocol/claude-agent-acp");
|
|
397
|
-
expect(resolved.agents.claude).toContain("--permission-mode");
|
|
398
|
-
expect(resolved.agents.claude).toContain("bypass");
|
|
399
|
-
});
|
|
400
|
-
|
|
401
|
-
it("leaves a custom Claude agent command alone", async () => {
|
|
402
|
-
const root = await makeTempDir();
|
|
403
|
-
const stateDir = path.join(root, "state");
|
|
404
|
-
const pluginConfig = resolveAcpxPluginConfig({
|
|
405
|
-
rawConfig: {
|
|
406
|
-
agents: {
|
|
407
|
-
claude: {
|
|
408
|
-
command: "node ./custom-claude-wrapper.mjs --flag",
|
|
409
|
-
},
|
|
410
|
-
},
|
|
411
|
-
},
|
|
412
|
-
workspaceDir: root,
|
|
413
|
-
});
|
|
414
|
-
|
|
415
|
-
const resolved = await prepareAcpxCodexAuthConfig({
|
|
416
|
-
pluginConfig,
|
|
417
|
-
stateDir,
|
|
418
|
-
resolveInstalledClaudeAcpBinPath: async () => path.join(root, "claude-agent-acp.js"),
|
|
419
|
-
});
|
|
420
|
-
|
|
421
|
-
expect(resolved.agents.claude).toBe("node ./custom-claude-wrapper.mjs --flag");
|
|
422
|
-
});
|
|
423
|
-
|
|
424
|
-
it("does not normalize custom Claude commands that only mention the package name", async () => {
|
|
425
|
-
const root = await makeTempDir();
|
|
426
|
-
const stateDir = path.join(root, "state");
|
|
427
|
-
const command =
|
|
428
|
-
"node ./custom-claude-wrapper.mjs @agentclientprotocol/claude-agent-acp@0.31.4 --flag";
|
|
429
|
-
const pluginConfig = resolveAcpxPluginConfig({
|
|
430
|
-
rawConfig: {
|
|
431
|
-
agents: {
|
|
432
|
-
claude: {
|
|
433
|
-
command,
|
|
434
|
-
},
|
|
435
|
-
},
|
|
436
|
-
},
|
|
437
|
-
workspaceDir: root,
|
|
438
|
-
});
|
|
439
|
-
|
|
440
|
-
const resolved = await prepareAcpxCodexAuthConfig({
|
|
441
|
-
pluginConfig,
|
|
442
|
-
stateDir,
|
|
443
|
-
resolveInstalledClaudeAcpBinPath: async () => path.join(root, "claude-agent-acp.js"),
|
|
444
|
-
});
|
|
445
|
-
|
|
446
|
-
expect(resolved.agents.claude).toBe(command);
|
|
447
|
-
});
|
|
448
|
-
});
|