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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/accounts-CCCdMen2.js +203 -0
  2. package/dist/api.js +52 -51
  3. package/dist/{channel-CScE82zY.js → channel-Dzb5jv3i.js} +53 -30
  4. package/dist/channel-plugin-api.js +1 -1
  5. package/dist/{channel.runtime-B21e1E0r.js → channel.runtime-CoPaHQQ6.js} +181 -142
  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-B0JkoiRj.js} +318 -41
  12. package/dist/{media-CEUraFOR.js → media-BjSy8fiy.js} +298 -182
  13. package/dist/{monitor-DngbaA6a.js → monitor-CeHCfROt.js} +3 -3
  14. package/dist/{monitor.account-BnTWCw55.js → monitor.account-DwdqexLU.js} +237 -158
  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 +1 -1
  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-B867acTt.js} +2 -2
  24. package/dist/subagent-hooks-api.js +1 -1
  25. package/dist/{thread-bindings-N3wkgkIN.js → thread-bindings-Itvfmx6_.js} +6 -3
  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,5 +1,5 @@
1
1
  import { t as getFeishuRuntime } from "./runtime-C5JxBWZp.js";
2
- import { r as registerFeishuAiAgent, t as probeFeishu } from "./probe-p3POS2RN.js";
2
+ import { r as registerFeishuAiAgent, t as probeFeishu } from "./probe-DVpy58s0.js";
3
3
  import { parseStrictPositiveInteger } from "openclaw/plugin-sdk/number-runtime";
