@zhin.js/adapter-icqq 5.0.2 → 6.0.1

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 (76) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +32 -4
  3. package/client/LoginAssistPanel.tsx +38 -3
  4. package/dist/index.js +2 -2
  5. package/lib/adapter.d.ts +12 -4
  6. package/lib/adapter.d.ts.map +1 -1
  7. package/lib/adapter.js +14 -6
  8. package/lib/adapter.js.map +1 -1
  9. package/lib/cq-message.d.ts.map +1 -1
  10. package/lib/cq-message.js +12 -3
  11. package/lib/cq-message.js.map +1 -1
  12. package/lib/endpoint.d.ts +12 -8
  13. package/lib/endpoint.d.ts.map +1 -1
  14. package/lib/endpoint.js +135 -47
  15. package/lib/endpoint.js.map +1 -1
  16. package/lib/icqq-guild.d.ts +48 -0
  17. package/lib/icqq-guild.d.ts.map +1 -0
  18. package/lib/icqq-guild.js +115 -0
  19. package/lib/icqq-guild.js.map +1 -0
  20. package/lib/icqq-inbound.d.ts +7 -0
  21. package/lib/icqq-inbound.d.ts.map +1 -1
  22. package/lib/icqq-inbound.js +39 -6
  23. package/lib/icqq-inbound.js.map +1 -1
  24. package/lib/icqq-login-assist-bridge.d.ts +5 -0
  25. package/lib/icqq-login-assist-bridge.d.ts.map +1 -0
  26. package/lib/icqq-login-assist-bridge.js +148 -0
  27. package/lib/icqq-login-assist-bridge.js.map +1 -0
  28. package/lib/index.d.ts +0 -2
  29. package/lib/index.d.ts.map +1 -1
  30. package/lib/index.js +2 -1
  31. package/lib/index.js.map +1 -1
  32. package/lib/login-assist-routes.d.ts +7 -0
  33. package/lib/login-assist-routes.d.ts.map +1 -0
  34. package/lib/login-assist-routes.js +29 -0
  35. package/lib/login-assist-routes.js.map +1 -0
  36. package/lib/login-ipc-contract.d.ts +44 -0
  37. package/lib/login-ipc-contract.d.ts.map +1 -0
  38. package/lib/login-ipc-contract.js +35 -0
  39. package/lib/login-ipc-contract.js.map +1 -0
  40. package/lib/protocol.d.ts +32 -1
  41. package/lib/protocol.d.ts.map +1 -1
  42. package/lib/protocol.js +23 -0
  43. package/lib/protocol.js.map +1 -1
  44. package/lib/segment-mapper.d.ts +2 -0
  45. package/lib/segment-mapper.d.ts.map +1 -0
  46. package/lib/segment-mapper.js +2 -0
  47. package/lib/segment-mapper.js.map +1 -0
  48. package/lib/tools/index.d.ts +1 -1
  49. package/lib/tools/index.js +8 -8
  50. package/lib/types.d.ts +0 -44
  51. package/lib/types.d.ts.map +1 -1
  52. package/package.json +18 -18
  53. package/skills/icqq/PERMITS.md +6 -6
  54. package/src/adapter.ts +14 -6
  55. package/src/cq-message.ts +11 -3
  56. package/src/endpoint.ts +169 -52
  57. package/src/icqq-guild.ts +157 -0
  58. package/src/icqq-inbound.ts +52 -7
  59. package/src/icqq-login-assist-bridge.ts +196 -0
  60. package/src/index.ts +2 -8
  61. package/src/login-assist-routes.ts +39 -0
  62. package/src/login-ipc-contract.ts +52 -0
  63. package/src/protocol.ts +32 -1
  64. package/src/segment-mapper.ts +1 -0
  65. package/src/tools/index.ts +9 -9
  66. package/src/types.ts +0 -45
  67. package/lib/typing-indicator-example.d.ts +0 -108
  68. package/lib/typing-indicator-example.d.ts.map +0 -1
  69. package/lib/typing-indicator-example.js +0 -220
  70. package/lib/typing-indicator-example.js.map +0 -1
  71. package/lib/typing-indicator.d.ts +0 -87
  72. package/lib/typing-indicator.d.ts.map +0 -1
  73. package/lib/typing-indicator.js +0 -225
  74. package/lib/typing-indicator.js.map +0 -1
  75. package/src/typing-indicator-example.ts +0 -269
  76. package/src/typing-indicator.ts +0 -313
