cc-lark 0.1.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/.github/workflows/ci.yml +47 -0
- package/.github/workflows/release.yml +47 -0
- package/.github/workflows/sync-upstream.yml +127 -0
- package/.prettierrc.json +7 -0
- package/README.md +214 -0
- package/dist/core/api-error.d.ts +193 -0
- package/dist/core/api-error.d.ts.map +1 -0
- package/dist/core/api-error.js +263 -0
- package/dist/core/api-error.js.map +1 -0
- package/dist/core/auth-errors.d.ts +13 -0
- package/dist/core/auth-errors.d.ts.map +1 -0
- package/dist/core/auth-errors.js +14 -0
- package/dist/core/auth-errors.js.map +1 -0
- package/dist/core/config.d.ts +60 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +115 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/device-flow.d.ts +80 -0
- package/dist/core/device-flow.d.ts.map +1 -0
- package/dist/core/device-flow.js +231 -0
- package/dist/core/device-flow.js.map +1 -0
- package/dist/core/index.d.ts +16 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +16 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/lark-client.d.ts +136 -0
- package/dist/core/lark-client.d.ts.map +1 -0
- package/dist/core/lark-client.js +315 -0
- package/dist/core/lark-client.js.map +1 -0
- package/dist/core/token-store.d.ts +67 -0
- package/dist/core/token-store.d.ts.map +1 -0
- package/dist/core/token-store.js +215 -0
- package/dist/core/token-store.js.map +1 -0
- package/dist/core/types.d.ts +286 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +11 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/uat-client.d.ts +64 -0
- package/dist/core/uat-client.d.ts.map +1 -0
- package/dist/core/uat-client.js +227 -0
- package/dist/core/uat-client.js.map +1 -0
- package/dist/core/version.d.ts +26 -0
- package/dist/core/version.d.ts.map +1 -0
- package/dist/core/version.js +50 -0
- package/dist/core/version.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +116 -0
- package/dist/index.js.map +1 -0
- package/dist/tools/bitable/app.d.ts +20 -0
- package/dist/tools/bitable/app.d.ts.map +1 -0
- package/dist/tools/bitable/app.js +301 -0
- package/dist/tools/bitable/app.js.map +1 -0
- package/dist/tools/bitable/field.d.ts +19 -0
- package/dist/tools/bitable/field.d.ts.map +1 -0
- package/dist/tools/bitable/field.js +315 -0
- package/dist/tools/bitable/field.js.map +1 -0
- package/dist/tools/bitable/index.d.ts +21 -0
- package/dist/tools/bitable/index.d.ts.map +1 -0
- package/dist/tools/bitable/index.js +39 -0
- package/dist/tools/bitable/index.js.map +1 -0
- package/dist/tools/bitable/record.d.ts +22 -0
- package/dist/tools/bitable/record.d.ts.map +1 -0
- package/dist/tools/bitable/record.js +434 -0
- package/dist/tools/bitable/record.js.map +1 -0
- package/dist/tools/bitable/table.d.ts +21 -0
- package/dist/tools/bitable/table.d.ts.map +1 -0
- package/dist/tools/bitable/table.js +361 -0
- package/dist/tools/bitable/table.js.map +1 -0
- package/dist/tools/calendar/calendar.d.ts +18 -0
- package/dist/tools/calendar/calendar.d.ts.map +1 -0
- package/dist/tools/calendar/calendar.js +192 -0
- package/dist/tools/calendar/calendar.js.map +1 -0
- package/dist/tools/calendar/event.d.ts +20 -0
- package/dist/tools/calendar/event.d.ts.map +1 -0
- package/dist/tools/calendar/event.js +465 -0
- package/dist/tools/calendar/event.js.map +1 -0
- package/dist/tools/calendar/index.d.ts +19 -0
- package/dist/tools/calendar/index.d.ts.map +1 -0
- package/dist/tools/calendar/index.js +37 -0
- package/dist/tools/calendar/index.js.map +1 -0
- package/dist/tools/chat/chat.d.ts +11 -0
- package/dist/tools/chat/chat.d.ts.map +1 -0
- package/dist/tools/chat/chat.js +106 -0
- package/dist/tools/chat/chat.js.map +1 -0
- package/dist/tools/chat/index.d.ts +11 -0
- package/dist/tools/chat/index.d.ts.map +1 -0
- package/dist/tools/chat/index.js +20 -0
- package/dist/tools/chat/index.js.map +1 -0
- package/dist/tools/chat/members.d.ts +9 -0
- package/dist/tools/chat/members.d.ts.map +1 -0
- package/dist/tools/chat/members.js +80 -0
- package/dist/tools/chat/members.js.map +1 -0
- package/dist/tools/common/get-user.d.ts +11 -0
- package/dist/tools/common/get-user.d.ts.map +1 -0
- package/dist/tools/common/get-user.js +112 -0
- package/dist/tools/common/get-user.js.map +1 -0
- package/dist/tools/common/index.d.ts +11 -0
- package/dist/tools/common/index.d.ts.map +1 -0
- package/dist/tools/common/index.js +20 -0
- package/dist/tools/common/index.js.map +1 -0
- package/dist/tools/common/search-user.d.ts +9 -0
- package/dist/tools/common/search-user.d.ts.map +1 -0
- package/dist/tools/common/search-user.js +88 -0
- package/dist/tools/common/search-user.js.map +1 -0
- package/dist/tools/doc/create.d.ts +17 -0
- package/dist/tools/doc/create.d.ts.map +1 -0
- package/dist/tools/doc/create.js +159 -0
- package/dist/tools/doc/create.js.map +1 -0
- package/dist/tools/doc/fetch.d.ts +17 -0
- package/dist/tools/doc/fetch.d.ts.map +1 -0
- package/dist/tools/doc/fetch.js +123 -0
- package/dist/tools/doc/fetch.js.map +1 -0
- package/dist/tools/doc/index.d.ts +21 -0
- package/dist/tools/doc/index.d.ts.map +1 -0
- package/dist/tools/doc/index.js +33 -0
- package/dist/tools/doc/index.js.map +1 -0
- package/dist/tools/doc/shared.d.ts +69 -0
- package/dist/tools/doc/shared.d.ts.map +1 -0
- package/dist/tools/doc/shared.js +172 -0
- package/dist/tools/doc/shared.js.map +1 -0
- package/dist/tools/doc/update.d.ts +25 -0
- package/dist/tools/doc/update.d.ts.map +1 -0
- package/dist/tools/doc/update.js +208 -0
- package/dist/tools/doc/update.js.map +1 -0
- package/dist/tools/drive/file.d.ts +13 -0
- package/dist/tools/drive/file.d.ts.map +1 -0
- package/dist/tools/drive/file.js +212 -0
- package/dist/tools/drive/file.js.map +1 -0
- package/dist/tools/drive/index.d.ts +12 -0
- package/dist/tools/drive/index.d.ts.map +1 -0
- package/dist/tools/drive/index.js +25 -0
- package/dist/tools/drive/index.js.map +1 -0
- package/dist/tools/im/format-messages.d.ts +99 -0
- package/dist/tools/im/format-messages.d.ts.map +1 -0
- package/dist/tools/im/format-messages.js +277 -0
- package/dist/tools/im/format-messages.js.map +1 -0
- package/dist/tools/im/helpers.d.ts +53 -0
- package/dist/tools/im/helpers.d.ts.map +1 -0
- package/dist/tools/im/helpers.js +85 -0
- package/dist/tools/im/helpers.js.map +1 -0
- package/dist/tools/im/index.d.ts +25 -0
- package/dist/tools/im/index.d.ts.map +1 -0
- package/dist/tools/im/index.js +44 -0
- package/dist/tools/im/index.js.map +1 -0
- package/dist/tools/im/message-read.d.ts +19 -0
- package/dist/tools/im/message-read.d.ts.map +1 -0
- package/dist/tools/im/message-read.js +526 -0
- package/dist/tools/im/message-read.js.map +1 -0
- package/dist/tools/im/message.d.ts +22 -0
- package/dist/tools/im/message.d.ts.map +1 -0
- package/dist/tools/im/message.js +233 -0
- package/dist/tools/im/message.js.map +1 -0
- package/dist/tools/im/resource.d.ts +19 -0
- package/dist/tools/im/resource.d.ts.map +1 -0
- package/dist/tools/im/resource.js +185 -0
- package/dist/tools/im/resource.js.map +1 -0
- package/dist/tools/im/time-utils.d.ts +70 -0
- package/dist/tools/im/time-utils.d.ts.map +1 -0
- package/dist/tools/im/time-utils.js +277 -0
- package/dist/tools/im/time-utils.js.map +1 -0
- package/dist/tools/index.d.ts +85 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +135 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/oauth.d.ts +15 -0
- package/dist/tools/oauth.d.ts.map +1 -0
- package/dist/tools/oauth.js +379 -0
- package/dist/tools/oauth.js.map +1 -0
- package/dist/tools/search/doc-search.d.ts +9 -0
- package/dist/tools/search/doc-search.d.ts.map +1 -0
- package/dist/tools/search/doc-search.js +219 -0
- package/dist/tools/search/doc-search.js.map +1 -0
- package/dist/tools/search/index.d.ts +11 -0
- package/dist/tools/search/index.d.ts.map +1 -0
- package/dist/tools/search/index.js +18 -0
- package/dist/tools/search/index.js.map +1 -0
- package/dist/tools/sheets/index.d.ts +11 -0
- package/dist/tools/sheets/index.d.ts.map +1 -0
- package/dist/tools/sheets/index.js +18 -0
- package/dist/tools/sheets/index.js.map +1 -0
- package/dist/tools/sheets/sheet.d.ts +11 -0
- package/dist/tools/sheets/sheet.d.ts.map +1 -0
- package/dist/tools/sheets/sheet.js +332 -0
- package/dist/tools/sheets/sheet.js.map +1 -0
- package/dist/tools/task/index.d.ts +12 -0
- package/dist/tools/task/index.d.ts.map +1 -0
- package/dist/tools/task/index.js +30 -0
- package/dist/tools/task/index.js.map +1 -0
- package/dist/tools/task/task.d.ts +13 -0
- package/dist/tools/task/task.d.ts.map +1 -0
- package/dist/tools/task/task.js +225 -0
- package/dist/tools/task/task.js.map +1 -0
- package/dist/tools/task/tasklist.d.ts +13 -0
- package/dist/tools/task/tasklist.d.ts.map +1 -0
- package/dist/tools/task/tasklist.js +206 -0
- package/dist/tools/task/tasklist.js.map +1 -0
- package/dist/tools/wiki/index.d.ts +11 -0
- package/dist/tools/wiki/index.d.ts.map +1 -0
- package/dist/tools/wiki/index.js +20 -0
- package/dist/tools/wiki/index.js.map +1 -0
- package/dist/tools/wiki/node.d.ts +11 -0
- package/dist/tools/wiki/node.d.ts.map +1 -0
- package/dist/tools/wiki/node.js +112 -0
- package/dist/tools/wiki/node.js.map +1 -0
- package/dist/tools/wiki/space.d.ts +11 -0
- package/dist/tools/wiki/space.d.ts.map +1 -0
- package/dist/tools/wiki/space.js +125 -0
- package/dist/tools/wiki/space.js.map +1 -0
- package/dist/utils/index.d.ts +8 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +8 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/logger.d.ts +36 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +101 -0
- package/dist/utils/logger.js.map +1 -0
- package/eslint.config.js +13 -0
- package/package.json +54 -0
- package/skills/feishu-bitable/SKILL.md +248 -0
- package/skills/feishu-bitable/references/examples.md +813 -0
- package/skills/feishu-bitable/references/field-properties.md +763 -0
- package/skills/feishu-bitable/references/record-values.md +911 -0
- package/skills/feishu-calendar/SKILL.md +244 -0
- package/skills/feishu-channel-rules/SKILL.md +18 -0
- package/skills/feishu-channel-rules/references/markdown-syntax.md +138 -0
- package/skills/feishu-create-doc/SKILL.md +719 -0
- package/skills/feishu-fetch-doc/SKILL.md +93 -0
- package/skills/feishu-im-read/SKILL.md +163 -0
- package/skills/feishu-task/SKILL.md +293 -0
- package/skills/feishu-troubleshoot/SKILL.md +70 -0
- package/skills/feishu-update-doc/SKILL.md +285 -0
- package/src/core/api-error.ts +342 -0
- package/src/core/auth-errors.ts +27 -0
- package/src/core/config.ts +134 -0
- package/src/core/device-flow.ts +314 -0
- package/src/core/index.ts +16 -0
- package/src/core/lark-client.ts +391 -0
- package/src/core/token-store.ts +249 -0
- package/src/core/types.ts +302 -0
- package/src/core/uat-client.ts +298 -0
- package/src/core/version.ts +53 -0
- package/src/index.ts +138 -0
- package/src/tools/bitable/app.ts +390 -0
- package/src/tools/bitable/field.ts +406 -0
- package/src/tools/bitable/index.ts +43 -0
- package/src/tools/bitable/record.ts +559 -0
- package/src/tools/bitable/table.ts +472 -0
- package/src/tools/calendar/calendar.ts +254 -0
- package/src/tools/calendar/event.ts +606 -0
- package/src/tools/calendar/index.ts +41 -0
- package/src/tools/chat/chat.ts +127 -0
- package/src/tools/chat/index.ts +24 -0
- package/src/tools/chat/members.ts +93 -0
- package/src/tools/common/get-user.ts +127 -0
- package/src/tools/common/index.ts +24 -0
- package/src/tools/common/search-user.ts +99 -0
- package/src/tools/doc/create.ts +184 -0
- package/src/tools/doc/fetch.ts +149 -0
- package/src/tools/doc/index.ts +38 -0
- package/src/tools/doc/shared.ts +228 -0
- package/src/tools/doc/update.ts +240 -0
- package/src/tools/drive/file.ts +265 -0
- package/src/tools/drive/index.ts +29 -0
- package/src/tools/im/format-messages.ts +391 -0
- package/src/tools/im/helpers.ts +109 -0
- package/src/tools/im/index.ts +49 -0
- package/src/tools/im/message-read.ts +676 -0
- package/src/tools/im/message.ts +303 -0
- package/src/tools/im/resource.ts +225 -0
- package/src/tools/im/time-utils.ts +347 -0
- package/src/tools/index.ts +205 -0
- package/src/tools/oauth.ts +460 -0
- package/src/tools/search/doc-search.ts +250 -0
- package/src/tools/search/index.ts +22 -0
- package/src/tools/sheets/index.ts +22 -0
- package/src/tools/sheets/sheet.ts +382 -0
- package/src/tools/task/index.ts +34 -0
- package/src/tools/task/task.ts +265 -0
- package/src/tools/task/tasklist.ts +262 -0
- package/src/tools/wiki/index.ts +24 -0
- package/src/tools/wiki/node.ts +131 -0
- package/src/tools/wiki/space.ts +152 -0
- package/src/utils/index.ts +8 -0
- package/src/utils/logger.ts +132 -0
- package/tests/core/config.test.ts +238 -0
- package/tests/core/device-flow.test.ts +490 -0
- package/tests/core/lark-client.test.ts +378 -0
- package/tests/core/token-store.test.ts +438 -0
- package/tests/index.test.ts +360 -0
- package/tests/tools/doc/create.test.ts +224 -0
- package/tests/tools/doc/fetch.test.ts +182 -0
- package/tests/tools/doc/shared.test.ts +183 -0
- package/tests/tools/doc/update.test.ts +330 -0
- package/tests/tools/im/format-messages.test.ts +184 -0
- package/tests/tools/im/time-utils.test.ts +178 -0
- package/tests/utils/logger.test.ts +140 -0
- package/tsconfig.json +20 -0
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*
|
|
5
|
+
* feishu_bitable_table tool - Manage Feishu Bitable tables.
|
|
6
|
+
*
|
|
7
|
+
* Actions: create, list, patch, delete, batch_create, batch_delete
|
|
8
|
+
*
|
|
9
|
+
* Uses the Feishu Bitable v1 API:
|
|
10
|
+
* - create: POST /open-apis/bitable/v1/apps/:app_token/tables
|
|
11
|
+
* - list: GET /open-apis/bitable/v1/apps/:app_token/tables
|
|
12
|
+
* - patch: PATCH /open-apis/bitable/v1/apps/:app_token/tables/:table_id
|
|
13
|
+
* - delete: DELETE /open-apis/bitable/v1/apps/:app_token/tables/:table_id
|
|
14
|
+
* - batch_create: POST /open-apis/bitable/v1/apps/:app_token/tables/batch_create
|
|
15
|
+
* - batch_delete: POST /open-apis/bitable/v1/apps/:app_token/tables/batch_delete
|
|
16
|
+
*
|
|
17
|
+
* Adapted from openclaw-lark for MCP Server architecture.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { z } from 'zod';
|
|
21
|
+
import type { ToolRegistry } from '../index.js';
|
|
22
|
+
import { LarkClient } from '../../core/lark-client.js';
|
|
23
|
+
import { getValidAccessToken, NeedAuthorizationError } from '../../core/uat-client.js';
|
|
24
|
+
import { assertLarkOk } from '../../core/api-error.js';
|
|
25
|
+
import { json, jsonError, type ToolResult } from '../im/helpers.js';
|
|
26
|
+
import { logger } from '../../utils/logger.js';
|
|
27
|
+
|
|
28
|
+
const log = logger('tools:bitable:table');
|
|
29
|
+
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
// Input schemas
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
|
|
34
|
+
const fieldSchema = z.object({
|
|
35
|
+
field_name: z.string().describe('Field name'),
|
|
36
|
+
type: z.number().describe('Field type (1=text, 2=number, 3=single_select, 4=multi_select, 5=date, 7=checkbox, 11=person, 13=phone, 15=url, 17=attachment, 1001=created_time, 1002=modified_time, etc.)'),
|
|
37
|
+
property: z.any().optional().describe('Field property configuration (varies by type)'),
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const createActionSchema = {
|
|
41
|
+
action: z.literal('create').describe('Create a new table in the Bitable'),
|
|
42
|
+
app_token: z.string().describe('Bitable app token'),
|
|
43
|
+
table: z.object({
|
|
44
|
+
name: z.string().describe('Table name'),
|
|
45
|
+
default_view_name: z.string().optional().describe('Default view name'),
|
|
46
|
+
fields: z.array(fieldSchema).optional().describe('Fields to create (recommended to define all fields at creation time)'),
|
|
47
|
+
}).describe('Table configuration'),
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const listActionSchema = {
|
|
51
|
+
action: z.literal('list').describe('List tables in the Bitable'),
|
|
52
|
+
app_token: z.string().describe('Bitable app token'),
|
|
53
|
+
page_size: z.number().min(1).max(100).optional().describe('Page size (default 50)'),
|
|
54
|
+
page_token: z.string().optional().describe('Pagination token'),
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const patchActionSchema = {
|
|
58
|
+
action: z.literal('patch').describe('Update table metadata'),
|
|
59
|
+
app_token: z.string().describe('Bitable app token'),
|
|
60
|
+
table_id: z.string().describe('Table ID'),
|
|
61
|
+
name: z.string().optional().describe('New table name'),
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const deleteActionSchema = {
|
|
65
|
+
action: z.literal('delete').describe('Delete a table'),
|
|
66
|
+
app_token: z.string().describe('Bitable app token'),
|
|
67
|
+
table_id: z.string().describe('Table ID'),
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const batchCreateActionSchema = {
|
|
71
|
+
action: z.literal('batch_create').describe('Create multiple tables at once'),
|
|
72
|
+
app_token: z.string().describe('Bitable app token'),
|
|
73
|
+
tables: z.array(z.object({
|
|
74
|
+
name: z.string().describe('Table name'),
|
|
75
|
+
})).describe('Tables to create'),
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const batchDeleteActionSchema = {
|
|
79
|
+
action: z.literal('batch_delete').describe('Delete multiple tables at once'),
|
|
80
|
+
app_token: z.string().describe('Bitable app token'),
|
|
81
|
+
table_ids: z.array(z.string()).describe('Table IDs to delete'),
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
// ---------------------------------------------------------------------------
|
|
85
|
+
// Tool registration
|
|
86
|
+
// ---------------------------------------------------------------------------
|
|
87
|
+
|
|
88
|
+
export function registerBitableTableTool(registry: ToolRegistry): void {
|
|
89
|
+
registry.register({
|
|
90
|
+
name: 'feishu_bitable_table_create',
|
|
91
|
+
description: [
|
|
92
|
+
'Create a new table in a Feishu Bitable.',
|
|
93
|
+
'',
|
|
94
|
+
'Parameters:',
|
|
95
|
+
'- app_token: Bitable app token',
|
|
96
|
+
'- table: Table configuration with name and optional fields',
|
|
97
|
+
'',
|
|
98
|
+
'Returns the created table ID.',
|
|
99
|
+
'Requires OAuth authorization.',
|
|
100
|
+
].join('\n'),
|
|
101
|
+
inputSchema: createActionSchema,
|
|
102
|
+
handler: async (args, context) => handleCreate(args, context),
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
registry.register({
|
|
106
|
+
name: 'feishu_bitable_table_list',
|
|
107
|
+
description: [
|
|
108
|
+
'List tables in a Feishu Bitable.',
|
|
109
|
+
'',
|
|
110
|
+
'Parameters:',
|
|
111
|
+
'- app_token: Bitable app token',
|
|
112
|
+
'- page_size: Page size (default 50)',
|
|
113
|
+
'- page_token: Pagination token',
|
|
114
|
+
'',
|
|
115
|
+
'Returns list of tables.',
|
|
116
|
+
'Requires OAuth authorization.',
|
|
117
|
+
].join('\n'),
|
|
118
|
+
inputSchema: listActionSchema,
|
|
119
|
+
handler: async (args, context) => handleList(args, context),
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
registry.register({
|
|
123
|
+
name: 'feishu_bitable_table_patch',
|
|
124
|
+
description: [
|
|
125
|
+
'Update a Feishu Bitable table name.',
|
|
126
|
+
'',
|
|
127
|
+
'Parameters:',
|
|
128
|
+
'- app_token: Bitable app token',
|
|
129
|
+
'- table_id: Table ID',
|
|
130
|
+
'- name: New table name',
|
|
131
|
+
'',
|
|
132
|
+
'Returns the updated table info.',
|
|
133
|
+
'Requires OAuth authorization.',
|
|
134
|
+
].join('\n'),
|
|
135
|
+
inputSchema: patchActionSchema,
|
|
136
|
+
handler: async (args, context) => handlePatch(args, context),
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
registry.register({
|
|
140
|
+
name: 'feishu_bitable_table_delete',
|
|
141
|
+
description: [
|
|
142
|
+
'Delete a table from a Feishu Bitable.',
|
|
143
|
+
'',
|
|
144
|
+
'Parameters:',
|
|
145
|
+
'- app_token: Bitable app token',
|
|
146
|
+
'- table_id: Table ID',
|
|
147
|
+
'',
|
|
148
|
+
'Returns success status.',
|
|
149
|
+
'Requires OAuth authorization.',
|
|
150
|
+
].join('\n'),
|
|
151
|
+
inputSchema: deleteActionSchema,
|
|
152
|
+
handler: async (args, context) => handleDelete(args, context),
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
registry.register({
|
|
156
|
+
name: 'feishu_bitable_table_batch_create',
|
|
157
|
+
description: [
|
|
158
|
+
'Create multiple tables in a Feishu Bitable at once.',
|
|
159
|
+
'',
|
|
160
|
+
'Parameters:',
|
|
161
|
+
'- app_token: Bitable app token',
|
|
162
|
+
'- tables: Array of table configurations',
|
|
163
|
+
'',
|
|
164
|
+
'Returns created table IDs.',
|
|
165
|
+
'Requires OAuth authorization.',
|
|
166
|
+
].join('\n'),
|
|
167
|
+
inputSchema: batchCreateActionSchema,
|
|
168
|
+
handler: async (args, context) => handleBatchCreate(args, context),
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
registry.register({
|
|
172
|
+
name: 'feishu_bitable_table_batch_delete',
|
|
173
|
+
description: [
|
|
174
|
+
'Delete multiple tables from a Feishu Bitable at once.',
|
|
175
|
+
'',
|
|
176
|
+
'Parameters:',
|
|
177
|
+
'- app_token: Bitable app token',
|
|
178
|
+
'- table_ids: Array of table IDs to delete',
|
|
179
|
+
'',
|
|
180
|
+
'Returns success status.',
|
|
181
|
+
'Requires OAuth authorization.',
|
|
182
|
+
].join('\n'),
|
|
183
|
+
inputSchema: batchDeleteActionSchema,
|
|
184
|
+
handler: async (args, context) => handleBatchDelete(args, context),
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
log.debug('feishu_bitable_table tools registered');
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// ---------------------------------------------------------------------------
|
|
191
|
+
// Helpers
|
|
192
|
+
// ---------------------------------------------------------------------------
|
|
193
|
+
|
|
194
|
+
async function getAccessToken(context: { larkClient: LarkClient | null; config: import('../../core/types.js').FeishuConfig }): Promise<string | ToolResult> {
|
|
195
|
+
const { larkClient, config } = context;
|
|
196
|
+
if (!larkClient) {
|
|
197
|
+
return jsonError('LarkClient not initialized. Check FEISHU_APP_ID and FEISHU_APP_SECRET.');
|
|
198
|
+
}
|
|
199
|
+
const { appId, appSecret, brand } = config;
|
|
200
|
+
if (!appId || !appSecret) {
|
|
201
|
+
return jsonError('Missing FEISHU_APP_ID or FEISHU_APP_SECRET.');
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const { listStoredTokens } = await import('../../core/token-store.js');
|
|
205
|
+
const tokens = await listStoredTokens(appId);
|
|
206
|
+
if (tokens.length === 0) {
|
|
207
|
+
return jsonError(
|
|
208
|
+
'No user authorization found. Please use the feishu_oauth tool with action="authorize" to authorize a user first.'
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const userOpenId = tokens[0].userOpenId;
|
|
213
|
+
|
|
214
|
+
try {
|
|
215
|
+
return await getValidAccessToken({
|
|
216
|
+
userOpenId,
|
|
217
|
+
appId,
|
|
218
|
+
appSecret,
|
|
219
|
+
domain: brand ?? 'feishu',
|
|
220
|
+
});
|
|
221
|
+
} catch (err) {
|
|
222
|
+
if (err instanceof NeedAuthorizationError) {
|
|
223
|
+
return jsonError(
|
|
224
|
+
`User authorization required or expired. Please use feishu_oauth tool with action="authorize" to re-authorize.`,
|
|
225
|
+
{ userOpenId }
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
throw err;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// ---------------------------------------------------------------------------
|
|
233
|
+
// Handlers
|
|
234
|
+
// ---------------------------------------------------------------------------
|
|
235
|
+
|
|
236
|
+
async function handleCreate(
|
|
237
|
+
args: unknown,
|
|
238
|
+
context: { larkClient: LarkClient | null; config: import('../../core/types.js').FeishuConfig }
|
|
239
|
+
): Promise<ToolResult> {
|
|
240
|
+
const p = args as z.infer<ReturnType<typeof z.object<typeof createActionSchema>>>;
|
|
241
|
+
const { larkClient } = context;
|
|
242
|
+
|
|
243
|
+
const accessTokenResult = await getAccessToken(context);
|
|
244
|
+
if (typeof accessTokenResult === 'object' && 'content' in accessTokenResult) {
|
|
245
|
+
return accessTokenResult;
|
|
246
|
+
}
|
|
247
|
+
const accessToken = accessTokenResult;
|
|
248
|
+
|
|
249
|
+
log.info(`create: app_token=${p.app_token}, table_name=${p.table.name}, fields_count=${p.table.fields?.length ?? 0}`);
|
|
250
|
+
|
|
251
|
+
const Lark = await import('@larksuiteoapi/node-sdk');
|
|
252
|
+
const opts = Lark.withUserAccessToken(accessToken);
|
|
253
|
+
|
|
254
|
+
// Handle special case: checkbox (type=7) and URL (type=15) fields must not have property
|
|
255
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
256
|
+
const tableData = { ...p.table } as any;
|
|
257
|
+
if (tableData.fields) {
|
|
258
|
+
tableData.fields = tableData.fields.map((field: { type: number; property?: unknown }) => {
|
|
259
|
+
if ((field.type === 7 || field.type === 15) && field.property !== undefined) {
|
|
260
|
+
const fieldTypeName = field.type === 15 ? 'URL' : 'Checkbox';
|
|
261
|
+
log.warn(`create: ${fieldTypeName} field (type=${field.type}) detected with property. Removing property to avoid API error.`);
|
|
262
|
+
const { property: _property, ...fieldWithoutProperty } = field;
|
|
263
|
+
return fieldWithoutProperty;
|
|
264
|
+
}
|
|
265
|
+
return field;
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
const res = await larkClient!.sdk.bitable.appTable.create(
|
|
270
|
+
{
|
|
271
|
+
path: { app_token: p.app_token },
|
|
272
|
+
data: { table: tableData },
|
|
273
|
+
},
|
|
274
|
+
opts
|
|
275
|
+
);
|
|
276
|
+
assertLarkOk(res);
|
|
277
|
+
|
|
278
|
+
log.info(`create: created table ${res.data?.table_id}`);
|
|
279
|
+
|
|
280
|
+
return json({
|
|
281
|
+
table_id: res.data?.table_id,
|
|
282
|
+
default_view_id: res.data?.default_view_id,
|
|
283
|
+
field_id_list: res.data?.field_id_list,
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
async function handleList(
|
|
288
|
+
args: unknown,
|
|
289
|
+
context: { larkClient: LarkClient | null; config: import('../../core/types.js').FeishuConfig }
|
|
290
|
+
): Promise<ToolResult> {
|
|
291
|
+
const p = args as z.infer<ReturnType<typeof z.object<typeof listActionSchema>>>;
|
|
292
|
+
const { larkClient } = context;
|
|
293
|
+
|
|
294
|
+
const accessTokenResult = await getAccessToken(context);
|
|
295
|
+
if (typeof accessTokenResult === 'object' && 'content' in accessTokenResult) {
|
|
296
|
+
return accessTokenResult;
|
|
297
|
+
}
|
|
298
|
+
const accessToken = accessTokenResult;
|
|
299
|
+
|
|
300
|
+
log.info(`list: app_token=${p.app_token}, page_size=${p.page_size ?? 50}`);
|
|
301
|
+
|
|
302
|
+
const Lark = await import('@larksuiteoapi/node-sdk');
|
|
303
|
+
const opts = Lark.withUserAccessToken(accessToken);
|
|
304
|
+
|
|
305
|
+
const res = await larkClient!.sdk.bitable.appTable.list(
|
|
306
|
+
{
|
|
307
|
+
path: { app_token: p.app_token },
|
|
308
|
+
params: {
|
|
309
|
+
page_size: p.page_size,
|
|
310
|
+
page_token: p.page_token,
|
|
311
|
+
},
|
|
312
|
+
},
|
|
313
|
+
opts
|
|
314
|
+
);
|
|
315
|
+
assertLarkOk(res);
|
|
316
|
+
|
|
317
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
318
|
+
const data = res.data as any;
|
|
319
|
+
|
|
320
|
+
log.info(`list: returned ${data?.items?.length ?? 0} tables`);
|
|
321
|
+
|
|
322
|
+
return json({
|
|
323
|
+
tables: data?.items,
|
|
324
|
+
has_more: data?.has_more ?? false,
|
|
325
|
+
page_token: data?.page_token,
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
async function handlePatch(
|
|
330
|
+
args: unknown,
|
|
331
|
+
context: { larkClient: LarkClient | null; config: import('../../core/types.js').FeishuConfig }
|
|
332
|
+
): Promise<ToolResult> {
|
|
333
|
+
const p = args as z.infer<ReturnType<typeof z.object<typeof patchActionSchema>>>;
|
|
334
|
+
const { larkClient } = context;
|
|
335
|
+
|
|
336
|
+
const accessTokenResult = await getAccessToken(context);
|
|
337
|
+
if (typeof accessTokenResult === 'object' && 'content' in accessTokenResult) {
|
|
338
|
+
return accessTokenResult;
|
|
339
|
+
}
|
|
340
|
+
const accessToken = accessTokenResult;
|
|
341
|
+
|
|
342
|
+
log.info(`patch: app_token=${p.app_token}, table_id=${p.table_id}, name=${p.name}`);
|
|
343
|
+
|
|
344
|
+
const Lark = await import('@larksuiteoapi/node-sdk');
|
|
345
|
+
const opts = Lark.withUserAccessToken(accessToken);
|
|
346
|
+
|
|
347
|
+
const res = await larkClient!.sdk.bitable.appTable.patch(
|
|
348
|
+
{
|
|
349
|
+
path: {
|
|
350
|
+
app_token: p.app_token,
|
|
351
|
+
table_id: p.table_id,
|
|
352
|
+
},
|
|
353
|
+
data: { name: p.name },
|
|
354
|
+
},
|
|
355
|
+
opts
|
|
356
|
+
);
|
|
357
|
+
assertLarkOk(res);
|
|
358
|
+
|
|
359
|
+
log.info(`patch: updated table ${p.table_id}`);
|
|
360
|
+
|
|
361
|
+
return json({
|
|
362
|
+
name: res.data?.name,
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
async function handleDelete(
|
|
367
|
+
args: unknown,
|
|
368
|
+
context: { larkClient: LarkClient | null; config: import('../../core/types.js').FeishuConfig }
|
|
369
|
+
): Promise<ToolResult> {
|
|
370
|
+
const p = args as z.infer<ReturnType<typeof z.object<typeof deleteActionSchema>>>;
|
|
371
|
+
const { larkClient } = context;
|
|
372
|
+
|
|
373
|
+
const accessTokenResult = await getAccessToken(context);
|
|
374
|
+
if (typeof accessTokenResult === 'object' && 'content' in accessTokenResult) {
|
|
375
|
+
return accessTokenResult;
|
|
376
|
+
}
|
|
377
|
+
const accessToken = accessTokenResult;
|
|
378
|
+
|
|
379
|
+
log.info(`delete: app_token=${p.app_token}, table_id=${p.table_id}`);
|
|
380
|
+
|
|
381
|
+
const Lark = await import('@larksuiteoapi/node-sdk');
|
|
382
|
+
const opts = Lark.withUserAccessToken(accessToken);
|
|
383
|
+
|
|
384
|
+
const res = await larkClient!.sdk.bitable.appTable.delete(
|
|
385
|
+
{
|
|
386
|
+
path: {
|
|
387
|
+
app_token: p.app_token,
|
|
388
|
+
table_id: p.table_id,
|
|
389
|
+
},
|
|
390
|
+
},
|
|
391
|
+
opts
|
|
392
|
+
);
|
|
393
|
+
assertLarkOk(res);
|
|
394
|
+
|
|
395
|
+
log.info(`delete: deleted table ${p.table_id}`);
|
|
396
|
+
|
|
397
|
+
return json({ success: true });
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
async function handleBatchCreate(
|
|
401
|
+
args: unknown,
|
|
402
|
+
context: { larkClient: LarkClient | null; config: import('../../core/types.js').FeishuConfig }
|
|
403
|
+
): Promise<ToolResult> {
|
|
404
|
+
const p = args as z.infer<ReturnType<typeof z.object<typeof batchCreateActionSchema>>>;
|
|
405
|
+
const { larkClient } = context;
|
|
406
|
+
|
|
407
|
+
if (!p.tables || p.tables.length === 0) {
|
|
408
|
+
return jsonError('tables is required and cannot be empty');
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
const accessTokenResult = await getAccessToken(context);
|
|
412
|
+
if (typeof accessTokenResult === 'object' && 'content' in accessTokenResult) {
|
|
413
|
+
return accessTokenResult;
|
|
414
|
+
}
|
|
415
|
+
const accessToken = accessTokenResult;
|
|
416
|
+
|
|
417
|
+
log.info(`batch_create: app_token=${p.app_token}, tables_count=${p.tables.length}`);
|
|
418
|
+
|
|
419
|
+
const Lark = await import('@larksuiteoapi/node-sdk');
|
|
420
|
+
const opts = Lark.withUserAccessToken(accessToken);
|
|
421
|
+
|
|
422
|
+
const res = await larkClient!.sdk.bitable.appTable.batchCreate(
|
|
423
|
+
{
|
|
424
|
+
path: { app_token: p.app_token },
|
|
425
|
+
data: { tables: p.tables },
|
|
426
|
+
},
|
|
427
|
+
opts
|
|
428
|
+
);
|
|
429
|
+
assertLarkOk(res);
|
|
430
|
+
|
|
431
|
+
log.info(`batch_create: created ${p.tables.length} tables`);
|
|
432
|
+
|
|
433
|
+
return json({
|
|
434
|
+
table_ids: res.data?.table_ids,
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
async function handleBatchDelete(
|
|
439
|
+
args: unknown,
|
|
440
|
+
context: { larkClient: LarkClient | null; config: import('../../core/types.js').FeishuConfig }
|
|
441
|
+
): Promise<ToolResult> {
|
|
442
|
+
const p = args as z.infer<ReturnType<typeof z.object<typeof batchDeleteActionSchema>>>;
|
|
443
|
+
const { larkClient } = context;
|
|
444
|
+
|
|
445
|
+
if (!p.table_ids || p.table_ids.length === 0) {
|
|
446
|
+
return jsonError('table_ids is required and cannot be empty');
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
const accessTokenResult = await getAccessToken(context);
|
|
450
|
+
if (typeof accessTokenResult === 'object' && 'content' in accessTokenResult) {
|
|
451
|
+
return accessTokenResult;
|
|
452
|
+
}
|
|
453
|
+
const accessToken = accessTokenResult;
|
|
454
|
+
|
|
455
|
+
log.info(`batch_delete: app_token=${p.app_token}, table_ids_count=${p.table_ids.length}`);
|
|
456
|
+
|
|
457
|
+
const Lark = await import('@larksuiteoapi/node-sdk');
|
|
458
|
+
const opts = Lark.withUserAccessToken(accessToken);
|
|
459
|
+
|
|
460
|
+
const res = await larkClient!.sdk.bitable.appTable.batchDelete(
|
|
461
|
+
{
|
|
462
|
+
path: { app_token: p.app_token },
|
|
463
|
+
data: { table_ids: p.table_ids },
|
|
464
|
+
},
|
|
465
|
+
opts
|
|
466
|
+
);
|
|
467
|
+
assertLarkOk(res);
|
|
468
|
+
|
|
469
|
+
log.info(`batch_delete: deleted ${p.table_ids.length} tables`);
|
|
470
|
+
|
|
471
|
+
return json({ success: true });
|
|
472
|
+
}
|