@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/package.json CHANGED
@@ -1,18 +1,33 @@
1
1
  {
2
2
  "name": "@openclaw/feishu",
3
- "version": "2026.3.13",
3
+ "version": "2026.5.2-beta.1",
4
4
  "description": "OpenClaw Feishu/Lark channel plugin (community maintained by @m1heng)",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/openclaw/openclaw"
8
+ },
5
9
  "type": "module",
6
10
  "dependencies": {
7
- "@larksuiteoapi/node-sdk": "^1.59.0",
8
- "@sinclair/typebox": "0.34.48",
9
- "https-proxy-agent": "^8.0.0",
10
- "zod": "^4.3.6"
11
+ "@larksuiteoapi/node-sdk": "^1.62.1",
12
+ "typebox": "1.1.37"
13
+ },
14
+ "devDependencies": {
15
+ "@openclaw/plugin-sdk": "workspace:*",
16
+ "openclaw": "workspace:*"
17
+ },
18
+ "peerDependencies": {
19
+ "openclaw": ">=2026.5.2-beta.1"
20
+ },
21
+ "peerDependenciesMeta": {
22
+ "openclaw": {
23
+ "optional": true
24
+ }
11
25
  },
12
26
  "openclaw": {
13
27
  "extensions": [
14
28
  "./index.ts"
15
29
  ],
30
+ "setupEntry": "./setup-entry.ts",
16
31
  "channel": {
17
32
  "id": "feishu",
18
33
  "label": "Feishu",
@@ -28,8 +43,18 @@
28
43
  },
29
44
  "install": {
30
45
  "npmSpec": "@openclaw/feishu",
31
- "localPath": "extensions/feishu",
32
- "defaultChoice": "npm"
46
+ "defaultChoice": "npm",
47
+ "minHostVersion": ">=2026.4.25"
48
+ },
49
+ "compat": {
50
+ "pluginApi": ">=2026.5.2-beta.1"
51
+ },
52
+ "build": {
53
+ "openclawVersion": "2026.5.2-beta.1"
54
+ },
55
+ "release": {
56
+ "publishToClawHub": true,
57
+ "publishToNpm": true
33
58
  }
34
59
  }
35
60
  }
