moltbot-feishu 0.1.0

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 (60) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +99 -0
  3. package/clawdbot.plugin.json +33 -0
  4. package/dist/index.d.ts +29 -0
  5. package/dist/index.d.ts.map +1 -0
  6. package/dist/index.js +32 -0
  7. package/dist/index.js.map +1 -0
  8. package/dist/src/accounts.d.ts +17 -0
  9. package/dist/src/accounts.d.ts.map +1 -0
  10. package/dist/src/accounts.js +81 -0
  11. package/dist/src/accounts.js.map +1 -0
  12. package/dist/src/channel.d.ts +8 -0
  13. package/dist/src/channel.d.ts.map +1 -0
  14. package/dist/src/channel.js +373 -0
  15. package/dist/src/channel.js.map +1 -0
  16. package/dist/src/config-schema.d.ts +157 -0
  17. package/dist/src/config-schema.d.ts.map +1 -0
  18. package/dist/src/config-schema.js +21 -0
  19. package/dist/src/config-schema.js.map +1 -0
  20. package/dist/src/dedup.d.ts +8 -0
  21. package/dist/src/dedup.d.ts.map +1 -0
  22. package/dist/src/dedup.js +25 -0
  23. package/dist/src/dedup.js.map +1 -0
  24. package/dist/src/group-filter.d.ts +15 -0
  25. package/dist/src/group-filter.d.ts.map +1 -0
  26. package/dist/src/group-filter.js +44 -0
  27. package/dist/src/group-filter.js.map +1 -0
  28. package/dist/src/media.d.ts +21 -0
  29. package/dist/src/media.d.ts.map +1 -0
  30. package/dist/src/media.js +133 -0
  31. package/dist/src/media.js.map +1 -0
  32. package/dist/src/onboarding.d.ts +51 -0
  33. package/dist/src/onboarding.d.ts.map +1 -0
  34. package/dist/src/onboarding.js +213 -0
  35. package/dist/src/onboarding.js.map +1 -0
  36. package/dist/src/probe.d.ts +10 -0
  37. package/dist/src/probe.d.ts.map +1 -0
  38. package/dist/src/probe.js +48 -0
  39. package/dist/src/probe.js.map +1 -0
  40. package/dist/src/receive.d.ts +25 -0
  41. package/dist/src/receive.d.ts.map +1 -0
  42. package/dist/src/receive.js +217 -0
  43. package/dist/src/receive.js.map +1 -0
  44. package/dist/src/runtime.d.ts +7 -0
  45. package/dist/src/runtime.d.ts.map +1 -0
  46. package/dist/src/runtime.js +14 -0
  47. package/dist/src/runtime.js.map +1 -0
  48. package/dist/src/send.d.ts +23 -0
  49. package/dist/src/send.d.ts.map +1 -0
  50. package/dist/src/send.js +158 -0
  51. package/dist/src/send.js.map +1 -0
  52. package/dist/src/status-issues.d.ts +7 -0
  53. package/dist/src/status-issues.d.ts.map +1 -0
  54. package/dist/src/status-issues.js +48 -0
  55. package/dist/src/status-issues.js.map +1 -0
  56. package/dist/src/types.d.ts +62 -0
  57. package/dist/src/types.d.ts.map +1 -0
  58. package/dist/src/types.js +5 -0
  59. package/dist/src/types.js.map +1 -0
  60. package/package.json +93 -0
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Smart group chat reply filter.
3
+ *
4
+ * In group chats, only respond when the message looks like a real
5
+ * question, request, or direct address — avoids spamming.
6
+ */
7
+ /** Default bot name patterns for address detection. */
8
+ const DEFAULT_BOT_NAMES = ["clawdbot", "moltbot", "bot", "助手", "智能体"];
9
+ /**
10
+ * Determine whether the bot should respond to a group message.
11
+ *
12
+ * @param text - Message text (after stripping @mention placeholders)
13
+ * @param mentions - Array of mention objects from the Feishu event
14
+ * @param botNames - Custom bot name list for address detection
15
+ */
16
+ export function shouldRespondInGroup(text, mentions, botNames) {
17
+ // Always respond to @-mentions
18
+ if (mentions.length > 0)
19
+ return true;
20
+ const t = text.toLowerCase();
21
+ // Ends with question mark
22
+ if (/[??]$/.test(text))
23
+ return true;
24
+ // English question words
25
+ if (/\b(why|how|what|when|where|who|help)\b/.test(t))
26
+ return true;
27
+ // Chinese request verbs
28
+ const verbs = [
29
+ "帮", "麻烦", "请", "能否", "可以", "解释", "看看",
30
+ "排查", "分析", "总结", "写", "改", "修", "查", "对比", "翻译",
31
+ ];
32
+ if (verbs.some((k) => text.includes(k)))
33
+ return true;
34
+ // Direct address by bot name
35
+ const names = botNames?.length ? botNames : DEFAULT_BOT_NAMES;
36
+ const namePattern = new RegExp(`^(${names.map(escapeRegex).join("|")})[\\s,:,:]`, "i");
37
+ if (namePattern.test(text))
38
+ return true;
39
+ return false;
40
+ }
41
+ function escapeRegex(s) {
42
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
43
+ }
44
+ //# sourceMappingURL=group-filter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"group-filter.js","sourceRoot":"","sources":["../../src/group-filter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,uDAAuD;AACvD,MAAM,iBAAiB,GAAG,CAAC,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;AAEtE;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAClC,IAAY,EACZ,QAAmB,EACnB,QAAmB;IAEnB,+BAA+B;IAC/B,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAErC,MAAM,CAAC,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IAE7B,0BAA0B;IAC1B,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAEpC,yBAAyB;IACzB,IAAI,wCAAwC,CAAC,IAAI,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAElE,wBAAwB;IACxB,MAAM,KAAK,GAAG;QACZ,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;QACtC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI;KACjD,CAAC;IACF,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAErD,6BAA6B;IAC7B,MAAM,KAAK,GAAG,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,iBAAiB,CAAC;IAC9D,MAAM,WAAW,GAAG,IAAI,MAAM,CAC5B,KAAK,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,EACjD,GAAG,CACJ,CAAC;IACF,IAAI,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAExC,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,WAAW,CAAC,CAAS;IAC5B,OAAO,CAAC,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;AAClD,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Media upload/download helpers for Feishu.
3
+ */
4
+ import type * as Lark from "@larksuiteoapi/node-sdk";
5
+ import type { FeishuMediaType } from "./types.js";
6
+ /** Detect media type from URL or mime type. */
7
+ export declare function getMediaType(url: string, mimeType?: string): FeishuMediaType;
8
+ /** Extract file extension from a URL. */
9
+ export declare function getFileExtension(url: string): string;
10
+ /** Download a URL to a temporary file. Returns path and cleanup flag. */
11
+ export declare function downloadToTempFile(url: string): Promise<{
12
+ path: string;
13
+ isTemp: boolean;
14
+ }>;
15
+ /** Upload an image to Feishu and return the image_key. */
16
+ export declare function uploadImage(client: InstanceType<typeof Lark.Client>, filePath: string): Promise<string>;
17
+ /** Upload a file to Feishu and return the file_key. */
18
+ export declare function uploadFile(client: InstanceType<typeof Lark.Client>, filePath: string, filename: string, fileType?: "stream" | "opus" | "mp4" | "pdf" | "doc" | "xls" | "ppt"): Promise<string>;
19
+ /** Clean up a temp file. */
20
+ export declare function cleanupTemp(filePath: string, isTemp: boolean): void;
21
+ //# sourceMappingURL=media.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media.d.ts","sourceRoot":"","sources":["../../src/media.ts"],"names":[],"mappings":"AAAA;;GAEG;AAQH,OAAO,KAAK,KAAK,IAAI,MAAM,yBAAyB,CAAC;AAErD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,+CAA+C;AAC/C,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,eAAe,CAc5E;AAED,yCAAyC;AACzC,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAGpD;AAED,yEAAyE;AACzE,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,MAAM,GACV,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,CAAC,CAiD5C;AAED,0DAA0D;AAC1D,wBAAsB,WAAW,CAC/B,MAAM,EAAE,YAAY,CAAC,OAAO,IAAI,CAAC,MAAM,CAAC,EACxC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,CAAC,CAejB;AAED,uDAAuD;AACvD,wBAAsB,UAAU,CAC9B,MAAM,EAAE,YAAY,CAAC,OAAO,IAAI,CAAC,MAAM,CAAC,EACxC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,QAAQ,GAAE,QAAQ,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,KAAgB,GAC7E,OAAO,CAAC,MAAM,CAAC,CAgBjB;AAED,4BAA4B;AAC5B,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI,CAInE"}
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Media upload/download helpers for Feishu.
3
+ */
4
+ import fs from "node:fs";
5
+ import os from "node:os";
6
+ import path from "node:path";
7
+ import https from "node:https";
8
+ import http from "node:http";
9
+ /** Detect media type from URL or mime type. */
10
+ export function getMediaType(url, mimeType) {
11
+ const urlLower = url.toLowerCase();
12
+ if (/\.(jpg|jpeg|png|gif|webp|bmp)(\?|$)/i.test(urlLower))
13
+ return "image";
14
+ if (/\.(mp4|mov|avi|mkv|webm)(\?|$)/i.test(urlLower))
15
+ return "video";
16
+ if (/\.(mp3|wav|ogg|m4a|aac)(\?|$)/i.test(urlLower))
17
+ return "audio";
18
+ if (mimeType) {
19
+ if (mimeType.startsWith("image/"))
20
+ return "image";
21
+ if (mimeType.startsWith("video/"))
22
+ return "video";
23
+ if (mimeType.startsWith("audio/"))
24
+ return "audio";
25
+ }
26
+ return "file";
27
+ }
28
+ /** Extract file extension from a URL. */
29
+ export function getFileExtension(url) {
30
+ const match = url.match(/\.([a-zA-Z0-9]+)(\?|$)/);
31
+ return match ? match[1].toLowerCase() : "bin";
32
+ }
33
+ /** Download a URL to a temporary file. Returns path and cleanup flag. */
34
+ export async function downloadToTempFile(url) {
35
+ // Local file reference
36
+ if (url.startsWith("/") || url.startsWith("file://")) {
37
+ const filePath = url.replace("file://", "");
38
+ return { path: filePath, isTemp: false };
39
+ }
40
+ const extension = getFileExtension(url);
41
+ const tempPath = path.join(os.tmpdir(), `feishu_${Date.now()}.${extension}`);
42
+ return new Promise((resolve, reject) => {
43
+ const protocol = url.startsWith("https") ? https : http;
44
+ const file = fs.createWriteStream(tempPath);
45
+ protocol
46
+ .get(url, (response) => {
47
+ if (response.statusCode === 301 || response.statusCode === 302) {
48
+ file.close();
49
+ try {
50
+ fs.unlinkSync(tempPath);
51
+ }
52
+ catch { /* ignore */ }
53
+ const location = response.headers.location;
54
+ if (!location) {
55
+ reject(new Error("Redirect without location header"));
56
+ return;
57
+ }
58
+ downloadToTempFile(location).then(resolve).catch(reject);
59
+ return;
60
+ }
61
+ if (response.statusCode !== 200) {
62
+ file.close();
63
+ try {
64
+ fs.unlinkSync(tempPath);
65
+ }
66
+ catch { /* ignore */ }
67
+ reject(new Error(`Failed to download: HTTP ${response.statusCode}`));
68
+ return;
69
+ }
70
+ response.pipe(file);
71
+ file.on("finish", () => {
72
+ file.close();
73
+ resolve({ path: tempPath, isTemp: true });
74
+ });
75
+ file.on("error", (err) => {
76
+ try {
77
+ fs.unlinkSync(tempPath);
78
+ }
79
+ catch { /* ignore */ }
80
+ reject(err);
81
+ });
82
+ })
83
+ .on("error", (err) => {
84
+ file.close();
85
+ try {
86
+ fs.unlinkSync(tempPath);
87
+ }
88
+ catch { /* ignore */ }
89
+ reject(err);
90
+ });
91
+ });
92
+ }
93
+ /** Upload an image to Feishu and return the image_key. */
94
+ export async function uploadImage(client, filePath) {
95
+ const response = await client.im.image.create({
96
+ data: {
97
+ image_type: "message",
98
+ image: fs.createReadStream(filePath),
99
+ },
100
+ });
101
+ const imageKey = response.image_key ??
102
+ response.data?.image_key;
103
+ if (!imageKey) {
104
+ throw new Error(`Upload image failed: ${JSON.stringify(response)}`);
105
+ }
106
+ return imageKey;
107
+ }
108
+ /** Upload a file to Feishu and return the file_key. */
109
+ export async function uploadFile(client, filePath, filename, fileType = "stream") {
110
+ const response = await client.im.file.create({
111
+ data: {
112
+ file_type: fileType,
113
+ file_name: filename,
114
+ file: fs.createReadStream(filePath),
115
+ },
116
+ });
117
+ const fileKey = response.file_key ??
118
+ response.data?.file_key;
119
+ if (!fileKey) {
120
+ throw new Error(`Upload file failed: ${JSON.stringify(response)}`);
121
+ }
122
+ return fileKey;
123
+ }
124
+ /** Clean up a temp file. */
125
+ export function cleanupTemp(filePath, isTemp) {
126
+ if (isTemp) {
127
+ try {
128
+ fs.unlinkSync(filePath);
129
+ }
130
+ catch { /* ignore */ }
131
+ }
132
+ }
133
+ //# sourceMappingURL=media.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media.js","sourceRoot":"","sources":["../../src/media.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Feishu onboarding wizard adapter.
3
+ */
4
+ import type { ClawdbotConfig } from "clawdbot/plugin-sdk";
5
+ /** WizardPrompter interface for onboarding. */
6
+ interface WizardPrompter {
7
+ note(message: string, title?: string): Promise<void>;
8
+ text(opts: {
9
+ message: string;
10
+ placeholder?: string;
11
+ initialValue?: string;
12
+ validate?: (value: unknown) => string | undefined;
13
+ }): Promise<string>;
14
+ select<T>(opts: {
15
+ message: string;
16
+ options: Array<{
17
+ value: T;
18
+ label: string;
19
+ }>;
20
+ initialValue?: T;
21
+ }): Promise<T>;
22
+ confirm?(opts: {
23
+ message: string;
24
+ initialValue?: boolean;
25
+ }): Promise<boolean>;
26
+ }
27
+ /** Feishu onboarding adapter for the channel. */
28
+ export declare const feishuOnboardingAdapter: {
29
+ /** Check if Feishu channel is configured. */
30
+ configuredCheck: (cfg: ClawdbotConfig) => boolean;
31
+ /** Set the DM policy. */
32
+ setDmPolicy: (cfg: ClawdbotConfig, policy: "pairing" | "allowlist" | "open" | "disabled") => ClawdbotConfig;
33
+ /** Prompt user for allowFrom configuration. */
34
+ promptAllowFrom: (params: {
35
+ cfg: ClawdbotConfig;
36
+ prompter: WizardPrompter;
37
+ accountId: string;
38
+ }) => Promise<ClawdbotConfig>;
39
+ /** Show setup help notes. */
40
+ noteSetupHelp: (prompter: WizardPrompter) => Promise<void>;
41
+ /** Run the full setup wizard. */
42
+ runSetupWizard: (params: {
43
+ cfg: ClawdbotConfig;
44
+ prompter: WizardPrompter;
45
+ accountOverrides?: Record<string, string | undefined>;
46
+ shouldPromptAccountIds?: boolean;
47
+ forceAllowFrom?: boolean;
48
+ }) => Promise<ClawdbotConfig>;
49
+ };
50
+ export {};
51
+ //# sourceMappingURL=onboarding.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"onboarding.d.ts","sourceRoot":"","sources":["../../src/onboarding.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,cAAc,EACf,MAAM,qBAAqB,CAAC;AAoD7B,+CAA+C;AAC/C,UAAU,cAAc;IACtB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,IAAI,CAAC,IAAI,EAAE;QACT,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,GAAG,SAAS,CAAC;KACnD,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACpB,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,EAAE,KAAK,CAAC;YAAE,KAAK,EAAE,CAAC,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QAC5C,YAAY,CAAC,EAAE,CAAC,CAAC;KAClB,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACf,OAAO,CAAC,CAAC,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC/E;AAmED,iDAAiD;AACjD,eAAO,MAAM,uBAAuB;IAClC,6CAA6C;2BACtB,cAAc,KAAG,OAAO;IAM/C,yBAAyB;uBACN,cAAc,UAAU,SAAS,GAAG,WAAW,GAAG,MAAM,GAAG,UAAU,KAAG,cAAc;IAIzG,+CAA+C;8BACf;QAC9B,GAAG,EAAE,cAAc,CAAC;QACpB,QAAQ,EAAE,cAAc,CAAC;QACzB,SAAS,EAAE,MAAM,CAAC;KACnB,KAAG,OAAO,CAAC,cAAc,CAAC;IAI3B,6BAA6B;8BACG,cAAc,KAAG,OAAO,CAAC,IAAI,CAAC;IAI9D,iCAAiC;6BACF;QAC7B,GAAG,EAAE,cAAc,CAAC;QACpB,QAAQ,EAAE,cAAc,CAAC;QACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;QACtD,sBAAsB,CAAC,EAAE,OAAO,CAAC;QACjC,cAAc,CAAC,EAAE,OAAO,CAAC;KAC1B,KAAG,OAAO,CAAC,cAAc,CAAC;CAsH5B,CAAC"}
@@ -0,0 +1,213 @@
1
+ /**
2
+ * Feishu onboarding wizard adapter.
3
+ */
4
+ import { addWildcardAllowFrom, DEFAULT_ACCOUNT_ID, normalizeAccountId, } from "clawdbot/plugin-sdk";
5
+ import { listFeishuAccountIds, resolveDefaultFeishuAccountId, resolveFeishuAccount, } from "./accounts.js";
6
+ const channel = "feishu";
7
+ function setFeishuDmPolicy(cfg, dmPolicy) {
8
+ const feishuCfg = cfg.channels?.feishu ?? {};
9
+ const existingAllowFrom = Array.isArray(feishuCfg.allowFrom) ? feishuCfg.allowFrom : [];
10
+ const allowFrom = dmPolicy === "open" ? addWildcardAllowFrom(existingAllowFrom) : undefined;
11
+ return {
12
+ ...cfg,
13
+ channels: {
14
+ ...(cfg.channels ?? {}),
15
+ feishu: {
16
+ ...feishuCfg,
17
+ dmPolicy,
18
+ ...(allowFrom ? { allowFrom } : {}),
19
+ },
20
+ },
21
+ };
22
+ }
23
+ async function noteFeishuSetupHelp(prompter) {
24
+ await prompter.note([
25
+ "1) Go to https://open.feishu.cn/app → Create self-built app",
26
+ "2) Add Bot capability to the app",
27
+ '3) Enable permissions: im:message, im:message.group_at_msg, im:message.p2p_msg',
28
+ '4) Events: add im.message.receive_v1, set delivery to "WebSocket long-connection"',
29
+ "5) Publish the app (create version → request approval)",
30
+ "6) Note the App ID (cli_xxx) and App Secret",
31
+ "",
32
+ "Docs: https://open.feishu.cn/document/home/index",
33
+ ].join("\n"), "Feishu Bot Setup");
34
+ }
35
+ async function promptFeishuAllowFrom(params) {
36
+ const { cfg, prompter, accountId } = params;
37
+ const resolved = resolveFeishuAccount({ cfg, accountId });
38
+ const existingAllowFrom = resolved.config.allowFrom ?? [];
39
+ const entry = await prompter.text({
40
+ message: "Feishu allowFrom (open_id or union_id)",
41
+ placeholder: "ou_xxxxxxxxxx",
42
+ initialValue: existingAllowFrom[0] ? String(existingAllowFrom[0]) : undefined,
43
+ validate: (value) => {
44
+ const raw = String(value ?? "").trim();
45
+ if (!raw)
46
+ return "Required";
47
+ return undefined;
48
+ },
49
+ });
50
+ const normalized = String(entry).trim();
51
+ const merged = [
52
+ ...existingAllowFrom.map((item) => String(item).trim()).filter(Boolean),
53
+ normalized,
54
+ ];
55
+ const unique = [...new Set(merged)];
56
+ const feishuCfg = (cfg.channels?.feishu ?? {});
57
+ const accounts = (feishuCfg.accounts ?? {});
58
+ if (accountId === DEFAULT_ACCOUNT_ID) {
59
+ return {
60
+ ...cfg,
61
+ channels: {
62
+ ...(cfg.channels ?? {}),
63
+ feishu: {
64
+ ...feishuCfg,
65
+ enabled: true,
66
+ dmPolicy: "allowlist",
67
+ allowFrom: unique,
68
+ },
69
+ },
70
+ };
71
+ }
72
+ const accountCfg = (accounts[accountId] ?? {});
73
+ return {
74
+ ...cfg,
75
+ channels: {
76
+ ...(cfg.channels ?? {}),
77
+ feishu: {
78
+ ...feishuCfg,
79
+ enabled: true,
80
+ accounts: {
81
+ ...accounts,
82
+ [accountId]: {
83
+ ...accountCfg,
84
+ enabled: accountCfg.enabled ?? true,
85
+ dmPolicy: "allowlist",
86
+ allowFrom: unique,
87
+ },
88
+ },
89
+ },
90
+ },
91
+ };
92
+ }
93
+ /** Feishu onboarding adapter for the channel. */
94
+ export const feishuOnboardingAdapter = {
95
+ /** Check if Feishu channel is configured. */
96
+ configuredCheck: (cfg) => {
97
+ return listFeishuAccountIds(cfg).some((accountId) => Boolean(resolveFeishuAccount({ cfg, accountId }).appId));
98
+ },
99
+ /** Set the DM policy. */
100
+ setDmPolicy: (cfg, policy) => {
101
+ return setFeishuDmPolicy(cfg, policy);
102
+ },
103
+ /** Prompt user for allowFrom configuration. */
104
+ promptAllowFrom: async (params) => {
105
+ return promptFeishuAllowFrom(params);
106
+ },
107
+ /** Show setup help notes. */
108
+ noteSetupHelp: async (prompter) => {
109
+ return noteFeishuSetupHelp(prompter);
110
+ },
111
+ /** Run the full setup wizard. */
112
+ runSetupWizard: async (params) => {
113
+ const { cfg, prompter, accountOverrides, shouldPromptAccountIds, forceAllowFrom } = params;
114
+ const feishuOverride = accountOverrides?.feishu?.trim();
115
+ const defaultAccountId = resolveDefaultFeishuAccountId(cfg);
116
+ let feishuAccountId = feishuOverride
117
+ ? normalizeAccountId(feishuOverride)
118
+ : defaultAccountId;
119
+ if (shouldPromptAccountIds && !feishuOverride) {
120
+ const accountIds = listFeishuAccountIds(cfg);
121
+ const options = accountIds.map((id) => ({ value: id, label: id }));
122
+ feishuAccountId = await prompter.select({
123
+ message: "Select Feishu account",
124
+ options,
125
+ initialValue: feishuAccountId,
126
+ });
127
+ }
128
+ let next = cfg;
129
+ const resolvedAccount = resolveFeishuAccount({ cfg: next, accountId: feishuAccountId });
130
+ const accountConfigured = Boolean(resolvedAccount.appId);
131
+ if (!accountConfigured) {
132
+ await noteFeishuSetupHelp(prompter);
133
+ }
134
+ const hasConfigCredentials = Boolean(resolvedAccount.config.appId && resolvedAccount.config.appSecret);
135
+ let appId = null;
136
+ let appSecret = null;
137
+ if (hasConfigCredentials && prompter.confirm) {
138
+ const keep = await prompter.confirm({
139
+ message: "Feishu credentials already configured. Keep them?",
140
+ initialValue: true,
141
+ });
142
+ if (!keep) {
143
+ appId = String(await prompter.text({
144
+ message: "Enter Feishu App ID (cli_xxx)",
145
+ validate: (value) => (String(value ?? "").trim() ? undefined : "Required"),
146
+ })).trim();
147
+ appSecret = String(await prompter.text({
148
+ message: "Enter Feishu App Secret",
149
+ validate: (value) => (String(value ?? "").trim() ? undefined : "Required"),
150
+ })).trim();
151
+ }
152
+ }
153
+ else if (!hasConfigCredentials) {
154
+ appId = String(await prompter.text({
155
+ message: "Enter Feishu App ID (cli_xxx)",
156
+ validate: (value) => (String(value ?? "").trim() ? undefined : "Required"),
157
+ })).trim();
158
+ appSecret = String(await prompter.text({
159
+ message: "Enter Feishu App Secret",
160
+ validate: (value) => (String(value ?? "").trim() ? undefined : "Required"),
161
+ })).trim();
162
+ }
163
+ const feishuCfg2 = (next.channels?.feishu ?? {});
164
+ const accounts2 = (feishuCfg2.accounts ?? {});
165
+ if (appId && appSecret) {
166
+ if (feishuAccountId === DEFAULT_ACCOUNT_ID) {
167
+ next = {
168
+ ...next,
169
+ channels: {
170
+ ...(next.channels ?? {}),
171
+ feishu: {
172
+ ...feishuCfg2,
173
+ enabled: true,
174
+ appId,
175
+ appSecret,
176
+ },
177
+ },
178
+ };
179
+ }
180
+ else {
181
+ const accountCfg2 = (accounts2[feishuAccountId] ?? {});
182
+ next = {
183
+ ...next,
184
+ channels: {
185
+ ...(next.channels ?? {}),
186
+ feishu: {
187
+ ...feishuCfg2,
188
+ enabled: true,
189
+ accounts: {
190
+ ...accounts2,
191
+ [feishuAccountId]: {
192
+ ...accountCfg2,
193
+ enabled: true,
194
+ appId,
195
+ appSecret,
196
+ },
197
+ },
198
+ },
199
+ },
200
+ };
201
+ }
202
+ }
203
+ if (forceAllowFrom) {
204
+ next = await promptFeishuAllowFrom({
205
+ cfg: next,
206
+ prompter,
207
+ accountId: feishuAccountId,
208
+ });
209
+ }
210
+ return next;
211
+ },
212
+ };
213
+ //# sourceMappingURL=onboarding.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"onboarding.js","sourceRoot":"","sources":["../../src/onboarding.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Feishu API connectivity probe.
3
+ */
4
+ import type { FeishuProbeResult } from "./types.js";
5
+ /**
6
+ * Probe the Feishu API by fetching bot info.
7
+ * Uses the internal tenant access token endpoint.
8
+ */
9
+ export declare function probeFeishu(appId: string, appSecret: string, timeoutMs?: number): Promise<FeishuProbeResult>;
10
+ //# sourceMappingURL=probe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"probe.d.ts","sourceRoot":"","sources":["../../src/probe.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,SAAS,SAAO,GACf,OAAO,CAAC,iBAAiB,CAAC,CA6C5B"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Feishu API connectivity probe.
3
+ */
4
+ import * as Lark from "@larksuiteoapi/node-sdk";
5
+ /**
6
+ * Probe the Feishu API by fetching bot info.
7
+ * Uses the internal tenant access token endpoint.
8
+ */
9
+ export async function probeFeishu(appId, appSecret, timeoutMs = 5000) {
10
+ if (!appId?.trim() || !appSecret?.trim()) {
11
+ return { ok: false, error: "Missing appId or appSecret", elapsedMs: 0 };
12
+ }
13
+ const startTime = Date.now();
14
+ try {
15
+ const client = new Lark.Client({
16
+ appId: appId.trim(),
17
+ appSecret: appSecret.trim(),
18
+ domain: Lark.Domain.Feishu,
19
+ appType: Lark.AppType.SelfBuild,
20
+ });
21
+ // Use bot info endpoint to validate credentials
22
+ const response = await client.bot.v3.botInfo.get({});
23
+ const elapsedMs = Date.now() - startTime;
24
+ const bot = response?.data?.bot;
25
+ if (bot) {
26
+ return {
27
+ ok: true,
28
+ bot: {
29
+ name: bot.bot_name,
30
+ openId: bot.open_id,
31
+ },
32
+ elapsedMs,
33
+ };
34
+ }
35
+ return { ok: true, elapsedMs };
36
+ }
37
+ catch (err) {
38
+ const elapsedMs = Date.now() - startTime;
39
+ if (err instanceof Error) {
40
+ if (err.name === "AbortError") {
41
+ return { ok: false, error: `Request timed out after ${timeoutMs}ms`, elapsedMs };
42
+ }
43
+ return { ok: false, error: err.message, elapsedMs };
44
+ }
45
+ return { ok: false, error: String(err), elapsedMs };
46
+ }
47
+ }
48
+ //# sourceMappingURL=probe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"probe.js","sourceRoot":"","sources":["../../src/probe.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,IAAI,MAAM,yBAAyB,CAAC;AAIhD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,KAAa,EACb,SAAiB,EACjB,SAAS,GAAG,IAAI;IAEhB,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,EAAE,CAAC;QACzC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,4BAA4B,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC;IAC1E,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAE7B,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC;YAC7B,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE;YACnB,SAAS,EAAE,SAAS,CAAC,IAAI,EAAE;YAC3B,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM;YAC1B,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS;SAChC,CAAC,CAAC;QAEH,gDAAgD;QAChD,MAAM,QAAQ,GAAG,MAAO,MAAqJ,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAErM,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;QAEzC,MAAM,GAAG,GAAG,QAAQ,EAAE,IAAI,EAAE,GAAG,CAAC;QAChC,IAAI,GAAG,EAAE,CAAC;YACR,OAAO;gBACL,EAAE,EAAE,IAAI;gBACR,GAAG,EAAE;oBACH,IAAI,EAAG,GAA+B,CAAC,QAA8B;oBACrE,MAAM,EAAG,GAA+B,CAAC,OAA6B;iBACvE;gBACD,SAAS;aACV,CAAC;QACJ,CAAC;QAED,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;IACjC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;QAEzC,IAAI,GAAG,YAAY,KAAK,EAAE,CAAC;YACzB,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;gBAC9B,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,2BAA2B,SAAS,IAAI,EAAE,SAAS,EAAE,CAAC;YACnF,CAAC;YACD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,SAAS,EAAE,CAAC;QACtD,CAAC;QAED,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,SAAS,EAAE,CAAC;IACtD,CAAC;AACH,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Feishu WebSocket message receive handler.
3
+ *
4
+ * Connects to Feishu via the SDK's WSClient, dispatches incoming
5
+ * messages to Clawdbot's channel reply infrastructure.
6
+ */
7
+ import type { ClawdbotConfig } from "clawdbot/plugin-sdk";
8
+ import type { ResolvedFeishuAccount } from "./types.js";
9
+ /** Options for the Feishu provider. */
10
+ export type FeishuProviderOptions = {
11
+ account: ResolvedFeishuAccount;
12
+ config: ClawdbotConfig;
13
+ log: {
14
+ info: (msg: string) => void;
15
+ error: (msg: string) => void;
16
+ debug?: (msg: string) => void;
17
+ };
18
+ abortSignal?: AbortSignal;
19
+ statusSink?: (patch: Record<string, unknown>) => void;
20
+ };
21
+ /** Start the Feishu WebSocket provider. Returns a stop function. */
22
+ export declare function startFeishuProvider(options: FeishuProviderOptions): {
23
+ stop: () => void;
24
+ };
25
+ //# sourceMappingURL=receive.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"receive.d.ts","sourceRoot":"","sources":["../../src/receive.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAOxD,uCAAuC;AACvC,MAAM,MAAM,qBAAqB,GAAG;IAClC,OAAO,EAAE,qBAAqB,CAAC;IAC/B,MAAM,EAAE,cAAc,CAAC;IACvB,GAAG,EAAE;QACH,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;QAC5B,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;QAC7B,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;KAC/B,CAAC;IACF,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;CACvD,CAAC;AAEF,oEAAoE;AACpE,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,qBAAqB,GAAG;IAAE,IAAI,EAAE,MAAM,IAAI,CAAA;CAAE,CAuDxF"}