@openclaw/feishu 2026.5.7 → 2026.5.10-beta.1

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.
@@ -0,0 +1,181 @@
1
+ import { t as detectIdType } from "./targets-JMFJRKSe.js";
2
+ import { normalizeOptionalLowercaseString } from "openclaw/plugin-sdk/text-runtime";
3
+ import { normalizeAccountId, resolveMergedAccountConfig } from "openclaw/plugin-sdk/account-resolution";
4
+ import { createChannelIngressResolver, defineStableChannelIngressIdentity } from "openclaw/plugin-sdk/channel-ingress-runtime";
5
+ //#region extensions/feishu/src/policy.ts
6
+ const FEISHU_PROVIDER_PREFIX_RE = /^(feishu|lark):/i;
7
+ const FEISHU_TYPED_PREFIX_RE = /^(chat|group|channel|user|dm|open_id):/i;
8
+ const FEISHU_ID_KIND = "plugin:feishu-id";
9
+ const feishuIngressIdentity = defineStableChannelIngressIdentity({
10
+ key: "feishu-id",
11
+ kind: FEISHU_ID_KIND,
12
+ normalize: normalizeFeishuAllowEntry,
13
+ sensitivity: "pii",
14
+ aliases: [{
15
+ key: "feishu-alt-id",
16
+ kind: FEISHU_ID_KIND,
17
+ normalizeEntry: () => null,
18
+ normalizeSubject: normalizeFeishuAllowEntry,
19
+ sensitivity: "pii"
20
+ }],
21
+ isWildcardEntry: (entry) => normalizeFeishuAllowEntry(entry) === "*",
22
+ resolveEntryId: ({ entryIndex }) => `feishu-entry-${entryIndex + 1}`
23
+ });
24
+ function normalizeFeishuAllowEntry(raw) {
25
+ const trimmed = raw.trim();
26
+ if (!trimmed) return "";
27
+ if (trimmed === "*") return "*";
28
+ let withoutProviderPrefix = trimmed;
29
+ while (FEISHU_PROVIDER_PREFIX_RE.test(withoutProviderPrefix)) withoutProviderPrefix = withoutProviderPrefix.replace(FEISHU_PROVIDER_PREFIX_RE, "").trim();
30
+ if (withoutProviderPrefix === "*") return "*";
31
+ const lowered = normalizeOptionalLowercaseString(withoutProviderPrefix) ?? "";
32
+ if (!lowered) return "";
33
+ const prefixed = lowered.match(FEISHU_TYPED_PREFIX_RE);
34
+ if (prefixed?.[1]) {
35
+ const kind = [
36
+ "chat",
37
+ "group",
38
+ "channel"
39
+ ].includes(prefixed[1]) ? "chat" : "user";
40
+ const value = withoutProviderPrefix.slice(prefixed[0].length).trim();
41
+ return value === "*" ? "*" : value ? `${kind}:${value}` : "";
42
+ }
43
+ const detectedType = detectIdType(withoutProviderPrefix);
44
+ if (detectedType === "chat_id") return `chat:${withoutProviderPrefix}`;
45
+ if (detectedType === "open_id" || detectedType === "user_id") return `user:${withoutProviderPrefix}`;
46
+ return "";
47
+ }
48
+ function normalizeFeishuDmPolicy(policy) {
49
+ return policy === "open" || policy === "pairing" || policy === "allowlist" || policy === "disabled" ? policy : "pairing";
50
+ }
51
+ function normalizeFeishuGroupPolicy(policy) {
52
+ return policy === "allowall" ? "open" : policy;
53
+ }
54
+ function createFeishuIngressSubject(params) {
55
+ const ids = [params.primaryId, ...params.alternateIds ?? []].map((value) => value?.trim()).filter((value) => Boolean(value));
56
+ return {
57
+ stableId: ids[0],
58
+ aliases: { "feishu-alt-id": ids[1] }
59
+ };
60
+ }
61
+ function createFeishuIngressResolver(params) {
62
+ return createChannelIngressResolver({
63
+ channelId: "feishu",
64
+ accountId: normalizeAccountId(params.accountId) ?? "default",
65
+ identity: feishuIngressIdentity,
66
+ cfg: params.cfg,
67
+ ...params.readAllowFromStore ? { readStoreAllowFrom: params.readAllowFromStore } : {}
68
+ });
69
+ }
70
+ async function resolveFeishuDmIngressAccess(params) {
71
+ return await createFeishuIngressResolver({
72
+ cfg: params.cfg,
73
+ accountId: params.accountId,
74
+ readAllowFromStore: params.readAllowFromStore
75
+ }).message({
76
+ subject: createFeishuIngressSubject({
77
+ primaryId: params.senderOpenId,
78
+ alternateIds: [params.senderUserId]
79
+ }),
80
+ conversation: {
81
+ kind: "direct",
82
+ id: params.conversationId
83
+ },
84
+ event: { mayPair: params.mayPair },
85
+ dmPolicy: normalizeFeishuDmPolicy(params.dmPolicy),
86
+ groupPolicy: "disabled",
87
+ allowFrom: params.allowFrom ?? [],
88
+ ...params.command ? { command: params.command } : {}
89
+ });
90
+ }
91
+ async function resolveFeishuGroupConversationIngressAccess(params) {
92
+ const groupPolicy = normalizeFeishuGroupPolicy(params.groupPolicy);
93
+ const groupAllowFrom = groupPolicy === "allowlist" && params.groupExplicitlyConfigured ? [...params.groupAllowFrom ?? [], params.chatId] : params.groupAllowFrom ?? [];
94
+ return await createFeishuIngressResolver({
95
+ cfg: params.cfg,
96
+ accountId: params.accountId
97
+ }).message({
98
+ subject: createFeishuIngressSubject({ primaryId: params.chatId }),
99
+ conversation: {
100
+ kind: "group",
101
+ id: params.chatId
102
+ },
103
+ dmPolicy: "disabled",
104
+ groupPolicy,
105
+ groupAllowFrom
106
+ });
107
+ }
108
+ async function resolveFeishuGroupSenderActivationIngressAccess(params) {
109
+ const groupAllowFrom = params.allowFrom ?? [];
110
+ return await createFeishuIngressResolver({
111
+ cfg: params.cfg,
112
+ accountId: params.accountId
113
+ }).message({
114
+ subject: createFeishuIngressSubject({
115
+ primaryId: params.senderOpenId,
116
+ alternateIds: [params.senderUserId]
117
+ }),
118
+ conversation: {
119
+ kind: "group",
120
+ id: params.chatId
121
+ },
122
+ dmPolicy: "disabled",
123
+ groupPolicy: groupAllowFrom.length > 0 ? "allowlist" : "open",
124
+ groupAllowFrom,
125
+ mentionFacts: {
126
+ canDetectMention: true,
127
+ wasMentioned: params.mentionedBot
128
+ },
129
+ policy: { activation: {
130
+ requireMention: params.requireMention,
131
+ allowTextCommands: false
132
+ } },
133
+ ...params.command ? { command: params.command } : {}
134
+ });
135
+ }
136
+ function resolveFeishuGroupConfig(params) {
137
+ const groups = params.cfg?.groups ?? {};
138
+ const wildcard = groups["*"];
139
+ const groupId = params.groupId?.trim();
140
+ if (!groupId) return;
141
+ const direct = groups[groupId];
142
+ if (direct) return direct;
143
+ const lowered = normalizeOptionalLowercaseString(groupId) ?? "";
144
+ const matchKey = Object.keys(groups).find((key) => normalizeOptionalLowercaseString(key) === lowered);
145
+ if (matchKey) return groups[matchKey];
146
+ return wildcard;
147
+ }
148
+ function hasExplicitFeishuGroupConfig(params) {
149
+ const groups = params.cfg?.groups ?? {};
150
+ const groupId = params.groupId?.trim();
151
+ if (!groupId) return false;
152
+ if (Object.prototype.hasOwnProperty.call(groups, groupId) && groupId !== "*") return true;
153
+ const lowered = normalizeOptionalLowercaseString(groupId) ?? "";
154
+ return Object.keys(groups).some((key) => key !== "*" && normalizeOptionalLowercaseString(key) === lowered);
155
+ }
156
+ function resolveFeishuGroupToolPolicy(params) {
157
+ const cfg = params.cfg.channels?.feishu;
158
+ if (!cfg) return;
159
+ return resolveFeishuGroupConfig({
160
+ cfg,
161
+ groupId: params.groupId
162
+ })?.tools;
163
+ }
164
+ function resolveFeishuReplyPolicy(params) {
165
+ if (params.isDirectMessage) return { requireMention: false };
166
+ const feishuCfg = params.cfg.channels?.feishu;
167
+ const resolvedCfg = resolveMergedAccountConfig({
168
+ channelConfig: feishuCfg,
169
+ accounts: feishuCfg?.accounts,
170
+ accountId: normalizeAccountId(params.accountId),
171
+ normalizeAccountId,
172
+ omitKeys: ["defaultAccount"]
173
+ });
174
+ const groupRequireMention = resolveFeishuGroupConfig({
175
+ cfg: resolvedCfg,
176
+ groupId: params.groupId
177
+ })?.requireMention;
178
+ return { requireMention: typeof groupRequireMention === "boolean" ? groupRequireMention : typeof resolvedCfg.requireMention === "boolean" ? resolvedCfg.requireMention : params.groupPolicy !== "open" };
179
+ }
180
+ //#endregion
181
+ export { resolveFeishuGroupSenderActivationIngressAccess as a, resolveFeishuGroupConversationIngressAccess as i, resolveFeishuDmIngressAccess as n, resolveFeishuGroupToolPolicy as o, resolveFeishuGroupConfig as r, resolveFeishuReplyPolicy as s, hasExplicitFeishuGroupConfig as t };
@@ -1,11 +1,11 @@
1
1
  import { n as setFeishuRuntime } from "./runtime-CG0DuRCy.js";
