@openclaw/feishu 2026.3.13 → 2026.5.1-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.
Files changed (188) hide show
  1. package/api.ts +31 -0
  2. package/channel-entry.ts +20 -0
  3. package/channel-plugin-api.ts +1 -0
  4. package/contract-api.ts +16 -0
  5. package/index.ts +70 -53
  6. package/openclaw.plugin.json +1653 -4
  7. package/package.json +32 -7
  8. package/runtime-api.ts +55 -0
  9. package/secret-contract-api.ts +5 -0
  10. package/security-contract-api.ts +1 -0
  11. package/session-key-api.ts +1 -0
  12. package/setup-api.ts +3 -0
  13. package/setup-entry.test.ts +14 -0
  14. package/setup-entry.ts +13 -0
  15. package/src/accounts.test.ts +95 -7
  16. package/src/accounts.ts +199 -117
  17. package/src/app-registration.ts +331 -0
  18. package/src/approval-auth.test.ts +24 -0
  19. package/src/approval-auth.ts +25 -0
  20. package/src/async.test.ts +35 -0
  21. package/src/async.ts +43 -1
  22. package/src/audio-preflight.runtime.ts +9 -0
  23. package/src/bitable.test.ts +131 -0
  24. package/src/bitable.ts +59 -22
  25. package/src/bot-content.ts +474 -0
  26. package/src/bot-group-name.test.ts +108 -0
  27. package/src/bot-runtime-api.ts +12 -0
  28. package/src/bot-sender-name.ts +125 -0
  29. package/src/bot.broadcast.test.ts +463 -0
  30. package/src/bot.card-action.test.ts +519 -5
  31. package/src/bot.checkBotMentioned.test.ts +92 -20
  32. package/src/bot.helpers.test.ts +118 -0
  33. package/src/bot.stripBotMention.test.ts +13 -21
  34. package/src/bot.test.ts +1334 -401
  35. package/src/bot.ts +778 -775
  36. package/src/card-action.ts +408 -40
  37. package/src/card-interaction.test.ts +129 -0
  38. package/src/card-interaction.ts +159 -0
  39. package/src/card-test-helpers.ts +47 -0
  40. package/src/card-ux-approval.ts +65 -0
  41. package/src/card-ux-launcher.test.ts +99 -0
  42. package/src/card-ux-launcher.ts +121 -0
  43. package/src/card-ux-shared.ts +33 -0
  44. package/src/channel-runtime-api.ts +16 -0
  45. package/src/channel.runtime.ts +47 -0
  46. package/src/channel.test.ts +914 -3
  47. package/src/channel.ts +1252 -309
  48. package/src/chat-schema.ts +5 -4
  49. package/src/chat.test.ts +84 -28
  50. package/src/chat.ts +68 -10
  51. package/src/client.test.ts +212 -103
  52. package/src/client.ts +115 -21
  53. package/src/comment-dispatcher-runtime-api.ts +6 -0
  54. package/src/comment-dispatcher.test.ts +169 -0
  55. package/src/comment-dispatcher.ts +107 -0
  56. package/src/comment-handler-runtime-api.ts +3 -0
  57. package/src/comment-handler.test.ts +486 -0
  58. package/src/comment-handler.ts +309 -0
  59. package/src/comment-reaction.test.ts +166 -0
  60. package/src/comment-reaction.ts +259 -0
  61. package/src/comment-shared.test.ts +182 -0
  62. package/src/comment-shared.ts +365 -0
  63. package/src/comment-target.ts +44 -0
  64. package/src/config-schema.test.ts +63 -1
  65. package/src/config-schema.ts +31 -4
  66. package/src/conversation-id.test.ts +18 -0
  67. package/src/conversation-id.ts +199 -0
  68. package/src/dedup-runtime-api.ts +1 -0
  69. package/src/dedup.ts +32 -94
  70. package/src/directory.static.ts +61 -0
  71. package/src/directory.test.ts +119 -20
  72. package/src/directory.ts +61 -91
  73. package/src/doc-schema.ts +1 -1
  74. package/src/docx-batch-insert.test.ts +39 -38
  75. package/src/docx-batch-insert.ts +55 -19
  76. package/src/docx-color-text.ts +9 -4
  77. package/src/docx-table-ops.test.ts +53 -0
  78. package/src/docx-table-ops.ts +52 -34
  79. package/src/docx-types.ts +38 -0
  80. package/src/docx.account-selection.test.ts +12 -3
  81. package/src/docx.test.ts +314 -74
  82. package/src/docx.ts +278 -122
  83. package/src/drive-schema.ts +47 -1
  84. package/src/drive.test.ts +1219 -0
  85. package/src/drive.ts +614 -13
  86. package/src/dynamic-agent.ts +10 -4
  87. package/src/event-types.ts +45 -0
  88. package/src/external-keys.ts +1 -1
  89. package/src/lifecycle.test-support.ts +220 -0
  90. package/src/media.test.ts +375 -26
  91. package/src/media.ts +434 -88
  92. package/src/mention-target.types.ts +5 -0
  93. package/src/mention.ts +32 -51
  94. package/src/message-action-contract.ts +13 -0
  95. package/src/monitor-state-runtime-api.ts +7 -0
  96. package/src/monitor-transport-runtime-api.ts +7 -0
  97. package/src/monitor.account.ts +218 -312
  98. package/src/monitor.acp-init-failure.lifecycle.test-support.ts +219 -0
  99. package/src/monitor.bot-identity.ts +86 -0
  100. package/src/monitor.bot-menu-handler.ts +165 -0
  101. package/src/monitor.bot-menu.lifecycle.test-support.ts +224 -0
  102. package/src/monitor.bot-menu.test.ts +178 -0
  103. package/src/monitor.broadcast.reply-once.lifecycle.test-support.ts +264 -0
  104. package/src/monitor.card-action.lifecycle.test-support.ts +373 -0
  105. package/src/monitor.cleanup.test.ts +376 -0
  106. package/src/monitor.comment-notice-handler.ts +105 -0
  107. package/src/monitor.comment.test.ts +937 -0
  108. package/src/monitor.comment.ts +1386 -0
  109. package/src/monitor.lifecycle.test.ts +4 -0
  110. package/src/monitor.message-handler.ts +339 -0
  111. package/src/monitor.reaction.lifecycle.test-support.ts +68 -0
  112. package/src/monitor.reaction.test.ts +108 -48
  113. package/src/monitor.reply-once.lifecycle.test-support.ts +190 -0
  114. package/src/monitor.startup.test.ts +11 -9
  115. package/src/monitor.startup.ts +26 -16
  116. package/src/monitor.state.ts +20 -5
  117. package/src/monitor.synthetic-error.ts +18 -0
  118. package/src/monitor.test-mocks.ts +2 -2
  119. package/src/monitor.transport.ts +220 -60
  120. package/src/monitor.ts +15 -10
  121. package/src/monitor.webhook-e2e.test.ts +65 -7
  122. package/src/monitor.webhook-security.test.ts +122 -0
  123. package/src/monitor.webhook.test-helpers.ts +44 -26
  124. package/src/outbound-runtime-api.ts +1 -0
  125. package/src/outbound.test.ts +616 -37
  126. package/src/outbound.ts +623 -81
  127. package/src/perm-schema.ts +1 -1
  128. package/src/perm.ts +1 -7
  129. package/src/pins.ts +108 -0
  130. package/src/policy.test.ts +297 -117
  131. package/src/policy.ts +142 -29
  132. package/src/post.ts +7 -6
  133. package/src/probe.test.ts +14 -9
  134. package/src/probe.ts +26 -16
  135. package/src/processing-claims.ts +59 -0
  136. package/src/qr-terminal.ts +1 -0
  137. package/src/reactions.ts +4 -34
  138. package/src/reasoning-preview.test.ts +59 -0
  139. package/src/reasoning-preview.ts +20 -0
  140. package/src/reply-dispatcher-runtime-api.ts +7 -0
  141. package/src/reply-dispatcher.test.ts +660 -29
  142. package/src/reply-dispatcher.ts +407 -154
  143. package/src/runtime.ts +6 -3
  144. package/src/secret-contract.ts +145 -0
  145. package/src/secret-input.ts +1 -13
  146. package/src/security-audit-shared.ts +69 -0
  147. package/src/security-audit.test.ts +61 -0
  148. package/src/security-audit.ts +1 -0
  149. package/src/send-result.ts +1 -1
  150. package/src/send-target.test.ts +9 -3
  151. package/src/send-target.ts +10 -4
  152. package/src/send.reply-fallback.test.ts +77 -2
  153. package/src/send.test.ts +386 -4
  154. package/src/send.ts +399 -86
  155. package/src/sequential-key.test.ts +72 -0
  156. package/src/sequential-key.ts +28 -0
  157. package/src/sequential-queue.test.ts +92 -0
  158. package/src/sequential-queue.ts +16 -0
  159. package/src/session-conversation.ts +42 -0
  160. package/src/session-route.ts +48 -0
  161. package/src/setup-core.ts +51 -0
  162. package/src/{onboarding.test.ts → setup-surface.test.ts} +52 -21
  163. package/src/setup-surface.ts +581 -0
  164. package/src/streaming-card.test.ts +138 -2
  165. package/src/streaming-card.ts +134 -18
  166. package/src/subagent-hooks.test.ts +603 -0
  167. package/src/subagent-hooks.ts +397 -0
  168. package/src/targets.ts +3 -13
  169. package/src/test-support/lifecycle-test-support.ts +479 -0
  170. package/src/thread-bindings.test.ts +143 -0
  171. package/src/thread-bindings.ts +330 -0
  172. package/src/tool-account-routing.test.ts +66 -8
  173. package/src/tool-account.test.ts +44 -0
  174. package/src/tool-account.ts +40 -17
  175. package/src/tool-factory-test-harness.ts +11 -8
  176. package/src/tool-result.ts +3 -1
  177. package/src/tools-config.ts +1 -1
  178. package/src/types.ts +16 -15
  179. package/src/typing.ts +10 -6
  180. package/src/wiki-schema.ts +1 -1
  181. package/src/wiki.ts +1 -7
  182. package/subagent-hooks-api.ts +31 -0
  183. package/tsconfig.json +16 -0
  184. package/src/feishu-command-handler.ts +0 -59
  185. package/src/onboarding.status.test.ts +0 -25
  186. package/src/onboarding.ts +0 -489
  187. package/src/send-message.ts +0 -71
  188. package/src/targets.test.ts +0 -70
