@actagent/feishu 2026.6.2

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 (207) hide show
  1. package/README.md +11 -0
  2. package/actagent.plugin.json +224 -0
  3. package/api.ts +33 -0
  4. package/channel-entry.ts +21 -0
  5. package/channel-plugin-api.ts +2 -0
  6. package/contract-api.ts +17 -0
  7. package/index.ts +83 -0
  8. package/legacy-state-migrations-api.ts +2 -0
  9. package/npm-shrinkwrap.json +539 -0
  10. package/package.json +64 -0
  11. package/runtime-api.ts +58 -0
  12. package/runtime-setter-api.ts +3 -0
  13. package/secret-contract-api.ts +6 -0
  14. package/security-contract-api.ts +2 -0
  15. package/session-key-api.ts +2 -0
  16. package/setup-api.ts +4 -0
  17. package/setup-entry.test.ts +33 -0
  18. package/setup-entry.ts +25 -0
  19. package/skills/feishu-doc/SKILL.md +211 -0
  20. package/skills/feishu-doc/references/block-types.md +103 -0
  21. package/skills/feishu-drive/SKILL.md +97 -0
  22. package/skills/feishu-perm/SKILL.md +119 -0
  23. package/skills/feishu-wiki/SKILL.md +113 -0
  24. package/src/accounts.test.ts +481 -0
  25. package/src/accounts.ts +380 -0
  26. package/src/agent-config.ts +22 -0
  27. package/src/app-registration.test.ts +62 -0
  28. package/src/app-registration.ts +355 -0
  29. package/src/approval-auth.test.ts +25 -0
  30. package/src/approval-auth.ts +26 -0
  31. package/src/async.test.ts +68 -0
  32. package/src/async.ts +109 -0
  33. package/src/audio-preflight.runtime.ts +10 -0
  34. package/src/bitable.test.ts +174 -0
  35. package/src/bitable.ts +781 -0
  36. package/src/bot-content.ts +488 -0
  37. package/src/bot-group-name.test.ts +148 -0
  38. package/src/bot-runtime-api.ts +13 -0
  39. package/src/bot-sender-name.test.ts +68 -0
  40. package/src/bot-sender-name.ts +137 -0
  41. package/src/bot.broadcast.test.ts +643 -0
  42. package/src/bot.card-action.test.ts +647 -0
  43. package/src/bot.checkBotMentioned.test.ts +266 -0
  44. package/src/bot.helpers.test.ts +136 -0
  45. package/src/bot.stripBotMention.test.ts +127 -0
  46. package/src/bot.test.ts +3817 -0
  47. package/src/bot.ts +1788 -0
  48. package/src/card-action.ts +515 -0
  49. package/src/card-interaction.test.ts +132 -0
  50. package/src/card-interaction.ts +160 -0
  51. package/src/card-test-helpers.ts +55 -0
  52. package/src/card-ux-approval.ts +66 -0
  53. package/src/card-ux-launcher.test.ts +126 -0
  54. package/src/card-ux-launcher.ts +136 -0
  55. package/src/card-ux-shared.ts +34 -0
  56. package/src/channel-runtime-api.ts +17 -0
  57. package/src/channel.runtime.ts +48 -0
  58. package/src/channel.test.ts +1337 -0
  59. package/src/channel.ts +1401 -0
  60. package/src/chat-schema.ts +30 -0
  61. package/src/chat.test.ts +295 -0
  62. package/src/chat.ts +198 -0
  63. package/src/client-timeout.ts +44 -0
  64. package/src/client.test.ts +463 -0
  65. package/src/client.ts +263 -0
  66. package/src/comment-dispatcher-runtime-api.ts +7 -0
  67. package/src/comment-dispatcher.test.ts +186 -0
  68. package/src/comment-dispatcher.ts +108 -0
  69. package/src/comment-handler-runtime-api.ts +4 -0
  70. package/src/comment-handler.test.ts +588 -0
  71. package/src/comment-handler.ts +304 -0
  72. package/src/comment-reaction.test.ts +139 -0
  73. package/src/comment-reaction.ts +260 -0
  74. package/src/comment-shared.test.ts +184 -0
  75. package/src/comment-shared.ts +405 -0
  76. package/src/comment-target.ts +45 -0
  77. package/src/config-schema.test.ts +327 -0
  78. package/src/config-schema.ts +338 -0
  79. package/src/conversation-id.test.ts +19 -0
  80. package/src/conversation-id.ts +199 -0
  81. package/src/dedup-migrations.test.ts +90 -0
  82. package/src/dedup-migrations.ts +103 -0
  83. package/src/dedup.test.ts +95 -0
  84. package/src/dedup.ts +304 -0
  85. package/src/dedupe-key.ts +68 -0
  86. package/src/directory.static.ts +62 -0
  87. package/src/directory.test.ts +142 -0
  88. package/src/directory.ts +125 -0
  89. package/src/doc-schema.ts +183 -0
  90. package/src/doctor.test.ts +382 -0
  91. package/src/doctor.ts +876 -0
  92. package/src/docx-batch-insert.test.ts +117 -0
  93. package/src/docx-batch-insert.ts +223 -0
  94. package/src/docx-color-text.ts +154 -0
  95. package/src/docx-table-ops.test.ts +54 -0
  96. package/src/docx-table-ops.ts +316 -0
  97. package/src/docx-types.ts +39 -0
  98. package/src/docx.account-selection.test.ts +96 -0
  99. package/src/docx.test.ts +706 -0
  100. package/src/docx.ts +1598 -0
  101. package/src/drive-schema.ts +93 -0
  102. package/src/drive.test.ts +1240 -0
  103. package/src/drive.ts +830 -0
  104. package/src/dynamic-agent.test.ts +156 -0
  105. package/src/dynamic-agent.ts +144 -0
  106. package/src/event-types.ts +46 -0
  107. package/src/external-keys.test.ts +21 -0
  108. package/src/external-keys.ts +20 -0
  109. package/src/lifecycle.test-support.ts +223 -0
  110. package/src/media.test.ts +956 -0
  111. package/src/media.ts +1106 -0
  112. package/src/mention-target.types.ts +6 -0
  113. package/src/mention.ts +115 -0
  114. package/src/message-action-contract.ts +14 -0
  115. package/src/monitor-state-runtime-api.ts +8 -0
  116. package/src/monitor-transport-runtime-api.ts +11 -0
  117. package/src/monitor.account.ts +501 -0
  118. package/src/monitor.acp-init-failure.lifecycle.test-support.ts +215 -0
  119. package/src/monitor.bot-identity.ts +87 -0
  120. package/src/monitor.bot-menu-handler.ts +164 -0
  121. package/src/monitor.bot-menu.lifecycle.test-support.ts +221 -0
  122. package/src/monitor.bot-menu.test.ts +200 -0
  123. package/src/monitor.broadcast.reply-once.lifecycle.test-support.ts +265 -0
  124. package/src/monitor.card-action.lifecycle.test-support.ts +418 -0
  125. package/src/monitor.cleanup.test.ts +384 -0
  126. package/src/monitor.comment-notice-handler.ts +106 -0
  127. package/src/monitor.comment.test.ts +968 -0
  128. package/src/monitor.comment.ts +1386 -0
  129. package/src/monitor.lifecycle.test.ts +5 -0
  130. package/src/monitor.message-handler.ts +346 -0
  131. package/src/monitor.reaction.test.ts +770 -0
  132. package/src/monitor.startup.test.ts +232 -0
  133. package/src/monitor.startup.ts +76 -0
  134. package/src/monitor.state.defaults.test.ts +47 -0
  135. package/src/monitor.state.ts +171 -0
  136. package/src/monitor.synthetic-error.ts +19 -0
  137. package/src/monitor.test-mocks.ts +47 -0
  138. package/src/monitor.transport.ts +451 -0
  139. package/src/monitor.ts +104 -0
  140. package/src/monitor.webhook-e2e.test.ts +284 -0
  141. package/src/monitor.webhook-security.test.ts +394 -0
  142. package/src/monitor.webhook.test-helpers.ts +138 -0
  143. package/src/outbound-runtime-api.ts +2 -0
  144. package/src/outbound.test.ts +1255 -0
  145. package/src/outbound.ts +742 -0
  146. package/src/perm-schema.ts +53 -0
  147. package/src/perm.ts +171 -0
  148. package/src/pins.ts +109 -0
  149. package/src/policy.test.ts +224 -0
  150. package/src/policy.ts +322 -0
  151. package/src/post.test.ts +106 -0
  152. package/src/post.ts +276 -0
  153. package/src/presentation-card.ts +204 -0
  154. package/src/probe.test.ts +310 -0
  155. package/src/probe.ts +181 -0
  156. package/src/processing-claims.ts +60 -0
  157. package/src/qr-terminal.ts +2 -0
  158. package/src/reactions.ts +124 -0
  159. package/src/reasoning-preview.test.ts +114 -0
  160. package/src/reasoning-preview.ts +29 -0
  161. package/src/reply-dispatcher-runtime-api.ts +8 -0
  162. package/src/reply-dispatcher.test.ts +2009 -0
  163. package/src/reply-dispatcher.ts +865 -0
  164. package/src/runtime.ts +10 -0
  165. package/src/secret-contract.ts +146 -0
  166. package/src/secret-input.ts +2 -0
  167. package/src/security-audit-shared.ts +70 -0
  168. package/src/security-audit.test.ts +60 -0
  169. package/src/security-audit.ts +2 -0
  170. package/src/send-result.ts +81 -0
  171. package/src/send-target.test.ts +87 -0
  172. package/src/send-target.ts +36 -0
  173. package/src/send.reply-fallback.test.ts +418 -0
  174. package/src/send.test.ts +661 -0
  175. package/src/send.ts +860 -0
  176. package/src/sequential-key.test.ts +73 -0
  177. package/src/sequential-key.ts +29 -0
  178. package/src/sequential-queue.test.ts +184 -0
  179. package/src/sequential-queue.ts +90 -0
  180. package/src/session-conversation.ts +42 -0
  181. package/src/session-route.ts +49 -0
  182. package/src/setup-core.ts +52 -0
  183. package/src/setup-surface.test.ts +485 -0
  184. package/src/setup-surface.ts +620 -0
  185. package/src/streaming-card.test.ts +549 -0
  186. package/src/streaming-card.ts +611 -0
  187. package/src/subagent-hooks.test.ts +632 -0
  188. package/src/subagent-hooks.ts +414 -0
  189. package/src/targets.ts +98 -0
  190. package/src/test-support/lifecycle-test-support.ts +459 -0
  191. package/src/thread-bindings.test.ts +181 -0
  192. package/src/thread-bindings.ts +332 -0
  193. package/src/tool-account-routing.test.ts +419 -0
  194. package/src/tool-account.test.ts +45 -0
  195. package/src/tool-account.ts +98 -0
  196. package/src/tool-factory-test-harness.ts +83 -0
  197. package/src/tool-result.test.ts +33 -0
  198. package/src/tool-result.ts +17 -0
  199. package/src/tools-config.test.ts +52 -0
  200. package/src/tools-config.ts +29 -0
  201. package/src/types.ts +111 -0
  202. package/src/typing.test.ts +145 -0
  203. package/src/typing.ts +215 -0
  204. package/src/wiki-schema.ts +70 -0
  205. package/src/wiki.ts +271 -0
  206. package/subagent-hooks-api.ts +22 -0
  207. package/tsconfig.json +16 -0
