@m1heng-clawd/feishu 0.1.15 → 0.1.17
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/README.md +28 -0
- package/index.ts +4 -0
- package/package.json +2 -1
- package/skills/feishu-message/SKILL.md +111 -0
- package/skills/feishu-reaction/SKILL.md +120 -0
- package/src/bot.ts +4 -0
- package/src/channel.ts +2 -0
- package/src/chat-tools/actions.ts +102 -33
- package/src/chat-tools/schemas.ts +57 -62
- package/src/config-schema.ts +2 -0
- package/src/doc-tools/actions.ts +63 -14
- package/src/doc-tools/schemas.ts +41 -77
- package/src/doc-write-service.ts +19 -0
- package/src/drive-tools/actions.ts +18 -6
- package/src/drive-tools/register.ts +1 -1
- package/src/drive-tools/schemas.ts +45 -58
- package/src/media-duration.ts +43 -8
- package/src/media.ts +31 -53
- package/src/message-tools/actions.ts +154 -0
- package/src/message-tools/index.ts +2 -0
- package/src/message-tools/register.ts +58 -0
- package/src/message-tools/schemas.ts +56 -0
- package/src/outbound.ts +2 -2
- package/src/perm-tools/actions.ts +27 -3
- package/src/perm-tools/schemas.ts +39 -45
- package/src/reaction-tools/actions.ts +127 -0
- package/src/reaction-tools/index.ts +2 -0
- package/src/reaction-tools/register.ts +51 -0
- package/src/reaction-tools/schemas.ts +34 -0
- package/src/reply-dispatcher.ts +23 -33
- package/src/streaming-card.ts +34 -11
- package/src/task-tools/actions.ts +145 -10
- package/src/task-tools/register.ts +56 -1
- package/src/task-tools/schemas.ts +23 -18
- package/src/tools-common/tool-context.ts +2 -0
- package/src/tools-config.ts +2 -0
- package/src/types.ts +4 -0
- package/src/wiki-tools/actions.ts +24 -6
- package/src/wiki-tools/schemas.ts +32 -51
|
@@ -6,19 +6,24 @@ import {
|
|
|
6
6
|
addTaskToTasklist,
|
|
7
7
|
addTasklistMembers,
|
|
8
8
|
createSubtask,
|
|
9
|
+
createTaskComment,
|
|
9
10
|
createTask,
|
|
10
11
|
createTasklist,
|
|
11
12
|
deleteTaskAttachment,
|
|
13
|
+
deleteTaskComment,
|
|
12
14
|
deleteTask,
|
|
13
15
|
deleteTasklist,
|
|
14
16
|
getTaskAttachment,
|
|
17
|
+
getTaskComment,
|
|
15
18
|
getTask,
|
|
16
19
|
getTasklist,
|
|
20
|
+
listTaskComments,
|
|
17
21
|
listTasklists,
|
|
18
22
|
removeTaskFromTasklist,
|
|
19
23
|
removeTasklistMembers,
|
|
20
24
|
listTaskAttachments,
|
|
21
25
|
uploadTaskAttachment,
|
|
26
|
+
updateTaskComment,
|
|
22
27
|
updateTask,
|
|
23
28
|
updateTasklist,
|
|
24
29
|
} from "./actions.js";
|
|
@@ -36,26 +41,36 @@ import {
|
|
|
36
41
|
type CreateTasklistParams,
|
|
37
42
|
DeleteTaskAttachmentSchema,
|
|
38
43
|
type DeleteTaskAttachmentParams,
|
|
44
|
+
DeleteTaskCommentSchema,
|
|
45
|
+
type DeleteTaskCommentParams,
|
|
39
46
|
DeleteTaskSchema,
|
|
40
47
|
type DeleteTaskParams,
|
|
41
48
|
DeleteTasklistSchema,
|
|
42
49
|
type DeleteTasklistParams,
|
|
43
50
|
GetTaskAttachmentSchema,
|
|
44
51
|
type GetTaskAttachmentParams,
|
|
52
|
+
GetTaskCommentSchema,
|
|
53
|
+
type GetTaskCommentParams,
|
|
45
54
|
GetTaskSchema,
|
|
46
55
|
type GetTaskParams,
|
|
47
56
|
GetTasklistSchema,
|
|
48
57
|
type GetTasklistParams,
|
|
49
58
|
ListTaskAttachmentsSchema,
|
|
50
59
|
type ListTaskAttachmentsParams,
|
|
60
|
+
ListTaskCommentsSchema,
|
|
61
|
+
type ListTaskCommentsParams,
|
|
51
62
|
ListTasklistsSchema,
|
|
52
63
|
type ListTasklistsParams,
|
|
53
64
|
RemoveTaskFromTasklistSchema,
|
|
54
65
|
type RemoveTaskFromTasklistParams,
|
|
55
66
|
RemoveTasklistMembersSchema,
|
|
56
67
|
type RemoveTasklistMembersParams,
|
|
68
|
+
CreateTaskCommentSchema,
|
|
69
|
+
type CreateTaskCommentParams,
|
|
57
70
|
UploadTaskAttachmentSchema,
|
|
58
71
|
type UploadTaskAttachmentParams,
|
|
72
|
+
UpdateTaskCommentSchema,
|
|
73
|
+
type UpdateTaskCommentParams,
|
|
59
74
|
UpdateTaskSchema,
|
|
60
75
|
UpdateTasklistSchema,
|
|
61
76
|
type UpdateTaskParams,
|
|
@@ -259,5 +274,45 @@ export function registerFeishuTaskTools(api: OpenClawPluginApi) {
|
|
|
259
274
|
run: async ({ client }, params) => updateTask(client, params),
|
|
260
275
|
});
|
|
261
276
|
|
|
262
|
-
api
|
|
277
|
+
registerTaskTool<CreateTaskCommentParams>(api, {
|
|
278
|
+
name: "feishu_task_comment_create",
|
|
279
|
+
label: "Feishu Task Comment Create",
|
|
280
|
+
description: "Create a comment on a Feishu task (task v2)",
|
|
281
|
+
parameters: CreateTaskCommentSchema,
|
|
282
|
+
run: async ({ client }, params) => createTaskComment(client, params),
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
registerTaskTool<ListTaskCommentsParams>(api, {
|
|
286
|
+
name: "feishu_task_comment_list",
|
|
287
|
+
label: "Feishu Task Comment List",
|
|
288
|
+
description: "List comments for a Feishu task (task v2)",
|
|
289
|
+
parameters: ListTaskCommentsSchema,
|
|
290
|
+
run: async ({ client }, params) => listTaskComments(client, params),
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
registerTaskTool<GetTaskCommentParams>(api, {
|
|
294
|
+
name: "feishu_task_comment_get",
|
|
295
|
+
label: "Feishu Task Comment Get",
|
|
296
|
+
description: "Get a Feishu task comment by comment_id (task v2)",
|
|
297
|
+
parameters: GetTaskCommentSchema,
|
|
298
|
+
run: async ({ client }, params) => getTaskComment(client, params),
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
registerTaskTool<UpdateTaskCommentParams>(api, {
|
|
302
|
+
name: "feishu_task_comment_update",
|
|
303
|
+
label: "Feishu Task Comment Update",
|
|
304
|
+
description: "Update a Feishu task comment by comment_id (task v2 patch)",
|
|
305
|
+
parameters: UpdateTaskCommentSchema,
|
|
306
|
+
run: async ({ client }, params) => updateTaskComment(client, params),
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
registerTaskTool<DeleteTaskCommentParams>(api, {
|
|
310
|
+
name: "feishu_task_comment_delete",
|
|
311
|
+
label: "Feishu Task Comment Delete",
|
|
312
|
+
description: "Delete a Feishu task comment by comment_id (task v2)",
|
|
313
|
+
parameters: DeleteTaskCommentSchema,
|
|
314
|
+
run: async ({ client }, params) => deleteTaskComment(client, params),
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
api.logger.debug?.("feishu_task: Registered task, comment, tasklist, subtask, and attachment tools");
|
|
263
318
|
}
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
2
|
import type { TaskClient } from "./common.js";
|
|
3
3
|
|
|
4
|
+
// NOTE: Avoid Type.Union([Type.Literal(...)]) which compiles to anyOf.
|
|
5
|
+
// Some providers reject anyOf in tool schemas; a flat string enum is safer.
|
|
6
|
+
function stringEnum<T extends readonly string[]>(
|
|
7
|
+
values: T,
|
|
8
|
+
options: { description?: string; default?: T[number] } = {},
|
|
9
|
+
) {
|
|
10
|
+
return Type.Unsafe<T[number]>({ type: "string", enum: [...values], ...options });
|
|
11
|
+
}
|
|
12
|
+
|
|
4
13
|
type TaskCreatePayload = NonNullable<Parameters<TaskClient["task"]["v2"]["task"]["create"]>[0]>;
|
|
5
14
|
type TaskUpdatePayload = NonNullable<Parameters<TaskClient["task"]["v2"]["task"]["patch"]>[0]>;
|
|
6
15
|
type TaskDeletePayload = NonNullable<Parameters<TaskClient["task"]["v2"]["task"]["delete"]>[0]>;
|
|
@@ -75,6 +84,7 @@ export const TASK_UPDATE_FIELD_VALUES = [
|
|
|
75
84
|
"mode",
|
|
76
85
|
"is_milestone",
|
|
77
86
|
] as const;
|
|
87
|
+
export const TASK_COMMENT_UPDATE_FIELD_VALUES = ["content"] as const;
|
|
78
88
|
export const TASKLIST_UPDATE_FIELD_VALUES = ["name", "owner", "archive_tasklist"] as const;
|
|
79
89
|
|
|
80
90
|
export type CreateTaskParams = {
|
|
@@ -245,23 +255,19 @@ const TasklistRefSchema = Type.Object({
|
|
|
245
255
|
section_guid: Type.Optional(Type.String({ description: "Section GUID in tasklist" })),
|
|
246
256
|
});
|
|
247
257
|
|
|
248
|
-
const TaskUpdateFieldSchema =
|
|
249
|
-
TASK_UPDATE_FIELD_VALUES.map((field) => Type.Literal(field)),
|
|
250
|
-
);
|
|
258
|
+
const TaskUpdateFieldSchema = stringEnum(TASK_UPDATE_FIELD_VALUES);
|
|
251
259
|
|
|
252
|
-
const
|
|
253
|
-
[Type.Literal("owner"), Type.Literal("editor"), Type.Literal("viewer")],
|
|
254
|
-
{ description: "Member role (owner/editor/viewer)" },
|
|
255
|
-
);
|
|
260
|
+
const TaskCommentUpdateFieldSchema = stringEnum(TASK_COMMENT_UPDATE_FIELD_VALUES);
|
|
256
261
|
|
|
257
|
-
const
|
|
258
|
-
|
|
259
|
-
);
|
|
262
|
+
const TasklistMemberRoleSchema = stringEnum(["owner", "editor", "viewer"] as const, {
|
|
263
|
+
description: "Member role (owner/editor/viewer)",
|
|
264
|
+
});
|
|
260
265
|
|
|
261
|
-
const
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
266
|
+
const TasklistUpdateFieldSchema = stringEnum(TASKLIST_UPDATE_FIELD_VALUES);
|
|
267
|
+
|
|
268
|
+
const TasklistOriginOwnerRoleSchema = stringEnum(["editor", "viewer", "none"] as const, {
|
|
269
|
+
description: "Role for original owner after owner transfer",
|
|
270
|
+
});
|
|
265
271
|
|
|
266
272
|
const TasklistMemberSchema = Type.Object({
|
|
267
273
|
id: Type.String({ description: "Member ID (with type controlled by user_id_type)" }),
|
|
@@ -372,9 +378,7 @@ export const ListTaskCommentsSchema = Type.Object({
|
|
|
372
378
|
),
|
|
373
379
|
page_token: Type.Optional(Type.String({ description: "Pagination token" })),
|
|
374
380
|
direction: Type.Optional(
|
|
375
|
-
|
|
376
|
-
description: "Sort direction",
|
|
377
|
-
}),
|
|
381
|
+
stringEnum(["asc", "desc"] as const, { description: "Sort direction" }),
|
|
378
382
|
),
|
|
379
383
|
user_id_type: Type.Optional(
|
|
380
384
|
Type.String({ description: "User ID type for returned creators" }),
|
|
@@ -399,9 +403,10 @@ export const UpdateTaskCommentSchema = Type.Object({
|
|
|
399
403
|
comment_id: Type.String({ description: "Comment ID to update" }),
|
|
400
404
|
comment: TaskCommentUpdateContentSchema,
|
|
401
405
|
update_fields: Type.Optional(
|
|
402
|
-
Type.Array(
|
|
406
|
+
Type.Array(TaskCommentUpdateFieldSchema, {
|
|
403
407
|
description: "Fields to update. If omitted, this tool infers from keys in comment (content)",
|
|
404
408
|
minItems: 1,
|
|
409
|
+
uniqueItems: true,
|
|
405
410
|
}),
|
|
406
411
|
),
|
|
407
412
|
user_id_type: Type.Optional(
|
package/src/tools-config.ts
CHANGED
package/src/types.ts
CHANGED
|
@@ -76,6 +76,10 @@ export type FeishuToolsConfig = {
|
|
|
76
76
|
chat?: boolean;
|
|
77
77
|
/** Enable the feishu_urgent tool (buzz/urgent notifications). Enabled by default. */
|
|
78
78
|
urgent?: boolean;
|
|
79
|
+
/** Enable the feishu_message tool (get/list messages). Enabled by default. */
|
|
80
|
+
message?: boolean;
|
|
81
|
+
/** Enable the feishu_reaction tool (add/remove/list emoji reactions). Enabled by default. */
|
|
82
|
+
reaction?: boolean;
|
|
79
83
|
};
|
|
80
84
|
|
|
81
85
|
export type DynamicAgentCreationConfig = {
|
|
@@ -7,6 +7,13 @@ const WIKI_ACCESS_HINT =
|
|
|
7
7
|
"To grant wiki access: Open wiki space -> Settings -> Members -> Add the bot. " +
|
|
8
8
|
"See: https://open.feishu.cn/document/server-docs/docs/wiki-v2/wiki-qa#a40ad4ca";
|
|
9
9
|
|
|
10
|
+
function requireString(value: unknown, field: string): string {
|
|
11
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
12
|
+
throw new Error(`${field} is required`);
|
|
13
|
+
}
|
|
14
|
+
return value;
|
|
15
|
+
}
|
|
16
|
+
|
|
10
17
|
async function listSpaces(client: WikiClient) {
|
|
11
18
|
const res = await runWikiApiCall("wiki.space.list", () => client.wiki.space.list({}));
|
|
12
19
|
const spaces =
|
|
@@ -140,26 +147,37 @@ export async function runWikiAction(client: WikiClient, params: FeishuWikiParams
|
|
|
140
147
|
case "spaces":
|
|
141
148
|
return listSpaces(client);
|
|
142
149
|
case "nodes":
|
|
143
|
-
return listNodes(client, params.space_id, params.parent_node_token);
|
|
150
|
+
return listNodes(client, requireString(params.space_id, "space_id"), params.parent_node_token);
|
|
144
151
|
case "get":
|
|
145
|
-
return getNode(client, params.token);
|
|
152
|
+
return getNode(client, requireString(params.token, "token"));
|
|
146
153
|
case "search":
|
|
147
154
|
return {
|
|
148
155
|
error:
|
|
149
156
|
"Search is not available. Use feishu_wiki with action: 'nodes' to browse or action: 'get' to lookup by token.",
|
|
150
157
|
};
|
|
151
158
|
case "create":
|
|
152
|
-
return createNode(
|
|
159
|
+
return createNode(
|
|
160
|
+
client,
|
|
161
|
+
requireString(params.space_id, "space_id"),
|
|
162
|
+
requireString(params.title, "title"),
|
|
163
|
+
params.obj_type,
|
|
164
|
+
params.parent_node_token,
|
|
165
|
+
);
|
|
153
166
|
case "move":
|
|
154
167
|
return moveNode(
|
|
155
168
|
client,
|
|
156
|
-
params.space_id,
|
|
157
|
-
params.node_token,
|
|
169
|
+
requireString(params.space_id, "space_id"),
|
|
170
|
+
requireString(params.node_token, "node_token"),
|
|
158
171
|
params.target_space_id,
|
|
159
172
|
params.target_parent_token,
|
|
160
173
|
);
|
|
161
174
|
case "rename":
|
|
162
|
-
return renameNode(
|
|
175
|
+
return renameNode(
|
|
176
|
+
client,
|
|
177
|
+
requireString(params.space_id, "space_id"),
|
|
178
|
+
requireString(params.node_token, "node_token"),
|
|
179
|
+
requireString(params.title, "title"),
|
|
180
|
+
);
|
|
163
181
|
default:
|
|
164
182
|
return { error: `Unknown action: ${(params as any).action}` };
|
|
165
183
|
}
|
|
@@ -1,55 +1,36 @@
|
|
|
1
1
|
import { Type, type Static } from "@sinclair/typebox";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
Type.
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}),
|
|
36
|
-
Type.Object({
|
|
37
|
-
action: Type.Literal("move"),
|
|
38
|
-
space_id: Type.String({ description: "Source knowledge space ID" }),
|
|
39
|
-
node_token: Type.String({ description: "Node token to move" }),
|
|
40
|
-
target_space_id: Type.Optional(
|
|
41
|
-
Type.String({ description: "Target space ID (optional, same space if omitted)" }),
|
|
42
|
-
),
|
|
43
|
-
target_parent_token: Type.Optional(
|
|
44
|
-
Type.String({ description: "Target parent node token (optional, root if omitted)" }),
|
|
45
|
-
),
|
|
46
|
-
}),
|
|
47
|
-
Type.Object({
|
|
48
|
-
action: Type.Literal("rename"),
|
|
49
|
-
space_id: Type.String({ description: "Knowledge space ID" }),
|
|
50
|
-
node_token: Type.String({ description: "Node token to rename" }),
|
|
51
|
-
title: Type.String({ description: "New title" }),
|
|
52
|
-
}),
|
|
53
|
-
]);
|
|
3
|
+
function stringEnum<T extends readonly string[]>(
|
|
4
|
+
values: T,
|
|
5
|
+
options: { description?: string; default?: T[number] } = {},
|
|
6
|
+
) {
|
|
7
|
+
return Type.Unsafe<T[number]>({ type: "string", enum: [...values], ...options });
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const WIKI_ACTION_VALUES = ["spaces", "nodes", "get", "search", "create", "move", "rename"] as const;
|
|
11
|
+
const WIKI_OBJ_TYPE_VALUES = ["docx", "sheet", "bitable"] as const;
|
|
12
|
+
|
|
13
|
+
export const FeishuWikiSchema = Type.Object({
|
|
14
|
+
action: stringEnum(WIKI_ACTION_VALUES, { description: "Wiki action" }),
|
|
15
|
+
space_id: Type.Optional(Type.String({ description: "Knowledge space ID" })),
|
|
16
|
+
parent_node_token: Type.Optional(
|
|
17
|
+
Type.String({ description: "Parent node token (optional, omit for root)" }),
|
|
18
|
+
),
|
|
19
|
+
token: Type.Optional(Type.String({ description: "Wiki node token (from URL /wiki/XXX)" })),
|
|
20
|
+
query: Type.Optional(Type.String({ description: "Search query" })),
|
|
21
|
+
title: Type.Optional(Type.String({ description: "Node title / new title" })),
|
|
22
|
+
obj_type: Type.Optional(
|
|
23
|
+
stringEnum(WIKI_OBJ_TYPE_VALUES, {
|
|
24
|
+
description: "Object type for create action (default: docx)",
|
|
25
|
+
}),
|
|
26
|
+
),
|
|
27
|
+
node_token: Type.Optional(Type.String({ description: "Node token" })),
|
|
28
|
+
target_space_id: Type.Optional(
|
|
29
|
+
Type.String({ description: "Target space ID (optional, same space if omitted)" }),
|
|
30
|
+
),
|
|
31
|
+
target_parent_token: Type.Optional(
|
|
32
|
+
Type.String({ description: "Target parent node token (optional, root if omitted)" }),
|
|
33
|
+
),
|
|
34
|
+
});
|
|
54
35
|
|
|
55
36
|
export type FeishuWikiParams = Static<typeof FeishuWikiSchema>;
|