@openclaw/feishu 2026.9.2 → 2026.9.4

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.
@@ -11,7 +11,7 @@ import { PlatformMessageNotDispatchedError, formatErrorMessage } from "openclaw/
11
11
  import { legacyInteractiveReplyToPresentation, normalizeLegacyInteractiveReply, normalizeMessagePresentation, renderMessagePresentationChartFallbackText, renderMessagePresentationFallbackText, renderMessagePresentationTableFallbackText, renderPresentationForDelivery, resolveLegacyInteractiveTextFallback } from "openclaw/plugin-sdk/interactive-runtime";
12
12
  import { parseStrictNonNegativeInteger } from "openclaw/plugin-sdk/number-runtime";
13
13
  import { isRecord, normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, normalizeStringEntries, readStringValue } from "openclaw/plugin-sdk/string-coerce-runtime";
14
- import { convertMarkdownTables } from "openclaw/plugin-sdk/text-chunking";
14
+ import { convertMarkdownTables, markdownToIRWithMeta } from "openclaw/plugin-sdk/text-chunking";
15
15
  import { resolveDefaultGroupPolicy, resolveOpenProviderRuntimeGroupPolicy } from "openclaw/plugin-sdk/runtime-group-policy";
16
16
  import { createChannelIngressResolver, defineStableChannelIngressIdentity } from "openclaw/plugin-sdk/channel-ingress-runtime";
17
17
  import fs from "node:fs";
@@ -20,7 +20,7 @@ import { fromMarkdown } from "mdast-util-from-markdown";
20
20
  import { gfmTableFromMarkdown } from "mdast-util-gfm-table";
21
21
  import { gfmTable } from "micromark-extension-gfm-table";
22
22
  import { chunkMarkdownTextWithMode } from "openclaw/plugin-sdk/reply-chunking";
23
- import { createChannelPartialDeliveryError } from "openclaw/plugin-sdk/channel-inbound";
23
+ import { createAcceptedChannelDeliveryResult, createChannelPartialDeliveryError } from "openclaw/plugin-sdk/channel-inbound";
24
24
  import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime";
25
25
  import { readRegularFile, wrapExternalContent, writeExternalFileWithinRoot } from "openclaw/plugin-sdk/security-runtime";
26
26
  import { retryAsync } from "openclaw/plugin-sdk/retry-runtime";