package/runtime-api.ts ADDED
@@ -0,0 +1,55 @@
1
+ // Private runtime barrel for the bundled Feishu extension.
2
+ // Keep this barrel thin and generic-only.
3
+
4
+ export type {
5
+ AllowlistMatch,
6
+ AnyAgentTool,
7
+ BaseProbeResult,
8
+ ChannelGroupContext,
9
+ ChannelMessageActionName,
10
+ ChannelMeta,
11
+ ChannelOutboundAdapter,
12
+ ChannelPlugin,
13
+ HistoryEntry,
14
+ OpenClawConfig,
15
+ OpenClawPluginApi,
16
+ OutboundIdentity,
17
+ PluginRuntime,
18
+ ReplyPayload,
19
+ } from "openclaw/plugin-sdk/core";
20
+ export type { OpenClawConfig as ClawdbotConfig } from "openclaw/plugin-sdk/core";
21
+ export type { RuntimeEnv } from "openclaw/plugin-sdk/runtime";
22
+ export type { GroupToolPolicyConfig } from "openclaw/plugin-sdk/config-types";
23
+ export {
24
+ DEFAULT_ACCOUNT_ID,
25
+ buildChannelConfigSchema,
26
+ createActionGate,
27
+ createDedupeCache,
28
+ } from "openclaw/plugin-sdk/core";
29
+ export {
30
+ PAIRING_APPROVED_MESSAGE,
31
+ buildProbeChannelStatusSummary,
32
+ createDefaultChannelRuntimeState,
33
+ } from "openclaw/plugin-sdk/channel-status";
34
+ export { buildAgentMediaPayload } from "openclaw/plugin-sdk/agent-media-payload";
35
+ export { createChannelPairingController } from "openclaw/plugin-sdk/channel-pairing";
36
+ export { createReplyPrefixContext } from "openclaw/plugin-sdk/channel-reply-pipeline";
37
+ export {
38
+ evaluateSupplementalContextVisibility,
39
+ filterSupplementalContextItems,
40
+ resolveChannelContextVisibilityMode,
41
+ } from "openclaw/plugin-sdk/context-visibility-runtime";
42
+ export {
43
+ loadSessionStore,
44
+ resolveSessionStoreEntry,
45
+ } from "openclaw/plugin-sdk/session-store-runtime";
46
+ export { readJsonFileWithFallback } from "openclaw/plugin-sdk/json-store";
47
+ export { createPersistentDedupe } from "openclaw/plugin-sdk/persistent-dedupe";
48
+ export { normalizeAgentId } from "openclaw/plugin-sdk/routing";
49
+ export { chunkTextForOutbound } from "openclaw/plugin-sdk/text-chunking";
50
+ export {
51
+ isRequestBodyLimitError,
52
+ readRequestBodyWithLimit,
53
+ requestBodyErrorToText,
54
+ } from "openclaw/plugin-sdk/webhook-ingress";
55
+ export { setFeishuRuntime } from "./src/runtime.js";
@@ -0,0 +1,5 @@
1
+ export {
2
+ channelSecrets,
3
+ collectRuntimeConfigAssignments,
4
+ secretTargetRegistryEntries,
5
+ } from "./src/secret-contract.js";
@@ -0,0 +1 @@
1
+ export { collectFeishuSecurityAuditFindings } from "./src/security-audit-shared.js";
@@ -0,0 +1 @@
1
+ export { resolveFeishuSessionConversation as resolveSessionConversation } from "./src/session-conversation.js";
package/setup-api.ts ADDED
@@ -0,0 +1,3 @@
1
+ export { feishuPlugin } from "./src/channel.js";
2
+ export { feishuSetupAdapter } from "./src/setup-core.js";
3
+ export { feishuSetupWizard } from "./src/setup-surface.js";
@@ -0,0 +1,14 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+
3
+ vi.mock("@larksuiteoapi/node-sdk", () => {
4
+ throw new Error("setup entry must not load the Feishu SDK");
5
+ });
6
+
7
+ describe("feishu setup entry", () => {
8
+ it("declares the setup entry without importing Feishu runtime dependencies", async () => {
9
+ const { default: setupEntry } = await import("./setup-entry.js");
10
+
11
+ expect(setupEntry.kind).toBe("bundled-channel-setup-entry");
12
+ expect(typeof setupEntry.loadSetupPlugin).toBe("function");
13
+ });
14
+ });
package/setup-entry.ts ADDED
@@ -0,0 +1,13 @@
1
+ import { defineBundledChannelSetupEntry } from "openclaw/plugin-sdk/channel-entry-contract";
2
+
3
+ export default defineBundledChannelSetupEntry({
4
+ importMetaUrl: import.meta.url,
5
+ plugin: {
6
+ specifier: "./setup-api.js",
7
+ exportName: "feishuPlugin",
8
+ },
9
+ secrets: {
10
+ specifier: "./secret-contract-api.js",
11
+ exportName: "channelSecrets",
12
+ },
13
+ });
@@ -1,14 +1,15 @@
1
1
  import { describe, expect, it } from "vitest";
2
2
  import {
3
+ FeishuSecretRefUnavailableError,
4
+ inspectFeishuCredentials,
3
5
  resolveDefaultFeishuAccountId,
4
6
  resolveDefaultFeishuAccountSelection,
5
7
  resolveFeishuAccount,
6
8
  resolveFeishuCredentials,
9
+ resolveFeishuRuntimeAccount,
7
10
  } from "./accounts.js";
8
11
  import type { FeishuConfig } from "./types.js";
9
12
 
