koishi-plugin-maibot 1.7.68 → 1.7.70

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,26 +1,25 @@
1
1
  import type { UserBinding } from './database';
2
2
  export declare function normalizePreviewUserId(userId: string | number): string;
3
- /** 与插件配置 bindingPlayerNameMatch 对应 */
4
- export interface BindingPlayerNameMatchConfig {
5
- /** 0–100:规范化后玩家名相似度下限(编辑距离比值×100)。100 须完全一致 */
6
- minSimilarityPercent?: number;
7
- }
8
- export interface BindingNameMatchOptions {
9
- minSimilarityPercent: number;
10
- }
11
- export declare function resolveBindingNameMatchOptions(cfg?: BindingPlayerNameMatchConfig): BindingNameMatchOptions;
12
- /** 玩家名规范化:去首尾空白 + Unicode NFKC(全角英数、兼容字符等与半角统一) */
13
- export declare function normalizePlayerNameForMatch(name: string): string;
14
- /** 0–1,分母为 max(len);用于短玩家名 */
15
- export declare function playerNameSimilarityRatio(a: string, b: string): number;
3
+ /** 老版本密钥存库的 maiUid 常见以 Base64 前缀 MDk(即 ASCII「097…」)开头 */
4
+ export declare function isLegacyMdkMaiUid(boundUid: string): boolean;
5
+ export type VerifyPreviewBindingResult = {
6
+ ok: true;
7
+ } | {
8
+ ok: false;
9
+ message: string;
10
+ } | {
11
+ ok: true;
12
+ migratedToUid: string;
13
+ notice: string;
14
+ };
16
15
  /**
17
- * 校验 preview 与绑定是否为同一街机账号(加密 UserID + 可选绑定时的玩家名)
18
- * @param nameMatch 玩家名:先 NFKC 规范化,再按 minSimilarityPercent 比较编辑距离比值
16
+ * 校验 preview 与绑定是否为同一街机账号:比较绑定记录的 maiUid 与二维码 preview 的 UserID。
17
+ * 绑定为老格式(maiUid MDk 开头)且与二维码 UID 不一致时,视为同账号升级格式,返回 ok + 迁移信息(由调用方写库并提示)。
19
18
  */
20
19
  export declare function verifyPreviewMatchesBinding(binding: UserBinding, preview: {
21
20
  UserID: string | number;
22
21
  UserName?: string;
23
- }, nameMatch?: BindingNameMatchOptions): string | null;
22
+ }): VerifyPreviewBindingResult;
24
23
  /** lastStateAt:maibot_user_rebind_state.lastBindChangeAt;bindTime:当前绑定记录的 bindTime(无绑定则 0) */
25
24
  export declare function msUntilBindChangeAllowed(lastStateAtMs: number, bindTimeMs: number, minIntervalDays: number): number;
26
25
  export declare function formatBindChangeWaitHuman(ms: number): string;
