@openclaw/feishu 2026.3.13 → 2026.5.2-beta.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 (187) hide show
  1. package/api.ts +31 -0
  2. package/channel-entry.ts +20 -0
  3. package/channel-plugin-api.ts +1 -0
  4. package/contract-api.ts +16 -0
  5. package/index.ts +70 -53
  6. package/openclaw.plugin.json +1827 -4
  7. package/package.json +32 -7
  8. package/runtime-api.ts +55 -0
  9. package/secret-contract-api.ts +5 -0
  10. package/security-contract-api.ts +1 -0
  11. package/session-key-api.ts +1 -0
  12. package/setup-api.ts +3 -0
  13. package/setup-entry.test.ts +14 -0
  14. package/setup-entry.ts +13 -0
  15. package/src/accounts.test.ts +95 -7
  16. package/src/accounts.ts +199 -117
  17. package/src/app-registration.ts +331 -0
  18. package/src/approval-auth.test.ts +24 -0
  19. package/src/approval-auth.ts +25 -0
  20. package/src/async.test.ts +35 -0
  21. package/src/async.ts +43 -1
  22. package/src/audio-preflight.runtime.ts +9 -0
  23. package/src/bitable.test.ts +131 -0
  24. package/src/bitable.ts +59 -22
  25. package/src/bot-content.ts +474 -0
  26. package/src/bot-group-name.test.ts +108 -0
  27. package/src/bot-runtime-api.ts +12 -0
  28. package/src/bot-sender-name.ts +125 -0
  29. package/src/bot.broadcast.test.ts +463 -0
  30. package/src/bot.card-action.test.ts +519 -5
  31. package/src/bot.checkBotMentioned.test.ts +92 -20
  32. package/src/bot.helpers.test.ts +118 -0
  33. package/src/bot.stripBotMention.test.ts +13 -21
  34. package/src/bot.test.ts +1334 -401
  35. package/src/bot.ts +778 -775
  36. package/src/card-action.ts +408 -40
  37. package/src/card-interaction.test.ts +129 -0
  38. package/src/card-interaction.ts +159 -0
  39. package/src/card-test-helpers.ts +47 -0
  40. package/src/card-ux-approval.ts +65 -0
  41. package/src/card-ux-launcher.test.ts +99 -0
  42. package/src/card-ux-launcher.ts +121 -0
  43. package/src/card-ux-shared.ts +33 -0
  44. package/src/channel-runtime-api.ts +16 -0
  45. package/src/channel.runtime.ts +47 -0
  46. package/src/channel.test.ts +914 -3
  47. package/src/channel.ts +1253 -309
  48. package/src/chat-schema.ts +5 -4
  49. package/src/chat.test.ts +135 -28
  50. package/src/chat.ts +68 -10
  51. package/src/client.test.ts +212 -103
  52. package/src/client.ts +115 -21
  53. package/src/comment-dispatcher-runtime-api.ts +6 -0
  54. package/src/comment-dispatcher.test.ts +169 -0
  55. package/src/comment-dispatcher.ts +107 -0
  56. package/src/comment-handler-runtime-api.ts +3 -0
  57. package/src/comment-handler.test.ts +486 -0
  58. package/src/comment-handler.ts +309 -0
  59. package/src/comment-reaction.test.ts +166 -0
  60. package/src/comment-reaction.ts +259 -0
  61. package/src/comment-shared.test.ts +182 -0
  62. package/src/comment-shared.ts +406 -0
  63. package/src/comment-target.ts +44 -0
  64. package/src/config-schema.test.ts +63 -1
  65. package/src/config-schema.ts +31 -4
  66. package/src/conversation-id.test.ts +18 -0
  67. package/src/conversation-id.ts +199 -0
  68. package/src/dedup-runtime-api.ts +1 -0
  69. package/src/dedup.ts +33 -95
  70. package/src/directory.static.ts +61 -0
  71. package/src/directory.test.ts +116 -20
  72. package/src/directory.ts +60 -92
  73. package/src/doc-schema.ts +1 -1
  74. package/src/docx-batch-insert.test.ts +39 -38
  75. package/src/docx-batch-insert.ts +55 -19
  76. package/src/docx-color-text.ts +9 -4
  77. package/src/docx-table-ops.test.ts +53 -0
  78. package/src/docx-table-ops.ts +52 -34
  79. package/src/docx-types.ts +38 -0
  80. package/src/docx.account-selection.test.ts +12 -3
  81. package/src/docx.test.ts +314 -74
  82. package/src/docx.ts +278 -122
  83. package/src/drive-schema.ts +47 -1
  84. package/src/drive.test.ts +1219 -0
  85. package/src/drive.ts +614 -13
  86. package/src/dynamic-agent.ts +10 -4
  87. package/src/event-types.ts +45 -0
  88. package/src/external-keys.ts +1 -1
  89. package/src/lifecycle.test-support.ts +220 -0
  90. package/src/media.test.ts +403 -26
  91. package/src/media.ts +509 -132
  92. package/src/mention-target.types.ts +5 -0
  93. package/src/mention.ts +32 -51
  94. package/src/message-action-contract.ts +13 -0
  95. package/src/monitor-state-runtime-api.ts +7 -0
  96. package/src/monitor-transport-runtime-api.ts +7 -0
  97. package/src/monitor.account.ts +218 -312
  98. package/src/monitor.acp-init-failure.lifecycle.test-support.ts +219 -0
  99. package/src/monitor.bot-identity.ts +86 -0
  100. package/src/monitor.bot-menu-handler.ts +165 -0
  101. package/src/monitor.bot-menu.lifecycle.test-support.ts +224 -0
  102. package/src/monitor.bot-menu.test.ts +178 -0
  103. package/src/monitor.broadcast.reply-once.lifecycle.test-support.ts +264 -0
  104. package/src/monitor.card-action.lifecycle.test-support.ts +373 -0
  105. package/src/monitor.cleanup.test.ts +376 -0
  106. package/src/monitor.comment-notice-handler.ts +105 -0
  107. package/src/monitor.comment.test.ts +937 -0
  108. package/src/monitor.comment.ts +1386 -0
  109. package/src/monitor.lifecycle.test.ts +4 -0
  110. package/src/monitor.message-handler.ts +339 -0
  111. package/src/monitor.reaction.lifecycle.test-support.ts +68 -0
  112. package/src/monitor.reaction.test.ts +108 -48
  113. package/src/monitor.startup.test.ts +11 -9
  114. package/src/monitor.startup.ts +26 -16
  115. package/src/monitor.state.ts +20 -5
  116. package/src/monitor.synthetic-error.ts +18 -0
  117. package/src/monitor.test-mocks.ts +2 -2
  118. package/src/monitor.transport.ts +220 -60
  119. package/src/monitor.ts +15 -10
  120. package/src/monitor.webhook-e2e.test.ts +65 -7
  121. package/src/monitor.webhook-security.test.ts +122 -0
  122. package/src/monitor.webhook.test-helpers.ts +44 -26
  123. package/src/outbound-runtime-api.ts +1 -0
  124. package/src/outbound.test.ts +616 -37
  125. package/src/outbound.ts +623 -81
  126. package/src/perm-schema.ts +1 -1
  127. package/src/perm.ts +1 -7
  128. package/src/pins.ts +108 -0
  129. package/src/policy.test.ts +297 -117
  130. package/src/policy.ts +142 -29
  131. package/src/post.ts +7 -6
  132. package/src/probe.test.ts +14 -9
  133. package/src/probe.ts +26 -16
  134. package/src/processing-claims.ts +59 -0
  135. package/src/qr-terminal.ts +1 -0
  136. package/src/reactions.ts +4 -34
  137. package/src/reasoning-preview.test.ts +59 -0
  138. package/src/reasoning-preview.ts +20 -0
  139. package/src/reply-dispatcher-runtime-api.ts +7 -0
  140. package/src/reply-dispatcher.test.ts +660 -29
  141. package/src/reply-dispatcher.ts +407 -154
  142. package/src/runtime.ts +6 -3
  143. package/src/secret-contract.ts +145 -0
  144. package/src/secret-input.ts +1 -13
  145. package/src/security-audit-shared.ts +69 -0
  146. package/src/security-audit.test.ts +61 -0
  147. package/src/security-audit.ts +1 -0
  148. package/src/send-result.ts +1 -1
  149. package/src/send-target.test.ts +9 -3
  150. package/src/send-target.ts +10 -4
  151. package/src/send.reply-fallback.test.ts +105 -2
  152. package/src/send.test.ts +386 -4
  153. package/src/send.ts +414 -95
  154. package/src/sequential-key.test.ts +72 -0
  155. package/src/sequential-key.ts +28 -0
  156. package/src/sequential-queue.test.ts +92 -0
  157. package/src/sequential-queue.ts +16 -0
  158. package/src/session-conversation.ts +42 -0
  159. package/src/session-route.ts +48 -0
  160. package/src/setup-core.ts +51 -0
  161. package/src/{onboarding.test.ts → setup-surface.test.ts} +52 -21
  162. package/src/setup-surface.ts +581 -0
  163. package/src/streaming-card.test.ts +138 -2
  164. package/src/streaming-card.ts +134 -18
  165. package/src/subagent-hooks.test.ts +603 -0
  166. package/src/subagent-hooks.ts +397 -0
  167. package/src/targets.ts +3 -13
  168. package/src/test-support/lifecycle-test-support.ts +453 -0
  169. package/src/thread-bindings.test.ts +143 -0
  170. package/src/thread-bindings.ts +330 -0
  171. package/src/tool-account-routing.test.ts +66 -8
  172. package/src/tool-account.test.ts +44 -0
  173. package/src/tool-account.ts +40 -17
  174. package/src/tool-factory-test-harness.ts +11 -8
  175. package/src/tool-result.ts +3 -1
  176. package/src/tools-config.ts +1 -1
  177. package/src/types.ts +16 -15
  178. package/src/typing.ts +10 -6
  179. package/src/wiki-schema.ts +1 -1
  180. package/src/wiki.ts +1 -7
  181. package/subagent-hooks-api.ts +31 -0
  182. package/tsconfig.json +16 -0
  183. package/src/feishu-command-handler.ts +0 -59
  184. package/src/onboarding.status.test.ts +0 -25
  185. package/src/onboarding.ts +0 -489
  186. package/src/send-message.ts +0 -71
  187. package/src/targets.test.ts +0 -70
