@zhin.js/adapter-icqq 1.1.18 → 1.1.20

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 (54) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/README.md +12 -8
  3. package/adapters/icqq/index.js +4 -28
  4. package/adapters/icqq/index.ts +3 -34
  5. package/commands/icqq/endpoint/definition.js +3 -25
  6. package/commands/icqq/endpoint/definition.ts +3 -24
  7. package/commands/icqq/login/code/index.js +3 -3
  8. package/commands/icqq/login/code/index.ts +3 -3
  9. package/commands/icqq/login/confirm/index.js +3 -3
  10. package/commands/icqq/login/confirm/index.ts +3 -3
  11. package/commands/icqq/login/definition.js +2 -2
  12. package/commands/icqq/login/definition.ts +2 -2
  13. package/commands/icqq/login/qr/index.js +3 -3
  14. package/commands/icqq/login/qr/index.ts +3 -3
  15. package/commands/icqq/login/retry/index.js +3 -3
  16. package/commands/icqq/login/retry/index.ts +3 -3
  17. package/commands/icqq/login/status/index.js +3 -3
  18. package/commands/icqq/login/status/index.ts +3 -3
  19. package/lib/adapter.d.ts +13 -0
  20. package/lib/adapter.js +27 -0
  21. package/lib/client.d.ts +6 -9
  22. package/lib/client.js +1 -3
  23. package/lib/console-spec.js +11 -1
  24. package/lib/console.d.ts +1 -7
  25. package/lib/console.js +2 -5
  26. package/lib/endpoint.d.ts +6 -16
  27. package/lib/endpoint.js +195 -143
  28. package/lib/group-moderation.d.ts +6 -3
  29. package/lib/group-moderation.js +9 -8
  30. package/lib/group-scene.d.ts +3 -3
  31. package/lib/group-scene.js +8 -7
  32. package/lib/icqq-login-assist.d.ts +3 -1
  33. package/lib/icqq-login-assist.js +3 -1
  34. package/lib/icqq-login-control.d.ts +8 -2
  35. package/lib/icqq-login-control.js +22 -5
  36. package/lib/index.d.ts +2 -1
  37. package/lib/index.js +1 -1
  38. package/lib/protocol.d.ts +3 -0
  39. package/package.json +18 -18
  40. package/plugin.js +1 -8
  41. package/src/adapter.ts +29 -0
  42. package/src/client.ts +6 -11
  43. package/src/console-spec.ts +9 -0
  44. package/src/console.ts +2 -6
  45. package/src/endpoint.ts +205 -153
  46. package/src/group-moderation.ts +10 -10
  47. package/src/group-scene.ts +8 -8
  48. package/src/icqq-login-assist.ts +6 -2
  49. package/src/icqq-login-control.ts +20 -8
  50. package/src/index.ts +2 -1
  51. package/src/protocol.ts +3 -0
  52. package/lib/icqq-runtime-state.d.ts +0 -1
  53. package/lib/icqq-runtime-state.js +0 -6
  54. package/src/icqq-runtime-state.ts +0 -7
package/CHANGELOG.md CHANGED
@@ -1,5 +1,49 @@
1
1
  # @zhin.js/adapter-icqq
2
2
 
3
+ ## 1.1.20
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [5e878ba]
8
+ - @zhin.js/page@1.1.12
9
+
10
+ ## 1.1.19
11
+
12
+ ### Patch Changes
13
+
14
+ - 2c3610a: Move account lifecycle ownership into the generic Adapter base and let native Endpoints retain their SDK Client inheritance. Infer platform-specific operation Sessions from a single adapter registry while preserving command parameter, option, configuration and factory inference.
15
+
16
+ Bind message replies, management ports, login challenges and Agent cancellation to the captured account incarnation. Persist runtime account intent with encrypted, revision-checked Host storage; keep account management independent of Root process restarts. Require explicit operator confirmation before importing existing accounts, and give replacement accounts a new identity without inheriting previous Sessions.
17
+
18
+ Expose account save, start, stop, update and replacement through the existing adapter Console, with exact account ownership, truthful pending/unknown outcomes and no startup configuration or environment-file rewrites.
19
+
20
+ Complete the target migration across every adapter, the public authoring API, generators, examples and Console. This intentionally removes the old create factory, inheritable Endpoint/ClientEndpoint classes, Client descriptors and file-rewrite account management; plugin authors must use createAdapter, native Client inheritance and the single AdapterRegistry. Satori and OneBot12 require explicit platform/userId selection, and WeCom requires a separate agentId.
21
+
22
+ Verify opaque credential changes before the same configuration snapshot is committed. Drain admitted native callbacks across close/rollback, cancel target work on stop, and keep raw transport parsing, platform ACK timing and SDK native methods under their existing owners. Account metadata conceals credentials carried in URLs.
23
+
24
+ - a9f4e48: PATCH COMPATIBILITY CUTOVER: this batch intentionally changes plugin APIs. The maintainer explicitly chose patch releases with declared version boundaries. Upgrade the complete tested dependency set; patch numbering does not promise compatibility with the removed interfaces.
25
+
26
+ The first planned floors are zhin.js 1.1.19, Core 1.1.54, Adapter 1.1.26, FeatureKit 1.1.10, Plugin Runtime 1.1.18, Runtime/Isolate 1.1.16 and Agent 1.1.45. Keep old-interface plugins with the earlier locked stack until they are migrated. Adapter's independent Feature API changes from 1.0.0 to 2.0.0; official consumers declare ^2.0.0. Existing Feature API admission rejects explicitly incompatible ranges; omitted API metadata keeps its existing behavior and does not certify compatibility. Runtime engine and patch-only release gates remain unchanged.
27
+
28
+ Use the native-Client Adapter target contract, canonical FeatureKit AdapterRegistry augmentation and named Endpoint control/management requests. Route message controls from canonical message/conversation refs; retain exact source authority and propagate caller/account/explicit-Root-stop cancellation. Replace removed Agent activity feedback exports with source-bound feedback. HMR pause/resume belongs to concrete plugin instances; plugins choose accepted-work policy without changing Controller commit/rollback authority. Cooperative worker/process control cancellation does not kill an isolate or reopen retired business admission.
29
+
30
+ Provide authenticated historical-data preview, exact selected binding, transactional application, authoritative inspection and explicit resumption, including active games. Preserve before-images and journals; never replay an unconfirmed effect, infer an account from an alias, or reuse historical permission grants. Owner V2 approvals remain inactive legacy data, while new writes use V3. Rollback requires matching software, lockfile and verified data; installing old code alone cannot read a new V3 approval file. Conflicting after-images are never overwritten.
31
+
32
+ See docs/plans/adapter-operation-version-boundaries.md and the Chinese/English upgrade guide for the complete version inventory, custom-plugin changes, acceptance and recovery sequence. These code and metadata changes do not authorize merging, publication, deployment, login, production migration or removal of installed workspace patches.
33
+
34
+ - Updated dependencies [2c3610a]
35
+ - Updated dependencies [a9f4e48]
36
+ - Updated dependencies [f8505b0]
37
+ - @zhin.js/adapter@1.1.26
38
+ - @zhin.js/feature-kit@1.1.10
39
+ - @zhin.js/core@1.1.54
40
+ - @zhin.js/client@1.1.22
41
+ - @zhin.js/page@1.1.11
42
+ - @zhin.js/agent-feature@1.1.11
43
+ - @zhin.js/skill@1.1.11
44
+ - @zhin.js/tool@1.1.13
45
+ - @zhin.js/permission@1.1.10
46
+
3
47
  ## 1.1.18
