@zaofan/dsh-qqbot 0.6.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.md +308 -0
- package/README_EN.md +273 -0
- package/client/qqbot-settings.js +1463 -0
- package/cordis.patch.yml +36 -0
- package/dist/api/group-admin.d.ts +112 -0
- package/dist/api/group-admin.d.ts.map +1 -0
- package/dist/api/group-admin.js +179 -0
- package/dist/api/group-admin.js.map +1 -0
- package/dist/channel-tools.d.ts +14 -0
- package/dist/channel-tools.d.ts.map +1 -0
- package/dist/channel-tools.js +880 -0
- package/dist/channel-tools.js.map +1 -0
- package/dist/commands/help.d.ts +11 -0
- package/dist/commands/help.d.ts.map +1 -0
- package/dist/commands/help.js +21 -0
- package/dist/commands/help.js.map +1 -0
- package/dist/commands/index.d.ts +13 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +29 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/misc.d.ts +14 -0
- package/dist/commands/misc.d.ts.map +1 -0
- package/dist/commands/misc.js +39 -0
- package/dist/commands/misc.js.map +1 -0
- package/dist/commands/model.d.ts +7 -0
- package/dist/commands/model.d.ts.map +1 -0
- package/dist/commands/model.js +58 -0
- package/dist/commands/model.js.map +1 -0
- package/dist/commands/session.d.ts +10 -0
- package/dist/commands/session.d.ts.map +1 -0
- package/dist/commands/session.js +26 -0
- package/dist/commands/session.js.map +1 -0
- package/dist/commands/status.d.ts +8 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +24 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/types.d.ts +12 -0
- package/dist/commands/types.d.ts.map +1 -0
- package/dist/commands/types.js +2 -0
- package/dist/commands/types.js.map +1 -0
- package/dist/config.d.ts +205 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +203 -0
- package/dist/config.js.map +1 -0
- package/dist/features/chat-ledger.d.ts +53 -0
- package/dist/features/chat-ledger.d.ts.map +1 -0
- package/dist/features/chat-ledger.js +185 -0
- package/dist/features/chat-ledger.js.map +1 -0
- package/dist/features/face-tags.d.ts +17 -0
- package/dist/features/face-tags.d.ts.map +1 -0
- package/dist/features/face-tags.js +79 -0
- package/dist/features/face-tags.js.map +1 -0
- package/dist/features/group-join-request.d.ts +65 -0
- package/dist/features/group-join-request.d.ts.map +1 -0
- package/dist/features/group-join-request.js +190 -0
- package/dist/features/group-join-request.js.map +1 -0
- package/dist/features/history-store.d.ts +8 -0
- package/dist/features/history-store.d.ts.map +1 -0
- package/dist/features/history-store.js +24 -0
- package/dist/features/history-store.js.map +1 -0
- package/dist/features/qq-approval.d.ts +78 -0
- package/dist/features/qq-approval.d.ts.map +1 -0
- package/dist/features/qq-approval.js +165 -0
- package/dist/features/qq-approval.js.map +1 -0
- package/dist/features/schedule-store.d.ts +62 -0
- package/dist/features/schedule-store.d.ts.map +1 -0
- package/dist/features/schedule-store.js +253 -0
- package/dist/features/schedule-store.js.map +1 -0
- package/dist/features/scheduler.d.ts +9 -0
- package/dist/features/scheduler.d.ts.map +1 -0
- package/dist/features/scheduler.js +146 -0
- package/dist/features/scheduler.js.map +1 -0
- package/dist/features/sticker-gate.d.ts +90 -0
- package/dist/features/sticker-gate.d.ts.map +1 -0
- package/dist/features/sticker-gate.js +391 -0
- package/dist/features/sticker-gate.js.map +1 -0
- package/dist/features/sticker-store.d.ts +158 -0
- package/dist/features/sticker-store.d.ts.map +1 -0
- package/dist/features/sticker-store.js +676 -0
- package/dist/features/sticker-store.js.map +1 -0
- package/dist/features/sticker-tagger.d.ts +10 -0
- package/dist/features/sticker-tagger.d.ts.map +1 -0
- package/dist/features/sticker-tagger.js +139 -0
- package/dist/features/sticker-tagger.js.map +1 -0
- package/dist/gateway/bootstrap.d.ts +12 -0
- package/dist/gateway/bootstrap.d.ts.map +1 -0
- package/dist/gateway/bootstrap.js +346 -0
- package/dist/gateway/bootstrap.js.map +1 -0
- package/dist/gateway/debounce.d.ts +40 -0
- package/dist/gateway/debounce.d.ts.map +1 -0
- package/dist/gateway/debounce.js +262 -0
- package/dist/gateway/debounce.js.map +1 -0
- package/dist/gateway/index.d.ts +3 -0
- package/dist/gateway/index.d.ts.map +1 -0
- package/dist/gateway/index.js +3 -0
- package/dist/gateway/index.js.map +1 -0
- package/dist/gateway/middleware-setup.d.ts +12 -0
- package/dist/gateway/middleware-setup.d.ts.map +1 -0
- package/dist/gateway/middleware-setup.js +156 -0
- package/dist/gateway/middleware-setup.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +187 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware/attachment.d.ts +11 -0
- package/dist/middleware/attachment.d.ts.map +1 -0
- package/dist/middleware/attachment.js +17 -0
- package/dist/middleware/attachment.js.map +1 -0
- package/dist/middleware/media-history.d.ts +30 -0
- package/dist/middleware/media-history.d.ts.map +1 -0
- package/dist/middleware/media-history.js +54 -0
- package/dist/middleware/media-history.js.map +1 -0
- package/dist/middleware/sticker-capture.d.ts +17 -0
- package/dist/middleware/sticker-capture.d.ts.map +1 -0
- package/dist/middleware/sticker-capture.js +97 -0
- package/dist/middleware/sticker-capture.js.map +1 -0
- package/dist/model/index.d.ts +10 -0
- package/dist/model/index.d.ts.map +1 -0
- package/dist/model/index.js +9 -0
- package/dist/model/index.js.map +1 -0
- package/dist/model/model-resolver.d.ts +88 -0
- package/dist/model/model-resolver.d.ts.map +1 -0
- package/dist/model/model-resolver.js +151 -0
- package/dist/model/model-resolver.js.map +1 -0
- package/dist/model/prefs-store.d.ts +24 -0
- package/dist/model/prefs-store.d.ts.map +1 -0
- package/dist/model/prefs-store.js +126 -0
- package/dist/model/prefs-store.js.map +1 -0
- package/dist/model/settings-reader.d.ts +19 -0
- package/dist/model/settings-reader.d.ts.map +1 -0
- package/dist/model/settings-reader.js +76 -0
- package/dist/model/settings-reader.js.map +1 -0
- package/dist/model/types.d.ts +15 -0
- package/dist/model/types.d.ts.map +1 -0
- package/dist/model/types.js +5 -0
- package/dist/model/types.js.map +1 -0
- package/dist/session/idle-evictor.d.ts +18 -0
- package/dist/session/idle-evictor.d.ts.map +1 -0
- package/dist/session/idle-evictor.js +31 -0
- package/dist/session/idle-evictor.js.map +1 -0
- package/dist/session/index.d.ts +9 -0
- package/dist/session/index.d.ts.map +1 -0
- package/dist/session/index.js +8 -0
- package/dist/session/index.js.map +1 -0
- package/dist/session/session-manager.d.ts +97 -0
- package/dist/session/session-manager.d.ts.map +1 -0
- package/dist/session/session-manager.js +624 -0
- package/dist/session/session-manager.js.map +1 -0
- package/dist/session/types.d.ts +130 -0
- package/dist/session/types.d.ts.map +1 -0
- package/dist/session/types.js +2 -0
- package/dist/session/types.js.map +1 -0
- package/dist/session/workspace-attach.d.ts +22 -0
- package/dist/session/workspace-attach.d.ts.map +1 -0
- package/dist/session/workspace-attach.js +21 -0
- package/dist/session/workspace-attach.js.map +1 -0
- package/dist/setup.d.ts +25 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +198 -0
- package/dist/setup.js.map +1 -0
- package/dist/shared/index.d.ts +7 -0
- package/dist/shared/index.d.ts.map +1 -0
- package/dist/shared/index.js +7 -0
- package/dist/shared/index.js.map +1 -0
- package/dist/shared/scope.d.ts +14 -0
- package/dist/shared/scope.d.ts.map +1 -0
- package/dist/shared/scope.js +12 -0
- package/dist/shared/scope.js.map +1 -0
- package/dist/shared/send-helper.d.ts +11 -0
- package/dist/shared/send-helper.d.ts.map +1 -0
- package/dist/shared/send-helper.js +13 -0
- package/dist/shared/send-helper.js.map +1 -0
- package/dist/shared/utils.d.ts +28 -0
- package/dist/shared/utils.d.ts.map +1 -0
- package/dist/shared/utils.js +143 -0
- package/dist/shared/utils.js.map +1 -0
- package/dist/transport/attachment.d.ts +18 -0
- package/dist/transport/attachment.d.ts.map +1 -0
- package/dist/transport/attachment.js +106 -0
- package/dist/transport/attachment.js.map +1 -0
- package/dist/transport/chunker.d.ts +14 -0
- package/dist/transport/chunker.d.ts.map +1 -0
- package/dist/transport/chunker.js +78 -0
- package/dist/transport/chunker.js.map +1 -0
- package/dist/transport/events.d.ts +80 -0
- package/dist/transport/events.d.ts.map +1 -0
- package/dist/transport/events.js +62 -0
- package/dist/transport/events.js.map +1 -0
- package/dist/transport/inbound.d.ts +8 -0
- package/dist/transport/inbound.d.ts.map +1 -0
- package/dist/transport/inbound.js +292 -0
- package/dist/transport/inbound.js.map +1 -0
- package/dist/transport/index.d.ts +10 -0
- package/dist/transport/index.d.ts.map +1 -0
- package/dist/transport/index.js +10 -0
- package/dist/transport/index.js.map +1 -0
- package/dist/transport/inject-rules.d.ts +24 -0
- package/dist/transport/inject-rules.d.ts.map +1 -0
- package/dist/transport/inject-rules.js +72 -0
- package/dist/transport/inject-rules.js.map +1 -0
- package/dist/transport/outbound-buffer.d.ts +56 -0
- package/dist/transport/outbound-buffer.d.ts.map +1 -0
- package/dist/transport/outbound-buffer.js +131 -0
- package/dist/transport/outbound-buffer.js.map +1 -0
- package/dist/transport/outbound.d.ts +30 -0
- package/dist/transport/outbound.d.ts.map +1 -0
- package/dist/transport/outbound.js +139 -0
- package/dist/transport/outbound.js.map +1 -0
- package/dist/transport/rich-media.d.ts +41 -0
- package/dist/transport/rich-media.d.ts.map +1 -0
- package/dist/transport/rich-media.js +104 -0
- package/dist/transport/rich-media.js.map +1 -0
- package/dist/transport/streaming-writer.d.ts +47 -0
- package/dist/transport/streaming-writer.d.ts.map +1 -0
- package/dist/transport/streaming-writer.js +110 -0
- package/dist/transport/streaming-writer.js.map +1 -0
- package/dist/transport/tool-presenter.d.ts +38 -0
- package/dist/transport/tool-presenter.d.ts.map +1 -0
- package/dist/transport/tool-presenter.js +121 -0
- package/dist/transport/tool-presenter.js.map +1 -0
- package/dist/types.d.ts +45 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/package.json +106 -0
- package/settings-host.js +927 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* chat-ledger.ts — 聊天台账(M3 v4, 2026-09-03 新增; 2026-09-05 加群成员维度)
|
|
3
|
+
*
|
|
4
|
+
* 定时唤醒/遥控台要"选一个聊天对象"却要主人手抄 openid——体验失败(主人已吐槽)。
|
|
5
|
+
* 本模块把机器人见过的每个聊天(群/私聊)自动记台账:
|
|
6
|
+
* {dataDir}/known-chats.jsonl append-only 一行一条
|
|
7
|
+
* {ts, scope:'group'|'c2c', id, name?}
|
|
8
|
+
* - c2c: id=用户 openid, name=用户昵称(QQ 平台给的 senderName)
|
|
9
|
+
* - group: id=group_openid, name=该群最近一条发言者昵称(群无群名, 用成员名帮主人辨认)
|
|
10
|
+
* 同时按群记成员(官方"成员列表"未开放时的本地兜底名单, 供群管理面板选人禁言):
|
|
11
|
+
* {dataDir}/group-members.jsonl {ts, gid, mid, name?} append-only
|
|
12
|
+
* host 半边读此文件聚合出"最近聊过的对象"下拉, ④区点选即填 targetId; 群管理读成员聚合出可选人。
|
|
13
|
+
* 中间件挂在 mentionGate 之前(未@消息也流经), 与活性计数同位置。
|
|
14
|
+
*
|
|
15
|
+
* ⚠️ 本地手改功能(fork 新增):维护清单见工作区根《插件改动维护注意事项.md》。
|
|
16
|
+
*/
|
|
17
|
+
import { appendFileSync, readFileSync, statSync, writeFileSync } from 'node:fs';
|
|
18
|
+
import { join } from 'node:path';
|
|
19
|
+
/** 台账文件路径(与图库同 dataDir, host 侧可经 sticker store 推导) */
|
|
20
|
+
export function ledgerPath(dataDir) {
|
|
21
|
+
return join(dataDir, 'known-chats.jsonl');
|
|
22
|
+
}
|
|
23
|
+
/** 群成员台账路径(同 dataDir) */
|
|
24
|
+
export function groupMembersPath(dataDir) {
|
|
25
|
+
return join(dataDir, 'group-members.jsonl');
|
|
26
|
+
}
|
|
27
|
+
/** 由 dsh-qqbot 侧写入(中间件); host 侧只读聚合 */
|
|
28
|
+
export function appendLedger(dataDir, line) {
|
|
29
|
+
try {
|
|
30
|
+
appendFileSync(ledgerPath(dataDir), JSON.stringify(line) + '\n', 'utf8');
|
|
31
|
+
}
|
|
32
|
+
catch { /* 台账失败不影响主链 */ }
|
|
33
|
+
}
|
|
34
|
+
/** 由 dsh-qqbot 侧写入一条"群成员发言"(中间件); host 侧读聚合出可禁言名单 */
|
|
35
|
+
export function appendGroupMember(dataDir, line) {
|
|
36
|
+
try {
|
|
37
|
+
appendFileSync(groupMembersPath(dataDir), JSON.stringify(line) + '\n', 'utf8');
|
|
38
|
+
}
|
|
39
|
+
catch { /* 台账失败不影响主链 */ }
|
|
40
|
+
}
|
|
41
|
+
/** 读某群的本地成员清单(聚合: 每成员保留最近昵称/最近时间/发言次数, 按最近发言倒序) */
|
|
42
|
+
export function readGroupMembers(dataDir, gid) {
|
|
43
|
+
try {
|
|
44
|
+
const raw = readFileSync(groupMembersPath(dataDir), 'utf8');
|
|
45
|
+
const map = new Map();
|
|
46
|
+
for (const l of raw.split('\n')) {
|
|
47
|
+
const t = l.trim();
|
|
48
|
+
if (!t)
|
|
49
|
+
continue;
|
|
50
|
+
try {
|
|
51
|
+
const o = JSON.parse(t);
|
|
52
|
+
if (!o || typeof o.mid !== 'string' || !o.mid || typeof o.gid !== 'string' || !o.gid)
|
|
53
|
+
continue;
|
|
54
|
+
if (gid && o.gid !== gid)
|
|
55
|
+
continue;
|
|
56
|
+
const key = `${o.gid}:${o.mid}`;
|
|
57
|
+
const cur = map.get(key);
|
|
58
|
+
if (!cur)
|
|
59
|
+
map.set(key, { gid: o.gid, mid: o.mid, name: o.name, lastSeen: o.ts, count: 1 });
|
|
60
|
+
else {
|
|
61
|
+
cur.count += 1;
|
|
62
|
+
if (o.ts > cur.lastSeen) {
|
|
63
|
+
cur.lastSeen = o.ts;
|
|
64
|
+
if (o.name)
|
|
65
|
+
cur.name = o.name;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
catch { /* 坏行跳过 */ }
|
|
70
|
+
}
|
|
71
|
+
return [...map.values()].sort((a, b) => b.lastSeen - a.lastSeen).slice(0, 300);
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return [];
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/** host 侧读台账文件(不存在/坏行容错), 返回按 ts 升序的行 */
|
|
78
|
+
export function readLedger(dataDir) {
|
|
79
|
+
try {
|
|
80
|
+
const raw = readFileSync(ledgerPath(dataDir), 'utf8');
|
|
81
|
+
const lines = [];
|
|
82
|
+
for (const l of raw.split('\n')) {
|
|
83
|
+
const t = l.trim();
|
|
84
|
+
if (!t)
|
|
85
|
+
continue;
|
|
86
|
+
try {
|
|
87
|
+
const o = JSON.parse(t);
|
|
88
|
+
if (o && typeof o.id === 'string' && (o.scope === 'group' || o.scope === 'c2c')) {
|
|
89
|
+
lines.push({ ts: typeof o.ts === 'number' ? o.ts : 0, scope: o.scope, id: o.id, name: typeof o.name === 'string' ? o.name : undefined });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
catch { /* 坏行跳过 */ }
|
|
93
|
+
}
|
|
94
|
+
return lines;
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
return [];
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* 聚合"最近聊过的对象"(供下拉): 每对象保留最近 ts/最近昵称 + 消息数。
|
|
102
|
+
* c2c 优先展示昵称; group 无群名, name=该群最近发言者昵称。
|
|
103
|
+
*/
|
|
104
|
+
export function aggregateKnownChats(lines, limit = 60) {
|
|
105
|
+
const map = new Map();
|
|
106
|
+
for (const l of lines) {
|
|
107
|
+
const key = `${l.scope}:${l.id}`;
|
|
108
|
+
const cur = map.get(key);
|
|
109
|
+
if (!cur) {
|
|
110
|
+
map.set(key, { scope: l.scope, id: l.id, name: l.name, lastSeen: l.ts, count: 1 });
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
cur.count += 1;
|
|
114
|
+
if (l.ts > cur.lastSeen) {
|
|
115
|
+
cur.lastSeen = l.ts;
|
|
116
|
+
if (l.name)
|
|
117
|
+
cur.name = l.name; // group: 群名不可得, 用最近发言者昵称帮助辨认
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return [...map.values()].sort((a, b) => b.lastSeen - a.lastSeen).slice(0, limit);
|
|
122
|
+
}
|
|
123
|
+
/** 台账文件大小(给 host 状态用; 不存在返回 0) */
|
|
124
|
+
export function ledgerSize(dataDir) {
|
|
125
|
+
try {
|
|
126
|
+
return statSync(ledgerPath(dataDir)).size;
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
return 0;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* 移除某群某成员的本地记录(成员已退群/禁言无效时调用, 保持本地名单干净)。
|
|
134
|
+
* 重写文件剔除该 gid+mid 的所有行; 文件不存在/无匹配则不动。
|
|
135
|
+
*/
|
|
136
|
+
export function removeGroupMember(dataDir, gid, mid) {
|
|
137
|
+
try {
|
|
138
|
+
const p = groupMembersPath(dataDir);
|
|
139
|
+
const raw = readFileSync(p, 'utf8');
|
|
140
|
+
const kept = [];
|
|
141
|
+
let removed = 0;
|
|
142
|
+
for (const l of raw.split('\n')) {
|
|
143
|
+
const t = l.trim();
|
|
144
|
+
if (!t) {
|
|
145
|
+
kept.push('');
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
try {
|
|
149
|
+
const o = JSON.parse(t);
|
|
150
|
+
if (o && o.gid === gid && o.mid === mid) {
|
|
151
|
+
removed += 1;
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
catch { /* 坏行保留 */ }
|
|
156
|
+
kept.push(l);
|
|
157
|
+
}
|
|
158
|
+
if (removed > 0) {
|
|
159
|
+
writeFileSync(p, kept.join('\n').replace(/\n{2,}/g, '\n').trimEnd() + (kept.length ? '\n' : ''), 'utf8');
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
catch { /* 忽略 */ }
|
|
163
|
+
}
|
|
164
|
+
/** 中间件: 记录见过的群/私聊 + 群内发言成员(放 mentionGate 之前, 未@消息也流经) */
|
|
165
|
+
export function chatLedgerRecorder(dataDir) {
|
|
166
|
+
return async (ctx, next) => {
|
|
167
|
+
try {
|
|
168
|
+
const msg = ctx.message;
|
|
169
|
+
const now = Date.now();
|
|
170
|
+
if (msg.kind === 'group' && msg.groupOpenid) {
|
|
171
|
+
appendLedger(dataDir, { ts: now, scope: 'group', id: msg.groupOpenid, name: msg.senderName || undefined });
|
|
172
|
+
// 群成员兜底名单(官方成员列表未开放): 每个发言者都记, 禁言面板按群聚合可"选人"
|
|
173
|
+
if (msg.senderId) {
|
|
174
|
+
appendGroupMember(dataDir, { ts: now, gid: msg.groupOpenid, mid: msg.senderId, name: msg.senderName || undefined });
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
else if ((msg.kind === 'c2c' || msg.kind === 'direct') && msg.senderId) {
|
|
178
|
+
appendLedger(dataDir, { ts: now, scope: 'c2c', id: msg.senderId, name: msg.senderName || undefined });
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
catch { /* 记录失败不影响主链 */ }
|
|
182
|
+
await next();
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
//# sourceMappingURL=chat-ledger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-ledger.js","sourceRoot":"","sources":["../../src/features/chat-ledger.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QQ 表情标签 → 可读文本(名字优先, faceId 兜底)
|
|
3
|
+
*
|
|
4
|
+
* QQ 入站消息里表情有两种形态:
|
|
5
|
+
* 老格式: [<face,id=0/>] → id 直接查表
|
|
6
|
+
* 新格式: <faceType=6,faceId="0",ext="base64"> → ext.text 优先, 空则按 faceId 查表
|
|
7
|
+
*
|
|
8
|
+
* ⚠️ 必须挂在 SDK contentSanitizer(parseFaceTags) **之前**: SDK 的正则
|
|
9
|
+
* 只解 ext.text, text 为空会把 faceId 一起丢掉 → 输出"未知表情"。
|
|
10
|
+
* 本层先把标签整体替换成可读文本, SDK 就再也匹配不到原标签了。
|
|
11
|
+
*/
|
|
12
|
+
import type { MiddlewareContext } from '@tencent-connect/qqbot-nodejs';
|
|
13
|
+
/** 把消息 content 里的表情标签全部转成可读文本 */
|
|
14
|
+
export declare function resolveFaceTags(text: string): string;
|
|
15
|
+
/** 中间件: 在 SDK contentSanitizer 之前清洗表情标签(不依赖 SDK 的 parseFaceTags) */
|
|
16
|
+
export declare function faceTagResolver(): (ctx: MiddlewareContext, next: () => Promise<void>) => Promise<void>;
|
|
17
|
+
//# sourceMappingURL=face-tags.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"face-tags.d.ts","sourceRoot":"","sources":["../../src/features/face-tags.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAoDvE,iCAAiC;AACjC,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAepD;AAED,oEAAoE;AACpE,wBAAgB,eAAe,KACf,KAAK,iBAAiB,EAAE,MAAM,MAAM,OAAO,CAAC,IAAI,CAAC,KAAG,OAAO,CAAC,IAAI,CAAC,CAMhF"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/** QQ 经典系统表情 faceId → 中文名(0=微笑…, 常见 0~138; 覆盖不全的按 ext.text) */
|
|
2
|
+
const QQ_FACE_NAMES = {
|
|
3
|
+
'0': '微笑', '1': '撇嘴', '2': '色', '3': '发呆', '4': '得意', '5': '流泪',
|
|
4
|
+
'6': '害羞', '7': '闭嘴', '8': '睡', '9': '大哭', '10': '尴尬', '11': '发怒',
|
|
5
|
+
'12': '调皮', '13': '呲牙', '14': '惊讶', '15': '难过', '16': '酷', '17': '冷汗',
|
|
6
|
+
'18': '抓狂', '19': '吐', '20': '偷笑', '21': '可爱', '22': '白眼', '23': '傲慢',
|
|
7
|
+
'24': '饥饿', '25': '困', '26': '惊恐', '27': '流汗', '28': '憨笑', '29': '悠闲',
|
|
8
|
+
'30': '奋斗', '31': '咒骂', '32': '疑问', '33': '嘘', '34': '晕', '35': '狂躁',
|
|
9
|
+
'36': '衰', '37': '骷髅', '38': '敲打', '39': '再见', '40': '擦汗', '41': '抠鼻',
|
|
10
|
+
'42': '鼓掌', '43': '糗大了', '44': '坏笑', '45': '左哼哼', '46': '右哼哼', '47': '哈欠',
|
|
11
|
+
'48': '鄙视', '49': '委屈', '50': '快哭了', '51': '阴险', '52': '亲亲', '53': '吓',
|
|
12
|
+
'54': '可怜', '55': '菜刀', '56': '西瓜', '57': '啤酒', '58': '篮球', '59': '乒乓',
|
|
13
|
+
'60': '咖啡', '61': '饭', '62': '猪头', '63': '玫瑰', '64': '凋谢', '65': '示爱',
|
|
14
|
+
'66': '爱心', '67': '心碎', '68': '蛋糕', '69': '闪电', '70': '炸弹', '71': '刀',
|
|
15
|
+
'72': '足球', '73': '便便', '74': '月亮', '75': '太阳', '76': '礼物', '77': '拥抱',
|
|
16
|
+
'78': '强', '79': '弱', '80': '握手', '81': '胜利', '82': '抱拳', '83': '勾引',
|
|
17
|
+
'84': '拳头', '85': '差劲', '86': '爱你', '87': 'NO', '88': 'OK', '89': '爱情',
|
|
18
|
+
'90': '飞吻', '91': '跳跳', '92': '发抖', '93': '怄火', '94': '转圈', '95': '磕头',
|
|
19
|
+
'96': '回头', '97': '跳绳', '98': '挥手', '99': '激动', '100': '街舞', '101': '献吻',
|
|
20
|
+
'102': '左太极', '103': '右太极', '104': '双喜', '105': '鞭炮', '106': '灯笼', '107': '发财',
|
|
21
|
+
'108': 'K歌', '109': '购物', '110': '邮件', '111': '帅', '112': '喝彩', '113': '祈祷',
|
|
22
|
+
'114': '爆筋', '115': '棒棒糖', '116': '喝奶', '117': '下面', '118': '香蕉', '119': '飞机',
|
|
23
|
+
'120': '开车', '121': '左车头', '122': '车厢', '123': '右车头', '124': '多云', '125': '下雨',
|
|
24
|
+
'126': '钞票', '127': '熊猫', '128': '灯泡', '129': '风车', '130': '闹钟', '131': '打伞',
|
|
25
|
+
'132': '彩球', '133': '钻戒', '134': '沙发', '135': '纸巾', '136': '药', '137': '手枪',
|
|
26
|
+
'138': '茶', '139': '眨眼', '140': '泪奔', '141': '无奈', '142': '托腮', '143': '卖萌',
|
|
27
|
+
'144': '斜眼笑', '145': 'doge', '146': '惊喜', '147': '骚扰', '148': '小纠结', '149': '赞',
|
|
28
|
+
'150': '无语', '151': '献花', '152': '撇嘴2', '153': '暗送秋波', '154': '挑眉', '155': '委屈2',
|
|
29
|
+
'156': '吓哭', '157': '财神', '158': '右太极', '159': '歌唱', '160': '水', '161': '猪头2',
|
|
30
|
+
};
|
|
31
|
+
/** 解新格式标签: 返回可读文本(找不到名字给通用占位) */
|
|
32
|
+
function decodeNewTag(_full, faceId, ext) {
|
|
33
|
+
// 1) ext 里带 text → 官方给的名字最准
|
|
34
|
+
if (ext) {
|
|
35
|
+
try {
|
|
36
|
+
const decoded = Buffer.from(ext, 'base64').toString('utf-8');
|
|
37
|
+
const parsed = JSON.parse(decoded);
|
|
38
|
+
const t = (parsed && typeof parsed.text === 'string' && parsed.text.trim()) ? parsed.text.trim() : '';
|
|
39
|
+
if (t)
|
|
40
|
+
return `【表情: ${t}】`;
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
/* ext 不可解 → 走 faceId 兜底 */
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
// 2) faceId 查表
|
|
47
|
+
const name = QQ_FACE_NAMES[faceId];
|
|
48
|
+
if (name)
|
|
49
|
+
return `【表情: ${name}】`;
|
|
50
|
+
return faceId ? `【表情: id${faceId}】` : '【表情】';
|
|
51
|
+
}
|
|
52
|
+
/** 把消息 content 里的表情标签全部转成可读文本 */
|
|
53
|
+
export function resolveFaceTags(text) {
|
|
54
|
+
if (!text)
|
|
55
|
+
return text;
|
|
56
|
+
// 新格式: <faceType=N,faceId="X",ext="b64"> (属性顺序可能与 SDK 不同, 宽松匹配)
|
|
57
|
+
let out = text.replace(/<faceType=\d+,faceId="([^"]*)",ext="([^"]*)">/g, (m, id, ex) => decodeNewTag(m, id, ex));
|
|
58
|
+
// 宽松形态(缺 ext / 顺序不同): <faceType=N,faceId="X">
|
|
59
|
+
out = out.replace(/<faceType=\d+,faceId="([^"]*)">/g, (_m, id) => {
|
|
60
|
+
const name = QQ_FACE_NAMES[id];
|
|
61
|
+
return name ? `【表情: ${name}】` : (id ? `【表情: id${id}】` : '【表情】');
|
|
62
|
+
});
|
|
63
|
+
// 老格式: [<face,id=N/>]
|
|
64
|
+
out = out.replace(/\[<face,id=(\d+)\/?>]/g, (_m, id) => {
|
|
65
|
+
const name = QQ_FACE_NAMES[id];
|
|
66
|
+
return name ? `【表情: ${name}】` : '【表情】';
|
|
67
|
+
});
|
|
68
|
+
return out;
|
|
69
|
+
}
|
|
70
|
+
/** 中间件: 在 SDK contentSanitizer 之前清洗表情标签(不依赖 SDK 的 parseFaceTags) */
|
|
71
|
+
export function faceTagResolver() {
|
|
72
|
+
return async (ctx, next) => {
|
|
73
|
+
if (typeof ctx.message.content === 'string') {
|
|
74
|
+
ctx.message.content = resolveFaceTags(ctx.message.content);
|
|
75
|
+
}
|
|
76
|
+
await next();
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=face-tags.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"face-tags.js","sourceRoot":"","sources":["../../src/features/face-tags.ts"],"names":[],"mappings":"AAaA,+DAA+D;AAC/D,MAAM,aAAa,GAA2B;IAC5C,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI;IAC/D,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;IACjE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI;IACrE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;IACrE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;IACrE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI;IACpE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;IACrE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI;IACzE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG;IACtE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;IACtE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;IACrE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG;IACrE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;IACtE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;IACpE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;IACtE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;IACtE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI;IACxE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI;IAC9E,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI;IAC3E,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI;IAC7E,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI;IAC9E,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI;IAC5E,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI;IAC3E,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI;IAC3E,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG;IAC/E,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK;IAChF,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK;CAC9E,CAAC;AAEF,iCAAiC;AACjC,SAAS,YAAY,CAAC,KAAa,EAAE,MAAc,EAAE,GAAW;IAC9D,4BAA4B;IAC5B,IAAI,GAAG,EAAE,CAAC;QACR,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;YAC7D,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAA6B,CAAC;YAC/D,MAAM,CAAC,GAAG,CAAC,MAAM,IAAI,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACtG,IAAI,CAAC;gBAAE,OAAO,QAAQ,CAAC,GAAG,CAAC;QAC7B,CAAC;QAAC,MAAM,CAAC;YACP,2BAA2B;QAC7B,CAAC;IACH,CAAC;IACD,eAAe;IACf,MAAM,IAAI,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IACnC,IAAI,IAAI;QAAE,OAAO,QAAQ,IAAI,GAAG,CAAC;IACjC,OAAO,MAAM,CAAC,CAAC,CAAC,UAAU,MAAM,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC;AAC/C,CAAC;AAED,iCAAiC;AACjC,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,gEAAgE;IAChE,IAAI,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,gDAAgD,EAAE,CAAC,CAAC,EAAE,EAAU,EAAE,EAAU,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;IACjI,8CAA8C;IAC9C,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,kCAAkC,EAAE,CAAC,EAAE,EAAE,EAAU,EAAE,EAAE;QACvE,MAAM,IAAI,GAAG,aAAa,CAAC,EAAE,CAAC,CAAC;QAC/B,OAAO,IAAI,CAAC,CAAC,CAAC,QAAQ,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IAClE,CAAC,CAAC,CAAC;IACH,sBAAsB;IACtB,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,wBAAwB,EAAE,CAAC,EAAE,EAAE,EAAU,EAAE,EAAE;QAC7D,MAAM,IAAI,GAAG,aAAa,CAAC,EAAE,CAAC,CAAC;QAC/B,OAAO,IAAI,CAAC,CAAC,CAAC,QAAQ,IAAI,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC;IACzC,CAAC,CAAC,CAAC;IACH,OAAO,GAAG,CAAC;AACb,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,eAAe;IAC7B,OAAO,KAAK,EAAE,GAAsB,EAAE,IAAyB,EAAiB,EAAE;QAChF,IAAI,OAAO,GAAG,CAAC,OAAO,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;YAC5C,GAAG,CAAC,OAAO,CAAC,OAAO,GAAG,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAC7D,CAAC;QACD,MAAM,IAAI,EAAE,CAAC;IACf,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { QQBotSender } from '../transport/outbound-buffer.js';
|
|
2
|
+
import type { ImQQBotConfig } from '../config.js';
|
|
3
|
+
import type { Logger } from '../types.js';
|
|
4
|
+
import type { SessionManager } from '../session/index.js';
|
|
5
|
+
/** 官方 GROUP_JOIN_REQUEST 事件体(与本项目用到的字段) */
|
|
6
|
+
export interface GroupJoinRequestEvent {
|
|
7
|
+
group_openid?: string;
|
|
8
|
+
join_request_id?: string;
|
|
9
|
+
member_openid?: string;
|
|
10
|
+
username?: string;
|
|
11
|
+
apply_at?: string;
|
|
12
|
+
apply_source?: 'self_apply' | 'invited';
|
|
13
|
+
invited_by?: string;
|
|
14
|
+
risk_tips?: string;
|
|
15
|
+
union_openid?: string;
|
|
16
|
+
bot?: boolean;
|
|
17
|
+
verify_info?: {
|
|
18
|
+
method?: string;
|
|
19
|
+
verify_message?: string;
|
|
20
|
+
review_qa_list?: Array<{
|
|
21
|
+
question: string;
|
|
22
|
+
answer: string;
|
|
23
|
+
}>;
|
|
24
|
+
};
|
|
25
|
+
auto_approved?: {
|
|
26
|
+
strategy_id?: string;
|
|
27
|
+
};
|
|
28
|
+
[key: string]: unknown;
|
|
29
|
+
}
|
|
30
|
+
/** pending 待办条目(落盘, UI/工具可读) */
|
|
31
|
+
export interface PendingJoinRequest {
|
|
32
|
+
group_openid: string;
|
|
33
|
+
join_request_id: string;
|
|
34
|
+
member_openid: string;
|
|
35
|
+
username?: string;
|
|
36
|
+
apply_at?: string;
|
|
37
|
+
apply_source?: string;
|
|
38
|
+
invited_by?: string;
|
|
39
|
+
risk_tips?: string;
|
|
40
|
+
verify_message?: string;
|
|
41
|
+
/** 事件到达时间(本机 ISO) */
|
|
42
|
+
seen_at: string;
|
|
43
|
+
/** 是否已发过群内提醒 */
|
|
44
|
+
notified: boolean;
|
|
45
|
+
}
|
|
46
|
+
/** 追加一条 pending(按 join_request_id 去重, 最新在前) */
|
|
47
|
+
export declare function pushPendingJoinRequest(cwd: string | undefined, ev: PendingJoinRequest): void;
|
|
48
|
+
/** 读某群 pending(UI/工具用; gid 空 = 全部) */
|
|
49
|
+
export declare function readPendingJoinRequests(cwd: string | undefined, gid?: string): PendingJoinRequest[];
|
|
50
|
+
/**
|
|
51
|
+
* 处理一条 GROUP_JOIN_REQUEST 事件(rawEvent 数据):
|
|
52
|
+
* ① auto_approved 下行(自动审批已通过)→ 仅记审计, 不打扰;
|
|
53
|
+
* ② 否则去重 → pending 落盘 → **注入该群 agent 的 inbox(next-step 队列, wakeup=false)**:
|
|
54
|
+
* - 等效"模拟用户消息 + 不触发模型回合"(dsh 底层: agent.inject = send(msg,'next-step',wakeup:false),
|
|
55
|
+
* 区别于 followup 的唤醒; 消息持久化在会话, 等主人下一条真人消息开回合时同批进 AI 上下文)
|
|
56
|
+
* - 宿主 agent 无 inject 能力/无活跃会话 → 兜底发一条 QQ 群静态提醒卡片(不静默丢)
|
|
57
|
+
* @returns true = 事件被消费(记录/注入), false = 忽略(重复或无效)
|
|
58
|
+
*/
|
|
59
|
+
export declare function handleGroupJoinRequestEvent(data: unknown, opts: {
|
|
60
|
+
sender: QQBotSender;
|
|
61
|
+
config: ImQQBotConfig;
|
|
62
|
+
logger: Logger;
|
|
63
|
+
manager: SessionManager;
|
|
64
|
+
}): Promise<boolean>;
|
|
65
|
+
//# sourceMappingURL=group-join-request.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"group-join-request.d.ts","sourceRoot":"","sources":["../../src/features/group-join-request.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,2CAA2C;AAC3C,MAAM,WAAW,qBAAqB;IACpC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,WAAW,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,KAAK,CAAC;YAAE,QAAQ,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;KAAE,CAAC;IACzH,aAAa,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACzC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,gCAAgC;AAChC,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,qBAAqB;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB;IAChB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAuCD,+CAA+C;AAC/C,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,MAAM,GAAG,SAAS,EACvB,EAAE,EAAE,kBAAkB,GACrB,IAAI,CAUN;AAED,sCAAsC;AACtC,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,MAAM,GAAG,SAAS,EACvB,GAAG,CAAC,EAAE,MAAM,GACX,kBAAkB,EAAE,CAItB;AAED;;;;;;;;GAQG;AACH,wBAAsB,2BAA2B,CAC/C,IAAI,EAAE,OAAO,EACb,IAAI,EAAE;IACJ,MAAM,EAAE,WAAW,CAAC;IACpB,MAAM,EAAE,aAAa,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,cAAc,CAAC;CACzB,GACA,OAAO,CAAC,OAAO,CAAC,CA2GlB"}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* group-join-request.ts — 入群申请事件(GROUP_JOIN_REQUEST)监听与提醒 (P2.5, 2026-09-05)
|
|
3
|
+
*
|
|
4
|
+
* 官方事件事实(参考文档/qqbot-api-v2-docs/autogen__event__group_join_request.html):
|
|
5
|
+
* - 事件名 GROUP_JOIN_REQUEST, Intent = GROUP_MEMBER_EVENT (1<<24), 仅机器人=群管理员收到;
|
|
6
|
+
* - 事件体: group_openid / join_request_id / member_openid / username / apply_at /
|
|
7
|
+
* apply_source(self_apply|invited) / invited_by / risk_tips / verify_info / auto_approved(下行, 自动审批通过时带);
|
|
8
|
+
* - 说明: 拉取/审批 REST 走 group-admin.ts(GroupAdminClient), 这里只接"实时事件 → 提醒 + 待办落盘"。
|
|
9
|
+
*
|
|
10
|
+
* SDK 接线(勘察 2026-09-05): @tencent-connect/qqbot-nodejs 未枚举该事件, 但三层透传全通:
|
|
11
|
+
* QQBot options.intents(自定义, 默认 FULL_INTENTS 不含 1<<24)
|
|
12
|
+
* → gateway dispatchEvent 未知事件返 {action:'raw'} → onRawEvent → bot.on('rawEvent')。
|
|
13
|
+
* 故订阅 = 构造 QQBot 时 intents 或上 1<<24 + 监听 rawEvent, SDK 零改动。
|
|
14
|
+
* 若官方未授权该 intent, Identify 可能被拒(close 4914/4915)→ 用 config.groupAdmin.watchJoinRequests 开关, 默认关。
|
|
15
|
+
*
|
|
16
|
+
* 提醒通道: QQ member_openid ≠ c2c user_openid(无法由 owners 群身份推导私聊目标),
|
|
17
|
+
* 故"提醒主人"落地 = ①在该群内发一条 bot 消息(群主/管理员即主人可见) + ②pending 待办落盘,
|
|
18
|
+
* UI ⑥区/P3 与群管理工具都能再读 pending; 全部动作走审计日志。
|
|
19
|
+
*/
|
|
20
|
+
import { mkdirSync, readFileSync, writeFileSync, existsSync } from 'node:fs';
|
|
21
|
+
import { join } from 'node:path';
|
|
22
|
+
import { createUserMessage } from '@deepseek-ai/dsh-llm';
|
|
23
|
+
/** 内存去重(join_request_id)与群内提醒限频: 每群 5 分钟至多 1 条, 防风暴 */
|
|
24
|
+
const recentIds = new Map();
|
|
25
|
+
const lastGroupNotify = new Map();
|
|
26
|
+
const DEDUP_TTL_MS = 24 * 3600_000;
|
|
27
|
+
const GROUP_NOTIFY_MIN_GAP_MS = 300_000;
|
|
28
|
+
const MAX_PENDING_PER_GROUP = 50;
|
|
29
|
+
/** pending 文件路径({cwd}/.qqbot/join-pending.json, 与 groups.json 同目录) */
|
|
30
|
+
function pendingPath(cwd) {
|
|
31
|
+
return join(cwd || process.cwd(), '.qqbot', 'join-pending.json');
|
|
32
|
+
}
|
|
33
|
+
function loadPending(path) {
|
|
34
|
+
try {
|
|
35
|
+
if (!existsSync(path))
|
|
36
|
+
return {};
|
|
37
|
+
const raw = JSON.parse(readFileSync(path, 'utf8'));
|
|
38
|
+
return raw && typeof raw === 'object' ? raw : {};
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return {};
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function savePending(path, store) {
|
|
45
|
+
try {
|
|
46
|
+
mkdirSync(join(path, '..'), { recursive: true });
|
|
47
|
+
writeFileSync(path, JSON.stringify(store, null, 1), 'utf8');
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
// 落盘失败不阻断主流程, 调用方已留审计
|
|
51
|
+
void err;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/** 追加一条 pending(按 join_request_id 去重, 最新在前) */
|
|
55
|
+
export function pushPendingJoinRequest(cwd, ev) {
|
|
56
|
+
const path = pendingPath(cwd);
|
|
57
|
+
const store = loadPending(path);
|
|
58
|
+
const gid = ev.group_openid;
|
|
59
|
+
const list = store[gid] ?? [];
|
|
60
|
+
const idx = list.findIndex((x) => x.join_request_id === ev.join_request_id);
|
|
61
|
+
if (idx >= 0)
|
|
62
|
+
list.splice(idx, 1);
|
|
63
|
+
list.unshift(ev);
|
|
64
|
+
store[gid] = list.slice(0, MAX_PENDING_PER_GROUP);
|
|
65
|
+
savePending(path, store);
|
|
66
|
+
}
|
|
67
|
+
/** 读某群 pending(UI/工具用; gid 空 = 全部) */
|
|
68
|
+
export function readPendingJoinRequests(cwd, gid) {
|
|
69
|
+
const store = loadPending(pendingPath(cwd));
|
|
70
|
+
if (gid)
|
|
71
|
+
return store[gid] ?? [];
|
|
72
|
+
return Object.values(store).flat();
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* 处理一条 GROUP_JOIN_REQUEST 事件(rawEvent 数据):
|
|
76
|
+
* ① auto_approved 下行(自动审批已通过)→ 仅记审计, 不打扰;
|
|
77
|
+
* ② 否则去重 → pending 落盘 → **注入该群 agent 的 inbox(next-step 队列, wakeup=false)**:
|
|
78
|
+
* - 等效"模拟用户消息 + 不触发模型回合"(dsh 底层: agent.inject = send(msg,'next-step',wakeup:false),
|
|
79
|
+
* 区别于 followup 的唤醒; 消息持久化在会话, 等主人下一条真人消息开回合时同批进 AI 上下文)
|
|
80
|
+
* - 宿主 agent 无 inject 能力/无活跃会话 → 兜底发一条 QQ 群静态提醒卡片(不静默丢)
|
|
81
|
+
* @returns true = 事件被消费(记录/注入), false = 忽略(重复或无效)
|
|
82
|
+
*/
|
|
83
|
+
export async function handleGroupJoinRequestEvent(data, opts) {
|
|
84
|
+
const { sender, config, logger, manager } = opts;
|
|
85
|
+
const ev = (data ?? {});
|
|
86
|
+
const gid = ev.group_openid;
|
|
87
|
+
const jid = ev.join_request_id;
|
|
88
|
+
const mid = ev.member_openid;
|
|
89
|
+
if (!gid || !jid || !mid) {
|
|
90
|
+
logger.warn(`[group-join] 事件缺关键字段, 忽略: ${JSON.stringify(ev).slice(0, 300)}`);
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
// 内存去重(重启后事件极少重推, 内存足够)
|
|
94
|
+
const now = Date.now();
|
|
95
|
+
for (const [id, ts] of recentIds) {
|
|
96
|
+
if (now - ts > DEDUP_TTL_MS)
|
|
97
|
+
recentIds.delete(id);
|
|
98
|
+
}
|
|
99
|
+
if (recentIds.has(jid)) {
|
|
100
|
+
logger.debug(`[group-join] 重复事件跳过: ${jid}`);
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
recentIds.set(jid, now);
|
|
104
|
+
// 自动审批下行: 只记审计, 不提醒(结果已确定, 无需管理员操作)
|
|
105
|
+
if (ev.auto_approved && ev.auto_approved.strategy_id) {
|
|
106
|
+
logger.info(`[group-join] 自动审批通过(下行): gid=${gid} user=${ev.username}(${mid}) strategy=${ev.auto_approved.strategy_id}`);
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
const verify = ev.verify_info?.verify_message || ev.verify_info?.method || '';
|
|
110
|
+
const item = {
|
|
111
|
+
group_openid: gid,
|
|
112
|
+
join_request_id: jid,
|
|
113
|
+
member_openid: mid,
|
|
114
|
+
username: ev.username,
|
|
115
|
+
apply_at: ev.apply_at,
|
|
116
|
+
apply_source: ev.apply_source,
|
|
117
|
+
invited_by: ev.invited_by,
|
|
118
|
+
risk_tips: ev.risk_tips,
|
|
119
|
+
verify_message: verify,
|
|
120
|
+
seen_at: new Date().toISOString(),
|
|
121
|
+
notified: false,
|
|
122
|
+
};
|
|
123
|
+
pushPendingJoinRequest(config.cwd, item);
|
|
124
|
+
logger.info(`[group-join] 新入群申请: gid=${gid} user=${ev.username ?? '?'}(${mid.slice(0, 10)}…) src=${ev.apply_source ?? '?'}${ev.risk_tips ? ` risk=${ev.risk_tips}` : ''}`);
|
|
125
|
+
// 通知策略(主人定稿 2026-09-05 21:10):
|
|
126
|
+
// 要"模拟用户消息 + 模拟点停止" = 把申请直接 append 为该群 agent 的 session log 一条
|
|
127
|
+
// user/message 事件(turn() 中让消息显示在 web 的那一步), 但【不 wake 不开回合】→
|
|
128
|
+
// web 会话流能看到这条消息(像用户真发过), AI 却不会主动思考/回复(不撞 QQ 限流)。
|
|
129
|
+
// 主人下次真人消息开新回合时, 这条 user/message 作为 log 历史被 deriveMessages 组装进
|
|
130
|
+
// 上下文 → AI 自然看到申请并能接应"通过/拒绝"。
|
|
131
|
+
if (config.groupAdmin?.notifyInGroup !== false) {
|
|
132
|
+
const last = lastGroupNotify.get(gid) ?? 0;
|
|
133
|
+
if (now - last >= GROUP_NOTIFY_MIN_GAP_MS) {
|
|
134
|
+
lastGroupNotify.set(gid, now);
|
|
135
|
+
const userPart = ev.username ?? '(未知昵称)';
|
|
136
|
+
const srcPart = ev.apply_source === 'invited'
|
|
137
|
+
? `被邀请${ev.invited_by ? `(邀请人 ${ev.invited_by.slice(0, 10)}…)` : ''}`
|
|
138
|
+
: '主动申请';
|
|
139
|
+
const verifyPart = verify ? ` 验证「${verify}」` : '';
|
|
140
|
+
const riskPart = ev.risk_tips ? ` ⚠️${ev.risk_tips}` : '';
|
|
141
|
+
const summary = `[入群申请] ${userPart}(${srcPart})${verifyPart}${riskPart}`;
|
|
142
|
+
// 有活跃会话直接用; 没有(空闲被回收)→ getOrCreate 恢复/重建会话(不触发回合, 只保证 log 存在)
|
|
143
|
+
let record = manager.findByPeer('group', gid);
|
|
144
|
+
if (!record) {
|
|
145
|
+
try {
|
|
146
|
+
const target = { scope: 'group', targetId: gid };
|
|
147
|
+
record = await manager.getOrCreate('group', gid, mid, target);
|
|
148
|
+
logger.info(`[group-join] 会话不在, 已 getOrCreate 恢复 gid=${gid}`);
|
|
149
|
+
}
|
|
150
|
+
catch (err) {
|
|
151
|
+
logger.warn(`[group-join] getOrCreate 失败: ${err instanceof Error ? err.message : String(err)}`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
const sess = record?.agent?.session;
|
|
155
|
+
if (sess && typeof sess.append === 'function') {
|
|
156
|
+
try {
|
|
157
|
+
// 与 turn() 同款: session.append('user/message', msg, {surfaceOp:'append'}) → web 可见;
|
|
158
|
+
// 不调 send/followup → 不 wakeDriver → AI 不触发回合(等效用户发消息后点停止)。
|
|
159
|
+
const msg = createUserMessage({
|
|
160
|
+
content: [{ type: 'text', text: summary }],
|
|
161
|
+
source: { kind: 'user' },
|
|
162
|
+
});
|
|
163
|
+
sess.append('user/message', msg, { surfaceOp: 'append' });
|
|
164
|
+
item.notified = true;
|
|
165
|
+
pushPendingJoinRequest(config.cwd, item);
|
|
166
|
+
logger.info(`[group-join] 已 append user/message 到会话 log(不唤醒, 模拟用户消息+停止) gid=${gid}`);
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
catch (err) {
|
|
170
|
+
logger.warn(`[group-join] append 失败: ${err instanceof Error ? err.message : String(err)}`);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
logger.warn(`[group-join] 会话无 append 能力, 兜底发 QQ 卡片 gid=${gid}`);
|
|
175
|
+
}
|
|
176
|
+
// 兜底: 无会话/append 不可用 → 发一条静态群消息提醒(不静默丢)
|
|
177
|
+
try {
|
|
178
|
+
const target = { scope: 'group', targetId: gid };
|
|
179
|
+
await sender.sendMarkdown(target, `${summary}\n\n主人可回复让我查看/审批(如: 查看入群申请)。`);
|
|
180
|
+
item.notified = true;
|
|
181
|
+
pushPendingJoinRequest(config.cwd, item);
|
|
182
|
+
}
|
|
183
|
+
catch (err) {
|
|
184
|
+
logger.warn(`[group-join] 群内提醒发送失败: ${err instanceof Error ? err.message : String(err)}`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return true;
|
|
189
|
+
}
|
|
190
|
+
//# sourceMappingURL=group-join-request.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"group-join-request.js","sourceRoot":"","sources":["../../src/features/group-join-request.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { HistoryStore } from '@tencent-connect/qqbot-nodejs';
|
|
2
|
+
/** 获取共享历史存储(单例) */
|
|
3
|
+
export declare function getHistoryStore(): HistoryStore;
|
|
4
|
+
/** 用 appId 前缀隔离群历史(单账号下等价于 groupOpenid,保留多账号扩展) */
|
|
5
|
+
export declare function historyGroupKey(appId: string, groupId: string): string;
|
|
6
|
+
/** 清空群历史(回复后调用,避免下次 @ 时重复组包) */
|
|
7
|
+
export declare function clearGroupHistory(appId: string, groupId: string): void;
|
|
8
|
+
//# sourceMappingURL=history-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"history-store.d.ts","sourceRoot":"","sources":["../../src/features/history-store.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAIlE,mBAAmB;AACnB,wBAAgB,eAAe,IAAI,YAAY,CAG9C;AAED,mDAAmD;AACnD,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED,gCAAgC;AAChC,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAEtE"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 群历史存储共享模块
|
|
3
|
+
*
|
|
4
|
+
* historyBuffer 中间件需要一个跨调用可访问的 HistoryStore 实例,
|
|
5
|
+
* 以便在回复完成后清空某群的历史缓存(避免下次 @ 时重复组包)。
|
|
6
|
+
* 对齐 openclaw-qqbot 的 features/history-store。
|
|
7
|
+
*/
|
|
8
|
+
import { MemoryHistoryStore } from '@tencent-connect/qqbot-nodejs';
|
|
9
|
+
let _store = null;
|
|
10
|
+
/** 获取共享历史存储(单例) */
|
|
11
|
+
export function getHistoryStore() {
|
|
12
|
+
if (!_store)
|
|
13
|
+
_store = new MemoryHistoryStore();
|
|
14
|
+
return _store;
|
|
15
|
+
}
|
|
16
|
+
/** 用 appId 前缀隔离群历史(单账号下等价于 groupOpenid,保留多账号扩展) */
|
|
17
|
+
export function historyGroupKey(appId, groupId) {
|
|
18
|
+
return `${appId}:${groupId}`;
|
|
19
|
+
}
|
|
20
|
+
/** 清空群历史(回复后调用,避免下次 @ 时重复组包) */
|
|
21
|
+
export function clearGroupHistory(appId, groupId) {
|
|
22
|
+
_store?.clear?.(historyGroupKey(appId, groupId));
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=history-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"history-store.js","sourceRoot":"","sources":["../../src/features/history-store.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAGnE,IAAI,MAAM,GAAwB,IAAI,CAAC;AAEvC,mBAAmB;AACnB,MAAM,UAAU,eAAe;IAC7B,IAAI,CAAC,MAAM;QAAE,MAAM,GAAG,IAAI,kBAAkB,EAAE,CAAC;IAC/C,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,mDAAmD;AACnD,MAAM,UAAU,eAAe,CAAC,KAAa,EAAE,OAAe;IAC5D,OAAO,GAAG,KAAK,IAAI,OAAO,EAAE,CAAC;AAC/B,CAAC;AAED,gCAAgC;AAChC,MAAM,UAAU,iBAAiB,CAAC,KAAa,EAAE,OAAe;IAC9D,MAAM,EAAE,KAAK,EAAE,CAAC,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC;AACnD,CAAC"}
|