dsh-qqchat 0.2.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.
- package/LICENSE +21 -0
- package/README.en.md +276 -0
- package/README.md +211 -0
- package/client-src/plugin.cts +15 -0
- package/client-src/settings.cts +216 -0
- package/client-src/shared.cts +104 -0
- package/client-src/workspace.cts +164 -0
- package/cordis.patch.yml +7 -0
- package/docs/ARCHITECTURE.en.md +346 -0
- package/docs/ARCHITECTURE.md +411 -0
- package/docs/DEVELOPMENT.md +69 -0
- package/docs/MEDIA_AND_QUOTES.md +644 -0
- package/docs/MEMORY.md +99 -0
- package/docs/MEMORY_CONTEXT.md +254 -0
- package/docs/QUOTES.md +355 -0
- package/docs/README.md +22 -0
- package/docs/SECURITY.md +62 -0
- package/docs/STREAMING.md +347 -0
- package/docs/assets//346/211/253/347/240/201/351/223/276/346/216/245.jpg +0 -0
- package/docs/assets//347/276/244/350/201/212/347/225/214/351/235/242.jpg +0 -0
- package/docs/assets//350/256/260/345/277/206/347/263/273/347/273/237.jpg +0 -0
- package/docs/assets//350/256/276/347/275/256/347/225/214/351/235/242.jpg +0 -0
- package/docs/devlog.md +24 -0
- package/lib/client.js +433 -0
- package/lib/commands/dispatch.d.ts +16 -0
- package/lib/commands/dispatch.js +48 -0
- package/lib/config.d.ts +3 -0
- package/lib/config.js +63 -0
- package/lib/gateway/api.d.ts +30 -0
- package/lib/gateway/api.js +202 -0
- package/lib/gateway/auth.d.ts +35 -0
- package/lib/gateway/auth.js +80 -0
- package/lib/gateway/crypto.d.ts +2 -0
- package/lib/gateway/crypto.js +17 -0
- package/lib/gateway/gateway.d.ts +32 -0
- package/lib/gateway/gateway.js +219 -0
- package/lib/gateway/normalize.d.ts +6 -0
- package/lib/gateway/normalize.js +248 -0
- package/lib/index.d.ts +14 -0
- package/lib/index.js +35 -0
- package/lib/media/image-tool.d.ts +4 -0
- package/lib/media/image-tool.js +62 -0
- package/lib/media/media-tools.d.ts +3 -0
- package/lib/media/media-tools.js +68 -0
- package/lib/media/store.d.ts +14 -0
- package/lib/media/store.js +176 -0
- package/lib/session/agent-bridge.d.ts +56 -0
- package/lib/session/agent-bridge.js +613 -0
- package/lib/session/memory-snapshot.d.ts +23 -0
- package/lib/session/memory-snapshot.js +27 -0
- package/lib/session/runtime.d.ts +41 -0
- package/lib/session/runtime.js +395 -0
- package/lib/shared/augmentations.d.ts +40 -0
- package/lib/shared/augmentations.js +1 -0
- package/lib/shared/logging.d.ts +14 -0
- package/lib/shared/logging.js +41 -0
- package/lib/storage/db.d.ts +82 -0
- package/lib/storage/db.js +669 -0
- package/lib/storage/memory.d.ts +50 -0
- package/lib/storage/memory.js +566 -0
- package/lib/transport/rpc.d.ts +18 -0
- package/lib/transport/rpc.js +318 -0
- package/lib/types.d.ts +416 -0
- package/lib/types.js +1 -0
- package/package.json +115 -0
- package/scripts/wrap-client.mjs +20 -0
- package/src/commands/dispatch.ts +75 -0
- package/src/config.ts +70 -0
- package/src/gateway/api.ts +260 -0
- package/src/gateway/auth.ts +99 -0
- package/src/gateway/crypto.ts +16 -0
- package/src/gateway/gateway.ts +207 -0
- package/src/gateway/normalize.ts +236 -0
- package/src/index.ts +46 -0
- package/src/media/image-tool.ts +62 -0
- package/src/media/media-tools.ts +66 -0
- package/src/media/store.ts +157 -0
- package/src/session/agent-bridge.ts +624 -0
- package/src/session/memory-snapshot.ts +41 -0
- package/src/session/runtime.ts +368 -0
- package/src/shared/augmentations.ts +45 -0
- package/src/shared/logging.ts +36 -0
- package/src/storage/db.ts +760 -0
- package/src/storage/memory.ts +581 -0
- package/src/transport/rpc.ts +316 -0
- package/src/types.ts +456 -0
- package/tsconfig.build.json +12 -0
- package/tsconfig.client.json +14 -0
- package/tsconfig.json +23 -0
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
# dsh-qqchat 架构
|
|
2
|
+
|
|
3
|
+
[English](./ARCHITECTURE.en.md)
|
|
4
|
+
|
|
5
|
+
## 核心边界
|
|
6
|
+
|
|
7
|
+
`dsh-qqchat` 是独立的 DSH out-of-tree 插件,不 fork DeepSeek Harness。
|
|
8
|
+
|
|
9
|
+
```text
|
|
10
|
+
dsh-qqchat
|
|
11
|
+
QQ protocol / auth / identity
|
|
12
|
+
QQ real history
|
|
13
|
+
receive policy
|
|
14
|
+
group + member memory
|
|
15
|
+
tool authority
|
|
16
|
+
proactive sending
|
|
17
|
+
QQ-specific Client presentation
|
|
18
|
+
|
|
19
|
+
DSH
|
|
20
|
+
Agent loop
|
|
21
|
+
Session lifecycle
|
|
22
|
+
model routing
|
|
23
|
+
tools
|
|
24
|
+
Session list
|
|
25
|
+
Conversation shell
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
QQ Chat 不维护第二套 AgentLoop,也不维护第二套聊天导航。
|
|
29
|
+
|
|
30
|
+
## Session 是主导航单位
|
|
31
|
+
|
|
32
|
+
每个 QQ peer 映射一个正常 DSH Session:
|
|
33
|
+
|
|
34
|
+
```text
|
|
35
|
+
group -> groups.dsh_session_id
|
|
36
|
+
c2c -> members.dsh_session_id
|
|
37
|
+
|
|
38
|
+
sessionId = qqchat-<uuid>
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
标题通过 DSH `sessionTitle` 写入:
|
|
42
|
+
|
|
43
|
+
```text
|
|
44
|
+
QQ群 · <群名>
|
|
45
|
+
QQ私聊 · <昵称>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Client 不再注册 `sidebar.footer.action` 会话选择器。QQ Session 直接由 DSH 自己的 Session/Workspace Browser 展示和打开。
|
|
49
|
+
|
|
50
|
+
DSH 用 `turn/start` 判断一个 Session 是否仍为 blank。只有静默记录的新 QQ peer 没有正常 Agent turn,因此插件创建 Session 后提交一次 `qq-chat-bootstrap` wake,并在 `agent/pre-step` 立即 reject。结果是:
|
|
51
|
+
|
|
52
|
+
- 有 durable turn boundary;
|
|
53
|
+
- Session 能进入 DSH 正常列表;
|
|
54
|
+
- 没有 model step;
|
|
55
|
+
- 不调用 LLM;
|
|
56
|
+
- 不发送 QQ 消息;
|
|
57
|
+
- bootstrap 不进入模型 history。
|
|
58
|
+
|
|
59
|
+
## Settings 边界
|
|
60
|
+
|
|
61
|
+
`settings.section: qqchat` 只放控制面:
|
|
62
|
+
|
|
63
|
+
```text
|
|
64
|
+
扫码 / 连接状态
|
|
65
|
+
自动回应 / @回复 / 静默记录
|
|
66
|
+
群聊消息兼容格式
|
|
67
|
+
私聊消息兼容格式
|
|
68
|
+
群成员可用工具
|
|
69
|
+
Owner stable ID
|
|
70
|
+
查看日志
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Settings 不包含群列表、私聊列表、聊天记录或记忆主界面。
|
|
74
|
+
|
|
75
|
+
## Conversation 边界
|
|
76
|
+
|
|
77
|
+
QQ Session 使用 DSH 主 Conversation。
|
|
78
|
+
|
|
79
|
+
```text
|
|
80
|
+
conversation.chat.node
|
|
81
|
+
qqchat-message # 仅静默/未触发 Agent 的 QQ transcript
|
|
82
|
+
|
|
83
|
+
conversation.composer
|
|
84
|
+
QQ Session composer # 主动发 QQ,不触发本地 Agent
|
|
85
|
+
|
|
86
|
+
conversation.session.header.utilities
|
|
87
|
+
QQ 记忆
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### 触发 Agent 的 QQ 消息
|
|
91
|
+
|
|
92
|
+
接收策略决定需要回复时,消息直接走 DSH 原生 `user/message`:
|
|
93
|
+
|
|
94
|
+
```text
|
|
95
|
+
QQ inbound
|
|
96
|
+
-> SQLite
|
|
97
|
+
-> context snapshot
|
|
98
|
+
-> Agent.followup()
|
|
99
|
+
-> user/message
|
|
100
|
+
-> DSH Agent loop
|
|
101
|
+
-> assistant/tool events
|
|
102
|
+
-> QQ API
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Source 的 `kind` 保持 `user`,同时附带 QQ metadata:
|
|
106
|
+
|
|
107
|
+
```text
|
|
108
|
+
channel=qq
|
|
109
|
+
botId
|
|
110
|
+
chatType
|
|
111
|
+
chatId
|
|
112
|
+
senderId
|
|
113
|
+
senderName
|
|
114
|
+
messageId
|
|
115
|
+
mentioned
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
因此 DSH Conversation 把它当普通 user turn;插件不再为同一条消息额外 append `qqchat/message`,避免双份显示。
|
|
119
|
+
|
|
120
|
+
### 不触发 Agent 的 QQ 消息
|
|
121
|
+
|
|
122
|
+
`@回复` 下未 @Bot 的消息、以及 `静默记录` 下的群消息:
|
|
123
|
+
|
|
124
|
+
```text
|
|
125
|
+
session.append('qqchat/message', ...)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
`qqchat/message` 是 log-only 自定义 Session event:
|
|
129
|
+
|
|
130
|
+
- Client 可渲染 QQ 群友气泡;
|
|
131
|
+
- 不属于 DSH model surface;
|
|
132
|
+
- 不会唤醒 Agent;
|
|
133
|
+
- 不会调用 LLM。
|
|
134
|
+
|
|
135
|
+
插件不再从 SQLite 重放整段历史到 DSH Session。DSH Session 保存它实际经历过的 display/Agent events,完整 QQ 世界历史始终由 SQLite 负责。
|
|
136
|
+
|
|
137
|
+
## Host / Client
|
|
138
|
+
|
|
139
|
+
```text
|
|
140
|
+
DSH Web Client
|
|
141
|
+
│
|
|
142
|
+
│ Connection RPC /qqchat
|
|
143
|
+
▼
|
|
144
|
+
┌──────────────────────────────────────┐
|
|
145
|
+
│ dsh-qqchat Host │
|
|
146
|
+
│ │
|
|
147
|
+
│ QQBindService │
|
|
148
|
+
│ QQGateway ── QQApiClient │
|
|
149
|
+
│ │ │
|
|
150
|
+
│ ▼ │
|
|
151
|
+
│ QQChatRuntime │
|
|
152
|
+
│ │ │ │
|
|
153
|
+
│ │ ├── QQChatDatabase │
|
|
154
|
+
│ │ ├── MemoryEngine │
|
|
155
|
+
│ │ └── QQChatLogger │
|
|
156
|
+
│ ▼ │
|
|
157
|
+
│ DshQQBridge │
|
|
158
|
+
└───┬──────────────────────────────────┘
|
|
159
|
+
▼
|
|
160
|
+
DSH Agent / Session / Tools
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
QQ credential、Token、扫码 AES 临时 key 都只存在 Host。
|
|
164
|
+
|
|
165
|
+
## 三个数据面
|
|
166
|
+
|
|
167
|
+
### 1. QQ 真实数据面
|
|
168
|
+
|
|
169
|
+
SQLite 是 QQ 世界事实来源:
|
|
170
|
+
|
|
171
|
+
```text
|
|
172
|
+
accounts
|
|
173
|
+
groups
|
|
174
|
+
members
|
|
175
|
+
group_members
|
|
176
|
+
messages
|
|
177
|
+
memory_documents
|
|
178
|
+
reflection_state
|
|
179
|
+
plugin_settings
|
|
180
|
+
outbox
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### 2. DSH Session / UI 数据面
|
|
184
|
+
|
|
185
|
+
记录:
|
|
186
|
+
|
|
187
|
+
- Agent 真正参与的 turn;
|
|
188
|
+
- assistant/tool events;
|
|
189
|
+
- 不唤醒 Agent 的 log-only QQ transcript;
|
|
190
|
+
- Session title 和 turn boundary。
|
|
191
|
+
|
|
192
|
+
### 3. Model surface
|
|
193
|
+
|
|
194
|
+
模型只看到 DSH 正常 surface 以及插件明确注入的 context snapshot。QQChat 的
|
|
195
|
+
记忆快照使用 DSH 官方 `@deepseek-ai/dsh-system-prompt` runtime-context 来源,
|
|
196
|
+
由 DSH 的 projection 机制替换旧快照,避免每轮重复追加完整记忆消息。
|
|
197
|
+
|
|
198
|
+
完整群聊不会因为存在 SQLite 或 QQ UI transcript 就自动进入模型 history。
|
|
199
|
+
|
|
200
|
+
## 入站状态机
|
|
201
|
+
|
|
202
|
+
```text
|
|
203
|
+
QQ dispatch
|
|
204
|
+
↓
|
|
205
|
+
normalize stable identity
|
|
206
|
+
↓
|
|
207
|
+
upsert member/group
|
|
208
|
+
↓
|
|
209
|
+
insert SQLite message
|
|
210
|
+
↓
|
|
211
|
+
receive mode
|
|
212
|
+
├─ silent
|
|
213
|
+
│ └─ qqchat/message -> stop
|
|
214
|
+
│
|
|
215
|
+
├─ mention + not @
|
|
216
|
+
│ └─ qqchat/message -> stop
|
|
217
|
+
│
|
|
218
|
+
└─ auto / mentioned / c2c
|
|
219
|
+
├─ assemble memory/context
|
|
220
|
+
├─ Agent.followup(user message)
|
|
221
|
+
├─ DSH tools/model loop
|
|
222
|
+
└─ QQ outbound
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
三种模式都会留下真实 QQ 历史并参与记忆活动;区别只是是否进入 Agent turn。
|
|
226
|
+
|
|
227
|
+
## Identity
|
|
228
|
+
|
|
229
|
+
稳定身份优先级:
|
|
230
|
+
|
|
231
|
+
```text
|
|
232
|
+
author.user_openid
|
|
233
|
+
|| author.member_openid
|
|
234
|
+
|| author.id
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
原则:
|
|
238
|
+
|
|
239
|
+
```text
|
|
240
|
+
senderId -> 身份 / 权限 / 记忆主键
|
|
241
|
+
senderName -> 仅展示
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
不根据昵称推断身份。
|
|
245
|
+
|
|
246
|
+
## Agent context
|
|
247
|
+
|
|
248
|
+
群聊每次 Agent turn 前从 SQLite 重新装配:
|
|
249
|
+
|
|
250
|
+
```text
|
|
251
|
+
recent group history
|
|
252
|
+
+ group profile
|
|
253
|
+
+ group summary
|
|
254
|
+
+ group memory
|
|
255
|
+
+ group daily
|
|
256
|
+
+ current member profile
|
|
257
|
+
+ current member pattern
|
|
258
|
+
+ current member summary
|
|
259
|
+
+ stable sender/group metadata
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
当前 QQ 消息本身以正常 user prompt 进入 turn;可靠身份信息则由 source metadata 和 context snapshot 提供。私聊快照包含 member 的 profile、pattern、summary、daily 和 memory;群聊快照包含群级文档、当前成员文档和近期群聊记录。
|
|
263
|
+
|
|
264
|
+
## 工具权限
|
|
265
|
+
|
|
266
|
+
使用 DSH 官方:
|
|
267
|
+
|
|
268
|
+
```text
|
|
269
|
+
tools/pre-execute
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
当前 QQ Agent turn 临时记录:
|
|
273
|
+
|
|
274
|
+
```text
|
|
275
|
+
sessionId -> { chatType, senderId }
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
规则:
|
|
279
|
+
|
|
280
|
+
```text
|
|
281
|
+
非 QQ group turn -> next()
|
|
282
|
+
groupMembersCanUseTools == true -> next()
|
|
283
|
+
senderId == ownerUserId -> next()
|
|
284
|
+
其他 -> deny
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
不修改 Tool Runtime 或 AgentLoop。
|
|
288
|
+
|
|
289
|
+
## Memory scope
|
|
290
|
+
|
|
291
|
+
### Group
|
|
292
|
+
|
|
293
|
+
```text
|
|
294
|
+
profile
|
|
295
|
+
summary
|
|
296
|
+
daily
|
|
297
|
+
memory
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### Member
|
|
301
|
+
|
|
302
|
+
```text
|
|
303
|
+
profile
|
|
304
|
+
pattern
|
|
305
|
+
summary
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
Group scope 不跨群;同一 Bot 下的 Member scope 可以跨群连续。
|
|
309
|
+
|
|
310
|
+
反思以 idle debounce / batch threshold 触发,并使用 stable sender ID 做归属。
|
|
311
|
+
|
|
312
|
+
## 记忆 UI
|
|
313
|
+
|
|
314
|
+
QQ Session 顶部 `QQ 记忆`:
|
|
315
|
+
|
|
316
|
+
群聊:
|
|
317
|
+
|
|
318
|
+
```text
|
|
319
|
+
group profile / summary / memory / daily
|
|
320
|
+
member list
|
|
321
|
+
-> 点击成员
|
|
322
|
+
-> member profile / pattern / summary / memory
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
私聊:
|
|
326
|
+
|
|
327
|
+
```text
|
|
328
|
+
member profile / pattern / summary
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
私聊 `daily` 和 `memory` 仍属于 member scope 的持久化文档,参与反思和压缩,但当前 UI 尚未单独展示。
|
|
332
|
+
|
|
333
|
+
## 主动发送
|
|
334
|
+
|
|
335
|
+
QQ Session composer 调用:
|
|
336
|
+
|
|
337
|
+
```text
|
|
338
|
+
chat/send
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
Host:
|
|
342
|
+
|
|
343
|
+
```text
|
|
344
|
+
group -> /v2/groups/.../messages
|
|
345
|
+
c2c -> /v2/users/.../messages
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
主动发送直接进 QQ,不再作为本地 Agent prompt。
|
|
349
|
+
|
|
350
|
+
`outbox` 独立于 Session live 生命周期,留给定时/主动任务。
|
|
351
|
+
|
|
352
|
+
## RPC
|
|
353
|
+
|
|
354
|
+
Host 注册 loopback RPC:
|
|
355
|
+
|
|
356
|
+
```text
|
|
357
|
+
/qqchat
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
主要 endpoints:
|
|
361
|
+
|
|
362
|
+
```text
|
|
363
|
+
status
|
|
364
|
+
auth/start
|
|
365
|
+
auth/poll
|
|
366
|
+
settings/get
|
|
367
|
+
settings/update
|
|
368
|
+
logs/list
|
|
369
|
+
chat/send
|
|
370
|
+
chat/info
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
旧的 `chats/list` / `chat/ensure` / `group/*` 仍可作为兼容 API,但当前主导航不再依赖它们。
|
|
374
|
+
|
|
375
|
+
## SQLite 与 DSH persistence 的关系
|
|
376
|
+
|
|
377
|
+
```text
|
|
378
|
+
qqchat.sqlite
|
|
379
|
+
QQ 真实历史 / identity / memory / settings / outbox
|
|
380
|
+
|
|
381
|
+
DSH Session persistence
|
|
382
|
+
Agent turns / model output / tools / DSH transcript
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
二者互不替代。
|
|
386
|
+
|
|
387
|
+
## TypeScript 构建
|
|
388
|
+
|
|
389
|
+
```text
|
|
390
|
+
src/
|
|
391
|
+
index.ts / config.ts / types.ts
|
|
392
|
+
commands/ DSH 原生命令的 QQ 分发适配
|
|
393
|
+
gateway/ QQ API、授权、Gateway、消息解析
|
|
394
|
+
session/ Agent bridge、Session runtime
|
|
395
|
+
transport/ DSH RPC
|
|
396
|
+
storage/ SQLite、记忆
|
|
397
|
+
shared/ 日志、DSH 类型扩展
|
|
398
|
+
client-src/*.cts
|
|
399
|
+
tests/*.test.ts
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
Host 使用 `tsc`;Client 编译到临时 CJS 后由 `scripts/wrap-client.mjs` 包装成 DSH Client factory。
|
|
403
|
+
|
|
404
|
+
`lib/` 是生成物,不作为源码真相。
|
|
405
|
+
|
|
406
|
+
## 开发与安全文档
|
|
407
|
+
|
|
408
|
+
- [开发与验证](DEVELOPMENT.md):安装、构建、测试、启动和浏览器验证。
|
|
409
|
+
- [记忆系统](MEMORY.md):scope、daily、反思和压缩契约。
|
|
410
|
+
- [安全与数据边界](SECURITY.md):凭据、身份、权限、日志和隔离。
|
|
411
|
+
- [开发日志](devlog.md):具体排查和设计决策。
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# 开发与验证
|
|
2
|
+
|
|
3
|
+
## 易读概述
|
|
4
|
+
|
|
5
|
+
QQChat 是 TypeScript 插件,Host 和 Client 一起构建。日常开发不需要单独运行一套 QQChat Web;插件应加载到 DSH Web 中验证。
|
|
6
|
+
|
|
7
|
+
## 环境要求
|
|
8
|
+
|
|
9
|
+
- Node.js `^22.19.0 || >=24.0.0`
|
|
10
|
+
- 可用的 DSH workspace
|
|
11
|
+
- 需要真实网关验证时,准备 QQ 官方 Bot 凭据;凭据只放在本地 Host 配置中
|
|
12
|
+
|
|
13
|
+
仓库当前不提交 `package-lock.json`,使用 `npm install` 安装依赖。
|
|
14
|
+
|
|
15
|
+
## 本地安装与检查
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install
|
|
19
|
+
npm run typecheck
|
|
20
|
+
npm test
|
|
21
|
+
npm run build
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
完整检查:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm run check
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
构建步骤:
|
|
31
|
+
|
|
32
|
+
```text
|
|
33
|
+
src/*.ts -> lib/*.js Host
|
|
34
|
+
client-src/*.cts -> 临时 CJS Client
|
|
35
|
+
临时 CJS -> lib/client.js DSH ModuleLoader factory
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
`lib/` 和临时 Client 构建目录是生成物,不是源码真相。
|
|
39
|
+
|
|
40
|
+
## 启动 DSH Web
|
|
41
|
+
|
|
42
|
+
在 DSH 仓库中:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pnpm dsh --profile qqchat --no-open --port 3080
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
打开 `http://127.0.0.1:3080`,进入设置中的 QQ Chat,检查:
|
|
49
|
+
|
|
50
|
+
1. 设置页面宽度、换行和弹窗滚动。
|
|
51
|
+
2. 群聊接收的三个按钮状态。
|
|
52
|
+
3. 群聊/私聊消息格式是否独立保存。
|
|
53
|
+
4. 消息发送人的用户名、@用户名和引用显示。
|
|
54
|
+
5. 记忆弹窗、日志弹窗在长内容下是否只在内部滚动。
|
|
55
|
+
|
|
56
|
+
修改 Client 后必须重新执行 `npm run build`,再重启 DSH;仅刷新浏览器不能保证 Host 已加载新的 `lib/client.js`。
|
|
57
|
+
|
|
58
|
+
## 测试约定
|
|
59
|
+
|
|
60
|
+
- 纯逻辑变化补充 `tests/*.test.ts` 回归测试。
|
|
61
|
+
- 测试名称说明触发路径和关键结果。
|
|
62
|
+
- 不通过删除断言、`skip` 或放宽校验来恢复绿色。
|
|
63
|
+
- 涉及真实 QQ Gateway、扫码、Session 恢复或 DSH Web 布局的变化,除了单测,还要做真实环境验证。
|
|
64
|
+
|
|
65
|
+
## Git 约定
|
|
66
|
+
|
|
67
|
+
- 提交前运行 `git diff --check`。
|
|
68
|
+
- 不提交 `qqchat.sqlite`、日志、截图、凭据和临时构建目录。
|
|
69
|
+
- 不使用 force push;需要同步远端时保留已有历史。
|