10
- const asConfig = (value: Partial<FeishuConfig>) => value as FeishuConfig;
11
-
12
13
  function makeDefaultAndRouterAccounts() {
13
14
  return {
14
15
  default: { appId: "cli_default", appSecret: "secret_default" }, // pragma: allowlist secret
@@ -44,6 +45,10 @@ function withEnvVar(key: string, value: string | undefined, run: () => void) {
44
45
  }
45
46
  }
46
47
 
48
+ function asConfig(config: Partial<FeishuConfig>): FeishuConfig {
49
+ return config as unknown as FeishuConfig;
50
+ }
51
+
47
52
  function expectUnresolvedEnvSecretRefError(key: string) {
48
53
  expect(() =>
49
54
  resolveFeishuCredentials(
@@ -169,6 +174,18 @@ describe("resolveFeishuCredentials", () => {
169
174
  expect(creds).toBeNull();
170
175
  });
171
176
 
177
+ it("supports explicit inspect mode for unresolved SecretRefs", () => {
178
+ const creds = resolveFeishuCredentials(
179
+ asConfig({
180
+ appId: "cli_123",
181
+ appSecret: { source: "file", provider: "default", id: "path/to/secret" } as never,
182
+ }),
183
+ { mode: "inspect" },
184
+ );
185
+
186
+ expect(creds).toBeNull();
187
+ });
188
+
172
189
  it("throws unresolved SecretRef error when env SecretRef points to missing env var", () => {
173
190
  const key = "FEISHU_APP_SECRET_MISSING_TEST";
174
191
  withEnvVar(key, undefined, () => {
@@ -274,6 +291,24 @@ describe("resolveFeishuCredentials", () => {
274
291
  domain: "feishu",
275
292
  });
276
293
  });
294
+
295
+ it("keeps required credentials when optional event SecretRefs are unresolved in inspect mode", () => {
296
+ const creds = inspectFeishuCredentials(
297
+ asConfig({
298
+ appId: "cli_123",
299
+ appSecret: "secret_456",
300
+ verificationToken: { source: "file", provider: "default", id: "path/to/token" } as never,
301
+ }),
302
+ );
303
+
304
+ expect(creds).toEqual({
305
+ appId: "cli_123",
306
+ appSecret: "secret_456", // pragma: allowlist secret
307
+ encryptKey: undefined,
308
+ verificationToken: undefined,
309
+ domain: "feishu",
310
+ });
311
+ });
277
312
  });
278
313
 
279
314
  describe("resolveFeishuAccount", () => {
@@ -328,9 +363,57 @@ describe("resolveFeishuAccount", () => {
328
363
  expect(account.appId).toBe("cli_default");
329
364
  });
330
365
 
331
- it("surfaces unresolved SecretRef errors in account resolution", () => {
332
- expect(() =>
333
- resolveFeishuAccount({
366
+ it("treats unresolved SecretRef as not configured in account resolution", () => {
367
+ const account = resolveFeishuAccount({
368
+ cfg: {
369
+ channels: {
370
+ feishu: {
371
+ accounts: {
372
+ main: {
373
+ appId: "cli_123",
374
+ appSecret: { source: "file", provider: "default", id: "path/to/secret" },
375
+ } as never,
376
+ },
377
+ },
378
+ },
379
+ } as never,
380
+ accountId: "main",
381
+ });
382
+ expect(account.configured).toBe(false);
383
+ expect(account.appSecret).toBeUndefined();
384
+ });
385
+
386
+ it("keeps account configured when optional event SecretRefs are unresolved in inspect mode", () => {
387
+ const account = resolveFeishuAccount({
388
+ cfg: {
389
+ channels: {
390
+ feishu: {
391
+ accounts: {
392
+ main: {
393
+ appId: "cli_123",
394
+ appSecret: "secret_456",
395
+ verificationToken: {
396
+ source: "file",
397
+ provider: "default",
398
+ id: "path/to/token",
399
+ },
400
+ } as never,
401
+ },
402
+ },
403
+ },
404
+ } as never,
405
+ accountId: "main",
406
+ });
407
+
408
+ expect(account.configured).toBe(true);
409
+ expect(account.appSecret).toBe("secret_456");
410
+ expect(account.verificationToken).toBeUndefined();
411
+ });
412
+
413
+ it("throws typed SecretRef errors in runtime account resolution", () => {
414
+ let caught: unknown;
415
+ try {
416
+ resolveFeishuRuntimeAccount({
334
417
  cfg: {
335
418
  channels: {
336
419
  feishu: {
@@ -344,8 +427,13 @@ describe("resolveFeishuAccount", () => {
344
427
  },
345
428
  } as never,
346
429
  accountId: "main",
347
- }),
348
- ).toThrow(/unresolved SecretRef/i);
430
+ });
431
+ } catch (error) {
432
+ caught = error;
433
+ }
434
+
435
+ expect(caught).toBeInstanceOf(FeishuSecretRefUnavailableError);
436
+ expect((caught as Error).message).toMatch(/channels\.feishu\.appSecret: unresolved SecretRef/i);
349
437
  });
350
438
 
351
439
  it("does not throw when account name is non-string", () => {