@@ -0,0 +1,196 @@
1
+ /**
2
+ * 将 icqq 守护进程 IPC 的 system.login.* 事件桥接到 core LoginAssist。
3
+ *
4
+ * 推送契约(@icqqjs/cli IpcEvent):
5
+ * { id: "*", event: "system.login.auth", data: { url, device } }
6
+ * 须在 endpoint.handleEvent 中按 event.event 先行处理(非 OneBot post_type)。
7
+ *
8
+ * 续传契约(LoginIpcActions ↔ LoginFlow)见 login-ipc-contract.ts。
9
+ */
10
+ import type { LoginAssist, LoginAssistType } from '@zhin.js/core';
11
+ import type { IcqqEndpoint } from './endpoint.js';
12
+ import {
13
+ LoginIpcActions,
14
+ type IcqqLoginDeviceInfo,
15
+ } from './login-ipc-contract.js';
16
+
17
+ const activeByEndpoint = new Set<string>();
18
+
19
+ function asRecord(value: unknown): Record<string, unknown> | null {
20
+ return value && typeof value === 'object' && !Array.isArray(value)
21
+ ? (value as Record<string, unknown>)
22
+ : null;
23
+ }
24
+
25
+ function resolveQrcodeImage(data: Record<string, unknown>): string | undefined {
26
+ const image = data.image;
27
+ if (image && typeof image === 'object') {
28
+ const buf = image as { type?: string; data?: string };
29
+ if (buf.type === 'Buffer' && typeof buf.data === 'string') {
30
+ return `data:image/png;base64,${buf.data}`;
31
+ }
32
+ }
33
+ if (typeof data.url === 'string' && data.url.startsWith('data:image')) {
34
+ return data.url;
35
+ }
36
+ return undefined;
37
+ }
38
+
39
+ function mapLoginEvent(
40
+ eventName: string,
41
+ data: Record<string, unknown>,
42
+ ): { type: LoginAssistType; payload: Record<string, unknown> } | null {
43
+ switch (eventName) {
44
+ case 'system.login.qrcode':
45
+ return {
46
+ type: 'qrcode',
47
+ payload: {
48
+ message: '请使用手机 QQ 扫码登录',
49
+ image: resolveQrcodeImage(data),
50
+ },
51
+ };
52
+ case 'system.login.slider':
53
+ return {
54
+ type: 'slider',
55
+ payload: {
56
+ message: '请完成滑块验证并提交 ticket',
57
+ url: String(data.url ?? ''),
58
+ },
59
+ };
60
+ case 'system.login.device':
61
+ return {
62
+ type: 'device',
63
+ payload: {
64
+ message: data.phone
65
+ ? `请完成设备锁验证(密保手机 ${String(data.phone)})`
66
+ : '请完成设备锁验证',
67
+ url: String(data.url ?? ''),
68
+ phone: data.phone,
69
+ },
70
+ };
71
+ case 'system.login.auth':
72
+ return {
73
+ type: 'auth',
74
+ payload: {
75
+ message: '请在浏览器完成身份验证(需使用下方设备信息)',
76
+ url: String(data.url ?? ''),
77
+ device: data.device as IcqqLoginDeviceInfo | undefined,
78
+ },
79
+ };
80
+ }
81
+ return null;
82
+ }
83
+
84
+ /** 对齐 @icqqjs/cli LoginFlow.handleSubmit → Client 方法 */
85
+ async function continueLoginAfterAssist(
86
+ endpoint: IcqqEndpoint,
87
+ loginType: LoginAssistType,
88
+ value: string | Record<string, unknown>,
89
+ ): Promise<void> {
90
+ if (!endpoint.ipc || endpoint.ipc.closed) return;
91
+
92
+ try {
93
+ if (loginType === 'slider') {
94
+ const ticket =
95
+ typeof value === 'string'
96
+ ? value.trim()
97
+ : typeof value === 'object' && value !== null
98
+ ? String((value as { ticket?: string }).ticket ?? '').trim()
99
+ : '';
100
+ if (!ticket) return;
101
+ await endpoint.ipc.request(LoginIpcActions.SUBMIT_SLIDER, { ticket });
102
+ return;
103
+ }
104
+
105
+ if (loginType === 'sms') {
106
+ const code = typeof value === 'string' ? value.trim() : '';
107
+ if (!code) return;
108
+ await endpoint.ipc.request(LoginIpcActions.SUBMIT_SMS_CODE, { code });
109
+ return;
110
+ }
111
+
112
+ if (loginType === 'device') {
113
+ if (
114
+ typeof value === 'object' &&
115
+ value !== null &&
116
+ (value as { action?: string }).action === 'sms'
117
+ ) {
118
+ await endpoint.ipc.request(LoginIpcActions.SEND_SMS_CODE, {});
119
+ return;
120
+ }
121
+ if (typeof value === 'string' && value.trim()) {
122
+ await endpoint.ipc.request(LoginIpcActions.SUBMIT_SMS_CODE, {
123
+ code: value.trim(),
124
+ });
125
+ return;
126
+ }
127
+ }
128
+
129
+ // qrcode / device 链接确认 / auth 237 确认 → client.login()
130
+ await endpoint.ipc.request(LoginIpcActions.LOGIN, {});
131
+ } catch (err) {
132
+ endpoint.logger.warn(
133
+ `登录辅助提交后 IPC 续传失败:${
134
+ err instanceof Error ? err.message : String(err)
135
+ }(action 须与 @icqqjs/cli action-catalog 一致)`,
136
+ );
137
+ }
138
+ }
139
+
140
+ export function handleIcqqLoginIpcEvent(
141
+ endpoint: IcqqEndpoint,
142
+ eventName: string,
143
+ rawData: unknown,
144
+ ): void {
145
+ if (!eventName.startsWith('system.login.')) return;
146
+
147
+ const root = endpoint.adapter.plugin.root;
148
+ const loginAssist = root.inject('loginAssist') as LoginAssist | undefined;
149
+ if (!loginAssist) {
150
+ endpoint.logger.debug(`收到 ${eventName},但 loginAssist 未启用`);
151
+ return;
152
+ }
153
+
154
+ if (eventName === 'system.login.error') {
155
+ const data = asRecord(rawData);
156
+ endpoint.logger.warn(
157
+ `icqq 登录错误:${String(data?.message ?? 'unknown')}${
158
+ data?.code != null ? ` [code=${String(data.code)}]` : ''
159
+ }`,
160
+ );
161
+ return;
162
+ }
163
+
164
+ const data = asRecord(rawData);
165
+ if (!data) return;
166
+
167
+ const mapped = mapLoginEvent(eventName, data);
168
+ if (!mapped) return;
169
+
170
+ const guardKey = endpoint.$id;
171
+ if (activeByEndpoint.has(guardKey)) {
172
+ endpoint.logger.debug(`跳过重复登录待办:${eventName}`);
173
+ return;
174
+ }
175
+ activeByEndpoint.add(guardKey);
176
+
177
+ endpoint.logger.info(`icqq 登录待办:${mapped.type}(${eventName})`);
178
+
179
+ void loginAssist
180
+ .waitForInput('icqq', endpoint.$id, mapped.type, mapped.payload)
181
+ .then((value) => continueLoginAfterAssist(endpoint, mapped.type, value))
182
+ .catch((err) => {
183
+ if (err instanceof Error && err.message !== 'cancelled') {
184
+ endpoint.logger.warn(`登录辅助已取消或失败:${err.message}`);
185
+ }
186
+ })
187
+ .finally(() => {
188
+ activeByEndpoint.delete(guardKey);
189
+ });
190
+ }
191
+
192
+ export function disposeIcqqLoginAssistBridge(endpointId: string): void {
193
+ activeByEndpoint.delete(endpointId);
194
+ }
195
+
196
+ export type { IcqqLoginDeviceInfo } from './login-ipc-contract.js';
package/src/index.ts CHANGED
@@ -14,6 +14,7 @@ import { PageManager } from "@zhin.js/host-api";
14
14
  import { IcqqAdapter } from "./adapter.js";
