mioku-plugin-admin 3.0.0 → 3.0.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.
@@ -1,4 +1,10 @@
1
- import type { MiokuContext } from "mioku";
1
+ import type {
2
+ Bot,
3
+ CommandDefinition,
4
+ CommandExecutionContext,
5
+ MessageEvent,
6
+ MiokuContext,
7
+ } from "mioku";
2
8
  import { extractImageUrls, getAtUserId, getMemberRole } from "../config";
3
9
  import {
4
10
  getGroupVerifyConfig,
@@ -29,7 +35,12 @@ const VERIFY_MODE_LABELS: Record<string, string> = {
29
35
  chiral: "手性碳",
30
36
  };
31
37
 
32
- import type { MessageEvent } from "mioku";
38
+ type VerifyContext = CommandExecutionContext & {
39
+ bot: Bot;
40
+ groupIdNum: number;
41
+ groupName: string;
42
+ selfId: number;
43
+ };
33
44
 
34
45
  async function extractQuoteImageUrls(event: MessageEvent): Promise<string[]> {
35
46
  const eventAny = event as MessageEvent & {
@@ -44,345 +55,343 @@ async function extractQuoteImageUrls(event: MessageEvent): Promise<string[]> {
44
55
  export function registerVerifyCommands(options: VerifyCommandOptions) {
45
56
  const { ctx, getVerifyConfig, setVerifyConfig, verifyController } = options;
46
57
 
47
- ctx.handle("message", async (event) => {
48
- const text = ctx.text(event)?.trim();
49
- if (!text) return;
50
- if (event.user_id === event.self_id) return;
51
-
52
- if (event.message_type !== "group") return;
53
- const groupIdNum = event.group_id ? Number(event.group_id) : 0;
54
- if (!groupIdNum) return;
55
-
56
- const isVerifyCommand =
57
- text === "/开启验证" ||
58
- text === "#开启验证" ||
59
- text === "/关闭验证" ||
60
- text === "#关闭验证" ||
61
- text.startsWith("/切换验证模式") ||
62
- text.startsWith("#切换验证模式") ||
63
- text.startsWith("/绕过验证") ||
64
- text.startsWith("#绕过验证") ||
65
- text.startsWith("/重新验证") ||
66
- text.startsWith("#重新验证") ||
67
- text.startsWith("/入群提示") ||
68
- text.startsWith("#入群提示");
69
-
70
- try {
71
- const selfId = Number(event.self_id);
72
- const bot = event.bot;
73
- if (!bot) return;
74
-
75
- const isMaster = ctx.isOwner?.(event) ?? false;
76
- const senderRole = await getMemberRole(bot, groupIdNum, Number(event.user_id));
77
- const hasAdminPermission =
78
- isMaster || senderRole === "owner" || senderRole === "admin";
79
-
80
- const ensureAdminPermission = async (instruction?: string) => {
81
- if (hasAdminPermission) return true;
82
- await replyAdminErrorNotice({
83
- ctx,
84
- event,
85
- instruction:
86
- instruction ||
87
- "用户想使用入群验证相关指令,但不是群主或管理员,无权限。请告诉用户需要管理权限。",
88
- fallbackMessage: "你得是群主或管理员才行哦~",
89
- });
90
- return false;
91
- };
92
-
93
- const groupName =
94
- String(event?.group?.group_name || "").trim() || String(groupIdNum);
95
-
96
- // /开启验证 | #开启验证
97
- if (text === "/开启验证" || text === "#开启验证") {
98
- if (!(await ensureAdminPermission())) return;
99
-
100
- const botRole = await getMemberRole(bot, groupIdNum, selfId);
101
- if (botRole !== "owner" && botRole !== "admin") {
58
+ const register = (
59
+ def: Omit<CommandDefinition, "handler">,
60
+ run: (c: VerifyContext) => Promise<void>,
61
+ ) => {
62
+ ctx.command({
63
+ ...def,
64
+ prefixes: false,
65
+ handler: async (c) => {
66
+ const event = c.event;
67
+ if (event.user_id === event.self_id) return;
68
+ if (event.message_type !== "group") return;
69
+ const bot = event.bot;
70
+ if (!bot) return;
71
+ const groupIdNum = event.group_id ? Number(event.group_id) : 0;
72
+ if (!groupIdNum) return;
73
+ try {
74
+ await run({
75
+ ...c,
76
+ bot,
77
+ groupIdNum,
78
+ groupName: String(event?.group?.group_name || "").trim() || String(groupIdNum),
79
+ selfId: Number(event.self_id),
80
+ });
81
+ } catch (err) {
82
+ ctx.logger.error(`[admin verify] 未捕获异常: ${String(err)}`);
102
83
  await replyAdminErrorNotice({
103
84
  ctx,
104
85
  event,
105
- instruction:
106
- "用户想开启入群验证,但Bot在群内不是群主或管理员,无法执行撤回/踢人等验证操作。请告诉用户需要先把Bot设为群主或管理员。",
107
- fallbackMessage: "我得是群主或管理员才能开验证哦~",
86
+ instruction: `入群验证指令执行时发生未捕获异常:${String(err)},请简要说明失败并建议稍后重试。`,
87
+ fallbackMessage: `出错了,笨蛋~ ${String(err)}`,
88
+ error: err,
108
89
  });
109
- return;
110
90
  }
91
+ },
92
+ });
93
+ };
111
94
 
112
- const current = getVerifyConfig();
113
- const groupCfg = getGroupVerifyConfig(current, groupIdNum);
114
- if (groupCfg.enabled) {
115
- await event.reply("本群已经开启验证啦~", true);
116
- return;
117
- }
118
- const next = upsertGroupVerifyConfig(current, groupIdNum, {
119
- enabled: true,
95
+ register(
96
+ {
97
+ name: "/开启验证",
98
+ match: /^[/#]开启验证$/,
99
+ permission: "admin",
100
+ description: "开启本群入群验证",
101
+ },
102
+ async (c) => {
103
+ const { ctx, event, bot, groupIdNum, selfId } = c;
104
+ const botRole = await getMemberRole(bot, groupIdNum, selfId);
105
+ if (botRole !== "owner" && botRole !== "admin") {
106
+ await replyAdminErrorNotice({
107
+ ctx,
108
+ event,
109
+ instruction:
110
+ "用户想开启入群验证,但Bot在群内不是群主或管理员,无法执行撤回/踢人等验证操作。请告诉用户需要先把Bot设为群主或管理员。",
111
+ fallbackMessage: "我得是群主或管理员才能开验证哦~",
120
112
  });
121
- await setVerifyConfig(next);
122
- await event.reply("已开启入群验证~", true);
123
113
  return;
124
114
  }
125
-
126
- // /关闭验证 | #关闭验证
127
- if (text === "/关闭验证" || text === "#关闭验证") {
128
- if (!(await ensureAdminPermission())) return;
129
-
130
- const current = getVerifyConfig();
131
- const groupCfg = getGroupVerifyConfig(current, groupIdNum);
132
- if (!groupCfg.enabled) {
133
- await event.reply("本群还没开启验证哦~", true);
134
- return;
135
- }
136
- const next = upsertGroupVerifyConfig(current, groupIdNum, {
137
- enabled: false,
115
+ const current = getVerifyConfig();
116
+ const groupCfg = getGroupVerifyConfig(current, groupIdNum);
117
+ if (groupCfg.enabled) {
118
+ await event.reply("本群已经开启验证啦~", true);
119
+ return;
120
+ }
121
+ const next = upsertGroupVerifyConfig(current, groupIdNum, {
122
+ enabled: true,
123
+ });
124
+ await setVerifyConfig(next);
125
+ await event.reply("已开启入群验证~", true);
126
+ },
127
+ );
128
+
129
+ register(
130
+ {
131
+ name: "/关闭验证",
132
+ match: /^[/#]关闭验证$/,
133
+ permission: "admin",
134
+ description: "关闭本群入群验证",
135
+ },
136
+ async (c) => {
137
+ const { event, groupIdNum } = c;
138
+ const current = getVerifyConfig();
139
+ const groupCfg = getGroupVerifyConfig(current, groupIdNum);
140
+ if (!groupCfg.enabled) {
141
+ await event.reply("本群还没开启验证哦~", true);
142
+ return;
143
+ }
144
+ const next = upsertGroupVerifyConfig(current, groupIdNum, {
145
+ enabled: false,
146
+ });
147
+ await setVerifyConfig(next);
148
+ await event.reply("已关闭入群验证~", true);
149
+ },
150
+ );
151
+
152
+ register(
153
+ {
154
+ name: "/切换验证模式",
155
+ match: /^[/#]切换验证模式(?:\s|$)/,
156
+ permission: "admin",
157
+ description: "切换验证模式:回应/数字/手性碳",
158
+ usage: "/切换验证模式 回应",
159
+ },
160
+ async (c) => {
161
+ const { ctx, event, groupIdNum, body } = c;
162
+ const arg = body.replace(/^[/#]切换验证模式\s*/, "").trim();
163
+ const mode = normalizeVerifyMode(arg);
164
+ if (!arg) {
165
+ await replyAdminErrorNotice({
166
+ ctx,
167
+ event,
168
+ instruction:
169
+ "用户想切换验证模式但没指定模式。请告诉用户可用模式:回应、数字、手性碳,用法:/切换验证模式 回应。",
170
+ fallbackMessage: "想切换成哪种模式呀~回应/数字/手性碳",
138
171
  });
139
- await setVerifyConfig(next);
140
- await event.reply("已关闭入群验证~", true);
141
172
  return;
142
173
  }
143
-
144
- // /切换验证模式 回应|数字|手性碳
145
- if (
146
- text.startsWith("/切换验证模式") ||
147
- text.startsWith("#切换验证模式")
148
- ) {
149
- if (!(await ensureAdminPermission())) return;
150
-
151
- const arg = text
152
- .replace(/^[/#]切换验证模式\s*/, "")
153
- .trim() as string;
154
- const mode = normalizeVerifyMode(arg);
155
- if (!arg) {
156
- await replyAdminErrorNotice({
157
- ctx,
158
- event,
159
- instruction:
160
- "用户想切换验证模式但没指定模式。请告诉用户可用模式:回应、数字、手性碳,用法:/切换验证模式 回应。",
161
- fallbackMessage: "想切换成哪种模式呀~回应/数字/手性碳",
162
- });
163
- return;
164
- }
165
-
166
- const current = getVerifyConfig();
167
- const next = upsertGroupVerifyConfig(current, groupIdNum, { mode });
168
- await setVerifyConfig(next);
169
- await event.reply(
170
- `验证模式已切换为:${VERIFY_MODE_LABELS[mode]}~`,
171
- true,
172
- );
174
+ const current = getVerifyConfig();
175
+ const next = upsertGroupVerifyConfig(current, groupIdNum, { mode });
176
+ await setVerifyConfig(next);
177
+ await event.reply(
178
+ `验证模式已切换为:${VERIFY_MODE_LABELS[mode]}~`,
179
+ true,
180
+ );
181
+ },
182
+ );
183
+
184
+ register(
185
+ {
186
+ name: "/绕过验证",
187
+ match: /^[/#]绕过验证(?:\s|$)/,
188
+ permission: "admin",
189
+ description: "绕过指定新成员的验证直接欢迎",
190
+ usage: "/绕过验证 @新成员",
191
+ },
192
+ async (c) => {
193
+ const { ctx, event, groupIdNum, groupName, selfId } = c;
194
+ const atUser = getAtUserId(event.message);
195
+ if (!atUser) {
196
+ await replyAdminErrorNotice({
197
+ ctx,
198
+ event,
199
+ instruction:
200
+ "用户想绕过某位新成员的验证,但没有@目标成员。请提醒用户在命令后@要绕过验证的新成员。",
201
+ fallbackMessage: "要绕过谁呀~先@一下~",
202
+ });
173
203
  return;
174
204
  }
175
-
176
- // /绕过验证 @新成员
177
- if (text.startsWith("/绕过验证") || text.startsWith("#绕过验证")) {
178
- if (!(await ensureAdminPermission())) return;
179
-
180
- const atUser = getAtUserId(event.message);
181
- if (!atUser) {
182
- await replyAdminErrorNotice({
183
- ctx,
184
- event,
185
- instruction:
186
- "用户想绕过某位新成员的验证,但没有@目标成员。请提醒用户在命令后@要绕过验证的新成员。",
187
- fallbackMessage: "要绕过谁呀~先@一下~",
188
- });
189
- return;
190
- }
191
-
192
- try {
193
- await verifyController.bypassVerification({
205
+ try {
206
+ await verifyController.bypassVerification({
207
+ selfId,
208
+ groupId: groupIdNum,
209
+ userId: atUser,
210
+ groupName,
211
+ });
212
+ await event.reply("done");
213
+ } catch (err) {
214
+ await replyAdminErrorNotice({
215
+ ctx,
216
+ event,
217
+ instruction: `绕过验证执行失败:${String(err)},请简要说明失败并建议稍后重试。`,
218
+ fallbackMessage: `出错了,笨蛋~ ${String(err)}`,
219
+ error: err,
220
+ });
221
+ }
222
+ },
223
+ );
224
+
225
+ register(
226
+ {
227
+ name: "/重新验证",
228
+ match: /^[/#]重新验证(?:\s|$)/,
229
+ permission: "admin",
230
+ description: "让指定成员重新进行入群验证",
231
+ usage: "/重新验证 @成员",
232
+ },
233
+ async (c) => {
234
+ const { ctx, event, bot, groupIdNum, groupName, selfId } = c;
235
+ const atUser = getAtUserId(event.message);
236
+ if (!atUser) {
237
+ await replyAdminErrorNotice({
238
+ ctx,
239
+ event,
240
+ instruction:
241
+ "用户想让某人重新进行入群验证,但没有@目标成员。请提醒用户在命令后@要重新验证的成员。",
242
+ fallbackMessage: "要重新验证谁呀~先@一下~",
243
+ });
244
+ return;
245
+ }
246
+ const isTargetMaster = ctx.isMaster?.(atUser) ?? false;
247
+ const targetRole = await getMemberRole(bot, groupIdNum, atUser);
248
+ if (isTargetMaster || targetRole === "owner" || targetRole === "admin") {
249
+ await replyAdminErrorNotice({
250
+ ctx,
251
+ event,
252
+ instruction:
253
+ "用户想让一位群主/管理员/主人重新验证,但这些成员无需验证。请告诉用户该成员是管理/群主或主人,不能对其重新验证。",
254
+ fallbackMessage: "管理/群主或主人可不用验证哦~",
255
+ });
256
+ return;
257
+ }
258
+ try {
259
+ const started = await verifyController.restartVerification(
260
+ {
194
261
  selfId,
195
262
  groupId: groupIdNum,
196
263
  userId: atUser,
197
264
  groupName,
198
- });
199
- await event.reply("done");
200
- } catch (err) {
201
- await replyAdminErrorNotice({
202
- ctx,
203
- event,
204
- instruction: `绕过验证执行失败:${String(err)},请简要说明失败并建议稍后重试。`,
205
- fallbackMessage: `出错了,笨蛋~ ${String(err)}`,
206
- error: err,
207
- });
265
+ },
266
+ bot,
267
+ );
268
+ if (!started) {
269
+ await event.reply("本群还没开启验证哦~", true);
208
270
  }
209
- return;
271
+ } catch (err) {
272
+ await replyAdminErrorNotice({
273
+ ctx,
274
+ event,
275
+ instruction: `重新验证执行失败:${String(err)},请简要说明失败并建议稍后重试。`,
276
+ fallbackMessage: `出错了,笨蛋~ ${String(err)}`,
277
+ error: err,
278
+ });
210
279
  }
211
-
212
- // /重新验证 @某人
213
- if (text.startsWith("/重新验证") || text.startsWith("#重新验证")) {
214
- if (!(await ensureAdminPermission())) return;
215
-
216
- const atUser = getAtUserId(event.message);
217
- if (!atUser) {
218
- await replyAdminErrorNotice({
219
- ctx,
220
- event,
221
- instruction:
222
- "用户想让某人重新进行入群验证,但没有@目标成员。请提醒用户在命令后@要重新验证的成员。",
223
- fallbackMessage: "要重新验证谁呀~先@一下~",
224
- });
280
+ },
281
+ );
282
+
283
+ register(
284
+ {
285
+ name: "/入群提示",
286
+ match: /^[/#]入群提示(?:\s|$)/,
287
+ permission: "admin",
288
+ description: "设置本群自定义入群提示,可附带文字+图片",
289
+ usage: "/入群提示 xxx;/入群提示 关闭",
290
+ },
291
+ async (c) => {
292
+ const { ctx, event, groupIdNum, body } = c;
293
+ const rawArg = body.replace(/^[/#]入群提示\s*/, "").trim();
294
+ const current = getVerifyConfig();
295
+ const groupCfg = getGroupVerifyConfig(current, groupIdNum);
296
+ const directImageUrls = extractImageUrls(event.message);
297
+ const quoteImageUrls = await extractQuoteImageUrls(event).catch(() => []);
298
+ const imageUrls =
299
+ directImageUrls.length > 0 ? directImageUrls : quoteImageUrls;
300
+
301
+ if (rawArg === "关闭" || rawArg === "清空" || rawArg === "关") {
302
+ if (!hasCustomPrompt(groupCfg)) {
303
+ await event.reply("本群还没设置自定义入群提示哦~", true);
225
304
  return;
226
305
  }
306
+ const removedFile = groupCfg.promptImage;
307
+ const next = upsertGroupVerifyConfig(current, groupIdNum, {
308
+ customPrompt: "",
309
+ promptImage: "",
310
+ });
311
+ await setVerifyConfig(next);
312
+ await pruneGroupPromptImages(groupIdNum, []).catch(() => {});
313
+ ctx.logger.info(
314
+ `admin verify 关闭群 ${groupIdNum} 自定义入群提示,清理图片 ${removedFile}`,
315
+ );
316
+ await event.reply("已关闭本群自定义入群提示~", true);
317
+ return;
318
+ }
227
319
 
228
- const isTargetMaster = ctx.isOwner?.(atUser) ?? false;
229
- const targetRole = await getMemberRole(bot, groupIdNum, atUser);
230
- if (isTargetMaster || targetRole === "owner" || targetRole === "admin") {
231
- await replyAdminErrorNotice({
232
- ctx,
233
- event,
234
- instruction:
235
- "用户想让一位群主/管理员/主人重新验证,但这些成员无需验证。请告诉用户该成员是管理/群主或主人,不能对其重新验证。",
236
- fallbackMessage: "管理/群主或主人可不用验证哦~",
237
- });
320
+ if (!rawArg && !imageUrls.length) {
321
+ if (!hasCustomPrompt(groupCfg)) {
322
+ await event.reply(
323
+ "用法:/入群提示 xxx(最多 50 字),可附带图片(当前消息或引用消息中的图片)一起发送;/入群提示 关闭 关闭自定义提示~",
324
+ true,
325
+ );
238
326
  return;
239
327
  }
328
+ const lines = ["已开启本群自定义入群提示"];
329
+ lines.push(
330
+ groupCfg.customPrompt
331
+ ? `文字:${groupCfg.customPrompt}`
332
+ : "文字:(未设置)",
333
+ );
334
+ lines.push(
335
+ groupCfg.promptImage
336
+ ? `图片:已设置(filename=${groupCfg.promptImage})`
337
+ : "图片:(未设置)",
338
+ );
339
+ await event.reply(lines.join("\n"), true);
340
+ return;
341
+ }
240
342
 
241
- try {
242
- const started = await verifyController.restartVerification(
243
- {
244
- selfId,
245
- groupId: groupIdNum,
246
- userId: atUser,
247
- groupName,
248
- },
249
- bot,
250
- );
251
- if (!started) {
252
- await event.reply("本群还没开启验证哦~", true);
253
- }
254
- } catch (err) {
343
+ if (rawArg) {
344
+ const argLength = Array.from(rawArg).length;
345
+ if (argLength > MAX_CUSTOM_PROMPT_LENGTH) {
255
346
  await replyAdminErrorNotice({
256
347
  ctx,
257
348
  event,
258
- instruction: `重新验证执行失败:${String(err)},请简要说明失败并建议稍后重试。`,
259
- fallbackMessage: `出错了,笨蛋~ ${String(err)}`,
260
- error: err,
261
- });
262
- }
263
- return;
264
- }
265
-
266
- // /入群提示 xxx
267
- // /入群提示 关闭
268
- // /入群提示(带图片,可来自当前消息或引用消息)— 仅图片也可
269
- if (text.startsWith("/入群提示") || text.startsWith("#入群提示")) {
270
- if (!(await ensureAdminPermission())) return;
271
-
272
- const rawArg = text.replace(/^[/#]入群提示\s*/, "").trim();
273
- const current = getVerifyConfig();
274
- const groupCfg = getGroupVerifyConfig(current, groupIdNum);
275
- const directImageUrls = extractImageUrls(event.message);
276
- const quoteImageUrls = await extractQuoteImageUrls(event).catch(() => []);
277
- const imageUrls =
278
- directImageUrls.length > 0 ? directImageUrls : quoteImageUrls;
279
-
280
- if (rawArg === "关闭" || rawArg === "清空" || rawArg === "关") {
281
- if (!hasCustomPrompt(groupCfg)) {
282
- await event.reply("本群还没设置自定义入群提示哦~", true);
283
- return;
284
- }
285
- const removedFile = groupCfg.promptImage;
286
- const next = upsertGroupVerifyConfig(current, groupIdNum, {
287
- customPrompt: "",
288
- promptImage: "",
349
+ instruction: `用户想设置本群入群提示,但内容长度 ${argLength} 超过了上限 ${MAX_CUSTOM_PROMPT_LENGTH} 字,请明确告诉用户最多 ${MAX_CUSTOM_PROMPT_LENGTH} 字。`,
350
+ fallbackMessage: `最多 ${MAX_CUSTOM_PROMPT_LENGTH} 字哦~当前 ${argLength} 字`,
289
351
  });
290
- await setVerifyConfig(next);
291
- await pruneGroupPromptImages(groupIdNum, []).catch(() => {});
292
- ctx.logger.info(
293
- `admin verify 关闭群 ${groupIdNum} 自定义入群提示,清理图片 ${removedFile}`,
294
- );
295
- await event.reply("已关闭本群自定义入群提示~", true);
296
352
  return;
297
353
  }
298
-
299
- if (!rawArg && !imageUrls.length) {
300
- if (!hasCustomPrompt(groupCfg)) {
301
- await event.reply(
302
- "用法:/入群提示 xxx(最多 50 字),可附带图片(当前消息或引用消息中的图片)一起发送;/入群提示 关闭 关闭自定义提示~",
303
- true,
354
+ }
355
+ const nextPrompt = rawArg
356
+ ? normalizeCustomPrompt(rawArg)
357
+ : groupCfg.customPrompt;
358
+
359
+ let nextImage = groupCfg.promptImage;
360
+ let imageNote = "";
361
+ if (imageUrls.length) {
362
+ const targetUrl = imageUrls[0];
363
+ const savedImage = await saveRemoteImageAsPrompt(groupIdNum, targetUrl);
364
+ if (savedImage) {
365
+ const previousImage = groupCfg.promptImage;
366
+ nextImage = savedImage.filename;
367
+ imageNote = previousImage
368
+ ? `图片已替换(旧文件 ${previousImage} 已删除)`
369
+ : `图片已设置(${savedImage.filename})`;
370
+ if (previousImage) {
371
+ ctx.logger.info(
372
+ `admin verify 替换群 ${groupIdNum} 入群提示图片:${previousImage} -> ${savedImage.filename}`,
304
373
  );
305
- return;
306
- }
307
- const lines = ["已开启本群自定义入群提示"];
308
- lines.push(
309
- groupCfg.customPrompt
310
- ? `文字:${groupCfg.customPrompt}`
311
- : "文字:(未设置)",
312
- );
313
- lines.push(
314
- groupCfg.promptImage
315
- ? `图片:已设置(filename=${groupCfg.promptImage})`
316
- : "图片:(未设置)",
317
- );
318
- await event.reply(lines.join("\n"), true);
319
- return;
320
- }
321
-
322
- if (rawArg) {
323
- const argLength = Array.from(rawArg).length;
324
- if (argLength > MAX_CUSTOM_PROMPT_LENGTH) {
325
- await replyAdminErrorNotice({
326
- ctx,
327
- event,
328
- instruction: `用户想设置本群入群提示,但内容长度 ${argLength} 超过了上限 ${MAX_CUSTOM_PROMPT_LENGTH} 字,请明确告诉用户最多 ${MAX_CUSTOM_PROMPT_LENGTH} 字。`,
329
- fallbackMessage: `最多 ${MAX_CUSTOM_PROMPT_LENGTH} 字哦~当前 ${argLength} 字`,
330
- });
331
- return;
332
- }
333
- }
334
- const nextPrompt = rawArg
335
- ? normalizeCustomPrompt(rawArg)
336
- : groupCfg.customPrompt;
337
-
338
- let nextImage = groupCfg.promptImage;
339
- let imageNote = "";
340
- if (imageUrls.length) {
341
- const targetUrl = imageUrls[0];
342
- const savedImage = await saveRemoteImageAsPrompt(groupIdNum, targetUrl);
343
- if (savedImage) {
344
- const previousImage = groupCfg.promptImage;
345
- nextImage = savedImage.filename;
346
- imageNote = previousImage
347
- ? `图片已替换(旧文件 ${previousImage} 已删除)`
348
- : `图片已设置(${savedImage.filename})`;
349
- if (previousImage) {
350
- ctx.logger.info(
351
- `admin verify 替换群 ${groupIdNum} 入群提示图片:${previousImage} -> ${savedImage.filename}`,
352
- );
353
- }
354
- } else {
355
- imageNote = "图片下载失败,请稍后重试";
356
374
  }
375
+ } else {
376
+ imageNote = "图片下载失败,请稍后重试";
357
377
  }
358
-
359
- const next = upsertGroupVerifyConfig(current, groupIdNum, {
360
- customPrompt: nextPrompt,
361
- promptImage: nextImage,
362
- });
363
- await setVerifyConfig(next);
364
- await pruneGroupPromptImages(groupIdNum, nextImage ? [nextImage] : []).catch(
365
- () => {},
366
- );
367
-
368
- const lines = ["已更新本群自定义入群提示"];
369
- if (rawArg) lines.push(`文字:${nextPrompt}`);
370
- else if (groupCfg.customPrompt)
371
- lines.push(`文字(保持):${groupCfg.customPrompt}`);
372
- if (imageUrls.length && imageNote) lines.push(imageNote);
373
- await event.reply(lines.join("\n"), true);
374
- return;
375
378
  }
376
- } catch (err) {
377
- ctx.logger.error(`[admin verify] 未捕获异常: ${String(err)}`);
378
- if (!isVerifyCommand) return;
379
- await replyAdminErrorNotice({
380
- ctx,
381
- event,
382
- instruction: `入群验证指令执行时发生未捕获异常:${String(err)},请简要说明失败并建议稍后重试。`,
383
- fallbackMessage: `出错了,笨蛋~ ${String(err)}`,
384
- error: err,
379
+
380
+ const next = upsertGroupVerifyConfig(current, groupIdNum, {
381
+ customPrompt: nextPrompt,
382
+ promptImage: nextImage,
385
383
  });
386
- }
387
- });
384
+ await setVerifyConfig(next);
385
+ await pruneGroupPromptImages(groupIdNum, nextImage ? [nextImage] : []).catch(
386
+ () => {},
387
+ );
388
+
389
+ const lines = ["已更新本群自定义入群提示"];
390
+ if (rawArg) lines.push(`文字:${nextPrompt}`);
391
+ else if (groupCfg.customPrompt)
392
+ lines.push(`文字(保持):${groupCfg.customPrompt}`);
393
+ if (imageUrls.length && imageNote) lines.push(imageNote);
394
+ await event.reply(lines.join("\n"), true);
395
+ },
396
+ );
388
397
  }