golembot 0.10.2 → 0.11.0-beta.10
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.
- package/dist/channel.d.ts +14 -1
- package/dist/channel.d.ts.map +1 -1
- package/dist/channel.js.map +1 -1
- package/dist/channels/dingtalk.d.ts +4 -2
- package/dist/channels/dingtalk.d.ts.map +1 -1
- package/dist/channels/dingtalk.js +16 -1
- package/dist/channels/dingtalk.js.map +1 -1
- package/dist/channels/discord.d.ts +4 -2
- package/dist/channels/discord.d.ts.map +1 -1
- package/dist/channels/discord.js +13 -1
- package/dist/channels/discord.js.map +1 -1
- package/dist/channels/feishu-format.d.ts +25 -7
- package/dist/channels/feishu-format.d.ts.map +1 -1
- package/dist/channels/feishu-format.js +74 -27
- package/dist/channels/feishu-format.js.map +1 -1
- package/dist/channels/feishu.d.ts +10 -2
- package/dist/channels/feishu.d.ts.map +1 -1
- package/dist/channels/feishu.js +74 -26
- package/dist/channels/feishu.js.map +1 -1
- package/dist/channels/slack-format.d.ts +20 -0
- package/dist/channels/slack-format.d.ts.map +1 -0
- package/dist/channels/slack-format.js +132 -0
- package/dist/channels/slack-format.js.map +1 -0
- package/dist/channels/slack.d.ts +5 -2
- package/dist/channels/slack.d.ts.map +1 -1
- package/dist/channels/slack.js +21 -2
- package/dist/channels/slack.js.map +1 -1
- package/dist/channels/telegram-format.d.ts +21 -0
- package/dist/channels/telegram-format.d.ts.map +1 -0
- package/dist/channels/telegram-format.js +167 -0
- package/dist/channels/telegram-format.js.map +1 -0
- package/dist/channels/telegram.d.ts +4 -2
- package/dist/channels/telegram.d.ts.map +1 -1
- package/dist/channels/telegram.js +16 -2
- package/dist/channels/telegram.js.map +1 -1
- package/dist/channels/wecom.d.ts +4 -2
- package/dist/channels/wecom.d.ts.map +1 -1
- package/dist/channels/wecom.js +17 -1
- package/dist/channels/wecom.js.map +1 -1
- package/dist/gateway.d.ts +10 -2
- package/dist/gateway.d.ts.map +1 -1
- package/dist/gateway.js +38 -2
- package/dist/gateway.js.map +1 -1
- package/package.json +1 -1
- package/skills/im-adapter/SKILL.md +11 -6
package/dist/channel.d.ts
CHANGED
|
@@ -13,12 +13,19 @@ export interface ChannelMessage {
|
|
|
13
13
|
*/
|
|
14
14
|
mentioned?: boolean;
|
|
15
15
|
}
|
|
16
|
+
export interface MentionTarget {
|
|
17
|
+
name: string;
|
|
18
|
+
platformId: string;
|
|
19
|
+
}
|
|
20
|
+
export interface ReplyOptions {
|
|
21
|
+
mentions?: MentionTarget[];
|
|
22
|
+
}
|
|
16
23
|
export interface ChannelAdapter {
|
|
17
24
|
readonly name: string;
|
|
18
25
|
/** Optional: override the default 4000-char message split limit for this channel. */
|
|
19
26
|
readonly maxMessageLength?: number;
|
|
20
27
|
start(onMessage: (msg: ChannelMessage) => void | Promise<void>): Promise<void>;
|
|
21
|
-
reply(msg: ChannelMessage, text: string): Promise<void>;
|
|
28
|
+
reply(msg: ChannelMessage, text: string, options?: ReplyOptions): Promise<void>;
|
|
22
29
|
stop(): Promise<void>;
|
|
23
30
|
/**
|
|
24
31
|
* Optional: send a "typing…" indicator to the chat.
|
|
@@ -26,6 +33,12 @@ export interface ChannelAdapter {
|
|
|
26
33
|
* Implementations should be idempotent and best-effort (errors are ignored).
|
|
27
34
|
*/
|
|
28
35
|
typing?(msg: ChannelMessage): Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* Optional: resolve group members for @mention support.
|
|
38
|
+
* Returns a map of display name → platform-specific user ID.
|
|
39
|
+
* Called by the gateway when the AI reply contains @mentions.
|
|
40
|
+
*/
|
|
41
|
+
getGroupMembers?(chatId: string): Promise<Map<string, string>>;
|
|
29
42
|
}
|
|
30
43
|
export declare function buildSessionKey(msg: ChannelMessage): string;
|
|
31
44
|
/**
|
package/dist/channel.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,IAAI,GAAG,OAAO,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,OAAO,CAAC;IACb;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,qFAAqF;IACrF,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,KAAK,CAAC,SAAS,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/E,KAAK,CAAC,GAAG,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,IAAI,GAAG,OAAO,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,OAAO,CAAC;IACb;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,aAAa,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,qFAAqF;IACrF,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,KAAK,CAAC,SAAS,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/E,KAAK,CAAC,GAAG,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChF,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB;;;;OAIG;IACH,MAAM,CAAC,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C;;;;OAIG;IACH,eAAe,CAAC,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAChE;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,cAAc,GAAG,MAAM,CAE3D;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKjD;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAGpE"}
|
package/dist/channel.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"channel.js","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"channel.js","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"AA8CA,MAAM,UAAU,eAAe,CAAC,GAAmB;IACjD,OAAO,GAAG,GAAG,CAAC,WAAW,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;AAC5D,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,OAAO,IAAI;SACR,OAAO,CAAC,sBAAsB,EAAE,EAAE,CAAC;SACnC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;SACpB,IAAI,EAAE,CAAC;AACZ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,OAAe;IACzD,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;IAC/D,OAAO,IAAI,MAAM,CAAC,IAAI,OAAO,oBAAoB,OAAO,SAAS,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACrF,CAAC"}
|
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import type { ChannelAdapter, ChannelMessage } from '../channel.js';
|
|
1
|
+
import type { ChannelAdapter, ChannelMessage, ReplyOptions } from '../channel.js';
|
|
2
2
|
import type { DingtalkChannelConfig } from '../workspace.js';
|
|
3
3
|
export declare class DingtalkAdapter implements ChannelAdapter {
|
|
4
4
|
readonly name = "dingtalk";
|
|
5
5
|
readonly maxMessageLength = 4000;
|
|
6
6
|
private config;
|
|
7
7
|
private dwClient;
|
|
8
|
+
private seenMsgIds;
|
|
9
|
+
private static readonly MAX_SEEN;
|
|
8
10
|
constructor(config: DingtalkChannelConfig);
|
|
9
11
|
start(onMessage: (msg: ChannelMessage) => void): Promise<void>;
|
|
10
|
-
reply(msg: ChannelMessage, text: string): Promise<void>;
|
|
12
|
+
reply(msg: ChannelMessage, text: string, options?: ReplyOptions): Promise<void>;
|
|
11
13
|
stop(): Promise<void>;
|
|
12
14
|
}
|
|
13
15
|
//# sourceMappingURL=dingtalk.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dingtalk.d.ts","sourceRoot":"","sources":["../../src/channels/dingtalk.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"dingtalk.d.ts","sourceRoot":"","sources":["../../src/channels/dingtalk.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAE7D,qBAAa,eAAgB,YAAW,cAAc;IACpD,QAAQ,CAAC,IAAI,cAAc;IAC3B,QAAQ,CAAC,gBAAgB,QAAQ;IACjC,OAAO,CAAC,MAAM,CAAwB;IACtC,OAAO,CAAC,QAAQ,CAAM;IACtB,OAAO,CAAC,UAAU,CAAqB;IACvC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAO;gBAE3B,MAAM,EAAE,qBAAqB;IAInC,KAAK,CAAC,SAAS,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IA6D9D,KAAK,CAAC,GAAG,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAuB/E,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAG5B"}
|
|
@@ -3,6 +3,8 @@ export class DingtalkAdapter {
|
|
|
3
3
|
maxMessageLength = 4000;
|
|
4
4
|
config;
|
|
5
5
|
dwClient;
|
|
6
|
+
seenMsgIds = new Set();
|
|
7
|
+
static MAX_SEEN = 500;
|
|
6
8
|
constructor(config) {
|
|
7
9
|
this.config = config;
|
|
8
10
|
}
|
|
@@ -20,6 +22,19 @@ export class DingtalkAdapter {
|
|
|
20
22
|
clientSecret: this.config.clientSecret,
|
|
21
23
|
});
|
|
22
24
|
this.dwClient.registerCallbackListener(TOPIC_ROBOT, async (res) => {
|
|
25
|
+
// Deduplicate re-delivered events.
|
|
26
|
+
const msgId = res.headers?.messageId || JSON.parse(res.data).msgId;
|
|
27
|
+
if (msgId) {
|
|
28
|
+
if (this.seenMsgIds.has(msgId)) {
|
|
29
|
+
this.dwClient.socketCallBackResponse(res.headers.messageId, { status: 'SUCCESS' });
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
this.seenMsgIds.add(msgId);
|
|
33
|
+
if (this.seenMsgIds.size > DingtalkAdapter.MAX_SEEN) {
|
|
34
|
+
const entries = [...this.seenMsgIds];
|
|
35
|
+
this.seenMsgIds = new Set(entries.slice(entries.length >> 1));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
23
38
|
const data = JSON.parse(res.data);
|
|
24
39
|
const text = data.text?.content?.trim() || '';
|
|
25
40
|
if (!text)
|
|
@@ -41,7 +56,7 @@ export class DingtalkAdapter {
|
|
|
41
56
|
await this.dwClient.connect();
|
|
42
57
|
console.log(`[dingtalk] Stream connection established`);
|
|
43
58
|
}
|
|
44
|
-
async reply(msg, text) {
|
|
59
|
+
async reply(msg, text, options) {
|
|
45
60
|
const raw = msg.raw;
|
|
46
61
|
const webhook = raw?._sessionWebhook;
|
|
47
62
|
if (!webhook)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dingtalk.js","sourceRoot":"","sources":["../../src/channels/dingtalk.ts"],"names":[],"mappings":"AAGA,MAAM,OAAO,eAAe;IACjB,IAAI,GAAG,UAAU,CAAC;IAClB,gBAAgB,GAAG,IAAI,CAAC;IACzB,MAAM,CAAwB;IAC9B,QAAQ,CAAM;
|
|
1
|
+
{"version":3,"file":"dingtalk.js","sourceRoot":"","sources":["../../src/channels/dingtalk.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ChannelAdapter, ChannelMessage } from '../channel.js';
|
|
1
|
+
import type { ChannelAdapter, ChannelMessage, ReplyOptions } from '../channel.js';
|
|
2
2
|
import type { DiscordChannelConfig } from '../workspace.js';
|
|
3
3
|
export declare class DiscordAdapter implements ChannelAdapter {
|
|
4
4
|
readonly name = "discord";
|
|
@@ -6,9 +6,11 @@ export declare class DiscordAdapter implements ChannelAdapter {
|
|
|
6
6
|
readonly maxMessageLength = 2000;
|
|
7
7
|
private config;
|
|
8
8
|
private client;
|
|
9
|
+
private seenMsgIds;
|
|
10
|
+
private static readonly MAX_SEEN;
|
|
9
11
|
constructor(config: DiscordChannelConfig);
|
|
10
12
|
start(onMessage: (msg: ChannelMessage) => void | Promise<void>): Promise<void>;
|
|
11
|
-
reply(msg: ChannelMessage, text: string): Promise<void>;
|
|
13
|
+
reply(msg: ChannelMessage, text: string, options?: ReplyOptions): Promise<void>;
|
|
12
14
|
typing(msg: ChannelMessage): Promise<void>;
|
|
13
15
|
stop(): Promise<void>;
|
|
14
16
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discord.d.ts","sourceRoot":"","sources":["../../src/channels/discord.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"discord.d.ts","sourceRoot":"","sources":["../../src/channels/discord.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClF,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAE5D,qBAAa,cAAe,YAAW,cAAc;IACnD,QAAQ,CAAC,IAAI,aAAa;IAC1B,kEAAkE;IAClE,QAAQ,CAAC,gBAAgB,QAAQ;IAEjC,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,UAAU,CAAqB;IACvC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAO;gBAE3B,MAAM,EAAE,oBAAoB;IAIlC,KAAK,CAAC,SAAS,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAyE9E,KAAK,CAAC,GAAG,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAK/E,MAAM,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAK1C,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAI5B"}
|
package/dist/channels/discord.js
CHANGED
|
@@ -4,6 +4,8 @@ export class DiscordAdapter {
|
|
|
4
4
|
maxMessageLength = 2000;
|
|
5
5
|
config;
|
|
6
6
|
client = null;
|
|
7
|
+
seenMsgIds = new Set();
|
|
8
|
+
static MAX_SEEN = 500;
|
|
7
9
|
constructor(config) {
|
|
8
10
|
this.config = config;
|
|
9
11
|
}
|
|
@@ -40,6 +42,16 @@ export class DiscordAdapter {
|
|
|
40
42
|
return;
|
|
41
43
|
if (!message.content)
|
|
42
44
|
return; // skip embed-only messages
|
|
45
|
+
// Deduplicate re-delivered events.
|
|
46
|
+
if (message.id) {
|
|
47
|
+
if (this.seenMsgIds.has(message.id))
|
|
48
|
+
return;
|
|
49
|
+
this.seenMsgIds.add(message.id);
|
|
50
|
+
if (this.seenMsgIds.size > DiscordAdapter.MAX_SEEN) {
|
|
51
|
+
const entries = [...this.seenMsgIds];
|
|
52
|
+
this.seenMsgIds = new Set(entries.slice(entries.length >> 1));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
43
55
|
const isDM = !message.guild;
|
|
44
56
|
// Detect mention via Discord's native <@userId> token (works even without botName).
|
|
45
57
|
const mentionPattern = new RegExp(`<@!?${botId}>`);
|
|
@@ -60,7 +72,7 @@ export class DiscordAdapter {
|
|
|
60
72
|
});
|
|
61
73
|
});
|
|
62
74
|
}
|
|
63
|
-
async reply(msg, text) {
|
|
75
|
+
async reply(msg, text, options) {
|
|
64
76
|
const raw = msg.raw;
|
|
65
77
|
await raw.reply({ content: text });
|
|
66
78
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discord.js","sourceRoot":"","sources":["../../src/channels/discord.ts"],"names":[],"mappings":"AAGA,MAAM,OAAO,cAAc;IAChB,IAAI,GAAG,SAAS,CAAC;IAC1B,kEAAkE;IACzD,gBAAgB,GAAG,IAAI,CAAC;IAEzB,MAAM,CAAuB;IAC7B,MAAM,GAAQ,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"discord.js","sourceRoot":"","sources":["../../src/channels/discord.ts"],"names":[],"mappings":"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"}
|
|
@@ -24,23 +24,41 @@ export interface CardElement {
|
|
|
24
24
|
content: string;
|
|
25
25
|
};
|
|
26
26
|
content?: string;
|
|
27
|
+
text_size?: string;
|
|
27
28
|
}
|
|
28
29
|
export interface CardContent {
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
schema: string;
|
|
31
|
+
body: {
|
|
32
|
+
elements: CardElement[];
|
|
33
|
+
};
|
|
34
|
+
header?: {
|
|
35
|
+
title: {
|
|
36
|
+
tag: string;
|
|
37
|
+
content: string;
|
|
38
|
+
};
|
|
39
|
+
template?: string;
|
|
31
40
|
};
|
|
32
|
-
elements: CardElement[];
|
|
33
41
|
}
|
|
34
42
|
/** Detect whether text contains Markdown formatting. */
|
|
35
43
|
export declare function hasMarkdown(text: string): boolean;
|
|
36
44
|
/** Convert Markdown text to Feishu post rich-text structure. */
|
|
37
45
|
export declare function markdownToPost(markdown: string): PostContent;
|
|
38
46
|
/**
|
|
39
|
-
* Convert Markdown text to a Feishu interactive card structure.
|
|
47
|
+
* Convert Markdown text to a Feishu interactive card v2 structure.
|
|
48
|
+
*
|
|
49
|
+
* Uses the card v2 `markdown` component which natively renders full CommonMark
|
|
50
|
+
* syntax including bold, italic, strikethrough, links, lists, code blocks,
|
|
51
|
+
* blockquotes, headings, and tables.
|
|
40
52
|
*
|
|
41
|
-
*
|
|
42
|
-
* strikethrough, links, and code blocks. We only preprocess syntax that
|
|
43
|
-
* lark_md does not support (checkboxes, blockquotes).
|
|
53
|
+
* Only checkboxes need preprocessing (not supported by card markdown).
|
|
44
54
|
*/
|
|
45
55
|
export declare function markdownToCard(markdown: string): CardContent;
|
|
56
|
+
/**
|
|
57
|
+
* Replace `@name` patterns in post content with Feishu `{ tag: 'at', user_id }` elements.
|
|
58
|
+
* Mutates the post in-place.
|
|
59
|
+
*/
|
|
60
|
+
export declare function injectMentionsIntoPost(post: PostContent, mentions: Array<{
|
|
61
|
+
name: string;
|
|
62
|
+
platformId: string;
|
|
63
|
+
}>): void;
|
|
46
64
|
//# sourceMappingURL=feishu-format.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feishu-format.d.ts","sourceRoot":"","sources":["../../src/channels/feishu-format.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,GAAG,GAAG,GAAG,IAAI,GAAG,KAAK,CAAC;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,CAAC,MAAM,GAAG,QAAQ,GAAG,WAAW,GAAG,aAAa,CAAC,EAAE,CAAC;CAC7D;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE;QACL,OAAO,EAAE,WAAW,EAAE,EAAE,CAAC;KAC1B,CAAC;CACH;AAMD,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"feishu-format.d.ts","sourceRoot":"","sources":["../../src/channels/feishu-format.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,GAAG,GAAG,GAAG,IAAI,GAAG,KAAK,CAAC;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,CAAC,MAAM,GAAG,QAAQ,GAAG,WAAW,GAAG,aAAa,CAAC,EAAE,CAAC;CAC7D;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE;QACL,OAAO,EAAE,WAAW,EAAE,EAAE,CAAC;KAC1B,CAAC;CACH;AAMD,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE;QAAE,QAAQ,EAAE,WAAW,EAAE,CAAA;KAAE,CAAC;IAClC,MAAM,CAAC,EAAE;QACP,KAAK,EAAE;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,CAAA;SAAE,CAAC;QACxC,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;CACH;AAsBD,wDAAwD;AACxD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEjD;AAOD,gEAAgE;AAChE,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,CAuC5D;AAsHD;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,CAc5D;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,WAAW,EACjB,QAAQ,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,GACpD,IAAI,CAuDN"}
|
|
@@ -81,15 +81,10 @@ function parseLine(line) {
|
|
|
81
81
|
const icon = checkboxMatch[1].toLowerCase() === 'x' ? '\u2705 ' : '\u2B1C ';
|
|
82
82
|
return [{ tag: 'text', text: icon }, ...parseInline(checkboxMatch[2])];
|
|
83
83
|
}
|
|
84
|
-
// Unordered list
|
|
85
|
-
const
|
|
86
|
-
if (
|
|
87
|
-
return [{ tag: 'text', text: '
|
|
88
|
-
}
|
|
89
|
-
// Ordered list
|
|
90
|
-
const orderedMatch = trimmed.match(/^(\d+)\.\s+(.+)$/);
|
|
91
|
-
if (orderedMatch) {
|
|
92
|
-
return [{ tag: 'text', text: `${orderedMatch[1]}. ` }, ...parseInline(orderedMatch[2])];
|
|
84
|
+
// Unordered list: - item → • item
|
|
85
|
+
const ulMatch = trimmed.match(/^[-*]\s+(.+)$/);
|
|
86
|
+
if (ulMatch) {
|
|
87
|
+
return [{ tag: 'text', text: '• ' }, ...parseInline(ulMatch[1])];
|
|
93
88
|
}
|
|
94
89
|
// Horizontal rule
|
|
95
90
|
if (/^[-*_]{3,}$/.test(trimmed)) {
|
|
@@ -172,41 +167,93 @@ function parseInline(text) {
|
|
|
172
167
|
// Markdown -> Card (interactive)
|
|
173
168
|
// ---------------------------------------------------------------------------
|
|
174
169
|
/**
|
|
175
|
-
* Convert Markdown text to a Feishu interactive card structure.
|
|
170
|
+
* Convert Markdown text to a Feishu interactive card v2 structure.
|
|
171
|
+
*
|
|
172
|
+
* Uses the card v2 `markdown` component which natively renders full CommonMark
|
|
173
|
+
* syntax including bold, italic, strikethrough, links, lists, code blocks,
|
|
174
|
+
* blockquotes, headings, and tables.
|
|
176
175
|
*
|
|
177
|
-
*
|
|
178
|
-
* strikethrough, links, and code blocks. We only preprocess syntax that
|
|
179
|
-
* lark_md does not support (checkboxes, blockquotes).
|
|
176
|
+
* Only checkboxes need preprocessing (not supported by card markdown).
|
|
180
177
|
*/
|
|
181
178
|
export function markdownToCard(markdown) {
|
|
182
179
|
const preprocessed = preprocessForCard(markdown);
|
|
183
180
|
return {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
181
|
+
schema: '2.0',
|
|
182
|
+
body: {
|
|
183
|
+
elements: [
|
|
184
|
+
{
|
|
185
|
+
tag: 'markdown',
|
|
186
|
+
content: preprocessed,
|
|
187
|
+
},
|
|
188
|
+
],
|
|
189
|
+
},
|
|
191
190
|
};
|
|
192
191
|
}
|
|
193
|
-
/**
|
|
192
|
+
/**
|
|
193
|
+
* Replace `@name` patterns in post content with Feishu `{ tag: 'at', user_id }` elements.
|
|
194
|
+
* Mutates the post in-place.
|
|
195
|
+
*/
|
|
196
|
+
export function injectMentionsIntoPost(post, mentions) {
|
|
197
|
+
if (!mentions.length)
|
|
198
|
+
return;
|
|
199
|
+
const mentionMap = new Map(mentions.map(m => [m.name, m.platformId]));
|
|
200
|
+
for (let i = 0; i < post.zh_cn.content.length; i++) {
|
|
201
|
+
const line = post.zh_cn.content[i];
|
|
202
|
+
const newLine = [];
|
|
203
|
+
for (const el of line) {
|
|
204
|
+
if (el.tag !== 'text' || !el.text) {
|
|
205
|
+
newLine.push(el);
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
// Split text on @name patterns and replace with at elements
|
|
209
|
+
let remaining = el.text;
|
|
210
|
+
const mentionPattern = /@([\w\u4e00-\u9fff]{1,20})/g;
|
|
211
|
+
let lastIdx = 0;
|
|
212
|
+
let match;
|
|
213
|
+
// Reset regex state
|
|
214
|
+
mentionPattern.lastIndex = 0;
|
|
215
|
+
const parts = [];
|
|
216
|
+
while ((match = mentionPattern.exec(remaining)) !== null) {
|
|
217
|
+
const name = match[1];
|
|
218
|
+
const userId = mentionMap.get(name);
|
|
219
|
+
if (!userId)
|
|
220
|
+
continue;
|
|
221
|
+
// Text before the mention
|
|
222
|
+
if (match.index > lastIdx) {
|
|
223
|
+
const beforeText = remaining.slice(lastIdx, match.index);
|
|
224
|
+
parts.push({ ...el, text: beforeText });
|
|
225
|
+
}
|
|
226
|
+
// The @mention element
|
|
227
|
+
parts.push({ tag: 'at', user_id: userId });
|
|
228
|
+
lastIdx = match.index + match[0].length;
|
|
229
|
+
}
|
|
230
|
+
if (parts.length === 0) {
|
|
231
|
+
// No mentions found in this element
|
|
232
|
+
newLine.push(el);
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
// Remaining text after last mention
|
|
236
|
+
if (lastIdx < remaining.length) {
|
|
237
|
+
parts.push({ ...el, text: remaining.slice(lastIdx) });
|
|
238
|
+
}
|
|
239
|
+
newLine.push(...parts);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
post.zh_cn.content[i] = newLine;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
/** Preprocess Markdown for card v2 markdown component. */
|
|
194
246
|
function preprocessForCard(text) {
|
|
195
247
|
return text
|
|
196
248
|
.split('\n')
|
|
197
249
|
.map((line) => {
|
|
198
250
|
const trimmed = line.trim();
|
|
199
|
-
// Checkbox -> emoji
|
|
251
|
+
// Checkbox -> emoji (not supported by card markdown)
|
|
200
252
|
const cbMatch = trimmed.match(/^[-*]\s+\[([ xX])\]\s+(.+)$/);
|
|
201
253
|
if (cbMatch) {
|
|
202
254
|
const icon = cbMatch[1].toLowerCase() === 'x' ? '\u2705' : '\u2B1C';
|
|
203
255
|
return `${icon} ${cbMatch[2]}`;
|
|
204
256
|
}
|
|
205
|
-
// Blockquote -> emoji prefix
|
|
206
|
-
const quoteMatch = trimmed.match(/^>\s*(.*)$/);
|
|
207
|
-
if (quoteMatch) {
|
|
208
|
-
return `\uD83D\uDCAC ${quoteMatch[1]}`;
|
|
209
|
-
}
|
|
210
257
|
return line;
|
|
211
258
|
})
|
|
212
259
|
.join('\n');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feishu-format.js","sourceRoot":"","sources":["../../src/channels/feishu-format.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"feishu-format.js","sourceRoot":"","sources":["../../src/channels/feishu-format.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAyCH,8EAA8E;AAC9E,qBAAqB;AACrB,8EAA8E;AAE9E,MAAM,WAAW,GAAa;IAC5B,YAAY,EAAiB,WAAW;IACxC,eAAe,EAAa,OAAO;IACnC,WAAW,EAAiB,SAAS;IACrC,qBAAqB,EAAO,QAAQ;IACpC,UAAU,EAAkB,iBAAiB;IAC7C,WAAW,EAAiB,eAAe;IAC3C,oBAAoB,EAAO,WAAW;IACtC,SAAS,EAAmB,cAAc;IAC1C,cAAc,EAAc,kBAAkB;IAC9C,OAAO,EAAqB,aAAa;IACzC,UAAU,EAAkB,QAAQ;IACpC,KAAK,EAAuB,aAAa;IACzC,WAAW,EAAiB,gBAAgB;CAC7C,CAAC;AAEF,wDAAwD;AACxD,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAO,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AAC/C,CAAC;AAGD,8EAA8E;AAC9E,+BAA+B;AAC/B,8EAA8E;AAE9E,gEAAgE;AAChE,MAAM,UAAU,cAAc,CAAC,QAAgB;IAC7C,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACnC,MAAM,OAAO,GAAoB,EAAE,CAAC;IAEpC,IAAI,WAAW,GAAG,KAAK,CAAC;IACxB,IAAI,aAAa,GAAG,EAAE,CAAC;IAEvB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;QACtD,IAAI,cAAc,EAAE,CAAC;YACnB,IAAI,CAAC,WAAW,EAAE,CAAC;gBACjB,WAAW,GAAG,IAAI,CAAC;gBACnB,aAAa,GAAG,cAAc,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC;gBAC5C,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,aAAa,eAAe,EAAE,CAAC,CAAC,CAAC;YACtF,CAAC;iBAAM,CAAC;gBACN,WAAW,GAAG,KAAK,CAAC;gBACpB,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,gFAAgF,EAAE,CAAC,CAAC,CAAC;gBACxH,aAAa,GAAG,EAAE,CAAC;YACrB,CAAC;YACD,SAAS;QACX,CAAC;QAED,IAAI,WAAW,EAAE,CAAC;YAChB,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;YACxD,SAAS;QACX,CAAC;QAED,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;QACjC,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxB,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACzB,CAAC;IACH,CAAC;IAED,4BAA4B;IAC5B,IAAI,WAAW,EAAE,CAAC;QAChB,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,gFAAgF,EAAE,CAAC,CAAC,CAAC;IAC1H,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,CAAC;AAChC,CAAC;AAED,yDAAyD;AACzD,SAAS,SAAS,CAAC,IAAY;IAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5B,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,CAAC;IAExB,kBAAkB;IAClB,MAAM,YAAY,GAAG,OAAO,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;IACtD,IAAI,YAAY,EAAE,CAAC;QACjB,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACnE,CAAC;IAED,0CAA0C;IAC1C,MAAM,aAAa,GAAG,OAAO,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;IACnE,IAAI,aAAa,EAAE,CAAC;QAClB,MAAM,IAAI,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;QAC5E,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,GAAG,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACzE,CAAC;IAED,kCAAkC;IAClC,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;IAC/C,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACnE,CAAC;IAED,kBAAkB;IAClB,IAAI,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QAChC,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,oEAAoE,EAAE,CAAC,CAAC;IACvG,CAAC;IAED,aAAa;IACb,MAAM,UAAU,GAAG,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IAC/C,IAAI,UAAU,EAAE,CAAC;QACf,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,GAAG,WAAW,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3E,CAAC;IAED,aAAa;IACb,OAAO,WAAW,CAAC,OAAO,CAAC,CAAC;AAC9B,CAAC;AAED,sCAAsC;AACtC,SAAS,WAAW,CAAC,IAAY;IAC/B,MAAM,QAAQ,GAAkB,EAAE,CAAC;IACnC,IAAI,SAAS,GAAG,IAAI,CAAC;IAErB,OAAO,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5B,mBAAmB;QACnB,MAAM,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;QAC9D,IAAI,SAAS,EAAE,CAAC;YACd,QAAQ,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YACpE,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;YACjD,SAAS;QACX,CAAC;QAED,4BAA4B;QAC5B,MAAM,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,kBAAkB,CAAC,IAAI,SAAS,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;QACzF,IAAI,SAAS,EAAE,CAAC;YACd,QAAQ,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACpE,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;YACjD,SAAS;QACX,CAAC;QAED,yBAAyB;QACzB,MAAM,WAAW,GAAG,SAAS,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;QACpD,IAAI,WAAW,EAAE,CAAC;YAChB,QAAQ,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;YAC7E,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;YACnD,SAAS;QACX,CAAC;QAED,0BAA0B;QAC1B,MAAM,WAAW,GAAG,SAAS,CAAC,KAAK,CAAC,cAAc,CAAC,IAAI,SAAS,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QACrF,IAAI,WAAW,EAAE,CAAC;YAChB,QAAQ,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;YACxE,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;YACnD,SAAS;QACX,CAAC;QAED,yCAAyC;QACzC,MAAM,oBAAoB,GACxB,SAAS,CAAC,KAAK,CAAC,sBAAsB,CAAC,IAAI,SAAS,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;QAC7E,IAAI,oBAAoB,EAAE,CAAC;YACzB,MAAM,IAAI,GAAG,oBAAoB,CAAC,CAAC,CAAC,IAAI,oBAAoB,CAAC,CAAC,CAAC,CAAC;YAChE,QAAQ,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,IAAI,QAAQ,EAAE,CAAC,CAAC;YAC5D,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;YAC5D,SAAS;QACX,CAAC;QAED,qBAAqB;QACrB,MAAM,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QAChD,IAAI,SAAS,EAAE,CAAC;YACd,QAAQ,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,SAAS,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;YACpE,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;YACjD,SAAS;QACX,CAAC;QAED,2CAA2C;QAC3C,MAAM,WAAW,GAAG,SAAS,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QAClD,IAAI,WAAW,KAAK,CAAC,CAAC,EAAE,CAAC;YACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;YAChD,MAAM;QACR,CAAC;aAAM,IAAI,WAAW,KAAK,CAAC,EAAE,CAAC;YAC7B,QAAQ,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YACnD,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACjC,CAAC;aAAM,CAAC;YACN,QAAQ,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,WAAW,CAAC,EAAE,CAAC,CAAC;YACtE,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QAC3C,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,8EAA8E;AAC9E,iCAAiC;AACjC,8EAA8E;AAE9E;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc,CAAC,QAAgB;IAC7C,MAAM,YAAY,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IAEjD,OAAO;QACL,MAAM,EAAE,KAAK;QACb,IAAI,EAAE;YACJ,QAAQ,EAAE;gBACR;oBACE,GAAG,EAAE,UAAU;oBACf,OAAO,EAAE,YAAY;iBACtB;aACF;SACF;KACF,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CACpC,IAAiB,EACjB,QAAqD;IAErD,IAAI,CAAC,QAAQ,CAAC,MAAM;QAAE,OAAO;IAC7B,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IAEtE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACnD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACnC,MAAM,OAAO,GAAkB,EAAE,CAAC;QAElC,KAAK,MAAM,EAAE,IAAI,IAAI,EAAE,CAAC;YACtB,IAAI,EAAE,CAAC,GAAG,KAAK,MAAM,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;gBAClC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBACjB,SAAS;YACX,CAAC;YAED,4DAA4D;YAC5D,IAAI,SAAS,GAAG,EAAE,CAAC,IAAI,CAAC;YACxB,MAAM,cAAc,GAAG,6BAA6B,CAAC;YACrD,IAAI,OAAO,GAAG,CAAC,CAAC;YAChB,IAAI,KAAK,CAAC;YAEV,oBAAoB;YACpB,cAAc,CAAC,SAAS,GAAG,CAAC,CAAC;YAC7B,MAAM,KAAK,GAAkB,EAAE,CAAC;YAEhC,OAAO,CAAC,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;gBACzD,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;gBACtB,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBACpC,IAAI,CAAC,MAAM;oBAAE,SAAS;gBAEtB,0BAA0B;gBAC1B,IAAI,KAAK,CAAC,KAAK,GAAG,OAAO,EAAE,CAAC;oBAC1B,MAAM,UAAU,GAAG,SAAS,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;oBACzD,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;gBAC1C,CAAC;gBAED,uBAAuB;gBACvB,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;gBAE3C,OAAO,GAAG,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;YAC1C,CAAC;YAED,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACvB,oCAAoC;gBACpC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACnB,CAAC;iBAAM,CAAC;gBACN,oCAAoC;gBACpC,IAAI,OAAO,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC;oBAC/B,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;gBACxD,CAAC;gBACD,OAAO,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC;YACzB,CAAC;QACH,CAAC;QAED,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC;IAClC,CAAC;AACH,CAAC;AAED,0DAA0D;AAC1D,SAAS,iBAAiB,CAAC,IAAY;IACrC,OAAO,IAAI;SACR,KAAK,CAAC,IAAI,CAAC;SACX,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACZ,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAE5B,qDAAqD;QACrD,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;QAC7D,IAAI,OAAO,EAAE,CAAC;YACZ,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;YACpE,OAAO,GAAG,IAAI,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;QACjC,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ChannelAdapter, ChannelMessage } from '../channel.js';
|
|
1
|
+
import type { ChannelAdapter, ChannelMessage, ReplyOptions } from '../channel.js';
|
|
2
2
|
import type { FeishuChannelConfig } from '../workspace.js';
|
|
3
3
|
export declare class FeishuAdapter implements ChannelAdapter {
|
|
4
4
|
readonly name = "feishu";
|
|
@@ -7,10 +7,18 @@ export declare class FeishuAdapter implements ChannelAdapter {
|
|
|
7
7
|
private client;
|
|
8
8
|
private wsClient;
|
|
9
9
|
private userNameCache;
|
|
10
|
+
/** Recent message IDs used to deduplicate re-delivered events. */
|
|
11
|
+
private seenMsgIds;
|
|
12
|
+
private static readonly MAX_SEEN;
|
|
13
|
+
/** Cached group members: chatId → (displayName → open_id). */
|
|
14
|
+
private groupMemberCache;
|
|
15
|
+
private groupMemberCacheTime;
|
|
16
|
+
private static readonly MEMBER_CACHE_TTL;
|
|
10
17
|
constructor(config: FeishuChannelConfig);
|
|
11
18
|
private resolveUserName;
|
|
12
19
|
start(onMessage: (msg: ChannelMessage) => void): Promise<void>;
|
|
13
|
-
|
|
20
|
+
getGroupMembers(chatId: string): Promise<Map<string, string>>;
|
|
21
|
+
reply(msg: ChannelMessage, text: string, options?: ReplyOptions): Promise<void>;
|
|
14
22
|
stop(): Promise<void>;
|
|
15
23
|
}
|
|
16
24
|
//# sourceMappingURL=feishu.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feishu.d.ts","sourceRoot":"","sources":["../../src/channels/feishu.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"feishu.d.ts","sourceRoot":"","sources":["../../src/channels/feishu.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,YAAY,EAAiB,MAAM,eAAe,CAAC;AACjG,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAG3D,qBAAa,aAAc,YAAW,cAAc;IAClD,QAAQ,CAAC,IAAI,YAAY;IACzB,QAAQ,CAAC,gBAAgB,QAAQ;IACjC,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,MAAM,CAAM;IACpB,OAAO,CAAC,QAAQ,CAAM;IAEtB,OAAO,CAAC,aAAa,CAA6B;IAClD,kEAAkE;IAClE,OAAO,CAAC,UAAU,CAAqB;IACvC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAO;IAEvC,8DAA8D;IAC9D,OAAO,CAAC,gBAAgB,CAA0C;IAClE,OAAO,CAAC,oBAAoB,CAA6B;IACzD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAkB;gBAE9C,MAAM,EAAE,mBAAmB;YAIzB,eAAe;IAiBvB,KAAK,CAAC,SAAS,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAqH9D,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAuC7D,KAAK,CAAC,GAAG,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAuC/E,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAM5B"}
|
package/dist/channels/feishu.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { hasMarkdown,
|
|
1
|
+
import { hasMarkdown, markdownToCard } from './feishu-format.js';
|
|
2
2
|
export class FeishuAdapter {
|
|
3
3
|
name = 'feishu';
|
|
4
4
|
maxMessageLength = 4000;
|
|
@@ -6,6 +6,13 @@ export class FeishuAdapter {
|
|
|
6
6
|
client;
|
|
7
7
|
wsClient;
|
|
8
8
|
userNameCache = new Map();
|
|
9
|
+
/** Recent message IDs used to deduplicate re-delivered events. */
|
|
10
|
+
seenMsgIds = new Set();
|
|
11
|
+
static MAX_SEEN = 500;
|
|
12
|
+
/** Cached group members: chatId → (displayName → open_id). */
|
|
13
|
+
groupMemberCache = new Map();
|
|
14
|
+
groupMemberCacheTime = new Map();
|
|
15
|
+
static MEMBER_CACHE_TTL = 10 * 60 * 1000; // 10 minutes
|
|
9
16
|
constructor(config) {
|
|
10
17
|
this.config = config;
|
|
11
18
|
}
|
|
@@ -66,6 +73,18 @@ export class FeishuAdapter {
|
|
|
66
73
|
const eventDispatcher = new lark.EventDispatcher({}).register({
|
|
67
74
|
'im.message.receive_v1': async (data) => {
|
|
68
75
|
const { message, sender } = data;
|
|
76
|
+
// Deduplicate re-delivered events.
|
|
77
|
+
const msgId = message.message_id;
|
|
78
|
+
if (msgId) {
|
|
79
|
+
if (this.seenMsgIds.has(msgId))
|
|
80
|
+
return;
|
|
81
|
+
this.seenMsgIds.add(msgId);
|
|
82
|
+
if (this.seenMsgIds.size > FeishuAdapter.MAX_SEEN) {
|
|
83
|
+
// Evict oldest half.
|
|
84
|
+
const entries = [...this.seenMsgIds];
|
|
85
|
+
this.seenMsgIds = new Set(entries.slice(entries.length >> 1));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
69
88
|
if (message.message_type !== 'text')
|
|
70
89
|
return;
|
|
71
90
|
let content;
|
|
@@ -119,34 +138,63 @@ export class FeishuAdapter {
|
|
|
119
138
|
await this.wsClient.start({ eventDispatcher });
|
|
120
139
|
console.log(`[feishu] WebSocket connection established`);
|
|
121
140
|
}
|
|
122
|
-
async
|
|
141
|
+
async getGroupMembers(chatId) {
|
|
142
|
+
const cached = this.groupMemberCache.get(chatId);
|
|
143
|
+
const ts = this.groupMemberCacheTime.get(chatId) ?? 0;
|
|
144
|
+
if (cached && Date.now() - ts < FeishuAdapter.MEMBER_CACHE_TTL)
|
|
145
|
+
return cached;
|
|
123
146
|
if (!this.client)
|
|
124
|
-
return;
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
},
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
else {
|
|
139
|
-
// Post rich text (default)
|
|
140
|
-
const post = markdownToPost(text);
|
|
141
|
-
await this.client.im.v1.message.create({
|
|
142
|
-
params: { receive_id_type: 'chat_id' },
|
|
143
|
-
data: {
|
|
144
|
-
receive_id: msg.chatId,
|
|
145
|
-
content: JSON.stringify(post),
|
|
146
|
-
msg_type: 'post',
|
|
147
|
-
},
|
|
147
|
+
return new Map();
|
|
148
|
+
try {
|
|
149
|
+
const token = await this.client.tokenManager.getTenantAccessToken();
|
|
150
|
+
const members = new Map();
|
|
151
|
+
let pageToken;
|
|
152
|
+
do {
|
|
153
|
+
const url = new URL(`https://open.feishu.cn/open-apis/im/v1/chats/${chatId}/members`);
|
|
154
|
+
url.searchParams.set('member_id_type', 'open_id');
|
|
155
|
+
if (pageToken)
|
|
156
|
+
url.searchParams.set('page_token', pageToken);
|
|
157
|
+
const resp = await fetch(url.toString(), {
|
|
158
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
148
159
|
});
|
|
160
|
+
const json = (await resp.json());
|
|
161
|
+
for (const item of json?.data?.items ?? []) {
|
|
162
|
+
if (item.name && item.member_id) {
|
|
163
|
+
members.set(item.name, item.member_id);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
pageToken = json?.data?.has_more ? json?.data?.page_token : undefined;
|
|
167
|
+
} while (pageToken);
|
|
168
|
+
this.groupMemberCache.set(chatId, members);
|
|
169
|
+
this.groupMemberCacheTime.set(chatId, Date.now());
|
|
170
|
+
return members;
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
return cached ?? new Map();
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
async reply(msg, text, options) {
|
|
177
|
+
if (!this.client)
|
|
178
|
+
return;
|
|
179
|
+
const mentions = options?.mentions;
|
|
180
|
+
const hasMentions = mentions && mentions.length > 0;
|
|
181
|
+
if (hasMarkdown(text) || hasMentions) {
|
|
182
|
+
// Card v2 (default) — best markdown rendering with native headings, lists, code blocks
|
|
183
|
+
let mdText = text;
|
|
184
|
+
if (hasMentions) {
|
|
185
|
+
for (const m of mentions) {
|
|
186
|
+
mdText = mdText.replace(new RegExp(`@${m.name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}`, 'g'), `<at id=${m.platformId}></at>`);
|
|
187
|
+
}
|
|
149
188
|
}
|
|
189
|
+
const card = markdownToCard(mdText);
|
|
190
|
+
await this.client.im.v1.message.create({
|
|
191
|
+
params: { receive_id_type: 'chat_id' },
|
|
192
|
+
data: {
|
|
193
|
+
receive_id: msg.chatId,
|
|
194
|
+
content: JSON.stringify(card),
|
|
195
|
+
msg_type: 'interactive',
|
|
196
|
+
},
|
|
197
|
+
});
|
|
150
198
|
}
|
|
151
199
|
else {
|
|
152
200
|
// Plain text
|