@zhin.js/adapter-qq 1.1.0 → 1.1.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.
Files changed (61) hide show
  1. package/CHANGELOG.md +112 -0
  2. package/README.md +18 -19
  3. package/adapters/{qq.js → qq/index.js} +7 -7
  4. package/adapters/{qq.ts → qq/index.ts} +11 -11
  5. package/agents/qq/agent.json +20 -0
  6. package/agents/qq/boundaries.md +3 -0
  7. package/agents/qq/conventions.md +3 -0
  8. package/agents/qq/skills/qq/SKILL.md +22 -0
  9. package/agents/qq/skills/qq/tools/add_role/index.js +21 -0
  10. package/{agent/tools/add_role.ts → agents/qq/skills/qq/tools/add_role/index.ts} +3 -3
  11. package/agents/qq/skills/qq/tools/channel_info/index.js +17 -0
  12. package/{agent/tools/channel_info.ts → agents/qq/skills/qq/tools/channel_info/index.ts} +3 -3
  13. package/agents/qq/skills/qq/tools/create_role/index.js +20 -0
  14. package/{agent/tools/create_role.ts → agents/qq/skills/qq/tools/create_role/index.ts} +3 -3
  15. package/agents/qq/skills/qq/tools/list_channels/index.js +18 -0
  16. package/{agent/tools/list_channels.ts → agents/qq/skills/qq/tools/list_channels/index.ts} +3 -3
  17. package/agents/qq/skills/qq/tools/list_guilds/index.js +14 -0
  18. package/{agent/tools/list_guilds.ts → agents/qq/skills/qq/tools/list_guilds/index.ts} +1 -1
  19. package/agents/qq/skills/qq/tools/list_roles/index.js +18 -0
  20. package/{agent/tools/list_roles.ts → agents/qq/skills/qq/tools/list_roles/index.ts} +3 -3
  21. package/agents/qq/skills/qq/tools/member_detail/index.js +18 -0
  22. package/{agent/tools/member_detail.ts → agents/qq/skills/qq/tools/member_detail/index.ts} +3 -3
  23. package/agents/qq/skills/qq/tools/remove_role/index.js +21 -0
  24. package/{agent/tools/remove_role.ts → agents/qq/skills/qq/tools/remove_role/index.ts} +3 -3
  25. package/agents/qq/system.md +3 -0
  26. package/commands/{endpoint/add/[[id]].js → qq/endpoint/add/[[id]]/index.js} +1 -1
  27. package/commands/qq/endpoint/add/[[id]]/index.ts +3 -0
  28. package/commands/{endpoint/cancel.js → qq/endpoint/cancel/index.js} +1 -2
  29. package/commands/{endpoint/cancel.ts → qq/endpoint/cancel/index.ts} +2 -2
  30. package/{lib/qq-endpoint-commands.js → commands/qq/endpoint/definition.js} +44 -36
  31. package/{src/qq-endpoint-commands.ts → commands/qq/endpoint/definition.ts} +57 -45
  32. package/commands/{endpoint/list.js → qq/endpoint/list/index.js} +1 -1
  33. package/commands/qq/endpoint/list/index.ts +3 -0
  34. package/commands/{endpoint/remove/[id].js → qq/endpoint/remove/[id]/index.js} +1 -1
  35. package/commands/qq/endpoint/remove/[id]/index.ts +3 -0
  36. package/lib/index.d.ts +1 -1
  37. package/lib/outbound.js +1 -1
  38. package/lib/protocol.d.ts +7 -28
  39. package/lib/protocol.js +19 -24
  40. package/lib/qq-bot-kind-prompt.js +1 -1
  41. package/middlewares/{bot-kind-reply.js → bot-kind-reply/index.js} +7 -6
  42. package/middlewares/{bot-kind-reply.ts → bot-kind-reply/index.ts} +11 -6
  43. package/package.json +34 -22
  44. package/schema.json +26 -10
  45. package/src/index.ts +1 -1
  46. package/src/outbound.ts +1 -1
  47. package/src/protocol.ts +25 -49
  48. package/src/qq-bot-kind-prompt.ts +1 -1
  49. package/src/ws.ts +1 -1
  50. package/agent/skills/qq.md +0 -97
  51. package/commands/endpoint/add/[[id]].ts +0 -3
  52. package/commands/endpoint/list.ts +0 -3
  53. package/commands/endpoint/remove/[id].ts +0 -3
  54. package/lib/qq-bind-persist.d.ts +0 -12
  55. package/lib/qq-bind-persist.js +0 -22
  56. package/lib/qq-endpoint-commands.d.ts +0 -45
  57. package/lib/qq-endpoint-config.d.ts +0 -17
  58. package/lib/qq-endpoint-config.js +0 -22
  59. package/src/qq-bind-persist.ts +0 -44
  60. package/src/qq-endpoint-config.ts +0 -44
  61. /package/{agent/PERMITS.md → PERMITS.md} +0 -0
