@kodelyth/feishu 2026.5.42 → 2026.6.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.
Files changed (192) hide show
  1. package/klaw.plugin.json +1712 -47
  2. package/package.json +17 -4
  3. package/api.ts +0 -32
  4. package/channel-entry.ts +0 -20
  5. package/channel-plugin-api.ts +0 -1
  6. package/contract-api.ts +0 -16
  7. package/index.ts +0 -82
  8. package/runtime-api.ts +0 -52
  9. package/secret-contract-api.ts +0 -5
  10. package/security-contract-api.ts +0 -1
  11. package/session-key-api.ts +0 -1
  12. package/setup-api.ts +0 -3
  13. package/setup-entry.test.ts +0 -19
  14. package/setup-entry.ts +0 -13
  15. package/src/accounts.test.ts +0 -480
  16. package/src/accounts.ts +0 -333
  17. package/src/agent-config.ts +0 -21
  18. package/src/app-registration.ts +0 -331
  19. package/src/approval-auth.test.ts +0 -24
  20. package/src/approval-auth.ts +0 -25
  21. package/src/async.test.ts +0 -35
  22. package/src/async.ts +0 -104
  23. package/src/audio-preflight.runtime.ts +0 -9
  24. package/src/bitable.test.ts +0 -136
  25. package/src/bitable.ts +0 -762
  26. package/src/bot-content.ts +0 -485
  27. package/src/bot-group-name.test.ts +0 -116
  28. package/src/bot-runtime-api.ts +0 -12
  29. package/src/bot-sender-name.ts +0 -125
  30. package/src/bot.broadcast.test.ts +0 -523
  31. package/src/bot.card-action.test.ts +0 -552
  32. package/src/bot.checkBotMentioned.test.ts +0 -265
  33. package/src/bot.helpers.test.ts +0 -135
  34. package/src/bot.stripBotMention.test.ts +0 -126
  35. package/src/bot.test.ts +0 -3671
  36. package/src/bot.ts +0 -1703
  37. package/src/card-action.ts +0 -447
  38. package/src/card-interaction.test.ts +0 -131
  39. package/src/card-interaction.ts +0 -159
  40. package/src/card-test-helpers.ts +0 -54
  41. package/src/card-ux-approval.ts +0 -65
  42. package/src/card-ux-launcher.test.ts +0 -106
  43. package/src/card-ux-launcher.ts +0 -121
  44. package/src/card-ux-shared.ts +0 -33
  45. package/src/channel-runtime-api.ts +0 -16
  46. package/src/channel.runtime.ts +0 -47
  47. package/src/channel.test.ts +0 -1151
  48. package/src/channel.ts +0 -1423
  49. package/src/chat-schema.ts +0 -25
  50. package/src/chat.test.ts +0 -240
  51. package/src/chat.ts +0 -188
  52. package/src/client-timeout.ts +0 -42
  53. package/src/client.test.ts +0 -447
  54. package/src/client.ts +0 -262
  55. package/src/comment-dispatcher-runtime-api.ts +0 -6
  56. package/src/comment-dispatcher.test.ts +0 -185
  57. package/src/comment-dispatcher.ts +0 -107
  58. package/src/comment-handler-runtime-api.ts +0 -3
  59. package/src/comment-handler.test.ts +0 -592
  60. package/src/comment-handler.ts +0 -303
  61. package/src/comment-reaction.test.ts +0 -138
  62. package/src/comment-reaction.ts +0 -259
  63. package/src/comment-shared.test.ts +0 -183
  64. package/src/comment-shared.ts +0 -406
  65. package/src/comment-target.ts +0 -44
  66. package/src/config-schema.test.ts +0 -326
  67. package/src/config-schema.ts +0 -335
  68. package/src/conversation-id.test.ts +0 -18
  69. package/src/conversation-id.ts +0 -199
  70. package/src/dedup-runtime-api.ts +0 -1
  71. package/src/dedup.ts +0 -141
  72. package/src/dedupe-key.ts +0 -72
  73. package/src/directory.static.ts +0 -61
  74. package/src/directory.test.ts +0 -141
  75. package/src/directory.ts +0 -124
  76. package/src/doc-schema.ts +0 -182
  77. package/src/docx-batch-insert.test.ts +0 -116
  78. package/src/docx-batch-insert.ts +0 -223
  79. package/src/docx-color-text.ts +0 -154
  80. package/src/docx-table-ops.test.ts +0 -53
  81. package/src/docx-table-ops.ts +0 -316
  82. package/src/docx-types.ts +0 -38
  83. package/src/docx.account-selection.test.ts +0 -95
  84. package/src/docx.test.ts +0 -701
  85. package/src/docx.ts +0 -1596
  86. package/src/drive-schema.ts +0 -92
  87. package/src/drive.test.ts +0 -1237
  88. package/src/drive.ts +0 -829
  89. package/src/dynamic-agent.test.ts +0 -155
  90. package/src/dynamic-agent.ts +0 -143
  91. package/src/event-types.ts +0 -45
  92. package/src/external-keys.test.ts +0 -20
  93. package/src/external-keys.ts +0 -19
  94. package/src/lifecycle.test-support.ts +0 -220
  95. package/src/media.test.ts +0 -955
  96. package/src/media.ts +0 -1105
  97. package/src/mention-target.types.ts +0 -5
  98. package/src/mention.ts +0 -114
  99. package/src/message-action-contract.ts +0 -13
  100. package/src/monitor-state-runtime-api.ts +0 -7
  101. package/src/monitor-transport-runtime-api.ts +0 -10
  102. package/src/monitor.account.ts +0 -492
  103. package/src/monitor.acp-init-failure.lifecycle.test-support.ts +0 -219
  104. package/src/monitor.bot-identity.ts +0 -86
  105. package/src/monitor.bot-menu-handler.ts +0 -165
  106. package/src/monitor.bot-menu.lifecycle.test-support.ts +0 -224
  107. package/src/monitor.bot-menu.test.ts +0 -188
  108. package/src/monitor.broadcast.reply-once.lifecycle.test-support.ts +0 -264
  109. package/src/monitor.card-action.lifecycle.test-support.ts +0 -421
  110. package/src/monitor.cleanup.test.ts +0 -383
  111. package/src/monitor.comment-notice-handler.ts +0 -105
  112. package/src/monitor.comment.test.ts +0 -967
  113. package/src/monitor.comment.ts +0 -1386
  114. package/src/monitor.lifecycle.test.ts +0 -4
  115. package/src/monitor.message-handler.ts +0 -350
  116. package/src/monitor.reaction.lifecycle.test-support.ts +0 -68
  117. package/src/monitor.reaction.test.ts +0 -739
  118. package/src/monitor.startup.test.ts +0 -213
  119. package/src/monitor.startup.ts +0 -74
  120. package/src/monitor.state.defaults.test.ts +0 -46
  121. package/src/monitor.state.ts +0 -170
  122. package/src/monitor.synthetic-error.ts +0 -18
  123. package/src/monitor.test-mocks.ts +0 -46
  124. package/src/monitor.transport.ts +0 -451
  125. package/src/monitor.ts +0 -100
  126. package/src/monitor.webhook-e2e.test.ts +0 -279
  127. package/src/monitor.webhook-security.test.ts +0 -389
  128. package/src/monitor.webhook.test-helpers.ts +0 -116
  129. package/src/outbound-runtime-api.ts +0 -1
  130. package/src/outbound.test.ts +0 -1118
  131. package/src/outbound.ts +0 -785
  132. package/src/perm-schema.ts +0 -52
  133. package/src/perm.ts +0 -170
  134. package/src/pins.ts +0 -108
  135. package/src/policy.test.ts +0 -223
  136. package/src/policy.ts +0 -318
  137. package/src/post.test.ts +0 -105
  138. package/src/post.ts +0 -275
  139. package/src/probe.test.ts +0 -283
  140. package/src/probe.ts +0 -166
  141. package/src/processing-claims.ts +0 -59
  142. package/src/qr-terminal.ts +0 -1
  143. package/src/reactions.ts +0 -123
  144. package/src/reasoning-preview.test.ts +0 -113
  145. package/src/reasoning-preview.ts +0 -28
  146. package/src/reply-dispatcher-runtime-api.ts +0 -7
  147. package/src/reply-dispatcher.test.ts +0 -1513
  148. package/src/reply-dispatcher.ts +0 -748
  149. package/src/runtime.ts +0 -9
  150. package/src/secret-contract.ts +0 -145
  151. package/src/secret-input.ts +0 -1
  152. package/src/security-audit-shared.ts +0 -69
  153. package/src/security-audit.test.ts +0 -59
  154. package/src/security-audit.ts +0 -1
  155. package/src/send-result.ts +0 -80
  156. package/src/send-target.test.ts +0 -86
  157. package/src/send-target.ts +0 -35
  158. package/src/send.reply-fallback.test.ts +0 -417
  159. package/src/send.test.ts +0 -621
  160. package/src/send.ts +0 -861
  161. package/src/sequential-key.test.ts +0 -72
  162. package/src/sequential-key.ts +0 -25
  163. package/src/sequential-queue.test.ts +0 -165
  164. package/src/sequential-queue.ts +0 -86
  165. package/src/session-conversation.ts +0 -42
  166. package/src/session-route.ts +0 -48
  167. package/src/setup-core.ts +0 -51
  168. package/src/setup-surface.test.ts +0 -484
  169. package/src/setup-surface.ts +0 -618
  170. package/src/streaming-card.test.ts +0 -397
  171. package/src/streaming-card.ts +0 -571
  172. package/src/subagent-hooks.test.ts +0 -627
  173. package/src/subagent-hooks.ts +0 -413
  174. package/src/targets.ts +0 -97
  175. package/src/test-support/lifecycle-test-support.ts +0 -454
  176. package/src/thread-bindings.test.ts +0 -180
  177. package/src/thread-bindings.ts +0 -331
  178. package/src/tool-account-routing.test.ts +0 -250
  179. package/src/tool-account.test.ts +0 -44
  180. package/src/tool-account.ts +0 -93
  181. package/src/tool-factory-test-harness.ts +0 -79
  182. package/src/tool-result.test.ts +0 -32
  183. package/src/tool-result.ts +0 -16
  184. package/src/tools-config.test.ts +0 -21
  185. package/src/tools-config.ts +0 -22
  186. package/src/types.ts +0 -106
  187. package/src/typing.test.ts +0 -144
  188. package/src/typing.ts +0 -214
  189. package/src/wiki-schema.ts +0 -69
  190. package/src/wiki.ts +0 -270
  191. package/subagent-hooks-api.ts +0 -31
  192. package/tsconfig.json +0 -16
