@openclaw/buzz 2026.9.6 → 2026.9.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  import { createLazyCliRuntimeLoader, createLiveTransportQaCliRegistration, runLiveTransportQaSuiteCommand } from "openclaw/plugin-sdk/qa-runner-runtime";
2
2
  //#region extensions/buzz/src/qa/cli.ts
3
3
  const DEFAULT_BUZZ_QA_SCENARIOS = ["channel-canary", "channel-mention-gating"];
4
- const loadBuzzQaAdapterRuntime = createLazyCliRuntimeLoader(() => import("./.setup/adapter.runtime-FIC9NMFI.mjs"));
4
+ const loadBuzzQaAdapterRuntime = createLazyCliRuntimeLoader(() => import("./.setup/adapter.runtime-Bpx9a0g6.mjs"));
5
5
  async function runQaBuzz(options) {
6
6
  await runLiveTransportQaSuiteCommand({
7
7
  channelId: "buzz",
@@ -1,2 +1,2 @@
1
- import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries, t as channelSecrets } from "./.setup/secret-contract-DjibkTDL.mjs";
1
+ import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries, t as channelSecrets } from "./.setup/secret-contract-B2-Mrm4v.mjs";
2
2
  export { channelSecrets, collectRuntimeConfigAssignments, secretTargetRegistryEntries };
@@ -4,11 +4,11 @@ import { fileURLToPath } from "node:url";
4
4
  var setup_entry_default = defineBundledChannelSetupEntry({
5
5
  importMetaUrl: import.meta.url,
6
6
  plugin: {
7
- specifier: fileURLToPath(new URL(".setup/setup-plugin-api-H-XWBzaF.mjs", import.meta.url).href),
7
+ specifier: fileURLToPath(new URL(".setup/setup-plugin-api-CtM1M1Oa.mjs", import.meta.url).href),
8
8
  exportName: "buzzSetupPlugin"
9
9
  },
10
10
  secrets: {
11
- specifier: fileURLToPath(new URL(".setup/secret-contract-api-DcFDI-eR.mjs", import.meta.url).href),
11
+ specifier: fileURLToPath(new URL(".setup/secret-contract-api-CfJYRXZf.mjs", import.meta.url).href),
12
12
  exportName: "channelSecrets"
13
13
  }
14
14
  });
@@ -1,2 +1,2 @@
1
- import { t as buzzSetupPlugin } from "./.setup/setup-plugin-api-DI8WfvKQ.mjs";
1
+ import { t as buzzSetupPlugin } from "./.setup/setup-plugin-api-m1pk2Cow.mjs";
2
2
  export { buzzSetupPlugin };
@@ -65,7 +65,7 @@
65
65
  },
66
66
  {
67
67
  "type": "string",
68
- "pattern": "^[wW][sS][sS]?:\\/\\/"
68
+ "pattern": "^[wW][sS][sS]?:\\/\\/.+"
69
69
  }
70
70
  ]
71
71
  },
@@ -304,6 +304,9 @@
304
304
  "requireMention": {
305
305
  "type": "boolean"
306
306
  },
307
+ "requireMentionInBotThreads": {
308
+ "type": "boolean"
309
+ },
307
310
  "groupPolicy": {
308
311
  "type": "string",
309
312
  "enum": [
@@ -384,7 +387,7 @@
384
387
  },
385
388
  {
386
389
  "type": "string",
387
- "pattern": "^[wW][sS][sS]?:\\/\\/"
390
+ "pattern": "^[wW][sS][sS]?:\\/\\/.+"
388
391
  }
389
392
  ]
390
393
  },
@@ -622,6 +625,9 @@
622
625
  "requireMention": {
623
626
  "type": "boolean"
624
627
  },
628
+ "requireMentionInBotThreads": {
629
+ "type": "boolean"
630
+ },
625
631
  "groupPolicy": {
626
632
  "type": "string",
627
633
  "enum": [
@@ -666,7 +672,17 @@
666
672
  "additionalProperties": false
667
673
  },
668
674
  "label": "Buzz",
669
- "description": "Connect OpenClaw agents to Buzz team rooms."
675
+ "description": "Connect OpenClaw agents to Buzz team rooms.",
676
+ "uiHints": {
677
+ "groups.*.requireMentionInBotThreads": {
678
+ "label": "Require Mention in Bot Threads",
679
+ "help": "Override mention gating in threads whose root message was signed by this bot in the same room. False allows unmentioned replies; true requires a mention. Omit to preserve the room's mention policy. Sender restrictions still apply."
680
+ },
681
+ "accounts.*.groups.*.requireMentionInBotThreads": {
682
+ "label": "Require Mention in Bot Threads",
683
+ "help": "Override mention gating in threads whose root message was signed by this bot in the same room. False allows unmentioned replies; true requires a mention. Omit to preserve the room's mention policy. Sender restrictions still apply."
684
+ }
685
+ }
670
686
  }
