koishi-plugin-bind-bot 2.1.0 → 2.1.2

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,20 @@ 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('生态'),
75
55
  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),
56
+ id: koishi_1.Schema.string().description('服务器唯一ID(不允许重复)').required(),
57
+ name: koishi_1.Schema.string().description('服务器名称(用于指令显示)').required(),
58
+ enabled: koishi_1.Schema.boolean().description('服务器是否启用').default(true),
85
59
  displayAddress: koishi_1.Schema.string()
86
60
  .description('服务器展示地址(显示给用户的连接地址)')
87
61
  .default(''),
@@ -91,9 +65,7 @@ exports.Config = koishi_1.Schema.object({
91
65
  rconAddress: koishi_1.Schema.string()
92
66
  .description('RCON地址,格式为 IP:端口,例如 127.0.0.1:25575')
93
67
  .required(),
94
- rconPassword: koishi_1.Schema.string()
95
- .description('RCON密码')
96
- .default(''),
68
+ rconPassword: koishi_1.Schema.string().description('RCON密码').default(''),
97
69
  addCommand: koishi_1.Schema.string()
98
70
  .description('添加白名单命令模板,使用${MCID}作为替换符')
99
71
  .default('whitelist add ${MCID}'),
@@ -103,14 +75,16 @@ exports.Config = koishi_1.Schema.object({
103
75
  idType: koishi_1.Schema.union([
104
76
  koishi_1.Schema.const('username').description('使用用户名'),
105
77
  koishi_1.Schema.const('uuid').description('使用UUID')
106
- ]).default('username').description('白名单添加时使用的ID类型'),
107
- allowSelfApply: koishi_1.Schema.boolean()
108
- .description('是否允许用户自行申请白名单')
109
- .default(false),
78
+ ])
79
+ .default('username')
80
+ .description('白名单添加时使用的ID类型'),
81
+ allowSelfApply: koishi_1.Schema.boolean().description('是否允许用户自行申请白名单').default(false),
110
82
  acceptEmptyResponse: koishi_1.Schema.boolean()
111
83
  .description('是否将命令的空响应视为成功(某些服务器成功执行命令后不返回内容,仅对本服务器生效)')
112
- .default(false),
113
- })).description('Minecraft服务器配置列表').default([]),
84
+ .default(false)
85
+ }))
86
+ .description('Minecraft服务器配置列表')
87
+ .default([])
114
88
  });