2
2
  import { normalizeAgentId } from "openclaw/plugin-sdk/routing";
3
+ import { createReplyPrefixContext } from "openclaw/plugin-sdk/channel-message";
3
4
  import { createChannelPairingController } from "openclaw/plugin-sdk/channel-pairing";
4
5
  import { PAIRING_APPROVED_MESSAGE, buildProbeChannelStatusSummary, createDefaultChannelRuntimeState } from "openclaw/plugin-sdk/channel-status";
5
6
  import { chunkTextForOutbound } from "openclaw/plugin-sdk/text-chunking";
6
7
  import { DEFAULT_ACCOUNT_ID, buildChannelConfigSchema, createActionGate, createDedupeCache } from "openclaw/plugin-sdk/core";
7
8
  import { buildAgentMediaPayload } from "openclaw/plugin-sdk/agent-media-payload";
8
- import { createReplyPrefixContext } from "openclaw/plugin-sdk/channel-reply-pipeline";
9
9
  import { evaluateSupplementalContextVisibility, filterSupplementalContextItems, resolveChannelContextVisibilityMode } from "openclaw/plugin-sdk/context-visibility-runtime";
10
10
  import { loadSessionStore, resolveSessionStoreEntry } from "openclaw/plugin-sdk/session-store-runtime";
