@openclaw/feishu 2026.7.2-beta.7 → 2026.8.1-beta.2
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/accounts-CCCdMen2.js +203 -0
- package/dist/api.js +52 -51
- package/dist/{channel-CScE82zY.js → channel-Dzb5jv3i.js} +53 -30
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{channel.runtime-B21e1E0r.js → channel.runtime-CoPaHQQ6.js} +181 -142
- package/dist/{client-Dcbs6vml.js → client-Hp7uo_cl.js} +27 -16
- package/dist/contract-api.js +2 -2
- package/dist/{conversation-id-BeJL-wq7.js → conversation-id-VYgGQ-GX.js} +11 -15
- package/dist/doctor-contract-api.js +1 -1
- package/dist/doctor-contract-bEQXIXyP.js +158 -0
- package/dist/{drive-hSi_Utp0.js → drive-B0JkoiRj.js} +318 -41
- package/dist/{media-CEUraFOR.js → media-BjSy8fiy.js} +298 -182
- package/dist/{monitor-DngbaA6a.js → monitor-CeHCfROt.js} +3 -3
- package/dist/{monitor.account-BnTWCw55.js → monitor.account-DwdqexLU.js} +237 -158
- package/dist/{monitor.startup-CqH2tiJq.js → monitor.startup-BGErejNH.js} +1 -1
- package/dist/{probe-p3POS2RN.js → probe-DVpy58s0.js} +2 -2
- package/dist/security-audit-D6Fz2h6p.js +23 -0
- package/dist/{send-result-B9_BpUPx.js → send-result-DEAycmOk.js} +18 -9
- package/dist/session-binding-contract-api.js +1 -1
- package/dist/{session-conversation-BksWrfzm.js → session-conversation-DFCIvQK-.js} +1 -1
- package/dist/session-key-api.js +1 -1
- package/dist/setup-api.js +1 -1
- package/dist/{subagent-hooks-Cx1cX7rW.js → subagent-hooks-B867acTt.js} +2 -2
- package/dist/subagent-hooks-api.js +1 -1
- package/dist/{thread-bindings-N3wkgkIN.js → thread-bindings-Itvfmx6_.js} +6 -3
- package/openclaw.plugin.json +143 -1
- package/package.json +4 -4
- package/skills/feishu-doc/SKILL.md +20 -195
- package/skills/feishu-doc/references/block-types.md +9 -14
- package/skills/feishu-drive/SKILL.md +16 -102
- package/skills/feishu-perm/SKILL.md +10 -110
- package/skills/feishu-wiki/SKILL.md +13 -109
- package/dist/accounts-u9X5Wsan.js +0 -469
- package/dist/doctor-contract-BiD9tyIv.js +0 -102
- package/dist/security-audit-D7WK_BHh.js +0 -11
|
@@ -1,20 +1,21 @@
|
|
|
1
|
-
import { o as resolveFeishuAccount, s as resolveFeishuRuntimeAccount
|
|
2
|
-
import { c as isFeishuCardWithinEnvelope, l as listFeishuDirectoryGroups, o as assertFeishuCardWithinEnvelope, s as buildFeishuPresentationCardElements, u as listFeishuDirectoryPeers } from "./channel-
|
|
3
|
-
import { a as readNativeFeishuCardJson, d as chunkFeishuPostMarkdown, f as materializeFeishuPostMarkdownSoftBreaks, o as resolveFeishuCardTemplate, s as sanitizeNativeFeishuCard, u as chunkFeishuMarkdown } from "./send-result-
|
|
4
|
-
import { r as createFeishuClient } from "./client-
|
|
5
|
-
import { c as
|
|
6
|
-
import {
|
|
7
|
-
import { t as probeFeishu } from "./probe-
|
|
1
|
+
import { o as resolveFeishuAccount, s as resolveFeishuRuntimeAccount } from "./accounts-CCCdMen2.js";
|
|
2
|
+
import { c as isFeishuCardWithinEnvelope, l as listFeishuDirectoryGroups, o as assertFeishuCardWithinEnvelope, s as buildFeishuPresentationCardElements, u as listFeishuDirectoryPeers } from "./channel-Dzb5jv3i.js";
|
|
3
|
+
import { a as readNativeFeishuCardJson, d as chunkFeishuPostMarkdown, f as materializeFeishuPostMarkdownSoftBreaks, o as resolveFeishuCardTemplate, s as sanitizeNativeFeishuCard, u as chunkFeishuMarkdown } from "./send-result-DEAycmOk.js";
|
|
4
|
+
import { r as createFeishuClient } from "./client-Hp7uo_cl.js";
|
|
5
|
+
import { _ as parseFeishuCommentTarget, a as assertFeishuChatMember, c as getChatMembers, l as getFeishuMemberInfo, o as buildFeishuDirectChatMembers, r as cleanupAmbientCommentTypingReaction, s as getChatInfo, t as deliverCommentThreadText } from "./drive-B0JkoiRj.js";
|
|
6
|
+
import { a as getMessageFeishu, b as resolveFeishuIdentityHeaderTitle, c as sendMarkdownCardFeishu, i as editMessageFeishu, l as sendMessageFeishu, n as sendMediaFeishu, r as shouldSuppressFeishuTextForVoiceMedia, s as sendCardFeishu, u as sendStructuredCardFeishu, v as buildFeishuMediaFallbackText } from "./media-BjSy8fiy.js";
|
|
7
|
+
import { t as probeFeishu } from "./probe-DVpy58s0.js";
|
|
8
8
|
import { createReplyToFanout } from "openclaw/plugin-sdk/channel-outbound";
|
|
9
9
|
import { legacyInteractiveReplyToPresentation, normalizeLegacyInteractiveReply, normalizeMessagePresentation, renderMessagePresentationFallbackText, resolveLegacyInteractiveTextFallback } from "openclaw/plugin-sdk/interactive-runtime";
|
|
10
10
|
import { isRecord, normalizeLowercaseStringOrEmpty, normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
11
11
|
import { convertMarkdownTables } from "openclaw/plugin-sdk/text-chunking";
|
|
12
12
|
import path from "node:path";
|
|
13
13
|
import { resolveChunkMode, resolveTextChunkLimit } from "openclaw/plugin-sdk/reply-chunking";
|
|
14
|
+
import { isChannelPartialDeliveryError } from "openclaw/plugin-sdk/channel-inbound";
|
|
15
|
+
import { statRegularFileSync } from "openclaw/plugin-sdk/security-runtime";
|
|
14
16
|
import { attachChannelToResult, createAttachedChannelResultAdapter } from "openclaw/plugin-sdk/channel-send-result";
|
|
15
17
|
import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime";
|
|
16
18
|
import { getReplyPayloadTtsSupplement, resolvePayloadMediaUrls, sendPayloadMediaSequenceAndFinalize, sendTextMediaPayload } from "openclaw/plugin-sdk/reply-payload";
|
|
17
|
-
import { statRegularFileSync } from "openclaw/plugin-sdk/security-runtime";
|
|
18
19
|
//#region extensions/feishu/src/directory.ts
|
|
19
20
|
const MAX_FEISHU_DIRECTORY_PAGES = 100;
|
|
20
21
|
async function listFeishuDirectoryPeersLive(params) {
|
|
@@ -111,6 +112,8 @@ function normalizePossibleLocalImagePath(text) {
|
|
|
111
112
|
".webp",
|
|
112
113
|
".bmp",
|
|
113
114
|
".ico",
|
|
115
|
+
".heic",
|
|
116
|
+
".tif",
|
|
114
117
|
".tiff"
|
|
115
118
|
].includes(ext)) return null;
|
|
116
119
|
if (!path.isAbsolute(raw)) return null;
|
|
@@ -140,6 +143,10 @@ function readNativeFeishuCard(payload) {
|
|
|
140
143
|
const sanitizedCard = sanitizeNativeFeishuCard(card);
|
|
141
144
|
return sanitizedCard ? markRenderedFeishuCard(sanitizedCard) : void 0;
|
|
142
145
|
}
|
|
146
|
+
async function reportFeishuOutboundDelivery(result, onDeliveryResult) {
|
|
147
|
+
await onDeliveryResult?.(attachChannelToResult("feishu", result));
|
|
148
|
+
return result;
|
|
149
|
+
}
|
|
143
150
|
function consumeFeishuPresentationFallbackMarker(payload) {
|
|
144
151
|
const feishuData = isRecord(payload.channelData?.feishu) ? payload.channelData.feishu : void 0;
|
|
145
152
|
if (feishuData?.[FEISHU_PRESENTATION_FALLBACK_MARKER] !== true) return {
|
|
@@ -295,7 +302,7 @@ async function sendCommentThreadReply(params) {
|
|
|
295
302
|
}
|
|
296
303
|
}
|
|
297
304
|
async function sendOutboundText(params) {
|
|
298
|
-
const { cfg, to, text, accountId, replyToMessageId, replyInThread } = params;
|
|
305
|
+
const { cfg, to, text, accountId, replyToMessageId, replyInThread, onDeliveryResult } = params;
|
|
299
306
|
const commentResult = await sendCommentThreadReply({
|
|
300
307
|
cfg,
|
|
301
308
|
to,
|
|
@@ -303,19 +310,19 @@ async function sendOutboundText(params) {
|
|
|
303
310
|
replyId: replyToMessageId,
|
|
304
311
|
accountId
|
|
305
312
|
});
|
|
306
|
-
if (commentResult) return commentResult;
|
|
313
|
+
if (commentResult) return await reportFeishuOutboundDelivery(commentResult, onDeliveryResult);
|
|
307
314
|
const renderMode = resolveFeishuAccount({
|
|
308
315
|
cfg,
|
|
309
316
|
accountId
|
|
310
317
|
}).config?.renderMode ?? "auto";
|
|
311
|
-
if (renderMode === "card" || renderMode === "auto" && shouldUseCard(text)) return sendMarkdownCardFeishu({
|
|
318
|
+
if (renderMode === "card" || renderMode === "auto" && shouldUseCard(text)) return await reportFeishuOutboundDelivery(await sendMarkdownCardFeishu({
|
|
312
319
|
cfg,
|
|
313
320
|
to,
|
|
314
321
|
text,
|
|
315
322
|
accountId,
|
|
316
323
|
replyToMessageId,
|
|
317
324
|
replyInThread
|
|
318
|
-
});
|
|
325
|
+
}), onDeliveryResult);
|
|
319
326
|
const normalizedText = materializeFeishuPostMarkdownSoftBreaks(convertMarkdownTables(text, resolveMarkdownTableMode({
|
|
320
327
|
cfg,
|
|
321
328
|
channel: "feishu"
|
|
@@ -325,24 +332,21 @@ async function sendOutboundText(params) {
|
|
|
325
332
|
limit: resolveTextChunkLimit(cfg, "feishu", accountId, { fallbackLimit: FEISHU_TEXT_CHUNK_LIMIT }),
|
|
326
333
|
mode: resolveChunkMode(cfg, "feishu", accountId)
|
|
327
334
|
});
|
|
328
|
-
if (subChunks.length <= 1) return sendMessageFeishu({
|
|
329
|
-
cfg,
|
|
330
|
-
to,
|
|
331
|
-
text: subChunks[0] ?? normalizedText,
|
|
332
|
-
accountId,
|
|
333
|
-
replyToMessageId,
|
|
334
|
-
replyInThread
|
|
335
|
-
});
|
|
336
335
|
let lastResult;
|
|
337
336
|
const preserveThread = replyInThread === true;
|
|
338
|
-
|
|
337
|
+
const nextReplyToMessageId = createReplyToFanout({
|
|
338
|
+
replyToId: replyToMessageId,
|
|
339
|
+
replyToIdSource: params.replyToIdSource,
|
|
340
|
+
replyToMode: params.replyToMode ?? "first"
|
|
341
|
+
});
|
|
342
|
+
for (const [i, chunk] of (subChunks.length ? subChunks : [normalizedText]).entries()) lastResult = await reportFeishuOutboundDelivery(await sendMessageFeishu({
|
|
339
343
|
cfg,
|
|
340
344
|
to,
|
|
341
345
|
text: chunk,
|
|
342
346
|
accountId,
|
|
343
|
-
replyToMessageId: preserveThread
|
|
347
|
+
replyToMessageId: preserveThread ? replyToMessageId : nextReplyToMessageId(),
|
|
344
348
|
replyInThread: preserveThread ? true : i === 0 ? replyInThread : void 0
|
|
345
|
-
});
|
|
349
|
+
}), onDeliveryResult);
|
|
346
350
|
return lastResult;
|
|
347
351
|
}
|
|
348
352
|
async function sendFeishuFallbackPayload(params) {
|
|
@@ -371,26 +375,18 @@ async function sendFeishuFallbackPayload(params) {
|
|
|
371
375
|
const sendText = feishuOutbound.sendText;
|
|
372
376
|
if (!sendMedia || !sendText) throw new Error("Feishu fallback delivery is not available.");
|
|
373
377
|
let lastResult;
|
|
374
|
-
for (const mediaUrl of mediaUrls) {
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
lastResult = await sendText({
|
|
387
|
-
...ctx,
|
|
388
|
-
text: chunk,
|
|
389
|
-
replyToId: nextReplyToId(),
|
|
390
|
-
onDeliveryResult: void 0
|
|
391
|
-
});
|
|
392
|
-
await ctx.onDeliveryResult?.(lastResult);
|
|
393
|
-
}
|
|
378
|
+
for (const mediaUrl of mediaUrls) lastResult = await sendMedia({
|
|
379
|
+
...ctx,
|
|
380
|
+
text: "",
|
|
381
|
+
mediaUrl,
|
|
382
|
+
replyToId: nextReplyToId(),
|
|
383
|
+
audioAsVoice: params.payload.audioAsVoice ?? ctx.audioAsVoice
|
|
384
|
+
});
|
|
385
|
+
for (const chunk of textChunks) lastResult = await sendText({
|
|
386
|
+
...ctx,
|
|
387
|
+
text: chunk,
|
|
388
|
+
replyToId: nextReplyToId()
|
|
389
|
+
});
|
|
394
390
|
return lastResult;
|
|
395
391
|
}
|
|
396
392
|
async function sendFeishuTtsSupplementPayload(params) {
|
|
@@ -416,15 +412,11 @@ async function sendFeishuTtsSupplementPayload(params) {
|
|
|
416
412
|
await ctx.onDeliveryResult?.(lastResult);
|
|
417
413
|
} else if (params.supplement.visibleTextAlreadyDelivered !== true) {
|
|
418
414
|
const text = params.payload.text?.trim() ? params.payload.text : params.supplement.spokenText;
|
|
419
|
-
for (const chunk of chunkFeishuMarkdown(text, FEISHU_TEXT_CHUNK_LIMIT)) {
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
onDeliveryResult: void 0
|
|
425
|
-
});
|
|
426
|
-
await ctx.onDeliveryResult?.(lastResult);
|
|
427
|
-
}
|
|
415
|
+
for (const chunk of chunkFeishuMarkdown(text, FEISHU_TEXT_CHUNK_LIMIT)) lastResult = await sendText({
|
|
416
|
+
...ctx,
|
|
417
|
+
text: chunk,
|
|
418
|
+
replyToId: nextReplyToId()
|
|
419
|
+
});
|
|
428
420
|
}
|
|
429
421
|
for (const mediaUrl of normalizeStringEntries(resolvePayloadMediaUrls(params.payload))) lastResult = await sendMedia({
|
|
430
422
|
...ctx,
|
|
@@ -563,7 +555,9 @@ const feishuOutbound = {
|
|
|
563
555
|
to: ctx.to,
|
|
564
556
|
mediaUrl,
|
|
565
557
|
accountId: ctx.accountId ?? void 0,
|
|
558
|
+
mediaAccess: ctx.mediaAccess,
|
|
566
559
|
mediaLocalRoots: ctx.mediaLocalRoots,
|
|
560
|
+
mediaReadFile: ctx.mediaReadFile,
|
|
567
561
|
replyToMessageId,
|
|
568
562
|
replyInThread,
|
|
569
563
|
...payload.audioAsVoice === true || ctx.audioAsVoice === true ? { audioAsVoice: true } : {}
|
|
@@ -584,32 +578,45 @@ const feishuOutbound = {
|
|
|
584
578
|
},
|
|
585
579
|
...createAttachedChannelResultAdapter({
|
|
586
580
|
channel: "feishu",
|
|
587
|
-
sendText: async ({ cfg, to, text, accountId, replyToId, threadId, mediaLocalRoots, identity }) => {
|
|
581
|
+
sendText: async ({ cfg, to, text, accountId, replyToId, replyToIdSource, replyToMode, threadId, mediaAccess, mediaLocalRoots, mediaReadFile, identity, onDeliveryResult }) => {
|
|
588
582
|
const { replyToMessageId, replyInThread } = resolveFeishuReplyMode({
|
|
589
583
|
replyToId,
|
|
590
584
|
threadId
|
|
591
585
|
});
|
|
586
|
+
const deliveryOptions = {
|
|
587
|
+
replyToIdSource,
|
|
588
|
+
replyToMode,
|
|
589
|
+
onDeliveryResult
|
|
590
|
+
};
|
|
592
591
|
const localImagePath = normalizePossibleLocalImagePath(text);
|
|
593
|
-
if (localImagePath)
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
592
|
+
if (localImagePath) {
|
|
593
|
+
let mediaResult;
|
|
594
|
+
try {
|
|
595
|
+
mediaResult = await sendMediaFeishu({
|
|
596
|
+
cfg,
|
|
597
|
+
to,
|
|
598
|
+
mediaUrl: localImagePath,
|
|
599
|
+
accountId: accountId ?? void 0,
|
|
600
|
+
replyToMessageId,
|
|
601
|
+
replyInThread,
|
|
602
|
+
mediaAccess,
|
|
603
|
+
mediaLocalRoots,
|
|
604
|
+
mediaReadFile
|
|
605
|
+
});
|
|
606
|
+
} catch (err) {
|
|
607
|
+
if (isChannelPartialDeliveryError(err)) throw err;
|
|
608
|
+
console.error(`[feishu] local image path auto-send failed:`, err);
|
|
609
|
+
return await sendOutboundText({
|
|
610
|
+
cfg,
|
|
611
|
+
to,
|
|
612
|
+
text: await buildFeishuMediaFallbackText({}),
|
|
613
|
+
accountId: accountId ?? void 0,
|
|
614
|
+
replyToMessageId,
|
|
615
|
+
replyInThread,
|
|
616
|
+
...deliveryOptions
|
|
617
|
+
});
|
|
618
|
+
}
|
|
619
|
+
return await reportFeishuOutboundDelivery(mediaResult, onDeliveryResult);
|
|
613
620
|
}
|
|
614
621
|
if (parseFeishuCommentTarget(to)) return await sendOutboundText({
|
|
615
622
|
cfg,
|
|
@@ -617,19 +624,20 @@ const feishuOutbound = {
|
|
|
617
624
|
text,
|
|
618
625
|
accountId: accountId ?? void 0,
|
|
619
626
|
replyToMessageId,
|
|
620
|
-
replyInThread
|
|
627
|
+
replyInThread,
|
|
628
|
+
...deliveryOptions
|
|
621
629
|
});
|
|
622
630
|
const card = readNativeFeishuCardJson(text);
|
|
623
631
|
if (card) {
|
|
624
632
|
assertFeishuCardWithinEnvelope(card, "Feishu native card");
|
|
625
|
-
return await sendCardFeishu({
|
|
633
|
+
return await reportFeishuOutboundDelivery(await sendCardFeishu({
|
|
626
634
|
cfg,
|
|
627
635
|
to,
|
|
628
636
|
card: markRenderedFeishuCard(card),
|
|
629
637
|
accountId: accountId ?? void 0,
|
|
630
638
|
replyToMessageId,
|
|
631
639
|
replyInThread
|
|
632
|
-
});
|
|
640
|
+
}), onDeliveryResult);
|
|
633
641
|
}
|
|
634
642
|
const renderMode = resolveFeishuAccount({
|
|
635
643
|
cfg,
|
|
@@ -640,7 +648,7 @@ const feishuOutbound = {
|
|
|
640
648
|
title: resolveFeishuIdentityHeaderTitle(identity),
|
|
641
649
|
template: "blue"
|
|
642
650
|
} : void 0;
|
|
643
|
-
return await sendStructuredCardFeishu({
|
|
651
|
+
return await reportFeishuOutboundDelivery(await sendStructuredCardFeishu({
|
|
644
652
|
cfg,
|
|
645
653
|
to,
|
|
646
654
|
text,
|
|
@@ -648,7 +656,7 @@ const feishuOutbound = {
|
|
|
648
656
|
replyInThread,
|
|
649
657
|
accountId: accountId ?? void 0,
|
|
650
658
|
header: header?.title ? header : void 0
|
|
651
|
-
});
|
|
659
|
+
}), onDeliveryResult);
|
|
652
660
|
}
|
|
653
661
|
return await sendOutboundText({
|
|
654
662
|
cfg,
|
|
@@ -656,14 +664,35 @@ const feishuOutbound = {
|
|
|
656
664
|
text,
|
|
657
665
|
accountId: accountId ?? void 0,
|
|
658
666
|
replyToMessageId,
|
|
659
|
-
replyInThread
|
|
667
|
+
replyInThread,
|
|
668
|
+
...deliveryOptions
|
|
660
669
|
});
|
|
661
670
|
},
|
|
662
|
-
sendMedia: async ({ cfg, to, text, mediaUrl, audioAsVoice, accountId, mediaLocalRoots, replyToId, threadId, onDeliveryResult }) => {
|
|
663
|
-
const {
|
|
671
|
+
sendMedia: async ({ cfg, to, text, mediaUrl, audioAsVoice, accountId, mediaAccess, mediaLocalRoots, mediaReadFile, replyToId, replyToIdSource, replyToMode, threadId, onDeliveryResult }) => {
|
|
672
|
+
const { normalizedReplyToId } = resolveFeishuReplyMode({
|
|
664
673
|
replyToId,
|
|
665
674
|
threadId
|
|
666
675
|
});
|
|
676
|
+
const nextReplyToId = createReplyToFanout({
|
|
677
|
+
replyToId: normalizedReplyToId,
|
|
678
|
+
replyToIdSource,
|
|
679
|
+
replyToMode
|
|
680
|
+
});
|
|
681
|
+
const nextReplyMode = () => {
|
|
682
|
+
const { replyToMessageId, replyInThread } = resolveFeishuReplyMode({
|
|
683
|
+
replyToId: nextReplyToId(),
|
|
684
|
+
threadId
|
|
685
|
+
});
|
|
686
|
+
return {
|
|
687
|
+
replyToMessageId,
|
|
688
|
+
replyInThread
|
|
689
|
+
};
|
|
690
|
+
};
|
|
691
|
+
const deliveryOptions = {
|
|
692
|
+
replyToIdSource,
|
|
693
|
+
replyToMode,
|
|
694
|
+
onDeliveryResult
|
|
695
|
+
};
|
|
667
696
|
if (parseFeishuCommentTarget(to)) return await sendOutboundText({
|
|
668
697
|
cfg,
|
|
669
698
|
to,
|
|
@@ -673,77 +702,72 @@ const feishuOutbound = {
|
|
|
673
702
|
mediaLinkStyle: "plain"
|
|
674
703
|
}) : text?.trim() ?? "",
|
|
675
704
|
accountId: accountId ?? void 0,
|
|
676
|
-
|
|
677
|
-
|
|
705
|
+
...nextReplyMode(),
|
|
706
|
+
...deliveryOptions
|
|
678
707
|
});
|
|
679
|
-
|
|
708
|
+
if (!mediaUrl) return await sendOutboundText({
|
|
709
|
+
cfg,
|
|
710
|
+
to,
|
|
711
|
+
text: text ?? "",
|
|
712
|
+
accountId: accountId ?? void 0,
|
|
713
|
+
...nextReplyMode(),
|
|
714
|
+
...deliveryOptions
|
|
715
|
+
});
|
|
716
|
+
const suppressTextForVoiceMedia = shouldSuppressFeishuTextForVoiceMedia({
|
|
680
717
|
mediaUrl,
|
|
681
718
|
audioAsVoice
|
|
682
719
|
});
|
|
683
|
-
const reportDelivery = async (result) => {
|
|
684
|
-
await onDeliveryResult?.(attachChannelToResult("feishu", result));
|
|
685
|
-
};
|
|
686
720
|
let textSent = false;
|
|
687
721
|
if (text?.trim() && !suppressTextForVoiceMedia) {
|
|
688
|
-
|
|
722
|
+
await sendOutboundText({
|
|
689
723
|
cfg,
|
|
690
724
|
to,
|
|
691
725
|
text,
|
|
692
726
|
accountId: accountId ?? void 0,
|
|
693
|
-
|
|
694
|
-
|
|
727
|
+
...nextReplyMode(),
|
|
728
|
+
...deliveryOptions
|
|
695
729
|
});
|
|
696
730
|
textSent = true;
|
|
697
|
-
await reportDelivery(textResult);
|
|
698
731
|
}
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
cfg,
|
|
704
|
-
to,
|
|
705
|
-
mediaUrl,
|
|
706
|
-
accountId: accountId ?? void 0,
|
|
707
|
-
mediaLocalRoots,
|
|
708
|
-
replyToMessageId,
|
|
709
|
-
replyInThread,
|
|
710
|
-
...audioAsVoice === true ? { audioAsVoice: true } : {}
|
|
711
|
-
});
|
|
712
|
-
} catch (err) {
|
|
713
|
-
console.error(`[feishu] sendMediaFeishu failed:`, err);
|
|
714
|
-
const fallbackResult = await sendOutboundText({
|
|
715
|
-
cfg,
|
|
716
|
-
to,
|
|
717
|
-
text: await buildFeishuMediaFallbackText({
|
|
718
|
-
text: textSent ? void 0 : text,
|
|
719
|
-
mediaUrl
|
|
720
|
-
}),
|
|
721
|
-
accountId: accountId ?? void 0,
|
|
722
|
-
replyToMessageId,
|
|
723
|
-
replyInThread
|
|
724
|
-
});
|
|
725
|
-
await reportDelivery(fallbackResult);
|
|
726
|
-
return fallbackResult;
|
|
727
|
-
}
|
|
728
|
-
await onDeliveryResult?.(attachChannelToResult("feishu", mediaResult));
|
|
729
|
-
if (mediaResult.voiceIntentDegradedToFile && text?.trim()) await reportDelivery(await sendOutboundText({
|
|
732
|
+
let mediaResult;
|
|
733
|
+
const mediaReplyMode = nextReplyMode();
|
|
734
|
+
try {
|
|
735
|
+
mediaResult = await sendMediaFeishu({
|
|
730
736
|
cfg,
|
|
731
737
|
to,
|
|
732
|
-
|
|
738
|
+
mediaUrl,
|
|
733
739
|
accountId: accountId ?? void 0,
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
740
|
+
mediaAccess,
|
|
741
|
+
mediaLocalRoots,
|
|
742
|
+
mediaReadFile,
|
|
743
|
+
...mediaReplyMode,
|
|
744
|
+
...audioAsVoice === true ? { audioAsVoice: true } : {}
|
|
745
|
+
});
|
|
746
|
+
} catch (err) {
|
|
747
|
+
if (isChannelPartialDeliveryError(err)) throw err;
|
|
748
|
+
console.error(`[feishu] sendMediaFeishu failed:`, err);
|
|
749
|
+
return await sendOutboundText({
|
|
750
|
+
cfg,
|
|
751
|
+
to,
|
|
752
|
+
text: await buildFeishuMediaFallbackText({
|
|
753
|
+
text: textSent ? void 0 : text,
|
|
754
|
+
mediaUrl
|
|
755
|
+
}),
|
|
756
|
+
accountId: accountId ?? void 0,
|
|
757
|
+
...textSent ? nextReplyMode() : mediaReplyMode,
|
|
758
|
+
...deliveryOptions
|
|
759
|
+
});
|
|
738
760
|
}
|
|
739
|
-
|
|
761
|
+
await reportFeishuOutboundDelivery(mediaResult, onDeliveryResult);
|
|
762
|
+
if (mediaResult.voiceIntentDegradedToFile && text?.trim()) await sendOutboundText({
|
|
740
763
|
cfg,
|
|
741
764
|
to,
|
|
742
|
-
text
|
|
765
|
+
text,
|
|
743
766
|
accountId: accountId ?? void 0,
|
|
744
|
-
|
|
745
|
-
|
|
767
|
+
...nextReplyMode(),
|
|
768
|
+
...deliveryOptions
|
|
746
769
|
});
|
|
770
|
+
return mediaResult;
|
|
747
771
|
}
|
|
748
772
|
})
|
|
749
773
|
};
|
|
@@ -847,20 +871,35 @@ async function removeReactionFeishu(params) {
|
|
|
847
871
|
*/
|
|
848
872
|
async function listReactionsFeishu(params) {
|
|
849
873
|
const { cfg, messageId, emojiType, accountId } = params;
|
|
850
|
-
const
|
|
874
|
+
const client = resolveConfiguredFeishuClient({
|
|
851
875
|
cfg,
|
|
852
876
|
accountId
|
|
853
|
-
}).im.messageReaction.list({
|
|
854
|
-
path: { message_id: messageId },
|
|
855
|
-
params: emojiType ? { reaction_type: emojiType } : void 0
|
|
856
877
|
});
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
878
|
+
const reactions = [];
|
|
879
|
+
const seenPageTokens = /* @__PURE__ */ new Set();
|
|
880
|
+
let pageToken;
|
|
881
|
+
while (true) {
|
|
882
|
+
const response = await client.im.messageReaction.list({
|
|
883
|
+
path: { message_id: messageId },
|
|
884
|
+
params: emojiType || pageToken ? {
|
|
885
|
+
...emojiType ? { reaction_type: emojiType } : {},
|
|
886
|
+
...pageToken ? { page_token: pageToken } : {}
|
|
887
|
+
} : void 0
|
|
888
|
+
});
|
|
889
|
+
assertFeishuReactionApiSuccess(response, "list reactions");
|
|
890
|
+
for (const item of response.data?.items ?? []) reactions.push({
|
|
891
|
+
reactionId: item.reaction_id ?? "",
|
|
892
|
+
emojiType: item.reaction_type?.emoji_type ?? "",
|
|
893
|
+
operatorType: item.operator?.operator_type === "app" ? "app" : item.operator?.operator_type === "user" ? "user" : "unknown",
|
|
894
|
+
operatorId: item.operator?.operator_id ?? ""
|
|
895
|
+
});
|
|
896
|
+
if (response.data?.has_more !== true) return reactions;
|
|
897
|
+
const nextPageToken = response.data.page_token?.trim();
|
|
898
|
+
if (!nextPageToken) throw new Error("Feishu reaction pagination is missing its next page token");
|
|
899
|
+
if (seenPageTokens.has(nextPageToken)) throw new Error("Feishu reaction pagination returned a repeated page token");
|
|
900
|
+
seenPageTokens.add(nextPageToken);
|
|
901
|
+
pageToken = nextPageToken;
|
|
902
|
+
}
|
|
864
903
|
}
|
|
865
904
|
//#endregion
|
|
866
905
|
//#region extensions/feishu/src/channel.runtime.ts
|
|
@@ -33,6 +33,7 @@ var client_exports = /* @__PURE__ */ __exportAll({
|
|
|
33
33
|
getFeishuUserAgent: () => getFeishuUserAgent
|
|
34
34
|
});
|
|
35
35
|
const FEISHU_USER_AGENT = `openclaw-feishu-builtin/${readPluginPackageVersion({ require: createRequire(import.meta.url) })}/${process.platform}`;
|
|
36
|
+
const FEISHU_SDK_ORIGIN = "https://open.feishu.cn";
|
|
36
37
|
const FEISHU_WS_CONFIG = { pingTimeout: 3 };
|
|
37
38
|
/** User-Agent header value for all Feishu API requests. */
|
|
38
39
|
function getFeishuUserAgent() {
|
|
@@ -145,10 +146,8 @@ async function getFeishuProxyAgent() {
|
|
|
145
146
|
}
|
|
146
147
|
}
|
|
147
148
|
const clientCache = /* @__PURE__ */ new Map();
|
|
148
|
-
function
|
|
149
|
-
|
|
150
|
-
if (domain === "feishu" || !domain) return feishuClientSdk.Domain.Feishu;
|
|
151
|
-
return domain.replace(/\/+$/, "");
|
|
149
|
+
function resolveSdkDomain(domain) {
|
|
150
|
+
return domain === "lark" ? feishuClientSdk.Domain.Lark : feishuClientSdk.Domain.Feishu;
|
|
152
151
|
}
|
|
153
152
|
/**
|
|
154
153
|
* Create an HTTP instance that delegates to the Lark SDK's default instance
|
|
@@ -156,13 +155,25 @@ function resolveDomain(domain) {
|
|
|
156
155
|
* indefinite hangs, set a standardized User-Agent per OAPI best practices, and
|
|
157
156
|
* keep axios from taking a separate ambient proxy path for HTTPS requests.
|
|
158
157
|
*/
|
|
159
|
-
function createFeishuHttpInstance(defaultTimeoutMs) {
|
|
158
|
+
function createFeishuHttpInstance(defaultTimeoutMs, configuredDomain) {
|
|
160
159
|
const base = feishuClientSdk.defaultHttpInstance;
|
|
160
|
+
const customDomain = configuredDomain && configuredDomain !== "feishu" && configuredDomain !== "lark" ? new URL(configuredDomain) : void 0;
|
|
161
|
+
function resolveRequestUrl(url) {
|
|
162
|
+
if (!customDomain) return url;
|
|
163
|
+
const requestUrl = new URL(url);
|
|
164
|
+
if (requestUrl.origin !== FEISHU_SDK_ORIGIN) return url;
|
|
165
|
+
const destination = new URL(customDomain);
|
|
166
|
+
destination.pathname = `${destination.pathname.replace(/\/+$/, "")}${requestUrl.pathname}`;
|
|
167
|
+
destination.search = requestUrl.search;
|
|
168
|
+
destination.hash = requestUrl.hash;
|
|
169
|
+
return destination.toString();
|
|
170
|
+
}
|
|
161
171
|
async function injectRequestOptions(opts) {
|
|
162
172
|
const next = {
|
|
163
173
|
timeout: defaultTimeoutMs,
|
|
164
174
|
...opts
|
|
165
175
|
};
|
|
176
|
+
if (typeof next.url === "string") next.url = resolveRequestUrl(next.url);
|
|
166
177
|
const agent = await getFeishuProxyAgent();
|
|
167
178
|
if (agent) {
|
|
168
179
|
if (isManagedProxyActive()) {
|
|
@@ -178,13 +189,13 @@ function createFeishuHttpInstance(defaultTimeoutMs) {
|
|
|
178
189
|
}
|
|
179
190
|
return {
|
|
180
191
|
request: async (opts) => base.request(await injectRequestOptions(normalizeMultipartUploadData(opts))),
|
|
181
|
-
get: async (url, opts) => base.get(url, await injectRequestOptions(opts)),
|
|
182
|
-
post: async (url, data, opts) => base.post(url, data, await injectRequestOptions(opts)),
|
|
183
|
-
put: async (url, data, opts) => base.put(url, data, await injectRequestOptions(opts)),
|
|
184
|
-
patch: async (url, data, opts) => base.patch(url, data, await injectRequestOptions(opts)),
|
|
185
|
-
delete: async (url, opts) => base.delete(url, await injectRequestOptions(opts)),
|
|
186
|
-
head: async (url, opts) => base.head(url, await injectRequestOptions(opts)),
|
|
187
|
-
options: async (url, opts) => base.options(url, await injectRequestOptions(opts))
|
|
192
|
+
get: async (url, opts) => base.get(resolveRequestUrl(url), await injectRequestOptions(opts)),
|
|
193
|
+
post: async (url, data, opts) => base.post(resolveRequestUrl(url), data, await injectRequestOptions(opts)),
|
|
194
|
+
put: async (url, data, opts) => base.put(resolveRequestUrl(url), data, await injectRequestOptions(opts)),
|
|
195
|
+
patch: async (url, data, opts) => base.patch(resolveRequestUrl(url), data, await injectRequestOptions(opts)),
|
|
196
|
+
delete: async (url, opts) => base.delete(resolveRequestUrl(url), await injectRequestOptions(opts)),
|
|
197
|
+
head: async (url, opts) => base.head(resolveRequestUrl(url), await injectRequestOptions(opts)),
|
|
198
|
+
options: async (url, opts) => base.options(resolveRequestUrl(url), await injectRequestOptions(opts))
|
|
188
199
|
};
|
|
189
200
|
}
|
|
190
201
|
/**
|
|
@@ -201,8 +212,8 @@ function createFeishuClient(creds) {
|
|
|
201
212
|
appId,
|
|
202
213
|
appSecret,
|
|
203
214
|
appType: feishuClientSdk.AppType.SelfBuild,
|
|
204
|
-
domain:
|
|
205
|
-
httpInstance: createFeishuHttpInstance(defaultHttpTimeoutMs)
|
|
215
|
+
domain: resolveSdkDomain(domain),
|
|
216
|
+
httpInstance: createFeishuHttpInstance(defaultHttpTimeoutMs, domain)
|
|
206
217
|
});
|
|
207
218
|
clientCache.set(accountId, {
|
|
208
219
|
client,
|
|
@@ -227,8 +238,8 @@ async function createFeishuWSClient(account, callbacks = {}) {
|
|
|
227
238
|
return new feishuClientSdk.WSClient({
|
|
228
239
|
appId,
|
|
229
240
|
appSecret,
|
|
230
|
-
domain:
|
|
231
|
-
httpInstance: createFeishuHttpInstance(defaultHttpTimeoutMs),
|
|
241
|
+
domain: resolveSdkDomain(domain),
|
|
242
|
+
httpInstance: createFeishuHttpInstance(defaultHttpTimeoutMs, domain),
|
|
232
243
|
...callbacks,
|
|
233
244
|
loggerLevel: feishuClientSdk.LoggerLevel.info,
|
|
234
245
|
wsConfig: FEISHU_WS_CONFIG,
|
package/dist/contract-api.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as parseFeishuTargetId, i as parseFeishuDirectConversationId, r as parseFeishuConversationId, t as buildFeishuConversationId } from "./conversation-id-
|
|
2
|
-
import { t as messageActionTargetAliases } from "./security-audit-
|
|
1
|
+
import { a as parseFeishuTargetId, i as parseFeishuDirectConversationId, r as parseFeishuConversationId, t as buildFeishuConversationId } from "./conversation-id-VYgGQ-GX.js";
|
|
2
|
+
import { t as messageActionTargetAliases } from "./security-audit-D6Fz2h6p.js";
|
|
3
3
|
import { t as collectFeishuSecurityAuditFindings } from "./security-audit-shared-BgpY7AiJ.js";
|
|
4
4
|
export { buildFeishuConversationId, collectFeishuSecurityAuditFindings, messageActionTargetAliases, parseFeishuConversationId, parseFeishuDirectConversationId, parseFeishuTargetId };
|
|
@@ -1,17 +1,13 @@
|
|
|
1
|
-
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
1
|
+
import { normalizeLowercaseStringOrEmpty, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
2
2
|
//#region extensions/feishu/src/conversation-id.ts
|
|
3
3
|
function resolveConfiguredFeishuGroupSessionScope(params) {
|
|
4
4
|
const legacyTopicSessionMode = params.groupConfig?.topicSessionMode ?? params.feishuCfg?.topicSessionMode ?? "disabled";
|
|
5
5
|
return params.groupConfig?.groupSessionScope ?? params.feishuCfg?.groupSessionScope ?? (legacyTopicSessionMode === "enabled" ? "group_topic" : "group");
|
|
6
6
|
}
|
|
7
|
-
function normalizeText(value) {
|
|
8
|
-
if (typeof value !== "string") return;
|
|
9
|
-
return value.trim() || void 0;
|
|
10
|
-
}
|
|
11
7
|
function buildFeishuConversationId(params) {
|
|
12
|
-
const chatId =
|
|
13
|
-
const senderOpenId =
|
|
14
|
-
const topicId =
|
|
8
|
+
const chatId = normalizeOptionalString(params.chatId) ?? "unknown";
|
|
9
|
+
const senderOpenId = normalizeOptionalString(params.senderOpenId);
|
|
10
|
+
const topicId = normalizeOptionalString(params.topicId);
|
|
15
11
|
switch (params.scope) {
|
|
16
12
|
case "group_sender": return senderOpenId ? `${chatId}:sender:${senderOpenId}` : chatId;
|
|
17
13
|
case "group_topic": return topicId ? `${chatId}:topic:${topicId}` : chatId;
|
|
@@ -23,7 +19,7 @@ function buildFeishuConversationId(params) {
|
|
|
23
19
|
}
|
|
24
20
|
}
|
|
25
21
|
function parseFeishuTargetId(raw) {
|
|
26
|
-
const target =
|
|
22
|
+
const target = normalizeOptionalString(raw);
|
|
27
23
|
if (!target) return;
|
|
28
24
|
const withoutProvider = target.replace(/^(feishu|lark):/i, "").trim();
|
|
29
25
|
if (!withoutProvider) return;
|
|
@@ -35,11 +31,11 @@ function parseFeishuTargetId(raw) {
|
|
|
35
31
|
"user:",
|
|
36
32
|
"dm:",
|
|
37
33
|
"open_id:"
|
|
38
|
-
]) if (lowered.startsWith(prefix)) return
|
|
34
|
+
]) if (lowered.startsWith(prefix)) return normalizeOptionalString(withoutProvider.slice(prefix.length));
|
|
39
35
|
return withoutProvider;
|
|
40
36
|
}
|
|
41
37
|
function parseFeishuDirectConversationId(raw) {
|
|
42
|
-
const target =
|
|
38
|
+
const target = normalizeOptionalString(raw);
|
|
43
39
|
if (!target) return;
|
|
44
40
|
const withoutProvider = target.replace(/^(feishu|lark):/i, "").trim();
|
|
45
41
|
if (!withoutProvider) return;
|
|
@@ -48,14 +44,14 @@ function parseFeishuDirectConversationId(raw) {
|
|
|
48
44
|
"user:",
|
|
49
45
|
"dm:",
|
|
50
46
|
"open_id:"
|
|
51
|
-
]) if (lowered.startsWith(prefix)) return
|
|
47
|
+
]) if (lowered.startsWith(prefix)) return normalizeOptionalString(withoutProvider.slice(prefix.length));
|
|
52
48
|
const id = parseFeishuTargetId(target);
|
|
53
49
|
if (!id) return;
|
|
54
50
|
if (id.startsWith("ou_") || id.startsWith("on_")) return id;
|
|
55
51
|
}
|
|
56
52
|
function parseFeishuConversationId(params) {
|
|
57
|
-
const conversationId =
|
|
58
|
-
const parentConversationId =
|
|
53
|
+
const conversationId = normalizeOptionalString(params.conversationId);
|
|
54
|
+
const parentConversationId = normalizeOptionalString(params.parentConversationId);
|
|
59
55
|
if (!conversationId) return null;
|
|
60
56
|
const topicSenderMatch = conversationId.match(/^(.+):topic:([^:]+):sender:([^:]+)$/i);
|
|
61
57
|
if (topicSenderMatch) {
|
|
@@ -121,7 +117,7 @@ function parseFeishuConversationId(params) {
|
|
|
121
117
|
};
|
|
122
118
|
}
|
|
123
119
|
function buildFeishuModelOverrideParentCandidates(parentConversationId) {
|
|
124
|
-
const rawId =
|
|
120
|
+
const rawId = normalizeOptionalString(parentConversationId);
|
|
125
121
|
if (!rawId) return [];
|
|
126
122
|
const topicSenderMatch = rawId.match(/^(.+):topic:([^:]+):sender:([^:]+)$/i);
|
|
127
123
|
if (topicSenderMatch) {
|