@nextclaw/channel-runtime 0.1.7 → 0.1.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.
- package/dist/index.d.ts +8 -0
- package/dist/index.js +177 -8
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -64,6 +64,9 @@ declare class DiscordChannel extends BaseChannel<Config["channels"]["discord"]>
|
|
|
64
64
|
send(msg: OutboundMessage): Promise<void>;
|
|
65
65
|
private handleIncoming;
|
|
66
66
|
private resolveProxyAgent;
|
|
67
|
+
private resolveAccountId;
|
|
68
|
+
private isAllowedByPolicy;
|
|
69
|
+
private resolveMentionState;
|
|
67
70
|
private resolveInboundAttachment;
|
|
68
71
|
private startTyping;
|
|
69
72
|
private stopTyping;
|
|
@@ -192,6 +195,8 @@ declare class TelegramChannel extends BaseChannel<Config["channels"]["telegram"]
|
|
|
192
195
|
private sessionManager?;
|
|
193
196
|
name: string;
|
|
194
197
|
private bot;
|
|
198
|
+
private botUserId;
|
|
199
|
+
private botUsername;
|
|
195
200
|
private readonly typingController;
|
|
196
201
|
private transcriber;
|
|
197
202
|
constructor(config: Config["channels"]["telegram"], bus: MessageBus, groqApiKey?: string, sessionManager?: SessionManager | undefined);
|
|
@@ -202,6 +207,9 @@ declare class TelegramChannel extends BaseChannel<Config["channels"]["telegram"]
|
|
|
202
207
|
private dispatchToBus;
|
|
203
208
|
private startTyping;
|
|
204
209
|
private stopTyping;
|
|
210
|
+
private resolveAccountId;
|
|
211
|
+
private isAllowedByPolicy;
|
|
212
|
+
private resolveMentionState;
|
|
205
213
|
}
|
|
206
214
|
|
|
207
215
|
declare class WeComChannel extends BaseChannel<Config["channels"]["wecom"]> {
|
package/dist/index.js
CHANGED
|
@@ -316,7 +316,12 @@ var DiscordChannel = class extends BaseChannel {
|
|
|
316
316
|
}
|
|
317
317
|
const senderId = message.author.id;
|
|
318
318
|
const channelId = message.channelId;
|
|
319
|
-
|
|
319
|
+
const isGroup = Boolean(message.guildId);
|
|
320
|
+
if (!this.isAllowedByPolicy({ senderId, channelId, isGroup })) {
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
const mentionState = this.resolveMentionState({ message, selfUserId, channelId, isGroup });
|
|
324
|
+
if (mentionState.requireMention && !mentionState.wasMentioned) {
|
|
320
325
|
return;
|
|
321
326
|
}
|
|
322
327
|
const contentParts = [];
|
|
@@ -358,8 +363,16 @@ var DiscordChannel = class extends BaseChannel {
|
|
|
358
363
|
attachments,
|
|
359
364
|
metadata: {
|
|
360
365
|
message_id: message.id,
|
|
366
|
+
channel_id: channelId,
|
|
361
367
|
guild_id: message.guildId,
|
|
362
368
|
reply_to: replyTo,
|
|
369
|
+
account_id: this.resolveAccountId(),
|
|
370
|
+
accountId: this.resolveAccountId(),
|
|
371
|
+
is_group: isGroup,
|
|
372
|
+
peer_kind: isGroup ? "channel" : "direct",
|
|
373
|
+
peer_id: isGroup ? channelId : senderId,
|
|
374
|
+
was_mentioned: mentionState.wasMentioned,
|
|
375
|
+
require_mention: mentionState.requireMention,
|
|
363
376
|
...attachmentIssues.length ? { attachment_issues: attachmentIssues } : {}
|
|
364
377
|
}
|
|
365
378
|
});
|
|
@@ -378,6 +391,62 @@ var DiscordChannel = class extends BaseChannel {
|
|
|
378
391
|
return null;
|
|
379
392
|
}
|
|
380
393
|
}
|
|
394
|
+
resolveAccountId() {
|
|
395
|
+
const accountId = this.config.accountId?.trim();
|
|
396
|
+
return accountId || "default";
|
|
397
|
+
}
|
|
398
|
+
isAllowedByPolicy(params) {
|
|
399
|
+
if (!params.isGroup) {
|
|
400
|
+
if (this.config.dmPolicy === "disabled") {
|
|
401
|
+
return false;
|
|
402
|
+
}
|
|
403
|
+
const allowFrom = this.config.allowFrom ?? [];
|
|
404
|
+
if (this.config.dmPolicy === "allowlist" || this.config.dmPolicy === "pairing") {
|
|
405
|
+
return this.isAllowed(params.senderId);
|
|
406
|
+
}
|
|
407
|
+
if (allowFrom.includes("*")) {
|
|
408
|
+
return true;
|
|
409
|
+
}
|
|
410
|
+
return allowFrom.length === 0 ? true : this.isAllowed(params.senderId);
|
|
411
|
+
}
|
|
412
|
+
if (this.config.groupPolicy === "disabled") {
|
|
413
|
+
return false;
|
|
414
|
+
}
|
|
415
|
+
if (this.config.groupPolicy === "allowlist") {
|
|
416
|
+
const allowFrom = this.config.groupAllowFrom ?? [];
|
|
417
|
+
return allowFrom.includes("*") || allowFrom.includes(params.channelId);
|
|
418
|
+
}
|
|
419
|
+
return true;
|
|
420
|
+
}
|
|
421
|
+
resolveMentionState(params) {
|
|
422
|
+
if (!params.isGroup) {
|
|
423
|
+
return { wasMentioned: false, requireMention: false };
|
|
424
|
+
}
|
|
425
|
+
const groups = this.config.groups ?? {};
|
|
426
|
+
const groupRule = groups[params.channelId] ?? groups["*"];
|
|
427
|
+
const requireMention = groupRule?.requireMention ?? this.config.requireMention ?? false;
|
|
428
|
+
if (!requireMention) {
|
|
429
|
+
return { wasMentioned: false, requireMention: false };
|
|
430
|
+
}
|
|
431
|
+
const patterns = [
|
|
432
|
+
...this.config.mentionPatterns ?? [],
|
|
433
|
+
...groupRule?.mentionPatterns ?? []
|
|
434
|
+
].map((pattern) => pattern.trim()).filter(Boolean);
|
|
435
|
+
const content = params.message.content ?? "";
|
|
436
|
+
const wasMentionedByUserRef = Boolean(params.selfUserId) && params.message.mentions.users.has(params.selfUserId ?? "");
|
|
437
|
+
const wasMentionedByText = Boolean(params.selfUserId) && (content.includes(`<@${params.selfUserId}>`) || content.includes(`<@!${params.selfUserId}>`));
|
|
438
|
+
const wasMentionedByPattern = patterns.some((pattern) => {
|
|
439
|
+
try {
|
|
440
|
+
return new RegExp(pattern, "i").test(content);
|
|
441
|
+
} catch {
|
|
442
|
+
return content.toLowerCase().includes(pattern.toLowerCase());
|
|
443
|
+
}
|
|
444
|
+
});
|
|
445
|
+
return {
|
|
446
|
+
wasMentioned: wasMentionedByUserRef || wasMentionedByText || wasMentionedByPattern,
|
|
447
|
+
requireMention
|
|
448
|
+
};
|
|
449
|
+
}
|
|
381
450
|
async resolveInboundAttachment(params) {
|
|
382
451
|
const { attachment, mediaDir, maxBytes, proxy } = params;
|
|
383
452
|
const id = attachment.id;
|
|
@@ -2395,6 +2464,8 @@ var TelegramChannel = class extends BaseChannel {
|
|
|
2395
2464
|
}
|
|
2396
2465
|
name = "telegram";
|
|
2397
2466
|
bot = null;
|
|
2467
|
+
botUserId = null;
|
|
2468
|
+
botUsername = null;
|
|
2398
2469
|
typingController;
|
|
2399
2470
|
transcriber;
|
|
2400
2471
|
async start() {
|
|
@@ -2407,6 +2478,14 @@ var TelegramChannel = class extends BaseChannel {
|
|
|
2407
2478
|
options.request = { proxy: this.config.proxy };
|
|
2408
2479
|
}
|
|
2409
2480
|
this.bot = new TelegramBot(this.config.token, options);
|
|
2481
|
+
try {
|
|
2482
|
+
const me = await this.bot.getMe();
|
|
2483
|
+
this.botUserId = me.id;
|
|
2484
|
+
this.botUsername = me.username ?? null;
|
|
2485
|
+
} catch {
|
|
2486
|
+
this.botUserId = null;
|
|
2487
|
+
this.botUsername = null;
|
|
2488
|
+
}
|
|
2410
2489
|
this.bot.onText(/^\/start$/, async (msg) => {
|
|
2411
2490
|
await this.bot?.sendMessage(
|
|
2412
2491
|
msg.chat.id,
|
|
@@ -2432,12 +2511,31 @@ Just send me a text message to chat!`;
|
|
|
2432
2511
|
await this.bot?.sendMessage(msg.chat.id, "\u26A0\uFE0F Session management is not available.");
|
|
2433
2512
|
return;
|
|
2434
2513
|
}
|
|
2435
|
-
const
|
|
2436
|
-
const
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2514
|
+
const accountId = this.resolveAccountId();
|
|
2515
|
+
const candidates = this.sessionManager.listSessions().filter((entry) => {
|
|
2516
|
+
const metadata = entry.metadata ?? {};
|
|
2517
|
+
const lastChannel = typeof metadata.last_channel === "string" ? metadata.last_channel : "";
|
|
2518
|
+
const lastTo = typeof metadata.last_to === "string" ? metadata.last_to : "";
|
|
2519
|
+
const lastAccountId = typeof metadata.last_account_id === "string" ? metadata.last_account_id : typeof metadata.last_accountId === "string" ? metadata.last_accountId : "default";
|
|
2520
|
+
return lastChannel === this.name && lastTo === chatId && lastAccountId === accountId;
|
|
2521
|
+
}).map((entry) => String(entry.key ?? "")).filter(Boolean);
|
|
2522
|
+
let totalCleared = 0;
|
|
2523
|
+
for (const key of candidates) {
|
|
2524
|
+
const session = this.sessionManager.getIfExists(key);
|
|
2525
|
+
if (!session) {
|
|
2526
|
+
continue;
|
|
2527
|
+
}
|
|
2528
|
+
totalCleared += session.messages.length;
|
|
2529
|
+
this.sessionManager.clear(session);
|
|
2530
|
+
this.sessionManager.save(session);
|
|
2531
|
+
}
|
|
2532
|
+
if (candidates.length === 0) {
|
|
2533
|
+
const legacySession = this.sessionManager.getOrCreate(`${this.name}:${chatId}`);
|
|
2534
|
+
totalCleared = legacySession.messages.length;
|
|
2535
|
+
this.sessionManager.clear(legacySession);
|
|
2536
|
+
this.sessionManager.save(legacySession);
|
|
2537
|
+
}
|
|
2538
|
+
await this.bot?.sendMessage(msg.chat.id, `\u{1F504} Conversation history cleared (${totalCleared} messages).`);
|
|
2441
2539
|
});
|
|
2442
2540
|
this.bot.on("message", async (msg) => {
|
|
2443
2541
|
if (!msg.text && !msg.caption && !msg.photo && !msg.voice && !msg.audio && !msg.document) {
|
|
@@ -2498,6 +2596,14 @@ Just send me a text message to chat!`;
|
|
|
2498
2596
|
return;
|
|
2499
2597
|
}
|
|
2500
2598
|
const chatId = String(message.chat.id);
|
|
2599
|
+
const isGroup = message.chat.type !== "private";
|
|
2600
|
+
if (!this.isAllowedByPolicy({ senderId: String(sender.id), chatId, isGroup })) {
|
|
2601
|
+
return;
|
|
2602
|
+
}
|
|
2603
|
+
const mentionState = this.resolveMentionState({ message, chatId, isGroup });
|
|
2604
|
+
if (mentionState.requireMention && !mentionState.wasMentioned) {
|
|
2605
|
+
return;
|
|
2606
|
+
}
|
|
2501
2607
|
let senderId = String(sender.id);
|
|
2502
2608
|
if (sender.username) {
|
|
2503
2609
|
senderId = `${senderId}|${sender.username}`;
|
|
@@ -2546,7 +2652,13 @@ Just send me a text message to chat!`;
|
|
|
2546
2652
|
first_name: sender.firstName,
|
|
2547
2653
|
sender_type: sender.type,
|
|
2548
2654
|
is_bot: sender.isBot,
|
|
2549
|
-
is_group:
|
|
2655
|
+
is_group: isGroup,
|
|
2656
|
+
account_id: this.resolveAccountId(),
|
|
2657
|
+
accountId: this.resolveAccountId(),
|
|
2658
|
+
peer_kind: isGroup ? "group" : "direct",
|
|
2659
|
+
peer_id: isGroup ? chatId : String(sender.id),
|
|
2660
|
+
was_mentioned: mentionState.wasMentioned,
|
|
2661
|
+
require_mention: mentionState.requireMention
|
|
2550
2662
|
});
|
|
2551
2663
|
} finally {
|
|
2552
2664
|
this.stopTyping(chatId);
|
|
@@ -2561,6 +2673,63 @@ Just send me a text message to chat!`;
|
|
|
2561
2673
|
stopTyping(chatId) {
|
|
2562
2674
|
this.typingController.stop(chatId);
|
|
2563
2675
|
}
|
|
2676
|
+
resolveAccountId() {
|
|
2677
|
+
const accountId = this.config.accountId?.trim();
|
|
2678
|
+
return accountId || "default";
|
|
2679
|
+
}
|
|
2680
|
+
isAllowedByPolicy(params) {
|
|
2681
|
+
if (!params.isGroup) {
|
|
2682
|
+
if (this.config.dmPolicy === "disabled") {
|
|
2683
|
+
return false;
|
|
2684
|
+
}
|
|
2685
|
+
const allowFrom = this.config.allowFrom ?? [];
|
|
2686
|
+
if (this.config.dmPolicy === "allowlist" || this.config.dmPolicy === "pairing") {
|
|
2687
|
+
return this.isAllowed(params.senderId);
|
|
2688
|
+
}
|
|
2689
|
+
if (allowFrom.includes("*")) {
|
|
2690
|
+
return true;
|
|
2691
|
+
}
|
|
2692
|
+
return allowFrom.length === 0 ? true : this.isAllowed(params.senderId);
|
|
2693
|
+
}
|
|
2694
|
+
if (this.config.groupPolicy === "disabled") {
|
|
2695
|
+
return false;
|
|
2696
|
+
}
|
|
2697
|
+
if (this.config.groupPolicy === "allowlist") {
|
|
2698
|
+
const allowFrom = this.config.groupAllowFrom ?? [];
|
|
2699
|
+
return allowFrom.includes("*") || allowFrom.includes(params.chatId);
|
|
2700
|
+
}
|
|
2701
|
+
return true;
|
|
2702
|
+
}
|
|
2703
|
+
resolveMentionState(params) {
|
|
2704
|
+
if (!params.isGroup) {
|
|
2705
|
+
return { wasMentioned: false, requireMention: false };
|
|
2706
|
+
}
|
|
2707
|
+
const groups = this.config.groups ?? {};
|
|
2708
|
+
const groupRule = groups[params.chatId] ?? groups["*"];
|
|
2709
|
+
const requireMention = groupRule?.requireMention ?? this.config.requireMention ?? false;
|
|
2710
|
+
if (!requireMention) {
|
|
2711
|
+
return { wasMentioned: false, requireMention: false };
|
|
2712
|
+
}
|
|
2713
|
+
const content = `${params.message.text ?? ""}
|
|
2714
|
+
${params.message.caption ?? ""}`.trim();
|
|
2715
|
+
const patterns = [
|
|
2716
|
+
...this.config.mentionPatterns ?? [],
|
|
2717
|
+
...groupRule?.mentionPatterns ?? []
|
|
2718
|
+
].map((pattern) => pattern.trim()).filter(Boolean);
|
|
2719
|
+
const usernameMentioned = this.botUsername ? content.includes(`@${this.botUsername}`) : false;
|
|
2720
|
+
const replyToBot = Boolean(this.botUserId) && Boolean(params.message.reply_to_message?.from) && params.message.reply_to_message?.from?.id === this.botUserId;
|
|
2721
|
+
const patternMentioned = patterns.some((pattern) => {
|
|
2722
|
+
try {
|
|
2723
|
+
return new RegExp(pattern, "i").test(content);
|
|
2724
|
+
} catch {
|
|
2725
|
+
return content.toLowerCase().includes(pattern.toLowerCase());
|
|
2726
|
+
}
|
|
2727
|
+
});
|
|
2728
|
+
return {
|
|
2729
|
+
wasMentioned: usernameMentioned || replyToBot || patternMentioned,
|
|
2730
|
+
requireMention
|
|
2731
|
+
};
|
|
2732
|
+
}
|
|
2564
2733
|
};
|
|
2565
2734
|
function resolveSender(message) {
|
|
2566
2735
|
if (message.from) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextclaw/channel-runtime",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Runtime implementations for NextClaw builtin channel plugins.",
|
|
6
6
|
"type": "module",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
],
|
|
16
16
|
"dependencies": {
|
|
17
17
|
"@larksuiteoapi/node-sdk": "^1.58.0",
|
|
18
|
-
"@nextclaw/core": "^0.6.
|
|
18
|
+
"@nextclaw/core": "^0.6.22",
|
|
19
19
|
"@slack/socket-mode": "^1.3.3",
|
|
20
20
|
"@slack/web-api": "^7.6.0",
|
|
21
21
|
"dingtalk-stream": "^2.1.4",
|