11
11
  import { readJsonFileWithFallback } from "openclaw/plugin-sdk/json-store";
@@ -1,14 +1,16 @@
1
1
  import { i as resolveReceiveIdType, r as normalizeFeishuTarget } from "./targets-JMFJRKSe.js";
2
2
  import { c as createFeishuApiError, f as isRecord$2, g as requestFeishuApi, s as resolveFeishuRuntimeAccount } from "./accounts-Ba3-WP1z.js";
3
+ import { i as toFeishuSendResult, r as resolveFeishuReceiptKind, t as assertFeishuMessageApiSuccess } from "./send-result-BVFTskB_.js";
3
4
  import { t as getFeishuRuntime } from "./runtime-CG0DuRCy.js";
4
5
  import { r as createFeishuClient } from "./client-DBVoQL5w.js";
5
6
  import { convertMarkdownTables, normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString } from "openclaw/plugin-sdk/text-runtime";
6
7
  import fs from "node:fs";
7
8
  import path from "node:path";
9
+ import { mediaKindFromMime } from "openclaw/plugin-sdk/media-mime";
8
10
  import { MEDIA_FFMPEG_MAX_AUDIO_DURATION_SECS, runFfmpeg } from "openclaw/plugin-sdk/media-runtime";
11
+ import { readRegularFile, writeExternalFileWithinRoot } from "openclaw/plugin-sdk/security-runtime";
9
12
  import { Readable } from "node:stream";
10
- import { mediaKindFromMime } from "openclaw/plugin-sdk/media-mime";
11
- import { resolvePreferredOpenClawTmpDir, withTempDownloadPath } from "openclaw/plugin-sdk/temp-path";
13
+ import { resolvePreferredOpenClawTmpDir, withTempDownloadPath, withTempWorkspace } from "openclaw/plugin-sdk/temp-path";
12
14
  import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime";
