@openclaw/raft 2026.7.2-beta.1 → 2026.7.2-beta.2
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/channel-plugin-api.js +31 -36
- package/npm-shrinkwrap.json +3 -3
- package/openclaw.plugin.json +3 -3
- package/package.json +4 -4
|
@@ -3,28 +3,20 @@ import { describeAccountSnapshot } from "openclaw/plugin-sdk/account-helpers";
|
|
|
3
3
|
import { createChatChannelPlugin } from "openclaw/plugin-sdk/channel-core";
|
|
4
4
|
import { detectBinary } from "openclaw/plugin-sdk/setup-tools";
|
|
5
5
|
import { buildBaseChannelStatusSummary, createComputedAccountStatusAdapter, createDefaultChannelRuntimeState } from "openclaw/plugin-sdk/status-helpers";
|
|
6
|
-
import { buildChannelConfigSchema } from "openclaw/plugin-sdk/channel-config-schema";
|
|
6
|
+
import { buildChannelConfigSchema, buildMultiAccountChannelSchema } from "openclaw/plugin-sdk/channel-config-schema";
|
|
7
7
|
import { z } from "zod";
|
|
8
8
|
import { spawn } from "node:child_process";
|
|
9
9
|
import { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
10
10
|
import { createServer } from "node:http";
|
|
11
11
|
import { keepHttpServerTaskAlive, waitUntilAbort } from "openclaw/plugin-sdk/channel-outbound";
|
|
12
12
|
import { KeyedAsyncQueue } from "openclaw/plugin-sdk/keyed-async-queue";
|
|
13
|
-
import {
|
|
13
|
+
import { createChannelReplayGuard } from "openclaw/plugin-sdk/persistent-dedupe";
|
|
14
14
|
import { safeEqualSecret } from "openclaw/plugin-sdk/security-runtime";
|
|
15
|
-
|
|
16
|
-
const RaftAccountSchema = z.object({
|
|
15
|
+
const raftChannelConfigSchema = buildChannelConfigSchema(buildMultiAccountChannelSchema(z.object({
|
|
17
16
|
name: z.string().optional(),
|
|
18
17
|
enabled: z.boolean().optional(),
|
|
19
18
|
profile: z.string().min(1).optional()
|
|
20
|
-
}).strict();
|
|
21
|
-
const raftChannelConfigSchema = buildChannelConfigSchema(z.object({
|
|
22
|
-
name: z.string().optional(),
|
|
23
|
-
enabled: z.boolean().optional(),
|
|
24
|
-
profile: z.string().min(1).optional(),
|
|
25
|
-
defaultAccount: z.string().optional(),
|
|
26
|
-
accounts: z.record(z.string(), RaftAccountSchema).optional()
|
|
27
|
-
}).strict());
|
|
19
|
+
}).strict()));
|
|
28
20
|
//#endregion
|
|
29
21
|
//#region extensions/raft/src/inbound.ts
|
|
30
22
|
const WAKE_TEXT = "Raft wake hint received. Check Raft for pending messages, then reply through the Raft CLI.";
|
|
@@ -138,6 +130,21 @@ const WAKE_EVENT_ID_FIELDS = [
|
|
|
138
130
|
"wake_id",
|
|
139
131
|
"id"
|
|
140
132
|
];
|
|
133
|
+
function createRaftWakeReplayGuard(params) {
|
|
134
|
+
return createChannelReplayGuard({
|
|
135
|
+
dedupe: {
|
|
136
|
+
ttlMs: WAKE_DEDUPE_TTL_MS,
|
|
137
|
+
memoryMaxSize: WAKE_DEDUPE_MEMORY_MAX_SIZE,
|
|
138
|
+
pluginId: RAFT_CHANNEL_ID,
|
|
139
|
+
namespacePrefix: "raft-wake-dedupe",
|
|
140
|
+
stateMaxEntries: WAKE_DEDUPE_STATE_MAX_ENTRIES,
|
|
141
|
+
...params?.env ? { env: params.env } : {},
|
|
142
|
+
...params?.onDiskError ? { onDiskError: params.onDiskError } : {}
|
|
143
|
+
},
|
|
144
|
+
buildReplayKey: (event) => event.key,
|
|
145
|
+
namespace: (event) => event.accountId
|
|
146
|
+
});
|
|
147
|
+
}
|
|
141
148
|
var WakeRequestError = class extends Error {
|
|
142
149
|
constructor(statusCode, message) {
|
|
143
150
|
super(message);
|
|
@@ -253,16 +260,9 @@ async function startRaftGatewayAccount(ctx, deps = {}) {
|
|
|
253
260
|
if (!profile) throw new Error(`Raft account "${ctx.accountId}" is missing a CLI profile.`);
|
|
254
261
|
if (!ctx.channelRuntime) throw new Error("Raft requires OpenClaw channel runtime support. Update OpenClaw and retry.");
|
|
255
262
|
const wakeQueue = new KeyedAsyncQueue();
|
|
256
|
-
const wakeDedupe = deps.wakeDedupe ??
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
pluginId: "raft",
|
|
260
|
-
namespacePrefix: "raft-wake-dedupe",
|
|
261
|
-
stateMaxEntries: WAKE_DEDUPE_STATE_MAX_ENTRIES,
|
|
262
|
-
onDiskError: (error) => {
|
|
263
|
-
ctx.log?.warn?.(`Raft wake dedupe storage failed: ${String(error)}`);
|
|
264
|
-
}
|
|
265
|
-
});
|
|
263
|
+
const wakeDedupe = deps.wakeDedupe ?? createRaftWakeReplayGuard({ onDiskError: (error) => {
|
|
264
|
+
ctx.log?.warn?.(`Raft wake dedupe storage failed: ${String(error)}`);
|
|
265
|
+
} });
|
|
266
266
|
const token = (deps.createToken ?? createToken)();
|
|
267
267
|
const runtimeSession = randomUUID();
|
|
268
268
|
const sockets = /* @__PURE__ */ new Set();
|
|
@@ -305,22 +305,17 @@ async function startRaftGatewayAccount(ctx, deps = {}) {
|
|
|
305
305
|
if (!dedupeKey) throw new WakeRequestError(400, "Wake payload must include a stable event identity.");
|
|
306
306
|
const dispatched = await wakeQueue.enqueue(ctx.accountId, async () => {
|
|
307
307
|
if (ctx.abortSignal?.aborted) throw new WakeRequestError(503, "Raft Gateway is stopping.");
|
|
308
|
-
const
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
throw new WakeRequestError(503, "Raft wake delivery is retrying.");
|
|
313
|
-
}
|
|
314
|
-
try {
|
|
308
|
+
const result = await wakeDedupe.processGuarded({
|
|
309
|
+
accountId: ctx.accountId,
|
|
310
|
+
key: dedupeKey
|
|
311
|
+
}, async () => {
|
|
315
312
|
await dispatchRaftWake({ ctx });
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
throw error;
|
|
313
|
+
});
|
|
314
|
+
if (result.kind === "duplicate") return false;
|
|
315
|
+
if (result.kind === "inflight") {
|
|
316
|
+
if (await result.pending) return false;
|
|
317
|
+
throw new WakeRequestError(503, "Raft wake delivery is retrying.");
|
|
322
318
|
}
|
|
323
|
-
await wakeDedupe.commit(dedupeKey, { namespace: ctx.accountId });
|
|
324
319
|
return true;
|
|
325
320
|
});
|
|
326
321
|
sendJson(response, 202, {
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/raft",
|
|
3
|
-
"version": "2026.7.2-beta.
|
|
3
|
+
"version": "2026.7.2-beta.2",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@openclaw/raft",
|
|
9
|
-
"version": "2026.7.2-beta.
|
|
9
|
+
"version": "2026.7.2-beta.2",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"zod": "4.4.3"
|
|
12
12
|
},
|
|
13
13
|
"peerDependencies": {
|
|
14
|
-
"openclaw": ">=2026.7.2-beta.
|
|
14
|
+
"openclaw": ">=2026.7.2-beta.2"
|
|
15
15
|
},
|
|
16
16
|
"peerDependenciesMeta": {
|
|
17
17
|
"openclaw": {
|
package/openclaw.plugin.json
CHANGED
|
@@ -24,9 +24,6 @@
|
|
|
24
24
|
"type": "string",
|
|
25
25
|
"minLength": 1
|
|
26
26
|
},
|
|
27
|
-
"defaultAccount": {
|
|
28
|
-
"type": "string"
|
|
29
|
-
},
|
|
30
27
|
"accounts": {
|
|
31
28
|
"type": "object",
|
|
32
29
|
"propertyNames": {
|
|
@@ -48,6 +45,9 @@
|
|
|
48
45
|
},
|
|
49
46
|
"additionalProperties": false
|
|
50
47
|
}
|
|
48
|
+
},
|
|
49
|
+
"defaultAccount": {
|
|
50
|
+
"type": "string"
|
|
51
51
|
}
|
|
52
52
|
},
|
|
53
53
|
"additionalProperties": false
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/raft",
|
|
3
|
-
"version": "2026.7.2-beta.
|
|
3
|
+
"version": "2026.7.2-beta.2",
|
|
4
4
|
"description": "OpenClaw Raft channel plugin for Raft CLI wake bridges.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"zod": "4.4.3"
|
|
12
12
|
},
|
|
13
13
|
"peerDependencies": {
|
|
14
|
-
"openclaw": ">=2026.7.2-beta.
|
|
14
|
+
"openclaw": ">=2026.7.2-beta.2"
|
|
15
15
|
},
|
|
16
16
|
"peerDependenciesMeta": {
|
|
17
17
|
"openclaw": {
|
|
@@ -29,10 +29,10 @@
|
|
|
29
29
|
"minHostVersion": ">=2026.6.8"
|
|
30
30
|
},
|
|
31
31
|
"compat": {
|
|
32
|
-
"pluginApi": ">=2026.7.2-beta.
|
|
32
|
+
"pluginApi": ">=2026.7.2-beta.2"
|
|
33
33
|
},
|
|
34
34
|
"build": {
|
|
35
|
-
"openclawVersion": "2026.7.2-beta.
|
|
35
|
+
"openclawVersion": "2026.7.2-beta.2"
|
|
36
36
|
},
|
|
37
37
|
"channel": {
|
|
38
38
|
"id": "raft",
|