@@ -0,0 +1,60 @@
1
+ // Feishu plugin module implements processing claims behavior.
2
+ const EVENT_DEDUP_TTL_MS = 5 * 60 * 1000;
3
+ const EVENT_MEMORY_MAX_SIZE = 2_000;
4
+
5
+ const processingClaims = new Map<string, number>();
6
+
7
+ function resolveEventDedupeKey(
8
+ namespace: string,
9
+ messageId: string | undefined | null,
10
+ ): string | null {
11
+ const trimmed = messageId?.trim();
12
+ return trimmed ? `${namespace}:${trimmed}` : null;
13
+ }
14
+
15
+ function pruneProcessingClaims(now: number): void {
16
+ const cutoff = now - EVENT_DEDUP_TTL_MS;
17
+ for (const [key, seenAt] of processingClaims) {
18
+ if (seenAt < cutoff) {
19
+ processingClaims.delete(key);
20
+ }
21
+ }
22
+ while (processingClaims.size > EVENT_MEMORY_MAX_SIZE) {
23
+ const oldestKey = processingClaims.keys().next().value;
24
+ if (!oldestKey) {
25
+ return;
26
+ }
27
+ processingClaims.delete(oldestKey);
28
+ }
29
+ }
30
+
31
+ export function tryBeginFeishuMessageProcessing(
32
+ messageId: string | undefined | null,
33
+ namespace = "global",
34
+ ): boolean {
35
+ const key = resolveEventDedupeKey(namespace, messageId);
36
+ if (!key) {
37
+ return true;
38
+ }
39
+ const now = Date.now();
40
+ pruneProcessingClaims(now);
41
+ if (processingClaims.has(key)) {
42
+ processingClaims.delete(key);
43
+ processingClaims.set(key, now);
44
+ pruneProcessingClaims(now);
45
+ return false;
46
+ }
47
+ processingClaims.set(key, now);
48
+ pruneProcessingClaims(now);
49
+ return true;
50
+ }
51
+
52
+ export function releaseFeishuMessageProcessing(
53
+ messageId: string | undefined | null,
54
+ namespace = "global",
55
+ ): void {
56
+ const key = resolveEventDedupeKey(namespace, messageId);
57
+ if (key) {
58
+ processingClaims.delete(key);
59
+ }
60
+ }
@@ -0,0 +1,2 @@
1
+ // Feishu plugin module implements qr terminal behavior.
2
+ export { renderQrTerminal } from "actagent/plugin-sdk/media-runtime";
@@ -0,0 +1,124 @@
1
+ // Feishu plugin module implements reactions behavior.
2
+ import type { ACTAgentBotConfig } from "../runtime-api.js";
3
+ import { resolveFeishuRuntimeAccount } from "./accounts.js";
4
+ import { createFeishuClient } from "./client.js";
5
+
6
+ type FeishuReaction = {
7
+ reactionId: string;
8
+ emojiType: string;
9
+ operatorType: "app" | "user";
10
+ operatorId: string;
11
+ };
12
+
13
+ function resolveConfiguredFeishuClient(params: { cfg: ACTAgentBotConfig; accountId?: string }) {
14
+ const account = resolveFeishuRuntimeAccount(params);
15
+ if (!account.configured) {
16
+ throw new Error(`Feishu account "${account.accountId}" not configured`);
17
+ }
18
+ return createFeishuClient(account);
19
+ }
20
+
21
+ function assertFeishuReactionApiSuccess(response: { code?: number; msg?: string }, action: string) {
22
+ if (response.code !== 0) {
23
+ throw new Error(`Feishu ${action} failed: ${response.msg || `code ${response.code}`}`);
24
+ }
25
+ }
26
+
27
+ /**
28
+ * Add a reaction (emoji) to a message.
29
+ * @param emojiType - Feishu emoji type, e.g., "SMILE", "THUMBSUP", "HEART"
30
+ * @see https://open.feishu.cn/document/server-docs/im-v1/message-reaction/emojis-introduce
31
+ */
32
+ export async function addReactionFeishu(params: {
33
+ cfg: ACTAgentBotConfig;
34
+ messageId: string;
35
+ emojiType: string;
36
+ accountId?: string;
37
+ }): Promise<{ reactionId: string }> {
38
+ const { cfg, messageId, emojiType, accountId } = params;
39
+ const client = resolveConfiguredFeishuClient({ cfg, accountId });
40
+
41
+ const response = (await client.im.messageReaction.create({
42
+ path: { message_id: messageId },
43
+ data: {
44
+ reaction_type: {
45
+ emoji_type: emojiType,
46
+ },
47
+ },
48
+ })) as {
49
+ code?: number;
50
+ msg?: string;
51
+ data?: { reaction_id?: string };
52
+ };
53
+
54
+ assertFeishuReactionApiSuccess(response, "add reaction");
55
+
56
+ const reactionId = response.data?.reaction_id;
57
+ if (!reactionId) {
58
+ throw new Error("Feishu add reaction failed: no reaction_id returned");
59
+ }
60
+
61
+ return { reactionId };
62
+ }
63
+
64
+ /**
65
+ * Remove a reaction from a message.
66
+ */
67
+ export async function removeReactionFeishu(params: {
68
+ cfg: ACTAgentBotConfig;
69
+ messageId: string;
70
+ reactionId: string;
71
+ accountId?: string;
72
+ }): Promise<void> {
73
+ const { cfg, messageId, reactionId, accountId } = params;
74
+ const client = resolveConfiguredFeishuClient({ cfg, accountId });
75
+
76
+ const response = (await client.im.messageReaction.delete({
77
+ path: {
78
+ message_id: messageId,
79
+ reaction_id: reactionId,
80
+ },
81
+ })) as { code?: number; msg?: string };
82
+
83
+ assertFeishuReactionApiSuccess(response, "remove reaction");
84
+ }
85
+
86
+ /**
87
+ * List all reactions for a message.
88
+ */
89
+ export async function listReactionsFeishu(params: {
90
+ cfg: ACTAgentBotConfig;
91
+ messageId: string;
92
+ emojiType?: string;
93
+ accountId?: string;
94
+ }): Promise<FeishuReaction[]> {
95
+ const { cfg, messageId, emojiType, accountId } = params;
96
+ const client = resolveConfiguredFeishuClient({ cfg, accountId });
97
+
98
+ const response = (await client.im.messageReaction.list({
99
+ path: { message_id: messageId },
100
+ params: emojiType ? { reaction_type: emojiType } : undefined,
101
+ })) as {
102
+ code?: number;
103
+ msg?: string;
104
+ data?: {
105
+ items?: Array<{
106
+ reaction_id?: string;
107
+ reaction_type?: { emoji_type?: string };
108
+ operator_type?: string;
109
+ operator_id?: { open_id?: string; user_id?: string; union_id?: string };
110
+ }>;
111
+ };
112
+ };
113
+
114
+ assertFeishuReactionApiSuccess(response, "list reactions");
115
+
116
+ const items = response.data?.items ?? [];
117
+ return items.map((item) => ({
118
+ reactionId: item.reaction_id ?? "",
119
+ emojiType: item.reaction_type?.emoji_type ?? "",
120
+ operatorType: item.operator_type === "app" ? "app" : "user",
121
+ operatorId:
122
+ item.operator_id?.open_id ?? item.operator_id?.user_id ?? item.operator_id?.union_id ?? "",
123
+ }));
124
+ }
@@ -0,0 +1,114 @@
1
+ // Feishu tests cover reasoning preview plugin behavior.
2
+ import { afterAll, beforeEach, describe, expect, it, vi } from "vitest";
3
+ import type { ACTAgentBotConfig } from "./bot-runtime-api.js";
4
+ import { resolveFeishuReasoningPreviewEnabled } from "./reasoning-preview.js";
5
+
6
+ const { loadSessionStoreMock } = vi.hoisted(() => ({
7
+ loadSessionStoreMock: vi.fn(),
8
+ }));
9
+
10
+ vi.mock("./bot-runtime-api.js", async () => {
11
+ const actual =
12
+ await vi.importActual<typeof import("./bot-runtime-api.js")>("./bot-runtime-api.js");
13
+ return {
14
+ ...actual,
15
+ loadSessionStore: loadSessionStoreMock,
16
+ };
17
+ });
18
+
19
+ afterAll(() => {
20
+ vi.doUnmock("./bot-runtime-api.js");
21
+ vi.resetModules();
22
+ });
23
+
24
+ describe("resolveFeishuReasoningPreviewEnabled", () => {
25
+ const emptyCfg: ACTAgentBotConfig = {};
26
+
27
+ beforeEach(() => {
28
+ vi.clearAllMocks();
29
+ });
30
+
31
+ it("enables previews only for stream reasoning sessions", () => {
32
+ loadSessionStoreMock.mockReturnValue({
33
+ "agent:main:feishu:dm:ou_sender_1": { reasoningLevel: "stream" },
34
+ "agent:main:feishu:dm:ou_sender_2": { reasoningLevel: "on" },
35
+ });
36
+
37
+ expect(
38
+ resolveFeishuReasoningPreviewEnabled({
39
+ cfg: emptyCfg,
40
+ agentId: "main",
41
+ storePath: "/tmp/feishu-sessions.json",
42
+ sessionKey: "agent:main:feishu:dm:ou_sender_1",
43
+ }),
44
+ ).toBe(true);
45
+ expect(
46
+ resolveFeishuReasoningPreviewEnabled({
47
+ cfg: emptyCfg,
48
+ agentId: "main",
49
+ storePath: "/tmp/feishu-sessions.json",
50
+ sessionKey: "agent:main:feishu:dm:ou_sender_2",
51
+ }),
52
+ ).toBe(false);
53
+ });
54
+
55
+ it("returns false for missing sessions or load failures", () => {
56
+ loadSessionStoreMock.mockImplementationOnce(() => {
57
+ throw new Error("disk unavailable");
58
+ });
59
+
60
+ expect(
61
+ resolveFeishuReasoningPreviewEnabled({
62
+ cfg: emptyCfg,
63
+ agentId: "main",
64
+ storePath: "/tmp/feishu-sessions.json",
65
+ sessionKey: "agent:main:feishu:dm:ou_sender_1",
66
+ }),
67
+ ).toBe(false);
68
+ expect(
69
+ resolveFeishuReasoningPreviewEnabled({
70
+ cfg: emptyCfg,
71
+ agentId: "main",
72
+ storePath: "/tmp/feishu-sessions.json",
73
+ }),
74
+ ).toBe(false);
75
+ });
76
+
77
+ it("falls back to configured stream defaults", () => {
78
+ loadSessionStoreMock.mockReturnValue({
79
+ "agent:main:feishu:dm:ou_sender_1": {},
80
+ "agent:main:feishu:dm:ou_sender_2": { reasoningLevel: "off" },
81
+ });
82
+
83
+ const cfg: ACTAgentBotConfig = {
84
+ agents: {
85
+ defaults: { reasoningDefault: "stream" },
86
+ list: [{ id: "Ops", reasoningDefault: "off" }],
87
+ },
88
+ };
89
+
90
+ expect(
91
+ resolveFeishuReasoningPreviewEnabled({
92
+ cfg,
93
+ agentId: "main",
94
+ storePath: "/tmp/feishu-sessions.json",
95
+ sessionKey: "agent:main:feishu:dm:ou_sender_1",
96
+ }),
97
+ ).toBe(true);
98
+ expect(
99
+ resolveFeishuReasoningPreviewEnabled({
100
+ cfg,
101
+ agentId: "ops",
102
+ storePath: "/tmp/feishu-sessions.json",
103
+ }),
104
+ ).toBe(false);
105
+ expect(
106
+ resolveFeishuReasoningPreviewEnabled({
107
+ cfg,
108
+ agentId: "main",
109
+ storePath: "/tmp/feishu-sessions.json",
110
+ sessionKey: "agent:main:feishu:dm:ou_sender_2",
111
+ }),
112
+ ).toBe(false);
113
+ });
114
+ });
@@ -0,0 +1,29 @@
1
+ // Feishu plugin module implements reasoning preview behavior.
2
+ import { resolveFeishuConfigReasoningDefault } from "./agent-config.js";
3
+ import { loadSessionStore, resolveSessionStoreEntry } from "./bot-runtime-api.js";
4
+ import type { ACTAgentBotConfig } from "./bot-runtime-api.js";
5
+
6
+ export function resolveFeishuReasoningPreviewEnabled(params: {
7
+ cfg: ACTAgentBotConfig;
8
+ agentId: string;
9
+ storePath: string;
10
+ sessionKey?: string;
11
+ }): boolean {
12
+ const configDefault = resolveFeishuConfigReasoningDefault(params.cfg, params.agentId);
13
+
14
+ if (!params.sessionKey) {
15
+ return configDefault === "stream";
16
+ }
17
+
18
+ try {
19
+ const store = loadSessionStore(params.storePath, { skipCache: true });
20
+ const level = resolveSessionStoreEntry({ store, sessionKey: params.sessionKey }).existing
21
+ ?.reasoningLevel;
22
+ if (level === "on" || level === "stream" || level === "off") {
23
+ return level === "stream";
24
+ }
25
+ } catch {
26
+ return false;
27
+ }
28
+ return configDefault === "stream";
29
+ }
@@ -0,0 +1,8 @@
1
+ // Feishu API module exposes the plugin public contract.
2
+ export {
3
+ createReplyPrefixContext,
4
+ type ACTAgentBotConfig,
5
+ type OutboundIdentity,
6
+ type ReplyPayload,
7
+ type RuntimeEnv,
8
+ } from "../runtime-api.js";