@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.
- package/api.ts +31 -0
- package/channel-entry.ts +20 -0
- package/channel-plugin-api.ts +1 -0
- package/contract-api.ts +16 -0
- package/index.ts +70 -53
- package/openclaw.plugin.json +1653 -4
- package/package.json +32 -7
- package/runtime-api.ts +55 -0
- package/secret-contract-api.ts +5 -0
- package/security-contract-api.ts +1 -0
- package/session-key-api.ts +1 -0
- package/setup-api.ts +3 -0
- package/setup-entry.test.ts +14 -0
- package/setup-entry.ts +13 -0
- package/src/accounts.test.ts +95 -7
- package/src/accounts.ts +199 -117
- package/src/app-registration.ts +331 -0
- package/src/approval-auth.test.ts +24 -0
- package/src/approval-auth.ts +25 -0
- package/src/async.test.ts +35 -0
- package/src/async.ts +43 -1
- package/src/audio-preflight.runtime.ts +9 -0
- package/src/bitable.test.ts +131 -0
- package/src/bitable.ts +59 -22
- package/src/bot-content.ts +474 -0
- package/src/bot-group-name.test.ts +108 -0
- package/src/bot-runtime-api.ts +12 -0
- package/src/bot-sender-name.ts +125 -0
- package/src/bot.broadcast.test.ts +463 -0
- package/src/bot.card-action.test.ts +519 -5
- package/src/bot.checkBotMentioned.test.ts +92 -20
- package/src/bot.helpers.test.ts +118 -0
- package/src/bot.stripBotMention.test.ts +13 -21
- package/src/bot.test.ts +1334 -401
- package/src/bot.ts +778 -775
- package/src/card-action.ts +408 -40
- package/src/card-interaction.test.ts +129 -0
- package/src/card-interaction.ts +159 -0
- package/src/card-test-helpers.ts +47 -0
- package/src/card-ux-approval.ts +65 -0
- package/src/card-ux-launcher.test.ts +99 -0
- package/src/card-ux-launcher.ts +121 -0
- package/src/card-ux-shared.ts +33 -0
- package/src/channel-runtime-api.ts +16 -0
- package/src/channel.runtime.ts +47 -0
- package/src/channel.test.ts +914 -3
- package/src/channel.ts +1252 -309
- package/src/chat-schema.ts +5 -4
- package/src/chat.test.ts +84 -28
- package/src/chat.ts +68 -10
- package/src/client.test.ts +212 -103
- package/src/client.ts +115 -21
- package/src/comment-dispatcher-runtime-api.ts +6 -0
- package/src/comment-dispatcher.test.ts +169 -0
- package/src/comment-dispatcher.ts +107 -0
- package/src/comment-handler-runtime-api.ts +3 -0
- package/src/comment-handler.test.ts +486 -0
- package/src/comment-handler.ts +309 -0
- package/src/comment-reaction.test.ts +166 -0
- package/src/comment-reaction.ts +259 -0
- package/src/comment-shared.test.ts +182 -0
- package/src/comment-shared.ts +365 -0
- package/src/comment-target.ts +44 -0
- package/src/config-schema.test.ts +63 -1
- package/src/config-schema.ts +31 -4
- package/src/conversation-id.test.ts +18 -0
- package/src/conversation-id.ts +199 -0
- package/src/dedup-runtime-api.ts +1 -0
- package/src/dedup.ts +32 -94
- package/src/directory.static.ts +61 -0
- package/src/directory.test.ts +119 -20
- package/src/directory.ts +61 -91
- package/src/doc-schema.ts +1 -1
- package/src/docx-batch-insert.test.ts +39 -38
- package/src/docx-batch-insert.ts +55 -19
- package/src/docx-color-text.ts +9 -4
- package/src/docx-table-ops.test.ts +53 -0
- package/src/docx-table-ops.ts +52 -34
- package/src/docx-types.ts +38 -0
- package/src/docx.account-selection.test.ts +12 -3
- package/src/docx.test.ts +314 -74
- package/src/docx.ts +278 -122
- package/src/drive-schema.ts +47 -1
- package/src/drive.test.ts +1219 -0
- package/src/drive.ts +614 -13
- package/src/dynamic-agent.ts +10 -4
- package/src/event-types.ts +45 -0
- package/src/external-keys.ts +1 -1
- package/src/lifecycle.test-support.ts +220 -0
- package/src/media.test.ts +375 -26
- package/src/media.ts +434 -88
- package/src/mention-target.types.ts +5 -0
- package/src/mention.ts +32 -51
- package/src/message-action-contract.ts +13 -0
- package/src/monitor-state-runtime-api.ts +7 -0
- package/src/monitor-transport-runtime-api.ts +7 -0
- package/src/monitor.account.ts +218 -312
- package/src/monitor.acp-init-failure.lifecycle.test-support.ts +219 -0
- package/src/monitor.bot-identity.ts +86 -0
- package/src/monitor.bot-menu-handler.ts +165 -0
- package/src/monitor.bot-menu.lifecycle.test-support.ts +224 -0
- package/src/monitor.bot-menu.test.ts +178 -0
- package/src/monitor.broadcast.reply-once.lifecycle.test-support.ts +264 -0
- package/src/monitor.card-action.lifecycle.test-support.ts +373 -0
- package/src/monitor.cleanup.test.ts +376 -0
- package/src/monitor.comment-notice-handler.ts +105 -0
- package/src/monitor.comment.test.ts +937 -0
- package/src/monitor.comment.ts +1386 -0
- package/src/monitor.lifecycle.test.ts +4 -0
- package/src/monitor.message-handler.ts +339 -0
- package/src/monitor.reaction.lifecycle.test-support.ts +68 -0
- package/src/monitor.reaction.test.ts +108 -48
- package/src/monitor.reply-once.lifecycle.test-support.ts +190 -0
- package/src/monitor.startup.test.ts +11 -9
- package/src/monitor.startup.ts +26 -16
- package/src/monitor.state.ts +20 -5
- package/src/monitor.synthetic-error.ts +18 -0
- package/src/monitor.test-mocks.ts +2 -2
- package/src/monitor.transport.ts +220 -60
- package/src/monitor.ts +15 -10
- package/src/monitor.webhook-e2e.test.ts +65 -7
- package/src/monitor.webhook-security.test.ts +122 -0
- package/src/monitor.webhook.test-helpers.ts +44 -26
- package/src/outbound-runtime-api.ts +1 -0
- package/src/outbound.test.ts +616 -37
- package/src/outbound.ts +623 -81
- package/src/perm-schema.ts +1 -1
- package/src/perm.ts +1 -7
- package/src/pins.ts +108 -0
- package/src/policy.test.ts +297 -117
- package/src/policy.ts +142 -29
- package/src/post.ts +7 -6
- package/src/probe.test.ts +14 -9
- package/src/probe.ts +26 -16
- package/src/processing-claims.ts +59 -0
- package/src/qr-terminal.ts +1 -0
- package/src/reactions.ts +4 -34
- package/src/reasoning-preview.test.ts +59 -0
- package/src/reasoning-preview.ts +20 -0
- package/src/reply-dispatcher-runtime-api.ts +7 -0
- package/src/reply-dispatcher.test.ts +660 -29
- package/src/reply-dispatcher.ts +407 -154
- package/src/runtime.ts +6 -3
- package/src/secret-contract.ts +145 -0
- package/src/secret-input.ts +1 -13
- package/src/security-audit-shared.ts +69 -0
- package/src/security-audit.test.ts +61 -0
- package/src/security-audit.ts +1 -0
- package/src/send-result.ts +1 -1
- package/src/send-target.test.ts +9 -3
- package/src/send-target.ts +10 -4
- package/src/send.reply-fallback.test.ts +77 -2
- package/src/send.test.ts +386 -4
- package/src/send.ts +399 -86
- package/src/sequential-key.test.ts +72 -0
- package/src/sequential-key.ts +28 -0
- package/src/sequential-queue.test.ts +92 -0
- package/src/sequential-queue.ts +16 -0
- package/src/session-conversation.ts +42 -0
- package/src/session-route.ts +48 -0
- package/src/setup-core.ts +51 -0
- package/src/{onboarding.test.ts → setup-surface.test.ts} +52 -21
- package/src/setup-surface.ts +581 -0
- package/src/streaming-card.test.ts +138 -2
- package/src/streaming-card.ts +134 -18
- package/src/subagent-hooks.test.ts +603 -0
- package/src/subagent-hooks.ts +397 -0
- package/src/targets.ts +3 -13
- package/src/test-support/lifecycle-test-support.ts +479 -0
- package/src/thread-bindings.test.ts +143 -0
- package/src/thread-bindings.ts +330 -0
- package/src/tool-account-routing.test.ts +66 -8
- package/src/tool-account.test.ts +44 -0
- package/src/tool-account.ts +40 -17
- package/src/tool-factory-test-harness.ts +11 -8
- package/src/tool-result.ts +3 -1
- package/src/tools-config.ts +1 -1
- package/src/types.ts +16 -15
- package/src/typing.ts +10 -6
- package/src/wiki-schema.ts +1 -1
- package/src/wiki.ts +1 -7
- package/subagent-hooks-api.ts +31 -0
- package/tsconfig.json +16 -0
- package/src/feishu-command-handler.ts +0 -59
- package/src/onboarding.status.test.ts +0 -25
- package/src/onboarding.ts +0 -489
- package/src/send-message.ts +0 -71
- package/src/targets.test.ts +0 -70
package/src/docx-table-ops.ts
CHANGED
|
@@ -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
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
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
|
|
82
|
+
const cellIds = normalizeChildBlockIds(tableBlock.children);
|
|
56
83
|
|
|
57
84
|
// Build block lookup map
|
|
58
|
-
|
|
59
|
-
const blockMap = new Map<string, any>();
|
|
85
|
+
const blockMap = new Map<string, FeishuDocxBlock>();
|
|
60
86
|
for (const block of blocks) {
|
|
61
|
-
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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)
|
|
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)
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
184
|
-
|
|
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
|
|
2
|
-
import {
|
|
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: {
|