4
48
 
5
49
  ### Patch Changes
package/README.md CHANGED
@@ -5,7 +5,7 @@ ICQQ Plugin Runtime 适配器 — 进程内直接使用 [@icqqjs/icqq](https://g
5
5
  ## 功能特性
6
6
 
7
7
  - 群聊 / 私聊 / 群临时会话 / QQ 频道消息
8
- - 入站:ICQQ Client 原始事件经 `Endpoint.emit(...)` 唯一入口上送;文本与图片 / 语音 / 视频 / 文件统一归一为 canonical `Segment` + `MediaRef`
8
+ - 入站:ICQQ Client 原始事件经 `endpoint[endpointSpec].events` 唯一入口上送;文本与图片 / 语音 / 视频 / 文件统一归一为 canonical `Segment` + `MediaRef`
9
9
  - 出站:canonical Segment 直接投影为 ICQQ 原生 `Sendable`,再由 `sendGroupMsg` / `sendPrivateMsg` / …发送
10
10
  - 群聊 reaction:`control.addReaction` / `removeReaction`(协议 ACK 失败不阻塞后续发送)
11
11
  - Agent 工具:按职责拆分在 `agents/icqq/skills/icqq-*/tools/`,只在对应 Skill 激活后披露
@@ -97,9 +97,9 @@ export default defineHandler({
97
97
  })
98
98
  ```
99
99
 
100
- `client` 就是当前账号的真实 ICQQ SDK 实例,不是 Endpoint facade。未知扩展事件可显式使用
100
+ 原生 Handler 参数中的 `client` 就是当前账号的真实 ICQQ SDK 实例,`event` 保留同一原生事件对象、原型和方法。消息操作的 `session.endpoint`、`session.event` 与 `session.adapter` 分别提供同一个实际 Endpoint、原始消息事件和所属 Adapter。未知扩展事件可显式使用
101
101
  `event: '*'`;此时 Client 类型保持完整,事件 payload 为 `unknown`。普通消息回复仍应走
102
- `Message.$reply`;群管理、请求审批与 ICQQ 专属查询可直接调用当前事件的 `client`。
102
+ `Message.$reply`;群管理、请求审批与 ICQQ 专属查询可直接调用当前 Session 的 Endpoint。
103
103
 
104
104
  Command context 的 `$client` 是按需读取的 getter:
105
105
 
@@ -140,16 +140,16 @@ export default defineAgentTool({
140
140
 
141
141
  `adapter` 缺失时 `$client` 静态类型为 `unknown`;声明后若实际 operation 不属于 ICQQ,
142
142
  运行时会在执行前拒绝。Client 只能在当前 operation 内使用。task、schedule 或 Host 等脱离
143
- IM turn 的场景,才使用 `icqqClient.get(context, endpointId)` 显式选择账号。
143
+ IM turn 的场景,应通过 Host 提供的显式账号作用域操作,不能缓存旧 Client 或从另一个可写目录选择账号。
144
144
 
145
145
  ## 架构
146
146
 
147
147
  - `plugin.ts` + `adapters/icqq/index.ts`:Plugin Runtime 入口与 `defineAdapter` 声明
148
- - `src/endpoint.ts`:组合 ICQQ `Client`,只协调账号 transport、Zhin lifecycle 与各能力端口
148
+ - `src/endpoint.ts`:继承真实 ICQQ `Client`,只协调账号 transport、Zhin lifecycle 与各能力端口
149
149
  - `src/content-resolver.ts`:保存已观察消息,并按深度和条数限制递归展开合并转发
150
150
  - `src/icqq-inbound.ts`:把 ICQQ 原生消息归一为 Zhin 入站消息
151
151
  - `src/protocol.ts`:配置解析、会话映射与出站目标转换
152
- - `src/client.ts`:向插件作者暴露 ICQQ `Client` / `EventMap` 类型注册
152
+ - `src/client.ts`:从原生 SDK 推导事件类型,并将实际 `IcqqAdapter` 注册到唯一 `AdapterRegistry`
153
153
  - Agent 工具:`agents/icqq/skills/icqq-*/tools/<name>/index.ts`;权限说明见 `PERMITS.md`
154
154
 
155
155
  阅读适配器实现时从 `endpoint.ts` 看能力装配,再进入对应能力文件。包外代码只从
@@ -163,7 +163,7 @@ IM turn 的场景,才使用 `icqqClient.get(context, endpointId)` 显式选择
163
163
  - ICQQ 的语音、视频、文件是独立消息元素;它们与其他段混发时适配器会明确拒绝,避免协议栈静默丢段。
164
164
  - 入站语音 / 视频在 Endpoint 持有原生 Client 时解析可下载 URL;解析失败则保留真实平台引用,不伪造或丢弃媒体。
165
165
  - **Console 社交/群管 RPC 已接线**:endpoint 把好友/群/群成员列表、请求审批和群管操作归一化为冻结的 `EndpointManagement`。Host 只消费该语义端口。
166
- - 好友/入群请求与通知:经 the unified `Endpoint.emit(...)` ingress 分发到 `handlers`(`notice.receive` / `request.receive`);审批走 `Request.$approve` / `EndpointManagement.approveRequest`。Console `request.list` 优先读 `management.listRequests()`(`getSystemMsg`),不再写入 `unified_inbox_request/notice`。
166
+ - 好友/入群请求与通知:经 the unified `endpoint[endpointSpec].events` ingress 分发到 `handlers`(`notice.receive` / `request.receive`);审批走 `Request.$approve` / `EndpointManagement.approveRequest`。Console `request.list` 优先读 `management.listRequests()`(`getSystemMsg`),不再写入 `unified_inbox_request/notice`。
167
167
  - `system.*`(登录扫码等)分发到 `system.receive`。
168
168
  - **登录辅助**:`system.login.qrcode|slider|device|auth` 经 `loginAssistToken`(`LoginAssist`)挂起待办;刷新后可用 Console `login.list` / `login.submit` 或终端 stdin 继续(对齐 icqq 官方 stdin 流程)。`system.online` / `login.error` 会清理该 endpoint 待办。
169
169
 
@@ -178,13 +178,17 @@ ICQQ Agent 可按需加载 `icqq-conversation` 查询当前群/频道和 Bot
178
178
  启动后打开 Console 的「ICQQ」页(地址 `/icqq`),可以:
179
179
 
180
180
  - 查看运行中的连接、点「测试连接」做连通性诊断;
181
- - 增删 `plugins.icqq.endpoints`(凭据写入 `.env`,配置里只保留 `${ENV}` 引用);
181
+ - 在账号库保存、修改、启动、停止、替换或删除该 Adapter 的账号;新增仅保存,不创建 SDK Client,需手动启动;
182
182
  - 处理登录待办(扫码 / 滑块 / 设备确认等,来自 LoginAssist);
183
183
 
184
184
  ICQQ 首次登录的二维码、滑块、设备确认会出现在「登录待办」里,不需要再回到终端确认。
185
185
 
186
186
  读取需要 `icqq:read`,写操作需要 `icqq:write`;管理员 full token 不受限。页面里的「添加 endpoint」等价于原来的 `icqq endpoint add`。
187
187
 
188
+ 首次修改启动配置里的既有账号前,管理员必须核对清单并确认一次迁移。原 canonical 身份与历史保留,完整账号配置加密进入 Host 数据库;此后账号管理只写数据库,不修改启动文件或 `.env`,不重启进程。没有持久化账号端口的环境可使用静态配置连接,动态写操作明确不可用。
189
+
190
+ 启停意图在进程重启后恢复。停止或删除会取消并关闭目标账号的在途操作,其他账号继续运行;删除保留历史。已启动账号的连接配置更新先关闭旧 incarnation,再仅重连该账号;平台身份变化按替换处理,分配新内部身份、保留旧历史,新账号不继承旧 Session、个人设置或启动意图。提交结果未知时先刷新核实,不自动重复 CAS 或平台操作。
191
+
188
192
  ## 掉线通知与重新登录
189
193
 
190
194
  配置 `notify` 后,ICQQ 被踢下线、登录失败或启动失败时,会通过另一个适配器实例给 master 发通知。例如用 QQ 官方机器人实例通知:
@@ -1,15 +1,10 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
- import { projectLocaleToken } from 'zhin.js/i18n';
2
+ import { IcqqAdapter } from "../../lib/adapter.js";
3
3
  /**
4
4
  * Convention entry: discover `adapters/icqq/index.ts` → defineAdapter.
5
5
  */
6
- import { createAdapterOutageNotifier, defineAdapter } from 'zhin.js/adapter';
7
- import { loginAssistToken } from '@zhin.js/core/runtime';
8
- import { outboundHostToken } from 'zhin.js';
9
- import { IcqqEndpoint } from "../../lib/endpoint.js";
10
- import { icqqRuntimeStateToken } from "../../lib/icqq-runtime-state.js";
11
- import { icqqLoginControlToken } from "../../lib/icqq-login-control.js";
12
- import { resolveIcqqConfig, } from "../../lib/protocol.js";
6
+ import { defineAdapter } from 'zhin.js/adapter';
7
+ import {} from "../../lib/protocol.js";
13
8
  export { IcqqEndpoint } from "../../lib/endpoint.js";
14
9
  export default defineAdapter({
15
10
  capabilities: ['inbound', 'outbound'],
@@ -39,24 +34,5 @@ export default defineAdapter({
39
34
  },
40
35
  },
41
36
  },
42
- create(context) {
43
- const config = resolveIcqqConfig(context.config);
44
- // 注册到插件运行时状态(icqq endpoint list 的"运行中"数据源)
45
- context.use(icqqRuntimeStateToken).endpoints.set(config.id, {
46
- id: config.id,
47
- mode: 'direct',
48
- });
49
- const outbound = context.has?.(outboundHostToken) ? context.use(outboundHostToken) : undefined;
50
- const endpoint = new IcqqEndpoint({
51
- id: context.id,
52
- loginAssist: context.use(loginAssistToken),
53
- locale: context.use(projectLocaleToken),
54
- config,
55
- notifier: createAdapterOutageNotifier(outbound, config.notify),
56
- });
57
- if (context.has?.(icqqLoginControlToken)) {
58
- context.use(icqqLoginControlToken).set(config.id, endpoint.loginControl);
59
- }
60
- return endpoint;
61
- },
37
+ createAdapter: context => new IcqqAdapter(context),
62
38
  });
@@ -1,27 +1,15 @@
1
- import { projectLocaleToken } from 'zhin.js/i18n';
1
+ import { IcqqAdapter } from '../../src/adapter.js';
2
2
  /**
3
3
  * Convention entry: discover `adapters/icqq/index.ts` → defineAdapter.
4
4
  */
5
- import { createAdapterOutageNotifier, defineAdapter } from 'zhin.js/adapter';
6
- import { loginAssistToken } from '@zhin.js/core/runtime';
7
- import { outboundHostToken } from 'zhin.js';
8
- import { IcqqEndpoint } from '../../src/endpoint.js';
9
- import { icqqRuntimeStateToken } from '../../src/icqq-runtime-state.js';
10
- import { icqqLoginControlToken } from '../../src/icqq-login-control.js';
5
+ import { defineAdapter } from 'zhin.js/adapter';
11
6
  import {
12
- resolveIcqqConfig,
13
7
  type IcqqEndpointConfig,
14
8
  } from '../../src/protocol.js';
15
9
 
16
10
  export { IcqqEndpoint } from '../../src/endpoint.js';
17
11
  export type { IcqqEndpointOptions } from '../../src/endpoint.js';
18
12
 
19
- declare module '@zhin.js/core' {
20
- interface AdapterEndpoints {
21
- icqq: import('../../src/endpoint.js').IcqqEndpoint;
22
- }
23
- }
24
-
25
13
  export default defineAdapter<IcqqEndpointConfig>({
26
14
  capabilities: ['inbound', 'outbound'],
27
15
  operations: ['recall', 'reaction'],
@@ -50,24 +38,5 @@ export default defineAdapter<IcqqEndpointConfig>({
50
38
  },
51
39
  },
52
40
  },
53
- create(context) {
54
- const config = resolveIcqqConfig(context.config);
55
- // 注册到插件运行时状态(icqq endpoint list 的"运行中"数据源)
56
- context.use(icqqRuntimeStateToken).endpoints.set(config.id, {
57
- id: config.id,
58
- mode: 'direct',
59
- });
60
- const outbound = context.has?.(outboundHostToken) ? context.use(outboundHostToken) : undefined;
61
- const endpoint = new IcqqEndpoint({
62
- id: context.id,
63
- loginAssist: context.use(loginAssistToken),
64
- locale: context.use(projectLocaleToken),
65
- config,
66
- notifier: createAdapterOutageNotifier(outbound, config.notify),
67
- });
68
- if (context.has?.(icqqLoginControlToken)) {
69
- context.use(icqqLoginControlToken).set(config.id, endpoint.loginControl);
70
- }
71
- return endpoint;
72
- },
41
+ createAdapter: context => new IcqqAdapter(context),
73
42
  });
@@ -1,33 +1,11 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
2
  import { messages as t } from "../../../lib/i18n.js";
3
- import { createEndpointCommands, endpointConfigurationStoreToken } from 'zhin.js/adapter';
3
+ import { createEndpointCommands } from 'zhin.js/adapter';
4
4
  import { defineCommand } from 'zhin.js/command';
5
- import { icqqRuntimeStateToken } from "../../../lib/icqq-runtime-state.js";
6
5
  export const icqqEndpointCommands = createEndpointCommands({
7
6
  adapterKey: 'icqq',
8
7
  adapterDisplayName: 'ICQQ',
9
- running: (use) => use(icqqRuntimeStateToken).endpoints.values(),
10
8
  describeEntry: (_entry, locale) => t(locale, 'direct'),
11
- addDescription: '登记 ICQQ endpoint(重启 zhin 生效)',
12
- addDescriptionI18n: { en: 'Register an ICQQ endpoint; restart zhin to apply' },
13
- bindFlow: async ({ id, use, locale, formatCommand }) => {
14
- if (!id) {
15
- const command = formatCommand?.('icqq endpoint add');
16
- return command ? t(locale, 'addUsage', { command }) : t(locale, 'uinRequired');
17
- }
18
- if (!/^\d+$/.test(id)) {
19
- return t(locale, 'uinInvalid');
20
- }
21
- try {
22
- const { filePath } = await use(endpointConfigurationStoreToken).add({
23
- adapterKey: 'icqq',
24
- entry: { id },
25
- environment: {},
26
- });
27
- return t(locale, 'endpointAdded', { id, file: filePath });
28
- }
29
- catch (error) {
30
- return t(locale, 'endpointAddFailed', { error: error instanceof Error ? error.message : String(error) });
31
- }
32
- },
9
+ addDescription: '保存 ICQQ 账号;保存后需手动启动',
10
+ addDescriptionI18n: { en: 'Save an ICQQ account; start it explicitly after saving' },
33
11
  }, defineCommand);
@@ -1,32 +1,11 @@
1
1
  import { messages as t } from '../../../src/i18n.js';
2
- import { createEndpointCommands, endpointConfigurationStoreToken } from 'zhin.js/adapter';
2
+ import { createEndpointCommands } from 'zhin.js/adapter';
3
3
  import { defineCommand } from 'zhin.js/command';
4
- import { icqqRuntimeStateToken } from '../../../src/icqq-runtime-state.js';
5
4
 
6
5
  export const icqqEndpointCommands = createEndpointCommands({
7
6
  adapterKey: 'icqq',
8
7
  adapterDisplayName: 'ICQQ',
9
- running: (use) => use(icqqRuntimeStateToken).endpoints.values(),
10
8
  describeEntry: (_entry, locale) => t(locale, 'direct'),
11
- addDescription: '登记 ICQQ endpoint(重启 zhin 生效)',
12
- addDescriptionI18n: { en: 'Register an ICQQ endpoint; restart zhin to apply' },
13
- bindFlow: async ({ id, use, locale, formatCommand }) => {
14
- if (!id) {
15
- const command = formatCommand?.('icqq endpoint add');
16
- return command ? t(locale, 'addUsage', { command }) : t(locale, 'uinRequired');
17
- }
18
- if (!/^\d+$/.test(id)) {
19
- return t(locale, 'uinInvalid');
20
- }
21
- try {
22
- const { filePath } = await use(endpointConfigurationStoreToken).add({
23
- adapterKey: 'icqq',
24
- entry: { id },
25
- environment: {},
26
- });
27
- return t(locale, 'endpointAdded', { id, file: filePath });
28
- } catch (error) {
29
- return t(locale, 'endpointAddFailed', { error: error instanceof Error ? error.message : String(error) });
30
- }
31
- },
9
+ addDescription: '保存 ICQQ 账号;保存后需手动启动',
10
+ addDescriptionI18n: { en: 'Save an ICQQ account; start it explicitly after saving' },
32
11
  }, defineCommand);
@@ -1,13 +1,13 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
2
  import { defineCommand } from 'zhin.js/command';
3
- import { icqqLoginControlToken, icqqLoginForbidden, isIcqqLoginOperator, pendingTaskLabel, pickIcqqLoginControl, } from '../definition.js';
3
+ import { icqqLoginControls, icqqLoginForbidden, isIcqqLoginOperator, pendingTaskLabel, pickIcqqLoginControl, } from '../definition.js';
4
4
  export default defineCommand({
5
5
  description: '提交 ICQQ 滑块/短信/设备验证内容',
6
6
  descriptionI18n: { en: 'Submit an ICQQ slider, SMS or device verification value' },
7
- async execute({ args, config, input, use }) {
7
+ async execute({ args, config, input, project, owner }) {
8
8
  if (!isIcqqLoginOperator(config, input))
9
9
  return icqqLoginForbidden();
10
- const controls = use(icqqLoginControlToken);
10
+ const controls = icqqLoginControls({ project, owner });
11
11
  // One endpoint: the whole argument is the code. Multiple: first arg selects the UIN.
12
12
  const requested = controls.size > 1 ? args[0] : undefined;
13
13
  const value = (controls.size > 1 ? args.slice(1) : args).join(' ').trim();
@@ -1,6 +1,6 @@
1
1
  import { defineCommand } from 'zhin.js/command';
2
2
  import {
3
- icqqLoginControlToken,
3
+ icqqLoginControls,
4
4
  icqqLoginForbidden,
5
5
  isIcqqLoginOperator,
6
6
  pendingTaskLabel,
@@ -10,9 +10,9 @@ import {
10
10
  export default defineCommand({
11
11
  description: '提交 ICQQ 滑块/短信/设备验证内容',
12
12
  descriptionI18n: { en: 'Submit an ICQQ slider, SMS or device verification value' },
13
- async execute({ args, config, input, use }) {
13
+ async execute({ args, config, input, project, owner }) {
14
14
  if (!isIcqqLoginOperator(config, input)) return icqqLoginForbidden();
15
- const controls = use(icqqLoginControlToken);
15
+ const controls = icqqLoginControls({ project, owner });
16
16
  // One endpoint: the whole argument is the code. Multiple: first arg selects the UIN.
17
17
  const requested = controls.size > 1 ? args[0] : undefined;
18
18
  const value = (controls.size > 1 ? args.slice(1) : args).join(' ').trim();
@@ -1,13 +1,13 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
2
  import { defineCommand } from 'zhin.js/command';
3
- import { icqqLoginControlToken, icqqLoginForbidden, isIcqqLoginOperator, pickIcqqLoginControl, } from '../definition.js';
3
+ import { icqqLoginControls, icqqLoginForbidden, isIcqqLoginOperator, pickIcqqLoginControl, } from '../definition.js';
4
4
  export default defineCommand({
5
5
  description: '确认已完成 ICQQ 扫码登录',
6
6
  descriptionI18n: { en: 'Confirm the ICQQ QR login was scanned' },
7
- async execute({ args, config, input, use }) {
7
+ async execute({ args, config, input, project, owner }) {
8
8
  if (!isIcqqLoginOperator(config, input))
9
9
  return icqqLoginForbidden();
10
- const picked = pickIcqqLoginControl(use(icqqLoginControlToken), args[0]);
10
+ const picked = pickIcqqLoginControl(icqqLoginControls({ project, owner }), args[0]);
11
11
  if (!picked.control)
12
12
  return picked.text ?? 'ICQQ 适配器还没有启动';
13
13
  const task = picked.control.pending().find((item) => item.type === 'qrcode' || item.type === 'auth');
@@ -1,6 +1,6 @@
1
1
  import { defineCommand } from 'zhin.js/command';
2
2
  import {
3
- icqqLoginControlToken,
3
+ icqqLoginControls,
4
4
  icqqLoginForbidden,
5
5
  isIcqqLoginOperator,
6
6
  pickIcqqLoginControl,
@@ -9,9 +9,9 @@ import {
9
9
  export default defineCommand({
10
10
  description: '确认已完成 ICQQ 扫码登录',
11
11
  descriptionI18n: { en: 'Confirm the ICQQ QR login was scanned' },
12
- async execute({ args, config, input, use }) {
12
+ async execute({ args, config, input, project, owner }) {
13
13
  if (!isIcqqLoginOperator(config, input)) return icqqLoginForbidden();
14
- const picked = pickIcqqLoginControl(use(icqqLoginControlToken), args[0]);
14
+ const picked = pickIcqqLoginControl(icqqLoginControls({ project, owner }), args[0]);
15
15
  if (!picked.control) return picked.text ?? 'ICQQ 适配器还没有启动';
16
16
  const task = picked.control.pending().find((item) => item.type === 'qrcode' || item.type === 'auth');
17
17
  if (!task) return '当前没有等待确认的扫码登录;发送 `icqq login qr` 获取二维码。';
@@ -7,8 +7,8 @@
7
7
  * master can fetch the QR image and confirm/send verification codes without the
8
8
  * Console or terminal.
9
9
  */
10
- import { icqqLoginControlToken } from "../../../lib/icqq-login-control.js";
11
- export { icqqLoginControlToken };
10
+ import { icqqLoginControls } from "../../../lib/icqq-login-control.js";
11
+ export { icqqLoginControls };
12
12
  /** Master = framework master(s), or the configured outage-notify conversation id(s). */
13
13
  export function isIcqqLoginOperator(config, input) {
14
14
  const cfg = (config ?? {});
@@ -6,9 +6,9 @@
6
6
  * master can fetch the QR image and confirm/send verification codes without the
7
7
  * Console or terminal.
8
8
  */
9
- import { icqqLoginControlToken, type IcqqLoginControl } from '../../../src/icqq-login-control.js';
9
+ import { icqqLoginControls, type IcqqLoginControl } from '../../../src/icqq-login-control.js';
10
10
 
11
- export { icqqLoginControlToken };
11
+ export { icqqLoginControls };
12
12
 
13
13
  /** Master = framework master(s), or the configured outage-notify conversation id(s). */
14
14
  export function isIcqqLoginOperator(config: unknown, input: unknown): boolean {
@@ -1,14 +1,14 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
2
  import { defineCommand } from 'zhin.js/command';
3
- import { icqqLoginControlToken, icqqLoginForbidden, isIcqqLoginOperator, pickIcqqLoginControl, } from '../definition.js';
3
+ import { icqqLoginControls, icqqLoginForbidden, isIcqqLoginOperator, pickIcqqLoginControl, } from '../definition.js';
4
4
  const QR_IMAGE = /^data:image\/[a-z0-9.+-]+;base64,(.+)$/iu;
5
5
  export default defineCommand({
6
6
  description: '获取 ICQQ 登录二维码(发给当前会话)',
7
7
  descriptionI18n: { en: 'Fetch the ICQQ login QR code into this conversation' },
8
- async execute({ args, config, input, use }) {
8
+ async execute({ args, config, input, project, owner }) {
9
9
  if (!isIcqqLoginOperator(config, input))
10
10
  return icqqLoginForbidden();
11
- const picked = pickIcqqLoginControl(use(icqqLoginControlToken), args[0]);
11
+ const picked = pickIcqqLoginControl(icqqLoginControls({ project, owner }), args[0]);
12
12
  if (!picked.control)
13
13
  return picked.text ?? 'ICQQ 适配器还没有启动';
14
14
  const control = picked.control;
@@ -1,6 +1,6 @@
1
1
  import { defineCommand } from 'zhin.js/command';
2
2
  import {
3
- icqqLoginControlToken,
3
+ icqqLoginControls,
4
4
  icqqLoginForbidden,
5
5
  isIcqqLoginOperator,
6
6
  pickIcqqLoginControl,
@@ -11,9 +11,9 @@ const QR_IMAGE = /^data:image\/[a-z0-9.+-]+;base64,(.+)$/iu;
11
11
  export default defineCommand({
12
12
  description: '获取 ICQQ 登录二维码(发给当前会话)',
13
13
  descriptionI18n: { en: 'Fetch the ICQQ login QR code into this conversation' },
14
- async execute({ args, config, input, use }) {
14
+ async execute({ args, config, input, project, owner }) {
15
15
  if (!isIcqqLoginOperator(config, input)) return icqqLoginForbidden();
16
- const picked = pickIcqqLoginControl(use(icqqLoginControlToken), args[0]);
16
+ const picked = pickIcqqLoginControl(icqqLoginControls({ project, owner }), args[0]);
17
17
  if (!picked.control) return picked.text ?? 'ICQQ 适配器还没有启动';
18
18
  const control = picked.control;
19
19
  const findQr = () => control.pending().find((task) => task.type === 'qrcode' || task.type === 'auth');
@@ -1,13 +1,13 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
2
  import { defineCommand } from 'zhin.js/command';
3
- import { icqqLoginControlToken, icqqLoginForbidden, isIcqqLoginOperator, pickIcqqLoginControl, } from '../definition.js';
3
+ import { icqqLoginControls, icqqLoginForbidden, isIcqqLoginOperator, pickIcqqLoginControl, } from '../definition.js';
4
4
  export default defineCommand({
5
5
  description: '重新触发 ICQQ 登录',
6
6
  descriptionI18n: { en: 'Trigger an ICQQ login attempt again' },
7
- async execute({ args, config, input, use }) {
7
+ async execute({ args, config, input, project, owner }) {
8
8
  if (!isIcqqLoginOperator(config, input))
9
9
  return icqqLoginForbidden();
10
- const picked = pickIcqqLoginControl(use(icqqLoginControlToken), args[0]);
10
+ const picked = pickIcqqLoginControl(icqqLoginControls({ project, owner }), args[0]);
11
11
  if (!picked.control)
12
12
  return picked.text ?? 'ICQQ 适配器还没有启动';
13
13
  try {
@@ -1,6 +1,6 @@
1
1
  import { defineCommand } from 'zhin.js/command';
2
2
  import {
3
- icqqLoginControlToken,
3
+ icqqLoginControls,
4
4
  icqqLoginForbidden,
5
5
  isIcqqLoginOperator,
6
6
  pickIcqqLoginControl,
@@ -9,9 +9,9 @@ import {
9
9
  export default defineCommand({
10
10
  description: '重新触发 ICQQ 登录',
11
11
  descriptionI18n: { en: 'Trigger an ICQQ login attempt again' },
12
- async execute({ args, config, input, use }) {
12
+ async execute({ args, config, input, project, owner }) {
13
13
  if (!isIcqqLoginOperator(config, input)) return icqqLoginForbidden();
14
- const picked = pickIcqqLoginControl(use(icqqLoginControlToken), args[0]);
14
+ const picked = pickIcqqLoginControl(icqqLoginControls({ project, owner }), args[0]);
15
15
  if (!picked.control) return picked.text ?? 'ICQQ 适配器还没有启动';
16
16
  try {
17
17
  await picked.control.relogin();
@@ -1,13 +1,13 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
2
  import { defineCommand } from 'zhin.js/command';
3
- import { icqqLoginControlToken, icqqLoginForbidden, isIcqqLoginOperator, pendingTaskLabel, pickIcqqLoginControl, } from '../definition.js';
3
+ import { icqqLoginControls, icqqLoginForbidden, isIcqqLoginOperator, pendingTaskLabel, pickIcqqLoginControl, } from '../definition.js';
4
4
  export default defineCommand({
5
5
  description: '查看 ICQQ 掉线状态与登录待办',
6
6
  descriptionI18n: { en: 'Show ICQQ offline status and pending login tasks' },
7
- async execute({ args, config, input, use }) {
7
+ async execute({ args, config, input, project, owner }) {
8
8
  if (!isIcqqLoginOperator(config, input))
9
9
  return icqqLoginForbidden();
10
- const picked = pickIcqqLoginControl(use(icqqLoginControlToken), args[0]);
10
+ const picked = pickIcqqLoginControl(icqqLoginControls({ project, owner }), args[0]);
11
11
  if (!picked.control)
12
12
  return picked.text ?? 'ICQQ 适配器还没有启动';
13
13
  const state = picked.control.state();
@@ -1,6 +1,6 @@
1
1
  import { defineCommand } from 'zhin.js/command';
2
2
  import {
3
- icqqLoginControlToken,
3
+ icqqLoginControls,
4
4
  icqqLoginForbidden,
5
5
  isIcqqLoginOperator,
6
6
  pendingTaskLabel,
@@ -10,9 +10,9 @@ import {
10
10
  export default defineCommand({
11
11
  description: '查看 ICQQ 掉线状态与登录待办',
12
12
  descriptionI18n: { en: 'Show ICQQ offline status and pending login tasks' },
13
- async execute({ args, config, input, use }) {
13
+ async execute({ args, config, input, project, owner }) {
14
14
  if (!isIcqqLoginOperator(config, input)) return icqqLoginForbidden();
15
- const picked = pickIcqqLoginControl(use(icqqLoginControlToken), args[0]);
15
+ const picked = pickIcqqLoginControl(icqqLoginControls({ project, owner }), args[0]);
16
16
  if (!picked.control) return picked.text ?? 'ICQQ 适配器还没有启动';
17
17
  const state = picked.control.state();
18
18
  const lines = [
@@ -0,0 +1,13 @@
1
+ import { Adapter, type AdapterContext, type EndpointCreationContext } from 'zhin.js/adapter';
2
+ import { IcqqEndpoint } from './endpoint.js';
3
+ import { type IcqqEndpointConfig } from './protocol.js';
4
+ import type { IcqqClientEventMap } from './client.js';
5
+ /** ICQQ account construction and actual SDK ownership belong to this Adapter. */
6
+ export declare class IcqqAdapter extends Adapter<IcqqEndpoint, IcqqEndpointConfig, IcqqClientEventMap> {
7
+ #private;
8
+ get configurationIdentityFields(): readonly string[];
9
+ get configurationUpdateFields(): readonly string[];
10
+ constructor(context: AdapterContext<IcqqEndpointConfig>);
11
+ protected validateConfiguration(config: IcqqEndpointConfig): void;
12
+ protected createEndpoint(input: IcqqEndpointConfig, execution: EndpointCreationContext): IcqqEndpoint;
13
+ }
package/lib/adapter.js ADDED
@@ -0,0 +1,27 @@
1
+ import { Adapter, createAdapterOutageNotifier } from 'zhin.js/adapter';
2
+ import { projectLocaleToken } from 'zhin.js/i18n';
3
+ import { loginAssistToken } from '@zhin.js/core/runtime';
4
+ import { outboundHostToken } from 'zhin.js';
5
+ import { IcqqEndpoint } from './endpoint.js';
6
+ import { resolveIcqqConfig } from './protocol.js';
7
+ /** ICQQ account construction and actual SDK ownership belong to this Adapter. */
8
+ export class IcqqAdapter extends Adapter {
9
+ get configurationIdentityFields() { return ['id']; }
10
+ get configurationUpdateFields() {
11
+ return ['password', 'platform', 'ver', 'dataDir', 'signApiAddr', 'autoReconnect', 'autoServer', 'qqnt', 'ntLogin'];
12
+ }
13
+ #context;
14
+ constructor(context) { super(); this.#context = context; }
15
+ validateConfiguration(config) { resolveIcqqConfig(config); }
16
+ createEndpoint(input, execution) {
17
+ const context = this.#context;
18
+ const config = resolveIcqqConfig(input);
19
+ const outbound = context.has?.(outboundHostToken) ? context.use(outboundHostToken) : undefined;
20
+ const endpoint = new IcqqEndpoint({ id: execution.canonicalId, config,
21
+ signal: execution.signal, endpointIdentity: { canonicalId: execution.canonicalId, instanceId: execution.instanceId, epoch: execution.epoch, incarnationId: execution.incarnationId },
22
+ loginAssist: context.use(loginAssistToken), locale: context.use(projectLocaleToken),
23
+ notifier: createAdapterOutageNotifier(outbound, config.notify),
24
+ });
25
+ return endpoint;
26
+ }
27
+ }
package/lib/client.d.ts CHANGED
@@ -1,19 +1,16 @@
1
- import type { Client, EventMap } from '@icqqjs/icqq';
1
+ import type { IcqqAdapter } from './adapter.js';
2
+ import type { IcqqEndpoint } from './endpoint.js';
3
+ import type { EventMap } from '@icqqjs/icqq';
2
4
  type EventPayload<TListener> = TListener extends (event: infer TEvent, ...rest: readonly unknown[]) => unknown ? TEvent : never;
3
5
  /** The actual ICQQ SDK instance exposed by every ICQQ Endpoint event. */
4
- export type IcqqClient = Client;
6
+ export type IcqqClient = IcqqEndpoint;
5
7
  /** Native ICQQ event-name → first public event payload, derived from the SDK SSOT. */
6
8
  export type IcqqClientEventMap = {
7
9
  readonly [TName in keyof EventMap]: EventPayload<EventMap[TName]>;
8
10
  };
9
11
  declare module '@zhin.js/feature-kit' {
10
- interface AdapterClientRegistry {
11
- readonly icqq: {
12
- readonly client: IcqqClient;
13
- readonly events: IcqqClientEventMap;
14
- };
12
+ interface AdapterRegistry {
13
+ readonly icqq: IcqqAdapter;
15
14
  }
16
15
  }
17
- /** Typed, generation-checked identity used by handlers, commands, tools and schedules. */
18
- export declare const icqqClient: import("@zhin.js/adapter").EndpointClientToken<Client, IcqqClientEventMap>;
19
16
  export {};
package/lib/client.js CHANGED
@@ -1,3 +1 @@
1
- import { defineEndpointClient } from 'zhin.js/adapter';
2
- /** Typed, generation-checked identity used by handlers, commands, tools and schedules. */
3
- export const icqqClient = defineEndpointClient('icqq');
1
+ export {};
@@ -1,7 +1,17 @@
1
1
  export const icqqConsoleSpec = {
2
2
  adapterKey: 'icqq',
3
3
  adapterDisplayName: 'ICQQ',
4
- fields: [],
4
+ fields: [
5
+ { key: 'password', env: true, description: 'QQ password; leave blank to retain the saved credential' },
6
+ { key: 'platform', type: 'number', description: 'ICQQ platform number' },
7
+ { key: 'ver', description: 'ICQQ protocol version' },
8
+ { key: 'dataDir', description: 'ICQQ device and session directory' },
9
+ { key: 'signApiAddr', description: 'ICQQ signing service URL' },
10
+ { key: 'autoReconnect', type: 'boolean', description: 'ICQQ reconnect setting' },
11
+ { key: 'autoServer', type: 'boolean', description: 'ICQQ automatic server selection' },
12
+ { key: 'qqnt', type: 'boolean', description: 'QQNT protocol' },
13
+ { key: 'ntLogin', type: 'boolean', description: 'QQNT login' },
14
+ ],
5
15
  docsUrl: 'https://zhin.js.org/adapters/icqq',
6
16
  readPermission: 'icqq:read',
7
17
  writePermission: 'icqq:write',
package/lib/console.d.ts CHANGED
@@ -1,8 +1,2 @@
1
- /**
2
- * ICQQ Console RPC:运行状态 + endpoint 增删(原 `icqq endpoint` 聊天命令)。
3
- *
4
- * 页面绑定 `pages/index`,读取 / 写入分别要求 `<adapter>:read` / `<adapter>:write`。
5
- */
6
- import { type AdapterConsoleResources } from 'zhin.js/adapter';
7
1
  import type { PluginConsoleRpc } from 'zhin.js';
8
- export declare function createIcqqConsoleRpc(resources: AdapterConsoleResources, getConfig: () => unknown): PluginConsoleRpc;
2
+ export declare function createIcqqConsoleRpc(getConfig: () => unknown): PluginConsoleRpc;