@zhin.js/adapter-icqq 1.1.15 → 1.1.16
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/CHANGELOG.md +36 -0
- package/PERMITS.md +14 -18
- package/README.md +12 -0
- package/adapters/icqq/index.js +2 -0
- package/adapters/icqq/index.ts +2 -0
- package/agents/icqq/conversation.js +72 -0
- package/agents/icqq/conversation.ts +67 -0
- package/agents/icqq/messages.js +144 -0
- package/agents/icqq/messages.ts +144 -0
- package/agents/icqq/skills/icqq-conversation/SKILL.md +24 -0
- package/agents/icqq/skills/icqq-conversation/tools/conversation_info/index.js +61 -0
- package/agents/icqq/skills/icqq-conversation/tools/conversation_info/index.ts +61 -0
- package/agents/icqq/skills/icqq-directory/tools/user_info/index.js +2 -1
- package/agents/icqq/skills/icqq-directory/tools/user_info/index.ts +2 -1
- package/agents/icqq/skills/icqq-group-admin/SKILL.md +11 -1
- package/agents/icqq/skills/icqq-group-admin/tools/announce/index.js +2 -1
- package/agents/icqq/skills/icqq-group-admin/tools/announce/index.ts +2 -1
- package/agents/icqq/skills/icqq-group-admin/tools/essence/index.js +2 -1
- package/agents/icqq/skills/icqq-group-admin/tools/essence/index.ts +2 -1
- package/agents/icqq/skills/icqq-group-admin/tools/group_invite/index.js +4 -3
- package/agents/icqq/skills/icqq-group-admin/tools/group_invite/index.ts +4 -3
- package/agents/icqq/skills/icqq-group-admin/tools/group_kick/index.js +4 -3
- package/agents/icqq/skills/icqq-group-admin/tools/group_kick/index.ts +4 -3
- package/agents/icqq/skills/icqq-group-admin/tools/group_leave/index.js +33 -0
- package/agents/icqq/skills/icqq-group-admin/tools/group_leave/index.ts +32 -0
- package/agents/icqq/skills/icqq-group-admin/tools/recall_member_message/index.js +33 -0
- package/agents/icqq/skills/icqq-group-admin/tools/recall_member_message/index.ts +32 -0
- package/agents/icqq/skills/icqq-group-admin/tools/set_anonymous/index.js +3 -2
- package/agents/icqq/skills/icqq-group-admin/tools/set_anonymous/index.ts +3 -2
- package/agents/icqq/skills/icqq-group-admin/tools/set_mute/index.js +4 -3
- package/agents/icqq/skills/icqq-group-admin/tools/set_mute/index.ts +4 -3
- package/agents/icqq/skills/icqq-group-admin/tools/set_title/index.js +4 -3
- package/agents/icqq/skills/icqq-group-admin/tools/set_title/index.ts +4 -3
- package/agents/icqq/skills/icqq-group-directory/tools/group_member_info/index.js +3 -2
- package/agents/icqq/skills/icqq-group-directory/tools/group_member_info/index.ts +3 -2
- package/agents/icqq/skills/icqq-group-interaction/tools/group_sign/index.js +3 -2
- package/agents/icqq/skills/icqq-group-interaction/tools/group_sign/index.ts +3 -2
- package/agents/icqq/skills/icqq-group-interaction/tools/poke/index.js +2 -1
- package/agents/icqq/skills/icqq-group-interaction/tools/poke/index.ts +2 -1
- package/agents/icqq/skills/icqq-group-state/tools/group_files/index.js +2 -1
- package/agents/icqq/skills/icqq-group-state/tools/group_files/index.ts +2 -1
- package/agents/icqq/skills/icqq-interaction/tools/send_user_like/index.js +3 -2
- package/agents/icqq/skills/icqq-interaction/tools/send_user_like/index.ts +3 -2
- package/agents/icqq/skills/icqq-messages/SKILL.md +28 -0
- package/agents/icqq/skills/icqq-messages/tools/forward_messages/index.js +42 -0
- package/agents/icqq/skills/icqq-messages/tools/forward_messages/index.ts +40 -0
- package/agents/icqq/skills/icqq-messages/tools/quote_reply/index.js +24 -0
- package/agents/icqq/skills/icqq-messages/tools/quote_reply/index.ts +24 -0
- package/agents/icqq/skills/icqq-messages/tools/recall_own_message/index.js +18 -0
- package/agents/icqq/skills/icqq-messages/tools/recall_own_message/index.ts +17 -0
- package/agents/icqq/system.md +4 -0
- package/commands/icqq/endpoint/definition.js +9 -7
- package/commands/icqq/endpoint/definition.ts +9 -9
- package/lib/endpoint.d.ts +1 -0
- package/lib/endpoint.js +6 -0
- package/lib/i18n.d.ts +1 -0
- package/lib/i18n.js +47 -0
- package/lib/icqq-login-assist.d.ts +2 -0
- package/lib/icqq-login-assist.js +8 -7
- package/lib/protocol.d.ts +1 -0
- package/lib/protocol.js +14 -1
- package/package.json +16 -16
- package/schema.json +250 -42
- package/src/endpoint.ts +7 -0
- package/src/i18n.ts +48 -0
- package/src/icqq-login-assist.ts +10 -7
- package/src/protocol.ts +13 -1
package/schema.json
CHANGED
|
@@ -4,75 +4,169 @@
|
|
|
4
4
|
"additionalProperties": false,
|
|
5
5
|
"properties": {
|
|
6
6
|
"master": {
|
|
7
|
-
"type": [
|
|
8
|
-
|
|
7
|
+
"type": [
|
|
8
|
+
"string",
|
|
9
|
+
"number"
|
|
10
|
+
],
|
|
11
|
+
"description": "框架 master QQ uin(/approve、AI/工具权限);endpoints[i].master 可逐项覆盖",
|
|
12
|
+
"x-i18n": {
|
|
13
|
+
"en": {
|
|
14
|
+
"description": "Framework master QQ uin list for approval and AI/tool permissions. endpoints[i].master can override this value."
|
|
15
|
+
}
|
|
16
|
+
}
|
|
9
17
|
},
|
|
10
18
|
"trusted": {
|
|
11
19
|
"type": "array",
|
|
12
|
-
"items": {
|
|
13
|
-
|
|
20
|
+
"items": {
|
|
21
|
+
"type": [
|
|
22
|
+
"string",
|
|
23
|
+
"number"
|
|
24
|
+
]
|
|
25
|
+
},
|
|
26
|
+
"description": "框架 trusted QQ uin 列表(弱于 master)",
|
|
27
|
+
"x-i18n": {
|
|
28
|
+
"en": {
|
|
29
|
+
"description": "Framework trusted QQ uin list, below master authority."
|
|
30
|
+
}
|
|
31
|
+
}
|
|
14
32
|
},
|
|
15
33
|
"password": {
|
|
16
34
|
"type": "string",
|
|
17
|
-
"description": "QQ 密码(可选,不填则扫码登录)"
|
|
35
|
+
"description": "QQ 密码(可选,不填则扫码登录)",
|
|
36
|
+
"x-i18n": {
|
|
37
|
+
"en": {
|
|
38
|
+
"description": "QQ password (optional); scan a QR code to log in when omitted."
|
|
39
|
+
}
|
|
40
|
+
}
|
|
18
41
|
},
|
|
19
42
|
"platform": {
|
|
20
43
|
"type": "number",
|
|
21
|
-
"enum": [
|
|
44
|
+
"enum": [
|
|
45
|
+
1,
|
|
46
|
+
2,
|
|
47
|
+
3,
|
|
48
|
+
4,
|
|
49
|
+
5,
|
|
50
|
+
6,
|
|
51
|
+
7
|
|
52
|
+
],
|
|
22
53
|
"default": 1,
|
|
23
|
-
"description": "登录设备平台:1=Android, 2=aPad, 3=Watch, 4=iMac, 5=iPad, 6=Tim, 7=Custom"
|
|
54
|
+
"description": "登录设备平台:1=Android, 2=aPad, 3=Watch, 4=iMac, 5=iPad, 6=Tim, 7=Custom",
|
|
55
|
+
"x-i18n": {
|
|
56
|
+
"en": {
|
|
57
|
+
"description": "Login device platform: 1=Android, 2=aPad, 3=Watch, 4=iMac, 5=iPad, 6=Tim, 7=Custom."
|
|
58
|
+
}
|
|
59
|
+
}
|
|
24
60
|
},
|
|
25
61
|
"ver": {
|
|
26
62
|
"type": "string",
|
|
27
|
-
"description": "协议版本号,仅在对应 platform 有多个版本时有效,不填则使用最新版本"
|
|
63
|
+
"description": "协议版本号,仅在对应 platform 有多个版本时有效,不填则使用最新版本",
|
|
64
|
+
"x-i18n": {
|
|
65
|
+
"en": {
|
|
66
|
+
"description": "Protocol version, only applicable when the selected platform has multiple versions. Uses the latest when omitted."
|
|
67
|
+
}
|
|
68
|
+
}
|
|
28
69
|
},
|
|
29
70
|
"signApiAddr": {
|
|
30
71
|
"type": "string",
|
|
31
|
-
"description": "签名服务器地址;未配置时若安装了 @icqqjs/qqsign 则自动使用本地签名"
|
|
72
|
+
"description": "签名服务器地址;未配置时若安装了 @icqqjs/qqsign 则自动使用本地签名",
|
|
73
|
+
"x-i18n": {
|
|
74
|
+
"en": {
|
|
75
|
+
"description": "Signing server URL. When omitted, uses local signing automatically if @icqqjs/qqsign is installed."
|
|
76
|
+
}
|
|
77
|
+
}
|
|
32
78
|
},
|
|
33
79
|
"dataDir": {
|
|
34
80
|
"type": "string",
|
|
35
|
-
"description": "数据存储文件夹路径,默认为主模块下的 data 文件夹"
|
|
81
|
+
"description": "数据存储文件夹路径,默认为主模块下的 data 文件夹",
|
|
82
|
+
"x-i18n": {
|
|
83
|
+
"en": {
|
|
84
|
+
"description": "Data directory path; defaults to the data directory under the main module."
|
|
85
|
+
}
|
|
86
|
+
}
|
|
36
87
|
},
|
|
37
88
|
"autoReconnect": {
|
|
38
89
|
"type": "boolean",
|
|
39
90
|
"default": true,
|
|
40
|
-
"description": "断线后是否自动重连(默认 true)"
|
|
91
|
+
"description": "断线后是否自动重连(默认 true)",
|
|
92
|
+
"x-i18n": {
|
|
93
|
+
"en": {
|
|
94
|
+
"description": "Reconnect automatically after disconnecting (default true)."
|
|
95
|
+
}
|
|
96
|
+
}
|
|
41
97
|
},
|
|
42
98
|
"outboundMedia": {
|
|
43
99
|
"type": "string",
|
|
44
|
-
"enum": [
|
|
100
|
+
"enum": [
|
|
101
|
+
"file",
|
|
102
|
+
"base64"
|
|
103
|
+
],
|
|
45
104
|
"default": "file",
|
|
46
|
-
"description": "出站媒体模式:file=落盘本地路径(默认); base64=CQ base64:// 内联"
|
|
105
|
+
"description": "出站媒体模式:file=落盘本地路径(默认); base64=CQ base64:// 内联",
|
|
106
|
+
"x-i18n": {
|
|
107
|
+
"en": {
|
|
108
|
+
"description": "Outbound media mode: file uses local file paths (default); base64 uses inline CQ base64:// data."
|
|
109
|
+
}
|
|
110
|
+
}
|
|
47
111
|
},
|
|
48
112
|
"ignoreSelf": {
|
|
49
113
|
"type": "boolean",
|
|
50
114
|
"default": true,
|
|
51
|
-
"description": "群聊和频道中是否过滤自己的消息(默认 true)"
|
|
115
|
+
"description": "群聊和频道中是否过滤自己的消息(默认 true)",
|
|
116
|
+
"x-i18n": {
|
|
117
|
+
"en": {
|
|
118
|
+
"description": "Filter the bot's own messages in groups and channels (default true)."
|
|
119
|
+
}
|
|
120
|
+
}
|
|
52
121
|
},
|
|
53
122
|
"resend": {
|
|
54
123
|
"type": "boolean",
|
|
55
124
|
"default": false,
|
|
56
|
-
"description": "被风控时是否尝试用分片发送(默认 false)"
|
|
125
|
+
"description": "被风控时是否尝试用分片发送(默认 false)",
|
|
126
|
+
"x-i18n": {
|
|
127
|
+
"en": {
|
|
128
|
+
"description": "Attempt fragmented sending when rate-limited by the platform (default false)."
|
|
129
|
+
}
|
|
130
|
+
}
|
|
57
131
|
},
|
|
58
132
|
"cacheGroupMember": {
|
|
59
133
|
"type": "boolean",
|
|
60
134
|
"default": true,
|
|
61
|
-
"description": "是否缓存群员列表(默认 true);群多时(500+)会多占约 100MB+ 内存"
|
|
135
|
+
"description": "是否缓存群员列表(默认 true);群多时(500+)会多占约 100MB+ 内存",
|
|
136
|
+
"x-i18n": {
|
|
137
|
+
"en": {
|
|
138
|
+
"description": "Cache group member lists (default true). Large numbers of groups (500+) may use approximately 100 MB or more of extra memory."
|
|
139
|
+
}
|
|
140
|
+
}
|
|
62
141
|
},
|
|
63
142
|
"autoServer": {
|
|
64
143
|
"type": "boolean",
|
|
65
144
|
"default": true,
|
|
66
|
-
"description": "是否自动选择最优服务器(默认 true)"
|
|
145
|
+
"description": "是否自动选择最优服务器(默认 true)",
|
|
146
|
+
"x-i18n": {
|
|
147
|
+
"en": {
|
|
148
|
+
"description": "Automatically select the optimal server (default true)."
|
|
149
|
+
}
|
|
150
|
+
}
|
|
67
151
|
},
|
|
68
152
|
"qqnt": {
|
|
69
153
|
"type": "boolean",
|
|
70
154
|
"default": true,
|
|
71
|
-
"description": "是否使用 QQNT 协议(默认 true)"
|
|
155
|
+
"description": "是否使用 QQNT 协议(默认 true)",
|
|
156
|
+
"x-i18n": {
|
|
157
|
+
"en": {
|
|
158
|
+
"description": "Use the QQNT protocol (default true)."
|
|
159
|
+
}
|
|
160
|
+
}
|
|
72
161
|
},
|
|
73
162
|
"ntLogin": {
|
|
74
163
|
"type": "boolean",
|
|
75
|
-
"description": "是否使用 NT 登录方式"
|
|
164
|
+
"description": "是否使用 NT 登录方式",
|
|
165
|
+
"x-i18n": {
|
|
166
|
+
"en": {
|
|
167
|
+
"description": "Use the NT login method."
|
|
168
|
+
}
|
|
169
|
+
}
|
|
76
170
|
},
|
|
77
171
|
"endpoints": {
|
|
78
172
|
"type": "array",
|
|
@@ -88,81 +182,195 @@
|
|
|
88
182
|
"description": "QQ uin"
|
|
89
183
|
},
|
|
90
184
|
"master": {
|
|
91
|
-
"type": [
|
|
92
|
-
|
|
185
|
+
"type": [
|
|
186
|
+
"string",
|
|
187
|
+
"number"
|
|
188
|
+
],
|
|
189
|
+
"description": "本 endpoint 的 master QQ uin;覆盖顶层 master",
|
|
190
|
+
"x-i18n": {
|
|
191
|
+
"en": {
|
|
192
|
+
"description": "Master QQ uin list for this endpoint, overriding the top-level master list."
|
|
193
|
+
}
|
|
194
|
+
}
|
|
93
195
|
},
|
|
94
196
|
"trusted": {
|
|
95
197
|
"type": "array",
|
|
96
|
-
"items": {
|
|
97
|
-
|
|
198
|
+
"items": {
|
|
199
|
+
"type": [
|
|
200
|
+
"string",
|
|
201
|
+
"number"
|
|
202
|
+
]
|
|
203
|
+
},
|
|
204
|
+
"description": "本 endpoint 的 trusted 列表",
|
|
205
|
+
"x-i18n": {
|
|
206
|
+
"en": {
|
|
207
|
+
"description": "Trusted users for this endpoint."
|
|
208
|
+
}
|
|
209
|
+
}
|
|
98
210
|
},
|
|
99
211
|
"password": {
|
|
100
212
|
"type": "string",
|
|
101
|
-
"description": "本 endpoint 的 QQ 密码"
|
|
213
|
+
"description": "本 endpoint 的 QQ 密码",
|
|
214
|
+
"x-i18n": {
|
|
215
|
+
"en": {
|
|
216
|
+
"description": "QQ password for this endpoint."
|
|
217
|
+
}
|
|
218
|
+
}
|
|
102
219
|
},
|
|
103
220
|
"platform": {
|
|
104
221
|
"type": "number",
|
|
105
|
-
"enum": [
|
|
106
|
-
|
|
222
|
+
"enum": [
|
|
223
|
+
1,
|
|
224
|
+
2,
|
|
225
|
+
3,
|
|
226
|
+
4,
|
|
227
|
+
5,
|
|
228
|
+
6,
|
|
229
|
+
7
|
|
230
|
+
],
|
|
231
|
+
"description": "登录设备平台:1=Android, 2=aPad, 3=Watch, 4=iMac, 5=iPad, 6=Tim, 7=Custom",
|
|
232
|
+
"x-i18n": {
|
|
233
|
+
"en": {
|
|
234
|
+
"description": "Login device platform: 1=Android, 2=aPad, 3=Watch, 4=iMac, 5=iPad, 6=Tim, 7=Custom."
|
|
235
|
+
}
|
|
236
|
+
}
|
|
107
237
|
},
|
|
108
238
|
"ver": {
|
|
109
239
|
"type": "string",
|
|
110
|
-
"description": "协议版本号"
|
|
240
|
+
"description": "协议版本号",
|
|
241
|
+
"x-i18n": {
|
|
242
|
+
"en": {
|
|
243
|
+
"description": "Protocol version."
|
|
244
|
+
}
|
|
245
|
+
}
|
|
111
246
|
},
|
|
112
247
|
"signApiAddr": {
|
|
113
248
|
"type": "string",
|
|
114
|
-
"description": "签名服务器地址"
|
|
249
|
+
"description": "签名服务器地址",
|
|
250
|
+
"x-i18n": {
|
|
251
|
+
"en": {
|
|
252
|
+
"description": "Signing server URL."
|
|
253
|
+
}
|
|
254
|
+
}
|
|
115
255
|
},
|
|
116
256
|
"dataDir": {
|
|
117
257
|
"type": "string",
|
|
118
|
-
"description": "数据存储文件夹路径"
|
|
258
|
+
"description": "数据存储文件夹路径",
|
|
259
|
+
"x-i18n": {
|
|
260
|
+
"en": {
|
|
261
|
+
"description": "Data directory path."
|
|
262
|
+
}
|
|
263
|
+
}
|
|
119
264
|
},
|
|
120
265
|
"autoReconnect": {
|
|
121
266
|
"type": "boolean",
|
|
122
|
-
"description": "断线后是否自动重连"
|
|
267
|
+
"description": "断线后是否自动重连",
|
|
268
|
+
"x-i18n": {
|
|
269
|
+
"en": {
|
|
270
|
+
"description": "Reconnect automatically after disconnecting."
|
|
271
|
+
}
|
|
272
|
+
}
|
|
123
273
|
},
|
|
124
274
|
"outboundMedia": {
|
|
125
275
|
"type": "string",
|
|
126
|
-
"enum": [
|
|
127
|
-
|
|
276
|
+
"enum": [
|
|
277
|
+
"file",
|
|
278
|
+
"base64"
|
|
279
|
+
],
|
|
280
|
+
"description": "出站媒体模式",
|
|
281
|
+
"x-i18n": {
|
|
282
|
+
"en": {
|
|
283
|
+
"description": "Outbound media mode."
|
|
284
|
+
}
|
|
285
|
+
}
|
|
128
286
|
},
|
|
129
287
|
"ignoreSelf": {
|
|
130
288
|
"type": "boolean",
|
|
131
|
-
"description": "是否过滤自己的消息"
|
|
289
|
+
"description": "是否过滤自己的消息",
|
|
290
|
+
"x-i18n": {
|
|
291
|
+
"en": {
|
|
292
|
+
"description": "Filter the bot's own messages."
|
|
293
|
+
}
|
|
294
|
+
}
|
|
132
295
|
},
|
|
133
296
|
"resend": {
|
|
134
297
|
"type": "boolean",
|
|
135
|
-
"description": "被风控时是否分片发送"
|
|
298
|
+
"description": "被风控时是否分片发送",
|
|
299
|
+
"x-i18n": {
|
|
300
|
+
"en": {
|
|
301
|
+
"description": "Use fragmented sending when rate-limited by the platform."
|
|
302
|
+
}
|
|
303
|
+
}
|
|
136
304
|
},
|
|
137
305
|
"cacheGroupMember": {
|
|
138
306
|
"type": "boolean",
|
|
139
|
-
"description": "是否缓存群员列表"
|
|
307
|
+
"description": "是否缓存群员列表",
|
|
308
|
+
"x-i18n": {
|
|
309
|
+
"en": {
|
|
310
|
+
"description": "Cache group member lists."
|
|
311
|
+
}
|
|
312
|
+
}
|
|
140
313
|
},
|
|
141
314
|
"autoServer": {
|
|
142
315
|
"type": "boolean",
|
|
143
|
-
"description": "是否自动选择最优服务器"
|
|
316
|
+
"description": "是否自动选择最优服务器",
|
|
317
|
+
"x-i18n": {
|
|
318
|
+
"en": {
|
|
319
|
+
"description": "Automatically select the optimal server."
|
|
320
|
+
}
|
|
321
|
+
}
|
|
144
322
|
},
|
|
145
323
|
"qqnt": {
|
|
146
324
|
"type": "boolean",
|
|
147
|
-
"description": "是否使用 QQNT 协议"
|
|
325
|
+
"description": "是否使用 QQNT 协议",
|
|
326
|
+
"x-i18n": {
|
|
327
|
+
"en": {
|
|
328
|
+
"description": "Use the QQNT protocol."
|
|
329
|
+
}
|
|
330
|
+
}
|
|
148
331
|
},
|
|
149
332
|
"ntLogin": {
|
|
150
333
|
"type": "boolean",
|
|
151
|
-
"description": "是否使用 NT 登录方式"
|
|
334
|
+
"description": "是否使用 NT 登录方式",
|
|
335
|
+
"x-i18n": {
|
|
336
|
+
"en": {
|
|
337
|
+
"description": "Use the NT login method."
|
|
338
|
+
}
|
|
339
|
+
}
|
|
152
340
|
},
|
|
153
341
|
"commandPrefix": {
|
|
154
342
|
"type": "string",
|
|
155
|
-
"description": "本 endpoint 的命令前缀"
|
|
343
|
+
"description": "本 endpoint 的命令前缀",
|
|
344
|
+
"x-i18n": {
|
|
345
|
+
"en": {
|
|
346
|
+
"description": "Command prefix for this endpoint."
|
|
347
|
+
}
|
|
348
|
+
}
|
|
156
349
|
}
|
|
157
350
|
},
|
|
158
|
-
"required": [
|
|
351
|
+
"required": [
|
|
352
|
+
"id"
|
|
353
|
+
]
|
|
354
|
+
},
|
|
355
|
+
"x-i18n": {
|
|
356
|
+
"en": {
|
|
357
|
+
"description": "Multiple accounts: mount multiple endpoints in one plugin instance. Each entry uses the top-level fields; id is required and other fields override defaults."
|
|
358
|
+
}
|
|
159
359
|
}
|
|
160
360
|
},
|
|
161
361
|
"commandPrefix": {
|
|
162
362
|
"type": "string",
|
|
163
363
|
"default": "",
|
|
164
|
-
"description": "命令前缀(默认 '' 无前缀)。endpoints[i] 可逐项覆盖"
|
|
364
|
+
"description": "命令前缀(默认 '' 无前缀)。endpoints[i] 可逐项覆盖",
|
|
365
|
+
"x-i18n": {
|
|
366
|
+
"en": {
|
|
367
|
+
"description": "Command prefix, empty by default. Each endpoints[i] can override it."
|
|
368
|
+
}
|
|
369
|
+
}
|
|
165
370
|
}
|
|
166
371
|
},
|
|
167
|
-
"required": [
|
|
372
|
+
"required": [
|
|
373
|
+
"master",
|
|
374
|
+
"endpoints"
|
|
375
|
+
]
|
|
168
376
|
}
|
package/src/endpoint.ts
CHANGED
|
@@ -67,6 +67,7 @@ export interface IcqqEndpointOptions {
|
|
|
67
67
|
readonly id: CapabilityId;
|
|
68
68
|
readonly config: ResolvedIcqqConfig;
|
|
69
69
|
readonly loginAssist: LoginAssist;
|
|
70
|
+
readonly locale?: import('zhin.js/i18n').Locale;
|
|
70
71
|
}
|
|
71
72
|
|
|
72
73
|
const BOUND_EVENTS = [
|
|
@@ -149,6 +150,11 @@ export class IcqqEndpoint extends Endpoint<Client> {
|
|
|
149
150
|
deleteFriend: async (userId) => {
|
|
150
151
|
await this.client.deleteFriend(Number(userId));
|
|
151
152
|
},
|
|
153
|
+
sendGroupNotice: async (groupId, content) => {
|
|
154
|
+
if (await this.client.sendGroupNotice(Number(groupId), content) === false) {
|
|
155
|
+
throw new Error('QQ did not confirm the group notice');
|
|
156
|
+
}
|
|
157
|
+
},
|
|
152
158
|
});
|
|
153
159
|
|
|
154
160
|
readonly control: EndpointControl = Object.freeze({
|
|
@@ -699,6 +705,7 @@ export class IcqqEndpoint extends Endpoint<Client> {
|
|
|
699
705
|
this.#logSystemEvent(`login.${step}`, event);
|
|
700
706
|
void runIcqqLoginAssistStep({
|
|
701
707
|
assist: this.#options.loginAssist,
|
|
708
|
+
locale: this.#options.locale,
|
|
702
709
|
client: this.client,
|
|
703
710
|
adapter: 'icqq',
|
|
704
711
|
endpointKey: this.endpointName,
|
package/src/i18n.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { createMessages } from 'zhin.js/i18n';
|
|
2
|
+
|
|
3
|
+
export const messages = createMessages({
|
|
4
|
+
"direct": {
|
|
5
|
+
"zh-CN": "direct(直连 @icqqjs/icqq)",
|
|
6
|
+
"en": "direct (@icqqjs/icqq)"
|
|
7
|
+
},
|
|
8
|
+
"addUsage": {
|
|
9
|
+
"zh-CN": "用法:{command} <uin>(uin 为纯数字 QQ 号)",
|
|
10
|
+
"en": "Usage: {command} <uin> (a numeric QQ account ID)"
|
|
11
|
+
},
|
|
12
|
+
"uinRequired": {
|
|
13
|
+
"zh-CN": "请提供纯数字 QQ 号(uin)",
|
|
14
|
+
"en": "Provide a numeric QQ account ID (uin)"
|
|
15
|
+
},
|
|
16
|
+
"uinInvalid": {
|
|
17
|
+
"zh-CN": "icqq endpoint 名必须是纯数字 QQ 号(uin)",
|
|
18
|
+
"en": "The ICQQ endpoint name must be a numeric QQ account ID (uin)"
|
|
19
|
+
},
|
|
20
|
+
"endpointAdded": {
|
|
21
|
+
"zh-CN": "✅ endpoint「{id}」已追加到 {file} 的 plugins.icqq.endpoints。\n重启 zhin 后生效。",
|
|
22
|
+
"en": "✅ Endpoint “{id}” added to plugins.icqq.endpoints in {file}.\nRestart zhin to apply."
|
|
23
|
+
},
|
|
24
|
+
"endpointAddFailed": {
|
|
25
|
+
"zh-CN": "添加失败:{error}",
|
|
26
|
+
"en": "Could not add the endpoint: {error}"
|
|
27
|
+
},
|
|
28
|
+
"loginQr": {
|
|
29
|
+
"zh-CN": "扫码登录:请在手机 QQ 扫描二维码,完成后在 Console / 终端确认继续",
|
|
30
|
+
"en": "Scan the QR code in mobile QQ, then confirm in Console or your terminal."
|
|
31
|
+
},
|
|
32
|
+
"loginSlider": {
|
|
33
|
+
"zh-CN": "滑动验证:打开链接完成滑块,将返回的 ticket(可含 randstr)提交继续",
|
|
34
|
+
"en": "Open the link, complete the slider challenge, and submit the returned ticket (with randstr if provided)."
|
|
35
|
+
},
|
|
36
|
+
"loginSms": {
|
|
37
|
+
"zh-CN": "设备锁:已请求短信验证码,请提交短信验证码继续",
|
|
38
|
+
"en": "Device verification: an SMS code was requested. Submit the code to continue."
|
|
39
|
+
},
|
|
40
|
+
"loginAuth": {
|
|
41
|
+
"zh-CN": "身份验证:完成后在 Console / 终端确认继续",
|
|
42
|
+
"en": "Complete identity verification, then confirm in Console or your terminal."
|
|
43
|
+
},
|
|
44
|
+
"loginOther": {
|
|
45
|
+
"zh-CN": "登录辅助({step})",
|
|
46
|
+
"en": "Login assistance ({step})"
|
|
47
|
+
}
|
|
48
|
+
});
|
package/src/icqq-login-assist.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { Locale } from 'zhin.js/i18n';
|
|
2
|
+
import { messages as t } from './i18n.js';
|
|
1
3
|
import type { LoginAssist, LoginAssistType, PendingLoginTaskPayload } from '@zhin.js/core';
|
|
2
4
|
import { formatCompact } from '@zhin.js/logger';
|
|
3
5
|
|
|
@@ -27,11 +29,12 @@ export async function runIcqqLoginAssistStep(input: {
|
|
|
27
29
|
logger: Logger;
|
|
28
30
|
step: LoginAssistType;
|
|
29
31
|
event: unknown;
|
|
32
|
+
locale?: Locale;
|
|
30
33
|
}): Promise<void> {
|
|
31
34
|
const { assist, client, adapter, endpointKey, owner, logger, step, event } = input;
|
|
32
35
|
assist.cancelOwned(owner, `replaced_by_${step}`);
|
|
33
36
|
|
|
34
|
-
const payload = buildPayload(step, event);
|
|
37
|
+
const payload = buildPayload(step, event, input.locale);
|
|
35
38
|
logger.info(formatCompact({
|
|
36
39
|
op: 'login_assist_pending',
|
|
37
40
|
endpoint: endpointKey,
|
|
@@ -82,33 +85,33 @@ export async function runIcqqLoginAssistStep(input: {
|
|
|
82
85
|
}
|
|
83
86
|
}
|
|
84
87
|
|
|
85
|
-
function buildPayload(step: LoginAssistType, event: unknown): PendingLoginTaskPayload {
|
|
88
|
+
function buildPayload(step: LoginAssistType, event: unknown, locale?: Locale): PendingLoginTaskPayload {
|
|
86
89
|
const raw = event && typeof event === 'object' ? event as Record<string, unknown> : {};
|
|
87
90
|
switch (step) {
|
|
88
91
|
case 'qrcode':
|
|
89
92
|
return {
|
|
90
|
-
message:
|
|
93
|
+
message: t(locale, 'loginQr'),
|
|
91
94
|
image: bufferToDataUrl(raw.image),
|
|
92
95
|
};
|
|
93
96
|
case 'slider':
|
|
94
97
|
return {
|
|
95
|
-
message:
|
|
98
|
+
message: t(locale, 'loginSlider'),
|
|
96
99
|
url: typeof raw.url === 'string' ? raw.url : undefined,
|
|
97
100
|
};
|
|
98
101
|
case 'device':
|
|
99
102
|
return {
|
|
100
|
-
message: '
|
|
103
|
+
message: t(locale, 'loginSms'),
|
|
101
104
|
url: typeof raw.url === 'string' ? raw.url : undefined,
|
|
102
105
|
phone: raw.phone,
|
|
103
106
|
};
|
|
104
107
|
case 'auth':
|
|
105
108
|
return {
|
|
106
|
-
message:
|
|
109
|
+
message: t(locale, 'loginAuth'),
|
|
107
110
|
url: typeof raw.url === 'string' ? raw.url : undefined,
|
|
108
111
|
device: raw.device,
|
|
109
112
|
};
|
|
110
113
|
default:
|
|
111
|
-
return { message:
|
|
114
|
+
return { message: t(locale, 'loginOther', { step }) };
|
|
112
115
|
}
|
|
113
116
|
}
|
|
114
117
|
|
package/src/protocol.ts
CHANGED
|
@@ -269,6 +269,7 @@ export interface ResolvedIcqqConfig {
|
|
|
269
269
|
export interface IcqqWireSegment {
|
|
270
270
|
readonly type: string;
|
|
271
271
|
readonly data?: Record<string, unknown>;
|
|
272
|
+
readonly platform?: Readonly<Record<string, unknown>>;
|
|
272
273
|
}
|
|
273
274
|
|
|
274
275
|
export interface IcqqInboundMessage {
|
|
@@ -394,6 +395,7 @@ const ICQQ_STANDALONE_ELEMENTS = new Set([
|
|
|
394
395
|
'json',
|
|
395
396
|
'share',
|
|
396
397
|
'long_msg',
|
|
398
|
+
'multimsg',
|
|
397
399
|
] as const);
|
|
398
400
|
|
|
399
401
|
/** Normalize inline image bytes before either temporary-file or native-base64 delivery. */
|
|
@@ -461,7 +463,7 @@ export function formatOutboundMessages(payload: unknown): Sendable[] {
|
|
|
461
463
|
}
|
|
462
464
|
const messages = groups.filter(group => group.some(element => typeof element === 'string'
|
|
463
465
|
? element.trim() !== ''
|
|
464
|
-
: element.type !== 'reply'));
|
|
466
|
+
: element.type !== 'reply' && element.type !== 'quote'));
|
|
465
467
|
if (messages.length === 0) return ['\u200b'];
|
|
466
468
|
return messages.map(group => group.length === 1 ? group[0]! : group);
|
|
467
469
|
}
|
|
@@ -502,6 +504,13 @@ function formatOutboundElements(payload: readonly unknown[]): (string | MessageE
|
|
|
502
504
|
case 'reply': {
|
|
503
505
|
const id = String(item.data?.message_id ?? item.data?.id ?? '').trim();
|
|
504
506
|
if (!id) throw new TypeError('ICQQ reply segment requires message_id');
|
|
507
|
+
const quote = item.platform?.icqqQuote as Record<string, unknown> | undefined;
|
|
508
|
+
if (quote) {
|
|
509
|
+
const { user_id, seq, rand, time, message } = quote;
|
|
510
|
+
if (typeof user_id !== 'number' || typeof seq !== 'number' || typeof rand !== 'number'
|
|
511
|
+
|| typeof time !== 'number' || typeof message !== 'string') throw new TypeError('Invalid ICQQ quote source');
|
|
512
|
+
return { type: 'quote', user_id, seq, rand, time, message };
|
|
513
|
+
}
|
|
505
514
|
return { type: 'reply', id };
|
|
506
515
|
}
|
|
507
516
|
case 'record':
|
|
@@ -528,6 +537,9 @@ function formatOutboundElements(payload: readonly unknown[]): (string | MessageE
|
|
|
528
537
|
case 'forward': {
|
|
529
538
|
const resid = String(item.data?.forward_id ?? item.data?.resid ?? item.data?.id ?? '').trim();
|
|
530
539
|
if (!resid) throw new TypeError('ICQQ forward segment requires forward_id');
|
|
540
|
+
// Prepared merged forwards need their filename; a long_msg would expand inline.
|
|
541
|
+
const filename = item.platform?.icqqForwardFilename;
|
|
542
|
+
if (typeof filename === 'string' && filename) return { type: 'multimsg', resid, filename };
|
|
531
543
|
return { type: 'long_msg', resid };
|
|
532
544
|
}
|
|
533
545
|
case 'share':
|