@zhin.js/adapter-icqq 2.0.25 → 3.0.0
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 +19 -0
- package/client/utils/api.ts +12 -2
- package/dist/index.js +2 -2
- package/lib/adapter.d.ts +1 -1
- package/lib/adapter.d.ts.map +1 -1
- package/lib/adapter.js +2 -3
- package/lib/adapter.js.map +1 -1
- package/lib/agent-prompt.d.ts +3 -0
- package/lib/agent-prompt.d.ts.map +1 -0
- package/lib/agent-prompt.js +104 -0
- package/lib/agent-prompt.js.map +1 -0
- package/lib/bot.d.ts +1 -1
- package/lib/bot.d.ts.map +1 -1
- package/lib/bot.js +44 -15
- package/lib/bot.js.map +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +4 -1
- package/lib/index.js.map +1 -1
- package/package.json +10 -10
- package/src/adapter.ts +2 -3
- package/src/agent-prompt.ts +115 -0
- package/src/bot.ts +44 -33
- package/src/index.ts +10 -1
- package/skills/icqq/SKILL.md +0 -41
- package/skills/icqq/references/friends.md +0 -54
- package/skills/icqq/references/general.md +0 -230
- package/skills/icqq/references/gfs.md +0 -49
- package/skills/icqq/references/groups.md +0 -71
- package/skills/icqq/references/messaging.md +0 -64
- package/skills/icqq/references/requests.md +0 -27
- package/skills/icqq/references/settings.md +0 -38
package/src/adapter.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ICQQ 适配器 — 通过 @icqqjs/cli 守护进程 IPC 管理 Bot 实例
|
|
3
3
|
*/
|
|
4
|
-
import { Adapter, Plugin } from
|
|
4
|
+
import { formatCompact, Adapter, Plugin } from 'zhin.js';
|
|
5
5
|
import { IcqqBot } from "./bot.js";
|
|
6
6
|
import type { IcqqBotConfig, IpcMemberInfo } from "./types.js";
|
|
7
7
|
import { Actions } from "./protocol.js";
|
|
@@ -17,12 +17,11 @@ export class IcqqAdapter extends Adapter<IcqqBot> {
|
|
|
17
17
|
|
|
18
18
|
async start(): Promise<void> {
|
|
19
19
|
await super.start();
|
|
20
|
-
this.logger.info("ICQQ 适配器已启动");
|
|
21
20
|
}
|
|
22
21
|
|
|
23
22
|
async stop(): Promise<void> {
|
|
24
23
|
await super.stop();
|
|
25
|
-
this.logger.
|
|
24
|
+
this.logger.debug(formatCompact({ stop: true }));
|
|
26
25
|
}
|
|
27
26
|
|
|
28
27
|
// ── IGroupManagement 标准群管方法(通过 IPC) ─────────────────────
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AgentPromptBuildContext,
|
|
3
|
+
AgentPromptContributor,
|
|
4
|
+
AgentPromptSection,
|
|
5
|
+
} from 'zhin.js';
|
|
6
|
+
import type { AgentTool } from 'zhin.js';
|
|
7
|
+
import { filterTools } from 'zhin.js';
|
|
8
|
+
|
|
9
|
+
function isIcqqDelegatedTask(query: string, goal: string): boolean {
|
|
10
|
+
const text = `${query} ${goal}`;
|
|
11
|
+
const lower = text.toLowerCase();
|
|
12
|
+
if (/\bicqq\b|mcp_icqq|send_private_msg|friend\s+send/i.test(text)) return true;
|
|
13
|
+
if (/\bfriend\s+like\b/.test(lower) && /qq|好友|\d{5,}/i.test(text)) return true;
|
|
14
|
+
if (/点赞/.test(text) && /qq|好友|\d{5,}/i.test(text)) return true;
|
|
15
|
+
if (/发消息|发送消息|私聊/.test(text) && /qq|\d{5,}/i.test(text)) return true;
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function selectIcqqDeferredTools(
|
|
20
|
+
query: string,
|
|
21
|
+
goal: string,
|
|
22
|
+
deferredCatalog: AgentTool[],
|
|
23
|
+
maxTools: number,
|
|
24
|
+
): AgentTool[] {
|
|
25
|
+
const pool = deferredCatalog.filter(
|
|
26
|
+
t => !t.name.startsWith('mcp_filesystem') && !t.name.startsWith('mcp_memory_'),
|
|
27
|
+
);
|
|
28
|
+
const icqqMcpTools = pool.filter(t => t.name.startsWith('mcp_icqq_'));
|
|
29
|
+
const icqqTools = pool.filter(t => t.name.startsWith('icqq_'));
|
|
30
|
+
const pinned: AgentTool[] = [];
|
|
31
|
+
const bash = pool.find(t => t.name === 'bash');
|
|
32
|
+
if (bash) pinned.push(bash);
|
|
33
|
+
const preferOrder = [
|
|
34
|
+
'mcp_icqq_icqq_invoke',
|
|
35
|
+
'mcp_icqq_icqq_list_actions',
|
|
36
|
+
'icqq_send_user_like',
|
|
37
|
+
'icqq_friend_list',
|
|
38
|
+
'icqq_poke',
|
|
39
|
+
];
|
|
40
|
+
for (const name of preferOrder) {
|
|
41
|
+
const t =
|
|
42
|
+
icqqMcpTools.find(x => x.name === name) ??
|
|
43
|
+
icqqTools.find(x => x.name === name);
|
|
44
|
+
if (t) pinned.push(t);
|
|
45
|
+
}
|
|
46
|
+
for (const t of [...icqqMcpTools, ...icqqTools]) {
|
|
47
|
+
if (pinned.length >= maxTools) break;
|
|
48
|
+
if (!pinned.some(p => p.name === t.name)) pinned.push(t);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const extra = filterTools(query, pool, { maxTools, minScore: 0.08 })
|
|
52
|
+
.filter(t => !pinned.some(p => p.name === t.name));
|
|
53
|
+
|
|
54
|
+
const merged: AgentTool[] = [...pinned];
|
|
55
|
+
for (const t of extra) {
|
|
56
|
+
if (merged.length >= maxTools) break;
|
|
57
|
+
merged.push(t);
|
|
58
|
+
}
|
|
59
|
+
return merged.slice(0, maxTools);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const ORCHESTRATOR_ICQQ = [
|
|
63
|
+
'On icqq/QQ: use run_deferred_task with tool_query "mcp_icqq_icqq_invoke" or "icqq_send_user_like".',
|
|
64
|
+
'Examples: send_private_msg, friend_like; do not use mcp_filesystem_* for QQ tasks.',
|
|
65
|
+
'Skip tool_search when the user clearly asks to send a message, like a friend, or poke on QQ.',
|
|
66
|
+
].join('\n');
|
|
67
|
+
|
|
68
|
+
const WORKER_ICQQ = [
|
|
69
|
+
'Send private message: `mcp_icqq_icqq_invoke` action `send_private_msg` params `{ user_id, message }`, or bash `icqq friend send <uid> "<text>"`.',
|
|
70
|
+
'Friend like: action `friend_like` or `icqq_send_user_like`, or bash `icqq friend like <uid> -t <times>`.',
|
|
71
|
+
'Use `icqq_list_actions` only if action name is unclear.',
|
|
72
|
+
'Do NOT use mcp_filesystem_* or explore node_modules / package.json to "discover" icqq.',
|
|
73
|
+
'Do not stop at --help; execute the action the goal describes.',
|
|
74
|
+
].map(line => `- ${line}`).join('\n');
|
|
75
|
+
|
|
76
|
+
export function createIcqqAgentPromptContributor(): AgentPromptContributor {
|
|
77
|
+
return {
|
|
78
|
+
platform: 'icqq',
|
|
79
|
+
|
|
80
|
+
async buildSections(ctx: AgentPromptBuildContext): Promise<AgentPromptSection[] | null> {
|
|
81
|
+
if (ctx.slot === 'orchestrator') {
|
|
82
|
+
if (!ctx.toolSearch) return null;
|
|
83
|
+
return [{
|
|
84
|
+
id: 'platform.icqq.orchestrator',
|
|
85
|
+
title: '## icqq / QQ',
|
|
86
|
+
body: ORCHESTRATOR_ICQQ,
|
|
87
|
+
priority: 50,
|
|
88
|
+
}];
|
|
89
|
+
}
|
|
90
|
+
if (ctx.slot === 'deferred_worker') {
|
|
91
|
+
const query = ctx.deferred?.toolQuery ?? ctx.deferred?.goal ?? '';
|
|
92
|
+
const goal = ctx.deferred?.goal ?? '';
|
|
93
|
+
if (!isIcqqDelegatedTask(query, goal)) return null;
|
|
94
|
+
return [{
|
|
95
|
+
id: 'platform.icqq.deferred_worker',
|
|
96
|
+
title: '## icqq / QQ(本任务)',
|
|
97
|
+
body: WORKER_ICQQ,
|
|
98
|
+
priority: 50,
|
|
99
|
+
}];
|
|
100
|
+
}
|
|
101
|
+
return null;
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
matchesDeferredTask(ctx: AgentPromptBuildContext): boolean {
|
|
105
|
+
const query = ctx.deferred?.toolQuery ?? ctx.deferred?.goal ?? ctx.userMessagePreview ?? '';
|
|
106
|
+
const goal = ctx.deferred?.goal ?? ctx.userMessagePreview ?? '';
|
|
107
|
+
return isIcqqDelegatedTask(query, goal);
|
|
108
|
+
},
|
|
109
|
+
|
|
110
|
+
selectDeferredTools(query, goal, catalog, maxTools) {
|
|
111
|
+
if (!isIcqqDelegatedTask(query, goal)) return null;
|
|
112
|
+
return selectIcqqDeferredTools(query, goal, catalog, maxTools);
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
}
|
package/src/bot.ts
CHANGED
|
@@ -4,14 +4,7 @@
|
|
|
4
4
|
* 不再直接依赖 @icqqjs/icqq 协议库。
|
|
5
5
|
* 登录由 `icqq login` 完成,本 Bot 只负责连接守护进程并收发消息。
|
|
6
6
|
*/
|
|
7
|
-
import {
|
|
8
|
-
Bot,
|
|
9
|
-
Message,
|
|
10
|
-
SendOptions,
|
|
11
|
-
MessageSegment,
|
|
12
|
-
SendContent,
|
|
13
|
-
segment,
|
|
14
|
-
} from "zhin.js";
|
|
7
|
+
import { formatCompact, Bot, Message, MessageSegment, segment, SendContent, SendOptions } from 'zhin.js';
|
|
15
8
|
import type {
|
|
16
9
|
IcqqBotConfig,
|
|
17
10
|
IcqqSenderInfo,
|
|
@@ -64,20 +57,20 @@ export class IcqqBot implements Bot<IcqqBotConfig, IpcMessageEventData> {
|
|
|
64
57
|
this.intentionalDisconnect = false;
|
|
65
58
|
const rpc = this.$config.rpc;
|
|
66
59
|
|
|
67
|
-
|
|
68
|
-
this
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
60
|
+
this.logger.debug(formatCompact( {
|
|
61
|
+
connecting: this.$id,
|
|
62
|
+
mode: rpc ? "rpc" : "ipc",
|
|
63
|
+
host: rpc?.host,
|
|
64
|
+
port: rpc?.port,
|
|
65
|
+
}));
|
|
74
66
|
|
|
75
67
|
await this.rebindIpcSession();
|
|
76
68
|
|
|
77
|
-
this.logger.info(
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
69
|
+
this.logger.info(formatCompact( {
|
|
70
|
+
bot: this.$id,
|
|
71
|
+
friends: this.friends.size,
|
|
72
|
+
groups: this.groups.size,
|
|
73
|
+
}));
|
|
81
74
|
}
|
|
82
75
|
|
|
83
76
|
/** 建立或恢复与守护进程的 IPC/RPC 会话(订阅、缓存列表) */
|
|
@@ -147,23 +140,33 @@ export class IcqqBot implements Bot<IcqqBotConfig, IpcMessageEventData> {
|
|
|
147
140
|
const delayMs = base + jitter;
|
|
148
141
|
|
|
149
142
|
this.$connected = false;
|
|
150
|
-
this.logger.warn(
|
|
151
|
-
|
|
152
|
-
|
|
143
|
+
this.logger.warn(formatCompact( {
|
|
144
|
+
op: "disconnect",
|
|
145
|
+
bot: this.$id,
|
|
146
|
+
ok: false,
|
|
147
|
+
delay_ms: delayMs,
|
|
148
|
+
attempt: attempt + 1,
|
|
149
|
+
}));
|
|
153
150
|
|
|
154
151
|
await new Promise<void>((r) => setTimeout(r, delayMs));
|
|
155
152
|
if (this.intentionalDisconnect) break;
|
|
156
153
|
|
|
157
154
|
try {
|
|
158
155
|
await this.rebindIpcSession();
|
|
159
|
-
this.logger.info(
|
|
160
|
-
|
|
161
|
-
|
|
156
|
+
this.logger.info(formatCompact( {
|
|
157
|
+
op: "reconnect",
|
|
158
|
+
bot: this.$id,
|
|
159
|
+
friends: this.friends.size,
|
|
160
|
+
groups: this.groups.size,
|
|
161
|
+
}));
|
|
162
162
|
break;
|
|
163
163
|
} catch (e: any) {
|
|
164
|
-
this.logger.warn(
|
|
165
|
-
|
|
166
|
-
|
|
164
|
+
this.logger.warn(formatCompact( {
|
|
165
|
+
op: "reconnect",
|
|
166
|
+
bot: this.$id,
|
|
167
|
+
ok: false,
|
|
168
|
+
error: e?.message ?? String(e),
|
|
169
|
+
}));
|
|
167
170
|
}
|
|
168
171
|
}
|
|
169
172
|
} finally {
|
|
@@ -204,7 +207,7 @@ export class IcqqBot implements Bot<IcqqBotConfig, IpcMessageEventData> {
|
|
|
204
207
|
this.subscriptions = [];
|
|
205
208
|
this.ipc?.close();
|
|
206
209
|
this.$connected = false;
|
|
207
|
-
this.logger.info(
|
|
210
|
+
this.logger.info(formatCompact( { op: "disconnect", bot: this.$id }));
|
|
208
211
|
}
|
|
209
212
|
|
|
210
213
|
// ── 消息处理 ───────────────────────────────────────────────────────
|
|
@@ -245,9 +248,12 @@ export class IcqqBot implements Bot<IcqqBotConfig, IpcMessageEventData> {
|
|
|
245
248
|
$timestamp: raw.time * 1000,
|
|
246
249
|
$recall: async () => {
|
|
247
250
|
// 合成 id 无法撤回
|
|
248
|
-
this.logger.warn(
|
|
249
|
-
|
|
250
|
-
|
|
251
|
+
this.logger.warn(formatCompact( {
|
|
252
|
+
op: "recall",
|
|
253
|
+
bot: this.$id,
|
|
254
|
+
ok: false,
|
|
255
|
+
error: "no message_id in push",
|
|
256
|
+
}));
|
|
251
257
|
},
|
|
252
258
|
$reply: async (
|
|
253
259
|
content: SendContent,
|
|
@@ -278,7 +284,12 @@ export class IcqqBot implements Bot<IcqqBotConfig, IpcMessageEventData> {
|
|
|
278
284
|
message_id: id,
|
|
279
285
|
});
|
|
280
286
|
if (!resp.ok) {
|
|
281
|
-
this.logger.warn(
|
|
287
|
+
this.logger.warn(formatCompact( {
|
|
288
|
+
op: "recall",
|
|
289
|
+
bot: this.$id,
|
|
290
|
+
ok: false,
|
|
291
|
+
error: resp.error,
|
|
292
|
+
}));
|
|
282
293
|
}
|
|
283
294
|
}
|
|
284
295
|
|
package/src/index.ts
CHANGED
|
@@ -2,7 +2,14 @@
|
|
|
2
2
|
* ICQQ 适配器入口:类型扩展、导出、注册
|
|
3
3
|
*/
|
|
4
4
|
import path from "path";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
usePlugin,
|
|
7
|
+
type Plugin,
|
|
8
|
+
type ToolFeature,
|
|
9
|
+
registerAgentPromptContributor,
|
|
10
|
+
unregisterAgentPromptContributor,
|
|
11
|
+
} from "zhin.js";
|
|
12
|
+
import { createIcqqAgentPromptContributor } from "./agent-prompt.js";
|
|
6
13
|
import type { Router } from "@zhin.js/http";
|
|
7
14
|
import { PageManager } from "@zhin.js/console";
|
|
8
15
|
import { IcqqAdapter } from "./adapter.js";
|
|
@@ -34,11 +41,13 @@ provide({
|
|
|
34
41
|
name: "icqq",
|
|
35
42
|
description: "ICQQ Adapter",
|
|
36
43
|
mounted: async (p: Plugin) => {
|
|
44
|
+
registerAgentPromptContributor(createIcqqAgentPromptContributor());
|
|
37
45
|
const adapter = new IcqqAdapter(p);
|
|
38
46
|
await adapter.start();
|
|
39
47
|
return adapter;
|
|
40
48
|
},
|
|
41
49
|
dispose: async (adapter: IcqqAdapter) => {
|
|
50
|
+
unregisterAgentPromptContributor("icqq");
|
|
42
51
|
await adapter.stop();
|
|
43
52
|
},
|
|
44
53
|
} as any);
|
package/skills/icqq/SKILL.md
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: icqq
|
|
3
|
-
platforms:
|
|
4
|
-
- icqq
|
|
5
|
-
description: '通过 icqq 命令行操作 QQ 账号。适用于:发私聊或群消息、撤回、查聊天记录;好友(列表、资料、备注、戳一戳、点赞、删好友、分组);群(禁言、踢人、公告、签到、精华、成员、邀请、全体禁言);好友/群验证与入群请求;群文件;昵称头像签名、在线状态;黑名单、OCR、Webhook、通知;登录与守护进程。用户提到 QQ、企鹅、好友、群聊、@、撤回、禁言、踢人、加群、好友请求、群文件、签到等时使用本技能。'
|
|
6
|
-
argument-hint: '用一句话说明要对 QQ 执行的操作,例如「给好友 12345 发一条你好」或「把群 11111 里的用户 67890 禁言 10 分钟」'
|
|
7
|
-
disable-model-invocation: true
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
# icqq — 用命令行操作 QQ
|
|
11
|
-
|
|
12
|
-
通过 **`icqq`** 命令行工具操作 QQ。需先 **`icqq login`** 启动守护进程后再执行其它命令。
|
|
13
|
-
|
|
14
|
-
## 使用流程
|
|
15
|
-
|
|
16
|
-
1. **判断模块** — 对照下方「模块表」,匹配用户意图属于哪一类
|
|
17
|
-
2. **只读对应参考** — 仅打开与意图相关的 `references/*.md`,不要凭记忆猜命令
|
|
18
|
-
3. **执行命令** — 在终端运行 `icqq …`,把结果回报给用户;未登录或守护未起时命令失败即如实说明
|
|
19
|
-
|
|
20
|
-
## 模块表
|
|
21
|
-
|
|
22
|
-
按用户想做的事,打开对应参考文件:
|
|
23
|
-
|
|
24
|
-
| 用户意图 | 模块 | 参考文档 |
|
|
25
|
-
|----------|------|----------|
|
|
26
|
-
| 发消息、撤回、聊天记录、消息详情、合并转发 | 消息 | [messaging.md](./references/messaging.md) |
|
|
27
|
-
| 好友列表、查看、发消息、戳一戳、点赞、删除、备注、文件、好友分组 | 好友 | [friends.md](./references/friends.md) |
|
|
28
|
-
| 群:发消息、禁言、踢人、公告、邀请、签到、精华、成员、表态 | 群管理 | [groups.md](./references/groups.md) |
|
|
29
|
-
| 昵称、头像、签名、群名片、群头衔、加群方式、匿名等设置 | 设置 | [settings.md](./references/settings.md) |
|
|
30
|
-
| 好友请求、群请求、入群验证 | 请求 | [requests.md](./references/requests.md) |
|
|
31
|
-
| 群文件:目录、上传下载、转发 | 群文件 | [gfs.md](./references/gfs.md) |
|
|
32
|
-
| 登录、服务/守护、配置、OCR、黑名单、Webhook、通知、UID 转换、陌生人、漫游表情、缓存、重载、频道、RPC、补全 | 通用 | [general.md](./references/general.md) |
|
|
33
|
-
|
|
34
|
-
## 全局约定
|
|
35
|
-
|
|
36
|
-
- `<uid>` = QQ 号(数字),`<gid>` = 群号(数字)
|
|
37
|
-
- 多账号:全局参数 `-u <uin>` 或环境变量 `ICQQ_CURRENT_UIN`;默认用配置里的 `currentUin`
|
|
38
|
-
- **自动执行发消息** 优先用 **`icqq friend send` / `icqq group send`**(非交互);`icqq friend chat` / `icqq group chat` 为交互式,不适合代理串行跑
|
|
39
|
-
- CQ 码片段:`[face:id]` `[image:路径或URL]` `[at:uid]` `[at:all]` `[dice]` `[rps]`
|
|
40
|
-
- 含空格的内容用英文双引号包起来:`icqq friend send 12345 "你好 世界"`
|
|
41
|
-
- 批量操作用 `&&` 串联多条命令
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
# Friends
|
|
2
|
-
|
|
3
|
-
## List & View
|
|
4
|
-
|
|
5
|
-
```
|
|
6
|
-
icqq friend list # List all friends
|
|
7
|
-
icqq friend view <uid> # View friend profile
|
|
8
|
-
icqq friend avatar-url <uid> # Get avatar URL
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## Actions
|
|
12
|
-
|
|
13
|
-
```
|
|
14
|
-
icqq friend send <uid> <message> # Send private message
|
|
15
|
-
icqq friend poke <uid> # Poke a friend
|
|
16
|
-
icqq friend like <uid> [-t times] # Like (1-20 times, default 1)
|
|
17
|
-
icqq friend delete <uid> [-b] # Delete friend (-b: also block)
|
|
18
|
-
icqq friend remark <uid> <remark> # Set friend remark/alias
|
|
19
|
-
icqq friend add <uid> # Add friend (optionally via group)
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
## Files
|
|
23
|
-
|
|
24
|
-
```
|
|
25
|
-
icqq friend send-file <uid> <file> # Send file to friend
|
|
26
|
-
icqq friend file-info <uid> <fid> # Get file info
|
|
27
|
-
icqq friend file-url <uid> <fid> # Get file download URL
|
|
28
|
-
icqq friend recall-file <uid> <fid> # Recall a sent file
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
## Friend Classes (Groups)
|
|
32
|
-
|
|
33
|
-
```
|
|
34
|
-
icqq friend class list # List friend groups
|
|
35
|
-
icqq friend class add <name> # Create friend group
|
|
36
|
-
icqq friend class delete <id> # Delete friend group
|
|
37
|
-
icqq friend class rename <id> <name> # Rename friend group
|
|
38
|
-
icqq friend class set <uid> <id> # Move friend to group
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
## Examples
|
|
42
|
-
|
|
43
|
-
```bash
|
|
44
|
-
icqq friend list
|
|
45
|
-
icqq friend view 12345
|
|
46
|
-
icqq friend send 12345 "你好"
|
|
47
|
-
icqq friend poke 12345
|
|
48
|
-
icqq friend like 12345 -t 10
|
|
49
|
-
icqq friend remark 12345 "小王"
|
|
50
|
-
icqq friend delete 12345 -b
|
|
51
|
-
icqq friend send-file 12345 ./doc.pdf
|
|
52
|
-
icqq friend class list
|
|
53
|
-
icqq friend class add "大学同学"
|
|
54
|
-
```
|
|
@@ -1,230 +0,0 @@
|
|
|
1
|
-
# General
|
|
2
|
-
|
|
3
|
-
## Account
|
|
4
|
-
|
|
5
|
-
> Use **`icqq service status`** for service/daemon state, or **`icqq profile`** / **`icqq friend list`** to verify the daemon answers over IPC.
|
|
6
|
-
|
|
7
|
-
```
|
|
8
|
-
icqq login # Login QQ and start daemon (interactive wizard)
|
|
9
|
-
icqq login -r # Quick reconnect using saved token
|
|
10
|
-
icqq login -q <uid> -r # Quick reconnect specific account
|
|
11
|
-
icqq logout # Logout and stop daemon (token invalidated)
|
|
12
|
-
icqq logout -k # Disconnect only, keep token (login -r still works)
|
|
13
|
-
icqq logout <uin> # Logout specific account
|
|
14
|
-
icqq switch # Switch current account (interactive)
|
|
15
|
-
icqq switch <uin> # Switch to specific account
|
|
16
|
-
icqq profile # View current account profile
|
|
17
|
-
icqq requests # View pending friend/group requests
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
## System Service (auto-restart on crash, start on boot)
|
|
21
|
-
|
|
22
|
-
```
|
|
23
|
-
icqq service install # Register daemon as system service (launchd/systemd)
|
|
24
|
-
icqq service install -a # Install service for all configured accounts
|
|
25
|
-
icqq service uninstall # Remove system service
|
|
26
|
-
icqq service uninstall -a # Uninstall all
|
|
27
|
-
icqq service start # Start installed service
|
|
28
|
-
icqq service start -a # Start all
|
|
29
|
-
icqq service stop # Stop service (keeps service file, no restart until start)
|
|
30
|
-
icqq service stop -a # Stop all
|
|
31
|
-
icqq service status # Show service install/running state
|
|
32
|
-
icqq service status -a # Show status for all accounts
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
Note: `icqq logout` does NOT prevent service auto-restart. To permanently stop, uninstall the service first.
|
|
36
|
-
|
|
37
|
-
## Config
|
|
38
|
-
|
|
39
|
-
```
|
|
40
|
-
icqq config get # View all config
|
|
41
|
-
icqq config get <key> # View specific config key (currentUin, webhookUrl, notifyEnabled)
|
|
42
|
-
icqq config set <key> <value> # Set config value
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
## Multi-Instance
|
|
46
|
-
|
|
47
|
-
Use `-u <uin>` global flag or `ICQQ_CURRENT_UIN` env to target a specific account.
|
|
48
|
-
Default falls back to `config.currentUin`.
|
|
49
|
-
|
|
50
|
-
```
|
|
51
|
-
icqq -u 12345 profile # View profile for account 12345
|
|
52
|
-
ICQQ_CURRENT_UIN=12345 icqq friend list
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
## Blacklist
|
|
56
|
-
|
|
57
|
-
```
|
|
58
|
-
icqq blacklist # View blacklist
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
## OCR
|
|
62
|
-
|
|
63
|
-
```
|
|
64
|
-
icqq ocr <image> # OCR image text recognition (local file path)
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
## Webhook
|
|
68
|
-
|
|
69
|
-
```
|
|
70
|
-
icqq webhook # View current webhook config
|
|
71
|
-
icqq webhook set <url> # Set webhook URL (daemon pushes events via POST)
|
|
72
|
-
icqq webhook off # Disable webhook
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
## Notification
|
|
76
|
-
|
|
77
|
-
```
|
|
78
|
-
icqq notify # View notification status
|
|
79
|
-
icqq notify on # Enable system notifications
|
|
80
|
-
icqq notify off # Disable system notifications
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
## Conversion
|
|
84
|
-
|
|
85
|
-
```
|
|
86
|
-
icqq convert uid <qq> # QQ number to UID
|
|
87
|
-
icqq convert uin <uid> # UID to QQ number
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
## Keys & URLs
|
|
91
|
-
|
|
92
|
-
```
|
|
93
|
-
icqq get client-key # Get ClientKey
|
|
94
|
-
icqq get pskey # Get PSKey
|
|
95
|
-
icqq get video-url <vid> # Get video download URL
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
## Stranger
|
|
99
|
-
|
|
100
|
-
```
|
|
101
|
-
icqq stranger view <uid> # View stranger profile
|
|
102
|
-
icqq stranger status <uid> # Check online status
|
|
103
|
-
icqq stranger add-setting <uid> # Check add-friend settings
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
## Roaming Emoji (Stamps)
|
|
107
|
-
|
|
108
|
-
```
|
|
109
|
-
icqq stamp list # List roaming emojis
|
|
110
|
-
icqq stamp delete # Delete roaming emoji
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
## Cache & Reload
|
|
114
|
-
|
|
115
|
-
```
|
|
116
|
-
icqq cache clean # Clear cache
|
|
117
|
-
icqq reload friends # Refresh friend list
|
|
118
|
-
icqq reload groups # Refresh group list
|
|
119
|
-
icqq reload blacklist # Reload blacklist
|
|
120
|
-
icqq reload guilds # Reload guild list
|
|
121
|
-
icqq reload strangers # Reload stranger list
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
## Guild (Server & Channel)
|
|
125
|
-
|
|
126
|
-
```
|
|
127
|
-
icqq guild list # List guilds
|
|
128
|
-
icqq guild info <guild_id> # View guild info
|
|
129
|
-
icqq guild members <guild_id> # List guild members
|
|
130
|
-
icqq guild channel list <guild_id> # List subchannels
|
|
131
|
-
icqq guild channel send <guild_id> <channel_id> <message> # Send channel message
|
|
132
|
-
icqq guild channel chat <guild_id> <channel_id> # Interactive channel chat
|
|
133
|
-
icqq guild channel recall <guild_id> <channel_id> <seq> # Recall channel message
|
|
134
|
-
icqq guild channel share <guild_id> <channel_id> <url> <title> # Share post link
|
|
135
|
-
icqq guild channel forum-url <guild_id> <channel_id> <forum_id> # Get forum URL
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
## Shell Completion
|
|
139
|
-
|
|
140
|
-
```
|
|
141
|
-
icqq completion [shell] # Generate shell completion script (bash/zsh/fish)
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
## RPC (TCP Remote Connection)
|
|
145
|
-
|
|
146
|
-
The daemon supports optional TCP remote access for cross-machine QQ account control.
|
|
147
|
-
|
|
148
|
-
### Configuration
|
|
149
|
-
|
|
150
|
-
In `~/.icqq/config.json`:
|
|
151
|
-
|
|
152
|
-
```json
|
|
153
|
-
{
|
|
154
|
-
"rpc": {
|
|
155
|
-
"enabled": true,
|
|
156
|
-
"host": "127.0.0.1",
|
|
157
|
-
"port": 0
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
Or via CLI:
|
|
163
|
-
|
|
164
|
-
```
|
|
165
|
-
icqq config set rpc.enabled true # Enable RPC TCP listener
|
|
166
|
-
icqq config set rpc.host 0.0.0.0 # Listen on all interfaces (for remote access)
|
|
167
|
-
icqq config set rpc.port 9100 # Set listen port (0 = auto-assign)
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
| Field | Description | Default |
|
|
171
|
-
|-------|-------------|---------|
|
|
172
|
-
| `enabled` | Enable RPC TCP listener | `false` |
|
|
173
|
-
| `host` | Listen address, `"0.0.0.0"` for remote | `"127.0.0.1"` |
|
|
174
|
-
| `port` | Listen port, `0` = auto-assign | `0` |
|
|
175
|
-
|
|
176
|
-
### Security
|
|
177
|
-
|
|
178
|
-
- **HMAC-SHA256 challenge-response auth** — token never transmitted over network
|
|
179
|
-
- **IP rate limiting** — 5 failures in 5 minutes → auto-block
|
|
180
|
-
- **Default localhost only** — must explicitly set `host: "0.0.0.0"` for remote access
|
|
181
|
-
- **4KB unauthenticated buffer limit** — prevents memory exhaustion
|
|
182
|
-
|
|
183
|
-
### Programmatic Access
|
|
184
|
-
|
|
185
|
-
```typescript
|
|
186
|
-
import { IpcClient } from "@icqqjs/cli/lib/ipc-client";
|
|
187
|
-
|
|
188
|
-
// Option 1: Specify host/port/token directly
|
|
189
|
-
const client = await IpcClient.connectRpc({
|
|
190
|
-
host: "192.168.1.100",
|
|
191
|
-
port: 9100,
|
|
192
|
-
token: "your-token-here",
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
// Option 2: Auto-read from daemon.rpc file (local only)
|
|
196
|
-
const client = await IpcClient.connectRpcByUin(12345);
|
|
197
|
-
|
|
198
|
-
const resp = await client.request("list_friends");
|
|
199
|
-
client.close();
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
### Auth Flow
|
|
203
|
-
|
|
204
|
-
1. Client connects to TCP port
|
|
205
|
-
2. Server sends `{ "challenge": "<random-hex>" }`
|
|
206
|
-
3. Client computes `HMAC-SHA256(token, challenge)` → digest
|
|
207
|
-
4. Client sends `{ "action": "auth", "params": { "digest": "<hex>" } }`
|
|
208
|
-
5. Server verifies → authenticated
|
|
209
|
-
|
|
210
|
-
## Examples
|
|
211
|
-
|
|
212
|
-
```bash
|
|
213
|
-
icqq service status
|
|
214
|
-
icqq profile
|
|
215
|
-
icqq requests
|
|
216
|
-
icqq login -r
|
|
217
|
-
icqq config get
|
|
218
|
-
icqq config set currentUin 12345
|
|
219
|
-
icqq switch 12345
|
|
220
|
-
icqq -u 12345 profile
|
|
221
|
-
icqq ocr ./screenshot.png
|
|
222
|
-
icqq webhook set https://example.com/hook
|
|
223
|
-
icqq notify on
|
|
224
|
-
icqq convert uid 12345
|
|
225
|
-
icqq stranger view 12345
|
|
226
|
-
icqq stamp list
|
|
227
|
-
icqq cache clean
|
|
228
|
-
icqq reload friends
|
|
229
|
-
icqq guild list
|
|
230
|
-
```
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
# Group File System (GFS)
|
|
2
|
-
|
|
3
|
-
## List Files
|
|
4
|
-
|
|
5
|
-
```
|
|
6
|
-
icqq group fs list <gid> # List root directory
|
|
7
|
-
icqq group fs list <gid> -p <pid> # List subdirectory by parent ID
|
|
8
|
-
```
|
|
9
|
-
|
|
10
|
-
## Info & Stats
|
|
11
|
-
|
|
12
|
-
```
|
|
13
|
-
icqq group fs info <gid> # View GFS usage stats (space, file count)
|
|
14
|
-
icqq group fs stat <gid> <fid> # View file/directory details
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
## Manage
|
|
18
|
-
|
|
19
|
-
```
|
|
20
|
-
icqq group fs mkdir <gid> <name> # Create directory
|
|
21
|
-
icqq group fs delete <gid> <fid> # Delete file/directory by ID
|
|
22
|
-
icqq group fs rename <gid> <fid> <name> # Rename file/directory
|
|
23
|
-
icqq group fs move <gid> <fid> <pid> # Move file to directory
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
## Upload & Download
|
|
27
|
-
|
|
28
|
-
```
|
|
29
|
-
icqq group fs upload <gid> <file> # Upload file to group
|
|
30
|
-
icqq group fs download <gid> <fid> # Get download URL
|
|
31
|
-
icqq group fs forward <gid> <fid> <target_gid> # Forward file to another group
|
|
32
|
-
icqq group fs forward-offline <gid> <fid> # Convert to offline file
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
The `<fid>` (file ID) is shown in `icqq group fs list` output.
|
|
36
|
-
|
|
37
|
-
## Examples
|
|
38
|
-
|
|
39
|
-
```bash
|
|
40
|
-
icqq group fs list 67890
|
|
41
|
-
icqq group fs info 67890
|
|
42
|
-
icqq group fs stat 67890 abc123
|
|
43
|
-
icqq group fs mkdir 67890 "会议资料"
|
|
44
|
-
icqq group fs upload 67890 ./report.pdf
|
|
45
|
-
icqq group fs download 67890 abc123
|
|
46
|
-
icqq group fs rename 67890 abc123 "新文件名"
|
|
47
|
-
icqq group fs move 67890 abc123 def456
|
|
48
|
-
icqq group fs delete 67890 abc123
|
|
49
|
-
```
|