@zhin.js/adapter-icqq 6.0.2 → 6.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +40 -0
- package/README.md +32 -437
- package/adapters/icqq.ts +30 -0
- package/agent/tools/announce.ts +2 -2
- package/agent/tools/essence.ts +2 -2
- package/agent/tools/friend_list.ts +2 -2
- package/agent/tools/group_files.ts +2 -2
- package/agent/tools/group_invite.ts +2 -2
- package/agent/tools/group_list.ts +2 -2
- package/agent/tools/group_sign.ts +2 -2
- package/agent/tools/list_muted.ts +2 -2
- package/agent/tools/poke.ts +2 -2
- package/agent/tools/send_user_like.ts +2 -2
- package/agent/tools/set_anonymous.ts +2 -2
- package/agent/tools/set_title.ts +2 -2
- package/lib/agent-prompt.d.ts +2 -0
- package/lib/{src/agent-prompt.js → agent-prompt.js} +0 -1
- package/lib/cq-message.d.ts +9 -0
- package/lib/{src/cq-message.js → cq-message.js} +0 -1
- package/lib/endpoint.d.ts +51 -0
- package/lib/endpoint.js +483 -0
- package/lib/forward-msg.d.ts +26 -0
- package/lib/{src/forward-msg.js → forward-msg.js} +0 -1
- package/lib/icqq-agent-deps.d.ts +25 -0
- package/lib/icqq-agent-deps.js +32 -0
- package/lib/icqq-guild.d.ts +47 -0
- package/lib/{src/icqq-guild.js → icqq-guild.js} +4 -2
- package/lib/icqq-inbound.d.ts +139 -0
- package/lib/{src/icqq-inbound.js → icqq-inbound.js} +27 -3
- package/lib/index.d.ts +6 -0
- package/lib/index.js +6 -0
- package/lib/ipc-client.d.ts +73 -0
- package/lib/{src/ipc-client.js → ipc-client.js} +0 -1
- package/lib/outbound-media.d.ts +13 -0
- package/lib/{src/outbound-media.js → outbound-media.js} +0 -1
- package/lib/protocol.d.ts +269 -0
- package/lib/{src/protocol.js → protocol.js} +124 -2
- package/lib/types.d.ts +72 -0
- package/lib/{src/types.js → types.js} +0 -1
- package/package.json +49 -45
- package/plugin.ts +32 -0
- package/schema.json +35 -0
- package/src/endpoint.ts +407 -796
- package/src/icqq-agent-deps.ts +48 -9
- package/src/icqq-guild.ts +1 -2
- package/src/icqq-inbound.ts +31 -2
- package/src/index.ts +35 -69
- package/src/protocol.ts +191 -1
- package/client/ICQQManagement.tsx +0 -147
- package/client/LoginAssistPanel.tsx +0 -300
- package/client/index.tsx +0 -11
- package/client/tsconfig.json +0 -7
- package/client/utils/api.ts +0 -30
- package/dist/index.js +0 -34
- package/lib/agent/tools/announce.js +0 -21
- package/lib/agent/tools/announce.js.map +0 -1
- package/lib/agent/tools/essence.js +0 -22
- package/lib/agent/tools/essence.js.map +0 -1
- package/lib/agent/tools/friend_list.js +0 -19
- package/lib/agent/tools/friend_list.js.map +0 -1
- package/lib/agent/tools/group_files.js +0 -29
- package/lib/agent/tools/group_files.js.map +0 -1
- package/lib/agent/tools/group_invite.js +0 -20
- package/lib/agent/tools/group_invite.js.map +0 -1
- package/lib/agent/tools/group_list.js +0 -20
- package/lib/agent/tools/group_list.js.map +0 -1
- package/lib/agent/tools/group_sign.js +0 -19
- package/lib/agent/tools/group_sign.js.map +0 -1
- package/lib/agent/tools/list_muted.js +0 -23
- package/lib/agent/tools/list_muted.js.map +0 -1
- package/lib/agent/tools/poke.js +0 -20
- package/lib/agent/tools/poke.js.map +0 -1
- package/lib/agent/tools/send_user_like.js +0 -22
- package/lib/agent/tools/send_user_like.js.map +0 -1
- package/lib/agent/tools/set_anonymous.js +0 -22
- package/lib/agent/tools/set_anonymous.js.map +0 -1
- package/lib/agent/tools/set_title.js +0 -25
- package/lib/agent/tools/set_title.js.map +0 -1
- package/lib/src/adapter.js +0 -128
- package/lib/src/adapter.js.map +0 -1
- package/lib/src/agent-prompt.js.map +0 -1
- package/lib/src/cq-message.js.map +0 -1
- package/lib/src/endpoint.js +0 -755
- package/lib/src/endpoint.js.map +0 -1
- package/lib/src/forward-msg.js.map +0 -1
- package/lib/src/get-msg.js +0 -46
- package/lib/src/get-msg.js.map +0 -1
- package/lib/src/icqq-agent-deps.js +0 -10
- package/lib/src/icqq-agent-deps.js.map +0 -1
- package/lib/src/icqq-guild.js.map +0 -1
- package/lib/src/icqq-inbound.js.map +0 -1
- package/lib/src/icqq-login-assist-bridge.js +0 -148
- package/lib/src/icqq-login-assist-bridge.js.map +0 -1
- package/lib/src/icqq-side-events.js +0 -130
- package/lib/src/icqq-side-events.js.map +0 -1
- package/lib/src/index.js +0 -50
- package/lib/src/index.js.map +0 -1
- package/lib/src/ipc-client.js.map +0 -1
- package/lib/src/login-assist-routes.js +0 -29
- package/lib/src/login-assist-routes.js.map +0 -1
- package/lib/src/login-ipc-contract.js +0 -35
- package/lib/src/login-ipc-contract.js.map +0 -1
- package/lib/src/outbound-media.js.map +0 -1
- package/lib/src/protocol.js.map +0 -1
- package/lib/src/routes.js +0 -67
- package/lib/src/routes.js.map +0 -1
- package/lib/src/segment-mapper.js +0 -2
- package/lib/src/segment-mapper.js.map +0 -1
- package/lib/src/tools/index.js +0 -23
- package/lib/src/tools/index.js.map +0 -1
- package/lib/src/types.js.map +0 -1
- package/plugin.yml +0 -3
- package/src/adapter.ts +0 -151
- package/src/get-msg.ts +0 -56
- package/src/icqq-login-assist-bridge.ts +0 -196
- package/src/icqq-side-events.ts +0 -143
- package/src/login-assist-routes.ts +0 -39
- package/src/login-ipc-contract.ts +0 -52
- package/src/routes.ts +0 -83
- package/src/segment-mapper.ts +0 -1
- package/src/tools/index.ts +0 -31
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
* 2. 认证通过后发送 IpcRequest → 等待 IpcResponse
|
|
10
10
|
* 3. 认证通过后自动接收 icqq 事件推送(IpcEvent),断开连接自动停止
|
|
11
11
|
*
|
|
12
|
-
* 登录相关:**推送**走 IpcEvent(`system.login
|
|
12
|
+
* 登录相关:**推送**走 IpcEvent(`system.login.*`)。
|
|
13
13
|
*/
|
|
14
|
+
import { pickCredential } from '@zhin.js/adapter';
|
|
14
15
|
/** 从 IPC 入站 payload 解析可用于引用/撤回的消息 ID */
|
|
15
16
|
export { resolveIcqqInboundMessageId } from "./icqq-inbound.js";
|
|
16
17
|
/**
|
|
@@ -184,4 +185,125 @@ export const Actions = {
|
|
|
184
185
|
SET_NOTIFY: "set_notify",
|
|
185
186
|
GET_NOTIFY: "get_notify",
|
|
186
187
|
};
|
|
187
|
-
|
|
188
|
+
export function resolveIcqqConfig(config = {}) {
|
|
189
|
+
const entry = config.endpoints?.find((item) => item.context === 'icqq');
|
|
190
|
+
const name = pickCredential(config.name, entry?.name, process.env.ICQQ_ACCOUNT);
|
|
191
|
+
if (!/^\d+$/.test(name)) {
|
|
192
|
+
throw new TypeError('ICQQ adapter requires numeric name (QQ uin) via plugins.<key>.name or ICQQ_ACCOUNT');
|
|
193
|
+
}
|
|
194
|
+
const autoReconnect = config.autoReconnect ?? entry?.autoReconnect ?? true;
|
|
195
|
+
const outboundMedia = config.outboundMedia ?? entry?.outboundMedia;
|
|
196
|
+
const rpcRaw = config.rpc ?? entry?.rpc;
|
|
197
|
+
const rpc = rpcRaw?.host && rpcRaw.port != null && rpcRaw.token
|
|
198
|
+
? { host: rpcRaw.host, port: Number(rpcRaw.port), token: rpcRaw.token }
|
|
199
|
+
: undefined;
|
|
200
|
+
return {
|
|
201
|
+
context: 'icqq',
|
|
202
|
+
name,
|
|
203
|
+
autoReconnect,
|
|
204
|
+
...(outboundMedia ? { outboundMedia } : {}),
|
|
205
|
+
...(rpc ? { rpc } : {}),
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
/** Gateway reply target: `private:uid` / `group:gid` / `temp:gid:uid` / `channel:guild:channel`. */
|
|
209
|
+
export function formatInboundTarget(input) {
|
|
210
|
+
if (input.channelType === 'private' && input.channelParentGroupId) {
|
|
211
|
+
return `temp:${input.channelParentGroupId}:${input.channelId}`;
|
|
212
|
+
}
|
|
213
|
+
if (input.channelType === 'channel' && input.guildId) {
|
|
214
|
+
return `channel:${input.guildId}:${input.channelId}`;
|
|
215
|
+
}
|
|
216
|
+
return `${input.channelType}:${input.channelId}`;
|
|
217
|
+
}
|
|
218
|
+
export function parseSendTarget(target) {
|
|
219
|
+
const trimmed = target.trim();
|
|
220
|
+
if (trimmed.startsWith('temp:')) {
|
|
221
|
+
const rest = trimmed.slice(5);
|
|
222
|
+
const [groupId, userId] = rest.split(':');
|
|
223
|
+
if (!groupId || !userId)
|
|
224
|
+
throw new TypeError(`Invalid icqq temp target: ${target}`);
|
|
225
|
+
return { kind: 'temp', groupId: Number(groupId), userId: Number(userId) };
|
|
226
|
+
}
|
|
227
|
+
if (trimmed.startsWith('channel:')) {
|
|
228
|
+
const rest = trimmed.slice(8);
|
|
229
|
+
const idx = rest.indexOf(':');
|
|
230
|
+
if (idx <= 0)
|
|
231
|
+
throw new TypeError(`Invalid icqq channel target: ${target}`);
|
|
232
|
+
return {
|
|
233
|
+
kind: 'channel',
|
|
234
|
+
guildId: rest.slice(0, idx),
|
|
235
|
+
channelId: rest.slice(idx + 1),
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
if (trimmed.startsWith('private:')) {
|
|
239
|
+
return { kind: 'private', userId: Number(trimmed.slice(8)) };
|
|
240
|
+
}
|
|
241
|
+
if (trimmed.startsWith('group:')) {
|
|
242
|
+
return { kind: 'group', groupId: Number(trimmed.slice(6)) };
|
|
243
|
+
}
|
|
244
|
+
// Bare numeric id → private (common reply path)
|
|
245
|
+
if (/^\d+$/.test(trimmed)) {
|
|
246
|
+
return { kind: 'private', userId: Number(trimmed) };
|
|
247
|
+
}
|
|
248
|
+
throw new TypeError(`Invalid icqq send target: ${target}`);
|
|
249
|
+
}
|
|
250
|
+
export function formatOutboundBody(payload) {
|
|
251
|
+
if (typeof payload === 'string') {
|
|
252
|
+
const text = payload.trim();
|
|
253
|
+
return text || '\u200b';
|
|
254
|
+
}
|
|
255
|
+
if (payload == null)
|
|
256
|
+
return '\u200b';
|
|
257
|
+
if (!Array.isArray(payload)) {
|
|
258
|
+
// 单个段对象(非数组)按单元素数组处理,杜绝 String(object) → '[object Object]'
|
|
259
|
+
if (isWireSegment(payload)) {
|
|
260
|
+
return formatOutboundBody([payload]);
|
|
261
|
+
}
|
|
262
|
+
if (typeof payload === 'object' && payload !== null && 'text' in payload) {
|
|
263
|
+
const text = String(payload.text ?? '').trim();
|
|
264
|
+
return text || '\u200b';
|
|
265
|
+
}
|
|
266
|
+
const text = String(payload).trim();
|
|
267
|
+
return text || '\u200b';
|
|
268
|
+
}
|
|
269
|
+
const joined = payload.map((seg) => {
|
|
270
|
+
if (typeof seg === 'string')
|
|
271
|
+
return seg;
|
|
272
|
+
const item = seg;
|
|
273
|
+
switch (item.type) {
|
|
274
|
+
case 'text':
|
|
275
|
+
return String(item.data?.text ?? '');
|
|
276
|
+
case 'at':
|
|
277
|
+
case 'mention':
|
|
278
|
+
return `[at:${item.data?.qq ?? item.data?.id ?? item.data?.target ?? ''}]`;
|
|
279
|
+
case 'image':
|
|
280
|
+
return `[image:${item.data?.file || item.data?.url || base64Media(item.data) || ''}]`;
|
|
281
|
+
case 'face':
|
|
282
|
+
return `[face:${item.data?.id ?? ''}]`;
|
|
283
|
+
case 'reply':
|
|
284
|
+
return `[reply:${item.data?.message_id ?? item.data?.id ?? ''}]`;
|
|
285
|
+
case 'record':
|
|
286
|
+
case 'audio':
|
|
287
|
+
return `[record:${item.data?.file || item.data?.url || base64Media(item.data) || ''}]`;
|
|
288
|
+
case 'video':
|
|
289
|
+
return `[video:${item.data?.file || item.data?.url || base64Media(item.data) || ''}]`;
|
|
290
|
+
default:
|
|
291
|
+
return String(item.data?.text ?? '');
|
|
292
|
+
}
|
|
293
|
+
}).join('').trim();
|
|
294
|
+
return joined || '\u200b';
|
|
295
|
+
}
|
|
296
|
+
export function formatInboundContent(rawMessage) {
|
|
297
|
+
return rawMessage;
|
|
298
|
+
}
|
|
299
|
+
/** base64 媒体回退:CQ `base64://` 由守护进程解码(异机 RPC 场景)。 */
|
|
300
|
+
function base64Media(data) {
|
|
301
|
+
const b64 = data?.base64;
|
|
302
|
+
return typeof b64 === 'string' && b64 ? `base64://${b64}` : undefined;
|
|
303
|
+
}
|
|
304
|
+
/** 段对象判定:`{ type: string, data? }`(非数组 payload 的防御入口)。 */
|
|
305
|
+
function isWireSegment(value) {
|
|
306
|
+
return typeof value === 'object'
|
|
307
|
+
&& value !== null
|
|
308
|
+
&& typeof value.type === 'string';
|
|
309
|
+
}
|
package/lib/types.d.ts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ICQQ 适配器类型与配置
|
|
3
|
+
*
|
|
4
|
+
* 不再直接依赖 @icqqjs/icqq,通过 @icqqjs/cli 守护进程 IPC 通信。
|
|
5
|
+
*/
|
|
6
|
+
export type GroupRole = "owner" | "admin" | "member";
|
|
7
|
+
export interface IcqqSenderInfo {
|
|
8
|
+
id: string;
|
|
9
|
+
name: string;
|
|
10
|
+
role?: GroupRole;
|
|
11
|
+
isOwner?: boolean;
|
|
12
|
+
isAdmin?: boolean;
|
|
13
|
+
permissions?: string[];
|
|
14
|
+
card?: string;
|
|
15
|
+
title?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Endpoint 配置:支持本地 IPC 和远程 RPC 两种连接模式。
|
|
19
|
+
*
|
|
20
|
+
* - 本地模式(默认):只需 name(QQ号),自动连接 ~/.icqq/<uin>/daemon.sock
|
|
21
|
+
* - 远程模式:额外配置 rpc.host / rpc.port / rpc.token
|
|
22
|
+
*/
|
|
23
|
+
export interface IcqqEndpointConfig {
|
|
24
|
+
context: "icqq";
|
|
25
|
+
/** QQ 号码字符串 */
|
|
26
|
+
name: `${number}`;
|
|
27
|
+
/** RPC 远程连接配置(不配置则使用本地 IPC) */
|
|
28
|
+
rpc?: {
|
|
29
|
+
/** 远程主机地址 */
|
|
30
|
+
host: string;
|
|
31
|
+
/** 远程端口 */
|
|
32
|
+
port: number;
|
|
33
|
+
/** 认证 token(用于 HMAC-SHA256 挑战-响应,不会明文传输) */
|
|
34
|
+
token: string;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* IPC/RPC 与守护进程连接意外断开时是否自动重连(指数退避,上限约 30s)。
|
|
38
|
+
* 默认 true;设为 false 则断开后仅将 `$connected` 置为 false,需手动重连。
|
|
39
|
+
*/
|
|
40
|
+
autoReconnect?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* 出站图片/语音/视频:file=本机临时文件路径(需与 icqq 守护进程同机可读);
|
|
43
|
+
* base64=经 CQ `base64://` 交给守护进程解码(Zhin 与 icqq 异进程/异机时用,配置 rpc 时默认 base64)。
|
|
44
|
+
*/
|
|
45
|
+
outboundMedia?: "file" | "base64";
|
|
46
|
+
}
|
|
47
|
+
/** IPC 返回的好友信息 */
|
|
48
|
+
export interface IpcFriendInfo {
|
|
49
|
+
user_id: number;
|
|
50
|
+
nickname: string;
|
|
51
|
+
remark?: string;
|
|
52
|
+
class_id?: number;
|
|
53
|
+
}
|
|
54
|
+
/** IPC 返回的群信息 */
|
|
55
|
+
export interface IpcGroupInfo {
|
|
56
|
+
group_id: number;
|
|
57
|
+
group_name: string;
|
|
58
|
+
member_count: number;
|
|
59
|
+
max_member_count: number;
|
|
60
|
+
owner_id?: number;
|
|
61
|
+
}
|
|
62
|
+
/** IPC 返回的群成员信息 */
|
|
63
|
+
export interface IpcMemberInfo {
|
|
64
|
+
user_id: number;
|
|
65
|
+
nickname: string;
|
|
66
|
+
card: string;
|
|
67
|
+
role: GroupRole;
|
|
68
|
+
title: string;
|
|
69
|
+
join_time?: number;
|
|
70
|
+
last_sent_time?: number;
|
|
71
|
+
shutup_time?: number;
|
|
72
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/adapter-icqq",
|
|
3
|
-
"version": "6.0.
|
|
4
|
-
"description": "Zhin.js adapter for
|
|
3
|
+
"version": "6.0.3",
|
|
4
|
+
"description": "Zhin.js ICQQ adapter for Plugin Runtime (IPC daemon client)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
7
7
|
"types": "./lib/index.d.ts",
|
|
@@ -33,60 +33,49 @@
|
|
|
33
33
|
"type": "git",
|
|
34
34
|
"directory": "plugins/adapters/icqq"
|
|
35
35
|
},
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"plugin.yml",
|
|
42
|
-
"README.md",
|
|
43
|
-
"CHANGELOG.md",
|
|
44
|
-
"agent"
|
|
45
|
-
],
|
|
46
|
-
"devDependencies": {
|
|
47
|
-
"@radix-ui/themes": "^3.2.1",
|
|
48
|
-
"@types/react": "^19.2.17",
|
|
49
|
-
"@types/react-dom": "^19.2.3",
|
|
50
|
-
"lucide-react": "^1.22.0",
|
|
51
|
-
"radix-ui": "^1.6.2",
|
|
52
|
-
"typescript": "^6.0.3",
|
|
53
|
-
"zod": "^4.4.3",
|
|
54
|
-
"@zhin.js/agent": "1.0.3",
|
|
55
|
-
"@zhin.js/cli": "1.0.93",
|
|
56
|
-
"@zhin.js/client": "2.0.5",
|
|
57
|
-
"@zhin.js/contract": "1.0.3",
|
|
58
|
-
"@zhin.js/core": "1.3.4",
|
|
59
|
-
"@zhin.js/host-api": "2.0.5",
|
|
60
|
-
"@zhin.js/host-router": "2.0.3",
|
|
61
|
-
"zhin.js": "4.1.2"
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"@zhin.js/adapter": "1.0.1",
|
|
38
|
+
"@zhin.js/core": "1.3.5",
|
|
39
|
+
"@zhin.js/logger": "1.0.75",
|
|
40
|
+
"@zhin.js/plugin-runtime": "1.0.1"
|
|
62
41
|
},
|
|
63
42
|
"peerDependencies": {
|
|
64
43
|
"zod": "^4.0.0",
|
|
65
|
-
"@zhin.js/
|
|
66
|
-
"@zhin.js/
|
|
67
|
-
"@zhin.js/
|
|
68
|
-
"@zhin.js/
|
|
69
|
-
"
|
|
70
|
-
"@zhin.js/host-router": "2.0.3",
|
|
71
|
-
"zhin.js": "4.1.2"
|
|
44
|
+
"@zhin.js/adapter": "1.0.1",
|
|
45
|
+
"@zhin.js/agent": "1.0.4",
|
|
46
|
+
"@zhin.js/core": "1.3.5",
|
|
47
|
+
"@zhin.js/plugin-runtime": "1.0.1",
|
|
48
|
+
"zhin.js": "4.1.3"
|
|
72
49
|
},
|
|
73
50
|
"peerDependenciesMeta": {
|
|
74
|
-
"
|
|
75
|
-
"optional": true
|
|
76
|
-
},
|
|
77
|
-
"@zhin.js/client": {
|
|
78
|
-
"optional": true
|
|
79
|
-
},
|
|
80
|
-
"@zhin.js/host-router": {
|
|
51
|
+
"zhin.js": {
|
|
81
52
|
"optional": true
|
|
82
53
|
},
|
|
83
|
-
"@zhin.js/
|
|
54
|
+
"@zhin.js/agent": {
|
|
84
55
|
"optional": true
|
|
85
56
|
},
|
|
86
57
|
"zod": {
|
|
87
58
|
"optional": true
|
|
88
59
|
}
|
|
89
60
|
},
|
|
61
|
+
"devDependencies": {
|
|
62
|
+
"@types/node": "^26.1.0",
|
|
63
|
+
"typescript": "^6.0.3",
|
|
64
|
+
"vitest": "^4.1.10",
|
|
65
|
+
"zod": "^4.4.3",
|
|
66
|
+
"@zhin.js/agent": "1.0.4",
|
|
67
|
+
"zhin.js": "4.1.3"
|
|
68
|
+
},
|
|
69
|
+
"files": [
|
|
70
|
+
"adapters",
|
|
71
|
+
"plugin.ts",
|
|
72
|
+
"schema.json",
|
|
73
|
+
"src",
|
|
74
|
+
"lib",
|
|
75
|
+
"agent",
|
|
76
|
+
"README.md",
|
|
77
|
+
"CHANGELOG.md"
|
|
78
|
+
],
|
|
90
79
|
"publishConfig": {
|
|
91
80
|
"access": "public",
|
|
92
81
|
"registry": "https://registry.npmjs.org"
|
|
@@ -94,8 +83,23 @@
|
|
|
94
83
|
"engines": {
|
|
95
84
|
"node": "^20.19.0 || >=22.12.0"
|
|
96
85
|
},
|
|
86
|
+
"zhin": {
|
|
87
|
+
"protocol": 1,
|
|
88
|
+
"type": "plugin",
|
|
89
|
+
"entry": "./plugin.ts",
|
|
90
|
+
"engine": "^1.0.0",
|
|
91
|
+
"runtime": "trusted",
|
|
92
|
+
"features": [
|
|
93
|
+
{
|
|
94
|
+
"package": "@zhin.js/adapter",
|
|
95
|
+
"api": "^1.0.0"
|
|
96
|
+
}
|
|
97
|
+
],
|
|
98
|
+
"plugins": []
|
|
99
|
+
},
|
|
97
100
|
"scripts": {
|
|
98
|
-
"build": "
|
|
99
|
-
"clean": "rimraf lib"
|
|
101
|
+
"build": "tsc",
|
|
102
|
+
"clean": "rimraf lib",
|
|
103
|
+
"test": "NODE_OPTIONS=--experimental-strip-types vitest run --root ../../.. plugins/adapters/icqq/tests"
|
|
100
104
|
}
|
|
101
105
|
}
|
package/plugin.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { definePlugin } from '@zhin.js/plugin-runtime';
|
|
2
|
+
|
|
3
|
+
// Module-level guard: multiple icqq instances (icqq, icqq-2, …) share this
|
|
4
|
+
// module, but the prompt contributor is per-platform — register it once.
|
|
5
|
+
let promptContributorRegistered = false;
|
|
6
|
+
|
|
7
|
+
export default definePlugin({
|
|
8
|
+
name: 'icqq',
|
|
9
|
+
metadata: {
|
|
10
|
+
displayName: 'ICQQ Adapter',
|
|
11
|
+
},
|
|
12
|
+
setup() {
|
|
13
|
+
// Agent prompt contributor (orchestrator/deferred-worker ICQQ guidance).
|
|
14
|
+
// `zhin.js/agent` is an optional peer — skip silently on IM-only installs.
|
|
15
|
+
if (promptContributorRegistered) return;
|
|
16
|
+
let cancelled = false;
|
|
17
|
+
let unregister: (() => void) | undefined;
|
|
18
|
+
void Promise.all([
|
|
19
|
+
import('zhin.js/agent'),
|
|
20
|
+
import('./src/agent-prompt.js'),
|
|
21
|
+
]).then(([agent, prompt]) => {
|
|
22
|
+
if (cancelled || promptContributorRegistered) return;
|
|
23
|
+
agent.registerAgentPromptContributor(prompt.createIcqqAgentPromptContributor());
|
|
24
|
+
promptContributorRegistered = true;
|
|
25
|
+
unregister = () => agent.unregisterAgentPromptContributor('icqq');
|
|
26
|
+
}).catch(() => { /* optional peer not installed */ });
|
|
27
|
+
return () => {
|
|
28
|
+
cancelled = true;
|
|
29
|
+
unregister?.();
|
|
30
|
+
};
|
|
31
|
+
},
|
|
32
|
+
});
|
package/schema.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"type": "object",
|
|
4
|
+
"additionalProperties": false,
|
|
5
|
+
"properties": {
|
|
6
|
+
"name": {
|
|
7
|
+
"type": "string",
|
|
8
|
+
"description": "QQ uin (must match icqq login account)"
|
|
9
|
+
},
|
|
10
|
+
"master": {
|
|
11
|
+
"type": ["string", "number"],
|
|
12
|
+
"description": "Endpoint Owner QQ uin (for /approve bash and master role)"
|
|
13
|
+
},
|
|
14
|
+
"autoReconnect": {
|
|
15
|
+
"type": "boolean",
|
|
16
|
+
"default": true
|
|
17
|
+
},
|
|
18
|
+
"outboundMedia": {
|
|
19
|
+
"type": "string",
|
|
20
|
+
"enum": ["file", "base64"],
|
|
21
|
+
"description": "file=local path (same host as daemon); base64=CQ base64:// (default when rpc set)"
|
|
22
|
+
},
|
|
23
|
+
"rpc": {
|
|
24
|
+
"type": "object",
|
|
25
|
+
"additionalProperties": false,
|
|
26
|
+
"properties": {
|
|
27
|
+
"host": { "type": "string" },
|
|
28
|
+
"port": { "type": "number" },
|
|
29
|
+
"token": { "type": "string" }
|
|
30
|
+
},
|
|
31
|
+
"required": ["host", "port", "token"]
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"required": ["name"]
|
|
35
|
+
}
|