mioku-plugin-admin 2.3.0 → 2.3.1
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/verify.ts +47 -1
- package/config.md +31 -3
- package/notify/welcome.ts +92 -76
- package/package.json +1 -1
- package/verify/chiral.ts +8 -2
- package/verify/config.ts +35 -3
- package/verify/index.ts +3 -3
- package/verify/number.ts +8 -2
- package/verify/reaction.ts +8 -2
package/commands/verify.ts
CHANGED
|
@@ -2,6 +2,8 @@ import type { MiokiContext } from "mioki";
|
|
|
2
2
|
import { getAtUserId, getMemberRole } from "../config";
|
|
3
3
|
import {
|
|
4
4
|
getGroupVerifyConfig,
|
|
5
|
+
MAX_EXTRA_PROMPT_LENGTH,
|
|
6
|
+
normalizeExtraPrompt,
|
|
5
7
|
normalizeVerifyMode,
|
|
6
8
|
upsertGroupVerifyConfig,
|
|
7
9
|
type VerifyConfig,
|
|
@@ -44,7 +46,9 @@ export function registerVerifyCommands(options: VerifyCommandOptions) {
|
|
|
44
46
|
text.startsWith("/绕过验证") ||
|
|
45
47
|
text.startsWith("#绕过验证") ||
|
|
46
48
|
text.startsWith("/重新验证") ||
|
|
47
|
-
text.startsWith("#重新验证")
|
|
49
|
+
text.startsWith("#重新验证") ||
|
|
50
|
+
text.startsWith("/入群提示") ||
|
|
51
|
+
text.startsWith("#入群提示");
|
|
48
52
|
|
|
49
53
|
try {
|
|
50
54
|
const selfId = event.self_id;
|
|
@@ -238,6 +242,48 @@ export function registerVerifyCommands(options: VerifyCommandOptions) {
|
|
|
238
242
|
}
|
|
239
243
|
return;
|
|
240
244
|
}
|
|
245
|
+
|
|
246
|
+
// /入群提示 xxx
|
|
247
|
+
if (text.startsWith("/入群提示") || text.startsWith("#入群提示")) {
|
|
248
|
+
if (!(await ensureAdminPermission())) return;
|
|
249
|
+
|
|
250
|
+
const rawArg = text.replace(/^[/#]入群提示\s*/, "").trim();
|
|
251
|
+
const current = getVerifyConfig();
|
|
252
|
+
const groupCfg = getGroupVerifyConfig(current, groupId);
|
|
253
|
+
|
|
254
|
+
if (!rawArg) {
|
|
255
|
+
if (!groupCfg.extraPrompt) {
|
|
256
|
+
await event.reply("本群还没设置额外的入群提示词哦~", true);
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
await setVerifyConfig(
|
|
260
|
+
upsertGroupVerifyConfig(current, groupId, { extraPrompt: "" }),
|
|
261
|
+
);
|
|
262
|
+
await event.reply("已清空本群额外入群提示词~", true);
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const argLength = Array.from(rawArg).length;
|
|
267
|
+
if (argLength > MAX_EXTRA_PROMPT_LENGTH) {
|
|
268
|
+
await replyAdminErrorNotice({
|
|
269
|
+
ctx,
|
|
270
|
+
event,
|
|
271
|
+
instruction: `用户想设置本群入群提示词,但内容长度 ${argLength} 超过了上限 ${MAX_EXTRA_PROMPT_LENGTH} 字,请明确告诉用户最多 ${MAX_EXTRA_PROMPT_LENGTH} 字。`,
|
|
272
|
+
fallbackMessage: `最多 ${MAX_EXTRA_PROMPT_LENGTH} 字哦~当前 ${argLength} 字`,
|
|
273
|
+
});
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const next = upsertGroupVerifyConfig(current, groupId, {
|
|
278
|
+
extraPrompt: normalizeExtraPrompt(rawArg),
|
|
279
|
+
});
|
|
280
|
+
await setVerifyConfig(next);
|
|
281
|
+
await event.reply(
|
|
282
|
+
`已设置本群额外入群提示词:${normalizeExtraPrompt(rawArg)}`,
|
|
283
|
+
true,
|
|
284
|
+
);
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
241
287
|
} catch (err) {
|
|
242
288
|
ctx.logger.error(`[admin verify] 未捕获异常: ${String(err)}`);
|
|
243
289
|
if (!isVerifyCommand) return;
|
package/config.md
CHANGED
|
@@ -74,9 +74,37 @@ fields:
|
|
|
74
74
|
|
|
75
75
|
- key: verify.groups
|
|
76
76
|
label: 各群入群验证配置
|
|
77
|
-
type:
|
|
78
|
-
description:
|
|
79
|
-
|
|
77
|
+
type: array
|
|
78
|
+
description:
|
|
79
|
+
itemFields:
|
|
80
|
+
- key: groupId
|
|
81
|
+
label: 群号
|
|
82
|
+
type: number
|
|
83
|
+
description: 该配置对应的 QQ 群号,每个群只能出现一次
|
|
84
|
+
placeholder: 123456789
|
|
85
|
+
|
|
86
|
+
- key: enabled
|
|
87
|
+
label: 启用验证
|
|
88
|
+
type: switch
|
|
89
|
+
description: 是否对该群开启入群验证
|
|
90
|
+
|
|
91
|
+
- key: mode
|
|
92
|
+
label: 验证模式
|
|
93
|
+
type: select
|
|
94
|
+
options:
|
|
95
|
+
- value: reaction
|
|
96
|
+
label: 回应
|
|
97
|
+
- value: number
|
|
98
|
+
label: 数字
|
|
99
|
+
- value: chiral
|
|
100
|
+
label: 手性碳
|
|
101
|
+
description: 该群入群验证使用的模式
|
|
102
|
+
|
|
103
|
+
- key: extraPrompt
|
|
104
|
+
label: 群额外入群提示词
|
|
105
|
+
type: textarea
|
|
106
|
+
description: 拼接在该群默认验证提示词之后发送,上限 50 字。可在群里直接用 /入群提示 xxx 设置或清空。
|
|
107
|
+
placeholder: 例:本群禁止复读机器人消息,请自觉
|
|
80
108
|
|
|
81
109
|
- key: verify.reactionEmojiId
|
|
82
110
|
label: 回应模式表态表情ID
|
package/notify/welcome.ts
CHANGED
|
@@ -75,8 +75,16 @@ async function flushBatch(options: {
|
|
|
75
75
|
members: PendingMember[];
|
|
76
76
|
promptInjections?: { content: string; title?: string }[];
|
|
77
77
|
}): Promise<string> {
|
|
78
|
-
const {
|
|
79
|
-
|
|
78
|
+
const {
|
|
79
|
+
ctx,
|
|
80
|
+
aiService,
|
|
81
|
+
config,
|
|
82
|
+
selfId,
|
|
83
|
+
groupId,
|
|
84
|
+
groupName,
|
|
85
|
+
members,
|
|
86
|
+
promptInjections,
|
|
87
|
+
} = options;
|
|
80
88
|
if (!members.length) return "";
|
|
81
89
|
|
|
82
90
|
const names = members.map((m) => m.memberName || String(m.userId));
|
|
@@ -106,7 +114,7 @@ async function flushBatch(options: {
|
|
|
106
114
|
groupId,
|
|
107
115
|
send: true,
|
|
108
116
|
instruction: [
|
|
109
|
-
`当前有 ${members.length} 位新成员同时入群,请一次性发送一段统一的欢迎语(不要逐个 @
|
|
117
|
+
`当前有 ${members.length} 位新成员同时入群,请一次性发送一段统一的欢迎语(不要逐个 @ 欢迎、不要重复点名)不要长篇大论,精简即可。`,
|
|
110
118
|
`新成员昵称:${userList}`,
|
|
111
119
|
`新成员 QQ:${userIdList}`,
|
|
112
120
|
`所在群:${groupName}`,
|
|
@@ -209,87 +217,47 @@ export function registerWelcomeHandler(
|
|
|
209
217
|
): () => void {
|
|
210
218
|
const batches = getBatchMap();
|
|
211
219
|
|
|
212
|
-
const dispose = ctx.handle(
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
220
|
+
const dispose = ctx.handle(
|
|
221
|
+
"notice.group.increase" as any,
|
|
222
|
+
async (event: any) => {
|
|
223
|
+
const cfg = getConfig();
|
|
224
|
+
const selfId = Number(event?.self_id || ctx.self_id);
|
|
225
|
+
const groupId = Number(event?.group_id || 0);
|
|
226
|
+
const userId = Number(event?.user_id || 0);
|
|
227
|
+
if (!groupId || !userId) return;
|
|
228
|
+
if (userId === selfId) return;
|
|
219
229
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
if (
|
|
224
|
-
shouldSuppress &&
|
|
225
|
-
(await shouldSuppress({ selfId, groupId, userId, groupName }))
|
|
226
|
-
) {
|
|
227
|
-
return;
|
|
228
|
-
}
|
|
230
|
+
const groupName =
|
|
231
|
+
String(event?.group?.group_name || "").trim() || String(groupId);
|
|
229
232
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
const memberName = await resolveMemberName(ctx, groupId, userId, selfId);
|
|
236
|
-
const welcomeMessage = await flushBatch({
|
|
237
|
-
ctx,
|
|
238
|
-
aiService,
|
|
239
|
-
config: cfg,
|
|
240
|
-
selfId,
|
|
241
|
-
groupId,
|
|
242
|
-
groupName,
|
|
243
|
-
members: [{ userId, memberName }],
|
|
244
|
-
});
|
|
245
|
-
if (!welcomeMessage) return;
|
|
246
|
-
const bot = ctx.pickBot(selfId);
|
|
247
|
-
if (!bot) return;
|
|
248
|
-
try {
|
|
249
|
-
await bot.sendGroupMsg(groupId, [ctx.segment.text(welcomeMessage)]);
|
|
250
|
-
} catch (error) {
|
|
251
|
-
ctx.logger.warn(`发送入群欢迎失败: ${error}`);
|
|
233
|
+
if (
|
|
234
|
+
shouldSuppress &&
|
|
235
|
+
(await shouldSuppress({ selfId, groupId, userId, groupName }))
|
|
236
|
+
) {
|
|
237
|
+
return;
|
|
252
238
|
}
|
|
253
|
-
return;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
const key = batchKey(selfId, groupId);
|
|
257
|
-
let state = batches.get(key);
|
|
258
|
-
if (!state) {
|
|
259
|
-
state = { members: [], timer: null, groupName };
|
|
260
|
-
batches.set(key, state);
|
|
261
|
-
}
|
|
262
|
-
if (groupName && groupName !== String(groupId)) {
|
|
263
|
-
state.groupName = groupName;
|
|
264
|
-
}
|
|
265
239
|
|
|
266
|
-
|
|
267
|
-
if (!state.members.some((m) => m.userId === userId)) {
|
|
268
|
-
state.members.push({ userId, memberName });
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
if (state.timer) {
|
|
272
|
-
return;
|
|
273
|
-
}
|
|
240
|
+
if (!cfg.welcome.enabled) return;
|
|
274
241
|
|
|
275
|
-
|
|
276
|
-
try {
|
|
277
|
-
const pending = state;
|
|
278
|
-
batches.delete(key);
|
|
279
|
-
if (!pending || !pending.members.length) return;
|
|
242
|
+
const batchWindowMs = Math.max(0, Number(cfg.welcome.batchWindowMs) || 0);
|
|
280
243
|
|
|
281
|
-
|
|
244
|
+
if (batchWindowMs === 0) {
|
|
245
|
+
const memberName = await resolveMemberName(
|
|
246
|
+
ctx,
|
|
247
|
+
groupId,
|
|
248
|
+
userId,
|
|
249
|
+
selfId,
|
|
250
|
+
);
|
|
282
251
|
const welcomeMessage = await flushBatch({
|
|
283
252
|
ctx,
|
|
284
253
|
aiService,
|
|
285
|
-
config:
|
|
254
|
+
config: cfg,
|
|
286
255
|
selfId,
|
|
287
256
|
groupId,
|
|
288
|
-
groupName
|
|
289
|
-
members:
|
|
257
|
+
groupName,
|
|
258
|
+
members: [{ userId, memberName }],
|
|
290
259
|
});
|
|
291
260
|
if (!welcomeMessage) return;
|
|
292
|
-
|
|
293
261
|
const bot = ctx.pickBot(selfId);
|
|
294
262
|
if (!bot) return;
|
|
295
263
|
try {
|
|
@@ -297,11 +265,59 @@ export function registerWelcomeHandler(
|
|
|
297
265
|
} catch (error) {
|
|
298
266
|
ctx.logger.warn(`发送入群欢迎失败: ${error}`);
|
|
299
267
|
}
|
|
300
|
-
|
|
301
|
-
ctx.logger.error(`admin welcome 批次处理失败: ${error}`);
|
|
268
|
+
return;
|
|
302
269
|
}
|
|
303
|
-
|
|
304
|
-
|
|
270
|
+
|
|
271
|
+
const key = batchKey(selfId, groupId);
|
|
272
|
+
let state = batches.get(key);
|
|
273
|
+
if (!state) {
|
|
274
|
+
state = { members: [], timer: null, groupName };
|
|
275
|
+
batches.set(key, state);
|
|
276
|
+
}
|
|
277
|
+
if (groupName && groupName !== String(groupId)) {
|
|
278
|
+
state.groupName = groupName;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const memberName = await resolveMemberName(ctx, groupId, userId, selfId);
|
|
282
|
+
if (!state.members.some((m) => m.userId === userId)) {
|
|
283
|
+
state.members.push({ userId, memberName });
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (state.timer) {
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
state.timer = setTimeout(async () => {
|
|
291
|
+
try {
|
|
292
|
+
const pending = state;
|
|
293
|
+
batches.delete(key);
|
|
294
|
+
if (!pending || !pending.members.length) return;
|
|
295
|
+
|
|
296
|
+
const currentConfig = getConfig();
|
|
297
|
+
const welcomeMessage = await flushBatch({
|
|
298
|
+
ctx,
|
|
299
|
+
aiService,
|
|
300
|
+
config: currentConfig,
|
|
301
|
+
selfId,
|
|
302
|
+
groupId,
|
|
303
|
+
groupName: pending.groupName,
|
|
304
|
+
members: pending.members,
|
|
305
|
+
});
|
|
306
|
+
if (!welcomeMessage) return;
|
|
307
|
+
|
|
308
|
+
const bot = ctx.pickBot(selfId);
|
|
309
|
+
if (!bot) return;
|
|
310
|
+
try {
|
|
311
|
+
await bot.sendGroupMsg(groupId, [ctx.segment.text(welcomeMessage)]);
|
|
312
|
+
} catch (error) {
|
|
313
|
+
ctx.logger.warn(`发送入群欢迎失败: ${error}`);
|
|
314
|
+
}
|
|
315
|
+
} catch (error) {
|
|
316
|
+
ctx.logger.error(`admin welcome 批次处理失败: ${error}`);
|
|
317
|
+
}
|
|
318
|
+
}, batchWindowMs);
|
|
319
|
+
},
|
|
320
|
+
);
|
|
305
321
|
|
|
306
322
|
return () => {
|
|
307
323
|
for (const state of batches.values()) {
|
|
@@ -310,4 +326,4 @@ export function registerWelcomeHandler(
|
|
|
310
326
|
batches.clear();
|
|
311
327
|
dispose();
|
|
312
328
|
};
|
|
313
|
-
}
|
|
329
|
+
}
|
package/package.json
CHANGED
package/verify/chiral.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import type { MiokiContext } from "mioki";
|
|
2
|
-
import
|
|
2
|
+
import {
|
|
3
|
+
resolveVerifyPrompt,
|
|
4
|
+
type VerifyConfig,
|
|
5
|
+
type VerifyGroupConfig,
|
|
6
|
+
} from "./config";
|
|
3
7
|
import type { PendingVerify } from "./types";
|
|
4
8
|
|
|
5
9
|
interface ChiralCaptcha {
|
|
@@ -43,6 +47,7 @@ async function fetchChiralCaptcha(
|
|
|
43
47
|
export async function prepareChiral(
|
|
44
48
|
ctx: MiokiContext,
|
|
45
49
|
cfg: VerifyConfig,
|
|
50
|
+
groupCfg: VerifyGroupConfig,
|
|
46
51
|
p: PendingVerify,
|
|
47
52
|
): Promise<boolean> {
|
|
48
53
|
const bot = ctx.pickBot(p.selfId);
|
|
@@ -51,10 +56,11 @@ export async function prepareChiral(
|
|
|
51
56
|
const captcha = await fetchChiralCaptcha(cfg.chiralApiUrl, cfg.chiralDifficulty);
|
|
52
57
|
p.requiredRegions = captcha.regions;
|
|
53
58
|
p.matchedRegions = new Set<string>();
|
|
54
|
-
const
|
|
59
|
+
const basePrompt = cfg.chiralPrompt.replace(
|
|
55
60
|
"{count}",
|
|
56
61
|
String(captcha.regions.length),
|
|
57
62
|
);
|
|
63
|
+
const prompt = resolveVerifyPrompt(basePrompt, groupCfg);
|
|
58
64
|
await bot.sendGroupMsg(p.groupId, [
|
|
59
65
|
ctx.segment.at(String(p.userId)),
|
|
60
66
|
ctx.segment.text(` ${prompt}`),
|
package/verify/config.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
export type VerifyMode = "reaction" | "number" | "chiral";
|
|
2
2
|
|
|
3
|
+
export const MAX_EXTRA_PROMPT_LENGTH = 50;
|
|
4
|
+
|
|
3
5
|
export interface VerifyGroupConfig {
|
|
4
6
|
groupId: number;
|
|
5
7
|
enabled: boolean;
|
|
6
8
|
mode: VerifyMode;
|
|
9
|
+
extraPrompt: string;
|
|
7
10
|
}
|
|
8
11
|
|
|
9
12
|
export interface VerifyConfig {
|
|
@@ -39,6 +42,22 @@ export const DEFAULT_VERIFY_CONFIG: VerifyConfig = {
|
|
|
39
42
|
kickOnTimeout: true,
|
|
40
43
|
};
|
|
41
44
|
|
|
45
|
+
export function normalizeExtraPrompt(value: unknown): string {
|
|
46
|
+
if (typeof value !== "string") return "";
|
|
47
|
+
const trimmed = value.trim();
|
|
48
|
+
if (!trimmed) return "";
|
|
49
|
+
return Array.from(trimmed).slice(0, MAX_EXTRA_PROMPT_LENGTH).join("");
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function resolveVerifyPrompt(
|
|
53
|
+
basePrompt: string,
|
|
54
|
+
groupCfg: VerifyGroupConfig | undefined,
|
|
55
|
+
): string {
|
|
56
|
+
const extra = String(groupCfg?.extraPrompt || "").trim();
|
|
57
|
+
if (!extra) return basePrompt;
|
|
58
|
+
return `${basePrompt}\n${extra}`;
|
|
59
|
+
}
|
|
60
|
+
|
|
42
61
|
export function normalizeVerifyMode(value: unknown): VerifyMode {
|
|
43
62
|
const v = String(value || "").trim();
|
|
44
63
|
if (v === "number" || v === "数字") return "number";
|
|
@@ -52,6 +71,7 @@ function normalizeVerifyGroup(raw: any): VerifyGroupConfig {
|
|
|
52
71
|
groupId: groupId > 0 ? groupId : 0,
|
|
53
72
|
enabled: raw?.enabled === true,
|
|
54
73
|
mode: normalizeVerifyMode(raw?.mode),
|
|
74
|
+
extraPrompt: normalizeExtraPrompt(raw?.extraPrompt ?? raw?.extra_prompt),
|
|
55
75
|
};
|
|
56
76
|
}
|
|
57
77
|
|
|
@@ -113,7 +133,7 @@ export function getGroupVerifyConfig(
|
|
|
113
133
|
): VerifyGroupConfig {
|
|
114
134
|
const found = config.groups.find((g) => g.groupId === groupId);
|
|
115
135
|
if (found) return found;
|
|
116
|
-
return { groupId, enabled: false, mode: "reaction" };
|
|
136
|
+
return { groupId, enabled: false, mode: "reaction", extraPrompt: "" };
|
|
117
137
|
}
|
|
118
138
|
|
|
119
139
|
export function upsertGroupVerifyConfig(
|
|
@@ -123,14 +143,26 @@ export function upsertGroupVerifyConfig(
|
|
|
123
143
|
): VerifyConfig {
|
|
124
144
|
const idx = config.groups.findIndex((g) => g.groupId === groupId);
|
|
125
145
|
const next = { ...config };
|
|
146
|
+
const normalizedPatch: Partial<Omit<VerifyGroupConfig, "groupId">> = {
|
|
147
|
+
...patch,
|
|
148
|
+
};
|
|
149
|
+
if (patch.extraPrompt !== undefined) {
|
|
150
|
+
normalizedPatch.extraPrompt = normalizeExtraPrompt(patch.extraPrompt);
|
|
151
|
+
}
|
|
126
152
|
if (idx >= 0) {
|
|
127
153
|
next.groups = config.groups.map((g, i) =>
|
|
128
|
-
i === idx ? { ...g, ...
|
|
154
|
+
i === idx ? { ...g, ...normalizedPatch } : g,
|
|
129
155
|
);
|
|
130
156
|
} else {
|
|
131
157
|
next.groups = [
|
|
132
158
|
...config.groups,
|
|
133
|
-
{
|
|
159
|
+
{
|
|
160
|
+
groupId,
|
|
161
|
+
enabled: false,
|
|
162
|
+
mode: "reaction",
|
|
163
|
+
extraPrompt: "",
|
|
164
|
+
...normalizedPatch,
|
|
165
|
+
},
|
|
134
166
|
];
|
|
135
167
|
}
|
|
136
168
|
return next;
|
package/verify/index.ts
CHANGED
|
@@ -204,12 +204,12 @@ export function createVerifyController(
|
|
|
204
204
|
const delay = skipDelay ? 0 : Math.max(0, cfg.reactionDelayMs);
|
|
205
205
|
entry.delayTimer = setTimeout(() => {
|
|
206
206
|
entry.delayTimer = null;
|
|
207
|
-
void sendReactionPrompt(ctx, cfg, entry);
|
|
207
|
+
void sendReactionPrompt(ctx, cfg, groupCfg, entry);
|
|
208
208
|
}, delay);
|
|
209
209
|
} else if (mode === "number") {
|
|
210
|
-
void sendNumberPrompt(ctx, cfg, entry);
|
|
210
|
+
void sendNumberPrompt(ctx, cfg, groupCfg, entry);
|
|
211
211
|
} else if (mode === "chiral") {
|
|
212
|
-
const ok = await prepareChiral(ctx, cfg, entry);
|
|
212
|
+
const ok = await prepareChiral(ctx, cfg, groupCfg, entry);
|
|
213
213
|
if (!ok) {
|
|
214
214
|
// 验证服务不可用时放行,避免误伤
|
|
215
215
|
removePending(key);
|
package/verify/number.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import type { MiokiContext } from "mioki";
|
|
2
|
-
import
|
|
2
|
+
import {
|
|
3
|
+
resolveVerifyPrompt,
|
|
4
|
+
type VerifyConfig,
|
|
5
|
+
type VerifyGroupConfig,
|
|
6
|
+
} from "./config";
|
|
3
7
|
import type { PendingVerify } from "./types";
|
|
4
8
|
|
|
5
9
|
function genNumberQuestion(): { question: string; answer: number } {
|
|
@@ -19,13 +23,15 @@ function extractNumbers(text: string): number[] {
|
|
|
19
23
|
export async function sendNumberPrompt(
|
|
20
24
|
ctx: MiokiContext,
|
|
21
25
|
cfg: VerifyConfig,
|
|
26
|
+
groupCfg: VerifyGroupConfig,
|
|
22
27
|
p: PendingVerify,
|
|
23
28
|
): Promise<void> {
|
|
24
29
|
const bot = ctx.pickBot(p.selfId);
|
|
25
30
|
if (!bot) return;
|
|
26
31
|
const { question, answer } = genNumberQuestion();
|
|
27
32
|
p.numberAnswer = answer;
|
|
28
|
-
const
|
|
33
|
+
const basePrompt = cfg.numberPrompt.replace("{question}", question);
|
|
34
|
+
const prompt = resolveVerifyPrompt(basePrompt, groupCfg);
|
|
29
35
|
try {
|
|
30
36
|
await bot.sendGroupMsg(p.groupId, [
|
|
31
37
|
ctx.segment.at(String(p.userId)),
|
package/verify/reaction.ts
CHANGED
|
@@ -1,19 +1,25 @@
|
|
|
1
1
|
import type { MiokiContext } from "mioki";
|
|
2
|
-
import
|
|
2
|
+
import {
|
|
3
|
+
resolveVerifyPrompt,
|
|
4
|
+
type VerifyConfig,
|
|
5
|
+
type VerifyGroupConfig,
|
|
6
|
+
} from "./config";
|
|
3
7
|
import type { PendingVerify } from "./types";
|
|
4
8
|
|
|
5
9
|
export async function sendReactionPrompt(
|
|
6
10
|
ctx: MiokiContext,
|
|
7
11
|
cfg: VerifyConfig,
|
|
12
|
+
groupCfg: VerifyGroupConfig,
|
|
8
13
|
p: PendingVerify,
|
|
9
14
|
): Promise<void> {
|
|
10
15
|
const bot = ctx.pickBot(p.selfId);
|
|
11
16
|
if (!bot) return;
|
|
17
|
+
const prompt = resolveVerifyPrompt(cfg.reactionPrompt, groupCfg);
|
|
12
18
|
let messageId: number | undefined;
|
|
13
19
|
try {
|
|
14
20
|
const res = await bot.sendGroupMsg(p.groupId, [
|
|
15
21
|
ctx.segment.at(String(p.userId)),
|
|
16
|
-
ctx.segment.text(` ${
|
|
22
|
+
ctx.segment.text(` ${prompt}`),
|
|
17
23
|
]);
|
|
18
24
|
messageId = Number(res?.message_id || 0) || undefined;
|
|
19
25
|
} catch (err) {
|