@cored-im/openclaw-plugin 0.1.10 → 0.1.11
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 +1 -5
- package/README.zh.md +1 -5
- package/dist/index.cjs +4 -28
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +4 -28
- package/dist/index.js.map +1 -1
- package/dist/setup-entry.cjs +4 -13
- package/dist/setup-entry.cjs.map +1 -1
- package/dist/setup-entry.d.cts +2 -2
- package/dist/setup-entry.d.ts +2 -2
- package/dist/setup-entry.js +4 -13
- package/dist/setup-entry.js.map +1 -1
- package/dist/{types-C6n4PnbR.d.cts → types-BEkT8vuK.d.cts} +1 -4
- package/dist/{types-C6n4PnbR.d.ts → types-BEkT8vuK.d.ts} +1 -4
- package/openclaw.plugin.json +4 -2
- package/package.json +1 -1
- package/src/channel.ts +1 -1
- package/src/config.test.ts +4 -10
- package/src/config.ts +1 -11
- package/src/messaging/inbound.test.ts +10 -158
- package/src/messaging/inbound.ts +1 -33
- package/src/setup-entry.ts +2 -2
- package/src/types.ts +3 -12
|
@@ -5,7 +5,6 @@ import { describe, it, expect, beforeEach, vi } from "vitest";
|
|
|
5
5
|
import {
|
|
6
6
|
parseMessageEvent,
|
|
7
7
|
checkMessageGate,
|
|
8
|
-
isBotMentioned,
|
|
9
8
|
isDuplicate,
|
|
10
9
|
_resetDedup,
|
|
11
10
|
buildContext,
|
|
@@ -26,15 +25,12 @@ function makeAccount(
|
|
|
26
25
|
): CoredAccountConfig {
|
|
27
26
|
return {
|
|
28
27
|
accountId: "test-account",
|
|
29
|
-
enabled: true,
|
|
30
28
|
appId: "app_test",
|
|
31
29
|
appSecret: "secret",
|
|
32
30
|
backendUrl: "https://your-backend-url.com",
|
|
31
|
+
enabled: true,
|
|
33
32
|
enableEncryption: true,
|
|
34
33
|
requestTimeout: 30_000,
|
|
35
|
-
requireMention: true,
|
|
36
|
-
botUserId: "bot_user_001",
|
|
37
|
-
inboundWhitelist: [],
|
|
38
34
|
...overrides,
|
|
39
35
|
};
|
|
40
36
|
}
|
|
@@ -197,112 +193,11 @@ describe("parseMessageEvent", () => {
|
|
|
197
193
|
describe("checkMessageGate", () => {
|
|
198
194
|
it("passes a normal direct message", () => {
|
|
199
195
|
const msg = parseMessageEvent(makeEvent())!;
|
|
200
|
-
const account = makeAccount({ requireMention: false });
|
|
201
|
-
const result = checkMessageGate(msg, account);
|
|
202
|
-
expect(result.pass).toBe(true);
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
it("blocks self-messages", () => {
|
|
206
|
-
const event = makeEvent({
|
|
207
|
-
sender: { userId: "bot_user_001" },
|
|
208
|
-
});
|
|
209
|
-
const msg = parseMessageEvent(event)!;
|
|
210
196
|
const account = makeAccount();
|
|
211
197
|
const result = checkMessageGate(msg, account);
|
|
212
|
-
expect(result.pass).toBe(false);
|
|
213
|
-
expect(result.reason).toBe("self-message");
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
it("blocks sender not in whitelist when whitelist is set", () => {
|
|
217
|
-
const msg = parseMessageEvent(makeEvent())!;
|
|
218
|
-
const account = makeAccount({
|
|
219
|
-
inboundWhitelist: ["allowed_user"],
|
|
220
|
-
});
|
|
221
|
-
const result = checkMessageGate(msg, account);
|
|
222
|
-
expect(result.pass).toBe(false);
|
|
223
|
-
expect(result.reason).toBe("sender-not-in-whitelist");
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
it("passes sender in whitelist", () => {
|
|
227
|
-
const msg = parseMessageEvent(makeEvent())!;
|
|
228
|
-
const account = makeAccount({
|
|
229
|
-
inboundWhitelist: ["user_sender_001"],
|
|
230
|
-
requireMention: false,
|
|
231
|
-
});
|
|
232
|
-
const result = checkMessageGate(msg, account);
|
|
233
198
|
expect(result.pass).toBe(true);
|
|
234
199
|
});
|
|
235
200
|
|
|
236
|
-
it("blocks group message without mention when requireMention is true", () => {
|
|
237
|
-
const event = makeEvent({ chatType: "group" });
|
|
238
|
-
const msg = parseMessageEvent(event)!;
|
|
239
|
-
const account = makeAccount({ requireMention: true });
|
|
240
|
-
const result = checkMessageGate(msg, account);
|
|
241
|
-
expect(result.pass).toBe(false);
|
|
242
|
-
expect(result.reason).toBe("group-no-mention");
|
|
243
|
-
});
|
|
244
|
-
|
|
245
|
-
it("passes group message with mention", () => {
|
|
246
|
-
const event = makeEvent({
|
|
247
|
-
chatType: "group",
|
|
248
|
-
mentionUserList: [{ userId: "bot_user_001" }],
|
|
249
|
-
});
|
|
250
|
-
const msg = parseMessageEvent(event)!;
|
|
251
|
-
const account = makeAccount({ requireMention: true });
|
|
252
|
-
const result = checkMessageGate(msg, account);
|
|
253
|
-
expect(result.pass).toBe(true);
|
|
254
|
-
});
|
|
255
|
-
|
|
256
|
-
it("passes group message when requireMention is false", () => {
|
|
257
|
-
const event = makeEvent({ chatType: "group" });
|
|
258
|
-
const msg = parseMessageEvent(event)!;
|
|
259
|
-
const account = makeAccount({ requireMention: false });
|
|
260
|
-
const result = checkMessageGate(msg, account);
|
|
261
|
-
expect(result.pass).toBe(true);
|
|
262
|
-
});
|
|
263
|
-
|
|
264
|
-
it("skips self-message check when botUserId is not set", () => {
|
|
265
|
-
const event = makeEvent({
|
|
266
|
-
sender: { userId: "any_user" },
|
|
267
|
-
});
|
|
268
|
-
const msg = parseMessageEvent(event)!;
|
|
269
|
-
const account = makeAccount({ botUserId: undefined });
|
|
270
|
-
const result = checkMessageGate(msg, account);
|
|
271
|
-
expect(result.pass).toBe(true);
|
|
272
|
-
});
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
// ---------------------------------------------------------------------------
|
|
276
|
-
// isBotMentioned
|
|
277
|
-
// ---------------------------------------------------------------------------
|
|
278
|
-
|
|
279
|
-
describe("isBotMentioned", () => {
|
|
280
|
-
it("returns true when bot is in mentionUserIds", () => {
|
|
281
|
-
const event = makeEvent({
|
|
282
|
-
mentionUserList: [{ userId: "bot_user_001" }],
|
|
283
|
-
});
|
|
284
|
-
const msg = parseMessageEvent(event)!;
|
|
285
|
-
const account = makeAccount();
|
|
286
|
-
expect(isBotMentioned(msg, account)).toBe(true);
|
|
287
|
-
});
|
|
288
|
-
|
|
289
|
-
it("returns false when bot is not mentioned", () => {
|
|
290
|
-
const event = makeEvent({
|
|
291
|
-
mentionUserList: [{ userId: "other_user" }],
|
|
292
|
-
});
|
|
293
|
-
const msg = parseMessageEvent(event)!;
|
|
294
|
-
const account = makeAccount();
|
|
295
|
-
expect(isBotMentioned(msg, account)).toBe(false);
|
|
296
|
-
});
|
|
297
|
-
|
|
298
|
-
it("returns false when botUserId is not set", () => {
|
|
299
|
-
const event = makeEvent({
|
|
300
|
-
mentionUserList: [{ userId: "bot_user_001" }],
|
|
301
|
-
});
|
|
302
|
-
const msg = parseMessageEvent(event)!;
|
|
303
|
-
const account = makeAccount({ botUserId: undefined });
|
|
304
|
-
expect(isBotMentioned(msg, account)).toBe(false);
|
|
305
|
-
});
|
|
306
201
|
});
|
|
307
202
|
|
|
308
203
|
// ---------------------------------------------------------------------------
|
|
@@ -348,7 +243,7 @@ describe("buildContext", () => {
|
|
|
348
243
|
expect(ctx.AccountId).toBe("test-account");
|
|
349
244
|
expect(ctx.Body).toBe("hello world");
|
|
350
245
|
expect(ctx.From).toBe("cored:user:user_sender_001");
|
|
351
|
-
expect(ctx.To).toBe("cored:bot:
|
|
246
|
+
expect(ctx.To).toBe("cored:bot:app_test");
|
|
352
247
|
expect(ctx.SessionKey).toBe("cored:user:user_sender_001");
|
|
353
248
|
expect(ctx.CommandAuthorized).toBe(true);
|
|
354
249
|
expect(ctx._cored.isGroup).toBe(false);
|
|
@@ -367,12 +262,6 @@ describe("buildContext", () => {
|
|
|
367
262
|
expect(ctx._cored.chatId).toBe("chat_group_1");
|
|
368
263
|
});
|
|
369
264
|
|
|
370
|
-
it("falls back to appId when botUserId is not set", () => {
|
|
371
|
-
const msg = parseMessageEvent(makeEvent())!;
|
|
372
|
-
const account = makeAccount({ botUserId: undefined });
|
|
373
|
-
const ctx = buildContext(msg, account);
|
|
374
|
-
expect(ctx.To).toBe("cored:bot:app_test");
|
|
375
|
-
});
|
|
376
265
|
});
|
|
377
266
|
|
|
378
267
|
// ---------------------------------------------------------------------------
|
|
@@ -386,7 +275,7 @@ describe("processInboundMessage", () => {
|
|
|
386
275
|
|
|
387
276
|
it("dispatches a valid direct message", async () => {
|
|
388
277
|
const api = makeMockApi();
|
|
389
|
-
const account = makeAccount(
|
|
278
|
+
const account = makeAccount();
|
|
390
279
|
const event = makeEvent();
|
|
391
280
|
const deliver = vi.fn().mockResolvedValue(undefined);
|
|
392
281
|
|
|
@@ -397,21 +286,9 @@ describe("processInboundMessage", () => {
|
|
|
397
286
|
expect(api.runtime.channel.session.recordInboundSession).toHaveBeenCalledOnce();
|
|
398
287
|
});
|
|
399
288
|
|
|
400
|
-
it("filters self-messages", async () => {
|
|
401
|
-
const api = makeMockApi();
|
|
402
|
-
const account = makeAccount();
|
|
403
|
-
const event = makeEvent({ sender: { userId: "bot_user_001" } });
|
|
404
|
-
const deliver = vi.fn();
|
|
405
|
-
|
|
406
|
-
const result = await processInboundMessage(api, account, event, { deliver });
|
|
407
|
-
|
|
408
|
-
expect(result).toBe(false);
|
|
409
|
-
expect(api.runtime.channel.reply.dispatchReplyWithBufferedBlockDispatcher).not.toHaveBeenCalled();
|
|
410
|
-
});
|
|
411
|
-
|
|
412
289
|
it("filters duplicate messages", async () => {
|
|
413
290
|
const api = makeMockApi();
|
|
414
|
-
const account = makeAccount(
|
|
291
|
+
const account = makeAccount();
|
|
415
292
|
const msgId = "msg_dedup_test";
|
|
416
293
|
const event = makeEvent({ messageId: msgId });
|
|
417
294
|
const deliver = vi.fn();
|
|
@@ -423,31 +300,6 @@ describe("processInboundMessage", () => {
|
|
|
423
300
|
expect(second).toBe(false);
|
|
424
301
|
});
|
|
425
302
|
|
|
426
|
-
it("filters group messages without mention when required", async () => {
|
|
427
|
-
const api = makeMockApi();
|
|
428
|
-
const account = makeAccount({ requireMention: true });
|
|
429
|
-
const event = makeEvent({ chatType: "group" });
|
|
430
|
-
const deliver = vi.fn();
|
|
431
|
-
|
|
432
|
-
const result = await processInboundMessage(api, account, event, { deliver });
|
|
433
|
-
|
|
434
|
-
expect(result).toBe(false);
|
|
435
|
-
});
|
|
436
|
-
|
|
437
|
-
it("dispatches group message with mention", async () => {
|
|
438
|
-
const api = makeMockApi();
|
|
439
|
-
const account = makeAccount({ requireMention: true });
|
|
440
|
-
const event = makeEvent({
|
|
441
|
-
chatType: "group",
|
|
442
|
-
mentionUserList: [{ userId: "bot_user_001" }],
|
|
443
|
-
});
|
|
444
|
-
const deliver = vi.fn().mockResolvedValue(undefined);
|
|
445
|
-
|
|
446
|
-
const result = await processInboundMessage(api, account, event, { deliver });
|
|
447
|
-
|
|
448
|
-
expect(result).toBe(true);
|
|
449
|
-
});
|
|
450
|
-
|
|
451
303
|
it("returns false for unparseable event", async () => {
|
|
452
304
|
const api = makeMockApi();
|
|
453
305
|
const account = makeAccount();
|
|
@@ -463,7 +315,7 @@ describe("processInboundMessage", () => {
|
|
|
463
315
|
const api = makeMockApi();
|
|
464
316
|
// Remove dispatch function
|
|
465
317
|
(api.runtime.channel.reply as Record<string, unknown>).dispatchReplyWithBufferedBlockDispatcher = undefined;
|
|
466
|
-
const account = makeAccount(
|
|
318
|
+
const account = makeAccount();
|
|
467
319
|
const event = makeEvent();
|
|
468
320
|
const deliver = vi.fn();
|
|
469
321
|
|
|
@@ -482,7 +334,7 @@ describe("processInboundMessage", () => {
|
|
|
482
334
|
});
|
|
483
335
|
api.runtime.channel.reply.dispatchReplyWithBufferedBlockDispatcher = mockDispatch;
|
|
484
336
|
|
|
485
|
-
const account = makeAccount(
|
|
337
|
+
const account = makeAccount();
|
|
486
338
|
const event = makeEvent({ chatId: "chat_deliver_test" });
|
|
487
339
|
const deliver = vi.fn().mockResolvedValue(undefined);
|
|
488
340
|
|
|
@@ -500,7 +352,7 @@ describe("processInboundMessage", () => {
|
|
|
500
352
|
});
|
|
501
353
|
api.runtime.channel.reply.dispatchReplyWithBufferedBlockDispatcher = mockDispatch;
|
|
502
354
|
|
|
503
|
-
const account = makeAccount(
|
|
355
|
+
const account = makeAccount();
|
|
504
356
|
const event = makeEvent();
|
|
505
357
|
const deliver = vi.fn();
|
|
506
358
|
|
|
@@ -511,7 +363,7 @@ describe("processInboundMessage", () => {
|
|
|
511
363
|
|
|
512
364
|
it("records session with updateLastRoute for DM", async () => {
|
|
513
365
|
const api = makeMockApi();
|
|
514
|
-
const account = makeAccount(
|
|
366
|
+
const account = makeAccount();
|
|
515
367
|
const event = makeEvent({ chatId: "chat_dm_001" });
|
|
516
368
|
const deliver = vi.fn().mockResolvedValue(undefined);
|
|
517
369
|
|
|
@@ -528,7 +380,7 @@ describe("processInboundMessage", () => {
|
|
|
528
380
|
|
|
529
381
|
it("does not set updateLastRoute for group messages", async () => {
|
|
530
382
|
const api = makeMockApi();
|
|
531
|
-
const account = makeAccount(
|
|
383
|
+
const account = makeAccount();
|
|
532
384
|
const event = makeEvent({ chatType: "group" });
|
|
533
385
|
const deliver = vi.fn().mockResolvedValue(undefined);
|
|
534
386
|
|
|
@@ -547,7 +399,7 @@ describe("processInboundMessage", () => {
|
|
|
547
399
|
});
|
|
548
400
|
api.runtime.channel.reply.dispatchReplyWithBufferedBlockDispatcher = mockDispatch;
|
|
549
401
|
|
|
550
|
-
const account = makeAccount(
|
|
402
|
+
const account = makeAccount();
|
|
551
403
|
const event = makeEvent();
|
|
552
404
|
const deliver = vi.fn();
|
|
553
405
|
|
package/src/messaging/inbound.ts
CHANGED
|
@@ -151,41 +151,9 @@ export function checkMessageGate(
|
|
|
151
151
|
msg: ParsedInboundMessage,
|
|
152
152
|
account: CoredAccountConfig,
|
|
153
153
|
): GateResult {
|
|
154
|
-
// 1. Self-message filter: ignore messages from the bot itself
|
|
155
|
-
if (account.botUserId && msg.senderId === account.botUserId) {
|
|
156
|
-
return { pass: false, reason: "self-message" };
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// 2. Whitelist filter: if whitelist is non-empty, only allow listed senders
|
|
160
|
-
if (account.inboundWhitelist.length > 0) {
|
|
161
|
-
if (!account.inboundWhitelist.includes(msg.senderId)) {
|
|
162
|
-
return { pass: false, reason: "sender-not-in-whitelist" };
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// 3. Group mention filter: in group chats, require @mention if configured
|
|
167
|
-
if (
|
|
168
|
-
msg.chatType === "group" &&
|
|
169
|
-
account.requireMention &&
|
|
170
|
-
!isBotMentioned(msg, account)
|
|
171
|
-
) {
|
|
172
|
-
return { pass: false, reason: "group-no-mention" };
|
|
173
|
-
}
|
|
174
|
-
|
|
175
154
|
return { pass: true };
|
|
176
155
|
}
|
|
177
156
|
|
|
178
|
-
/**
|
|
179
|
-
* Check if the bot was @mentioned in a message.
|
|
180
|
-
*/
|
|
181
|
-
export function isBotMentioned(
|
|
182
|
-
msg: ParsedInboundMessage,
|
|
183
|
-
account: CoredAccountConfig,
|
|
184
|
-
): boolean {
|
|
185
|
-
if (!account.botUserId) return false;
|
|
186
|
-
return msg.mentionUserIds.includes(account.botUserId);
|
|
187
|
-
}
|
|
188
|
-
|
|
189
157
|
// ---------------------------------------------------------------------------
|
|
190
158
|
// Dedup — skip already-processed message IDs
|
|
191
159
|
// ---------------------------------------------------------------------------
|
|
@@ -279,7 +247,7 @@ export function buildContext(
|
|
|
279
247
|
return {
|
|
280
248
|
Body: msg.body,
|
|
281
249
|
From: isGroup ? `cored:chat:${msg.chatId}` : `cored:user:${msg.senderId}`,
|
|
282
|
-
To: `cored:bot:${account.
|
|
250
|
+
To: `cored:bot:${account.appId}`,
|
|
283
251
|
SessionKey: sessionKey,
|
|
284
252
|
AccountId: account.accountId,
|
|
285
253
|
ChatType: isGroup ? "group" : "direct",
|
package/src/setup-entry.ts
CHANGED
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
4
|
import { defineSetupPluginEntry } from "openclaw/plugin-sdk/core";
|
|
5
|
-
import {
|
|
5
|
+
import { base } from "./channel.js";
|
|
6
6
|
|
|
7
|
-
export default defineSetupPluginEntry(
|
|
7
|
+
export default defineSetupPluginEntry(base);
|
package/src/types.ts
CHANGED
|
@@ -5,39 +5,30 @@
|
|
|
5
5
|
|
|
6
6
|
export interface CoredAccountConfig {
|
|
7
7
|
accountId: string;
|
|
8
|
-
enabled: boolean;
|
|
9
8
|
appId: string;
|
|
10
9
|
appSecret: string;
|
|
11
10
|
backendUrl: string;
|
|
11
|
+
enabled: boolean;
|
|
12
12
|
enableEncryption: boolean;
|
|
13
13
|
requestTimeout: number;
|
|
14
|
-
requireMention: boolean;
|
|
15
|
-
botUserId?: string;
|
|
16
|
-
inboundWhitelist: string[];
|
|
17
14
|
}
|
|
18
15
|
|
|
19
16
|
export interface CoredRawAccountConfig {
|
|
20
17
|
appId?: string;
|
|
21
18
|
appSecret?: string;
|
|
22
19
|
backendUrl?: string;
|
|
20
|
+
enabled?: boolean;
|
|
23
21
|
enableEncryption?: boolean;
|
|
24
22
|
requestTimeout?: number;
|
|
25
|
-
requireMention?: boolean;
|
|
26
|
-
enabled?: boolean;
|
|
27
|
-
botUserId?: string;
|
|
28
|
-
inboundWhitelist?: string[];
|
|
29
23
|
}
|
|
30
24
|
|
|
31
25
|
export interface CoredChannelConfig {
|
|
32
26
|
appId?: string;
|
|
33
27
|
appSecret?: string;
|
|
34
28
|
backendUrl?: string;
|
|
29
|
+
enabled?: boolean;
|
|
35
30
|
enableEncryption?: boolean;
|
|
36
31
|
requestTimeout?: number;
|
|
37
|
-
requireMention?: boolean;
|
|
38
|
-
enabled?: boolean;
|
|
39
|
-
botUserId?: string;
|
|
40
|
-
inboundWhitelist?: string[];
|
|
41
32
|
accounts?: Record<string, CoredRawAccountConfig>;
|
|
42
33
|
}
|
|
43
34
|
|