package/src/typing.ts DELETED
@@ -1,214 +0,0 @@
1
- import type { ClawdbotConfig, RuntimeEnv } from "../runtime-api.js";
2
- import { resolveFeishuRuntimeAccount } from "./accounts.js";
3
- import { createFeishuClient } from "./client.js";
4
- import { getFeishuRuntime } from "./runtime.js";
5
-
6
- // Feishu emoji types for typing indicator
7
- // See: https://open.feishu.cn/document/server-docs/im-v1/message-reaction/emojis-introduce
8
- // Full list: https://github.com/go-lark/lark/blob/main/emoji.go
9
- const TYPING_EMOJI = "Typing"; // Typing indicator emoji
10
-
11
- /**
12
- * Feishu API error codes that indicate the caller should back off.
13
- * These must propagate to the typing circuit breaker so the keepalive loop
14
- * can trip and stop retrying.
15
- *
16
- * - 99991400: Rate limit (too many requests per second)
17
- * - 99991403: Monthly API call quota exceeded
18
- * - 429: Standard HTTP 429 returned as a Feishu SDK error code
19
- *
20
- * @see https://open.feishu.cn/document/server-docs/api-call-guide/generic-error-code
21
- */
22
- const FEISHU_BACKOFF_CODES = new Set([99991400, 99991403, 429]);
23
-
24
- /**
25
- * Custom error class for Feishu backoff conditions detected from non-throwing
26
- * SDK responses. Carries a numeric `.code` so that `isFeishuBackoffError()`
27
- * recognises it when the error is caught downstream.
28
- */
29
- export class FeishuBackoffError extends Error {
30
- code: number;
31
- constructor(code: number) {
32
- super(`Feishu API backoff: code ${code}`);
33
- this.name = "FeishuBackoffError";
34
- this.code = code;
35
- }
36
- }
37
-
38
- export type TypingIndicatorState = {
39
- messageId: string;
40
- reactionId: string | null;
41
- };
42
-
43
- type FeishuMessageReactionCreateResponse = Awaited<
44
- ReturnType<ReturnType<typeof createFeishuClient>["im"]["messageReaction"]["create"]>
45
- >;
46
-
47
- /**
48
- * Check whether an error represents a rate-limit or quota-exceeded condition
49
- * from the Feishu API that should stop the typing keepalive loop.
50
- *
51
- * Handles two shapes:
52
- * 1. AxiosError with `response.status` and `response.data.code`
53
- * 2. Feishu SDK error with a top-level `code` property
54
- */
55
- export function isFeishuBackoffError(err: unknown): boolean {
56
- if (typeof err !== "object" || err === null) {
57
- return false;
58
- }
59
-
60
- // AxiosError shape: err.response.status / err.response.data.code
61
- const response = (err as { response?: { status?: number; data?: { code?: number } } }).response;
62
- if (response) {
63
- if (response.status === 429) {
64
- return true;
65
- }
66
- if (typeof response.data?.code === "number" && FEISHU_BACKOFF_CODES.has(response.data.code)) {
67
- return true;
68
- }
69
- }
70
-
71
- // Feishu SDK error shape: err.code
72
- const code = (err as { code?: number }).code;
73
- if (typeof code === "number" && FEISHU_BACKOFF_CODES.has(code)) {
74
- return true;
75
- }
76
-
77
- return false;
78
- }
79
-
80
- /**
81
- * Check whether a Feishu SDK response object contains a backoff error code.
82
- *
83
- * The Feishu SDK sometimes returns a normal response (no throw) with an
84
- * API-level error code in the response body. This must be detected so the
85
- * circuit breaker can trip. See codex review on #28157.
86
- */
87
- export function getBackoffCodeFromResponse(response: unknown): number | undefined {
88
- if (typeof response !== "object" || response === null) {
89
- return undefined;
90
- }
91
- const code = (response as { code?: number }).code;
92
- if (typeof code === "number" && FEISHU_BACKOFF_CODES.has(code)) {
93
- return code;
94
- }
95
- return undefined;
96
- }
97
-
98
- /**
99
- * Add a typing indicator (reaction) to a message.
100
- *
101
- * Rate-limit and quota errors are re-thrown so the circuit breaker in
102
- * `createTypingCallbacks` (typing-start-guard) can trip and stop the
103
- * keepalive loop. See #28062.
104
- *
105
- * Also checks for backoff codes in non-throwing SDK responses (#28157).
106
- */
107
- export async function addTypingIndicator(params: {
108
- cfg: ClawdbotConfig;
109
- messageId: string;
110
- accountId?: string;
111
- runtime?: RuntimeEnv;
112
- }): Promise<TypingIndicatorState> {
113
- const { cfg, messageId, accountId, runtime } = params;
114
- const account = resolveFeishuRuntimeAccount({ cfg, accountId });
115
- if (!account.configured) {
116
- return { messageId, reactionId: null };
117
- }
118
-
119
- const client = createFeishuClient(account);
120
-
121
- try {
122
- const response = await client.im.messageReaction.create({
123
- path: { message_id: messageId },
124
- data: {
125
- reaction_type: { emoji_type: TYPING_EMOJI },
126
- },
127
- });
128
-
129
- // Feishu SDK may return a normal response with an API-level error code
130
- // instead of throwing. Detect backoff codes and throw to trip the breaker.
131
- const backoffCode = getBackoffCodeFromResponse(response);
132
- if (backoffCode !== undefined) {
133
- if (getFeishuRuntime().logging.shouldLogVerbose()) {
134
- runtime?.log?.(
135
- `[feishu] typing indicator response contains backoff code ${backoffCode}, stopping keepalive`,
136
- );
137
- }
138
- throw new FeishuBackoffError(backoffCode);
139
- }
140
-
141
- const typedResponse: FeishuMessageReactionCreateResponse = response;
142
- const reactionId = typedResponse.data?.reaction_id ?? null;
143
- return { messageId, reactionId };
144
- } catch (err) {
145
- if (isFeishuBackoffError(err)) {
146
- if (getFeishuRuntime().logging.shouldLogVerbose()) {
147
- runtime?.log?.("[feishu] typing indicator hit rate-limit/quota, stopping keepalive");
148
- }
149
- throw err;
150
- }
151
- // Silently fail for other non-critical errors (e.g. message deleted, permission issues)
152
- if (getFeishuRuntime().logging.shouldLogVerbose()) {
153
- runtime?.log?.(`[feishu] failed to add typing indicator: ${String(err)}`);
154
- }
155
- return { messageId, reactionId: null };
156
- }
157
- }
158
-
159
- /**
160
- * Remove a typing indicator (reaction) from a message.
161
- *
162
- * Rate-limit and quota errors are re-thrown for the same reason as above.
163
- */
164
- export async function removeTypingIndicator(params: {
165
- cfg: ClawdbotConfig;
166
- state: TypingIndicatorState;
167
- accountId?: string;
168
- runtime?: RuntimeEnv;
169
- }): Promise<void> {
170
- const { cfg, state, accountId, runtime } = params;
171
- if (!state.reactionId) {
172
- return;
173
- }
174
-
175
- const account = resolveFeishuRuntimeAccount({ cfg, accountId });
176
- if (!account.configured) {
177
- return;
178
- }
179
-
180
- const client = createFeishuClient(account);
181
-
182
- try {
183
- const result = await client.im.messageReaction.delete({
184
- path: {
185
- message_id: state.messageId,
186
- reaction_id: state.reactionId,
187
- },
188
- });
189
-
190
- // Check for backoff codes in non-throwing SDK responses
191
- const backoffCode = getBackoffCodeFromResponse(result);
192
- if (backoffCode !== undefined) {
193
- if (getFeishuRuntime().logging.shouldLogVerbose()) {
194
- runtime?.log?.(
195
- `[feishu] typing indicator removal response contains backoff code ${backoffCode}, stopping keepalive`,
196
- );
197
- }
198
- throw new FeishuBackoffError(backoffCode);
199
- }
200
- } catch (err) {
201
- if (isFeishuBackoffError(err)) {
202
- if (getFeishuRuntime().logging.shouldLogVerbose()) {
203
- runtime?.log?.(
204
- "[feishu] typing indicator removal hit rate-limit/quota, stopping keepalive",
205
- );
206
- }
207
- throw err;
208
- }
209
- // Silently fail for other non-critical errors
210
- if (getFeishuRuntime().logging.shouldLogVerbose()) {
211
- runtime?.log?.(`[feishu] failed to remove typing indicator: ${String(err)}`);
212
- }
213
- }
214
- }
@@ -1,69 +0,0 @@
1
- import { Type, type Static } from "typebox";
2
-
3
- const WIKI_SPACE_ID_DESCRIPTION =
4
- "Knowledge space ID. Treat as an opaque string and keep it quoted; never pass numeric-looking IDs as numbers.";
5
-
6
- export const FeishuWikiSchema = Type.Union([
7
- Type.Object({
8
- action: Type.Literal("spaces"),
9
- }),
10
- Type.Object({
11
- action: Type.Literal("nodes"),
12
- space_id: Type.String({ description: WIKI_SPACE_ID_DESCRIPTION }),
13
- parent_node_token: Type.Optional(
14
- Type.String({ description: "Parent node token (optional, omit for root)" }),
15
- ),
16
- }),
17
- Type.Object({
18
- action: Type.Literal("get"),
19
- token: Type.String({ description: "Wiki node token (from URL /wiki/XXX)" }),
20
- }),
21
- Type.Object({
22
- action: Type.Literal("search"),
23
- query: Type.String({ description: "Search query" }),
24
- space_id: Type.Optional(
25
- Type.String({
26
- description:
27
- "Limit search to this knowledge space. Treat as an opaque string and keep it quoted; never pass numeric-looking IDs as numbers.",
28
- }),
29
- ),
30
- }),
31
- Type.Object({
32
- action: Type.Literal("create"),
33
- space_id: Type.String({ description: WIKI_SPACE_ID_DESCRIPTION }),
34
- title: Type.String({ description: "Node title" }),
35
- obj_type: Type.Optional(
36
- Type.Union([Type.Literal("docx"), Type.Literal("sheet"), Type.Literal("bitable")], {
37
- description: "Object type (default: docx)",
38
- }),
39
- ),
40
- parent_node_token: Type.Optional(
41
- Type.String({ description: "Parent node token (optional, omit for root)" }),
42
- ),
43
- }),
44
- Type.Object({
45
- action: Type.Literal("move"),
46
- space_id: Type.String({
47
- description:
48
- "Source knowledge space ID. Treat as an opaque string and keep it quoted; never pass numeric-looking IDs as numbers.",
49
- }),
50
- node_token: Type.String({ description: "Node token to move" }),
51
- target_space_id: Type.Optional(
52
- Type.String({
53
- description:
54
- "Target knowledge space ID (optional, same space if omitted). Treat as an opaque string and keep it quoted; never pass numeric-looking IDs as numbers.",
55
- }),
56
- ),
57
- target_parent_token: Type.Optional(
58
- Type.String({ description: "Target parent node token (optional, root if omitted)" }),
59
- ),
60
- }),
61
- Type.Object({
62
- action: Type.Literal("rename"),
63
- space_id: Type.String({ description: WIKI_SPACE_ID_DESCRIPTION }),
64
- node_token: Type.String({ description: "Node token to rename" }),
65
- title: Type.String({ description: "New title" }),
66
- }),
67
- ]);
68
-
69
- export type FeishuWikiParams = Static<typeof FeishuWikiSchema>;
package/src/wiki.ts DELETED
@@ -1,270 +0,0 @@
1
- import type * as Lark from "@larksuiteoapi/node-sdk";
2
- import type { KlawPluginApi } from "../runtime-api.js";
3
- import { listEnabledFeishuAccounts } from "./accounts.js";
4
- import { createFeishuToolClient, resolveAnyEnabledFeishuToolsConfig } from "./tool-account.js";
5
- import {
6
- jsonToolResult,
7
- toolExecutionErrorResult,
8
- unknownToolActionResult,
9
- } from "./tool-result.js";
10
- import { FeishuWikiSchema, type FeishuWikiParams } from "./wiki-schema.js";
11
-
12
- type ObjType = "doc" | "sheet" | "mindnote" | "bitable" | "file" | "docx" | "slides";
13
-
14
- // ============ Actions ============
15
-
16
- const WIKI_ACCESS_HINT =
17
- "To grant wiki access: Open wiki space → Settings → Members → Add the bot. " +
18
- "See: https://open.feishu.cn/document/server-docs/docs/wiki-v2/wiki-qa#a40ad4ca";
19
-
20
- function requireWikiSpaceId(value: unknown, fieldName: string): string {
21
- if (typeof value !== "string") {
22
- throw new Error(
23
- `${fieldName} must be a string. Feishu wiki space IDs are opaque identifiers; pass them quoted to avoid JavaScript number precision loss.`,
24
- );
25
- }
26
-
27
- const trimmed = value.trim();
28
- if (!trimmed) {
29
- throw new Error(`${fieldName} must not be empty.`);
30
- }
31
-
32
- return trimmed;
33
- }
34
-
35
- function optionalWikiSpaceId(value: unknown, fieldName: string): string | undefined {
36
- if (value === undefined || value === null || value === "") {
37
- return undefined;
38
- }
39
- return requireWikiSpaceId(value, fieldName);
40
- }
41
-
42
- async function listSpaces(client: Lark.Client) {
43
- const res = await client.wiki.space.list({});
44
- if (res.code !== 0) {
45
- throw new Error(res.msg);
46
- }
47
-
48
- const spaces =
49
- res.data?.items?.map((s) => ({
50
- space_id: s.space_id,
51
- name: s.name,
52
- description: s.description,
53
- visibility: s.visibility,
54
- })) ?? [];
55
-
56
- return {
57
- spaces,
58
- ...(spaces.length === 0 && { hint: WIKI_ACCESS_HINT }),
59
- };
60
- }
61
-
62
- async function listNodes(client: Lark.Client, spaceId: string, parentNodeToken?: string) {
63
- const res = await client.wiki.spaceNode.list({
64
- path: { space_id: spaceId },
65
- params: { parent_node_token: parentNodeToken },
66
- });
67
- if (res.code !== 0) {
68
- throw new Error(res.msg);
69
- }
70
-
71
- return {
72
- nodes:
73
- res.data?.items?.map((n) => ({
74
- node_token: n.node_token,
75
- obj_token: n.obj_token,
76
- obj_type: n.obj_type,
77
- title: n.title,
78
- has_child: n.has_child,
79
- })) ?? [],
80
- };
81
- }
82
-
83
- async function getNode(client: Lark.Client, token: string) {
84
- const res = await client.wiki.space.getNode({
85
- params: { token },
86
- });
87
- if (res.code !== 0) {
88
- throw new Error(res.msg);
89
- }
90
-
91
- const node = res.data?.node;
92
- return {
93
- node_token: node?.node_token,
94
- space_id: node?.space_id,
95
- obj_token: node?.obj_token,
96
- obj_type: node?.obj_type,
97
- title: node?.title,
98
- parent_node_token: node?.parent_node_token,
99
- has_child: node?.has_child,
100
- creator: node?.creator,
101
- create_time: node?.node_create_time,
102
- };
103
- }
104
-
105
- async function createNode(
106
- client: Lark.Client,
107
- spaceId: string,
108
- title: string,
109
- objType?: string,
110
- parentNodeToken?: string,
111
- ) {
112
- const res = await client.wiki.spaceNode.create({
113
- path: { space_id: spaceId },
114
- data: {
115
- obj_type: (objType as ObjType) || "docx",
116
- node_type: "origin" as const,
117
- title,
118
- parent_node_token: parentNodeToken,
119
- },
120
- });
121
- if (res.code !== 0) {
122
- throw new Error(res.msg);
123
- }
124
-
125
- const node = res.data?.node;
126
- return {
127
- node_token: node?.node_token,
128
- obj_token: node?.obj_token,
129
- obj_type: node?.obj_type,
130
- title: node?.title,
131
- };
132
- }
133
-
134
- async function moveNode(
135
- client: Lark.Client,
136
- spaceId: string,
137
- nodeToken: string,
138
- targetSpaceId?: string,
139
- targetParentToken?: string,
140
- ) {
141
- const res = await client.wiki.spaceNode.move({
142
- path: { space_id: spaceId, node_token: nodeToken },
143
- data: {
144
- target_space_id: targetSpaceId || spaceId,
145
- target_parent_token: targetParentToken,
146
- },
147
- });
148
- if (res.code !== 0) {
149
- throw new Error(res.msg);
150
- }
151
-
152
- return {
153
- success: true,
154
- node_token: res.data?.node?.node_token,
155
- };
156
- }
157
-
158
- async function renameNode(client: Lark.Client, spaceId: string, nodeToken: string, title: string) {
159
- const res = await client.wiki.spaceNode.updateTitle({
160
- path: { space_id: spaceId, node_token: nodeToken },
161
- data: { title },
162
- });
163
- if (res.code !== 0) {
164
- throw new Error(res.msg);
165
- }
166
-
167
- return {
168
- success: true,
169
- node_token: nodeToken,
170
- title,
171
- };
172
- }
173
-
174
- // ============ Tool Registration ============
175
-
176
- export function registerFeishuWikiTools(api: KlawPluginApi) {
177
- if (!api.config) {
178
- return;
179
- }
180
-
181
- const accounts = listEnabledFeishuAccounts(api.config);
182
- if (accounts.length === 0) {
183
- return;
184
- }
185
-
186
- const toolsCfg = resolveAnyEnabledFeishuToolsConfig(accounts);
187
- if (!toolsCfg.wiki) {
188
- return;
189
- }
190
-
191
- type FeishuWikiExecuteParams = FeishuWikiParams & { accountId?: string };
192
-
193
- api.registerTool(
194
- (ctx) => {
195
- const defaultAccountId = ctx.agentAccountId;
196
- return {
197
- name: "feishu_wiki",
198
- label: "Feishu Wiki",
199
- description:
200
- "Feishu knowledge base operations. Actions: spaces, nodes, get, create, move, rename",
201
- parameters: FeishuWikiSchema,
202
- async execute(_toolCallId, params) {
203
- const p = params as FeishuWikiExecuteParams;
204
- try {
205
- const createClient = () =>
206
- createFeishuToolClient({
207
- api,
208
- executeParams: p,
209
- defaultAccountId,
210
- });
211
- switch (p.action) {
212
- case "spaces":
213
- return jsonToolResult(await listSpaces(createClient()));
214
- case "nodes": {
215
- const spaceId = requireWikiSpaceId(p.space_id, "space_id");
216
- return jsonToolResult(
217
- await listNodes(createClient(), spaceId, p.parent_node_token),
218
- );
219
- }
220
- case "get":
221
- return jsonToolResult(await getNode(createClient(), p.token));
222
- case "search":
223
- optionalWikiSpaceId(p.space_id, "space_id");
224
- createClient();
225
- return jsonToolResult({
226
- error:
227
- "Search is not available. Use feishu_wiki with action: 'nodes' to browse or action: 'get' to lookup by token.",
228
- });
229
- case "create": {
230
- const spaceId = requireWikiSpaceId(p.space_id, "space_id");
231
- return jsonToolResult(
232
- await createNode(
233
- createClient(),
234
- spaceId,
235
- p.title,
236
- p.obj_type,
237
- p.parent_node_token,
238
- ),
239
- );
240
- }
241
- case "move": {
242
- const spaceId = requireWikiSpaceId(p.space_id, "space_id");
243
- return jsonToolResult(
244
- await moveNode(
245
- createClient(),
246
- spaceId,
247
- p.node_token,
248
- optionalWikiSpaceId(p.target_space_id, "target_space_id"),
249
- p.target_parent_token,
250
- ),
251
- );
252
- }
253
- case "rename": {
254
- const spaceId = requireWikiSpaceId(p.space_id, "space_id");
255
- return jsonToolResult(
256
- await renameNode(createClient(), spaceId, p.node_token, p.title),
257
- );
258
- }
259
- default:
260
- return unknownToolActionResult((p as { action?: unknown }).action);
261
- }
262
- } catch (err) {
263
- return toolExecutionErrorResult(err);
264
- }
265
- },
266
- };
267
- },
268
- { name: "feishu_wiki" },
269
- );
270
- }
@@ -1,31 +0,0 @@
1
- import type { KlawPluginApi } from "klaw/plugin-sdk/channel-entry-contract";
2
-
3
- type FeishuSubagentHooksModule = typeof import("./src/subagent-hooks.js");
4
-
5
- let feishuSubagentHooksPromise: Promise<FeishuSubagentHooksModule> | null = null;
6
-
7
- function loadFeishuSubagentHooksModule() {
8
- feishuSubagentHooksPromise ??= import("./src/subagent-hooks.js");
9
- return feishuSubagentHooksPromise;
10
- }
11
-
12
- export function registerFeishuSubagentHooks(api: KlawPluginApi): void {
13
- api.on("subagent_spawning", async (event, ctx) => {
14
- const { handleFeishuSubagentSpawning } = await loadFeishuSubagentHooksModule();
15
- return await handleFeishuSubagentSpawning(event, ctx);
16
- });
17
- api.on("subagent_delivery_target", async (event) => {
18
- const { handleFeishuSubagentDeliveryTarget } = await loadFeishuSubagentHooksModule();
19
- return handleFeishuSubagentDeliveryTarget(event);
20
- });
21
- api.on("subagent_ended", async (event) => {
22
- const { handleFeishuSubagentEnded } = await loadFeishuSubagentHooksModule();
23
- handleFeishuSubagentEnded(event);
24
- });
25
- }
26
-
27
- export {
28
- handleFeishuSubagentDeliveryTarget,
29
- handleFeishuSubagentEnded,
30
- handleFeishuSubagentSpawning,
31
- } from "./src/subagent-hooks.js";
package/tsconfig.json DELETED
@@ -1,16 +0,0 @@
1
- {
2
- "extends": "../tsconfig.package-boundary.base.json",
3
- "compilerOptions": {
4
- "rootDir": "."
5
- },
6
- "include": ["./*.ts", "./src/**/*.ts"],
7
- "exclude": [
8
- "./**/*.test.ts",
9
- "./dist/**",
10
- "./node_modules/**",
11
- "./src/test-support/**",
12
- "./src/**/*test-helpers.ts",
13
- "./src/**/*test-harness.ts",
14
- "./src/**/*test-support.ts"
15
- ]
16
- }