@m1heng-clawd/feishu 0.1.11 → 0.1.12
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 +123 -4
- package/index.ts +6 -6
- package/package.json +13 -3
- package/skills/feishu-doc/SKILL.md +40 -2
- package/skills/feishu-task/SKILL.md +210 -0
- package/src/bitable-tools/index.ts +1 -0
- package/src/bot.ts +181 -70
- package/src/channel.ts +2 -0
- package/src/config-schema.ts +4 -0
- package/src/doc-tools/actions.ts +341 -0
- package/src/doc-tools/common.ts +33 -0
- package/src/doc-tools/index.ts +2 -0
- package/src/doc-tools/register.ts +90 -0
- package/src/{doc-schema.ts → doc-tools/schemas.ts} +31 -1
- package/src/drive-tools/actions.ts +182 -0
- package/src/drive-tools/common.ts +18 -0
- package/src/drive-tools/index.ts +2 -0
- package/src/drive-tools/register.ts +71 -0
- package/src/{drive-schema.ts → drive-tools/schemas.ts} +2 -1
- package/src/media.ts +5 -3
- package/src/perm-tools/actions.ts +111 -0
- package/src/perm-tools/common.ts +18 -0
- package/src/perm-tools/index.ts +2 -0
- package/src/perm-tools/register.ts +65 -0
- package/src/policy.ts +13 -0
- package/src/reply-dispatcher.ts +6 -4
- package/src/send.ts +33 -2
- package/src/task-tools/actions.ts +466 -13
- package/src/task-tools/constants.ts +13 -0
- package/src/task-tools/index.ts +1 -0
- package/src/task-tools/register.ts +175 -13
- package/src/task-tools/schemas.ts +433 -4
- package/src/text/markdown-links.ts +104 -0
- package/src/types.ts +1 -0
- package/src/wiki-tools/actions.ts +166 -0
- package/src/wiki-tools/common.ts +18 -0
- package/src/wiki-tools/index.ts +2 -0
- package/src/wiki-tools/register.ts +66 -0
- package/src/bitable.ts +0 -1
- package/src/docx.ts +0 -276
- package/src/drive.ts +0 -237
- package/src/perm.ts +0 -165
- package/src/task.ts +0 -1
- package/src/wiki.ts +0 -223
- /package/src/{perm-schema.ts → perm-tools/schemas.ts} +0 -0
- /package/src/{wiki-schema.ts → wiki-tools/schemas.ts} +0 -0
package/src/bot.ts
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
recordPendingHistoryEntryIfEnabled,
|
|
5
5
|
clearHistoryEntriesIfEnabled,
|
|
6
6
|
DEFAULT_GROUP_HISTORY_LIMIT,
|
|
7
|
+
resolveMentionGatingWithBypass,
|
|
7
8
|
type HistoryEntry,
|
|
8
9
|
} from "openclaw/plugin-sdk";
|
|
9
10
|
import type { FeishuConfig, FeishuMessageContext, FeishuMediaInfo, ResolvedFeishuAccount } from "./types.js";
|
|
@@ -14,6 +15,7 @@ import { tryRecordMessage } from "./dedup.js";
|
|
|
14
15
|
import {
|
|
15
16
|
resolveFeishuGroupConfig,
|
|
16
17
|
resolveFeishuReplyPolicy,
|
|
18
|
+
resolveFeishuGroupCommandMentionBypass,
|
|
17
19
|
resolveFeishuAllowlistMatch,
|
|
18
20
|
isFeishuGroupAllowed,
|
|
19
21
|
} from "./policy.js";
|
|
@@ -145,6 +147,40 @@ async function resolveFeishuSenderName(params: {
|
|
|
145
147
|
}
|
|
146
148
|
}
|
|
147
149
|
|
|
150
|
+
// Cache group bot counts for command mention bypass policy checks.
|
|
151
|
+
const GROUP_BOT_COUNT_TTL_MS = 10 * 60 * 1000;
|
|
152
|
+
const groupBotCountCache = new Map<string, { count: number; expireAt: number }>();
|
|
153
|
+
|
|
154
|
+
async function resolveFeishuGroupBotCount(params: {
|
|
155
|
+
account: ResolvedFeishuAccount;
|
|
156
|
+
chatId: string;
|
|
157
|
+
log: (...args: any[]) => void;
|
|
158
|
+
}): Promise<number | undefined> {
|
|
159
|
+
const { account, chatId, log } = params;
|
|
160
|
+
if (!account.configured || !chatId) return undefined;
|
|
161
|
+
|
|
162
|
+
const cacheKey = `${account.accountId}:${chatId}`;
|
|
163
|
+
const now = Date.now();
|
|
164
|
+
const cached = groupBotCountCache.get(cacheKey);
|
|
165
|
+
if (cached && cached.expireAt > now) return cached.count;
|
|
166
|
+
|
|
167
|
+
try {
|
|
168
|
+
const client = createFeishuClient(account);
|
|
169
|
+
const res: any = await client.im.chat.get({
|
|
170
|
+
path: { chat_id: chatId },
|
|
171
|
+
});
|
|
172
|
+
const parsed = Number.parseInt(String(res?.data?.bot_count ?? ""), 10);
|
|
173
|
+
if (Number.isFinite(parsed) && parsed >= 0) {
|
|
174
|
+
groupBotCountCache.set(cacheKey, { count: parsed, expireAt: now + GROUP_BOT_COUNT_TTL_MS });
|
|
175
|
+
return parsed;
|
|
176
|
+
}
|
|
177
|
+
return undefined;
|
|
178
|
+
} catch (err) {
|
|
179
|
+
log(`feishu[${account.accountId}]: failed to resolve bot_count for ${chatId}: ${String(err)}`);
|
|
180
|
+
return undefined;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
148
184
|
export type FeishuMessageEvent = {
|
|
149
185
|
sender: {
|
|
150
186
|
sender_id: {
|
|
@@ -204,12 +240,21 @@ function parseMessageContent(content: string, messageType: string): string {
|
|
|
204
240
|
}
|
|
205
241
|
}
|
|
206
242
|
|
|
207
|
-
function checkBotMentioned(
|
|
208
|
-
|
|
209
|
-
|
|
243
|
+
function checkBotMentioned(
|
|
244
|
+
event: FeishuMessageEvent,
|
|
245
|
+
botOpenId?: string,
|
|
246
|
+
postMentionIds: string[] = [],
|
|
247
|
+
): boolean {
|
|
248
|
+
const normalizedBotOpenId = botOpenId?.trim();
|
|
210
249
|
// Keep explicit bot mention semantics: without a resolved botOpenId, do not trigger.
|
|
211
|
-
if (!
|
|
212
|
-
|
|
250
|
+
if (!normalizedBotOpenId) return false;
|
|
251
|
+
|
|
252
|
+
const mentions = event.message.mentions ?? [];
|
|
253
|
+
return (
|
|
254
|
+
mentions.some(
|
|
255
|
+
(m) => m.id.open_id === normalizedBotOpenId || m.id.user_id === normalizedBotOpenId,
|
|
256
|
+
) || postMentionIds.some((id) => id === normalizedBotOpenId)
|
|
257
|
+
);
|
|
213
258
|
}
|
|
214
259
|
|
|
215
260
|
function stripBotMention(text: string, mentions?: FeishuMessageEvent["message"]["mentions"]): string {
|
|
@@ -262,6 +307,7 @@ function parseMediaKeys(
|
|
|
262
307
|
function parsePostContent(content: string): {
|
|
263
308
|
textContent: string;
|
|
264
309
|
imageKeys: string[];
|
|
310
|
+
mentionIds: string[];
|
|
265
311
|
} {
|
|
266
312
|
try {
|
|
267
313
|
const parsed = JSON.parse(content);
|
|
@@ -269,6 +315,7 @@ function parsePostContent(content: string): {
|
|
|
269
315
|
const contentBlocks = parsed.content || [];
|
|
270
316
|
let textContent = title ? `${title}\n\n` : "";
|
|
271
317
|
const imageKeys: string[] = [];
|
|
318
|
+
const mentionIds: string[] = [];
|
|
272
319
|
|
|
273
320
|
for (const paragraph of contentBlocks) {
|
|
274
321
|
if (Array.isArray(paragraph)) {
|
|
@@ -280,7 +327,11 @@ function parsePostContent(content: string): {
|
|
|
280
327
|
textContent += element.text || element.href || "";
|
|
281
328
|
} else if (element.tag === "at") {
|
|
282
329
|
// Mention: @username
|
|
283
|
-
|
|
330
|
+
const mentionId =
|
|
331
|
+
String(element.open_id ?? element.user_id ?? element.union_id ?? "").trim() ||
|
|
332
|
+
undefined;
|
|
333
|
+
if (mentionId) mentionIds.push(mentionId);
|
|
334
|
+
textContent += `@${element.user_name || mentionId || ""}`;
|
|
284
335
|
} else if (element.tag === "img" && element.image_key) {
|
|
285
336
|
// Embedded image
|
|
286
337
|
imageKeys.push(element.image_key);
|
|
@@ -293,9 +344,10 @@ function parsePostContent(content: string): {
|
|
|
293
344
|
return {
|
|
294
345
|
textContent: textContent.trim() || "[富文本消息]",
|
|
295
346
|
imageKeys,
|
|
347
|
+
mentionIds,
|
|
296
348
|
};
|
|
297
349
|
} catch {
|
|
298
|
-
return { textContent: "[富文本消息]", imageKeys: [] };
|
|
350
|
+
return { textContent: "[富文本消息]", imageKeys: [], mentionIds: [] };
|
|
299
351
|
}
|
|
300
352
|
}
|
|
301
353
|
|
|
@@ -479,8 +531,12 @@ export function parseFeishuMessageEvent(
|
|
|
479
531
|
event: FeishuMessageEvent,
|
|
480
532
|
botOpenId?: string,
|
|
481
533
|
): FeishuMessageContext {
|
|
534
|
+
const parsedPost =
|
|
535
|
+
event.message.message_type === "post" ? parsePostContent(event.message.content) : undefined;
|
|
482
536
|
const rawContent = parseMessageContent(event.message.content, event.message.message_type);
|
|
483
|
-
const mentionedBot = checkBotMentioned(event, botOpenId);
|
|
537
|
+
const mentionedBot = checkBotMentioned(event, botOpenId, parsedPost?.mentionIds ?? []);
|
|
538
|
+
const hasAnyMention =
|
|
539
|
+
(event.message.mentions?.length ?? 0) > 0 || (parsedPost?.mentionIds.length ?? 0) > 0;
|
|
484
540
|
const content = stripBotMention(rawContent, event.message.mentions);
|
|
485
541
|
|
|
486
542
|
const ctx: FeishuMessageContext = {
|
|
@@ -494,6 +550,7 @@ export function parseFeishuMessageEvent(
|
|
|
494
550
|
parentId: event.message.parent_id || undefined,
|
|
495
551
|
content,
|
|
496
552
|
contentType: event.message.message_type,
|
|
553
|
+
hasAnyMention,
|
|
497
554
|
};
|
|
498
555
|
|
|
499
556
|
// Detect mention forward request: message mentions bot + at least one other user
|
|
@@ -519,11 +576,11 @@ export async function handleFeishuMessage(params: {
|
|
|
519
576
|
accountId?: string;
|
|
520
577
|
}): Promise<void> {
|
|
521
578
|
const { cfg, event, botOpenId, runtime, chatHistories, accountId } = params;
|
|
522
|
-
|
|
579
|
+
|
|
523
580
|
// Resolve account with merged config
|
|
524
581
|
const account = resolveFeishuAccount({ cfg, accountId });
|
|
525
582
|
const feishuCfg = account.config;
|
|
526
|
-
|
|
583
|
+
|
|
527
584
|
const log = runtime?.log ?? console.log;
|
|
528
585
|
const error = runtime?.error ?? console.error;
|
|
529
586
|
|
|
@@ -578,69 +635,17 @@ export async function handleFeishuMessage(params: {
|
|
|
578
635
|
const configAllowFrom = feishuCfg?.allowFrom ?? [];
|
|
579
636
|
const useAccessGroups = cfg.commands?.useAccessGroups !== false;
|
|
580
637
|
|
|
581
|
-
if (isGroup) {
|
|
582
|
-
const groupPolicy = feishuCfg?.groupPolicy ?? "open";
|
|
583
|
-
const groupAllowFrom = feishuCfg?.groupAllowFrom ?? [];
|
|
584
|
-
|
|
585
|
-
// Check if this GROUP is allowed (groupAllowFrom contains group IDs like oc_xxx, not user IDs)
|
|
586
|
-
const groupAllowed = isFeishuGroupAllowed({
|
|
587
|
-
groupPolicy,
|
|
588
|
-
allowFrom: groupAllowFrom,
|
|
589
|
-
senderId: ctx.chatId, // Check group ID, not sender ID
|
|
590
|
-
senderName: undefined,
|
|
591
|
-
});
|
|
592
|
-
|
|
593
|
-
if (!groupAllowed) {
|
|
594
|
-
log(`feishu[${account.accountId}]: sender ${ctx.senderOpenId} not in group allowlist`);
|
|
595
|
-
return;
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
// Additional sender-level allowlist check if group has specific allowFrom config
|
|
599
|
-
const senderAllowFrom = groupConfig?.allowFrom ?? [];
|
|
600
|
-
if (senderAllowFrom.length > 0) {
|
|
601
|
-
const senderAllowed = isFeishuGroupAllowed({
|
|
602
|
-
groupPolicy: "allowlist",
|
|
603
|
-
allowFrom: senderAllowFrom,
|
|
604
|
-
senderId: ctx.senderOpenId,
|
|
605
|
-
senderName: ctx.senderName,
|
|
606
|
-
});
|
|
607
|
-
if (!senderAllowed) {
|
|
608
|
-
log(`feishu: sender ${ctx.senderOpenId} not in group ${ctx.chatId} sender allowlist`);
|
|
609
|
-
return;
|
|
610
|
-
}
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
const { requireMention } = resolveFeishuReplyPolicy({
|
|
614
|
-
isDirectMessage: false,
|
|
615
|
-
globalConfig: feishuCfg,
|
|
616
|
-
groupConfig,
|
|
617
|
-
});
|
|
618
|
-
|
|
619
|
-
if (requireMention && !ctx.mentionedBot) {
|
|
620
|
-
log(`feishu[${account.accountId}]: message in group ${ctx.chatId} did not mention bot, recording to history`);
|
|
621
|
-
if (chatHistories) {
|
|
622
|
-
recordPendingHistoryEntryIfEnabled({
|
|
623
|
-
historyMap: chatHistories,
|
|
624
|
-
historyKey: ctx.chatId,
|
|
625
|
-
limit: historyLimit,
|
|
626
|
-
entry: {
|
|
627
|
-
sender: ctx.senderOpenId,
|
|
628
|
-
body: `${ctx.senderName ?? ctx.senderOpenId}: ${ctx.content}`,
|
|
629
|
-
timestamp: Date.now(),
|
|
630
|
-
messageId: ctx.messageId,
|
|
631
|
-
},
|
|
632
|
-
});
|
|
633
|
-
}
|
|
634
|
-
return;
|
|
635
|
-
}
|
|
636
|
-
}
|
|
637
|
-
|
|
638
638
|
try {
|
|
639
639
|
const core = getFeishuRuntime();
|
|
640
640
|
const shouldComputeCommandAuthorized = core.channel.commands.shouldComputeCommandAuthorized(
|
|
641
641
|
ctx.content,
|
|
642
642
|
cfg,
|
|
643
643
|
);
|
|
644
|
+
const allowTextCommands = core.channel.commands.shouldHandleTextCommands({
|
|
645
|
+
cfg,
|
|
646
|
+
surface: "feishu",
|
|
647
|
+
});
|
|
648
|
+
const hasControlCommand = core.channel.text.hasControlCommand(ctx.content, cfg);
|
|
644
649
|
const storeAllowFrom =
|
|
645
650
|
!isGroup && (dmPolicy !== "open" || shouldComputeCommandAuthorized)
|
|
646
651
|
? await core.channel.pairing.readAllowFromStore("feishu").catch(() => [])
|
|
@@ -686,7 +691,11 @@ export async function handleFeishuMessage(params: {
|
|
|
686
691
|
return;
|
|
687
692
|
}
|
|
688
693
|
|
|
689
|
-
const commandAllowFrom = isGroup
|
|
694
|
+
const commandAllowFrom = isGroup
|
|
695
|
+
? groupConfig?.allowFrom && groupConfig.allowFrom.length > 0
|
|
696
|
+
? groupConfig.allowFrom
|
|
697
|
+
: configAllowFrom
|
|
698
|
+
: effectiveDmAllowFrom;
|
|
690
699
|
const senderAllowedForCommands = resolveFeishuAllowlistMatch({
|
|
691
700
|
allowFrom: commandAllowFrom,
|
|
692
701
|
senderId: ctx.senderOpenId,
|
|
@@ -700,6 +709,105 @@ export async function handleFeishuMessage(params: {
|
|
|
700
709
|
],
|
|
701
710
|
})
|
|
702
711
|
: undefined;
|
|
712
|
+
let effectiveWasMentioned = ctx.mentionedBot;
|
|
713
|
+
|
|
714
|
+
if (isGroup) {
|
|
715
|
+
if (groupConfig?.enabled === false) {
|
|
716
|
+
log(`feishu[${account.accountId}]: group ${ctx.chatId} is disabled`);
|
|
717
|
+
return;
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
const groupPolicy = feishuCfg?.groupPolicy ?? "open";
|
|
721
|
+
const groupAllowFrom = feishuCfg?.groupAllowFrom ?? [];
|
|
722
|
+
|
|
723
|
+
// Check if this GROUP is allowed (groupAllowFrom contains group IDs like oc_xxx, not user IDs)
|
|
724
|
+
const groupAllowed = isFeishuGroupAllowed({
|
|
725
|
+
groupPolicy,
|
|
726
|
+
allowFrom: groupAllowFrom,
|
|
727
|
+
senderId: ctx.chatId, // Check group ID, not sender ID
|
|
728
|
+
senderName: undefined,
|
|
729
|
+
});
|
|
730
|
+
|
|
731
|
+
if (!groupAllowed) {
|
|
732
|
+
log(`feishu[${account.accountId}]: group ${ctx.chatId} not in groupAllowFrom (groupPolicy=${groupPolicy})`);
|
|
733
|
+
return;
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
// Additional sender-level allowlist check if group has specific allowFrom config
|
|
737
|
+
const senderAllowFrom = groupConfig?.allowFrom ?? [];
|
|
738
|
+
if (senderAllowFrom.length > 0) {
|
|
739
|
+
const senderAllowed = isFeishuGroupAllowed({
|
|
740
|
+
groupPolicy: "allowlist",
|
|
741
|
+
allowFrom: senderAllowFrom,
|
|
742
|
+
senderId: ctx.senderOpenId,
|
|
743
|
+
senderName: ctx.senderName,
|
|
744
|
+
});
|
|
745
|
+
if (!senderAllowed) {
|
|
746
|
+
log(`feishu: sender ${ctx.senderOpenId} not in group ${ctx.chatId} sender allowlist`);
|
|
747
|
+
return;
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
const { requireMention } = resolveFeishuReplyPolicy({
|
|
752
|
+
isDirectMessage: false,
|
|
753
|
+
globalConfig: feishuCfg,
|
|
754
|
+
groupConfig,
|
|
755
|
+
});
|
|
756
|
+
|
|
757
|
+
if (requireMention) {
|
|
758
|
+
const bypassPolicy = resolveFeishuGroupCommandMentionBypass({
|
|
759
|
+
globalConfig: feishuCfg,
|
|
760
|
+
groupConfig,
|
|
761
|
+
});
|
|
762
|
+
let bypassAllowedByPolicy = bypassPolicy === "always";
|
|
763
|
+
|
|
764
|
+
if (!bypassAllowedByPolicy && bypassPolicy === "single_bot" && hasControlCommand) {
|
|
765
|
+
const botCount = await resolveFeishuGroupBotCount({
|
|
766
|
+
account,
|
|
767
|
+
chatId: ctx.chatId,
|
|
768
|
+
log,
|
|
769
|
+
});
|
|
770
|
+
bypassAllowedByPolicy = botCount !== undefined && botCount <= 1;
|
|
771
|
+
if (botCount === undefined) {
|
|
772
|
+
log(
|
|
773
|
+
`feishu[${account.accountId}]: unable to resolve bot count for ${ctx.chatId}, command mention bypass disabled`,
|
|
774
|
+
);
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
const mentionGate = resolveMentionGatingWithBypass({
|
|
779
|
+
isGroup: true,
|
|
780
|
+
requireMention,
|
|
781
|
+
canDetectMention: true,
|
|
782
|
+
wasMentioned: ctx.mentionedBot,
|
|
783
|
+
hasAnyMention: ctx.hasAnyMention,
|
|
784
|
+
allowTextCommands: allowTextCommands && bypassAllowedByPolicy,
|
|
785
|
+
hasControlCommand,
|
|
786
|
+
commandAuthorized: commandAuthorized === true,
|
|
787
|
+
});
|
|
788
|
+
effectiveWasMentioned = mentionGate.effectiveWasMentioned;
|
|
789
|
+
|
|
790
|
+
if (mentionGate.shouldSkip) {
|
|
791
|
+
log(
|
|
792
|
+
`feishu[${account.accountId}]: message in group ${ctx.chatId} skipped (mention required)`,
|
|
793
|
+
);
|
|
794
|
+
if (chatHistories) {
|
|
795
|
+
recordPendingHistoryEntryIfEnabled({
|
|
796
|
+
historyMap: chatHistories,
|
|
797
|
+
historyKey: ctx.chatId,
|
|
798
|
+
limit: historyLimit,
|
|
799
|
+
entry: {
|
|
800
|
+
sender: ctx.senderOpenId,
|
|
801
|
+
body: `${ctx.senderName ?? ctx.senderOpenId}: ${ctx.content}`,
|
|
802
|
+
timestamp: Date.now(),
|
|
803
|
+
messageId: ctx.messageId,
|
|
804
|
+
},
|
|
805
|
+
});
|
|
806
|
+
}
|
|
807
|
+
return;
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
}
|
|
703
811
|
|
|
704
812
|
// In group chats, the session is scoped to the group, but the *speaker* is the sender.
|
|
705
813
|
// Using a group-scoped From causes the agent to treat different users as the same person.
|
|
@@ -763,8 +871,11 @@ export async function handleFeishuMessage(params: {
|
|
|
763
871
|
const inboundLabel = isGroup
|
|
764
872
|
? `Feishu[${account.accountId}] message in group ${ctx.chatId}`
|
|
765
873
|
: `Feishu[${account.accountId}] DM from ${ctx.senderOpenId}`;
|
|
874
|
+
const systemEventText = permissionErrorForAgent
|
|
875
|
+
? inboundLabel
|
|
876
|
+
: `${inboundLabel}: ${preview}`;
|
|
766
877
|
|
|
767
|
-
core.system.enqueueSystemEvent(
|
|
878
|
+
core.system.enqueueSystemEvent(systemEventText, {
|
|
768
879
|
sessionKey: route.sessionKey,
|
|
769
880
|
contextKey: `feishu:message:${ctx.chatId}:${ctx.messageId}`,
|
|
770
881
|
});
|
|
@@ -928,7 +1039,7 @@ export async function handleFeishuMessage(params: {
|
|
|
928
1039
|
Surface: "feishu" as const,
|
|
929
1040
|
MessageSid: ctx.messageId,
|
|
930
1041
|
Timestamp: Date.now(),
|
|
931
|
-
WasMentioned:
|
|
1042
|
+
WasMentioned: effectiveWasMentioned,
|
|
932
1043
|
CommandAuthorized: commandAuthorized,
|
|
933
1044
|
OriginatingChannel: "feishu" as const,
|
|
934
1045
|
OriginatingTo: feishuTo,
|
package/src/channel.ts
CHANGED
|
@@ -90,6 +90,7 @@ export const feishuPlugin: ChannelPlugin<ResolvedFeishuAccount> = {
|
|
|
90
90
|
groupPolicy: { type: "string", enum: ["open", "allowlist", "disabled"] },
|
|
91
91
|
groupAllowFrom: { type: "array", items: { oneOf: [{ type: "string" }, { type: "number" }] } },
|
|
92
92
|
requireMention: { type: "boolean" },
|
|
93
|
+
groupCommandMentionBypass: { type: "string", enum: ["never", "single_bot", "always"] },
|
|
93
94
|
topicSessionMode: { type: "string", enum: ["disabled", "enabled"] },
|
|
94
95
|
historyLimit: { type: "integer", minimum: 0 },
|
|
95
96
|
dmHistoryLimit: { type: "integer", minimum: 0 },
|
|
@@ -110,6 +111,7 @@ export const feishuPlugin: ChannelPlugin<ResolvedFeishuAccount> = {
|
|
|
110
111
|
verificationToken: { type: "string" },
|
|
111
112
|
domain: { type: "string", enum: ["feishu", "lark"] },
|
|
112
113
|
connectionMode: { type: "string", enum: ["websocket", "webhook"] },
|
|
114
|
+
groupCommandMentionBypass: { type: "string", enum: ["never", "single_bot", "always"] },
|
|
113
115
|
},
|
|
114
116
|
},
|
|
115
117
|
},
|
package/src/config-schema.ts
CHANGED
|
@@ -3,6 +3,7 @@ export { z };
|
|
|
3
3
|
|
|
4
4
|
const DmPolicySchema = z.enum(["open", "pairing", "allowlist"]);
|
|
5
5
|
const GroupPolicySchema = z.enum(["open", "allowlist", "disabled"]);
|
|
6
|
+
const GroupCommandMentionBypassSchema = z.enum(["never", "single_bot", "always"]).optional();
|
|
6
7
|
const FeishuDomainSchema = z.union([
|
|
7
8
|
z.enum(["feishu", "lark"]),
|
|
8
9
|
z.string().url().startsWith("https://"),
|
|
@@ -104,6 +105,7 @@ const TopicSessionModeSchema = z.enum(["disabled", "enabled"]).optional();
|
|
|
104
105
|
export const FeishuGroupSchema = z
|
|
105
106
|
.object({
|
|
106
107
|
requireMention: z.boolean().optional(),
|
|
108
|
+
groupCommandMentionBypass: GroupCommandMentionBypassSchema,
|
|
107
109
|
tools: ToolPolicySchema,
|
|
108
110
|
skills: z.array(z.string()).optional(),
|
|
109
111
|
enabled: z.boolean().optional(),
|
|
@@ -137,6 +139,7 @@ export const FeishuAccountConfigSchema = z
|
|
|
137
139
|
groupPolicy: GroupPolicySchema.optional(),
|
|
138
140
|
groupAllowFrom: z.array(z.union([z.string(), z.number()])).optional(),
|
|
139
141
|
requireMention: z.boolean().optional(),
|
|
142
|
+
groupCommandMentionBypass: GroupCommandMentionBypassSchema,
|
|
140
143
|
groups: z.record(z.string(), FeishuGroupSchema.optional()).optional(),
|
|
141
144
|
historyLimit: z.number().int().min(0).optional(),
|
|
142
145
|
dmHistoryLimit: z.number().int().min(0).optional(),
|
|
@@ -172,6 +175,7 @@ export const FeishuConfigSchema = z
|
|
|
172
175
|
groupPolicy: GroupPolicySchema.optional().default("allowlist"),
|
|
173
176
|
groupAllowFrom: z.array(z.union([z.string(), z.number()])).optional(),
|
|
174
177
|
requireMention: z.boolean().optional().default(true),
|
|
178
|
+
groupCommandMentionBypass: GroupCommandMentionBypassSchema.default("single_bot"),
|
|
175
179
|
groups: z.record(z.string(), FeishuGroupSchema.optional()).optional(),
|
|
176
180
|
topicSessionMode: TopicSessionModeSchema,
|
|
177
181
|
historyLimit: z.number().int().min(0).optional(),
|