@@ -1 +1 @@
1
- {"version":3,"file":"binding-verify.d.ts","sourceRoot":"","sources":["../src/binding-verify.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAE7C,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAEtE;AAED,sCAAsC;AACtC,MAAM,WAAW,4BAA4B;IAC3C,+CAA+C;IAC/C,oBAAoB,CAAC,EAAE,MAAM,CAAA;CAC9B;AAED,MAAM,WAAW,uBAAuB;IACtC,oBAAoB,EAAE,MAAM,CAAA;CAC7B;AAID,wBAAgB,8BAA8B,CAC5C,GAAG,CAAC,EAAE,4BAA4B,GACjC,uBAAuB,CAKzB;AAED,mDAAmD;AACnD,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhE;AAsBD,8BAA8B;AAC9B,wBAAgB,yBAAyB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAKtE;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE;IAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,EACvD,SAAS,GAAE,uBAA0D,GACpE,MAAM,GAAG,IAAI,CAgCf;AAED,8FAA8F;AAC9F,wBAAgB,wBAAwB,CACtC,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,MAAM,EAClB,eAAe,EAAE,MAAM,GACtB,MAAM,CAMR;AAED,wBAAgB,yBAAyB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAS5D"}
1
+ {"version":3,"file":"binding-verify.d.ts","sourceRoot":"","sources":["../src/binding-verify.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAE7C,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAEtE;AAED,yDAAyD;AACzD,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAE3D;AAED,MAAM,MAAM,0BAA0B,GAClC;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GACZ;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC9B;IACE,EAAE,EAAE,IAAI,CAAA;IACR,aAAa,EAAE,MAAM,CAAA;IACrB,MAAM,EAAE,MAAM,CAAA;CACf,CAAA;AAEL;;;GAGG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE;IAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GACtD,0BAA0B,CA4B5B;AAED,8FAA8F;AAC9F,wBAAgB,wBAAwB,CACtC,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,MAAM,EAClB,eAAe,EAAE,MAAM,GACtB,MAAM,CAMR;AAED,wBAAgB,yBAAyB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAS5D"}
@@ -1,94 +1,47 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.normalizePreviewUserId = normalizePreviewUserId;
4
- exports.resolveBindingNameMatchOptions = resolveBindingNameMatchOptions;
5
- exports.normalizePlayerNameForMatch = normalizePlayerNameForMatch;
6
- exports.playerNameSimilarityRatio = playerNameSimilarityRatio;
4
+ exports.isLegacyMdkMaiUid = isLegacyMdkMaiUid;
7
5
  exports.verifyPreviewMatchesBinding = verifyPreviewMatchesBinding;
8
6
  exports.msUntilBindChangeAllowed = msUntilBindChangeAllowed;
9
7
  exports.formatBindChangeWaitHuman = formatBindChangeWaitHuman;
10
8
  function normalizePreviewUserId(userId) {
11
9
  return String(userId);
12
10
  }
13
- const DEFAULT_MIN_SIMILARITY = 100;
14
- function resolveBindingNameMatchOptions(cfg) {
15
- let p = cfg?.minSimilarityPercent;
16
- if (typeof p !== 'number' || Number.isNaN(p))
17
- p = DEFAULT_MIN_SIMILARITY;
18
- p = Math.min(100, Math.max(0, p));
19
- return { minSimilarityPercent: p };
20
- }
21
- /** 玩家名规范化:去首尾空白 + Unicode NFKC(全角英数、兼容字符等与半角统一) */
22
- function normalizePlayerNameForMatch(name) {
23
- return name.normalize('NFKC').trim();
24
- }
25
- function levenshtein(a, b) {
26
- const m = a.length;
27
- const n = b.length;
28
- if (m === 0)
29
- return n;
30
- if (n === 0)
31
- return m;
32
- const dp = new Uint32Array(n + 1);
33
- for (let j = 0; j <= n; j++)
34
- dp[j] = j;
35
- for (let i = 1; i <= m; i++) {
36
- let prev = dp[0];
37
- dp[0] = i;
38
- for (let j = 1; j <= n; j++) {
39
- const tmp = dp[j];
40
- const cost = a[i - 1] === b[j - 1] ? 0 : 1;
41
- dp[j] = Math.min(dp[j] + 1, dp[j - 1] + 1, prev + cost);
42
- prev = tmp;
43
- }
44
- }
45
- return dp[n];
46
- }
47
- /** 0–1,分母为 max(len);用于短玩家名 */
48
- function playerNameSimilarityRatio(a, b) {
49
- if (a === b)
50
- return 1;
51
- const maxLen = Math.max(a.length, b.length);
52
- if (maxLen === 0)
53
- return 1;
54
- return Math.max(0, 1 - levenshtein(a, b) / maxLen);
11
+ /** 老版本密钥存库的 maiUid 常见以 Base64 前缀 MDk(即 ASCII「097…」)开头 */
12
+ function isLegacyMdkMaiUid(boundUid) {
13
+ return String(boundUid).startsWith('MDk');
55
14
  }
56
15
  /**
57
- * 校验 preview 与绑定是否为同一街机账号(加密 UserID + 可选绑定时的玩家名)
58
- * @param nameMatch 玩家名:先 NFKC 规范化,再按 minSimilarityPercent 比较编辑距离比值
16
+ * 校验 preview 与绑定是否为同一街机账号:比较绑定记录的 maiUid 与二维码 preview 的 UserID。
17
+ * 绑定为老格式(maiUid MDk 开头)且与二维码 UID 不一致时,视为同账号升级格式,返回 ok + 迁移信息(由调用方写库并提示)。
59
18
  */
60
- function verifyPreviewMatchesBinding(binding, preview, nameMatch = resolveBindingNameMatchOptions()) {
19
+ function verifyPreviewMatchesBinding(binding, preview) {
61
20
  const pid = normalizePreviewUserId(preview.UserID);
62
21
  if (pid === '-1' || preview.UserID === -1) {
63
- return '❌ 无效或过期的二维码,无法完成验证。';
64
- }
65
- if (String(binding.maiUid) !== pid) {
66
- return '❌ 当前二维码对应的街机账号与绑定不一致,请使用已绑定账号本人微信获取的二维码。';
67
- }
68
- const boundName = binding.boundPlayerName?.trim();
69
- if (!boundName || preview.UserName === undefined) {
70
- return null;
71
- }
72
- const current = String(preview.UserName).trim();
73
- const na = normalizePlayerNameForMatch(boundName);
74
- const nb = normalizePlayerNameForMatch(current);
75
- if (!na) {
76
- return null;
77
- }
78
- if (!nb) {
79
- return `❌ 玩家名与绑定记录不一致(绑定为「${boundName}」,当前玩家名为空)。如已改名请使用解绑卡流程后重新绑定。`;
22
+ return { ok: false, message: '❌ 无效或过期的二维码,无法完成验证。请重新获取玩家二维码后重试。' };
80
23
  }
81
- const min = nameMatch.minSimilarityPercent;
82
- const ratio = playerNameSimilarityRatio(na, nb);
83
- const pct = ratio * 100;
84
- if (pct + 1e-9 >= min) {
85
- return null;
24
+ const boundUid = String(binding.maiUid);
25
+ if (boundUid === pid) {
26
+ return { ok: true };
86
27
  }
87
- const minDisp = Number.isInteger(min) ? String(min) : min.toFixed(1);
88
- if (min >= 100) {
89
- return `❌ 玩家名与绑定记录不一致(绑定为「${boundName}」,当前为「${current}」)。如已改名请使用解绑卡流程后重新绑定。`;
28
+ if (isLegacyMdkMaiUid(boundUid)) {
29
+ return {
30
+ ok: true,
31
+ migratedToUid: pid,
32
+ notice: `💾 街机账号 UID 不一致:\n` +
33
+ `• 当前绑定记录的 UID:${boundUid}\n` +
34
+ `• 当前二维码对应的 UID:${pid}\n` +
35
+ `已为您自动迁移到新格式。`,
36
+ };
90
37
  }
91
- return `❌ 玩家名与绑定记录不一致(绑定为「${boundName}」,当前为「${current}」)。规范化后相似度约 ${pct.toFixed(0)}%(要求≥${minDisp}%)。可在插件配置中调低「玩家名最低相似度」或解绑后重新绑定。`;
38
+ return {
39
+ ok: false,
40
+ message: `❌ 街机账号 UID 不一致:\n` +
41
+ `• 当前绑定记录的 UID:${boundUid}\n` +
42
+ `• 当前二维码对应的 UID:${pid}\n` +
43
+ `若您已更换游戏账号,请使用 /mai解绑 后重新绑定(换绑冷却期内请使用 /mai解绑卡)。`,
44
+ };
92
45
  }
93
46
  /** lastStateAt:maibot_user_rebind_state.lastBindChangeAt;bindTime:当前绑定记录的 bindTime(无绑定则 0) */
94
47
  function msUntilBindChangeAllowed(lastStateAtMs, bindTimeMs, minIntervalDays) {
@@ -1 +1 @@
1
- {"version":3,"file":"binding-verify.js","sourceRoot":"","sources":["../src/binding-verify.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"binding-verify.js","sourceRoot":"","sources":["../src/binding-verify.ts"],"names":[],"mappings":"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"}
package/lib/index.d.ts CHANGED
@@ -69,11 +69,6 @@ export interface Config {
69
69
  minDaysBetweenBindChange: number;
70
70
  shopUrl?: string;
71
71
  };
72
- /** SGID / preview 校验时:绑定快照玩家名与当前玩家名的匹配(含 /mai状态、mymai 等) */
73
- bindingPlayerNameMatch?: {
74
- /** 0–100:NFKC 规范化后,编辑距离相似度下限;100 为须完全一致。全角如 Milk 与半角 Milk 在 100 下通常视为一致 */
75
- minSimilarityPercent: number;
76
- };
77
72
  }
78
73
  export declare const Config: Schema<Config>;
79
74
  export declare function apply(ctx: Context, config: Config): void;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAW,MAAM,QAAQ,CAAA;AASjD,OAAO,EAoBL,KAAK,sBAAsB,EAC5B,MAAM,qBAAqB,CAAA;AAE5B,eAAO,MAAM,IAAI,WAAW,CAAA;AAC5B,eAAO,MAAM,MAAM,UAAe,CAAA;AAElC,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,MAAM;IACrB,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,WAAW,EAAE,WAAW,CAAA;IACxB,cAAc,EAAE,MAAM,CAAA;IACtB,iBAAiB,CAAC,EAAE;QAClB,OAAO,EAAE,OAAO,CAAA;QAChB,SAAS,EAAE,MAAM,CAAA;QACjB,OAAO,EAAE,MAAM,CAAA;QACf,OAAO,EAAE,MAAM,CAAA;KAChB,CAAA;IACD,aAAa,CAAC,EAAE;QACd,YAAY,EAAE,MAAM,CAAA;QACpB,aAAa,EAAE,MAAM,CAAA;KACtB,CAAA;IACD,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,sBAAsB,CAAC,EAAE,MAAM,CAAA;IAC/B,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,uBAAuB,CAAC,EAAE,MAAM,CAAA;IAChC,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B,SAAS,CAAC,EAAE;QACV,OAAO,EAAE,OAAO,CAAA;QAChB,QAAQ,EAAE,MAAM,EAAE,CAAA;QAClB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;QAClB,OAAO,EAAE,MAAM,CAAA;KAChB,CAAA;IACD,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,KAAK,CAAC,EAAE;QACN,OAAO,EAAE,OAAO,CAAA;QAChB,QAAQ,EAAE,MAAM,CAAA;QAChB,OAAO,EAAE,MAAM,CAAA;KAChB,CAAA;IACD,YAAY,CAAC,EAAE;QACb,OAAO,EAAE,OAAO,CAAA;QAChB,UAAU,EAAE,MAAM,CAAA;KACnB,CAAA;IACD,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,4BAA4B,CAAC,EAAE,OAAO,CAAA;IACtC,+CAA+C;IAC/C,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,6EAA6E;IAC7E,gBAAgB,CAAC,EAAE,sBAAsB,CAAA;IACzC,wDAAwD;IACxD,YAAY,CAAC,EAAE;QACb,wBAAwB,EAAE,MAAM,CAAA;QAChC,OAAO,CAAC,EAAE,MAAM,CAAA;KACjB,CAAA;CACF;AAED,eAAO,MAAM,MAAM,EAAE,MAAM,CAAC,MAAM,CAsHhC,CAAA;AA03CF,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,QAu6KjD"}
package/lib/index.js CHANGED
@@ -123,15 +123,6 @@ exports.Config = koishi_1.Schema.object({
123
123
  minDaysBetweenBindChange: 30,
124
124
  shopUrl: '',
125
125
  }),
126
- bindingPlayerNameMatch: koishi_1.Schema.object({
127
- minSimilarityPercent: koishi_1.Schema.number()
128
- .default(100)
129
- .min(0)
130
- .max(100)
131
- .description('玩家名最低相似度(0–100)。先进行 Unicode NFKC 规范化(全角/半角英数字统一)再按编辑距离计算;100 表示须完全一致。略低于 100 可容忍少量字符差异(改名、显示差异等)。'),
132
- })
133
- .description('绑定记录中的玩家名与 preview 的校验(maiUid 一致时的第二道校验)')
134
- .default({ minSimilarityPercent: 100 }),
135
126
  });
136
127
  // 我认识了很多朋友 以下是我认识的好朋友们!
137
128
  // Fracture_Hikaritsu
@@ -210,6 +201,36 @@ function getSessionCommandUsageHint(session) {
210
201
  function isMaiPluginCommandName(name) {
211
202
  return name.trim().startsWith('mai');
212
203
  }
204
+ /**
205
+ * <spec:text> 会把「clear -g 群号」整段吃成一个参数;从首尾拆出 -g 群标识,并与 .option('-g') 合并(优先已解析的 -g)。
206
+ */
207
+ function splitGroupPrioritySpecAndGuild(specRaw, optionGuild) {
208
+ let specStr = (specRaw ?? '').trim();
209
+ let guild = String(optionGuild ?? '').trim();
210
+ const lead = specStr.match(/^\s*-g\s+(\S+)\s+([\s\S]+)$/i);
211
+ if (lead) {
212
+ if (!guild)
213
+ guild = lead[1];
214
+ specStr = lead[2].trim();
215
+ }
216
+ const tail = specStr.match(/^([\s\S]+?)\s+-g\s+(\S+)\s*$/i);
217
+ if (tail) {
218
+ specStr = tail[1].trim();
219
+ if (!guild)
220
+ guild = tail[2];
221
+ }
222
+ return { spec: specStr, guild };
223
+ }
224
+ /** 群优先表里的 guildKey 多为 platform:guildId;仅填数字时按当前会话平台补前缀 */
225
+ function normalizeGuildKeyForPriority(gk, session) {
226
+ const t = gk.trim();
227
+ if (!t)
228
+ return t;
229
+ if (!/^\d+$/.test(t))
230
+ return t;
231
+ const p = String(session.platform || '').trim().toLowerCase();
232
+ return p ? `${p}:${t}` : t;
233
+ }
213
234
  async function computeMaiCommandUsageHint(command, session) {
214
235
  if (!command || !isMaiPluginCommandName(String(command.name || '')))
215
236
  return '';
@@ -1159,6 +1180,18 @@ async function waitForUserReply(session, ctx, timeout, expectedQuoteMessageIds)
1159
1180
  }, timeout);
1160
1181
  });
1161
1182
  }
1183
+ /** 处理 preview 校验结果:拦截错误、老 MDk* maiUid 自动迁移并同步内存中的 binding */
1184
+ async function applyVerifyPreviewBinding(ctx, binding, result, logger) {
1185
+ if (!result.ok)
1186
+ return { blocked: true, message: result.message };
1187
+ if ('migratedToUid' in result) {
1188
+ await ctx.database.set('maibot_bindings', { userId: binding.userId }, { maiUid: result.migratedToUid });
1189
+ binding.maiUid = result.migratedToUid;
1190
+ logger.info(`maiUid 老格式(MDk*) 已自动迁移 userId=${binding.userId}`);
1191
+ return { blocked: false, migrationNotice: result.notice };
1192
+ }
1193
+ return { blocked: false };
1194
+ }
1162
1195
  /**
1163
1196
  * 获取二维码文本(qr_text)
1164
1197
  * 有有效缓存则直接用;缓存过期则直接问用户发送 SGID/链接
@@ -1174,8 +1207,11 @@ async function getQrText(session, ctx, api, binding, config, timeout = 60000, pr
1174
1207
  if (cacheAge < cacheValidDuration && binding.lastQrCode.startsWith('SGWCMAID')) {
1175
1208
  try {
1176
1209
  const previewCached = await api.getPreview(config.machineInfo.clientId, binding.lastQrCode);
1177
- const vErr = (0, binding_verify_1.verifyPreviewMatchesBinding)(binding, previewCached, (0, binding_verify_1.resolveBindingNameMatchOptions)(config.bindingPlayerNameMatch));
1178
- if (!vErr) {
1210
+ const vr = (0, binding_verify_1.verifyPreviewMatchesBinding)(binding, previewCached);
1211
+ const hv = await applyVerifyPreviewBinding(ctx, binding, vr, logger);
1212
+ if (!hv.blocked) {
1213
+ if (hv.migrationNotice)
1214
+ await session.send(hv.migrationNotice);
1179
1215
  if (previewCached.UserName != null && !binding.boundPlayerName?.trim()) {
1180
1216
  await ctx.database.set('maibot_bindings', { userId: binding.userId }, {
1181
1217
  boundPlayerName: String(previewCached.UserName).trim(),
@@ -1288,11 +1324,14 @@ async function getQrText(session, ctx, api, binding, config, timeout = 60000, pr
1288
1324
  return { qrText: '', error: '无效或过期的二维码' };
1289
1325
  }
1290
1326
  if (binding) {
1291
- const vErr = (0, binding_verify_1.verifyPreviewMatchesBinding)(binding, preview, (0, binding_verify_1.resolveBindingNameMatchOptions)(config.bindingPlayerNameMatch));
1292
- if (vErr) {
1293
- await session.send(vErr);
1294
- return { qrText: '', error: vErr };
1327
+ const vr = (0, binding_verify_1.verifyPreviewMatchesBinding)(binding, preview);
1328
+ const hv = await applyVerifyPreviewBinding(ctx, binding, vr, logger);
1329
+ if (hv.blocked) {
1330
+ await session.send(hv.message);
1331
+ return { qrText: '', error: hv.message };
1295
1332
  }
1333
+ if (hv.migrationNotice)
1334
+ await session.send(hv.migrationNotice);
1296
1335
  const patch = {
1297
1336
  qrCode: qrText,
1298
1337
  lastQrCode: qrText,
@@ -2258,7 +2297,7 @@ function apply(ctx, config) {
2258
2297
  /mai管理员取消群组优先 [群标识] — 取消群组优先;省略时在群内则针对当前群
2259
2298
  /mai管理员取消个人优先 <@或ID> — 清除个人优先记录
2260
2299
  /mai管理员设置个人优先 <@或ID> <spec> — spec:永久、7d、clear 等
2261
- /mai管理员设置群组优先 <spec> [-g 群标识] — 直接改群组优先;spec:永久、7d、clear;-g 省略且群内则当前群
2300
+ /mai管理员设置群组优先 <spec> [-g 群标识] — spec 与 -g 可同一段输入(如 clear -g qq:群号);纯数字 -g 会按当前平台补前缀;-g 省略且在群内则当前群
2262
2301
  /maibypass <@用户|用户ID> — 清除该用户当前全部指令冷却(别名 /mai管理员清除冷却)`;
2263
2302
  }
2264
2303
  helpText += `
@@ -3593,10 +3632,13 @@ function apply(ctx, config) {
3593
3632
  if (preview.UserID === -1 || (typeof preview.UserID === 'string' && preview.UserID === '-1')) {
3594
3633
  return '❌ 无效或过期的二维码,请重新发送';
3595
3634
  }
3596
- const vErr = (0, binding_verify_1.verifyPreviewMatchesBinding)(binding, preview, (0, binding_verify_1.resolveBindingNameMatchOptions)(config.bindingPlayerNameMatch));
3597
- if (vErr) {
3598
- return vErr;
3635
+ const vr = (0, binding_verify_1.verifyPreviewMatchesBinding)(binding, preview);
3636
+ const hv = await applyVerifyPreviewBinding(ctx, binding, vr, ctx.logger('maibot'));
3637
+ if (hv.blocked) {
3638
+ return hv.message;
3599
3639
  }
3640
+ if (hv.migrationNotice)
3641
+ await session.send(hv.migrationNotice);
3600
3642
  const patch = {
3601
3643
  lastQrCode: qrCode,
3602
3644
  lastQrCodeTime: new Date(),
@@ -3778,10 +3820,13 @@ function apply(ctx, config) {
3778
3820
  if (preview.UserID === -1 || (typeof preview.UserID === 'string' && preview.UserID === '-1')) {
3779
3821
  return '❌ 无效或过期的二维码,请重新发送';
3780
3822
  }
3781
- const vErr = (0, binding_verify_1.verifyPreviewMatchesBinding)(binding, preview, (0, binding_verify_1.resolveBindingNameMatchOptions)(config.bindingPlayerNameMatch));
3782
- if (vErr) {
3783
- return vErr;
3823
+ const vr = (0, binding_verify_1.verifyPreviewMatchesBinding)(binding, preview);
3824
+ const hv = await applyVerifyPreviewBinding(ctx, binding, vr, ctx.logger('maibot'));
3825
+ if (hv.blocked) {
3826
+ return hv.message;
3784
3827
  }
3828
+ if (hv.migrationNotice)
3829
+ await session.send(hv.migrationNotice);
3785
3830
  const patch = {
3786
3831
  lastQrCode: qrCode,
3787
3832
  lastQrCodeTime: new Date(),
@@ -4208,10 +4253,13 @@ function apply(ctx, config) {
4208
4253
  if (preview.UserID === -1 || (typeof preview.UserID === 'string' && preview.UserID === '-1')) {
4209
4254
  return '❌ 无效或过期的二维码,请重新发送';
4210
4255
  }
4211
- const vErr = (0, binding_verify_1.verifyPreviewMatchesBinding)(binding, preview, (0, binding_verify_1.resolveBindingNameMatchOptions)(config.bindingPlayerNameMatch));
4212
- if (vErr) {
4213
- return vErr;
4256
+ const vr = (0, binding_verify_1.verifyPreviewMatchesBinding)(binding, preview);
4257
+ const hv = await applyVerifyPreviewBinding(ctx, binding, vr, ctx.logger('maibot'));
4258
+ if (hv.blocked) {
4259
+ return hv.message;
4214
4260
  }
4261
+ if (hv.migrationNotice)
4262
+ await session.send(hv.migrationNotice);
4215
4263
  const patch = {
4216
4264
  lastQrCode: qrCode,
4217
4265
  lastQrCodeTime: new Date(),
@@ -4331,10 +4379,13 @@ function apply(ctx, config) {
4331
4379
  if (preview.UserID === -1 || (typeof preview.UserID === 'string' && preview.UserID === '-1')) {
4332
4380
  return '❌ 无效或过期的二维码,请重新发送';
4333
4381
  }
4334
- const vErr = (0, binding_verify_1.verifyPreviewMatchesBinding)(binding, preview, (0, binding_verify_1.resolveBindingNameMatchOptions)(config.bindingPlayerNameMatch));
4335
- if (vErr) {
4336
- return vErr;
4382
+ const vr = (0, binding_verify_1.verifyPreviewMatchesBinding)(binding, preview);
4383
+ const hv = await applyVerifyPreviewBinding(ctx, binding, vr, ctx.logger('maibot'));
4384
+ if (hv.blocked) {
4385
+ return hv.message;
4337
4386
  }
4387
+ if (hv.migrationNotice)
4388
+ await session.send(hv.migrationNotice);
4338
4389
  const patch = {
4339
4390
  lastQrCode: qrCode,
4340
4391
  lastQrCodeTime: new Date(),
@@ -4732,10 +4783,13 @@ function apply(ctx, config) {
4732
4783
  if (preview.UserID === -1 || (typeof preview.UserID === 'string' && preview.UserID === '-1')) {
4733
4784
  return '❌ 无效或过期的二维码,请重新发送';
4734
4785
  }
4735
- const vErr = (0, binding_verify_1.verifyPreviewMatchesBinding)(binding, preview, (0, binding_verify_1.resolveBindingNameMatchOptions)(config.bindingPlayerNameMatch));
4736
- if (vErr) {
4737
- return vErr;
4786
+ const vr = (0, binding_verify_1.verifyPreviewMatchesBinding)(binding, preview);
4787
+ const hv = await applyVerifyPreviewBinding(ctx, binding, vr, ctx.logger('maibot'));
4788
+ if (hv.blocked) {
4789
+ return hv.message;
4738
4790
  }
4791
+ if (hv.migrationNotice)
4792
+ await session.send(hv.migrationNotice);
4739
4793
  const patch = {
4740
4794
  lastQrCode: qrCode,
4741
4795
  lastQrCodeTime: new Date(),
@@ -6299,6 +6353,9 @@ function apply(ctx, config) {
6299
6353
  });
6300
6354
  ctx.command('mai管理员设置群组优先 <spec:text>', '直接设置群组优先(-g 指定群,默认当前群)')
6301
6355
  .userFields(['authority'])
6356
+ .usage(' 示例:/mai管理员设置群组优先 clear -g qq:5911013814031454\n' +
6357
+ '或:/mai管理员设置群组优先 -g qq:5911013814031454 永久\n' +
6358
+ '(仅数字群号时请写 qq:群号;在群内执行可省略 -g)')
6302
6359
  .option('guild', '-g <guildKey:string> 群标识,如 qq:群号')
6303
6360
  .action(async ({ session, options }, spec) => {
6304
6361
  if (!session)
@@ -6306,14 +6363,16 @@ function apply(ctx, config) {
6306
6363
  if ((session.user?.authority ?? 0) < authLevelForCardAdmin) {
6307
6364
  return `❌ 权限不足,需要 auth 等级 ${authLevelForCardAdmin} 以上`;
6308
6365
  }
6309
- if (!spec?.trim()) {
6366
+ const { spec: specOnly, guild: guildOpt } = splitGroupPrioritySpecAndGuild(spec, options?.guild);
6367
+ if (!specOnly) {
6310
6368
  return '❌ 用法:/mai管理员设置群组优先 <永久|7d|clear> [-g 群标识]';
6311
6369
  }
6312
- const sp = (0, priority_cooldown_1.parsePriorityAdminSpec)(spec);
6370
+ const sp = (0, priority_cooldown_1.parsePriorityAdminSpec)(specOnly);
6313
6371
  if (sp === null) {
6314
6372
  return '❌ 无效的 spec,示例:永久、7d、clear';
6315
6373
  }
6316
- const gk = (String(options?.guild ?? '').trim() || (0, priority_cooldown_1.canonicalGuildPriorityKey)(session) || '').trim();
6374
+ let gk = (guildOpt.trim() || (0, priority_cooldown_1.canonicalGuildPriorityKey)(session) || '').trim();
6375
+ gk = normalizeGuildKeyForPriority(gk, session);
6317
6376
  if (!gk) {
6318
6377
  return '❌ 请使用 -g 指定群标识(platform:guildId),或在群聊内执行。';
6319
6378
  }