@openclaw/feishu 2026.7.2-beta.4 → 2026.7.2-beta.5

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/README.md CHANGED
@@ -5,7 +5,7 @@ Official OpenClaw channel plugin for Feishu and Lark workplace chats. Community
5
5
  Install from OpenClaw:
6
6
 
7
7
  ```bash
8
- openclaw plugin add @openclaw/feishu
8
+ openclaw plugins install @openclaw/feishu
9
9
  ```
10
10
 
11
11
  Configure the Feishu/Lark app credentials in OpenClaw, then connect the plugin to the chats where agents should receive and send messages.
@@ -372,13 +372,6 @@ function resolveDefaultFeishuAccountSelection(cfg) {
372
372
  function resolveDefaultFeishuAccountId(cfg) {
373
373
  return resolveDefaultAccountId(cfg);
374
374
  }
375
- function resolveRawFeishuAccountConfig(accounts, accountId) {
376
- if (!accounts || typeof accounts !== "object") return;
377
- if (Object.hasOwn(accounts, accountId)) return accounts[accountId];
378
- const normalized = accountId.toLowerCase();
379
- const matchKey = Object.keys(accounts).find((key) => key.toLowerCase() === normalized);
380
- return matchKey ? accounts[matchKey] : void 0;
381
- }
382
375
  /**
383
376
  * Merge top-level config with account-specific config.
384
377
  * Account-specific fields override top-level fields.
@@ -386,7 +379,6 @@ function resolveRawFeishuAccountConfig(accounts, accountId) {
386
379
  function mergeFeishuAccountConfig(cfg, accountId) {
387
380
  const feishuCfg = cfg.channels?.feishu;
388
381
  const accounts = feishuCfg?.accounts;
389
- const accountTools = resolveRawFeishuAccountConfig(accounts, accountId)?.tools;
390
382
  const merged = resolveMergedAccountConfig({
391
383
  channelConfig: feishuCfg,
392
384
  accounts,
@@ -399,20 +391,11 @@ function mergeFeishuAccountConfig(cfg, accountId) {
399
391
  ...merged,
400
392
  tools: topTools
401
393
  };
402
- if (topTools?.bitable === false || topTools?.bitable === void 0 && topTools?.base === false) return {
403
- ...merged,
404
- tools: {
405
- ...merged.tools,
406
- bitable: false,
407
- base: false
408
- }
409
- };
410
- if (accountTools?.bitable === void 0 && accountTools?.base !== void 0) return {
394
+ if (topTools?.bitable === false) return {
411
395
  ...merged,
412
396
  tools: {
413
397
  ...merged.tools,
414
- bitable: accountTools.base,
415
- base: accountTools.base
398
+ bitable: false
416
399
  }
417
400
  };
418
401
  return merged;
package/dist/api.js CHANGED
@@ -1,12 +1,12 @@
1
- import { r as listEnabledFeishuAccounts } from "./accounts-BDoGHJDk.js";
2
- import { a as setFeishuNamedAccountEnabled, i as feishuSetupAdapter, n as feishuSetupWizard, r as runFeishuLogin, t as feishuPlugin } from "./channel-DB1x6UJX.js";
3
- import { p as parseFeishuMarkdown, u as chunkFeishuMarkdown } from "./send-result-DfE5Fhz6.js";
1
+ import { r as listEnabledFeishuAccounts } from "./accounts-CKhCa76b.js";
2
+ import { a as setFeishuNamedAccountEnabled, i as feishuSetupAdapter, n as feishuSetupWizard, r as runFeishuLogin, t as feishuPlugin } from "./channel-CBNICmK9.js";
3
+ import { p as parseFeishuMarkdown, u as chunkFeishuMarkdown } from "./send-result-Bcofg0Vv.js";
4
4
  import { a as parseFeishuTargetId, i as parseFeishuDirectConversationId, n as buildFeishuModelOverrideParentCandidates, r as parseFeishuConversationId, t as buildFeishuConversationId } from "./conversation-id-BeJL-wq7.js";
5
5
  import { r as createFeishuClient, s as resolveConfiguredHttpTimeoutMs } from "./client-Dee7cKsS.js";
6
6
  import { t as getFeishuRuntime } from "./runtime-C5JxBWZp.js";
7
- import { a as toolExecutionErrorResult, f as registerFeishuChatTools, g as resolveToolsConfig, h as resolveFeishuToolAccount, m as resolveAnyEnabledFeishuToolsConfig, n as registerFeishuDriveTools, o as unknownToolActionResult, p as createFeishuToolClient } from "./drive-_zrcOxzS.js";
8
- import { n as getFeishuThreadBindingManager, r as testing, t as createFeishuThreadBindingManager } from "./thread-bindings-V0bwk0A1.js";
9
- import { n as handleFeishuSubagentEnded, r as handleFeishuSubagentSpawning, t as handleFeishuSubagentDeliveryTarget } from "./subagent-hooks-BKTOxB-T.js";
7
+ import { a as toolExecutionErrorResult, f as registerFeishuChatTools, g as resolveToolsConfig, h as resolveFeishuToolAccount, m as resolveAnyEnabledFeishuToolsConfig, n as registerFeishuDriveTools, o as unknownToolActionResult, p as createFeishuToolClient } from "./drive-DG6pKTPE.js";
8
+ import { n as getFeishuThreadBindingManager, r as testing, t as createFeishuThreadBindingManager } from "./thread-bindings-Dqs_A0du.js";
9
+ import { n as handleFeishuSubagentEnded, r as handleFeishuSubagentSpawning, t as handleFeishuSubagentDeliveryTarget } from "./subagent-hooks-DL2SC5zX.js";
10
10
  import { optionalPositiveIntegerSchema } from "openclaw/plugin-sdk/channel-actions";
11
11
  import { normalizeLowercaseStringOrEmpty, normalizeOptionalString, readStringValue, uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
12
12
  import { existsSync } from "node:fs";
@@ -1085,6 +1085,27 @@ async function processImages(client, docToken, images, insertedBlocks, maxBytes,
1085
1085
  }
1086
1086
  return processed;
1087
1087
  }
1088
+ async function convertInsertAndProcessDocx(params) {
1089
+ const { client, docToken, logger, target } = params;
1090
+ logger?.info?.("feishu_doc: Converting markdown...");
1091
+ const { blocks, firstLevelBlockIds, images } = await chunkedConvertMarkdown(client, createDocxMarkdownPlan(params.markdown).chunks);
1092
+ await params.onConverted(blocks.length);
1093
+ if (blocks.length === 0) return {
1094
+ blocks,
1095
+ inserted: [],
1096
+ imagesProcessed: 0
1097
+ };
1098
+ const { orderedBlocks, rootIds } = normalizeConvertedBlockTree(blocks, firstLevelBlockIds);
1099
+ logger?.info?.(`feishu_doc: Converted to ${blocks.length} blocks, inserting${target ? ` at index ${target.index}` : ""}...`);
1100
+ const { children: inserted } = blocks.length > 1e3 ? await insertBlocksInBatches(client, docToken, orderedBlocks, rootIds, logger, target?.parentBlockId, target?.index) : await insertBlocksWithDescendant(client, docToken, orderedBlocks, rootIds, target);
1101
+ const imagesProcessed = await processImages(client, docToken, images, inserted, params.maxBytes, params.imageReadTimeoutMs);
1102
+ logger?.info?.(`feishu_doc: Done (${blocks.length} blocks, ${imagesProcessed} images)`);
1103
+ return {
1104
+ blocks,
1105
+ inserted,
1106
+ imagesProcessed
1107
+ };
1108
+ }
1088
1109
  async function uploadImageBlock(client, docToken, maxBytes, imageReadTimeoutMs, localRoots, url, filePath, parentBlockId, filename, index, imageInput) {
1089
1110
  const upload = await resolveDocxUploadInput({
1090
1111
  url,
@@ -1263,21 +1284,18 @@ async function createDoc(client, title, folderToken, options) {
1263
1284
  };
1264
1285
  }
1265
1286
  async function writeDoc(client, docToken, markdown, maxBytes, imageReadTimeoutMs, logger) {
1266
- const markdownPlan = createDocxMarkdownPlan(markdown);
1267
- logger?.info?.("feishu_doc: Converting markdown...");
1268
- const { blocks, firstLevelBlockIds, images } = await chunkedConvertMarkdown(client, markdownPlan.chunks);
1269
- const deleted = await clearDocumentContent(client, docToken);
1270
- if (blocks.length === 0) return {
1271
- success: true,
1272
- blocks_deleted: deleted,
1273
- blocks_added: 0,
1274
- images_processed: 0
1275
- };
1276
- logger?.info?.(`feishu_doc: Converted to ${blocks.length} blocks, inserting...`);
1277
- const { orderedBlocks, rootIds } = normalizeConvertedBlockTree(blocks, firstLevelBlockIds);
1278
- const { children: inserted } = blocks.length > 1e3 ? await insertBlocksInBatches(client, docToken, orderedBlocks, rootIds, logger) : await insertBlocksWithDescendant(client, docToken, orderedBlocks, rootIds);
1279
- const imagesProcessed = await processImages(client, docToken, images, inserted, maxBytes, imageReadTimeoutMs);
1280
- logger?.info?.(`feishu_doc: Done (${blocks.length} blocks, ${imagesProcessed} images)`);
1287
+ let deleted = 0;
1288
+ const { blocks, imagesProcessed } = await convertInsertAndProcessDocx({
1289
+ client,
1290
+ docToken,
1291
+ markdown,
1292
+ maxBytes,
1293
+ imageReadTimeoutMs,
1294
+ logger,
1295
+ onConverted: async () => {
1296
+ deleted = await clearDocumentContent(client, docToken);
1297
+ }
1298
+ });
1281
1299
  return {
1282
1300
  success: true,
1283
1301
  blocks_deleted: deleted,
@@ -1286,15 +1304,17 @@ async function writeDoc(client, docToken, markdown, maxBytes, imageReadTimeoutMs
1286
1304
  };
1287
1305
  }
1288
1306
  async function appendDoc(client, docToken, markdown, maxBytes, imageReadTimeoutMs, logger) {
1289
- const markdownPlan = createDocxMarkdownPlan(markdown);
1290
- logger?.info?.("feishu_doc: Converting markdown...");
1291
- const { blocks, firstLevelBlockIds, images } = await chunkedConvertMarkdown(client, markdownPlan.chunks);
1292
- if (blocks.length === 0) throw new Error("Content is empty");
1293
- logger?.info?.(`feishu_doc: Converted to ${blocks.length} blocks, inserting...`);
1294
- const { orderedBlocks, rootIds } = normalizeConvertedBlockTree(blocks, firstLevelBlockIds);
1295
- const { children: inserted } = blocks.length > 1e3 ? await insertBlocksInBatches(client, docToken, orderedBlocks, rootIds, logger) : await insertBlocksWithDescendant(client, docToken, orderedBlocks, rootIds);
1296
- const imagesProcessed = await processImages(client, docToken, images, inserted, maxBytes, imageReadTimeoutMs);
1297
- logger?.info?.(`feishu_doc: Done (${blocks.length} blocks, ${imagesProcessed} images)`);
1307
+ const { blocks, inserted, imagesProcessed } = await convertInsertAndProcessDocx({
1308
+ client,
1309
+ docToken,
1310
+ markdown,
1311
+ maxBytes,
1312
+ imageReadTimeoutMs,
1313
+ logger,
1314
+ onConverted: (blockCount) => {
1315
+ if (blockCount === 0) throw new Error("Content is empty");
1316
+ }
1317
+ });
1298
1318
  return {
1299
1319
  success: true,
1300
1320
  blocks_added: blocks.length,
@@ -1303,7 +1323,6 @@ async function appendDoc(client, docToken, markdown, maxBytes, imageReadTimeoutM
1303
1323
  };
1304
1324
  }
1305
1325
  async function insertDoc(client, docToken, markdown, afterBlockId, maxBytes, imageReadTimeoutMs, logger) {
1306
- const markdownPlan = createDocxMarkdownPlan(markdown);
1307
1326
  const blockInfo = await client.docx.documentBlock.get({ path: {
1308
1327
  document_id: docToken,
1309
1328
  block_id: afterBlockId
@@ -1326,18 +1345,21 @@ async function insertDoc(client, docToken, markdown, afterBlockId, maxBytes, ima
1326
1345
  } while (pageToken);
1327
1346
  const blockIndex = items.findIndex((item) => item.block_id === afterBlockId);
1328
1347
  if (blockIndex === -1) throw new Error(`after_block_id "${afterBlockId}" was not found among the children of parent block "${parentId}". Use list_blocks to verify the block ID.`);
1329
- const insertIndex = blockIndex + 1;
1330
- logger?.info?.("feishu_doc: Converting markdown...");
1331
- const { blocks, firstLevelBlockIds, images } = await chunkedConvertMarkdown(client, markdownPlan.chunks);
1332
- if (blocks.length === 0) throw new Error("Content is empty");
1333
- const { orderedBlocks, rootIds } = normalizeConvertedBlockTree(blocks, firstLevelBlockIds);
1334
- logger?.info?.(`feishu_doc: Converted to ${blocks.length} blocks, inserting at index ${insertIndex}...`);
1335
- const { children: inserted } = blocks.length > 1e3 ? await insertBlocksInBatches(client, docToken, orderedBlocks, rootIds, logger, parentId, insertIndex) : await insertBlocksWithDescendant(client, docToken, orderedBlocks, rootIds, {
1336
- parentBlockId: parentId,
1337
- index: insertIndex
1348
+ const { blocks, inserted, imagesProcessed } = await convertInsertAndProcessDocx({
1349
+ client,
1350
+ docToken,
1351
+ markdown,
1352
+ maxBytes,
1353
+ imageReadTimeoutMs,
1354
+ logger,
1355
+ target: {
1356
+ parentBlockId: parentId,
1357
+ index: blockIndex + 1
1358
+ },
1359
+ onConverted: (blockCount) => {
1360
+ if (blockCount === 0) throw new Error("Content is empty");
1361
+ }
1338
1362
  });
1339
- const imagesProcessed = await processImages(client, docToken, images, inserted, maxBytes, imageReadTimeoutMs);
1340
- logger?.info?.(`feishu_doc: Done (${blocks.length} blocks, ${imagesProcessed} images)`);
1341
1363
  return {
1342
1364
  success: true,
1343
1365
  blocks_added: blocks.length,
@@ -1,11 +1,11 @@
1
- import { a as resolveDefaultFeishuAccountId, d as isRecord$1, i as listFeishuAccountIds, n as inspectFeishuCredentials, o as resolveFeishuAccount, r as listEnabledFeishuAccounts, s as resolveFeishuRuntimeAccount } from "./accounts-BDoGHJDk.js";
1
+ import { a as resolveDefaultFeishuAccountId, d as isRecord$1, i as listFeishuAccountIds, n as inspectFeishuCredentials, o as resolveFeishuAccount, r as listEnabledFeishuAccounts, s as resolveFeishuRuntimeAccount } from "./accounts-CKhCa76b.js";
2
2
  import { i as resolveReceiveIdType, n as looksLikeFeishuId, r as normalizeFeishuTarget } from "./targets-BUjQ1TcA.js";
3
- import { A as resolveFeishuChatType, D as resolveFeishuGroupToolPolicy, N as createFeishuCardInteractionEnvelope, _ as canEnumerateAllFeishuPeers, a as readNativeFeishuCardJson, b as resolveFeishuChatReadPreliminaryAuthorization, g as canEnumerateAllFeishuGroups, h as authorizeFeishuChatMemberRead, k as normalizeFeishuChatType, m as assertFeishuChatReadAllowed, n as createFeishuSendReceipt, u as chunkFeishuMarkdown, v as isFeishuGroupReadAllowed, w as resolveFeishuGroupConfig, y as isFeishuGroupReadEnabled } from "./send-result-DfE5Fhz6.js";
3
+ import { A as resolveFeishuChatType, D as resolveFeishuGroupToolPolicy, N as createFeishuCardInteractionEnvelope, _ as canEnumerateAllFeishuPeers, a as readNativeFeishuCardJson, b as resolveFeishuChatReadPreliminaryAuthorization, g as canEnumerateAllFeishuGroups, h as authorizeFeishuChatMemberRead, k as normalizeFeishuChatType, m as assertFeishuChatReadAllowed, n as createFeishuSendReceipt, u as chunkFeishuMarkdown, v as isFeishuGroupReadAllowed, w as resolveFeishuGroupConfig, y as isFeishuGroupReadEnabled } from "./send-result-Bcofg0Vv.js";
4
4
  import { a as parseFeishuTargetId, i as parseFeishuDirectConversationId, n as buildFeishuModelOverrideParentCandidates, o as resolveConfiguredFeishuGroupSessionScope, r as parseFeishuConversationId, t as buildFeishuConversationId } from "./conversation-id-BeJL-wq7.js";
5
- import { n as normalizeCompatibilityConfig, t as legacyConfigRules } from "./doctor-contract-Cw5sdjOm.js";
6
- import { t as messageActionTargetAliases } from "./security-audit-BIeA3W3Q.js";
5
+ import { n as normalizeCompatibilityConfig, t as legacyConfigRules } from "./doctor-contract-BiD9tyIv.js";
6
+ import { t as messageActionTargetAliases } from "./security-audit-D7WK_BHh.js";
7
7
  import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./secret-contract-BCpDLdg9.js";
8
- import { t as collectFeishuSecurityAuditFindings } from "./security-audit-shared-BIHeF-S_.js";
8
+ import { t as collectFeishuSecurityAuditFindings } from "./security-audit-shared-BgpY7AiJ.js";
9
9
  import { t as resolveFeishuSessionConversation } from "./session-conversation-BksWrfzm.js";
10
10
  import { createLazyRuntimeModule, createLazyRuntimeNamedExport } from "openclaw/plugin-sdk/lazy-runtime";
11
11
  import { describeAccountSnapshot } from "openclaw/plugin-sdk/account-helpers";
@@ -38,6 +38,7 @@ import { deleteSessionEntry, isValidAgentHarnessSessionStoreEntry, listSessionEn
38
38
  import { resolveStateDir } from "openclaw/plugin-sdk/state-paths";
39
39
  import { defineChannelSetupContract } from "openclaw/plugin-sdk/channel-setup";
40
40
  import { DEFAULT_ACCOUNT_ID as DEFAULT_ACCOUNT_ID$2, createSetupTranslator, formatDocsLink, hasConfiguredSecretInput as hasConfiguredSecretInput$1, mergeAllowFromEntries, patchTopLevelChannelConfigSection, promptSingleChannelSecretInput, setSetupChannelEnabled, splitSetupEntries } from "openclaw/plugin-sdk/setup";
41
+ import { createChannelDmPolicy } from "openclaw/plugin-sdk/channel-dm-policy";
41
42
  //#region extensions/feishu/src/approval-auth.ts
42
43
  function normalizeFeishuApproverId(value) {
43
44
  const trimmed = normalizeOptionalLowercaseString(normalizeFeishuTarget(String(value)));
@@ -145,8 +146,7 @@ const FeishuToolsConfigSchema = z.object({
145
146
  drive: z.boolean().optional(),
146
147
  perm: z.boolean().optional(),
147
148
  scopes: z.boolean().optional(),
148
- bitable: z.boolean().optional(),
149
- base: z.boolean().optional()
149
+ bitable: z.boolean().optional()
150
150
  }).strict().optional();
151
151
  /**
152
152
  * Group session scope for routing Feishu group messages.
@@ -1198,7 +1198,7 @@ function resolveFeishuOutboundSessionRoute(params) {
1198
1198
  }
1199
1199
  //#endregion
1200
1200
  //#region extensions/feishu/src/setup-core.ts
1201
- function setFeishuNamedAccountEnabled$1(cfg, accountId, enabled) {
1201
+ function setFeishuNamedAccountEnabled(cfg, accountId, enabled) {
1202
1202
  const feishuCfg = cfg.channels?.feishu;
1203
1203
  return {
1204
1204
  ...cfg,
@@ -1230,7 +1230,7 @@ const feishuSetupAdapter = {
1230
1230
  }
1231
1231
  }
1232
1232
  };
1233
- return setFeishuNamedAccountEnabled$1(cfg, accountId, true);
1233
+ return setFeishuNamedAccountEnabled(cfg, accountId, true);
1234
1234
  }
1235
1235
  };
1236
1236
  const feishuSetupContract = defineChannelSetupContract({
@@ -1333,38 +1333,25 @@ async function promptFeishuAppId(params) {
1333
1333
  validate: (value) => value?.trim() ? void 0 : t("common.required")
1334
1334
  })).trim();
1335
1335
  }
1336
- const feishuDmPolicy = {
1336
+ const feishuDmPolicy = createChannelDmPolicy({
1337
1337
  label: "Feishu",
1338
1338
  channel,
1339
- policyKey: "channels.feishu.dmPolicy",
1340
- allowFromKey: "channels.feishu.allowFrom",
1341
- resolveConfigKeys: (_cfg, accountId) => {
1342
- const resolvedAccountId = accountId ?? resolveDefaultFeishuAccountId(_cfg);
1343
- return resolvedAccountId !== DEFAULT_ACCOUNT_ID$2 ? {
1344
- policyKey: `channels.feishu.accounts.${resolvedAccountId}.dmPolicy`,
1345
- allowFromKey: `channels.feishu.accounts.${resolvedAccountId}.allowFrom`
1346
- } : {
1347
- policyKey: "channels.feishu.dmPolicy",
1348
- allowFromKey: "channels.feishu.allowFrom"
1349
- };
1350
- },
1351
- getCurrent: (cfg, accountId) => {
1339
+ resolveAccount: (cfg, accountId) => {
1352
1340
  const feishuCfg = cfg.channels?.feishu;
1353
1341
  const resolvedAccountId = accountId ?? resolveDefaultFeishuAccountId(cfg);
1354
- if (resolvedAccountId !== DEFAULT_ACCOUNT_ID$2) {
1355
- const account = feishuCfg?.accounts?.[resolvedAccountId];
1356
- if (account?.dmPolicy) return account.dmPolicy;
1357
- }
1358
- return feishuCfg?.dmPolicy ?? "pairing";
1359
- },
1360
- setPolicy: (cfg, policy, accountId) => {
1361
- return patchFeishuConfig(cfg, accountId ?? resolveDefaultFeishuAccountId(cfg), {
1362
- dmPolicy: policy,
1363
- ...policy === "open" ? { allowFrom: mergeAllowFromEntries([], ["*"]) } : {}
1364
- });
1342
+ const account = resolvedAccountId === DEFAULT_ACCOUNT_ID$2 ? void 0 : feishuCfg?.accounts?.[resolvedAccountId];
1343
+ return {
1344
+ accountId: resolvedAccountId,
1345
+ config: {
1346
+ dmPolicy: account?.dmPolicy ?? feishuCfg?.dmPolicy,
1347
+ allowFrom: account?.allowFrom ?? feishuCfg?.allowFrom
1348
+ }
1349
+ };
1365
1350
  },
1351
+ resolveAllowFrom: ({ policy }) => policy === "open" ? ["*"] : void 0,
1352
+ applyPatch: ({ cfg, account, patch }) => patchFeishuConfig(cfg, account.accountId, patch),
1366
1353
  promptAllowFrom: promptFeishuAllowFrom
1367
- };
1354
+ });
1368
1355
  function applyNewAppSecurityPolicy(cfg, accountId, openId, groupPolicy) {
1369
1356
  let next = cfg;
1370
1357
  if (openId) next = patchFeishuConfig(next, accountId, {
@@ -1673,7 +1660,7 @@ const meta = {
1673
1660
  order: 70,
1674
1661
  preferSessionLookupForAnnounceTarget: true
1675
1662
  };
1676
- const loadFeishuChannelRuntime = createLazyRuntimeNamedExport(() => import("./channel.runtime-B5yAAvbT.js"), "feishuChannelRuntime");
1663
+ const loadFeishuChannelRuntime = createLazyRuntimeNamedExport(() => import("./channel.runtime-CSlJVqy4.js"), "feishuChannelRuntime");
1677
1664
  function toFeishuMessageSendResult(result, kind) {
1678
1665
  const receipt = result.receipt ?? createFeishuSendReceipt({
1679
1666
  messageId: result.messageId,
@@ -1781,25 +1768,6 @@ function describeFeishuMessageTool({ cfg, accountId }) {
1781
1768
  capabilities: enabled ? ["presentation"] : []
1782
1769
  };
1783
1770
  }
1784
- function setFeishuNamedAccountEnabled(cfg, accountId, enabled) {
1785
- const feishuCfg = cfg.channels?.feishu;
1786
- return {
1787
- ...cfg,
1788
- channels: {
1789
- ...cfg.channels,
1790
- feishu: {
1791
- ...feishuCfg,
1792
- accounts: {
1793
- ...feishuCfg?.accounts,
1794
- [accountId]: {
1795
- ...feishuCfg?.accounts?.[accountId],
1796
- enabled
1797
- }
1798
- }
1799
- }
1800
- }
1801
- };
1802
- }
1803
1771
  const feishuConfigAdapter = createHybridChannelConfigAdapter({
1804
1772
  sectionKey: "feishu",
1805
1773
  listAccountIds: listFeishuAccountIds,
@@ -2155,19 +2123,6 @@ const feishuPlugin = createChatChannelPlugin({
2155
2123
  configSchema: FeishuChannelConfigSchema,
2156
2124
  config: {
2157
2125
  ...feishuConfigAdapter,
2158
- setAccountEnabled: ({ cfg, accountId, enabled }) => {
2159
- if (accountId === DEFAULT_ACCOUNT_ID$3) return {
2160
- ...cfg,
2161
- channels: {
2162
- ...cfg.channels,
2163
- feishu: {
2164
- ...cfg.channels?.feishu,
2165
- enabled
2166
- }
2167
- }
2168
- };
2169
- return setFeishuNamedAccountEnabled(cfg, accountId, enabled);
2170
- },
2171
2126
  deleteAccount: ({ cfg, accountId }) => {
2172
2127
  if (accountId === DEFAULT_ACCOUNT_ID$3) {
2173
2128
  const next = { ...cfg };
@@ -2764,7 +2719,7 @@ const feishuPlugin = createChatChannelPlugin({
2764
2719
  })
2765
2720
  }),
2766
2721
  gateway: { startAccount: async (ctx) => {
2767
- const { monitorFeishuProvider } = await import("./monitor-8CLu6myv.js");
2722
+ const { monitorFeishuProvider } = await import("./monitor-DEHJlyWW.js");
2768
2723
  const account = resolveFeishuRuntimeAccount({
2769
2724
  cfg: ctx.cfg,
2770
2725
  accountId: ctx.accountId
@@ -2858,4 +2813,4 @@ const feishuPlugin = createChatChannelPlugin({
2858
2813
  }
2859
2814
  });
2860
2815
  //#endregion
2861
- export { setFeishuNamedAccountEnabled$1 as a, isFeishuCardWithinEnvelope as c, feishuSetupAdapter as i, listFeishuDirectoryGroups as l, feishuSetupWizard as n, assertFeishuCardWithinEnvelope as o, runFeishuLogin as r, buildFeishuPresentationCardElements as s, feishuPlugin as t, listFeishuDirectoryPeers as u };
2816
+ export { setFeishuNamedAccountEnabled as a, isFeishuCardWithinEnvelope as c, feishuSetupAdapter as i, listFeishuDirectoryGroups as l, feishuSetupWizard as n, assertFeishuCardWithinEnvelope as o, runFeishuLogin as r, buildFeishuPresentationCardElements as s, feishuPlugin as t, listFeishuDirectoryPeers as u };
@@ -1,2 +1,2 @@
1
- import { t as feishuPlugin } from "./channel-DB1x6UJX.js";
1
+ import { t as feishuPlugin } from "./channel-CBNICmK9.js";
2
2
  export { feishuPlugin };
@@ -1,9 +1,9 @@
1
- import { o as resolveFeishuAccount, s as resolveFeishuRuntimeAccount, v as parseFeishuCommentTarget } from "./accounts-BDoGHJDk.js";
2
- import { c as isFeishuCardWithinEnvelope, l as listFeishuDirectoryGroups, o as assertFeishuCardWithinEnvelope, s as buildFeishuPresentationCardElements, u as listFeishuDirectoryPeers } from "./channel-DB1x6UJX.js";
3
- import { a as readNativeFeishuCardJson, d as chunkFeishuPostMarkdown, f as materializeFeishuPostMarkdownSoftBreaks, o as resolveFeishuCardTemplate, s as sanitizeNativeFeishuCard, u as chunkFeishuMarkdown } from "./send-result-DfE5Fhz6.js";
1
+ import { o as resolveFeishuAccount, s as resolveFeishuRuntimeAccount, v as parseFeishuCommentTarget } from "./accounts-CKhCa76b.js";
2
+ import { c as isFeishuCardWithinEnvelope, l as listFeishuDirectoryGroups, o as assertFeishuCardWithinEnvelope, s as buildFeishuPresentationCardElements, u as listFeishuDirectoryPeers } from "./channel-CBNICmK9.js";
3
+ import { a as readNativeFeishuCardJson, d as chunkFeishuPostMarkdown, f as materializeFeishuPostMarkdownSoftBreaks, o as resolveFeishuCardTemplate, s as sanitizeNativeFeishuCard, u as chunkFeishuMarkdown } from "./send-result-Bcofg0Vv.js";
4
4
  import { r as createFeishuClient } from "./client-Dee7cKsS.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-_zrcOxzS.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-CRJunSRr.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-DG6pKTPE.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-DOwcLJ1j.js";
7
7
  import { t as probeFeishu } from "./probe-Za1kgUvx.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";
@@ -1,4 +1,4 @@
1
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-BIeA3W3Q.js";
3
- import { t as collectFeishuSecurityAuditFindings } from "./security-audit-shared-BIHeF-S_.js";
2
+ import { t as messageActionTargetAliases } from "./security-audit-D7WK_BHh.js";
3
+ import { t as collectFeishuSecurityAuditFindings } from "./security-audit-shared-BgpY7AiJ.js";
4
4
  export { buildFeishuConversationId, collectFeishuSecurityAuditFindings, messageActionTargetAliases, parseFeishuConversationId, parseFeishuDirectConversationId, parseFeishuTargetId };
@@ -1,4 +1,4 @@
1
- import { asObjectRecord, defineChannelAliasMigration, normalizeChannelConfigEntries } from "openclaw/plugin-sdk/runtime-doctor";
1
+ import { asObjectRecord, defineChannelAliasMigration, defineKeyMoveMigration, hasLegacyAccountStreamingAliases, normalizeChannelConfigEntries } from "openclaw/plugin-sdk/runtime-doctor";
2
2
  //#region extensions/feishu/src/doctor-contract.ts
3
3
  const streamingAliasMigration = defineChannelAliasMigration({
4
4
  channelId: "feishu",
@@ -11,6 +11,12 @@ const LEGACY_COALESCE_FIELDS = [
11
11
  "maxDelayMs"
12
12
  ];
13
13
  const LEGACY_HEARTBEAT_FIELDS = ["visibility", "intervalMs"];
14
+ const toolsBaseMigration = defineKeyMoveMigration({
15
+ from: ["tools", "base"],
16
+ to: ["tools", "bitable"],
17
+ match: (value) => typeof value === "boolean",
18
+ sourceOwn: false
19
+ });
14
20
  function sanitizeLegacyHeartbeatFields(params) {
15
21
  const heartbeat = asObjectRecord(params.entry.heartbeat);
16
22
  if (!heartbeat || Object.keys(heartbeat).length > 0 && !LEGACY_HEARTBEAT_FIELDS.some((field) => Object.hasOwn(heartbeat, field))) return {
@@ -61,19 +67,30 @@ function sanitizeFeishuCoalesce(cfg, changes) {
61
67
  channelId: "feishu",
62
68
  changes,
63
69
  normalizeEntry: (params) => {
64
- const coalesce = sanitizeLegacyCoalesceFields(params);
70
+ const tools = toolsBaseMigration.normalize(params);
71
+ const coalesce = sanitizeLegacyCoalesceFields({
72
+ ...params,
73
+ entry: tools.entry
74
+ });
65
75
  const heartbeat = sanitizeLegacyHeartbeatFields({
66
76
  ...params,
67
77
  entry: coalesce.entry
68
78
  });
69
79
  return {
70
80
  entry: heartbeat.entry,
71
- changed: coalesce.changed || heartbeat.changed
81
+ changed: tools.changed || coalesce.changed || heartbeat.changed
72
82
  };
73
83
  }
74
84
  }).config;
75
85
  }
76
- const legacyConfigRules = streamingAliasMigration.legacyConfigRules;
86
+ const legacyConfigRules = [...streamingAliasMigration.legacyConfigRules, {
87
+ path: ["channels", "feishu"],
88
+ message: "channels.feishu[.accounts.<id>].tools.base is legacy; use tools.bitable. Run \"openclaw doctor --fix\".",
89
+ match: (value) => {
90
+ const entry = asObjectRecord(value);
91
+ return toolsBaseMigration.hasLegacy(entry) || hasLegacyAccountStreamingAliases(entry?.accounts, toolsBaseMigration.hasLegacy);
92
+ }
93
+ }];
77
94
  function normalizeCompatibilityConfig({ cfg }) {
78
95
  const aliases = streamingAliasMigration.normalizeChannelConfig({ cfg });
79
96
  return {
@@ -1,2 +1,2 @@
1
- import { n as normalizeCompatibilityConfig, t as legacyConfigRules } from "./doctor-contract-Cw5sdjOm.js";
1
+ import { n as normalizeCompatibilityConfig, t as legacyConfigRules } from "./doctor-contract-BiD9tyIv.js";
2
2
  export { legacyConfigRules, normalizeCompatibilityConfig };
@@ -1,8 +1,9 @@
1
- import { c as encodeQuery, d as isRecord$1, i as listFeishuAccountIds, l as extractReplyText, m as readString, o as resolveFeishuAccount, r as listEnabledFeishuAccounts, s as resolveFeishuRuntimeAccount, u as formatFeishuApiError, v as parseFeishuCommentTarget } from "./accounts-BDoGHJDk.js";
2
- import { A as resolveFeishuChatType, b as resolveFeishuChatReadPreliminaryAuthorization, h as authorizeFeishuChatMemberRead, m as assertFeishuChatReadAllowed } from "./send-result-DfE5Fhz6.js";
1
+ import { a as resolveDefaultFeishuAccountId, c as encodeQuery, d as isRecord$1, i as listFeishuAccountIds, l as extractReplyText, m as readString, o as resolveFeishuAccount, r as listEnabledFeishuAccounts, s as resolveFeishuRuntimeAccount, u as formatFeishuApiError, v as parseFeishuCommentTarget } from "./accounts-CKhCa76b.js";
2
+ import { A as resolveFeishuChatType, b as resolveFeishuChatReadPreliminaryAuthorization, h as authorizeFeishuChatMemberRead, m as assertFeishuChatReadAllowed } from "./send-result-Bcofg0Vv.js";
3
3
  import { r as createFeishuClient } from "./client-Dee7cKsS.js";
4
4
  import { optionalPositiveIntegerSchema } from "openclaw/plugin-sdk/channel-actions";
5
5
  import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
6
+ import { normalizeOptionalAccountId } from "openclaw/plugin-sdk/account-resolution";
6
7
  import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
7
8
  import { jsonResult } from "openclaw/plugin-sdk/tool-results";
8
9
  import { Type } from "typebox";
@@ -10,7 +11,7 @@ import { readPositiveIntegerParam } from "openclaw/plugin-sdk/param-readers";
10
11
  //#region extensions/feishu/src/tools-config.ts
11
12
  /**
12
13
  * Default tool configuration.
13
- * - doc, chat, wiki, drive, scopes, bitable/base: enabled by default
14
+ * - doc, chat, wiki, drive, scopes, bitable: enabled by default
14
15
  * - perm: disabled by default (sensitive operation)
15
16
  */
16
17
  const DEFAULT_TOOLS_CONFIG = {
@@ -20,29 +21,33 @@ const DEFAULT_TOOLS_CONFIG = {
20
21
  drive: true,
21
22
  perm: false,
22
23
  scopes: true,
23
- bitable: true,
24
- base: true
24
+ bitable: true
25
25
  };
26
- /**
27
- * Resolve tools config with defaults.
28
- *
29
- * `base` is a backward-compatible alias for the Bitable tool family. When both
30
- * keys are present, the explicit `bitable` value wins and `base` mirrors it.
31
- */
26
+ /** Resolve tools config with defaults. */
32
27
  function resolveToolsConfig(cfg) {
33
- const bitable = cfg?.bitable ?? cfg?.base ?? DEFAULT_TOOLS_CONFIG.bitable;
34
28
  return {
35
29
  ...DEFAULT_TOOLS_CONFIG,
36
- ...cfg,
37
- bitable,
38
- base: bitable
30
+ ...cfg
39
31
  };
40
32
  }
41
33
  //#endregion
42
34
  //#region extensions/feishu/src/tool-account.ts
43
35
  function resolveImplicitToolAccountId(params) {
44
36
  const explicitAccountId = normalizeOptionalString(params.executeParams?.accountId);
45
- if (explicitAccountId) return explicitAccountId;
37
+ if (explicitAccountId) {
38
+ const normalizedAccountId = normalizeOptionalAccountId(explicitAccountId);
39
+ if (!normalizedAccountId) throw new Error(`Invalid Feishu account ID "${explicitAccountId}"`);
40
+ const listedAccountId = listFeishuAccountIds(params.api.config).find((accountId) => normalizeOptionalAccountId(accountId) === normalizedAccountId) ?? (() => {
41
+ const defaultAccountId = resolveDefaultFeishuAccountId(params.api.config);
42
+ return normalizeOptionalAccountId(defaultAccountId) === normalizedAccountId ? defaultAccountId : void 0;
43
+ })();
44
+ if (!listedAccountId) throw new Error(`Unknown Feishu account "${explicitAccountId}"`);
45
+ if (!resolveFeishuAccount({
46
+ cfg: params.api.config,
47
+ accountId: normalizedAccountId
48
+ }).enabled) throw new Error(`Feishu account "${listedAccountId}" is disabled`);
49
+ return normalizedAccountId;
50
+ }
46
51
  const contextualAccountId = normalizeOptionalString(params.defaultAccountId);
47
52
  if (contextualAccountId && listFeishuAccountIds(params.api.config).includes(contextualAccountId)) {
48
53
  if (resolveFeishuAccount({
@@ -80,8 +85,7 @@ function resolveAnyEnabledFeishuToolsConfig(accounts) {
80
85
  drive: false,
81
86
  perm: false,
82
87
  scopes: false,
83
- bitable: false,
84
- base: false
88
+ bitable: false
85
89
  };
86
90
  for (const account of accounts) {
87
91
  const cfg = resolveToolsConfig(account.config.tools);
@@ -92,7 +96,6 @@ function resolveAnyEnabledFeishuToolsConfig(accounts) {
92
96
  merged.perm = merged.perm || cfg.perm;
93
97
  merged.scopes = merged.scopes || cfg.scopes;
94
98
  merged.bitable = merged.bitable || cfg.bitable;
95
- merged.base = merged.base || cfg.base;
96
99
  }
97
100
  return merged;
98
101
  }
@@ -1,6 +1,6 @@
1
- import { d as isRecord$1, h as requestFeishuApi, s as resolveFeishuRuntimeAccount } from "./accounts-BDoGHJDk.js";
1
+ import { d as isRecord$1, h as requestFeishuApi, s as resolveFeishuRuntimeAccount } from "./accounts-CKhCa76b.js";
2
2
  import { i as resolveReceiveIdType, r as normalizeFeishuTarget } from "./targets-BUjQ1TcA.js";
3
- import { c as assertFeishuPostWithinEnvelope, f as materializeFeishuPostMarkdownSoftBreaks, i as toFeishuSendResult, l as buildFeishuPostMessageContent, o as resolveFeishuCardTemplate, r as resolveFeishuReceiptKind, t as assertFeishuMessageApiSuccess } from "./send-result-DfE5Fhz6.js";
3
+ import { c as assertFeishuPostWithinEnvelope, f as materializeFeishuPostMarkdownSoftBreaks, i as toFeishuSendResult, l as buildFeishuPostMessageContent, o as resolveFeishuCardTemplate, r as resolveFeishuReceiptKind, t as assertFeishuMessageApiSuccess } from "./send-result-Bcofg0Vv.js";
4
4
  import { r as createFeishuClient } from "./client-Dee7cKsS.js";
5
5
  import { t as getFeishuRuntime } from "./runtime-C5JxBWZp.js";
6
6
  import { parseStrictNonNegativeInteger } from "openclaw/plugin-sdk/number-runtime";
@@ -1,8 +1,8 @@
1
- import { r as listEnabledFeishuAccounts, s as resolveFeishuRuntimeAccount } from "./accounts-BDoGHJDk.js";
1
+ import { r as listEnabledFeishuAccounts, s as resolveFeishuRuntimeAccount } from "./accounts-CKhCa76b.js";
2
2
  import { t as fetchBotIdentityForMonitor } from "./monitor.startup-CSUPT_U1.js";
3
3
  import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
4
4
  //#region extensions/feishu/src/monitor.ts
5
- const loadMonitorAccountRuntime = createLazyRuntimeModule(() => import("./monitor.account-CkYj45PC.js"));
5
+ const loadMonitorAccountRuntime = createLazyRuntimeModule(() => import("./monitor.account-DEHl8Non.js"));
6
6
  async function monitorFeishuProvider(opts = {}) {
7
7
  const cfg = opts.config;
8
8
  if (!cfg) throw new Error("Config is required for Feishu monitor");