@openclaw/feishu 2026.7.2-beta.7 → 2026.8.1-beta.3

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.
Files changed (35) hide show
  1. package/dist/accounts-CCCdMen2.js +203 -0
  2. package/dist/api.js +61 -60
  3. package/dist/{channel-CScE82zY.js → channel-Ceq80_zP.js} +71 -42
  4. package/dist/channel-plugin-api.js +1 -1
  5. package/dist/{channel.runtime-B21e1E0r.js → channel.runtime-DnRyzGoU.js} +201 -152
  6. package/dist/{client-Dcbs6vml.js → client-Hp7uo_cl.js} +27 -16
  7. package/dist/contract-api.js +2 -2
  8. package/dist/{conversation-id-BeJL-wq7.js → conversation-id-VYgGQ-GX.js} +11 -15
  9. package/dist/doctor-contract-api.js +1 -1
  10. package/dist/doctor-contract-bEQXIXyP.js +158 -0
  11. package/dist/{drive-hSi_Utp0.js → drive-BVYM_Y4k.js} +325 -44
  12. package/dist/{media-CEUraFOR.js → media-BDouVaaM.js} +298 -182
  13. package/dist/{monitor-DngbaA6a.js → monitor-CZ8cDXrq.js} +3 -3
  14. package/dist/{monitor.account-BnTWCw55.js → monitor.account-Dq_voVMB.js} +263 -179
  15. package/dist/{monitor.startup-CqH2tiJq.js → monitor.startup-BGErejNH.js} +1 -1
  16. package/dist/{probe-p3POS2RN.js → probe-DVpy58s0.js} +2 -2
  17. package/dist/security-audit-D6Fz2h6p.js +23 -0
  18. package/dist/{send-result-B9_BpUPx.js → send-result-DEAycmOk.js} +18 -9
  19. package/dist/session-binding-contract-api.js +2 -2
  20. package/dist/{session-conversation-BksWrfzm.js → session-conversation-DFCIvQK-.js} +1 -1
  21. package/dist/session-key-api.js +1 -1
  22. package/dist/setup-api.js +1 -1
  23. package/dist/{subagent-hooks-Cx1cX7rW.js → subagent-hooks-KUi-7vUy.js} +4 -64
  24. package/dist/subagent-hooks-api.js +1 -1
  25. package/dist/{thread-bindings-N3wkgkIN.js → thread-bindings-CptM_YU6.js} +7 -9
  26. package/openclaw.plugin.json +143 -1
  27. package/package.json +4 -4
  28. package/skills/feishu-doc/SKILL.md +20 -195
  29. package/skills/feishu-doc/references/block-types.md +9 -14
  30. package/skills/feishu-drive/SKILL.md +16 -102
  31. package/skills/feishu-perm/SKILL.md +10 -110
  32. package/skills/feishu-wiki/SKILL.md +13 -109
  33. package/dist/accounts-u9X5Wsan.js +0 -469
  34. package/dist/doctor-contract-BiD9tyIv.js +0 -102
  35. package/dist/security-audit-D7WK_BHh.js +0 -11
