@zhin.js/adapter-qq 1.1.14 → 1.1.16
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 +53 -0
- package/README.md +31 -1
- package/agents/qq/messages.js +24 -0
- package/agents/qq/messages.ts +24 -0
- package/agents/qq/skills/qq/SKILL.md +16 -10
- package/agents/qq/skills/qq/tools/add_role/index.js +3 -1
- package/agents/qq/skills/qq/tools/add_role/index.ts +3 -1
- package/agents/qq/skills/qq/tools/channel_info/index.js +1 -0
- package/agents/qq/skills/qq/tools/channel_info/index.ts +1 -0
- package/agents/qq/skills/qq/tools/create_role/index.js +3 -1
- package/agents/qq/skills/qq/tools/create_role/index.ts +3 -1
- package/agents/qq/skills/qq/tools/list_channels/index.js +1 -0
- package/agents/qq/skills/qq/tools/list_channels/index.ts +1 -0
- package/agents/qq/skills/qq/tools/list_roles/index.js +1 -0
- package/agents/qq/skills/qq/tools/list_roles/index.ts +1 -0
- package/agents/qq/skills/qq/tools/member_detail/index.js +1 -0
- package/agents/qq/skills/qq/tools/member_detail/index.ts +1 -0
- package/agents/qq/skills/qq/tools/remove_role/index.js +3 -1
- package/agents/qq/skills/qq/tools/remove_role/index.ts +3 -1
- package/agents/qq/skills/qq-directory/SKILL.md +14 -0
- package/commands/qq/endpoint/cancel/index.js +6 -5
- package/commands/qq/endpoint/cancel/index.ts +5 -5
- package/commands/qq/endpoint/definition.js +32 -30
- package/commands/qq/endpoint/definition.ts +36 -31
- package/lib/endpoint.js +28 -36
- package/lib/i18n.d.ts +1 -0
- package/lib/i18n.js +72 -0
- package/lib/passive-reply.d.ts +61 -0
- package/lib/passive-reply.js +122 -0
- package/lib/qq-bind-flow.d.ts +2 -0
- package/lib/qq-bind-flow.js +2 -1
- package/lib/qq-bot-kind-prompt.d.ts +5 -6
- package/lib/qq-bot-kind-prompt.js +26 -26
- package/lib/qq-runtime-state.d.ts +6 -0
- package/lib/qq-send.d.ts +28 -0
- package/lib/qq-send.js +109 -0
- package/lib/webhook.js +4 -4
- package/lib/ws.d.ts +10 -4
- package/lib/ws.js +4 -4
- package/middlewares/bot-kind-reply/index.js +6 -5
- package/middlewares/bot-kind-reply/index.ts +6 -5
- package/package.json +18 -18
- package/schema.json +59 -9
- package/src/endpoint.ts +26 -34
- package/src/i18n.ts +73 -0
- package/src/passive-reply.ts +159 -0
- package/src/qq-bind-flow.ts +4 -1
- package/src/qq-bot-kind-prompt.ts +22 -37
- package/src/qq-runtime-state.ts +6 -0
- package/src/qq-send.ts +138 -0
- package/src/webhook.ts +4 -4
- package/src/ws.ts +15 -8
- /package/agents/qq/skills/{qq → qq-directory}/tools/list_guilds/index.js +0 -0
- /package/agents/qq/skills/{qq → qq-directory}/tools/list_guilds/index.ts +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,58 @@
|
|
|
1
1
|
# @zhin.js/adapter-qq
|
|
2
2
|
|
|
3
|
+
## 1.1.16
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 53bc6a0: 适配器配置标签、端点命令和工具反馈支持中英文;复用当前操作语言,保持协议值、用户内容、身份、权限与发送链路不变。Sandbox 展示使用项目语言,QQ 绑定与交互状态保留完整会话身份。
|
|
8
|
+
- Updated dependencies [334e92d]
|
|
9
|
+
- Updated dependencies [f3b7c9f]
|
|
10
|
+
- Updated dependencies [658a5fb]
|
|
11
|
+
- Updated dependencies [144a17b]
|
|
12
|
+
- Updated dependencies [18296cf]
|
|
13
|
+
- Updated dependencies [08e64de]
|
|
14
|
+
- Updated dependencies [9cade30]
|
|
15
|
+
- Updated dependencies [53bc6a0]
|
|
16
|
+
- Updated dependencies [7595136]
|
|
17
|
+
- Updated dependencies [66b6404]
|
|
18
|
+
- Updated dependencies [adb4af2]
|
|
19
|
+
- Updated dependencies [69f9ef6]
|
|
20
|
+
- Updated dependencies [17d1301]
|
|
21
|
+
- @zhin.js/adapter@1.1.23
|
|
22
|
+
- @zhin.js/host-http@1.1.10
|
|
23
|
+
- @zhin.js/core@1.1.51
|
|
24
|
+
- @zhin.js/permission@1.1.9
|
|
25
|
+
- @zhin.js/tool@1.1.10
|
|
26
|
+
- @zhin.js/skill@1.1.10
|
|
27
|
+
- @zhin.js/im-contract@1.1.7
|
|
28
|
+
- @zhin.js/agent-feature@1.1.10
|
|
29
|
+
- @zhin.js/feature-kit@1.1.9
|
|
30
|
+
|
|
31
|
+
## 1.1.15
|
|
32
|
+
|
|
33
|
+
### Patch Changes
|
|
34
|
+
|
|
35
|
+
- 7d68df6: 精简 Agent 内置固定提示词与消息说明,保留工具、审批和结构化回复能力。适配器 Skill 按会话场景拆分,群/频道管理仅向对应场景披露;提示段与模型消息段支持场景声明,沿用当前回合权限和 generation 投影。
|
|
36
|
+
- e684ade: Upgrade `qq-official-bot` to 1.3.3 and send the passive-reply `msg_seq` the Endpoint assigns per source, so the platform's `msg_id + msg_seq` deduplication protects a retried passive reply.
|
|
37
|
+
- 34c536b: Send QQ replies as passive messages. The Endpoint never passed the user message's `msg_id`, so every reply went out as an active message (quota-limited, blocked when the user turns off active messages). It now records each conversation's recent `msg_id` and interaction `event_id` and replies passively within the platform limits (group 5 min × 5, C2C 60 min × 4, guild 5 min), preferring an explicit reply segment. An expired or exhausted source falls back to one active message; an unknown outcome or a content rejection never does. Conversations that refuse active messages are skipped for an hour, and Markdown the platform does not allow is resent as plain text. Requires `qq-official-bot` 1.3.3, which accepts the Endpoint's per-source `msg_seq` so a retried passive reply is deduplicated by the platform.
|
|
38
|
+
- Updated dependencies [f98025b]
|
|
39
|
+
- Updated dependencies [66ec1a5]
|
|
40
|
+
- Updated dependencies [7d68df6]
|
|
41
|
+
- Updated dependencies [bf0fa9f]
|
|
42
|
+
- Updated dependencies [3326db3]
|
|
43
|
+
- Updated dependencies [e91235e]
|
|
44
|
+
- Updated dependencies [6da2bad]
|
|
45
|
+
- Updated dependencies [3781f1c]
|
|
46
|
+
- @zhin.js/core@1.1.50
|
|
47
|
+
- @zhin.js/adapter@1.1.22
|
|
48
|
+
- @zhin.js/im-contract@1.1.6
|
|
49
|
+
- @zhin.js/tool@1.1.9
|
|
50
|
+
- @zhin.js/host-http@1.1.9
|
|
51
|
+
- @zhin.js/agent-feature@1.1.9
|
|
52
|
+
- @zhin.js/feature-kit@1.1.8
|
|
53
|
+
- @zhin.js/permission@1.1.8
|
|
54
|
+
- @zhin.js/skill@1.1.9
|
|
55
|
+
|
|
3
56
|
## 1.1.14
|
|
4
57
|
|
|
5
58
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -174,6 +174,28 @@ Markdown + 指令按钮组。按钮值与手动输入共用同一解析入口,
|
|
|
174
174
|
不支持原生按钮的 Adapter 会在 Core 中把同一 keyboard 语义降级为编号列表,并保存数字到
|
|
175
175
|
payload 的回跳映射。图片、音频、视频和文件仍沿 canonical `MediaRef` 出站链投递。
|
|
176
176
|
|
|
177
|
+
## 被动回复与主动消息
|
|
178
|
+
|
|
179
|
+
QQ 开放平台按有没有带上用户消息的 `msg_id`(或事件的 `event_id`)区分被动回复和主动消息。
|
|
180
|
+
主动消息有额度限制,用户还可以在客户端关闭"允许主动发送"。Endpoint 会记录每个会话最近
|
|
181
|
+
收到的 `msg_id`,以及按钮回调(`INTERACTION_CREATE`)的 `event_id`,发送时自动带上:
|
|
182
|
+
|
|
183
|
+
| 场景 | 被动回复有效期 | 每个来源最多回复 |
|
|
184
|
+
| --- | --- | --- |
|
|
185
|
+
| 群聊 | 5 分钟 | 5 次 |
|
|
186
|
+
| 单聊(C2C) | 60 分钟 | 4 次 |
|
|
187
|
+
| 频道 / 频道私信 | 5 分钟 | 5 次(平台未公布次数) |
|
|
188
|
+
|
|
189
|
+
- **怎么选来源**:每条消息取会话里最新的可用来源。payload 里有 `reply` 段时,优先用它指向的消息。快到有效期时(提前 15 秒)就不再使用,`msg_seq` 按来源递增,经 `qq-official-bot` 的 `SendOptions.msgSeq` 传给平台。
|
|
190
|
+
- **来源不可用**:平台返回来源过期、次数用完或 msg_id 错误(`40034128`、`40034005`、`304027`、`304026` 等)时,这个来源作废,这条消息改发一次主动消息。
|
|
191
|
+
- **结果未知不重发**:超时、断线这类结果未知的情况,不会改发主动消息,因为第一次请求可能已经送达;会报告 `deliveryUnknown`。
|
|
192
|
+
- **内容被拒不改发主动**:审核、敏感词等内容类错误照常报失败,不改发主动消息,以免消耗主动额度。
|
|
193
|
+
- **主动消息被拒**:平台拒绝主动消息时(无权限 `40034105`、私信已关闭、额度用完等),这个会话 1 小时内不再尝试主动发送,直接报失败。
|
|
194
|
+
- **Markdown 没有权限**:平台拒绝 Markdown 时(`304036`、`304014`、`50056`),同一条消息改成纯文本重发,按钮会被去掉。
|
|
195
|
+
|
|
196
|
+
公域机器人在群里只能收到 @ 它的消息,所以群聊旁听(`ai.trigger.ambient`)只对拥有全量
|
|
197
|
+
消息权限的私域机器人有意义。
|
|
198
|
+
|
|
177
199
|
## 故障排查
|
|
178
200
|
|
|
179
201
|
| 现象 | 排查 |
|
|
@@ -181,7 +203,9 @@ payload 的回跳映射。图片、音频、视频和文件仍沿 canonical `Med
|
|
|
181
203
|
| Gateway Identify 后断线 | 检查 `botKind` 与 intents;公域机器人不要订阅受限 intent |
|
|
182
204
|
| 二维码绑定后仍离线 | 在 Console 登录待办确认结果,并检查 App ID、Secret 与 Token |
|
|
183
205
|
| Webhook 无事件 | 检查 HTTP Host、公网路径、平台回调与签名参数 |
|
|
184
|
-
| Markdown/按钮发送失败 |
|
|
206
|
+
| Markdown/按钮发送失败 | 检查平台模板与权限;无权限时 Endpoint 会自动改发纯文本 |
|
|
207
|
+
| 日志出现 `qq_active_unavailable` | 该会话拒绝主动消息:让用户打开"允许主动发送",或等用户再发消息后以被动回复送达 |
|
|
208
|
+
| 定时任务、超时通知发不出 | 触发时会话里没有有效期内的 `msg_id`,只能发主动消息;检查主动消息权限与额度 |
|
|
185
209
|
|
|
186
210
|
## 许可证
|
|
187
211
|
|
|
@@ -213,3 +237,9 @@ QQ 当前未实现 canonical `share` 的标题/描述/URL 消息卡片。适配
|
|
|
213
237
|
可选 `streamProxy: { port: 18443, serverName: "实际网关 hostname" }` 将 WSS 的 TCP 连接导向 `127.0.0.1:port`。需代理固定转发到相同官方网关的 443 端口;SDK 每次仍动态调用 `getWsUrl()`,hostname/443 不匹配会拒绝连接并只记录 hostname,不能自动绕过代理。原始 URL、HTTP Host、TLS SNI 保留,证书验证始终开启。不要填带 query 的 URL。
|
|
214
238
|
|
|
215
239
|
仅 WSS 入站、心跳和会话认证经过此代理;AppSecret 换 token、网关发现 HTTP、消息 API 和媒体上传仍直连。故障恢复由 `createEndpointLifecycle` 负责,SDK 内置重连关闭,避免双重重连。此入口用于受控网络验收,不提供全局代理或 TLS 验证绕过。
|
|
240
|
+
|
|
241
|
+
## 语言与绑定会话
|
|
242
|
+
|
|
243
|
+
Endpoint 管理命令和工具反馈使用当前操作语言。扫码绑定在开始时固定语言,后续二维码刷新、公域/私域选择和结果回复保持一致;`public` / `private` 是稳定的配置值,两种语言都可使用,中文别名只在中文流程中接受。
|
|
244
|
+
|
|
245
|
+
取消指引使用发起命令时的真实前缀及插件命名空间,不猜测调用方式。确认回复仅接受发起者所在的完整会话(Endpoint、会话、父容器、线程和发送者);其他成员或线程不会完成该绑定。
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
+
import { createMessages } from 'zhin.js/i18n';
|
|
3
|
+
export const messages = createMessages({
|
|
4
|
+
"operationFailed": {
|
|
5
|
+
"zh-CN": "操作失败",
|
|
6
|
+
"en": "Operation failed"
|
|
7
|
+
},
|
|
8
|
+
"roleAdded": {
|
|
9
|
+
"zh-CN": "已给成员添加角色",
|
|
10
|
+
"en": "Role added to the member"
|
|
11
|
+
},
|
|
12
|
+
"createFailed": {
|
|
13
|
+
"zh-CN": "创建失败",
|
|
14
|
+
"en": "Creation failed"
|
|
15
|
+
},
|
|
16
|
+
"namedRoleCreated": {
|
|
17
|
+
"zh-CN": "角色 \"{p0}\" 创建成功",
|
|
18
|
+
"en": "Role \"{p0}\" created"
|
|
19
|
+
},
|
|
20
|
+
"roleRemoved": {
|
|
21
|
+
"zh-CN": "已移除成员的角色",
|
|
22
|
+
"en": "Role removed from the member"
|
|
23
|
+
}
|
|
24
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { createMessages } from 'zhin.js/i18n';
|
|
2
|
+
|
|
3
|
+
export const messages = createMessages({
|
|
4
|
+
"operationFailed": {
|
|
5
|
+
"zh-CN": "操作失败",
|
|
6
|
+
"en": "Operation failed"
|
|
7
|
+
},
|
|
8
|
+
"roleAdded": {
|
|
9
|
+
"zh-CN": "已给成员添加角色",
|
|
10
|
+
"en": "Role added to the member"
|
|
11
|
+
},
|
|
12
|
+
"createFailed": {
|
|
13
|
+
"zh-CN": "创建失败",
|
|
14
|
+
"en": "Creation failed"
|
|
15
|
+
},
|
|
16
|
+
"namedRoleCreated": {
|
|
17
|
+
"zh-CN": "角色 \"{p0}\" 创建成功",
|
|
18
|
+
"en": "Role \"{p0}\" created"
|
|
19
|
+
},
|
|
20
|
+
"roleRemoved": {
|
|
21
|
+
"zh-CN": "已移除成员的角色",
|
|
22
|
+
"en": "Role removed from the member"
|
|
23
|
+
}
|
|
24
|
+
});
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: qq
|
|
3
|
-
platforms:
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
platforms:
|
|
4
|
+
- qq
|
|
5
|
+
description: QQ 官方机器人频道、角色和成员详情管理。
|
|
6
|
+
keywords:
|
|
7
|
+
- qq
|
|
8
|
+
- guild
|
|
9
|
+
- channel
|
|
10
|
+
- role
|
|
11
|
+
- member
|
|
12
|
+
tags:
|
|
13
|
+
- adapter
|
|
14
|
+
- community
|
|
7
15
|
tools:
|
|
8
|
-
- list_guilds
|
|
9
16
|
- list_channels
|
|
10
17
|
- list_roles
|
|
11
18
|
- create_role
|
|
@@ -13,10 +20,9 @@ tools:
|
|
|
13
20
|
- remove_role
|
|
14
21
|
- channel_info
|
|
15
22
|
- member_detail
|
|
23
|
+
scopes:
|
|
24
|
+
- channel
|
|
16
25
|
---
|
|
26
|
+
# QQ 频道
|
|
17
27
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
先用 `list_guilds` 和 `list_channels` 确认频道上下文。角色操作前用 `list_roles` 获取角色 ID;成员操作前用 `member_detail` 确认目标。创建、授予和移除角色属于写操作,应遵守对应 Tool 的审批策略。
|
|
21
|
-
|
|
22
|
-
当前 Agent Tool 不提供群踢人、禁言或成员列表能力。
|
|
28
|
+
确认频道和成员 ID 后查询详情或维护角色;权限与审批由各 Tool 执行。可访问频道列表使用 qq-directory。
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
+
import { messages as t } from "../../../../messages.js";
|
|
2
3
|
import { defineAgentTool } from '@zhin.js/tool';
|
|
3
4
|
import { z } from 'zod';
|
|
4
5
|
import { platformPermission } from '@zhin.js/permission';
|
|
@@ -11,11 +12,12 @@ export default defineAgentTool({
|
|
|
11
12
|
role_id: z.string().describe('角色 ID'),
|
|
12
13
|
}),
|
|
13
14
|
adapter: 'qq',
|
|
15
|
+
scopes: ["channel"],
|
|
14
16
|
tags: ['qq'],
|
|
15
17
|
permissions: [platformPermission('qq', 'manage_roles')],
|
|
16
18
|
async execute({ guild_id, channel_id, user_id, role_id }, context) {
|
|
17
19
|
const client = context.$client;
|
|
18
20
|
const success = await client.addMemberRole(guild_id, channel_id, user_id, role_id);
|
|
19
|
-
return { success, message: success ? '
|
|
21
|
+
return { success, message: success ? t(context.locale, 'roleAdded') : t(context.locale, 'operationFailed') };
|
|
20
22
|
},
|
|
21
23
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { messages as t } from "../../../../messages.js";
|
|
1
2
|
import { defineAgentTool } from '@zhin.js/tool';
|
|
2
3
|
import { z } from 'zod';
|
|
3
4
|
import { platformPermission } from '@zhin.js/permission';
|
|
@@ -11,11 +12,12 @@ export default defineAgentTool<{ guild_id: string; channel_id: string; user_id:
|
|
|
11
12
|
role_id: z.string().describe('角色 ID'),
|
|
12
13
|
}),
|
|
13
14
|
adapter: 'qq',
|
|
15
|
+
scopes: ["channel"],
|
|
14
16
|
tags: ['qq'],
|
|
15
17
|
permissions: [platformPermission('qq', 'manage_roles')],
|
|
16
18
|
async execute({ guild_id, channel_id, user_id, role_id }: { guild_id: string; channel_id: string; user_id: string; role_id: string }, context) {
|
|
17
19
|
const client = context.$client;
|
|
18
20
|
const success = await client.addMemberRole(guild_id, channel_id, user_id, role_id);
|
|
19
|
-
return { success, message: success ? '
|
|
21
|
+
return { success, message: success ? t(context.locale, 'roleAdded') : t(context.locale, 'operationFailed') };
|
|
20
22
|
},
|
|
21
23
|
});
|
|
@@ -8,6 +8,7 @@ export default defineAgentTool<{ channel_id: string }>({
|
|
|
8
8
|
channel_id: z.string().describe('子频道 ID'),
|
|
9
9
|
}),
|
|
10
10
|
adapter: 'qq',
|
|
11
|
+
scopes: ["channel"],
|
|
11
12
|
tags: ['qq'],
|
|
12
13
|
permissions: [platformPermission('qq', 'guild_admin')],
|
|
13
14
|
async execute({ channel_id }: { channel_id: string }, context) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
+
import { messages as t } from "../../../../messages.js";
|
|
2
3
|
import { defineAgentTool } from '@zhin.js/tool';
|
|
3
4
|
import { z } from 'zod';
|
|
4
5
|
import { platformPermission } from '@zhin.js/permission';
|
|
@@ -10,11 +11,12 @@ export default defineAgentTool({
|
|
|
10
11
|
color: z.number().optional().describe('颜色(RGB 十进制数值)'),
|
|
11
12
|
}),
|
|
12
13
|
adapter: 'qq',
|
|
14
|
+
scopes: ["channel"],
|
|
13
15
|
tags: ['qq'],
|
|
14
16
|
permissions: [platformPermission('qq', 'guild_owner')],
|
|
15
17
|
async execute({ guild_id, name, color }, context) {
|
|
16
18
|
const client = context.$client;
|
|
17
19
|
const role = await client.createGuildRole(guild_id, name, color);
|
|
18
|
-
return { success: !!role, role, message: role ?
|
|
20
|
+
return { success: !!role, role, message: role ? t(context.locale, 'namedRoleCreated', { p0: name }) : t(context.locale, 'createFailed') };
|
|
19
21
|
},
|
|
20
22
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { messages as t } from "../../../../messages.js";
|
|
1
2
|
import { defineAgentTool } from '@zhin.js/tool';
|
|
2
3
|
import { z } from 'zod';
|
|
3
4
|
import { platformPermission } from '@zhin.js/permission';
|
|
@@ -10,11 +11,12 @@ export default defineAgentTool<{ guild_id: string; name: string; color?: number
|
|
|
10
11
|
color: z.number().optional().describe('颜色(RGB 十进制数值)'),
|
|
11
12
|
}),
|
|
12
13
|
adapter: 'qq',
|
|
14
|
+
scopes: ["channel"],
|
|
13
15
|
tags: ['qq'],
|
|
14
16
|
permissions: [platformPermission('qq', 'guild_owner')],
|
|
15
17
|
async execute({ guild_id, name, color }: { guild_id: string; name: string; color?: number }, context) {
|
|
16
18
|
const client = context.$client;
|
|
17
19
|
const role = await client.createGuildRole(guild_id, name, color);
|
|
18
|
-
return { success: !!role, role, message: role ?
|
|
20
|
+
return { success: !!role, role, message: role ? t(context.locale, 'namedRoleCreated', { p0: name }) : t(context.locale, 'createFailed') };
|
|
19
21
|
},
|
|
20
22
|
});
|
|
@@ -8,6 +8,7 @@ export default defineAgentTool<{ guild_id: string }>({
|
|
|
8
8
|
guild_id: z.string().describe('频道 ID'),
|
|
9
9
|
}),
|
|
10
10
|
adapter: 'qq',
|
|
11
|
+
scopes: ["channel"],
|
|
11
12
|
tags: ['qq'],
|
|
12
13
|
permissions: [platformPermission('qq', 'manage_channels')],
|
|
13
14
|
async execute({ guild_id }: { guild_id: string }, context) {
|
|
@@ -8,6 +8,7 @@ export default defineAgentTool<{ guild_id: string }>({
|
|
|
8
8
|
guild_id: z.string().describe('频道 ID'),
|
|
9
9
|
}),
|
|
10
10
|
adapter: 'qq',
|
|
11
|
+
scopes: ["channel"],
|
|
11
12
|
tags: ['qq'],
|
|
12
13
|
permissions: [platformPermission('qq', 'manage_roles')],
|
|
13
14
|
async execute({ guild_id }: { guild_id: string }, context) {
|
|
@@ -9,6 +9,7 @@ export default defineAgentTool<{ guild_id: string; user_id: string }>({
|
|
|
9
9
|
user_id: z.string().describe('用户 ID'),
|
|
10
10
|
}),
|
|
11
11
|
adapter: 'qq',
|
|
12
|
+
scopes: ["channel"],
|
|
12
13
|
tags: ['qq'],
|
|
13
14
|
permissions: [platformPermission('qq', 'guild_admin')],
|
|
14
15
|
async execute({ guild_id, user_id }: { guild_id: string; user_id: string }, context) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
+
import { messages as t } from "../../../../messages.js";
|
|
2
3
|
import { defineAgentTool } from '@zhin.js/tool';
|
|
3
4
|
import { z } from 'zod';
|
|
4
5
|
import { platformPermission } from '@zhin.js/permission';
|
|
@@ -11,11 +12,12 @@ export default defineAgentTool({
|
|
|
11
12
|
role_id: z.string().describe('角色 ID'),
|
|
12
13
|
}),
|
|
13
14
|
adapter: 'qq',
|
|
15
|
+
scopes: ["channel"],
|
|
14
16
|
tags: ['qq'],
|
|
15
17
|
permissions: [platformPermission('qq', 'manage_roles')],
|
|
16
18
|
async execute({ guild_id, channel_id, user_id, role_id }, context) {
|
|
17
19
|
const client = context.$client;
|
|
18
20
|
const success = await client.removeMemberRole(guild_id, channel_id, user_id, role_id);
|
|
19
|
-
return { success, message: success ? '
|
|
21
|
+
return { success, message: success ? t(context.locale, 'roleRemoved') : t(context.locale, 'operationFailed') };
|
|
20
22
|
},
|
|
21
23
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { messages as t } from "../../../../messages.js";
|
|
1
2
|
import { defineAgentTool } from '@zhin.js/tool';
|
|
2
3
|
import { z } from 'zod';
|
|
3
4
|
import { platformPermission } from '@zhin.js/permission';
|
|
@@ -11,11 +12,12 @@ export default defineAgentTool<{ guild_id: string; channel_id: string; user_id:
|
|
|
11
12
|
role_id: z.string().describe('角色 ID'),
|
|
12
13
|
}),
|
|
13
14
|
adapter: 'qq',
|
|
15
|
+
scopes: ["channel"],
|
|
14
16
|
tags: ['qq'],
|
|
15
17
|
permissions: [platformPermission('qq', 'manage_roles')],
|
|
16
18
|
async execute({ guild_id, channel_id, user_id, role_id }: { guild_id: string; channel_id: string; user_id: string; role_id: string }, context) {
|
|
17
19
|
const client = context.$client;
|
|
18
20
|
const success = await client.removeMemberRole(guild_id, channel_id, user_id, role_id);
|
|
19
|
-
return { success, message: success ? '
|
|
21
|
+
return { success, message: success ? t(context.locale, 'roleRemoved') : t(context.locale, 'operationFailed') };
|
|
20
22
|
},
|
|
21
23
|
});
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
+
import { endpointCommandForbidden } from 'zhin.js/adapter';
|
|
2
3
|
import { defineCommand } from 'zhin.js/command';
|
|
3
|
-
import { isQqEndpointOperator,
|
|
4
|
+
import { isQqEndpointOperator, qqRuntimeStateToken, runQqEndpointCancel, } from '../definition.js';
|
|
4
5
|
export default defineCommand({
|
|
5
|
-
description: '取消进行中的 QQ 扫码绑定或公域/私域选择',
|
|
6
|
-
execute({ config, input, use }) {
|
|
6
|
+
description: '取消进行中的 QQ 扫码绑定或公域/私域选择', descriptionI18n: { en: "Cancel an active QQ QR binding or public/private-domain selection" },
|
|
7
|
+
execute({ config, input, use, locale }) {
|
|
7
8
|
if (!isQqEndpointOperator(config, input))
|
|
8
|
-
return
|
|
9
|
-
return runQqEndpointCancel(use(qqRuntimeStateToken));
|
|
9
|
+
return endpointCommandForbidden('QQ', locale);
|
|
10
|
+
return runQqEndpointCancel(use(qqRuntimeStateToken), locale);
|
|
10
11
|
},
|
|
11
12
|
});
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
+
import { endpointCommandForbidden } from 'zhin.js/adapter';
|
|
1
2
|
import { defineCommand } from 'zhin.js/command';
|
|
2
3
|
import {
|
|
3
4
|
isQqEndpointOperator,
|
|
4
|
-
QQ_ENDPOINT_FORBIDDEN,
|
|
5
5
|
qqRuntimeStateToken,
|
|
6
6
|
runQqEndpointCancel,
|
|
7
7
|
} from '../definition.js';
|
|
8
8
|
|
|
9
9
|
export default defineCommand({
|
|
10
|
-
description: '取消进行中的 QQ 扫码绑定或公域/私域选择',
|
|
11
|
-
execute({ config, input, use }) {
|
|
12
|
-
if (!isQqEndpointOperator(config, input)) return
|
|
13
|
-
return runQqEndpointCancel(use(qqRuntimeStateToken));
|
|
10
|
+
description: '取消进行中的 QQ 扫码绑定或公域/私域选择', descriptionI18n: { en: "Cancel an active QQ QR binding or public/private-domain selection" },
|
|
11
|
+
execute({ config, input, use, locale }) {
|
|
12
|
+
if (!isQqEndpointOperator(config, input)) return endpointCommandForbidden('QQ', locale);
|
|
13
|
+
return runQqEndpointCancel(use(qqRuntimeStateToken), locale);
|
|
14
14
|
},
|
|
15
15
|
});
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
+
import { resolveLocale } from 'zhin.js/i18n';
|
|
3
|
+
import { messages as t } from "../../../lib/i18n.js";
|
|
2
4
|
/**
|
|
3
5
|
* `qq endpoint` 命令的业务逻辑(与命令定义文件分离,便于测试)。
|
|
4
6
|
* 通用部分(权限 / list / remove / 配置写回 / .env 持久化)已迁移到
|
|
@@ -8,7 +10,7 @@
|
|
|
8
10
|
*/
|
|
9
11
|
import { buildEndpointEnvKey, createEndpointCommands, endpointCommandForbidden, endpointConfigurationStoreToken, extractEndpointCommandReply, formatEndpointList, isEndpointOperator, removeEndpointById, } from 'zhin.js/adapter';
|
|
10
12
|
import { defineCommand } from 'zhin.js/command';
|
|
11
|
-
import {
|
|
13
|
+
import { qqBotKindPrompt, qqCommandSessionKey } from "../../../lib/qq-bot-kind-prompt.js";
|
|
12
14
|
import { startQqBindFlow } from "../../../lib/qq-bind-flow.js";
|
|
13
15
|
import { defaultQqEndpointIntentFields } from "../../../lib/qq-intents.js";
|
|
14
16
|
import { qqRuntimeStateToken, } from "../../../lib/qq-runtime-state.js";
|
|
@@ -28,20 +30,20 @@ export const QQ_ENDPOINT_FORBIDDEN = endpointCommandForbidden('QQ');
|
|
|
28
30
|
export function extractQqCommandReply(input) {
|
|
29
31
|
return extractEndpointCommandReply(input);
|
|
30
32
|
}
|
|
31
|
-
function busyFooter(state) {
|
|
33
|
+
function busyFooter(state, locale) {
|
|
32
34
|
if (state.bindFlow)
|
|
33
|
-
return '
|
|
35
|
+
return t(locale, 'bindingBusy') + (state.bindFlow.cancelCommand ? `\n${t(locale, 'cancelHint', { command: state.bindFlow.cancelCommand })}` : '');
|
|
34
36
|
if (state.pendingBotKind) {
|
|
35
|
-
return
|
|
37
|
+
return t(locale, 'kindBusy', { id: state.pendingBotKind.endpointId });
|
|
36
38
|
}
|
|
37
39
|
return undefined;
|
|
38
40
|
}
|
|
39
41
|
/** `qq endpoint list`:运行中的 endpoints(本 generation adapter create 注册)+ 配置里的 endpoints */
|
|
40
|
-
export async function runQqEndpointList(state, store) {
|
|
42
|
+
export async function runQqEndpointList(state, store, locale) {
|
|
41
43
|
return formatEndpointList(qqEndpointListSpec, {
|
|
42
44
|
running: state.endpoints.values(),
|
|
43
45
|
configured: await store.list('qq'),
|
|
44
|
-
footer: busyFooter(state),
|
|
46
|
+
footer: busyFooter(state, locale), locale,
|
|
45
47
|
});
|
|
46
48
|
}
|
|
47
49
|
const qqEndpointListSpec = {
|
|
@@ -50,6 +52,7 @@ const qqEndpointListSpec = {
|
|
|
50
52
|
describeEntry: (entry) => `appid: ${String(entry.appid)}`,
|
|
51
53
|
};
|
|
52
54
|
async function writeEndpointWithBotKind(pending, botKind, store) {
|
|
55
|
+
const locale = pending.locale;
|
|
53
56
|
const appidKey = buildEndpointEnvKey('qq', pending.endpointId, 'appid');
|
|
54
57
|
const secretKey = buildEndpointEnvKey('qq', pending.endpointId, 'secret');
|
|
55
58
|
const intentFields = defaultQqEndpointIntentFields(botKind);
|
|
@@ -67,9 +70,7 @@ async function writeEndpointWithBotKind(pending, botKind, store) {
|
|
|
67
70
|
[secretKey]: pending.appSecret,
|
|
68
71
|
},
|
|
69
72
|
});
|
|
70
|
-
return (
|
|
71
|
-
`intents: ${intentFields.intents.join(', ')}。\n` +
|
|
72
|
-
'⚠️ 需重启 zhin 后新 endpoint 才会生效。');
|
|
73
|
+
return t(locale, 'endpointSaved', { kind: intentFields.botKind, id: pending.endpointId, file: filePath, intents: intentFields.intents.join(', ') });
|
|
73
74
|
}
|
|
74
75
|
/**
|
|
75
76
|
* 完成 pending 的公域/私域选择:一次性写 .env + yaml。
|
|
@@ -84,9 +85,9 @@ export async function completeQqPendingBotKind(pending, botKind, store) {
|
|
|
84
85
|
* 后续状态(已扫码 / 成功 / 失败 / 过期刷新)通过 reply 推回当前会话。
|
|
85
86
|
* 扫码成功后凭据暂存内存并询问公域/私域;确认后一次性写 .env + yaml。
|
|
86
87
|
*/
|
|
87
|
-
export function runQqEndpointAdd(state, id, reply, store, input) {
|
|
88
|
+
export function runQqEndpointAdd(state, id, reply, store, input, locale = 'zh-CN', cancelCommand, commandHeads) {
|
|
88
89
|
if (state.bindFlow || state.pendingBotKind) {
|
|
89
|
-
return Promise.resolve(
|
|
90
|
+
return Promise.resolve(t(locale, 'existingFlow'));
|
|
90
91
|
}
|
|
91
92
|
const endpointId = id?.trim() || undefined;
|
|
92
93
|
const sessionKey = qqCommandSessionKey(input);
|
|
@@ -106,11 +107,11 @@ export function runQqEndpointAdd(state, id, reply, store, input) {
|
|
|
106
107
|
const stop = startQqBindFlow({
|
|
107
108
|
onQrDisplayed: (url) => {
|
|
108
109
|
// QQ 出站当前仅支持纯文本(富媒体未迁移),二维码只能发链接文本
|
|
109
|
-
settle(
|
|
110
|
+
settle(t(locale, 'scanLink', { url }));
|
|
110
111
|
},
|
|
111
112
|
onQrExpired: async () => {
|
|
112
113
|
try {
|
|
113
|
-
await reply('
|
|
114
|
+
await reply(t(locale, 'qrExpired'));
|
|
114
115
|
}
|
|
115
116
|
catch {
|
|
116
117
|
// same as settle follow-up: best-effort after command scope ends
|
|
@@ -127,45 +128,45 @@ export function runQqEndpointAdd(state, id, reply, store, input) {
|
|
|
127
128
|
endpointId: finalName,
|
|
128
129
|
appId,
|
|
129
130
|
appSecret,
|
|
130
|
-
sessionKey: '',
|
|
131
|
+
sessionKey: '', locale, cancelCommand,
|
|
131
132
|
}, 'public', store) +
|
|
132
|
-
'
|
|
133
|
+
t(locale, 'noInteractiveKind'));
|
|
133
134
|
return;
|
|
134
135
|
}
|
|
135
136
|
state.pendingBotKind = {
|
|
136
137
|
endpointId: finalName,
|
|
137
138
|
appId,
|
|
138
139
|
appSecret,
|
|
139
|
-
sessionKey,
|
|
140
|
+
sessionKey, locale, cancelCommand, commandHeads,
|
|
140
141
|
};
|
|
141
|
-
settle(
|
|
142
|
-
QQ_BOT_KIND_PROMPT);
|
|
142
|
+
settle(t(locale, 'scanned', { id: finalName, prompt: qqBotKindPrompt(locale, cancelCommand) }));
|
|
143
143
|
}
|
|
144
144
|
catch (error) {
|
|
145
|
-
settle(
|
|
145
|
+
settle(t(locale, 'writeFailed', { error: error instanceof Error ? error.message : String(error) }));
|
|
146
146
|
}
|
|
147
147
|
},
|
|
148
148
|
onFailure: (error) => {
|
|
149
149
|
state.bindFlow = null;
|
|
150
|
-
settle(
|
|
150
|
+
settle(t(locale, 'bindingFailed', { error: error.message }));
|
|
151
151
|
},
|
|
152
|
-
}, { source: 'zhin' });
|
|
153
|
-
state.bindFlow = { id: endpointId, stop };
|
|
152
|
+
}, { source: 'zhin', locale });
|
|
153
|
+
state.bindFlow = { id: endpointId, stop, locale, cancelCommand, commandHeads };
|
|
154
154
|
});
|
|
155
155
|
}
|
|
156
156
|
/** `qq endpoint cancel`:中止进行中的绑定或待选 botKind */
|
|
157
|
-
export function runQqEndpointCancel(state) {
|
|
157
|
+
export function runQqEndpointCancel(state, preference) {
|
|
158
|
+
const locale = resolveLocale(state.pendingBotKind?.locale ?? state.bindFlow?.locale ?? preference);
|
|
158
159
|
if (state.bindFlow) {
|
|
159
160
|
state.bindFlow.stop();
|
|
160
161
|
state.bindFlow = null;
|
|
161
|
-
return
|
|
162
|
+
return t(locale, 'cancelled');
|
|
162
163
|
}
|
|
163
164
|
if (state.pendingBotKind) {
|
|
164
165
|
const name = state.pendingBotKind.endpointId;
|
|
165
166
|
state.pendingBotKind = null;
|
|
166
|
-
return
|
|
167
|
+
return t(locale, 'pendingCancelled', { name });
|
|
167
168
|
}
|
|
168
|
-
return
|
|
169
|
+
return t(locale, 'noFlow');
|
|
169
170
|
}
|
|
170
171
|
/** `qq endpoint remove <id>`:从 zhin.config.yml 移除对应 endpoints 项 */
|
|
171
172
|
export async function runQqEndpointRemove(_state, id, store) {
|
|
@@ -178,11 +179,12 @@ export async function runQqEndpointRemove(_state, id, store) {
|
|
|
178
179
|
export const qqEndpointCommands = createEndpointCommands({
|
|
179
180
|
...qqEndpointListSpec,
|
|
180
181
|
fields: [
|
|
181
|
-
{ key: 'appid', required: true, env: true, description: 'QQ 机器人 appid' },
|
|
182
|
-
{ key: 'secret', required: true, env: true, description: 'QQ 机器人 secret' },
|
|
182
|
+
{ key: 'appid', required: true, env: true, description: 'QQ 机器人 appid', descriptionI18n: { en: "QQ bot app ID" } },
|
|
183
|
+
{ key: 'secret', required: true, env: true, description: 'QQ 机器人 secret', descriptionI18n: { en: "QQ bot secret" } },
|
|
183
184
|
],
|
|
184
185
|
running: (use) => use(qqRuntimeStateToken).endpoints.values(),
|
|
185
|
-
listFooter: (use) => busyFooter(use(qqRuntimeStateToken)),
|
|
186
|
+
listFooter: (use, locale) => busyFooter(use(qqRuntimeStateToken), locale),
|
|
187
|
+
addDescriptionI18n: { en: 'Bind a bot through mobile QQ, choose public/private, then save configuration; restart to apply' },
|
|
186
188
|
addDescription: '手机 QQ 扫码绑定机器人:确认公域/私域后一次性写入 .env 与 zhin.config.yml(重启生效)',
|
|
187
|
-
bindFlow: ({ id, reply, input, use }) => runQqEndpointAdd(use(qqRuntimeStateToken), id, reply, use(endpointConfigurationStoreToken), input),
|
|
189
|
+
bindFlow: ({ id, reply, input, use, locale, formatCommand }) => runQqEndpointAdd(use(qqRuntimeStateToken), id, reply, use(endpointConfigurationStoreToken), input, locale, formatCommand?.('qq endpoint cancel'), ['qq endpoint list', 'qq endpoint add', 'qq endpoint remove', 'qq endpoint cancel'].flatMap(path => { const head = formatCommand?.(path); return head ? [head] : []; })),
|
|
188
190
|
}, defineCommand);
|