package/src/types.ts CHANGED
@@ -1,24 +1,17 @@
1
- import type { BaseProbeResult } from "openclaw/plugin-sdk/feishu";
2
- import type {
3
- FeishuConfigSchema,
4
- FeishuGroupSchema,
5
- FeishuAccountConfigSchema,
6
- z,
7
- } from "./config-schema.js";
8
- import type { MentionTarget } from "./mention.js";
1
+ import type { BaseProbeResult } from "openclaw/plugin-sdk/core";
2
+ import type { FeishuConfigSchema, FeishuAccountConfigSchema, z } from "./config-schema.js";
3
+ import type { MentionTarget } from "./mention-target.types.js";
9
4
 
10
5
  export type FeishuConfig = z.infer<typeof FeishuConfigSchema>;
11
- export type FeishuGroupConfig = z.infer<typeof FeishuGroupSchema>;
12
6
  export type FeishuAccountConfig = z.infer<typeof FeishuAccountConfigSchema>;
13
7
 
14
8
  export type FeishuDomain = "feishu" | "lark" | (string & {});
15
- export type FeishuConnectionMode = "websocket" | "webhook";
16
9
 
17
10
  export type FeishuDefaultAccountSelectionSource =
18
11
  | "explicit-default"
19
12
  | "mapped-default"