@@ -1,20 +1,21 @@
1
- import { o as resolveFeishuAccount, s as resolveFeishuRuntimeAccount, v as parseFeishuCommentTarget } from "./accounts-u9X5Wsan.js";
2
- import { c as isFeishuCardWithinEnvelope, l as listFeishuDirectoryGroups, o as assertFeishuCardWithinEnvelope, s as buildFeishuPresentationCardElements, u as listFeishuDirectoryPeers } from "./channel-CScE82zY.js";
3
- import { a as readNativeFeishuCardJson, d as chunkFeishuPostMarkdown, f as materializeFeishuPostMarkdownSoftBreaks, o as resolveFeishuCardTemplate, s as sanitizeNativeFeishuCard, u as chunkFeishuMarkdown } from "./send-result-B9_BpUPx.js";
4
- import { r as createFeishuClient } from "./client-Dcbs6vml.js";
5
- import { c as buildFeishuDirectChatMembers, d as getFeishuMemberInfo, l as getChatInfo, r as cleanupAmbientCommentTypingReaction, s as assertFeishuChatMember, t as deliverCommentThreadText, u as getChatMembers } from "./drive-hSi_Utp0.js";
6
- import { _ as buildFeishuMediaFallbackText, a as getMessageFeishu, c as sendMarkdownCardFeishu, i as editMessageFeishu, l as sendMessageFeishu, n as sendMediaFeishu, r as shouldSuppressFeishuTextForVoiceMedia, s as sendCardFeishu, u as sendStructuredCardFeishu, y as resolveFeishuIdentityHeaderTitle } from "./media-CEUraFOR.js";
7
- import { t as probeFeishu } from "./probe-p3POS2RN.js";
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-Ceq80_zP.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-BVYM_Y4k.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-BDouVaaM.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,20 @@ function readNativeFeishuCard(payload) {
140
143
  const sanitizedCard = sanitizeNativeFeishuCard(card);
141
144
  return sanitizedCard ? markRenderedFeishuCard(sanitizedCard) : void 0;
142
145
  }
