@zhin.js/adapter-icqq 6.0.1 → 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 +59 -0
- package/README.md +32 -437
- package/adapters/icqq.ts +30 -0
- package/agent/tools/announce.ts +21 -0
- package/agent/tools/essence.ts +22 -0
- package/agent/tools/friend_list.ts +19 -0
- package/agent/tools/group_files.ts +27 -0
- package/agent/tools/group_invite.ts +20 -0
- package/agent/tools/group_list.ts +20 -0
- package/agent/tools/group_sign.ts +19 -0
- package/agent/tools/list_muted.ts +22 -0
- package/agent/tools/poke.ts +20 -0
- package/agent/tools/send_user_like.ts +22 -0
- package/agent/tools/set_anonymous.ts +22 -0
- package/agent/tools/set_title.ts +25 -0
- package/lib/agent-prompt.d.ts +0 -1
- package/lib/agent-prompt.js +0 -1
- package/lib/cq-message.d.ts +0 -1
- package/lib/cq-message.js +0 -1
- package/lib/endpoint.d.ts +45 -97
- package/lib/endpoint.js +357 -628
- package/lib/forward-msg.d.ts +1 -2
- package/lib/forward-msg.js +4 -2
- package/lib/icqq-agent-deps.d.ts +25 -0
- package/lib/icqq-agent-deps.js +32 -0
- package/lib/icqq-guild.d.ts +1 -2
- package/lib/icqq-guild.js +4 -2
- package/lib/icqq-inbound.d.ts +10 -1
- package/lib/icqq-inbound.js +27 -3
- package/lib/index.d.ts +6 -18
- package/lib/index.js +6 -50
- package/lib/ipc-client.d.ts +0 -1
- package/lib/ipc-client.js +0 -1
- package/lib/outbound-media.d.ts +0 -1
- package/lib/outbound-media.js +0 -1
- package/lib/protocol.d.ts +73 -2
- package/lib/protocol.js +124 -2
- package/lib/types.d.ts +0 -1
- package/lib/types.js +0 -1
- package/package.json +51 -43
- package/plugin.ts +32 -0
- package/schema.json +35 -0
- package/src/agent-prompt.ts +1 -2
- package/src/endpoint.ts +399 -800
- package/src/forward-msg.ts +2 -2
- package/src/icqq-agent-deps.ts +57 -0
- 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/adapter.d.ts +0 -46
- package/lib/adapter.d.ts.map +0 -1
- package/lib/adapter.js +0 -128
- package/lib/adapter.js.map +0 -1
- package/lib/agent-prompt.d.ts.map +0 -1
- package/lib/agent-prompt.js.map +0 -1
- package/lib/cq-message.d.ts.map +0 -1
- package/lib/cq-message.js.map +0 -1
- package/lib/endpoint.d.ts.map +0 -1
- package/lib/endpoint.js.map +0 -1
- package/lib/forward-msg.d.ts.map +0 -1
- package/lib/forward-msg.js.map +0 -1
- package/lib/get-msg.d.ts +0 -3
- package/lib/get-msg.d.ts.map +0 -1
- package/lib/get-msg.js +0 -46
- package/lib/get-msg.js.map +0 -1
- package/lib/icqq-guild.d.ts.map +0 -1
- package/lib/icqq-guild.js.map +0 -1
- package/lib/icqq-inbound.d.ts.map +0 -1
- package/lib/icqq-inbound.js.map +0 -1
- package/lib/icqq-login-assist-bridge.d.ts +0 -5
- package/lib/icqq-login-assist-bridge.d.ts.map +0 -1
- package/lib/icqq-login-assist-bridge.js +0 -148
- package/lib/icqq-login-assist-bridge.js.map +0 -1
- package/lib/icqq-side-events.d.ts +0 -34
- package/lib/icqq-side-events.d.ts.map +0 -1
- package/lib/icqq-side-events.js +0 -194
- package/lib/icqq-side-events.js.map +0 -1
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/ipc-client.d.ts.map +0 -1
- package/lib/ipc-client.js.map +0 -1
- package/lib/login-assist-routes.d.ts +0 -7
- package/lib/login-assist-routes.d.ts.map +0 -1
- package/lib/login-assist-routes.js +0 -29
- package/lib/login-assist-routes.js.map +0 -1
- package/lib/login-ipc-contract.d.ts +0 -44
- package/lib/login-ipc-contract.d.ts.map +0 -1
- package/lib/login-ipc-contract.js +0 -35
- package/lib/login-ipc-contract.js.map +0 -1
- package/lib/outbound-media.d.ts.map +0 -1
- package/lib/outbound-media.js.map +0 -1
- package/lib/protocol.d.ts.map +0 -1
- package/lib/protocol.js.map +0 -1
- package/lib/routes.d.ts +0 -8
- package/lib/routes.d.ts.map +0 -1
- package/lib/routes.js +0 -67
- package/lib/routes.js.map +0 -1
- package/lib/segment-mapper.d.ts +0 -2
- package/lib/segment-mapper.d.ts.map +0 -1
- package/lib/segment-mapper.js +0 -2
- package/lib/segment-mapper.js.map +0 -1
- package/lib/tools/index.d.ts +0 -10
- package/lib/tools/index.d.ts.map +0 -1
- package/lib/tools/index.js +0 -341
- package/lib/tools/index.js.map +0 -1
- package/lib/types.d.ts.map +0 -1
- package/lib/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 -228
- 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 -412
- /package/{skills/icqq → agent}/PERMITS.md +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,64 @@
|
|
|
1
1
|
# @zhin.js/adapter-icqq
|
|
2
2
|
|
|
3
|
+
## 6.0.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- cc5c94d: 约定式插件运行时迁移(breaking):插件与适配器由 `usePlugin()` / `extends Adapter` 迁移为 `definePlugin` / `defineAdapter` + `plugin.ts` + 约定目录(`adapters/`、`commands/`、`components/`、`tools/` 等)。
|
|
8
|
+
|
|
9
|
+
- 新增约定式运行时包:`@zhin.js/plugin-runtime`、`@zhin.js/adapter`、`@zhin.js/runtime`、`@zhin.js/host-http`(首版 1.0.0 走 init-publish,不在本 changeset 内 bump)。
|
|
10
|
+
- 全部 20 个平台适配器改为约定式 `defineAdapter`,旧 `usePlugin` / `extends Adapter` / `segment-mapper` 生产入口已删除;onebot11 反向 WSS、onebot12 webhook/wss、milky sse/webhook/wss、satori webhook、kook webhook、qq webhook/middleware 等 slice 1 推迟的连接模式已补齐。
|
|
11
|
+
- 游戏 / 工具 / 服务插件同步迁移到约定目录结构。
|
|
12
|
+
- CLI 增加 plugin-runtime host installer(http/database/outbound/schedule/console 等)。
|
|
13
|
+
|
|
14
|
+
后续加固(同批):
|
|
15
|
+
|
|
16
|
+
- CLI:`zhin runtime start --daemon`(pidfile/崩溃拉起/风暴保护),orphan watchdog 防僵尸进程;legacy `zhin dev` / `zhin start` 已移除(含 `zhin restart`),`zhin stop` 兼容新 daemon。
|
|
17
|
+
- 安全:builtin 工具统一走 `security/policy-facade.ts` 的 `runToolPolicies`(声明式策略表,deny 优先);审计日志 close flush + 背压队列;`splitCompoundCommand` 引号感知、`extractCommandName` 去引号堵绕过。
|
|
18
|
+
- 日志:Logger 双堆栈修复、本地时区、`getLogger` 挂树(`setLevel` 递归生效)、第三方库(log4js/discord)桥接、启动人读总结。
|
|
19
|
+
- 结构:`plugins/games/shared` 迁为 `packages/game-kit`(`@zhin.js/game-kit`);死目录 `plugins/adapters/common` 删除。
|
|
20
|
+
- 脚手架:`create-zhin-app` / `zhin new` / scaffold-wizard 生成物改为 Plugin Runtime 形态(minimal-bot 同构,新配置格式)。
|
|
21
|
+
- Console:endpoint.list 真实名称与 phase、schema:get-all 按 instanceKey 映射、db:\* 接 DatabaseHost。
|
|
22
|
+
|
|
23
|
+
注:按仓库发布惯例(见 1bb345dd2),本次 breaking 迁移统一使用 patch,避免 zhin.js 5.0 级联。
|
|
24
|
+
|
|
25
|
+
- 447f3e2: 迁移缺口修复(legacy 功能对齐):
|
|
26
|
+
|
|
27
|
+
- html 段出站规范化:经 `@zhin.js/html-renderer` 渲染为 image 段(sandbox 豁免、无渲染器时降级文本),修复真实平台 `[object Object]`。
|
|
28
|
+
- 群聊 @ 触发 AI:适配器入站标注 `metadata.mentioned`(icqq/qq/slack/onebot11/onebot12/napcat/milky/discord/telegram/kook/dingtalk/satori),`matchAiTrigger` 补齐 ignorePrefixes/respondToAt/respondToPrivate/keywords(默认值与 legacy 对齐)。
|
|
29
|
+
- im_transcripts 全量流水恢复写入(chat_history 工具可用);群聊旁听上下文回迁。
|
|
30
|
+
- `ai.trigger.timeout/thinkingMessage/errorTemplate` 生效;masters/trusted 角色解析对齐 legacy。
|
|
31
|
+
- `Message.sender` 统一为用户 ID(onebot11/12、napcat、milky 原误传显示名);quote_id 经 metadata 接入 AI 引用上下文。
|
|
32
|
+
|
|
33
|
+
- Updated dependencies [16ec4e8]
|
|
34
|
+
- Updated dependencies [cc5c94d]
|
|
35
|
+
- Updated dependencies [447f3e2]
|
|
36
|
+
- @zhin.js/core@1.3.5
|
|
37
|
+
- @zhin.js/agent@1.0.4
|
|
38
|
+
- zhin.js@4.1.3
|
|
39
|
+
- @zhin.js/logger@1.0.75
|
|
40
|
+
- @zhin.js/plugin-runtime@1.0.1
|
|
41
|
+
- @zhin.js/adapter@1.0.1
|
|
42
|
+
|
|
43
|
+
## 6.0.2
|
|
44
|
+
|
|
45
|
+
### Patch Changes
|
|
46
|
+
|
|
47
|
+
- 872c583: Slack 适配器 Phase 1/2:mrkdwn 出站、长消息切分、斜杠/按钮 ephemeral 反馈、入站 mrkdwn→Markdown、editMessage 对齐 core。
|
|
48
|
+
|
|
49
|
+
Logger 表格日志与 string-width 列宽;Agent AI Handler 框线表格与 introspection/MCP 导出;Core side-event 归一化;Schedule 时区规划;多适配器 side-event 与 API surface 更新。
|
|
50
|
+
|
|
51
|
+
- 872c583: fix: 代码格式优化
|
|
52
|
+
- Updated dependencies [872c583]
|
|
53
|
+
- Updated dependencies [872c583]
|
|
54
|
+
- @zhin.js/agent@1.0.3
|
|
55
|
+
- @zhin.js/client@2.0.5
|
|
56
|
+
- @zhin.js/contract@1.0.3
|
|
57
|
+
- @zhin.js/core@1.3.4
|
|
58
|
+
- @zhin.js/host-api@2.0.5
|
|
59
|
+
- @zhin.js/host-router@2.0.3
|
|
60
|
+
- zhin.js@4.1.2
|
|
61
|
+
|
|
3
62
|
## 6.0.1
|
|
4
63
|
|
|
5
64
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -1,464 +1,59 @@
|
|
|
1
1
|
# @zhin.js/adapter-icqq
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
Zhin.js ICQQ 适配器,通过 **[@icqqjs/cli](https://github.com/icqqjs/cli) 守护进程 IPC** 连接已登录的 QQ 账号,支持群聊和私聊消息。协议与登录由 CLI 负责,Zhin 侧只配置 QQ 号并连接本地/远程守护进程。
|
|
3
|
+
ICQQ Plugin Runtime 适配器 — 通过 [@icqqjs/cli](https://github.com/icqqjs/cli) 守护进程 IPC 连接已登录 QQ 账号(无 `httpHostToken`)。
|
|
6
4
|
|
|
7
5
|
## 功能特性
|
|
8
6
|
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
- 🔄 消息格式转换和适配
|
|
14
|
-
- 📁 自动数据目录管理
|
|
15
|
-
- 🖼️ 支持图片、语音、视频等多媒体消息
|
|
16
|
-
- 🎯 支持 @ 提及和引用回复
|
|
17
|
-
- 🔧 **群管理工具**:踢人、禁言、设置管理员、群名片、头衔等(AI 可调用)
|
|
18
|
-
- 🔒 **权限控制**:基于群角色的工具权限过滤
|
|
7
|
+
- 群聊 / 私聊 / 群临时会话 / QQ 频道消息
|
|
8
|
+
- 入站:`messageGatewayToken`(IPC 事件订阅)
|
|
9
|
+
- 出站:`send({ target, payload })` → `send_group_msg` / `send_private_msg` / …
|
|
10
|
+
- Agent 工具:`agent/tools/`(戳一戳、群管、好友列表等)保留
|
|
19
11
|
|
|
20
12
|
## 安装
|
|
21
13
|
|
|
22
14
|
```bash
|
|
23
15
|
pnpm add @zhin.js/adapter-icqq
|
|
16
|
+
pnpm add -g @icqqjs/cli # 或 npx icqq login
|
|
24
17
|
```
|
|
25
18
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
```bash
|
|
29
|
-
pnpm add -g @icqqjs/cli
|
|
30
|
-
# 或:npx icqq login
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
## 配置
|
|
34
|
-
|
|
35
|
-
在 `zhin.config.yml` 中声明 bot(**不在此填写 QQ 密码**):
|
|
19
|
+
## 配置(Plugin Runtime)
|
|
36
20
|
|
|
37
21
|
```yaml
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
name: "${ICQQ_ACCOUNT}" # QQ 号,须与 icqq login
|
|
41
|
-
autoReconnect: true
|
|
42
|
-
#
|
|
43
|
-
# rpc:
|
|
22
|
+
plugins:
|
|
23
|
+
icqq:
|
|
24
|
+
name: "${ICQQ_ACCOUNT}" # QQ 号,须与 icqq login 一致
|
|
25
|
+
autoReconnect: true
|
|
26
|
+
# rpc: # 可选远程守护进程
|
|
44
27
|
# host: 10.0.0.2
|
|
45
28
|
# port: 9527
|
|
46
29
|
# token: ${ICQQ_RPC_TOKEN}
|
|
47
|
-
typingIndicator: # 可选:AI 处理中的群/私聊提示
|
|
48
|
-
enabled: true
|
|
49
|
-
defaultEmoji: "⏳"
|
|
50
|
-
|
|
51
|
-
plugins:
|
|
52
|
-
- "@zhin.js/adapter-icqq"
|
|
53
|
-
- "@zhin.js/host-router" # 可选
|
|
54
|
-
- "@zhin.js/host-api" # 可选,Remote Console /icqq 页
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
TypeScript 配置等价写法:
|
|
58
|
-
|
|
59
|
-
```typescript
|
|
60
|
-
import { defineConfig } from 'zhin.js'
|
|
61
|
-
|
|
62
|
-
export default defineConfig({
|
|
63
|
-
endpoints: [
|
|
64
|
-
{
|
|
65
|
-
context: 'icqq',
|
|
66
|
-
name: process.env.ICQQ_ACCOUNT!,
|
|
67
|
-
},
|
|
68
|
-
],
|
|
69
|
-
plugins: ['@zhin.js/adapter-icqq'],
|
|
70
|
-
})
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
## 配置参数说明
|
|
74
|
-
|
|
75
|
-
### 必需参数
|
|
76
|
-
|
|
77
|
-
- `context`: 固定为 `'icqq'`
|
|
78
|
-
- `name`: QQ 号(字符串,与守护进程账号一致)
|
|
79
|
-
|
|
80
|
-
### 可选参数
|
|
81
|
-
|
|
82
|
-
- `autoReconnect`: IPC/RPC 意外断开时是否指数退避重连(默认 `true`)
|
|
83
|
-
- `rpc`: 远程守护进程连接(`host` / `port` / `token`);不配置则使用本地 Unix socket `~/.icqq/<uin>/daemon.sock`
|
|
84
|
-
- `typingIndicator`: AI 处理中的 reaction 或临时消息提示(见 `IcqqEndpointConfig` 类型)
|
|
85
|
-
|
|
86
|
-
## 使用示例
|
|
87
|
-
|
|
88
|
-
### 基础消息处理
|
|
89
|
-
|
|
90
|
-
```typescript
|
|
91
|
-
import { addCommand, MessageCommand } from 'zhin.js'
|
|
92
|
-
|
|
93
|
-
addCommand(new MessageCommand('hello <name:text>')
|
|
94
|
-
.action(async (message, result) => {
|
|
95
|
-
return `你好,${result.params.name}!`
|
|
96
|
-
})
|
|
97
|
-
)
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
### 群聊消息
|
|
101
|
-
|
|
102
|
-
```typescript
|
|
103
|
-
import { onGroupMessage } from 'zhin.js'
|
|
104
|
-
|
|
105
|
-
onGroupMessage(async (message) => {
|
|
106
|
-
console.log(`群 ${message.$channel.id} 收到消息:${message.$raw}`)
|
|
107
|
-
|
|
108
|
-
// 回复群消息
|
|
109
|
-
await message.$reply('收到消息了!')
|
|
110
|
-
})
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
### 私聊消息
|
|
114
|
-
|
|
115
|
-
```typescript
|
|
116
|
-
import { onPrivateMessage } from 'zhin.js'
|
|
117
|
-
|
|
118
|
-
onPrivateMessage(async (message) => {
|
|
119
|
-
console.log(`私聊消息来自:${message.$sender.name}`)
|
|
120
|
-
await message.$reply('你好!')
|
|
121
|
-
})
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
### 发送图片
|
|
125
|
-
|
|
126
|
-
```typescript
|
|
127
|
-
addCommand(new MessageCommand('pic <url:text>')
|
|
128
|
-
.action(async (message, result) => {
|
|
129
|
-
return [
|
|
130
|
-
{ type: 'image', data: { file: result.params.url } }
|
|
131
|
-
]
|
|
132
|
-
})
|
|
133
|
-
)
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
**Zhin 与 icqq 守护进程不在同一台机器时**,请在 `zhin.config.yml` 为该 bot 设置 `outboundMedia: base64`(或配置 `rpc` 时会自动默认 `base64`)。此时 segment 保留 `base64`,经 CQ `[image:base64://...]` 交给守护进程解码,不要使用仅在本机有效的临时文件路径。
|
|
137
|
-
|
|
138
|
-
Agent **`generate_image` 文生图**出站的大图同样依赖上述配置;同机默认可用本机临时文件路径(`outboundMedia: file`)。详见 [文生图 (generate_image)](https://github.com/zhinjs/zhin/blob/main/docs/advanced/ai.md#文生图-generate_image)。
|
|
139
|
-
|
|
140
|
-
```yaml
|
|
141
|
-
endpoints:
|
|
142
|
-
- context: icqq
|
|
143
|
-
name: "123456"
|
|
144
|
-
outboundMedia: base64 # 异机 / 远程 RPC
|
|
145
|
-
# rpc: { host: ..., port: ..., token: ... } # 配置 rpc 时默认已是 base64
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
### 发送语音
|
|
149
|
-
|
|
150
|
-
```typescript
|
|
151
|
-
addCommand(new MessageCommand('voice <file:text>')
|
|
152
|
-
.action(async (message, result) => {
|
|
153
|
-
return [
|
|
154
|
-
{ type: 'record', data: { file: result.params.file } }
|
|
155
|
-
]
|
|
156
|
-
})
|
|
157
|
-
)
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
### @ 提及
|
|
161
|
-
|
|
162
|
-
```typescript
|
|
163
|
-
addCommand(new MessageCommand('at <user:at>')
|
|
164
|
-
.action(async (message, result) => {
|
|
165
|
-
const atUser = result.params.user
|
|
166
|
-
return [
|
|
167
|
-
{ type: 'at', data: { qq: atUser.data.qq } },
|
|
168
|
-
{ type: 'text', data: { text: ' 你好!' } }
|
|
169
|
-
]
|
|
170
|
-
})
|
|
171
|
-
)
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
## 登录流程
|
|
175
|
-
|
|
176
|
-
1. **先登录 QQ**:在终端执行 `icqq login`,按 CLI 提示完成密码/扫码/滑块/设备锁等验证;会话由 `@icqqjs/cli` 守护进程维护。
|
|
177
|
-
2. **再启动 Zhin**:`zhin.config.yml` 中 `endpoints[].name` 与上一步 QQ 号一致,启动 `zhin dev` / `zhin start`;适配器连接守护进程并开始收发消息。
|
|
178
|
-
3. 若守护进程未运行或账号未登录,适配器会保持未连接状态,日志中会提示检查 `icqq` 守护进程。
|
|
179
|
-
|
|
180
|
-
### Web 控制台登录辅助(可选)
|
|
181
|
-
|
|
182
|
-
与 **`@zhin.js/host-api`** 同时启用时,Remote Console 的 **ICQQ 管理**(`/icqq`)可提供登录辅助 Tab,对应 API:`GET/POST /api/login-assist/*`(依赖核心 `loginAssist` 服务)。
|
|
183
|
-
|
|
184
|
-
守护进程在登录/重连时按 **`@icqqjs/cli` IPC 契约**推送 `IpcEvent`(`id: "*"` + `event: "system.login.*"` + `data`)。其中 **`system.login.auth`** 携带 `url` + `device` 设备指纹(形状见 `@icqqjs/icqq` `EventMap`)。适配器将其桥接到 `LoginAssist` 并在控制台展示;用户完成验证后,续传 invoke 与 CLI `LoginFlow` 一致(`login` / `submit_slider` / `submit_sms_code` / `send_sms_code`,见 `login-ipc-contract.ts`)。
|
|
185
|
-
|
|
186
|
-
## 消息类型支持
|
|
187
|
-
|
|
188
|
-
### 接收消息类型
|
|
189
|
-
|
|
190
|
-
- ✅ 文本消息
|
|
191
|
-
- ✅ 图片消息
|
|
192
|
-
- ✅ 语音消息
|
|
193
|
-
- ✅ 视频消息
|
|
194
|
-
- ✅ @ 提及
|
|
195
|
-
- ✅ 表情消息
|
|
196
|
-
- ✅ 引用回复
|
|
197
|
-
- ✅ 文件消息
|
|
198
|
-
- ✅ JSON 卡片消息
|
|
199
|
-
- ✅ **群临时会话**(`message_type=private` + `sub_type=group`;`$channel` 为 `private` + `parent.group`)
|
|
200
|
-
|
|
201
|
-
### 发送消息类型
|
|
202
|
-
|
|
203
|
-
- ✅ 文本消息
|
|
204
|
-
- ✅ 图片消息(支持本地文件、URL、Base64)
|
|
205
|
-
- ✅ 语音消息
|
|
206
|
-
- ✅ 视频消息
|
|
207
|
-
- ✅ @ 提及
|
|
208
|
-
- ✅ 表情消息
|
|
209
|
-
- ✅ 引用回复
|
|
210
|
-
- ✅ 文件消息
|
|
211
|
-
- ✅ JSON 卡片消息
|
|
212
|
-
- ✅ 戳一戳
|
|
213
|
-
- ✅ 音乐分享
|
|
214
|
-
- ✅ **群临时会话**(`type: private` + `parent: { type: 'group', id }` → IPC `send_temp_msg`)
|
|
215
|
-
|
|
216
|
-
## 群临时会话
|
|
217
|
-
|
|
218
|
-
当群成员通过「临时会话」私聊机器人时,新版 `@icqqjs/cli` 会以私聊事件推送(`sub_type: group`,`sender.group_id` 为来源群)。适配器使用 `private` + `parent.group` 表达场景,而非发明新的顶层 `MessageType`。
|
|
219
|
-
|
|
220
|
-
| 字段 | 值 |
|
|
221
|
-
|------|-----|
|
|
222
|
-
| `$channel.type` | `private`(对端 QQ) |
|
|
223
|
-
| `$channel.parent` | `{ type: 'group', id: 群号 }` |
|
|
224
|
-
|
|
225
|
-
`message.$reply` 会原样带上 `parent`,出站自动走 `send_temp_msg`。
|
|
226
|
-
|
|
227
|
-
```typescript
|
|
228
|
-
await adapter.sendMessage({
|
|
229
|
-
context: 'icqq',
|
|
230
|
-
endpoint: '你的QQ号',
|
|
231
|
-
type: 'private',
|
|
232
|
-
id: '987654321',
|
|
233
|
-
parent: { type: 'group', id: '123456789' },
|
|
234
|
-
content: [{ type: 'text', data: { text: '你好' } }],
|
|
235
|
-
})
|
|
236
30
|
```
|
|
237
31
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
```typescript
|
|
241
|
-
const endpoint = app.adapters.get('icqq')?.endpoints.get('你的QQ号')
|
|
242
|
-
|
|
243
|
-
// 发送群消息
|
|
244
|
-
await endpoint.sendGroupMsg(groupId, '消息内容')
|
|
245
|
-
|
|
246
|
-
// 发送私聊消息
|
|
247
|
-
await endpoint.sendPrivateMsg(userId, '消息内容')
|
|
32
|
+
先执行 `icqq login`,再启动 Zhin。
|
|
248
33
|
|
|
249
|
-
|
|
250
|
-
await endpoint.$recallMessage(messageId)
|
|
34
|
+
## Send target
|
|
251
35
|
|
|
252
|
-
|
|
253
|
-
|
|
36
|
+
| 类型 | target |
|
|
37
|
+
|------|--------|
|
|
38
|
+
| 私聊 | `private:uin` |
|
|
39
|
+
| 群聊 | `group:gid` |
|
|
40
|
+
| 群临时会话 | `temp:gid:uin` |
|
|
41
|
+
| 频道 | `channel:guildId:channelId` |
|
|
254
42
|
|
|
255
|
-
|
|
256
|
-
const friendList = endpoint.getFriendList()
|
|
43
|
+
## 架构
|
|
257
44
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
适配器通过覆写 `ISceneManagement` 标准方法自动注册群管理工具,同时保留平台特有工具,这些工具可以被 AI 调用,实现智能化的群管理。
|
|
265
|
-
|
|
266
|
-
### 标准群管工具(自动生成)
|
|
267
|
-
|
|
268
|
-
通过覆写 `ISceneManagement` 方法,`start()` 时自动检测并生成对应 Tool:
|
|
269
|
-
|
|
270
|
-
| 工具 | 覆写方法 | 所需权限 | 说明 |
|
|
271
|
-
|------|---------|----------|------|
|
|
272
|
-
| `icqq_kick_member` | `kickMember` | 管理员 | 踢出群成员 |
|
|
273
|
-
| `icqq_mute_member` | `muteMember` | 管理员 | 禁言群成员 |
|
|
274
|
-
| `icqq_mute_all` | `muteAll` | 管理员 | 全员禁言 |
|
|
275
|
-
| `icqq_set_admin` | `setAdmin` | 群主 | 设置/取消管理员 |
|
|
276
|
-
| `icqq_set_nickname` | `setMemberNickname` | 管理员 | 设置群名片 |
|
|
277
|
-
| `icqq_set_group_name` | `setGroupName` | 管理员 | 修改群名称 |
|
|
278
|
-
| `icqq_list_members` | `listMembers` | 普通用户 | 获取群成员列表 |
|
|
279
|
-
|
|
280
|
-
### 平台特有工具(手动注册)
|
|
281
|
-
|
|
282
|
-
| 工具 | 所需权限 | 说明 |
|
|
283
|
-
|------|----------|------|
|
|
284
|
-
| `icqq_set_title` | 群主 | 设置专属头衔 |
|
|
285
|
-
| `icqq_announce` | 管理员 | 发送群公告 |
|
|
286
|
-
| `icqq_poke` | 普通用户 | 戳一戳 |
|
|
287
|
-
| `icqq_list_muted` | 普通用户 | 获取被禁言成员列表 |
|
|
288
|
-
| `icqq_send_user_like` | 普通用户 | 发送用户点赞 |
|
|
289
|
-
| `icqq_set_anonymous` | 管理员 | 开启/关闭匿名聊天 |
|
|
290
|
-
| `icqq_group_files` | 普通用户 | 获取群文件列表 |
|
|
291
|
-
| `icqq_friend_list` | 普通用户 | 获取好友列表 |
|
|
292
|
-
|
|
293
|
-
### 使用示例
|
|
294
|
-
|
|
295
|
-
#### 通过 AI 对话管理群
|
|
296
|
-
|
|
297
|
-
```
|
|
298
|
-
用户(群主):把 @小明 踢出群并拉黑
|
|
299
|
-
AI:已将 小明 踢出群并拉黑。
|
|
300
|
-
|
|
301
|
-
用户(管理员):禁言 @捣蛋鬼 1小时
|
|
302
|
-
AI:已禁言 捣蛋鬼 3600 秒。
|
|
303
|
-
|
|
304
|
-
用户(管理员):发个群公告:明天下午3点开会
|
|
305
|
-
AI:群公告已发送。
|
|
306
|
-
|
|
307
|
-
用户:戳一戳 @朋友
|
|
308
|
-
AI:已戳了戳 朋友。
|
|
309
|
-
```
|
|
310
|
-
|
|
311
|
-
#### 编程调用
|
|
312
|
-
|
|
313
|
-
```typescript
|
|
314
|
-
// 获取 ICQQ Endpoint 实例
|
|
315
|
-
const icqqAdapter = app.adapters.get('icqq')
|
|
316
|
-
const endpoint = icqqAdapter?.endpoints.get('你的QQ号')
|
|
317
|
-
|
|
318
|
-
// 踢出成员
|
|
319
|
-
await endpoint.kickMember(groupId, userId, true) // 第三个参数为是否拉黑
|
|
320
|
-
|
|
321
|
-
// 禁言成员(单位:秒)
|
|
322
|
-
await endpoint.muteMember(groupId, userId, 600) // 禁言 10 分钟
|
|
323
|
-
await endpoint.muteMember(groupId, userId, 0) // 解除禁言
|
|
324
|
-
|
|
325
|
-
// 全员禁言
|
|
326
|
-
await endpoint.muteAll(groupId, true) // 开启
|
|
327
|
-
await endpoint.muteAll(groupId, false) // 关闭
|
|
328
|
-
|
|
329
|
-
// 设置管理员
|
|
330
|
-
await endpoint.setAdmin(groupId, userId, true) // 设为管理员
|
|
331
|
-
await endpoint.setAdmin(groupId, userId, false) // 取消管理员
|
|
332
|
-
|
|
333
|
-
// 设置群名片
|
|
334
|
-
await endpoint.setCard(groupId, userId, '新名片')
|
|
335
|
-
|
|
336
|
-
// 设置专属头衔
|
|
337
|
-
await endpoint.setTitle(groupId, userId, '大佬', -1) // -1 表示永久
|
|
338
|
-
|
|
339
|
-
// 修改群名
|
|
340
|
-
await endpoint.setGroupName(groupId, '新群名')
|
|
341
|
-
|
|
342
|
-
// 发送群公告
|
|
343
|
-
await endpoint.sendAnnounce(groupId, '公告内容')
|
|
344
|
-
|
|
345
|
-
// 戳一戳
|
|
346
|
-
await endpoint.pokeMember(groupId, userId)
|
|
347
|
-
|
|
348
|
-
// 获取群成员列表
|
|
349
|
-
const members = await endpoint.getMemberList(groupId)
|
|
350
|
-
|
|
351
|
-
// 获取被禁言成员列表
|
|
352
|
-
const mutedList = await endpoint.getMutedMembers(groupId)
|
|
353
|
-
|
|
354
|
-
// 开启/关闭匿名
|
|
355
|
-
await endpoint.setAnonymous(groupId, true)
|
|
356
|
-
```
|
|
357
|
-
|
|
358
|
-
### 发送者权限信息
|
|
359
|
-
|
|
360
|
-
消息中的 `$sender` 包含 ICQQ 特有的权限信息:
|
|
361
|
-
|
|
362
|
-
```typescript
|
|
363
|
-
interface IcqqSenderInfo {
|
|
364
|
-
id: string; // QQ 号
|
|
365
|
-
name: string; // 昵称
|
|
366
|
-
role?: GroupRole; // 'owner' | 'admin' | 'member'
|
|
367
|
-
isOwner?: boolean; // 是否为群主
|
|
368
|
-
isAdmin?: boolean; // 是否为管理员
|
|
369
|
-
card?: string; // 群名片
|
|
370
|
-
title?: string; // 专属头衔
|
|
371
|
-
}
|
|
372
|
-
```
|
|
373
|
-
|
|
374
|
-
#### 在插件中检查权限
|
|
375
|
-
|
|
376
|
-
```typescript
|
|
377
|
-
onGroupMessage(async (message) => {
|
|
378
|
-
const sender = message.$sender as IcqqSenderInfo;
|
|
379
|
-
|
|
380
|
-
if (sender.isOwner) {
|
|
381
|
-
console.log('这是群主的消息');
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
if (sender.isAdmin) {
|
|
385
|
-
console.log('这是管理员的消息');
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
if (sender.role === 'member') {
|
|
389
|
-
console.log('这是普通成员的消息');
|
|
390
|
-
}
|
|
391
|
-
})
|
|
392
|
-
```
|
|
393
|
-
|
|
394
|
-
## icqq CLI 与 AI bash 安全
|
|
395
|
-
|
|
396
|
-
启用 **icqq 技能**(`skills/icqq`)时,模型通常会通过 **`bash`** 调用 `icqq …` 命令行。此时由框架 **`execSecurity` / `execApprovalMode`** 与 **Owner 私聊指令**(`approve always bash`、`approve rule <正则>` 等)共同约束:在 `allowlist` 下,**非敏感**子命令多数可直接执行;**敏感**子命令(踢人、禁言、解散、支付等)在 `execApprovalMode: ask` 时需 Owner 确认,并可用 **正则匹配整条子命令** 做持久化放行(不必把 QQ 号写进配置)。持久化文件为数据目录下的 `owner-approve-always.json`。
|
|
397
|
-
|
|
398
|
-
完整说明与指令表见仓库文档:[docs/advanced/ai.md](../../../docs/advanced/ai.md)(锚点:`#icqq-bash-exec`、`#owner-approve-commands`)。
|
|
399
|
-
|
|
400
|
-
## 注意事项
|
|
401
|
-
|
|
402
|
-
### 账号安全
|
|
403
|
-
|
|
404
|
-
- 建议使用小号测试
|
|
405
|
-
- 避免短时间内发送大量消息
|
|
406
|
-
- 保持 `@icqqjs/cli` 与适配器版本更新
|
|
407
|
-
|
|
408
|
-
### 风控与掉线
|
|
409
|
-
|
|
410
|
-
- 登录设备类型、签名服务等由 **`icqq login` / CLI 配置** 管理,不在 `zhin.config` 的 bot 段配置
|
|
411
|
-
- 掉线时先检查守护进程:`icqq` 是否仍在运行、账号是否被踢下线
|
|
412
|
-
- 可降低发消息频率,并在手机 QQ 完成安全验证后重新 `icqq login`
|
|
413
|
-
|
|
414
|
-
## 常见问题
|
|
415
|
-
|
|
416
|
-
### Q: 启动后 bot 一直未连接?
|
|
417
|
-
|
|
418
|
-
A:
|
|
419
|
-
1. 确认已对该 QQ 号执行过 `icqq login` 且守护进程在运行
|
|
420
|
-
2. 确认 `endpoints[].name` 与登录 QQ 号一致
|
|
421
|
-
3. 远程部署时检查 `rpc.host` / `rpc.port` / `rpc.token`
|
|
422
|
-
|
|
423
|
-
### Q: 还需要在 zhin.config 里写 password / platform 吗?
|
|
424
|
-
|
|
425
|
-
A: **不需要**。这些字段属于旧版直连协议,当前适配器仅通过 IPC 连接 CLI 守护进程。
|
|
426
|
-
|
|
427
|
-
### Q: 无法发送图片?
|
|
428
|
-
|
|
429
|
-
A:
|
|
430
|
-
1. 检查图片 URL 是否有效
|
|
431
|
-
2. 本地文件需使用绝对路径
|
|
432
|
-
3. 确认图片格式和大小符合要求
|
|
433
|
-
|
|
434
|
-
### Q: 如何处理滑块/设备锁验证?
|
|
435
|
-
|
|
436
|
-
A: 在运行 `icqq login` 的终端按提示操作;若启用了 Host API,也可在 Remote Console `/icqq` 登录辅助 Tab 提交验证码。
|
|
437
|
-
|
|
438
|
-
## 相关链接
|
|
439
|
-
|
|
440
|
-
- [@icqqjs/cli](https://github.com/icqqjs/cli)
|
|
441
|
-
- [ICQQ 协议库](https://github.com/icqqjs/icqq)
|
|
442
|
-
- [Zhin.js 官方文档](https://github.com/zhinjs/zhin)
|
|
443
|
-
- [签名服务器](https://github.com/fuqiuluo/unidbg-fetch-qsign)
|
|
444
|
-
|
|
445
|
-
## 依赖项
|
|
446
|
-
|
|
447
|
-
- `@icqqjs/cli` - 登录与守护进程(运行时需已安装并在 PATH 中)
|
|
448
|
-
- `zhin.js` / `@zhin.js/core` - Zhin 框架(peer)
|
|
449
|
-
- `@zhin.js/host-router` / `@zhin.js/host-api` - 可选,Console 与 HTTP 路由
|
|
450
|
-
|
|
451
|
-
## 开发
|
|
452
|
-
|
|
453
|
-
```bash
|
|
454
|
-
pnpm build # 构建
|
|
455
|
-
pnpm clean # 清理构建文件
|
|
456
|
-
```
|
|
45
|
+
- `plugin.ts` + `adapters/icqq.ts`(`defineAdapter`)
|
|
46
|
+
- 协议常量 / 配置:`src/protocol.ts`
|
|
47
|
+
- IPC 客户端:`src/ipc-client.ts`(无 host-http)
|
|
48
|
+
- Console loginAssist / host-router 延期
|
|
49
|
+
- 旧 `usePlugin` / `extends Adapter` / Endpoint 生产入口已删除
|
|
457
50
|
|
|
458
|
-
##
|
|
51
|
+
## Plugin Runtime 迁移说明
|
|
459
52
|
|
|
460
|
-
|
|
53
|
+
- `autoReconnect` 已恢复实现:IPC/RPC 意外断开后按指数退避自动重连(`stop()` 为主动断开,不触发重连)。
|
|
54
|
+
- `outboundMedia: file | base64` 已恢复实现:`file` 模式把 segment base64 落盘为临时文件后发 `[image:path]`;`base64` 模式(配置 `rpc` 时默认)发 `[image:base64://...]` 由守护进程解码。
|
|
55
|
+
- **notice / request 入站事件已移除**:Plugin Runtime 的 `MessageGateway` 仅有 message 通道,没有 `notice.receive` / `request.receive` 事件机制,旧 `icqq-side-events.ts` / `get-msg.ts` / `login-ipc-contract.ts` / `agent-prompt.ts` 随之删除。需要好友/入群请求处理能力时请等待 runtime 提供事件通道后再恢复。
|
|
461
56
|
|
|
462
|
-
##
|
|
57
|
+
## License
|
|
463
58
|
|
|
464
|
-
|
|
59
|
+
MIT
|
package/adapters/icqq.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convention entry: discover `adapters/icqq.ts` → defineAdapter.
|
|
3
|
+
*/
|
|
4
|
+
import { defineAdapter } from '@zhin.js/adapter';
|
|
5
|
+
import { messageGatewayToken } from '@zhin.js/core/runtime';
|
|
6
|
+
import { IcqqIpcEndpoint } from '../src/endpoint.js';
|
|
7
|
+
import {
|
|
8
|
+
resolveIcqqConfig,
|
|
9
|
+
type IcqqAdapterConfig,
|
|
10
|
+
} from '../src/protocol.js';
|
|
11
|
+
|
|
12
|
+
export { IcqqIpcEndpoint } from '../src/endpoint.js';
|
|
13
|
+
export type {
|
|
14
|
+
CreateIcqqIpc,
|
|
15
|
+
IcqqEndpointOptions,
|
|
16
|
+
IcqqIpcTransport,
|
|
17
|
+
} from '../src/endpoint.js';
|
|
18
|
+
|
|
19
|
+
export default defineAdapter<IcqqAdapterConfig>({
|
|
20
|
+
capabilities: ['inbound', 'outbound'],
|
|
21
|
+
create(context) {
|
|
22
|
+
// Client-library / IPC daemon path — no httpHostToken.
|
|
23
|
+
// Console loginAssist + host-router routes deferred.
|
|
24
|
+
return new IcqqIpcEndpoint({
|
|
25
|
+
id: context.id,
|
|
26
|
+
gateway: context.use(messageGatewayToken),
|
|
27
|
+
config: resolveIcqqConfig(context.config),
|
|
28
|
+
});
|
|
29
|
+
},
|
|
30
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { defineAgentTool } from '@zhin.js/agent/tools';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { getIcqqAgentDeps } from '../../src/icqq-agent-deps.js';
|
|
4
|
+
export default defineAgentTool<{ endpoint_id: string; group_id: number; content: string }>({
|
|
5
|
+
description: '发送 QQ 群公告(需要管理员权限)',
|
|
6
|
+
inputSchema: z.object({
|
|
7
|
+
endpoint_id: z.string().describe('Endpoint QQ号'),
|
|
8
|
+
group_id: z.number().describe('目标群号'),
|
|
9
|
+
content: z.string().describe('公告内容'),
|
|
10
|
+
}),
|
|
11
|
+
platforms: ['icqq'],
|
|
12
|
+
tags: ['icqq'],
|
|
13
|
+
permissions: ['platform(icqq,scene_admin)'],
|
|
14
|
+
async execute({ endpoint_id, group_id, content }: { endpoint_id: string; group_id: number; content: string }) {
|
|
15
|
+
const { Actions } = await import('../../src/protocol.js');
|
|
16
|
+
const endpoint = getIcqqAgentDeps().getEndpoint(endpoint_id);
|
|
17
|
+
const resp = await endpoint.ipc.request(Actions.GROUP_ANNOUNCE, { group_id, content });
|
|
18
|
+
return { success: resp.ok, message: resp.ok ? '群公告已发送' : (resp.error ?? '发送失败') };
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { defineAgentTool } from '@zhin.js/agent/tools';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { getIcqqAgentDeps } from '../../src/icqq-agent-deps.js';
|
|
4
|
+
export default defineAgentTool<{ endpoint_id: string; message_id: string; action: 'add' | 'remove' }>({
|
|
5
|
+
description: '设置或移除 QQ 群精华消息',
|
|
6
|
+
inputSchema: z.object({
|
|
7
|
+
endpoint_id: z.string().describe('Endpoint QQ号'),
|
|
8
|
+
message_id: z.string().describe('消息 ID'),
|
|
9
|
+
action: z.enum(['add', 'remove']).describe('add=设为精华, remove=移除精华'),
|
|
10
|
+
}),
|
|
11
|
+
platforms: ['icqq'],
|
|
12
|
+
tags: ['icqq'],
|
|
13
|
+
permissions: ['platform(icqq,scene_admin)'],
|
|
14
|
+
async execute({ endpoint_id, message_id, action }: { endpoint_id: string; message_id: string; action: 'add' | 'remove' }) {
|
|
15
|
+
const { Actions } = await import('../../src/protocol.js');
|
|
16
|
+
const endpoint = getIcqqAgentDeps().getEndpoint(endpoint_id);
|
|
17
|
+
const act = action === 'add' ? Actions.GROUP_ESSENCE_ADD : Actions.GROUP_ESSENCE_REMOVE;
|
|
18
|
+
const resp = await endpoint.ipc.request(act, { message_id });
|
|
19
|
+
return { success: resp.ok, message: resp.ok ? (action === 'add' ? '已设为精华' : '已移除精华') : (resp.error ?? '操作失败') };
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { defineAgentTool } from '@zhin.js/agent/tools';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { getIcqqAgentDeps } from '../../src/icqq-agent-deps.js';
|
|
4
|
+
export default defineAgentTool<{ endpoint_id: string }>({
|
|
5
|
+
description: '获取 QQ 好友列表',
|
|
6
|
+
inputSchema: z.object({
|
|
7
|
+
endpoint_id: z.string().describe('Endpoint 名称'),
|
|
8
|
+
}),
|
|
9
|
+
platforms: ['icqq'],
|
|
10
|
+
tags: ['icqq'],
|
|
11
|
+
async execute({ endpoint_id }: { endpoint_id: string }) {
|
|
12
|
+
const endpoint = getIcqqAgentDeps().getEndpoint(endpoint_id);
|
|
13
|
+
const friends = Array.from(endpoint.friends.values()).map((f) => ({
|
|
14
|
+
user_id: f.user_id, nickname: f.nickname, remark: f.remark,
|
|
15
|
+
}));
|
|
16
|
+
return { friends: friends.slice(0, 50), count: endpoint.friends.size };
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
|