20
13
  | "fallback";
21
- export type FeishuAccountSelectionSource = "explicit" | FeishuDefaultAccountSelectionSource;
14
+ type FeishuAccountSelectionSource = "explicit" | FeishuDefaultAccountSelectionSource;
22
15
 
23
16
  export type ResolvedFeishuAccount = {
24
17
  accountId: string;
@@ -40,10 +33,12 @@ export type FeishuIdType = "open_id" | "user_id" | "union_id" | "chat_id";
40
33
  export type FeishuMessageContext = {
41
34
  chatId: string;
42
35
  messageId: string;
36
+ replyTargetMessageId?: string;
37
+ suppressReplyTarget?: boolean;
43
38
  senderId: string;
44
39
  senderOpenId: string;
45
40
  senderName?: string;
46
- chatType: "p2p" | "group" | "private";
41
+ chatType: FeishuChatType;
47
42
  mentionedBot: boolean;
48
43
  hasAnyMention?: boolean;
49
44
  rootId?: string;
@@ -60,7 +55,11 @@ export type FeishuSendResult = {
60
55
  chatId: string;
61
56
  };
62
57
 
63
- export type FeishuChatType = "p2p" | "group" | "private";
58
+ export type FeishuChatType = "p2p" | "group" | "topic_group" | "private";
59
+
60
+ export function isFeishuGroupChatType(chatType: FeishuChatType | undefined): boolean {
61
+ return chatType === "group" || chatType === "topic_group";
62
+ }
64
63
 
65
64
  export type FeishuMessageInfo = {
66
65
  messageId: string;
@@ -72,13 +71,15 @@ export type FeishuMessageInfo = {
72
71
  content: string;
73
72
  contentType: string;
74
73
  createTime?: number;
74
+ /** Feishu thread ID (omt_xxx) — present when the message belongs to a topic thread. */
75
+ threadId?: string;
75
76
  };
76
77
 
77
- export type FeishuProbeResult = BaseProbeResult<string> & {
78
+ export interface FeishuProbeResult extends BaseProbeResult {
78
79
  appId?: string;
79
80
  botName?: string;
80
81
  botOpenId?: string;
81
- };
82
+ }
82
83
 
83
84
  export type FeishuMediaInfo = {
84
85
  path: string;
package/src/typing.ts CHANGED
@@ -1,5 +1,5 @@
1
- import type { ClawdbotConfig, RuntimeEnv } from "openclaw/plugin-sdk/feishu";
2
- import { resolveFeishuAccount } from "./accounts.js";
1
+ import type { ClawdbotConfig, RuntimeEnv } from "../runtime-api.js";
2
+ import { resolveFeishuRuntimeAccount } from "./accounts.js";
3
3
  import { createFeishuClient } from "./client.js";
4
4
  import { getFeishuRuntime } from "./runtime.js";
5
5
 
@@ -40,6 +40,10 @@ export type TypingIndicatorState = {
40
40
  reactionId: string | null;
41
41
  };
42
42
 
43
+ type FeishuMessageReactionCreateResponse = Awaited<
44
+ ReturnType<ReturnType<typeof createFeishuClient>["im"]["messageReaction"]["create"]>
45
+ >;
46
+
43
47
  /**
44
48
  * Check whether an error represents a rate-limit or quota-exceeded condition
45
49
  * from the Feishu API that should stop the typing keepalive loop.
@@ -107,7 +111,7 @@ export async function addTypingIndicator(params: {
107
111
  runtime?: RuntimeEnv;
108
112
  }): Promise<TypingIndicatorState> {
109
113
  const { cfg, messageId, accountId, runtime } = params;
110
- const account = resolveFeishuAccount({ cfg, accountId });
114
+ const account = resolveFeishuRuntimeAccount({ cfg, accountId });
111
115
  if (!account.configured) {
112
116
  return { messageId, reactionId: null };
113
117
  }
@@ -134,8 +138,8 @@ export async function addTypingIndicator(params: {
134
138
  throw new FeishuBackoffError(backoffCode);
135
139
  }
136
140
 
137
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- SDK response type
138
- const reactionId = (response as any)?.data?.reaction_id ?? null;
141
+ const typedResponse: FeishuMessageReactionCreateResponse = response;
142
+ const reactionId = typedResponse.data?.reaction_id ?? null;
139
143
  return { messageId, reactionId };
140
144
  } catch (err) {
141
145
  if (isFeishuBackoffError(err)) {
@@ -168,7 +172,7 @@ export async function removeTypingIndicator(params: {
168
172
  return;
169
173
  }
170
174
 
171
- const account = resolveFeishuAccount({ cfg, accountId });
175
+ const account = resolveFeishuRuntimeAccount({ cfg, accountId });
172
176
  if (!account.configured) {
173
177
  return;
174
178
  }
@@ -1,4 +1,4 @@
1
- import { Type, type Static } from "@sinclair/typebox";
1
+ import { Type, type Static } from "typebox";
2
2
 
3
3
  export const FeishuWikiSchema = Type.Union([
4
4
  Type.Object({
package/src/wiki.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type * as Lark from "@larksuiteoapi/node-sdk";
2
- import type { OpenClawPluginApi } from "openclaw/plugin-sdk/feishu";
2
+ import type { OpenClawPluginApi } from "../runtime-api.js";
3
3
  import { listEnabledFeishuAccounts } from "./accounts.js";
4
4
  import { createFeishuToolClient, resolveAnyEnabledFeishuToolsConfig } from "./tool-account.js";
5
5
  import {
@@ -153,19 +153,16 @@ async function renameNode(client: Lark.Client, spaceId: string, nodeToken: strin
153
153
 
154
154
  export function registerFeishuWikiTools(api: OpenClawPluginApi) {
155
155
  if (!api.config) {
156
- api.logger.debug?.("feishu_wiki: No config available, skipping wiki tools");
157
156
  return;
158
157
  }
159
158
 
160
159
  const accounts = listEnabledFeishuAccounts(api.config);
161
160
  if (accounts.length === 0) {
162
- api.logger.debug?.("feishu_wiki: No Feishu accounts configured, skipping wiki tools");
163
161
  return;
164
162
  }
165
163
 
166
164
  const toolsCfg = resolveAnyEnabledFeishuToolsConfig(accounts);
167
165
  if (!toolsCfg.wiki) {
168
- api.logger.debug?.("feishu_wiki: wiki tool disabled in config");
169
166
  return;
170
167
  }
171
168
 
@@ -217,7 +214,6 @@ export function registerFeishuWikiTools(api: OpenClawPluginApi) {
217
214
  case "rename":
218
215
  return jsonToolResult(await renameNode(client, p.space_id, p.node_token, p.title));
219
216
  default:
220
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- exhaustive check fallback
221
217
  return unknownToolActionResult((p as { action?: unknown }).action);
222
218
  }
223
219
  } catch (err) {
@@ -228,6 +224,4 @@ export function registerFeishuWikiTools(api: OpenClawPluginApi) {
228
224
  },
229
225
  { name: "feishu_wiki" },
230
226
  );
231
-
232
- api.logger.info?.(`feishu_wiki: Registered feishu_wiki tool`);
233
227
  }
@@ -0,0 +1,31 @@
1
+ import type { OpenClawPluginApi } from "openclaw/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: OpenClawPluginApi): 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 ADDED
@@ -0,0 +1,16 @@
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
+ }
@@ -1,59 +0,0 @@
1
- const DEFAULT_RESET_TRIGGERS = ["/new", "/reset"] as const;
2
-
3
- type FeishuBeforeResetContext = {
4
- cfg: Record<string, unknown>;
5
- sessionEntry: Record<string, unknown>;
6
- previousSessionEntry?: Record<string, unknown>;
7
- commandSource: string;
8
- timestamp: number;
9
- };
10
-
11
- type FeishuBeforeResetEvent = {
12
- type: "command";
13
- action: "new" | "reset";
14
- context: FeishuBeforeResetContext;
15
- };
16
-
17
- type FeishuBeforeResetRunner = {
18
- runBeforeReset: (
19
- event: FeishuBeforeResetEvent,
20
- ctx: { agentId: string; sessionKey: string },
21
- ) => Promise<void>;
22
- };
23
-
24
- /**
25
- * Handle Feishu command messages and trigger reset hooks.
26
- */
27
- export async function handleFeishuCommand(
28
- messageText: string,
29
- sessionKey: string,
30
- hookRunner: FeishuBeforeResetRunner,
31
- context: FeishuBeforeResetContext,
32
- ): Promise<boolean> {
33
- const trimmed = messageText.trim().toLowerCase();
34
- const isResetCommand = DEFAULT_RESET_TRIGGERS.some(
35
- (trigger) => trimmed === trigger || trimmed.startsWith(`${trigger} `),
36
- );
37
- if (!isResetCommand) {
38
- return false;
39
- }
40
-
41
- const command = trimmed.split(" ")[0];
42
- const action: "new" | "reset" = command === "/new" ? "new" : "reset";
43
- await hookRunner.runBeforeReset(
44
- {
45
- type: "command",
46
- action,
47
- context: {
48
- ...context,
49
- commandSource: "feishu",
50
- },
51
- },
52
- {
53
- agentId: "main",
54
- sessionKey,
55
- },
56
- );
57
-
58
- return true;
59
- }
@@ -1,25 +0,0 @@
1
- import type { OpenClawConfig } from "openclaw/plugin-sdk/feishu";
2
- import { describe, expect, it } from "vitest";
3
- import { feishuOnboardingAdapter } from "./onboarding.js";
4
-
5
- describe("feishu onboarding status", () => {
6
- it("treats SecretRef appSecret as configured when appId is present", async () => {
7
- const status = await feishuOnboardingAdapter.getStatus({
8
- cfg: {
9
- channels: {
10
- feishu: {
11
- appId: "cli_a123456",
12
- appSecret: {
13
- source: "env",
14
- provider: "default",
15
- id: "FEISHU_APP_SECRET",
16
- },
17
- },
18
- },
19
- } as OpenClawConfig,
20
- accountOverrides: {},
21
- });
22
-
23
- expect(status.configured).toBe(true);
24
- });
25
- });