@claw-manager/openclaw-api-channel 2026.6.28 → 2026.6.30
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 +2 -1
- package/dist/index.js +3 -24
- package/dist/index.js.map +1 -1
- package/dist/src/channel.js +197 -16
- package/dist/src/channel.js.map +1 -1
- package/dist/src/openviking-handoff.js +72 -0
- package/dist/src/openviking-handoff.js.map +1 -0
- package/index.ts +5 -29
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/src/channel.ts +243 -17
- package/src/openviking-handoff.ts +102 -0
package/README.md
CHANGED
|
@@ -2,4 +2,5 @@
|
|
|
2
2
|
|
|
3
3
|
OpenClaw channel plugin used by Claw Manager to deliver external API messages into the normal OpenClaw agent runtime.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Claw Manager writes request files into the instance queue under `.openclaw/claw-manager-api/requests`.
|
|
6
|
+
When the Gateway starts the `claw-manager-api` channel, this plugin runs a queue monitor, converts each request into an inbound direct-message context, writes an OpenViking sender handoff for the current API user, dispatches the turn through OpenClaw, and writes the response under `.openclaw/claw-manager-api/responses`.
|
package/dist/index.js
CHANGED
|
@@ -1,33 +1,12 @@
|
|
|
1
|
-
import { apiChannelPlugin
|
|
2
|
-
export const API_GATEWAY_METHOD = "claw-manager-api.sendMessage";
|
|
1
|
+
import { apiChannelPlugin } from "./src/channel.js";
|
|
3
2
|
export default {
|
|
4
3
|
id: "claw-manager-api",
|
|
5
4
|
name: "Claw Manager API",
|
|
6
5
|
description: "External API channel for Claw Manager",
|
|
7
6
|
register(api) {
|
|
7
|
+
api.logger?.info?.(`claw-manager-api: register channel mode=${String(api.registrationMode ?? "unknown")} ` +
|
|
8
|
+
`hasGatewayMethod=${String(typeof api.registerGatewayMethod === "function")}`);
|
|
8
9
|
api.registerChannel({ plugin: apiChannelPlugin });
|
|
9
|
-
api.registerGatewayMethod(API_GATEWAY_METHOD, async ({ params, context, respond }) => {
|
|
10
|
-
try {
|
|
11
|
-
const result = await dispatchApiMessage({
|
|
12
|
-
...(params ?? {}),
|
|
13
|
-
cfg: context.getRuntimeConfig(),
|
|
14
|
-
channelRuntime: api.runtime.channel,
|
|
15
|
-
});
|
|
16
|
-
respond(true, result);
|
|
17
|
-
}
|
|
18
|
-
catch (error) {
|
|
19
|
-
respond(false, undefined, {
|
|
20
|
-
code: "INVALID_REQUEST",
|
|
21
|
-
message: errorMessage(error),
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
}, { scope: "operator.admin" });
|
|
25
10
|
},
|
|
26
11
|
};
|
|
27
|
-
function errorMessage(error) {
|
|
28
|
-
if (error instanceof Error && error.message.trim()) {
|
|
29
|
-
return error.message;
|
|
30
|
-
}
|
|
31
|
-
return String(error);
|
|
32
|
-
}
|
|
33
12
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEpD,eAAe;IACb,EAAE,EAAE,kBAAkB;IACtB,IAAI,EAAE,kBAAkB;IACxB,WAAW,EAAE,uCAAuC;IACpD,QAAQ,CAAC,GAAsB;QAC7B,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,CAChB,2CAA2C,MAAM,CAAC,GAAG,CAAC,gBAAgB,IAAI,SAAS,CAAC,GAAG;YACrF,oBAAoB,MAAM,CAAC,OAAO,GAAG,CAAC,qBAAqB,KAAK,UAAU,CAAC,EAAE,CAChF,CAAC;QACF,GAAG,CAAC,eAAe,CAAC,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC,CAAC;IACpD,CAAC;CACF,CAAC"}
|
package/dist/src/channel.js
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
|
+
import fs from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
2
4
|
import { createTypingCallbacks } from "openclaw/plugin-sdk/channel-runtime";
|
|
5
|
+
import { writeApiOpenVikingHandoff } from "./openviking-handoff.js";
|
|
6
|
+
const API_CHANNEL_ID = "claw-manager-api";
|
|
7
|
+
const API_ACCOUNT_ID = "global";
|
|
8
|
+
const API_QUEUE_POLL_MS = 200;
|
|
9
|
+
async function writeOpenVikingHandoffForTurn(params) {
|
|
10
|
+
const secret = trim(process.env.OPENVIKING_IDENTITY_HASH_SECRET);
|
|
11
|
+
if (!secret) {
|
|
12
|
+
params.log?.debug?.(`[${API_ACCOUNT_ID}] openviking handoff skipped: identity secret missing`);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
try {
|
|
16
|
+
const wrote = await writeApiOpenVikingHandoff({
|
|
17
|
+
sessionKey: params.sessionKey,
|
|
18
|
+
openVikingUserId: params.openVikingUserId,
|
|
19
|
+
senderHash: params.senderHash,
|
|
20
|
+
secret,
|
|
21
|
+
});
|
|
22
|
+
if (wrote) {
|
|
23
|
+
params.log?.info?.(`[${API_ACCOUNT_ID}] openviking handoff written user=${params.openVikingUserId}`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
params.log?.warn?.(`[${API_ACCOUNT_ID}] openviking handoff write failed: ${errorMessage(error)}`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
3
30
|
export function buildApiInboundContext(params) {
|
|
4
31
|
const message = trim(params.message);
|
|
5
32
|
const openVikingUserId = trim(params.openVikingUserId) || trim(params.openvikingUserId);
|
|
@@ -52,8 +79,8 @@ export async function dispatchApiMessage(ctx) {
|
|
|
52
79
|
const inbound = buildApiInboundContext(ctx);
|
|
53
80
|
const route = runtime.routing.resolveAgentRoute({
|
|
54
81
|
cfg: ctx.cfg,
|
|
55
|
-
channel:
|
|
56
|
-
accountId:
|
|
82
|
+
channel: API_CHANNEL_ID,
|
|
83
|
+
accountId: API_ACCOUNT_ID,
|
|
57
84
|
peer: { kind: "direct", id: inbound.To },
|
|
58
85
|
});
|
|
59
86
|
const sessionKey = route.sessionKey ?? inbound.SessionKey;
|
|
@@ -62,15 +89,21 @@ export async function dispatchApiMessage(ctx) {
|
|
|
62
89
|
agentId: route.agentId,
|
|
63
90
|
});
|
|
64
91
|
const finalized = runtime.reply.finalizeInboundContext(inbound);
|
|
92
|
+
await writeOpenVikingHandoffForTurn({
|
|
93
|
+
sessionKey,
|
|
94
|
+
openVikingUserId: inbound.openVikingUserId,
|
|
95
|
+
senderHash: trim(ctx.senderHash),
|
|
96
|
+
log: ctx.log,
|
|
97
|
+
});
|
|
65
98
|
await runtime.session.recordInboundSession({
|
|
66
99
|
storePath,
|
|
67
100
|
sessionKey,
|
|
68
101
|
ctx: finalized,
|
|
69
102
|
updateLastRoute: {
|
|
70
103
|
sessionKey: route.mainSessionKey ?? sessionKey,
|
|
71
|
-
channel:
|
|
104
|
+
channel: API_CHANNEL_ID,
|
|
72
105
|
to: inbound.To,
|
|
73
|
-
accountId:
|
|
106
|
+
accountId: API_ACCOUNT_ID,
|
|
74
107
|
},
|
|
75
108
|
onRecordError: (error) => ctx.log?.error?.(`recordInboundSession: ${String(error)}`),
|
|
76
109
|
});
|
|
@@ -108,19 +141,158 @@ export async function dispatchApiMessage(ctx) {
|
|
|
108
141
|
markDispatchIdle();
|
|
109
142
|
}
|
|
110
143
|
return {
|
|
111
|
-
channel:
|
|
144
|
+
channel: API_CHANNEL_ID,
|
|
112
145
|
messageId: trim(ctx.requestId) || randomUUID(),
|
|
113
146
|
text: replyText,
|
|
114
147
|
};
|
|
115
148
|
}
|
|
149
|
+
export function resolveApiQueueRoot() {
|
|
150
|
+
const home = trim(process.env.OPENCLAW_HOME) || trim(process.env.HOME) || process.cwd();
|
|
151
|
+
return path.join(home, ".openclaw", API_CHANNEL_ID);
|
|
152
|
+
}
|
|
153
|
+
export async function monitorApiQueue(ctx) {
|
|
154
|
+
if (!ctx.channelRuntime) {
|
|
155
|
+
throw new Error("ctx.channelRuntime missing");
|
|
156
|
+
}
|
|
157
|
+
if (!ctx.cfg) {
|
|
158
|
+
throw new Error("ctx.cfg missing");
|
|
159
|
+
}
|
|
160
|
+
const root = resolveApiQueueRoot();
|
|
161
|
+
const dirs = {
|
|
162
|
+
root,
|
|
163
|
+
requests: path.join(root, "requests"),
|
|
164
|
+
processing: path.join(root, "processing"),
|
|
165
|
+
responses: path.join(root, "responses"),
|
|
166
|
+
failed: path.join(root, "failed"),
|
|
167
|
+
};
|
|
168
|
+
await Promise.all(Object.values(dirs).map((dir) => fs.mkdir(dir, { recursive: true })));
|
|
169
|
+
ctx.log?.info?.(`[${API_ACCOUNT_ID}] claw-manager-api queue monitor started (${root})`);
|
|
170
|
+
ctx.setStatus?.({
|
|
171
|
+
accountId: API_ACCOUNT_ID,
|
|
172
|
+
running: true,
|
|
173
|
+
configured: true,
|
|
174
|
+
lastStartAt: Date.now(),
|
|
175
|
+
lastError: null,
|
|
176
|
+
});
|
|
177
|
+
while (!ctx.abortSignal?.aborted) {
|
|
178
|
+
await processPendingApiRequests(ctx, dirs);
|
|
179
|
+
await sleep(API_QUEUE_POLL_MS, ctx.abortSignal);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
async function processPendingApiRequests(ctx, dirs) {
|
|
183
|
+
let files = [];
|
|
184
|
+
try {
|
|
185
|
+
files = (await fs.readdir(dirs.requests))
|
|
186
|
+
.filter((file) => file.endsWith(".json"))
|
|
187
|
+
.sort();
|
|
188
|
+
}
|
|
189
|
+
catch (error) {
|
|
190
|
+
ctx.log?.error?.(`[${API_ACCOUNT_ID}] read queue failed: ${errorMessage(error)}`);
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
for (const file of files) {
|
|
194
|
+
if (ctx.abortSignal?.aborted) {
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
const requestPath = path.join(dirs.requests, file);
|
|
198
|
+
const processingPath = path.join(dirs.processing, file);
|
|
199
|
+
try {
|
|
200
|
+
await fs.rename(requestPath, processingPath);
|
|
201
|
+
}
|
|
202
|
+
catch {
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
await processApiRequestFile(ctx, processingPath, path.join(dirs.responses, file), path.join(dirs.failed, file));
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
async function processApiRequestFile(ctx, processingPath, responsePath, failedPath) {
|
|
209
|
+
let request = {};
|
|
210
|
+
let requestId = path.basename(processingPath, ".json");
|
|
211
|
+
try {
|
|
212
|
+
request = JSON.parse(await fs.readFile(processingPath, "utf8"));
|
|
213
|
+
requestId = trim(request.requestId) || requestId;
|
|
214
|
+
ctx.log?.info?.(`[${API_ACCOUNT_ID}] api request received requestId=${requestId} user=${trim(request.openVikingUserId) || trim(request.openvikingUserId) || "missing"}`);
|
|
215
|
+
ctx.setStatus?.({
|
|
216
|
+
accountId: API_ACCOUNT_ID,
|
|
217
|
+
running: true,
|
|
218
|
+
lastInboundAt: Date.now(),
|
|
219
|
+
lastEventAt: Date.now(),
|
|
220
|
+
});
|
|
221
|
+
const result = await dispatchApiMessage({
|
|
222
|
+
...request,
|
|
223
|
+
requestId,
|
|
224
|
+
cfg: ctx.cfg,
|
|
225
|
+
channelRuntime: ctx.channelRuntime,
|
|
226
|
+
log: ctx.log,
|
|
227
|
+
});
|
|
228
|
+
await writeQueueResponse(responsePath, {
|
|
229
|
+
ok: true,
|
|
230
|
+
requestId,
|
|
231
|
+
messageId: result.messageId,
|
|
232
|
+
text: result.text,
|
|
233
|
+
finishedAt: new Date().toISOString(),
|
|
234
|
+
});
|
|
235
|
+
ctx.setStatus?.({
|
|
236
|
+
accountId: API_ACCOUNT_ID,
|
|
237
|
+
running: true,
|
|
238
|
+
lastOutboundAt: Date.now(),
|
|
239
|
+
lastEventAt: Date.now(),
|
|
240
|
+
lastError: null,
|
|
241
|
+
});
|
|
242
|
+
ctx.log?.info?.(`[${API_ACCOUNT_ID}] api request completed requestId=${requestId} textLen=${result.text.length}`);
|
|
243
|
+
await safeUnlink(processingPath);
|
|
244
|
+
}
|
|
245
|
+
catch (error) {
|
|
246
|
+
const message = errorMessage(error);
|
|
247
|
+
ctx.log?.error?.(`[${API_ACCOUNT_ID}] api request failed requestId=${requestId}: ${message}`);
|
|
248
|
+
await writeQueueResponse(responsePath, {
|
|
249
|
+
ok: false,
|
|
250
|
+
requestId,
|
|
251
|
+
error: message,
|
|
252
|
+
finishedAt: new Date().toISOString(),
|
|
253
|
+
});
|
|
254
|
+
await fs.mkdir(path.dirname(failedPath), { recursive: true });
|
|
255
|
+
await fs.rename(processingPath, failedPath).catch(() => safeUnlink(processingPath));
|
|
256
|
+
ctx.setStatus?.({
|
|
257
|
+
accountId: API_ACCOUNT_ID,
|
|
258
|
+
running: true,
|
|
259
|
+
lastError: message,
|
|
260
|
+
lastEventAt: Date.now(),
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
async function writeQueueResponse(responsePath, response) {
|
|
265
|
+
await fs.mkdir(path.dirname(responsePath), { recursive: true });
|
|
266
|
+
const tmpPath = `${responsePath}.tmp-${process.pid}-${Date.now()}`;
|
|
267
|
+
await fs.writeFile(tmpPath, JSON.stringify(response), "utf8");
|
|
268
|
+
await fs.rename(tmpPath, responsePath);
|
|
269
|
+
}
|
|
270
|
+
async function safeUnlink(file) {
|
|
271
|
+
try {
|
|
272
|
+
await fs.unlink(file);
|
|
273
|
+
}
|
|
274
|
+
catch { }
|
|
275
|
+
}
|
|
276
|
+
function sleep(ms, signal) {
|
|
277
|
+
if (signal?.aborted) {
|
|
278
|
+
return Promise.resolve();
|
|
279
|
+
}
|
|
280
|
+
return new Promise((resolve) => {
|
|
281
|
+
const timer = setTimeout(resolve, ms);
|
|
282
|
+
signal?.addEventListener("abort", () => {
|
|
283
|
+
clearTimeout(timer);
|
|
284
|
+
resolve();
|
|
285
|
+
}, { once: true });
|
|
286
|
+
});
|
|
287
|
+
}
|
|
116
288
|
export const apiChannelPlugin = {
|
|
117
|
-
id:
|
|
289
|
+
id: API_CHANNEL_ID,
|
|
118
290
|
meta: {
|
|
119
|
-
id:
|
|
120
|
-
label:
|
|
291
|
+
id: API_CHANNEL_ID,
|
|
292
|
+
label: API_CHANNEL_ID,
|
|
121
293
|
selectionLabel: "Claw Manager API",
|
|
122
|
-
docsPath:
|
|
123
|
-
docsLabel:
|
|
294
|
+
docsPath: `/channels/${API_CHANNEL_ID}`,
|
|
295
|
+
docsLabel: API_CHANNEL_ID,
|
|
124
296
|
blurb: "External API channel.",
|
|
125
297
|
order: 80,
|
|
126
298
|
},
|
|
@@ -137,11 +309,11 @@ export const apiChannelPlugin = {
|
|
|
137
309
|
blockStreaming: true,
|
|
138
310
|
},
|
|
139
311
|
config: {
|
|
140
|
-
listAccountIds: () => [
|
|
312
|
+
listAccountIds: () => [API_ACCOUNT_ID],
|
|
141
313
|
resolveAccount: () => ({}),
|
|
142
314
|
isConfigured: () => true,
|
|
143
315
|
describeAccount: () => ({
|
|
144
|
-
accountId:
|
|
316
|
+
accountId: API_ACCOUNT_ID,
|
|
145
317
|
name: "Claw Manager API",
|
|
146
318
|
enabled: true,
|
|
147
319
|
configured: true,
|
|
@@ -151,14 +323,14 @@ export const apiChannelPlugin = {
|
|
|
151
323
|
deliveryMode: "direct",
|
|
152
324
|
textChunkLimit: 8000,
|
|
153
325
|
sendText: async (ctx) => ({
|
|
154
|
-
channel:
|
|
326
|
+
channel: API_CHANNEL_ID,
|
|
155
327
|
messageId: randomUUID(),
|
|
156
328
|
text: ctx.text ?? "",
|
|
157
329
|
}),
|
|
158
330
|
},
|
|
159
331
|
status: {
|
|
160
332
|
defaultRuntime: {
|
|
161
|
-
accountId:
|
|
333
|
+
accountId: API_ACCOUNT_ID,
|
|
162
334
|
lastError: null,
|
|
163
335
|
lastInboundAt: null,
|
|
164
336
|
lastOutboundAt: null,
|
|
@@ -172,17 +344,26 @@ export const apiChannelPlugin = {
|
|
|
172
344
|
}),
|
|
173
345
|
buildAccountSnapshot: ({ runtime }) => ({
|
|
174
346
|
...runtime,
|
|
175
|
-
accountId:
|
|
347
|
+
accountId: API_ACCOUNT_ID,
|
|
176
348
|
name: "Claw Manager API",
|
|
177
349
|
enabled: true,
|
|
178
350
|
configured: true,
|
|
179
351
|
}),
|
|
180
352
|
},
|
|
181
353
|
gateway: {
|
|
182
|
-
|
|
354
|
+
startAccount: async (ctx) => monitorApiQueue(ctx),
|
|
355
|
+
stopAccount: async (ctx) => {
|
|
356
|
+
ctx.log?.info?.(`[${API_ACCOUNT_ID}] claw-manager-api queue monitor stopping`);
|
|
357
|
+
},
|
|
183
358
|
},
|
|
184
359
|
};
|
|
185
360
|
function trim(value) {
|
|
186
361
|
return typeof value === "string" ? value.trim() : "";
|
|
187
362
|
}
|
|
363
|
+
function errorMessage(error) {
|
|
364
|
+
if (error instanceof Error && error.message.trim()) {
|
|
365
|
+
return error.message;
|
|
366
|
+
}
|
|
367
|
+
return String(error);
|
|
368
|
+
}
|
|
188
369
|
//# sourceMappingURL=channel.js.map
|
package/dist/src/channel.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"channel.js","sourceRoot":"","sources":["../../src/channel.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"channel.js","sourceRoot":"","sources":["../../src/channel.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { createHmac } from "node:crypto";
|
|
2
|
+
import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
function trimString(value) {
|
|
6
|
+
return typeof value === "string" ? value.trim() : "";
|
|
7
|
+
}
|
|
8
|
+
function hmacSha256Hex(secret, value) {
|
|
9
|
+
return createHmac("sha256", secret).update(value, "utf8").digest("hex");
|
|
10
|
+
}
|
|
11
|
+
export function resolveApiOpenVikingHandoffStateDir(stateDir) {
|
|
12
|
+
return (trimString(stateDir) ||
|
|
13
|
+
trimString(process.env.OPENCLAW_STATE_DIR) ||
|
|
14
|
+
trimString(process.env.CLAWDBOT_STATE_DIR) ||
|
|
15
|
+
path.join(os.homedir(), ".openclaw"));
|
|
16
|
+
}
|
|
17
|
+
function handoffPath(stateDir) {
|
|
18
|
+
return path.join(resolveApiOpenVikingHandoffStateDir(stateDir), "openviking", "sender-handoff.json");
|
|
19
|
+
}
|
|
20
|
+
function sessionKeyHash(sessionKey, secret) {
|
|
21
|
+
const normalizedSessionKey = trimString(sessionKey);
|
|
22
|
+
const normalizedSecret = trimString(secret);
|
|
23
|
+
if (!normalizedSessionKey || !normalizedSecret) {
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
return hmacSha256Hex(normalizedSecret, normalizedSessionKey).slice(0, 32);
|
|
27
|
+
}
|
|
28
|
+
async function readHandoffFile(filePath) {
|
|
29
|
+
try {
|
|
30
|
+
const raw = await readFile(filePath, "utf8");
|
|
31
|
+
const parsed = JSON.parse(raw);
|
|
32
|
+
return {
|
|
33
|
+
version: 1,
|
|
34
|
+
entries: parsed.entries && typeof parsed.entries === "object" ? parsed.entries : {},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
if (error.code === "ENOENT") {
|
|
39
|
+
return { version: 1, entries: {} };
|
|
40
|
+
}
|
|
41
|
+
throw error;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
export async function writeApiOpenVikingHandoff(params) {
|
|
45
|
+
const key = sessionKeyHash(params.sessionKey ?? "", params.secret ?? "");
|
|
46
|
+
const openVikingUserId = trimString(params.openVikingUserId);
|
|
47
|
+
const senderHash = trimString(params.senderHash);
|
|
48
|
+
if (!key || !openVikingUserId || !senderHash) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
const filePath = handoffPath(params.stateDir);
|
|
52
|
+
await mkdir(path.dirname(filePath), { recursive: true });
|
|
53
|
+
const file = await readHandoffFile(filePath);
|
|
54
|
+
file.entries[key] = {
|
|
55
|
+
openVikingUserId,
|
|
56
|
+
senderHash,
|
|
57
|
+
updatedAt: new Date().toISOString(),
|
|
58
|
+
};
|
|
59
|
+
const tempPath = `${filePath}.${process.pid}.tmp`;
|
|
60
|
+
await writeFile(tempPath, `${JSON.stringify(file, null, 2)}\n`, "utf8");
|
|
61
|
+
await rename(tempPath, filePath);
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
export async function readApiOpenVikingHandoff(params) {
|
|
65
|
+
const key = sessionKeyHash(params.sessionKey ?? "", params.secret ?? "");
|
|
66
|
+
if (!key) {
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
const file = await readHandoffFile(handoffPath(params.stateDir));
|
|
70
|
+
return file.entries[key];
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=openviking-handoff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openviking-handoff.js","sourceRoot":"","sources":["../../src/openviking-handoff.ts"],"names":[],"mappings":"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"}
|
package/index.ts
CHANGED
|
@@ -1,40 +1,16 @@
|
|
|
1
1
|
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-entry";
|
|
2
2
|
|
|
3
|
-
import { apiChannelPlugin
|
|
4
|
-
|
|
5
|
-
export const API_GATEWAY_METHOD = "claw-manager-api.sendMessage";
|
|
3
|
+
import { apiChannelPlugin } from "./src/channel.js";
|
|
6
4
|
|
|
7
5
|
export default {
|
|
8
6
|
id: "claw-manager-api",
|
|
9
7
|
name: "Claw Manager API",
|
|
10
8
|
description: "External API channel for Claw Manager",
|
|
11
9
|
register(api: OpenClawPluginApi) {
|
|
12
|
-
api.
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
async ({ params, context, respond }) => {
|
|
16
|
-
try {
|
|
17
|
-
const result = await dispatchApiMessage({
|
|
18
|
-
...(params ?? {}),
|
|
19
|
-
cfg: context.getRuntimeConfig(),
|
|
20
|
-
channelRuntime: api.runtime.channel,
|
|
21
|
-
});
|
|
22
|
-
respond(true, result);
|
|
23
|
-
} catch (error) {
|
|
24
|
-
respond(false, undefined, {
|
|
25
|
-
code: "INVALID_REQUEST",
|
|
26
|
-
message: errorMessage(error),
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
},
|
|
30
|
-
{ scope: "operator.admin" },
|
|
10
|
+
api.logger?.info?.(
|
|
11
|
+
`claw-manager-api: register channel mode=${String(api.registrationMode ?? "unknown")} ` +
|
|
12
|
+
`hasGatewayMethod=${String(typeof api.registerGatewayMethod === "function")}`,
|
|
31
13
|
);
|
|
14
|
+
api.registerChannel({ plugin: apiChannelPlugin });
|
|
32
15
|
},
|
|
33
16
|
};
|
|
34
|
-
|
|
35
|
-
function errorMessage(error: unknown): string {
|
|
36
|
-
if (error instanceof Error && error.message.trim()) {
|
|
37
|
-
return error.message;
|
|
38
|
-
}
|
|
39
|
-
return String(error);
|
|
40
|
-
}
|
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED
package/src/channel.ts
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
|
+
import fs from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
2
4
|
|
|
3
5
|
import { createTypingCallbacks } from "openclaw/plugin-sdk/channel-runtime";
|
|
4
6
|
import type { ChannelPlugin, OpenClawConfig, PluginRuntime } from "openclaw/plugin-sdk/core";
|
|
5
7
|
|
|
8
|
+
import { writeApiOpenVikingHandoff } from "./openviking-handoff.js";
|
|
9
|
+
|
|
6
10
|
export type ApiSendMessageParams = {
|
|
7
11
|
requestId?: string;
|
|
8
12
|
openVikingUserId?: string;
|
|
@@ -39,9 +43,63 @@ export type ApiMsgContext = {
|
|
|
39
43
|
type GatewaySendMessageContext = ApiSendMessageParams & {
|
|
40
44
|
cfg?: OpenClawConfig;
|
|
41
45
|
channelRuntime?: PluginRuntime["channel"];
|
|
42
|
-
log?:
|
|
46
|
+
log?: ApiLogSink;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
type ApiLogSink = {
|
|
50
|
+
debug?: (message: string) => void;
|
|
51
|
+
info?: (message: string) => void;
|
|
52
|
+
warn?: (message: string) => void;
|
|
53
|
+
error?: (message: string) => void;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
type ApiGatewayStartContext = {
|
|
57
|
+
cfg?: OpenClawConfig;
|
|
58
|
+
channelRuntime?: PluginRuntime["channel"];
|
|
59
|
+
abortSignal?: AbortSignal;
|
|
60
|
+
log?: ApiLogSink;
|
|
61
|
+
setStatus?: (next: Record<string, unknown>) => void;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
type ApiQueueResponse = {
|
|
65
|
+
ok: boolean;
|
|
66
|
+
requestId: string;
|
|
67
|
+
messageId?: string;
|
|
68
|
+
text?: string;
|
|
69
|
+
error?: string;
|
|
70
|
+
finishedAt: string;
|
|
43
71
|
};
|
|
44
72
|
|
|
73
|
+
const API_CHANNEL_ID = "claw-manager-api";
|
|
74
|
+
const API_ACCOUNT_ID = "global";
|
|
75
|
+
const API_QUEUE_POLL_MS = 200;
|
|
76
|
+
|
|
77
|
+
async function writeOpenVikingHandoffForTurn(params: {
|
|
78
|
+
sessionKey?: string;
|
|
79
|
+
openVikingUserId?: string;
|
|
80
|
+
senderHash?: string;
|
|
81
|
+
log?: ApiLogSink;
|
|
82
|
+
}): Promise<void> {
|
|
83
|
+
const secret = trim(process.env.OPENVIKING_IDENTITY_HASH_SECRET);
|
|
84
|
+
if (!secret) {
|
|
85
|
+
params.log?.debug?.(`[${API_ACCOUNT_ID}] openviking handoff skipped: identity secret missing`);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
const wrote = await writeApiOpenVikingHandoff({
|
|
90
|
+
sessionKey: params.sessionKey,
|
|
91
|
+
openVikingUserId: params.openVikingUserId,
|
|
92
|
+
senderHash: params.senderHash,
|
|
93
|
+
secret,
|
|
94
|
+
});
|
|
95
|
+
if (wrote) {
|
|
96
|
+
params.log?.info?.(`[${API_ACCOUNT_ID}] openviking handoff written user=${params.openVikingUserId}`);
|
|
97
|
+
}
|
|
98
|
+
} catch (error) {
|
|
99
|
+
params.log?.warn?.(`[${API_ACCOUNT_ID}] openviking handoff write failed: ${errorMessage(error)}`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
45
103
|
export function buildApiInboundContext(params: ApiSendMessageParams): ApiMsgContext {
|
|
46
104
|
const message = trim(params.message);
|
|
47
105
|
const openVikingUserId = trim(params.openVikingUserId) || trim(params.openvikingUserId);
|
|
@@ -95,8 +153,8 @@ export async function dispatchApiMessage(ctx: GatewaySendMessageContext): Promis
|
|
|
95
153
|
const inbound = buildApiInboundContext(ctx);
|
|
96
154
|
const route = runtime.routing.resolveAgentRoute({
|
|
97
155
|
cfg: ctx.cfg,
|
|
98
|
-
channel:
|
|
99
|
-
accountId:
|
|
156
|
+
channel: API_CHANNEL_ID,
|
|
157
|
+
accountId: API_ACCOUNT_ID,
|
|
100
158
|
peer: { kind: "direct", id: inbound.To },
|
|
101
159
|
});
|
|
102
160
|
const sessionKey = route.sessionKey ?? inbound.SessionKey;
|
|
@@ -107,15 +165,21 @@ export async function dispatchApiMessage(ctx: GatewaySendMessageContext): Promis
|
|
|
107
165
|
const finalized = runtime.reply.finalizeInboundContext(
|
|
108
166
|
inbound as Parameters<typeof runtime.reply.finalizeInboundContext>[0],
|
|
109
167
|
) as unknown as ApiMsgContext & { CommandAuthorized: boolean };
|
|
168
|
+
await writeOpenVikingHandoffForTurn({
|
|
169
|
+
sessionKey,
|
|
170
|
+
openVikingUserId: inbound.openVikingUserId,
|
|
171
|
+
senderHash: trim(ctx.senderHash),
|
|
172
|
+
log: ctx.log,
|
|
173
|
+
});
|
|
110
174
|
await runtime.session.recordInboundSession({
|
|
111
175
|
storePath,
|
|
112
176
|
sessionKey,
|
|
113
177
|
ctx: finalized as Parameters<typeof runtime.session.recordInboundSession>[0]["ctx"],
|
|
114
178
|
updateLastRoute: {
|
|
115
179
|
sessionKey: route.mainSessionKey ?? sessionKey,
|
|
116
|
-
channel:
|
|
180
|
+
channel: API_CHANNEL_ID,
|
|
117
181
|
to: inbound.To,
|
|
118
|
-
accountId:
|
|
182
|
+
accountId: API_ACCOUNT_ID,
|
|
119
183
|
},
|
|
120
184
|
onRecordError: (error: unknown) => ctx.log?.error?.(`recordInboundSession: ${String(error)}`),
|
|
121
185
|
});
|
|
@@ -155,20 +219,172 @@ export async function dispatchApiMessage(ctx: GatewaySendMessageContext): Promis
|
|
|
155
219
|
markDispatchIdle();
|
|
156
220
|
}
|
|
157
221
|
return {
|
|
158
|
-
channel:
|
|
222
|
+
channel: API_CHANNEL_ID,
|
|
159
223
|
messageId: trim(ctx.requestId) || randomUUID(),
|
|
160
224
|
text: replyText,
|
|
161
225
|
};
|
|
162
226
|
}
|
|
163
227
|
|
|
228
|
+
export function resolveApiQueueRoot(): string {
|
|
229
|
+
const home = trim(process.env.OPENCLAW_HOME) || trim(process.env.HOME) || process.cwd();
|
|
230
|
+
return path.join(home, ".openclaw", API_CHANNEL_ID);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export async function monitorApiQueue(ctx: ApiGatewayStartContext): Promise<void> {
|
|
234
|
+
if (!ctx.channelRuntime) {
|
|
235
|
+
throw new Error("ctx.channelRuntime missing");
|
|
236
|
+
}
|
|
237
|
+
if (!ctx.cfg) {
|
|
238
|
+
throw new Error("ctx.cfg missing");
|
|
239
|
+
}
|
|
240
|
+
const root = resolveApiQueueRoot();
|
|
241
|
+
const dirs = {
|
|
242
|
+
root,
|
|
243
|
+
requests: path.join(root, "requests"),
|
|
244
|
+
processing: path.join(root, "processing"),
|
|
245
|
+
responses: path.join(root, "responses"),
|
|
246
|
+
failed: path.join(root, "failed"),
|
|
247
|
+
};
|
|
248
|
+
await Promise.all(Object.values(dirs).map((dir) => fs.mkdir(dir, { recursive: true })));
|
|
249
|
+
ctx.log?.info?.(`[${API_ACCOUNT_ID}] claw-manager-api queue monitor started (${root})`);
|
|
250
|
+
ctx.setStatus?.({
|
|
251
|
+
accountId: API_ACCOUNT_ID,
|
|
252
|
+
running: true,
|
|
253
|
+
configured: true,
|
|
254
|
+
lastStartAt: Date.now(),
|
|
255
|
+
lastError: null,
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
while (!ctx.abortSignal?.aborted) {
|
|
259
|
+
await processPendingApiRequests(ctx, dirs);
|
|
260
|
+
await sleep(API_QUEUE_POLL_MS, ctx.abortSignal);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
async function processPendingApiRequests(
|
|
265
|
+
ctx: ApiGatewayStartContext,
|
|
266
|
+
dirs: { requests: string; processing: string; responses: string; failed: string },
|
|
267
|
+
): Promise<void> {
|
|
268
|
+
let files: string[] = [];
|
|
269
|
+
try {
|
|
270
|
+
files = (await fs.readdir(dirs.requests))
|
|
271
|
+
.filter((file) => file.endsWith(".json"))
|
|
272
|
+
.sort();
|
|
273
|
+
} catch (error) {
|
|
274
|
+
ctx.log?.error?.(`[${API_ACCOUNT_ID}] read queue failed: ${errorMessage(error)}`);
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
for (const file of files) {
|
|
279
|
+
if (ctx.abortSignal?.aborted) {
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
const requestPath = path.join(dirs.requests, file);
|
|
283
|
+
const processingPath = path.join(dirs.processing, file);
|
|
284
|
+
try {
|
|
285
|
+
await fs.rename(requestPath, processingPath);
|
|
286
|
+
} catch {
|
|
287
|
+
continue;
|
|
288
|
+
}
|
|
289
|
+
await processApiRequestFile(ctx, processingPath, path.join(dirs.responses, file), path.join(dirs.failed, file));
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
async function processApiRequestFile(
|
|
294
|
+
ctx: ApiGatewayStartContext,
|
|
295
|
+
processingPath: string,
|
|
296
|
+
responsePath: string,
|
|
297
|
+
failedPath: string,
|
|
298
|
+
): Promise<void> {
|
|
299
|
+
let request: ApiSendMessageParams = {};
|
|
300
|
+
let requestId = path.basename(processingPath, ".json");
|
|
301
|
+
try {
|
|
302
|
+
request = JSON.parse(await fs.readFile(processingPath, "utf8")) as ApiSendMessageParams;
|
|
303
|
+
requestId = trim(request.requestId) || requestId;
|
|
304
|
+
ctx.log?.info?.(`[${API_ACCOUNT_ID}] api request received requestId=${requestId} user=${trim(request.openVikingUserId) || trim(request.openvikingUserId) || "missing"}`);
|
|
305
|
+
ctx.setStatus?.({
|
|
306
|
+
accountId: API_ACCOUNT_ID,
|
|
307
|
+
running: true,
|
|
308
|
+
lastInboundAt: Date.now(),
|
|
309
|
+
lastEventAt: Date.now(),
|
|
310
|
+
});
|
|
311
|
+
const result = await dispatchApiMessage({
|
|
312
|
+
...request,
|
|
313
|
+
requestId,
|
|
314
|
+
cfg: ctx.cfg,
|
|
315
|
+
channelRuntime: ctx.channelRuntime,
|
|
316
|
+
log: ctx.log,
|
|
317
|
+
});
|
|
318
|
+
await writeQueueResponse(responsePath, {
|
|
319
|
+
ok: true,
|
|
320
|
+
requestId,
|
|
321
|
+
messageId: result.messageId,
|
|
322
|
+
text: result.text,
|
|
323
|
+
finishedAt: new Date().toISOString(),
|
|
324
|
+
});
|
|
325
|
+
ctx.setStatus?.({
|
|
326
|
+
accountId: API_ACCOUNT_ID,
|
|
327
|
+
running: true,
|
|
328
|
+
lastOutboundAt: Date.now(),
|
|
329
|
+
lastEventAt: Date.now(),
|
|
330
|
+
lastError: null,
|
|
331
|
+
});
|
|
332
|
+
ctx.log?.info?.(`[${API_ACCOUNT_ID}] api request completed requestId=${requestId} textLen=${result.text.length}`);
|
|
333
|
+
await safeUnlink(processingPath);
|
|
334
|
+
} catch (error) {
|
|
335
|
+
const message = errorMessage(error);
|
|
336
|
+
ctx.log?.error?.(`[${API_ACCOUNT_ID}] api request failed requestId=${requestId}: ${message}`);
|
|
337
|
+
await writeQueueResponse(responsePath, {
|
|
338
|
+
ok: false,
|
|
339
|
+
requestId,
|
|
340
|
+
error: message,
|
|
341
|
+
finishedAt: new Date().toISOString(),
|
|
342
|
+
});
|
|
343
|
+
await fs.mkdir(path.dirname(failedPath), { recursive: true });
|
|
344
|
+
await fs.rename(processingPath, failedPath).catch(() => safeUnlink(processingPath));
|
|
345
|
+
ctx.setStatus?.({
|
|
346
|
+
accountId: API_ACCOUNT_ID,
|
|
347
|
+
running: true,
|
|
348
|
+
lastError: message,
|
|
349
|
+
lastEventAt: Date.now(),
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
async function writeQueueResponse(responsePath: string, response: ApiQueueResponse): Promise<void> {
|
|
355
|
+
await fs.mkdir(path.dirname(responsePath), { recursive: true });
|
|
356
|
+
const tmpPath = `${responsePath}.tmp-${process.pid}-${Date.now()}`;
|
|
357
|
+
await fs.writeFile(tmpPath, JSON.stringify(response), "utf8");
|
|
358
|
+
await fs.rename(tmpPath, responsePath);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
async function safeUnlink(file: string): Promise<void> {
|
|
362
|
+
try {
|
|
363
|
+
await fs.unlink(file);
|
|
364
|
+
} catch {}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
function sleep(ms: number, signal?: AbortSignal): Promise<void> {
|
|
368
|
+
if (signal?.aborted) {
|
|
369
|
+
return Promise.resolve();
|
|
370
|
+
}
|
|
371
|
+
return new Promise((resolve) => {
|
|
372
|
+
const timer = setTimeout(resolve, ms);
|
|
373
|
+
signal?.addEventListener("abort", () => {
|
|
374
|
+
clearTimeout(timer);
|
|
375
|
+
resolve();
|
|
376
|
+
}, { once: true });
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
|
|
164
380
|
export const apiChannelPlugin: ChannelPlugin<Record<string, never>> = {
|
|
165
|
-
id:
|
|
381
|
+
id: API_CHANNEL_ID,
|
|
166
382
|
meta: {
|
|
167
|
-
id:
|
|
168
|
-
label:
|
|
383
|
+
id: API_CHANNEL_ID,
|
|
384
|
+
label: API_CHANNEL_ID,
|
|
169
385
|
selectionLabel: "Claw Manager API",
|
|
170
|
-
docsPath:
|
|
171
|
-
docsLabel:
|
|
386
|
+
docsPath: `/channels/${API_CHANNEL_ID}`,
|
|
387
|
+
docsLabel: API_CHANNEL_ID,
|
|
172
388
|
blurb: "External API channel.",
|
|
173
389
|
order: 80,
|
|
174
390
|
},
|
|
@@ -185,11 +401,11 @@ export const apiChannelPlugin: ChannelPlugin<Record<string, never>> = {
|
|
|
185
401
|
blockStreaming: true,
|
|
186
402
|
},
|
|
187
403
|
config: {
|
|
188
|
-
listAccountIds: () => [
|
|
404
|
+
listAccountIds: () => [API_ACCOUNT_ID],
|
|
189
405
|
resolveAccount: () => ({}),
|
|
190
406
|
isConfigured: () => true,
|
|
191
407
|
describeAccount: () => ({
|
|
192
|
-
accountId:
|
|
408
|
+
accountId: API_ACCOUNT_ID,
|
|
193
409
|
name: "Claw Manager API",
|
|
194
410
|
enabled: true,
|
|
195
411
|
configured: true,
|
|
@@ -199,14 +415,14 @@ export const apiChannelPlugin: ChannelPlugin<Record<string, never>> = {
|
|
|
199
415
|
deliveryMode: "direct",
|
|
200
416
|
textChunkLimit: 8000,
|
|
201
417
|
sendText: async (ctx: { text?: string }) => ({
|
|
202
|
-
channel:
|
|
418
|
+
channel: API_CHANNEL_ID,
|
|
203
419
|
messageId: randomUUID(),
|
|
204
420
|
text: ctx.text ?? "",
|
|
205
421
|
}),
|
|
206
422
|
},
|
|
207
423
|
status: {
|
|
208
424
|
defaultRuntime: {
|
|
209
|
-
accountId:
|
|
425
|
+
accountId: API_ACCOUNT_ID,
|
|
210
426
|
lastError: null,
|
|
211
427
|
lastInboundAt: null,
|
|
212
428
|
lastOutboundAt: null,
|
|
@@ -220,17 +436,27 @@ export const apiChannelPlugin: ChannelPlugin<Record<string, never>> = {
|
|
|
220
436
|
}),
|
|
221
437
|
buildAccountSnapshot: ({ runtime }: { runtime: Record<string, unknown> }) => ({
|
|
222
438
|
...runtime,
|
|
223
|
-
accountId:
|
|
439
|
+
accountId: API_ACCOUNT_ID,
|
|
224
440
|
name: "Claw Manager API",
|
|
225
441
|
enabled: true,
|
|
226
442
|
configured: true,
|
|
227
443
|
}),
|
|
228
444
|
},
|
|
229
445
|
gateway: {
|
|
230
|
-
|
|
446
|
+
startAccount: async (ctx: ApiGatewayStartContext) => monitorApiQueue(ctx),
|
|
447
|
+
stopAccount: async (ctx: { log?: ApiLogSink }) => {
|
|
448
|
+
ctx.log?.info?.(`[${API_ACCOUNT_ID}] claw-manager-api queue monitor stopping`);
|
|
449
|
+
},
|
|
231
450
|
},
|
|
232
451
|
} as unknown as ChannelPlugin<Record<string, never>>;
|
|
233
452
|
|
|
234
453
|
function trim(value: unknown): string {
|
|
235
454
|
return typeof value === "string" ? value.trim() : "";
|
|
236
455
|
}
|
|
456
|
+
|
|
457
|
+
function errorMessage(error: unknown): string {
|
|
458
|
+
if (error instanceof Error && error.message.trim()) {
|
|
459
|
+
return error.message;
|
|
460
|
+
}
|
|
461
|
+
return String(error);
|
|
462
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { createHmac } from "node:crypto";
|
|
2
|
+
import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
|
|
6
|
+
export type ApiOpenVikingHandoff = {
|
|
7
|
+
openVikingUserId: string;
|
|
8
|
+
senderHash: string;
|
|
9
|
+
updatedAt: string;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
type HandoffFile = {
|
|
13
|
+
version: 1;
|
|
14
|
+
entries: Record<string, ApiOpenVikingHandoff>;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
function trimString(value: unknown): string {
|
|
18
|
+
return typeof value === "string" ? value.trim() : "";
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function hmacSha256Hex(secret: string, value: string): string {
|
|
22
|
+
return createHmac("sha256", secret).update(value, "utf8").digest("hex");
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function resolveApiOpenVikingHandoffStateDir(stateDir?: string): string {
|
|
26
|
+
return (
|
|
27
|
+
trimString(stateDir) ||
|
|
28
|
+
trimString(process.env.OPENCLAW_STATE_DIR) ||
|
|
29
|
+
trimString(process.env.CLAWDBOT_STATE_DIR) ||
|
|
30
|
+
path.join(os.homedir(), ".openclaw")
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function handoffPath(stateDir?: string): string {
|
|
35
|
+
return path.join(resolveApiOpenVikingHandoffStateDir(stateDir), "openviking", "sender-handoff.json");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function sessionKeyHash(sessionKey: string, secret: string): string | undefined {
|
|
39
|
+
const normalizedSessionKey = trimString(sessionKey);
|
|
40
|
+
const normalizedSecret = trimString(secret);
|
|
41
|
+
if (!normalizedSessionKey || !normalizedSecret) {
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
return hmacSha256Hex(normalizedSecret, normalizedSessionKey).slice(0, 32);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async function readHandoffFile(filePath: string): Promise<HandoffFile> {
|
|
48
|
+
try {
|
|
49
|
+
const raw = await readFile(filePath, "utf8");
|
|
50
|
+
const parsed = JSON.parse(raw) as Partial<HandoffFile>;
|
|
51
|
+
return {
|
|
52
|
+
version: 1,
|
|
53
|
+
entries: parsed.entries && typeof parsed.entries === "object" ? parsed.entries : {},
|
|
54
|
+
};
|
|
55
|
+
} catch (error) {
|
|
56
|
+
if ((error as NodeJS.ErrnoException).code === "ENOENT") {
|
|
57
|
+
return { version: 1, entries: {} };
|
|
58
|
+
}
|
|
59
|
+
throw error;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export async function writeApiOpenVikingHandoff(params: {
|
|
64
|
+
stateDir?: string;
|
|
65
|
+
sessionKey?: string;
|
|
66
|
+
openVikingUserId?: string;
|
|
67
|
+
senderHash?: string;
|
|
68
|
+
secret?: string;
|
|
69
|
+
}): Promise<boolean> {
|
|
70
|
+
const key = sessionKeyHash(params.sessionKey ?? "", params.secret ?? "");
|
|
71
|
+
const openVikingUserId = trimString(params.openVikingUserId);
|
|
72
|
+
const senderHash = trimString(params.senderHash);
|
|
73
|
+
if (!key || !openVikingUserId || !senderHash) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const filePath = handoffPath(params.stateDir);
|
|
78
|
+
await mkdir(path.dirname(filePath), { recursive: true });
|
|
79
|
+
const file = await readHandoffFile(filePath);
|
|
80
|
+
file.entries[key] = {
|
|
81
|
+
openVikingUserId,
|
|
82
|
+
senderHash,
|
|
83
|
+
updatedAt: new Date().toISOString(),
|
|
84
|
+
};
|
|
85
|
+
const tempPath = `${filePath}.${process.pid}.tmp`;
|
|
86
|
+
await writeFile(tempPath, `${JSON.stringify(file, null, 2)}\n`, "utf8");
|
|
87
|
+
await rename(tempPath, filePath);
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export async function readApiOpenVikingHandoff(params: {
|
|
92
|
+
stateDir?: string;
|
|
93
|
+
sessionKey?: string;
|
|
94
|
+
secret?: string;
|
|
95
|
+
}): Promise<ApiOpenVikingHandoff | undefined> {
|
|
96
|
+
const key = sessionKeyHash(params.sessionKey ?? "", params.secret ?? "");
|
|
97
|
+
if (!key) {
|
|
98
|
+
return undefined;
|
|
99
|
+
}
|
|
100
|
+
const file = await readHandoffFile(handoffPath(params.stateDir));
|
|
101
|
+
return file.entries[key];
|
|
102
|
+
}
|