@zhin.js/adapter-icqq 1.0.71 → 1.1.2
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 +1216 -52
- package/PERMITS.md +24 -0
- package/README.md +123 -429
- package/adapters/icqq/index.js +31 -0
- package/adapters/icqq/index.ts +42 -0
- package/agents/icqq/agent.json +20 -0
- package/agents/icqq/boundaries.md +3 -0
- package/agents/icqq/conventions.md +3 -0
- package/agents/icqq/skills/icqq-directory/SKILL.md +20 -0
- package/agents/icqq/skills/icqq-directory/tools/friend_list/index.js +19 -0
- package/agents/icqq/skills/icqq-directory/tools/friend_list/index.ts +19 -0
- package/agents/icqq/skills/icqq-directory/tools/group_list/index.js +20 -0
- package/agents/icqq/skills/icqq-directory/tools/group_list/index.ts +20 -0
- package/agents/icqq/skills/icqq-directory/tools/group_member_info/index.js +26 -0
- package/agents/icqq/skills/icqq-directory/tools/group_member_info/index.ts +28 -0
- package/agents/icqq/skills/icqq-directory/tools/user_info/index.js +15 -0
- package/agents/icqq/skills/icqq-directory/tools/user_info/index.ts +14 -0
- package/agents/icqq/skills/icqq-group-admin/SKILL.md +25 -0
- package/agents/icqq/skills/icqq-group-admin/tools/announce/index.js +18 -0
- package/agents/icqq/skills/icqq-group-admin/tools/announce/index.ts +17 -0
- package/agents/icqq/skills/icqq-group-admin/tools/essence/index.js +24 -0
- package/agents/icqq/skills/icqq-group-admin/tools/essence/index.ts +22 -0
- package/agents/icqq/skills/icqq-group-admin/tools/group_invite/index.js +23 -0
- package/agents/icqq/skills/icqq-group-admin/tools/group_invite/index.ts +20 -0
- package/agents/icqq/skills/icqq-group-admin/tools/group_kick/index.js +27 -0
- package/agents/icqq/skills/icqq-group-admin/tools/group_kick/index.ts +23 -0
- package/agents/icqq/skills/icqq-group-admin/tools/set_anonymous/index.js +23 -0
- package/agents/icqq/skills/icqq-group-admin/tools/set_anonymous/index.ts +21 -0
- package/agents/icqq/skills/icqq-group-admin/tools/set_mute/index.js +25 -0
- package/agents/icqq/skills/icqq-group-admin/tools/set_mute/index.ts +22 -0
- package/agents/icqq/skills/icqq-group-admin/tools/set_title/index.js +26 -0
- package/agents/icqq/skills/icqq-group-admin/tools/set_title/index.ts +23 -0
- package/agents/icqq/skills/icqq-group-state/SKILL.md +17 -0
- package/agents/icqq/skills/icqq-group-state/tools/group_files/index.js +24 -0
- package/agents/icqq/skills/icqq-group-state/tools/group_files/index.ts +22 -0
- package/agents/icqq/skills/icqq-group-state/tools/list_muted/index.js +18 -0
- package/agents/icqq/skills/icqq-group-state/tools/list_muted/index.ts +17 -0
- package/agents/icqq/skills/icqq-interaction/SKILL.md +19 -0
- package/agents/icqq/skills/icqq-interaction/tools/group_sign/index.js +20 -0
- package/agents/icqq/skills/icqq-interaction/tools/group_sign/index.ts +18 -0
- package/agents/icqq/skills/icqq-interaction/tools/poke/index.js +17 -0
- package/agents/icqq/skills/icqq-interaction/tools/poke/index.ts +16 -0
- package/agents/icqq/skills/icqq-interaction/tools/send_user_like/index.js +26 -0
- package/agents/icqq/skills/icqq-interaction/tools/send_user_like/index.ts +22 -0
- package/agents/icqq/system.md +3 -0
- package/commands/icqq/endpoint/add/[[id]]/index.js +3 -0
- package/commands/icqq/endpoint/add/[[id]]/index.ts +3 -0
- package/commands/icqq/endpoint/definition.js +31 -0
- package/commands/icqq/endpoint/definition.ts +32 -0
- package/commands/icqq/endpoint/list/index.js +3 -0
- package/commands/icqq/endpoint/list/index.ts +3 -0
- package/commands/icqq/endpoint/remove/[id]/index.js +3 -0
- package/commands/icqq/endpoint/remove/[id]/index.ts +3 -0
- package/lib/client.d.ts +19 -0
- package/lib/client.js +3 -0
- package/lib/content-resolver.d.ts +10 -0
- package/lib/content-resolver.js +98 -0
- package/lib/cq-message.d.ts +14 -0
- package/lib/cq-message.js +106 -0
- package/lib/endpoint.d.ts +30 -0
- package/lib/endpoint.js +1003 -0
- package/lib/forward-msg.d.ts +6 -0
- package/lib/forward-msg.js +107 -0
- package/lib/icqq-guild.d.ts +57 -0
- package/lib/icqq-guild.js +109 -0
- package/lib/icqq-inbound.d.ts +165 -0
- package/lib/icqq-inbound.js +651 -0
- package/lib/icqq-inbox.d.ts +25 -0
- package/lib/icqq-inbox.js +129 -0
- package/lib/icqq-login-assist.d.ts +27 -0
- package/lib/icqq-login-assist.js +109 -0
- package/lib/icqq-runtime-state.d.ts +1 -0
- package/lib/icqq-runtime-state.js +6 -0
- package/lib/index.d.ts +5 -18
- package/lib/index.js +5 -124
- package/lib/outbound-media.d.ts +14 -0
- package/lib/outbound-media.js +76 -0
- package/lib/protocol.d.ts +258 -0
- package/lib/protocol.js +422 -0
- package/lib/types.d.ts +33 -13
- package/lib/types.js +0 -1
- package/package.json +86 -32
- package/plugin.js +19 -0
- package/prompt-sections/platform/index.js +16 -0
- package/prompt-sections/platform/index.ts +16 -0
- package/schema.json +168 -0
- package/src/client.ts +29 -0
- package/src/content-resolver.ts +131 -0
- package/src/cq-message.ts +113 -0
- package/src/endpoint.ts +1084 -0
- package/src/forward-msg.ts +112 -0
- package/src/icqq-guild.ts +154 -0
- package/src/icqq-inbound.ts +814 -0
- package/src/icqq-inbox.ts +147 -0
- package/src/icqq-login-assist.ts +132 -0
- package/src/icqq-runtime-state.ts +7 -0
- package/src/index.ts +30 -149
- package/src/outbound-media.ts +103 -0
- package/src/protocol.ts +551 -0
- package/src/types.ts +35 -13
- package/LICENSE +0 -21
- package/client/ICQQManagement.tsx +0 -139
- package/client/LoginAssistPanel.tsx +0 -293
- package/client/index.tsx +0 -11
- package/client/tsconfig.json +0 -7
- package/client/utils/api.ts +0 -20
- package/dist/index.js +0 -1
- package/lib/adapter.d.ts +0 -34
- package/lib/adapter.d.ts.map +0 -1
- package/lib/adapter.js +0 -396
- package/lib/adapter.js.map +0 -1
- package/lib/bot.d.ts +0 -46
- package/lib/bot.d.ts.map +0 -1
- package/lib/bot.js +0 -457
- package/lib/bot.js.map +0 -1
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/types.d.ts.map +0 -1
- package/lib/types.js.map +0 -1
- package/skills/icqq/SKILL.md +0 -22
- package/src/adapter.ts +0 -448
- package/src/bot.ts +0 -521
package/PERMITS.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# ICQQ Platform Permits(QQ 群)
|
|
2
|
+
|
|
3
|
+
## 入站字段
|
|
4
|
+
|
|
5
|
+
群成员 `owner` / `admin` / `member` 写入 `$sender.role`(IPC 侧已有)。
|
|
6
|
+
|
|
7
|
+
## Permit 词汇表
|
|
8
|
+
|
|
9
|
+
平台范围用工具的 `platforms: ['icqq']`,不要写非法的 `platform(icqq)`(缺 perm 时 PermissionHost 会直接拒绝,工具对模型不可见)。
|
|
10
|
+
|
|
11
|
+
| `platform(icqq,…)` | 含义 |
|
|
12
|
+
|--------------------|------|
|
|
13
|
+
| `scene_owner` | 群主 |
|
|
14
|
+
| `scene_admin` | 群管理员(含群主) |
|
|
15
|
+
|
|
16
|
+
## 扩展工具示例
|
|
17
|
+
|
|
18
|
+
| 工具 | permit |
|
|
19
|
+
|------|--------|
|
|
20
|
+
| `icqq_set_title` | `scene_owner` |
|
|
21
|
+
| `icqq_announce` / `icqq_essence` / `icqq_list_muted` | `scene_admin` |
|
|
22
|
+
| `icqq_set_anonymous` | `scene_owner` |
|
|
23
|
+
|
|
24
|
+
工厂群管工具使用默认 `scene_admin` / `scene_owner`。
|
package/README.md
CHANGED
|
@@ -1,483 +1,177 @@
|
|
|
1
1
|
# @zhin.js/adapter-icqq
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
ICQQ Plugin Runtime 适配器 — 进程内直接使用 [@icqqjs/icqq](https://github.com/icqqjs/icqq) `Client`
|
|
4
4
|
|
|
5
5
|
## 功能特性
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
- 🖼️ 支持图片、语音、视频等多媒体消息
|
|
14
|
-
- 🎯 支持 @ 提及和引用回复
|
|
15
|
-
- 🔧 **群管理工具**:踢人、禁言、设置管理员、群名片、头衔等(AI 可调用)
|
|
16
|
-
- 🔒 **权限控制**:基于群角色的工具权限过滤
|
|
7
|
+
- 群聊 / 私聊 / 群临时会话 / QQ 频道消息
|
|
8
|
+
- 入站:ICQQ Client 原始事件经 `Endpoint.emit(...)` 唯一入口上送;文本与图片 / 语音 / 视频 / 文件统一归一为 canonical `Segment` + `MediaRef`
|
|
9
|
+
- 出站:canonical Segment 直接投影为 ICQQ 原生 `Sendable`,再由 `sendGroupMsg` / `sendPrivateMsg` / …发送
|
|
10
|
+
- 群聊 reaction:`control.addReaction` / `removeReaction`(协议 ACK 失败不阻塞后续发送)
|
|
11
|
+
- Agent 工具:按职责拆分在 `agents/icqq/skills/icqq-*/tools/`,只在对应 Skill 激活后披露
|
|
12
|
+
- Console Endpoint 管理:`src/endpoint.ts` 显式实现 `EndpointManagement`(好友/群/群成员列表、请求审批、删好友、踢人、禁言、设管理)
|
|
17
13
|
|
|
18
14
|
## 安装
|
|
19
15
|
|
|
20
16
|
```bash
|
|
21
17
|
pnpm add @zhin.js/adapter-icqq @icqqjs/icqq
|
|
18
|
+
# 可选:未配置 signApiAddr 时走本地签名
|
|
19
|
+
pnpm add @icqqjs/qqsign
|
|
22
20
|
```
|
|
23
21
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
### 密码登录
|
|
27
|
-
|
|
28
|
-
```typescript
|
|
29
|
-
// zhin.config.ts
|
|
30
|
-
import { defineConfig } from 'zhin.js'
|
|
31
|
-
|
|
32
|
-
export default defineConfig({
|
|
33
|
-
bots: [
|
|
34
|
-
{
|
|
35
|
-
context: 'icqq',
|
|
36
|
-
name: process.env.ICQQ_LOGIN_UIN, // QQ 号(必需)
|
|
37
|
-
password: process.env.ICQQ_PASSWORD, // QQ 密码
|
|
38
|
-
platform: 2, // 登录设备平台
|
|
39
|
-
log_level: 'info', // 日志级别
|
|
40
|
-
data_dir: './data', // 数据目录
|
|
41
|
-
sign_api_addr: process.env.SIGN_API // 签名 API 地址(可选)
|
|
42
|
-
}
|
|
43
|
-
],
|
|
44
|
-
plugins: [
|
|
45
|
-
'adapter-icqq'
|
|
46
|
-
]
|
|
47
|
-
})
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
### 扫码登录
|
|
51
|
-
|
|
52
|
-
```typescript
|
|
53
|
-
export default defineConfig({
|
|
54
|
-
bots: [
|
|
55
|
-
{
|
|
56
|
-
context: 'icqq',
|
|
57
|
-
name: process.env.ICQQ_LOGIN_UIN, // QQ 号
|
|
58
|
-
password: '', // 留空使用扫码登录
|
|
59
|
-
platform: 2,
|
|
60
|
-
log_level: 'info',
|
|
61
|
-
data_dir: './data'
|
|
62
|
-
}
|
|
63
|
-
],
|
|
64
|
-
plugins: ['adapter-icqq']
|
|
65
|
-
})
|
|
66
|
-
```
|
|
22
|
+
`@icqqjs/icqq` 是适配器的**可选对等依赖**(`peerDependencies` + `optional`)。应用侧需自行安装;monorepo 内另在 `devDependencies` 声明以便构建/测试。
|
|
67
23
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
### 必需参数
|
|
71
|
-
|
|
72
|
-
- `context`: 固定为 `'icqq'`
|
|
73
|
-
- `name`: QQ 账号(字符串格式)
|
|
74
|
-
|
|
75
|
-
### 可选参数
|
|
76
|
-
|
|
77
|
-
- `password`: QQ 密码(留空则使用扫码登录)
|
|
78
|
-
- `platform`: 登录平台类型
|
|
79
|
-
- `1`: Android Phone(安卓手机)
|
|
80
|
-
- `2`: Android Watch(安卓手表,推荐)
|
|
81
|
-
- `3`: MacOS
|
|
82
|
-
- `4`: 企点
|
|
83
|
-
- `5`: iPad
|
|
84
|
-
- `log_level`: 日志级别
|
|
85
|
-
- `'off'`: 关闭
|
|
86
|
-
- `'fatal'`: 致命错误
|
|
87
|
-
- `'error'`: 错误
|
|
88
|
-
- `'warn'`: 警告
|
|
89
|
-
- `'info'`: 信息
|
|
90
|
-
- `'debug'`: 调试
|
|
91
|
-
- `'trace'`: 追踪
|
|
92
|
-
- `data_dir`: 数据存储目录(默认:`./data`)
|
|
93
|
-
- `sign_api_addr`: 签名服务器地址(可选,用于提高稳定性)
|
|
94
|
-
|
|
95
|
-
## 使用示例
|
|
96
|
-
|
|
97
|
-
### 基础消息处理
|
|
98
|
-
|
|
99
|
-
```typescript
|
|
100
|
-
import { addCommand, MessageCommand } from 'zhin.js'
|
|
101
|
-
|
|
102
|
-
addCommand(new MessageCommand('hello <name:text>')
|
|
103
|
-
.action(async (message, result) => {
|
|
104
|
-
return `你好,${result.params.name}!`
|
|
105
|
-
})
|
|
106
|
-
)
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
### 群聊消息
|
|
110
|
-
|
|
111
|
-
```typescript
|
|
112
|
-
import { onGroupMessage } from 'zhin.js'
|
|
24
|
+
`@icqqjs/*` 发布在 GitHub Packages,需:
|
|
113
25
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
// 回复群消息
|
|
118
|
-
await message.$reply('收到消息了!')
|
|
119
|
-
})
|
|
26
|
+
```ini
|
|
27
|
+
@icqqjs:registry=https://npm.pkg.github.com
|
|
28
|
+
//npm.pkg.github.com/:_authToken=${NPM_TOKEN}
|
|
120
29
|
```
|
|
121
30
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
```typescript
|
|
125
|
-
import { onPrivateMessage } from 'zhin.js'
|
|
31
|
+
并设置具有 `read:packages` 权限的 `NPM_TOKEN`(CI 使用仓库 secret `PERSONAL_TOKEN`)。
|
|
126
32
|
|
|
127
|
-
|
|
128
|
-
console.log(`私聊消息来自:${message.$sender.name}`)
|
|
129
|
-
await message.$reply('你好!')
|
|
130
|
-
})
|
|
131
|
-
```
|
|
33
|
+
签名:未配置 `signApiAddr` 时,若已安装 `@icqqjs/qqsign` 则自动走本地签名。
|
|
132
34
|
|
|
133
|
-
|
|
35
|
+
## 前置条件
|
|
134
36
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
return [
|
|
139
|
-
{ type: 'image', data: { file: result.params.url } }
|
|
140
|
-
]
|
|
141
|
-
})
|
|
142
|
-
)
|
|
143
|
-
```
|
|
37
|
+
1. 准备可登录的 QQ 账号,并选择远程 `signApiAddr` 或安装本地 `@icqqjs/qqsign`。
|
|
38
|
+
2. 确保运行目录可持久化设备与登录状态;容器部署应挂载对应数据目录。
|
|
39
|
+
3. 首次登录可能要求二维码、滑块或设备确认,可在 Console 登录待办或终端完成。
|
|
144
40
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
```typescript
|
|
148
|
-
addCommand(new MessageCommand('voice <file:text>')
|
|
149
|
-
.action(async (message, result) => {
|
|
150
|
-
return [
|
|
151
|
-
{ type: 'record', data: { file: result.params.file } }
|
|
152
|
-
]
|
|
153
|
-
})
|
|
154
|
-
)
|
|
155
|
-
```
|
|
41
|
+
## 配置(Plugin Runtime)
|
|
156
42
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
{ type: 'text', data: { text: ' 你好!' } }
|
|
166
|
-
]
|
|
167
|
-
})
|
|
168
|
-
)
|
|
43
|
+
```yaml
|
|
44
|
+
plugins:
|
|
45
|
+
icqq:
|
|
46
|
+
master: "1659488338" # 必填,顶层共享(/approve 与 master 角色)
|
|
47
|
+
autoReconnect: true
|
|
48
|
+
endpoints:
|
|
49
|
+
- id: "${ICQQ_ACCOUNT}" # QQ 号
|
|
50
|
+
# password: "${ICQQ_PASSWORD}" # 可选;不填则扫码登录
|
|
169
51
|
```
|
|
170
52
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
1. 配置中同时启用 **`@zhin.js/console`** 与本适配器(且 console 建议 **`lazyLoad: false`**,以便扩展 `addEntry` 正常注册)。
|
|
174
|
-
2. 打开控制台中的 **ICQQ 管理**(`/icqq`),切换到 **登录辅助** Tab;仅展示当前 **icqq** 适配器相关的待处理登录步骤。
|
|
175
|
-
3. 若未启用 console,仅启动机器人进程时,仍可通过日志完成登录;**不提供** Console 专属的 `/api/login-assist` 降级路径。
|
|
176
|
-
|
|
177
|
-
## 登录流程
|
|
178
|
-
|
|
179
|
-
### 密码登录
|
|
180
|
-
|
|
181
|
-
1. 配置 QQ 号和密码
|
|
182
|
-
2. 启动机器人
|
|
183
|
-
3. 如需验证,根据提示输入验证码或完成滑块验证
|
|
184
|
-
4. 登录成功后会保存登录状态
|
|
185
|
-
|
|
186
|
-
### 扫码登录
|
|
53
|
+
多账号:一个插件实例挂多个 endpoint(`endpoints` 数组逐项覆盖顶层字段,`id` 必填):
|
|
187
54
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
如遇设备锁:
|
|
197
|
-
1. 选择短信验证或扫码验证
|
|
198
|
-
2. 短信验证:输入收到的验证码
|
|
199
|
-
3. 扫码验证:扫描二维码并在手机确认
|
|
200
|
-
|
|
201
|
-
## 消息类型支持
|
|
202
|
-
|
|
203
|
-
### 接收消息类型
|
|
204
|
-
|
|
205
|
-
- ✅ 文本消息
|
|
206
|
-
- ✅ 图片消息
|
|
207
|
-
- ✅ 语音消息
|
|
208
|
-
- ✅ 视频消息
|
|
209
|
-
- ✅ @ 提及
|
|
210
|
-
- ✅ 表情消息
|
|
211
|
-
- ✅ 引用回复
|
|
212
|
-
- ✅ 文件消息
|
|
213
|
-
- ✅ JSON 卡片消息
|
|
214
|
-
|
|
215
|
-
### 发送消息类型
|
|
216
|
-
|
|
217
|
-
- ✅ 文本消息
|
|
218
|
-
- ✅ 图片消息(支持本地文件、URL、Base64)
|
|
219
|
-
- ✅ 语音消息
|
|
220
|
-
- ✅ 视频消息
|
|
221
|
-
- ✅ @ 提及
|
|
222
|
-
- ✅ 表情消息
|
|
223
|
-
- ✅ 引用回复
|
|
224
|
-
- ✅ 文件消息
|
|
225
|
-
- ✅ JSON 卡片消息
|
|
226
|
-
- ✅ 戳一戳
|
|
227
|
-
- ✅ 音乐分享
|
|
228
|
-
|
|
229
|
-
## API 方法
|
|
230
|
-
|
|
231
|
-
```typescript
|
|
232
|
-
const bot = app.adapters.get('icqq')?.bots.get('你的QQ号')
|
|
233
|
-
|
|
234
|
-
// 发送群消息
|
|
235
|
-
await bot.sendGroupMsg(groupId, '消息内容')
|
|
236
|
-
|
|
237
|
-
// 发送私聊消息
|
|
238
|
-
await bot.sendPrivateMsg(userId, '消息内容')
|
|
239
|
-
|
|
240
|
-
// 撤回消息
|
|
241
|
-
await bot.$recallMessage(messageId)
|
|
242
|
-
|
|
243
|
-
// 获取群列表
|
|
244
|
-
const groupList = bot.getGroupList()
|
|
245
|
-
|
|
246
|
-
// 获取好友列表
|
|
247
|
-
const friendList = bot.getFriendList()
|
|
248
|
-
|
|
249
|
-
// 获取群成员信息
|
|
250
|
-
const memberInfo = bot.getGroupMemberInfo(groupId, userId)
|
|
55
|
+
```yaml
|
|
56
|
+
plugins:
|
|
57
|
+
icqq:
|
|
58
|
+
master: "1659488338"
|
|
59
|
+
endpoints:
|
|
60
|
+
- id: "${ICQQ_ACCOUNT}"
|
|
61
|
+
- id: "${ICQQ_ACCOUNT_2}"
|
|
62
|
+
- id: "${ICQQ_ACCOUNT_3}"
|
|
251
63
|
```
|
|
252
64
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
### 标准群管工具(自动生成)
|
|
258
|
-
|
|
259
|
-
通过覆写 `IGroupManagement` 方法,`start()` 时自动检测并生成对应 Tool:
|
|
260
|
-
|
|
261
|
-
| 工具 | 覆写方法 | 所需权限 | 说明 |
|
|
262
|
-
|------|---------|----------|------|
|
|
263
|
-
| `icqq_kick_member` | `kickMember` | 管理员 | 踢出群成员 |
|
|
264
|
-
| `icqq_mute_member` | `muteMember` | 管理员 | 禁言群成员 |
|
|
265
|
-
| `icqq_mute_all` | `muteAll` | 管理员 | 全员禁言 |
|
|
266
|
-
| `icqq_set_admin` | `setAdmin` | 群主 | 设置/取消管理员 |
|
|
267
|
-
| `icqq_set_nickname` | `setMemberNickname` | 管理员 | 设置群名片 |
|
|
268
|
-
| `icqq_set_group_name` | `setGroupName` | 管理员 | 修改群名称 |
|
|
269
|
-
| `icqq_list_members` | `listMembers` | 普通用户 | 获取群成员列表 |
|
|
270
|
-
|
|
271
|
-
### 平台特有工具(手动注册)
|
|
65
|
+
`AdapterIndex` 会先合并插件实例默认值与 endpoint 覆盖值,再把一份完整配置交给
|
|
66
|
+
ICQQ adapter。协议层只接受这份展开后的 endpoint 配置,不读取环境变量,也不再次解析
|
|
67
|
+
嵌套的 `endpoints`。环境变量替换由 composition root 在配置加载阶段完成。
|
|
272
68
|
|
|
273
|
-
|
|
274
|
-
|------|----------|------|
|
|
275
|
-
| `icqq_set_title` | 群主 | 设置专属头衔 |
|
|
276
|
-
| `icqq_announce` | 管理员 | 发送群公告 |
|
|
277
|
-
| `icqq_poke` | 普通用户 | 戳一戳 |
|
|
278
|
-
| `icqq_list_muted` | 普通用户 | 获取被禁言成员列表 |
|
|
279
|
-
| `icqq_send_user_like` | 普通用户 | 发送用户点赞 |
|
|
280
|
-
| `icqq_set_anonymous` | 管理员 | 开启/关闭匿名聊天 |
|
|
281
|
-
| `icqq_group_files` | 普通用户 | 获取群文件列表 |
|
|
282
|
-
| `icqq_friend_list` | 普通用户 | 获取好友列表 |
|
|
69
|
+
## Send conversation
|
|
283
70
|
|
|
284
|
-
|
|
71
|
+
| 类型 | conversation |
|
|
72
|
+
|------|--------------|
|
|
73
|
+
| 私聊 | `{ kind: 'private', id: uin }` |
|
|
74
|
+
| 群聊 | `{ kind: 'group', id: gid }` |
|
|
75
|
+
| 群临时会话 | `{ kind: 'private', id: uin, parent: { kind: 'group', id: gid } }` |
|
|
76
|
+
| 频道 | `{ kind: 'channel', id: channelId, parent: { kind: 'channel', id: guildId } }` |
|
|
285
77
|
|
|
286
|
-
|
|
78
|
+
## 直接使用完整 ICQQ Client
|
|
287
79
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
AI:已将 小明 踢出群并拉黑。
|
|
291
|
-
|
|
292
|
-
用户(管理员):禁言 @捣蛋鬼 1小时
|
|
293
|
-
AI:已禁言 捣蛋鬼 3600 秒。
|
|
80
|
+
适配器把 `icqq` 注册为 `@icqqjs/icqq.Client` 与 SDK `EventMap` 的类型判别项。
|
|
81
|
+
所有 Feature 都使用同一个 `adapter` 字段完成类型缩窄与运行时过滤:
|
|
294
82
|
|
|
295
|
-
|
|
296
|
-
|
|
83
|
+
```ts
|
|
84
|
+
import { defineHandler } from 'zhin.js/handler'
|
|
85
|
+
import '@zhin.js/adapter-icqq'
|
|
297
86
|
|
|
298
|
-
|
|
299
|
-
|
|
87
|
+
export default defineHandler({
|
|
88
|
+
adapter: 'icqq',
|
|
89
|
+
event: 'request.group.add',
|
|
90
|
+
async handle({ client, event }) {
|
|
91
|
+
await client.setGroupAddRequest(event.flag, true)
|
|
92
|
+
},
|
|
93
|
+
})
|
|
300
94
|
```
|
|
301
95
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
// 获取 ICQQ Bot 实例
|
|
306
|
-
const icqqAdapter = app.adapters.get('icqq')
|
|
307
|
-
const bot = icqqAdapter?.bots.get('你的QQ号')
|
|
308
|
-
|
|
309
|
-
// 踢出成员
|
|
310
|
-
await bot.kickMember(groupId, userId, true) // 第三个参数为是否拉黑
|
|
311
|
-
|
|
312
|
-
// 禁言成员(单位:秒)
|
|
313
|
-
await bot.muteMember(groupId, userId, 600) // 禁言 10 分钟
|
|
314
|
-
await bot.muteMember(groupId, userId, 0) // 解除禁言
|
|
315
|
-
|
|
316
|
-
// 全员禁言
|
|
317
|
-
await bot.muteAll(groupId, true) // 开启
|
|
318
|
-
await bot.muteAll(groupId, false) // 关闭
|
|
319
|
-
|
|
320
|
-
// 设置管理员
|
|
321
|
-
await bot.setAdmin(groupId, userId, true) // 设为管理员
|
|
322
|
-
await bot.setAdmin(groupId, userId, false) // 取消管理员
|
|
323
|
-
|
|
324
|
-
// 设置群名片
|
|
325
|
-
await bot.setCard(groupId, userId, '新名片')
|
|
326
|
-
|
|
327
|
-
// 设置专属头衔
|
|
328
|
-
await bot.setTitle(groupId, userId, '大佬', -1) // -1 表示永久
|
|
96
|
+
`client` 就是当前账号的真实 ICQQ SDK 实例,不是 Endpoint facade。未知扩展事件可显式使用
|
|
97
|
+
`event: '*'`;此时 Client 类型保持完整,事件 payload 为 `unknown`。普通消息回复仍应走
|
|
98
|
+
`Message.$reply`;群管理、请求审批与 ICQQ 专属查询可直接调用当前事件的 `client`。
|
|
329
99
|
|
|
330
|
-
|
|
331
|
-
await bot.setGroupName(groupId, '新群名')
|
|
100
|
+
Command context 的 `$client` 是按需读取的 getter:
|
|
332
101
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
await
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
// 获取被禁言成员列表
|
|
343
|
-
const mutedList = await bot.getMutedMembers(groupId)
|
|
344
|
-
|
|
345
|
-
// 开启/关闭匿名
|
|
346
|
-
await bot.setAnonymous(groupId, true)
|
|
102
|
+
```ts
|
|
103
|
+
export default defineCommand({
|
|
104
|
+
adapter: 'icqq',
|
|
105
|
+
async execute(context) {
|
|
106
|
+
await context.$client.sendLike(Number(context.sender!.id), 10)
|
|
107
|
+
return 'ok'
|
|
108
|
+
},
|
|
109
|
+
})
|
|
347
110
|
```
|
|
348
111
|
|
|
349
|
-
|
|
112
|
+
Middleware 使用同一个判别字段;不声明 `adapter` 时 `$client` 的类型是 `unknown`:
|
|
350
113
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
isAdmin?: boolean; // 是否为管理员
|
|
360
|
-
card?: string; // 群名片
|
|
361
|
-
title?: string; // 专属头衔
|
|
362
|
-
}
|
|
363
|
-
```
|
|
364
|
-
|
|
365
|
-
#### 在插件中检查权限
|
|
366
|
-
|
|
367
|
-
```typescript
|
|
368
|
-
onGroupMessage(async (message) => {
|
|
369
|
-
const sender = message.$sender as IcqqSenderInfo;
|
|
370
|
-
|
|
371
|
-
if (sender.isOwner) {
|
|
372
|
-
console.log('这是群主的消息');
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
if (sender.isAdmin) {
|
|
376
|
-
console.log('这是管理员的消息');
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
if (sender.role === 'member') {
|
|
380
|
-
console.log('这是普通成员的消息');
|
|
381
|
-
}
|
|
114
|
+
```ts
|
|
115
|
+
export default defineMiddleware<Message>({
|
|
116
|
+
target: 'inbound',
|
|
117
|
+
adapter: 'icqq',
|
|
118
|
+
async handle(context, next) {
|
|
119
|
+
console.log(context.$client.uin, context.input.content)
|
|
120
|
+
await next()
|
|
121
|
+
},
|
|
382
122
|
})
|
|
383
123
|
```
|
|
384
124
|
|
|
385
|
-
|
|
125
|
+
Agent tool 的 IM turn 同样直接读取当前 Client:
|
|
386
126
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
127
|
+
```ts
|
|
128
|
+
export default defineAgentTool({
|
|
129
|
+
adapter: 'icqq',
|
|
130
|
+
description: '获取群列表',
|
|
131
|
+
async execute(_input, context) {
|
|
132
|
+
return context.$client.getGroupList()
|
|
133
|
+
},
|
|
134
|
+
})
|
|
393
135
|
```
|
|
394
136
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
137
|
+
`adapter` 缺失时 `$client` 静态类型为 `unknown`;声明后若实际 operation 不属于 ICQQ,
|
|
138
|
+
运行时会在执行前拒绝。Client 只能在当前 operation 内使用。task、schedule 或 Host 等脱离
|
|
139
|
+
IM turn 的场景,才使用 `icqqClient.get(context, endpointId)` 显式选择账号。
|
|
398
140
|
|
|
399
|
-
##
|
|
141
|
+
## 架构
|
|
400
142
|
|
|
401
|
-
|
|
143
|
+
- `plugin.ts` + `adapters/icqq/index.ts`:Plugin Runtime 入口与 `defineAdapter` 声明
|
|
144
|
+
- `src/endpoint.ts`:组合 ICQQ `Client`,只协调账号 transport、Zhin lifecycle 与各能力端口
|
|
145
|
+
- `src/content-resolver.ts`:保存已观察消息,并按深度和条数限制递归展开合并转发
|
|
146
|
+
- `src/icqq-inbound.ts`:把 ICQQ 原生消息归一为 Zhin 入站消息
|
|
147
|
+
- `src/protocol.ts`:配置解析、会话映射与出站目标转换
|
|
148
|
+
- `src/client.ts`:向插件作者暴露 ICQQ `Client` / `EventMap` 类型注册
|
|
149
|
+
- Agent 工具:`agents/icqq/skills/icqq-*/tools/<name>/index.ts`;权限说明见 `PERMITS.md`
|
|
402
150
|
|
|
403
|
-
|
|
404
|
-
-
|
|
405
|
-
- 建议配置签名服务器
|
|
406
|
-
- 定期更新 ICQQ 版本
|
|
151
|
+
阅读适配器实现时从 `endpoint.ts` 看能力装配,再进入对应能力文件。包外代码只从
|
|
152
|
+
`@zhin.js/adapter-icqq` 与 `zhin.js/adapter` 的公开入口导入,不依赖上述源码路径。
|
|
407
153
|
|
|
408
|
-
|
|
154
|
+
## Plugin Runtime 迁移说明
|
|
409
155
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
推荐使用的 platform 值:
|
|
420
|
-
- `2` (Android Watch): 最稳定,推荐
|
|
421
|
-
- `5` (iPad): 功能较全
|
|
422
|
-
- `3` (MacOS): 较稳定
|
|
423
|
-
|
|
424
|
-
避免使用:
|
|
425
|
-
- `1` (Android Phone): 容易被风控
|
|
426
|
-
|
|
427
|
-
## 常见问题
|
|
428
|
-
|
|
429
|
-
### Q: 登录时提示"密码错误"?
|
|
430
|
-
|
|
431
|
-
A:
|
|
432
|
-
1. 确认密码是否正确
|
|
433
|
-
2. 尝试使用扫码登录
|
|
434
|
-
3. 检查是否被风控,需要在手机 QQ 上验证
|
|
435
|
-
|
|
436
|
-
### Q: 登录后频繁掉线?
|
|
437
|
-
|
|
438
|
-
A:
|
|
439
|
-
1. 配置签名服务器
|
|
440
|
-
2. 更换 platform 参数
|
|
441
|
-
3. 检查网络连接是否稳定
|
|
442
|
-
4. 降低消息发送频率
|
|
443
|
-
|
|
444
|
-
### Q: 无法发送图片?
|
|
445
|
-
|
|
446
|
-
A:
|
|
447
|
-
1. 检查图片 URL 是否有效
|
|
448
|
-
2. 本地文件需使用绝对路径
|
|
449
|
-
3. 确认图片格式和大小符合要求
|
|
450
|
-
|
|
451
|
-
### Q: 如何处理滑块验证?
|
|
452
|
-
|
|
453
|
-
A:
|
|
454
|
-
1. 控制台会显示滑块验证链接
|
|
455
|
-
2. 在浏览器中打开链接
|
|
456
|
-
3. 完成滑块验证
|
|
457
|
-
4. 将验证票据复制到控制台
|
|
458
|
-
|
|
459
|
-
## 相关链接
|
|
460
|
-
|
|
461
|
-
- [ICQQ 项目](https://github.com/icqqjs/icqq)
|
|
462
|
-
- [Zhin.js 官方文档](https://github.com/zhinjs/zhin)
|
|
463
|
-
- [签名服务器](https://github.com/fuqiuluo/unidbg-fetch-qsign)
|
|
464
|
-
|
|
465
|
-
## 依赖项
|
|
466
|
-
|
|
467
|
-
- `@icqqjs/icqq` - ICQQ 核心库
|
|
468
|
-
- `zhin.js` - Zhin 核心框架
|
|
469
|
-
|
|
470
|
-
## 开发
|
|
471
|
-
|
|
472
|
-
```bash
|
|
473
|
-
pnpm build # 构建
|
|
474
|
-
pnpm clean # 清理构建文件
|
|
475
|
-
```
|
|
156
|
+
- 不再经过 `@icqqjs/cli` IPC 守护进程;登录态与协议栈都在本进程。
|
|
157
|
+
- `autoReconnect`:Client 断线后按配置自动重连(`stop()` 为主动断开,不触发重连)。
|
|
158
|
+
- `outboundMedia: file | base64`:`file` 在发送期间把 segment base64 物化为临时文件并于发送结束清理;`base64` 使用 ICQQ 原生支持的 `base64://` file 参数。
|
|
159
|
+
- ICQQ 的语音、视频、文件是独立消息元素;它们与其他段混发时适配器会明确拒绝,避免协议栈静默丢段。
|
|
160
|
+
- 入站语音 / 视频在 Endpoint 持有原生 Client 时解析可下载 URL;解析失败则保留真实平台引用,不伪造或丢弃媒体。
|
|
161
|
+
- **Console 社交/群管 RPC 已接线**:endpoint 把好友/群/群成员列表、请求审批和群管操作归一化为冻结的 `EndpointManagement`。Host 只消费该语义端口。
|
|
162
|
+
- 好友/入群请求与通知:经 the unified `Endpoint.emit(...)` ingress 分发到 `handlers`(`notice.receive` / `request.receive`);审批走 `Request.$approve` / `EndpointManagement.approveRequest`。Console `request.list` 优先读 `management.listRequests()`(`getSystemMsg`),不再写入 `unified_inbox_request/notice`。
|
|
163
|
+
- `system.*`(登录扫码等)分发到 `system.receive`。
|
|
164
|
+
- **登录辅助**:`system.login.qrcode|slider|device|auth` 经 `loginAssistToken`(`LoginAssist`)挂起待办;刷新后可用 Console `login.list` / `login.submit` 或终端 stdin 继续(对齐 icqq 官方 stdin 流程)。`system.online` / `login.error` 会清理该 endpoint 待办。
|
|
476
165
|
|
|
477
|
-
##
|
|
166
|
+
## 故障排查
|
|
478
167
|
|
|
479
|
-
|
|
168
|
+
| 现象 | 排查 |
|
|
169
|
+
| --- | --- |
|
|
170
|
+
| 一直停在登录中 | 打开 Console 登录待办,完成二维码、滑块或设备确认 |
|
|
171
|
+
| 签名失败 | 检查 `signApiAddr`;本地模式确认 `@icqqjs/qqsign` 已安装且版本匹配 |
|
|
172
|
+
| 重启后重复登录 | 持久化设备与会话数据目录,避免每次生成新设备 |
|
|
173
|
+
| 请求或通知未显示 | 在 Endpoint 详情检查请求视图;ICQQ 优先读取平台请求列表 |
|
|
480
174
|
|
|
481
|
-
##
|
|
175
|
+
## License
|
|
482
176
|
|
|
483
|
-
|
|
177
|
+
MIT
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
+
/**
|
|
3
|
+
* Convention entry: discover `adapters/icqq/index.ts` → defineAdapter.
|
|
4
|
+
*/
|
|
5
|
+
import { defineAdapter } from 'zhin.js/adapter';
|
|
6
|
+
import { loginAssistToken } from '@zhin.js/core/runtime';
|
|
7
|
+
import { IcqqEndpoint } from "../../lib/endpoint.js";
|
|
8
|
+
import { icqqRuntimeStateToken } from "../../lib/icqq-runtime-state.js";
|
|
9
|
+
import { resolveIcqqConfig, } from "../../lib/protocol.js";
|
|
10
|
+
export { IcqqEndpoint } from "../../lib/endpoint.js";
|
|
11
|
+
export default defineAdapter({
|
|
12
|
+
capabilities: ['inbound', 'outbound'],
|
|
13
|
+
operations: ['recall', 'reaction'],
|
|
14
|
+
segments: {
|
|
15
|
+
outboundMedia: ['base64', 'url', 'path'],
|
|
16
|
+
interactive: 'text',
|
|
17
|
+
},
|
|
18
|
+
create(context) {
|
|
19
|
+
const config = resolveIcqqConfig(context.config);
|
|
20
|
+
// 注册到插件运行时状态(icqq endpoint list 的"运行中"数据源)
|
|
21
|
+
context.use(icqqRuntimeStateToken).endpoints.set(config.id, {
|
|
22
|
+
id: config.id,
|
|
23
|
+
mode: 'direct',
|
|
24
|
+
});
|
|
25
|
+
return new IcqqEndpoint({
|
|
26
|
+
id: context.id,
|
|
27
|
+
loginAssist: context.use(loginAssistToken),
|
|
28
|
+
config,
|
|
29
|
+
});
|
|
30
|
+
},
|
|
31
|
+
});
|