115
89
  function apply(ctx, config) {
116
90
  // 创建日志服务
@@ -153,7 +127,7 @@ function apply(ctx, config) {
153
127
  const lastReminder = reminderCooldown.get(userId);
154
128
  if (!lastReminder)
155
129
  return false;
156
- return (Date.now() - lastReminder) < REMINDER_COOLDOWN_TIME;
130
+ return Date.now() - lastReminder < REMINDER_COOLDOWN_TIME;
157
131
  };
158
132
  // 设置用户提醒冷却
159
133
  const setReminderCooldown = (userId) => {
@@ -219,7 +193,12 @@ function apply(ctx, config) {
219
193
  // 发送超时消息,@用户
220
194
  const normalizedUser = normalizeQQId(userId);
221
195
  ctx.bots.forEach(bot => {
222
- bot.sendMessage(channelId, [koishi_1.h.at(normalizedUser), koishi_1.h.text(' 绑定会话已超时,请重新开始绑定流程\n\n⚠️ 温馨提醒:若在管理员多次提醒后仍不配合绑定账号信息,将按群规进行相应处理。')]).catch(() => { });
196
+ bot
197
+ .sendMessage(channelId, [
198
+ koishi_1.h.at(normalizedUser),
199
+ koishi_1.h.text(' 绑定会话已超时,请重新开始绑定流程\n\n⚠️ 温馨提醒:若在管理员多次提醒后仍不配合绑定账号信息,将按群规进行相应处理。')
200
+ ])
201
+ .catch(() => { });
223
202
  });
224
203
  logger.info(`[交互绑定] QQ(${normalizedUser})的绑定会话因超时被清理`);
225
204
  }, BINDING_SESSION_TIMEOUT);
@@ -259,7 +238,39 @@ function apply(ctx, config) {
259
238
  if (!content)
260
239
  return false;
261
240
  // 常见的聊天用语或明显无关的内容
262
- const chatKeywords = ['你好', 'hello', 'hi', '在吗', '在不在', '怎么样', '什么', '为什么', '好的', '谢谢', '哈哈', '呵呵', '早上好', '晚上好', '晚安', '再见', '拜拜', '666', '牛', '厉害', '真的吗', '不是吧', '哇', '哦', '嗯', '好吧', '行', '可以', '没事', '没问题', '没关系'];
241
+ const chatKeywords = [
242
+ '你好',
243
+ 'hello',
244
+ 'hi',
245
+ '在吗',
246
+ '在不在',
247
+ '怎么样',
248
+ '什么',
249
+ '为什么',
250
+ '好的',
251
+ '谢谢',
252
+ '哈哈',
253
+ '呵呵',
254
+ '早上好',
255
+ '晚上好',
256
+ '晚安',
257
+ '再见',
258
+ '拜拜',
259
+ '666',
260
+ '牛',
261
+ '厉害',
262
+ '真的吗',
263
+ '不是吧',
264
+ '哇',
265
+ '哦',
266
+ '嗯',
267
+ '好吧',
268
+ '行',
269
+ '可以',
270
+ '没事',
271
+ '没问题',
272
+ '没关系'
273
+ ];
263
274
  const lowercaseContent = content.toLowerCase();
264
275
  // 检查是否包含明显的聊天用语
265
276
  if (chatKeywords.some(keyword => lowercaseContent.includes(keyword))) {
@@ -285,7 +296,10 @@ function apply(ctx, config) {
285
296
  return true;
286
297
  }
287
298
  // 如果是明显的指令格式
288
- if (content.startsWith('.') || content.startsWith('/') || content.startsWith('mcid') || content.startsWith('buid')) {
299
+ if (content.startsWith('.') ||
300
+ content.startsWith('/') ||
301
+ content.startsWith('mcid') ||
302
+ content.startsWith('buid')) {
289
303
  return true;
290
304
  }
291
305
  }
@@ -303,7 +317,10 @@ function apply(ctx, config) {
303
317
  return true;
304
318
  }
305
319
  // 如果是明显的指令格式
306
- if (content.startsWith('.') || content.startsWith('/') || content.startsWith('mcid') || content.startsWith('buid')) {
320
+ if (content.startsWith('.') ||
321
+ content.startsWith('/') ||
322
+ content.startsWith('mcid') ||
323
+ content.startsWith('buid')) {
307
324
  return true;
308
325
  }
309
326
  }
@@ -314,9 +331,9 @@ function apply(ctx, config) {
314
331
  const getCommandPrefix = () => {
315
332
  if (config.allowTextPrefix && config.botNickname) {
316
333
  // 检查botNickname是否已经包含@符号,避免重复添加
317
- const nickname = config.botNickname.startsWith('@') ?
318
- config.botNickname :
319
- `@${config.botNickname}`;
334
+ const nickname = config.botNickname.startsWith('@')
335
+ ? config.botNickname
336
+ : `@${config.botNickname}`;
320
337
  return `${nickname} `;
321
338
  }
322
339
  return '';
@@ -413,7 +430,8 @@ function apply(ctx, config) {
413
430
  }
414
431
  else {
415
432
  // 不在禁言时间,自动启动交互式绑定
416
- welcomeMessage += `📋 请选择绑定方式:\n1️⃣ 发送您的B站UID进行B站绑定\n2️⃣ 发送"跳过"仅绑定MC账号`;
433
+ welcomeMessage +=
434
+ '📋 请选择绑定方式:\n1️⃣ 发送您的B站UID进行B站绑定\n2️⃣ 发送"跳过"仅绑定MC账号';
417
435
  await session.bot.sendMessage(session.channelId, welcomeMessage);
418
436
  logger.info(`[新人绑定] 为新成员QQ(${normalizedUserId})自动启动交互式绑定流程`);
419
437
  // 创建绑定会话并发送初始提示
@@ -428,7 +446,7 @@ function apply(ctx, config) {
428
446
  if (existingBind.mcUsername.startsWith('_temp_')) {
429
447
  // 临时用户名,实际上应该是只绑定了B站但MC是临时的,不应该进入这个分支
430
448
  // 这种情况应该按照"只绑定了B站"处理
431
- welcomeMessage += `📋 检测到您已绑定B站账号,但尚未绑定MC账号\n`;
449
+ welcomeMessage += '📋 检测到您已绑定B站账号,但尚未绑定MC账号\n';
432
450
  welcomeMessage += `🎮 可使用 ${formatCommand('mcid bind <MC用户名>')} 绑定MC账号`;
433
451
  await session.bot.sendMessage(session.channelId, welcomeMessage);
434
452
  logger.info(`[新人绑定] 新成员QQ(${normalizedUserId})实际只绑定了B站(MC为临时用户名),已发送绑定提醒`);
@@ -445,7 +463,7 @@ function apply(ctx, config) {
445
463
  }
446
464
  else {
447
465
  // 不在禁言时间,自动启动B站绑定
448
- welcomeMessage += `📋 请发送您的B站UID进行绑定`;
466
+ welcomeMessage += '📋 请发送您的B站UID进行绑定';
449
467
  await session.bot.sendMessage(session.channelId, welcomeMessage);
450
468
  logger.info(`[新人绑定] 为新成员QQ(${normalizedUserId})自动启动B站绑定流程`);
451
469
  // 创建绑定会话,直接进入B站绑定步骤
@@ -458,14 +476,16 @@ function apply(ctx, config) {
458
476
  }
459
477
  else if (!existingBind.mcUsername && existingBind.buidUid) {
460
478
  // 只绑定了B站,未绑定MC - 仅发送提醒
461
- welcomeMessage += `📋 检测到您已绑定B站账号,但尚未绑定MC账号\n`;
479
+ welcomeMessage += '📋 检测到您已绑定B站账号,但尚未绑定MC账号\n';
462
480
  welcomeMessage += `🎮 可使用 ${formatCommand('mcid bind <MC用户名>')} 绑定MC账号`;
463
481
  await session.bot.sendMessage(session.channelId, welcomeMessage);
464
482
  logger.info(`[新人绑定] 新成员QQ(${normalizedUserId})已绑定B站但未绑定MC,已发送绑定提醒`);
465
483
  }
466
- else if (existingBind.mcUsername && existingBind.mcUsername.startsWith('_temp_') && existingBind.buidUid) {
484
+ else if (existingBind.mcUsername &&
485
+ existingBind.mcUsername.startsWith('_temp_') &&
486
+ existingBind.buidUid) {
467
487
  // MC是临时用户名但已绑定B站 - 也按照"只绑定了B站"处理
468
- welcomeMessage += `📋 检测到您已绑定B站账号,但尚未绑定MC账号\n`;
488
+ welcomeMessage += '📋 检测到您已绑定B站账号,但尚未绑定MC账号\n';
469
489
  welcomeMessage += `🎮 可使用 ${formatCommand('mcid bind <MC用户名>')} 绑定MC账号`;
470
490
  await session.bot.sendMessage(session.channelId, welcomeMessage);
471
491
  logger.info(`[新人绑定] 新成员QQ(${normalizedUserId})已绑定B站但MC为临时用户名,已发送绑定提醒`);
@@ -479,10 +499,10 @@ function apply(ctx, config) {
479
499
  // 注册天选开奖 Webhook
480
500
  ctx.server.post('/lottery', async (content) => {
481
501
  try {
482
- logger.info(`[天选开奖] 收到天选开奖webhook请求`);
502
+ logger.info('[天选开奖] 收到天选开奖webhook请求');
483
503
  // 检查天选播报开关
484
504
  if (!config?.enableLotteryBroadcast) {
485
- logger.info(`[天选开奖] 天选播报功能已禁用,忽略webhook请求`);
505
+ logger.info('[天选开奖] 天选播报功能已禁用,忽略webhook请求');
486
506
  content.status = 200;
487
507
  content.body = 'Lottery broadcast disabled';
488
508
  return;
@@ -520,7 +540,7 @@ function apply(ctx, config) {
520
540
  return;
521
541
  }
522
542
  if (!lotteryData.lottery_id || !lotteryData.winners || !Array.isArray(lotteryData.winners)) {
523
- logger.warn(`[天选开奖] 数据格式不完整`);
543
+ logger.warn('[天选开奖] 数据格式不完整');
524
544
  content.status = 400;
525
545
  content.body = 'Incomplete data format';
526
546
  return;
@@ -549,92 +569,92 @@ function apply(ctx, config) {
549
569
  // 在数据库中创建MCIDBIND表
550
570
  ctx.model.extend('mcidbind', {
551
571
  qqId: {
552
- type: 'string',
572
+ type: 'string'
553
573
  },
554
574
  mcUsername: {
555
575
  type: 'string',
556
- initial: '',
576
+ initial: ''
557
577
  },
558
578
  mcUuid: {
559
579
  type: 'string',
560
- initial: '',
580
+ initial: ''
561
581
  },
562
582
  lastModified: {
563
583
  type: 'timestamp',
564
- initial: null,
584
+ initial: null
565
585
  },
566
586
  isAdmin: {
567
587
  type: 'boolean',
568
- initial: false,
588
+ initial: false
569
589
  },
570
590
  whitelist: {
571
591
  type: 'json',
572
- initial: [],
592
+ initial: []
573
593
  },
574
594
  tags: {
575
595
  type: 'json',
576
- initial: [],
596
+ initial: []
577
597
  },
578
598
  // BUID相关字段
579
599
  buidUid: {
580
600
  type: 'string',
581
- initial: '',
601
+ initial: ''
582
602
  },
583
603
  buidUsername: {
584
604
  type: 'string',
585
- initial: '',
605
+ initial: ''
586
606
  },
587
607
  guardLevel: {
588
608
  type: 'integer',
589
- initial: 0,
609
+ initial: 0
590
610
  },
591
611
  guardLevelText: {
592
612
  type: 'string',
593
- initial: '',
613
+ initial: ''
594
614
  },
595
615
  maxGuardLevel: {
596
616
  type: 'integer',
597
- initial: 0,
617
+ initial: 0
598
618
  },
599
619
  maxGuardLevelText: {
600
620
  type: 'string',
601
- initial: '',
621
+ initial: ''
602
622
  },
603
623
  medalName: {
604
624
  type: 'string',
605
- initial: '',
625
+ initial: ''
606
626
  },
607
627
  medalLevel: {
608
628
  type: 'integer',
609
- initial: 0,
629
+ initial: 0
610
630
  },
611
631
  wealthMedalLevel: {
612
632
  type: 'integer',
613
- initial: 0,
633
+ initial: 0
614
634
  },
615
635
  lastActiveTime: {
616
636
  type: 'timestamp',
617
- initial: null,
637
+ initial: null
618
638
  },
619
639
  reminderCount: {
620
640
  type: 'integer',
621
- initial: 0,
641
+ initial: 0
622
642
  },
623
643
  usernameLastChecked: {
624
644
  type: 'timestamp',
625
- initial: null,
645
+ initial: null
626
646
  },
627
647
  usernameCheckFailCount: {
628
648
  type: 'integer',
629
- initial: 0,
630
- },
649
+ initial: 0
650
+ }
631
651
  }, {
632
652
  // 设置主键为qqId
633
653
  primary: 'qqId',
634
654
  // 添加索引
635
655
  unique: [['mcUsername'], ['buidUid']],
636
656
  // 添加isAdmin索引,提高查询效率
637
- indexes: [['isAdmin'], ['buidUid']],
657
+ indexes: [['isAdmin'], ['buidUid']]
638
658
  });
639
659
  // 检查表结构是否包含旧字段
640
660
  const checkTableStructure = async () => {
@@ -698,7 +718,7 @@ function apply(ctx, config) {
698
718
  logger.info(`[初始化] 成功为${updatedCount}条记录添加缺失字段`);
699
719
  }
700
720
  else {
701
- logger.info(`[初始化] 所有记录都包含必要字段,无需更新`);
721
+ logger.info('[初始化] 所有记录都包含必要字段,无需更新');
702
722
  }
703
723
  return true;
704
724
  }
@@ -717,7 +737,8 @@ function apply(ctx, config) {
717
737
  const backupData = JSON.parse(JSON.stringify(oldRecords));
718
738
  try {
719
739
  // 提取有效数据
720
- const validRecords = oldRecords.map(record => {
740
+ const validRecords = oldRecords
741
+ .map(record => {
721
742
  // 确保qqId存在
722
743
  if (!record.qqId) {
723
744
  // 如果没有qqId但有userId,尝试从userId提取
@@ -738,7 +759,8 @@ function apply(ctx, config) {
738
759
  whitelist: record.whitelist || [],
739
760
  tags: record.tags || []
740
761
  };
741
- }).filter(record => record !== null);
762
+ })
763
+ .filter(record => record !== null);
742
764
  // 删除现有表
743
765
  await mcidbindRepo.deleteAll();
744
766
  logger.info('[初始化] 成功删除旧表数据');
@@ -786,7 +808,7 @@ function apply(ctx, config) {
786
808
  const normalizeQQId = (userId) => {
787
809
  // 处理空值情况
788
810
  if (!userId) {
789
- logger.warn(`[用户ID] 收到空用户ID`);
811
+ logger.warn('[用户ID] 收到空用户ID');
790
812
  return '';
791
813
  }
792
814
  let extractedId = '';
@@ -840,8 +862,12 @@ function apply(ctx, config) {
840
862
  // 处理私聊和群聊的消息格式
841
863
  // 主动消息不引用原消息
842
864
  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]);
865
+ ? isProactiveMessage
866
+ ? content
867
+ : [koishi_1.h.quote(session.messageId), ...content]
868
+ : isProactiveMessage
869
+ ? [koishi_1.h.at(normalizedQQId), '\n', ...content]
870
+ : [koishi_1.h.quote(session.messageId), koishi_1.h.at(normalizedQQId), '\n', ...content];
845
871
  // 发送消息并获取返回的消息ID
846
872
  const messageResult = await session.send(promptMessage);
847
873
  if (config.debugMode) {
@@ -853,11 +879,18 @@ function apply(ctx, config) {
853
879
  // 但如果用户在绑定会话中发送聊天消息(不包括指令),不撤回
854
880
  // 主动消息不撤回用户消息
855
881
  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) {
882
+ const isBindingCommand = session.content &&
883
+ (session.content.trim() === '绑定' ||
884
+ (session.content.includes('@') && session.content.includes('绑定')));
885
+ const shouldNotRecallUserMessage = bindingSession &&
886
+ session.content &&
887
+ !isBindingCommand &&
888
+ checkIrrelevantInput(bindingSession, session.content.trim());
889
+ if (config.recallUserMessage &&
890
+ isGroupMessage &&
891
+ session.messageId &&
892
+ !shouldNotRecallUserMessage &&
893
+ !isProactiveMessage) {
861
894
  setTimeout(async () => {
862
895
  try {
863
896
  await session.bot.deleteMessage(session.channelId, session.messageId);
@@ -877,7 +910,7 @@ function apply(ctx, config) {
877
910
  logDebug('消息', `QQ(${normalizedQQId})在绑定会话中发送聊天消息,跳过撤回用户消息`);
878
911
  }
879
912
  else if (isProactiveMessage && config.debugMode) {
880
- logDebug('消息', `主动发送的消息,跳过撤回用户消息`);
913
+ logDebug('消息', '主动发送的消息,跳过撤回用户消息');
881
914
  }
882
915
  // 处理撤回机器人消息 - 只在群聊中撤回机器人自己的消息
883
916
  // 检查是否为不应撤回的重要提示消息(只有绑定会话超时提醒)
@@ -904,9 +937,10 @@ function apply(ctx, config) {
904
937
  }
905
938
  else if (messageResult && typeof messageResult === 'object') {
906
939
  // 尝试提取各种可能的消息ID格式
907
- messageId = messageResult.messageId ||
908
- messageResult.id ||
909
- messageResult.message_id;
940
+ messageId =
941
+ messageResult.messageId ||
942
+ messageResult.id ||
943
+ messageResult.message_id;
910
944
  }
911
945
  if (messageId) {
912
946
  // 设置定时器延迟撤回
@@ -926,11 +960,11 @@ function apply(ctx, config) {
926
960
  }
927
961
  }
928
962
  else if (config.debugMode) {
929
- logWarn('消息', `无法获取消息ID,自动撤回功能无法生效`);
963
+ logWarn('消息', '无法获取消息ID,自动撤回功能无法生效');
930
964
  }
931
965
  }
932
966
  else if (config.debugMode) {
933
- logDebug('消息', `检测到私聊消息,不撤回机器人回复`);
967
+ logDebug('消息', '检测到私聊消息,不撤回机器人回复');
934
968
  }
935
969
  }
936
970
  }
@@ -964,7 +998,7 @@ function apply(ctx, config) {
964
998
  const getServerConfigById = (serverId) => {
965
999
  if (!config.servers || !Array.isArray(config.servers))
966
1000
  return null;
967
- return config.servers.find(server => server.id === serverId && (server.enabled !== false)) || null;
1001
+ return config.servers.find(server => server.id === serverId && server.enabled !== false) || null;
968
1002
  };
969
1003
  // 根据服务器名称获取服务器配置
970
1004
  const getServerConfigByName = (serverName) => {
@@ -1118,9 +1152,9 @@ function apply(ctx, config) {
1118
1152
  const regularPrefixRegex = new RegExp(`^${escapeRegExp(botNickname)}\\s+((mcid|buid|绑定|bind)\\s*.*)$`, 'i');
1119
1153
  const regularMatch = content.match(regularPrefixRegex);
1120
1154
  // 2. 如果botNickname不包含@,也尝试匹配带@的版本
1121
- const atPrefixRegex = !botNickname.startsWith('@') ?
1122
- new RegExp(`^@${escapeRegExp(botNickname)}\\s+((mcid|buid|绑定|bind)\\s*.*)$`, 'i') :
1123
- null;
1155
+ const atPrefixRegex = !botNickname.startsWith('@')
1156
+ ? new RegExp(`^@${escapeRegExp(botNickname)}\\s+((mcid|buid|绑定|bind)\\s*.*)$`, 'i')
1157
+ : null;
1124
1158
  if (regularMatch && regularMatch[1]) {
1125
1159
  matchedCommand = regularMatch[1].trim();
1126
1160
  }
@@ -1165,8 +1199,12 @@ function apply(ctx, config) {
1165
1199
  return next();
1166
1200
  }
1167
1201
  // 跳过空消息或命令消息
1168
- if (!session.content || session.content.startsWith('.') || session.content.startsWith('/') ||
1169
- session.content.includes('mcid') || session.content.includes('buid') || session.content.includes('绑定')) {
1202
+ if (!session.content ||
1203
+ session.content.startsWith('.') ||
1204
+ session.content.startsWith('/') ||
1205
+ session.content.includes('mcid') ||
1206
+ session.content.includes('buid') ||
1207
+ session.content.includes('绑定')) {
1170
1208
  return next();
1171
1209
  }
1172
1210
  // 检查当前时间是否在群组禁言时间段内
@@ -1182,7 +1220,7 @@ function apply(ctx, config) {
1182
1220
  }
1183
1221
  // 随机触发概率:管理员 1%,普通用户 80%,避免过于频繁
1184
1222
  const isUserAdmin = await isAdmin(session.userId);
1185
- const triggerRate = isUserAdmin ? 0.01 : 0.80;
1223
+ const triggerRate = isUserAdmin ? 0.01 : 0.8;
1186
1224
  if (Math.random() > triggerRate) {
1187
1225
  return next();
1188
1226
  }
@@ -1242,7 +1280,9 @@ function apply(ctx, config) {
1242
1280
  return next();
1243
1281
  }
1244
1282
  // 情况2:只绑定了B站,未绑定MC
1245
- if (bind.buidUid && bind.buidUsername && (!bind.mcUsername || bind.mcUsername.startsWith('_temp_'))) {
1283
+ if (bind.buidUid &&
1284
+ bind.buidUsername &&
1285
+ (!bind.mcUsername || bind.mcUsername.startsWith('_temp_'))) {
1246
1286
  const mcInfo = null;
1247
1287
  const isNicknameCorrect = services.nickname.checkNicknameFormat(currentNickname, bind.buidUsername, mcInfo);
1248
1288
  if (!isNicknameCorrect) {
@@ -1263,7 +1303,10 @@ function apply(ctx, config) {
1263
1303
  return next();
1264
1304
  }
1265
1305
  // 情况3:都已绑定,但群昵称格式不正确
1266
- if (bind.buidUid && bind.buidUsername && bind.mcUsername && !bind.mcUsername.startsWith('_temp_')) {
1306
+ if (bind.buidUid &&
1307
+ bind.buidUsername &&
1308
+ bind.mcUsername &&
1309
+ !bind.mcUsername.startsWith('_temp_')) {
1267
1310
  const isNicknameCorrect = services.nickname.checkNicknameFormat(currentNickname, bind.buidUsername, bind.mcUsername);
1268
1311
  if (!isNicknameCorrect) {
1269
1312
  // 更新提醒次数
@@ -1305,19 +1348,26 @@ function apply(ctx, config) {
1305
1348
  if (content === '取消' || content === 'cancel') {
1306
1349
  removeBindingSession(session.userId, session.channelId);
1307
1350
  logger.info(`[交互绑定] QQ(${normalizedUserId})手动取消了绑定会话`);
1308
- await sendMessage(session, [koishi_1.h.text('❌ 绑定会话已取消\n\n📋 温馨提醒:请按群规设置合适的群昵称。若在管理员多次提醒后仍不配合绑定账号信息或按规修改群昵称,将按群规进行相应处理。')]);
1351
+ await sendMessage(session, [
1352
+ koishi_1.h.text('❌ 绑定会话已取消\n\n📋 温馨提醒:请按群规设置合适的群昵称。若在管理员多次提醒后仍不配合绑定账号信息或按规修改群昵称,将按群规进行相应处理。')
1353
+ ]);
1309
1354
  return;
1310
1355
  }
1311
1356
  // 检查是否在绑定过程中使用了其他绑定相关命令(排除跳过选项)
1312
1357
  // 这里使用原始内容检测命令,避免误判@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('/'))) {
1358
+ if (rawContent &&
1359
+ content !== '跳过' &&
1360
+ content !== 'skip' &&
1361
+ (rawContent.includes('绑定') ||
1362
+ rawContent.includes('bind') ||
1363
+ rawContent.includes('mcid') ||
1364
+ rawContent.includes('buid') ||
1365
+ rawContent.startsWith('.') ||
1366
+ rawContent.startsWith('/'))) {
1319
1367
  const currentState = bindingSession.state === 'waiting_mc_username' ? 'MC用户名' : 'B站UID';
1320
- await sendMessage(session, [koishi_1.h.text(`🔄 您正在进行交互式绑定,请继续输入${currentState}\n\n如需取消当前绑定,请发送"取消"`)]);
1368
+ await sendMessage(session, [
1369
+ koishi_1.h.text(`🔄 您正在进行交互式绑定,请继续输入${currentState}\n\n如需取消当前绑定,请发送"取消"`)
1370
+ ]);
1321
1371
  return;
1322
1372
  }
1323
1373
  // 检查是否为明显无关的输入
@@ -1329,7 +1379,39 @@ function apply(ctx, config) {
1329
1379
  invalidInputCount: newCount
1330
1380
  });
1331
1381
  // 检查是否为明显的聊天内容(使用清理后的内容)
1332
- const chatKeywords = ['你好', 'hello', 'hi', '在吗', '在不在', '怎么样', '什么', '为什么', '好的', '谢谢', '哈哈', '呵呵', '早上好', '晚上好', '晚安', '再见', '拜拜', '666', '牛', '厉害', '真的吗', '不是吧', '哇', '哦', '嗯', '好吧', '行', '可以', '没事', '没问题', '没关系'];
1382
+ const chatKeywords = [
1383
+ '你好',
1384
+ 'hello',
1385
+ 'hi',
1386
+ '在吗',
1387
+ '在不在',
1388
+ '怎么样',
1389
+ '什么',
1390
+ '为什么',
1391
+ '好的',
1392
+ '谢谢',
1393
+ '哈哈',
1394
+ '呵呵',
1395
+ '早上好',
1396
+ '晚上好',
1397
+ '晚安',
1398
+ '再见',
1399
+ '拜拜',
1400
+ '666',
1401
+ '牛',
1402
+ '厉害',
1403
+ '真的吗',
1404
+ '不是吧',
1405
+ '哇',
1406
+ '哦',
1407
+ '嗯',
1408
+ '好吧',
1409
+ '行',
1410
+ '可以',
1411
+ '没事',
1412
+ '没问题',
1413
+ '没关系'
1414
+ ];
1333
1415
  const isChatMessage = chatKeywords.some(keyword => content.toLowerCase().includes(keyword)) ||
1334
1416
  /[!?。,;:""''()【】〈〉《》「」『』〔〕〖〗〘〙〚〛]{2,}/.test(content) ||
1335
1417
  /[!?.,;:"'()[\]<>{}]{3,}/.test(content);
@@ -1339,13 +1421,17 @@ function apply(ctx, config) {
1339
1421
  removeBindingSession(session.userId, session.channelId);
1340
1422
  logger.info(`[交互绑定] QQ(${normalizedUserId})持续发送聊天消息,自动取消绑定会话避免打扰`);
1341
1423
  // 对于聊天取消,给一个更温和的提示,同时提醒群规
1342
- await sendMessage(session, [koishi_1.h.text(`💬 看起来您在聊天,绑定流程已自动取消\n\n📋 温馨提醒:请按群规设置合适的群昵称。若在管理员多次提醒后仍不配合绑定账号信息或按规修改群昵称,将按群规进行相应处理。\n\n如需绑定账号,请随时使用 ${formatCommand('绑定')} 命令重新开始`)]);
1424
+ await sendMessage(session, [
1425
+ koishi_1.h.text(`💬 看起来您在聊天,绑定流程已自动取消\n\n📋 温馨提醒:请按群规设置合适的群昵称。若在管理员多次提醒后仍不配合绑定账号信息或按规修改群昵称,将按群规进行相应处理。\n\n如需绑定账号,请随时使用 ${formatCommand('绑定')} 命令重新开始`)
1426
+ ]);
1343
1427
  return;
1344
1428
  }
1345
1429
  else {
1346
1430
  // 第一次聊天消息,给温和提醒
1347
1431
  const expectedInput = bindingSession.state === 'waiting_mc_username' ? 'MC用户名' : 'B站UID';
1348
- await sendMessage(session, [koishi_1.h.text(`💭 您当前正在进行账号绑定,需要输入${expectedInput}\n\n如不需要绑定,请发送"取消",或继续聊天我们会自动取消绑定流程`)]);
1432
+ await sendMessage(session, [
1433
+ koishi_1.h.text(`💭 您当前正在进行账号绑定,需要输入${expectedInput}\n\n如不需要绑定,请发送"取消",或继续聊天我们会自动取消绑定流程`)
1434
+ ]);
1349
1435
  return;
1350
1436
  }
1351
1437
  }
@@ -1354,14 +1440,20 @@ function apply(ctx, config) {
1354
1440
  if (newCount === 1) {
1355
1441
  // 第1次无关输入,提醒检查
1356
1442
  const expectedInput = bindingSession.state === 'waiting_mc_username' ? 'MC用户名' : 'B站UID';
1357
- await sendMessage(session, [koishi_1.h.text(`🤔 您当前正在进行绑定流程,需要输入${expectedInput}\n\n如果您想取消绑定,请发送"取消"`)]);
1443
+ await sendMessage(session, [
1444
+ koishi_1.h.text(`🤔 您当前正在进行绑定流程,需要输入${expectedInput}\n\n如果您想取消绑定,请发送"取消"`)
1445
+ ]);
1358
1446
  return;
1359
1447
  }
1360
1448
  else if (newCount >= 2) {
1361
1449
  // 第2次无关输入,建议取消
1362
1450
  removeBindingSession(session.userId, session.channelId);
1363
1451
  logger.info(`[交互绑定] QQ(${normalizedUserId})因多次无关输入自动取消绑定会话`);
1364
- await sendMessage(session, [koishi_1.h.text('🔄 检测到您可能不想继续绑定流程,已自动取消绑定会话\n\n📋 温馨提醒:请按群规设置合适的群昵称。若在管理员多次提醒后仍不配合绑定账号信息或按规修改群昵称,将按群规进行相应处理。\n\n如需重新绑定,请使用 ' + formatCommand('绑定') + ' 命令')]);
1452
+ await sendMessage(session, [
1453
+ koishi_1.h.text('🔄 检测到您可能不想继续绑定流程,已自动取消绑定会话\n\n📋 温馨提醒:请按群规设置合适的群昵称。若在管理员多次提醒后仍不配合绑定账号信息或按规修改群昵称,将按群规进行相应处理。\n\n如需重新绑定,请使用 ' +
1454
+ formatCommand('绑定') +
1455
+ ' 命令')
1456
+ ]);
1365
1457
  return;
1366
1458
  }
1367
1459
  }
@@ -1409,7 +1501,9 @@ function apply(ctx, config) {
1409
1501
  }
1410
1502
  await sendMessage(session, [
1411
1503
  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`)] : [])
1504
+ ...(config?.showAvatar
1505
+ ? [koishi_1.h.image(`https://workers.vrp.moe/bilibili/avatar/${existingBind.buidUid}?size=160`)]
1506
+ : [])
1413
1507
  ]);
1414
1508
  return;
1415
1509
  }
@@ -1446,7 +1540,9 @@ function apply(ctx, config) {
1446
1540
  const profile = await services.api.validateUsername(content);
1447
1541
  if (!profile) {
1448
1542
  logger.warn(`[交互绑定] QQ(${normalizedUserId})输入的MC用户名"${content}"不存在`);
1449
- await sendMessage(session, [koishi_1.h.text(`❌ 用户名 ${content} 不存在\n请重新输入或发送"跳过"完成绑定`)]);
1543
+ await sendMessage(session, [
1544
+ koishi_1.h.text(`❌ 用户名 ${content} 不存在\n请重新输入或发送"跳过"完成绑定`)
1545
+ ]);
1450
1546
  return;
1451
1547
  }
1452
1548
  const username = profile.name;
@@ -1455,22 +1551,28 @@ function apply(ctx, config) {
1455
1551
  const existingBind = await services.database.getMcBindByQQId(normalizedUserId);
1456
1552
  if (existingBind && existingBind.mcUsername && !existingBind.mcUsername.startsWith('_temp_')) {
1457
1553
  // 检查冷却时间
1458
- if (!await isAdmin(session.userId) && !checkCooldown(existingBind.lastModified)) {
1554
+ if (!(await isAdmin(session.userId)) && !checkCooldown(existingBind.lastModified)) {
1459
1555
  const days = config.cooldownDays;
1460
1556
  const now = new Date();
1461
1557
  const diffTime = now.getTime() - existingBind.lastModified.getTime();
1462
1558
  const passedDays = Math.floor(diffTime / (1000 * 60 * 60 * 24));
1463
1559
  const remainingDays = days - passedDays;
1464
1560
  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')} 命令或联系管理员`)]);
1561
+ const displayUsername = existingBind.mcUsername && !existingBind.mcUsername.startsWith('_temp_')
1562
+ ? existingBind.mcUsername
1563
+ : '未绑定';
1564
+ await sendMessage(session, [
1565
+ koishi_1.h.text(`❌ 您已绑定MC账号: ${displayUsername}\n\n如需修改,请在冷却期结束后(还需${remainingDays}天)使用 ${formatCommand('mcid change')} 命令或联系管理员`)
1566
+ ]);
1467
1567
  return;
1468
1568
  }
1469
1569
  }
1470
1570
  // 检查用户名是否已被其他人绑定
1471
1571
  if (await services.database.checkUsernameExists(username, session.userId, uuid)) {
1472
1572
  logger.warn(`[交互绑定] MC用户名"${username}"已被其他用户绑定`);
1473
- await sendMessage(session, [koishi_1.h.text(`❌ 用户名 ${username} 已被其他用户绑定\n\n请输入其他MC用户名或发送"跳过"完成绑定`)]);
1573
+ await sendMessage(session, [
1574
+ koishi_1.h.text(`❌ 用户名 ${username} 已被其他用户绑定\n\n请输入其他MC用户名或发送"跳过"完成绑定`)
1575
+ ]);
1474
1576
  return;
1475
1577
  }
1476
1578
  // 绑定MC账号
@@ -1578,20 +1680,26 @@ function apply(ctx, config) {
1578
1680
  // 验证UID格式
1579
1681
  if (!actualUid || !/^\d+$/.test(actualUid)) {
1580
1682
  logger.warn(`[交互绑定] QQ(${normalizedUserId})输入的B站UID"${content}"格式无效`);
1581
- await sendMessage(session, [koishi_1.h.text('❌ UID格式无效,请重新输入\n支持格式:纯数字、UID:数字、空间链接\n或发送"跳过"仅绑定MC账号')]);
1683
+ await sendMessage(session, [
1684
+ koishi_1.h.text('❌ UID格式无效,请重新输入\n支持格式:纯数字、UID:数字、空间链接\n或发送"跳过"仅绑定MC账号')
1685
+ ]);
1582
1686
  return;
1583
1687
  }
1584
1688
  // 检查UID是否已被绑定
1585
1689
  if (await services.database.checkBuidExists(actualUid, session.userId)) {
1586
1690
  logger.warn(`[交互绑定] B站UID"${actualUid}"已被其他用户绑定`);
1587
- await sendMessage(session, [koishi_1.h.text(`❌ UID ${actualUid} 已被其他用户绑定\n\n请输入其他B站UID\n或发送"跳过"仅绑定MC账号`)]);
1691
+ await sendMessage(session, [
1692
+ koishi_1.h.text(`❌ UID ${actualUid} 已被其他用户绑定\n\n请输入其他B站UID\n或发送"跳过"仅绑定MC账号`)
1693
+ ]);
1588
1694
  return;
1589
1695
  }
1590
1696
  // 验证UID是否存在
1591
1697
  const buidUser = await services.api.validateBUID(actualUid);
1592
1698
  if (!buidUser) {
1593
1699
  logger.warn(`[交互绑定] QQ(${normalizedUserId})输入的B站UID"${actualUid}"不存在`);
1594
- await sendMessage(session, [koishi_1.h.text(`❌ 无法验证UID: ${actualUid}\n\n该用户可能不存在或未被发现\n可以去直播间发个弹幕后重试绑定\n或发送"跳过"仅绑定MC账号`)]);
1700
+ await sendMessage(session, [
1701
+ koishi_1.h.text(`❌ 无法验证UID: ${actualUid}\n\n该用户可能不存在或未被发现\n可以去直播间发个弹幕后重试绑定\n或发送"跳过"仅绑定MC账号`)
1702
+ ]);
1595
1703
  return;
1596
1704
  }
1597
1705
  // 绑定B站账号
@@ -1600,9 +1708,13 @@ function apply(ctx, config) {
1600
1708
  logger.error(`[交互绑定] QQ(${normalizedUserId})绑定B站账号失败`);
1601
1709
  removeBindingSession(session.userId, session.channelId);
1602
1710
  // 根据是否有MC绑定提供不同的提示
1603
- const displayMcName = bindingSession.mcUsername && !bindingSession.mcUsername.startsWith('_temp_') ? bindingSession.mcUsername : null;
1711
+ const displayMcName = bindingSession.mcUsername && !bindingSession.mcUsername.startsWith('_temp_')
1712
+ ? bindingSession.mcUsername
1713
+ : null;
1604
1714
  const mcStatus = displayMcName ? `您的MC账号${displayMcName}已成功绑定\n` : '';
1605
- await sendMessage(session, [koishi_1.h.text(`❌ B站账号绑定失败,数据库操作出错\n\n${mcStatus}可稍后使用 ${formatCommand('buid bind <UID>')} 命令单独绑定B站账号`)]);
1715
+ await sendMessage(session, [
1716
+ koishi_1.h.text(`❌ B站账号绑定失败,数据库操作出错\n\n${mcStatus}可稍后使用 ${formatCommand('buid bind <UID>')} 命令单独绑定B站账号`)
1717
+ ]);
1606
1718
  return;
1607
1719
  }
1608
1720
  logger.info(`[交互绑定] QQ(${normalizedUserId})成功绑定B站UID: ${actualUid}`);
@@ -1611,7 +1723,9 @@ function apply(ctx, config) {
1611
1723
  // 自动群昵称设置功能 - 使用新的autoSetGroupNickname函数
1612
1724
  try {
1613
1725
  // 检查是否有有效的MC用户名(不是临时用户名)
1614
- const mcName = bindingSession.mcUsername && !bindingSession.mcUsername.startsWith('_temp_') ? bindingSession.mcUsername : null;
1726
+ const mcName = bindingSession.mcUsername && !bindingSession.mcUsername.startsWith('_temp_')
1727
+ ? bindingSession.mcUsername
1728
+ : null;
1615
1729
  await services.nickname.autoSetGroupNickname(session, mcName, buidUser.username, String(buidUser.uid));
1616
1730
  logger.info(`[交互绑定] QQ(${normalizedUserId})绑定完成,已设置群昵称`);
1617
1731
  }
@@ -1632,7 +1746,9 @@ function apply(ctx, config) {
1632
1746
  extraInfo += `\n荣耀等级: ${buidUser.wealthMedalLevel}`;
1633
1747
  }
1634
1748
  // 准备完成消息
1635
- const displayMcName = bindingSession.mcUsername && !bindingSession.mcUsername.startsWith('_temp_') ? bindingSession.mcUsername : null;
1749
+ const displayMcName = bindingSession.mcUsername && !bindingSession.mcUsername.startsWith('_temp_')
1750
+ ? bindingSession.mcUsername
1751
+ : null;
1636
1752
  const mcInfo = displayMcName ? `MC: ${displayMcName}` : 'MC: 未绑定';
1637
1753
  let extraTip = '';
1638
1754
  // 如果用户跳过了MC绑定或MC账号是temp,提供后续绑定的指引
@@ -1641,7 +1757,9 @@ function apply(ctx, config) {
1641
1757
  }
1642
1758
  await sendMessage(session, [
1643
1759
  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`)] : [])
1760
+ ...(config?.showAvatar
1761
+ ? [koishi_1.h.image(`https://workers.vrp.moe/bilibili/avatar/${buidUser.uid}?size=160`)]
1762
+ : [])
1645
1763
  ]);
1646
1764
  };
1647
1765
  // 帮助函数:转义正则表达式中的特殊字符
@@ -1661,7 +1779,7 @@ function apply(ctx, config) {
1661
1779
  // @Bot昵称 格式(如果配置了botNickname)
1662
1780
  config.botNickname ? new RegExp(`^@${escapeRegExp(config.botNickname)}\\s+`, 'i') : null,
1663
1781
  // @botUserId 格式
1664
- new RegExp(`^@${escapeRegExp(botUserId)}\\s+`, 'i'),
1782
+ new RegExp(`^@${escapeRegExp(botUserId)}\\s+`, 'i')
1665
1783
  ].filter(Boolean);
1666
1784
  let cleanedContent = content.trim();
1667
1785
  // 尝试匹配并移除@Bot前缀