@openclaw/feishu 2026.3.2 → 2026.3.8-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.
- package/index.ts +2 -2
- package/package.json +1 -1
- package/src/accounts.test.ts +199 -13
- package/src/accounts.ts +45 -17
- package/src/bitable.ts +40 -28
- package/src/bot.checkBotMentioned.test.ts +8 -0
- package/src/bot.stripBotMention.test.ts +118 -22
- package/src/bot.test.ts +516 -9
- package/src/bot.ts +366 -109
- package/src/card-action.ts +1 -1
- package/src/channel.test.ts +1 -1
- package/src/channel.ts +52 -64
- package/src/chat.test.ts +2 -2
- package/src/chat.ts +1 -1
- package/src/client.test.ts +207 -4
- package/src/client.ts +70 -5
- package/src/config-schema.test.ts +14 -6
- package/src/config-schema.ts +5 -1
- package/src/dedup.ts +1 -1
- package/src/directory.test.ts +40 -0
- package/src/directory.ts +29 -50
- package/src/docx-batch-insert.test.ts +90 -0
- package/src/docx-batch-insert.ts +8 -11
- package/src/docx.account-selection.test.ts +3 -3
- package/src/docx.ts +1 -1
- package/src/drive.ts +13 -17
- package/src/dynamic-agent.ts +1 -1
- package/src/feishu-command-handler.ts +59 -0
- package/src/media.test.ts +60 -13
- package/src/media.ts +23 -9
- package/src/monitor.account.ts +19 -8
- package/src/monitor.reaction.test.ts +111 -105
- package/src/monitor.startup.test.ts +11 -10
- package/src/monitor.startup.ts +20 -7
- package/src/monitor.state.ts +4 -1
- package/src/monitor.test-mocks.ts +42 -9
- package/src/monitor.transport.ts +4 -1
- package/src/monitor.ts +4 -4
- package/src/monitor.webhook-security.test.ts +8 -23
- package/src/onboarding.status.test.ts +1 -1
- package/src/onboarding.test.ts +143 -0
- package/src/onboarding.ts +86 -71
- package/src/outbound.test.ts +178 -0
- package/src/outbound.ts +39 -6
- package/src/perm.ts +11 -15
- package/src/policy.test.ts +40 -0
- package/src/policy.ts +9 -10
- package/src/probe.test.ts +18 -18
- package/src/reactions.ts +1 -1
- package/src/reply-dispatcher.test.ts +175 -0
- package/src/reply-dispatcher.ts +69 -21
- package/src/runtime.ts +5 -13
- package/src/secret-input.ts +8 -14
- package/src/send-message.ts +71 -0
- package/src/send-target.test.ts +1 -1
- package/src/send-target.ts +1 -1
- package/src/send.reply-fallback.test.ts +74 -0
- package/src/send.test.ts +1 -1
- package/src/send.ts +88 -49
- package/src/streaming-card.test.ts +54 -0
- package/src/streaming-card.ts +96 -28
- package/src/targets.ts +5 -1
- package/src/tool-account-routing.test.ts +3 -3
- package/src/tool-account.ts +1 -1
- package/src/tool-factory-test-harness.ts +1 -1
- package/src/tool-result.test.ts +32 -0
- package/src/tool-result.ts +14 -0
- package/src/types.ts +2 -3
- package/src/typing.ts +1 -1
- package/src/wiki.ts +15 -19
|
@@ -1,38 +1,134 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
|
-
import {
|
|
2
|
+
import { parseFeishuMessageEvent } from "./bot.js";
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
function makeEvent(
|
|
5
|
+
text: string,
|
|
6
|
+
mentions?: Array<{ key: string; name: string; id: { open_id?: string; user_id?: string } }>,
|
|
7
|
+
chatType: "p2p" | "group" = "p2p",
|
|
8
|
+
) {
|
|
9
|
+
return {
|
|
10
|
+
sender: { sender_id: { user_id: "u1", open_id: "ou_sender" } },
|
|
11
|
+
message: {
|
|
12
|
+
message_id: "msg_1",
|
|
13
|
+
chat_id: "oc_chat1",
|
|
14
|
+
chat_type: chatType,
|
|
15
|
+
message_type: "text",
|
|
16
|
+
content: JSON.stringify({ text }),
|
|
17
|
+
mentions,
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
}
|
|
5
21
|
|
|
6
|
-
|
|
22
|
+
const BOT_OPEN_ID = "ou_bot";
|
|
23
|
+
|
|
24
|
+
describe("normalizeMentions (via parseFeishuMessageEvent)", () => {
|
|
7
25
|
it("returns original text when mentions are missing", () => {
|
|
8
|
-
|
|
26
|
+
const ctx = parseFeishuMessageEvent(makeEvent("hello world", undefined) as any, BOT_OPEN_ID);
|
|
27
|
+
expect(ctx.content).toBe("hello world");
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("strips bot mention in p2p (addressing prefix, not semantic content)", () => {
|
|
31
|
+
const ctx = parseFeishuMessageEvent(
|
|
32
|
+
makeEvent("@_bot_1 hello", [
|
|
33
|
+
{ key: "@_bot_1", name: "Bot", id: { open_id: "ou_bot" } },
|
|
34
|
+
]) as any,
|
|
35
|
+
BOT_OPEN_ID,
|
|
36
|
+
);
|
|
37
|
+
expect(ctx.content).toBe("hello");
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("strips bot mention in group so slash commands work (#35994)", () => {
|
|
41
|
+
const ctx = parseFeishuMessageEvent(
|
|
42
|
+
makeEvent(
|
|
43
|
+
"@_bot_1 hello",
|
|
44
|
+
[{ key: "@_bot_1", name: "Bot", id: { open_id: "ou_bot" } }],
|
|
45
|
+
"group",
|
|
46
|
+
) as any,
|
|
47
|
+
BOT_OPEN_ID,
|
|
48
|
+
);
|
|
49
|
+
expect(ctx.content).toBe("hello");
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("strips bot mention in group preserving slash command prefix (#35994)", () => {
|
|
53
|
+
const ctx = parseFeishuMessageEvent(
|
|
54
|
+
makeEvent(
|
|
55
|
+
"@_bot_1 /model",
|
|
56
|
+
[{ key: "@_bot_1", name: "Bot", id: { open_id: "ou_bot" } }],
|
|
57
|
+
"group",
|
|
58
|
+
) as any,
|
|
59
|
+
BOT_OPEN_ID,
|
|
60
|
+
);
|
|
61
|
+
expect(ctx.content).toBe("/model");
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("strips bot mention but normalizes other mentions in p2p (mention-forward)", () => {
|
|
65
|
+
const ctx = parseFeishuMessageEvent(
|
|
66
|
+
makeEvent("@_bot_1 @_user_alice hello", [
|
|
67
|
+
{ key: "@_bot_1", name: "Bot", id: { open_id: "ou_bot" } },
|
|
68
|
+
{ key: "@_user_alice", name: "Alice", id: { open_id: "ou_alice" } },
|
|
69
|
+
]) as any,
|
|
70
|
+
BOT_OPEN_ID,
|
|
71
|
+
);
|
|
72
|
+
expect(ctx.content).toBe('<at user_id="ou_alice">Alice</at> hello');
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it("falls back to @name when open_id is absent", () => {
|
|
76
|
+
const ctx = parseFeishuMessageEvent(
|
|
77
|
+
makeEvent("@_user_1 hi", [
|
|
78
|
+
{ key: "@_user_1", name: "Alice", id: { user_id: "uid_alice" } },
|
|
79
|
+
]) as any,
|
|
80
|
+
BOT_OPEN_ID,
|
|
81
|
+
);
|
|
82
|
+
expect(ctx.content).toBe("@Alice hi");
|
|
9
83
|
});
|
|
10
84
|
|
|
11
|
-
it("
|
|
12
|
-
const
|
|
13
|
-
|
|
85
|
+
it("falls back to plain @name when no id is present", () => {
|
|
86
|
+
const ctx = parseFeishuMessageEvent(
|
|
87
|
+
makeEvent("@_unknown hey", [{ key: "@_unknown", name: "Nobody", id: {} }]) as any,
|
|
88
|
+
BOT_OPEN_ID,
|
|
89
|
+
);
|
|
90
|
+
expect(ctx.content).toBe("@Nobody hey");
|
|
14
91
|
});
|
|
15
92
|
|
|
16
|
-
it("treats mention
|
|
17
|
-
const
|
|
18
|
-
|
|
93
|
+
it("treats mention key regex metacharacters as literal text", () => {
|
|
94
|
+
const ctx = parseFeishuMessageEvent(
|
|
95
|
+
makeEvent("hello world", [{ key: ".*", name: "Bot", id: { open_id: "ou_bot" } }]) as any,
|
|
96
|
+
BOT_OPEN_ID,
|
|
97
|
+
);
|
|
98
|
+
expect(ctx.content).toBe("hello world");
|
|
19
99
|
});
|
|
20
100
|
|
|
21
|
-
it("
|
|
22
|
-
const
|
|
23
|
-
|
|
101
|
+
it("normalizes multiple mentions in one pass", () => {
|
|
102
|
+
const ctx = parseFeishuMessageEvent(
|
|
103
|
+
makeEvent("@_bot_1 hi @_user_2", [
|
|
104
|
+
{ key: "@_bot_1", name: "Bot One", id: { open_id: "ou_bot_1" } },
|
|
105
|
+
{ key: "@_user_2", name: "User Two", id: { open_id: "ou_user_2" } },
|
|
106
|
+
]) as any,
|
|
107
|
+
BOT_OPEN_ID,
|
|
108
|
+
);
|
|
109
|
+
expect(ctx.content).toBe(
|
|
110
|
+
'<at user_id="ou_bot_1">Bot One</at> hi <at user_id="ou_user_2">User Two</at>',
|
|
111
|
+
);
|
|
24
112
|
});
|
|
25
113
|
|
|
26
|
-
it("
|
|
27
|
-
const
|
|
28
|
-
|
|
114
|
+
it("treats $ in display name as literal (no replacement-pattern interpolation)", () => {
|
|
115
|
+
const ctx = parseFeishuMessageEvent(
|
|
116
|
+
makeEvent("@_user_1 hi", [
|
|
117
|
+
{ key: "@_user_1", name: "$& the user", id: { open_id: "ou_x" } },
|
|
118
|
+
]) as any,
|
|
119
|
+
BOT_OPEN_ID,
|
|
120
|
+
);
|
|
121
|
+
// $ is preserved literally (no $& pattern substitution); & is not escaped in tag body
|
|
122
|
+
expect(ctx.content).toBe('<at user_id="ou_x">$& the user</at> hi');
|
|
29
123
|
});
|
|
30
124
|
|
|
31
|
-
it("
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
125
|
+
it("escapes < and > in mention name to protect tag structure", () => {
|
|
126
|
+
const ctx = parseFeishuMessageEvent(
|
|
127
|
+
makeEvent("@_user_1 test", [
|
|
128
|
+
{ key: "@_user_1", name: "<script>", id: { open_id: "ou_x" } },
|
|
129
|
+
]) as any,
|
|
130
|
+
BOT_OPEN_ID,
|
|
131
|
+
);
|
|
132
|
+
expect(ctx.content).toBe('<at user_id="ou_x"><script></at> test');
|
|
37
133
|
});
|
|
38
134
|
});
|