mioku-plugin-admin 3.0.1 → 3.0.3
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/commands/group.ts +41 -52
- package/commands/notice.ts +2 -2
- package/commands/personal.ts +29 -30
- package/commands/verify.ts +15 -16
- package/config.ts +20 -10
- package/notify/index.ts +64 -57
- package/notify/welcome.ts +31 -31
- package/package.json +1 -1
- package/skills/group.ts +9 -7
- package/skills/message-image.ts +18 -8
- package/skills/personal.ts +2 -2
- package/utils/prompt-image-store.ts +7 -7
- package/verify/config.ts +6 -6
- package/verify/index.ts +16 -31
- package/verify/reaction.ts +35 -10
- package/verify/state.ts +2 -2
- package/verify/types.ts +7 -7
package/commands/group.ts
CHANGED
|
@@ -21,7 +21,7 @@ function formatGroupRole(role: string): string {
|
|
|
21
21
|
|
|
22
22
|
type GroupContext = CommandExecutionContext & {
|
|
23
23
|
bot: Bot;
|
|
24
|
-
groupIdNum:
|
|
24
|
+
groupIdNum: string;
|
|
25
25
|
senderRole: string;
|
|
26
26
|
};
|
|
27
27
|
|
|
@@ -32,19 +32,20 @@ export function registerGroupAdminCommands(ctx: MiokuContext) {
|
|
|
32
32
|
) => {
|
|
33
33
|
ctx.command({
|
|
34
34
|
...def,
|
|
35
|
-
|
|
35
|
+
// 原设计:裸命令与 /命令 都可用;这里保留两者并补上 . 前缀
|
|
36
|
+
prefixes: ["", ".", "/"],
|
|
36
37
|
handler: async (c) => {
|
|
37
38
|
const event = c.event;
|
|
38
39
|
if (event.user_id === event.self_id) return;
|
|
39
40
|
if (event.message_type !== "group") return;
|
|
40
41
|
const bot = event.bot;
|
|
41
42
|
if (!bot) return;
|
|
42
|
-
const groupIdNum = event.group_id
|
|
43
|
+
const groupIdNum = String(event.group_id ?? "").trim();
|
|
43
44
|
if (!groupIdNum) return;
|
|
44
45
|
const senderRole = await getMemberRole(
|
|
45
46
|
bot,
|
|
46
47
|
groupIdNum,
|
|
47
|
-
|
|
48
|
+
String(event.user_id ?? "").trim(),
|
|
48
49
|
);
|
|
49
50
|
try {
|
|
50
51
|
await run({ ...c, bot, groupIdNum, senderRole });
|
|
@@ -64,7 +65,7 @@ export function registerGroupAdminCommands(ctx: MiokuContext) {
|
|
|
64
65
|
|
|
65
66
|
const ensureDangerousTargetPermission = async (
|
|
66
67
|
c: GroupContext,
|
|
67
|
-
targetUserId:
|
|
68
|
+
targetUserId: string,
|
|
68
69
|
actionName: string,
|
|
69
70
|
): Promise<boolean> => {
|
|
70
71
|
const { bot, groupIdNum, senderRole, event } = c;
|
|
@@ -89,7 +90,7 @@ export function registerGroupAdminCommands(ctx: MiokuContext) {
|
|
|
89
90
|
async (c) => {
|
|
90
91
|
const { ctx, event, bot, groupIdNum, body } = c;
|
|
91
92
|
const atUser = getAtUserId(event.message);
|
|
92
|
-
if (atUser != null && atUser !==
|
|
93
|
+
if (atUser != null && atUser !== String(event.user_id ?? "").trim()) {
|
|
93
94
|
await event.reply("管好自己呗~", true);
|
|
94
95
|
return;
|
|
95
96
|
}
|
|
@@ -115,47 +116,43 @@ export function registerGroupAdminCommands(ctx: MiokuContext) {
|
|
|
115
116
|
|
|
116
117
|
register(
|
|
117
118
|
{
|
|
118
|
-
name: "
|
|
119
|
-
match:
|
|
119
|
+
name: "改头衔",
|
|
120
|
+
match: /^\/??改头衔(?:\s|$)/,
|
|
120
121
|
permission: "admin",
|
|
121
122
|
description: "设置群成员专属头衔",
|
|
122
|
-
usage: "
|
|
123
|
+
usage: ".改头衔 <用户ID或@人> 头衔",
|
|
123
124
|
},
|
|
124
125
|
async (c) => {
|
|
125
126
|
const { ctx, event, bot, groupIdNum, body } = c;
|
|
126
|
-
const rest = body.replace(
|
|
127
|
+
const rest = body.replace(/^\/??改头衔\s*/, "").trim();
|
|
127
128
|
const atUser = getAtUserId(event.message);
|
|
128
|
-
let targetUser:
|
|
129
|
+
let targetUser: string | undefined = atUser;
|
|
129
130
|
let title: string;
|
|
130
131
|
|
|
131
|
-
const isSlashCommand = body.startsWith("/");
|
|
132
|
-
|
|
133
132
|
if (atUser) {
|
|
134
|
-
title = rest.replace(
|
|
133
|
+
title = rest.replace(/@[A-Za-z0-9_-]{4,64}\s*/, "").trim();
|
|
135
134
|
} else {
|
|
136
135
|
const parts = rest.split(/\s+/);
|
|
137
136
|
if (parts.length < 2) {
|
|
138
|
-
if (!isSlashCommand) return;
|
|
139
137
|
await replyAdminErrorNotice({
|
|
140
138
|
ctx,
|
|
141
139
|
event,
|
|
142
140
|
instruction:
|
|
143
|
-
"
|
|
141
|
+
"用户在让你修改别人的头衔时缺少参数,请提示用户命令后需要加用户ID或@人",
|
|
144
142
|
fallbackMessage: "想改谁的头衔呀~",
|
|
145
143
|
});
|
|
146
144
|
return;
|
|
147
145
|
}
|
|
148
|
-
targetUser =
|
|
146
|
+
targetUser = String(parts[0]).trim();
|
|
149
147
|
title = parts.slice(1).join(" ");
|
|
150
148
|
}
|
|
151
149
|
|
|
152
150
|
if (!targetUser || !title) {
|
|
153
|
-
if (!isSlashCommand) return;
|
|
154
151
|
await replyAdminErrorNotice({
|
|
155
152
|
ctx,
|
|
156
153
|
event,
|
|
157
154
|
instruction:
|
|
158
|
-
"
|
|
155
|
+
"用户触发改头衔时参数无效,请提示用户命令后需要加用户ID或@人",
|
|
159
156
|
fallbackMessage: "想改谁的头衔呀~",
|
|
160
157
|
});
|
|
161
158
|
return;
|
|
@@ -178,16 +175,14 @@ export function registerGroupAdminCommands(ctx: MiokuContext) {
|
|
|
178
175
|
|
|
179
176
|
register(
|
|
180
177
|
{
|
|
181
|
-
name: "
|
|
182
|
-
match:
|
|
178
|
+
name: "踢",
|
|
179
|
+
match: /^\/??踢(?:\s|$)/,
|
|
183
180
|
permission: "admin",
|
|
184
181
|
description: "踢出群成员",
|
|
185
182
|
},
|
|
186
183
|
async (c) => {
|
|
187
184
|
const { ctx, event, bot, groupIdNum, body } = c;
|
|
188
185
|
const atUser = getAtUserId(event.message);
|
|
189
|
-
const isSlashCommand = body.startsWith("/");
|
|
190
|
-
if (!atUser && !isSlashCommand) return;
|
|
191
186
|
if (!atUser) {
|
|
192
187
|
await replyAdminErrorNotice({
|
|
193
188
|
ctx,
|
|
@@ -216,17 +211,15 @@ export function registerGroupAdminCommands(ctx: MiokuContext) {
|
|
|
216
211
|
|
|
217
212
|
register(
|
|
218
213
|
{
|
|
219
|
-
name: "
|
|
220
|
-
match:
|
|
214
|
+
name: "禁言",
|
|
215
|
+
match: /^\/??禁(?:言)?(?:\s|$)/,
|
|
221
216
|
permission: "admin",
|
|
222
217
|
description: "禁言群成员(支持分钟/小时/天)",
|
|
223
|
-
usage: "
|
|
218
|
+
usage: ".禁言 @人 10分钟",
|
|
224
219
|
},
|
|
225
220
|
async (c) => {
|
|
226
221
|
const { ctx, event, bot, groupIdNum, body } = c;
|
|
227
222
|
const atUser = getAtUserId(event.message);
|
|
228
|
-
const isSlashCommand = body.startsWith("/");
|
|
229
|
-
if (!atUser && !isSlashCommand) return;
|
|
230
223
|
if (!atUser) {
|
|
231
224
|
await replyAdminErrorNotice({
|
|
232
225
|
ctx,
|
|
@@ -238,8 +231,8 @@ export function registerGroupAdminCommands(ctx: MiokuContext) {
|
|
|
238
231
|
return;
|
|
239
232
|
}
|
|
240
233
|
if (!(await ensureDangerousTargetPermission(c, atUser, "禁言"))) return;
|
|
241
|
-
const rest = body.replace(
|
|
242
|
-
const durationStr = rest.replace(
|
|
234
|
+
const rest = body.replace(/^\/??禁言\s*/, "").trim();
|
|
235
|
+
const durationStr = rest.replace(/@[A-Za-z0-9_-]{4,64}\s*/, "").trim();
|
|
243
236
|
const durationSec = parseDuration(durationStr) || 10 * 60;
|
|
244
237
|
try {
|
|
245
238
|
await bot.banMember(groupIdNum, atUser, durationSec);
|
|
@@ -258,16 +251,14 @@ export function registerGroupAdminCommands(ctx: MiokuContext) {
|
|
|
258
251
|
|
|
259
252
|
register(
|
|
260
253
|
{
|
|
261
|
-
name: "
|
|
262
|
-
match:
|
|
254
|
+
name: "解禁",
|
|
255
|
+
match: /^\/??解(?:禁)?(?:\s|$)/,
|
|
263
256
|
permission: "admin",
|
|
264
257
|
description: "解除群成员禁言",
|
|
265
258
|
},
|
|
266
259
|
async (c) => {
|
|
267
260
|
const { ctx, event, bot, groupIdNum, body } = c;
|
|
268
261
|
const atUser = getAtUserId(event.message);
|
|
269
|
-
const isSlashCommand = body.startsWith("/");
|
|
270
|
-
if (!atUser && !isSlashCommand) return;
|
|
271
262
|
if (!atUser) {
|
|
272
263
|
await replyAdminErrorNotice({
|
|
273
264
|
ctx,
|
|
@@ -295,16 +286,14 @@ export function registerGroupAdminCommands(ctx: MiokuContext) {
|
|
|
295
286
|
|
|
296
287
|
register(
|
|
297
288
|
{
|
|
298
|
-
name: "
|
|
299
|
-
match:
|
|
289
|
+
name: "设管理",
|
|
290
|
+
match: /^\/??设管理(?:\s|$)/,
|
|
300
291
|
permission: "admin",
|
|
301
292
|
description: "设置群管理员",
|
|
302
293
|
},
|
|
303
294
|
async (c) => {
|
|
304
295
|
const { ctx, event, bot, groupIdNum, body } = c;
|
|
305
296
|
const atUser = getAtUserId(event.message);
|
|
306
|
-
const isSlashCommand = body.startsWith("/");
|
|
307
|
-
if (!atUser && !isSlashCommand) return;
|
|
308
297
|
if (!atUser) {
|
|
309
298
|
await replyAdminErrorNotice({
|
|
310
299
|
ctx,
|
|
@@ -332,8 +321,8 @@ export function registerGroupAdminCommands(ctx: MiokuContext) {
|
|
|
332
321
|
|
|
333
322
|
register(
|
|
334
323
|
{
|
|
335
|
-
name: "
|
|
336
|
-
match:
|
|
324
|
+
name: "全体禁言",
|
|
325
|
+
match: /^\/?全体禁言$/,
|
|
337
326
|
permission: "admin",
|
|
338
327
|
description: "开启全体禁言",
|
|
339
328
|
},
|
|
@@ -356,8 +345,8 @@ export function registerGroupAdminCommands(ctx: MiokuContext) {
|
|
|
356
345
|
|
|
357
346
|
register(
|
|
358
347
|
{
|
|
359
|
-
name: "
|
|
360
|
-
match:
|
|
348
|
+
name: "全体解禁",
|
|
349
|
+
match: /^\/?全体解禁$/,
|
|
361
350
|
permission: "admin",
|
|
362
351
|
description: "关闭全体禁言",
|
|
363
352
|
},
|
|
@@ -380,14 +369,14 @@ export function registerGroupAdminCommands(ctx: MiokuContext) {
|
|
|
380
369
|
|
|
381
370
|
register(
|
|
382
371
|
{
|
|
383
|
-
name: "
|
|
384
|
-
match:
|
|
372
|
+
name: "改群名片",
|
|
373
|
+
match: /^\/??改群名片(?:\s|$)/,
|
|
385
374
|
permission: "admin",
|
|
386
375
|
description: "修改Bot在群里的名片",
|
|
387
376
|
},
|
|
388
377
|
async (c) => {
|
|
389
378
|
const { ctx, event, bot, groupIdNum, body } = c;
|
|
390
|
-
const card = body.replace(
|
|
379
|
+
const card = body.replace(/^\/??改群名片\s*/, "").trim();
|
|
391
380
|
if (!card) {
|
|
392
381
|
await replyAdminErrorNotice({
|
|
393
382
|
ctx,
|
|
@@ -414,14 +403,14 @@ export function registerGroupAdminCommands(ctx: MiokuContext) {
|
|
|
414
403
|
|
|
415
404
|
register(
|
|
416
405
|
{
|
|
417
|
-
name: "
|
|
418
|
-
match:
|
|
406
|
+
name: "改群昵称",
|
|
407
|
+
match: /^\/?改群昵称/,
|
|
419
408
|
permission: "admin",
|
|
420
409
|
description: "修改群聊名称",
|
|
421
410
|
},
|
|
422
411
|
async (c) => {
|
|
423
412
|
const { ctx, event, bot, groupIdNum, body } = c;
|
|
424
|
-
const groupName = body.replace(
|
|
413
|
+
const groupName = body.replace(/^\/?改群昵称\s*/, "").trim();
|
|
425
414
|
if (!groupName) {
|
|
426
415
|
await replyAdminErrorNotice({
|
|
427
416
|
ctx,
|
|
@@ -449,8 +438,8 @@ export function registerGroupAdminCommands(ctx: MiokuContext) {
|
|
|
449
438
|
|
|
450
439
|
register(
|
|
451
440
|
{
|
|
452
|
-
name: "
|
|
453
|
-
match:
|
|
441
|
+
name: "改群头像",
|
|
442
|
+
match: /^\/?改群头像/,
|
|
454
443
|
permission: "admin",
|
|
455
444
|
description: "修改群头像",
|
|
456
445
|
},
|
|
@@ -484,8 +473,8 @@ export function registerGroupAdminCommands(ctx: MiokuContext) {
|
|
|
484
473
|
|
|
485
474
|
register(
|
|
486
475
|
{
|
|
487
|
-
name: "
|
|
488
|
-
match:
|
|
476
|
+
name: "撤回",
|
|
477
|
+
match: /^\/??撤回(?:\s|$)/,
|
|
489
478
|
permission: "admin",
|
|
490
479
|
description: "撤回别人的消息",
|
|
491
480
|
usage: "引用一条消息后输入 /撤回",
|
package/commands/notice.ts
CHANGED
|
@@ -23,8 +23,8 @@ export async function replyAdminErrorNotice(options: {
|
|
|
23
23
|
error?: unknown;
|
|
24
24
|
}): Promise<void> {
|
|
25
25
|
const text = options.ctx.text(options.event)?.trim() ?? "";
|
|
26
|
-
|
|
27
|
-
if (
|
|
26
|
+
// 只对真正的命令消息做 AI 兜底提示,普通聊天不打扰(命令支持 / 与 . 前缀)
|
|
27
|
+
if (!/^[./]/.test(text)) {
|
|
28
28
|
return;
|
|
29
29
|
}
|
|
30
30
|
if (options.error != null) {
|
package/commands/personal.ts
CHANGED
|
@@ -154,7 +154,6 @@ export function registerPersonalCommands(ctx: MiokuContext) {
|
|
|
154
154
|
const { handler, ...rest } = command;
|
|
155
155
|
ctx.command({
|
|
156
156
|
...rest,
|
|
157
|
-
prefixes: false,
|
|
158
157
|
handler: async (c) => {
|
|
159
158
|
if (c.event.user_id === c.event.self_id) return;
|
|
160
159
|
await handler(c);
|
|
@@ -163,8 +162,8 @@ export function registerPersonalCommands(ctx: MiokuContext) {
|
|
|
163
162
|
};
|
|
164
163
|
|
|
165
164
|
register({
|
|
166
|
-
name: "
|
|
167
|
-
match:
|
|
165
|
+
name: "改头像",
|
|
166
|
+
match: /^\/?改头像/,
|
|
168
167
|
permission: "master",
|
|
169
168
|
description: "修改Bot头像",
|
|
170
169
|
handler: async ({ event }) => {
|
|
@@ -191,14 +190,14 @@ export function registerPersonalCommands(ctx: MiokuContext) {
|
|
|
191
190
|
});
|
|
192
191
|
|
|
193
192
|
register({
|
|
194
|
-
name: "
|
|
195
|
-
match:
|
|
193
|
+
name: "改昵称",
|
|
194
|
+
match: /^\/?改昵称/,
|
|
196
195
|
permission: "master",
|
|
197
196
|
description: "修改Bot昵称",
|
|
198
197
|
handler: async ({ event, body }) => {
|
|
199
198
|
const bot = event.bot;
|
|
200
199
|
if (!bot) return;
|
|
201
|
-
const nickname = body.replace(
|
|
200
|
+
const nickname = body.replace(/^\/?改昵称\s*/, "").trim();
|
|
202
201
|
if (!nickname) {
|
|
203
202
|
await event.reply("想改成什么昵称呀~", true);
|
|
204
203
|
return;
|
|
@@ -219,14 +218,14 @@ export function registerPersonalCommands(ctx: MiokuContext) {
|
|
|
219
218
|
});
|
|
220
219
|
|
|
221
220
|
register({
|
|
222
|
-
name: "
|
|
223
|
-
match:
|
|
221
|
+
name: "改签名",
|
|
222
|
+
match: /^\/?改签名/,
|
|
224
223
|
permission: "master",
|
|
225
224
|
description: "修改Bot个性签名",
|
|
226
225
|
handler: async ({ event, body }) => {
|
|
227
226
|
const bot = event.bot;
|
|
228
227
|
if (!bot) return;
|
|
229
|
-
const personalNote = body.replace(
|
|
228
|
+
const personalNote = body.replace(/^\/?改签名\s*/, "").trim();
|
|
230
229
|
if (!personalNote) {
|
|
231
230
|
await event.reply("想改成什么签名呀~", true);
|
|
232
231
|
return;
|
|
@@ -247,14 +246,14 @@ export function registerPersonalCommands(ctx: MiokuContext) {
|
|
|
247
246
|
});
|
|
248
247
|
|
|
249
248
|
register({
|
|
250
|
-
name: "
|
|
251
|
-
match:
|
|
249
|
+
name: "改性别",
|
|
250
|
+
match: /^\/?改性别/,
|
|
252
251
|
permission: "master",
|
|
253
252
|
description: "修改Bot性别",
|
|
254
253
|
handler: async ({ event, body }) => {
|
|
255
254
|
const bot = event.bot;
|
|
256
255
|
if (!bot) return;
|
|
257
|
-
const sex = parseProfileSex(body.replace(
|
|
256
|
+
const sex = parseProfileSex(body.replace(/^\/?改性别\s*/, ""));
|
|
258
257
|
try {
|
|
259
258
|
await bot.setProfile({ sex });
|
|
260
259
|
await event.reply("done");
|
|
@@ -271,15 +270,15 @@ export function registerPersonalCommands(ctx: MiokuContext) {
|
|
|
271
270
|
});
|
|
272
271
|
|
|
273
272
|
register({
|
|
274
|
-
name: "
|
|
275
|
-
match:
|
|
273
|
+
name: "删好友",
|
|
274
|
+
match: /^\/?删好友(?:\s|$)/,
|
|
276
275
|
permission: "master",
|
|
277
276
|
description: "删除好友",
|
|
278
|
-
usage: "
|
|
277
|
+
usage: ".删好友 qq号",
|
|
279
278
|
handler: async ({ event, body }) => {
|
|
280
279
|
const bot = event.bot;
|
|
281
280
|
if (!bot) return;
|
|
282
|
-
const qq = parseInt(body.replace(
|
|
281
|
+
const qq = parseInt(body.replace(/^\/?删好友\s*/, "").trim(), 10);
|
|
283
282
|
if (!qq) {
|
|
284
283
|
await replyAdminErrorNotice({
|
|
285
284
|
ctx,
|
|
@@ -305,15 +304,15 @@ export function registerPersonalCommands(ctx: MiokuContext) {
|
|
|
305
304
|
});
|
|
306
305
|
|
|
307
306
|
register({
|
|
308
|
-
name: "
|
|
309
|
-
match:
|
|
307
|
+
name: "退群",
|
|
308
|
+
match: /^\/?退群(?:\s|$)/,
|
|
310
309
|
permission: "master",
|
|
311
310
|
description: "退出群聊",
|
|
312
|
-
usage: "
|
|
311
|
+
usage: ".退群 群号",
|
|
313
312
|
handler: async ({ event, body }) => {
|
|
314
313
|
const bot = event.bot;
|
|
315
314
|
if (!bot) return;
|
|
316
|
-
const targetGroup = parseInt(body.replace(
|
|
315
|
+
const targetGroup = parseInt(body.replace(/^\/?退群\s*/, "").trim(), 10);
|
|
317
316
|
if (!targetGroup) {
|
|
318
317
|
await replyAdminErrorNotice({
|
|
319
318
|
ctx,
|
|
@@ -339,11 +338,11 @@ export function registerPersonalCommands(ctx: MiokuContext) {
|
|
|
339
338
|
});
|
|
340
339
|
|
|
341
340
|
register({
|
|
342
|
-
name: "
|
|
343
|
-
match:
|
|
341
|
+
name: "发好友",
|
|
342
|
+
match: /^\/?发好友(?:\s|$)/,
|
|
344
343
|
permission: "master",
|
|
345
344
|
description: "给好友发送私聊消息",
|
|
346
|
-
usage: "
|
|
345
|
+
usage: ".发好友 qq号 内容",
|
|
347
346
|
handler: async ({ event, body }) => {
|
|
348
347
|
const bot = event.bot;
|
|
349
348
|
if (!bot) return;
|
|
@@ -392,11 +391,11 @@ export function registerPersonalCommands(ctx: MiokuContext) {
|
|
|
392
391
|
});
|
|
393
392
|
|
|
394
393
|
register({
|
|
395
|
-
name: "
|
|
396
|
-
match:
|
|
394
|
+
name: "发群聊",
|
|
395
|
+
match: /^\/?发群聊(?:\s|$)/,
|
|
397
396
|
permission: "master",
|
|
398
397
|
description: "给群聊发送消息",
|
|
399
|
-
usage: "
|
|
398
|
+
usage: ".发群聊 群号 内容",
|
|
400
399
|
handler: async ({ event, body }) => {
|
|
401
400
|
const bot = event.bot;
|
|
402
401
|
if (!bot) return;
|
|
@@ -445,8 +444,8 @@ export function registerPersonalCommands(ctx: MiokuContext) {
|
|
|
445
444
|
});
|
|
446
445
|
|
|
447
446
|
register({
|
|
448
|
-
name: "
|
|
449
|
-
match:
|
|
447
|
+
name: "全部好友",
|
|
448
|
+
match: /^\/?全部好友$/,
|
|
450
449
|
permission: "master",
|
|
451
450
|
description: "获取全部好友列表",
|
|
452
451
|
handler: async ({ event }) => {
|
|
@@ -496,8 +495,8 @@ export function registerPersonalCommands(ctx: MiokuContext) {
|
|
|
496
495
|
});
|
|
497
496
|
|
|
498
497
|
register({
|
|
499
|
-
name: "
|
|
500
|
-
match:
|
|
498
|
+
name: "全部群聊",
|
|
499
|
+
match: /^\/?全部群聊$/,
|
|
501
500
|
permission: "master",
|
|
502
501
|
description: "获取全部群聊列表",
|
|
503
502
|
handler: async ({ event }) => {
|
package/commands/verify.ts
CHANGED
|
@@ -37,9 +37,9 @@ const VERIFY_MODE_LABELS: Record<string, string> = {
|
|
|
37
37
|
|
|
38
38
|
type VerifyContext = CommandExecutionContext & {
|
|
39
39
|
bot: Bot;
|
|
40
|
-
groupIdNum:
|
|
40
|
+
groupIdNum: string;
|
|
41
41
|
groupName: string;
|
|
42
|
-
selfId:
|
|
42
|
+
selfId: string;
|
|
43
43
|
};
|
|
44
44
|
|
|
45
45
|
async function extractQuoteImageUrls(event: MessageEvent): Promise<string[]> {
|
|
@@ -61,22 +61,21 @@ export function registerVerifyCommands(options: VerifyCommandOptions) {
|
|
|
61
61
|
) => {
|
|
62
62
|
ctx.command({
|
|
63
63
|
...def,
|
|
64
|
-
prefixes: false,
|
|
65
64
|
handler: async (c) => {
|
|
66
65
|
const event = c.event;
|
|
67
66
|
if (event.user_id === event.self_id) return;
|
|
68
67
|
if (event.message_type !== "group") return;
|
|
69
68
|
const bot = event.bot;
|
|
70
69
|
if (!bot) return;
|
|
71
|
-
const groupIdNum = event.group_id
|
|
70
|
+
const groupIdNum = String(event.group_id ?? "").trim();
|
|
72
71
|
if (!groupIdNum) return;
|
|
73
72
|
try {
|
|
74
73
|
await run({
|
|
75
74
|
...c,
|
|
76
75
|
bot,
|
|
77
76
|
groupIdNum,
|
|
78
|
-
groupName: String(event?.group?.group_name || "").trim() ||
|
|
79
|
-
selfId:
|
|
77
|
+
groupName: String(event?.group?.group_name || "").trim() || groupIdNum,
|
|
78
|
+
selfId: String(event.self_id ?? "").trim(),
|
|
80
79
|
});
|
|
81
80
|
} catch (err) {
|
|
82
81
|
ctx.logger.error(`[admin verify] 未捕获异常: ${String(err)}`);
|
|
@@ -94,7 +93,7 @@ export function registerVerifyCommands(options: VerifyCommandOptions) {
|
|
|
94
93
|
|
|
95
94
|
register(
|
|
96
95
|
{
|
|
97
|
-
name: "
|
|
96
|
+
name: "开启验证",
|
|
98
97
|
match: /^[/#]开启验证$/,
|
|
99
98
|
permission: "admin",
|
|
100
99
|
description: "开启本群入群验证",
|
|
@@ -128,7 +127,7 @@ export function registerVerifyCommands(options: VerifyCommandOptions) {
|
|
|
128
127
|
|
|
129
128
|
register(
|
|
130
129
|
{
|
|
131
|
-
name: "
|
|
130
|
+
name: "关闭验证",
|
|
132
131
|
match: /^[/#]关闭验证$/,
|
|
133
132
|
permission: "admin",
|
|
134
133
|
description: "关闭本群入群验证",
|
|
@@ -151,11 +150,11 @@ export function registerVerifyCommands(options: VerifyCommandOptions) {
|
|
|
151
150
|
|
|
152
151
|
register(
|
|
153
152
|
{
|
|
154
|
-
name: "
|
|
153
|
+
name: "切换验证模式",
|
|
155
154
|
match: /^[/#]切换验证模式(?:\s|$)/,
|
|
156
155
|
permission: "admin",
|
|
157
156
|
description: "切换验证模式:回应/数字/手性碳",
|
|
158
|
-
usage: "
|
|
157
|
+
usage: ".切换验证模式 回应",
|
|
159
158
|
},
|
|
160
159
|
async (c) => {
|
|
161
160
|
const { ctx, event, groupIdNum, body } = c;
|
|
@@ -183,11 +182,11 @@ export function registerVerifyCommands(options: VerifyCommandOptions) {
|
|
|
183
182
|
|
|
184
183
|
register(
|
|
185
184
|
{
|
|
186
|
-
name: "
|
|
185
|
+
name: "绕过验证",
|
|
187
186
|
match: /^[/#]绕过验证(?:\s|$)/,
|
|
188
187
|
permission: "admin",
|
|
189
188
|
description: "绕过指定新成员的验证直接欢迎",
|
|
190
|
-
usage: "
|
|
189
|
+
usage: ".绕过验证 @新成员",
|
|
191
190
|
},
|
|
192
191
|
async (c) => {
|
|
193
192
|
const { ctx, event, groupIdNum, groupName, selfId } = c;
|
|
@@ -224,11 +223,11 @@ export function registerVerifyCommands(options: VerifyCommandOptions) {
|
|
|
224
223
|
|
|
225
224
|
register(
|
|
226
225
|
{
|
|
227
|
-
name: "
|
|
226
|
+
name: "重新验证",
|
|
228
227
|
match: /^[/#]重新验证(?:\s|$)/,
|
|
229
228
|
permission: "admin",
|
|
230
229
|
description: "让指定成员重新进行入群验证",
|
|
231
|
-
usage: "
|
|
230
|
+
usage: ".重新验证 @成员",
|
|
232
231
|
},
|
|
233
232
|
async (c) => {
|
|
234
233
|
const { ctx, event, bot, groupIdNum, groupName, selfId } = c;
|
|
@@ -282,11 +281,11 @@ export function registerVerifyCommands(options: VerifyCommandOptions) {
|
|
|
282
281
|
|
|
283
282
|
register(
|
|
284
283
|
{
|
|
285
|
-
name: "
|
|
284
|
+
name: "入群提示",
|
|
286
285
|
match: /^[/#]入群提示(?:\s|$)/,
|
|
287
286
|
permission: "admin",
|
|
288
287
|
description: "设置本群自定义入群提示,可附带文字+图片",
|
|
289
|
-
usage: "
|
|
288
|
+
usage: ".入群提示 xxx;/入群提示 关闭",
|
|
290
289
|
},
|
|
291
290
|
async (c) => {
|
|
292
291
|
const { ctx, event, groupIdNum, body } = c;
|
package/config.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import type { RecvAtElement, RecvElement, RecvImageElement } from "napcat-sdk";
|
|
2
1
|
|
|
3
2
|
export interface AdminConfig {
|
|
4
|
-
notifyTarget:
|
|
3
|
+
notifyTarget: string[];
|
|
5
4
|
notifyFriendMsg: boolean;
|
|
6
5
|
notifyFriendRequest: boolean;
|
|
7
6
|
notifyGroupInvite: boolean;
|
|
@@ -37,7 +36,9 @@ export const DEFAULT_CONFIG: AdminConfig = {
|
|
|
37
36
|
export function normalizeConfig(raw: any): AdminConfig {
|
|
38
37
|
return {
|
|
39
38
|
notifyTarget: Array.isArray(raw?.notifyTarget)
|
|
40
|
-
? raw.notifyTarget
|
|
39
|
+
? raw.notifyTarget
|
|
40
|
+
.map((v: unknown) => String(v ?? "").trim())
|
|
41
|
+
.filter((id: string) => id.length > 0)
|
|
41
42
|
: DEFAULT_CONFIG.notifyTarget,
|
|
42
43
|
notifyFriendMsg: raw?.notifyFriendMsg ?? DEFAULT_CONFIG.notifyFriendMsg,
|
|
43
44
|
notifyFriendRequest:
|
|
@@ -136,7 +137,9 @@ export function extractImageUrls(message: readonly SegmentLike[] | null | undefi
|
|
|
136
137
|
}
|
|
137
138
|
|
|
138
139
|
// 从消息中提取被@的人的QQ号
|
|
139
|
-
export function getAtUserId(
|
|
140
|
+
export function getAtUserId(
|
|
141
|
+
message: readonly SegmentLike[] | null | undefined,
|
|
142
|
+
): string | undefined {
|
|
140
143
|
if (!Array.isArray(message)) return undefined;
|
|
141
144
|
const atSeg = message.find(
|
|
142
145
|
(seg) =>
|
|
@@ -144,18 +147,25 @@ export function getAtUserId(message: readonly SegmentLike[] | null | undefined):
|
|
|
144
147
|
String(seg.data?.qq ?? seg.data?.target) !== "all",
|
|
145
148
|
);
|
|
146
149
|
if (!atSeg) return undefined;
|
|
147
|
-
const
|
|
148
|
-
return
|
|
150
|
+
const id = String(atSeg.data?.qq ?? atSeg.data?.target ?? "").trim();
|
|
151
|
+
return id || undefined;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/** qlogo 头像服务只认数字 QQ 号,openid 一律返回空串 */
|
|
155
|
+
function qlogoUrl(host: string, id: string, suffix: string): string {
|
|
156
|
+
if (!/^\d+$/.test(id)) return "";
|
|
157
|
+
return `https://${host}/${id}${suffix}`;
|
|
149
158
|
}
|
|
150
159
|
|
|
151
160
|
// 获取群成员头像URL
|
|
152
|
-
export function getAvatarUrl(userId:
|
|
153
|
-
return
|
|
161
|
+
export function getAvatarUrl(userId: string): string {
|
|
162
|
+
return qlogoUrl("q1.qlogo.cn/g?b=qq&nk=", String(userId ?? "").trim(), "&s=640");
|
|
154
163
|
}
|
|
155
164
|
|
|
156
165
|
// 获取群头像URL
|
|
157
|
-
export function getGroupAvatarUrl(groupId:
|
|
158
|
-
const g = String(groupId);
|
|
166
|
+
export function getGroupAvatarUrl(groupId: string): string {
|
|
167
|
+
const g = String(groupId ?? "").trim();
|
|
168
|
+
if (!/^\d+$/.test(g)) return "";
|
|
159
169
|
return `https://p.qlogo.cn/gh/${g}/${g}/640/`;
|
|
160
170
|
}
|
|
161
171
|
|