13
15
  //#region extensions/feishu/src/external-keys.ts
14
16
  const CONTROL_CHARS_RE = /\p{Cc}/u;
@@ -22,17 +24,6 @@ function normalizeFeishuExternalKey(value) {
22
24
  return normalized;
23
25
  }
24
26
  //#endregion
25
- //#region extensions/feishu/src/send-result.ts
26
- function assertFeishuMessageApiSuccess(response, errorPrefix) {
27
- if (response.code !== 0) throw new Error(`${errorPrefix}: ${response.msg || `code ${response.code}`}`);
28
- }
29
- function toFeishuSendResult(response, chatId) {
30
- return {
31
- messageId: response.data?.message_id ?? "unknown",
32
- chatId
33
- };
34
- }
35
- //#endregion
36
27
  //#region extensions/feishu/src/send-target.ts
37
28
  function resolveFeishuSendTarget(params) {
38
29
  const target = params.to.trim();
@@ -237,7 +228,7 @@ async function uploadImageFeishu(params) {
237
228
  cfg,
238
229
  accountId
239
230
  });
240
- const imageData = typeof image === "string" ? fs.createReadStream(image) : image;
231
+ const imageData = typeof image === "string" ? (await readRegularFile({ filePath: image })).buffer : image;
241
232
  return { imageKey: extractFeishuUploadKey(await requestFeishuApi(() => client.im.image.create({ data: {
242
233
  image_type: imageType,
243
234
  image: imageData
@@ -269,7 +260,7 @@ async function uploadFileFeishu(params) {
269
260
  cfg,
270
261
  accountId
271
262
  });
272
- const fileData = typeof file === "string" ? fs.createReadStream(file) : file;
263
+ const fileData = typeof file === "string" ? (await readRegularFile({ filePath: file })).buffer : file;
273
264
  const safeFileName = sanitizeFileNameForUpload(fileName);
274
265
  return { fileKey: extractFeishuUploadKey(await requestFeishuApi(() => client.im.file.create({ data: {
275
266
  file_type: fileType,
@@ -302,7 +293,7 @@ async function sendImageFeishu(params) {
302
293
  }
303
294
  }), "Feishu image reply failed", { includeNestedErrorLogId: true });
304
295
  assertFeishuMessageApiSuccess(response, "Feishu image reply failed");
305
- return toFeishuSendResult(response, receiveId);
296
+ return toFeishuSendResult(response, receiveId, "media");
306
297
  }
307
298
  const response = await requestFeishuApi(() => client.im.message.create({
308
299
  params: { receive_id_type: receiveIdType },
@@ -313,7 +304,7 @@ async function sendImageFeishu(params) {
313
304
  }
314
305
  }), "Feishu image send failed", { includeNestedErrorLogId: true });
315
306
  assertFeishuMessageApiSuccess(response, "Feishu image send failed");
316
- return toFeishuSendResult(response, receiveId);
307
+ return toFeishuSendResult(response, receiveId, "media");
317
308
  }
318
309
  /**
319
310
  * Send a file message using a file_key
@@ -337,7 +328,7 @@ async function sendFileFeishu(params) {
337
328
  }
338
329
  }), "Feishu file reply failed", { includeNestedErrorLogId: true });
339
330
  assertFeishuMessageApiSuccess(response, "Feishu file reply failed");
340
- return toFeishuSendResult(response, receiveId);
331
+ return toFeishuSendResult(response, receiveId, resolveFeishuReceiptKind(msgType));
341
332
  }
342
333
  const response = await requestFeishuApi(() => client.im.message.create({
343
334
  params: { receive_id_type: receiveIdType },
@@ -348,7 +339,7 @@ async function sendFileFeishu(params) {
348
339
  }
349
340
  }), "Feishu file send failed", { includeNestedErrorLogId: true });
350
341
  assertFeishuMessageApiSuccess(response, "Feishu file send failed");
351
- return toFeishuSendResult(response, receiveId);
342
+ return toFeishuSendResult(response, receiveId, resolveFeishuReceiptKind(msgType));
352
343
  }
353
344
  /**
354
345
  * Helper to detect file type from extension
@@ -432,51 +423,47 @@ function isLikelyTranscodableAudio(params) {
432
423
  return FEISHU_TRANSCODABLE_AUDIO_EXTS.has(ext) || mediaKindFromMime(contentType) === "audio";
433
424
  }
434
425
  async function transcodeToFeishuVoiceOpus(params) {
435
- const tempRoot = resolvePreferredOpenClawTmpDir();
436
- await fs.promises.mkdir(tempRoot, {
437
- recursive: true,
438
- mode: 448
439
- });
440
- const tempDir = await fs.promises.mkdtemp(path.join(tempRoot, "feishu-voice-"));
441
- try {
426
+ return await withTempWorkspace({
427
+ rootDir: resolvePreferredOpenClawTmpDir(),
428
+ prefix: "feishu-voice-"
429
+ }, async (workspace) => {
442
430
  const ext = normalizeLowercaseStringOrEmpty(path.extname(params.fileName));
443
431
  const inputExt = ext && ext.length <= 12 ? ext : ".audio";
444
- const inputPath = path.join(tempDir, `input${inputExt}`);
445
- const outputPath = path.join(tempDir, FEISHU_VOICE_FILE_NAME);
446
- await fs.promises.writeFile(inputPath, params.buffer, { mode: 384 });
447
- await runFfmpeg([
448
- "-hide_banner",
449
- "-loglevel",
450
- "error",
451
- "-y",
452
- "-i",
453
- inputPath,
454
- "-vn",
455
- "-sn",
456
- "-dn",
457
- "-t",
458
- String(MEDIA_FFMPEG_MAX_AUDIO_DURATION_SECS),
459
- "-ar",
460
- String(FEISHU_VOICE_SAMPLE_RATE_HZ),
461
- "-ac",
462
- "1",
463
- "-c:a",
464
- "libopus",
465
- "-b:a",
466
- FEISHU_VOICE_BITRATE,
467
- outputPath
468
- ]);
432
+ const inputPath = await workspace.write(`input${inputExt}`, params.buffer);
433
+ await writeExternalFileWithinRoot({
434
+ rootDir: workspace.dir,
435
+ path: FEISHU_VOICE_FILE_NAME,
436
+ write: async (outputPath) => {
437
+ await runFfmpeg([
438
+ "-hide_banner",
439
+ "-loglevel",
440
+ "error",
441
+ "-y",
442
+ "-i",
443
+ inputPath,
444
+ "-vn",
445
+ "-sn",
446
+ "-dn",
447
+ "-t",
448
+ String(MEDIA_FFMPEG_MAX_AUDIO_DURATION_SECS),
449
+ "-ar",
450
+ String(FEISHU_VOICE_SAMPLE_RATE_HZ),
451
+ "-ac",
452
+ "1",
453
+ "-c:a",
454
+ "libopus",
455
+ "-b:a",
456
+ FEISHU_VOICE_BITRATE,
457
+ outputPath
458
+ ]);
459
+ }
460
+ });
469
461
  return {
470
- buffer: await fs.promises.readFile(outputPath),
462
+ buffer: await workspace.read(FEISHU_VOICE_FILE_NAME),
471
463
  fileName: FEISHU_VOICE_FILE_NAME,
472
464
  contentType: "audio/ogg"
473
465
  };
474
- } finally {
475
- await fs.promises.rm(tempDir, {
476
- recursive: true,
477
- force: true
478
- });
479
- }
466
+ });
480
467
  }
481
468
  async function prepareFeishuVoiceMedia(params) {
482
469
  if (isFeishuNativeVoiceAudio(params)) return params;
@@ -845,7 +832,7 @@ async function sendFallbackDirect(client, params, errorPrefix) {
845
832
  }
846
833
  }), errorPrefix, { includeNestedErrorLogId: true });
847
834
  assertFeishuMessageApiSuccess(response, errorPrefix);
848
- return toFeishuSendResult(response, params.receiveId);
835
+ return toFeishuSendResult(response, params.receiveId, resolveFeishuReceiptKind(params.msgType));
849
836
  }
850
837
  async function sendReplyOrFallbackDirect(client, params) {
851
838
  if (!params.replyToMessageId) return sendFallbackDirect(client, params.directParams, params.directErrorPrefix);
@@ -870,7 +857,7 @@ async function sendReplyOrFallbackDirect(client, params) {
870
857
  return sendFallbackDirect(client, params.directParams, params.directErrorPrefix);
871
858
  }
872
859
  assertFeishuMessageApiSuccess(response, params.replyErrorPrefix);
873
- return toFeishuSendResult(response, params.directParams.receiveId);
860
+ return toFeishuSendResult(response, params.directParams.receiveId, resolveFeishuReceiptKind(params.msgType));
874
861
  }
875
862
  function normalizeCardTemplateVariable(value) {
876
863
  if (typeof value === "string") return value;
@@ -1215,4 +1202,4 @@ async function sendMarkdownCardFeishu(params) {
1215
1202
  });
1216
1203
  }
1217
1204
  //#endregion
1218
- export { shouldSuppressFeishuTextForVoiceMedia as _, sendCardFeishu as a, sendStructuredCardFeishu as c, extractMentionTargets as d, isFeishuBroadcastMention as f, sendMediaFeishu as g, downloadMessageResourceFeishu as h, resolveFeishuCardTemplate as i, parsePostContent as l, isFeishuGroupChatType as m, getMessageFeishu as n, sendMarkdownCardFeishu as o, isMentionForwardRequest as p, listFeishuThreadMessages as r, sendMessageFeishu as s, editMessageFeishu as t, buildMentionedCardContent as u, normalizeFeishuExternalKey as v };
1205
+ export { normalizeFeishuExternalKey as _, sendCardFeishu as a, sendStructuredCardFeishu as c, isFeishuBroadcastMention as d, isMentionForwardRequest as f, shouldSuppressFeishuTextForVoiceMedia as g, sendMediaFeishu as h, resolveFeishuCardTemplate as i, parsePostContent as l, downloadMessageResourceFeishu as m, getMessageFeishu as n, sendMarkdownCardFeishu as o, isFeishuGroupChatType as p, listFeishuThreadMessages as r, sendMessageFeishu as s, editMessageFeishu as t, extractMentionTargets as u };
@@ -1,4 +1,5 @@
1
1
  import { f as isRecord } from "./accounts-Ba3-WP1z.js";
2
+ import { createMessageReceiptFromOutboundResults } from "openclaw/plugin-sdk/channel-message";
2
3
  //#region extensions/feishu/src/card-interaction.ts
3
4
  const FEISHU_CARD_INTERACTION_VERSION = "ocf1";
4
5
  function isInteractionKind(value) {
@@ -93,4 +94,47 @@ function decodeFeishuCardAction(params) {
93
94
  };
94
95
  }
95
96
  //#endregion
96
- export { decodeFeishuCardAction as i, buildFeishuCardActionTextFallback as n, createFeishuCardInteractionEnvelope as r, FEISHU_CARD_INTERACTION_VERSION as t };
97
+ //#region extensions/feishu/src/send-result.ts
98
+ function resolveFeishuReceiptKind(msgType) {
99
+ switch (msgType) {
100
+ case "audio": return "voice";
101
+ case "image":
102
+ case "media":
103
+ case "file": return "media";
104
+ case "interactive": return "card";
105
+ case "post":
106
+ case "text": return "text";
107
+ default: return "unknown";
108
+ }
109
+ }
110
+ function createFeishuSendReceipt(params) {
111
+ const messageId = params.messageId?.trim();
112
+ const chatId = params.chatId.trim();
113
+ return createMessageReceiptFromOutboundResults({
114
+ results: messageId ? [{
115
+ channel: "feishu",
116
+ messageId,
117
+ chatId,
118
+ conversationId: chatId
119
+ }] : [],
120
+ ...chatId ? { threadId: chatId } : {},
121
+ kind: params.kind ?? "unknown"
122
+ });
123
+ }
124
+ function assertFeishuMessageApiSuccess(response, errorPrefix) {
125
+ if (response.code !== 0) throw new Error(`${errorPrefix}: ${response.msg || `code ${response.code}`}`);
126
+ }
127
+ function toFeishuSendResult(response, chatId, kind) {
128
+ const messageId = response.data?.message_id ?? "unknown";
129
+ return {
130
+ messageId,
131
+ chatId,
132
+ receipt: createFeishuSendReceipt({
133
+ messageId,
134
+ chatId,
135
+ kind
136
+ })
137
+ };
138
+ }
139
+ //#endregion
140
+ export { FEISHU_CARD_INTERACTION_VERSION as a, decodeFeishuCardAction as c, toFeishuSendResult as i, createFeishuSendReceipt as n, buildFeishuCardActionTextFallback as o, resolveFeishuReceiptKind as r, createFeishuCardInteractionEnvelope as s, assertFeishuMessageApiSuccess as t };
package/dist/setup-api.js CHANGED
@@ -1,2 +1,2 @@
1
- import { i as feishuSetupAdapter, n as feishuSetupWizard, t as feishuPlugin } from "./channel-BegH3cJm.js";
1
+ import { i as feishuSetupAdapter, n as feishuSetupWizard, t as feishuPlugin } from "./channel-DCSECj4a.js";
2
2
  export { feishuPlugin, feishuSetupAdapter, feishuSetupWizard };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/feishu",
3
- "version": "2026.5.7",
3
+ "version": "2026.5.10-beta.1",
4
4
  "description": "OpenClaw Feishu/Lark channel plugin (community maintained by @m1heng)",
5
5
  "repository": {
6
6
  "type": "git",
@@ -8,15 +8,15 @@
8
8
  },
9
9
  "type": "module",
10
10
  "dependencies": {
11
- "@larksuiteoapi/node-sdk": "^1.62.1",
12
- "typebox": "1.1.37"
11
+ "@larksuiteoapi/node-sdk": "^1.63.1",
12
+ "typebox": "1.1.38"
13
13
  },
14
14
  "devDependencies": {
15
15
  "@openclaw/plugin-sdk": "workspace:*",
16
16
  "openclaw": "workspace:*"
17
17
  },
18
18
  "peerDependencies": {
19
- "openclaw": ">=2026.5.7"
19
+ "openclaw": ">=2026.5.10-beta.1"
20
20
  },
21
21
  "peerDependenciesMeta": {
22
22
  "openclaw": {
@@ -47,10 +47,10 @@
47
47
  "minHostVersion": ">=2026.4.25"
48
48
  },
49
49
  "compat": {
50
- "pluginApi": ">=2026.5.7"
50
+ "pluginApi": ">=2026.5.10-beta.1"
51
51
  },
52
52
  "build": {
53
- "openclawVersion": "2026.5.7"
53
+ "openclawVersion": "2026.5.10-beta.1"
54
54
  },
55
55
  "release": {
56
56
  "publishToClawHub": true,
@@ -1,118 +0,0 @@
1
- import { t as detectIdType } from "./targets-JMFJRKSe.js";
2
- import { normalizeOptionalLowercaseString } from "openclaw/plugin-sdk/text-runtime";
3
- import { normalizeAccountId, resolveMergedAccountConfig } from "openclaw/plugin-sdk/account-resolution";
4
- import { evaluateSenderGroupAccessForPolicy } from "openclaw/plugin-sdk/group-access";
5
- //#region extensions/feishu/src/policy.ts
6
- const FEISHU_PROVIDER_PREFIX_RE = /^(feishu|lark):/i;
7
- function stripRepeatedFeishuProviderPrefixes(raw) {
8
- let normalized = raw.trim();
9
- while (FEISHU_PROVIDER_PREFIX_RE.test(normalized)) normalized = normalized.replace(FEISHU_PROVIDER_PREFIX_RE, "").trim();
10
- return normalized;
11
- }
12
- function canonicalizeFeishuAllowlistKey(params) {
13
- const value = params.value.trim();
14
- if (!value) return "";
15
- if (value === "*") return "*";
16
- return `${params.kind}:${value}`;
17
- }
18
- function normalizeFeishuAllowEntry(raw) {
19
- const trimmed = raw.trim();
20
- if (!trimmed) return "";
21
- if (trimmed === "*") return "*";
22
- const withoutProviderPrefix = stripRepeatedFeishuProviderPrefixes(trimmed);
23
- if (withoutProviderPrefix === "*") return "*";
24
- const lowered = normalizeOptionalLowercaseString(withoutProviderPrefix) ?? "";
25
- if (!lowered) return "";
26
- if (lowered.startsWith("chat:") || lowered.startsWith("group:") || lowered.startsWith("channel:")) return canonicalizeFeishuAllowlistKey({
27
- kind: "chat",
28
- value: withoutProviderPrefix.slice(withoutProviderPrefix.indexOf(":") + 1)
29
- });
30
- if (lowered.startsWith("user:") || lowered.startsWith("dm:")) return canonicalizeFeishuAllowlistKey({
31
- kind: "user",
32
- value: withoutProviderPrefix.slice(withoutProviderPrefix.indexOf(":") + 1)
33
- });
34
- if (lowered.startsWith("open_id:")) return canonicalizeFeishuAllowlistKey({
35
- kind: "user",
36
- value: withoutProviderPrefix.slice(withoutProviderPrefix.indexOf(":") + 1)
37
- });
38
- const detectedType = detectIdType(withoutProviderPrefix);
39
- if (detectedType === "chat_id") return canonicalizeFeishuAllowlistKey({
40
- kind: "chat",
41
- value: withoutProviderPrefix
42
- });
43
- if (detectedType === "open_id" || detectedType === "user_id") return canonicalizeFeishuAllowlistKey({
44
- kind: "user",
45
- value: withoutProviderPrefix
46
- });
47
- return "";
48
- }
49
- function resolveFeishuAllowlistMatch(params) {
50
- const allowFrom = params.allowFrom.map((entry) => normalizeFeishuAllowEntry(String(entry))).filter(Boolean);
51
- if (allowFrom.length === 0) return { allowed: false };
52
- if (allowFrom.includes("*")) return {
53
- allowed: true,
54
- matchKey: "*",
55
- matchSource: "wildcard"
56
- };
57
- const senderCandidates = [params.senderId, ...params.senderIds ?? []].map((entry) => normalizeFeishuAllowEntry(entry ?? "")).filter(Boolean);
58
- for (const senderId of senderCandidates) if (allowFrom.includes(senderId)) return {
59
- allowed: true,
60
- matchKey: senderId,
61
- matchSource: "id"
62
- };
63
- return { allowed: false };
64
- }
65
- function resolveFeishuGroupConfig(params) {
66
- const groups = params.cfg?.groups ?? {};
67
- const wildcard = groups["*"];
68
- const groupId = params.groupId?.trim();
69
- if (!groupId) return;
70
- const direct = groups[groupId];
71
- if (direct) return direct;
72
- const lowered = normalizeOptionalLowercaseString(groupId) ?? "";
73
- const matchKey = Object.keys(groups).find((key) => normalizeOptionalLowercaseString(key) === lowered);
74
- if (matchKey) return groups[matchKey];
75
- return wildcard;
76
- }
77
- function hasExplicitFeishuGroupConfig(params) {
78
- const groups = params.cfg?.groups ?? {};
79
- const groupId = params.groupId?.trim();
80
- if (!groupId) return false;
81
- if (Object.prototype.hasOwnProperty.call(groups, groupId) && groupId !== "*") return true;
82
- const lowered = normalizeOptionalLowercaseString(groupId) ?? "";
83
- return Object.keys(groups).some((key) => key !== "*" && normalizeOptionalLowercaseString(key) === lowered);
84
- }
85
- function resolveFeishuGroupToolPolicy(params) {
86
- const cfg = params.cfg.channels?.feishu;
87
- if (!cfg) return;
88
- return resolveFeishuGroupConfig({
89
- cfg,
90
- groupId: params.groupId
91
- })?.tools;
92
- }
93
- function isFeishuGroupAllowed(params) {
94
- return evaluateSenderGroupAccessForPolicy({
95
- groupPolicy: params.groupPolicy === "allowall" ? "open" : params.groupPolicy,
96
- groupAllowFrom: params.allowFrom.map((entry) => String(entry)),
97
- senderId: params.senderId,
98
- isSenderAllowed: () => resolveFeishuAllowlistMatch(params).allowed
99
- }).allowed;
100
- }
101
- function resolveFeishuReplyPolicy(params) {
102
- if (params.isDirectMessage) return { requireMention: false };
103
- const feishuCfg = params.cfg.channels?.feishu;
104
- const resolvedCfg = resolveMergedAccountConfig({
105
- channelConfig: feishuCfg,
106
- accounts: feishuCfg?.accounts,
107
- accountId: normalizeAccountId(params.accountId),
108
- normalizeAccountId,
109
- omitKeys: ["defaultAccount"]
110
- });
111
- const groupRequireMention = resolveFeishuGroupConfig({
112
- cfg: resolvedCfg,
113
- groupId: params.groupId
114
- })?.requireMention;
115
- return { requireMention: typeof groupRequireMention === "boolean" ? groupRequireMention : typeof resolvedCfg.requireMention === "boolean" ? resolvedCfg.requireMention : params.groupPolicy !== "open" };
116
- }
117
- //#endregion
118
- export { resolveFeishuGroupToolPolicy as a, resolveFeishuGroupConfig as i, isFeishuGroupAllowed as n, resolveFeishuReplyPolicy as o, resolveFeishuAllowlistMatch as r, hasExplicitFeishuGroupConfig as t };