671
687
  },
672
688
  "configSchema": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/buzz",
3
- "version": "2026.9.6",
3
+ "version": "2026.9.8",
4
4
  "description": "Connect OpenClaw agents to Buzz rooms",
5
5
  "repository": {
6
6
  "type": "git",
@@ -12,7 +12,7 @@
12
12
  "zod": "4.6.5"
13
13
  },
14
14
  "peerDependencies": {
15
- "openclaw": ">=2026.9.6"
15
+ "openclaw": ">=2026.9.8"
16
16
  },
17
17
  "peerDependenciesMeta": {
18
18
  "openclaw": {
@@ -84,10 +84,10 @@
84
84
  "minHostVersion": ">=2026.7.2"
85
85
  },
86
86
  "compat": {
87
- "pluginApi": ">=2026.9.6"
87
+ "pluginApi": ">=2026.9.8"
88
88
  },
89
89
  "build": {
90
- "openclawVersion": "2026.9.6"
90
+ "openclawVersion": "2026.9.8"
91
91
  },
92
92
  "release": {
93
93
  "publishToClawHub": true,
@@ -1,43 +0,0 @@
1
- import { i as resolveBuzzAccount, m as parseBuzzTarget, u as buildBuzzTarget } from "./types-CeupBG0P.mjs";
2
- //#region extensions/buzz/src/directory-query.ts
3
- function matchesDirectoryQuery(entry, query) {
4
- if (!query) return true;
5
- return [
6
- entry.id,
7
- entry.name,
8
- entry.handle
9
- ].some((value) => value?.toLowerCase().includes(query));
10
- }
11
- function applyBuzzDirectoryQueryAndLimit(entries, params) {
12
- const query = params.query?.trim().toLowerCase() ?? "";
13
- const limit = typeof params.limit === "number" && params.limit > 0 ? Math.floor(params.limit) : void 0;
14
- const result = [];
15
- for (const entry of entries) {
16
- if (!matchesDirectoryQuery(entry, query)) continue;
17
- result.push(entry);
18
- if (limit !== void 0 && result.length >= limit) break;
19
- }
20
- return result;
21
- }
22
- //#endregion
23
- //#region extensions/buzz/src/directory-config.ts
24
- async function listBuzzDirectoryPeersFromConfig(_params) {
25
- return [];
26
- }
27
- async function listBuzzDirectoryGroupsFromConfig(params) {
28
- const account = resolveBuzzAccount({
29
- cfg: params.cfg,
30
- accountId: params.accountId
31
- });
32
- return applyBuzzDirectoryQueryAndLimit(Object.entries(account.config.groups ?? {}).filter(([, config]) => config.enabled !== false).map(([roomId]) => {
33
- const id = parseBuzzTarget(roomId);
34
- return {
35
- kind: "group",
36
- id: buildBuzzTarget(id),
37
- name: id,
38
- raw: { roomId: id }
39
- };
40
- }).toSorted((a, b) => a.id.localeCompare(b.id)), params);
41
- }
42
- //#endregion
43
- export { listBuzzDirectoryPeersFromConfig as n, applyBuzzDirectoryQueryAndLimit as r, listBuzzDirectoryGroupsFromConfig as t };
@@ -1,276 +0,0 @@
1
- import { l as BUZZ_CHANNEL_ID_PATTERN } from "./types-CeupBG0P.mjs";
2
- import { Relay, finalizeEvent } from "nostr-tools";
3
- import { readProviderJsonObjectResponse } from "openclaw/plugin-sdk/provider-http";
4
- import { fetchWithSsrFGuard, ssrfPolicyFromHttpBaseUrlAllowedOrigin } from "openclaw/plugin-sdk/ssrf-runtime";
5
- //#region extensions/buzz/src/event-order.ts
6
- function isNewerBuzzRevision(candidate, current) {
7
- return !current || candidate.createdAt > current.createdAt || candidate.createdAt === current.createdAt && candidate.eventId < current.eventId;
8
- }
9
- //#endregion
10
- //#region extensions/buzz/src/relay-subscription.ts
11
- function openBuzzRelaySubscription(relay, filters, params, requestFilters = filters) {
12
- relay.idleSince = void 0;
13
- relay.ongoingOperations += 1;
14
- let subscription;
15
- try {
16
- subscription = relay.prepareSubscription(filters, params);
17
- } catch (error) {
18
- relay.ongoingOperations -= 1;
19
- if (relay.ongoingOperations === 0) {
20
- relay.idleSince = Date.now();
21
- relay.scheduleIdleClose();
22
- }
23
- throw error;
24
- }
25
- const frame = JSON.stringify([
26
- "REQ",
27
- subscription.id,
28
- ...requestFilters
29
- ]);
30
- relay.send(frame).catch((error) => {
31
- if (subscription.closed || relay.openSubs.get(subscription.id) !== subscription) return;
32
- const message = error instanceof Error ? error.message : String(error);
33
- subscription.close(`Buzz relay subscription request failed: ${message}`);
34
- });
35
- return subscription;
36
- }
37
- async function queryBuzzRelaySnapshot(params) {
38
- return await new Promise((resolve, reject) => {
39
- let settled = false;
40
- let receivedEose = false;
41
- let subscriptionClosed = false;
42
- let subscription;
43
- const timeout = setTimeout(() => {
44
- const error = new Error(params.timeoutMessage);
45
- finish(error);
46
- params.onTimeout?.(error);
47
- if (params.closeRelayOnTimeout !== false) params.relay.close();
48
- }, params.timeoutMs ?? 1e4);
49
- const closeAfterRealEose = () => {
50
- if (receivedEose && subscription && !subscriptionClosed) {
51
- subscriptionClosed = true;
52
- subscription.close(params.closeReason);
53
- }
54
- };
55
- const finish = (error) => {
56
- if (settled) return;
57
- settled = true;
58
- clearTimeout(timeout);
59
- params.signal?.removeEventListener("abort", onAbort);
60
- closeAfterRealEose();
61
- if (error === void 0) resolve(params.result());
62
- else reject(error instanceof Error ? error : new Error(params.failureMessage, { cause: error }));
63
- };
64
- const onAbort = () => finish(params.signal?.reason ?? new Error(params.abortMessage));
65
- params.signal?.addEventListener("abort", onAbort, { once: true });
66
- try {
67
- subscription = openBuzzRelaySubscription(params.relay, params.filters, {
68
- onevent: params.onEvent,
69
- oneose: () => {
70
- receivedEose = true;
71
- if (settled) closeAfterRealEose();
72
- else finish();
73
- },
74
- onclose: (reason) => {
75
- if (reason !== params.closeReason) finish(new Error(params.closeMessage(reason)));
76
- }
77
- });
78
- } catch (error) {
79
- finish(error);
80
- return;
81
- }
82
- closeAfterRealEose();
83
- if (params.checkAbortAfterSubscribe && params.signal?.aborted) onAbort();
84
- });
85
- }
86
- //#endregion
87
- //#region extensions/buzz/src/relay-auth.ts
88
- const AUTH_CHALLENGE_TIMEOUT_MS = 2e4;
89
- const AUTH_CHALLENGE_POLL_MS = 25;
90
- const RELAY_SESSION_SETUP_TIMEOUT_MS = 2e4;
91
- const HEX_PUBLIC_KEY_PATTERN$1 = /^[0-9a-f]{64}$/u;
92
- const BUZZ_RELAY_SOFTWARE = "https://github.com/block/buzz";
93
- const BUZZ_LOCAL_DEV_RELAY_PUBLIC_KEY = "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798";
94
- function parseBuzzAuthTag(raw) {
95
- if (!raw.trim()) return;
96
- const parsed = JSON.parse(raw);
97
- if (!Array.isArray(parsed) || parsed.length !== 4 || parsed[0] !== "auth" || parsed.some((value) => typeof value !== "string")) throw new Error("Buzz authTag must be [\"auth\",\"<pubkey>\",\"<conditions>\",\"<signature>\"]");
98
- return parsed;
99
- }
100
- async function waitWithSignal(promise, signal) {
101
- signal.throwIfAborted();
102
- return await new Promise((resolve, reject) => {
103
- const onAbort = () => {
104
- const reason = signal.reason;
105
- reject(reason instanceof Error ? reason : new Error("Buzz relay authentication aborted", { cause: reason }));
106
- };
107
- signal.addEventListener("abort", onAbort, { once: true });
108
- promise.then(resolve, reject).finally(() => signal.removeEventListener("abort", onAbort));
109
- });
110
- }
111
- function createBuzzAuthSigner(params) {
112
- return async (template) => finalizeEvent({
113
- ...template,
114
- tags: params.authTag ? [...template.tags, params.authTag] : template.tags
115
- }, params.secretKey);
116
- }
117
- function isLoopbackRelayUrl(relayUrl) {
118
- const hostname = new URL(relayUrl).hostname.toLowerCase();
119
- return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]";
120
- }
121
- async function resolveBuzzRelayPublicKey(params) {
122
- const infoUrl = new URL(params.relayUrl);
123
- infoUrl.protocol = infoUrl.protocol === "wss:" ? "https:" : "http:";
124
- const url = infoUrl.toString();
125
- const { response, release } = await fetchWithSsrFGuard({
126
- url,
127
- init: { headers: { Accept: "application/nostr+json" } },
128
- signal: params.signal,
129
- policy: ssrfPolicyFromHttpBaseUrlAllowedOrigin(url),
130
- auditContext: "buzz.relay_info"
131
- });
132
- try {
133
- if (!response.ok) {
134
- await response.body?.cancel().catch(() => void 0);
135
- throw new Error(`Buzz relay information request failed with HTTP ${response.status}`);
136
- }
137
- const document = await readProviderJsonObjectResponse(response, "Buzz relay information");
138
- const relayPublicKey = typeof document.self === "string" ? document.self.trim().toLowerCase() : "";
139
- if (HEX_PUBLIC_KEY_PATTERN$1.test(relayPublicKey)) return relayPublicKey;
140
- if (document.software === BUZZ_RELAY_SOFTWARE && isLoopbackRelayUrl(params.relayUrl)) return BUZZ_LOCAL_DEV_RELAY_PUBLIC_KEY;
141
- throw new Error("Buzz relay information document is missing a valid NIP-11 self public key");
142
- } finally {
143
- await release();
144
- }
145
- }
146
- async function connectAndAuthenticateBuzzRelay(params) {
147
- const signAuth = createBuzzAuthSigner({
148
- secretKey: params.secretKey,
149
- authTag: params.authTag
150
- });
151
- await params.relay.connect({ abort: params.signal });
152
- await authenticateBuzzRelay({
153
- relay: params.relay,
154
- signAuth,
155
- signal: params.signal
156
- });
157
- params.relay.onauth = signAuth;
158
- }
159
- async function connectAuthenticatedBuzzRelay(params) {
160
- const relay = new Relay(params.relayUrl, { enableReconnect: false });
161
- try {
162
- await connectAndAuthenticateBuzzRelay({
163
- ...params,
164
- relay
165
- });
166
- return relay;
167
- } catch (error) {
168
- relay.close();
169
- throw error;
170
- }
171
- }
172
- async function connectAuthenticatedBuzzRelaySession(params) {
173
- const relay = new Relay(params.relayUrl, { enableReconnect: false });
174
- const setupAbort = new AbortController();
175
- const signal = params.signal ? AbortSignal.any([params.signal, setupAbort.signal]) : setupAbort.signal;
176
- let setupTimedOut = false;
177
- const setupTimeout = setTimeout(() => {
178
- setupTimedOut = true;
179
- setupAbort.abort(/* @__PURE__ */ new Error("Timed out setting up Buzz relay session"));
180
- }, RELAY_SESSION_SETUP_TIMEOUT_MS);
181
- const authPromise = connectAndAuthenticateBuzzRelay({
182
- ...params,
183
- relay,
184
- signal
185
- });
186
- const relayIdentityPromise = resolveBuzzRelayPublicKey({
187
- relayUrl: params.relayUrl,
188
- signal
189
- });
190
- try {
191
- const [, relayPublicKey] = await Promise.all([authPromise, relayIdentityPromise]);
192
- return {
193
- relay,
194
- relayPublicKey
195
- };
196
- } catch (error) {
197
- setupAbort.abort(error);
198
- relay.close();
199
- await Promise.allSettled([authPromise, relayIdentityPromise]);
200
- if (setupTimedOut && !params.signal?.aborted) throw new Error("Timed out setting up Buzz relay session", { cause: error });
201
- throw error;
202
- } finally {
203
- clearTimeout(setupTimeout);
204
- }
205
- }
206
- async function authenticateBuzzRelay(params) {
207
- const challengeTimeout = AbortSignal.timeout(AUTH_CHALLENGE_TIMEOUT_MS);
208
- const signal = params.signal ? AbortSignal.any([params.signal, challengeTimeout]) : challengeTimeout;
209
- try {
210
- while (true) {
211
- signal.throwIfAborted();
212
- try {
213
- await waitWithSignal(params.relay.auth(params.signAuth), signal);
214
- return;
215
- } catch (error) {
216
- if (!(error instanceof Error && error.message === "can't perform auth, no challenge was received")) throw error;
217
- await waitWithSignal(new Promise((resolve) => {
218
- setTimeout(resolve, AUTH_CHALLENGE_POLL_MS);
219
- }), signal);
220
- }
221
- }
222
- } catch (error) {
223
- if (challengeTimeout.aborted && !params.signal?.aborted) throw new Error("Timed out waiting for Buzz NIP-42 authentication challenge", { cause: error });
224
- throw error;
225
- }
226
- }
227
- //#endregion
228
- //#region extensions/buzz/src/room-membership.ts
229
- const BUZZ_ROOM_MEMBERSHIP_KIND = 39002;
230
- const BUZZ_ROOM_SYSTEM_KIND = 40099;
231
- const HEX_PUBLIC_KEY_PATTERN = /^[0-9a-f]{64}$/u;
232
- const MEMBERSHIP_CHANGE_TYPES = /* @__PURE__ */ new Set([
233
- "member_joined",
234
- "member_left",
235
- "member_removed"
236
- ]);
237
- function parseBuzzRoomMembershipEvent(event, relayPublicKey) {
238
- if (event.kind !== 39002 || event.pubkey.toLowerCase() !== relayPublicKey) return;
239
- const roomId = event.tags.find((tag) => tag[0] === "d")?.[1]?.trim().toLowerCase();
240
- if (!roomId || !BUZZ_CHANNEL_ID_PATTERN.test(roomId)) return;
241
- const members = /* @__PURE__ */ new Set();
242
- const roles = /* @__PURE__ */ new Map();
243
- for (const tag of event.tags) {
244
- if (tag[0] !== "p") continue;
245
- const publicKey = tag[1]?.trim().toLowerCase();
246
- if (!publicKey || !HEX_PUBLIC_KEY_PATTERN.test(publicKey)) continue;
247
- members.add(publicKey);
248
- const role = tag[3]?.trim().toLowerCase();
249
- if (role) roles.set(publicKey, role);
250
- }
251
- return {
252
- roomId,
253
- createdAt: event.created_at,
254
- eventId: event.id,
255
- publisherPublicKey: event.pubkey.toLowerCase(),
256
- members,
257
- roles
258
- };
259
- }
260
- function parseBuzzRoomMembershipChangeEvent(event, membership) {
261
- if (event.kind !== 40099 || event.pubkey.toLowerCase() !== membership.publisherPublicKey || !event.tags.some((tag) => tag[0] === "h" && tag[1]?.toLowerCase() === membership.roomId)) return;
262
- try {
263
- const content = JSON.parse(event.content);
264
- if (typeof content.type !== "string" || !MEMBERSHIP_CHANGE_TYPES.has(content.type)) return;
265
- const target = typeof content.target === "string" ? content.target.trim().toLowerCase() : content.type === "member_left" && typeof content.actor === "string" ? content.actor.trim().toLowerCase() : "";
266
- if (!HEX_PUBLIC_KEY_PATTERN.test(target)) return;
267
- return {
268
- type: content.type,
269
- targetPublicKey: target
270
- };
271
- } catch {
272
- return;
273
- }
274
- }
275
- //#endregion
276
- export { connectAuthenticatedBuzzRelay as a, openBuzzRelaySubscription as c, parseBuzzRoomMembershipEvent as i, queryBuzzRelaySnapshot as l, BUZZ_ROOM_SYSTEM_KIND as n, connectAuthenticatedBuzzRelaySession as o, parseBuzzRoomMembershipChangeEvent as r, parseBuzzAuthTag as s, BUZZ_ROOM_MEMBERSHIP_KIND as t, isNewerBuzzRevision as u };
@@ -1,2 +0,0 @@
1
- import { t as buzzSetupPlugin } from "./setup-plugin-api-DI8WfvKQ.mjs";
2
- export { buzzSetupPlugin };
@@ -1 +0,0 @@
1
- export {};