15
15
  import { registerTools } from "./tools/index.js";
16
16
  import { registerRoutes } from "./routes.js";
17
+ import { registerLoginAssistRoutes } from "./login-assist-routes.js";
17
18
 
18
19
  declare module "zhin.js" {
19
20
  namespace Plugin {
@@ -30,14 +31,6 @@ declare module "zhin.js" {
30
31
  export * from "./types.js";
31
32
  export { IcqqEndpoint } from "./endpoint.js";
32
33
  export { IcqqAdapter } from "./adapter.js";
33
- export {
34
- ICQQTypingIndicatorManager,
35
- createICQQTypingIndicatorManager,
36
- startICQQTypingIndicator,
37
- enableTypingIndicator,
38
- type ICQQTypingIndicatorConfig,
39
- } from "./typing-indicator.js";
40
- export type { TypingIndicatorConfig } from "./types.js";
41
34
 
42
35
  const plugin = usePlugin();
43
36
  const { provide, useContext, addCommand, root } = plugin;
@@ -76,4 +69,5 @@ useContext("web", (pageManager) => {
76
69
  // ── HTTP 路由 ──────────────────────────────────────────────────────
77
70
  useContext("router", "icqq", async (router: Router, icqq: IcqqAdapter) => {
78
71
  registerRoutes(router, icqq, root);
72
+ registerLoginAssistRoutes(router, root);
79
73
  });
@@ -0,0 +1,39 @@
1
+ /**
2
+ * loginAssist HTTP 路由(供 Web 控制台 /icqq 登录辅助 Tab)
3
+ */
4
+ import type { Router } from "@zhin.js/host-router";
5
+ import type { Plugin } from "zhin.js";
6
+
7
+ export function registerLoginAssistRoutes(router: Router, root: Plugin): void {
8
+ const loginAssist = root.inject("loginAssist");
9
+ if (!loginAssist) return;
10
+
11
+ router.get("/api/login-assist/pending", async (ctx) => {
12
+ ctx.body = loginAssist.listPending();
13
+ });
14
+
15
+ router.post("/api/login-assist/submit", async (ctx: any) => {
16
+ const body = (ctx.request.body ?? {}) as {
17
+ id?: string;
18
+ value?: string | Record<string, unknown>;
19
+ };
20
+ if (!body.id) {
21
+ ctx.status = 400;
22
+ ctx.body = { success: false, message: "missing id" };
23
+ return;
24
+ }
25
+ const ok = loginAssist.submit(body.id, body.value ?? "");
26
+ ctx.body = { success: ok };
27
+ });
28
+
29
+ router.post("/api/login-assist/cancel", async (ctx: any) => {
30
+ const body = (ctx.request.body ?? {}) as { id?: string; reason?: string };
31
+ if (!body.id) {
32
+ ctx.status = 400;
33
+ ctx.body = { success: false, message: "missing id" };
34
+ return;
35
+ }
36
+ const ok = loginAssist.cancel(body.id, body.reason);
37
+ ctx.body = { success: ok };
38
+ });
39
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * ICQQ 登录 IPC 契约(与 @icqqjs/cli / @icqqjs/icqq 对齐)
3
+ *
4
+ * **推送(Daemon → Client)** — 见 @icqqjs/cli `src/daemon/protocol.ts` 的 `IpcEvent`:
5
+ * ```json
6
+ * { "id": "*", "event": "system.login.auth", "data": { "url", "device" } }
7
+ * ```
8
+ * 事件名与载荷形状以 @icqqjs/icqq `EventMap` 为准(非 OneBot `post_type`)。
9
+ *
10
+ * **续传(Client → Daemon)** — 与 CLI `LoginFlow` / `AccountBootstrap` 对 icqq Client 的调用一致,
11
+ * action 名为 Client 方法的 snake_case;收录于守护进程 `action-catalog` 后可通过 IPC invoke。
12
+ *
13
+ * @see https://github.com/icqqjs/cli/blob/master/src/daemon/protocol.ts
14
+ * @see https://github.com/icqqjs/cli/blob/master/src/lib/account-bootstrap.ts
15
+ * @see https://github.com/icqqjs/cli/blob/master/src/components/LoginFlow.tsx
16
+ */
17
+
18
+ /** system.login.auth 等设备指纹(@icqqjs/icqq EventMap) */
19
+ export interface IcqqLoginDeviceInfo {
20
+ guid?: string;
21
+ qimei?: string;
22
+ qimei36?: string;
23
+ subappid?: string;
24
+ platform?: string;
25
+ brand?: string;
26
+ model?: string;
27
+ bssid?: string;
28
+ devInfo?: string;
29
+ sysVersion?: string;
30
+ }
31
+
32
+ /** 登录续传 IPC action(与 LoginFlow → Client 方法一一对应) */
33
+ export const LoginIpcActions = {
34
+ /** 扫码确认 / 设备锁链接确认 / auth 237 验证完成后继续 — client.login() */
35
+ LOGIN: 'login',
36
+ /** 滑块 ticket — client.submitSlider(ticket) */
37
+ SUBMIT_SLIDER: 'submit_slider',
38
+ /** 设备锁短信验证码 — client.submitSmsCode(code) */
39
+ SUBMIT_SMS_CODE: 'submit_sms_code',
40
+ /** 请求发送设备锁短信 — client.sendSmsCode() */
41
+ SEND_SMS_CODE: 'send_sms_code',
42
+ } as const;
43
+
44
+ export type LoginIpcAction = (typeof LoginIpcActions)[keyof typeof LoginIpcActions];
45
+
46
+ /** CLI LoginFlow 237 验证步骤(供 Web 控制台展示) */
47
+ export const AUTH_DEVICE_STEPS = [
48
+ '打开上方验证链接,正常完成验证流程,直到发送完验证码,不要点击「我已发送」',
49
+ '复制下方 JS,打开浏览器开发者工具(F12)→ Console,粘贴并回车',
50
+ '在弹窗中粘贴设备信息 JSON 并确认(可使用下方单行 JSON)',
51
+ '回到验证页点击「我已发送」,完成 237 验证后回到控制台点击确认',
52
+ ] as const;
package/src/protocol.ts CHANGED
@@ -3,6 +3,13 @@
3
3
  *
4
4
  * CLI 与守护进程通过 Unix Domain Socket 通信,
5
5
  * 使用 JSON + 换行符(\n)分隔的文本协议。
6
+ *
7
+ * 通信流程(@icqqjs/cli `src/daemon/protocol.ts`):
8
+ * 1. CLI 连接 Socket → auth(token)
9
+ * 2. 认证通过后发送 IpcRequest → 等待 IpcResponse
10
+ * 3. 认证通过后自动接收 icqq 事件推送(IpcEvent),断开连接自动停止
11
+ *
12
+ * 登录相关:**推送**走 IpcEvent(`system.login.*`),续传 invoke 见 `login-ipc-contract.ts`。
6
13
  */
7
14
 
8
15
  /** CLI → Daemon 请求 */
@@ -20,10 +27,18 @@ export type IpcResponse = {
20
27
  error?: string;
21
28
  };
22
29
 
23
- /** Daemon → CLI 事件推送 */
30
+ /**
31
+ * Daemon → CLI 事件推送(icqq client.em 分发的全部事件)
32
+ *
33
+ * 登录/重连时推送 `system.login.*`(如 `system.login.auth` 含 url + device),
34
+ * 语义在 `event` 字段,不在 OneBot 式 `post_type` 里。
35
+ */
24
36
  export type IpcEvent = {
37
+ /** 固定为 `"*"`,客户端应忽略,由本地 handler 按 `event` 过滤 */
25
38
  id: string;
39
+ /** icqq 事件名,如 `system.login.auth`、`message.group.normal` */
26
40
  event: string;
41
+ /** icqq 事件 toJSON 后的 plain object */
27
42
  data: unknown;
28
43
  };
29
44
 
@@ -53,6 +68,7 @@ export interface IpcGuildMessageEventData {
53
68
  */
54
69
  export const Actions = {
55
70
  PING: "ping",
71
+ LOGOUT: "logout",
56
72
 
57
73
  // ── 列表查询 ──
58
74
  LIST_FRIENDS: "list_friends",
@@ -66,7 +82,10 @@ export const Actions = {
66
82
  GET_GROUP_INFO: "get_group_info",
67
83
  GET_GROUP_MEMBER_INFO: "get_group_member_info",
68
84
  GET_STRANGER_INFO: "get_stranger_info",
85
+ LIST_STRANGERS: "list_strangers",
86
+ GET_PROFILE: "get_profile",
69
87
  GET_STATUS: "get_status",
88
+ GET_ONLINE_STATUS: "get_online_status",
70
89
  GET_SELF_PROFILE: "get_self_profile",
71
90
 
72
91
  // ── 消息发送 ──
@@ -78,6 +97,8 @@ export const Actions = {
78
97
  GET_MSG: "get_msg",
79
98
  HISTORY_PRIVATE: "history_private",
80
99
  HISTORY_GROUP: "history_group",
100
+ HISTORY_BY_MSG_ID: "history_by_msg_id",
101
+ SEND_LONG_MSG: "send_long_msg",
81
102
  MARK_READ: "mark_read",
82
103
  DELETE_MSG: "delete_msg",
83
104
 
@@ -165,6 +186,9 @@ export const Actions = {
165
186
  SEND_PRIVATE_FILE: "send_private_file",
166
187
  SEND_GROUP_FILE: "send_group_file",
167
188
  FRIEND_RECALL_FILE: "friend_recall_file",
189
+ FRIEND_FORWARD_FILE: "friend_forward_file",
190
+ SEARCH_SAME_GROUP: "search_same_group",
191
+ SEND_CONTACT_SHARE: "send_contact_share",
168
192
  GFS_UPLOAD: "gfs_upload",
169
193
 
170
194
  // ── 群消息表态 ──
@@ -179,6 +203,7 @@ export const Actions = {
179
203
  GUILD_LIST: "guild_list",
180
204
  GUILD_INFO: "guild_info",
181
205
  GUILD_CHANNELS: "guild_channels",
206
+ GET_CHANNEL_INFO: "get_channel_info",
182
207
  GUILD_MEMBERS: "guild_members",
183
208
  GUILD_SEND_MSG: "guild_send_msg",
184
209
  GUILD_RECALL_MSG: "guild_recall_msg",
@@ -208,7 +233,13 @@ export const Actions = {
208
233
  GET_CLIENT_KEY: "get_client_key",
209
234
  GET_PSKEY: "get_pskey",
210
235
  UID2UIN: "uid2uin",
236
+ UID2UINS: "uid2uins",
211
237
  UIN2UID: "uin2uid",
238
+ UIN2UIDS: "uin2uids",
239
+ GET_COOKIES: "get_cookies",
240
+ GET_CSRF_TOKEN: "get_csrf_token",
241
+ REFRESH_NT_PIC_RKEY: "refresh_nt_pic_rkey",
242
+ SEND_DISCUSS_MSG: "send_discuss_msg",
212
243
 
213
244
  // ── 视频/加好友设置 ──
214
245
  GET_VIDEO_URL: "get_video_url",
@@ -0,0 +1 @@
1
+ export { toCanonicalSegments, fromCanonicalSegments } from 'zhin.js';
@@ -1,11 +1,11 @@
1
1
  /**
2
2
  * ICQQ 平台特有工具注册 — 通过 IPC 调用守护进程 Actions
3
3
  *
4
- * 通用群管理工具由 createGroupManagementTools() 自动生成;
4
+ * 通用群管理工具由 createSceneManagementTools() 自动生成;
5
5
  * 本模块注册 ICQQ 独有的扩展工具。
6
6
  */
7
7
  import type { ToolFeature } from "zhin.js";
8
- import { createGroupManagementTools } from "zhin.js";
8
+ import { createSceneManagementTools } from "zhin.js";
9
9
  import type { IcqqAdapter } from "../adapter.js";
10
10
  import { Actions } from "../protocol.js";
11
11
 
@@ -17,8 +17,8 @@ export function registerTools(
17
17
  const disposers: (() => void)[] = [];
18
18
 
19
19
  // ── 通用群管工具 ───────────────────────────────────────────────────
20
- const groupTools = createGroupManagementTools(icqq, "icqq");
21
- disposers.push(...groupTools.map((t) => toolService.addTool(t, pluginName)));
20
+ const sceneTools = createSceneManagementTools(icqq, "icqq");
21
+ disposers.push(...sceneTools.map((t) => toolService.addTool(t, pluginName)));
22
22
 
23
23
  // ── 设置头衔 ───────────────────────────────────────────────────────
24
24
  disposers.push(
@@ -39,7 +39,7 @@ export function registerTools(
39
39
  },
40
40
  platforms: ["icqq"],
41
41
  tags: ["icqq"],
42
- permissions: ["platform(icqq,group_owner)"],
42
+ permissions: ["platform(icqq,scene_owner)"],
43
43
  execute: async (args: Record<string, any>) => {
44
44
  const endpoint = icqq.endpoints.get(args.endpoint_id);
45
45
  if (!endpoint) throw new Error(`Endpoint ${args.endpoint_id} 不存在`);
@@ -73,7 +73,7 @@ export function registerTools(
73
73
  },
74
74
  platforms: ["icqq"],
75
75
  tags: ["icqq"],
76
- permissions: ["platform(icqq,group_admin)"],
76
+ permissions: ["platform(icqq,scene_admin)"],
77
77
  execute: async (args: Record<string, any>) => {
78
78
  const endpoint = icqq.endpoints.get(args.endpoint_id);
79
79
  if (!endpoint) throw new Error(`Endpoint ${args.endpoint_id} 不存在`);
@@ -135,7 +135,7 @@ export function registerTools(
135
135
  },
136
136
  platforms: ["icqq"],
137
137
  tags: ["icqq"],
138
- permissions: ["platform(icqq,group_admin)"],
138
+ permissions: ["platform(icqq,scene_admin)"],
139
139
  execute: async (args: Record<string, any>) => {
140
140
  const endpoint = icqq.endpoints.get(args.endpoint_id);
141
141
  if (!endpoint) throw new Error(`Endpoint ${args.endpoint_id} 不存在`);
@@ -199,7 +199,7 @@ export function registerTools(
199
199
  },
200
200
  platforms: ["icqq"],
201
201
  tags: ["icqq"],
202
- permissions: ["platform(icqq,group_owner)"],
202
+ permissions: ["platform(icqq,scene_owner)"],
203
203
  execute: async (args: Record<string, any>) => {
204
204
  const endpoint = icqq.endpoints.get(args.endpoint_id);
205
205
  if (!endpoint) throw new Error(`Endpoint ${args.endpoint_id} 不存在`);
@@ -393,7 +393,7 @@ export function registerTools(
393
393
  },
394
394
  platforms: ["icqq"],
395
395
  tags: ["icqq"],
396
- permissions: ["platform(icqq,group_admin)"],
396
+ permissions: ["platform(icqq,scene_admin)"],
397
397
  execute: async (args: Record<string, any>) => {
398
398
  const endpoint = icqq.endpoints.get(args.endpoint_id);
399
399
  if (!endpoint) throw new Error(`Endpoint ${args.endpoint_id} 不存在`);
package/src/types.ts CHANGED
@@ -17,46 +17,6 @@ export interface IcqqSenderInfo {
17
17
  title?: string;
18
18
  }
19
19
 
20
- /**
21
- * Typing Indicator 配置
22
- */
23
- export interface TypingIndicatorConfig {
24
- /** 是否启用(默认 true) */
25
- enabled?: boolean;
26
- /** 默认表情(默认 '⏳') */
27
- defaultEmoji?: string;
28
- /** 是否在完成后自动移除(默认 true) */
29
- autoRemove?: boolean;
30
- /** 自动移除延迟,毫秒(默认 5000) */
31
- removeDelay?: number;
32
- /** 私聊配置 */
33
- privateConfig?: {
34
- /** 提示类型 */
35
- type: 'message' | 'reaction';
36
- /** 消息内容(type='message' 时使用) */
37
- message?: string;
38
- /** 表情符号(type='reaction' 时使用) */
39
- emoji?: string;
40
- /** 是否自动移除 */
41
- autoRemove?: boolean;
42
- /** 自动移除延迟 */
43
- removeDelay?: number;
44
- };
45
- /** 群聊配置 */
46
- groupConfig?: {
47
- /** 提示类型 */
48
- type: 'message' | 'reaction';
49
- /** 消息内容(type='message' 时使用) */
50
- message?: string;
51
- /** 表情符号(type='reaction' 时使用) */
52
- emoji?: string;
53
- /** 是否自动移除 */
54
- autoRemove?: boolean;
55
- /** 自动移除延迟 */
56
- removeDelay?: number;
57
- };
58
- }
59
-
60
20
  /**
61
21
  * Endpoint 配置:支持本地 IPC 和远程 RPC 两种连接模式。
62
22
  *
@@ -81,11 +41,6 @@ export interface IcqqEndpointConfig {
81
41
  * 默认 true;设为 false 则断开后仅将 `$connected` 置为 false,需手动重连。
82
42
  */
83
43
  autoReconnect?: boolean;
84
- /**
85
- * Typing Indicator 配置
86
- * 用于在 AI 处理消息时提示用户正在处理中
87
- */
88
- typingIndicator?: TypingIndicatorConfig;
89
44
  /**
90
45
  * 出站图片/语音/视频:file=本机临时文件路径(需与 icqq 守护进程同机可读);
91
46
  * base64=经 CQ `base64://` 交给守护进程解码(Zhin 与 icqq 异进程/异机时用,配置 rpc 时默认 base64)。
@@ -1,108 +0,0 @@
1
- /**
2
- * ICQQ Typing Indicator 使用示例
3
- *
4
- * 展示如何在 ICQQ 适配器中集成消息处理状态提示
5
- */
6
- import type { IcqqEndpoint } from './endpoint.js';
7
- import type { IcqqAdapter } from './adapter.js';
8
- import { ICQQTypingIndicatorManager, type ICQQTypingIndicatorConfig } from './typing-indicator.js';
9
- /**
10
- * 在 ICQQ 适配器初始化时启用 Typing Indicator
11
- */
12
- export declare function enableTypingIndicatorForAdapter(adapter: IcqqAdapter): void;
13
- /**
14
- * 在消息处理流程中使用 Typing Indicator
15
- *
16
- * 使用示例:
17
- * ```typescript
18
- * // 在消息处理开始时
19
- * const indicator = await startTypingIndicator(endpoint, {
20
- * messageId: message.$id,
21
- * sessionId: `${message.$channel.type}:${message.$channel.id}`,
22
- * userId: message.$sender.id,
23
- * groupId: message.$channel.type === 'group' ? message.$channel.id : undefined,
24
- * sceneType: message.$channel.type as 'private' | 'group',
25
- * });
26
- *
27
- * try {
28
- * // 执行 AI 处理
29
- * const result = await processMessage(message);
30
- * return result;
31
- * } finally {
32
- * // 处理完成后停止提示
33
- * await indicator.stop();
34
- * }
35
- * ```
36
- */
37
- export declare function withTypingIndicator<T>(endpoint: IcqqEndpoint, options: {
38
- messageId?: string;
39
- sessionId: string;
40
- userId?: string;
41
- groupId?: string;
42
- sceneType: 'private' | 'group';
43
- }, fn: () => Promise<T>): Promise<T>;
44
- /**
45
- * 自定义 Typing Indicator 配置
46
- */
47
- export declare const customConfigs: Record<string, Partial<ICQQTypingIndicatorConfig>>;
48
- /**
49
- * 在 ICQQ 插件中集成 Typing Indicator
50
- *
51
- * 在 `index.ts` 中添加:
52
- * ```typescript
53
- * import { enableTypingIndicatorForAdapter } from './typing-indicator-example.js';
54
- *
55
- * // 在适配器 mounted 后启用
56
- * provide({
57
- * name: "icqq",
58
- * mounted: async (p: Plugin) => {
59
- * const adapter = new IcqqAdapter(p);
60
- * await adapter.start();
61
- *
62
- * // 启用 Typing Indicator
63
- * enableTypingIndicatorForAdapter(adapter);
64
- *
65
- * return adapter;
66
- * },
67
- * });
68
- * ```
69
- */
70
- /**
71
- * 监听消息事件并自动添加 Typing Indicator
72
- */
73
- export declare function setupTypingIndicatorHooks(adapter: IcqqAdapter): void;
74
- /**
75
- * 批量管理多个 Endpoint 的 Typing Indicator
76
- */
77
- export declare class BatchTypingIndicatorManager {
78
- private managers;
79
- /**
80
- * 注册 Endpoint
81
- */
82
- registerEndpoint(endpoint: IcqqEndpoint, config?: Partial<ICQQTypingIndicatorConfig>): void;
83
- /**
84
- * 开始提示
85
- */
86
- start(endpointId: string, options: {
87
- messageId?: string;
88
- sessionId: string;
89
- userId?: string;
90
- groupId?: string;
91
- sceneType: 'private' | 'group';
92
- }): Promise<void>;
93
- /**
94
- * 停止提示
95
- */
96
- stop(endpointId: string, options: {
97
- sessionId: string;
98
- }): Promise<void>;
99
- /**
100
- * 停止所有提示
101
- */
102
- stopAll(): Promise<void>;
103
- /**
104
- * 获取 Endpoint 的管理器
105
- */
106
- getManager(endpointId: string): ICQQTypingIndicatorManager | undefined;
107
- }
108
- //# sourceMappingURL=typing-indicator-example.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"typing-indicator-example.d.ts","sourceRoot":"","sources":["../src/typing-indicator-example.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EACL,0BAA0B,EAG1B,KAAK,yBAAyB,EAC/B,MAAM,uBAAuB,CAAC;AAI/B;;GAEG;AACH,wBAAgB,+BAA+B,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,CA0B1E;AAID;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,mBAAmB,CAAC,CAAC,EACzC,QAAQ,EAAE,YAAY,EACtB,OAAO,EAAE;IACP,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC;CAChC,EACD,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GACnB,OAAO,CAAC,CAAC,CAAC,CAkBZ;AAID;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,yBAAyB,CAAC,CAyC5E,CAAC;AAIF;;;;;;;;;;;;;;;;;;;;;GAqBG;AAIH;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,CAwBpE;AAID;;GAEG;AACH,qBAAa,2BAA2B;IACtC,OAAO,CAAC,QAAQ,CAAsD;IAEtE;;OAEG;IACH,gBAAgB,CAAC,QAAQ,EAAE,YAAY,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,yBAAyB,CAAC,GAAG,IAAI;IAK3F;;OAEG;IACG,KAAK,CACT,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE;QACP,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC;KAChC,GACA,OAAO,CAAC,IAAI,CAAC;IAOhB;;OAEG;IACG,IAAI,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAO7E;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAM9B;;OAEG;IACH,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,0BAA0B,GAAG,SAAS;CAGvE"}