@openclaw-plugins/feishu-plus 0.1.7-fork.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/LICENSE +21 -0
- package/README.md +560 -0
- package/index.ts +74 -0
- package/openclaw.plugin.json +10 -0
- package/package.json +65 -0
- package/skills/feishu-doc/SKILL.md +99 -0
- package/skills/feishu-doc/references/block-types.md +102 -0
- package/skills/feishu-drive/SKILL.md +96 -0
- package/skills/feishu-perm/SKILL.md +90 -0
- package/skills/feishu-wiki/SKILL.md +96 -0
- package/src/accounts.ts +140 -0
- package/src/bitable.ts +441 -0
- package/src/bot.ts +919 -0
- package/src/channel.ts +335 -0
- package/src/client.ts +114 -0
- package/src/config-schema.ts +199 -0
- package/src/directory.ts +165 -0
- package/src/doc-schema.ts +47 -0
- package/src/docx.ts +525 -0
- package/src/drive-schema.ts +46 -0
- package/src/drive.ts +207 -0
- package/src/dynamic-agent.ts +131 -0
- package/src/media.ts +523 -0
- package/src/mention.ts +121 -0
- package/src/monitor.ts +190 -0
- package/src/onboarding.ts +358 -0
- package/src/outbound.ts +40 -0
- package/src/perm-schema.ts +52 -0
- package/src/perm.ts +166 -0
- package/src/policy.ts +92 -0
- package/src/probe.ts +115 -0
- package/src/reactions.ts +160 -0
- package/src/reply-dispatcher.ts +225 -0
- package/src/runtime.ts +14 -0
- package/src/send.ts +492 -0
- package/src/stream.ts +160 -0
- package/src/targets.ts +58 -0
- package/src/tools-config.ts +21 -0
- package/src/types.ts +77 -0
- package/src/typing.ts +75 -0
- package/src/wiki-schema.ts +55 -0
- package/src/wiki.ts +224 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { FeishuToolsConfig } from "./types.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Default tool configuration.
|
|
5
|
+
* - doc, wiki, drive, scopes: enabled by default
|
|
6
|
+
* - perm: disabled by default (sensitive operation)
|
|
7
|
+
*/
|
|
8
|
+
export const DEFAULT_TOOLS_CONFIG: Required<FeishuToolsConfig> = {
|
|
9
|
+
doc: true,
|
|
10
|
+
wiki: true,
|
|
11
|
+
drive: true,
|
|
12
|
+
perm: false,
|
|
13
|
+
scopes: true,
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Resolve tools config with defaults.
|
|
18
|
+
*/
|
|
19
|
+
export function resolveToolsConfig(cfg?: FeishuToolsConfig): Required<FeishuToolsConfig> {
|
|
20
|
+
return { ...DEFAULT_TOOLS_CONFIG, ...cfg };
|
|
21
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { FeishuConfigSchema, FeishuGroupSchema, FeishuAccountConfigSchema, z } from "./config-schema.js";
|
|
2
|
+
import type { MentionTarget } from "./mention.js";
|
|
3
|
+
|
|
4
|
+
export type FeishuConfig = z.infer<typeof FeishuConfigSchema>;
|
|
5
|
+
export type FeishuGroupConfig = z.infer<typeof FeishuGroupSchema>;
|
|
6
|
+
export type FeishuAccountConfig = z.infer<typeof FeishuAccountConfigSchema>;
|
|
7
|
+
|
|
8
|
+
export type FeishuDomain = "feishu" | "lark" | (string & {});
|
|
9
|
+
export type FeishuConnectionMode = "websocket" | "webhook";
|
|
10
|
+
|
|
11
|
+
export type ResolvedFeishuAccount = {
|
|
12
|
+
accountId: string;
|
|
13
|
+
enabled: boolean;
|
|
14
|
+
configured: boolean;
|
|
15
|
+
name?: string;
|
|
16
|
+
appId?: string;
|
|
17
|
+
appSecret?: string;
|
|
18
|
+
encryptKey?: string;
|
|
19
|
+
verificationToken?: string;
|
|
20
|
+
domain: FeishuDomain;
|
|
21
|
+
/** Merged config (top-level defaults + account-specific overrides) */
|
|
22
|
+
config: FeishuConfig;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export type FeishuIdType = "open_id" | "user_id" | "union_id" | "chat_id";
|
|
26
|
+
|
|
27
|
+
export type FeishuMessageContext = {
|
|
28
|
+
chatId: string;
|
|
29
|
+
messageId: string;
|
|
30
|
+
senderId: string;
|
|
31
|
+
senderOpenId: string;
|
|
32
|
+
senderName?: string;
|
|
33
|
+
chatType: "p2p" | "group";
|
|
34
|
+
mentionedBot: boolean;
|
|
35
|
+
rootId?: string;
|
|
36
|
+
parentId?: string;
|
|
37
|
+
content: string;
|
|
38
|
+
contentType: string;
|
|
39
|
+
/** Mention forward targets (excluding the bot itself) */
|
|
40
|
+
mentionTargets?: MentionTarget[];
|
|
41
|
+
/** Extracted message body (after removing @ placeholders) */
|
|
42
|
+
mentionMessageBody?: string;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export type FeishuSendResult = {
|
|
46
|
+
messageId: string;
|
|
47
|
+
chatId: string;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export type FeishuProbeResult = {
|
|
51
|
+
ok: boolean;
|
|
52
|
+
error?: string;
|
|
53
|
+
appId?: string;
|
|
54
|
+
botName?: string;
|
|
55
|
+
botOpenId?: string;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export type FeishuMediaInfo = {
|
|
59
|
+
path: string;
|
|
60
|
+
contentType?: string;
|
|
61
|
+
placeholder: string;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export type FeishuToolsConfig = {
|
|
65
|
+
doc?: boolean;
|
|
66
|
+
wiki?: boolean;
|
|
67
|
+
drive?: boolean;
|
|
68
|
+
perm?: boolean;
|
|
69
|
+
scopes?: boolean;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export type DynamicAgentCreationConfig = {
|
|
73
|
+
enabled?: boolean;
|
|
74
|
+
workspaceTemplate?: string;
|
|
75
|
+
agentDirTemplate?: string;
|
|
76
|
+
maxAgents?: number;
|
|
77
|
+
};
|
package/src/typing.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { ClawdbotConfig } from "openclaw/plugin-sdk";
|
|
2
|
+
import { createFeishuClient } from "./client.js";
|
|
3
|
+
import { resolveFeishuAccount } from "./accounts.js";
|
|
4
|
+
|
|
5
|
+
// Feishu emoji types for typing indicator
|
|
6
|
+
// See: https://open.feishu.cn/document/server-docs/im-v1/message-reaction/emojis-introduce
|
|
7
|
+
// Full list: https://github.com/go-lark/lark/blob/main/emoji.go
|
|
8
|
+
const TYPING_EMOJI = "Typing"; // Typing indicator emoji
|
|
9
|
+
|
|
10
|
+
export type TypingIndicatorState = {
|
|
11
|
+
messageId: string;
|
|
12
|
+
reactionId: string | null;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Add a typing indicator (reaction) to a message
|
|
17
|
+
*/
|
|
18
|
+
export async function addTypingIndicator(params: {
|
|
19
|
+
cfg: ClawdbotConfig;
|
|
20
|
+
messageId: string;
|
|
21
|
+
accountId?: string;
|
|
22
|
+
}): Promise<TypingIndicatorState> {
|
|
23
|
+
const { cfg, messageId, accountId } = params;
|
|
24
|
+
const account = resolveFeishuAccount({ cfg, accountId });
|
|
25
|
+
if (!account.configured) {
|
|
26
|
+
return { messageId, reactionId: null };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const client = createFeishuClient(account);
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
const response = await client.im.messageReaction.create({
|
|
33
|
+
path: { message_id: messageId },
|
|
34
|
+
data: {
|
|
35
|
+
reaction_type: { emoji_type: TYPING_EMOJI },
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const reactionId = (response as any)?.data?.reaction_id ?? null;
|
|
40
|
+
return { messageId, reactionId };
|
|
41
|
+
} catch (err) {
|
|
42
|
+
// Silently fail - typing indicator is not critical
|
|
43
|
+
console.log(`[feishu] failed to add typing indicator: ${err}`);
|
|
44
|
+
return { messageId, reactionId: null };
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Remove a typing indicator (reaction) from a message
|
|
50
|
+
*/
|
|
51
|
+
export async function removeTypingIndicator(params: {
|
|
52
|
+
cfg: ClawdbotConfig;
|
|
53
|
+
state: TypingIndicatorState;
|
|
54
|
+
accountId?: string;
|
|
55
|
+
}): Promise<void> {
|
|
56
|
+
const { cfg, state, accountId } = params;
|
|
57
|
+
if (!state.reactionId) return;
|
|
58
|
+
|
|
59
|
+
const account = resolveFeishuAccount({ cfg, accountId });
|
|
60
|
+
if (!account.configured) return;
|
|
61
|
+
|
|
62
|
+
const client = createFeishuClient(account);
|
|
63
|
+
|
|
64
|
+
try {
|
|
65
|
+
await client.im.messageReaction.delete({
|
|
66
|
+
path: {
|
|
67
|
+
message_id: state.messageId,
|
|
68
|
+
reaction_id: state.reactionId,
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
} catch (err) {
|
|
72
|
+
// Silently fail - cleanup is not critical
|
|
73
|
+
console.log(`[feishu] failed to remove typing indicator: ${err}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Type, type Static } from "@sinclair/typebox";
|
|
2
|
+
|
|
3
|
+
export const FeishuWikiSchema = Type.Union([
|
|
4
|
+
Type.Object({
|
|
5
|
+
action: Type.Literal("spaces"),
|
|
6
|
+
}),
|
|
7
|
+
Type.Object({
|
|
8
|
+
action: Type.Literal("nodes"),
|
|
9
|
+
space_id: Type.String({ description: "Knowledge space ID" }),
|
|
10
|
+
parent_node_token: Type.Optional(
|
|
11
|
+
Type.String({ description: "Parent node token (optional, omit for root)" }),
|
|
12
|
+
),
|
|
13
|
+
}),
|
|
14
|
+
Type.Object({
|
|
15
|
+
action: Type.Literal("get"),
|
|
16
|
+
token: Type.String({ description: "Wiki node token (from URL /wiki/XXX)" }),
|
|
17
|
+
}),
|
|
18
|
+
Type.Object({
|
|
19
|
+
action: Type.Literal("search"),
|
|
20
|
+
query: Type.String({ description: "Search query" }),
|
|
21
|
+
space_id: Type.Optional(Type.String({ description: "Limit search to this space (optional)" })),
|
|
22
|
+
}),
|
|
23
|
+
Type.Object({
|
|
24
|
+
action: Type.Literal("create"),
|
|
25
|
+
space_id: Type.String({ description: "Knowledge space ID" }),
|
|
26
|
+
title: Type.String({ description: "Node title" }),
|
|
27
|
+
obj_type: Type.Optional(
|
|
28
|
+
Type.Union([Type.Literal("docx"), Type.Literal("sheet"), Type.Literal("bitable")], {
|
|
29
|
+
description: "Object type (default: docx)",
|
|
30
|
+
}),
|
|
31
|
+
),
|
|
32
|
+
parent_node_token: Type.Optional(
|
|
33
|
+
Type.String({ description: "Parent node token (optional, omit for root)" }),
|
|
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
|
+
]);
|
|
54
|
+
|
|
55
|
+
export type FeishuWikiParams = Static<typeof FeishuWikiSchema>;
|
package/src/wiki.ts
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
|
2
|
+
import { createFeishuClient } from "./client.js";
|
|
3
|
+
import { listEnabledFeishuAccounts } from "./accounts.js";
|
|
4
|
+
import type * as Lark from "@larksuiteoapi/node-sdk";
|
|
5
|
+
import { FeishuWikiSchema, type FeishuWikiParams } from "./wiki-schema.js";
|
|
6
|
+
import { resolveToolsConfig } from "./tools-config.js";
|
|
7
|
+
|
|
8
|
+
// ============ Helpers ============
|
|
9
|
+
|
|
10
|
+
function json(data: unknown) {
|
|
11
|
+
return {
|
|
12
|
+
content: [{ type: "text" as const, text: JSON.stringify(data, null, 2) }],
|
|
13
|
+
details: data,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
type ObjType = "doc" | "sheet" | "mindnote" | "bitable" | "file" | "docx" | "slides";
|
|
18
|
+
|
|
19
|
+
// ============ Actions ============
|
|
20
|
+
|
|
21
|
+
const WIKI_ACCESS_HINT =
|
|
22
|
+
"To grant wiki access: Open wiki space → Settings → Members → Add the bot. " +
|
|
23
|
+
"See: https://open.feishu.cn/document/server-docs/docs/wiki-v2/wiki-qa#a40ad4ca";
|
|
24
|
+
|
|
25
|
+
async function listSpaces(client: Lark.Client) {
|
|
26
|
+
const res = await client.wiki.space.list({});
|
|
27
|
+
if (res.code !== 0) throw new Error(res.msg);
|
|
28
|
+
|
|
29
|
+
const spaces =
|
|
30
|
+
res.data?.items?.map((s) => ({
|
|
31
|
+
space_id: s.space_id,
|
|
32
|
+
name: s.name,
|
|
33
|
+
description: s.description,
|
|
34
|
+
visibility: s.visibility,
|
|
35
|
+
})) ?? [];
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
spaces,
|
|
39
|
+
...(spaces.length === 0 && { hint: WIKI_ACCESS_HINT }),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function listNodes(client: Lark.Client, spaceId: string, parentNodeToken?: string) {
|
|
44
|
+
const res = await client.wiki.spaceNode.list({
|
|
45
|
+
path: { space_id: spaceId },
|
|
46
|
+
params: { parent_node_token: parentNodeToken },
|
|
47
|
+
});
|
|
48
|
+
if (res.code !== 0) throw new Error(res.msg);
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
nodes:
|
|
52
|
+
res.data?.items?.map((n) => ({
|
|
53
|
+
node_token: n.node_token,
|
|
54
|
+
obj_token: n.obj_token,
|
|
55
|
+
obj_type: n.obj_type,
|
|
56
|
+
title: n.title,
|
|
57
|
+
has_child: n.has_child,
|
|
58
|
+
})) ?? [],
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async function getNode(client: Lark.Client, token: string) {
|
|
63
|
+
const res = await client.wiki.space.getNode({
|
|
64
|
+
params: { token },
|
|
65
|
+
});
|
|
66
|
+
if (res.code !== 0) throw new Error(res.msg);
|
|
67
|
+
|
|
68
|
+
const node = res.data?.node;
|
|
69
|
+
return {
|
|
70
|
+
node_token: node?.node_token,
|
|
71
|
+
space_id: node?.space_id,
|
|
72
|
+
obj_token: node?.obj_token,
|
|
73
|
+
obj_type: node?.obj_type,
|
|
74
|
+
title: node?.title,
|
|
75
|
+
parent_node_token: node?.parent_node_token,
|
|
76
|
+
has_child: node?.has_child,
|
|
77
|
+
creator: node?.creator,
|
|
78
|
+
create_time: node?.node_create_time,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async function createNode(
|
|
83
|
+
client: Lark.Client,
|
|
84
|
+
spaceId: string,
|
|
85
|
+
title: string,
|
|
86
|
+
objType?: string,
|
|
87
|
+
parentNodeToken?: string,
|
|
88
|
+
) {
|
|
89
|
+
const res = await client.wiki.spaceNode.create({
|
|
90
|
+
path: { space_id: spaceId },
|
|
91
|
+
data: {
|
|
92
|
+
obj_type: (objType as ObjType) || "docx",
|
|
93
|
+
node_type: "origin" as const,
|
|
94
|
+
title,
|
|
95
|
+
parent_node_token: parentNodeToken,
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
if (res.code !== 0) throw new Error(res.msg);
|
|
99
|
+
|
|
100
|
+
const node = res.data?.node;
|
|
101
|
+
return {
|
|
102
|
+
node_token: node?.node_token,
|
|
103
|
+
obj_token: node?.obj_token,
|
|
104
|
+
obj_type: node?.obj_type,
|
|
105
|
+
title: node?.title,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async function moveNode(
|
|
110
|
+
client: Lark.Client,
|
|
111
|
+
spaceId: string,
|
|
112
|
+
nodeToken: string,
|
|
113
|
+
targetSpaceId?: string,
|
|
114
|
+
targetParentToken?: string,
|
|
115
|
+
) {
|
|
116
|
+
const res = await client.wiki.spaceNode.move({
|
|
117
|
+
path: { space_id: spaceId, node_token: nodeToken },
|
|
118
|
+
data: {
|
|
119
|
+
target_space_id: targetSpaceId || spaceId,
|
|
120
|
+
target_parent_token: targetParentToken,
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
if (res.code !== 0) throw new Error(res.msg);
|
|
124
|
+
|
|
125
|
+
return {
|
|
126
|
+
success: true,
|
|
127
|
+
node_token: res.data?.node?.node_token,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
async function renameNode(
|
|
132
|
+
client: Lark.Client,
|
|
133
|
+
spaceId: string,
|
|
134
|
+
nodeToken: string,
|
|
135
|
+
title: string,
|
|
136
|
+
) {
|
|
137
|
+
const res = await client.wiki.spaceNode.updateTitle({
|
|
138
|
+
path: { space_id: spaceId, node_token: nodeToken },
|
|
139
|
+
data: { title },
|
|
140
|
+
});
|
|
141
|
+
if (res.code !== 0) throw new Error(res.msg);
|
|
142
|
+
|
|
143
|
+
return {
|
|
144
|
+
success: true,
|
|
145
|
+
node_token: nodeToken,
|
|
146
|
+
title,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// ============ Tool Registration ============
|
|
151
|
+
|
|
152
|
+
export function registerFeishuWikiTools(api: OpenClawPluginApi) {
|
|
153
|
+
if (!api.config) {
|
|
154
|
+
api.logger.debug?.("feishu_wiki: No config available, skipping wiki tools");
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const accounts = listEnabledFeishuAccounts(api.config);
|
|
159
|
+
if (accounts.length === 0) {
|
|
160
|
+
api.logger.debug?.("feishu_wiki: No Feishu accounts configured, skipping wiki tools");
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const firstAccount = accounts[0];
|
|
165
|
+
const toolsCfg = resolveToolsConfig(firstAccount.config.tools);
|
|
166
|
+
if (!toolsCfg.wiki) {
|
|
167
|
+
api.logger.debug?.("feishu_wiki: wiki tool disabled in config");
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const getClient = () => createFeishuClient(firstAccount);
|
|
172
|
+
|
|
173
|
+
api.registerTool(
|
|
174
|
+
{
|
|
175
|
+
name: "feishu_wiki",
|
|
176
|
+
label: "Feishu Wiki",
|
|
177
|
+
description:
|
|
178
|
+
"Feishu knowledge base operations. Actions: spaces, nodes, get, create, move, rename",
|
|
179
|
+
parameters: FeishuWikiSchema,
|
|
180
|
+
async execute(_toolCallId, params) {
|
|
181
|
+
const p = params as FeishuWikiParams;
|
|
182
|
+
try {
|
|
183
|
+
const client = getClient();
|
|
184
|
+
switch (p.action) {
|
|
185
|
+
case "spaces":
|
|
186
|
+
return json(await listSpaces(client));
|
|
187
|
+
case "nodes":
|
|
188
|
+
return json(await listNodes(client, p.space_id, p.parent_node_token));
|
|
189
|
+
case "get":
|
|
190
|
+
return json(await getNode(client, p.token));
|
|
191
|
+
case "search":
|
|
192
|
+
return json({
|
|
193
|
+
error:
|
|
194
|
+
"Search is not available. Use feishu_wiki with action: 'nodes' to browse or action: 'get' to lookup by token.",
|
|
195
|
+
});
|
|
196
|
+
case "create":
|
|
197
|
+
return json(
|
|
198
|
+
await createNode(client, p.space_id, p.title, p.obj_type, p.parent_node_token),
|
|
199
|
+
);
|
|
200
|
+
case "move":
|
|
201
|
+
return json(
|
|
202
|
+
await moveNode(
|
|
203
|
+
client,
|
|
204
|
+
p.space_id,
|
|
205
|
+
p.node_token,
|
|
206
|
+
p.target_space_id,
|
|
207
|
+
p.target_parent_token,
|
|
208
|
+
),
|
|
209
|
+
);
|
|
210
|
+
case "rename":
|
|
211
|
+
return json(await renameNode(client, p.space_id, p.node_token, p.title));
|
|
212
|
+
default:
|
|
213
|
+
return json({ error: `Unknown action: ${(p as any).action}` });
|
|
214
|
+
}
|
|
215
|
+
} catch (err) {
|
|
216
|
+
return json({ error: err instanceof Error ? err.message : String(err) });
|
|
217
|
+
}
|
|
218
|
+
},
|
|
219
|
+
},
|
|
220
|
+
{ name: "feishu_wiki" },
|
|
221
|
+
);
|
|
222
|
+
|
|
223
|
+
api.logger.info?.(`feishu_wiki: Registered feishu_wiki tool`);
|
|
224
|
+
}
|