@openclaw/acpx 2026.5.27 → 2026.5.28-beta.1
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 +1 -1
- package/dist/mcp-proxy.mjs +7 -1
- package/dist/register.runtime-CIbEVqqU.js +250 -0
- package/dist/register.runtime.js +1 -247
- package/dist/{runtime-BMXFIXQq.js → runtime-BaP1xg1D.js} +2 -1
- package/dist/{service-CvQo2rym.js → service-Dj4-xaW3.js} +3 -143
- package/npm-shrinkwrap.json +2 -2
- package/package.json +4 -8
- package/skills/acp-router/SKILL.md +3 -6
- package/dist/error-format.mjs +0 -6
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createAcpxRuntimeService } from "./register.runtime.js";
|
|
1
|
+
import { t as createAcpxRuntimeService } from "./register.runtime-CIbEVqqU.js";
|
|
2
2
|
import { tryDispatchAcpReplyHook } from "openclaw/plugin-sdk/acp-runtime-backend";
|
|
3
3
|
//#region extensions/acpx/index.ts
|
|
4
4
|
const plugin = {
|
package/dist/mcp-proxy.mjs
CHANGED
|
@@ -4,9 +4,15 @@ import { spawn } from "node:child_process";
|
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { createInterface } from "node:readline";
|
|
6
6
|
import { pathToFileURL } from "node:url";
|
|
7
|
-
import { formatErrorMessage } from "./error-format.mjs";
|
|
8
7
|
import { splitCommandLine } from "./mcp-command-line.mjs";
|
|
9
8
|
|
|
9
|
+
function formatErrorMessage(error) {
|
|
10
|
+
if (error instanceof Error) {
|
|
11
|
+
return error.message || error.name || "Error";
|
|
12
|
+
}
|
|
13
|
+
return String(error);
|
|
14
|
+
}
|
|
15
|
+
|
|
10
16
|
function decodePayload(argv) {
|
|
11
17
|
const payloadIndex = argv.indexOf("--payload");
|
|
12
18
|
if (payloadIndex < 0) {
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import { getAcpRuntimeBackend, registerAcpRuntimeBackend, unregisterAcpRuntimeBackend } from "openclaw/plugin-sdk/acp-runtime-backend";
|
|
2
|
+
//#region extensions/acpx/src/runtime-turn.ts
|
|
3
|
+
function createDeferredResult() {
|
|
4
|
+
let resolve;
|
|
5
|
+
let reject;
|
|
6
|
+
return {
|
|
7
|
+
promise: new Promise((resolvePromise, rejectPromise) => {
|
|
8
|
+
resolve = resolvePromise;
|
|
9
|
+
reject = rejectPromise;
|
|
10
|
+
}),
|
|
11
|
+
resolve,
|
|
12
|
+
reject
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
var LegacyRunTurnEventQueue = class {
|
|
16
|
+
constructor() {
|
|
17
|
+
this.items = [];
|
|
18
|
+
this.waits = [];
|
|
19
|
+
this.closed = false;
|
|
20
|
+
}
|
|
21
|
+
push(item) {
|
|
22
|
+
if (this.closed) return;
|
|
23
|
+
const waiter = this.waits.shift();
|
|
24
|
+
if (waiter) {
|
|
25
|
+
waiter.resolve(item);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
this.items.push(item);
|
|
29
|
+
}
|
|
30
|
+
clear() {
|
|
31
|
+
this.items.length = 0;
|
|
32
|
+
}
|
|
33
|
+
close() {
|
|
34
|
+
if (this.closed) return;
|
|
35
|
+
this.closed = true;
|
|
36
|
+
for (const waiter of this.waits.splice(0)) waiter.resolve(null);
|
|
37
|
+
}
|
|
38
|
+
fail(error) {
|
|
39
|
+
if (this.closed) return;
|
|
40
|
+
this.error = error;
|
|
41
|
+
this.closed = true;
|
|
42
|
+
for (const waiter of this.waits.splice(0)) waiter.reject(error);
|
|
43
|
+
}
|
|
44
|
+
async next() {
|
|
45
|
+
const item = this.items.shift();
|
|
46
|
+
if (item) return item;
|
|
47
|
+
if (this.error) throw this.error;
|
|
48
|
+
if (this.closed) return null;
|
|
49
|
+
return await new Promise((resolve, reject) => {
|
|
50
|
+
this.waits.push({
|
|
51
|
+
resolve,
|
|
52
|
+
reject
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
async *iterate() {
|
|
57
|
+
for (;;) {
|
|
58
|
+
const item = await this.next();
|
|
59
|
+
if (!item) return;
|
|
60
|
+
yield item;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
function legacyRunTurnAsStartTurn(runtime, input) {
|
|
65
|
+
const result = createDeferredResult();
|
|
66
|
+
result.promise.catch(() => {});
|
|
67
|
+
const queue = new LegacyRunTurnEventQueue();
|
|
68
|
+
let resultSettled = false;
|
|
69
|
+
const settleResult = (next) => {
|
|
70
|
+
if (resultSettled) return;
|
|
71
|
+
resultSettled = true;
|
|
72
|
+
result.resolve(next);
|
|
73
|
+
};
|
|
74
|
+
(async () => {
|
|
75
|
+
try {
|
|
76
|
+
for await (const event of runtime.runTurn(input)) {
|
|
77
|
+
if (event.type === "done") {
|
|
78
|
+
settleResult({
|
|
79
|
+
status: "completed",
|
|
80
|
+
...event.stopReason ? { stopReason: event.stopReason } : {}
|
|
81
|
+
});
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
if (event.type === "error") {
|
|
85
|
+
settleResult({
|
|
86
|
+
status: "failed",
|
|
87
|
+
error: {
|
|
88
|
+
message: event.message,
|
|
89
|
+
...event.code ? { code: event.code } : {},
|
|
90
|
+
...event.detailCode ? { detailCode: event.detailCode } : {},
|
|
91
|
+
...event.retryable === void 0 ? {} : { retryable: event.retryable }
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
queue.push(event);
|
|
97
|
+
}
|
|
98
|
+
settleResult({
|
|
99
|
+
status: "failed",
|
|
100
|
+
error: {
|
|
101
|
+
code: "ACP_TURN_FAILED",
|
|
102
|
+
message: "ACP turn ended without a terminal done event."
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
} catch (error) {
|
|
106
|
+
result.reject(error);
|
|
107
|
+
queue.fail(error);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
queue.close();
|
|
111
|
+
})();
|
|
112
|
+
return {
|
|
113
|
+
requestId: input.requestId,
|
|
114
|
+
events: queue.iterate(),
|
|
115
|
+
result: result.promise,
|
|
116
|
+
async cancel(inputArgs) {
|
|
117
|
+
await runtime.cancel({
|
|
118
|
+
handle: input.handle,
|
|
119
|
+
reason: inputArgs?.reason
|
|
120
|
+
});
|
|
121
|
+
},
|
|
122
|
+
async closeStream() {
|
|
123
|
+
queue.clear();
|
|
124
|
+
queue.close();
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
function startRuntimeTurn(runtime, input) {
|
|
129
|
+
return runtime.startTurn?.(input) ?? legacyRunTurnAsStartTurn(runtime, input);
|
|
130
|
+
}
|
|
131
|
+
function lazyStartRuntimeTurn(resolveRuntime, input) {
|
|
132
|
+
const turnPromise = resolveRuntime().then((runtime) => startRuntimeTurn(runtime, input));
|
|
133
|
+
return {
|
|
134
|
+
requestId: input.requestId,
|
|
135
|
+
events: { async *[Symbol.asyncIterator]() {
|
|
136
|
+
yield* (await turnPromise).events;
|
|
137
|
+
} },
|
|
138
|
+
result: turnPromise.then((turn) => turn.result),
|
|
139
|
+
cancel(inputArgs) {
|
|
140
|
+
return turnPromise.then((turn) => turn.cancel(inputArgs));
|
|
141
|
+
},
|
|
142
|
+
closeStream(inputArgs) {
|
|
143
|
+
return turnPromise.then((turn) => turn.closeStream(inputArgs));
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
//#endregion
|
|
148
|
+
//#region extensions/acpx/register.runtime.ts
|
|
149
|
+
const ACPX_BACKEND_ID = "acpx";
|
|
150
|
+
let serviceModulePromise = null;
|
|
151
|
+
function loadServiceModule() {
|
|
152
|
+
serviceModulePromise ??= import("./service-Dj4-xaW3.js");
|
|
153
|
+
return serviceModulePromise;
|
|
154
|
+
}
|
|
155
|
+
async function startRealService(state) {
|
|
156
|
+
if (state.realRuntime) return state.realRuntime;
|
|
157
|
+
if (!state.ctx) throw new Error("ACPX runtime service is not started");
|
|
158
|
+
state.startPromise ??= (async () => {
|
|
159
|
+
const { createAcpxRuntimeService } = await loadServiceModule();
|
|
160
|
+
const service = createAcpxRuntimeService(state.params);
|
|
161
|
+
state.realService = service;
|
|
162
|
+
await service.start(state.ctx);
|
|
163
|
+
const backend = getAcpRuntimeBackend(ACPX_BACKEND_ID);
|
|
164
|
+
if (!backend?.runtime) throw new Error("ACPX runtime service did not register an ACP backend");
|
|
165
|
+
state.realRuntime = backend.runtime;
|
|
166
|
+
return state.realRuntime;
|
|
167
|
+
})();
|
|
168
|
+
try {
|
|
169
|
+
return await state.startPromise;
|
|
170
|
+
} catch (error) {
|
|
171
|
+
state.startPromise = null;
|
|
172
|
+
state.realService = null;
|
|
173
|
+
throw error;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
function createDeferredRuntime(state) {
|
|
177
|
+
const resolveRuntime = () => startRealService(state);
|
|
178
|
+
return {
|
|
179
|
+
async ensureSession(input) {
|
|
180
|
+
return await (await resolveRuntime()).ensureSession(input);
|
|
181
|
+
},
|
|
182
|
+
startTurn(input) {
|
|
183
|
+
return lazyStartRuntimeTurn(resolveRuntime, input);
|
|
184
|
+
},
|
|
185
|
+
async *runTurn(input) {
|
|
186
|
+
yield* (await resolveRuntime()).runTurn(input);
|
|
187
|
+
},
|
|
188
|
+
async getCapabilities(input) {
|
|
189
|
+
return await (await resolveRuntime()).getCapabilities?.(input) ?? { controls: [] };
|
|
190
|
+
},
|
|
191
|
+
async getStatus(input) {
|
|
192
|
+
return await (await resolveRuntime()).getStatus?.(input) ?? {};
|
|
193
|
+
},
|
|
194
|
+
async setMode(input) {
|
|
195
|
+
await (await resolveRuntime()).setMode?.(input);
|
|
196
|
+
},
|
|
197
|
+
async setConfigOption(input) {
|
|
198
|
+
await (await resolveRuntime()).setConfigOption?.(input);
|
|
199
|
+
},
|
|
200
|
+
async doctor() {
|
|
201
|
+
return await (await resolveRuntime()).doctor?.() ?? {
|
|
202
|
+
ok: true,
|
|
203
|
+
message: "ok"
|
|
204
|
+
};
|
|
205
|
+
},
|
|
206
|
+
async prepareFreshSession(input) {
|
|
207
|
+
await (await resolveRuntime()).prepareFreshSession?.(input);
|
|
208
|
+
},
|
|
209
|
+
async cancel(input) {
|
|
210
|
+
await (await resolveRuntime()).cancel(input);
|
|
211
|
+
},
|
|
212
|
+
async close(input) {
|
|
213
|
+
await (await resolveRuntime()).close(input);
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
function createAcpxRuntimeService(params = {}) {
|
|
218
|
+
const state = {
|
|
219
|
+
ctx: null,
|
|
220
|
+
params,
|
|
221
|
+
realRuntime: null,
|
|
222
|
+
realService: null,
|
|
223
|
+
startPromise: null
|
|
224
|
+
};
|
|
225
|
+
return {
|
|
226
|
+
id: "acpx-runtime",
|
|
227
|
+
async start(ctx) {
|
|
228
|
+
if (process.env.OPENCLAW_SKIP_ACPX_RUNTIME === "1") {
|
|
229
|
+
ctx.logger.info("skipping embedded acpx runtime backend (OPENCLAW_SKIP_ACPX_RUNTIME=1)");
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
state.ctx = ctx;
|
|
233
|
+
registerAcpRuntimeBackend({
|
|
234
|
+
id: ACPX_BACKEND_ID,
|
|
235
|
+
runtime: createDeferredRuntime(state)
|
|
236
|
+
});
|
|
237
|
+
ctx.logger.info("embedded acpx runtime backend registered lazily");
|
|
238
|
+
},
|
|
239
|
+
async stop(ctx) {
|
|
240
|
+
if (state.realService) await state.realService.stop?.(ctx);
|
|
241
|
+
else unregisterAcpRuntimeBackend(ACPX_BACKEND_ID);
|
|
242
|
+
state.ctx = null;
|
|
243
|
+
state.realRuntime = null;
|
|
244
|
+
state.realService = null;
|
|
245
|
+
state.startPromise = null;
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
//#endregion
|
|
250
|
+
export { lazyStartRuntimeTurn as n, createAcpxRuntimeService as t };
|
package/dist/register.runtime.js
CHANGED
|
@@ -1,248 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
//#region extensions/acpx/register.runtime.ts
|
|
3
|
-
const ACPX_BACKEND_ID = "acpx";
|
|
4
|
-
let serviceModulePromise = null;
|
|
5
|
-
function createDeferredResult() {
|
|
6
|
-
let resolve;
|
|
7
|
-
let reject;
|
|
8
|
-
return {
|
|
9
|
-
promise: new Promise((resolvePromise, rejectPromise) => {
|
|
10
|
-
resolve = resolvePromise;
|
|
11
|
-
reject = rejectPromise;
|
|
12
|
-
}),
|
|
13
|
-
resolve,
|
|
14
|
-
reject
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
var LegacyRunTurnEventQueue = class {
|
|
18
|
-
constructor() {
|
|
19
|
-
this.items = [];
|
|
20
|
-
this.waits = [];
|
|
21
|
-
this.closed = false;
|
|
22
|
-
}
|
|
23
|
-
push(item) {
|
|
24
|
-
if (this.closed) return;
|
|
25
|
-
const waiter = this.waits.shift();
|
|
26
|
-
if (waiter) {
|
|
27
|
-
waiter.resolve(item);
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
this.items.push(item);
|
|
31
|
-
}
|
|
32
|
-
clear() {
|
|
33
|
-
this.items.length = 0;
|
|
34
|
-
}
|
|
35
|
-
close() {
|
|
36
|
-
if (this.closed) return;
|
|
37
|
-
this.closed = true;
|
|
38
|
-
for (const waiter of this.waits.splice(0)) waiter.resolve(null);
|
|
39
|
-
}
|
|
40
|
-
fail(error) {
|
|
41
|
-
if (this.closed) return;
|
|
42
|
-
this.error = error;
|
|
43
|
-
this.closed = true;
|
|
44
|
-
for (const waiter of this.waits.splice(0)) waiter.reject(error);
|
|
45
|
-
}
|
|
46
|
-
async next() {
|
|
47
|
-
const item = this.items.shift();
|
|
48
|
-
if (item) return item;
|
|
49
|
-
if (this.error) throw this.error;
|
|
50
|
-
if (this.closed) return null;
|
|
51
|
-
return await new Promise((resolve, reject) => {
|
|
52
|
-
this.waits.push({
|
|
53
|
-
resolve,
|
|
54
|
-
reject
|
|
55
|
-
});
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
async *iterate() {
|
|
59
|
-
for (;;) {
|
|
60
|
-
const item = await this.next();
|
|
61
|
-
if (!item) return;
|
|
62
|
-
yield item;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
};
|
|
66
|
-
function loadServiceModule() {
|
|
67
|
-
serviceModulePromise ??= import("./service-CvQo2rym.js");
|
|
68
|
-
return serviceModulePromise;
|
|
69
|
-
}
|
|
70
|
-
async function startRealService(state) {
|
|
71
|
-
if (state.realRuntime) return state.realRuntime;
|
|
72
|
-
if (!state.ctx) throw new Error("ACPX runtime service is not started");
|
|
73
|
-
state.startPromise ??= (async () => {
|
|
74
|
-
const { createAcpxRuntimeService } = await loadServiceModule();
|
|
75
|
-
const service = createAcpxRuntimeService(state.params);
|
|
76
|
-
state.realService = service;
|
|
77
|
-
await service.start(state.ctx);
|
|
78
|
-
const backend = getAcpRuntimeBackend(ACPX_BACKEND_ID);
|
|
79
|
-
if (!backend?.runtime) throw new Error("ACPX runtime service did not register an ACP backend");
|
|
80
|
-
state.realRuntime = backend.runtime;
|
|
81
|
-
return state.realRuntime;
|
|
82
|
-
})();
|
|
83
|
-
try {
|
|
84
|
-
return await state.startPromise;
|
|
85
|
-
} catch (error) {
|
|
86
|
-
state.startPromise = null;
|
|
87
|
-
state.realService = null;
|
|
88
|
-
throw error;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
function lazyStartTurn(resolveRuntime, input) {
|
|
92
|
-
const turnPromise = resolveRuntime().then((runtime) => {
|
|
93
|
-
if (runtime.startTurn) return runtime.startTurn(input);
|
|
94
|
-
return legacyRunTurnAsStartTurn(runtime, input);
|
|
95
|
-
});
|
|
96
|
-
return {
|
|
97
|
-
requestId: input.requestId,
|
|
98
|
-
events: { async *[Symbol.asyncIterator]() {
|
|
99
|
-
yield* (await turnPromise).events;
|
|
100
|
-
} },
|
|
101
|
-
result: turnPromise.then((turn) => turn.result),
|
|
102
|
-
cancel(inputArgs) {
|
|
103
|
-
return turnPromise.then((turn) => turn.cancel(inputArgs));
|
|
104
|
-
},
|
|
105
|
-
closeStream(inputArgs) {
|
|
106
|
-
return turnPromise.then((turn) => turn.closeStream(inputArgs));
|
|
107
|
-
}
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
function legacyRunTurnAsStartTurn(runtime, input) {
|
|
111
|
-
const result = createDeferredResult();
|
|
112
|
-
result.promise.catch(() => {});
|
|
113
|
-
const queue = new LegacyRunTurnEventQueue();
|
|
114
|
-
let resultSettled = false;
|
|
115
|
-
const settleResult = (next) => {
|
|
116
|
-
if (resultSettled) return;
|
|
117
|
-
resultSettled = true;
|
|
118
|
-
result.resolve(next);
|
|
119
|
-
};
|
|
120
|
-
(async () => {
|
|
121
|
-
try {
|
|
122
|
-
for await (const event of runtime.runTurn(input)) {
|
|
123
|
-
if (event.type === "done") {
|
|
124
|
-
settleResult({
|
|
125
|
-
status: "completed",
|
|
126
|
-
...event.stopReason ? { stopReason: event.stopReason } : {}
|
|
127
|
-
});
|
|
128
|
-
continue;
|
|
129
|
-
}
|
|
130
|
-
if (event.type === "error") {
|
|
131
|
-
settleResult({
|
|
132
|
-
status: "failed",
|
|
133
|
-
error: {
|
|
134
|
-
message: event.message,
|
|
135
|
-
...event.code ? { code: event.code } : {},
|
|
136
|
-
...event.detailCode ? { detailCode: event.detailCode } : {},
|
|
137
|
-
...event.retryable === void 0 ? {} : { retryable: event.retryable }
|
|
138
|
-
}
|
|
139
|
-
});
|
|
140
|
-
continue;
|
|
141
|
-
}
|
|
142
|
-
queue.push(event);
|
|
143
|
-
}
|
|
144
|
-
settleResult({
|
|
145
|
-
status: "failed",
|
|
146
|
-
error: {
|
|
147
|
-
code: "ACP_TURN_FAILED",
|
|
148
|
-
message: "ACP turn ended without a terminal done event."
|
|
149
|
-
}
|
|
150
|
-
});
|
|
151
|
-
} catch (error) {
|
|
152
|
-
result.reject(error);
|
|
153
|
-
queue.fail(error);
|
|
154
|
-
return;
|
|
155
|
-
}
|
|
156
|
-
queue.close();
|
|
157
|
-
})();
|
|
158
|
-
return {
|
|
159
|
-
requestId: input.requestId,
|
|
160
|
-
events: queue.iterate(),
|
|
161
|
-
result: result.promise,
|
|
162
|
-
async cancel(inputArgs) {
|
|
163
|
-
await runtime.cancel({
|
|
164
|
-
handle: input.handle,
|
|
165
|
-
reason: inputArgs?.reason
|
|
166
|
-
});
|
|
167
|
-
},
|
|
168
|
-
async closeStream() {
|
|
169
|
-
queue.clear();
|
|
170
|
-
queue.close();
|
|
171
|
-
}
|
|
172
|
-
};
|
|
173
|
-
}
|
|
174
|
-
function createDeferredRuntime(state) {
|
|
175
|
-
const resolveRuntime = () => startRealService(state);
|
|
176
|
-
return {
|
|
177
|
-
async ensureSession(input) {
|
|
178
|
-
return await (await resolveRuntime()).ensureSession(input);
|
|
179
|
-
},
|
|
180
|
-
startTurn(input) {
|
|
181
|
-
return lazyStartTurn(resolveRuntime, input);
|
|
182
|
-
},
|
|
183
|
-
async *runTurn(input) {
|
|
184
|
-
yield* (await resolveRuntime()).runTurn(input);
|
|
185
|
-
},
|
|
186
|
-
async getCapabilities(input) {
|
|
187
|
-
return await (await resolveRuntime()).getCapabilities?.(input) ?? { controls: [] };
|
|
188
|
-
},
|
|
189
|
-
async getStatus(input) {
|
|
190
|
-
return await (await resolveRuntime()).getStatus?.(input) ?? {};
|
|
191
|
-
},
|
|
192
|
-
async setMode(input) {
|
|
193
|
-
await (await resolveRuntime()).setMode?.(input);
|
|
194
|
-
},
|
|
195
|
-
async setConfigOption(input) {
|
|
196
|
-
await (await resolveRuntime()).setConfigOption?.(input);
|
|
197
|
-
},
|
|
198
|
-
async doctor() {
|
|
199
|
-
return await (await resolveRuntime()).doctor?.() ?? {
|
|
200
|
-
ok: true,
|
|
201
|
-
message: "ok"
|
|
202
|
-
};
|
|
203
|
-
},
|
|
204
|
-
async prepareFreshSession(input) {
|
|
205
|
-
await (await resolveRuntime()).prepareFreshSession?.(input);
|
|
206
|
-
},
|
|
207
|
-
async cancel(input) {
|
|
208
|
-
await (await resolveRuntime()).cancel(input);
|
|
209
|
-
},
|
|
210
|
-
async close(input) {
|
|
211
|
-
await (await resolveRuntime()).close(input);
|
|
212
|
-
}
|
|
213
|
-
};
|
|
214
|
-
}
|
|
215
|
-
function createAcpxRuntimeService(params = {}) {
|
|
216
|
-
const state = {
|
|
217
|
-
ctx: null,
|
|
218
|
-
params,
|
|
219
|
-
realRuntime: null,
|
|
220
|
-
realService: null,
|
|
221
|
-
startPromise: null
|
|
222
|
-
};
|
|
223
|
-
return {
|
|
224
|
-
id: "acpx-runtime",
|
|
225
|
-
async start(ctx) {
|
|
226
|
-
if (process.env.OPENCLAW_SKIP_ACPX_RUNTIME === "1") {
|
|
227
|
-
ctx.logger.info("skipping embedded acpx runtime backend (OPENCLAW_SKIP_ACPX_RUNTIME=1)");
|
|
228
|
-
return;
|
|
229
|
-
}
|
|
230
|
-
state.ctx = ctx;
|
|
231
|
-
registerAcpRuntimeBackend({
|
|
232
|
-
id: ACPX_BACKEND_ID,
|
|
233
|
-
runtime: createDeferredRuntime(state)
|
|
234
|
-
});
|
|
235
|
-
ctx.logger.info("embedded acpx runtime backend registered lazily");
|
|
236
|
-
},
|
|
237
|
-
async stop(ctx) {
|
|
238
|
-
if (state.realService) await state.realService.stop?.(ctx);
|
|
239
|
-
else unregisterAcpRuntimeBackend(ACPX_BACKEND_ID);
|
|
240
|
-
state.ctx = null;
|
|
241
|
-
state.realRuntime = null;
|
|
242
|
-
state.realService = null;
|
|
243
|
-
state.startPromise = null;
|
|
244
|
-
}
|
|
245
|
-
};
|
|
246
|
-
}
|
|
247
|
-
//#endregion
|
|
1
|
+
import { t as createAcpxRuntimeService } from "./register.runtime-CIbEVqqU.js";
|
|
248
2
|
export { createAcpxRuntimeService };
|
|
@@ -5,6 +5,7 @@ import { AsyncLocalStorage } from "node:async_hooks";
|
|
|
5
5
|
import fs from "node:fs/promises";
|
|
6
6
|
import path, { resolve } from "node:path";
|
|
7
7
|
import { ACPX_BACKEND_ID, AcpxRuntime as AcpxRuntime$1, createAcpRuntime, createAgentRegistry, createFileSessionStore, decodeAcpxRuntimeHandleState, encodeAcpxRuntimeHandleState } from "acpx/runtime";
|
|
8
|
+
import { parseStrictPositiveInteger } from "openclaw/plugin-sdk/number-runtime";
|
|
8
9
|
import { redactSensitiveText } from "openclaw/plugin-sdk/security-runtime";
|
|
9
10
|
//#region extensions/acpx/src/runtime.ts
|
|
10
11
|
function withOpenClawManagedTurnTimeout(input) {
|
|
@@ -63,7 +64,7 @@ function readRecordAgentPid(record) {
|
|
|
63
64
|
if (typeof record !== "object" || record === null) return;
|
|
64
65
|
const { pid, processId } = record;
|
|
65
66
|
const rawPid = pid ?? processId;
|
|
66
|
-
const numericPid = typeof rawPid === "number" ? rawPid : typeof rawPid === "string" ?
|
|
67
|
+
const numericPid = typeof rawPid === "number" ? rawPid : typeof rawPid === "string" ? parseStrictPositiveInteger(rawPid) : void 0;
|
|
67
68
|
return numericPid && Number.isInteger(numericPid) && numericPid > 0 ? numericPid : void 0;
|
|
68
69
|
}
|
|
69
70
|
function readOpenClawLeaseIdFromRecord(record) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { n as lazyStartRuntimeTurn } from "./register.runtime-CIbEVqqU.js";
|
|
1
2
|
import { registerAcpRuntimeBackend, unregisterAcpRuntimeBackend } from "./runtime-api.js";
|
|
2
3
|
import { a as resolveAcpxPluginRoot, c as OPENCLAW_ACPX_LEASE_ID_ENV, d as createAcpxProcessLeaseStore, h as splitCommandParts, i as resolveAcpxPluginConfig, l as OPENCLAW_GATEWAY_INSTANCE_ID_ARG, m as quoteCommandPart, o as toAcpMcpServers, r as reapStaleOpenClawOwnedAcpxOrphans, s as OPENCLAW_ACPX_LEASE_ID_ARG, t as cleanupOpenClawOwnedAcpxProcessTree } from "./process-reaper-CAUlLOkM.js";
|
|
3
4
|
import { createRequire } from "node:module";
|
|
@@ -800,137 +801,9 @@ const SKIP_RUNTIME_PROBE_ENV = "OPENCLAW_SKIP_ACPX_RUNTIME_PROBE";
|
|
|
800
801
|
const ACPX_BACKEND_ID = "acpx";
|
|
801
802
|
let runtimeModulePromise = null;
|
|
802
803
|
function loadRuntimeModule() {
|
|
803
|
-
runtimeModulePromise ??= import("./runtime-
|
|
804
|
+
runtimeModulePromise ??= import("./runtime-BaP1xg1D.js");
|
|
804
805
|
return runtimeModulePromise;
|
|
805
806
|
}
|
|
806
|
-
function createDeferredResult() {
|
|
807
|
-
let resolve;
|
|
808
|
-
let reject;
|
|
809
|
-
return {
|
|
810
|
-
promise: new Promise((resolvePromise, rejectPromise) => {
|
|
811
|
-
resolve = resolvePromise;
|
|
812
|
-
reject = rejectPromise;
|
|
813
|
-
}),
|
|
814
|
-
resolve,
|
|
815
|
-
reject
|
|
816
|
-
};
|
|
817
|
-
}
|
|
818
|
-
var LegacyRunTurnEventQueue = class {
|
|
819
|
-
constructor() {
|
|
820
|
-
this.items = [];
|
|
821
|
-
this.waits = [];
|
|
822
|
-
this.closed = false;
|
|
823
|
-
}
|
|
824
|
-
push(item) {
|
|
825
|
-
if (this.closed) return;
|
|
826
|
-
const waiter = this.waits.shift();
|
|
827
|
-
if (waiter) {
|
|
828
|
-
waiter.resolve(item);
|
|
829
|
-
return;
|
|
830
|
-
}
|
|
831
|
-
this.items.push(item);
|
|
832
|
-
}
|
|
833
|
-
clear() {
|
|
834
|
-
this.items.length = 0;
|
|
835
|
-
}
|
|
836
|
-
close() {
|
|
837
|
-
if (this.closed) return;
|
|
838
|
-
this.closed = true;
|
|
839
|
-
for (const waiter of this.waits.splice(0)) waiter.resolve(null);
|
|
840
|
-
}
|
|
841
|
-
fail(error) {
|
|
842
|
-
if (this.closed) return;
|
|
843
|
-
this.error = error;
|
|
844
|
-
this.closed = true;
|
|
845
|
-
for (const waiter of this.waits.splice(0)) waiter.reject(error);
|
|
846
|
-
}
|
|
847
|
-
async next() {
|
|
848
|
-
const item = this.items.shift();
|
|
849
|
-
if (item) return item;
|
|
850
|
-
if (this.error) throw this.error;
|
|
851
|
-
if (this.closed) return null;
|
|
852
|
-
return await new Promise((resolve, reject) => {
|
|
853
|
-
this.waits.push({
|
|
854
|
-
resolve,
|
|
855
|
-
reject
|
|
856
|
-
});
|
|
857
|
-
});
|
|
858
|
-
}
|
|
859
|
-
async *iterate() {
|
|
860
|
-
for (;;) {
|
|
861
|
-
const item = await this.next();
|
|
862
|
-
if (!item) return;
|
|
863
|
-
yield item;
|
|
864
|
-
}
|
|
865
|
-
}
|
|
866
|
-
};
|
|
867
|
-
function legacyRunTurnAsStartTurn(runtime, input) {
|
|
868
|
-
const result = createDeferredResult();
|
|
869
|
-
result.promise.catch(() => {});
|
|
870
|
-
const queue = new LegacyRunTurnEventQueue();
|
|
871
|
-
let resultSettled = false;
|
|
872
|
-
const settleResult = (next) => {
|
|
873
|
-
if (resultSettled) return;
|
|
874
|
-
resultSettled = true;
|
|
875
|
-
result.resolve(next);
|
|
876
|
-
};
|
|
877
|
-
(async () => {
|
|
878
|
-
try {
|
|
879
|
-
for await (const event of runtime.runTurn(input)) {
|
|
880
|
-
if (event.type === "done") {
|
|
881
|
-
settleResult({
|
|
882
|
-
status: "completed",
|
|
883
|
-
...event.stopReason ? { stopReason: event.stopReason } : {}
|
|
884
|
-
});
|
|
885
|
-
continue;
|
|
886
|
-
}
|
|
887
|
-
if (event.type === "error") {
|
|
888
|
-
settleResult({
|
|
889
|
-
status: "failed",
|
|
890
|
-
error: {
|
|
891
|
-
message: event.message,
|
|
892
|
-
...event.code ? { code: event.code } : {},
|
|
893
|
-
...event.detailCode ? { detailCode: event.detailCode } : {},
|
|
894
|
-
...event.retryable === void 0 ? {} : { retryable: event.retryable }
|
|
895
|
-
}
|
|
896
|
-
});
|
|
897
|
-
continue;
|
|
898
|
-
}
|
|
899
|
-
queue.push(event);
|
|
900
|
-
}
|
|
901
|
-
settleResult({
|
|
902
|
-
status: "failed",
|
|
903
|
-
error: {
|
|
904
|
-
code: "ACP_TURN_FAILED",
|
|
905
|
-
message: "ACP turn ended without a terminal done event."
|
|
906
|
-
}
|
|
907
|
-
});
|
|
908
|
-
} catch (error) {
|
|
909
|
-
result.reject(error);
|
|
910
|
-
queue.fail(error);
|
|
911
|
-
return;
|
|
912
|
-
}
|
|
913
|
-
queue.close();
|
|
914
|
-
})();
|
|
915
|
-
return {
|
|
916
|
-
requestId: input.requestId,
|
|
917
|
-
events: queue.iterate(),
|
|
918
|
-
result: result.promise,
|
|
919
|
-
async cancel(inputArgs) {
|
|
920
|
-
await runtime.cancel({
|
|
921
|
-
handle: input.handle,
|
|
922
|
-
reason: inputArgs?.reason
|
|
923
|
-
});
|
|
924
|
-
},
|
|
925
|
-
async closeStream() {
|
|
926
|
-
queue.clear();
|
|
927
|
-
queue.close();
|
|
928
|
-
}
|
|
929
|
-
};
|
|
930
|
-
}
|
|
931
|
-
function startRuntimeTurn(runtime, input) {
|
|
932
|
-
return runtime.startTurn?.(input) ?? legacyRunTurnAsStartTurn(runtime, input);
|
|
933
|
-
}
|
|
934
807
|
function createLazyDefaultRuntime(params) {
|
|
935
808
|
let runtime = null;
|
|
936
809
|
let runtimePromise = null;
|
|
@@ -959,20 +832,7 @@ function createLazyDefaultRuntime(params) {
|
|
|
959
832
|
return await (await resolveRuntime()).ensureSession(input);
|
|
960
833
|
},
|
|
961
834
|
startTurn(input) {
|
|
962
|
-
|
|
963
|
-
return {
|
|
964
|
-
requestId: input.requestId,
|
|
965
|
-
events: { async *[Symbol.asyncIterator]() {
|
|
966
|
-
yield* (await turnPromise).events;
|
|
967
|
-
} },
|
|
968
|
-
result: turnPromise.then((turn) => turn.result),
|
|
969
|
-
cancel(inputArgs) {
|
|
970
|
-
return turnPromise.then((turn) => turn.cancel(inputArgs));
|
|
971
|
-
},
|
|
972
|
-
closeStream(inputArgs) {
|
|
973
|
-
return turnPromise.then((turn) => turn.closeStream(inputArgs));
|
|
974
|
-
}
|
|
975
|
-
};
|
|
835
|
+
return lazyStartRuntimeTurn(resolveRuntime, input);
|
|
976
836
|
},
|
|
977
837
|
async *runTurn(input) {
|
|
978
838
|
yield* (await resolveRuntime()).runTurn(input);
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/acpx",
|
|
3
|
-
"version": "2026.5.
|
|
3
|
+
"version": "2026.5.28-beta.1",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@openclaw/acpx",
|
|
9
|
-
"version": "2026.5.
|
|
9
|
+
"version": "2026.5.28-beta.1",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@agentclientprotocol/claude-agent-acp": "0.37.0",
|
|
12
12
|
"@zed-industries/codex-acp": "0.15.0",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/acpx",
|
|
3
|
-
"version": "2026.5.
|
|
3
|
+
"version": "2026.5.28-beta.1",
|
|
4
4
|
"description": "OpenClaw ACP runtime backend with plugin-owned session and transport management.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -26,19 +26,15 @@
|
|
|
26
26
|
"minHostVersion": ">=2026.4.25"
|
|
27
27
|
},
|
|
28
28
|
"compat": {
|
|
29
|
-
"pluginApi": ">=2026.5.
|
|
29
|
+
"pluginApi": ">=2026.5.28-beta.1"
|
|
30
30
|
},
|
|
31
31
|
"build": {
|
|
32
|
-
"openclawVersion": "2026.5.
|
|
32
|
+
"openclawVersion": "2026.5.28-beta.1",
|
|
33
33
|
"staticAssets": [
|
|
34
34
|
{
|
|
35
35
|
"source": "./src/runtime-internals/mcp-proxy.mjs",
|
|
36
36
|
"output": "mcp-proxy.mjs"
|
|
37
37
|
},
|
|
38
|
-
{
|
|
39
|
-
"source": "./src/runtime-internals/error-format.mjs",
|
|
40
|
-
"output": "error-format.mjs"
|
|
41
|
-
},
|
|
42
38
|
{
|
|
43
39
|
"source": "./src/runtime-internals/mcp-command-line.mjs",
|
|
44
40
|
"output": "mcp-command-line.mjs"
|
|
@@ -61,7 +57,7 @@
|
|
|
61
57
|
"skills/**"
|
|
62
58
|
],
|
|
63
59
|
"peerDependencies": {
|
|
64
|
-
"openclaw": ">=2026.5.
|
|
60
|
+
"openclaw": ">=2026.5.28-beta.1"
|
|
65
61
|
},
|
|
66
62
|
"peerDependenciesMeta": {
|
|
67
63
|
"openclaw": {
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: acp-router
|
|
3
|
-
description: Route plain-language requests for
|
|
3
|
+
description: Route plain-language requests for Claude Code, Cursor, Copilot, OpenClaw ACP, OpenCode, Gemini CLI, Qwen, Kiro, Kimi, iFlow, Factory Droid, Kilocode, or explicit ACP harness work into either OpenClaw ACP runtime sessions or direct acpx-driven sessions ("telephone game" flow). For coding-agent thread requests, read this skill first, then use only `sessions_spawn` for thread creation. Codex chat binding defaults to the native Codex app-server plugin unless ACP is explicit or background spawn needs ACP.
|
|
4
4
|
user-invocable: false
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# ACP Harness Router
|
|
8
8
|
|
|
9
|
-
When user intent is "run this in
|
|
9
|
+
When user intent is "run this in Claude Code/Cursor/Copilot/OpenClaw/OpenCode/Gemini/Qwen/Kiro/Kimi/iFlow/Droid/Kilocode (ACP harness)", do not use subagent runtime or PTY scraping. Route through ACP-aware flows.
|
|
10
10
|
|
|
11
11
|
Codex is special: plain chat/conversation binding and control should use the native Codex app-server plugin (`/codex bind`, `/codex threads`, `/codex resume`) instead of the default ACP path. Use ACP for Codex only when the user explicitly names ACP/`/acp`/acpx, or when spawning background child sessions through `sessions_spawn` where a native Codex runtime spawn is not available yet.
|
|
12
12
|
|
|
@@ -14,7 +14,7 @@ Codex is special: plain chat/conversation binding and control should use the nat
|
|
|
14
14
|
|
|
15
15
|
Trigger this skill when the user asks OpenClaw to:
|
|
16
16
|
|
|
17
|
-
- run something in
|
|
17
|
+
- run something in Claude Code / Cursor / Copilot / OpenClaw / OpenCode / Gemini / Qwen / Kiro / Kimi / iFlow / Droid / Kilocode
|
|
18
18
|
- run Codex explicitly through ACP, `/acp`, or acpx
|
|
19
19
|
- continue existing harness work
|
|
20
20
|
- relay instructions to an external coding harness
|
|
@@ -48,7 +48,6 @@ Do not use:
|
|
|
48
48
|
|
|
49
49
|
Use these defaults when user names a harness directly:
|
|
50
50
|
|
|
51
|
-
- "pi" -> `agentId: "pi"`
|
|
52
51
|
- "openclaw" -> `agentId: "openclaw"`
|
|
53
52
|
- "claude" or "claude code" -> `agentId: "claude"`
|
|
54
53
|
- "codex" -> `agentId: "codex"` only for explicit ACP/acpx requests or background ACP runtime spawn
|
|
@@ -203,7 +202,6 @@ ${ACPX_CMD} codex sessions close oc-codex-<conversationId>
|
|
|
203
202
|
- `kiro`
|
|
204
203
|
- `openclaw`
|
|
205
204
|
- `opencode`
|
|
206
|
-
- `pi`
|
|
207
205
|
- `qwen`
|
|
208
206
|
|
|
209
207
|
### Built-in adapter commands in acpx
|
|
@@ -222,7 +220,6 @@ Defaults are:
|
|
|
222
220
|
- `kimi -> kimi acp`
|
|
223
221
|
- `kiro -> kiro-cli acp`
|
|
224
222
|
- `opencode -> npx -y opencode-ai acp`
|
|
225
|
-
- `pi -> npx pi-acp@^0.0.22`
|
|
226
223
|
- `qwen -> qwen --acp`
|
|
227
224
|
|
|
228
225
|
If `~/.acpx/config.json` overrides `agents`, those overrides replace defaults.
|