@openclaw/acpx 2026.9.4 → 2026.9.6

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.
@@ -1,9 +1,8 @@
1
- import { a as hashAcpxProcessCommand, c as openAcpxProcessLeaseStateStore, l as readAcpxProcessLeaseIdentity, o as normalizeAcpxProcessLease } from "./process-lease-B83BGiLj.js";
2
- import { t as resolveAcpxPluginConfig } from "./config-D2FTk0K7.js";
1
+ import { t as resolveAcpxPluginConfig } from "./config-CdPsIued.mjs";
2
+ import { a as hashAcpxProcessCommand, c as openAcpxProcessLeaseStateStore, l as readAcpxProcessLeaseIdentity, o as normalizeAcpxProcessLease } from "./process-lease-C3dNPtu8.mjs";
3
3
  import path from "node:path";
4
4
  import fs from "node:fs/promises";
5
5
  import { archiveLegacyStateSource, asObjectRecord } from "openclaw/plugin-sdk/runtime-doctor-migrations";
6
- import { randomUUID } from "node:crypto";
7
6
  import { isDeepStrictEqual } from "node:util";
8
7
  //#region extensions/acpx/src/session-owner-migration.ts
9
8
  function sessionDirectory(input) {
@@ -23,7 +22,7 @@ async function legacyRecords(input) {
23
22
  directory,
24
23
  ids
25
24
  };
26
- const { resolveAcpxSessionResource } = await import("./session-resource-UWe7qD3m.js").then((n) => n.n);
25
+ const { resolveAcpxSessionResource } = await import("./session-resource-BaJ6bs5d.mjs").then((n) => n.n);
27
26
  const evidence = await input.context.inspectAcpSessionClaims?.();
28
27
  const { decodeAcpxRuntimeHandleState } = await import("acpx/runtime");
29
28
  return {
@@ -66,7 +65,7 @@ async function migrateRecord(input, directory, oldId, claims, changes, warnings)
66
65
  const raw = asObjectRecord(JSON.parse(sourceBytes));
67
66
  if (!raw || raw.acpx_record_id !== oldId || typeof raw.name !== "string" || !raw.name.trim() || raw.name !== oldId && !oldId.startsWith(`${raw.name}:oneshot:`)) throw new Error("record ID/name is not a recognized ACPX locator");
68
67
  requireStoppedPid(raw.pid);
69
- const { resolveAcpxSessionResource } = await import("./session-resource-UWe7qD3m.js").then((n) => n.n);
68
+ const { resolveAcpxSessionResource } = await import("./session-resource-BaJ6bs5d.mjs").then((n) => n.n);
70
69
  const { createFileSessionStore, decodeAcpxRuntimeHandleState, encodeAcpxRuntimeHandleState } = await import("acpx/runtime");
71
70
  const candidates = claims.filter((claim) => matchesClaimRecord(claim, raw, oldId, resolveAcpxSessionResource(claim), decodeAcpxRuntimeHandleState));
72
71
  if (candidates.length !== 1) throw new Error("exactly one current canonical owner claim is required");
@@ -96,20 +95,21 @@ async function migrateRecord(input, directory, oldId, claims, changes, warnings)
96
95
  name: resource
97
96
  };
98
97
  const candidateBytes = `${JSON.stringify(candidate, null, 2)}\n`;
99
- const store = createFileSessionStore({ stateDir: path.dirname(directory) });
100
- const source = await store.load(oldId);
98
+ const source = await createFileSessionStore({ stateDir: path.dirname(directory) }).load(oldId);
101
99
  if (!source) throw new Error("pinned ACPX reader rejected the source record");
102
- const temporaryId = `.openclaw-owner-${randomUUID()}`;
103
- const temporaryPath = recordPath(directory, temporaryId);
104
- const file = await fs.open(temporaryPath, "wx", 384);
100
+ const temporaryDirectory = await fs.mkdtemp(path.join(directory, ".openclaw-owner-"));
101
+ const temporarySessions = path.join(temporaryDirectory, "sessions");
102
+ const temporaryPath = recordPath(temporarySessions, recordId);
105
103
  try {
104
+ await fs.mkdir(temporarySessions, { mode: 448 });
105
+ const file = await fs.open(temporaryPath, "wx", 384);
106
106
  try {
107
107
  await file.writeFile(candidateBytes);
108
108
  await file.sync();
109
109
  } finally {
110
110
  await file.close();
111
111
  }
112
- const interpreted = await store.load(temporaryId);
112
+ const interpreted = await createFileSessionStore({ stateDir: temporaryDirectory }).load(recordId);
113
113
  if (!interpreted || !isDeepStrictEqual(interpreted, oneshot ? source : {
114
114
  ...source,
115
115
  acpxRecordId: resource,
@@ -158,7 +158,10 @@ async function migrateRecord(input, directory, oldId, claims, changes, warnings)
158
158
  warnings
159
159
  });
160
160
  } finally {
161
- await fs.rm(temporaryPath, { force: true });
161
+ await fs.rm(temporaryDirectory, {
162
+ recursive: true,
163
+ force: true
164
+ });
162
165
  }
163
166
  }
164
167
  const acpxSessionOwnerMigration = {
@@ -1,7 +1,19 @@
1
- import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
2
- import { AcpRuntimeError } from "./runtime-api.js";
1
+ import { AcpRuntimeError } from "../runtime-api.js";
2
+ import "node:module";
3
3
  import { createHash } from "node:crypto";
4
4
  import { normalizeAgentId, parseAgentSessionKey } from "openclaw/plugin-sdk/routing";
5
+ //#region \0rolldown/runtime.js
6
+ var __defProp = Object.defineProperty;
7
+ var __exportAll = (all, no_symbols) => {
8
+ let target = {};
9
+ for (var name in all) __defProp(target, name, {
10
+ get: all[name],
11
+ enumerable: true
12
+ });
13
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
14
+ return target;
15
+ };
16
+ //#endregion
5
17
  //#region extensions/acpx/src/session-resource.ts
6
18
  var session_resource_exports = /* @__PURE__ */ __exportAll({ resolveAcpxSessionResource: () => resolveAcpxSessionResource });
7
19
  /** Logical OpenClaw keys stay intact; only bare backend resource names need a namespace. */
@@ -1,4 +1,4 @@
1
- import { c as openAcpxProcessLeaseStateStore, d as ACPX_GATEWAY_INSTANCE_KEY, f as ACPX_GATEWAY_INSTANCE_NAMESPACE, h as normalizeAcpxGatewayInstanceRecord, m as ACPX_LEGACY_PROCESS_LEASE_FILE, o as normalizeAcpxProcessLease, p as ACPX_LEGACY_GATEWAY_INSTANCE_FILE, s as normalizeAcpxProcessLeaseFile } from "./process-lease-B83BGiLj.js";
1
+ import { c as openAcpxProcessLeaseStateStore, d as ACPX_GATEWAY_INSTANCE_KEY, f as ACPX_GATEWAY_INSTANCE_NAMESPACE, h as normalizeAcpxGatewayInstanceRecord, m as ACPX_LEGACY_PROCESS_LEASE_FILE, o as normalizeAcpxProcessLease, p as ACPX_LEGACY_GATEWAY_INSTANCE_FILE, s as normalizeAcpxProcessLeaseFile } from "./.setup/process-lease-C3dNPtu8.mjs";
2
2
  import path from "node:path";
3
3
  import fs from "node:fs/promises";
4
4
  import { archiveLegacyStateSource, asObjectRecord } from "openclaw/plugin-sdk/runtime-doctor-migrations";
@@ -137,10 +137,10 @@ const stateMigrations = [{
137
137
  doctorOnly: true,
138
138
  phase: "after-session-repair",
139
139
  async detectLegacyState(input) {
140
- return (await import("./session-owner-migration-D36AH9RC.js")).acpxSessionOwnerMigration.detectLegacyState(input);
140
+ return (await import("./.setup/session-owner-migration-CdJSYRk1.mjs")).acpxSessionOwnerMigration.detectLegacyState(input);
141
141
  },
142
142
  async migrateLegacyState(input) {
143
- return (await import("./session-owner-migration-D36AH9RC.js")).acpxSessionOwnerMigration.migrateLegacyState(input);
143
+ return (await import("./.setup/session-owner-migration-CdJSYRk1.mjs")).acpxSessionOwnerMigration.migrateLegacyState(input);
144
144
  }
145
145
  }];
146
146
  //#endregion
package/dist/index.js CHANGED
@@ -1,14 +1,232 @@
1
- import { t as createAcpxRuntimeService } from "./register.runtime-CksaMeEx.js";
2
- import "./config-schema-DN_uAi4R.js";
3
- import { a as PI_SESSIONS_CAPABILITY, c as PI_SESSION_READ_COMMAND, l as PI_TERMINAL_RESUME_COMMAND, o as PI_SESSIONS_LIST_COMMAND, r as piSessionStoreAvailable, s as PI_SESSION_ID_PATTERN } from "./pi-session-paths-EMbd4Hkz.js";
1
+ import { t as createAcpxRuntimeService } from "./.setup/register.runtime-Bm4HrMCp.mjs";
2
+ import { a as ACPX_NATIVE_AGENT_IDS, o as AcpxNativeAgentsSchema, t as resolveAcpxPluginConfig } from "./.setup/config-CdPsIued.mjs";
3
+ import { a as PI_SESSIONS_CAPABILITY, c as PI_SESSION_READ_COMMAND, l as PI_TERMINAL_RESUME_COMMAND, o as PI_SESSIONS_LIST_COMMAND, r as piSessionStoreAvailable, s as PI_SESSION_ID_PATTERN } from "./.setup/pi-session-paths-CIvyk6KB.mjs";
4
+ import { createAgentRegistry } from "acpx/agent-registry";
4
5
  import { tryDispatchAcpReplyHook } from "openclaw/plugin-sdk/acp-runtime-backend";
5
- import { finiteSecondsToTimerSafeMilliseconds } from "openclaw/plugin-sdk/number-runtime";
6
6
  import { createLazyRuntimeModule, createLazyRuntimeSurface } from "openclaw/plugin-sdk/lazy-runtime";
7
+ import { inspectAgentModels } from "acpx/runtime";
8
+ import { finiteSecondsToTimerSafeMilliseconds } from "openclaw/plugin-sdk/number-runtime";
9
+ import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
7
10
  import { resolveNodeHostExecutable } from "openclaw/plugin-sdk/node-host";
8
11
  import { createSessionCatalogNodeHostBindings } from "openclaw/plugin-sdk/session-catalog";
9
- import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
12
+ //#region extensions/acpx/src/native-agents.ts
13
+ function isAcpxNativeAgentEnabled(flags, agent) {
14
+ return AcpxNativeAgentsSchema.parse(flags)?.[agent] !== false;
15
+ }
16
+ function createAcpxAgentRegistry(rawConfig) {
17
+ const config = resolveAcpxPluginConfig({ rawConfig });
18
+ return createAgentRegistry({ overrides: config.agents });
19
+ }
20
+ function listAcpxNativeAgents(rawConfig, agents) {
21
+ const registry = createAcpxAgentRegistry(rawConfig);
22
+ const enabled = AcpxNativeAgentsSchema.parse(rawConfig?.nativeAgents);
23
+ return agents.map((agent) => ({
24
+ ...agent,
25
+ installation: registry.inspect(agent.id)?.launch.kind ?? "unverified",
26
+ enabled: enabled?.[agent.id] !== false
27
+ }));
28
+ }
29
+ //#endregion
30
+ //#region extensions/acpx/src/harness.ts
31
+ const LOCAL_TOOL_REQUIREMENTS = [
32
+ "ls",
33
+ "read",
34
+ "write",
35
+ "edit",
36
+ "exec"
37
+ ];
38
+ const NATIVE_TOOL_REQUIREMENTS = {
39
+ opencode: [
40
+ ...LOCAL_TOOL_REQUIREMENTS,
41
+ "apply_patch",
42
+ "web_fetch",
43
+ "web_search",
44
+ "sessions_spawn",
45
+ "sessions_send",
46
+ "ask_user"
47
+ ],
48
+ qwen: [
49
+ ...LOCAL_TOOL_REQUIREMENTS,
50
+ "process",
51
+ "sessions_spawn",
52
+ "sessions_send",
53
+ "sessions_list",
54
+ "subagents",
55
+ "web_fetch",
56
+ "web_search",
57
+ "view_image",
58
+ "ask_user",
59
+ "automations",
60
+ "image_generate"
61
+ ],
62
+ pi: LOCAL_TOOL_REQUIREMENTS,
63
+ kilocode: [
64
+ ...LOCAL_TOOL_REQUIREMENTS,
65
+ "apply_patch",
66
+ "web_fetch",
67
+ "web_search",
68
+ "sessions_spawn",
69
+ "sessions_send",
70
+ "sessions_search",
71
+ "sessions_history",
72
+ "memory_search",
73
+ "memory_get",
74
+ "message",
75
+ "image_generate"
76
+ ],
77
+ copilot: [
78
+ ...LOCAL_TOOL_REQUIREMENTS,
79
+ "apply_patch",
80
+ "process",
81
+ "browser",
82
+ "web_fetch",
83
+ "web_search",
84
+ "sessions_spawn",
85
+ "sessions_send",
86
+ "sessions_list",
87
+ "sessions_search",
88
+ "sessions_history",
89
+ "subagents",
90
+ "memory_search",
91
+ "memory_get",
92
+ "view_image",
93
+ "ask_user"
94
+ ]
95
+ };
96
+ function createAcpAgentHarness(params) {
97
+ const id = `acp-${params.agent}`;
98
+ const generation = new AbortController();
99
+ let agentRegistry;
100
+ const inspectAgent = () => (agentRegistry ??= createAcpxAgentRegistry(params.api.pluginConfig)).inspect(params.agent);
101
+ const runtimeFor = (workspaceDir) => params.getRuntime({
102
+ config: params.api.config,
103
+ workspaceDir,
104
+ stateDir: params.api.runtime.state.resolveStateDir(),
105
+ logger: params.api.logger
106
+ });
107
+ const resource = (agentId, sessionId) => `agent:${agentId}:harness:${id}:${sessionId}`;
108
+ const retire = async (input, assertCurrent) => {
109
+ const runtime = await runtimeFor();
110
+ assertCurrent();
111
+ const handle = await runtime.findSession({
112
+ sessionKey: resource(input.agentId, input.sessionId),
113
+ agent: params.agent,
114
+ agentId: input.agentId
115
+ });
116
+ assertCurrent();
117
+ if (handle) {
118
+ const ownedHandle = {
119
+ ...handle,
120
+ bridgeSession: {
121
+ sessionKey: input.sessionKey,
122
+ agentId: input.agentId,
123
+ native: true
124
+ }
125
+ };
126
+ await runtime.prepareFreshSession({ handle: ownedHandle });
127
+ }
128
+ };
129
+ return {
130
+ id,
131
+ label: params.label,
132
+ autoSelection: { providerIds: [] },
133
+ authBootstrap: "harness",
134
+ executionEnvironment: "host-only",
135
+ conversationToolPolicyNativeTools: NATIVE_TOOL_REQUIREMENTS[params.agent],
136
+ supports: ({ requestedRuntime, modelProvider }) => {
137
+ if (!params.isEnabled()) return {
138
+ supported: false,
139
+ reason: `${params.label} is disabled in Models settings.`
140
+ };
141
+ if (requestedRuntime !== id) return {
142
+ supported: false,
143
+ reason: `Choose ${params.label} explicitly`
144
+ };
145
+ if (modelProvider?.endpointOverrides === void 0) return {
146
+ supported: false,
147
+ reason: "Update OpenClaw to use this native runtime."
148
+ };
149
+ if (modelProvider?.requestTransportOverrides === "present" || modelProvider?.endpointOverrides === "present" || modelProvider?.preparedAuth?.source === "profile" || modelProvider?.preparedAuth?.source === "direct" || modelProvider?.runtimePolicy && !modelProvider.runtimePolicy.compatibleIds.includes(id)) return {
150
+ supported: false,
151
+ reason: `${params.label} owns its login and cannot use an OpenClaw credential or custom provider transport`
152
+ };
153
+ return {
154
+ supported: true,
155
+ priority: 100
156
+ };
157
+ },
158
+ async loadModelCatalog(input) {
159
+ generation.signal.throwIfAborted();
160
+ if (!params.isEnabled()) return [];
161
+ const inspection = inspectAgent();
162
+ if (inspection?.launch.kind !== "installed") return [];
163
+ const config = resolveAcpxPluginConfig({
164
+ rawConfig: params.api.pluginConfig,
165
+ workspaceDir: input.workspaceDir
166
+ });
167
+ const models = await inspectAgentModels({
168
+ agentCommand: inspection.launch.argv,
169
+ cwd: input.workspaceDir ?? config.cwd,
170
+ signal: generation.signal,
171
+ timeoutMs: config.timeoutSeconds === void 0 ? void 0 : finiteSecondsToTimerSafeMilliseconds(config.timeoutSeconds) ?? 1
172
+ });
173
+ generation.signal.throwIfAborted();
174
+ return (params.isEnabled() ? models?.availableModels ?? [] : []).map((model) => ({
175
+ provider: id,
176
+ id: model.modelId,
177
+ name: model.name,
178
+ nativeRuntime: id
179
+ }));
180
+ },
181
+ async runAttempt(input) {
182
+ generation.signal.throwIfAborted();
183
+ if (!params.isEnabled()) throw new Error(`${params.label} is disabled. Enable it in Models settings to start a turn.`);
184
+ const inspection = inspectAgent();
185
+ if (inspection?.launch.kind !== "installed") throw new Error(`${params.label} is not installed; refresh the model catalog`);
186
+ const runtime = await runtimeFor(input.workspaceDir);
187
+ generation.signal.throwIfAborted();
188
+ const { runAcpHarnessAttempt } = await import("./.setup/harness-attempt-CDXMeP5Z.mjs");
189
+ return await runAcpHarnessAttempt({
190
+ input,
191
+ runtime,
192
+ agent: params.agent,
193
+ harnessId: id,
194
+ label: params.label,
195
+ command: inspection.launch.argv,
196
+ generationSignal: generation.signal
197
+ });
198
+ },
199
+ async reset(input) {
200
+ if (input.agentId && input.sessionId && input.sessionKey) await retire({
201
+ agentId: input.agentId,
202
+ sessionId: input.sessionId,
203
+ sessionKey: input.sessionKey
204
+ }, () => generation.signal.throwIfAborted());
205
+ },
206
+ async withSessionDeletion(input, run) {
207
+ let committed = false;
208
+ try {
209
+ return await run({
210
+ commit: () => {
211
+ committed = true;
212
+ },
213
+ rollback: () => {
214
+ committed = false;
215
+ }
216
+ });
217
+ } finally {
218
+ if (committed) await retire(input, input.assertCurrent);
219
+ }
220
+ },
221
+ async dispose() {
222
+ generation.abort();
223
+ await params.shutdown();
224
+ }
225
+ };
226
+ }
227
+ //#endregion
10
228
  //#region extensions/acpx/src/pi-session-catalog-plugin.ts
11
- const loadPiSessionCatalogModule = createLazyRuntimeModule(() => import("./pi-session-catalog-runtime-BrPX6xQV.js"));
229
+ const loadPiSessionCatalogModule = createLazyRuntimeModule(() => import("./.setup/pi-session-catalog-runtime-UhiQSaDw.mjs"));
12
230
  function fullConfigCatalogEnabled(config) {
13
231
  if (!isRecord(config) || !isRecord(config.plugins) || !isRecord(config.plugins.entries)) return true;
14
232
  const entry = config.plugins.entries.acpx;
@@ -27,6 +245,7 @@ function createPiSessionNodeHostBindings() {
27
245
  terminalCommand: PI_TERMINAL_RESUME_COMMAND,
28
246
  sessionIdPattern: PI_SESSION_ID_PATTERN,
29
247
  executable: "pi",
248
+ hasActiveWork: () => false,
30
249
  args: (threadId) => ["--session", threadId],
31
250
  listAvailable: storeAvailable,
32
251
  terminalAvailable: ({ config, env }) => storeAvailable({
@@ -76,39 +295,56 @@ function registerPiSessionCatalog(api) {
76
295
  * ACPX runtime plugin entry. It registers the embedded ACP backend service and
77
296
  * wires reply-dispatch hooks into the plugin SDK runtime.
78
297
  */
79
- function resolveReplyDispatchTimeoutMs(pluginConfig) {
80
- const timeoutSeconds = pluginConfig?.timeoutSeconds;
81
- return finiteSecondsToTimerSafeMilliseconds(typeof timeoutSeconds === "number" && Number.isFinite(timeoutSeconds) && timeoutSeconds > 0 ? timeoutSeconds : 120) ?? 1;
82
- }
83
- async function tryDispatchAcpReplyHookWithTimeout(event, ctx, timeoutMs) {
84
- const timeoutController = new AbortController();
85
- const timeout = setTimeout(() => timeoutController.abort(), timeoutMs);
86
- timeout.unref?.();
87
- const abortSignal = ctx.abortSignal ? AbortSignal.any([ctx.abortSignal, timeoutController.signal]) : timeoutController.signal;
88
- try {
89
- return await tryDispatchAcpReplyHook(event, {
90
- ...ctx,
91
- abortSignal
92
- });
93
- } finally {
94
- clearTimeout(timeout);
95
- }
96
- }
97
298
  const plugin = {
98
299
  id: "acpx",
99
300
  name: "ACPX Runtime",
100
301
  description: "Embedded ACP runtime backend with plugin-owned session and transport management.",
101
302
  register(api) {
102
- const replyDispatchTimeoutMs = resolveReplyDispatchTimeoutMs(api.pluginConfig);
103
303
  registerPiSessionCatalog(api);
104
- api.registerService(createAcpxRuntimeService({
304
+ const service = createAcpxRuntimeService({
105
305
  pluginConfig: api.pluginConfig,
306
+ getAllowedAgents: () => api.runtime.config.current().acp?.allowedAgents,
106
307
  openKeyedStore: (options) => api.runtime.state.openKeyedStore(options)
107
- }));
108
- api.on("reply_dispatch", (event, ctx) => tryDispatchAcpReplyHookWithTimeout(event, ctx, replyDispatchTimeoutMs), {
109
- timeoutMs: replyDispatchTimeoutMs,
110
- eligibleDispatchKinds: ["acp"]
111
308
  });
309
+ api.registerService(service);
310
+ const currentConfig = () => api.runtime.config.current().plugins?.entries?.acpx?.config;
311
+ const registry = createAgentRegistry();
312
+ const nativeAgents = ACPX_NATIVE_AGENT_IDS.map((agentId) => {
313
+ const agent = registry.inspect(agentId);
314
+ if (!agent) throw new Error(`Unknown ACP harness: ${agentId}`);
315
+ api.registerAgentHarness(createAcpAgentHarness({
316
+ agent: agentId,
317
+ label: agent.name,
318
+ isEnabled: () => isAcpxNativeAgentEnabled(currentConfig()?.nativeAgents, agentId),
319
+ api,
320
+ getRuntime: service.getRuntime,
321
+ shutdown: () => service.stop?.({
322
+ config: api.config,
323
+ stateDir: api.runtime.state.resolveStateDir(),
324
+ logger: api.logger
325
+ })
326
+ }));
327
+ return {
328
+ id: agentId,
329
+ name: agent.name,
330
+ runtimeId: `acp-${agentId}`
331
+ };
332
+ });
333
+ api.registerReload({ noopPrefixes: ["plugins.entries.acpx.config.nativeAgents"] });
334
+ api.registerGatewayMethod("acpx.agents.list", ({ params, respond }) => {
335
+ if (Object.keys(params).length > 0) {
336
+ respond(false, void 0, {
337
+ code: "INVALID_REQUEST",
338
+ message: "acpx.agents.list takes no parameters"
339
+ });
340
+ return;
341
+ }
342
+ respond(true, { agents: listAcpxNativeAgents(currentConfig(), nativeAgents) }, void 0);
343
+ }, {
344
+ scope: "operator.read",
345
+ profileAccess: "independent"
346
+ });
347
+ api.on("reply_dispatch", tryDispatchAcpReplyHook, { eligibleDispatchKinds: ["acp"] });
112
348
  }
113
349
  };
114
350
  //#endregion
@@ -1,2 +1,2 @@
1
- import { t as createAcpxRuntimeService } from "./register.runtime-CksaMeEx.js";
1
+ import { t as createAcpxRuntimeService } from "./.setup/register.runtime-Bm4HrMCp.mjs";
2
2
  export { createAcpxRuntimeService };
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "id": "acpx",
3
- "categories": ["runtime", "tools"],
3
+ "categories": ["agent-runtimes"],
4
4
  "backupResources": [
5
5
  {
6
6
  "disposition": "regenerable",
@@ -25,12 +25,39 @@
25
25
  ]
26
26
  },
27
27
  "activation": {
28
- "onStartup": true
28
+ "onStartup": true,
29
+ "onAgentHarnesses": ["acp-opencode", "acp-qwen", "acp-pi", "acp-kilocode", "acp-copilot"]
29
30
  },
30
31
  "enabledByDefault": true,
31
32
  "name": "ACPX Runtime",
32
33
  "description": "OpenClaw ACP runtime backend with plugin-owned session and transport management.",
33
34
  "skills": ["./skills"],
35
+ "configGroups": [
36
+ {
37
+ "id": "agent-runtime",
38
+ "title": "Agent runtime",
39
+ "order": 10,
40
+ "properties": ["cwd", "stateDir", "probeAgent", "agents", "timeoutSeconds", "nativeAgents"]
41
+ },
42
+ {
43
+ "id": "permissions",
44
+ "title": "Permissions",
45
+ "order": 20,
46
+ "properties": ["permissionMode", "nonInteractivePermissions"]
47
+ },
48
+ {
49
+ "id": "tools-and-mcp-servers",
50
+ "title": "Tools and MCP servers",
51
+ "order": 30,
52
+ "properties": ["pluginToolsMcpBridge", "openClawToolsMcpBridge", "mcpServers"]
53
+ },
54
+ {
55
+ "id": "pi-sessions",
56
+ "title": "Pi sessions",
57
+ "order": 40,
58
+ "properties": ["piSessionCatalog"]
59
+ }
60
+ ],
34
61
  "configSchema": {
35
62
  "type": "object",
36
63
  "additionalProperties": false,
@@ -100,6 +127,17 @@
100
127
  "required": ["command"]
101
128
  }
102
129
  },
130
+ "nativeAgents": {
131
+ "type": "object",
132
+ "additionalProperties": false,
133
+ "properties": {
134
+ "opencode": { "type": "boolean" },
135
+ "qwen": { "type": "boolean" },
136
+ "pi": { "type": "boolean" },
137
+ "kilocode": { "type": "boolean" },
138
+ "copilot": { "type": "boolean" }
139
+ }
140
+ },
103
141
  "agents": {
104
142
  "type": "object",
105
143
  "additionalProperties": {
@@ -166,6 +204,10 @@
166
204
  "help": "Named MCP server definitions to inject into embedded ACP session bootstrap. Each entry needs a command and can include args and env.",
167
205
  "advanced": true
168
206
  },
207
+ "nativeAgents": {
208
+ "label": "Native agents",
209
+ "help": "Choose which installed agents can be used for new chat turns. Missing flags are enabled. Running turns and classic ACP sessions are unchanged."
210
+ },
169
211
  "agents": {
170
212
  "label": "Agent Commands",
171
213
  "help": "Optional per-agent command overrides for the embedded ACP runtime.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/acpx",
3
- "version": "2026.9.4",
3
+ "version": "2026.9.6",
4
4
  "description": "OpenClaw ACP runtime backend with plugin-owned session and transport management.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -8,11 +8,11 @@
8
8
  },
9
9
  "type": "module",
10
10
  "dependencies": {
11
- "@agentclientprotocol/claude-agent-acp": "0.70.0",
12
- "@agentclientprotocol/codex-acp": "1.6.2",
13
- "acpx": "0.13.2",
11
+ "@agentclientprotocol/claude-agent-acp": "0.76.0",
12
+ "@agentclientprotocol/codex-acp": "1.11.0",
13
+ "acpx": "0.19.0",
14
14
  "smol-toml": "1.8.0",
15
- "zod": "4.4.3"
15
+ "zod": "4.6.5"
16
16
  },
17
17
  "devDependencies": {
18
18
  "@openclaw/plugin-sdk": "workspace:*"
@@ -44,10 +44,10 @@
44
44
  ]
45
45
  },
46
46
  "compat": {
47
- "pluginApi": ">=2026.9.4"
47
+ "pluginApi": ">=2026.9.5"
48
48
  },
49
49
  "build": {
50
- "openclawVersion": "2026.9.4",
50
+ "openclawVersion": "2026.9.5",
51
51
  "staticAssets": [
52
52
  {
53
53
  "source": "./src/runtime-internals/mcp-proxy.mjs",
@@ -72,10 +72,12 @@
72
72
  "dist/**",
73
73
  "openclaw.plugin.json",
74
74
  "README.md",
75
+ "assets/icon.png",
76
+ "assets/activity.svg",
75
77
  "skills/**"
76
78
  ],
77
79
  "peerDependencies": {
78
- "openclaw": ">=2026.9.4"
80
+ "openclaw": ">=2026.9.5"
79
81
  },
80
82
  "peerDependenciesMeta": {
81
83
  "openclaw": {
@@ -209,8 +209,8 @@ ${ACPX_CMD} codex sessions close oc-codex-<conversationId>
209
209
  Defaults are:
210
210
 
211
211
  - `openclaw -> openclaw acp`
212
- - `claude -> bundled @agentclientprotocol/claude-agent-acp@0.70.0`
213
- - `codex -> bundled @agentclientprotocol/codex-acp@1.6.2 through OpenClaw's isolated CODEX_HOME wrapper`
212
+ - `claude -> bundled @agentclientprotocol/claude-agent-acp@0.76.0`
213
+ - `codex -> bundled @agentclientprotocol/codex-acp@1.11.0 through OpenClaw's isolated CODEX_HOME wrapper`
214
214
  - `copilot -> copilot --acp --stdio`
215
215
  - `cursor -> cursor-agent acp`
216
216
  - `droid -> droid exec --output-format acp`
@@ -1,37 +0,0 @@
1
- import { z } from "zod";
2
- //#region extensions/acpx/src/config-schema.ts
3
- /**
4
- * ACPX plugin configuration schema and public config types. Runtime setup uses
5
- * this file as the single source of truth for validation and defaulting.
6
- */
7
- const ACPX_PERMISSION_MODES = [
8
- "approve-all",
9
- "approve-reads",
10
- "deny-all"
11
- ];
12
- const ACPX_NON_INTERACTIVE_POLICIES = ["deny", "fail"];
13
- const nonEmptyTrimmedString = (message) => z.string({ error: message }).trim().min(1, { error: message });
14
- const McpServerConfigSchema = z.object({
15
- command: nonEmptyTrimmedString("command must be a non-empty string").describe("Command to run the MCP server"),
16
- 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"),
17
- 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")
18
- });
19
- /** Zod schema for validating raw ACPX plugin config from OpenClaw config. */
20
- const AcpxPluginConfigSchema = z.strictObject({
21
- cwd: nonEmptyTrimmedString("cwd must be a non-empty string").optional(),
22
- stateDir: nonEmptyTrimmedString("stateDir must be a non-empty string").optional(),
23
- probeAgent: nonEmptyTrimmedString("probeAgent must be a non-empty string").optional(),
24
- permissionMode: z.enum(ACPX_PERMISSION_MODES, { error: `permissionMode must be one of: ${ACPX_PERMISSION_MODES.join(", ")}` }).optional(),
25
- nonInteractivePermissions: z.enum(ACPX_NON_INTERACTIVE_POLICIES, { error: `nonInteractivePermissions must be one of: ${ACPX_NON_INTERACTIVE_POLICIES.join(", ")}` }).optional(),
26
- pluginToolsMcpBridge: z.boolean({ error: "pluginToolsMcpBridge must be a boolean" }).optional(),
27
- openClawToolsMcpBridge: z.boolean({ error: "openClawToolsMcpBridge must be a boolean" }).optional(),
28
- timeoutSeconds: z.number({ error: "timeoutSeconds must be a number >= 0.001" }).min(.001, { error: "timeoutSeconds must be a number >= 0.001" }).default(120),
29
- piSessionCatalog: z.strictObject({ enabled: z.boolean({ error: "piSessionCatalog.enabled must be a boolean" }).default(true) }).optional(),
30
- mcpServers: z.record(z.string(), McpServerConfigSchema).optional(),
31
- agents: z.record(z.string(), z.strictObject({
32
- command: nonEmptyTrimmedString("agents.<id>.command must be a non-empty string"),
33
- args: z.array(z.string({ error: "args must be an array of strings" })).optional()
34
- })).optional()
35
- });
36
- //#endregion
37
- export { AcpxPluginConfigSchema as t };
@@ -1,14 +0,0 @@
1
- import "node:module";
2
- //#region \0rolldown/runtime.js
3
- var __defProp = Object.defineProperty;
4
- var __exportAll = (all, no_symbols) => {
5
- let target = {};
6
- for (var name in all) __defProp(target, name, {
7
- get: all[name],
8
- enumerable: true
9
- });
10
- if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
11
- return target;
12
- };
13
- //#endregion
14
- export { __exportAll as t };