@yesod/openclaw 0.0.2 → 0.1.0
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/README.md +10 -2
- package/dist/chunk-XNL6KP5G.js +861 -0
- package/dist/chunk-XNL6KP5G.js.map +1 -0
- package/dist/index.cjs +850 -36
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +152 -32
- package/dist/index.d.ts +152 -32
- package/dist/index.js +23 -55
- package/dist/index.js.map +1 -1
- package/dist/mcp-entry.cjs +886 -0
- package/dist/mcp-entry.cjs.map +1 -0
- package/dist/mcp-entry.d.cts +1 -0
- package/dist/mcp-entry.d.ts +1 -0
- package/dist/mcp-entry.js +47 -0
- package/dist/mcp-entry.js.map +1 -0
- package/package.json +5 -2
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,74 +17,886 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/index.ts
|
|
21
31
|
var index_exports = {};
|
|
22
32
|
__export(index_exports, {
|
|
23
|
-
GatewayApiClient: () => GatewayApiClient,
|
|
24
33
|
GatewayWebSocketClient: () => GatewayWebSocketClient,
|
|
25
|
-
OpenClawAdapter: () => OpenClawAdapter
|
|
34
|
+
OpenClawAdapter: () => OpenClawAdapter,
|
|
35
|
+
buildAuthPayload: () => buildAuthPayload,
|
|
36
|
+
createYesodMcpServer: () => createYesodMcpServer,
|
|
37
|
+
deviceIdFromPrivateKey: () => deviceIdFromPrivateKey,
|
|
38
|
+
enrichInstruction: () => enrichInstruction,
|
|
39
|
+
generateDeviceIdentity: () => generateDeviceIdentity,
|
|
40
|
+
loadOrCreateIdentity: () => loadOrCreateIdentity,
|
|
41
|
+
parseOutput: () => parseOutput,
|
|
42
|
+
signPayload: () => signPayload,
|
|
43
|
+
startMcpServer: () => startMcpServer
|
|
26
44
|
});
|
|
27
45
|
module.exports = __toCommonJS(index_exports);
|
|
28
46
|
|
|
29
47
|
// src/adapter.ts
|
|
30
|
-
var
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
48
|
+
var import_node_crypto2 = require("crypto");
|
|
49
|
+
var import_core = require("@yesod/core");
|
|
50
|
+
|
|
51
|
+
// src/websocket.ts
|
|
52
|
+
var import_ws = __toESM(require("ws"), 1);
|
|
53
|
+
|
|
54
|
+
// src/identity.ts
|
|
55
|
+
var import_node_crypto = require("crypto");
|
|
56
|
+
var import_node_fs = require("fs");
|
|
57
|
+
var import_node_path = require("path");
|
|
58
|
+
var import_node_os = require("os");
|
|
59
|
+
var PROTOCOL_VERSION = "v2";
|
|
60
|
+
var DEFAULT_IDENTITY_PATH = (0, import_node_path.join)((0, import_node_os.homedir)(), ".yesod", "device.json");
|
|
61
|
+
function generateDeviceIdentity() {
|
|
62
|
+
const { publicKey, privateKey } = (0, import_node_crypto.generateKeyPairSync)("ed25519");
|
|
63
|
+
const pubKeyDer = publicKey.export({ type: "spki", format: "der" });
|
|
64
|
+
const pubKeyRaw = pubKeyDer.subarray(pubKeyDer.length - 32);
|
|
65
|
+
const publicKeyB64Url = pubKeyRaw.toString("base64url");
|
|
66
|
+
const deviceId = (0, import_node_crypto.createHash)("sha256").update(pubKeyRaw).digest("hex");
|
|
67
|
+
const privateKeyPem = privateKey.export({ type: "pkcs8", format: "pem" }).toString();
|
|
68
|
+
return { deviceId, publicKeyB64Url, privateKeyPem };
|
|
69
|
+
}
|
|
70
|
+
function loadOrCreateIdentity(path = DEFAULT_IDENTITY_PATH) {
|
|
71
|
+
if ((0, import_node_fs.existsSync)(path)) {
|
|
72
|
+
const data = JSON.parse((0, import_node_fs.readFileSync)(path, "utf-8"));
|
|
73
|
+
return data;
|
|
74
|
+
}
|
|
75
|
+
const identity = generateDeviceIdentity();
|
|
76
|
+
const dir = (0, import_node_path.dirname)(path);
|
|
77
|
+
if (!(0, import_node_fs.existsSync)(dir)) {
|
|
78
|
+
(0, import_node_fs.mkdirSync)(dir, { recursive: true });
|
|
34
79
|
}
|
|
80
|
+
(0, import_node_fs.writeFileSync)(path, JSON.stringify(identity, null, 2), "utf-8");
|
|
81
|
+
return identity;
|
|
82
|
+
}
|
|
83
|
+
function signPayload(privateKeyPem, payload) {
|
|
84
|
+
const sig = (0, import_node_crypto.sign)(null, Buffer.from(payload), privateKeyPem);
|
|
85
|
+
return sig.toString("base64url");
|
|
86
|
+
}
|
|
87
|
+
function buildAuthPayload(deviceId, clientId, nonce, scopes, token = "") {
|
|
88
|
+
const signedAtMs = Date.now();
|
|
89
|
+
const parts = [
|
|
90
|
+
PROTOCOL_VERSION,
|
|
91
|
+
deviceId,
|
|
92
|
+
clientId,
|
|
93
|
+
clientId,
|
|
94
|
+
// clientMode = clientId
|
|
95
|
+
"operator",
|
|
96
|
+
scopes.join(","),
|
|
97
|
+
String(signedAtMs),
|
|
98
|
+
token,
|
|
99
|
+
nonce
|
|
100
|
+
];
|
|
101
|
+
return { payload: parts.join("|"), signedAtMs };
|
|
102
|
+
}
|
|
103
|
+
function deviceIdFromPrivateKey(privateKeyPem) {
|
|
104
|
+
const pubKey = (0, import_node_crypto.createPublicKey)(privateKeyPem);
|
|
105
|
+
const pubKeyDer = pubKey.export({ type: "spki", format: "der" });
|
|
106
|
+
const pubKeyRaw = pubKeyDer.subarray(pubKeyDer.length - 32);
|
|
107
|
+
return (0, import_node_crypto.createHash)("sha256").update(pubKeyRaw).digest("hex");
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// src/websocket.ts
|
|
111
|
+
var PROTOCOL_VERSION2 = 3;
|
|
112
|
+
var DEFAULT_SCOPES = ["operator.read", "operator.write", "operator.admin"];
|
|
113
|
+
var GatewayWebSocketClient = class {
|
|
114
|
+
ws = null;
|
|
115
|
+
identity;
|
|
116
|
+
scopes;
|
|
117
|
+
clientId;
|
|
118
|
+
displayName;
|
|
119
|
+
reqCounter = 0;
|
|
120
|
+
pendingRequests = /* @__PURE__ */ new Map();
|
|
121
|
+
eventHandlers = [];
|
|
122
|
+
connected = false;
|
|
123
|
+
disposed = false;
|
|
124
|
+
reconnectEnabled;
|
|
125
|
+
maxReconnectDelay;
|
|
126
|
+
reconnectDelay = 1e3;
|
|
127
|
+
reconnectTimer = null;
|
|
35
128
|
gatewayUrl;
|
|
36
|
-
|
|
129
|
+
constructor(config) {
|
|
130
|
+
this.gatewayUrl = config.gatewayUrl;
|
|
131
|
+
this.identity = config.identity ?? generateDeviceIdentity();
|
|
132
|
+
this.scopes = config.scopes ?? DEFAULT_SCOPES;
|
|
133
|
+
this.clientId = config.clientId ?? "cli";
|
|
134
|
+
this.displayName = config.displayName ?? "yesod";
|
|
135
|
+
this.reconnectEnabled = config.reconnect ?? false;
|
|
136
|
+
this.maxReconnectDelay = config.maxReconnectDelayMs ?? 3e4;
|
|
137
|
+
}
|
|
37
138
|
async connect() {
|
|
139
|
+
if (this.connected) return;
|
|
140
|
+
return new Promise((resolve, reject) => {
|
|
141
|
+
const ws = new import_ws.default(this.gatewayUrl);
|
|
142
|
+
this.ws = ws;
|
|
143
|
+
const timeout = setTimeout(() => {
|
|
144
|
+
ws.close();
|
|
145
|
+
reject(new Error("Connection timeout"));
|
|
146
|
+
}, 15e3);
|
|
147
|
+
ws.on("error", (err) => {
|
|
148
|
+
clearTimeout(timeout);
|
|
149
|
+
reject(err);
|
|
150
|
+
});
|
|
151
|
+
ws.on("open", async () => {
|
|
152
|
+
try {
|
|
153
|
+
await this.handleAuth(ws);
|
|
154
|
+
clearTimeout(timeout);
|
|
155
|
+
this.connected = true;
|
|
156
|
+
this.reconnectDelay = 1e3;
|
|
157
|
+
this.setupMessageHandler(ws);
|
|
158
|
+
this.setupCloseHandler(ws);
|
|
159
|
+
resolve();
|
|
160
|
+
} catch (err) {
|
|
161
|
+
clearTimeout(timeout);
|
|
162
|
+
ws.close();
|
|
163
|
+
reject(err);
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
});
|
|
38
167
|
}
|
|
39
|
-
async
|
|
168
|
+
async handleAuth(ws) {
|
|
169
|
+
const challenge = await this.waitForFrame(
|
|
170
|
+
ws,
|
|
171
|
+
(f) => f.type === "event" && f.event === "connect.challenge",
|
|
172
|
+
1e4
|
|
173
|
+
);
|
|
174
|
+
const nonce = challenge.payload.nonce;
|
|
175
|
+
const { payload: authPayload, signedAtMs } = buildAuthPayload(
|
|
176
|
+
this.identity.deviceId,
|
|
177
|
+
this.clientId,
|
|
178
|
+
nonce,
|
|
179
|
+
this.scopes
|
|
180
|
+
);
|
|
181
|
+
const signature = signPayload(this.identity.privateKeyPem, authPayload);
|
|
182
|
+
const connectId = `r${++this.reqCounter}`;
|
|
183
|
+
const connectReq = {
|
|
184
|
+
type: "req",
|
|
185
|
+
id: connectId,
|
|
186
|
+
method: "connect",
|
|
187
|
+
params: {
|
|
188
|
+
minProtocol: PROTOCOL_VERSION2,
|
|
189
|
+
maxProtocol: PROTOCOL_VERSION2,
|
|
190
|
+
client: {
|
|
191
|
+
id: this.clientId,
|
|
192
|
+
displayName: this.displayName,
|
|
193
|
+
version: "0.0.2",
|
|
194
|
+
platform: "linux",
|
|
195
|
+
mode: this.clientId
|
|
196
|
+
},
|
|
197
|
+
role: "operator",
|
|
198
|
+
scopes: this.scopes,
|
|
199
|
+
caps: ["tool-events"],
|
|
200
|
+
device: {
|
|
201
|
+
id: this.identity.deviceId,
|
|
202
|
+
publicKey: this.identity.publicKeyB64Url,
|
|
203
|
+
signature,
|
|
204
|
+
signedAt: signedAtMs,
|
|
205
|
+
nonce
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
ws.send(JSON.stringify(connectReq));
|
|
210
|
+
const res = await this.waitForFrame(
|
|
211
|
+
ws,
|
|
212
|
+
(f) => f.type === "res" && f.id === connectId,
|
|
213
|
+
15e3
|
|
214
|
+
);
|
|
215
|
+
const resFrame = res;
|
|
216
|
+
if (!resFrame.ok) {
|
|
217
|
+
throw new Error(
|
|
218
|
+
`Connect failed: ${resFrame.error?.message ?? "unknown error"}`
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
waitForFrame(ws, filter, timeoutMs) {
|
|
223
|
+
return new Promise((resolve, reject) => {
|
|
224
|
+
const timer = setTimeout(
|
|
225
|
+
() => {
|
|
226
|
+
ws.off("message", handler);
|
|
227
|
+
reject(new Error("Timeout waiting for frame"));
|
|
228
|
+
},
|
|
229
|
+
timeoutMs
|
|
230
|
+
);
|
|
231
|
+
const handler = (data) => {
|
|
232
|
+
let frame;
|
|
233
|
+
try {
|
|
234
|
+
frame = JSON.parse(String(data));
|
|
235
|
+
} catch {
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
if (!filter(frame)) return;
|
|
239
|
+
clearTimeout(timer);
|
|
240
|
+
ws.off("message", handler);
|
|
241
|
+
resolve(frame);
|
|
242
|
+
};
|
|
243
|
+
ws.on("message", handler);
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
setupMessageHandler(ws) {
|
|
247
|
+
ws.on("message", (data) => {
|
|
248
|
+
let frame;
|
|
249
|
+
try {
|
|
250
|
+
frame = JSON.parse(String(data));
|
|
251
|
+
} catch {
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
if (frame.type === "res") {
|
|
255
|
+
const pending = this.pendingRequests.get(frame.id);
|
|
256
|
+
if (pending) {
|
|
257
|
+
clearTimeout(pending.timer);
|
|
258
|
+
this.pendingRequests.delete(frame.id);
|
|
259
|
+
pending.resolve(frame);
|
|
260
|
+
}
|
|
261
|
+
} else if (frame.type === "event") {
|
|
262
|
+
for (const handler of this.eventHandlers) {
|
|
263
|
+
handler(frame);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
});
|
|
40
267
|
}
|
|
41
|
-
|
|
268
|
+
setupCloseHandler(ws) {
|
|
269
|
+
ws.on("close", () => {
|
|
270
|
+
this.connected = false;
|
|
271
|
+
for (const [id, pending] of this.pendingRequests) {
|
|
272
|
+
clearTimeout(pending.timer);
|
|
273
|
+
pending.reject(new Error("Connection closed"));
|
|
274
|
+
this.pendingRequests.delete(id);
|
|
275
|
+
}
|
|
276
|
+
if (this.reconnectEnabled && !this.disposed) {
|
|
277
|
+
this.scheduleReconnect();
|
|
278
|
+
}
|
|
279
|
+
});
|
|
42
280
|
}
|
|
43
|
-
|
|
281
|
+
scheduleReconnect() {
|
|
282
|
+
if (this.reconnectTimer) return;
|
|
283
|
+
this.reconnectTimer = setTimeout(async () => {
|
|
284
|
+
this.reconnectTimer = null;
|
|
285
|
+
try {
|
|
286
|
+
await this.connect();
|
|
287
|
+
} catch {
|
|
288
|
+
this.reconnectDelay = Math.min(
|
|
289
|
+
this.reconnectDelay * 2,
|
|
290
|
+
this.maxReconnectDelay
|
|
291
|
+
);
|
|
292
|
+
this.scheduleReconnect();
|
|
293
|
+
}
|
|
294
|
+
}, this.reconnectDelay);
|
|
295
|
+
}
|
|
296
|
+
async request(method, params = {}, timeoutMs = 3e4) {
|
|
297
|
+
if (!this.ws || !this.connected) {
|
|
298
|
+
throw new Error("Not connected");
|
|
299
|
+
}
|
|
300
|
+
const id = `r${++this.reqCounter}`;
|
|
301
|
+
const frame = { type: "req", id, method, params };
|
|
302
|
+
return new Promise((resolve, reject) => {
|
|
303
|
+
const timer = setTimeout(() => {
|
|
304
|
+
this.pendingRequests.delete(id);
|
|
305
|
+
reject(new Error(`Request timeout: ${method}`));
|
|
306
|
+
}, timeoutMs);
|
|
307
|
+
this.pendingRequests.set(id, { resolve, reject, timer });
|
|
308
|
+
this.ws.send(JSON.stringify(frame));
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
onEvent(handler) {
|
|
312
|
+
this.eventHandlers.push(handler);
|
|
313
|
+
return () => {
|
|
314
|
+
const idx = this.eventHandlers.indexOf(handler);
|
|
315
|
+
if (idx >= 0) this.eventHandlers.splice(idx, 1);
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
async subscribeToSession(sessionKey) {
|
|
319
|
+
await this.request("sessions.subscribe", { sessionKey });
|
|
320
|
+
await this.request("sessions.messages.subscribe", { sessionKey });
|
|
321
|
+
}
|
|
322
|
+
isConnected() {
|
|
323
|
+
return this.connected;
|
|
324
|
+
}
|
|
325
|
+
async disconnect() {
|
|
326
|
+
this.disposed = true;
|
|
327
|
+
if (this.reconnectTimer) {
|
|
328
|
+
clearTimeout(this.reconnectTimer);
|
|
329
|
+
this.reconnectTimer = null;
|
|
330
|
+
}
|
|
331
|
+
if (this.ws) {
|
|
332
|
+
this.ws.close();
|
|
333
|
+
this.ws = null;
|
|
334
|
+
}
|
|
335
|
+
this.connected = false;
|
|
336
|
+
}
|
|
337
|
+
getIdentity() {
|
|
338
|
+
return this.identity;
|
|
44
339
|
}
|
|
45
340
|
};
|
|
46
341
|
|
|
47
|
-
// src/
|
|
48
|
-
var
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
342
|
+
// src/prompt.ts
|
|
343
|
+
var FORMAT_INSTRUCTIONS = {
|
|
344
|
+
summary: "When you are done, output a final summary of what you accomplished. Keep it concise (1-3 paragraphs).",
|
|
345
|
+
structured: "When you are done, output your result as a JSON object with the requested fields. Wrap the JSON in a ```json code block.",
|
|
346
|
+
diff: 'When you are done, output a JSON object summarizing the changes: { "summary": "...", "filesChanged": [{ "path": "...", "linesAdded": N, "linesRemoved": N }] }. Wrap in a ```json code block.',
|
|
347
|
+
review: 'When you are done, output a JSON object: { "summary": "...", "findings": [{ "severity": "critical|high|medium|low|info", "location": "file:line", "issue": "..." }], "filesReviewed": ["..."] }. Wrap in a ```json code block.',
|
|
348
|
+
test: 'When you are done, output a JSON object: { "summary": "...", "passed": N, "failed": N, "skipped": N, "failures": [{ "test": "...", "error": "..." }] }. Wrap in a ```json code block.'
|
|
349
|
+
};
|
|
350
|
+
function formatPriorContext(results) {
|
|
351
|
+
const parts = results.map((r) => {
|
|
352
|
+
const status = r.status === "completed" ? "completed" : `${r.status}`;
|
|
353
|
+
let outputSummary;
|
|
354
|
+
if (r.output.format === "summary") {
|
|
355
|
+
outputSummary = r.output.summary;
|
|
356
|
+
} else if (r.output.format === "raw") {
|
|
357
|
+
outputSummary = r.output.raw.slice(0, 500);
|
|
358
|
+
} else if ("summary" in r.output) {
|
|
359
|
+
outputSummary = r.output.summary;
|
|
360
|
+
} else {
|
|
361
|
+
outputSummary = JSON.stringify(r.output).slice(0, 500);
|
|
362
|
+
}
|
|
363
|
+
return `[Step "${r.stepId}" \u2014 ${status}]
|
|
364
|
+
${outputSummary}`;
|
|
365
|
+
});
|
|
366
|
+
return parts.join("\n\n");
|
|
367
|
+
}
|
|
368
|
+
function enrichInstruction(taskSpec) {
|
|
369
|
+
const parts = [];
|
|
370
|
+
if (taskSpec.priorContext && taskSpec.priorContext.length > 0) {
|
|
371
|
+
parts.push("## Context from prior steps\n");
|
|
372
|
+
parts.push(formatPriorContext(taskSpec.priorContext));
|
|
373
|
+
parts.push("");
|
|
374
|
+
}
|
|
375
|
+
parts.push(taskSpec.instruction);
|
|
376
|
+
const formatInstr = FORMAT_INSTRUCTIONS[taskSpec.expectedResult.format];
|
|
377
|
+
if (formatInstr) {
|
|
378
|
+
parts.push("");
|
|
379
|
+
parts.push("## Output format");
|
|
380
|
+
parts.push(formatInstr);
|
|
381
|
+
}
|
|
382
|
+
if (taskSpec.expectedResult.format === "structured" && taskSpec.expectedResult.fields?.length) {
|
|
383
|
+
parts.push(
|
|
384
|
+
`Include these fields: ${taskSpec.expectedResult.fields.join(", ")}`
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
if (taskSpec.expectedResult.maxLength) {
|
|
388
|
+
parts.push(
|
|
389
|
+
`Keep your output under ${taskSpec.expectedResult.maxLength} characters.`
|
|
390
|
+
);
|
|
391
|
+
}
|
|
392
|
+
return parts.join("\n");
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// src/output-parser.ts
|
|
396
|
+
function extractJsonBlock(text) {
|
|
397
|
+
const match = text.match(/```json\s*([\s\S]*?)```/);
|
|
398
|
+
if (match) return match[1].trim();
|
|
399
|
+
const objMatch = text.match(/\{[\s\S]*\}/);
|
|
400
|
+
if (objMatch) return objMatch[0];
|
|
401
|
+
return null;
|
|
402
|
+
}
|
|
403
|
+
function tryParse(text) {
|
|
404
|
+
const json = extractJsonBlock(text);
|
|
405
|
+
if (!json) return null;
|
|
406
|
+
try {
|
|
407
|
+
return JSON.parse(json);
|
|
408
|
+
} catch {
|
|
409
|
+
return null;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
function parseSummary(text, spec) {
|
|
413
|
+
const summary = spec.maxLength ? text.slice(0, spec.maxLength) : text;
|
|
414
|
+
return { format: "summary", summary };
|
|
415
|
+
}
|
|
416
|
+
function parseDiff(text) {
|
|
417
|
+
const obj = tryParse(text);
|
|
418
|
+
if (!obj || typeof obj.summary !== "string") return null;
|
|
419
|
+
return {
|
|
420
|
+
format: "diff",
|
|
421
|
+
summary: obj.summary,
|
|
422
|
+
filesChanged: Array.isArray(obj.filesChanged) ? obj.filesChanged.map((f) => ({
|
|
423
|
+
path: String(f.path ?? ""),
|
|
424
|
+
linesAdded: Number(f.linesAdded ?? 0),
|
|
425
|
+
linesRemoved: Number(f.linesRemoved ?? 0)
|
|
426
|
+
})) : []
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
function parseReview(text) {
|
|
430
|
+
const obj = tryParse(text);
|
|
431
|
+
if (!obj || typeof obj.summary !== "string") return null;
|
|
432
|
+
return {
|
|
433
|
+
format: "review",
|
|
434
|
+
summary: obj.summary,
|
|
435
|
+
findings: Array.isArray(obj.findings) ? obj.findings.map((f) => ({
|
|
436
|
+
severity: f.severity ?? "info",
|
|
437
|
+
location: String(f.location ?? ""),
|
|
438
|
+
issue: String(f.issue ?? "")
|
|
439
|
+
})) : [],
|
|
440
|
+
filesReviewed: Array.isArray(obj.filesReviewed) ? obj.filesReviewed.map(String) : []
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
function parseTest(text) {
|
|
444
|
+
const obj = tryParse(text);
|
|
445
|
+
if (!obj || typeof obj.summary !== "string") return null;
|
|
446
|
+
return {
|
|
447
|
+
format: "test",
|
|
448
|
+
summary: obj.summary,
|
|
449
|
+
passed: Number(obj.passed ?? 0),
|
|
450
|
+
failed: Number(obj.failed ?? 0),
|
|
451
|
+
skipped: Number(obj.skipped ?? 0),
|
|
452
|
+
failures: Array.isArray(obj.failures) ? obj.failures.map((f) => ({
|
|
453
|
+
test: String(f.test ?? ""),
|
|
454
|
+
error: String(f.error ?? "")
|
|
455
|
+
})) : []
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
function parseStructured(text, spec) {
|
|
459
|
+
const obj = tryParse(text);
|
|
460
|
+
if (!obj) return null;
|
|
461
|
+
const fields = {};
|
|
462
|
+
if (spec.fields?.length) {
|
|
463
|
+
for (const key of spec.fields) {
|
|
464
|
+
fields[key] = obj[key];
|
|
465
|
+
}
|
|
466
|
+
} else {
|
|
467
|
+
Object.assign(fields, obj);
|
|
468
|
+
}
|
|
469
|
+
return { format: "structured", fields };
|
|
470
|
+
}
|
|
471
|
+
function rawFallback(text, parseError) {
|
|
472
|
+
return { format: "raw", raw: text, parseError };
|
|
473
|
+
}
|
|
474
|
+
function parseOutput(rawText, spec) {
|
|
475
|
+
if (!rawText || rawText.trim().length === 0) {
|
|
476
|
+
return rawFallback(rawText, "Empty output");
|
|
477
|
+
}
|
|
478
|
+
switch (spec.format) {
|
|
479
|
+
case "summary":
|
|
480
|
+
return parseSummary(rawText, spec);
|
|
481
|
+
case "diff": {
|
|
482
|
+
const result = parseDiff(rawText);
|
|
483
|
+
return result ?? rawFallback(rawText, "Failed to parse diff output");
|
|
484
|
+
}
|
|
485
|
+
case "review": {
|
|
486
|
+
const result = parseReview(rawText);
|
|
487
|
+
return result ?? rawFallback(rawText, "Failed to parse review output");
|
|
488
|
+
}
|
|
489
|
+
case "test": {
|
|
490
|
+
const result = parseTest(rawText);
|
|
491
|
+
return result ?? rawFallback(rawText, "Failed to parse test output");
|
|
492
|
+
}
|
|
493
|
+
case "structured": {
|
|
494
|
+
const result = parseStructured(rawText, spec);
|
|
495
|
+
return result ?? rawFallback(rawText, "Failed to parse structured output");
|
|
496
|
+
}
|
|
497
|
+
default:
|
|
498
|
+
return rawFallback(rawText);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
// src/adapter.ts
|
|
503
|
+
var OpenClawAdapter = class {
|
|
504
|
+
name = "openclaw";
|
|
505
|
+
description = "OpenClaw gateway runtime adapter";
|
|
506
|
+
ws;
|
|
507
|
+
config;
|
|
508
|
+
sessions = /* @__PURE__ */ new Map();
|
|
509
|
+
eventHandlers = [];
|
|
510
|
+
unsubscribeEvents = null;
|
|
511
|
+
constructor(config) {
|
|
512
|
+
this.config = config;
|
|
513
|
+
this.ws = new GatewayWebSocketClient({
|
|
514
|
+
gatewayUrl: config.gatewayUrl,
|
|
515
|
+
scopes: config.scopes,
|
|
516
|
+
reconnect: true
|
|
517
|
+
});
|
|
52
518
|
}
|
|
53
|
-
gatewayUrl;
|
|
54
|
-
authToken;
|
|
55
|
-
handlers = [];
|
|
56
519
|
async connect() {
|
|
520
|
+
await this.ws.connect();
|
|
521
|
+
this.unsubscribeEvents = this.ws.onEvent(
|
|
522
|
+
(frame) => this.handleGatewayEvent(frame)
|
|
523
|
+
);
|
|
57
524
|
}
|
|
58
|
-
async
|
|
525
|
+
async spawn(opts) {
|
|
526
|
+
const instruction = enrichInstruction(opts.task);
|
|
527
|
+
const agentId = this.config.defaultAgentId ?? "test-orchestrator";
|
|
528
|
+
const res = await this.ws.request("sessions.create", {
|
|
529
|
+
agentId,
|
|
530
|
+
message: instruction
|
|
531
|
+
});
|
|
532
|
+
if (!res.ok || !res.payload) {
|
|
533
|
+
throw new Error(
|
|
534
|
+
`Failed to create session: ${res.error?.message ?? "unknown"}`
|
|
535
|
+
);
|
|
536
|
+
}
|
|
537
|
+
const sessionKey = res.payload.sessionKey;
|
|
538
|
+
const sessionId = res.payload.sessionId;
|
|
539
|
+
const handle = {
|
|
540
|
+
id: sessionId,
|
|
541
|
+
adapter: this.name,
|
|
542
|
+
metadata: {
|
|
543
|
+
sessionKey,
|
|
544
|
+
runId: res.payload.runId,
|
|
545
|
+
agentId
|
|
546
|
+
}
|
|
547
|
+
};
|
|
548
|
+
this.sessions.set(sessionId, {
|
|
549
|
+
handle,
|
|
550
|
+
sessionKey,
|
|
551
|
+
spawnOptions: opts,
|
|
552
|
+
startedAt: Date.now(),
|
|
553
|
+
accumulatedText: ""
|
|
554
|
+
});
|
|
555
|
+
await this.ws.subscribeToSession(sessionKey);
|
|
556
|
+
this.emitEvent({
|
|
557
|
+
id: (0, import_node_crypto2.randomUUID)(),
|
|
558
|
+
type: import_core.EventType.SessionSpawned,
|
|
559
|
+
source: this.name,
|
|
560
|
+
timestamp: Date.now(),
|
|
561
|
+
sessionId,
|
|
562
|
+
workflowId: opts.context?.workflowId,
|
|
563
|
+
stepId: opts.context?.stepId,
|
|
564
|
+
payload: {
|
|
565
|
+
agentId,
|
|
566
|
+
runtime: opts.runtime,
|
|
567
|
+
decision: opts.decision
|
|
568
|
+
}
|
|
569
|
+
});
|
|
570
|
+
return handle;
|
|
571
|
+
}
|
|
572
|
+
async send(session, message) {
|
|
573
|
+
const tracked = this.sessions.get(session.id);
|
|
574
|
+
if (!tracked) throw new Error(`Unknown session: ${session.id}`);
|
|
575
|
+
await this.ws.request("sessions.send", {
|
|
576
|
+
sessionKey: tracked.sessionKey,
|
|
577
|
+
message
|
|
578
|
+
});
|
|
579
|
+
}
|
|
580
|
+
async kill(session) {
|
|
581
|
+
const tracked = this.sessions.get(session.id);
|
|
582
|
+
if (!tracked) return;
|
|
583
|
+
try {
|
|
584
|
+
await this.ws.request("subagents", {
|
|
585
|
+
action: "kill",
|
|
586
|
+
target: session.id
|
|
587
|
+
});
|
|
588
|
+
} catch {
|
|
589
|
+
}
|
|
590
|
+
this.sessions.delete(session.id);
|
|
591
|
+
this.emitEvent({
|
|
592
|
+
id: (0, import_node_crypto2.randomUUID)(),
|
|
593
|
+
type: import_core.EventType.SessionKilled,
|
|
594
|
+
source: this.name,
|
|
595
|
+
timestamp: Date.now(),
|
|
596
|
+
sessionId: session.id,
|
|
597
|
+
payload: {}
|
|
598
|
+
});
|
|
599
|
+
}
|
|
600
|
+
async status(session) {
|
|
601
|
+
try {
|
|
602
|
+
const res = await this.ws.request("subagents", { action: "list" });
|
|
603
|
+
if (!res.ok) return "unknown";
|
|
604
|
+
const agents = res.payload?.agents ?? [];
|
|
605
|
+
const match = agents.find((a) => a.id === session.id);
|
|
606
|
+
if (!match) return this.sessions.has(session.id) ? "running" : null;
|
|
607
|
+
const statusMap = {
|
|
608
|
+
running: "running",
|
|
609
|
+
completed: "completed",
|
|
610
|
+
failed: "failed",
|
|
611
|
+
killed: "killed"
|
|
612
|
+
};
|
|
613
|
+
return statusMap[match.status] ?? "unknown";
|
|
614
|
+
} catch {
|
|
615
|
+
return "unknown";
|
|
616
|
+
}
|
|
59
617
|
}
|
|
60
618
|
onEvent(handler) {
|
|
61
|
-
this.
|
|
619
|
+
this.eventHandlers.push(handler);
|
|
62
620
|
}
|
|
63
|
-
|
|
64
|
-
|
|
621
|
+
async dispose() {
|
|
622
|
+
for (const [, tracked] of this.sessions) {
|
|
623
|
+
try {
|
|
624
|
+
await this.kill(tracked.handle);
|
|
625
|
+
} catch {
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
this.sessions.clear();
|
|
629
|
+
if (this.unsubscribeEvents) {
|
|
630
|
+
this.unsubscribeEvents();
|
|
631
|
+
}
|
|
632
|
+
await this.ws.disconnect();
|
|
65
633
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
634
|
+
// --- Internal ---
|
|
635
|
+
handleGatewayEvent(frame) {
|
|
636
|
+
if (frame.event === "agent") {
|
|
637
|
+
this.handleAgentEvent(frame);
|
|
638
|
+
} else if (frame.event === "chat") {
|
|
639
|
+
this.handleChatEvent(frame);
|
|
640
|
+
}
|
|
72
641
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
642
|
+
handleAgentEvent(frame) {
|
|
643
|
+
const payload = frame.payload;
|
|
644
|
+
if (payload.stream === "lifecycle") {
|
|
645
|
+
const lifecycle = payload;
|
|
646
|
+
if (lifecycle.phase === "complete") {
|
|
647
|
+
this.handleSessionComplete(frame);
|
|
648
|
+
} else if (lifecycle.phase === "error") {
|
|
649
|
+
this.handleSessionError(frame, lifecycle.error ?? "Unknown error");
|
|
650
|
+
}
|
|
651
|
+
} else if (payload.stream === "assistant") {
|
|
652
|
+
const delta = payload.delta;
|
|
653
|
+
if (delta) {
|
|
654
|
+
for (const [, tracked] of this.sessions) {
|
|
655
|
+
tracked.accumulatedText += delta;
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
this.emitEvent({
|
|
659
|
+
id: (0, import_node_crypto2.randomUUID)(),
|
|
660
|
+
type: import_core.EventType.SessionMessage,
|
|
661
|
+
source: this.name,
|
|
662
|
+
timestamp: Date.now(),
|
|
663
|
+
payload: { stream: "assistant", delta }
|
|
664
|
+
});
|
|
665
|
+
}
|
|
76
666
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
667
|
+
handleChatEvent(frame) {
|
|
668
|
+
const payload = frame.payload;
|
|
669
|
+
if (payload.state === "error") {
|
|
670
|
+
for (const [sessionId] of this.sessions) {
|
|
671
|
+
this.handleSessionError(
|
|
672
|
+
frame,
|
|
673
|
+
payload.errorMessage ?? "Chat error",
|
|
674
|
+
sessionId
|
|
675
|
+
);
|
|
676
|
+
break;
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
handleSessionComplete(frame) {
|
|
681
|
+
const sessionId = this.findSessionId(frame);
|
|
682
|
+
const tracked = sessionId ? this.sessions.get(sessionId) : null;
|
|
683
|
+
if (!tracked) return;
|
|
684
|
+
const lifecycle = frame.payload;
|
|
685
|
+
const durationMs = Date.now() - tracked.startedAt;
|
|
686
|
+
const cost = {
|
|
687
|
+
tokens: {
|
|
688
|
+
input: lifecycle.cost?.input ?? 0,
|
|
689
|
+
output: lifecycle.cost?.output ?? 0,
|
|
690
|
+
cacheRead: lifecycle.cost?.cacheRead,
|
|
691
|
+
cacheWrite: lifecycle.cost?.cacheWrite
|
|
692
|
+
},
|
|
693
|
+
usd: lifecycle.cost?.totalCost ?? 0,
|
|
694
|
+
runtime: tracked.spawnOptions.runtime
|
|
695
|
+
};
|
|
696
|
+
const output = parseOutput(
|
|
697
|
+
tracked.accumulatedText,
|
|
698
|
+
tracked.spawnOptions.task.expectedResult
|
|
699
|
+
);
|
|
700
|
+
const stepResult = {
|
|
701
|
+
stepId: tracked.spawnOptions.context?.stepId ?? sessionId,
|
|
702
|
+
status: "completed",
|
|
703
|
+
output,
|
|
704
|
+
meta: {
|
|
705
|
+
runtime: tracked.spawnOptions.runtime,
|
|
706
|
+
decision: tracked.spawnOptions.decision,
|
|
707
|
+
cost,
|
|
708
|
+
durationMs,
|
|
709
|
+
retries: (tracked.spawnOptions.context?.attempt ?? 1) - 1
|
|
710
|
+
}
|
|
711
|
+
};
|
|
712
|
+
this.sessions.delete(sessionId);
|
|
713
|
+
this.emitEvent({
|
|
714
|
+
id: (0, import_node_crypto2.randomUUID)(),
|
|
715
|
+
type: import_core.EventType.SessionCompleted,
|
|
716
|
+
source: this.name,
|
|
717
|
+
timestamp: Date.now(),
|
|
718
|
+
sessionId,
|
|
719
|
+
workflowId: tracked.spawnOptions.context?.workflowId,
|
|
720
|
+
stepId: tracked.spawnOptions.context?.stepId,
|
|
721
|
+
payload: { stepResult },
|
|
722
|
+
metadata: { cost, duration: durationMs }
|
|
723
|
+
});
|
|
724
|
+
}
|
|
725
|
+
handleSessionError(frame, error, overrideSessionId) {
|
|
726
|
+
const sessionId = overrideSessionId ?? this.findSessionId(frame);
|
|
727
|
+
const tracked = sessionId ? this.sessions.get(sessionId) : null;
|
|
728
|
+
if (!tracked) return;
|
|
729
|
+
const durationMs = Date.now() - tracked.startedAt;
|
|
730
|
+
this.sessions.delete(sessionId);
|
|
731
|
+
this.emitEvent({
|
|
732
|
+
id: (0, import_node_crypto2.randomUUID)(),
|
|
733
|
+
type: import_core.EventType.SessionFailed,
|
|
734
|
+
source: this.name,
|
|
735
|
+
timestamp: Date.now(),
|
|
736
|
+
sessionId,
|
|
737
|
+
workflowId: tracked.spawnOptions.context?.workflowId,
|
|
738
|
+
stepId: tracked.spawnOptions.context?.stepId,
|
|
739
|
+
payload: { error },
|
|
740
|
+
metadata: { duration: durationMs }
|
|
741
|
+
});
|
|
742
|
+
}
|
|
743
|
+
findSessionId(frame) {
|
|
744
|
+
const fromPayload = frame.payload.sessionId;
|
|
745
|
+
if (fromPayload && this.sessions.has(fromPayload)) return fromPayload;
|
|
746
|
+
if (this.sessions.size === 1) {
|
|
747
|
+
return this.sessions.keys().next().value;
|
|
748
|
+
}
|
|
749
|
+
return void 0;
|
|
750
|
+
}
|
|
751
|
+
emitEvent(event) {
|
|
752
|
+
for (const handler of this.eventHandlers) {
|
|
753
|
+
handler(event);
|
|
754
|
+
}
|
|
80
755
|
}
|
|
81
756
|
};
|
|
757
|
+
|
|
758
|
+
// src/mcp-server.ts
|
|
759
|
+
var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
760
|
+
var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
761
|
+
var import_core2 = require("@yesod/core");
|
|
762
|
+
function createYesodMcpServer(engine) {
|
|
763
|
+
const server = new import_mcp.McpServer({
|
|
764
|
+
name: "yesod",
|
|
765
|
+
version: "0.0.2"
|
|
766
|
+
});
|
|
767
|
+
server.tool(
|
|
768
|
+
import_core2.YESOD_TOOLS.yesod_create_workflow.name,
|
|
769
|
+
import_core2.YESOD_TOOLS.yesod_create_workflow.description,
|
|
770
|
+
import_core2.YESOD_TOOLS.yesod_create_workflow.inputSchema.properties,
|
|
771
|
+
async (args) => {
|
|
772
|
+
const name = args.name;
|
|
773
|
+
const steps = args.steps.map(
|
|
774
|
+
(s) => ({
|
|
775
|
+
id: s.id,
|
|
776
|
+
name: s.name,
|
|
777
|
+
task: s.task,
|
|
778
|
+
expectedResult: s.expectedResult,
|
|
779
|
+
runtime: s.runtime,
|
|
780
|
+
decision: s.decision,
|
|
781
|
+
dependsOn: s.dependsOn ?? [],
|
|
782
|
+
timeout: s.timeout
|
|
783
|
+
})
|
|
784
|
+
);
|
|
785
|
+
const workflow = {
|
|
786
|
+
id: "",
|
|
787
|
+
name,
|
|
788
|
+
steps,
|
|
789
|
+
state: "created",
|
|
790
|
+
createdAt: Date.now()
|
|
791
|
+
};
|
|
792
|
+
const created = engine.createWorkflow(workflow);
|
|
793
|
+
await engine.startWorkflow(created.id);
|
|
794
|
+
return {
|
|
795
|
+
content: [
|
|
796
|
+
{
|
|
797
|
+
type: "text",
|
|
798
|
+
text: JSON.stringify(
|
|
799
|
+
{
|
|
800
|
+
workflowId: created.id,
|
|
801
|
+
status: "started",
|
|
802
|
+
steps: created.steps.map((s) => s.id)
|
|
803
|
+
},
|
|
804
|
+
null,
|
|
805
|
+
2
|
|
806
|
+
)
|
|
807
|
+
}
|
|
808
|
+
]
|
|
809
|
+
};
|
|
810
|
+
}
|
|
811
|
+
);
|
|
812
|
+
server.tool(
|
|
813
|
+
import_core2.YESOD_TOOLS.yesod_workflow_status.name,
|
|
814
|
+
import_core2.YESOD_TOOLS.yesod_workflow_status.description,
|
|
815
|
+
import_core2.YESOD_TOOLS.yesod_workflow_status.inputSchema.properties,
|
|
816
|
+
async (args) => {
|
|
817
|
+
const workflowId = args.workflowId;
|
|
818
|
+
try {
|
|
819
|
+
const status = engine.getWorkflowStatus(workflowId);
|
|
820
|
+
return {
|
|
821
|
+
content: [
|
|
822
|
+
{ type: "text", text: JSON.stringify(status, null, 2) }
|
|
823
|
+
]
|
|
824
|
+
};
|
|
825
|
+
} catch (err) {
|
|
826
|
+
return {
|
|
827
|
+
content: [
|
|
828
|
+
{
|
|
829
|
+
type: "text",
|
|
830
|
+
text: `Error: ${err instanceof Error ? err.message : String(err)}`
|
|
831
|
+
}
|
|
832
|
+
],
|
|
833
|
+
isError: true
|
|
834
|
+
};
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
);
|
|
838
|
+
server.tool(
|
|
839
|
+
import_core2.YESOD_TOOLS.yesod_cancel_workflow.name,
|
|
840
|
+
import_core2.YESOD_TOOLS.yesod_cancel_workflow.description,
|
|
841
|
+
import_core2.YESOD_TOOLS.yesod_cancel_workflow.inputSchema.properties,
|
|
842
|
+
async (args) => {
|
|
843
|
+
const workflowId = args.workflowId;
|
|
844
|
+
try {
|
|
845
|
+
await engine.cancelWorkflow(workflowId);
|
|
846
|
+
return {
|
|
847
|
+
content: [
|
|
848
|
+
{
|
|
849
|
+
type: "text",
|
|
850
|
+
text: JSON.stringify({ workflowId, status: "cancelled" })
|
|
851
|
+
}
|
|
852
|
+
]
|
|
853
|
+
};
|
|
854
|
+
} catch (err) {
|
|
855
|
+
return {
|
|
856
|
+
content: [
|
|
857
|
+
{
|
|
858
|
+
type: "text",
|
|
859
|
+
text: `Error: ${err instanceof Error ? err.message : String(err)}`
|
|
860
|
+
}
|
|
861
|
+
],
|
|
862
|
+
isError: true
|
|
863
|
+
};
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
);
|
|
867
|
+
server.tool(
|
|
868
|
+
import_core2.YESOD_TOOLS.yesod_cost_summary.name,
|
|
869
|
+
import_core2.YESOD_TOOLS.yesod_cost_summary.description,
|
|
870
|
+
import_core2.YESOD_TOOLS.yesod_cost_summary.inputSchema.properties ?? {},
|
|
871
|
+
async (args) => {
|
|
872
|
+
const workflowId = args.workflowId;
|
|
873
|
+
const summary = engine.getCostSummary(workflowId);
|
|
874
|
+
return {
|
|
875
|
+
content: [
|
|
876
|
+
{ type: "text", text: JSON.stringify(summary, null, 2) }
|
|
877
|
+
]
|
|
878
|
+
};
|
|
879
|
+
}
|
|
880
|
+
);
|
|
881
|
+
return server;
|
|
882
|
+
}
|
|
883
|
+
async function startMcpServer(engine) {
|
|
884
|
+
const server = createYesodMcpServer(engine);
|
|
885
|
+
const transport = new import_stdio.StdioServerTransport();
|
|
886
|
+
await server.connect(transport);
|
|
887
|
+
}
|
|
82
888
|
// Annotate the CommonJS export names for ESM import in node:
|
|
83
889
|
0 && (module.exports = {
|
|
84
|
-
GatewayApiClient,
|
|
85
890
|
GatewayWebSocketClient,
|
|
86
|
-
OpenClawAdapter
|
|
891
|
+
OpenClawAdapter,
|
|
892
|
+
buildAuthPayload,
|
|
893
|
+
createYesodMcpServer,
|
|
894
|
+
deviceIdFromPrivateKey,
|
|
895
|
+
enrichInstruction,
|
|
896
|
+
generateDeviceIdentity,
|
|
897
|
+
loadOrCreateIdentity,
|
|
898
|
+
parseOutput,
|
|
899
|
+
signPayload,
|
|
900
|
+
startMcpServer
|
|
87
901
|
});
|
|
88
902
|
//# sourceMappingURL=index.cjs.map
|