chatccc 0.2.52 → 0.2.54
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/README.md +95 -256
- package/bin/chatccc.mjs +23 -23
- package/demo/ilink_echo_probe.ts +222 -222
- package/im-skills/feishu-skill/download-video.mjs +162 -162
- package/im-skills/feishu-skill/receive-send-file.md +66 -66
- package/im-skills/feishu-skill/receive-send-image.md +27 -27
- package/im-skills/feishu-skill/send-file.mjs +50 -50
- package/im-skills/feishu-skill/send-image.mjs +50 -50
- package/im-skills/feishu-skill/skill.md +10 -10
- package/package.json +59 -59
- package/src/__tests__/agent-image-rpc.test.ts +33 -33
- package/src/__tests__/agent-rpc-body.test.ts +41 -41
- package/src/__tests__/card-plain-text.test.ts +42 -42
- package/src/__tests__/codex-adapter.test.ts +304 -304
- package/src/__tests__/config-reload.test.ts +26 -26
- package/src/__tests__/config-sample.test.ts +19 -19
- package/src/__tests__/crash-logging.test.ts +62 -62
- package/src/__tests__/fixtures/codex_simple_text.jsonl +4 -4
- package/src/__tests__/fixtures/codex_with_tool.jsonl +6 -6
- package/src/__tests__/im-skills.test.ts +46 -46
- package/src/__tests__/privacy.test.ts +143 -0
- package/src/__tests__/session.test.ts +57 -2
- package/src/__tests__/sim-agent.test.ts +173 -173
- package/src/__tests__/sim-platform.test.ts +76 -76
- package/src/__tests__/sim-store.test.ts +213 -213
- package/src/__tests__/stream-state.test.ts +134 -134
- package/src/__tests__/wechat-platform.test.ts +57 -32
- package/src/adapters/codex-adapter.ts +294 -294
- package/src/adapters/codex-session-meta-store.ts +130 -130
- package/src/agent-file-rpc.ts +156 -156
- package/src/agent-image-rpc.ts +152 -152
- package/src/agent-rpc-body.ts +48 -48
- package/src/card-plain-text.ts +108 -108
- package/src/feishu-api.ts +7 -3
- package/src/im-skills.ts +109 -109
- package/src/platform-adapter.ts +60 -60
- package/src/privacy.ts +68 -0
- package/src/session-chat-binding.ts +6 -1
- package/src/session.ts +40 -35
- package/src/sim-agent.ts +167 -167
- package/src/trace.ts +50 -50
- package/src/wechat-platform.ts +4 -1
|
@@ -1,214 +1,214 @@
|
|
|
1
|
-
import { describe, it, expect, afterAll } from "vitest";
|
|
2
|
-
import { unlink } from "node:fs/promises";
|
|
3
|
-
import { homedir } from "node:os";
|
|
4
|
-
import { join } from "node:path";
|
|
5
|
-
|
|
6
|
-
import { SimStore, simStore, SIM_DEFAULT_CHAT_ID } from "../sim-store.ts";
|
|
7
|
-
import type { SimAccount, SimChat, SimMessage } from "../sim-store.ts";
|
|
8
|
-
|
|
9
|
-
const MESSAGES_FILE = join(homedir(), ".chatccc", "sim", "messages.jsonl");
|
|
10
|
-
|
|
11
|
-
describe("SimStore", () => {
|
|
12
|
-
afterAll(async () => {
|
|
13
|
-
try { await unlink(MESSAGES_FILE); } catch { /* ok */ }
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
// ---- 初始化 ----
|
|
17
|
-
|
|
18
|
-
it("默认初始化 bot + 默认用户 + 默认群", () => {
|
|
19
|
-
const store = new SimStore();
|
|
20
|
-
expect(store.getAccount("bot")).toBeDefined();
|
|
21
|
-
expect(store.getAccount("sim_user_001")).toBeDefined();
|
|
22
|
-
expect(store.getChat("sim_default")).toBeDefined();
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it("默认群成员包含 bot 和 sim_user_001", () => {
|
|
26
|
-
const store = new SimStore();
|
|
27
|
-
const chat = store.getChat("sim_default")!;
|
|
28
|
-
expect(chat.memberIds).toContain("bot");
|
|
29
|
-
expect(chat.memberIds).toContain("sim_user_001");
|
|
30
|
-
expect(chat.type).toBe("group");
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
// ---- 账户管理 ----
|
|
34
|
-
|
|
35
|
-
it("registerAccount 注册新用户", () => {
|
|
36
|
-
const store = new SimStore();
|
|
37
|
-
store.registerAccount({ id: "alice", kind: "user", name: "Alice" });
|
|
38
|
-
const a = store.getAccount("alice");
|
|
39
|
-
expect(a).toBeDefined();
|
|
40
|
-
expect(a!.name).toBe("Alice");
|
|
41
|
-
expect(a!.kind).toBe("user");
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it("registerAccount 重复 id 抛出错误", () => {
|
|
45
|
-
const store = new SimStore();
|
|
46
|
-
store.registerAccount({ id: "bob", kind: "user", name: "Bob" });
|
|
47
|
-
expect(() => store.registerAccount({ id: "bob", kind: "user", name: "Bob2" }))
|
|
48
|
-
.toThrow('Account "bob" already exists');
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
// ---- 群聊管理 ----
|
|
52
|
-
|
|
53
|
-
it("createGroupChat 创建群,bot 自动加入", () => {
|
|
54
|
-
const store = new SimStore();
|
|
55
|
-
store.registerAccount({ id: "alice", kind: "user", name: "Alice" });
|
|
56
|
-
const chat = store.createGroupChat("测试群", ["alice"]);
|
|
57
|
-
expect(chat.id).toMatch(/^sim_[0-9a-f]{8}$/);
|
|
58
|
-
expect(chat.name).toBe("测试群");
|
|
59
|
-
expect(chat.type).toBe("group");
|
|
60
|
-
expect(chat.memberIds).toContain("bot");
|
|
61
|
-
expect(chat.memberIds).toContain("alice");
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
it("createGroupChat emit chat_created 和 member_added 事件", () => {
|
|
65
|
-
const store = new SimStore();
|
|
66
|
-
store.registerAccount({ id: "alice", kind: "user", name: "Alice" });
|
|
67
|
-
|
|
68
|
-
let createdChat: SimChat | null = null;
|
|
69
|
-
let addedUserId = "";
|
|
70
|
-
store.on("chat_created", ({ chat }) => { createdChat = chat; });
|
|
71
|
-
store.on("member_added", ({ userId }) => { addedUserId = userId; });
|
|
72
|
-
|
|
73
|
-
store.createGroupChat("测试群", ["alice"]);
|
|
74
|
-
expect(createdChat).not.toBeNull();
|
|
75
|
-
expect(createdChat!.name).toBe("测试群");
|
|
76
|
-
expect(addedUserId).toBe("alice");
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
it("createP2pChat 创建私聊", () => {
|
|
80
|
-
const store = new SimStore();
|
|
81
|
-
store.registerAccount({ id: "alice", kind: "user", name: "Alice" });
|
|
82
|
-
const chat = store.createP2pChat("alice");
|
|
83
|
-
expect(chat.id).toBe("p2p_alice_bot");
|
|
84
|
-
expect(chat.type).toBe("p2p");
|
|
85
|
-
expect(chat.memberIds).toContain("bot");
|
|
86
|
-
expect(chat.memberIds).toContain("alice");
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
it("createP2pChat 重复调用返回同一个 chat", () => {
|
|
90
|
-
const store = new SimStore();
|
|
91
|
-
store.registerAccount({ id: "alice", kind: "user", name: "Alice" });
|
|
92
|
-
const c1 = store.createP2pChat("alice");
|
|
93
|
-
const c2 = store.createP2pChat("alice");
|
|
94
|
-
expect(c1.id).toBe(c2.id);
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
it("getChatsForUser 返回用户所在的所有会话", () => {
|
|
98
|
-
const store = new SimStore();
|
|
99
|
-
store.registerAccount({ id: "alice", kind: "user", name: "Alice" });
|
|
100
|
-
store.createP2pChat("alice");
|
|
101
|
-
store.createGroupChat("群1", ["alice"]);
|
|
102
|
-
store.createGroupChat("群2", ["alice"]);
|
|
103
|
-
|
|
104
|
-
const chats = store.getChatsForUser("alice");
|
|
105
|
-
expect(chats.length).toBeGreaterThanOrEqual(2);
|
|
106
|
-
expect(chats.some((c) => c.type === "p2p")).toBe(true);
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
it("addMember 添加成员并 emit 事件", () => {
|
|
110
|
-
const store = new SimStore();
|
|
111
|
-
store.registerAccount({ id: "alice", kind: "user", name: "Alice" });
|
|
112
|
-
const chat = store.createGroupChat("测试群", []);
|
|
113
|
-
|
|
114
|
-
let addedUserId = "";
|
|
115
|
-
store.on("member_added", ({ userId }) => { addedUserId = userId; });
|
|
116
|
-
|
|
117
|
-
store.addMember(chat.id, "alice");
|
|
118
|
-
expect(chat.memberIds).toContain("alice");
|
|
119
|
-
expect(addedUserId).toBe("alice");
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
it("updateChatInfo 更新已有群信息", () => {
|
|
123
|
-
const store = new SimStore();
|
|
124
|
-
store.registerAccount({ id: "alice", kind: "user", name: "Alice" });
|
|
125
|
-
const chat = store.createGroupChat("原群名", ["alice"]);
|
|
126
|
-
store.updateChatInfo(chat.id, "新群名", "Claude Code Session: abc123");
|
|
127
|
-
expect(chat.name).toBe("新群名");
|
|
128
|
-
expect(chat.description).toBe("Claude Code Session: abc123");
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
it("updateChatInfo 对不存在的群自动创建", () => {
|
|
132
|
-
const store = new SimStore();
|
|
133
|
-
store.updateChatInfo("sim_fake", "新群", "desc");
|
|
134
|
-
const chat = store.getChat("sim_fake");
|
|
135
|
-
expect(chat).toBeDefined();
|
|
136
|
-
expect(chat!.name).toBe("新群");
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
// ---- 消息管理 ----
|
|
140
|
-
|
|
141
|
-
it("recordMessage 记录用户消息到 chat 历史", () => {
|
|
142
|
-
const store = new SimStore();
|
|
143
|
-
store.registerAccount({ id: "alice", kind: "user", name: "Alice" });
|
|
144
|
-
const chat = store.createGroupChat("测试群", ["alice"]);
|
|
145
|
-
store.recordMessage(chat.id, "alice", "text", "你好");
|
|
146
|
-
expect(chat.messages.length).toBe(1);
|
|
147
|
-
expect(chat.messages[0].content).toBe("你好");
|
|
148
|
-
expect(chat.messages[0].senderId).toBe("alice");
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
it("recordMessage emit message 事件", () => {
|
|
152
|
-
const store = new SimStore();
|
|
153
|
-
store.registerAccount({ id: "alice", kind: "user", name: "Alice" });
|
|
154
|
-
const chat = store.createGroupChat("测试群", ["alice"]);
|
|
155
|
-
|
|
156
|
-
let emittedMsg: SimMessage | null = null;
|
|
157
|
-
let emittedChatId = "";
|
|
158
|
-
store.on("message", ({ chatId, message }) => {
|
|
159
|
-
emittedChatId = chatId;
|
|
160
|
-
emittedMsg = message;
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
store.recordMessage(chat.id, "alice", "text", "hello");
|
|
164
|
-
expect(emittedChatId).toBe(chat.id);
|
|
165
|
-
expect(emittedMsg!.content).toBe("hello");
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
it("recordMessage 非成员不能看到消息", () => {
|
|
169
|
-
const store = new SimStore();
|
|
170
|
-
store.registerAccount({ id: "alice", kind: "user", name: "Alice" });
|
|
171
|
-
store.registerAccount({ id: "bob", kind: "user", name: "Bob" });
|
|
172
|
-
const chat = store.createGroupChat("测试群", ["alice"]); // bob 不在群内
|
|
173
|
-
|
|
174
|
-
store.recordMessage(chat.id, "alice", "text", "hello");
|
|
175
|
-
const msgs = store.getMessages(chat.id, "bob"); // bob 请求消息
|
|
176
|
-
expect(msgs.length).toBe(0);
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
it("recordMessage 成员可以看到消息", () => {
|
|
180
|
-
const store = new SimStore();
|
|
181
|
-
store.registerAccount({ id: "alice", kind: "user", name: "Alice" });
|
|
182
|
-
const chat = store.createGroupChat("测试群", ["alice"]);
|
|
183
|
-
|
|
184
|
-
store.recordMessage(chat.id, "alice", "text", "hello");
|
|
185
|
-
const msgs = store.getMessages(chat.id, "alice");
|
|
186
|
-
expect(msgs.length).toBe(1);
|
|
187
|
-
expect(msgs[0].content).toBe("hello");
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
it("sendReply 即使 chat 不存在也能记录并 emit", () => {
|
|
191
|
-
const store = new SimStore();
|
|
192
|
-
let emitted = false;
|
|
193
|
-
store.on("message", () => { emitted = true; });
|
|
194
|
-
|
|
195
|
-
const msg = store.sendReply("unknown_chat", "text", "测试");
|
|
196
|
-
expect(msg.senderId).toBe("bot");
|
|
197
|
-
expect(emitted).toBe(true);
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
it("sendReply 追加到已有 chat 的消息历史", () => {
|
|
201
|
-
const store = new SimStore();
|
|
202
|
-
store.registerAccount({ id: "alice", kind: "user", name: "Alice" });
|
|
203
|
-
const chat = store.createGroupChat("测试群", ["alice"]);
|
|
204
|
-
|
|
205
|
-
store.sendReply(chat.id, "text", "bot reply");
|
|
206
|
-
expect(chat.messages.length).toBe(1);
|
|
207
|
-
expect(chat.messages[0].senderId).toBe("bot");
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
it("getMessages 对不存在的 chat 返回空数组", () => {
|
|
211
|
-
const store = new SimStore();
|
|
212
|
-
expect(store.getMessages("nonexistent", "alice")).toEqual([]);
|
|
213
|
-
});
|
|
1
|
+
import { describe, it, expect, afterAll } from "vitest";
|
|
2
|
+
import { unlink } from "node:fs/promises";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
|
|
6
|
+
import { SimStore, simStore, SIM_DEFAULT_CHAT_ID } from "../sim-store.ts";
|
|
7
|
+
import type { SimAccount, SimChat, SimMessage } from "../sim-store.ts";
|
|
8
|
+
|
|
9
|
+
const MESSAGES_FILE = join(homedir(), ".chatccc", "sim", "messages.jsonl");
|
|
10
|
+
|
|
11
|
+
describe("SimStore", () => {
|
|
12
|
+
afterAll(async () => {
|
|
13
|
+
try { await unlink(MESSAGES_FILE); } catch { /* ok */ }
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
// ---- 初始化 ----
|
|
17
|
+
|
|
18
|
+
it("默认初始化 bot + 默认用户 + 默认群", () => {
|
|
19
|
+
const store = new SimStore();
|
|
20
|
+
expect(store.getAccount("bot")).toBeDefined();
|
|
21
|
+
expect(store.getAccount("sim_user_001")).toBeDefined();
|
|
22
|
+
expect(store.getChat("sim_default")).toBeDefined();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it("默认群成员包含 bot 和 sim_user_001", () => {
|
|
26
|
+
const store = new SimStore();
|
|
27
|
+
const chat = store.getChat("sim_default")!;
|
|
28
|
+
expect(chat.memberIds).toContain("bot");
|
|
29
|
+
expect(chat.memberIds).toContain("sim_user_001");
|
|
30
|
+
expect(chat.type).toBe("group");
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// ---- 账户管理 ----
|
|
34
|
+
|
|
35
|
+
it("registerAccount 注册新用户", () => {
|
|
36
|
+
const store = new SimStore();
|
|
37
|
+
store.registerAccount({ id: "alice", kind: "user", name: "Alice" });
|
|
38
|
+
const a = store.getAccount("alice");
|
|
39
|
+
expect(a).toBeDefined();
|
|
40
|
+
expect(a!.name).toBe("Alice");
|
|
41
|
+
expect(a!.kind).toBe("user");
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("registerAccount 重复 id 抛出错误", () => {
|
|
45
|
+
const store = new SimStore();
|
|
46
|
+
store.registerAccount({ id: "bob", kind: "user", name: "Bob" });
|
|
47
|
+
expect(() => store.registerAccount({ id: "bob", kind: "user", name: "Bob2" }))
|
|
48
|
+
.toThrow('Account "bob" already exists');
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// ---- 群聊管理 ----
|
|
52
|
+
|
|
53
|
+
it("createGroupChat 创建群,bot 自动加入", () => {
|
|
54
|
+
const store = new SimStore();
|
|
55
|
+
store.registerAccount({ id: "alice", kind: "user", name: "Alice" });
|
|
56
|
+
const chat = store.createGroupChat("测试群", ["alice"]);
|
|
57
|
+
expect(chat.id).toMatch(/^sim_[0-9a-f]{8}$/);
|
|
58
|
+
expect(chat.name).toBe("测试群");
|
|
59
|
+
expect(chat.type).toBe("group");
|
|
60
|
+
expect(chat.memberIds).toContain("bot");
|
|
61
|
+
expect(chat.memberIds).toContain("alice");
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("createGroupChat emit chat_created 和 member_added 事件", () => {
|
|
65
|
+
const store = new SimStore();
|
|
66
|
+
store.registerAccount({ id: "alice", kind: "user", name: "Alice" });
|
|
67
|
+
|
|
68
|
+
let createdChat: SimChat | null = null;
|
|
69
|
+
let addedUserId = "";
|
|
70
|
+
store.on("chat_created", ({ chat }) => { createdChat = chat; });
|
|
71
|
+
store.on("member_added", ({ userId }) => { addedUserId = userId; });
|
|
72
|
+
|
|
73
|
+
store.createGroupChat("测试群", ["alice"]);
|
|
74
|
+
expect(createdChat).not.toBeNull();
|
|
75
|
+
expect(createdChat!.name).toBe("测试群");
|
|
76
|
+
expect(addedUserId).toBe("alice");
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it("createP2pChat 创建私聊", () => {
|
|
80
|
+
const store = new SimStore();
|
|
81
|
+
store.registerAccount({ id: "alice", kind: "user", name: "Alice" });
|
|
82
|
+
const chat = store.createP2pChat("alice");
|
|
83
|
+
expect(chat.id).toBe("p2p_alice_bot");
|
|
84
|
+
expect(chat.type).toBe("p2p");
|
|
85
|
+
expect(chat.memberIds).toContain("bot");
|
|
86
|
+
expect(chat.memberIds).toContain("alice");
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("createP2pChat 重复调用返回同一个 chat", () => {
|
|
90
|
+
const store = new SimStore();
|
|
91
|
+
store.registerAccount({ id: "alice", kind: "user", name: "Alice" });
|
|
92
|
+
const c1 = store.createP2pChat("alice");
|
|
93
|
+
const c2 = store.createP2pChat("alice");
|
|
94
|
+
expect(c1.id).toBe(c2.id);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("getChatsForUser 返回用户所在的所有会话", () => {
|
|
98
|
+
const store = new SimStore();
|
|
99
|
+
store.registerAccount({ id: "alice", kind: "user", name: "Alice" });
|
|
100
|
+
store.createP2pChat("alice");
|
|
101
|
+
store.createGroupChat("群1", ["alice"]);
|
|
102
|
+
store.createGroupChat("群2", ["alice"]);
|
|
103
|
+
|
|
104
|
+
const chats = store.getChatsForUser("alice");
|
|
105
|
+
expect(chats.length).toBeGreaterThanOrEqual(2);
|
|
106
|
+
expect(chats.some((c) => c.type === "p2p")).toBe(true);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it("addMember 添加成员并 emit 事件", () => {
|
|
110
|
+
const store = new SimStore();
|
|
111
|
+
store.registerAccount({ id: "alice", kind: "user", name: "Alice" });
|
|
112
|
+
const chat = store.createGroupChat("测试群", []);
|
|
113
|
+
|
|
114
|
+
let addedUserId = "";
|
|
115
|
+
store.on("member_added", ({ userId }) => { addedUserId = userId; });
|
|
116
|
+
|
|
117
|
+
store.addMember(chat.id, "alice");
|
|
118
|
+
expect(chat.memberIds).toContain("alice");
|
|
119
|
+
expect(addedUserId).toBe("alice");
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it("updateChatInfo 更新已有群信息", () => {
|
|
123
|
+
const store = new SimStore();
|
|
124
|
+
store.registerAccount({ id: "alice", kind: "user", name: "Alice" });
|
|
125
|
+
const chat = store.createGroupChat("原群名", ["alice"]);
|
|
126
|
+
store.updateChatInfo(chat.id, "新群名", "Claude Code Session: abc123");
|
|
127
|
+
expect(chat.name).toBe("新群名");
|
|
128
|
+
expect(chat.description).toBe("Claude Code Session: abc123");
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it("updateChatInfo 对不存在的群自动创建", () => {
|
|
132
|
+
const store = new SimStore();
|
|
133
|
+
store.updateChatInfo("sim_fake", "新群", "desc");
|
|
134
|
+
const chat = store.getChat("sim_fake");
|
|
135
|
+
expect(chat).toBeDefined();
|
|
136
|
+
expect(chat!.name).toBe("新群");
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
// ---- 消息管理 ----
|
|
140
|
+
|
|
141
|
+
it("recordMessage 记录用户消息到 chat 历史", () => {
|
|
142
|
+
const store = new SimStore();
|
|
143
|
+
store.registerAccount({ id: "alice", kind: "user", name: "Alice" });
|
|
144
|
+
const chat = store.createGroupChat("测试群", ["alice"]);
|
|
145
|
+
store.recordMessage(chat.id, "alice", "text", "你好");
|
|
146
|
+
expect(chat.messages.length).toBe(1);
|
|
147
|
+
expect(chat.messages[0].content).toBe("你好");
|
|
148
|
+
expect(chat.messages[0].senderId).toBe("alice");
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it("recordMessage emit message 事件", () => {
|
|
152
|
+
const store = new SimStore();
|
|
153
|
+
store.registerAccount({ id: "alice", kind: "user", name: "Alice" });
|
|
154
|
+
const chat = store.createGroupChat("测试群", ["alice"]);
|
|
155
|
+
|
|
156
|
+
let emittedMsg: SimMessage | null = null;
|
|
157
|
+
let emittedChatId = "";
|
|
158
|
+
store.on("message", ({ chatId, message }) => {
|
|
159
|
+
emittedChatId = chatId;
|
|
160
|
+
emittedMsg = message;
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
store.recordMessage(chat.id, "alice", "text", "hello");
|
|
164
|
+
expect(emittedChatId).toBe(chat.id);
|
|
165
|
+
expect(emittedMsg!.content).toBe("hello");
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it("recordMessage 非成员不能看到消息", () => {
|
|
169
|
+
const store = new SimStore();
|
|
170
|
+
store.registerAccount({ id: "alice", kind: "user", name: "Alice" });
|
|
171
|
+
store.registerAccount({ id: "bob", kind: "user", name: "Bob" });
|
|
172
|
+
const chat = store.createGroupChat("测试群", ["alice"]); // bob 不在群内
|
|
173
|
+
|
|
174
|
+
store.recordMessage(chat.id, "alice", "text", "hello");
|
|
175
|
+
const msgs = store.getMessages(chat.id, "bob"); // bob 请求消息
|
|
176
|
+
expect(msgs.length).toBe(0);
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it("recordMessage 成员可以看到消息", () => {
|
|
180
|
+
const store = new SimStore();
|
|
181
|
+
store.registerAccount({ id: "alice", kind: "user", name: "Alice" });
|
|
182
|
+
const chat = store.createGroupChat("测试群", ["alice"]);
|
|
183
|
+
|
|
184
|
+
store.recordMessage(chat.id, "alice", "text", "hello");
|
|
185
|
+
const msgs = store.getMessages(chat.id, "alice");
|
|
186
|
+
expect(msgs.length).toBe(1);
|
|
187
|
+
expect(msgs[0].content).toBe("hello");
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it("sendReply 即使 chat 不存在也能记录并 emit", () => {
|
|
191
|
+
const store = new SimStore();
|
|
192
|
+
let emitted = false;
|
|
193
|
+
store.on("message", () => { emitted = true; });
|
|
194
|
+
|
|
195
|
+
const msg = store.sendReply("unknown_chat", "text", "测试");
|
|
196
|
+
expect(msg.senderId).toBe("bot");
|
|
197
|
+
expect(emitted).toBe(true);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it("sendReply 追加到已有 chat 的消息历史", () => {
|
|
201
|
+
const store = new SimStore();
|
|
202
|
+
store.registerAccount({ id: "alice", kind: "user", name: "Alice" });
|
|
203
|
+
const chat = store.createGroupChat("测试群", ["alice"]);
|
|
204
|
+
|
|
205
|
+
store.sendReply(chat.id, "text", "bot reply");
|
|
206
|
+
expect(chat.messages.length).toBe(1);
|
|
207
|
+
expect(chat.messages[0].senderId).toBe("bot");
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it("getMessages 对不存在的 chat 返回空数组", () => {
|
|
211
|
+
const store = new SimStore();
|
|
212
|
+
expect(store.getMessages("nonexistent", "alice")).toEqual([]);
|
|
213
|
+
});
|
|
214
214
|
});
|