@zhin.js/adapter-icqq 1.1.15 → 1.1.17
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/CHANGELOG.md +62 -0
- package/PERMITS.md +14 -18
- package/README.md +12 -0
- package/adapters/icqq/index.js +2 -0
- package/adapters/icqq/index.ts +2 -0
- package/agents/icqq/conversation.js +72 -0
- package/agents/icqq/conversation.ts +67 -0
- package/agents/icqq/members.js +16 -0
- package/agents/icqq/members.ts +17 -0
- package/agents/icqq/messages.js +144 -0
- package/agents/icqq/messages.ts +144 -0
- package/agents/icqq/skills/icqq-conversation/SKILL.md +24 -0
- package/agents/icqq/skills/icqq-conversation/tools/conversation_info/index.js +61 -0
- package/agents/icqq/skills/icqq-conversation/tools/conversation_info/index.ts +61 -0
- package/agents/icqq/skills/icqq-directory/tools/user_info/index.js +2 -1
- package/agents/icqq/skills/icqq-directory/tools/user_info/index.ts +2 -1
- package/agents/icqq/skills/icqq-group-admin/SKILL.md +11 -1
- package/agents/icqq/skills/icqq-group-admin/tools/announce/index.js +2 -1
- package/agents/icqq/skills/icqq-group-admin/tools/announce/index.ts +2 -1
- package/agents/icqq/skills/icqq-group-admin/tools/essence/index.js +3 -2
- package/agents/icqq/skills/icqq-group-admin/tools/essence/index.ts +3 -2
- package/agents/icqq/skills/icqq-group-admin/tools/group_invite/index.js +6 -5
- package/agents/icqq/skills/icqq-group-admin/tools/group_invite/index.ts +5 -4
- package/agents/icqq/skills/icqq-group-admin/tools/group_kick/index.js +4 -3
- package/agents/icqq/skills/icqq-group-admin/tools/group_kick/index.ts +4 -3
- package/agents/icqq/skills/icqq-group-admin/tools/group_leave/index.js +34 -0
- package/agents/icqq/skills/icqq-group-admin/tools/group_leave/index.ts +33 -0
- package/agents/icqq/skills/icqq-group-admin/tools/recall_member_message/index.js +34 -0
- package/agents/icqq/skills/icqq-group-admin/tools/recall_member_message/index.ts +33 -0
- package/agents/icqq/skills/icqq-group-admin/tools/set_anonymous/index.js +5 -4
- package/agents/icqq/skills/icqq-group-admin/tools/set_anonymous/index.ts +4 -3
- package/agents/icqq/skills/icqq-group-admin/tools/set_mute/index.js +8 -7
- package/agents/icqq/skills/icqq-group-admin/tools/set_mute/index.ts +6 -5
- package/agents/icqq/skills/icqq-group-admin/tools/set_title/index.js +8 -7
- package/agents/icqq/skills/icqq-group-admin/tools/set_title/index.ts +6 -5
- package/agents/icqq/skills/icqq-group-directory/tools/group_member_info/index.js +18 -7
- package/agents/icqq/skills/icqq-group-directory/tools/group_member_info/index.ts +17 -5
- package/agents/icqq/skills/icqq-group-interaction/tools/group_sign/index.js +3 -2
- package/agents/icqq/skills/icqq-group-interaction/tools/group_sign/index.ts +3 -2
- package/agents/icqq/skills/icqq-group-interaction/tools/poke/index.js +2 -1
- package/agents/icqq/skills/icqq-group-interaction/tools/poke/index.ts +2 -1
- package/agents/icqq/skills/icqq-group-state/tools/group_files/index.js +2 -1
- package/agents/icqq/skills/icqq-group-state/tools/group_files/index.ts +2 -1
- package/agents/icqq/skills/icqq-interaction/tools/send_user_like/index.js +3 -2
- package/agents/icqq/skills/icqq-interaction/tools/send_user_like/index.ts +3 -2
- package/agents/icqq/skills/icqq-messages/SKILL.md +28 -0
- package/agents/icqq/skills/icqq-messages/tools/forward_messages/index.js +42 -0
- package/agents/icqq/skills/icqq-messages/tools/forward_messages/index.ts +40 -0
- package/agents/icqq/skills/icqq-messages/tools/quote_reply/index.js +24 -0
- package/agents/icqq/skills/icqq-messages/tools/quote_reply/index.ts +24 -0
- package/agents/icqq/skills/icqq-messages/tools/recall_own_message/index.js +18 -0
- package/agents/icqq/skills/icqq-messages/tools/recall_own_message/index.ts +17 -0
- package/agents/icqq/system.md +5 -1
- package/commands/icqq/endpoint/definition.js +9 -7
- package/commands/icqq/endpoint/definition.ts +9 -9
- package/lib/endpoint.d.ts +1 -0
- package/lib/endpoint.js +12 -8
- package/lib/group-moderation.js +7 -2
- package/lib/group-scene.d.ts +11 -0
- package/lib/group-scene.js +71 -0
- package/lib/i18n.d.ts +1 -0
- package/lib/i18n.js +47 -0
- package/lib/icqq-inbound.d.ts +2 -0
- package/lib/icqq-inbound.js +3 -0
- package/lib/icqq-inbox.d.ts +5 -0
- package/lib/icqq-inbox.js +14 -0
- package/lib/icqq-login-assist.d.ts +2 -0
- package/lib/icqq-login-assist.js +8 -7
- package/lib/protocol.d.ts +3 -0
- package/lib/protocol.js +18 -3
- package/package.json +16 -16
- package/schema.json +250 -42
- package/src/endpoint.ts +13 -7
- package/src/group-moderation.ts +7 -2
- package/src/group-scene.ts +76 -0
- package/src/i18n.ts +48 -0
- package/src/icqq-inbound.ts +5 -0
- package/src/icqq-inbox.ts +15 -0
- package/src/icqq-login-assist.ts +10 -7
- package/src/protocol.ts +19 -3
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/** Listing a very large roster only to find admins is not worth the packet; adminIds stay unknown. */
|
|
2
|
+
export const ADMIN_SCAN_MAX_MEMBERS = 1000;
|
|
3
|
+
const MAX_ADMIN_IDS = 20;
|
|
4
|
+
function positiveId(value) {
|
|
5
|
+
return typeof value === 'number' && Number.isSafeInteger(value) && value > 0 ? String(value) : undefined;
|
|
6
|
+
}
|
|
7
|
+
function numericId(value) {
|
|
8
|
+
const id = Number(value);
|
|
9
|
+
if (!/^[1-9]\d*$/.test(value) || !Number.isSafeInteger(id))
|
|
10
|
+
throw new Error('Invalid QQ identifier');
|
|
11
|
+
return id;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* ADR 0041 scene facts: one uncached group-info read, plus (small groups only) one roster read for
|
|
15
|
+
* admins. A roster failure leaves adminIds unknown instead of failing the other facts.
|
|
16
|
+
*/
|
|
17
|
+
export async function inspectGroupScene(client, groupId, signal) {
|
|
18
|
+
signal.throwIfAborted();
|
|
19
|
+
const group = numericId(groupId);
|
|
20
|
+
const info = await client.getGroupInfo(group, true);
|
|
21
|
+
signal.throwIfAborted();
|
|
22
|
+
if (info.group_id !== group)
|
|
23
|
+
return {};
|
|
24
|
+
const memberCount = Number.isSafeInteger(info.member_count) && info.member_count > 0 ? info.member_count : undefined;
|
|
25
|
+
const ownerId = positiveId(info.owner_id);
|
|
26
|
+
let adminIds;
|
|
27
|
+
if (memberCount === undefined || memberCount <= ADMIN_SCAN_MAX_MEMBERS) {
|
|
28
|
+
try {
|
|
29
|
+
const roster = await client.getGroupMemberList(group);
|
|
30
|
+
signal.throwIfAborted();
|
|
31
|
+
adminIds = [...roster.values()]
|
|
32
|
+
.filter(member => member.role === 'admin' && member.group_id === group)
|
|
33
|
+
.map(member => positiveId(member.user_id))
|
|
34
|
+
.filter((id) => id !== undefined)
|
|
35
|
+
.slice(0, MAX_ADMIN_IDS);
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
signal.throwIfAborted();
|
|
39
|
+
adminIds = undefined;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const name = typeof info.group_name === 'string' && info.group_name.trim() ? info.group_name.trim() : undefined;
|
|
43
|
+
const nowSeconds = Date.now() / 1000;
|
|
44
|
+
return {
|
|
45
|
+
...(name ? { name } : {}),
|
|
46
|
+
...(ownerId ? { ownerId } : {}),
|
|
47
|
+
...(adminIds ? { adminIds } : {}),
|
|
48
|
+
...(memberCount !== undefined ? { memberCount } : {}),
|
|
49
|
+
...(typeof info.shutup_time_whole === 'number' ? { muteAll: info.shutup_time_whole > nowSeconds } : {}),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/** ADR 0041 member facts from one uncached lookup (same rationale as the agent `freshMember` helper). */
|
|
53
|
+
export async function inspectGroupMemberProfile(client, groupId, userId, signal) {
|
|
54
|
+
signal.throwIfAborted();
|
|
55
|
+
const group = numericId(groupId);
|
|
56
|
+
const user = numericId(userId);
|
|
57
|
+
const member = await client.getGroupMemberInfo(group, user, true);
|
|
58
|
+
signal.throwIfAborted();
|
|
59
|
+
if (member.user_id !== user || member.group_id !== group)
|
|
60
|
+
return {};
|
|
61
|
+
const card = typeof member.card === 'string' && member.card.trim() ? member.card.trim() : undefined;
|
|
62
|
+
const title = typeof member.title === 'string' && member.title.trim() ? member.title.trim() : undefined;
|
|
63
|
+
const shutupSeconds = member.shutup_time;
|
|
64
|
+
return {
|
|
65
|
+
...(member.role === 'owner' || member.role === 'admin' || member.role === 'member' ? { platformRole: member.role } : {}),
|
|
66
|
+
...(card ? { card } : {}),
|
|
67
|
+
...(title ? { title } : {}),
|
|
68
|
+
...(typeof shutupSeconds === 'number' && Number.isFinite(shutupSeconds)
|
|
69
|
+
? { mutedUntil: shutupSeconds * 1000 > Date.now() ? shutupSeconds * 1000 : 0 } : {}),
|
|
70
|
+
};
|
|
71
|
+
}
|
package/lib/i18n.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const messages: (locale: import("zhin.js").Locale | undefined, key: "direct" | "addUsage" | "uinRequired" | "uinInvalid" | "endpointAdded" | "endpointAddFailed" | "loginQr" | "loginSlider" | "loginSms" | "loginAuth" | "loginOther", values?: import("zhin.js").MessageValues) => string;
|
package/lib/i18n.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { createMessages } from 'zhin.js/i18n';
|
|
2
|
+
export const messages = createMessages({
|
|
3
|
+
"direct": {
|
|
4
|
+
"zh-CN": "direct(直连 @icqqjs/icqq)",
|
|
5
|
+
"en": "direct (@icqqjs/icqq)"
|
|
6
|
+
},
|
|
7
|
+
"addUsage": {
|
|
8
|
+
"zh-CN": "用法:{command} <uin>(uin 为纯数字 QQ 号)",
|
|
9
|
+
"en": "Usage: {command} <uin> (a numeric QQ account ID)"
|
|
10
|
+
},
|
|
11
|
+
"uinRequired": {
|
|
12
|
+
"zh-CN": "请提供纯数字 QQ 号(uin)",
|
|
13
|
+
"en": "Provide a numeric QQ account ID (uin)"
|
|
14
|
+
},
|
|
15
|
+
"uinInvalid": {
|
|
16
|
+
"zh-CN": "icqq endpoint 名必须是纯数字 QQ 号(uin)",
|
|
17
|
+
"en": "The ICQQ endpoint name must be a numeric QQ account ID (uin)"
|
|
18
|
+
},
|
|
19
|
+
"endpointAdded": {
|
|
20
|
+
"zh-CN": "✅ endpoint「{id}」已追加到 {file} 的 plugins.icqq.endpoints。\n重启 zhin 后生效。",
|
|
21
|
+
"en": "✅ Endpoint “{id}” added to plugins.icqq.endpoints in {file}.\nRestart zhin to apply."
|
|
22
|
+
},
|
|
23
|
+
"endpointAddFailed": {
|
|
24
|
+
"zh-CN": "添加失败:{error}",
|
|
25
|
+
"en": "Could not add the endpoint: {error}"
|
|
26
|
+
},
|
|
27
|
+
"loginQr": {
|
|
28
|
+
"zh-CN": "扫码登录:请在手机 QQ 扫描二维码,完成后在 Console / 终端确认继续",
|
|
29
|
+
"en": "Scan the QR code in mobile QQ, then confirm in Console or your terminal."
|
|
30
|
+
},
|
|
31
|
+
"loginSlider": {
|
|
32
|
+
"zh-CN": "滑动验证:打开链接完成滑块,将返回的 ticket(可含 randstr)提交继续",
|
|
33
|
+
"en": "Open the link, complete the slider challenge, and submit the returned ticket (with randstr if provided)."
|
|
34
|
+
},
|
|
35
|
+
"loginSms": {
|
|
36
|
+
"zh-CN": "设备锁:已请求短信验证码,请提交短信验证码继续",
|
|
37
|
+
"en": "Device verification: an SMS code was requested. Submit the code to continue."
|
|
38
|
+
},
|
|
39
|
+
"loginAuth": {
|
|
40
|
+
"zh-CN": "身份验证:完成后在 Console / 终端确认继续",
|
|
41
|
+
"en": "Complete identity verification, then confirm in Console or your terminal."
|
|
42
|
+
},
|
|
43
|
+
"loginOther": {
|
|
44
|
+
"zh-CN": "登录辅助({step})",
|
|
45
|
+
"en": "Login assistance ({step})"
|
|
46
|
+
}
|
|
47
|
+
});
|
package/lib/icqq-inbound.d.ts
CHANGED
package/lib/icqq-inbound.js
CHANGED
|
@@ -688,6 +688,9 @@ export function normalizeIcqqInboundMessage(data) {
|
|
|
688
688
|
channelType,
|
|
689
689
|
channelId,
|
|
690
690
|
channelParentGroupId,
|
|
691
|
+
...(channelType === "group" && typeof ext.group_name === "string" && ext.group_name.trim()
|
|
692
|
+
? { groupName: ext.group_name.trim() }
|
|
693
|
+
: {}),
|
|
691
694
|
userId: String(userIdNum),
|
|
692
695
|
nickname,
|
|
693
696
|
senderRole,
|
package/lib/icqq-inbox.d.ts
CHANGED
|
@@ -8,6 +8,11 @@ export interface IcqqInboxBase {
|
|
|
8
8
|
export declare function isIcqqRequestPayload(payload: unknown): boolean;
|
|
9
9
|
/** post_type=notice / notice.* 判定。 */
|
|
10
10
|
export declare function isIcqqNoticePayload(payload: unknown): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* notice 去重键。成员与操作人分开记:同一管理员先后拉两个人进群时,`operator_id ?? user_id`
|
|
13
|
+
* 会撞键(icqq 群通知又常不带 time),后一次入群被当重复吞掉。
|
|
14
|
+
*/
|
|
15
|
+
export declare function icqqNoticeDedupeKey(payload: Record<string, unknown>): string;
|
|
11
16
|
/**
|
|
12
17
|
* request 事件载荷 → unified_inbox_request 行。
|
|
13
18
|
* platform_request_id 取 flag(审批回执句柄),缺省回退 seq;两者皆无则无法审批,丢弃。
|
package/lib/icqq-inbox.js
CHANGED
|
@@ -10,6 +10,20 @@ export function isIcqqNoticePayload(payload) {
|
|
|
10
10
|
return typeof postType === 'string'
|
|
11
11
|
&& (postType === 'notice' || postType.startsWith('notice.'));
|
|
12
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* notice 去重键。成员与操作人分开记:同一管理员先后拉两个人进群时,`operator_id ?? user_id`
|
|
15
|
+
* 会撞键(icqq 群通知又常不带 time),后一次入群被当重复吞掉。
|
|
16
|
+
*/
|
|
17
|
+
export function icqqNoticeDedupeKey(payload) {
|
|
18
|
+
return `notice:${[
|
|
19
|
+
payload.time,
|
|
20
|
+
payload.group_id,
|
|
21
|
+
payload.user_id,
|
|
22
|
+
payload.operator_id,
|
|
23
|
+
payload.notice_type ?? payload.type,
|
|
24
|
+
payload.sub_type,
|
|
25
|
+
].join('_')}`;
|
|
26
|
+
}
|
|
13
27
|
/**
|
|
14
28
|
* request 事件载荷 → unified_inbox_request 行。
|
|
15
29
|
* platform_request_id 取 flag(审批回执句柄),缺省回退 seq;两者皆无则无法审批,丢弃。
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Locale } from 'zhin.js/i18n';
|
|
1
2
|
import type { LoginAssist, LoginAssistType } from '@zhin.js/core';
|
|
2
3
|
type IcqqLoginClient = {
|
|
3
4
|
login(password?: string): Promise<unknown>;
|
|
@@ -23,5 +24,6 @@ export declare function runIcqqLoginAssistStep(input: {
|
|
|
23
24
|
logger: Logger;
|
|
24
25
|
step: LoginAssistType;
|
|
25
26
|
event: unknown;
|
|
27
|
+
locale?: Locale;
|
|
26
28
|
}): Promise<void>;
|
|
27
29
|
export {};
|
package/lib/icqq-login-assist.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { messages as t } from './i18n.js';
|
|
1
2
|
import { formatCompact } from '@zhin.js/logger';
|
|
2
3
|
/**
|
|
3
4
|
* Drive ICQQ login challenges through LoginAssist (refresh-safe pending tasks).
|
|
@@ -7,7 +8,7 @@ import { formatCompact } from '@zhin.js/logger';
|
|
|
7
8
|
export async function runIcqqLoginAssistStep(input) {
|
|
8
9
|
const { assist, client, adapter, endpointKey, owner, logger, step, event } = input;
|
|
9
10
|
assist.cancelOwned(owner, `replaced_by_${step}`);
|
|
10
|
-
const payload = buildPayload(step, event);
|
|
11
|
+
const payload = buildPayload(step, event, input.locale);
|
|
11
12
|
logger.info(formatCompact({
|
|
12
13
|
op: 'login_assist_pending',
|
|
13
14
|
endpoint: endpointKey,
|
|
@@ -56,33 +57,33 @@ export async function runIcqqLoginAssistStep(input) {
|
|
|
56
57
|
}));
|
|
57
58
|
}
|
|
58
59
|
}
|
|
59
|
-
function buildPayload(step, event) {
|
|
60
|
+
function buildPayload(step, event, locale) {
|
|
60
61
|
const raw = event && typeof event === 'object' ? event : {};
|
|
61
62
|
switch (step) {
|
|
62
63
|
case 'qrcode':
|
|
63
64
|
return {
|
|
64
|
-
message:
|
|
65
|
+
message: t(locale, 'loginQr'),
|
|
65
66
|
image: bufferToDataUrl(raw.image),
|
|
66
67
|
};
|
|
67
68
|
case 'slider':
|
|
68
69
|
return {
|
|
69
|
-
message:
|
|
70
|
+
message: t(locale, 'loginSlider'),
|
|
70
71
|
url: typeof raw.url === 'string' ? raw.url : undefined,
|
|
71
72
|
};
|
|
72
73
|
case 'device':
|
|
73
74
|
return {
|
|
74
|
-
message: '
|
|
75
|
+
message: t(locale, 'loginSms'),
|
|
75
76
|
url: typeof raw.url === 'string' ? raw.url : undefined,
|
|
76
77
|
phone: raw.phone,
|
|
77
78
|
};
|
|
78
79
|
case 'auth':
|
|
79
80
|
return {
|
|
80
|
-
message:
|
|
81
|
+
message: t(locale, 'loginAuth'),
|
|
81
82
|
url: typeof raw.url === 'string' ? raw.url : undefined,
|
|
82
83
|
device: raw.device,
|
|
83
84
|
};
|
|
84
85
|
default:
|
|
85
|
-
return { message:
|
|
86
|
+
return { message: t(locale, 'loginOther', { step }) };
|
|
86
87
|
}
|
|
87
88
|
}
|
|
88
89
|
function normalizeSubmitValue(value) {
|
package/lib/protocol.d.ts
CHANGED
|
@@ -198,6 +198,7 @@ export interface ResolvedIcqqConfig {
|
|
|
198
198
|
export interface IcqqWireSegment {
|
|
199
199
|
readonly type: string;
|
|
200
200
|
readonly data?: Record<string, unknown>;
|
|
201
|
+
readonly platform?: Readonly<Record<string, unknown>>;
|
|
201
202
|
}
|
|
202
203
|
export interface IcqqInboundMessage {
|
|
203
204
|
readonly id: string;
|
|
@@ -245,6 +246,8 @@ export declare function icqqInboundConversation(endpointKey: string, input: {
|
|
|
245
246
|
readonly channelId: string;
|
|
246
247
|
readonly channelParentGroupId?: string;
|
|
247
248
|
readonly guildId?: string;
|
|
249
|
+
/** 群名(仅 group 会话使用) */
|
|
250
|
+
readonly name?: string;
|
|
248
251
|
}): ConversationRef;
|
|
249
252
|
/**
|
|
250
253
|
* 出站:从 ConversationRef 派生 action 路由。
|
package/lib/protocol.js
CHANGED
|
@@ -232,7 +232,8 @@ export function icqqInboundConversation(endpointKey, input) {
|
|
|
232
232
|
parent: { kind: 'channel', id: input.guildId },
|
|
233
233
|
};
|
|
234
234
|
}
|
|
235
|
-
|
|
235
|
+
const name = input.channelType === 'group' ? input.name?.trim() : undefined;
|
|
236
|
+
return { endpoint, kind: input.channelType, id: input.channelId, ...(name ? { name } : {}) };
|
|
236
237
|
}
|
|
237
238
|
/**
|
|
238
239
|
* 出站:从 ConversationRef 派生 action 路由。
|
|
@@ -265,6 +266,7 @@ const ICQQ_STANDALONE_ELEMENTS = new Set([
|
|
|
265
266
|
'json',
|
|
266
267
|
'share',
|
|
267
268
|
'long_msg',
|
|
269
|
+
'multimsg',
|
|
268
270
|
]);
|
|
269
271
|
/** Normalize inline image bytes before either temporary-file or native-base64 delivery. */
|
|
270
272
|
export function normalizeIcqqImageMedia(content) {
|
|
@@ -336,7 +338,7 @@ export function formatOutboundMessages(payload) {
|
|
|
336
338
|
}
|
|
337
339
|
const messages = groups.filter(group => group.some(element => typeof element === 'string'
|
|
338
340
|
? element.trim() !== ''
|
|
339
|
-
: element.type !== 'reply'));
|
|
341
|
+
: element.type !== 'reply' && element.type !== 'quote'));
|
|
340
342
|
if (messages.length === 0)
|
|
341
343
|
return ['\u200b'];
|
|
342
344
|
return messages.map(group => group.length === 1 ? group[0] : group);
|
|
@@ -361,7 +363,8 @@ function formatOutboundElements(payload) {
|
|
|
361
363
|
if (!Number.isSafeInteger(qq) || qq <= 0) {
|
|
362
364
|
throw new TypeError(`Invalid ICQQ mention target: ${String(target ?? '')}`);
|
|
363
365
|
}
|
|
364
|
-
|
|
366
|
+
const name = typeof item.data?.name === 'string' ? item.data.name.trim() : '';
|
|
367
|
+
return name ? { type: 'at', qq, text: name.startsWith('@') ? name : `@${name}` } : { type: 'at', qq };
|
|
365
368
|
}
|
|
366
369
|
case 'image': {
|
|
367
370
|
const arg = resolveIcqqMediaFile(normalizeIcqqImageData(item.data));
|
|
@@ -380,6 +383,14 @@ function formatOutboundElements(payload) {
|
|
|
380
383
|
const id = String(item.data?.message_id ?? item.data?.id ?? '').trim();
|
|
381
384
|
if (!id)
|
|
382
385
|
throw new TypeError('ICQQ reply segment requires message_id');
|
|
386
|
+
const quote = item.platform?.icqqQuote;
|
|
387
|
+
if (quote) {
|
|
388
|
+
const { user_id, seq, rand, time, message } = quote;
|
|
389
|
+
if (typeof user_id !== 'number' || typeof seq !== 'number' || typeof rand !== 'number'
|
|
390
|
+
|| typeof time !== 'number' || typeof message !== 'string')
|
|
391
|
+
throw new TypeError('Invalid ICQQ quote source');
|
|
392
|
+
return { type: 'quote', user_id, seq, rand, time, message };
|
|
393
|
+
}
|
|
383
394
|
return { type: 'reply', id };
|
|
384
395
|
}
|
|
385
396
|
case 'record':
|
|
@@ -410,6 +421,10 @@ function formatOutboundElements(payload) {
|
|
|
410
421
|
const resid = String(item.data?.forward_id ?? item.data?.resid ?? item.data?.id ?? '').trim();
|
|
411
422
|
if (!resid)
|
|
412
423
|
throw new TypeError('ICQQ forward segment requires forward_id');
|
|
424
|
+
// Prepared merged forwards need their filename; a long_msg would expand inline.
|
|
425
|
+
const filename = item.platform?.icqqForwardFilename;
|
|
426
|
+
if (typeof filename === 'string' && filename)
|
|
427
|
+
return { type: 'multimsg', resid, filename };
|
|
413
428
|
return { type: 'long_msg', resid };
|
|
414
429
|
}
|
|
415
430
|
case 'share':
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/adapter-icqq",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.17",
|
|
4
4
|
"description": "Zhin.js ICQQ adapter — direct connection to @icqqjs/icqq",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -33,24 +33,24 @@
|
|
|
33
33
|
"directory": "plugins/adapters/icqq"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@zhin.js/adapter": "1.1.
|
|
37
|
-
"@zhin.js/agent-feature": "1.1.
|
|
38
|
-
"@zhin.js/core": "1.1.
|
|
39
|
-
"@zhin.js/feature-kit": "1.1.
|
|
40
|
-
"@zhin.js/im-contract": "1.1.
|
|
36
|
+
"@zhin.js/adapter": "1.1.24",
|
|
37
|
+
"@zhin.js/agent-feature": "1.1.10",
|
|
38
|
+
"@zhin.js/core": "1.1.52",
|
|
39
|
+
"@zhin.js/feature-kit": "1.1.9",
|
|
40
|
+
"@zhin.js/im-contract": "1.1.8",
|
|
41
41
|
"@zhin.js/logger": "1.1.2",
|
|
42
|
-
"@zhin.js/permission": "1.1.
|
|
43
|
-
"@zhin.js/skill": "1.1.
|
|
44
|
-
"@zhin.js/tool": "1.1.
|
|
42
|
+
"@zhin.js/permission": "1.1.9",
|
|
43
|
+
"@zhin.js/skill": "1.1.10",
|
|
44
|
+
"@zhin.js/tool": "1.1.11"
|
|
45
45
|
},
|
|
46
46
|
"peerDependencies": {
|
|
47
47
|
"@icqqjs/icqq": "^1.12.2",
|
|
48
48
|
"zod": "^4.0.0",
|
|
49
|
-
"@zhin.js/adapter": "^1.1.
|
|
50
|
-
"@zhin.js/command": "^1.1.
|
|
51
|
-
"@zhin.js/core": "^1.1.
|
|
52
|
-
"@zhin.js/prompt-section": "^1.1.
|
|
53
|
-
"zhin.js": "^1.1.
|
|
49
|
+
"@zhin.js/adapter": "^1.1.24",
|
|
50
|
+
"@zhin.js/command": "^1.1.11",
|
|
51
|
+
"@zhin.js/core": "^1.1.52",
|
|
52
|
+
"@zhin.js/prompt-section": "^1.1.9",
|
|
53
|
+
"zhin.js": "^1.1.17"
|
|
54
54
|
},
|
|
55
55
|
"peerDependenciesMeta": {
|
|
56
56
|
"@icqqjs/icqq": {
|
|
@@ -75,8 +75,8 @@
|
|
|
75
75
|
"typescript": "^6.0.3",
|
|
76
76
|
"vitest": "^4.1.10",
|
|
77
77
|
"zod": "^4.4.3",
|
|
78
|
-
"@zhin.js/prompt-section": "1.1.
|
|
79
|
-
"zhin.js": "1.1.
|
|
78
|
+
"@zhin.js/prompt-section": "1.1.9",
|
|
79
|
+
"zhin.js": "1.1.17"
|
|
80
80
|
},
|
|
81
81
|
"files": [
|
|
82
82
|
"adapters",
|