146
+ function toFeishuOutboundResult(result) {
147
+ const { chatId, ...delivery } = result;
148
+ return {
149
+ ...delivery,
150
+ target: {
151
+ kind: "chat",
152
+ id: chatId
153
+ }
154
+ };
155
+ }
156
+ async function reportFeishuOutboundDelivery(result, onDeliveryResult) {
157
+ await onDeliveryResult?.(attachChannelToResult("feishu", toFeishuOutboundResult(result)));
158
+ return result;
159
+ }
143
160
  function consumeFeishuPresentationFallbackMarker(payload) {
144
161
  const feishuData = isRecord(payload.channelData?.feishu) ? payload.channelData.feishu : void 0;
145
162
  if (feishuData?.[FEISHU_PRESENTATION_FALLBACK_MARKER] !== true) return {
@@ -295,7 +312,7 @@ async function sendCommentThreadReply(params) {
295
312
  }
296
313
  }
297
314
  async function sendOutboundText(params) {
298
- const { cfg, to, text, accountId, replyToMessageId, replyInThread } = params;
315
+ const { cfg, to, text, accountId, replyToMessageId, replyInThread, onDeliveryResult } = params;
299
316
  const commentResult = await sendCommentThreadReply({
300
317
  cfg,
301
318
  to,
@@ -303,19 +320,19 @@ async function sendOutboundText(params) {
303
320
  replyId: replyToMessageId,
304
321
  accountId
305
322
  });
306
- if (commentResult) return commentResult;
323
+ if (commentResult) return await reportFeishuOutboundDelivery(commentResult, onDeliveryResult);
307
324
  const renderMode = resolveFeishuAccount({
308
325
  cfg,
309
326
  accountId
310
327
  }).config?.renderMode ?? "auto";
311
- if (renderMode === "card" || renderMode === "auto" && shouldUseCard(text)) return sendMarkdownCardFeishu({
328
+ if (renderMode === "card" || renderMode === "auto" && shouldUseCard(text)) return await reportFeishuOutboundDelivery(await sendMarkdownCardFeishu({
312
329
  cfg,
313
330
  to,
314
331
  text,
315
332
  accountId,
316
333
  replyToMessageId,
317
334
  replyInThread
318
- });
335
+ }), onDeliveryResult);
319
336
  const normalizedText = materializeFeishuPostMarkdownSoftBreaks(convertMarkdownTables(text, resolveMarkdownTableMode({
320
337
  cfg,
321
338
  channel: "feishu"
@@ -325,24 +342,21 @@ async function sendOutboundText(params) {
325
342
  limit: resolveTextChunkLimit(cfg, "feishu", accountId, { fallbackLimit: FEISHU_TEXT_CHUNK_LIMIT }),
326
343
  mode: resolveChunkMode(cfg, "feishu", accountId)
327
344
  });
328
- if (subChunks.length <= 1) return sendMessageFeishu({
329
- cfg,
330
- to,
331
- text: subChunks[0] ?? normalizedText,
332
- accountId,
333
- replyToMessageId,
334
- replyInThread
335
- });
336
345
  let lastResult;
337
346
  const preserveThread = replyInThread === true;
338
- for (const [i, chunk] of subChunks.entries()) lastResult = await sendMessageFeishu({
347
+ const nextReplyToMessageId = createReplyToFanout({
348
+ replyToId: replyToMessageId,
349
+ replyToIdSource: params.replyToIdSource,
350
+ replyToMode: params.replyToMode ?? "first"
351
+ });
352
+ for (const [i, chunk] of (subChunks.length ? subChunks : [normalizedText]).entries()) lastResult = await reportFeishuOutboundDelivery(await sendMessageFeishu({
339
353
  cfg,
340
354
  to,
341
355
  text: chunk,
342
356
  accountId,
343
- replyToMessageId: preserveThread || i === 0 ? replyToMessageId : void 0,
357
+ replyToMessageId: preserveThread ? replyToMessageId : nextReplyToMessageId(),
344
358
  replyInThread: preserveThread ? true : i === 0 ? replyInThread : void 0
345
- });
359
+ }), onDeliveryResult);
346
360
  return lastResult;
347
361
  }
348
362
  async function sendFeishuFallbackPayload(params) {
@@ -371,26 +385,18 @@ async function sendFeishuFallbackPayload(params) {
371
385
  const sendText = feishuOutbound.sendText;
372
386
  if (!sendMedia || !sendText) throw new Error("Feishu fallback delivery is not available.");
373
387
  let lastResult;
374
- for (const mediaUrl of mediaUrls) {
375
- lastResult = await sendMedia({
376
- ...ctx,
377
- text: "",
378
- mediaUrl,
379
- replyToId: nextReplyToId(),
380
- audioAsVoice: params.payload.audioAsVoice ?? ctx.audioAsVoice,
381
- onDeliveryResult: void 0
382
- });
383
- await ctx.onDeliveryResult?.(lastResult);
384
- }
385
- for (const chunk of textChunks) {
386
- lastResult = await sendText({
387
- ...ctx,
388
- text: chunk,
389
- replyToId: nextReplyToId(),
390
- onDeliveryResult: void 0
391
- });
392
- await ctx.onDeliveryResult?.(lastResult);
393
- }
388
+ for (const mediaUrl of mediaUrls) lastResult = await sendMedia({
389
+ ...ctx,
390
+ text: "",
391
+ mediaUrl,
392
+ replyToId: nextReplyToId(),
393
+ audioAsVoice: params.payload.audioAsVoice ?? ctx.audioAsVoice
394
+ });
395
+ for (const chunk of textChunks) lastResult = await sendText({
396
+ ...ctx,
397
+ text: chunk,
398
+ replyToId: nextReplyToId()
399
+ });
394
400
  return lastResult;
395
401
  }
396
402
  async function sendFeishuTtsSupplementPayload(params) {
@@ -416,15 +422,11 @@ async function sendFeishuTtsSupplementPayload(params) {
416
422
  await ctx.onDeliveryResult?.(lastResult);
417
423
  } else if (params.supplement.visibleTextAlreadyDelivered !== true) {
418
424
  const text = params.payload.text?.trim() ? params.payload.text : params.supplement.spokenText;
419
- for (const chunk of chunkFeishuMarkdown(text, FEISHU_TEXT_CHUNK_LIMIT)) {
420
- lastResult = await sendText({
421
- ...ctx,
422
- text: chunk,
423
- replyToId: nextReplyToId(),
424
- onDeliveryResult: void 0
425
- });
426
- await ctx.onDeliveryResult?.(lastResult);
427
- }
425
+ for (const chunk of chunkFeishuMarkdown(text, FEISHU_TEXT_CHUNK_LIMIT)) lastResult = await sendText({
426
+ ...ctx,
427
+ text: chunk,
428
+ replyToId: nextReplyToId()
429
+ });
428
430
  }
429
431
  for (const mediaUrl of normalizeStringEntries(resolvePayloadMediaUrls(params.payload))) lastResult = await sendMedia({
430
432
  ...ctx,
@@ -526,14 +528,14 @@ const feishuOutbound = {
526
528
  replyToId,
527
529
  threadId: ctx.threadId
528
530
  });
529
- return attachChannelToResult("feishu", await sendCardFeishu({
531
+ return attachChannelToResult("feishu", toFeishuOutboundResult(await sendCardFeishu({
530
532
  cfg: ctx.cfg,
531
533
  to: ctx.to,
532
534
  card,
533
535
  replyToMessageId,
534
536
  replyInThread,
535
537
  accountId: ctx.accountId ?? void 0
536
- }));
538
+ })));
537
539
  }
538
540
  });
539
541
  const { normalizedReplyToId } = resolveFeishuReplyMode({
@@ -550,11 +552,11 @@ const feishuOutbound = {
550
552
  threadId: ctx.threadId
551
553
  });
552
554
  const mediaUrls = normalizeStringEntries(resolvePayloadMediaUrls(payload));
553
- return attachChannelToResult("feishu", await sendPayloadMediaSequenceAndFinalize({
555
+ return attachChannelToResult("feishu", toFeishuOutboundResult(await sendPayloadMediaSequenceAndFinalize({
554
556
  text: payload.text ?? "",
555
557
  mediaUrls,
556
558
  onResult: async (deliveryResult) => {
557
- await ctx.onDeliveryResult?.(attachChannelToResult("feishu", deliveryResult));
559
+ await ctx.onDeliveryResult?.(attachChannelToResult("feishu", toFeishuOutboundResult(deliveryResult)));
558
560
  },
559
561
  send: async ({ mediaUrl }) => {
560
562
  const { replyToMessageId, replyInThread } = nextReplyMode();
@@ -563,7 +565,9 @@ const feishuOutbound = {
563
565
  to: ctx.to,
564
566
  mediaUrl,
565
567
  accountId: ctx.accountId ?? void 0,
568
+ mediaAccess: ctx.mediaAccess,
566
569
  mediaLocalRoots: ctx.mediaLocalRoots,
570
+ mediaReadFile: ctx.mediaReadFile,
567
571
  replyToMessageId,
568
572
  replyInThread,
569
573
  ...payload.audioAsVoice === true || ctx.audioAsVoice === true ? { audioAsVoice: true } : {}
@@ -580,56 +584,70 @@ const feishuOutbound = {
580
584
  accountId: ctx.accountId ?? void 0
581
585
  });
582
586
  }
583
- }));
587
+ })));
584
588
  },
585
589
  ...createAttachedChannelResultAdapter({
586
590
  channel: "feishu",
587
- sendText: async ({ cfg, to, text, accountId, replyToId, threadId, mediaLocalRoots, identity }) => {
591
+ sendText: async ({ cfg, to, text, accountId, replyToId, replyToIdSource, replyToMode, threadId, mediaAccess, mediaLocalRoots, mediaReadFile, identity, onDeliveryResult }) => {
588
592
  const { replyToMessageId, replyInThread } = resolveFeishuReplyMode({
589
593
  replyToId,
590
594
  threadId
591
595
  });
596
+ const deliveryOptions = {
597
+ replyToIdSource,
598
+ replyToMode,
599
+ onDeliveryResult
600
+ };
592
601
  const localImagePath = normalizePossibleLocalImagePath(text);
593
- if (localImagePath) try {
594
- return await sendMediaFeishu({
595
- cfg,
596
- to,
597
- mediaUrl: localImagePath,
598
- accountId: accountId ?? void 0,
599
- replyToMessageId,
600
- replyInThread,
601
- mediaLocalRoots
602
- });
603
- } catch (err) {
604
- console.error(`[feishu] local image path auto-send failed:`, err);
605
- return await sendOutboundText({
606
- cfg,
607
- to,
608
- text: await buildFeishuMediaFallbackText({}),
609
- accountId: accountId ?? void 0,
610
- replyToMessageId,
611
- replyInThread
612
- });
602
+ if (localImagePath) {
603
+ let mediaResult;
604
+ try {
605
+ mediaResult = await sendMediaFeishu({
606
+ cfg,
607
+ to,
608
+ mediaUrl: localImagePath,
609
+ accountId: accountId ?? void 0,
610
+ replyToMessageId,
611
+ replyInThread,
612
+ mediaAccess,
613
+ mediaLocalRoots,
614
+ mediaReadFile
615
+ });
616
+ } catch (err) {
617
+ if (isChannelPartialDeliveryError(err)) throw err;
618
+ console.error(`[feishu] local image path auto-send failed:`, err);
619
+ return toFeishuOutboundResult(await sendOutboundText({
620
+ cfg,
621
+ to,
622
+ text: await buildFeishuMediaFallbackText({}),
623
+ accountId: accountId ?? void 0,
624
+ replyToMessageId,
625
+ replyInThread,
626
+ ...deliveryOptions
627
+ }));
628
+ }
629
+ return toFeishuOutboundResult(await reportFeishuOutboundDelivery(mediaResult, onDeliveryResult));
613
630
  }
614
- if (parseFeishuCommentTarget(to)) return await sendOutboundText({
631
+ if (parseFeishuCommentTarget(to)) return toFeishuOutboundResult(await sendOutboundText({
615
632
  cfg,
616
633
  to,
617
634
  text,
618
635
  accountId: accountId ?? void 0,
619
636
  replyToMessageId,
620
- replyInThread
621
- });
637
+ replyInThread,
638
+ ...deliveryOptions
639
+ }));
622
640
  const card = readNativeFeishuCardJson(text);
623
641
  if (card) {
624
642
  assertFeishuCardWithinEnvelope(card, "Feishu native card");
625
- return await sendCardFeishu({
643
+ return toFeishuOutboundResult(await reportFeishuOutboundDelivery(await sendCardFeishu({
626
644
  cfg,
627
645
  to,
628
646
  card: markRenderedFeishuCard(card),
629
647
  accountId: accountId ?? void 0,
630
648
  replyToMessageId,
631
649
  replyInThread
632
- });
650
+ }), onDeliveryResult));
633
651
  }
634
652
  const renderMode = resolveFeishuAccount({
635
653
  cfg,
@@ -640,7 +658,7 @@ const feishuOutbound = {
640
658
  title: resolveFeishuIdentityHeaderTitle(identity),
641
659
  template: "blue"
642
660
  } : void 0;
643
- return await sendStructuredCardFeishu({
661
+ return toFeishuOutboundResult(await reportFeishuOutboundDelivery(await sendStructuredCardFeishu({
644
662
  cfg,
645
663
  to,
646
664
  text,
@@ -648,23 +666,44 @@ const feishuOutbound = {
648
666
  replyInThread,
649
667
  accountId: accountId ?? void 0,
650
668
  header: header?.title ? header : void 0
651
- });
669
+ }), onDeliveryResult));
652
670
  }
653
- return await sendOutboundText({
671
+ return toFeishuOutboundResult(await sendOutboundText({
654
672
  cfg,
655
673
  to,
656
674
  text,
657
675
  accountId: accountId ?? void 0,
658
676
  replyToMessageId,
659
- replyInThread
660
- });
677
+ replyInThread,
678
+ ...deliveryOptions
679
+ }));
661
680
  },
662
- sendMedia: async ({ cfg, to, text, mediaUrl, audioAsVoice, accountId, mediaLocalRoots, replyToId, threadId, onDeliveryResult }) => {
663
- const { replyToMessageId, replyInThread } = resolveFeishuReplyMode({
681
+ sendMedia: async ({ cfg, to, text, mediaUrl, audioAsVoice, accountId, mediaAccess, mediaLocalRoots, mediaReadFile, replyToId, replyToIdSource, replyToMode, threadId, onDeliveryResult }) => {
682
+ const { normalizedReplyToId } = resolveFeishuReplyMode({
664
683
  replyToId,
665
684
  threadId
666
685
  });
667
- if (parseFeishuCommentTarget(to)) return await sendOutboundText({
686
+ const nextReplyToId = createReplyToFanout({
687
+ replyToId: normalizedReplyToId,
688
+ replyToIdSource,
689
+ replyToMode
690
+ });
691
+ const nextReplyMode = () => {
692
+ const { replyToMessageId, replyInThread } = resolveFeishuReplyMode({
693
+ replyToId: nextReplyToId(),
694
+ threadId
695
+ });
696
+ return {
697
+ replyToMessageId,
698
+ replyInThread
699
+ };
700
+ };
701
+ const deliveryOptions = {
702
+ replyToIdSource,
703
+ replyToMode,
704
+ onDeliveryResult
705
+ };
706
+ if (parseFeishuCommentTarget(to)) return toFeishuOutboundResult(await sendOutboundText({
668
707
  cfg,
669
708
  to,
670
709
  text: mediaUrl?.trim() ? await buildFeishuMediaFallbackText({
@@ -673,77 +712,72 @@ const feishuOutbound = {
673
712
  mediaLinkStyle: "plain"
674
713
  }) : text?.trim() ?? "",
675
714
  accountId: accountId ?? void 0,
676
- replyToMessageId,
677
- replyInThread
678
- });
679
- const suppressTextForVoiceMedia = mediaUrl !== void 0 && shouldSuppressFeishuTextForVoiceMedia({
715
+ ...nextReplyMode(),
716
+ ...deliveryOptions
717
+ }));
718
+ if (!mediaUrl) return toFeishuOutboundResult(await sendOutboundText({
719
+ cfg,
720
+ to,
721
+ text: text ?? "",
722
+ accountId: accountId ?? void 0,
723
+ ...nextReplyMode(),
724
+ ...deliveryOptions
725
+ }));
726
+ const suppressTextForVoiceMedia = shouldSuppressFeishuTextForVoiceMedia({
680
727
  mediaUrl,
681
728
  audioAsVoice
682
729
  });
683
- const reportDelivery = async (result) => {
684
- await onDeliveryResult?.(attachChannelToResult("feishu", result));
685
- };
686
730
  let textSent = false;
687
731
  if (text?.trim() && !suppressTextForVoiceMedia) {
688
- const textResult = await sendOutboundText({
732
+ await sendOutboundText({
689
733
  cfg,
690
734
  to,
691
735
  text,
692
736
  accountId: accountId ?? void 0,
693
- replyToMessageId,
694
- replyInThread
737
+ ...nextReplyMode(),
738
+ ...deliveryOptions
695
739
  });
696
740
  textSent = true;
697
- await reportDelivery(textResult);
698
741
  }
699
- if (mediaUrl) {
700
- let mediaResult;
701
- try {
702
- mediaResult = await sendMediaFeishu({
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({
742
+ let mediaResult;
743
+ const mediaReplyMode = nextReplyMode();
744
+ try {
745
+ mediaResult = await sendMediaFeishu({
730
746
  cfg,
731
747
  to,
732
- text,
748
+ mediaUrl,
733
749
  accountId: accountId ?? void 0,
734
- replyToMessageId,
735
- replyInThread
750
+ mediaAccess,
751
+ mediaLocalRoots,
752
+ mediaReadFile,
753
+ ...mediaReplyMode,
754
+ ...audioAsVoice === true ? { audioAsVoice: true } : {}
755
+ });
756
+ } catch (err) {
757
+ if (isChannelPartialDeliveryError(err)) throw err;
758
+ console.error(`[feishu] sendMediaFeishu failed:`, err);
759
+ return toFeishuOutboundResult(await sendOutboundText({
760
+ cfg,
761
+ to,
762
+ text: await buildFeishuMediaFallbackText({
763
+ text: textSent ? void 0 : text,
764
+ mediaUrl
765
+ }),
766
+ accountId: accountId ?? void 0,
767
+ ...textSent ? nextReplyMode() : mediaReplyMode,
768
+ ...deliveryOptions
736
769
  }));
737
- return mediaResult;
738
770
  }
739
- return await sendOutboundText({
771
+ await reportFeishuOutboundDelivery(mediaResult, onDeliveryResult);
772
+ if (mediaResult.voiceIntentDegradedToFile && text?.trim()) await sendOutboundText({
740
773
  cfg,
741
774
  to,
742
- text: text ?? "",
775
+ text,
743
776
  accountId: accountId ?? void 0,
744
- replyToMessageId,
745
- replyInThread
777
+ ...nextReplyMode(),
778
+ ...deliveryOptions
746
779
  });
780
+ return toFeishuOutboundResult(mediaResult);
747
781
  }
748
782
  })
749
783
  };
@@ -847,20 +881,35 @@ async function removeReactionFeishu(params) {
847
881
  */
848
882
  async function listReactionsFeishu(params) {
849
883
  const { cfg, messageId, emojiType, accountId } = params;
850
- const response = await resolveConfiguredFeishuClient({
884
+ const client = resolveConfiguredFeishuClient({
851
885
  cfg,
852
886
  accountId
853
- }).im.messageReaction.list({
854
- path: { message_id: messageId },
855
- params: emojiType ? { reaction_type: emojiType } : void 0
856
887
  });
857
- assertFeishuReactionApiSuccess(response, "list reactions");
858
- return (response.data?.items ?? []).map((item) => ({
859
- reactionId: item.reaction_id ?? "",
860
- emojiType: item.reaction_type?.emoji_type ?? "",
861
- operatorType: item.operator?.operator_type === "app" ? "app" : item.operator?.operator_type === "user" ? "user" : "unknown",
862
- operatorId: item.operator?.operator_id ?? ""
863
- }));
888
+ const reactions = [];
889
+ const seenPageTokens = /* @__PURE__ */ new Set();
890
+ let pageToken;
891
+ while (true) {
892
+ const response = await client.im.messageReaction.list({
893
+ path: { message_id: messageId },
894
+ params: emojiType || pageToken ? {
895
+ ...emojiType ? { reaction_type: emojiType } : {},
896
+ ...pageToken ? { page_token: pageToken } : {}
897
+ } : void 0
898
+ });
899
+ assertFeishuReactionApiSuccess(response, "list reactions");
900
+ for (const item of response.data?.items ?? []) reactions.push({
901
+ reactionId: item.reaction_id ?? "",
902
+ emojiType: item.reaction_type?.emoji_type ?? "",
903
+ operatorType: item.operator?.operator_type === "app" ? "app" : item.operator?.operator_type === "user" ? "user" : "unknown",
904
+ operatorId: item.operator?.operator_id ?? ""
905
+ });
906
+ if (response.data?.has_more !== true) return reactions;
907
+ const nextPageToken = response.data.page_token?.trim();
908
+ if (!nextPageToken) throw new Error("Feishu reaction pagination is missing its next page token");
909
+ if (seenPageTokens.has(nextPageToken)) throw new Error("Feishu reaction pagination returned a repeated page token");
910
+ seenPageTokens.add(nextPageToken);
911
+ pageToken = nextPageToken;
912
+ }
864
913
  }
865
914
  //#endregion
866
915
  //#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 resolveDomain(domain) {
149
- if (domain === "lark") return feishuClientSdk.Domain.Lark;
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: resolveDomain(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: resolveDomain(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,
@@ -1,4 +1,4 @@
1
- import { a as parseFeishuTargetId, i as parseFeishuDirectConversationId, r as parseFeishuConversationId, t as buildFeishuConversationId } from "./conversation-id-BeJL-wq7.js";
2
- import { t as messageActionTargetAliases } from "./security-audit-D7WK_BHh.js";
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 };