koishi-plugin-bind-bot 2.1.1 → 2.1.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/lib/index.js CHANGED
@@ -20,12 +20,8 @@ exports.inject = ['database', 'server'];
20
20
  // 注意:Config 作为 Schema 常量导出,类型使用 IConfig 或从 './types' 导入
21
21
  // 创建配置Schema
22
22
  exports.Config = koishi_1.Schema.object({
23
- cooldownDays: koishi_1.Schema.number()
24
- .description('操作冷却时间(天)')
25
- .default(15),
26
- masterId: koishi_1.Schema.string()
27
- .description('主人QQ号,拥有管理员管理权限')
28
- .default(''),
23
+ cooldownDays: koishi_1.Schema.number().description('操作冷却时间(天)').default(15),
24
+ masterId: koishi_1.Schema.string().description('主人QQ号,拥有管理员管理权限').default(''),
29
25
  allowTextPrefix: koishi_1.Schema.boolean()
30
26
  .description('是否允许通过文本前缀触发指令(如"@机器人 mcid bind xxx")')
31
27
  .default(false),
@@ -35,12 +31,8 @@ exports.Config = koishi_1.Schema.object({
35
31
  autoRecallTime: koishi_1.Schema.number()
36
32
  .description('消息自动撤回时间(秒),同时控制机器人和用户消息,设置为0表示不自动撤回')
37
33
  .default(0),
38
- recallUserMessage: koishi_1.Schema.boolean()
39
- .description('是否撤回用户发送的指令消息')
40
- .default(false),
41
- debugMode: koishi_1.Schema.boolean()
42
- .description('调试模式,启用详细日志输出')
43
- .default(false),
34
+ recallUserMessage: koishi_1.Schema.boolean().description('是否撤回用户发送的指令消息').default(false),
35
+ debugMode: koishi_1.Schema.boolean().description('调试模式,启用详细日志输出').default(false),
44
36
  showAvatar: koishi_1.Schema.boolean()
45
37
  .description('是否显示头像图片(MC用头图,B站用头像)')
46
38
  .default(false),
@@ -50,38 +42,39 @@ exports.Config = koishi_1.Schema.object({
50
42
  zminfoApiUrl: koishi_1.Schema.string()
51
43
  .description('ZMINFO API地址')
52
44
  .default('https://zminfo-api.wittf.com'),
53
- enableLotteryBroadcast: koishi_1.Schema.boolean()
54
- .description('是否启用天选开奖播报功能')
55
- .default(false),
56
- lotteryTargetGroupId: koishi_1.Schema.string()
57
- .description('天选开奖播报目标群ID'),
58
- lotteryTargetPrivateId: koishi_1.Schema.string()
59
- .description('天选开奖播报私聊目标ID(格式:private:QQ号)'),
60
- autoNicknameGroupId: koishi_1.Schema.string()
61
- .description('自动群昵称设置目标群ID')
62
- .default('123456789'),
45
+ enableLotteryBroadcast: koishi_1.Schema.boolean().description('是否启用天选开奖播报功能').default(false),
46
+ lotteryTargetGroupId: koishi_1.Schema.string().description('天选开奖播报目标群ID'),
47
+ lotteryTargetPrivateId: koishi_1.Schema.string().description('天选开奖播报私聊目标ID(格式:private:QQ号)'),
48
+ autoNicknameGroupId: koishi_1.Schema.string().description('自动群昵称设置目标群ID').default('123456789'),
63
49
  forceBindSessdata: koishi_1.Schema.string()
64
50
  .description('B站Cookie信息,用于强制绑定时获取粉丝牌信息(支持完整Cookie或单独SESSDATA)')
65
51
  .default(''),
66
- forceBindTargetUpUid: koishi_1.Schema.number()
67
- .description('强制绑定目标UP主UID')
68
- .default(686127),
69
- forceBindTargetRoomId: koishi_1.Schema.number()
70
- .description('强制绑定目标房间号')
71
- .default(544853),
72
- forceBindTargetMedalName: koishi_1.Schema.string()
73
- .description('强制绑定目标粉丝牌名称')
74
- .default('生态'),
52
+ forceBindTargetUpUid: koishi_1.Schema.number().description('强制绑定目标UP主UID').default(686127),
53
+ forceBindTargetRoomId: koishi_1.Schema.number().description('强制绑定目标房间号').default(544853),
54
+ forceBindTargetMedalName: koishi_1.Schema.string().description('强制绑定目标粉丝牌名称').default('生态'),
55
+ groupRequestReview: koishi_1.Schema.object({
56
+ enabled: koishi_1.Schema.boolean().description('是否启用入群申请审批功能').default(false),
57
+ targetGroupId: koishi_1.Schema.string()
58
+ .description('需要审批的目标群ID(入群申请来源群)')
59
+ .default('931805503'),
60
+ reviewGroupId: koishi_1.Schema.string()
61
+ .description('管理员审批操作所在的群ID(播报群)')
62
+ .default('290238092'),
63
+ approveAutoBindEmoji: koishi_1.Schema.string()
64
+ .description('批准并自动绑定的表情ID(/太赞了)')
65
+ .default('389'),
66
+ approveInteractiveBindEmoji: koishi_1.Schema.string()
67
+ .description('批准并交互式绑定的表情ID(/偷感)')
68
+ .default('427'),
69
+ rejectEmoji: koishi_1.Schema.string().description('拒绝申请的表情ID(/NO)').default('123'),
70
+ autoCleanupHours: koishi_1.Schema.number()
71
+ .description('待审批记录自动清理时间(小时)')
72
+ .default(24)
73
+ }).description('入群申请审批功能配置'),
75
74
  servers: koishi_1.Schema.array(koishi_1.Schema.object({
76
- id: koishi_1.Schema.string()
77
- .description('服务器唯一ID(不允许重复)')
78
- .required(),
79
- name: koishi_1.Schema.string()
80
- .description('服务器名称(用于指令显示)')
81
- .required(),
82
- enabled: koishi_1.Schema.boolean()
83
- .description('服务器是否启用')
84
- .default(true),
75
+ id: koishi_1.Schema.string().description('服务器唯一ID(不允许重复)').required(),
76
+ name: koishi_1.Schema.string().description('服务器名称(用于指令显示)').required(),
77
+ enabled: koishi_1.Schema.boolean().description('服务器是否启用').default(true),
85
78
  displayAddress: koishi_1.Schema.string()
86
79
  .description('服务器展示地址(显示给用户的连接地址)')
87
80
  .default(''),
@@ -91,9 +84,7 @@ exports.Config = koishi_1.Schema.object({
91
84
  rconAddress: koishi_1.Schema.string()
92
85
  .description('RCON地址,格式为 IP:端口,例如 127.0.0.1:25575')
93
86
  .required(),
94
- rconPassword: koishi_1.Schema.string()
95
- .description('RCON密码')
96
- .default(''),
87
+ rconPassword: koishi_1.Schema.string().description('RCON密码').default(''),
97
88
  addCommand: koishi_1.Schema.string()
98
89
  .description('添加白名单命令模板,使用${MCID}作为替换符')
99
90
  .default('whitelist add ${MCID}'),
@@ -103,14 +94,16 @@ exports.Config = koishi_1.Schema.object({
103
94
  idType: koishi_1.Schema.union([
104
95
  koishi_1.Schema.const('username').description('使用用户名'),
105
96
  koishi_1.Schema.const('uuid').description('使用UUID')
106
- ]).default('username').description('白名单添加时使用的ID类型'),
107
- allowSelfApply: koishi_1.Schema.boolean()
108
- .description('是否允许用户自行申请白名单')
109
- .default(false),
97
+ ])
98
+ .default('username')
99
+ .description('白名单添加时使用的ID类型'),
100
+ allowSelfApply: koishi_1.Schema.boolean().description('是否允许用户自行申请白名单').default(false),
110
101
  acceptEmptyResponse: koishi_1.Schema.boolean()
111
102
  .description('是否将命令的空响应视为成功(某些服务器成功执行命令后不返回内容,仅对本服务器生效)')
112
- .default(false),
113
- })).description('Minecraft服务器配置列表').default([]),
103
+ .default(false)
104
+ }))
105
+ .description('Minecraft服务器配置列表')
106
+ .default([])
114
107
  });
115
108
  function apply(ctx, config) {
116
109
  // 创建日志服务
@@ -153,7 +146,7 @@ function apply(ctx, config) {
153
146
  const lastReminder = reminderCooldown.get(userId);
154
147
  if (!lastReminder)
155
148
  return false;
156
- return (Date.now() - lastReminder) < REMINDER_COOLDOWN_TIME;
149
+ return Date.now() - lastReminder < REMINDER_COOLDOWN_TIME;
157
150
  };
158
151
  // 设置用户提醒冷却
159
152
  const setReminderCooldown = (userId) => {
@@ -219,7 +212,12 @@ function apply(ctx, config) {
219
212
  // 发送超时消息,@用户
220
213
  const normalizedUser = normalizeQQId(userId);
221
214
  ctx.bots.forEach(bot => {
222
- bot.sendMessage(channelId, [koishi_1.h.at(normalizedUser), koishi_1.h.text(' 绑定会话已超时,请重新开始绑定流程\n\n⚠️ 温馨提醒:若在管理员多次提醒后仍不配合绑定账号信息,将按群规进行相应处理。')]).catch(() => { });
215
+ bot
216
+ .sendMessage(channelId, [
217
+ koishi_1.h.at(normalizedUser),
218
+ koishi_1.h.text(' 绑定会话已超时,请重新开始绑定流程\n\n⚠️ 温馨提醒:若在管理员多次提醒后仍不配合绑定账号信息,将按群规进行相应处理。')
219
+ ])
220
+ .catch(() => { });
223
221
  });
224
222
  logger.info(`[交互绑定] QQ(${normalizedUser})的绑定会话因超时被清理`);
225
223
  }, BINDING_SESSION_TIMEOUT);
@@ -259,7 +257,39 @@ function apply(ctx, config) {
259
257
  if (!content)
260
258
  return false;
261
259
  // 常见的聊天用语或明显无关的内容
262
- const chatKeywords = ['你好', 'hello', 'hi', '在吗', '在不在', '怎么样', '什么', '为什么', '好的', '谢谢', '哈哈', '呵呵', '早上好', '晚上好', '晚安', '再见', '拜拜', '666', '牛', '厉害', '真的吗', '不是吧', '哇', '哦', '嗯', '好吧', '行', '可以', '没事', '没问题', '没关系'];
260
+ const chatKeywords = [
261
+ '你好',
262
+ 'hello',
263
+ 'hi',
264
+ '在吗',
265
+ '在不在',
266
+ '怎么样',
267
+ '什么',
268
+ '为什么',
269
+ '好的',
270
+ '谢谢',
271
+ '哈哈',
272
+ '呵呵',
273
+ '早上好',
274
+ '晚上好',
275
+ '晚安',
276
+ '再见',
277
+ '拜拜',
278
+ '666',
279
+ '牛',
280
+ '厉害',
281
+ '真的吗',
282
+ '不是吧',
283
+ '哇',
284
+ '哦',
285
+ '嗯',
286
+ '好吧',
287
+ '行',
288
+ '可以',
289
+ '没事',
290
+ '没问题',
291
+ '没关系'
292
+ ];
263
293
  const lowercaseContent = content.toLowerCase();
264
294
  // 检查是否包含明显的聊天用语
265
295
  if (chatKeywords.some(keyword => lowercaseContent.includes(keyword))) {
@@ -285,7 +315,10 @@ function apply(ctx, config) {
285
315
  return true;
286
316
  }
287
317
  // 如果是明显的指令格式
288
- if (content.startsWith('.') || content.startsWith('/') || content.startsWith('mcid') || content.startsWith('buid')) {
318
+ if (content.startsWith('.') ||
319
+ content.startsWith('/') ||
320
+ content.startsWith('mcid') ||
321
+ content.startsWith('buid')) {
289
322
  return true;
290
323
  }
291
324
  }
@@ -303,7 +336,10 @@ function apply(ctx, config) {
303
336
  return true;
304
337
  }
305
338
  // 如果是明显的指令格式
306
- if (content.startsWith('.') || content.startsWith('/') || content.startsWith('mcid') || content.startsWith('buid')) {
339
+ if (content.startsWith('.') ||
340
+ content.startsWith('/') ||
341
+ content.startsWith('mcid') ||
342
+ content.startsWith('buid')) {
307
343
  return true;
308
344
  }
309
345
  }
@@ -314,9 +350,9 @@ function apply(ctx, config) {
314
350
  const getCommandPrefix = () => {
315
351
  if (config.allowTextPrefix && config.botNickname) {
316
352
  // 检查botNickname是否已经包含@符号,避免重复添加
317
- const nickname = config.botNickname.startsWith('@') ?
318
- config.botNickname :
319
- `@${config.botNickname}`;
353
+ const nickname = config.botNickname.startsWith('@')
354
+ ? config.botNickname
355
+ : `@${config.botNickname}`;
320
356
  return `${nickname} `;
321
357
  }
322
358
  return '';
@@ -413,7 +449,8 @@ function apply(ctx, config) {
413
449
  }
414
450
  else {
415
451
  // 不在禁言时间,自动启动交互式绑定
416
- welcomeMessage += `📋 请选择绑定方式:\n1️⃣ 发送您的B站UID进行B站绑定\n2️⃣ 发送"跳过"仅绑定MC账号`;
452
+ welcomeMessage +=
453
+ '📋 请选择绑定方式:\n1️⃣ 发送您的B站UID进行B站绑定\n2️⃣ 发送"跳过"仅绑定MC账号';
417
454
  await session.bot.sendMessage(session.channelId, welcomeMessage);
418
455
  logger.info(`[新人绑定] 为新成员QQ(${normalizedUserId})自动启动交互式绑定流程`);
419
456
  // 创建绑定会话并发送初始提示
@@ -428,7 +465,7 @@ function apply(ctx, config) {
428
465
  if (existingBind.mcUsername.startsWith('_temp_')) {
429
466
  // 临时用户名,实际上应该是只绑定了B站但MC是临时的,不应该进入这个分支
430
467
  // 这种情况应该按照"只绑定了B站"处理
431
- welcomeMessage += `📋 检测到您已绑定B站账号,但尚未绑定MC账号\n`;
468
+ welcomeMessage += '📋 检测到您已绑定B站账号,但尚未绑定MC账号\n';
432
469
  welcomeMessage += `🎮 可使用 ${formatCommand('mcid bind <MC用户名>')} 绑定MC账号`;
433
470
  await session.bot.sendMessage(session.channelId, welcomeMessage);
434
471
  logger.info(`[新人绑定] 新成员QQ(${normalizedUserId})实际只绑定了B站(MC为临时用户名),已发送绑定提醒`);
@@ -445,7 +482,7 @@ function apply(ctx, config) {
445
482
  }
446
483
  else {
447
484
  // 不在禁言时间,自动启动B站绑定
448
- welcomeMessage += `📋 请发送您的B站UID进行绑定`;
485
+ welcomeMessage += '📋 请发送您的B站UID进行绑定';
449
486
  await session.bot.sendMessage(session.channelId, welcomeMessage);
450
487
  logger.info(`[新人绑定] 为新成员QQ(${normalizedUserId})自动启动B站绑定流程`);
451
488
  // 创建绑定会话,直接进入B站绑定步骤
@@ -458,14 +495,16 @@ function apply(ctx, config) {
458
495
  }
459
496
  else if (!existingBind.mcUsername && existingBind.buidUid) {
460
497
  // 只绑定了B站,未绑定MC - 仅发送提醒
461
- welcomeMessage += `📋 检测到您已绑定B站账号,但尚未绑定MC账号\n`;
498
+ welcomeMessage += '📋 检测到您已绑定B站账号,但尚未绑定MC账号\n';
462
499
  welcomeMessage += `🎮 可使用 ${formatCommand('mcid bind <MC用户名>')} 绑定MC账号`;
463
500
  await session.bot.sendMessage(session.channelId, welcomeMessage);
464
501
  logger.info(`[新人绑定] 新成员QQ(${normalizedUserId})已绑定B站但未绑定MC,已发送绑定提醒`);
465
502
  }
466
- else if (existingBind.mcUsername && existingBind.mcUsername.startsWith('_temp_') && existingBind.buidUid) {
503
+ else if (existingBind.mcUsername &&
504
+ existingBind.mcUsername.startsWith('_temp_') &&
505
+ existingBind.buidUid) {
467
506
  // MC是临时用户名但已绑定B站 - 也按照"只绑定了B站"处理
468
- welcomeMessage += `📋 检测到您已绑定B站账号,但尚未绑定MC账号\n`;
507
+ welcomeMessage += '📋 检测到您已绑定B站账号,但尚未绑定MC账号\n';
469
508
  welcomeMessage += `🎮 可使用 ${formatCommand('mcid bind <MC用户名>')} 绑定MC账号`;
470
509
  await session.bot.sendMessage(session.channelId, welcomeMessage);
471
510
  logger.info(`[新人绑定] 新成员QQ(${normalizedUserId})已绑定B站但MC为临时用户名,已发送绑定提醒`);
@@ -479,10 +518,10 @@ function apply(ctx, config) {
479
518
  // 注册天选开奖 Webhook
480
519
  ctx.server.post('/lottery', async (content) => {
481
520
  try {
482
- logger.info(`[天选开奖] 收到天选开奖webhook请求`);
521
+ logger.info('[天选开奖] 收到天选开奖webhook请求');
483
522
  // 检查天选播报开关
484
523
  if (!config?.enableLotteryBroadcast) {
485
- logger.info(`[天选开奖] 天选播报功能已禁用,忽略webhook请求`);
524
+ logger.info('[天选开奖] 天选播报功能已禁用,忽略webhook请求');
486
525
  content.status = 200;
487
526
  content.body = 'Lottery broadcast disabled';
488
527
  return;
@@ -520,7 +559,7 @@ function apply(ctx, config) {
520
559
  return;
521
560
  }
522
561
  if (!lotteryData.lottery_id || !lotteryData.winners || !Array.isArray(lotteryData.winners)) {
523
- logger.warn(`[天选开奖] 数据格式不完整`);
562
+ logger.warn('[天选开奖] 数据格式不完整');
524
563
  content.status = 400;
525
564
  content.body = 'Incomplete data format';
526
565
  return;
@@ -549,92 +588,92 @@ function apply(ctx, config) {
549
588
  // 在数据库中创建MCIDBIND表
550
589
  ctx.model.extend('mcidbind', {
551
590
  qqId: {
552
- type: 'string',
591
+ type: 'string'
553
592
  },
554
593
  mcUsername: {
555
594
  type: 'string',
556
- initial: '',
595
+ initial: ''
557
596
  },
558
597
  mcUuid: {
559
598
  type: 'string',
560
- initial: '',
599
+ initial: ''
561
600
  },
562
601
  lastModified: {
563
602
  type: 'timestamp',
564
- initial: null,
603
+ initial: null
565
604
  },
566
605
  isAdmin: {
567
606
  type: 'boolean',
568
- initial: false,
607
+ initial: false
569
608
  },
570
609
  whitelist: {
571
610
  type: 'json',
572
- initial: [],
611
+ initial: []
573
612
  },
574
613
  tags: {
575
614
  type: 'json',
576
- initial: [],
615
+ initial: []
577
616
  },
578
617
  // BUID相关字段
579
618
  buidUid: {
580
619
  type: 'string',
581
- initial: '',
620
+ initial: ''
582
621
  },
583
622
  buidUsername: {
584
623
  type: 'string',
585
- initial: '',
624
+ initial: ''
586
625
  },
587
626
  guardLevel: {
588
627
  type: 'integer',
589
- initial: 0,
628
+ initial: 0
590
629
  },
591
630
  guardLevelText: {
592
631
  type: 'string',
593
- initial: '',
632
+ initial: ''
594
633
  },
595
634
  maxGuardLevel: {
596
635
  type: 'integer',
597
- initial: 0,
636
+ initial: 0
598
637
  },
599
638
  maxGuardLevelText: {
600
639
  type: 'string',
601
- initial: '',
640
+ initial: ''
602
641
  },
603
642
  medalName: {
604
643
  type: 'string',
605
- initial: '',
644
+ initial: ''
606
645
  },
607
646
  medalLevel: {
608
647
  type: 'integer',
609
- initial: 0,
648
+ initial: 0
610
649
  },
611
650
  wealthMedalLevel: {
612
651
  type: 'integer',
613
- initial: 0,
652
+ initial: 0
614
653
  },
615
654
  lastActiveTime: {
616
655
  type: 'timestamp',
617
- initial: null,
656
+ initial: null
618
657
  },
619
658
  reminderCount: {
620
659
  type: 'integer',
621
- initial: 0,
660
+ initial: 0
622
661
  },
623
662
  usernameLastChecked: {
624
663
  type: 'timestamp',
625
- initial: null,
664
+ initial: null
626
665
  },
627
666
  usernameCheckFailCount: {
628
667
  type: 'integer',
629
- initial: 0,
630
- },
668
+ initial: 0
669
+ }
631
670
  }, {
632
671
  // 设置主键为qqId
633
672
  primary: 'qqId',
634
673
  // 添加索引
635
674
  unique: [['mcUsername'], ['buidUid']],
636
675
  // 添加isAdmin索引,提高查询效率
637
- indexes: [['isAdmin'], ['buidUid']],
676
+ indexes: [['isAdmin'], ['buidUid']]
638
677
  });
639
678
  // 检查表结构是否包含旧字段
640
679
  const checkTableStructure = async () => {
@@ -698,7 +737,7 @@ function apply(ctx, config) {
698
737
  logger.info(`[初始化] 成功为${updatedCount}条记录添加缺失字段`);
699
738
  }
700
739
  else {
701
- logger.info(`[初始化] 所有记录都包含必要字段,无需更新`);
740
+ logger.info('[初始化] 所有记录都包含必要字段,无需更新');
702
741
  }
703
742
  return true;
704
743
  }
@@ -717,7 +756,8 @@ function apply(ctx, config) {
717
756
  const backupData = JSON.parse(JSON.stringify(oldRecords));
718
757
  try {
719
758
  // 提取有效数据
720
- const validRecords = oldRecords.map(record => {
759
+ const validRecords = oldRecords
760
+ .map(record => {
721
761
  // 确保qqId存在
722
762
  if (!record.qqId) {
723
763
  // 如果没有qqId但有userId,尝试从userId提取
@@ -738,7 +778,8 @@ function apply(ctx, config) {
738
778
  whitelist: record.whitelist || [],
739
779
  tags: record.tags || []
740
780
  };
741
- }).filter(record => record !== null);
781
+ })
782
+ .filter(record => record !== null);
742
783
  // 删除现有表
743
784
  await mcidbindRepo.deleteAll();
744
785
  logger.info('[初始化] 成功删除旧表数据');
@@ -786,7 +827,7 @@ function apply(ctx, config) {
786
827
  const normalizeQQId = (userId) => {
787
828
  // 处理空值情况
788
829
  if (!userId) {
789
- logger.warn(`[用户ID] 收到空用户ID`);
830
+ logger.warn('[用户ID] 收到空用户ID');
790
831
  return '';
791
832
  }
792
833
  let extractedId = '';
@@ -840,8 +881,12 @@ function apply(ctx, config) {
840
881
  // 处理私聊和群聊的消息格式
841
882
  // 主动消息不引用原消息
842
883
  const promptMessage = session.channelId?.startsWith('private:')
843
- ? (isProactiveMessage ? content : [koishi_1.h.quote(session.messageId), ...content])
844
- : (isProactiveMessage ? [koishi_1.h.at(normalizedQQId), '\n', ...content] : [koishi_1.h.quote(session.messageId), koishi_1.h.at(normalizedQQId), '\n', ...content]);
884
+ ? isProactiveMessage
885
+ ? content
886
+ : [koishi_1.h.quote(session.messageId), ...content]
887
+ : isProactiveMessage
888
+ ? [koishi_1.h.at(normalizedQQId), '\n', ...content]
889
+ : [koishi_1.h.quote(session.messageId), koishi_1.h.at(normalizedQQId), '\n', ...content];
845
890
  // 发送消息并获取返回的消息ID
846
891
  const messageResult = await session.send(promptMessage);
847
892
  if (config.debugMode) {
@@ -853,11 +898,18 @@ function apply(ctx, config) {
853
898
  // 但如果用户在绑定会话中发送聊天消息(不包括指令),不撤回
854
899
  // 主动消息不撤回用户消息
855
900
  const bindingSession = getBindingSession(session.userId, session.channelId);
856
- const isBindingCommand = session.content && (session.content.trim() === '绑定' ||
857
- session.content.includes('@') && session.content.includes('绑定'));
858
- const shouldNotRecallUserMessage = bindingSession && session.content &&
859
- !isBindingCommand && checkIrrelevantInput(bindingSession, session.content.trim());
860
- if (config.recallUserMessage && isGroupMessage && session.messageId && !shouldNotRecallUserMessage && !isProactiveMessage) {
901
+ const isBindingCommand = session.content &&
902
+ (session.content.trim() === '绑定' ||
903
+ (session.content.includes('@') && session.content.includes('绑定')));
904
+ const shouldNotRecallUserMessage = bindingSession &&
905
+ session.content &&
906
+ !isBindingCommand &&
907
+ checkIrrelevantInput(bindingSession, session.content.trim());
908
+ if (config.recallUserMessage &&
909
+ isGroupMessage &&
910
+ session.messageId &&
911
+ !shouldNotRecallUserMessage &&
912
+ !isProactiveMessage) {
861
913
  setTimeout(async () => {
862
914
  try {
863
915
  await session.bot.deleteMessage(session.channelId, session.messageId);
@@ -877,7 +929,7 @@ function apply(ctx, config) {
877
929
  logDebug('消息', `QQ(${normalizedQQId})在绑定会话中发送聊天消息,跳过撤回用户消息`);
878
930
  }
879
931
  else if (isProactiveMessage && config.debugMode) {
880
- logDebug('消息', `主动发送的消息,跳过撤回用户消息`);
932
+ logDebug('消息', '主动发送的消息,跳过撤回用户消息');
881
933
  }
882
934
  // 处理撤回机器人消息 - 只在群聊中撤回机器人自己的消息
883
935
  // 检查是否为不应撤回的重要提示消息(只有绑定会话超时提醒)
@@ -904,9 +956,10 @@ function apply(ctx, config) {
904
956
  }
905
957
  else if (messageResult && typeof messageResult === 'object') {
906
958
  // 尝试提取各种可能的消息ID格式
907
- messageId = messageResult.messageId ||
908
- messageResult.id ||
909
- messageResult.message_id;
959
+ messageId =
960
+ messageResult.messageId ||
961
+ messageResult.id ||
962
+ messageResult.message_id;
910
963
  }
911
964
  if (messageId) {
912
965
  // 设置定时器延迟撤回
@@ -926,11 +979,11 @@ function apply(ctx, config) {
926
979
  }
927
980
  }
928
981
  else if (config.debugMode) {
929
- logWarn('消息', `无法获取消息ID,自动撤回功能无法生效`);
982
+ logWarn('消息', '无法获取消息ID,自动撤回功能无法生效');
930
983
  }
931
984
  }
932
985
  else if (config.debugMode) {
933
- logDebug('消息', `检测到私聊消息,不撤回机器人回复`);
986
+ logDebug('消息', '检测到私聊消息,不撤回机器人回复');
934
987
  }
935
988
  }
936
989
  }
@@ -964,7 +1017,7 @@ function apply(ctx, config) {
964
1017
  const getServerConfigById = (serverId) => {
965
1018
  if (!config.servers || !Array.isArray(config.servers))
966
1019
  return null;
967
- return config.servers.find(server => server.id === serverId && (server.enabled !== false)) || null;
1020
+ return config.servers.find(server => server.id === serverId && server.enabled !== false) || null;
968
1021
  };
969
1022
  // 根据服务器名称获取服务器配置
970
1023
  const getServerConfigByName = (serverName) => {
@@ -1097,6 +1150,9 @@ function apply(ctx, config) {
1097
1150
  // 实例化McidCommandHandler并注册命令
1098
1151
  const mcidHandler = new handlers_1.McidCommandHandler(ctx, config, loggerService, repositories, handlerDependencies);
1099
1152
  mcidHandler.register();
1153
+ // 实例化并注册入群申请审批Handler
1154
+ const groupRequestReviewHandler = new handlers_1.GroupRequestReviewHandler(ctx, config, loggerService, repositories, handlerDependencies);
1155
+ groupRequestReviewHandler.register();
1100
1156
  // 自定义文本前缀匹配
1101
1157
  if (config.allowTextPrefix && config.botNickname) {
1102
1158
  // 创建一个前缀匹配器
@@ -1118,9 +1174,9 @@ function apply(ctx, config) {
1118
1174
  const regularPrefixRegex = new RegExp(`^${escapeRegExp(botNickname)}\\s+((mcid|buid|绑定|bind)\\s*.*)$`, 'i');
1119
1175
  const regularMatch = content.match(regularPrefixRegex);
1120
1176
  // 2. 如果botNickname不包含@,也尝试匹配带@的版本
1121
- const atPrefixRegex = !botNickname.startsWith('@') ?
1122
- new RegExp(`^@${escapeRegExp(botNickname)}\\s+((mcid|buid|绑定|bind)\\s*.*)$`, 'i') :
1123
- null;
1177
+ const atPrefixRegex = !botNickname.startsWith('@')
1178
+ ? new RegExp(`^@${escapeRegExp(botNickname)}\\s+((mcid|buid|绑定|bind)\\s*.*)$`, 'i')
1179
+ : null;
1124
1180
  if (regularMatch && regularMatch[1]) {
1125
1181
  matchedCommand = regularMatch[1].trim();
1126
1182
  }
@@ -1165,8 +1221,12 @@ function apply(ctx, config) {
1165
1221
  return next();
1166
1222
  }
1167
1223
  // 跳过空消息或命令消息
1168
- if (!session.content || session.content.startsWith('.') || session.content.startsWith('/') ||
1169
- session.content.includes('mcid') || session.content.includes('buid') || session.content.includes('绑定')) {
1224
+ if (!session.content ||
1225
+ session.content.startsWith('.') ||
1226
+ session.content.startsWith('/') ||
1227
+ session.content.includes('mcid') ||
1228
+ session.content.includes('buid') ||
1229
+ session.content.includes('绑定')) {
1170
1230
  return next();
1171
1231
  }
1172
1232
  // 检查当前时间是否在群组禁言时间段内
@@ -1182,7 +1242,7 @@ function apply(ctx, config) {
1182
1242
  }
1183
1243
  // 随机触发概率:管理员 1%,普通用户 80%,避免过于频繁
1184
1244
  const isUserAdmin = await isAdmin(session.userId);
1185
- const triggerRate = isUserAdmin ? 0.01 : 0.80;
1245
+ const triggerRate = isUserAdmin ? 0.01 : 0.8;
1186
1246
  if (Math.random() > triggerRate) {
1187
1247
  return next();
1188
1248
  }
@@ -1242,7 +1302,9 @@ function apply(ctx, config) {
1242
1302
  return next();
1243
1303
  }
1244
1304
  // 情况2:只绑定了B站,未绑定MC
1245
- if (bind.buidUid && bind.buidUsername && (!bind.mcUsername || bind.mcUsername.startsWith('_temp_'))) {
1305
+ if (bind.buidUid &&
1306
+ bind.buidUsername &&
1307
+ (!bind.mcUsername || bind.mcUsername.startsWith('_temp_'))) {
1246
1308
  const mcInfo = null;
1247
1309
  const isNicknameCorrect = services.nickname.checkNicknameFormat(currentNickname, bind.buidUsername, mcInfo);
1248
1310
  if (!isNicknameCorrect) {
@@ -1263,7 +1325,10 @@ function apply(ctx, config) {
1263
1325
  return next();
1264
1326
  }
1265
1327
  // 情况3:都已绑定,但群昵称格式不正确
1266
- if (bind.buidUid && bind.buidUsername && bind.mcUsername && !bind.mcUsername.startsWith('_temp_')) {
1328
+ if (bind.buidUid &&
1329
+ bind.buidUsername &&
1330
+ bind.mcUsername &&
1331
+ !bind.mcUsername.startsWith('_temp_')) {
1267
1332
  const isNicknameCorrect = services.nickname.checkNicknameFormat(currentNickname, bind.buidUsername, bind.mcUsername);
1268
1333
  if (!isNicknameCorrect) {
1269
1334
  // 更新提醒次数
@@ -1305,19 +1370,26 @@ function apply(ctx, config) {
1305
1370
  if (content === '取消' || content === 'cancel') {
1306
1371
  removeBindingSession(session.userId, session.channelId);
1307
1372
  logger.info(`[交互绑定] QQ(${normalizedUserId})手动取消了绑定会话`);
1308
- await sendMessage(session, [koishi_1.h.text('❌ 绑定会话已取消\n\n📋 温馨提醒:请按群规设置合适的群昵称。若在管理员多次提醒后仍不配合绑定账号信息或按规修改群昵称,将按群规进行相应处理。')]);
1373
+ await sendMessage(session, [
1374
+ koishi_1.h.text('❌ 绑定会话已取消\n\n📋 温馨提醒:请按群规设置合适的群昵称。若在管理员多次提醒后仍不配合绑定账号信息或按规修改群昵称,将按群规进行相应处理。')
1375
+ ]);
1309
1376
  return;
1310
1377
  }
1311
1378
  // 检查是否在绑定过程中使用了其他绑定相关命令(排除跳过选项)
1312
1379
  // 这里使用原始内容检测命令,避免误判@Bot发送的正常输入
1313
- if (rawContent && content !== '跳过' && content !== 'skip' && (rawContent.includes('绑定') ||
1314
- rawContent.includes('bind') ||
1315
- rawContent.includes('mcid') ||
1316
- rawContent.includes('buid') ||
1317
- rawContent.startsWith('.') ||
1318
- rawContent.startsWith('/'))) {
1380
+ if (rawContent &&
1381
+ content !== '跳过' &&
1382
+ content !== 'skip' &&
1383
+ (rawContent.includes('绑定') ||
1384
+ rawContent.includes('bind') ||
1385
+ rawContent.includes('mcid') ||
1386
+ rawContent.includes('buid') ||
1387
+ rawContent.startsWith('.') ||
1388
+ rawContent.startsWith('/'))) {
1319
1389
  const currentState = bindingSession.state === 'waiting_mc_username' ? 'MC用户名' : 'B站UID';
1320
- await sendMessage(session, [koishi_1.h.text(`🔄 您正在进行交互式绑定,请继续输入${currentState}\n\n如需取消当前绑定,请发送"取消"`)]);
1390
+ await sendMessage(session, [
1391
+ koishi_1.h.text(`🔄 您正在进行交互式绑定,请继续输入${currentState}\n\n如需取消当前绑定,请发送"取消"`)
1392
+ ]);
1321
1393
  return;
1322
1394
  }
1323
1395
  // 检查是否为明显无关的输入
@@ -1329,7 +1401,39 @@ function apply(ctx, config) {
1329
1401
  invalidInputCount: newCount
1330
1402
  });
1331
1403
  // 检查是否为明显的聊天内容(使用清理后的内容)
1332
- const chatKeywords = ['你好', 'hello', 'hi', '在吗', '在不在', '怎么样', '什么', '为什么', '好的', '谢谢', '哈哈', '呵呵', '早上好', '晚上好', '晚安', '再见', '拜拜', '666', '牛', '厉害', '真的吗', '不是吧', '哇', '哦', '嗯', '好吧', '行', '可以', '没事', '没问题', '没关系'];
1404
+ const chatKeywords = [
1405
+ '你好',
1406
+ 'hello',
1407
+ 'hi',
1408
+ '在吗',
1409
+ '在不在',
1410
+ '怎么样',
1411
+ '什么',
1412
+ '为什么',
1413
+ '好的',
1414
+ '谢谢',
1415
+ '哈哈',
1416
+ '呵呵',
1417
+ '早上好',
1418
+ '晚上好',
1419
+ '晚安',
1420
+ '再见',
1421
+ '拜拜',
1422
+ '666',
1423
+ '牛',
1424
+ '厉害',
1425
+ '真的吗',
1426
+ '不是吧',
1427
+ '哇',
1428
+ '哦',
1429
+ '嗯',
1430
+ '好吧',
1431
+ '行',
1432
+ '可以',
1433
+ '没事',
1434
+ '没问题',
1435
+ '没关系'
1436
+ ];
1333
1437
  const isChatMessage = chatKeywords.some(keyword => content.toLowerCase().includes(keyword)) ||
1334
1438
  /[!?。,;:""''()【】〈〉《》「」『』〔〕〖〗〘〙〚〛]{2,}/.test(content) ||
1335
1439
  /[!?.,;:"'()[\]<>{}]{3,}/.test(content);
@@ -1339,13 +1443,17 @@ function apply(ctx, config) {
1339
1443
  removeBindingSession(session.userId, session.channelId);
1340
1444
  logger.info(`[交互绑定] QQ(${normalizedUserId})持续发送聊天消息,自动取消绑定会话避免打扰`);
1341
1445
  // 对于聊天取消,给一个更温和的提示,同时提醒群规
1342
- await sendMessage(session, [koishi_1.h.text(`💬 看起来您在聊天,绑定流程已自动取消\n\n📋 温馨提醒:请按群规设置合适的群昵称。若在管理员多次提醒后仍不配合绑定账号信息或按规修改群昵称,将按群规进行相应处理。\n\n如需绑定账号,请随时使用 ${formatCommand('绑定')} 命令重新开始`)]);
1446
+ await sendMessage(session, [
1447
+ koishi_1.h.text(`💬 看起来您在聊天,绑定流程已自动取消\n\n📋 温馨提醒:请按群规设置合适的群昵称。若在管理员多次提醒后仍不配合绑定账号信息或按规修改群昵称,将按群规进行相应处理。\n\n如需绑定账号,请随时使用 ${formatCommand('绑定')} 命令重新开始`)
1448
+ ]);
1343
1449
  return;
1344
1450
  }
1345
1451
  else {
1346
1452
  // 第一次聊天消息,给温和提醒
1347
1453
  const expectedInput = bindingSession.state === 'waiting_mc_username' ? 'MC用户名' : 'B站UID';
1348
- await sendMessage(session, [koishi_1.h.text(`💭 您当前正在进行账号绑定,需要输入${expectedInput}\n\n如不需要绑定,请发送"取消",或继续聊天我们会自动取消绑定流程`)]);
1454
+ await sendMessage(session, [
1455
+ koishi_1.h.text(`💭 您当前正在进行账号绑定,需要输入${expectedInput}\n\n如不需要绑定,请发送"取消",或继续聊天我们会自动取消绑定流程`)
1456
+ ]);
1349
1457
  return;
1350
1458
  }
1351
1459
  }
@@ -1354,14 +1462,20 @@ function apply(ctx, config) {
1354
1462
  if (newCount === 1) {
1355
1463
  // 第1次无关输入,提醒检查
1356
1464
  const expectedInput = bindingSession.state === 'waiting_mc_username' ? 'MC用户名' : 'B站UID';
1357
- await sendMessage(session, [koishi_1.h.text(`🤔 您当前正在进行绑定流程,需要输入${expectedInput}\n\n如果您想取消绑定,请发送"取消"`)]);
1465
+ await sendMessage(session, [
1466
+ koishi_1.h.text(`🤔 您当前正在进行绑定流程,需要输入${expectedInput}\n\n如果您想取消绑定,请发送"取消"`)
1467
+ ]);
1358
1468
  return;
1359
1469
  }
1360
1470
  else if (newCount >= 2) {
1361
1471
  // 第2次无关输入,建议取消
1362
1472
  removeBindingSession(session.userId, session.channelId);
1363
1473
  logger.info(`[交互绑定] QQ(${normalizedUserId})因多次无关输入自动取消绑定会话`);
1364
- await sendMessage(session, [koishi_1.h.text('🔄 检测到您可能不想继续绑定流程,已自动取消绑定会话\n\n📋 温馨提醒:请按群规设置合适的群昵称。若在管理员多次提醒后仍不配合绑定账号信息或按规修改群昵称,将按群规进行相应处理。\n\n如需重新绑定,请使用 ' + formatCommand('绑定') + ' 命令')]);
1474
+ await sendMessage(session, [
1475
+ koishi_1.h.text('🔄 检测到您可能不想继续绑定流程,已自动取消绑定会话\n\n📋 温馨提醒:请按群规设置合适的群昵称。若在管理员多次提醒后仍不配合绑定账号信息或按规修改群昵称,将按群规进行相应处理。\n\n如需重新绑定,请使用 ' +
1476
+ formatCommand('绑定') +
1477
+ ' 命令')
1478
+ ]);
1365
1479
  return;
1366
1480
  }
1367
1481
  }
@@ -1409,7 +1523,9 @@ function apply(ctx, config) {
1409
1523
  }
1410
1524
  await sendMessage(session, [
1411
1525
  koishi_1.h.text(`🎉 绑定完成!\nMC: 未绑定\nB站: ${existingBind.buidUsername}\n\n💡 您可以随时使用 ${formatCommand('mcid bind <用户名>')} 绑定MC账号`),
1412
- ...(config?.showAvatar ? [koishi_1.h.image(`https://workers.vrp.moe/bilibili/avatar/${existingBind.buidUid}?size=160`)] : [])
1526
+ ...(config?.showAvatar
1527
+ ? [koishi_1.h.image(`https://workers.vrp.moe/bilibili/avatar/${existingBind.buidUid}?size=160`)]
1528
+ : [])
1413
1529
  ]);
1414
1530
  return;
1415
1531
  }
@@ -1446,7 +1562,9 @@ function apply(ctx, config) {
1446
1562
  const profile = await services.api.validateUsername(content);
1447
1563
  if (!profile) {
1448
1564
  logger.warn(`[交互绑定] QQ(${normalizedUserId})输入的MC用户名"${content}"不存在`);
1449
- await sendMessage(session, [koishi_1.h.text(`❌ 用户名 ${content} 不存在\n请重新输入或发送"跳过"完成绑定`)]);
1565
+ await sendMessage(session, [
1566
+ koishi_1.h.text(`❌ 用户名 ${content} 不存在\n请重新输入或发送"跳过"完成绑定`)
1567
+ ]);
1450
1568
  return;
1451
1569
  }
1452
1570
  const username = profile.name;
@@ -1455,22 +1573,28 @@ function apply(ctx, config) {
1455
1573
  const existingBind = await services.database.getMcBindByQQId(normalizedUserId);
1456
1574
  if (existingBind && existingBind.mcUsername && !existingBind.mcUsername.startsWith('_temp_')) {
1457
1575
  // 检查冷却时间
1458
- if (!await isAdmin(session.userId) && !checkCooldown(existingBind.lastModified)) {
1576
+ if (!(await isAdmin(session.userId)) && !checkCooldown(existingBind.lastModified)) {
1459
1577
  const days = config.cooldownDays;
1460
1578
  const now = new Date();
1461
1579
  const diffTime = now.getTime() - existingBind.lastModified.getTime();
1462
1580
  const passedDays = Math.floor(diffTime / (1000 * 60 * 60 * 24));
1463
1581
  const remainingDays = days - passedDays;
1464
1582
  removeBindingSession(session.userId, session.channelId);
1465
- const displayUsername = existingBind.mcUsername && !existingBind.mcUsername.startsWith('_temp_') ? existingBind.mcUsername : '未绑定';
1466
- await sendMessage(session, [koishi_1.h.text(`❌ 您已绑定MC账号: ${displayUsername}\n\n如需修改,请在冷却期结束后(还需${remainingDays}天)使用 ${formatCommand('mcid change')} 命令或联系管理员`)]);
1583
+ const displayUsername = existingBind.mcUsername && !existingBind.mcUsername.startsWith('_temp_')
1584
+ ? existingBind.mcUsername
1585
+ : '未绑定';
1586
+ await sendMessage(session, [
1587
+ koishi_1.h.text(`❌ 您已绑定MC账号: ${displayUsername}\n\n如需修改,请在冷却期结束后(还需${remainingDays}天)使用 ${formatCommand('mcid change')} 命令或联系管理员`)
1588
+ ]);
1467
1589
  return;
1468
1590
  }
1469
1591
  }
1470
1592
  // 检查用户名是否已被其他人绑定
1471
1593
  if (await services.database.checkUsernameExists(username, session.userId, uuid)) {
1472
1594
  logger.warn(`[交互绑定] MC用户名"${username}"已被其他用户绑定`);
1473
- await sendMessage(session, [koishi_1.h.text(`❌ 用户名 ${username} 已被其他用户绑定\n\n请输入其他MC用户名或发送"跳过"完成绑定`)]);
1595
+ await sendMessage(session, [
1596
+ koishi_1.h.text(`❌ 用户名 ${username} 已被其他用户绑定\n\n请输入其他MC用户名或发送"跳过"完成绑定`)
1597
+ ]);
1474
1598
  return;
1475
1599
  }
1476
1600
  // 绑定MC账号
@@ -1578,20 +1702,26 @@ function apply(ctx, config) {
1578
1702
  // 验证UID格式
1579
1703
  if (!actualUid || !/^\d+$/.test(actualUid)) {
1580
1704
  logger.warn(`[交互绑定] QQ(${normalizedUserId})输入的B站UID"${content}"格式无效`);
1581
- await sendMessage(session, [koishi_1.h.text('❌ UID格式无效,请重新输入\n支持格式:纯数字、UID:数字、空间链接\n或发送"跳过"仅绑定MC账号')]);
1705
+ await sendMessage(session, [
1706
+ koishi_1.h.text('❌ UID格式无效,请重新输入\n支持格式:纯数字、UID:数字、空间链接\n或发送"跳过"仅绑定MC账号')
1707
+ ]);
1582
1708
  return;
1583
1709
  }
1584
1710
  // 检查UID是否已被绑定
1585
1711
  if (await services.database.checkBuidExists(actualUid, session.userId)) {
1586
1712
  logger.warn(`[交互绑定] B站UID"${actualUid}"已被其他用户绑定`);
1587
- await sendMessage(session, [koishi_1.h.text(`❌ UID ${actualUid} 已被其他用户绑定\n\n请输入其他B站UID\n或发送"跳过"仅绑定MC账号`)]);
1713
+ await sendMessage(session, [
1714
+ koishi_1.h.text(`❌ UID ${actualUid} 已被其他用户绑定\n\n请输入其他B站UID\n或发送"跳过"仅绑定MC账号`)
1715
+ ]);
1588
1716
  return;
1589
1717
  }
1590
1718
  // 验证UID是否存在
1591
1719
  const buidUser = await services.api.validateBUID(actualUid);
1592
1720
  if (!buidUser) {
1593
1721
  logger.warn(`[交互绑定] QQ(${normalizedUserId})输入的B站UID"${actualUid}"不存在`);
1594
- await sendMessage(session, [koishi_1.h.text(`❌ 无法验证UID: ${actualUid}\n\n该用户可能不存在或未被发现\n可以去直播间发个弹幕后重试绑定\n或发送"跳过"仅绑定MC账号`)]);
1722
+ await sendMessage(session, [
1723
+ koishi_1.h.text(`❌ 无法验证UID: ${actualUid}\n\n该用户可能不存在或未被发现\n可以去直播间发个弹幕后重试绑定\n或发送"跳过"仅绑定MC账号`)
1724
+ ]);
1595
1725
  return;
1596
1726
  }
1597
1727
  // 绑定B站账号
@@ -1600,9 +1730,13 @@ function apply(ctx, config) {
1600
1730
  logger.error(`[交互绑定] QQ(${normalizedUserId})绑定B站账号失败`);
1601
1731
  removeBindingSession(session.userId, session.channelId);
1602
1732
  // 根据是否有MC绑定提供不同的提示
1603
- const displayMcName = bindingSession.mcUsername && !bindingSession.mcUsername.startsWith('_temp_') ? bindingSession.mcUsername : null;
1733
+ const displayMcName = bindingSession.mcUsername && !bindingSession.mcUsername.startsWith('_temp_')
1734
+ ? bindingSession.mcUsername
1735
+ : null;
1604
1736
  const mcStatus = displayMcName ? `您的MC账号${displayMcName}已成功绑定\n` : '';
1605
- await sendMessage(session, [koishi_1.h.text(`❌ B站账号绑定失败,数据库操作出错\n\n${mcStatus}可稍后使用 ${formatCommand('buid bind <UID>')} 命令单独绑定B站账号`)]);
1737
+ await sendMessage(session, [
1738
+ koishi_1.h.text(`❌ B站账号绑定失败,数据库操作出错\n\n${mcStatus}可稍后使用 ${formatCommand('buid bind <UID>')} 命令单独绑定B站账号`)
1739
+ ]);
1606
1740
  return;
1607
1741
  }
1608
1742
  logger.info(`[交互绑定] QQ(${normalizedUserId})成功绑定B站UID: ${actualUid}`);
@@ -1611,7 +1745,9 @@ function apply(ctx, config) {
1611
1745
  // 自动群昵称设置功能 - 使用新的autoSetGroupNickname函数
1612
1746
  try {
1613
1747
  // 检查是否有有效的MC用户名(不是临时用户名)
1614
- const mcName = bindingSession.mcUsername && !bindingSession.mcUsername.startsWith('_temp_') ? bindingSession.mcUsername : null;
1748
+ const mcName = bindingSession.mcUsername && !bindingSession.mcUsername.startsWith('_temp_')
1749
+ ? bindingSession.mcUsername
1750
+ : null;
1615
1751
  await services.nickname.autoSetGroupNickname(session, mcName, buidUser.username, String(buidUser.uid));
1616
1752
  logger.info(`[交互绑定] QQ(${normalizedUserId})绑定完成,已设置群昵称`);
1617
1753
  }
@@ -1632,7 +1768,9 @@ function apply(ctx, config) {
1632
1768
  extraInfo += `\n荣耀等级: ${buidUser.wealthMedalLevel}`;
1633
1769
  }
1634
1770
  // 准备完成消息
1635
- const displayMcName = bindingSession.mcUsername && !bindingSession.mcUsername.startsWith('_temp_') ? bindingSession.mcUsername : null;
1771
+ const displayMcName = bindingSession.mcUsername && !bindingSession.mcUsername.startsWith('_temp_')
1772
+ ? bindingSession.mcUsername
1773
+ : null;
1636
1774
  const mcInfo = displayMcName ? `MC: ${displayMcName}` : 'MC: 未绑定';
1637
1775
  let extraTip = '';
1638
1776
  // 如果用户跳过了MC绑定或MC账号是temp,提供后续绑定的指引
@@ -1641,7 +1779,9 @@ function apply(ctx, config) {
1641
1779
  }
1642
1780
  await sendMessage(session, [
1643
1781
  koishi_1.h.text(`🎉 绑定完成!\n${mcInfo}\nB站: ${buidUser.username}${extraInfo}${extraTip}`),
1644
- ...(config?.showAvatar ? [koishi_1.h.image(`https://workers.vrp.moe/bilibili/avatar/${buidUser.uid}?size=160`)] : [])
1782
+ ...(config?.showAvatar
1783
+ ? [koishi_1.h.image(`https://workers.vrp.moe/bilibili/avatar/${buidUser.uid}?size=160`)]
1784
+ : [])
1645
1785
  ]);
1646
1786
  };
1647
1787
  // 帮助函数:转义正则表达式中的特殊字符
@@ -1661,7 +1801,7 @@ function apply(ctx, config) {
1661
1801
  // @Bot昵称 格式(如果配置了botNickname)
1662
1802
  config.botNickname ? new RegExp(`^@${escapeRegExp(config.botNickname)}\\s+`, 'i') : null,
1663
1803
  // @botUserId 格式
1664
- new RegExp(`^@${escapeRegExp(botUserId)}\\s+`, 'i'),
1804
+ new RegExp(`^@${escapeRegExp(botUserId)}\\s+`, 'i')
1665
1805
  ].filter(Boolean);
1666
1806
  let cleanedContent = content.trim();
1667
1807
  // 尝试匹配并移除@Bot前缀