@@ -8,6 +8,7 @@
8
8
  */
9
9
 
10
10
  import type * as Lark from "@larksuiteoapi/node-sdk";
11
+ import type { FeishuBlockTable, FeishuDocxBlock } from "./docx-types.js";
11
12
 
12
13
  // ============ Table Utilities ============
13
14
 
@@ -33,11 +34,34 @@ const DEFAULT_TABLE_WIDTH = 730; // Approximate Feishu page content width
33
34
  * @param tableBlockId - The block_id of the table block
34
35
  * @returns Array of column widths in pixels
35
36
  */
36
- export function calculateAdaptiveColumnWidths(
37
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
38
- blocks: any[],
39
- tableBlockId: string,
40
- ): number[] {
37
+ function normalizeChildBlockIds(children: string[] | string | undefined): string[] {
38
+ if (Array.isArray(children)) {
39
+ return children;
40
+ }
41
+ return typeof children === "string" ? [children] : [];
42
+ }
43
+
44
+ function omitParentId(block: FeishuDocxBlock): FeishuDocxBlock {
45
+ const cleanBlock = { ...block };
46
+ delete cleanBlock.parent_id;
47
+ return cleanBlock;
48
+ }
49
+
50
+ function createDescendantTable(
51
+ table: FeishuBlockTable,
52
+ adaptiveWidths: number[] | undefined,
53
+ ): FeishuBlockTable {
54
+ const { row_size, column_size } = table.property || {};
55
+ return {
56
+ property: {
57
+ row_size,
58
+ column_size,
59
+ ...(adaptiveWidths?.length ? { column_width: adaptiveWidths } : {}),
60
+ },
61
+ };
62
+ }
63
+
64
+ function calculateAdaptiveColumnWidths(blocks: FeishuDocxBlock[], tableBlockId: string): number[] {
41
65
  // Find the table block
42
66
  const tableBlock = blocks.find((b) => b.block_id === tableBlockId && b.block_type === 31);
43
67
 
@@ -46,28 +70,30 @@ export function calculateAdaptiveColumnWidths(
46
70
  }
47
71
 
48
72
  const { row_size, column_size, column_width: originalWidths } = tableBlock.table.property;
73
+ if (!row_size || !column_size) {
74
+ return [];
75
+ }
49
76
 
50
77
  // Use original total width from Convert API, or fall back to default
51
78
  const totalWidth =
52
79
  originalWidths && originalWidths.length > 0
53
80
  ? originalWidths.reduce((a: number, b: number) => a + b, 0)
54
81
  : DEFAULT_TABLE_WIDTH;
55
- const cellIds: string[] = tableBlock.children || [];
82
+ const cellIds = normalizeChildBlockIds(tableBlock.children);
56
83
 
57
84
  // Build block lookup map
58
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
59
- const blockMap = new Map<string, any>();
85
+ const blockMap = new Map<string, FeishuDocxBlock>();
60
86
  for (const block of blocks) {
61
- blockMap.set(block.block_id, block);
87
+ if (block.block_id) {
88
+ blockMap.set(block.block_id, block);
89
+ }
62
90
  }
63
91
 
64
92
  // Extract text content from a table cell
65
93
  function getCellText(cellId: string): string {
66
94
  const cell = blockMap.get(cellId);
67
- if (!cell?.children) return "";
68
-
69
95
  let text = "";
70
- const childIds = Array.isArray(cell.children) ? cell.children : [cell.children];
96
+ const childIds = normalizeChildBlockIds(cell?.children);
71
97
 
72
98
  for (const childId of childIds) {
73
99
  const child = blockMap.get(childId);
@@ -85,13 +111,13 @@ export function calculateAdaptiveColumnWidths(
85
111
  // Calculate weighted length (CJK chars count as 2)
86
112
  // CJK (Chinese/Japanese/Korean) characters render ~2x wider than ASCII
87
113
  function getWeightedLength(text: string): number {
88
- return [...text].reduce((sum, char) => {
114
+ return Array.from(text).reduce((sum, char) => {
89
115
  return sum + (char.charCodeAt(0) > 255 ? 2 : 1);
90
116
  }, 0);
91
117
  }
92
118
 
93
119
  // Find max content length per column
94
- const maxLengths: number[] = new Array(column_size).fill(0);
120
+ const maxLengths = Array.from({ length: column_size }, () => 0);
95
121
 
96
122
  for (let row = 0; row < row_size; row++) {
97
123
  for (let col = 0; col < column_size; col++) {
@@ -114,7 +140,7 @@ export function calculateAdaptiveColumnWidths(
114
140
  MIN_COLUMN_WIDTH,
115
141
  Math.min(MAX_COLUMN_WIDTH, Math.floor(totalWidth / column_size)),
116
142
  );
117
- return new Array(column_size).fill(equalWidth);
143
+ return Array.from({ length: column_size }, () => equalWidth);
118
144
  }
119
145
 
120
146
  // Calculate proportional widths
@@ -131,11 +157,15 @@ export function calculateAdaptiveColumnWidths(
131
157
  while (remaining > 0) {
132
158
  // Find columns that can still grow (not at max)
133
159
  const growable = widths.map((w, i) => (w < MAX_COLUMN_WIDTH ? i : -1)).filter((i) => i >= 0);
134
- if (growable.length === 0) break;
160
+ if (growable.length === 0) {
161
+ break;
162
+ }
135
163
 
136
164
  // Distribute evenly among growable columns
137
165
  const perColumn = Math.floor(remaining / growable.length);
138
- if (perColumn === 0) break;
166
+ if (perColumn === 0) {
167
+ break;
168
+ }
139
169
 
140
170
  for (const i of growable) {
141
171
  const add = Math.min(perColumn, MAX_COLUMN_WIDTH - widths[i]);
@@ -158,20 +188,18 @@ export function calculateAdaptiveColumnWidths(
158
188
  * @param blocks - Array of blocks from Convert API
159
189
  * @returns Cleaned blocks ready for Descendant API
160
190
  */
161
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
162
- export function cleanBlocksForDescendant(blocks: any[]): any[] {
191
+ export function cleanBlocksForDescendant(blocks: FeishuDocxBlock[]): FeishuDocxBlock[] {
163
192
  // Pre-calculate adaptive widths for all tables
164
193
  const tableWidths = new Map<string, number[]>();
165
194
  for (const block of blocks) {
166
- if (block.block_type === 31) {
195
+ if (block.block_type === 31 && block.block_id) {
167
196
  const widths = calculateAdaptiveColumnWidths(blocks, block.block_id);
168
197
  tableWidths.set(block.block_id, widths);
169
198
  }
170
199
  }
171
200
 
172
201
  return blocks.map((block) => {
173
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
174
- const { parent_id: _parentId, ...cleanBlock } = block;
202
+ const cleanBlock = omitParentId(block);
175
203
 
176
204
  // Fix: Convert API sometimes returns children as string for TableCell
177
205
  if (cleanBlock.block_type === 32 && typeof cleanBlock.children === "string") {
@@ -180,18 +208,8 @@ export function cleanBlocksForDescendant(blocks: any[]): any[] {
180
208
 
181
209
  // Clean table blocks
182
210
  if (cleanBlock.block_type === 31 && cleanBlock.table) {
183
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
184
- const { cells: _cells, ...tableWithoutCells } = cleanBlock.table;
185
- const { row_size, column_size } = tableWithoutCells.property || {};
186
- const adaptiveWidths = tableWidths.get(block.block_id);
187
-
188
- cleanBlock.table = {
189
- property: {
190
- row_size,
191
- column_size,
192
- ...(adaptiveWidths?.length && { column_width: adaptiveWidths }),
193
- },
194
- };
211
+ const adaptiveWidths = block.block_id ? tableWidths.get(block.block_id) : undefined;
212
+ cleanBlock.table = createDescendantTable(cleanBlock.table, adaptiveWidths);
195
213
  }
196
214
 
197
215
  return cleanBlock;
@@ -0,0 +1,38 @@
1
+ type FeishuBlockText = {
2
+ elements?: Array<{
3
+ text_run?: {
4
+ content?: string;
5
+ };
6
+ }>;
7
+ };
8
+
9
+ type FeishuBlockTableProperty = {
10
+ row_size?: number;
11
+ column_size?: number;
12
+ column_width?: number[];
13
+ };
14
+
15
+ export type FeishuBlockTable = {
16
+ property?: FeishuBlockTableProperty;
17
+ merge_info?: Array<{ row_span?: number; col_span?: number }>;
18
+ cells?: string[];
19
+ };
20
+
21
+ export type FeishuDocxBlock = {
22
+ block_id?: string;
23
+ parent_id?: string;
24
+ children?: string[] | string;
25
+ block_type: number;
26
+ text?: FeishuBlockText;
27
+ table?: FeishuBlockTable;
28
+ image?: object;
29
+ [key: string]: object | string | number | boolean | string[] | undefined;
30
+ };
31
+
32
+ export type FeishuDocxBlockChild = {
33
+ block_id?: string;
34
+ parent_id?: string;
35
+ block_type?: number;
36
+ children?: string[] | FeishuDocxBlockChild[];
37
+ table?: FeishuBlockTable;
38
+ };
@@ -1,6 +1,5 @@
1
- import type { OpenClawPluginApi } from "openclaw/plugin-sdk/feishu";
2
- import { describe, expect, test, vi } from "vitest";
3
- import { registerFeishuDocTools } from "./docx.js";
1
+ import { beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
2
+ import type { OpenClawPluginApi } from "../runtime-api.js";
4
3
  import { createToolFactoryHarness } from "./tool-factory-test-harness.js";
5
4
 
6
5
  const createFeishuClientMock = vi.fn((creds: { appId?: string } | undefined) => ({
@@ -21,6 +20,16 @@ vi.mock("@larksuiteoapi/node-sdk", () => {
21
20
  });
22
21
 
23
22
  describe("feishu_doc account selection", () => {
23
+ let registerFeishuDocTools: typeof import("./docx.js").registerFeishuDocTools;
24
+
25
+ beforeAll(async () => {
26
+ ({ registerFeishuDocTools } = await import("./docx.js"));
27
+ });
28
+
29
+ beforeEach(() => {
30
+ vi.clearAllMocks();
31
+ });
32
+
24
33
  function createDocEnabledConfig(): OpenClawPluginApi["config"] {
25
34
  return {
26
35
  channels: {