feat(feishu): sync with clawdbot-feishu #137 (multi-account support)

- Sync latest changes from clawdbot-feishu including multi-account support
- Add eslint-disable comments for SDK-related any types
- Remove unused imports
- Fix no-floating-promises in monitor.ts

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Yifeng Wang
2026-02-05 19:18:25 +08:00
committed by cpojer
parent 7e005acd3c
commit 5f6e1c19bd
22 changed files with 785 additions and 369 deletions

View File

@@ -1,6 +1,7 @@
import type { ClawdbotConfig } from "openclaw/plugin-sdk";
import type { MentionTarget } from "./mention.js";
import type { FeishuConfig, FeishuSendResult } from "./types.js";
import type { FeishuSendResult } from "./types.js";
import { resolveFeishuAccount } from "./accounts.js";
import { createFeishuClient } from "./client.js";
import { buildMentionedMessage, buildMentionedCardContent } from "./mention.js";
import { getFeishuRuntime } from "./runtime.js";
@@ -23,14 +24,15 @@ export type FeishuMessageInfo = {
export async function getMessageFeishu(params: {
cfg: ClawdbotConfig;
messageId: string;
accountId?: string;
}): Promise<FeishuMessageInfo | null> {
const { cfg, messageId } = params;
const feishuCfg = cfg.channels?.feishu as FeishuConfig | undefined;
if (!feishuCfg) {
throw new Error("Feishu channel not configured");
const { cfg, messageId, accountId } = params;
const account = resolveFeishuAccount({ cfg, accountId });
if (!account.configured) {
throw new Error(`Feishu account "${account.accountId}" not configured`);
}
const client = createFeishuClient(feishuCfg);
const client = createFeishuClient(account);
try {
const response = (await client.im.message.get({
@@ -95,9 +97,11 @@ export type SendFeishuMessageParams = {
replyToMessageId?: string;
/** Mention target users */
mentions?: MentionTarget[];
/** Account ID (optional, uses default if not specified) */
accountId?: string;
};
function buildFeishuPostMessagePayload(params: { feishuCfg: FeishuConfig; messageText: string }): {
function buildFeishuPostMessagePayload(params: { messageText: string }): {
content: string;
msgType: string;
} {
@@ -122,13 +126,13 @@ function buildFeishuPostMessagePayload(params: { feishuCfg: FeishuConfig; messag
export async function sendMessageFeishu(
params: SendFeishuMessageParams,
): Promise<FeishuSendResult> {
const { cfg, to, text, replyToMessageId, mentions } = params;
const feishuCfg = cfg.channels?.feishu as FeishuConfig | undefined;
if (!feishuCfg) {
throw new Error("Feishu channel not configured");
const { cfg, to, text, replyToMessageId, mentions, accountId } = params;
const account = resolveFeishuAccount({ cfg, accountId });
if (!account.configured) {
throw new Error(`Feishu account "${account.accountId}" not configured`);
}
const client = createFeishuClient(feishuCfg);
const client = createFeishuClient(account);
const receiveId = normalizeFeishuTarget(to);
if (!receiveId) {
throw new Error(`Invalid Feishu target: ${to}`);
@@ -147,10 +151,7 @@ export async function sendMessageFeishu(
}
const messageText = getFeishuRuntime().channel.text.convertMarkdownTables(rawText, tableMode);
const { content, msgType } = buildFeishuPostMessagePayload({
feishuCfg,
messageText,
});
const { content, msgType } = buildFeishuPostMessagePayload({ messageText });
if (replyToMessageId) {
const response = await client.im.message.reply({
@@ -195,16 +196,17 @@ export type SendFeishuCardParams = {
to: string;
card: Record<string, unknown>;
replyToMessageId?: string;
accountId?: string;
};
export async function sendCardFeishu(params: SendFeishuCardParams): Promise<FeishuSendResult> {
const { cfg, to, card, replyToMessageId } = params;
const feishuCfg = cfg.channels?.feishu as FeishuConfig | undefined;
if (!feishuCfg) {
throw new Error("Feishu channel not configured");
const { cfg, to, card, replyToMessageId, accountId } = params;
const account = resolveFeishuAccount({ cfg, accountId });
if (!account.configured) {
throw new Error(`Feishu account "${account.accountId}" not configured`);
}
const client = createFeishuClient(feishuCfg);
const client = createFeishuClient(account);
const receiveId = normalizeFeishuTarget(to);
if (!receiveId) {
throw new Error(`Invalid Feishu target: ${to}`);
@@ -255,14 +257,15 @@ export async function updateCardFeishu(params: {
cfg: ClawdbotConfig;
messageId: string;
card: Record<string, unknown>;
accountId?: string;
}): Promise<void> {
const { cfg, messageId, card } = params;
const feishuCfg = cfg.channels?.feishu as FeishuConfig | undefined;
if (!feishuCfg) {
throw new Error("Feishu channel not configured");
const { cfg, messageId, card, accountId } = params;
const account = resolveFeishuAccount({ cfg, accountId });
if (!account.configured) {
throw new Error(`Feishu account "${account.accountId}" not configured`);
}
const client = createFeishuClient(feishuCfg);
const client = createFeishuClient(account);
const content = JSON.stringify(card);
const response = await client.im.message.patch({
@@ -304,15 +307,16 @@ export async function sendMarkdownCardFeishu(params: {
replyToMessageId?: string;
/** Mention target users */
mentions?: MentionTarget[];
accountId?: string;
}): Promise<FeishuSendResult> {
const { cfg, to, text, replyToMessageId, mentions } = params;
const { cfg, to, text, replyToMessageId, mentions, accountId } = params;
// Build message content (with @mention support)
let cardText = text;
if (mentions && mentions.length > 0) {
cardText = buildMentionedCardContent(mentions, text);
}
const card = buildMarkdownCard(cardText);
return sendCardFeishu({ cfg, to, card, replyToMessageId });
return sendCardFeishu({ cfg, to, card, replyToMessageId, accountId });
}
/**
@@ -323,24 +327,22 @@ export async function editMessageFeishu(params: {
cfg: ClawdbotConfig;
messageId: string;
text: string;
accountId?: string;
}): Promise<void> {
const { cfg, messageId, text } = params;
const feishuCfg = cfg.channels?.feishu as FeishuConfig | undefined;
if (!feishuCfg) {
throw new Error("Feishu channel not configured");
const { cfg, messageId, text, accountId } = params;
const account = resolveFeishuAccount({ cfg, accountId });
if (!account.configured) {
throw new Error(`Feishu account "${account.accountId}" not configured`);
}
const client = createFeishuClient(feishuCfg);
const client = createFeishuClient(account);
const tableMode = getFeishuRuntime().channel.text.resolveMarkdownTableMode({
cfg,
channel: "feishu",
});
const messageText = getFeishuRuntime().channel.text.convertMarkdownTables(text ?? "", tableMode);
const { content, msgType } = buildFeishuPostMessagePayload({
feishuCfg,
messageText,
});
const { content, msgType } = buildFeishuPostMessagePayload({ messageText });
const response = await client.im.message.update({
path: { message_id: messageId },