@@ -1,8 +1,9 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
2
  import { defineMiddleware } from 'zhin.js/middleware';
3
- import { completeQqPendingBotKind, } from "../lib/qq-endpoint-commands.js";
4
- import { parseQqBotKindAnswer, qqCommandSessionKey, QQ_BOT_KIND_PROMPT, } from "../lib/qq-bot-kind-prompt.js";
5
- import { qqRuntimeStateToken } from "../lib/qq-runtime-state.js";
3
+ import { endpointConfigurationStoreToken } from 'zhin.js/adapter';
4
+ import { completeQqPendingBotKind, } from '../../commands/qq/endpoint/definition.js';
5
+ import { parseQqBotKindAnswer, qqCommandSessionKey, QQ_BOT_KIND_PROMPT, } from "../../lib/qq-bot-kind-prompt.js";
6
+ import { qqRuntimeStateToken } from "../../lib/qq-runtime-state.js";
6
7
  /**
7
8
  * 扫码绑定成功后,在同一会话收取 public/private(或 公域/私域)回复并写入 intents。
8
9
  * 非待确认会话、或内容无法识别为 botKind 时放行后续中间件/命令。
@@ -24,8 +25,8 @@ export default defineMiddleware({
24
25
  return;
25
26
  }
26
27
  const raw = String(context.input.content ?? '').trim();
27
- // 让 qq.endpoint cancel 等命令继续走命令链
28
- if (raw.toLowerCase().startsWith('qq.endpoint')) {
28
+ // 让 qq endpoint cancel 等命令继续走命令链
29
+ if (raw.toLowerCase().startsWith('qq endpoint')) {
29
30
  await next();
30
31
  return;
31
32
  }
@@ -35,7 +36,7 @@ export default defineMiddleware({
35
36
  return;
36
37
  }
37
38
  try {
38
- const text = completeQqPendingBotKind(pending, botKind);
39
+ const text = await completeQqPendingBotKind(pending, botKind, context.use(endpointConfigurationStoreToken));
39
40
  state.pendingBotKind = null;
40
41
  await context.input.$reply?.(text);
41
42
  }
@@ -1,14 +1,15 @@
1
1
  import { defineMiddleware } from 'zhin.js/middleware';
2
2
  import type { CommandMessage } from 'zhin.js/command';
3
+ import { endpointConfigurationStoreToken } from 'zhin.js/adapter';
3
4
  import {
4
5
  completeQqPendingBotKind,
5
- } from '../src/qq-endpoint-commands.js';
6
+ } from '../../commands/qq/endpoint/definition.js';
6
7
  import {
7
8
  parseQqBotKindAnswer,
8
9
  qqCommandSessionKey,
9
10
  QQ_BOT_KIND_PROMPT,
10
- } from '../src/qq-bot-kind-prompt.js';
11
- import { qqRuntimeStateToken } from '../src/qq-runtime-state.js';
11
+ } from '../../src/qq-bot-kind-prompt.js';
12
+ import { qqRuntimeStateToken } from '../../src/qq-runtime-state.js';
12
13
 
13
14
  /**
14
15
  * 扫码绑定成功后,在同一会话收取 public/private(或 公域/私域)回复并写入 intents。
@@ -33,8 +34,8 @@ export default defineMiddleware<CommandMessage>({
33
34
  }
34
35
 
35
36
  const raw = String(context.input.content ?? '').trim();
36
- // 让 qq.endpoint cancel 等命令继续走命令链
37
- if (raw.toLowerCase().startsWith('qq.endpoint')) {
37
+ // 让 qq endpoint cancel 等命令继续走命令链
38
+ if (raw.toLowerCase().startsWith('qq endpoint')) {
38
39
  await next();
39
40
  return;
40
41
  }
@@ -48,7 +49,11 @@ export default defineMiddleware<CommandMessage>({
48
49
  }
49
50
 
50
51
  try {
51
- const text = completeQqPendingBotKind(pending, botKind);
52
+ const text = await completeQqPendingBotKind(
53
+ pending,
54
+ botKind,
55
+ context.use(endpointConfigurationStoreToken),
56
+ );
52
57
  state.pendingBotKind = null;
53
58
  await context.input.$reply?.(text);
54
59
  } catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhin.js/adapter-qq",
3
- "version": "1.1.0",
3
+ "version": "1.1.3",
4
4
  "description": "Zhin.js QQ Official adapter for Plugin Runtime (WebSocket gateway)",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -35,27 +35,26 @@
35
35
  },
36
36
  "dependencies": {
37
37
  "qq-official-bot": "^1.3.0",
38
- "@zhin.js/adapter": "1.1.12",
39
- "@zhin.js/core": "1.1.35",
40
- "@zhin.js/feature-kit": "1.1.0",
41
- "@zhin.js/host-http": "1.1.0",
42
- "@zhin.js/im-contract": "1.1.0",
43
- "@zhin.js/logger": "1.1.0",
44
- "@zhin.js/permission": "1.1.0"
38
+ "@zhin.js/adapter": "1.1.15",
39
+ "@zhin.js/agent-feature": "1.1.2",
40
+ "@zhin.js/core": "1.1.38",
41
+ "@zhin.js/feature-kit": "1.1.2",
42
+ "@zhin.js/host-http": "1.1.2",
43
+ "@zhin.js/im-contract": "1.1.2",
44
+ "@zhin.js/logger": "1.1.1",
45
+ "@zhin.js/permission": "1.1.2",
46
+ "@zhin.js/skill": "1.1.2",
47
+ "@zhin.js/tool": "1.1.2"
45
48
  },
46
49
  "peerDependencies": {
47
50
  "zod": "^4.0.0",
48
- "@zhin.js/adapter": "^1.1.12",
49
- "@zhin.js/agent": "^1.1.23",
50
- "@zhin.js/command": "^1.1.0",
51
- "@zhin.js/core": "^1.1.35",
52
- "@zhin.js/middleware": "^1.1.0",
53
- "zhin.js": "^1.1.0"
51
+ "@zhin.js/adapter": "^1.1.15",
52
+ "@zhin.js/command": "^1.1.2",
53
+ "@zhin.js/core": "^1.1.38",
54
+ "@zhin.js/middleware": "^1.1.2",
55
+ "zhin.js": "^1.1.3"
54
56
  },
55
57
  "peerDependenciesMeta": {
56
- "@zhin.js/agent": {
57
- "optional": true
58
- },
59
58
  "@zhin.js/command": {
60
59
  "optional": true
61
60
  },
@@ -74,9 +73,8 @@
74
73
  "typescript": "^6.0.3",
75
74
  "vitest": "^4.1.10",
76
75
  "zod": "^4.4.3",
77
- "@zhin.js/agent": "1.1.23",
78
- "@zhin.js/host-http": "1.1.0",
79
- "zhin.js": "1.1.0"
76
+ "@zhin.js/host-http": "1.1.2",
77
+ "zhin.js": "1.1.3"
80
78
  },
81
79
  "files": [
82
80
  "adapters",
@@ -86,9 +84,11 @@
86
84
  "schema.json",
87
85
  "src",
88
86
  "lib",
89
- "agent",
87
+ "tools",
88
+ "agents",
90
89
  "README.md",
91
- "CHANGELOG.md"
90
+ "CHANGELOG.md",
91
+ "PERMITS.md"
92
92
  ],
93
93
  "publishConfig": {
94
94
  "access": "public",
@@ -115,6 +115,18 @@
115
115
  {
116
116
  "package": "@zhin.js/middleware",
117
117
  "api": "^1.0.0"
118
+ },
119
+ {
120
+ "package": "@zhin.js/tool",
121
+ "api": "^1.0.0"
122
+ },
123
+ {
124
+ "package": "@zhin.js/skill",
125
+ "api": "^1.0.0"
126
+ },
127
+ {
128
+ "package": "@zhin.js/agent-feature",
129
+ "api": "^1.0.0"
118
130
  }
119
131
  ],
120
132
  "plugins": []
package/schema.json CHANGED
@@ -62,20 +62,13 @@
62
62
  "default": "/qq/webhook",
63
63
  "description": "POST path on httpHostToken for webhook/middleware modes."
64
64
  },
65
- "port": {
66
- "type": "number",
67
- "description": "Legacy standalone webhook port (unused with httpHostToken)."
68
- },
69
- "path": {
70
- "type": "string",
71
- "description": "Legacy standalone webhook path (unused with httpHostToken)."
72
- },
73
65
  "endpoints": {
74
66
  "type": "array",
75
- "description": "多账号:一个插件实例挂多个 endpoint。每项与顶层字段同构(id 必填,其余覆盖顶层)",
67
+ "minItems": 1,
68
+ "description": "多账号:每项定义一个 endpoint,id/appid/secret 必填,其余字段覆盖实例默认值",
76
69
  "items": {
77
70
  "type": "object",
78
- "additionalProperties": true,
71
+ "additionalProperties": false,
79
72
  "properties": {
80
73
  "appid": {
81
74
  "type": "string",
@@ -85,6 +78,17 @@
85
78
  "type": "string",
86
79
  "description": "QQ official bot secret"
87
80
  },
81
+ "mode": {
82
+ "type": "string",
83
+ "enum": [
84
+ "websocket",
85
+ "webhook",
86
+ "middleware"
87
+ ]
88
+ },
89
+ "sandbox": {
90
+ "type": "boolean"
91
+ },
88
92
  "master": {
89
93
  "type": [
90
94
  "string",
@@ -118,6 +122,18 @@
118
122
  },
119
123
  "description": "覆盖顶层 intents"
120
124
  },
125
+ "accessTokenUrl": {
126
+ "type": "string"
127
+ },
128
+ "gatewayUrl": {
129
+ "type": "string"
130
+ },
131
+ "webhookPath": {
132
+ "type": "string"
133
+ },
134
+ "commandPrefix": {
135
+ "type": "string"
136
+ },
121
137
  "id": {
122
138
  "type": "string",
123
139
  "description": "QQ bot name"
package/src/index.ts CHANGED
@@ -4,7 +4,7 @@ export {
4
4
  resolveOutboundMessageId,
5
5
  resolveQqConfig,
6
6
  senderDisplayName,
7
- type QqAdapterConfig,
7
+ type QqEndpointConfig,
8
8
  type QqChannelKind,
9
9
  type QqInboundMessage,
10
10
  type QqWireSegment,
package/src/outbound.ts CHANGED
@@ -13,7 +13,7 @@
13
13
  * 不可映射的段一律降级为文本并 warn(保持既有 fallback 行为)。
14
14
  */
