@zhin.js/adapter-icqq 1.1.27 → 1.1.29

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.
@@ -0,0 +1,187 @@
1
+ import { messages as t } from './i18n.js';
2
+ /** Challenge ids are stable per kind so the Console can keep UI state across re-opened challenges. */
3
+ export const ICQQ_CHALLENGE_IDS = Object.freeze({
4
+ qrcode: 'icqq-qrcode', slider: 'icqq-slider', device: 'icqq-device', sms: 'icqq-sms', auth: 'icqq-auth',
5
+ });
6
+ /** SMS resend cooldown (QQ refuses a second code within a minute). */
7
+ export const ICQQ_SMS_COOLDOWN_MS = 60_000;
8
+ /** Page the `auth` helper script runs on (QQ's "send verification code" page). */
9
+ export const ICQQ_AUTH_SCRIPT_HOST = 'accounts.qq.com';
10
+ export const ICQQ_AUTH_SCRIPT_PATH = '/login/attack';
11
+ export function qrcodeDescriptor(input, locale) {
12
+ return {
13
+ id: ICQQ_CHALLENGE_IDS.qrcode,
14
+ kind: 'qrcode',
15
+ title: t(locale, 'qrTitle'),
16
+ help: {
17
+ short: t(locale, 'qrShort'),
18
+ steps: [t(locale, 'qrStepScan'), t(locale, 'qrStepConfirm'), t(locale, 'qrStepContinue')],
19
+ },
20
+ media: { ...(input.image ? { qrImage: input.image } : {}), refreshable: true },
21
+ actions: [{ id: 'confirm', label: t(locale, 'qrConfirm'), variant: 'primary' }],
22
+ };
23
+ }
24
+ export function sliderDescriptor(url, locale) {
25
+ const query = url ? sliderCaptchaQuery(url) : undefined;
26
+ return {
27
+ id: ICQQ_CHALLENGE_IDS.slider,
28
+ kind: 'slider',
29
+ title: t(locale, 'sliderTitle'),
30
+ help: {
31
+ short: t(locale, 'sliderShort'),
32
+ steps: [
33
+ { text: t(locale, 'sliderStepOpen'), ...(url ? { blockId: 'slider-link', doneWhen: 'opened' } : {}) },
34
+ t(locale, 'sliderStepDevtools'),
35
+ t(locale, 'sliderStepCopy'),
36
+ ],
37
+ },
38
+ ...(url ? { blocks: [{ kind: 'link', id: 'slider-link', label: t(locale, 'sliderLink'), url }] } : {}),
39
+ ...(query ? { media: { captcha: { provider: 'tencent', query } } } : {}),
40
+ input: { kind: 'ticket', label: t(locale, 'sliderInput'), extract: 'ticket-json-or-url' },
41
+ actions: [{ id: 'submit', label: t(locale, 'loginSubmit'), variant: 'primary', requiresInput: true }],
42
+ };
43
+ }
44
+ export function deviceDescriptor(input, locale) {
45
+ const steps = [
46
+ input.url ? { text: t(locale, 'deviceStepScan'), blockId: 'verify-link', doneWhen: 'opened' } : t(locale, 'deviceStepNoLink'),
47
+ t(locale, 'deviceStepVerify'),
48
+ t(locale, 'deviceStepContinue'),
49
+ ];
50
+ if (input.phone)
51
+ steps.push(t(locale, 'deviceStepSms'));
52
+ return {
53
+ id: ICQQ_CHALLENGE_IDS.device,
54
+ kind: 'device',
55
+ title: t(locale, 'deviceTitle'),
56
+ help: { short: t(locale, 'deviceShort'), steps },
57
+ ...(input.url ? { blocks: [{ kind: 'link', id: 'verify-link', label: t(locale, 'deviceLink'), url: input.url, showQr: true }] } : {}),
58
+ actions: [
59
+ { id: 'continue', label: t(locale, 'deviceContinue'), variant: 'primary' },
60
+ // The SDK only reports a phone when SMS verification is possible for this lock.
61
+ ...(input.phone ? [{ id: 'sms', label: t(locale, 'deviceSms'), variant: 'secondary' }] : []),
62
+ ],
63
+ };
64
+ }
65
+ export function smsDescriptor(input, locale) {
66
+ return {
67
+ id: ICQQ_CHALLENGE_IDS.sms,
68
+ kind: 'sms',
69
+ title: t(locale, 'smsTitle'),
70
+ help: { short: t(locale, 'smsShort', { phone: input.phone || t(locale, 'smsPhoneFallback') }) },
71
+ input: { kind: 'code', label: t(locale, 'smsInput'), length: 6, pattern: '^\\d{6}$', patternHint: t(locale, 'smsHint') },
72
+ actions: [
73
+ { id: 'submit', label: t(locale, 'loginSubmit'), variant: 'primary', requiresInput: true },
74
+ { id: 'resend', label: t(locale, 'smsResend'), variant: 'secondary', cooldownMs: ICQQ_SMS_COOLDOWN_MS },
75
+ ],
76
+ };
77
+ }
78
+ export function authDescriptor(input, locale) {
79
+ const deviceJson = formatDeviceJson(input.device);
80
+ const hasLink = !!input.url;
81
+ const steps = [];
82
+ if (deviceJson)
83
+ steps.push({ text: t(locale, 'authStepCopy'), blockId: 'device-json', doneWhen: 'copied' });
84
+ steps.push(hasLink ? { text: t(locale, 'authStepOpen'), blockId: 'verify-link', doneWhen: 'opened' } : t(locale, 'authStepOpen'));
85
+ steps.push(deviceJson ? { text: t(locale, 'authStepScript'), blockId: 'helper-script', doneWhen: 'copied' } : t(locale, 'authStepVerify'));
86
+ steps.push({ text: t(locale, 'authStepContinue'), doneWhen: 'manual' });
87
+ return {
88
+ id: ICQQ_CHALLENGE_IDS.auth,
89
+ kind: 'auth',
90
+ title: t(locale, 'authTitle'),
91
+ help: { short: t(locale, 'authShort'), steps, ...(deviceJson ? { warning: t(locale, 'authWarning') } : {}) },
92
+ blocks: [
93
+ ...(deviceJson ? [{
94
+ kind: 'copy', id: 'device-json', label: t(locale, 'authJson'), content: deviceJson, format: 'json',
95
+ sensitive: true, ...(hasLink ? { thenOpen: 'verify-link' } : {}),
96
+ }] : []),
97
+ ...(hasLink ? [{ kind: 'link', id: 'verify-link', label: t(locale, 'authLink'), url: input.url, showQr: true }] : []),
98
+ ...(deviceJson ? [{
99
+ kind: 'copy', id: 'helper-script', label: t(locale, 'authScript'), content: icqqAuthHelperScript(locale),
100
+ format: 'script', collapsed: true, collapsedLabel: t(locale, 'authScriptCollapsed'), bookmarklet: true,
101
+ }] : []),
102
+ ],
103
+ actions: [{ id: 'continue', label: t(locale, 'authContinue'), variant: 'primary' }],
104
+ };
105
+ }
106
+ /** Query string of the slider URL (for the hosted captcha helper), or undefined for a non-http URL. */
107
+ export function sliderCaptchaQuery(url) {
108
+ try {
109
+ const parsed = new URL(url);
110
+ if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:')
111
+ return undefined;
112
+ const query = parsed.search.replace(/^\?/u, '');
113
+ return query || undefined;
114
+ }
115
+ catch {
116
+ return undefined;
117
+ }
118
+ }
119
+ /** Device information of `system.login.auth` as pretty JSON (string fields only), or undefined. */
120
+ export function formatDeviceJson(device) {
121
+ if (!device || typeof device !== 'object' || Array.isArray(device))
122
+ return undefined;
123
+ const fields = {};
124
+ for (const [key, value] of Object.entries(device)) {
125
+ if (typeof value === 'string')
126
+ fields[key] = value;
127
+ else if (typeof value === 'number' && Number.isFinite(value))
128
+ fields[key] = String(value);
129
+ }
130
+ if (typeof fields.guid !== 'string' || !fields.guid)
131
+ return undefined;
132
+ return JSON.stringify(fields, null, 2);
133
+ }
134
+ const SCRIPT_TEXT = {
135
+ 'zh-CN': {
136
+ wrongPage: '请在 accounts.qq.com/login/attack(发送验证码的页面)运行这段脚本',
137
+ prompt: '粘贴从 Zhin 复制的设备 JSON',
138
+ badJson: '设备 JSON 格式不正确,请重新复制',
139
+ noGuid: '设备 JSON 缺少 guid,请重新复制',
140
+ notReady: '页面还没有加载完成,请刷新后再运行',
141
+ done: '设备信息已写入。请在页面上继续完成验证,完成后回到 Zhin 点「已完成,继续登录」',
142
+ },
143
+ en: {
144
+ wrongPage: 'Run this script on accounts.qq.com/login/attack (the page that sends the verification code)',
145
+ prompt: 'Paste the device JSON copied from Zhin',
146
+ badJson: 'The device JSON is not valid. Copy it again',
147
+ noGuid: 'The device JSON has no guid. Copy it again',
148
+ notReady: 'The page has not finished loading. Reload it and run the script again',
149
+ done: 'Device information set. Finish the verification on the page, then choose “Done, continue logging in” in Zhin',
150
+ },
151
+ };
152
+ /**
153
+ * Static helper script for the `auth` challenge. It runs only on the QQ verification page, asks for
154
+ * the device JSON with `prompt()`, checks it, sets `window.__INITIAL_STATE__.deviceInfo` and reports
155
+ * the result. It never submits anything and contains no device or user data. No `//` comments: the
156
+ * same text becomes a one-line bookmarklet.
157
+ */
158
+ export function icqqAuthHelperScript(locale) {
159
+ const text = SCRIPT_TEXT[locale === 'en' ? 'en' : 'zh-CN'];
160
+ const s = (value) => JSON.stringify(value);
161
+ return [
162
+ '(function () {',
163
+ ` if (location.hostname !== ${s(ICQQ_AUTH_SCRIPT_HOST)} || location.pathname !== ${s(ICQQ_AUTH_SCRIPT_PATH)}) {`,
164
+ ` alert(${s(text.wrongPage)});`,
165
+ ' return;',
166
+ ' }',
167
+ ` var raw = prompt(${s(text.prompt)});`,
168
+ ' if (!raw) return;',
169
+ ' var info;',
170
+ ' try { info = JSON.parse(raw); } catch (error) {',
171
+ ` alert(${s(text.badJson)});`,
172
+ ' return;',
173
+ ' }',
174
+ " if (!info || typeof info !== 'object' || typeof info.guid !== 'string' || !info.guid) {",
175
+ ` alert(${s(text.noGuid)});`,
176
+ ' return;',
177
+ ' }',
178
+ ' var state = window.__INITIAL_STATE__;',
179
+ " if (!state || typeof state !== 'object') {",
180
+ ` alert(${s(text.notReady)});`,
181
+ ' return;',
182
+ ' }',
183
+ ' state.deviceInfo = info;',
184
+ ` alert(${s(text.done)});`,
185
+ '})();',
186
+ ].join('\n');
187
+ }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * ICQQ `system.login.error` → LoginAssist error codes (ADR 0058 §5).
3
+ *
4
+ * One table: exact SDK codes first (`LoginErrorCode` of the legacy wtlogin path, `NTLoginErrorCode`
5
+ * of the NT path), then message patterns for errors the SDK only reports as text. The platform's
6
+ * message is kept only as a sanitized single line (no control characters, no local file paths).
7
+ */
8
+ import type { Locale } from 'zhin.js/i18n';
9
+ import type { LoginErrorCode, LoginNextAction } from '@zhin.js/core';
10
+ export interface IcqqLoginErrorRule {
11
+ /** Exact SDK error codes. */
12
+ readonly codes?: readonly number[];
13
+ /** Matched against the SDK message when no code rule applies. */
14
+ readonly pattern?: RegExp;
15
+ readonly code: LoginErrorCode;
16
+ readonly next: LoginNextAction;
17
+ /** What the SDK means (documentation). */
18
+ readonly note: string;
19
+ /** Localized message used instead of the SDK text (when the SDK text would mislead). */
20
+ readonly messageKey?: 'loginErrorTokenIncompatible';
21
+ }
22
+ /** Ordered: the first matching rule wins; code rules are checked before message rules. */
23
+ export declare const ICQQ_LOGIN_ERROR_TABLE: readonly IcqqLoginErrorRule[];
24
+ export interface IcqqLoginErrorMapping {
25
+ readonly code: LoginErrorCode;
26
+ readonly next: LoginNextAction;
27
+ /** Sanitized platform message, or a localized label when the SDK gave none. */
28
+ readonly message: string;
29
+ /** The SDK code, for logs. */
30
+ readonly platformCode?: number;
31
+ }
32
+ /** Map one `system.login.error` payload (`{ code, message }`). */
33
+ export declare function mapIcqqLoginError(event: unknown, locale?: Locale, uin?: string): IcqqLoginErrorMapping;
34
+ /** Localized label of an error code. */
35
+ export declare function icqqLoginErrorLabel(code: LoginErrorCode, locale?: Locale): string;
36
+ /** Classify a failed `sendSmsCode()`: too frequent → `rate_limited`, anything else `unknown`. */
37
+ export declare function classifyIcqqSmsFailure(error: unknown): Extract<LoginErrorCode, 'rate_limited' | 'unknown'>;
38
+ /**
39
+ * One line, no control characters, local file paths replaced, at most 200 characters.
40
+ * (The device-blacklist message embeds the absolute path of `device.json`.)
41
+ */
42
+ export declare function sanitizeIcqqLoginMessage(value: unknown): string;
@@ -0,0 +1,77 @@
1
+ import { messages as t } from './i18n.js';
2
+ /** Ordered: the first matching rule wins; code rules are checked before message rules. */
3
+ export const ICQQ_LOGIN_ERROR_TABLE = Object.freeze([
4
+ // --- exact codes ---
5
+ { codes: [1, 140022013, 150022029, 150022032], code: 'credential_invalid', next: 'relogin',
6
+ note: 'WrongPassword / AccountOrPasswordError / MultiplePasswordIncorrect / PasswordModifiedDuringLogin' },
7
+ // The saved token does not fit the protocol; logging in again reads the same file, so only
8
+ // removing it helps.
9
+ { codes: [123456], code: 'credential_invalid', next: 'none', note: 'token incompatible', messageKey: 'loginErrorTokenIncompatible' },
10
+ { codes: [140022009], code: 'credential_invalid', next: 'relogin', note: 'RefusePasswordLogin (log in by QR code instead)' },
11
+ { codes: [163, 150022026, 140022016], code: 'code_invalid', next: 'retry_input', note: 'WrongSmsCode / SmsInvalid / IllegalTicket' },
12
+ { codes: [162, 150022022, 150022023], code: 'rate_limited', next: 'wait', note: 'TooManySms / TooOften / TooManyTimesToday' },
13
+ { codes: [40, 235, 140022005, 140022019, 150022021, 150022030, 150022033], code: 'risk_blocked', next: 'none',
14
+ note: 'AccountFrozen / device blacklisted / Frozen / NeedVerifyRealName / BlackAccount / IllegalAccount / LhrEfundFreeze' },
15
+ { codes: [140022014, 150022035, 150022039], code: 'challenge_expired', next: 'relogin', note: 'ExpireTicket / LongTimeOfNoOperation / CookieExpired' },
16
+ { codes: [140022002, 140022003, 150022031], code: 'network', next: 'wait', note: 'SystemFailed / TimeoutRetry / InterfaceUnavailable' },
17
+ // --- message patterns (the SDK reuses codes such as 237 for different texts) ---
18
+ { pattern: /频繁|频率|too (?:many|often)|frequent/iu, code: 'rate_limited', next: 'wait', note: 'too frequent' },
19
+ { pattern: /冻结|拉黑|封禁|封号|风险|风控|安全原因|frozen|blocked/iu, code: 'risk_blocked', next: 'none', note: 'risk control' },
20
+ // Before the ticket rule: "ticket 已过期" is an expired challenge, not a wrong answer.
21
+ { pattern: /过期|超时|expired|timed? ?out/iu, code: 'challenge_expired', next: 'relogin', note: 'expired' },
22
+ { pattern: /验证码(?:错误|不正确|无效)|ticket|wrong code/iu, code: 'code_invalid', next: 'retry_input', note: 'wrong code' },
23
+ { pattern: /密码|password/iu, code: 'credential_invalid', next: 'relogin', note: 'password' },
24
+ { pattern: /网络|繁忙|network|busy/iu, code: 'network', next: 'wait', note: 'network' },
25
+ ]);
26
+ const LABEL_KEYS = {
27
+ code_invalid: 'loginErrorCodeInvalid',
28
+ rate_limited: 'loginErrorRateLimited',
29
+ challenge_expired: 'loginErrorExpired',
30
+ risk_blocked: 'loginErrorRisk',
31
+ credential_invalid: 'loginErrorCredential',
32
+ network: 'loginErrorNetwork',
33
+ unknown: 'loginErrorUnknown',
34
+ };
35
+ /** Map one `system.login.error` payload (`{ code, message }`). */
36
+ export function mapIcqqLoginError(event, locale, uin) {
37
+ const raw = event && typeof event === 'object' ? event : {};
38
+ const platformCode = typeof raw.code === 'number' && Number.isFinite(raw.code) ? raw.code : undefined;
39
+ const text = typeof raw.message === 'string' ? raw.message : '';
40
+ const rule = ICQQ_LOGIN_ERROR_TABLE.find((item) => platformCode !== undefined && item.codes?.includes(platformCode))
41
+ ?? ICQQ_LOGIN_ERROR_TABLE.find((item) => item.pattern && text && item.pattern.test(text));
42
+ const code = rule?.code ?? 'unknown';
43
+ return Object.freeze({
44
+ code,
45
+ next: rule?.next ?? 'relogin',
46
+ message: rule?.messageKey ? t(locale, rule.messageKey, { uin: uin || '<uin>' })
47
+ : sanitizeIcqqLoginMessage(text) || t(locale, LABEL_KEYS[code]),
48
+ ...(platformCode !== undefined ? { platformCode } : {}),
49
+ });
50
+ }
51
+ /** Localized label of an error code. */
52
+ export function icqqLoginErrorLabel(code, locale) {
53
+ return t(locale, LABEL_KEYS[code]);
54
+ }
55
+ /** Classify a failed `sendSmsCode()`: too frequent → `rate_limited`, anything else `unknown`. */
56
+ export function classifyIcqqSmsFailure(error) {
57
+ const text = error instanceof Error ? error.message : typeof error === 'string' ? error : '';
58
+ const code = error && typeof error === 'object' && typeof error.code === 'number'
59
+ ? error.code : undefined;
60
+ if (code === 162 || /频繁|频率|上限|too (?:many|often)|frequent|limit/iu.test(text))
61
+ return 'rate_limited';
62
+ return 'unknown';
63
+ }
64
+ /**
65
+ * One line, no control characters, local file paths replaced, at most 200 characters.
66
+ * (The device-blacklist message embeds the absolute path of `device.json`.)
67
+ */
68
+ export function sanitizeIcqqLoginMessage(value) {
69
+ if (typeof value !== 'string')
70
+ return '';
71
+ // eslint-disable-next-line no-control-regex
72
+ let text = value.replace(/[\u0000-\u001f\u007f]+/gu, ' ').replace(/\s+/gu, ' ').trim();
73
+ text = text
74
+ .replace(/(["'“”])(?:[A-Za-z]:)?[\\/][^"'“”]*\1/gu, '$1…$1')
75
+ .replace(/(?:^|(?<=\s))(?:[A-Za-z]:)?(?:[\\/][\w.@-]+){2,}/gu, '…');
76
+ return text.length > 200 ? `${text.slice(0, 199)}…` : text;
77
+ }
@@ -0,0 +1,14 @@
1
+ export interface IcqqSdkLogger {
2
+ level?: unknown;
3
+ trace(...args: unknown[]): unknown;
4
+ debug(...args: unknown[]): unknown;
5
+ info(...args: unknown[]): unknown;
6
+ warn(...args: unknown[]): unknown;
7
+ error(...args: unknown[]): unknown;
8
+ fatal(...args: unknown[]): unknown;
9
+ mark(...args: unknown[]): unknown;
10
+ }
11
+ /** Links keep scheme, host and path; query and fragment become `…`. Phone numbers become `***`. */
12
+ export declare function redactIcqqLogText(text: string): string;
13
+ /** Wrap the SDK logger; `level` reads and writes through to the original. */
14
+ export declare function redactingIcqqLogger<T extends IcqqSdkLogger>(original: T): T;
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Redacting wrapper for the ICQQ SDK's own logger.
3
+ *
4
+ * The SDK logs slider / device-lock / identity verification links (they carry a session id: `sid`,
5
+ * `sig`, `uin-token`) and the account's phone number at `mark` level, which `log_level: 'info'`
6
+ * does not suppress. The wrapper keeps every SDK diagnostic but strips link queries and phone
7
+ * numbers before they reach the SDK's log4js logger.
8
+ *
9
+ * Not covered (SDK code that bypasses its logger): the terminal QR code drawing and the
10
+ * `console.log(proto.toJSON())` of the legacy 237 branch; see the README "登录" section.
11
+ */
12
+ const LEVELS = ['trace', 'debug', 'info', 'warn', 'error', 'fatal', 'mark'];
13
+ const REDACTED = Symbol('icqq.redacted-logger');
14
+ /** Links keep scheme, host and path; query and fragment become `…`. Phone numbers become `***`. */
15
+ export function redactIcqqLogText(text) {
16
+ return text
17
+ .replace(/(https?:\/\/[^\s?#"'<>]+)[?#][^\s"'<>]*/giu, '$1?…')
18
+ // Masked (138****0000) and full mainland numbers, with or without a country code.
19
+ .replace(/(?<![\w*])(?:\+?86[- ]?)?1\d{2}(?:\*{2,}|\d{4})\d{4}(?![\w*])/gu, '***')
20
+ .replace(/(?<![\w*])\d{2,3}\*{2,}\d{2,4}(?![\w*])/gu, '***');
21
+ }
22
+ function redactArg(value) {
23
+ if (typeof value === 'string')
24
+ return redactIcqqLogText(value);
25
+ if (value instanceof Error)
26
+ return redactIcqqLogText(value.stack ?? value.message);
27
+ return value;
28
+ }
29
+ /** Wrap the SDK logger; `level` reads and writes through to the original. */
30
+ export function redactingIcqqLogger(original) {
31
+ if (original[REDACTED])
32
+ return original;
33
+ const wrapper = Object.create(null);
34
+ for (const level of LEVELS) {
35
+ wrapper[level] = (...args) => original[level](...args.map(redactArg));
36
+ }
37
+ Object.defineProperty(wrapper, 'level', {
38
+ get: () => original.level,
39
+ set: (value) => { original.level = value; },
40
+ enumerable: true,
41
+ });
42
+ Object.defineProperty(wrapper, REDACTED, { value: true });
43
+ return wrapper;
44
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhin.js/adapter-icqq",
3
- "version": "1.1.27",
3
+ "version": "1.1.29",
4
4
  "description": "Zhin.js ICQQ adapter — direct connection to @icqqjs/icqq",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -34,27 +34,27 @@
34
34
  },
35
35
  "dependencies": {
36
36
  "zod": "^4.6.7",
37
- "@zhin.js/adapter": "1.1.33",
38
- "@zhin.js/adapter-onebot-events": "0.0.6",
39
- "@zhin.js/agent-feature": "1.1.17",
37
+ "@zhin.js/adapter": "1.1.34",
38
+ "@zhin.js/agent-feature": "1.1.18",
39
+ "@zhin.js/adapter-onebot-events": "0.0.8",
40
+ "@zhin.js/core": "1.7.0",
40
41
  "@zhin.js/console-contract": "1.1.6",
41
- "@zhin.js/core": "1.2.0",
42
- "@zhin.js/feature-kit": "1.1.16",
43
42
  "@zhin.js/im-contract": "1.1.14",
43
+ "@zhin.js/feature-kit": "1.1.17",
44
44
  "@zhin.js/logger": "1.1.3",
45
- "@zhin.js/page": "1.1.18",
46
- "@zhin.js/permission": "1.2.0",
47
- "@zhin.js/skill": "1.1.17",
48
- "@zhin.js/tool": "1.1.19"
45
+ "@zhin.js/page": "1.1.19",
46
+ "@zhin.js/tool": "1.1.20",
47
+ "@zhin.js/skill": "1.1.18",
48
+ "@zhin.js/permission": "1.2.1"
49
49
  },
50
50
  "peerDependencies": {
51
51
  "@icqqjs/icqq": "^1.12.2",
52
- "@zhin.js/adapter": "^1.1.33",
53
- "@zhin.js/agent": "^1.2.0",
54
- "@zhin.js/command": "^1.2.0",
55
- "@zhin.js/core": "^1.2.0",
56
- "@zhin.js/prompt-section": "^1.1.16",
57
- "zhin.js": "^1.1.26"
52
+ "@zhin.js/adapter": "^1.1.34",
53
+ "@zhin.js/agent": "^1.3.1",
54
+ "@zhin.js/command": "^1.2.2",
55
+ "@zhin.js/core": "^1.7.0",
56
+ "zhin.js": "^1.2.0",
57
+ "@zhin.js/prompt-section": "^1.1.17"
58
58
  },
59
59
  "peerDependenciesMeta": {
60
60
  "@icqqjs/icqq": {
@@ -78,9 +78,9 @@
78
78
  "@types/node": "^26.1.2",
79
79
  "typescript": "^6.0.3",
80
80
  "vitest": "^4.1.10",
81
- "@zhin.js/agent": "1.2.0",
82
- "@zhin.js/prompt-section": "1.1.16",
83
- "zhin.js": "1.1.26"
81
+ "@zhin.js/prompt-section": "1.1.17",
82
+ "zhin.js": "1.2.0",
83
+ "@zhin.js/agent": "1.3.1"
84
84
  },
85
85
  "files": [
86
86
  "adapters",