@larksuite/openclaw-lark 2026.4.8 → 2026.4.9-beta.0
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/package.json +2 -1
- package/skills/feishu-task/SKILL.md +51 -32
- package/src/core/raw-request.js +26 -2
- package/src/core/tool-scopes.d.ts +2 -2
- package/src/core/tool-scopes.js +6 -1
- package/src/tools/oapi/index.js +2 -0
- package/src/tools/oapi/task/attachment.d.ts +18 -0
- package/src/tools/oapi/task/attachment.js +107 -0
- package/src/tools/oapi/task/comment.d.ts +1 -1
- package/src/tools/oapi/task/comment.js +11 -5
- package/src/tools/oapi/task/index.d.ts +2 -0
- package/src/tools/oapi/task/index.js +5 -1
- package/src/tools/oapi/task/section.d.ts +1 -1
- package/src/tools/oapi/task/section.js +15 -7
- package/src/tools/oapi/task/subtask.d.ts +1 -1
- package/src/tools/oapi/task/subtask.js +12 -6
- package/src/tools/oapi/task/task.d.ts +3 -0
- package/src/tools/oapi/task/task.js +174 -9
- package/src/tools/oapi/task/task_agent.d.ts +14 -0
- package/src/tools/oapi/task/task_agent.js +108 -0
- package/src/tools/oapi/task/tasklist.d.ts +1 -1
- package/src/tools/oapi/task/tasklist.js +30 -13
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@larksuite/openclaw-lark",
|
|
3
|
-
"version": "2026.4.
|
|
3
|
+
"version": "2026.4.9-beta.0",
|
|
4
4
|
"description": "OpenClaw Lark/Feishu channel plugin",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"@larksuiteoapi/node-sdk": "^1.60.0",
|
|
27
27
|
"@sinclair/typebox": "0.34.48",
|
|
28
28
|
"image-size": "^2.0.2",
|
|
29
|
+
"undici-types": "^8.1.0",
|
|
29
30
|
"zod": "^4.3.6"
|
|
30
31
|
},
|
|
31
32
|
"peerDependencies": {
|
|
@@ -8,7 +8,7 @@ description: |
|
|
|
8
8
|
(2) 需要创建、管理任务清单
|
|
9
9
|
(3) 需要查看任务列表或清单内的任务
|
|
10
10
|
(4) 用户提到"任务"、"待办"、"to-do"、"清单"、"task"
|
|
11
|
-
(5)
|
|
11
|
+
(5) 需要设置任务负责人、关注人、截止时间、添加成员
|
|
12
12
|
---
|
|
13
13
|
|
|
14
14
|
# 飞书任务管理
|
|
@@ -16,6 +16,7 @@ description: |
|
|
|
16
16
|
## 🚨 执行前必读
|
|
17
17
|
|
|
18
18
|
- ✅ **时间格式**:ISO 8601 / RFC 3339(带时区),例如 `2026-02-28T17:00:00+08:00`
|
|
19
|
+
- ✅ **身份授权**:工具支持 `auth_type` 为 `user`(默认,用户身份)或 `tenant`(应用身份)。
|
|
19
20
|
- ✅ **current_user_id 强烈建议**:从消息上下文的 SenderId 获取(ou_...),工具会自动添加为 follower(如不在 members 中),确保创建者可以编辑任务
|
|
20
21
|
- ✅ **patch/get 必须**:task_guid
|
|
21
22
|
- ✅ **tasklist.tasks 必须**:tasklist_guid
|
|
@@ -28,12 +29,13 @@ description: |
|
|
|
28
29
|
|
|
29
30
|
| 用户意图 | 工具 | action | 必填参数 | 强烈建议 | 常用可选 |
|
|
30
31
|
|---------|------|--------|---------|---------|---------|
|
|
31
|
-
| 新建待办 | feishu_task_task | create | summary | current_user_id(SenderId) | members, due, description |
|
|
32
|
-
| 查未完成任务 | feishu_task_task | list | - | completed=false | page_size |
|
|
33
|
-
| 获取任务详情 | feishu_task_task | get | task_guid | - |
|
|
34
|
-
| 完成任务 | feishu_task_task | patch | task_guid, completed_at | - |
|
|
35
|
-
| 反完成任务 | feishu_task_task | patch | task_guid, completed_at="0" | - |
|
|
36
|
-
| 改截止时间 | feishu_task_task | patch | task_guid, due | - |
|
|
32
|
+
| 新建待办 | feishu_task_task | create | summary | current_user_id(SenderId) | members, due, description, auth_type |
|
|
33
|
+
| 查未完成任务 | feishu_task_task | list | - | completed=false | page_size, auth_type |
|
|
34
|
+
| 获取任务详情 | feishu_task_task | get | task_guid | - | auth_type |
|
|
35
|
+
| 完成任务 | feishu_task_task | patch | task_guid, completed_at | - | auth_type |
|
|
36
|
+
| 反完成任务 | feishu_task_task | patch | task_guid, completed_at="0" | - | auth_type |
|
|
37
|
+
| 改截止时间 | feishu_task_task | patch | task_guid, due | - | auth_type |
|
|
38
|
+
| 添加任务成员 | feishu_task_task | add_members | task_guid, members[] | - | auth_type |
|
|
37
39
|
| 创建清单 | feishu_task_tasklist | create | name | - | members |
|
|
38
40
|
| 查看清单任务 | feishu_task_tasklist | tasks | tasklist_guid | - | completed |
|
|
39
41
|
| 添加清单成员 | feishu_task_tasklist | add_members | tasklist_guid, members[] | - | - |
|
|
@@ -42,38 +44,39 @@ description: |
|
|
|
42
44
|
|
|
43
45
|
## 🎯 核心约束(Schema 未透露的知识)
|
|
44
46
|
|
|
45
|
-
### 1.
|
|
47
|
+
### 1. 授权身份与可见性 (auth_type)
|
|
46
48
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
-
|
|
51
|
-
-
|
|
52
|
-
- ⚠️ **如果创建时没把自己加入成员,后续无法编辑该任务**
|
|
49
|
+
**工具支持两种调用身份 `auth_type`**:
|
|
50
|
+
- **`user` (默认)**:用户身份(user_access_token)。用于需要严格代表用户操作或查询用户私有任务的场景。
|
|
51
|
+
- ⚠️ 使用 `user` 身份时,只能查看和编辑**自己是成员的任务**。
|
|
52
|
+
- ⚠️ **如果创建时没把自己加入成员,后续无法编辑该任务**。
|
|
53
|
+
- **`tenant`**:应用身份(tenant_access_token)。当用户身份不满足要求时,使用应用身份。如果创建的任务没有把用户加入成员,用户可能看不见。
|
|
53
54
|
|
|
54
55
|
**自动保护机制**:
|
|
55
56
|
- 传入 `current_user_id` 参数(从 SenderId 获取)
|
|
56
57
|
- 如果 `members` 中不包含 `current_user_id`,工具会**自动添加为 follower**
|
|
57
|
-
-
|
|
58
|
-
|
|
59
|
-
**推荐用法**:创建任务时始终传 `current_user_id`,工具会自动处理成员关系。
|
|
58
|
+
- 确保创建者始终可以编辑和查看任务
|
|
60
59
|
|
|
61
|
-
### 2.
|
|
60
|
+
### 2. 任务成员的角色与类型
|
|
62
61
|
|
|
63
|
-
-
|
|
64
|
-
- **
|
|
62
|
+
- **角色 (role)**:
|
|
63
|
+
- **assignee(负责人)**:负责完成任务,可以编辑任务
|
|
64
|
+
- **follower(关注人)**:关注任务进展,接收通知
|
|
65
|
+
- **类型 (type)**:
|
|
66
|
+
- **user(默认,用户)**:普通的飞书用户
|
|
67
|
+
- **app(应用/机器人)**:如果是把机器人自己或者其他应用加入任务,必须指定 `type: "app"`
|
|
65
68
|
|
|
66
69
|
**添加成员示例**:
|
|
67
70
|
```json
|
|
68
71
|
{
|
|
69
72
|
"members": [
|
|
70
|
-
{"id": "ou_xxx", "role": "assignee"}, //
|
|
71
|
-
{"id": "
|
|
73
|
+
{"id": "ou_xxx", "role": "assignee", "type": "user"}, // 负责人(用户)
|
|
74
|
+
{"id": "cli_yyy", "role": "follower", "type": "app"} // 关注人(机器人/应用)
|
|
72
75
|
]
|
|
73
76
|
}
|
|
74
77
|
```
|
|
75
78
|
|
|
76
|
-
**说明**:`id`
|
|
79
|
+
**说明**:`id` 默认使用 `open_id`。
|
|
77
80
|
|
|
78
81
|
### 3. 任务清单角色冲突
|
|
79
82
|
|
|
@@ -133,12 +136,13 @@ description: |
|
|
|
133
136
|
"summary": "准备周会材料",
|
|
134
137
|
"description": "整理本周工作进展和下周计划",
|
|
135
138
|
"current_user_id": "ou_发送者的open_id",
|
|
139
|
+
"auth_type": "tenant",
|
|
136
140
|
"due": {
|
|
137
141
|
"timestamp": "2026-02-28 17:00:00",
|
|
138
142
|
"is_all_day": false
|
|
139
143
|
},
|
|
140
144
|
"members": [
|
|
141
|
-
{"id": "ou_协作者的open_id", "role": "assignee"}
|
|
145
|
+
{"id": "ou_协作者的open_id", "role": "assignee", "type": "user"}
|
|
142
146
|
]
|
|
143
147
|
}
|
|
144
148
|
```
|
|
@@ -147,7 +151,7 @@ description: |
|
|
|
147
151
|
- `summary` 是必填字段
|
|
148
152
|
- `current_user_id` 强烈建议传入(从 SenderId 获取),工具会自动添加为 follower
|
|
149
153
|
- `members` 可以只包含其他协作者,当前用户会被自动添加
|
|
150
|
-
-
|
|
154
|
+
- 时间使用带时区的 ISO 8601 格式
|
|
151
155
|
|
|
152
156
|
### 场景 2: 查询我负责的未完成任务
|
|
153
157
|
|
|
@@ -155,11 +159,25 @@ description: |
|
|
|
155
159
|
{
|
|
156
160
|
"action": "list",
|
|
157
161
|
"completed": false,
|
|
158
|
-
"page_size": 20
|
|
162
|
+
"page_size": 20,
|
|
163
|
+
"auth_type": "user"
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### 场景 3: 为现有任务添加机器人或成员
|
|
168
|
+
|
|
169
|
+
```json
|
|
170
|
+
{
|
|
171
|
+
"action": "add_members",
|
|
172
|
+
"task_guid": "任务的guid",
|
|
173
|
+
"auth_type": "tenant",
|
|
174
|
+
"members": [
|
|
175
|
+
{"id": "cli_机器人的app_id", "role": "follower", "type": "app"}
|
|
176
|
+
]
|
|
159
177
|
}
|
|
160
178
|
```
|
|
161
179
|
|
|
162
|
-
### 场景
|
|
180
|
+
### 场景 4: 完成任务
|
|
163
181
|
|
|
164
182
|
```json
|
|
165
183
|
{
|
|
@@ -169,7 +187,7 @@ description: |
|
|
|
169
187
|
}
|
|
170
188
|
```
|
|
171
189
|
|
|
172
|
-
### 场景
|
|
190
|
+
### 场景 5: 反完成任务(恢复未完成状态)
|
|
173
191
|
|
|
174
192
|
```json
|
|
175
193
|
{
|
|
@@ -179,7 +197,7 @@ description: |
|
|
|
179
197
|
}
|
|
180
198
|
```
|
|
181
199
|
|
|
182
|
-
### 场景
|
|
200
|
+
### 场景 6: 创建清单并添加协作者
|
|
183
201
|
|
|
184
202
|
```json
|
|
185
203
|
{
|
|
@@ -192,7 +210,7 @@ description: |
|
|
|
192
210
|
}
|
|
193
211
|
```
|
|
194
212
|
|
|
195
|
-
### 场景
|
|
213
|
+
### 场景 7: 查看清单内的未完成任务
|
|
196
214
|
|
|
197
215
|
```json
|
|
198
216
|
{
|
|
@@ -202,7 +220,7 @@ description: |
|
|
|
202
220
|
}
|
|
203
221
|
```
|
|
204
222
|
|
|
205
|
-
### 场景
|
|
223
|
+
### 场景 8: 全天任务
|
|
206
224
|
|
|
207
225
|
```json
|
|
208
226
|
{
|
|
@@ -222,10 +240,11 @@ description: |
|
|
|
222
240
|
| 错误现象 | 根本原因 | 解决方案 |
|
|
223
241
|
|---------|---------|---------|
|
|
224
242
|
| **创建后无法编辑任务** | 创建时未将自己加入 members | 创建时至少将当前用户(SenderId)加为 assignee 或 follower |
|
|
225
|
-
| **patch 失败提示 task_guid 缺失** | 未传 task_guid 参数 | patch/get 必须传 task_guid |
|
|
243
|
+
| **patch 失败提示 task_guid 缺失** | 未传 task_guid 参数 | patch/get/add_members 必须传 task_guid |
|
|
226
244
|
| **tasks 失败提示 tasklist_guid 缺失** | 未传 tasklist_guid 参数 | tasklist.tasks action 必须传 tasklist_guid |
|
|
227
245
|
| **反完成失败** | completed_at 格式错误 | 使用 `"0"` 字符串,不是数字 0 |
|
|
228
246
|
| **时间不对** | 使用了 Unix 时间戳 | 改用 ISO 8601 格式(带时区):`2024-01-01T00:00:00+08:00` |
|
|
247
|
+
| **添加机器人失败** | 未指定成员 type 为 app | 将机器人的 type 指定为 `"app"` |
|
|
229
248
|
|
|
230
249
|
---
|
|
231
250
|
|
package/src/core/raw-request.js
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.resolveDomainUrl = resolveDomainUrl;
|
|
13
13
|
exports.rawLarkRequest = rawLarkRequest;
|
|
14
|
+
const node_url_1 = require("node:url");
|
|
14
15
|
const feishu_fetch_1 = require("./feishu-fetch.js");
|
|
15
16
|
// ---------------------------------------------------------------------------
|
|
16
17
|
// Domain URL resolution
|
|
@@ -23,6 +24,24 @@ function resolveDomainUrl(brand) {
|
|
|
23
24
|
};
|
|
24
25
|
return map[brand] ?? `https://${brand}`;
|
|
25
26
|
}
|
|
27
|
+
function isFormDataBody(body) {
|
|
28
|
+
return (typeof body === 'object' &&
|
|
29
|
+
body !== null &&
|
|
30
|
+
typeof body.append === 'function' &&
|
|
31
|
+
typeof body.entries === 'function');
|
|
32
|
+
}
|
|
33
|
+
function isBinaryBody(body) {
|
|
34
|
+
return body instanceof ArrayBuffer || ArrayBuffer.isView(body);
|
|
35
|
+
}
|
|
36
|
+
function buildRequestBody(body) {
|
|
37
|
+
if (typeof body === 'string' || body instanceof node_url_1.URLSearchParams || isFormDataBody(body) || isBinaryBody(body)) {
|
|
38
|
+
return { body: body };
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
headers: { 'Content-Type': 'application/json' },
|
|
42
|
+
body: JSON.stringify(body),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
26
45
|
/**
|
|
27
46
|
* 发起 raw HTTP 请求到飞书 API,自动处理域名解析、header 注入和错误检测。
|
|
28
47
|
*
|
|
@@ -37,11 +56,16 @@ async function rawLarkRequest(options) {
|
|
|
37
56
|
}
|
|
38
57
|
}
|
|
39
58
|
const headers = {};
|
|
59
|
+
let requestBody;
|
|
40
60
|
if (options.accessToken) {
|
|
41
61
|
headers['Authorization'] = `Bearer ${options.accessToken}`;
|
|
42
62
|
}
|
|
43
63
|
if (options.body !== undefined) {
|
|
44
|
-
|
|
64
|
+
const prepared = buildRequestBody(options.body);
|
|
65
|
+
requestBody = prepared.body;
|
|
66
|
+
if (prepared.headers) {
|
|
67
|
+
Object.assign(headers, prepared.headers);
|
|
68
|
+
}
|
|
45
69
|
}
|
|
46
70
|
if (options.headers) {
|
|
47
71
|
Object.assign(headers, options.headers);
|
|
@@ -49,7 +73,7 @@ async function rawLarkRequest(options) {
|
|
|
49
73
|
const resp = await (0, feishu_fetch_1.feishuFetch)(url.toString(), {
|
|
50
74
|
method: options.method ?? 'GET',
|
|
51
75
|
headers,
|
|
52
|
-
...(
|
|
76
|
+
...(requestBody !== undefined ? { body: requestBody } : {}),
|
|
53
77
|
});
|
|
54
78
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
55
79
|
const data = (await resp.json());
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
*
|
|
54
54
|
* 总计:96 个工具动作
|
|
55
55
|
*/
|
|
56
|
-
export type ToolActionKey = 'feishu_bitable_app.copy' | 'feishu_bitable_app.create' | 'feishu_bitable_app.get' | 'feishu_bitable_app.list' | 'feishu_bitable_app.patch' | 'feishu_bitable_app_table.batch_create' | 'feishu_bitable_app_table.create' | 'feishu_bitable_app_table.list' | 'feishu_bitable_app_table.patch' | 'feishu_bitable_app_table_field.create' | 'feishu_bitable_app_table_field.delete' | 'feishu_bitable_app_table_field.list' | 'feishu_bitable_app_table_field.update' | 'feishu_bitable_app_table_record.batch_create' | 'feishu_bitable_app_table_record.batch_delete' | 'feishu_bitable_app_table_record.batch_update' | 'feishu_bitable_app_table_record.create' | 'feishu_bitable_app_table_record.delete' | 'feishu_bitable_app_table_record.list' | 'feishu_bitable_app_table_record.update' | 'feishu_bitable_app_table_view.create' | 'feishu_bitable_app_table_view.get' | 'feishu_bitable_app_table_view.list' | 'feishu_bitable_app_table_view.patch' | 'feishu_calendar_calendar.get' | 'feishu_calendar_calendar.list' | 'feishu_calendar_calendar.primary' | 'feishu_calendar_event.create' | 'feishu_calendar_event.delete' | 'feishu_calendar_event.get' | 'feishu_calendar_event.instance_view' | 'feishu_calendar_event.instances' | 'feishu_calendar_event.list' | 'feishu_calendar_event.patch' | 'feishu_calendar_event.reply' | 'feishu_calendar_event.search' | 'feishu_calendar_event_attendee.create' | 'feishu_calendar_event_attendee.list' | 'feishu_calendar_freebusy.list' | 'feishu_chat.get' | 'feishu_chat.search' | 'feishu_chat_members.default' | 'feishu_create_doc.default' | 'feishu_doc_comments.create' | 'feishu_doc_comments.list' | 'feishu_doc_comments.list_replies' | 'feishu_doc_comments.patch' | 'feishu_doc_comments.reply' | 'feishu_doc_media.download' | 'feishu_doc_media.insert' | 'feishu_drive_file.copy' | 'feishu_drive_file.delete' | 'feishu_drive_file.download' | 'feishu_drive_file.get_meta' | 'feishu_drive_file.list' | 'feishu_drive_file.move' | 'feishu_drive_file.upload' | 'feishu_fetch_doc.default' | 'feishu_get_user.basic_batch' | 'feishu_get_user.default' | 'feishu_im_user_fetch_resource.default' | 'feishu_im_user_get_messages.default' | 'feishu_im_user_message.reply' | 'feishu_im_user_message.send' | 'feishu_im_user_search_messages.default' | 'feishu_search_doc_wiki.search' | 'feishu_search_user.default' | 'feishu_task_comment.create' | 'feishu_task_comment.get' | 'feishu_task_comment.list' | 'feishu_task_section.create' | 'feishu_task_section.get' | 'feishu_task_section.list' | 'feishu_task_section.patch' | 'feishu_task_section.tasks' | 'feishu_task_subtask.create' | 'feishu_task_subtask.list' | 'feishu_task_task.create' | 'feishu_task_task.get' | 'feishu_task_task.list' | 'feishu_task_task.patch' | 'feishu_task_tasklist.add_members' | 'feishu_task_tasklist.create' | 'feishu_task_tasklist.get' | 'feishu_task_tasklist.list' | 'feishu_task_tasklist.patch' | 'feishu_task_tasklist.tasks' | 'feishu_update_doc.default' | 'feishu_wiki_space.create' | 'feishu_wiki_space.get' | 'feishu_wiki_space.list' | 'feishu_wiki_space_node.copy' | 'feishu_wiki_space_node.create' | 'feishu_wiki_space_node.get' | 'feishu_wiki_space_node.list' | 'feishu_wiki_space_node.move' | 'feishu_sheet.info' | 'feishu_sheet.read' | 'feishu_sheet.write' | 'feishu_sheet.append' | 'feishu_sheet.find' | 'feishu_sheet.create' | 'feishu_sheet.export';
|
|
56
|
+
export type ToolActionKey = 'feishu_bitable_app.copy' | 'feishu_bitable_app.create' | 'feishu_bitable_app.get' | 'feishu_bitable_app.list' | 'feishu_bitable_app.patch' | 'feishu_bitable_app_table.batch_create' | 'feishu_bitable_app_table.create' | 'feishu_bitable_app_table.list' | 'feishu_bitable_app_table.patch' | 'feishu_bitable_app_table_field.create' | 'feishu_bitable_app_table_field.delete' | 'feishu_bitable_app_table_field.list' | 'feishu_bitable_app_table_field.update' | 'feishu_bitable_app_table_record.batch_create' | 'feishu_bitable_app_table_record.batch_delete' | 'feishu_bitable_app_table_record.batch_update' | 'feishu_bitable_app_table_record.create' | 'feishu_bitable_app_table_record.delete' | 'feishu_bitable_app_table_record.list' | 'feishu_bitable_app_table_record.update' | 'feishu_bitable_app_table_view.create' | 'feishu_bitable_app_table_view.get' | 'feishu_bitable_app_table_view.list' | 'feishu_bitable_app_table_view.patch' | 'feishu_calendar_calendar.get' | 'feishu_calendar_calendar.list' | 'feishu_calendar_calendar.primary' | 'feishu_calendar_event.create' | 'feishu_calendar_event.delete' | 'feishu_calendar_event.get' | 'feishu_calendar_event.instance_view' | 'feishu_calendar_event.instances' | 'feishu_calendar_event.list' | 'feishu_calendar_event.patch' | 'feishu_calendar_event.reply' | 'feishu_calendar_event.search' | 'feishu_calendar_event_attendee.create' | 'feishu_calendar_event_attendee.list' | 'feishu_calendar_freebusy.list' | 'feishu_chat.get' | 'feishu_chat.search' | 'feishu_chat_members.default' | 'feishu_create_doc.default' | 'feishu_doc_comments.create' | 'feishu_doc_comments.list' | 'feishu_doc_comments.list_replies' | 'feishu_doc_comments.patch' | 'feishu_doc_comments.reply' | 'feishu_doc_media.download' | 'feishu_doc_media.insert' | 'feishu_drive_file.copy' | 'feishu_drive_file.delete' | 'feishu_drive_file.download' | 'feishu_drive_file.get_meta' | 'feishu_drive_file.list' | 'feishu_drive_file.move' | 'feishu_drive_file.upload' | 'feishu_fetch_doc.default' | 'feishu_get_user.basic_batch' | 'feishu_get_user.default' | 'feishu_im_user_fetch_resource.default' | 'feishu_im_user_get_messages.default' | 'feishu_im_user_message.reply' | 'feishu_im_user_message.send' | 'feishu_im_user_search_messages.default' | 'feishu_search_doc_wiki.search' | 'feishu_search_user.default' | 'feishu_task_attachment.upload' | 'feishu_task_comment.create' | 'feishu_task_comment.get' | 'feishu_task_comment.list' | 'feishu_task_section.create' | 'feishu_task_section.get' | 'feishu_task_section.list' | 'feishu_task_section.patch' | 'feishu_task_section.tasks' | 'feishu_task_subtask.create' | 'feishu_task_subtask.list' | 'feishu_task_task.create' | 'feishu_task_task.get' | 'feishu_task_task.list' | 'feishu_task_task.patch' | 'feishu_task_task.add_members' | 'feishu_task_task.append_steps' | 'feishu_task_tasklist.add_members' | 'feishu_task_tasklist.create' | 'feishu_task_tasklist.get' | 'feishu_task_tasklist.list' | 'feishu_task_tasklist.patch' | 'feishu_task_tasklist.tasks' | 'feishu_task_agent.register' | 'feishu_task_agent.update_profile' | 'feishu_update_doc.default' | 'feishu_wiki_space.create' | 'feishu_wiki_space.get' | 'feishu_wiki_space.list' | 'feishu_wiki_space_node.copy' | 'feishu_wiki_space_node.create' | 'feishu_wiki_space_node.get' | 'feishu_wiki_space_node.list' | 'feishu_wiki_space_node.move' | 'feishu_sheet.info' | 'feishu_sheet.read' | 'feishu_sheet.write' | 'feishu_sheet.append' | 'feishu_sheet.find' | 'feishu_sheet.create' | 'feishu_sheet.export';
|
|
57
57
|
/**
|
|
58
58
|
* Tool Scope 映射类型
|
|
59
59
|
*
|
|
@@ -153,4 +153,4 @@ export declare function filterSensitiveScopes(scopes: string[]): string[];
|
|
|
153
153
|
* 唯一 scope 总数: 74
|
|
154
154
|
* 必需应用权限总数: 20
|
|
155
155
|
* 高敏感权限总数: 4
|
|
156
|
-
*/
|
|
156
|
+
*/
|
package/src/core/tool-scopes.js
CHANGED
|
@@ -107,10 +107,13 @@ exports.TOOL_SCOPES = {
|
|
|
107
107
|
'feishu_calendar_event_attendee.create': ['calendar:calendar.event:update'],
|
|
108
108
|
'feishu_calendar_event_attendee.list': ['calendar:calendar.event:read'],
|
|
109
109
|
'feishu_calendar_freebusy.list': ['calendar:calendar.free_busy:read'],
|
|
110
|
+
'feishu_task_attachment.upload': ['task:attachment:write'],
|
|
110
111
|
'feishu_task_task.create': ['task:task:write', 'task:task:writeonly'],
|
|
111
112
|
'feishu_task_task.get': ['task:task:read', 'task:task:write'],
|
|
112
113
|
'feishu_task_task.list': ['task:task:read', 'task:task:write'],
|
|
113
114
|
'feishu_task_task.patch': ['task:task:write', 'task:task:writeonly'],
|
|
115
|
+
'feishu_task_task.add_members': ['task:task:write', 'task:task:writeonly'],
|
|
116
|
+
'feishu_task_task.append_steps': ['task:task:write', 'task:task:writeonly'],
|
|
114
117
|
'feishu_task_tasklist.create': ['task:tasklist:write'],
|
|
115
118
|
'feishu_task_tasklist.get': ['task:tasklist:read', 'task:tasklist:write'],
|
|
116
119
|
'feishu_task_tasklist.list': ['task:tasklist:read', 'task:tasklist:write'],
|
|
@@ -127,6 +130,8 @@ exports.TOOL_SCOPES = {
|
|
|
127
130
|
'feishu_task_section.tasks': ['task:task'],
|
|
128
131
|
'feishu_task_subtask.create': ['task:task:write'],
|
|
129
132
|
'feishu_task_subtask.list': ['task:task:read', 'task:task:write'],
|
|
133
|
+
'feishu_task_agent.register': ['task:task:write'],
|
|
134
|
+
'feishu_task_agent.update_profile': ['task:task:write', 'task:task:writeonly'],
|
|
130
135
|
'feishu_chat.search': ['im:chat:read'],
|
|
131
136
|
'feishu_chat.get': ['im:chat:read'],
|
|
132
137
|
'feishu_chat_members.default': ['im:chat.members:read'],
|
|
@@ -336,4 +341,4 @@ function filterSensitiveScopes(scopes) {
|
|
|
336
341
|
* 唯一 scope 总数: 74
|
|
337
342
|
* 必需应用权限总数: 20
|
|
338
343
|
* 高敏感权限总数: 4
|
|
339
|
-
*/
|
|
344
|
+
*/
|
package/src/tools/oapi/index.js
CHANGED
|
@@ -39,9 +39,11 @@ function registerOapiTools(api) {
|
|
|
39
39
|
// Task tools
|
|
40
40
|
(0, index_3.registerFeishuTaskTaskTool)(api);
|
|
41
41
|
(0, index_3.registerFeishuTaskTasklistTool)(api);
|
|
42
|
+
(0, index_3.registerFeishuTaskAttachmentTool)(api);
|
|
42
43
|
(0, index_3.registerFeishuTaskSectionTool)(api);
|
|
43
44
|
(0, index_3.registerFeishuTaskCommentTool)(api);
|
|
44
45
|
(0, index_3.registerFeishuTaskSubtaskTool)(api);
|
|
46
|
+
(0, index_3.registerFeishuTaskAgentTool)(api);
|
|
45
47
|
// Bitable tools
|
|
46
48
|
(0, index_4.registerFeishuBitableAppTool)(api);
|
|
47
49
|
(0, index_4.registerFeishuBitableAppTableTool)(api);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*
|
|
5
|
+
* feishu_task_attachment tool -- Manage task attachments.
|
|
6
|
+
*
|
|
7
|
+
* Actions:
|
|
8
|
+
* - upload: Upload task attachment (tenant identity)
|
|
9
|
+
*/
|
|
10
|
+
import type { OpenClawPluginApi } from 'openclaw/plugin-sdk';
|
|
11
|
+
export interface FeishuTaskAttachmentParams {
|
|
12
|
+
action: 'upload';
|
|
13
|
+
resource_type?: 'task' | 'task_delivery';
|
|
14
|
+
resource_id: string;
|
|
15
|
+
file: string;
|
|
16
|
+
name?: string;
|
|
17
|
+
}
|
|
18
|
+
export declare function registerFeishuTaskAttachmentTool(api: OpenClawPluginApi): void;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*
|
|
6
|
+
* feishu_task_attachment tool -- Manage task attachments.
|
|
7
|
+
*
|
|
8
|
+
* Actions:
|
|
9
|
+
* - upload: Upload task attachment (tenant identity)
|
|
10
|
+
*/
|
|
11
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.registerFeishuTaskAttachmentTool = registerFeishuTaskAttachmentTool;
|
|
14
|
+
const typebox_1 = require("@sinclair/typebox");
|
|
15
|
+
const helpers_1 = require("../helpers.js");
|
|
16
|
+
const raw_request_1 = require("../../../core/raw-request.js");
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
// Schema
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
const FeishuTaskAttachmentSchema = typebox_1.Type.Union([
|
|
21
|
+
typebox_1.Type.Object({
|
|
22
|
+
action: typebox_1.Type.Literal('upload'),
|
|
23
|
+
resource_type: typebox_1.Type.Optional((0, helpers_1.StringEnum)(['task', 'task_delivery'], {
|
|
24
|
+
description: '资源类型,可选值:task、task_delivery。默认 task。',
|
|
25
|
+
default: 'task',
|
|
26
|
+
})),
|
|
27
|
+
resource_id: typebox_1.Type.String({
|
|
28
|
+
description: '资源 ID。',
|
|
29
|
+
}),
|
|
30
|
+
file: typebox_1.Type.String({
|
|
31
|
+
description: '文件内容base64编码字符串',
|
|
32
|
+
}),
|
|
33
|
+
name: typebox_1.Type.Optional(typebox_1.Type.String({
|
|
34
|
+
description: '文件名。',
|
|
35
|
+
})),
|
|
36
|
+
}),
|
|
37
|
+
]);
|
|
38
|
+
;
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
// Internal helpers
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
function resolvePathForAction(action) {
|
|
43
|
+
if (action === 'upload') {
|
|
44
|
+
return { path: '/open-apis/task/v2/attachments/upload', env: [] };
|
|
45
|
+
}
|
|
46
|
+
return { path: '/open-apis/task/v2/attachments/upload', env: [] };
|
|
47
|
+
}
|
|
48
|
+
// ---------------------------------------------------------------------------
|
|
49
|
+
// Registration
|
|
50
|
+
// ---------------------------------------------------------------------------
|
|
51
|
+
function registerFeishuTaskAttachmentTool(api) {
|
|
52
|
+
if (!api.config)
|
|
53
|
+
return;
|
|
54
|
+
const cfg = api.config;
|
|
55
|
+
const { toolClient } = (0, helpers_1.createToolContext)(api, 'feishu_task_attachment');
|
|
56
|
+
(0, helpers_1.registerTool)(api, {
|
|
57
|
+
name: 'feishu_task_attachment',
|
|
58
|
+
label: 'Feishu Task Attachment',
|
|
59
|
+
description: '飞书任务附件工具。当前提供 upload action,用于上传任务附件。',
|
|
60
|
+
parameters: FeishuTaskAttachmentSchema,
|
|
61
|
+
async execute(_toolCallId, params) {
|
|
62
|
+
const p = params;
|
|
63
|
+
try {
|
|
64
|
+
const resolved = resolvePathForAction(p.action);
|
|
65
|
+
const client = toolClient();
|
|
66
|
+
const resourceType = p.resource_type ?? 'task';
|
|
67
|
+
const formData = new FormData();
|
|
68
|
+
formData.append('resource_type', resourceType);
|
|
69
|
+
formData.append('resource_id', p.resource_id);
|
|
70
|
+
// 将 base64 字符串解码为二进制文件
|
|
71
|
+
const fileBuffer = Buffer.from(p.file, 'base64');
|
|
72
|
+
// 创建 File 对象并添加到 FormData
|
|
73
|
+
const file = new File([fileBuffer], p.name ?? 'attachment');
|
|
74
|
+
formData.append('file', file);
|
|
75
|
+
const as = 'tenant';
|
|
76
|
+
const tatRes = await (0, raw_request_1.rawLarkRequest)({
|
|
77
|
+
brand: client.account.brand,
|
|
78
|
+
path: '/open-apis/auth/v3/tenant_access_token/internal/',
|
|
79
|
+
method: 'POST',
|
|
80
|
+
body: {
|
|
81
|
+
app_id: client.account.appId,
|
|
82
|
+
app_secret: client.account.appSecret,
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
const token = tatRes?.tenant_access_token;
|
|
86
|
+
if (!token) {
|
|
87
|
+
return (0, helpers_1.json)({
|
|
88
|
+
error: 'Failed to get tenant_access_token.',
|
|
89
|
+
response: tatRes,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
const res = await client.invokeByPath('feishu_task_attachment.upload', resolved.path, {
|
|
93
|
+
method: 'POST',
|
|
94
|
+
as,
|
|
95
|
+
body: formData,
|
|
96
|
+
headers: {
|
|
97
|
+
'Authorization': `Bearer ${token}`,
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
return (0, helpers_1.json)(res);
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
return await (0, helpers_1.handleInvokeErrorWithAutoAuth)(err, cfg);
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
}, { name: 'feishu_task_attachment' });
|
|
107
|
+
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* feishu_task_comment tool -- Manage Feishu task comments.
|
|
6
6
|
*
|
|
7
|
-
* P1 Actions: create, list, get
|
|
7
|
+
* P1 Actions: create, list, get 支持通过 auth_type 参数切换用户(user)或应用(tenant)身份。
|
|
8
8
|
*
|
|
9
9
|
* Uses the Feishu Task v2 API:
|
|
10
10
|
* - create: POST /open-apis/task/v2/tasks/:task_guid/comments
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* feishu_task_comment tool -- Manage Feishu task comments.
|
|
7
7
|
*
|
|
8
|
-
* P1 Actions: create, list, get
|
|
8
|
+
* P1 Actions: create, list, get 支持通过 auth_type 参数切换用户(user)或应用(tenant)身份。
|
|
9
9
|
*
|
|
10
10
|
* Uses the Feishu Task v2 API:
|
|
11
11
|
* - create: POST /open-apis/task/v2/tasks/:task_guid/comments
|
|
@@ -19,10 +19,14 @@ const helpers_1 = require("../helpers.js");
|
|
|
19
19
|
// ---------------------------------------------------------------------------
|
|
20
20
|
// Schema
|
|
21
21
|
// ---------------------------------------------------------------------------
|
|
22
|
+
const FeishuTaskCommentAuthType = typebox_1.Type.Optional((0, helpers_1.StringEnum)(['tenant', 'user'], {
|
|
23
|
+
description: '调用 API 时使用的 Token 类型。可选值:"tenant"(应用身份) 或 "user"(用户身份)。默认使用 "user"。',
|
|
24
|
+
}));
|
|
22
25
|
const FeishuTaskCommentSchema = typebox_1.Type.Union([
|
|
23
26
|
// CREATE (P1)
|
|
24
27
|
typebox_1.Type.Object({
|
|
25
28
|
action: typebox_1.Type.Literal('create'),
|
|
29
|
+
auth_type: FeishuTaskCommentAuthType,
|
|
26
30
|
task_guid: typebox_1.Type.String({ description: '任务 GUID' }),
|
|
27
31
|
content: typebox_1.Type.String({ description: '评论内容(纯文本,最长 3000 字符)' }),
|
|
28
32
|
reply_to_comment_id: typebox_1.Type.Optional(typebox_1.Type.String({ description: '要回复的评论 ID(用于回复评论)' })),
|
|
@@ -30,6 +34,7 @@ const FeishuTaskCommentSchema = typebox_1.Type.Union([
|
|
|
30
34
|
// LIST (P1)
|
|
31
35
|
typebox_1.Type.Object({
|
|
32
36
|
action: typebox_1.Type.Literal('list'),
|
|
37
|
+
auth_type: FeishuTaskCommentAuthType,
|
|
33
38
|
resource_id: typebox_1.Type.String({ description: '要获取评论的资源 ID(任务 GUID)' }),
|
|
34
39
|
direction: typebox_1.Type.Optional((0, helpers_1.StringEnum)(['asc', 'desc'], {
|
|
35
40
|
description: '排序方式(asc=从旧到新,desc=从新到旧,默认 asc)',
|
|
@@ -40,6 +45,7 @@ const FeishuTaskCommentSchema = typebox_1.Type.Union([
|
|
|
40
45
|
// GET (P1)
|
|
41
46
|
typebox_1.Type.Object({
|
|
42
47
|
action: typebox_1.Type.Literal('get'),
|
|
48
|
+
auth_type: FeishuTaskCommentAuthType,
|
|
43
49
|
comment_id: typebox_1.Type.String({ description: '评论 ID' }),
|
|
44
50
|
}),
|
|
45
51
|
]);
|
|
@@ -54,7 +60,7 @@ function registerFeishuTaskCommentTool(api) {
|
|
|
54
60
|
(0, helpers_1.registerTool)(api, {
|
|
55
61
|
name: 'feishu_task_comment',
|
|
56
62
|
label: 'Feishu Task Comments',
|
|
57
|
-
description: '
|
|
63
|
+
description: '【以用户或应用身份】飞书任务评论管理工具。当用户要求添加/查询任务评论、回复评论时使用。Actions: create(添加评论), list(列出任务的所有评论), get(获取单个评论详情)。',
|
|
58
64
|
parameters: FeishuTaskCommentSchema,
|
|
59
65
|
async execute(_toolCallId, params) {
|
|
60
66
|
const p = params;
|
|
@@ -81,7 +87,7 @@ function registerFeishuTaskCommentTool(api) {
|
|
|
81
87
|
user_id_type: 'open_id',
|
|
82
88
|
},
|
|
83
89
|
data,
|
|
84
|
-
}, opts), { as: 'user' });
|
|
90
|
+
}, opts), { as: p.auth_type || 'user' });
|
|
85
91
|
(0, helpers_1.assertLarkOk)(res);
|
|
86
92
|
log.info(`create: created comment ${res.data?.comment?.id}`);
|
|
87
93
|
return (0, helpers_1.json)({
|
|
@@ -103,7 +109,7 @@ function registerFeishuTaskCommentTool(api) {
|
|
|
103
109
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
104
110
|
user_id_type: 'open_id',
|
|
105
111
|
},
|
|
106
|
-
}, opts), { as: 'user' });
|
|
112
|
+
}, opts), { as: p.auth_type || 'user' });
|
|
107
113
|
(0, helpers_1.assertLarkOk)(res);
|
|
108
114
|
const data = res.data;
|
|
109
115
|
log.info(`list: returned ${data?.items?.length ?? 0} comments`);
|
|
@@ -126,7 +132,7 @@ function registerFeishuTaskCommentTool(api) {
|
|
|
126
132
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
127
133
|
user_id_type: 'open_id',
|
|
128
134
|
},
|
|
129
|
-
}, opts), { as: 'user' });
|
|
135
|
+
}, opts), { as: p.auth_type || 'user' });
|
|
130
136
|
(0, helpers_1.assertLarkOk)(res);
|
|
131
137
|
log.info(`get: returned comment ${p.comment_id}`);
|
|
132
138
|
return (0, helpers_1.json)({
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
*/
|
|
5
5
|
export { registerFeishuTaskTaskTool } from './task';
|
|
6
6
|
export { registerFeishuTaskTasklistTool } from './tasklist';
|
|
7
|
+
export { registerFeishuTaskAttachmentTool } from './attachment';
|
|
7
8
|
export { registerFeishuTaskCommentTool } from './comment';
|
|
8
9
|
export { registerFeishuTaskSubtaskTool } from './subtask';
|
|
9
10
|
export { registerFeishuTaskSectionTool } from './section';
|
|
11
|
+
export { registerFeishuTaskAgentTool } from './task_agent';
|
|
@@ -4,14 +4,18 @@
|
|
|
4
4
|
* SPDX-License-Identifier: MIT
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.registerFeishuTaskSectionTool = exports.registerFeishuTaskSubtaskTool = exports.registerFeishuTaskCommentTool = exports.registerFeishuTaskTasklistTool = exports.registerFeishuTaskTaskTool = void 0;
|
|
7
|
+
exports.registerFeishuTaskAgentTool = exports.registerFeishuTaskSectionTool = exports.registerFeishuTaskSubtaskTool = exports.registerFeishuTaskCommentTool = exports.registerFeishuTaskAttachmentTool = exports.registerFeishuTaskTasklistTool = exports.registerFeishuTaskTaskTool = void 0;
|
|
8
8
|
var task_1 = require("./task.js");
|
|
9
9
|
Object.defineProperty(exports, "registerFeishuTaskTaskTool", { enumerable: true, get: function () { return task_1.registerFeishuTaskTaskTool; } });
|
|
10
10
|
var tasklist_1 = require("./tasklist.js");
|
|
11
11
|
Object.defineProperty(exports, "registerFeishuTaskTasklistTool", { enumerable: true, get: function () { return tasklist_1.registerFeishuTaskTasklistTool; } });
|
|
12
|
+
var attachment_1 = require("./attachment.js");
|
|
13
|
+
Object.defineProperty(exports, "registerFeishuTaskAttachmentTool", { enumerable: true, get: function () { return attachment_1.registerFeishuTaskAttachmentTool; } });
|
|
12
14
|
var comment_1 = require("./comment.js");
|
|
13
15
|
Object.defineProperty(exports, "registerFeishuTaskCommentTool", { enumerable: true, get: function () { return comment_1.registerFeishuTaskCommentTool; } });
|
|
14
16
|
var subtask_1 = require("./subtask.js");
|
|
15
17
|
Object.defineProperty(exports, "registerFeishuTaskSubtaskTool", { enumerable: true, get: function () { return subtask_1.registerFeishuTaskSubtaskTool; } });
|
|
16
18
|
var section_1 = require("./section.js");
|
|
17
19
|
Object.defineProperty(exports, "registerFeishuTaskSectionTool", { enumerable: true, get: function () { return section_1.registerFeishuTaskSectionTool; } });
|
|
20
|
+
var task_agent_1 = require("./task_agent.js");
|
|
21
|
+
Object.defineProperty(exports, "registerFeishuTaskAgentTool", { enumerable: true, get: function () { return task_agent_1.registerFeishuTaskAgentTool; } });
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* feishu_task_section tool -- Manage Feishu task sections.
|
|
6
6
|
*
|
|
7
|
-
* P0 Actions: create, get, list, patch, tasks
|
|
7
|
+
* P0 Actions: create, get, list, patch, tasks 支持通过 auth_type 参数切换用户(user)或应用(tenant)身份。
|
|
8
8
|
*
|
|
9
9
|
* Uses the Feishu Task v2 API:
|
|
10
10
|
* - create: POST /open-apis/task/v2/sections
|