4
4
  import { normalizeLowercaseStringOrEmpty, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
5
5
  import { normalizeAccountId } from "openclaw/plugin-sdk/account-resolution";
@@ -1,7 +1,7 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
2
- import { r as createFeishuClient } from "./client-Dcbs6vml.js";
3
- import { asDateTimestampMs, resolveExpiresAtMsFromDurationMs, resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
2
+ import { r as createFeishuClient } from "./client-Hp7uo_cl.js";
4
3
  import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
4
+ import { asDateTimestampMs, resolveExpiresAtMsFromDurationMs, resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
5
5
  import { createHash } from "node:crypto";
6
6
  //#region extensions/feishu/src/async.ts
7
7
  const RACE_TIMEOUT = Symbol("race-timeout");
@@ -0,0 +1,23 @@
1
+ import "./security-audit-shared-BgpY7AiJ.js";
2
+ //#region extensions/feishu/src/message-action-contract.ts
3
+ const FEISHU_NATIVE_CHAT_TARGET_ALIASES = [
4
+ "chatId",
5
+ "chat_id",
6
+ "channel_id"
7
+ ];
8
+ function createMessageMutationTargetAliases() {
9
+ return {
10
+ aliases: ["messageId", ...FEISHU_NATIVE_CHAT_TARGET_ALIASES],
11
+ deliveryTargetAliases: [...FEISHU_NATIVE_CHAT_TARGET_ALIASES]
12
+ };
13
+ }
14
+ const messageActionTargetAliases = {
15
+ read: { aliases: ["messageId"] },
16
+ edit: createMessageMutationTargetAliases(),
17
+ pin: createMessageMutationTargetAliases(),
18
+ unpin: createMessageMutationTargetAliases(),
19
+ "list-pins": { aliases: ["chatId"] },
20
+ "channel-info": { aliases: ["chatId"] }
21
+ };
22
+ //#endregion
23
+ export { messageActionTargetAliases as t };
@@ -1,4 +1,3 @@
1
- import { d as isRecord$1 } from "./accounts-u9X5Wsan.js";
2
1
  import { r as normalizeFeishuTarget, t as detectIdType } from "./targets-BUjQ1TcA.js";
3
2
  import { compileAllowlist, resolveAllowlistMatchByCandidates } from "openclaw/plugin-sdk/allow-from";
4
3
  import { ToolAuthorizationError } from "openclaw/plugin-sdk/channel-actions";
@@ -11,6 +10,7 @@ import { fromMarkdown } from "mdast-util-from-markdown";
11
10
  import { gfmTableFromMarkdown } from "mdast-util-gfm-table";
12
11
  import { gfmTable } from "micromark-extension-gfm-table";
13
12
  import { chunkMarkdownTextWithMode } from "openclaw/plugin-sdk/reply-chunking";
13
+ import { createChannelPartialDeliveryError } from "openclaw/plugin-sdk/channel-inbound";
14
14
  //#region extensions/feishu/src/card-interaction.ts
15
15
  const FEISHU_CARD_INTERACTION_VERSION = "ocf1";
16
16
  function isInteractionKind(value) {
@@ -27,7 +27,7 @@ function createFeishuCardInteractionEnvelope(envelope) {
27
27
  }
28
28
  function buildFeishuCardActionTextFallback(event) {
29
29
  const actionValue = event.action.value;
30
- if (isRecord$1(actionValue)) {
30
+ if (isRecord(actionValue)) {
31
31
  if (typeof actionValue.text === "string") return actionValue.text;
32
32
  if (typeof actionValue.command === "string") return actionValue.command;
33
33
  return JSON.stringify(actionValue);
@@ -37,7 +37,7 @@ function buildFeishuCardActionTextFallback(event) {
37
37
  function decodeFeishuCardAction(params) {
38
38
  const { event, now = Date.now() } = params;
39
39
  const actionValue = event.action.value;
40
- if (!isRecord$1(actionValue) || actionValue.oc !== "ocf1") return {
40
+ if (!isRecord(actionValue) || actionValue.oc !== "ocf1") return {
41
41
  kind: "legacy",
42
42
  text: buildFeishuCardActionTextFallback(event)
43
43
  };
@@ -50,7 +50,7 @@ function decodeFeishuCardAction(params) {
50
50
  reason: "malformed"
51
51
  };
52
52
  if (actionValue.m !== void 0) {
53
- if (!isRecord$1(actionValue.m)) return {
53
+ if (!isRecord(actionValue.m)) return {
54
54
  kind: "invalid",
55
55
  reason: "malformed"
56
56
  };
@@ -60,7 +60,7 @@ function decodeFeishuCardAction(params) {
60
60
  };
61
61
  }
62
62
  if (actionValue.c !== void 0) {
63
- if (!isRecord$1(actionValue.c)) return {
63
+ if (!isRecord(actionValue.c)) return {
64
64
  kind: "invalid",
65
65
  reason: "malformed"
66
66
  };
@@ -197,6 +197,7 @@ async function resolveFeishuDmIngressAccess(params) {
197
197
  kind: "direct",
198
198
  id: params.conversationId
199
199
  },
200
+ ...params.contextBinding ? { contextBinding: params.contextBinding } : {},
200
201
  event: { mayPair: params.mayPair },
201
202
  dmPolicy: normalizeFeishuDmPolicy(params.dmPolicy),
202
203
  groupPolicy: "disabled",
@@ -214,8 +215,10 @@ async function resolveFeishuGroupConversationIngressAccess(params) {
214
215
  subject: createFeishuIngressSubject({ primaryId: params.chatId }),
215
216
  conversation: {
216
217
  kind: "group",
217
- id: params.chatId
218
+ id: params.chatId,
219
+ threadId: params.threadId
218
220
  },
221
+ ...params.contextBinding ? { contextBinding: params.contextBinding } : {},
219
222
  dmPolicy: "disabled",
220
223
  groupPolicy,
221
224
  groupAllowFrom
@@ -233,8 +236,10 @@ async function resolveFeishuGroupSenderActivationIngressAccess(params) {
233
236
  }),
234
237
  conversation: {
235
238
  kind: "group",
236
- id: params.chatId
239
+ id: params.chatId,
240
+ threadId: params.threadId
237
241
  },
242
+ ...params.contextBinding ? { contextBinding: params.contextBinding } : {},
238
243
  dmPolicy: "disabled",
239
244
  groupPolicy: groupAllowFrom.length > 0 ? "allowlist" : "open",
240
245
  groupAllowFrom,
@@ -754,8 +759,12 @@ function createFeishuSendReceipt(params) {
754
759
  function assertFeishuMessageApiSuccess(response, errorPrefix) {
755
760
  if (response.code !== 0) throw new Error(`${errorPrefix}: ${response.msg || `code ${response.code}`}`);
756
761
  }
757
- function toFeishuSendResult(response, chatId, kind) {
758
- const messageId = response.data?.message_id ?? "unknown";
762
+ function toFeishuSendResult(response, chatId, kind, errorPrefix = "Feishu send failed") {
763
+ const messageId = response.data?.message_id?.trim();
764
+ if (!messageId) throw createChannelPartialDeliveryError(/* @__PURE__ */ new Error(`${errorPrefix}: no message_id returned`), {
765
+ messageIds: [],
766
+ visibleReplySent: true
767
+ });
759
768
  return {
760
769
  messageId,
761
770
  chatId,
@@ -1,2 +1,2 @@
1
- import { r as testing, t as createFeishuThreadBindingManager } from "./thread-bindings-N3wkgkIN.js";
1
+ import { r as testing, t as createFeishuThreadBindingManager } from "./thread-bindings-Itvfmx6_.js";
2
2
  export { createFeishuThreadBindingManager, testing as feishuThreadBindingTesting };
@@ -1,4 +1,4 @@
1
- import { r as parseFeishuConversationId, t as buildFeishuConversationId } from "./conversation-id-BeJL-wq7.js";
1
+ import { r as parseFeishuConversationId, t as buildFeishuConversationId } from "./conversation-id-VYgGQ-GX.js";
2
2
  //#region extensions/feishu/src/session-conversation.ts
3
3
  function resolveFeishuParentConversationCandidates(rawId) {
4
4
  const parsed = parseFeishuConversationId({ conversationId: rawId });
@@ -1,2 +1,2 @@
1
- import { t as resolveFeishuSessionConversation } from "./session-conversation-BksWrfzm.js";
1
+ import { t as resolveFeishuSessionConversation } from "./session-conversation-DFCIvQK-.js";
2
2
  export { resolveFeishuSessionConversation as resolveSessionConversation };
package/dist/setup-api.js CHANGED
@@ -1,2 +1,2 @@
1
- import { i as feishuSetupAdapter, n as feishuSetupWizard, t as feishuPlugin } from "./channel-CScE82zY.js";
1
+ import { i as feishuSetupAdapter, n as feishuSetupWizard, t as feishuPlugin } from "./channel-Dzb5jv3i.js";
2
2
  export { feishuPlugin, feishuSetupAdapter, feishuSetupWizard };
@@ -1,7 +1,7 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
2
2
  import { r as normalizeFeishuTarget } from "./targets-BUjQ1TcA.js";
3
- import { r as parseFeishuConversationId, t as buildFeishuConversationId } from "./conversation-id-BeJL-wq7.js";
4
- import { n as getFeishuThreadBindingManager } from "./thread-bindings-N3wkgkIN.js";
3
+ import { r as parseFeishuConversationId, t as buildFeishuConversationId } from "./conversation-id-VYgGQ-GX.js";
4
+ import { n as getFeishuThreadBindingManager } from "./thread-bindings-Itvfmx6_.js";
5
5
  import { normalizeOptionalLowercaseString, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
6
6
  //#region extensions/feishu/src/subagent-hooks.ts
7
7
  var subagent_hooks_exports = /* @__PURE__ */ __exportAll({
@@ -1,6 +1,6 @@
1
1
  import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
2
2
  //#region extensions/feishu/subagent-hooks-api.ts
3
- const loadFeishuSubagentHooksModule = createLazyRuntimeModule(() => import("./subagent-hooks-Cx1cX7rW.js").then((n) => n.i));
3
+ const loadFeishuSubagentHooksModule = createLazyRuntimeModule(() => import("./subagent-hooks-B867acTt.js").then((n) => n.i));
4
4
  function registerFeishuSubagentHooks(api) {
5
5
  api.on("subagent_delivery_target", async (event) => {
6
6
  const { handleFeishuSubagentDeliveryTarget } = await loadFeishuSubagentHooksModule();
@@ -1,8 +1,8 @@
1
1
  import { registerSessionBindingAdapter, resolveThreadBindingConversationIdFromBindingId, resolveThreadBindingIdleTimeoutMsForChannel, resolveThreadBindingMaxAgeMsForChannel, unregisterSessionBindingAdapter } from "openclaw/plugin-sdk/conversation-runtime";
2
2
  import { isFutureDateTimestampMs } from "openclaw/plugin-sdk/number-runtime";
3
3
  import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
4
- import { normalizeAccountId, resolveAgentIdFromSessionKey } from "openclaw/plugin-sdk/routing";
5
- import { resolveDefaultAgentId } from "openclaw/plugin-sdk/agent-runtime";
4
+ import { normalizeAccountId } from "openclaw/plugin-sdk/routing";
5
+ import { resolveSessionAgentId } from "openclaw/plugin-sdk/agent-scope-runtime";
6
6
  //#region extensions/feishu/src/thread-bindings.ts
7
7
  const FEISHU_THREAD_BINDINGS_STATE_KEY = Symbol.for("openclaw.feishuThreadBindingsState");
8
8
  let state;
@@ -107,7 +107,10 @@ function createFeishuThreadBindingManager(params) {
107
107
  deliveryThreadId: typeof metadata?.deliveryThreadId === "string" && metadata.deliveryThreadId.trim() ? metadata.deliveryThreadId.trim() : existingLocal?.deliveryThreadId,
108
108
  targetKind: toFeishuTargetKind(targetKind),
109
109
  targetSessionKey: normalizedTargetSessionKey,
110
- agentId: typeof metadata?.agentId === "string" && metadata.agentId.trim() ? metadata.agentId.trim() : existingLocal?.agentId ?? resolveAgentIdFromSessionKey(normalizedTargetSessionKey, resolveDefaultAgentId(params.cfg)),
110
+ agentId: normalizeOptionalString(metadata?.agentId) ?? existingLocal?.agentId ?? resolveSessionAgentId({
111
+ config: params.cfg,
112
+ sessionKey: normalizedTargetSessionKey
113
+ }),
111
114
  label: typeof metadata?.label === "string" && metadata.label.trim() ? metadata.label.trim() : existingLocal?.label,
112
115
  boundBy: typeof metadata?.boundBy === "string" && metadata.boundBy.trim() ? metadata.boundBy.trim() : existingLocal?.boundBy,
113
116
  boundAt: now,
@@ -1,5 +1,8 @@
1
1
  {
2
2
  "id": "feishu",
3
+ "doctorContract": {
4
+ "configRepair": true
5
+ },
3
6
  "name": "Feishu/Lark",
4
7
  "description": "OpenClaw Feishu/Lark channel plugin for chats and workplace tools (community maintained by @m1heng).",
5
8
  "activation": {
@@ -310,7 +313,8 @@
310
313
  "enum": [
311
314
  "env",
312
315
  "file",
313
- "exec"
316
+ "exec",
317
+ "store"
314
318
  ]
315
319
  },
316
320
  "provider": {
@@ -580,6 +584,29 @@
580
584
  ],
581
585
  "additionalProperties": false
582
586
  },
587
+ {
588
+ "type": "object",
589
+ "properties": {
590
+ "source": {
591
+ "type": "string",
592
+ "const": "store"
593
+ },
594
+ "provider": {
595
+ "type": "string",
596
+ "pattern": "^[a-z][a-z0-9_-]{0,63}$"
597
+ },
598
+ "id": {
599
+ "type": "string",
600
+ "pattern": "^[A-Z][A-Z0-9_]{0,127}$"
601
+ }
602
+ },
603
+ "required": [
604
+ "source",
605
+ "provider",
606
+ "id"
607
+ ],
608
+ "additionalProperties": false
609
+ },
583
610
  {
584
611
  "type": "object",
585
612
  "properties": {
@@ -658,6 +685,29 @@
658
685
  ],
659
686
  "additionalProperties": false
660
687
  },
688
+ {
689
+ "type": "object",
690
+ "properties": {
691
+ "source": {
692
+ "type": "string",
693
+ "const": "store"
694
+ },
695
+ "provider": {
696
+ "type": "string",
697
+ "pattern": "^[a-z][a-z0-9_-]{0,63}$"
698
+ },
699
+ "id": {
700
+ "type": "string",
701
+ "pattern": "^[A-Z][A-Z0-9_]{0,127}$"
702
+ }
703
+ },
704
+ "required": [
705
+ "source",
706
+ "provider",
707
+ "id"
708
+ ],
709
+ "additionalProperties": false
710
+ },
661
711
  {
662
712
  "type": "object",
663
713
  "properties": {
@@ -736,6 +786,29 @@
736
786
  ],
737
787
  "additionalProperties": false
738
788
  },
789
+ {
790
+ "type": "object",
791
+ "properties": {
792
+ "source": {
793
+ "type": "string",
794
+ "const": "store"
795
+ },
796
+ "provider": {
797
+ "type": "string",
798
+ "pattern": "^[a-z][a-z0-9_-]{0,63}$"
799
+ },
800
+ "id": {
801
+ "type": "string",
802
+ "pattern": "^[A-Z][A-Z0-9_]{0,127}$"
803
+ }
804
+ },
805
+ "required": [
806
+ "source",
807
+ "provider",
808
+ "id"
809
+ ],
810
+ "additionalProperties": false
811
+ },
739
812
  {
740
813
  "type": "object",
741
814
  "properties": {
@@ -1348,6 +1421,29 @@
1348
1421
  ],
1349
1422
  "additionalProperties": false
1350
1423
  },
1424
+ {
1425
+ "type": "object",
1426
+ "properties": {
1427
+ "source": {
1428
+ "type": "string",
1429
+ "const": "store"
1430
+ },
1431
+ "provider": {
1432
+ "type": "string",
1433
+ "pattern": "^[a-z][a-z0-9_-]{0,63}$"
1434
+ },
1435
+ "id": {
1436
+ "type": "string",
1437
+ "pattern": "^[A-Z][A-Z0-9_]{0,127}$"
1438
+ }
1439
+ },
1440
+ "required": [
1441
+ "source",
1442
+ "provider",
1443
+ "id"
1444
+ ],
1445
+ "additionalProperties": false
1446
+ },
1351
1447
  {
1352
1448
  "type": "object",
1353
1449
  "properties": {
@@ -1426,6 +1522,29 @@
1426
1522
  ],
1427
1523
  "additionalProperties": false
1428
1524
  },
1525
+ {
1526
+ "type": "object",
1527
+ "properties": {
1528
+ "source": {
1529
+ "type": "string",
1530
+ "const": "store"
1531
+ },
1532
+ "provider": {
1533
+ "type": "string",
1534
+ "pattern": "^[a-z][a-z0-9_-]{0,63}$"
1535
+ },
1536
+ "id": {
1537
+ "type": "string",
1538
+ "pattern": "^[A-Z][A-Z0-9_]{0,127}$"
1539
+ }
1540
+ },
1541
+ "required": [
1542
+ "source",
1543
+ "provider",
1544
+ "id"
1545
+ ],
1546
+ "additionalProperties": false
1547
+ },
1429
1548
  {
1430
1549
  "type": "object",
1431
1550
  "properties": {
@@ -1504,6 +1623,29 @@
1504
1623
  ],
1505
1624
  "additionalProperties": false
1506
1625
  },
1626
+ {
1627
+ "type": "object",
1628
+ "properties": {
1629
+ "source": {
1630
+ "type": "string",
1631
+ "const": "store"
1632
+ },
1633
+ "provider": {
1634
+ "type": "string",
1635
+ "pattern": "^[a-z][a-z0-9_-]{0,63}$"
1636
+ },
1637
+ "id": {
1638
+ "type": "string",
1639
+ "pattern": "^[A-Z][A-Z0-9_]{0,127}$"
1640
+ }
1641
+ },
1642
+ "required": [
1643
+ "source",
1644
+ "provider",
1645
+ "id"
1646
+ ],
1647
+ "additionalProperties": false
1648
+ },
1507
1649
  {
1508
1650
  "type": "object",
1509
1651
  "properties": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/feishu",
3
- "version": "2026.7.2-beta.7",
3
+ "version": "2026.8.1-beta.2",
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.7.2-beta.7"
19
+ "openclaw": ">=2026.8.1-beta.2"
20
20
  },
21
21
  "peerDependenciesMeta": {
22
22
  "openclaw": {
@@ -60,10 +60,10 @@
60
60
  "minHostVersion": ">=2026.5.29"
61
61
  },
62
62
  "compat": {
63
- "pluginApi": ">=2026.7.2-beta.7"
63
+ "pluginApi": ">=2026.8.1-beta.2"
64
64
  },
65
65
  "build": {
66
- "openclawVersion": "2026.7.2-beta.7"
66
+ "openclawVersion": "2026.8.1-beta.2"
67
67
  },
68
68
  "release": {
69
69
  "publishToClawHub": true,
@@ -1,215 +1,40 @@
1
1
  ---
2
2
  name: feishu-doc
3
3
  description: |
4
- Feishu document read/write operations. Activate when user mentions Feishu docs, cloud docs, or docx links.
4
+ Feishu document read/write workflows. Activate when the user mentions Feishu docs, cloud docs, or docx links.
5
5
  ---
6
6
 
7
- # Feishu Document Tool
7
+ # Feishu documents
8
8
 
9
- Single tool `feishu_doc` with action parameter for all document operations, including table creation for Docx.
9
+ Use the single `feishu_doc` tool. Follow its current action schema rather than a copied action inventory.
10
10
 
11
- ## Token Extraction
11
+ From `https://example.feishu.cn/docx/ABC123def`, use `ABC123def` as `doc_token`.
12
12
 
13
- From URL `https://xxx.feishu.cn/docx/ABC123def` → `doc_token` = `ABC123def`
13
+ ## Read and edit
14
14
 
15
- ## Actions
15
+ 1. Start with `read` for plain text and block statistics.
16
+ 2. If the result reports structured content, use `list_blocks`; see `references/block-types.md` for block meanings.
17
+ 3. Use `update_block` or `delete_block` for one known block. Use `insert` with `after_block_id` to place new Markdown after a known block.
18
+ 4. Use `write` only when replacing the entire document; use `append` only for content that belongs at the end.
16
19
 
17
- ### Read Document
20
+ Markdown writes support ordinary text structure and images, but not Markdown tables. For tables, use the explicit table actions exposed by the tool. Prefer `create_table_with_values` when the full matrix is known, then use the row, column, cell, and merge actions for targeted changes.
18
21
 
19
- ```json
20
- { "action": "read", "doc_token": "ABC123def" }
21
- ```
22
-
23
- Returns: title, plain text content, block statistics. Check `hint` field - if present, structured content (tables, images) exists that requires `list_blocks`.
24
-
25
- ### Write Document (Replace All)
26
-
27
- ```json
28
- { "action": "write", "doc_token": "ABC123def", "content": "# Title\n\nMarkdown content..." }
29
- ```
30
-
31
- Replaces entire document with markdown content. Supports: headings, lists, code blocks, quotes, links, images (`![](url)` auto-uploaded), bold/italic/strikethrough.
32
-
33
- **Limitation:** Markdown tables are NOT supported.
34
-
35
- ### Append Content
36
-
37
- ```json
38
- { "action": "append", "doc_token": "ABC123def", "content": "Additional content" }
39
- ```
40
-
41
- Appends markdown to end of document.
42
-
43
- ### Create Document
44
-
45
- ```json
46
- { "action": "create", "title": "New Document", "owner_open_id": "ou_xxx" }
47
- ```
48
-
49
- With folder:
50
-
51
- ```json
52
- {
53
- "action": "create",
54
- "title": "New Document",
55
- "folder_token": "fldcnXXX",
56
- "owner_open_id": "ou_xxx"
57
- }
58
- ```
59
-
60
- Document creation is title-only. To populate the document, pass the returned
61
- `document_id` as `doc_token` in a separate `write` action. Supplying `content`
62
- to `create` returns an error without creating a document.
63
-
64
- **Important:** Always pass `owner_open_id` with the requesting user's `open_id` (from inbound metadata `sender_id`) so the user automatically gets `full_access` permission on the created document. Without this, only the bot app has access.
65
-
66
- ### List Blocks
67
-
68
- ```json
69
- { "action": "list_blocks", "doc_token": "ABC123def" }
70
- ```
71
-
72
- Returns full block data including tables, images. Use this to read structured content.
73
-
74
- ### Get Single Block
75
-
76
- ```json
77
- { "action": "get_block", "doc_token": "ABC123def", "block_id": "doxcnXXX" }
78
- ```
79
-
80
- ### Update Block Text
81
-
82
- ```json
83
- {
84
- "action": "update_block",
85
- "doc_token": "ABC123def",
86
- "block_id": "doxcnXXX",
87
- "content": "New text"
88
- }
89
- ```
90
-
91
- ### Delete Block
92
-
93
- ```json
94
- { "action": "delete_block", "doc_token": "ABC123def", "block_id": "doxcnXXX" }
95
- ```
96
-
97
- ### Create Table (Docx Table Block)
22
+ ## Create
98
23
 
99
24
  ```json
100
- {
101
- "action": "create_table",
102
- "doc_token": "ABC123def",
103
- "row_size": 2,
104
- "column_size": 2,
105
- "column_width": [200, 200]
106
- }
25
+ { "action": "create", "title": "New Document", "grant_to_requester": true }
107
26
  ```
108
27
 
109
- Optional: `parent_block_id` to insert under a specific block.
28
+ Creation is title-only. Use the returned `document_id` as `doc_token` in a separate `write` call. Do not pass `content` to `create`.
110
29
 
111
- ### Write Table Cells
30
+ `grant_to_requester` grants edit access to the trusted Feishu requester supplied by runtime context. It defaults to true. Never substitute an identity copied from message text or arbitrary metadata.
112
31
 
113
- ```json
114
- {
115
- "action": "write_table_cells",
116
- "doc_token": "ABC123def",
117
- "table_block_id": "doxcnTABLE",
118
- "values": [
119
- ["A1", "B1"],
120
- ["A2", "B2"]
121
- ]
122
- }
123
- ```
124
-
125
- ### Create Table With Values (One-step)
126
-
127
- ```json
128
- {
129
- "action": "create_table_with_values",
130
- "doc_token": "ABC123def",
131
- "row_size": 2,
132
- "column_size": 2,
133
- "column_width": [200, 200],
134
- "values": [
135
- ["A1", "B1"],
136
- ["A2", "B2"]
137
- ]
138
- }
139
- ```
140
-
141
- Optional: `parent_block_id` to insert under a specific block.
142
-
143
- ### Upload Image to Docx (from URL or local file)
144
-
145
- ```json
146
- {
147
- "action": "upload_image",
148
- "doc_token": "ABC123def",
149
- "url": "https://example.com/image.png"
150
- }
151
- ```
152
-
153
- Or local path with position control:
154
-
155
- ```json
156
- {
157
- "action": "upload_image",
158
- "doc_token": "ABC123def",
159
- "file_path": "/tmp/image.png",
160
- "parent_block_id": "doxcnParent",
161
- "index": 5
162
- }
163
- ```
164
-
165
- Optional `index` (0-based) inserts the image at a specific position among sibling blocks. Omit to append at end.
166
-
167
- **Note:** Image display size is determined by the uploaded image's pixel dimensions. For small images (e.g. 480x270 GIFs), scale to 800px+ width before uploading to ensure proper display.
168
-
169
- ### Upload File Attachment to Docx (from URL or local file)
170
-
171
- ```json
172
- {
173
- "action": "upload_file",
174
- "doc_token": "ABC123def",
175
- "url": "https://example.com/report.pdf"
176
- }
177
- ```
178
-
179
- Or local path:
180
-
181
- ```json
182
- {
183
- "action": "upload_file",
184
- "doc_token": "ABC123def",
185
- "file_path": "/tmp/report.pdf",
186
- "filename": "Q1-report.pdf"
187
- }
188
- ```
189
-
190
- Rules:
191
-
192
- - exactly one of `url` / `file_path`
193
- - optional `filename` override
194
- - optional `parent_block_id`
195
-
196
- ## Reading Workflow
197
-
198
- 1. Start with `action: "read"` - get plain text + statistics
199
- 2. Check `block_types` in response for Table, Image, Code, etc.
200
- 3. If structured content exists, use `action: "list_blocks"` for full data
201
-
202
- ## Configuration
203
-
204
- ```yaml
205
- channels:
206
- feishu:
207
- tools:
208
- doc: true # default: true
209
- ```
32
+ ## Media
210
33
 
211
- **Note:** `feishu_wiki` depends on this tool - wiki page content is read/written via `feishu_doc`.
34
+ Use `upload_image` or `upload_file` with exactly one supported source field from the current schema. Pass `parent_block_id` and `index` only when placement matters. Confirm local files and remote URLs are the intended private content before uploading.
212
35
 
213
- ## Permissions
36
+ ## Safety
214
37
 
215
- Required: `docx:document`, `docx:document:readonly`, `docx:document.block:convert`, `drive:drive`
38
+ - Resolve exact document and block IDs before destructive edits.
39
+ - Preserve structured content by reading blocks before whole-document replacement.
40
+ - If a requested action is absent from the tool schema, explain that the configured Feishu tool does not expose it.