15
15
  import { formatCompact, getLogger } from '@zhin.js/logger';
16
- import { isMediaRef } from '@zhin.js/core';
16
+ import { isMediaRef } from '@zhin.js/im-contract';
17
17
  import type { QqWireSegment } from './protocol.js';
18
18
 
19
19
  const logger = getLogger('qq');
package/src/protocol.ts CHANGED
@@ -1,20 +1,16 @@
1
- /**
2
- * QQ Official Bot protocol helpers — no legacy Adapter/Endpoint / segment-mapper.
3
- * Canonicalization is owned by gateway/core before endpoint.send.
4
- */
1
+ /** QQ Official Bot protocol helpers. Canonicalization is owned by Core. */
5
2
 
6
- import { pickCredential } from 'zhin.js/adapter';
7
3
  import type { ConversationKind, ConversationRef } from '@zhin.js/im-contract';
8
4
  import { formatCompact, getLogger } from '@zhin.js/logger';
9
5
  import { resolveQqIntents } from './qq-intents.js';
10
6
 
11
7
  const logger = getLogger('qq');
12
8
 
13
- /** Plugin Runtime owner config (`plugins.<instanceKey>` / schema.json). */
14
- export interface QqAdapterConfig {
15
- readonly id?: string;
16
- readonly appid?: string;
17
- readonly secret?: string;
9
+ /** One endpoint config after AdapterIndex expands `plugins.<instanceKey>.endpoints`. */
10
+ export interface QqEndpointConfig {
11
+ readonly id: string;
12
+ readonly appid: string;
13
+ readonly secret: string;
18
14
  /** Default `websocket`. `webhook` / `middleware` use httpHostToken POST. */
19
15
  readonly mode?: 'websocket' | 'webhook' | 'middleware';
20
16
  readonly sandbox?: boolean;
@@ -25,24 +21,6 @@ export interface QqAdapterConfig {
25
21
  readonly accessTokenUrl?: string;
26
22
  readonly gatewayUrl?: string;
27
23
  readonly webhookPath?: string;
28
- readonly port?: number;
29
- readonly path?: string;
30
- /** Transitional: legacy root `endpoints[]` with `context: qq`. */
31
- readonly endpoints?: ReadonlyArray<{
32
- readonly context?: string;
33
- readonly id?: string;
34
- readonly appid?: string;
35
- readonly secret?: string;
36
- readonly mode?: 'websocket' | 'webhook' | 'middleware';
37
- readonly sandbox?: boolean;
38
- readonly intents?: readonly string[];
39
- readonly botKind?: string;
40
- readonly accessTokenUrl?: string;
41
- readonly gatewayUrl?: string;
42
- readonly webhookPath?: string;
43
- readonly port?: number;
44
- readonly path?: string;
45
- }>;
46
24
  }
47
25
 
48
26
  export interface ResolvedQqWebsocketConfig {
@@ -98,23 +76,14 @@ export interface QqWireSegment {
98
76
  readonly data?: Record<string, unknown>;
99
77
  }
100
78
 
101
- export function resolveQqConfig(config: QqAdapterConfig = {}): ResolvedQqConfig {
102
- const entry = config.endpoints?.find((item) => item.context === 'qq' || !item.context);
103
- const appid = pickCredential(config.appid, entry?.appid, process.env.QQ_APPID, process.env.QQ_BOT_APPID);
104
- const secret = pickCredential(config.secret, entry?.secret, process.env.QQ_SECRET, process.env.QQ_BOT_SECRET);
105
- if (!appid || !secret) {
106
- throw new TypeError(
107
- 'QQ adapter requires appid + secret (plugins.<key>.appid/secret or endpoints with context: qq)',
108
- );
109
- }
110
- const id = (typeof config.id === 'string' && config.id)
111
- || (typeof entry?.id === 'string' && entry.id)
112
- || process.env.QQ_BOT_NAME
113
- || 'qq-bot';
114
- const mode = config.mode ?? entry?.mode ?? 'websocket';
79
+ export function resolveQqConfig(config: QqEndpointConfig): ResolvedQqConfig {
80
+ const id = requiredEndpointField(config.id, 'id');
81
+ const appid = requiredEndpointField(config.appid, 'appid');
82
+ const secret = requiredEndpointField(config.secret, 'secret');
83
+ const mode = config.mode ?? 'websocket';
115
84
 
116
85
  if (mode === 'webhook' || mode === 'middleware') {
117
- const webhookPathRaw = config.webhookPath ?? entry?.webhookPath ?? '/qq/webhook';
86
+ const webhookPathRaw = config.webhookPath ?? '/qq/webhook';
118
87
  const webhookPath = webhookPathRaw.startsWith('/') ? webhookPathRaw : `/${webhookPathRaw}`;
119
88
  return {
120
89
  context: 'qq',
@@ -123,7 +92,7 @@ export function resolveQqConfig(config: QqAdapterConfig = {}): ResolvedQqConfig
123
92
  appid,
124
93
  secret,
125
94
  webhookPath,
126
- sandbox: config.sandbox === true || entry?.sandbox === true,
95
+ sandbox: config.sandbox === true,
127
96
  };
128
97
  }
129
98
 
@@ -133,16 +102,23 @@ export function resolveQqConfig(config: QqAdapterConfig = {}): ResolvedQqConfig
133
102
  id,
134
103
  appid,
135
104
  secret,
136
- sandbox: config.sandbox === true || entry?.sandbox === true,
105
+ sandbox: config.sandbox === true,
137
106
  intents: resolveQqIntents({
138
- intents: config.intents ?? entry?.intents,
139
- botKind: config.botKind ?? entry?.botKind,
107
+ intents: config.intents,
108
+ botKind: config.botKind,
140
109
  }),
141
- accessTokenUrl: config.accessTokenUrl ?? entry?.accessTokenUrl,
142
- gatewayUrl: config.gatewayUrl ?? entry?.gatewayUrl,
110
+ accessTokenUrl: config.accessTokenUrl,
111
+ gatewayUrl: config.gatewayUrl,
143
112
  };
144
113
  }
145
114
 
115
+ function requiredEndpointField(value: unknown, field: 'id' | 'appid' | 'secret'): string {
116
+ if (typeof value !== 'string' || !value.trim()) {
117
+ throw new TypeError(`QQ endpoint requires a non-empty ${field}`);
118
+ }
119
+ return value.trim();
120
+ }
121
+
146
122
  /**
147
123
  * 入站归一化 → ConversationRef:`direct`(频道私信)映射为 guild 容器内的
148
124
  * private 会话;频道消息的所属 guild 进 `parent`。
@@ -44,4 +44,4 @@ export function parseQqBotKindAnswer(raw: unknown): QqBotKind | undefined {
44
44
 
45
45
  export const QQ_BOT_KIND_PROMPT =
46
46
  '请回复 public(公域)或 private(私域),确认后一次性写入 .env 与配置。\n'
47
- + '也可发 qq.endpoint cancel 取消。';
47
+ + '也可发 qq endpoint cancel 取消。';
package/src/ws.ts CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  type ApproveJoinRequestOptions,
9
9
  type Sendable,
10
10
  } from 'qq-official-bot';
11
- import type { MediaRef, Segment } from '@zhin.js/core';
11
+ import type { MediaRef, Segment } from '@zhin.js/im-contract';
12
12
  import type { QqOutboundMessage } from './outbound.js';
13
13
  import type { QqChannelKind, QqInboundMessage, ResolvedQqWebsocketConfig } from './protocol.js';
14
14
 
@@ -1,97 +0,0 @@
1
- ---
2
- name: qq
3
- platforms:
4
- - qq
5
- description: >-
6
- QQ 官方机器人管理能力。当用户在 QQ 官方机器人(非 OneBot/NapCat)中请求群管(踢人、
7
- 禁言、全员禁言)、频道/子频道管理、角色管理(创建/添加/移除角色)、
8
- 或查询成员详情时使用。即使用户没有明确提到 QQ 官方机器人,只要 Endpoint 平台是 qq
9
- (官方 API)且涉及上述操作,就应触发。仅有昵称时先 list_members 查 user_id。
10
- keywords:
11
- - qq
12
- - QQ
13
- - adapter:qq
14
- - 群管理
15
- - 频道
16
- - 子频道
17
- - 角色
18
- - 官方机器人
19
- - list_members
20
- tags:
21
- - group
22
- - management
23
- - im
24
- tools:
25
- - qq_list_guilds
26
- - qq_list_channels
27
- - qq_list_roles
28
- - qq_create_role
29
- - qq_add_role
30
- - qq_remove_role
31
- - qq_channel_info
32
- - qq_member_detail
33
- - qq_kick_member
34
- - qq_mute_member
35
- - qq_mute_all
36
- - qq_list_members
37
- - qq_get_group_info
38
- ---
39
-
40
- # QQ 官方机器人管理技能
41
-
42
- QQ 官方机器人 API 同时支持「群聊」和「频道」两种场景,频道有 Guild/Channel 二级结构。
43
-
44
- ## 核心原则
45
-
46
- ### 群 vs 频道
47
-
48
- QQ 官方机器人有两个独立的体系:
49
- - **群聊**(Group):传统 QQ 群,用 `group_id` 标识
50
- - **频道**(Guild + Channel):类似 Discord,Guild 是大频道,Channel 是子频道
51
-
52
- 操作前确认用户说的是「群」还是「频道」。
53
-
54
- ### 频道导航链
55
-
56
- 频道操作需要逐级获取 ID:
57
- ```
58
- qq_list_guilds → 获取 guild_id
59
- qq_list_channels(guild_id) → 获取 channel_id
60
- qq_channel_info(channel_id) → 子频道详情
61
- ```
62
-
63
- ## 工具分类
64
-
65
- ### 群聊管理
66
-
67
- | 工具 | 用途 | 说明 |
68
- |------|------|------|
69
- | `qq_kick_member` | 踢出成员 | — |
70
- | `qq_mute_member` | 禁言 | — |
71
- | `qq_mute_all` | 全员禁言/解除 | — |
72
- | `qq_list_members` | 成员列表 | — |
73
- | `qq_get_group_info` | 群信息 | — |
74
-
75
- ### 频道管理
76
-
77
- | 工具 | 用途 | 说明 |
78
- |------|------|------|
79
- | `qq_list_guilds` | 频道列表 | 获取所有 Guild |
80
- | `qq_list_channels` | 子频道列表 | 获取 Guild 下的 Channel |
81
- | `qq_channel_info` | 子频道详情 | — |
82
- | `qq_member_detail` | 成员详情 | — |
83
-
84
- ### 角色管理
85
-
86
- | 工具 | 用途 | 说明 |
87
- |------|------|------|
88
- | `qq_create_role` | 创建角色 | — |
89
- | `qq_add_role` | 授予角色 | 需 role_id |
90
- | `qq_remove_role` | 移除角色 | 需 role_id |
91
- | `qq_list_roles` | 角色列表 | 获取所有角色及 ID |
92
-
93
- ## 易错点
94
-
95
- 1. **频道操作需要 guild_id + channel_id 二级 ID**,不能只用一个。先 `list_guilds` 再 `list_channels`。
96
- 2. **角色操作需要 role_id**,先 `qq_list_roles` 查询。
97
- 3. **此适配器是 QQ 官方 API**,功能受限于官方开放的接口,不如 NapCat/ICQQ 灵活。
@@ -1,3 +0,0 @@
1
- import { qqEndpointCommands } from '../../../src/qq-endpoint-commands.js';
2
-
3
- export default qqEndpointCommands.add;
@@ -1,3 +0,0 @@
1
- import { qqEndpointCommands } from '../../src/qq-endpoint-commands.js';
2
-
3
- export default qqEndpointCommands.list;
@@ -1,3 +0,0 @@
1
- import { qqEndpointCommands } from '../../../src/qq-endpoint-commands.js';
2
-
3
- export default qqEndpointCommands.remove;
@@ -1,12 +0,0 @@
1
- import { resolveProjectRoot } from 'zhin.js/adapter';
2
- export { resolveProjectRoot };
3
- export interface QqCredentialEnvKeys {
4
- appidKey: string;
5
- secretKey: string;
6
- appidRef: string;
7
- secretRef: string;
8
- }
9
- /** 按 endpoint 名称生成唯一 env 键(如 `QQ_MY_BOT_APPID`) */
10
- export declare function buildQqCredentialEnvKeys(endpointId: string): QqCredentialEnvKeys;
11
- /** 写入或更新 `.env` 中的键值,并同步到当前进程 `process.env` */
12
- export declare function persistQqCredentialsToEnv(endpointId: string, appId: string, appSecret: string, projectRoot?: string): QqCredentialEnvKeys;
@@ -1,22 +0,0 @@
1
- import { buildEndpointEnvKey, persistEndpointEnvValues, resolveProjectRoot, } from 'zhin.js/adapter';
2
- export { resolveProjectRoot };
3
- /** 按 endpoint 名称生成唯一 env 键(如 `QQ_MY_BOT_APPID`) */
4
- export function buildQqCredentialEnvKeys(endpointId) {
5
- const appidKey = buildEndpointEnvKey('qq', endpointId, 'appid');
6
- const secretKey = buildEndpointEnvKey('qq', endpointId, 'secret');
7
- return {
8
- appidKey,
9
- secretKey,
10
- appidRef: `\${${appidKey}}`,
11
- secretRef: `\${${secretKey}}`,
12
- };
13
- }
14
- /** 写入或更新 `.env` 中的键值,并同步到当前进程 `process.env` */
15
- export function persistQqCredentialsToEnv(endpointId, appId, appSecret, projectRoot) {
16
- const keys = buildQqCredentialEnvKeys(endpointId);
17
- persistEndpointEnvValues({
18
- [keys.appidKey]: appId,
19
- [keys.secretKey]: appSecret,
20
- }, projectRoot);
21
- return keys;
22
- }
@@ -1,45 +0,0 @@
1
- /**
2
- * `qq.endpoint` 命令的业务逻辑(与命令定义文件分离,便于测试)。
3
- * 通用部分(权限 / list / remove / 配置写回 / .env 持久化)已迁移到
4
- * @zhin.js/adapter 的 createEndpointCommands 套件;本文件保留 QQ 特化的
5
- * 扫码绑定 add 流程(经套件 bindFlow 钩子接入)与 cancel,并导出
6
- * qqEndpointCommands 供 commands/endpoint/ 下的命令文件默认导出。
7
- */
8
- import { type EndpointCommandReply } from 'zhin.js/adapter';
9
- import { type QqBotKind } from './qq-intents.js';
10
- import { type QqPendingBotKind, type QqRuntimeState } from './qq-runtime-state.js';
11
- export type QqCommandReply = EndpointCommandReply;
12
- /**
13
- * endpoint 管理命令的操作者校验:实例配置声明了 master(顶层或任一端点项)时
14
- * 仅 master 可执行 add/cancel/remove;未配置则放行(首个扫码绑定者即为 owner,
15
- * legacy applyBindOwnership 会把 operator 写为新端点的 master)。
16
- */
17
- export declare function isQqEndpointOperator(config: unknown, input: unknown): boolean;
18
- export declare const QQ_ENDPOINT_FORBIDDEN: string;
19
- /**
20
- * 从命令 input(Runtime Message)提取 $reply;非消息来源(如 Host API 调用)降级为 no-op。
21
- */
22
- export declare function extractQqCommandReply(input: unknown): QqCommandReply;
23
- /** `qq.endpoint list`:运行中的 endpoints(本 generation adapter create 注册)+ 配置里的 endpoints */
24
- export declare function runQqEndpointList(state: QqRuntimeState, projectRoot?: string): string;
25
- /**
26
- * 完成 pending 的公域/私域选择:一次性写 .env + yaml。
27
- * @returns 成功文案;调用方负责清 pending。
28
- */
29
- export declare function completeQqPendingBotKind(pending: QqPendingBotKind, botKind: QqBotKind, projectRoot?: string): string;
30
- /**
31
- * `qq.endpoint add [id]`:启动扫码绑定流程。
32
- * 返回的 Promise 在二维码链接就绪(或前置失败)时 resolve 为首条回复;
33
- * 后续状态(已扫码 / 成功 / 失败 / 过期刷新)通过 reply 推回当前会话。
34
- * 扫码成功后凭据暂存内存并询问公域/私域;确认后一次性写 .env + yaml。
35
- */
36
- export declare function runQqEndpointAdd(state: QqRuntimeState, id: string | undefined, reply: QqCommandReply, projectRoot?: string, input?: unknown): Promise<string>;
37
- /** `qq.endpoint cancel`:中止进行中的绑定或待选 botKind */
38
- export declare function runQqEndpointCancel(state: QqRuntimeState): string;
39
- /** `qq.endpoint remove <id>`:从 zhin.config.yml 移除对应 endpoints 项 */
40
- export declare function runQqEndpointRemove(_state: QqRuntimeState, id: string, projectRoot?: string): string;
41
- /**
42
- * 通用套件生成的 QQ endpoint 命令(add 经 bindFlow 钩子走扫码绑定)。
43
- * commands/endpoint/ 下的 list / add / remove 直接默认导出这三项;cancel 为 QQ 特化,单独定义。
44
- */
45
- export declare const qqEndpointCommands: import("@zhin.js/adapter").EndpointCommands<Readonly<import("@zhin.js/command").CommandDefinition<unknown, unknown, import("@zhin.js/command").CommandMessage, string | undefined>>>;
@@ -1,17 +0,0 @@
1
- export interface QqEndpointConfigEntry {
2
- id: string;
3
- appid: string;
4
- secret: string;
5
- [key: string]: unknown;
6
- }
7
- /** 定位项目配置文件:ZHIN_CONFIG 指定优先,否则发现 zhin.config.yml/.yaml,都没有则默认新建 zhin.config.yml */
8
- export declare function findQqConfigFile(projectRoot?: string): string;
9
- /** 读取 plugins.qq.endpoints(plain JS);plugins/qq 缺失或形态不符时返回 [] */
10
- export declare function listQqEndpointEntries(projectRoot?: string): QqEndpointConfigEntry[];
11
- /** 追加 endpoint 到 plugins.qq.endpoints;id 已存在时报错 */
12
- export declare function addQqEndpointToConfig(entry: QqEndpointConfigEntry, projectRoot?: string): string;
13
- /** 按 id 移除 plugins.qq.endpoints 项;不存在返回 false */
14
- export declare function removeQqEndpointFromConfig(id: string, projectRoot?: string): {
15
- removed: boolean;
16
- filePath: string;
17
- };
@@ -1,22 +0,0 @@
1
- /**
2
- * zhin.config.yml 中 plugins.qq.endpoints 的读写(Plugin Runtime 版)。
3
- * 实现已泛化到 @zhin.js/adapter 的 endpoint-commands 套件(Document 节点级保留注释);
4
- * 本文件仅保留 QQ 专用签名以兼容既有调用与测试。
5
- */
6
- import { addEndpointToConfig, findEndpointConfigFile, listConfiguredEndpoints, removeEndpointFromConfig, } from 'zhin.js/adapter';
7
- /** 定位项目配置文件:ZHIN_CONFIG 指定优先,否则发现 zhin.config.yml/.yaml,都没有则默认新建 zhin.config.yml */
8
- export function findQqConfigFile(projectRoot) {
9
- return findEndpointConfigFile('qq', projectRoot);
10
- }
11
- /** 读取 plugins.qq.endpoints(plain JS);plugins/qq 缺失或形态不符时返回 [] */
12
- export function listQqEndpointEntries(projectRoot) {
13
- return listConfiguredEndpoints('qq', projectRoot);
14
- }
15
- /** 追加 endpoint 到 plugins.qq.endpoints;id 已存在时报错 */
16
- export function addQqEndpointToConfig(entry, projectRoot) {
17
- return addEndpointToConfig('qq', entry, projectRoot);
18
- }
19
- /** 按 id 移除 plugins.qq.endpoints 项;不存在返回 false */
20
- export function removeQqEndpointFromConfig(id, projectRoot) {
21
- return removeEndpointFromConfig('qq', id, projectRoot);
22
- }