@openclaw/acpx 2026.5.4-beta.1 → 2026.5.4-beta.3
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/register.runtime.js
CHANGED
|
@@ -4,7 +4,7 @@ const ACPX_BACKEND_ID = "acpx";
|
|
|
4
4
|
const ENABLE_STARTUP_PROBE_ENV = "OPENCLAW_ACPX_RUNTIME_STARTUP_PROBE";
|
|
5
5
|
let serviceModulePromise = null;
|
|
6
6
|
function loadServiceModule() {
|
|
7
|
-
serviceModulePromise ??= import("./service-
|
|
7
|
+
serviceModulePromise ??= import("./service-DXpBsJTq.js");
|
|
8
8
|
return serviceModulePromise;
|
|
9
9
|
}
|
|
10
10
|
function shouldRunStartupProbe(env = process.env) {
|
|
@@ -4,20 +4,226 @@ import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtim
|
|
|
4
4
|
import fs from "node:fs/promises";
|
|
5
5
|
import { inspect } from "node:util";
|
|
6
6
|
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
7
|
+
import fsSync from "node:fs";
|
|
7
8
|
import path from "node:path";
|
|
8
|
-
import fs$1 from "node:fs";
|
|
9
9
|
import { fileURLToPath } from "node:url";
|
|
10
10
|
import { formatPluginConfigIssue } from "openclaw/plugin-sdk/extension-shared";
|
|
11
11
|
import { z } from "openclaw/plugin-sdk/zod";
|
|
12
|
+
//#region extensions/acpx/src/config-schema.ts
|
|
13
|
+
const ACPX_PERMISSION_MODES = [
|
|
14
|
+
"approve-all",
|
|
15
|
+
"approve-reads",
|
|
16
|
+
"deny-all"
|
|
17
|
+
];
|
|
18
|
+
const ACPX_NON_INTERACTIVE_POLICIES = ["deny", "fail"];
|
|
19
|
+
const nonEmptyTrimmedString = (message) => z.string({ error: message }).trim().min(1, { error: message });
|
|
20
|
+
const McpServerConfigSchema = z.object({
|
|
21
|
+
command: nonEmptyTrimmedString("command must be a non-empty string").describe("Command to run the MCP server"),
|
|
22
|
+
args: z.array(z.string({ error: "args must be an array of strings" }), { error: "args must be an array of strings" }).optional().describe("Arguments to pass to the command"),
|
|
23
|
+
env: z.record(z.string(), z.string({ error: "env values must be strings" }), { error: "env must be an object of strings" }).optional().describe("Environment variables for the MCP server")
|
|
24
|
+
});
|
|
25
|
+
const AcpxPluginConfigSchema = z.strictObject({
|
|
26
|
+
cwd: nonEmptyTrimmedString("cwd must be a non-empty string").optional(),
|
|
27
|
+
stateDir: nonEmptyTrimmedString("stateDir must be a non-empty string").optional(),
|
|
28
|
+
probeAgent: nonEmptyTrimmedString("probeAgent must be a non-empty string").optional(),
|
|
29
|
+
permissionMode: z.enum(ACPX_PERMISSION_MODES, { error: `permissionMode must be one of: ${ACPX_PERMISSION_MODES.join(", ")}` }).optional(),
|
|
30
|
+
nonInteractivePermissions: z.enum(ACPX_NON_INTERACTIVE_POLICIES, { error: `nonInteractivePermissions must be one of: ${ACPX_NON_INTERACTIVE_POLICIES.join(", ")}` }).optional(),
|
|
31
|
+
pluginToolsMcpBridge: z.boolean({ error: "pluginToolsMcpBridge must be a boolean" }).optional(),
|
|
32
|
+
openClawToolsMcpBridge: z.boolean({ error: "openClawToolsMcpBridge must be a boolean" }).optional(),
|
|
33
|
+
strictWindowsCmdWrapper: z.boolean({ error: "strictWindowsCmdWrapper must be a boolean" }).optional(),
|
|
34
|
+
timeoutSeconds: z.number({ error: "timeoutSeconds must be a number >= 0.001" }).min(.001, { error: "timeoutSeconds must be a number >= 0.001" }).default(120),
|
|
35
|
+
queueOwnerTtlSeconds: z.number({ error: "queueOwnerTtlSeconds must be a number >= 0" }).min(0, { error: "queueOwnerTtlSeconds must be a number >= 0" }).optional(),
|
|
36
|
+
mcpServers: z.record(z.string(), McpServerConfigSchema).optional(),
|
|
37
|
+
agents: z.record(z.string(), z.strictObject({ command: nonEmptyTrimmedString("agents.<id>.command must be a non-empty string") })).optional()
|
|
38
|
+
});
|
|
39
|
+
//#endregion
|
|
40
|
+
//#region extensions/acpx/src/config.ts
|
|
41
|
+
const ACPX_PLUGIN_TOOLS_MCP_SERVER_NAME = "openclaw-plugin-tools";
|
|
42
|
+
const ACPX_OPENCLAW_TOOLS_MCP_SERVER_NAME = "openclaw-tools";
|
|
43
|
+
const requireFromHere$1 = createRequire(import.meta.url);
|
|
44
|
+
function isAcpxPluginRoot(dir) {
|
|
45
|
+
return fsSync.existsSync(path.join(dir, "openclaw.plugin.json")) && fsSync.existsSync(path.join(dir, "package.json"));
|
|
46
|
+
}
|
|
47
|
+
function resolveNearestAcpxPluginRoot(moduleUrl) {
|
|
48
|
+
let cursor = path.dirname(fileURLToPath(moduleUrl));
|
|
49
|
+
for (let i = 0; i < 3; i += 1) {
|
|
50
|
+
if (isAcpxPluginRoot(cursor)) return cursor;
|
|
51
|
+
const parent = path.dirname(cursor);
|
|
52
|
+
if (parent === cursor) break;
|
|
53
|
+
cursor = parent;
|
|
54
|
+
}
|
|
55
|
+
return path.resolve(path.dirname(fileURLToPath(moduleUrl)), "..");
|
|
56
|
+
}
|
|
57
|
+
function resolveWorkspaceAcpxPluginRoot(currentRoot) {
|
|
58
|
+
if (path.basename(currentRoot) !== "acpx" || path.basename(path.dirname(currentRoot)) !== "extensions" || path.basename(path.dirname(path.dirname(currentRoot))) !== "dist") return null;
|
|
59
|
+
const workspaceRoot = path.resolve(currentRoot, "..", "..", "..", "extensions", "acpx");
|
|
60
|
+
return isAcpxPluginRoot(workspaceRoot) ? workspaceRoot : null;
|
|
61
|
+
}
|
|
62
|
+
function resolveRepoAcpxPluginRoot(currentRoot) {
|
|
63
|
+
const workspaceRoot = path.join(currentRoot, "extensions", "acpx");
|
|
64
|
+
return isAcpxPluginRoot(workspaceRoot) ? workspaceRoot : null;
|
|
65
|
+
}
|
|
66
|
+
function resolveAcpxPluginRootFromOpenClawLayout(moduleUrl) {
|
|
67
|
+
let cursor = path.dirname(fileURLToPath(moduleUrl));
|
|
68
|
+
for (let i = 0; i < 5; i += 1) {
|
|
69
|
+
const candidates = [
|
|
70
|
+
path.join(cursor, "extensions", "acpx"),
|
|
71
|
+
path.join(cursor, "dist", "extensions", "acpx"),
|
|
72
|
+
path.join(cursor, "dist-runtime", "extensions", "acpx")
|
|
73
|
+
];
|
|
74
|
+
for (const candidate of candidates) if (isAcpxPluginRoot(candidate)) return candidate;
|
|
75
|
+
const parent = path.dirname(cursor);
|
|
76
|
+
if (parent === cursor) break;
|
|
77
|
+
cursor = parent;
|
|
78
|
+
}
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
function resolveAcpxPluginRoot(moduleUrl = import.meta.url) {
|
|
82
|
+
const resolvedRoot = resolveNearestAcpxPluginRoot(moduleUrl);
|
|
83
|
+
return resolveWorkspaceAcpxPluginRoot(resolvedRoot) ?? resolveRepoAcpxPluginRoot(resolvedRoot) ?? resolveAcpxPluginRootFromOpenClawLayout(moduleUrl) ?? resolvedRoot;
|
|
84
|
+
}
|
|
85
|
+
const DEFAULT_PERMISSION_MODE = "approve-reads";
|
|
86
|
+
const DEFAULT_NON_INTERACTIVE_POLICY = "fail";
|
|
87
|
+
const DEFAULT_QUEUE_OWNER_TTL_SECONDS = .1;
|
|
88
|
+
const DEFAULT_STRICT_WINDOWS_CMD_WRAPPER = true;
|
|
89
|
+
function parseAcpxPluginConfig(value) {
|
|
90
|
+
if (value === void 0) return {
|
|
91
|
+
ok: true,
|
|
92
|
+
value: void 0
|
|
93
|
+
};
|
|
94
|
+
const parsed = AcpxPluginConfigSchema.safeParse(value);
|
|
95
|
+
if (!parsed.success) return {
|
|
96
|
+
ok: false,
|
|
97
|
+
message: formatPluginConfigIssue(parsed.error.issues[0])
|
|
98
|
+
};
|
|
99
|
+
return {
|
|
100
|
+
ok: true,
|
|
101
|
+
value: parsed.data
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function resolveOpenClawRoot(currentRoot) {
|
|
105
|
+
if (path.basename(currentRoot) === "acpx" && path.basename(path.dirname(currentRoot)) === "extensions") {
|
|
106
|
+
const parent = path.dirname(path.dirname(currentRoot));
|
|
107
|
+
if (path.basename(parent) === "dist") return path.dirname(parent);
|
|
108
|
+
return parent;
|
|
109
|
+
}
|
|
110
|
+
return path.resolve(currentRoot, "..");
|
|
111
|
+
}
|
|
112
|
+
function resolveTsxImportSpecifier() {
|
|
113
|
+
try {
|
|
114
|
+
return requireFromHere$1.resolve("tsx");
|
|
115
|
+
} catch {
|
|
116
|
+
return "tsx";
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function resolvePluginToolsMcpServerConfig(moduleUrl = import.meta.url) {
|
|
120
|
+
const openClawRoot = resolveOpenClawRoot(resolveAcpxPluginRoot(moduleUrl));
|
|
121
|
+
const distEntry = path.join(openClawRoot, "dist", "mcp", "plugin-tools-serve.js");
|
|
122
|
+
if (fsSync.existsSync(distEntry)) return {
|
|
123
|
+
command: process.execPath,
|
|
124
|
+
args: [distEntry]
|
|
125
|
+
};
|
|
126
|
+
const sourceEntry = path.join(openClawRoot, "src", "mcp", "plugin-tools-serve.ts");
|
|
127
|
+
return {
|
|
128
|
+
command: process.execPath,
|
|
129
|
+
args: [
|
|
130
|
+
"--import",
|
|
131
|
+
resolveTsxImportSpecifier(),
|
|
132
|
+
sourceEntry
|
|
133
|
+
]
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
function resolveOpenClawToolsMcpServerConfig(moduleUrl = import.meta.url) {
|
|
137
|
+
const openClawRoot = resolveOpenClawRoot(resolveAcpxPluginRoot(moduleUrl));
|
|
138
|
+
const distEntry = path.join(openClawRoot, "dist", "mcp", "openclaw-tools-serve.js");
|
|
139
|
+
if (fsSync.existsSync(distEntry)) return {
|
|
140
|
+
command: process.execPath,
|
|
141
|
+
args: [distEntry]
|
|
142
|
+
};
|
|
143
|
+
const sourceEntry = path.join(openClawRoot, "src", "mcp", "openclaw-tools-serve.ts");
|
|
144
|
+
return {
|
|
145
|
+
command: process.execPath,
|
|
146
|
+
args: [
|
|
147
|
+
"--import",
|
|
148
|
+
resolveTsxImportSpecifier(),
|
|
149
|
+
sourceEntry
|
|
150
|
+
]
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
function resolveConfiguredMcpServers(params) {
|
|
154
|
+
const resolved = { ...params.mcpServers };
|
|
155
|
+
if (params.pluginToolsMcpBridge && resolved[ACPX_PLUGIN_TOOLS_MCP_SERVER_NAME]) throw new Error(`mcpServers.${ACPX_PLUGIN_TOOLS_MCP_SERVER_NAME} is reserved when pluginToolsMcpBridge=true`);
|
|
156
|
+
if (params.openClawToolsMcpBridge && resolved[ACPX_OPENCLAW_TOOLS_MCP_SERVER_NAME]) throw new Error(`mcpServers.${ACPX_OPENCLAW_TOOLS_MCP_SERVER_NAME} is reserved when openClawToolsMcpBridge=true`);
|
|
157
|
+
if (params.pluginToolsMcpBridge) resolved[ACPX_PLUGIN_TOOLS_MCP_SERVER_NAME] = resolvePluginToolsMcpServerConfig(params.moduleUrl);
|
|
158
|
+
if (params.openClawToolsMcpBridge) resolved[ACPX_OPENCLAW_TOOLS_MCP_SERVER_NAME] = resolveOpenClawToolsMcpServerConfig(params.moduleUrl);
|
|
159
|
+
return resolved;
|
|
160
|
+
}
|
|
161
|
+
function toAcpMcpServers(mcpServers) {
|
|
162
|
+
return Object.entries(mcpServers).map(([name, server]) => ({
|
|
163
|
+
name,
|
|
164
|
+
command: server.command,
|
|
165
|
+
args: [...server.args ?? []],
|
|
166
|
+
env: Object.entries(server.env ?? {}).map(([envName, value]) => ({
|
|
167
|
+
name: envName,
|
|
168
|
+
value
|
|
169
|
+
}))
|
|
170
|
+
}));
|
|
171
|
+
}
|
|
172
|
+
function resolveAcpxPluginConfig(params) {
|
|
173
|
+
const parsed = parseAcpxPluginConfig(params.rawConfig);
|
|
174
|
+
if (!parsed.ok) throw new Error(parsed.message);
|
|
175
|
+
const normalized = parsed.value ?? {};
|
|
176
|
+
const workspaceDir = params.workspaceDir?.trim() || process.cwd();
|
|
177
|
+
const fallbackCwd = workspaceDir;
|
|
178
|
+
const cwd = path.resolve(normalized.cwd?.trim() || fallbackCwd);
|
|
179
|
+
const stateDir = path.resolve(normalized.stateDir?.trim() || path.join(workspaceDir, "state"));
|
|
180
|
+
const pluginToolsMcpBridge = normalized.pluginToolsMcpBridge === true;
|
|
181
|
+
const openClawToolsMcpBridge = normalized.openClawToolsMcpBridge === true;
|
|
182
|
+
const mcpServers = resolveConfiguredMcpServers({
|
|
183
|
+
mcpServers: normalized.mcpServers,
|
|
184
|
+
pluginToolsMcpBridge,
|
|
185
|
+
openClawToolsMcpBridge,
|
|
186
|
+
moduleUrl: params.moduleUrl
|
|
187
|
+
});
|
|
188
|
+
const agents = Object.fromEntries(Object.entries(normalized.agents ?? {}).map(([name, entry]) => [normalizeLowercaseStringOrEmpty(name), entry.command.trim()]));
|
|
189
|
+
return {
|
|
190
|
+
cwd,
|
|
191
|
+
stateDir,
|
|
192
|
+
probeAgent: normalizeLowercaseStringOrEmpty(normalized.probeAgent) || void 0,
|
|
193
|
+
permissionMode: normalized.permissionMode ?? DEFAULT_PERMISSION_MODE,
|
|
194
|
+
nonInteractivePermissions: normalized.nonInteractivePermissions ?? DEFAULT_NON_INTERACTIVE_POLICY,
|
|
195
|
+
pluginToolsMcpBridge,
|
|
196
|
+
openClawToolsMcpBridge,
|
|
197
|
+
strictWindowsCmdWrapper: normalized.strictWindowsCmdWrapper ?? DEFAULT_STRICT_WINDOWS_CMD_WRAPPER,
|
|
198
|
+
timeoutSeconds: normalized.timeoutSeconds ?? 120,
|
|
199
|
+
queueOwnerTtlSeconds: normalized.queueOwnerTtlSeconds ?? DEFAULT_QUEUE_OWNER_TTL_SECONDS,
|
|
200
|
+
legacyCompatibilityConfig: {
|
|
201
|
+
strictWindowsCmdWrapper: normalized.strictWindowsCmdWrapper,
|
|
202
|
+
queueOwnerTtlSeconds: normalized.queueOwnerTtlSeconds
|
|
203
|
+
},
|
|
204
|
+
mcpServers,
|
|
205
|
+
agents
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
//#endregion
|
|
12
209
|
//#region extensions/acpx/src/codex-auth-bridge.ts
|
|
13
210
|
const CODEX_ACP_PACKAGE = "@zed-industries/codex-acp";
|
|
14
|
-
const CODEX_ACP_PACKAGE_RANGE = "^0.12.0";
|
|
15
211
|
const CODEX_ACP_BIN = "codex-acp";
|
|
16
212
|
const CLAUDE_ACP_PACKAGE = "@agentclientprotocol/claude-agent-acp";
|
|
17
|
-
const CLAUDE_ACP_PACKAGE_VERSION = "0.31.4";
|
|
18
213
|
const CLAUDE_ACP_BIN = "claude-agent-acp";
|
|
19
214
|
const RUN_CONFIGURED_COMMAND_SENTINEL = "--openclaw-run-configured";
|
|
20
|
-
const requireFromHere
|
|
215
|
+
const requireFromHere = createRequire(import.meta.url);
|
|
216
|
+
function readSelfManifest() {
|
|
217
|
+
const manifestPath = path.join(resolveAcpxPluginRoot(import.meta.url), "package.json");
|
|
218
|
+
return JSON.parse(fsSync.readFileSync(manifestPath, "utf8"));
|
|
219
|
+
}
|
|
220
|
+
function readManifestDependencyVersion(packageName) {
|
|
221
|
+
const version = readSelfManifest().dependencies?.[packageName];
|
|
222
|
+
if (typeof version !== "string" || version.trim() === "") throw new Error(`Missing ${packageName} dependency version in @openclaw/acpx manifest`);
|
|
223
|
+
return version;
|
|
224
|
+
}
|
|
225
|
+
const CODEX_ACP_PACKAGE_VERSION = readManifestDependencyVersion(CODEX_ACP_PACKAGE);
|
|
226
|
+
const CLAUDE_ACP_PACKAGE_VERSION = readManifestDependencyVersion(CLAUDE_ACP_PACKAGE);
|
|
21
227
|
function quoteCommandPart(value) {
|
|
22
228
|
return JSON.stringify(value);
|
|
23
229
|
}
|
|
@@ -69,7 +275,7 @@ function resolvePackageBinPath(packageJsonPath, manifest, binName) {
|
|
|
69
275
|
}
|
|
70
276
|
async function resolveInstalledAcpPackageBinPath(packageName, binName) {
|
|
71
277
|
try {
|
|
72
|
-
const packageJsonPath = requireFromHere
|
|
278
|
+
const packageJsonPath = requireFromHere.resolve(`${packageName}/package.json`);
|
|
73
279
|
const manifest = JSON.parse(await fs.readFile(packageJsonPath, "utf8"));
|
|
74
280
|
if (manifest.name !== packageName) return;
|
|
75
281
|
const binPath = resolvePackageBinPath(packageJsonPath, manifest, binName);
|
|
@@ -163,7 +369,7 @@ child.on("exit", (code, signal) => {
|
|
|
163
369
|
function buildCodexAcpWrapperScript(installedBinPath) {
|
|
164
370
|
return buildAdapterWrapperScript({
|
|
165
371
|
displayName: "Codex",
|
|
166
|
-
packageSpec: `${CODEX_ACP_PACKAGE}@${
|
|
372
|
+
packageSpec: `${CODEX_ACP_PACKAGE}@${CODEX_ACP_PACKAGE_VERSION}`,
|
|
167
373
|
binName: CODEX_ACP_BIN,
|
|
168
374
|
installedBinPath,
|
|
169
375
|
envSetup: `const codexHome = fileURLToPath(new URL("./codex-home/", import.meta.url));
|
|
@@ -282,203 +488,6 @@ async function prepareAcpxCodexAuthConfig(params) {
|
|
|
282
488
|
};
|
|
283
489
|
}
|
|
284
490
|
//#endregion
|
|
285
|
-
//#region extensions/acpx/src/config-schema.ts
|
|
286
|
-
const ACPX_PERMISSION_MODES = [
|
|
287
|
-
"approve-all",
|
|
288
|
-
"approve-reads",
|
|
289
|
-
"deny-all"
|
|
290
|
-
];
|
|
291
|
-
const ACPX_NON_INTERACTIVE_POLICIES = ["deny", "fail"];
|
|
292
|
-
const nonEmptyTrimmedString = (message) => z.string({ error: message }).trim().min(1, { error: message });
|
|
293
|
-
const McpServerConfigSchema = z.object({
|
|
294
|
-
command: nonEmptyTrimmedString("command must be a non-empty string").describe("Command to run the MCP server"),
|
|
295
|
-
args: z.array(z.string({ error: "args must be an array of strings" }), { error: "args must be an array of strings" }).optional().describe("Arguments to pass to the command"),
|
|
296
|
-
env: z.record(z.string(), z.string({ error: "env values must be strings" }), { error: "env must be an object of strings" }).optional().describe("Environment variables for the MCP server")
|
|
297
|
-
});
|
|
298
|
-
const AcpxPluginConfigSchema = z.strictObject({
|
|
299
|
-
cwd: nonEmptyTrimmedString("cwd must be a non-empty string").optional(),
|
|
300
|
-
stateDir: nonEmptyTrimmedString("stateDir must be a non-empty string").optional(),
|
|
301
|
-
probeAgent: nonEmptyTrimmedString("probeAgent must be a non-empty string").optional(),
|
|
302
|
-
permissionMode: z.enum(ACPX_PERMISSION_MODES, { error: `permissionMode must be one of: ${ACPX_PERMISSION_MODES.join(", ")}` }).optional(),
|
|
303
|
-
nonInteractivePermissions: z.enum(ACPX_NON_INTERACTIVE_POLICIES, { error: `nonInteractivePermissions must be one of: ${ACPX_NON_INTERACTIVE_POLICIES.join(", ")}` }).optional(),
|
|
304
|
-
pluginToolsMcpBridge: z.boolean({ error: "pluginToolsMcpBridge must be a boolean" }).optional(),
|
|
305
|
-
openClawToolsMcpBridge: z.boolean({ error: "openClawToolsMcpBridge must be a boolean" }).optional(),
|
|
306
|
-
strictWindowsCmdWrapper: z.boolean({ error: "strictWindowsCmdWrapper must be a boolean" }).optional(),
|
|
307
|
-
timeoutSeconds: z.number({ error: "timeoutSeconds must be a number >= 0.001" }).min(.001, { error: "timeoutSeconds must be a number >= 0.001" }).default(120),
|
|
308
|
-
queueOwnerTtlSeconds: z.number({ error: "queueOwnerTtlSeconds must be a number >= 0" }).min(0, { error: "queueOwnerTtlSeconds must be a number >= 0" }).optional(),
|
|
309
|
-
mcpServers: z.record(z.string(), McpServerConfigSchema).optional(),
|
|
310
|
-
agents: z.record(z.string(), z.strictObject({ command: nonEmptyTrimmedString("agents.<id>.command must be a non-empty string") })).optional()
|
|
311
|
-
});
|
|
312
|
-
//#endregion
|
|
313
|
-
//#region extensions/acpx/src/config.ts
|
|
314
|
-
const ACPX_PLUGIN_TOOLS_MCP_SERVER_NAME = "openclaw-plugin-tools";
|
|
315
|
-
const ACPX_OPENCLAW_TOOLS_MCP_SERVER_NAME = "openclaw-tools";
|
|
316
|
-
const requireFromHere = createRequire(import.meta.url);
|
|
317
|
-
function isAcpxPluginRoot(dir) {
|
|
318
|
-
return fs$1.existsSync(path.join(dir, "openclaw.plugin.json")) && fs$1.existsSync(path.join(dir, "package.json"));
|
|
319
|
-
}
|
|
320
|
-
function resolveNearestAcpxPluginRoot(moduleUrl) {
|
|
321
|
-
let cursor = path.dirname(fileURLToPath(moduleUrl));
|
|
322
|
-
for (let i = 0; i < 3; i += 1) {
|
|
323
|
-
if (isAcpxPluginRoot(cursor)) return cursor;
|
|
324
|
-
const parent = path.dirname(cursor);
|
|
325
|
-
if (parent === cursor) break;
|
|
326
|
-
cursor = parent;
|
|
327
|
-
}
|
|
328
|
-
return path.resolve(path.dirname(fileURLToPath(moduleUrl)), "..");
|
|
329
|
-
}
|
|
330
|
-
function resolveWorkspaceAcpxPluginRoot(currentRoot) {
|
|
331
|
-
if (path.basename(currentRoot) !== "acpx" || path.basename(path.dirname(currentRoot)) !== "extensions" || path.basename(path.dirname(path.dirname(currentRoot))) !== "dist") return null;
|
|
332
|
-
const workspaceRoot = path.resolve(currentRoot, "..", "..", "..", "extensions", "acpx");
|
|
333
|
-
return isAcpxPluginRoot(workspaceRoot) ? workspaceRoot : null;
|
|
334
|
-
}
|
|
335
|
-
function resolveRepoAcpxPluginRoot(currentRoot) {
|
|
336
|
-
const workspaceRoot = path.join(currentRoot, "extensions", "acpx");
|
|
337
|
-
return isAcpxPluginRoot(workspaceRoot) ? workspaceRoot : null;
|
|
338
|
-
}
|
|
339
|
-
function resolveAcpxPluginRootFromOpenClawLayout(moduleUrl) {
|
|
340
|
-
let cursor = path.dirname(fileURLToPath(moduleUrl));
|
|
341
|
-
for (let i = 0; i < 5; i += 1) {
|
|
342
|
-
const candidates = [
|
|
343
|
-
path.join(cursor, "extensions", "acpx"),
|
|
344
|
-
path.join(cursor, "dist", "extensions", "acpx"),
|
|
345
|
-
path.join(cursor, "dist-runtime", "extensions", "acpx")
|
|
346
|
-
];
|
|
347
|
-
for (const candidate of candidates) if (isAcpxPluginRoot(candidate)) return candidate;
|
|
348
|
-
const parent = path.dirname(cursor);
|
|
349
|
-
if (parent === cursor) break;
|
|
350
|
-
cursor = parent;
|
|
351
|
-
}
|
|
352
|
-
return null;
|
|
353
|
-
}
|
|
354
|
-
function resolveAcpxPluginRoot(moduleUrl = import.meta.url) {
|
|
355
|
-
const resolvedRoot = resolveNearestAcpxPluginRoot(moduleUrl);
|
|
356
|
-
return resolveWorkspaceAcpxPluginRoot(resolvedRoot) ?? resolveRepoAcpxPluginRoot(resolvedRoot) ?? resolveAcpxPluginRootFromOpenClawLayout(moduleUrl) ?? resolvedRoot;
|
|
357
|
-
}
|
|
358
|
-
const DEFAULT_PERMISSION_MODE = "approve-reads";
|
|
359
|
-
const DEFAULT_NON_INTERACTIVE_POLICY = "fail";
|
|
360
|
-
const DEFAULT_QUEUE_OWNER_TTL_SECONDS = .1;
|
|
361
|
-
const DEFAULT_STRICT_WINDOWS_CMD_WRAPPER = true;
|
|
362
|
-
function parseAcpxPluginConfig(value) {
|
|
363
|
-
if (value === void 0) return {
|
|
364
|
-
ok: true,
|
|
365
|
-
value: void 0
|
|
366
|
-
};
|
|
367
|
-
const parsed = AcpxPluginConfigSchema.safeParse(value);
|
|
368
|
-
if (!parsed.success) return {
|
|
369
|
-
ok: false,
|
|
370
|
-
message: formatPluginConfigIssue(parsed.error.issues[0])
|
|
371
|
-
};
|
|
372
|
-
return {
|
|
373
|
-
ok: true,
|
|
374
|
-
value: parsed.data
|
|
375
|
-
};
|
|
376
|
-
}
|
|
377
|
-
function resolveOpenClawRoot(currentRoot) {
|
|
378
|
-
if (path.basename(currentRoot) === "acpx" && path.basename(path.dirname(currentRoot)) === "extensions") {
|
|
379
|
-
const parent = path.dirname(path.dirname(currentRoot));
|
|
380
|
-
if (path.basename(parent) === "dist") return path.dirname(parent);
|
|
381
|
-
return parent;
|
|
382
|
-
}
|
|
383
|
-
return path.resolve(currentRoot, "..");
|
|
384
|
-
}
|
|
385
|
-
function resolveTsxImportSpecifier() {
|
|
386
|
-
try {
|
|
387
|
-
return requireFromHere.resolve("tsx");
|
|
388
|
-
} catch {
|
|
389
|
-
return "tsx";
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
function resolvePluginToolsMcpServerConfig(moduleUrl = import.meta.url) {
|
|
393
|
-
const openClawRoot = resolveOpenClawRoot(resolveAcpxPluginRoot(moduleUrl));
|
|
394
|
-
const distEntry = path.join(openClawRoot, "dist", "mcp", "plugin-tools-serve.js");
|
|
395
|
-
if (fs$1.existsSync(distEntry)) return {
|
|
396
|
-
command: process.execPath,
|
|
397
|
-
args: [distEntry]
|
|
398
|
-
};
|
|
399
|
-
const sourceEntry = path.join(openClawRoot, "src", "mcp", "plugin-tools-serve.ts");
|
|
400
|
-
return {
|
|
401
|
-
command: process.execPath,
|
|
402
|
-
args: [
|
|
403
|
-
"--import",
|
|
404
|
-
resolveTsxImportSpecifier(),
|
|
405
|
-
sourceEntry
|
|
406
|
-
]
|
|
407
|
-
};
|
|
408
|
-
}
|
|
409
|
-
function resolveOpenClawToolsMcpServerConfig(moduleUrl = import.meta.url) {
|
|
410
|
-
const openClawRoot = resolveOpenClawRoot(resolveAcpxPluginRoot(moduleUrl));
|
|
411
|
-
const distEntry = path.join(openClawRoot, "dist", "mcp", "openclaw-tools-serve.js");
|
|
412
|
-
if (fs$1.existsSync(distEntry)) return {
|
|
413
|
-
command: process.execPath,
|
|
414
|
-
args: [distEntry]
|
|
415
|
-
};
|
|
416
|
-
const sourceEntry = path.join(openClawRoot, "src", "mcp", "openclaw-tools-serve.ts");
|
|
417
|
-
return {
|
|
418
|
-
command: process.execPath,
|
|
419
|
-
args: [
|
|
420
|
-
"--import",
|
|
421
|
-
resolveTsxImportSpecifier(),
|
|
422
|
-
sourceEntry
|
|
423
|
-
]
|
|
424
|
-
};
|
|
425
|
-
}
|
|
426
|
-
function resolveConfiguredMcpServers(params) {
|
|
427
|
-
const resolved = { ...params.mcpServers };
|
|
428
|
-
if (params.pluginToolsMcpBridge && resolved[ACPX_PLUGIN_TOOLS_MCP_SERVER_NAME]) throw new Error(`mcpServers.${ACPX_PLUGIN_TOOLS_MCP_SERVER_NAME} is reserved when pluginToolsMcpBridge=true`);
|
|
429
|
-
if (params.openClawToolsMcpBridge && resolved[ACPX_OPENCLAW_TOOLS_MCP_SERVER_NAME]) throw new Error(`mcpServers.${ACPX_OPENCLAW_TOOLS_MCP_SERVER_NAME} is reserved when openClawToolsMcpBridge=true`);
|
|
430
|
-
if (params.pluginToolsMcpBridge) resolved[ACPX_PLUGIN_TOOLS_MCP_SERVER_NAME] = resolvePluginToolsMcpServerConfig(params.moduleUrl);
|
|
431
|
-
if (params.openClawToolsMcpBridge) resolved[ACPX_OPENCLAW_TOOLS_MCP_SERVER_NAME] = resolveOpenClawToolsMcpServerConfig(params.moduleUrl);
|
|
432
|
-
return resolved;
|
|
433
|
-
}
|
|
434
|
-
function toAcpMcpServers(mcpServers) {
|
|
435
|
-
return Object.entries(mcpServers).map(([name, server]) => ({
|
|
436
|
-
name,
|
|
437
|
-
command: server.command,
|
|
438
|
-
args: [...server.args ?? []],
|
|
439
|
-
env: Object.entries(server.env ?? {}).map(([envName, value]) => ({
|
|
440
|
-
name: envName,
|
|
441
|
-
value
|
|
442
|
-
}))
|
|
443
|
-
}));
|
|
444
|
-
}
|
|
445
|
-
function resolveAcpxPluginConfig(params) {
|
|
446
|
-
const parsed = parseAcpxPluginConfig(params.rawConfig);
|
|
447
|
-
if (!parsed.ok) throw new Error(parsed.message);
|
|
448
|
-
const normalized = parsed.value ?? {};
|
|
449
|
-
const workspaceDir = params.workspaceDir?.trim() || process.cwd();
|
|
450
|
-
const fallbackCwd = workspaceDir;
|
|
451
|
-
const cwd = path.resolve(normalized.cwd?.trim() || fallbackCwd);
|
|
452
|
-
const stateDir = path.resolve(normalized.stateDir?.trim() || path.join(workspaceDir, "state"));
|
|
453
|
-
const pluginToolsMcpBridge = normalized.pluginToolsMcpBridge === true;
|
|
454
|
-
const openClawToolsMcpBridge = normalized.openClawToolsMcpBridge === true;
|
|
455
|
-
const mcpServers = resolveConfiguredMcpServers({
|
|
456
|
-
mcpServers: normalized.mcpServers,
|
|
457
|
-
pluginToolsMcpBridge,
|
|
458
|
-
openClawToolsMcpBridge,
|
|
459
|
-
moduleUrl: params.moduleUrl
|
|
460
|
-
});
|
|
461
|
-
const agents = Object.fromEntries(Object.entries(normalized.agents ?? {}).map(([name, entry]) => [normalizeLowercaseStringOrEmpty(name), entry.command.trim()]));
|
|
462
|
-
return {
|
|
463
|
-
cwd,
|
|
464
|
-
stateDir,
|
|
465
|
-
probeAgent: normalizeLowercaseStringOrEmpty(normalized.probeAgent) || void 0,
|
|
466
|
-
permissionMode: normalized.permissionMode ?? DEFAULT_PERMISSION_MODE,
|
|
467
|
-
nonInteractivePermissions: normalized.nonInteractivePermissions ?? DEFAULT_NON_INTERACTIVE_POLICY,
|
|
468
|
-
pluginToolsMcpBridge,
|
|
469
|
-
openClawToolsMcpBridge,
|
|
470
|
-
strictWindowsCmdWrapper: normalized.strictWindowsCmdWrapper ?? DEFAULT_STRICT_WINDOWS_CMD_WRAPPER,
|
|
471
|
-
timeoutSeconds: normalized.timeoutSeconds ?? 120,
|
|
472
|
-
queueOwnerTtlSeconds: normalized.queueOwnerTtlSeconds ?? DEFAULT_QUEUE_OWNER_TTL_SECONDS,
|
|
473
|
-
legacyCompatibilityConfig: {
|
|
474
|
-
strictWindowsCmdWrapper: normalized.strictWindowsCmdWrapper,
|
|
475
|
-
queueOwnerTtlSeconds: normalized.queueOwnerTtlSeconds
|
|
476
|
-
},
|
|
477
|
-
mcpServers,
|
|
478
|
-
agents
|
|
479
|
-
};
|
|
480
|
-
}
|
|
481
|
-
//#endregion
|
|
482
491
|
//#region extensions/acpx/src/service.ts
|
|
483
492
|
const ENABLE_STARTUP_PROBE_ENV = "OPENCLAW_ACPX_RUNTIME_STARTUP_PROBE";
|
|
484
493
|
const ACPX_BACKEND_ID = "acpx";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/acpx",
|
|
3
|
-
"version": "2026.5.4-beta.
|
|
3
|
+
"version": "2026.5.4-beta.3",
|
|
4
4
|
"description": "OpenClaw ACP runtime backend",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
},
|
|
9
9
|
"type": "module",
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"@agentclientprotocol/claude-agent-acp": "0.
|
|
12
|
-
"@zed-industries/codex-acp": "0.
|
|
11
|
+
"@agentclientprotocol/claude-agent-acp": "0.32.0",
|
|
12
|
+
"@zed-industries/codex-acp": "0.13.0",
|
|
13
13
|
"acpx": "0.6.1"
|
|
14
14
|
},
|
|
15
15
|
"devDependencies": {
|
|
@@ -25,10 +25,10 @@
|
|
|
25
25
|
"minHostVersion": ">=2026.4.25"
|
|
26
26
|
},
|
|
27
27
|
"compat": {
|
|
28
|
-
"pluginApi": ">=2026.5.4-beta.
|
|
28
|
+
"pluginApi": ">=2026.5.4-beta.3"
|
|
29
29
|
},
|
|
30
30
|
"build": {
|
|
31
|
-
"openclawVersion": "2026.5.4-beta.
|
|
31
|
+
"openclawVersion": "2026.5.4-beta.3",
|
|
32
32
|
"staticAssets": [
|
|
33
33
|
{
|
|
34
34
|
"source": "./src/runtime-internals/mcp-proxy.mjs",
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
"skills/**"
|
|
59
59
|
],
|
|
60
60
|
"peerDependencies": {
|
|
61
|
-
"openclaw": ">=2026.5.4-beta.
|
|
61
|
+
"openclaw": ">=2026.5.4-beta.3"
|
|
62
62
|
},
|
|
63
63
|
"peerDependenciesMeta": {
|
|
64
64
|
"openclaw": {
|
|
@@ -211,8 +211,8 @@ ${ACPX_CMD} codex sessions close oc-codex-<conversationId>
|
|
|
211
211
|
Defaults are:
|
|
212
212
|
|
|
213
213
|
- `openclaw -> openclaw acp`
|
|
214
|
-
- `claude ->
|
|
215
|
-
- `codex -> bundled @zed-industries/codex-acp@0.
|
|
214
|
+
- `claude -> bundled @agentclientprotocol/claude-agent-acp@0.32.0`
|
|
215
|
+
- `codex -> bundled @zed-industries/codex-acp@0.13.0 through OpenClaw's isolated CODEX_HOME wrapper`
|
|
216
216
|
- `copilot -> copilot --acp --stdio`
|
|
217
217
|
- `cursor -> cursor-agent acp`
|
|
218
218
|
- `droid -> droid exec --output-format acp`
|