@@ -34,6 +34,7 @@ import { MEDIA_FFMPEG_MAX_AUDIO_DURATION_SECS, buildOutboundMediaLoadOptions, ru
34
34
  import { saveMediaBuffer, saveMediaStream } from "openclaw/plugin-sdk/media-store";
35
35
  import { resolvePreferredOpenClawTmpDir, withTempDownloadPath, withTempWorkspace } from "openclaw/plugin-sdk/temp-path";
36
36
  import { logVerbose } from "openclaw/plugin-sdk/runtime-env";
37
+ import { escapeHtml, truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
37
38
  //#region extensions/feishu/src/card-interaction.ts
38
39
  const FEISHU_CARD_INTERACTION_VERSION = "ocf1";
39
40
  function isInteractionKind(value) {
@@ -1266,32 +1267,32 @@ function resolveImplicitToolAccountId(params) {
1266
1267
  if (explicitAccountId) {
1267
1268
  const normalizedAccountId = normalizeOptionalAccountId(explicitAccountId);
1268
1269
  if (!normalizedAccountId) throw new Error(`Invalid Feishu account ID "${explicitAccountId}"`);
1269
- const listedAccountId = listFeishuAccountIds(params.api.config).find((accountId) => normalizeOptionalAccountId(accountId) === normalizedAccountId) ?? (() => {
1270
- const defaultAccountId = resolveDefaultFeishuAccountId(params.api.config);
1270
+ const listedAccountId = listFeishuAccountIds(params.cfg).find((accountId) => normalizeOptionalAccountId(accountId) === normalizedAccountId) ?? (() => {
1271
+ const defaultAccountId = resolveDefaultFeishuAccountId(params.cfg);
1271
1272
  return normalizeOptionalAccountId(defaultAccountId) === normalizedAccountId ? defaultAccountId : void 0;
1272
1273
  })();
1273
1274
  if (!listedAccountId) throw new Error(`Unknown Feishu account "${explicitAccountId}"`);
1274
1275
  if (!resolveFeishuAccount({
1275
- cfg: params.api.config,
1276
+ cfg: params.cfg,
1276
1277
  accountId: normalizedAccountId
1277
1278
  }).enabled) throw new Error(`Feishu account "${listedAccountId}" is disabled`);
1278
1279
  return normalizedAccountId;
1279
1280
  }
1280
1281
  const contextualAccountId = normalizeOptionalString(params.defaultAccountId);
1281
- if (contextualAccountId && listFeishuAccountIds(params.api.config).includes(contextualAccountId)) {
1282
+ if (contextualAccountId && listFeishuAccountIds(params.cfg).includes(contextualAccountId)) {
1282
1283
  if (resolveFeishuAccount({
1283
- cfg: params.api.config,
1284
+ cfg: params.cfg,
1284
1285
  accountId: contextualAccountId
1285
1286
  }).enabled) return contextualAccountId;
1286
1287
  }
1287
- const configuredDefaultAccountId = normalizeOptionalString((params.api.config?.channels?.feishu)?.defaultAccount);
1288
+ const configuredDefaultAccountId = normalizeOptionalString((params.cfg.channels?.feishu)?.defaultAccount);
1288
1289
  if (configuredDefaultAccountId && resolveFeishuAccount({
1289
- cfg: params.api.config,
1290
+ cfg: params.cfg,
1290
1291
  accountId: configuredDefaultAccountId
1291
1292
  }).enabled) return configuredDefaultAccountId;
1292
- if (params.api.config) for (const accountId of listFeishuAccountIds(params.api.config)) {
1293
+ for (const accountId of listFeishuAccountIds(params.cfg)) {
1293
1294
  const account = resolveFeishuAccount({
1294
- cfg: params.api.config,
1295
+ cfg: params.cfg,
1295
1296
  accountId
1296
1297
  });
1297
1298
  if (account.enabled && account.configured && resolveToolsConfig(account.config.tools)[params.requiredTool.family]) return accountId;
@@ -1299,9 +1300,8 @@ function resolveImplicitToolAccountId(params) {
1299
1300
  throw new Error(`No usable Feishu account has ${params.requiredTool.label} tools enabled`);
1300
1301
  }
1301
1302
  function resolveFeishuToolAccount(params) {
1302
- if (!params.api.config) throw new Error("Feishu config unavailable");
1303
1303
  const account = resolveFeishuRuntimeAccount({
1304
- cfg: params.api.config,
1304
+ cfg: params.cfg,
1305
1305
  accountId: resolveImplicitToolAccountId(params)
1306
1306
  });
1307
1307
  if (!resolveToolsConfig(account.config.tools)[params.requiredTool.family]) throw new Error(`Feishu ${params.requiredTool.label} tools are disabled for account "${account.accountId}"`);
@@ -1707,9 +1707,9 @@ async function deliverCommentThreadText(client, params) {
1707
1707
  }
1708
1708
  }
1709
1709
  function registerFeishuDriveTools(api) {
1710
- if (!api.config) return;
1711
- if (!resolveAnyEnabledFeishuToolsConfig(api.config).drive) return;
1712
1710
  api.registerTool((ctx) => {
1711
+ const cfg = ctx.runtimeConfig ?? ctx.config ?? api.config;
1712
+ if (!cfg || !resolveAnyEnabledFeishuToolsConfig(cfg).drive) return null;
1713
1713
  const defaultAccountId = ctx.agentAccountId;
1714
1714
  return {
1715
1715
  name: "feishu_drive",
@@ -1721,7 +1721,7 @@ function registerFeishuDriveTools(api) {
1721
1721
  const p = params;
1722
1722
  try {
1723
1723
  const client = createFeishuToolClient({
1724
- api,
1724
+ cfg,
1725
1725
  executeParams: p,
1726
1726
  defaultAccountId,
1727
1727
  requiredTool: {
@@ -1941,13 +1941,6 @@ function toStringOrEmpty(value) {
1941
1941
  function escapeMarkdownText(text) {
1942
1942
  return text.replace(MARKDOWN_SPECIAL_CHARS, "\\$1");
1943
1943
  }
1944
- function toBoolean(value) {
1945
- return value === true || value === 1 || value === "true";
1946
- }
1947
- function isStyleEnabled(style, key) {
1948
- if (!style) return false;
1949
- return toBoolean(style[key]);
1950
- }
1951
1944
  function wrapInlineCode(text) {
1952
1945
  const maxRun = Math.max(0, ...(text.match(/`+/g) ?? []).map((run) => run.length));
1953
1946
  const fence = "`".repeat(maxRun + 1);
@@ -1956,17 +1949,15 @@ function wrapInlineCode(text) {
1956
1949
  function sanitizeFenceLanguage(language) {
1957
1950
  return language.trim().replace(/[^A-Za-z0-9_+#.-]/g, "");
1958
1951
  }
1959
- function renderTextElement(element) {
1960
- const text = toStringOrEmpty(element.text);
1961
- const style = isRecord(element.style) ? element.style : void 0;
1962
- if (isStyleEnabled(style, "code")) return wrapInlineCode(text);
1963
- let rendered = escapeMarkdownText(text);
1964
- if (!rendered) return "";
1965
- if (isStyleEnabled(style, "bold")) rendered = `**${rendered}**`;
1966
- if (isStyleEnabled(style, "italic")) rendered = `*${rendered}*`;
1967
- if (isStyleEnabled(style, "underline")) rendered = `<u>${rendered}</u>`;
1968
- if (isStyleEnabled(style, "strikethrough") || isStyleEnabled(style, "line_through") || isStyleEnabled(style, "lineThrough")) rendered = `~~${rendered}~~`;
1969
- return rendered;
1952
+ function applyInlineStyles(text, style) {
1953
+ const content = text.trim();
1954
+ if (!content || !Array.isArray(style)) return text;
1955
+ let rendered = content;
1956
+ if (style.includes("bold")) rendered = `**${rendered}**`;
1957
+ if (style.includes("italic")) rendered = `*${rendered}*`;
1958
+ if (style.includes("underline")) rendered = `<u>${rendered}</u>`;
1959
+ if (style.includes("lineThrough")) rendered = `~~${rendered}~~`;
1960
+ return text.replace(content, () => rendered);
1970
1961
  }
1971
1962
  function renderLinkElement(element) {
1972
1963
  const href = toStringOrEmpty(element.href).trim();
@@ -1991,15 +1982,15 @@ function renderCodeBlockElement(element) {
1991
1982
  function renderElement(element, attachments, mentionedOpenIds, renderMediaPlaceholders) {
1992
1983
  if (!isRecord(element)) return escapeMarkdownText(toStringOrEmpty(element));
1993
1984
  switch (normalizeLowercaseStringOrEmpty(toStringOrEmpty(element.tag))) {
1994
- case "text": return renderTextElement(element);
1995
- case "a": return renderLinkElement(element);
1985
+ case "text": return applyInlineStyles(escapeMarkdownText(toStringOrEmpty(element.text)), element.style);
1986
+ case "a": return applyInlineStyles(renderLinkElement(element), element.style);
1996
1987
  case "at":
1997
1988
  {
1998
1989
  const mentioned = toStringOrEmpty(element.open_id) || toStringOrEmpty(element.user_id);
1999
1990
  const normalizedMention = normalizeFeishuExternalKey(mentioned);
2000
1991
  if (normalizedMention) mentionedOpenIds.push(normalizedMention);
2001
1992
  }
2002
- return renderMentionElement(element);
1993
+ return applyInlineStyles(renderMentionElement(element), element.style);
2003
1994
  case "img": {
2004
1995
  const imageKey = normalizeFeishuExternalKey(toStringOrEmpty(element.image_key));
2005
1996
  if (imageKey) attachments.push({
@@ -2282,6 +2273,57 @@ function buildMentionedCardContent(targets, message) {
2282
2273
  return `${targets.map((t) => formatMentionForCard(t)).join(" ")} ${message}`;
2283
2274
  }
2284
2275
  //#endregion
2276
+ //#region extensions/feishu/src/message-content.ts
2277
+ function formatFeishuMediaContent(parsed, messageType) {
2278
+ if (messageType === "sticker") {
2279
+ const fileKey = normalizeFeishuExternalKey(parsed?.file_key);
2280
+ return fileKey ? `<sticker key="${escapeHtml(fileKey)}"/>` : "[Sticker]";
2281
+ }
2282
+ const speechToText = messageType === "audio" && typeof parsed.speech_to_text === "string" ? parsed.speech_to_text.trim() : "";
2283
+ if (speechToText) return speechToText;
2284
+ return "";
2285
+ }
2286
+ function formatSubMessageContent(content, contentType) {
2287
+ try {
2288
+ const parsed = JSON.parse(content);
2289
+ switch (contentType) {
2290
+ case "text": return parsed.text || content;
2291
+ case "post": return parsePostContent(content).textContent;
2292
+ case "interactive": return parseInteractiveCardContent(parsed);
2293
+ case "image": return "[Image]";
2294
+ case "file": return `[File: ${parsed.file_name || "unknown"}]`;
2295
+ case "audio": return "[Audio]";
2296
+ case "video": return "[Video]";
2297
+ case "sticker": return formatFeishuMediaContent(parsed, contentType);
2298
+ case "merge_forward": return "[Nested Merged Forward]";
2299
+ default: return `[${contentType}]`;
2300
+ }
2301
+ } catch {
2302
+ return content;
2303
+ }
2304
+ }
2305
+ function parseMergeForwardContent(params) {
2306
+ const { content } = params;
2307
+ const maxMessages = 50;
2308
+ let items;
2309
+ try {
2310
+ items = JSON.parse(content);
2311
+ } catch {
2312
+ return "[Merged and Forwarded Message - parse error]";
2313
+ }
2314
+ if (!Array.isArray(items) || items.length === 0) return "[Merged and Forwarded Message - no sub-messages]";
2315
+ const container = items.find((item) => item.msg_type === "merge_forward" && !item.upper_message_id);
2316
+ const subMessages = container ? items.filter((item) => item !== container) : items.filter((item) => item.upper_message_id);
2317
+ if (subMessages.length === 0) return "[Merged and Forwarded Message - no sub-messages found]";
2318
+ subMessages.sort((a, b) => (parseStrictNonNegativeInteger(a.create_time) ?? 0) - (parseStrictNonNegativeInteger(b.create_time) ?? 0));
2319
+ const lines = ["[Merged and Forwarded Messages]"];
2320
+ for (const item of subMessages.slice(0, maxMessages)) lines.push(`- ${formatSubMessageContent(item.body?.content || "", item.msg_type || "text")}`);
2321
+ if (subMessages.length > maxMessages) lines.push(`... and ${subMessages.length - maxMessages} more messages`);
2322
+ const rendered = lines.join("\n");
2323
+ return rendered.length <= 2e4 ? rendered : `${truncateUtf16Safe(rendered, 19961).trimEnd()}
2324
+ ... [Merged-forward content truncated]`;
2325
+ }
2326
+ //#endregion
2285
2327
  //#region extensions/feishu/src/send.ts
2286
2328
  const WITHDRAWN_REPLY_ERROR_CODES = /* @__PURE__ */ new Set([230011, 231003]);
2287
2329
  function shouldFallbackFromReplyTarget(response) {
@@ -2396,10 +2438,16 @@ async function getMessageFeishu(params) {
2396
2438
  path: { message_id: messageId }
2397
2439
  });
2398
2440
  if (response.code !== 0) return null;
2399
- const rawItem = response.data?.items?.[0] ?? response.data;
2441
+ const responseItems = response.data?.items;
2442
+ const rawItem = responseItems?.find((item) => item.msg_type === "merge_forward" && !item.upper_message_id) ?? responseItems?.[0] ?? response.data;
2400
2443
  const item = rawItem && (rawItem.body !== void 0 || rawItem.message_id !== void 0) ? rawItem : null;
2401
2444
  if (!item) return null;
2402
- return parseFeishuMessageItem(item, messageId);
2445
+ const parsedItem = parseFeishuMessageItem(item, messageId);
2446
+ if (parsedItem.contentType === "merge_forward" && responseItems) return {
2447
+ ...parsedItem,
2448
+ content: parseMergeForwardContent({ content: JSON.stringify(responseItems) })
2449
+ };
2450
+ return parsedItem;
2403
2451
  } catch {
2404
2452
  return null;
2405
2453
  }
@@ -3292,6 +3340,24 @@ function isFeishuCardWithinEnvelope(card) {
3292
3340
  function assertFeishuCardWithinEnvelope(card, label = "Feishu card") {
3293
3341
  if (!isFeishuCardWithinEnvelope(card)) throw new Error(`${label} exceeds the 30 KB or 200-element API limit.`);
3294
3342
  }
3343
+ /** Feishu allows at most five table components per static interactive card. */
3344
+ const FEISHU_CARD_TABLE_LIMIT = 5;
3345
+ function countMarkdownTables(text) {
3346
+ return text.includes("|") ? markdownToIRWithMeta(text, { tableMode: "block" }).tables.length : 0;
3347
+ }
3348
+ function withinCardTableLimit(text) {
3349
+ return countMarkdownTables(text) <= FEISHU_CARD_TABLE_LIMIT;
3350
+ }
3351
+ function feishuCardWithinTableLimit(card) {
3352
+ let remaining = FEISHU_CARD_TABLE_LIMIT;
3353
+ const visit = (value) => {
3354
+ if (Array.isArray(value)) return value.every(visit);
3355
+ if (!isRecord(value)) return true;
3356
+ if (value.tag === "markdown" && typeof value.content === "string") remaining -= countMarkdownTables(value.content);
3357
+ return remaining >= 0 && Object.values(value).every(visit);
3358
+ };
3359
+ return visit(card);
3360
+ }
3295
3361
  function resolveFeishuButtonUrl(button) {
3296
3362
  if (button.action?.type === "url" || button.action?.type === "web-app") return button.action.url;
3297
3363
  if (button.action) return;
@@ -3477,8 +3543,11 @@ function buildFeishuPayloadCard(params) {
3477
3543
  }, ...card.body.elements]
3478
3544
  }
3479
3545
  };
3480
- if (isNativeCard) assertFeishuCardWithinEnvelope(card, "Feishu native card");
3481
- return isFeishuCardWithinEnvelope(card) ? markRenderedFeishuCard(card) : void 0;
3546
+ if (isNativeCard) {
3547
+ assertFeishuCardWithinEnvelope(card, "Feishu native card");
3548
+ return markRenderedFeishuCard(card);
3549
+ }
3550
+ return isFeishuCardWithinEnvelope(card) && feishuCardWithinTableLimit(card) ? markRenderedFeishuCard(card) : void 0;
3482
3551
  }
3483
3552
  function renderFeishuPresentationPayload({ payload, presentation, sourcePresentation, ctx }) {
3484
3553
  const card = buildFeishuPayloadCard({
@@ -3549,20 +3618,15 @@ function hasProviderIdentity(result) {
3549
3618
  /** Normalizes every physical Lark send behind one logical reply payload. */
3550
3619
  function createFeishuReplyDeliveryResult(params) {
3551
3620
  const results = params.visibleReplySent ? (params.results ?? []).filter(hasProviderIdentity) : [];
3552
- const receipt = results.length > 0 ? createMessageReceiptFromOutboundResults({
3553
- results,
3554
- ...params.kind ? { kind: params.kind } : {}
3555
- }) : void 0;
3556
- if (!receipt) return {
3557
- visibleReplySent: params.visibleReplySent,
3558
- ...params.content === void 0 ? {} : { content: params.content }
3559
- };
3560
- return {
3561
- messageIds: [...receipt.platformMessageIds],
3562
- receipt,
3621
+ if (results.length === 0) return {
3563
3622
  visibleReplySent: params.visibleReplySent,
3564
3623
  ...params.content === void 0 ? {} : { content: params.content }
3565
3624
  };
3625
+ return createAcceptedChannelDeliveryResult({
3626
+ results,
3627
+ kind: params.kind,
3628
+ content: params.content
3629
+ });
3566
3630
  }
3567
3631
  /** Preserves the first result's provider identity while retaining supplemental ids. */
3568
3632
  function mergeFeishuReplyDeliveryResults(results, content) {
@@ -3583,4 +3647,4 @@ function createFeishuPartialReplyDeliveryError(cause, result) {
3583
3647
  });
3584
3648
  }
3585
3649
  //#endregion
3586
- export { parseCommentContentElements as $, isFeishuBroadcastMention as A, decodeFeishuCardAction as At, deliverCommentThreadText as B, editMessageFeishu as C, resolveFeishuGroupToolPolicy as Ct, sendMessageFeishu as D, FEISHU_CARD_INTERACTION_VERSION as Dt, sendCardFeishu as E, resolveFeishuChatType as Et, createFeishuSendReceipt as F, createFeishuToolClient as G, feishuExternalToolResult as H, assertFeishuApiSuccess as I, cleanupAmbientCommentTypingReaction as J, resolveAnyEnabledFeishuToolsConfig as K, buildFeishuMediaFallbackText as L, isFeishuGroupChatType as M, parseInteractiveCardContent as N, sendStructuredCardFeishu as O, buildFeishuCardActionTextFallback as Ot, parsePostContent as P, formatFeishuApiError as Q, resolveFeishuIdentityEmoji as R, chunkFeishuCardMarkdown as S, resolveFeishuGroupSenderActivationIngressAccess as St, listFeishuThreadMessages as T, normalizeFeishuChatType as Tt, toolExecutionErrorResult as U, registerFeishuDriveTools as V, unknownToolActionResult as W, encodeQuery as X, createCommentTypingReactionLifecycle as Y, extractReplyText as Z, resolveFeishuRichReply as _, hasExplicitFeishuGroupConfig as _t, FEISHU_PRESENTATION_CAPABILITIES as a, resolveFeishuCardTemplate as at, sendStickerFeishu as b, resolveFeishuGroupConfig as bt, buildFeishuPresentationCard as c, materializeFeishuPostMarkdownSoftBreaks as ct, isFeishuCardWithinEnvelope as d, authorizeFeishuChatMemberRead as dt, requestFeishuApi as et, markRenderedFeishuCard as f, canEnumerateAllFeishuGroups as ft, renderFeishuReplyPayload as g, resolveFeishuChatReadPreliminaryAuthorization as gt, renderFeishuPresentationPayload as h, isFeishuGroupReadEnabled as ht, noVisibleFeishuReplyDelivery as i, readNativeFeishuCardJson as it, isMentionForwardRequest as j, extractMentionTargets as k, createFeishuCardInteractionEnvelope as kt, buildFeishuPresentationFallback as l, parseFeishuMarkdown as lt, renderFeishuPresentationFallbackText as m, isFeishuGroupReadAllowed as mt, createFeishuReplyDeliveryResult as n, normalizeCommentFileType as nt, assertFeishuCardWithinEnvelope as o, chunkFeishuMarkdown as ot, readNativeFeishuCard as p, canEnumerateAllFeishuPeers as pt, resolveFeishuToolAccount as q, mergeFeishuReplyDeliveryResults as r, parseFeishuCommentTarget as rt, buildFeishuPayloadCard as s, chunkFeishuPostMarkdown as st, createFeishuPartialReplyDeliveryError as t, buildFeishuCommentTarget as tt, consumeFeishuPresentationFallbackMarker as u, assertFeishuChatReadAllowed as ut, saveMessageResourceFeishu as v, normalizeFeishuAllowEntry as vt, getMessageFeishu as w, resolveFeishuReplyPolicy as wt, shouldSuppressFeishuTextForVoiceMedia as x, resolveFeishuGroupConversationIngressAccess as xt, sendMediaFeishu as y, resolveFeishuDmIngressAccess as yt, resolveFeishuIdentityHeaderTitle as z };
3650
+ export { encodeQuery as $, sendStructuredCardFeishu as A, FEISHU_CARD_INTERACTION_VERSION as At, buildFeishuMediaFallbackText as B, shouldSuppressFeishuTextForVoiceMedia as C, resolveFeishuGroupConfig as Ct, listFeishuThreadMessages as D, resolveFeishuReplyPolicy as Dt, getMessageFeishu as E, resolveFeishuGroupToolPolicy as Et, isFeishuGroupChatType as F, feishuExternalToolResult as G, resolveFeishuIdentityHeaderTitle as H, parseInteractiveCardContent as I, createFeishuToolClient as J, toolExecutionErrorResult as K, parsePostContent as L, extractMentionTargets as M, createFeishuCardInteractionEnvelope as Mt, isFeishuBroadcastMention as N, decodeFeishuCardAction as Nt, sendCardFeishu as O, normalizeFeishuChatType as Ot, isMentionForwardRequest as P, createCommentTypingReactionLifecycle as Q, createFeishuSendReceipt as R, sendStickerFeishu as S, resolveFeishuDmIngressAccess as St, editMessageFeishu as T, resolveFeishuGroupSenderActivationIngressAccess as Tt, deliverCommentThreadText as U, resolveFeishuIdentityEmoji as V, registerFeishuDriveTools as W, resolveFeishuToolAccount as X, resolveAnyEnabledFeishuToolsConfig as Y, cleanupAmbientCommentTypingReaction as Z, renderFeishuReplyPayload as _, isFeishuGroupReadAllowed as _t, FEISHU_PRESENTATION_CAPABILITIES as a, normalizeCommentFileType as at, saveMessageResourceFeishu as b, hasExplicitFeishuGroupConfig as bt, buildFeishuPresentationCard as c, resolveFeishuCardTemplate as ct, feishuCardWithinTableLimit as d, materializeFeishuPostMarkdownSoftBreaks as dt, extractReplyText as et, isFeishuCardWithinEnvelope as f, parseFeishuMarkdown as ft, renderFeishuPresentationPayload as g, canEnumerateAllFeishuPeers as gt, renderFeishuPresentationFallbackText as h, canEnumerateAllFeishuGroups as ht, noVisibleFeishuReplyDelivery as i, buildFeishuCommentTarget as it, formatFeishuMediaContent as j, buildFeishuCardActionTextFallback as jt, sendMessageFeishu as k, resolveFeishuChatType as kt, buildFeishuPresentationFallback as l, chunkFeishuMarkdown as lt, readNativeFeishuCard as m, authorizeFeishuChatMemberRead as mt, createFeishuReplyDeliveryResult as n, parseCommentContentElements as nt, assertFeishuCardWithinEnvelope as o, parseFeishuCommentTarget as ot, markRenderedFeishuCard as p, assertFeishuChatReadAllowed as pt, unknownToolActionResult as q, mergeFeishuReplyDeliveryResults as r, requestFeishuApi as rt, buildFeishuPayloadCard as s, readNativeFeishuCardJson as st, createFeishuPartialReplyDeliveryError as t, formatFeishuApiError as tt, consumeFeishuPresentationFallbackMarker as u, chunkFeishuPostMarkdown as ut, resolveFeishuRichReply as v, isFeishuGroupReadEnabled as vt, chunkFeishuCardMarkdown as w, resolveFeishuGroupConversationIngressAccess as wt, sendMediaFeishu as x, normalizeFeishuAllowEntry as xt, withinCardTableLimit as y, resolveFeishuChatReadPreliminaryAuthorization as yt, assertFeishuApiSuccess as z };
package/dist/setup-api.js CHANGED
@@ -1,2 +1,2 @@
1
- import { i as feishuSetupAdapter, n as feishuSetupWizard, t as feishuPlugin } from "./channel-VytDDz_B.js";
1
+ import { i as feishuSetupAdapter, n as feishuSetupWizard, t as feishuPlugin } from "./channel-HDnQAH4Z.js";
2
2
  export { feishuPlugin, feishuSetupAdapter, feishuSetupWizard };
@@ -1,5 +1,9 @@
1
1
  {
2
2
  "id": "feishu",
3
+ "categories": [
4
+ "channels",
5
+ "tools"
6
+ ],
3
7
  "doctorContract": {
4
8
  "configRepair": true
5
9
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/feishu",
3
- "version": "2026.9.2",
3
+ "version": "2026.9.4",
4
4
  "description": "OpenClaw Feishu/Lark channel plugin for chats and workplace tools (community maintained by @m1heng).",
5
5
  "repository": {
6
6
  "type": "git",
@@ -16,7 +16,7 @@
16
16
  "zod": "4.4.3"
17
17
  },
18
18
  "peerDependencies": {
19
- "openclaw": ">=2026.9.2"
19
+ "openclaw": ">=2026.9.4"
20
20
  },
21
21
  "peerDependenciesMeta": {
22
22
  "openclaw": {
@@ -62,11 +62,11 @@
62
62
  "minHostVersion": ">=2026.5.29"
63
63
  },
64
64
  "compat": {
65
- "pluginApi": ">=2026.9.2"
65
+ "pluginApi": ">=2026.9.4"
66
66
  },
67
67
  "build": {
68
68
  "bundledDist": false,
69
- "openclawVersion": "2026.9.2"
69
+ "openclawVersion": "2026.9.4"
70
70
  },
71
71
  "release": {
72
72
  "publishToClawHub": true,