@zhin.js/adapter-icqq 8.0.8 → 8.0.10

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 (87) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +36 -28
  3. package/adapters/icqq.js +4 -9
  4. package/adapters/icqq.ts +5 -14
  5. package/agent/PERMITS.md +2 -0
  6. package/lib/agent-prompt.js +17 -22
  7. package/lib/cq-message.d.ts +2 -2
  8. package/lib/cq-message.js +7 -2
  9. package/lib/endpoint.d.ts +4 -74
  10. package/lib/endpoint.js +348 -507
  11. package/lib/forward-msg.d.ts +7 -8
  12. package/lib/forward-msg.js +11 -24
  13. package/lib/icqq-agent-deps.d.ts +3 -15
  14. package/lib/icqq-agent-deps.js +0 -5
  15. package/lib/icqq-endpoint-commands.js +4 -13
  16. package/lib/icqq-guild.d.ts +15 -11
  17. package/lib/icqq-guild.js +9 -17
  18. package/lib/icqq-inbound.d.ts +20 -20
  19. package/lib/icqq-inbound.js +9 -9
  20. package/lib/icqq-inbox.d.ts +2 -10
  21. package/lib/index.d.ts +2 -3
  22. package/lib/index.js +2 -3
  23. package/lib/outbound-media.d.ts +3 -8
  24. package/lib/outbound-media.js +3 -8
  25. package/lib/protocol.d.ts +38 -57
  26. package/lib/protocol.js +67 -21
  27. package/lib/types.d.ts +4 -40
  28. package/lib/types.js +0 -5
  29. package/package.json +26 -14
  30. package/plugin.js +6 -1
  31. package/schema.json +119 -61
  32. package/src/agent-prompt.ts +17 -22
  33. package/src/cq-message.ts +7 -2
  34. package/src/endpoint.ts +359 -600
  35. package/src/forward-msg.ts +12 -26
  36. package/src/icqq-agent-deps.ts +3 -17
  37. package/src/icqq-endpoint-commands.ts +4 -13
  38. package/src/icqq-guild.ts +16 -25
  39. package/src/icqq-inbound.ts +26 -26
  40. package/src/icqq-inbox.ts +2 -10
  41. package/src/icqqjs-icqq.d.ts +88 -0
  42. package/src/index.ts +2 -9
  43. package/src/outbound-media.ts +4 -9
  44. package/src/protocol.ts +108 -66
  45. package/src/types.ts +4 -41
  46. package/tools/announce.js +19 -0
  47. package/tools/announce.ts +18 -0
  48. package/tools/essence.js +24 -0
  49. package/{agent/tools → tools}/essence.ts +8 -8
  50. package/tools/friend_list.js +20 -0
  51. package/{agent/tools → tools}/friend_list.ts +7 -7
  52. package/tools/group_files.js +25 -0
  53. package/tools/group_files.ts +23 -0
  54. package/tools/group_invite.js +25 -0
  55. package/tools/group_invite.ts +22 -0
  56. package/tools/group_kick.js +28 -0
  57. package/tools/group_kick.ts +24 -0
  58. package/tools/group_list.js +21 -0
  59. package/{agent/tools → tools}/group_list.ts +7 -7
  60. package/tools/group_sign.js +21 -0
  61. package/tools/group_sign.ts +19 -0
  62. package/tools/list_muted.js +20 -0
  63. package/tools/list_muted.ts +19 -0
  64. package/tools/poke.js +19 -0
  65. package/tools/poke.ts +18 -0
  66. package/tools/send_user_like.js +28 -0
  67. package/tools/send_user_like.ts +25 -0
  68. package/tools/set_anonymous.js +23 -0
  69. package/tools/set_anonymous.ts +21 -0
  70. package/tools/set_mute.js +26 -0
  71. package/tools/set_mute.ts +23 -0
  72. package/tools/set_title.js +27 -0
  73. package/tools/set_title.ts +24 -0
  74. package/tools/user_info.js +17 -0
  75. package/tools/user_info.ts +16 -0
  76. package/agent/tools/announce.ts +0 -21
  77. package/agent/tools/group_files.ts +0 -27
  78. package/agent/tools/group_invite.ts +0 -20
  79. package/agent/tools/group_sign.ts +0 -19
  80. package/agent/tools/list_muted.ts +0 -22
  81. package/agent/tools/poke.ts +0 -20
  82. package/agent/tools/send_user_like.ts +0 -22
  83. package/agent/tools/set_anonymous.ts +0 -22
  84. package/agent/tools/set_title.ts +0 -25
  85. package/lib/ipc-client.d.ts +0 -73
  86. package/lib/ipc-client.js +0 -358
  87. package/src/ipc-client.ts +0 -417
@@ -1,8 +1,4 @@
1
- /**
2
- * 合并转发(聊天记录)解析:从 json/xml 提取 resid,经 IPC get_forward_msg 拉取正文。
3
- */
4
1
  import { type MessageSegment, type QuotedMessagePayload } from 'zhin.js';
5
- import type { IpcClient } from "./ipc-client.js";
6
2
  import { type IcqqMessageElement } from "./icqq-inbound.js";
7
3
  /** 从 QQ 合并转发 json 元素提取 resid */
8
4
  export declare function extractForwardResidFromJsonElement(el: IcqqMessageElement): string | undefined;
@@ -16,11 +12,14 @@ export declare function extractForwardResidFromGetMsgElements(elements: IcqqMess
16
12
  export declare function extractForwardResidFromGetMsg(data: unknown): string | undefined;
17
13
  export declare function extractForwardResidFromSegments(content: MessageSegment[]): string | undefined;
18
14
  export declare function extractForwardResidFromPayload(payload: QuotedMessagePayload): string | undefined;
19
- /** 在 get_msg / IPC 原始对象里深度搜索 resid */
15
+ /** 在 get_msg 原始对象里深度搜索 resid */
20
16
  export declare function extractForwardResidDeep(root: unknown, maxDepth?: number): string | undefined;
21
17
  export declare function isForwardPlaceholderPayload(payload: QuotedMessagePayload): boolean;
22
18
  /** 将 get_forward_msg 响应格式化为可读聊天记录 */
23
19
  export declare function formatForwardMsgResponse(data: unknown): string;
24
- export declare function fetchForwardMsgText(ipc: IpcClient, id: string): Promise<string>;
25
- /** 若 payload 含合并转发,拉取并追加到 content */
26
- export declare function enrichQuotedPayloadWithForward(ipc: IpcClient | null | undefined, payload: QuotedMessagePayload, ipcRaw?: unknown): Promise<QuotedMessagePayload>;
20
+ export declare function fetchForwardMsgText(client: {
21
+ getForwardMsg(resId: string, fileName?: string): Promise<unknown[]>;
22
+ }, id: string): Promise<string>;
23
+ export declare function enrichQuotedPayloadWithForward(client: {
24
+ getForwardMsg(resId: string, fileName?: string): Promise<unknown[]>;
25
+ } | null | undefined, payload: QuotedMessagePayload, rawData?: unknown): Promise<QuotedMessagePayload>;
@@ -1,8 +1,4 @@
1
- /**
2
- * 合并转发(聊天记录)解析:从 json/xml 提取 resid,经 IPC get_forward_msg 拉取正文。
3
- */
4
1
  import { segment } from 'zhin.js';
5
- import { Actions } from "./protocol.js";
6
2
  import { icqqElementsToSegments, } from "./icqq-inbound.js";
7
3
  import { parseCqMessage } from "./cq-message.js";
8
4
  const RESID_IN_XML_RE = /(?:m_resid|resid|fileid|res_id)=["']?([A-Za-z0-9+/=_.-]{8,})/i;
@@ -191,7 +187,7 @@ export function extractForwardResidFromPayload(payload) {
191
187
  }
192
188
  return undefined;
193
189
  }
194
- /** 在 get_msg / IPC 原始对象里深度搜索 resid */
190
+ /** 在 get_msg 原始对象里深度搜索 resid */
195
191
  export function extractForwardResidDeep(root, maxDepth = 14) {
196
192
  const seen = new Set();
197
193
  function walk(node, depth) {
@@ -336,22 +332,14 @@ export function formatForwardMsgResponse(data) {
336
332
  }
337
333
  return lines.join("\n\n");
338
334
  }
339
- export async function fetchForwardMsgText(ipc, id) {
340
- const attempts = [
341
- { message_id: id },
342
- { id },
343
- { resid: id },
344
- { res_id: id },
345
- { msg_id: id },
346
- ];
347
- for (const params of attempts) {
348
- const resp = await ipc.request(Actions.GET_FORWARD_MSG, params);
349
- if (!resp.ok)
350
- continue;
351
- const text = formatForwardMsgResponse(resp.data);
335
+ export async function fetchForwardMsgText(client, id) {
336
+ try {
337
+ const messages = await client.getForwardMsg(id);
338
+ const text = formatForwardMsgResponse(messages);
352
339
  if (text.trim())
353
340
  return text.trim();
354
341
  }
342
+ catch { /* ignore */ }
355
343
  return "";
356
344
  }
357
345
  function appendForwardBlock(payload, block) {
@@ -367,19 +355,18 @@ function appendForwardBlock(payload, block) {
367
355
  content: prev ? `${prev}\n\n${block}` : block,
368
356
  };
369
357
  }
370
- /** 若 payload 含合并转发,拉取并追加到 content */
371
- export async function enrichQuotedPayloadWithForward(ipc, payload, ipcRaw) {
372
- if (!ipc || hasMergedForwardBlock(payload))
358
+ export async function enrichQuotedPayloadWithForward(client, payload, rawData) {
359
+ if (!client || hasMergedForwardBlock(payload))
373
360
  return payload;
374
361
  const resid = extractForwardResidFromPayload(payload) ??
375
- (ipcRaw ? extractForwardResidFromGetMsg(ipcRaw) : undefined) ??
376
- (ipcRaw ? extractForwardResidDeep(ipcRaw) : undefined);
362
+ (rawData ? extractForwardResidFromGetMsg(rawData) : undefined) ??
363
+ (rawData ? extractForwardResidDeep(rawData) : undefined);
377
364
  const fetchIds = [
378
365
  resid,
379
366
  isForwardPlaceholderPayload(payload) ? payload.messageId : undefined,
380
367
  ].filter((v, i, a) => !!v && a.indexOf(v) === i);
381
368
  for (const fetchId of fetchIds) {
382
- const forwardText = await fetchForwardMsgText(ipc, fetchId);
369
+ const forwardText = await fetchForwardMsgText(client, fetchId);
383
370
  if (!forwardText.trim())
384
371
  continue;
385
372
  const block = `[Merged chat history — id ${fetchId}]\n${forwardText.trim()}`;
@@ -1,17 +1,6 @@
1
- /**
2
- * Agent tool deps for icqq.
3
- * Endpoints register themselves on start; tools look up by config name / QQ uin.
4
- */
5
- import type { IpcFriendInfo, IpcGroupInfo } from './types.js';
6
- import type { IpcResponse } from './protocol.js';
7
- export interface IcqqAgentEndpoint {
8
- readonly name: string;
9
- readonly ipc: {
10
- request(action: string, params?: Record<string, unknown>): Promise<IpcResponse>;
11
- };
12
- readonly friends: Map<number, IpcFriendInfo>;
13
- readonly groups: Map<number, IpcGroupInfo>;
14
- request(action: string, params?: Record<string, unknown>): Promise<IpcResponse>;
1
+ import type { Client } from '@icqqjs/icqq';
2
+ export interface IcqqAgentEndpoint extends Client {
3
+ readonly endpointName: string;
15
4
  }
16
5
  export interface IcqqAgentDeps {
17
6
  getEndpoint: (endpointKey: string) => IcqqAgentEndpoint;
@@ -20,6 +9,5 @@ export interface IcqqAgentDeps {
20
9
  };
21
10
  }
22
11
  export declare function registerIcqqAgentEndpoint(endpointKey: string, endpoint: IcqqAgentEndpoint): () => void;
23
- /** Optional override used by tests / transitional callers. Pass `null` to clear. */
24
12
  export declare function setIcqqAgentDeps(deps: IcqqAgentDeps | null): void;
25
13
  export declare function getIcqqAgentDeps(): IcqqAgentDeps;
@@ -1,7 +1,3 @@
1
- /**
2
- * Agent tool deps for icqq.
3
- * Endpoints register themselves on start; tools look up by config name / QQ uin.
4
- */
5
1
  const endpoints = new Map();
6
2
  let override = null;
7
3
  export function registerIcqqAgentEndpoint(endpointKey, endpoint) {
@@ -12,7 +8,6 @@ export function registerIcqqAgentEndpoint(endpointKey, endpoint) {
12
8
  }
13
9
  };
14
10
  }
15
- /** Optional override used by tests / transitional callers. Pass `null` to clear. */
16
11
  export function setIcqqAgentDeps(deps) {
17
12
  override = deps;
18
13
  }
@@ -1,12 +1,3 @@
1
- /**
2
- * `icqq.endpoint` 命令族:由 @zhin.js/adapter 的 createEndpointCommands 套件生成。
3
- *
4
- * ICQQ 的凭据由外部守护进程(@icqqjs/cli)按账号持有(~/.icqq/<uin>/),
5
- * 其 IPC/RPC 协议是「按 uin 连接 + auth + 账号级 action」,没有 add-account /
6
- * 触发 login 的 action——扫码登录只能经 `icqq login <uin>` CLI 完成。
7
- * 因此 add 不走 kv 凭据录入,而是 bindFlow:校验 uin、把 { id: '<uin>' }
8
- * 追加到 plugins.icqq.endpoints,并引导用户先完成守护进程登录。
9
- */
10
1
  import { addEndpointToConfig, createEndpointCommands } from '@zhin.js/adapter';
11
2
  import { defineCommand } from '@zhin.js/command';
12
3
  import { icqqRuntimeStateToken } from './icqq-runtime-state.js';
@@ -14,11 +5,11 @@ export const icqqEndpointCommands = createEndpointCommands({
14
5
  adapterKey: 'icqq',
15
6
  adapterDisplayName: 'ICQQ',
16
7
  running: (use) => use(icqqRuntimeStateToken).endpoints.values(),
17
- describeEntry: (entry) => (entry.rpc ? 'rpc(远程守护进程)' : 'ipc(本地守护进程)'),
18
- addDescription: '登记 ICQQ endpoint(uin 需先经 icqq login 完成扫码登录;重启 zhin 生效)',
8
+ describeEntry: () => 'direct(直连 @icqqjs/icqq)',
9
+ addDescription: '登记 ICQQ endpoint(重启 zhin 生效)',
19
10
  bindFlow: ({ id }) => {
20
11
  if (!id) {
21
- return '用法:icqq.endpoint add <uin>(uin 为纯数字 QQ 号,且需先执行 icqq login <uin> 完成扫码登录)';
12
+ return '用法:icqq.endpoint add <uin>(uin 为纯数字 QQ 号)';
22
13
  }
23
14
  if (!/^\d+$/.test(id)) {
24
15
  return 'icqq endpoint 名必须是纯数字 QQ 号(uin)';
@@ -26,7 +17,7 @@ export const icqqEndpointCommands = createEndpointCommands({
26
17
  try {
27
18
  const filePath = addEndpointToConfig('icqq', { id });
28
19
  return (`✅ endpoint「${id}」已追加到 ${filePath} 的 plugins.icqq.endpoints。\n` +
29
- `⚠️ 请确保已执行 icqq login ${id} 启动守护进程并完成扫码登录;重启 zhin 后生效。`);
20
+ `重启 zhin 后生效。`);
30
21
  }
31
22
  catch (error) {
32
23
  return `添加失败:${error instanceof Error ? error.message : String(error)}`;
@@ -2,12 +2,16 @@
2
2
  * ICQQ guild (QQ 频道) catalog sync, inbound normalize, Console channel list.
3
3
  */
4
4
  import { type MessageSegment } from "zhin.js";
5
- import { type IpcGuildMessageEventData } from "./protocol.js";
6
- /** Narrow request port shared by the real IPC client and endpoint test transports. */
7
- export interface IcqqGuildRpc {
8
- request(action: string, params?: Record<string, unknown>): Promise<{
9
- ok: boolean;
10
- data?: unknown;
5
+ import type { GuildMessageEventData } from "./protocol.js";
6
+ export interface IcqqGuildClient {
7
+ getGuildList(): Array<{
8
+ guild_id: string;
9
+ guild_name: string;
10
+ }>;
11
+ getChannelList(guildId: string): Array<{
12
+ guild_id: string;
13
+ channel_id: string;
14
+ channel_name: string;
11
15
  }>;
12
16
  }
13
17
  export interface IcqqGuildChannelEntry {
@@ -27,14 +31,14 @@ export interface NormalizedIcqqGuildInbound {
27
31
  content: MessageSegment[];
28
32
  rawMessage: string;
29
33
  timestampMs: number;
30
- raw: IpcGuildMessageEventData;
34
+ raw: GuildMessageEventData;
31
35
  }
32
36
  export declare class IcqqGuildCatalog {
33
37
  private readonly channels;
34
38
  private readonly guilds;
35
39
  clear(): void;
36
- syncAll(ipc: IcqqGuildRpc): Promise<void>;
37
- upsertFromInbound(data: IpcGuildMessageEventData): void;
40
+ syncAll(client: IcqqGuildClient): Promise<void>;
41
+ upsertFromInbound(data: GuildMessageEventData): void;
38
42
  getGuildChannelList(): Array<{
39
43
  id: string;
40
44
  name: string;
@@ -49,5 +53,5 @@ export declare class IcqqGuildCatalog {
49
53
  parentName?: string;
50
54
  };
51
55
  }
52
- export declare function isIcqqGuildIpcEvent(eventName: string | undefined): boolean;
53
- export declare function normalizeIcqqGuildInboundMessage(data: IpcGuildMessageEventData & Record<string, unknown>): NormalizedIcqqGuildInbound | null;
56
+ export declare function isIcqqGuildEvent(eventName: string | undefined): boolean;
57
+ export declare function normalizeIcqqGuildInboundMessage(data: GuildMessageEventData & Record<string, unknown>): NormalizedIcqqGuildInbound | null;
package/lib/icqq-guild.js CHANGED
@@ -2,7 +2,6 @@
2
2
  * ICQQ guild (QQ 频道) catalog sync, inbound normalize, Console channel list.
3
3
  */
4
4
  import { toCanonicalSegments } from "zhin.js";
5
- import { Actions } from "./protocol.js";
6
5
  import { parseCqMessage } from "./cq-message.js";
7
6
  export class IcqqGuildCatalog {
8
7
  channels = new Map();
@@ -11,27 +10,20 @@ export class IcqqGuildCatalog {
11
10
  this.channels.clear();
12
11
  this.guilds.clear();
13
12
  }
14
- async syncAll(ipc) {
15
- const listResp = await ipc.request(Actions.GUILD_LIST);
16
- if (!listResp.ok)
17
- return;
18
- const guildRows = Array.isArray(listResp.data) ? listResp.data : [];
13
+ async syncAll(client) {
14
+ const guildRows = client.getGuildList();
19
15
  for (const row of guildRows) {
20
- const rec = row;
21
- const guild_id = String(rec.guild_id ?? rec.id ?? "");
16
+ const guild_id = String(row.guild_id ?? "");
22
17
  if (!guild_id)
23
18
  continue;
24
- const guild_name = String(rec.guild_name ?? rec.name ?? guild_id);
19
+ const guild_name = String(row.guild_name ?? guild_id);
25
20
  this.guilds.set(guild_id, { guild_id, guild_name });
26
- const chResp = await ipc.request(Actions.GUILD_CHANNELS, { guild_id });
27
- if (!chResp.ok || !Array.isArray(chResp.data))
28
- continue;
29
- for (const ch of chResp.data) {
30
- const chRec = ch;
31
- const channel_id = String(chRec.channel_id ?? chRec.id ?? "");
21
+ const channels = client.getChannelList(guild_id);
22
+ for (const ch of channels) {
23
+ const channel_id = String(ch.channel_id ?? "");
32
24
  if (!channel_id)
33
25
  continue;
34
- const channel_name = String(chRec.channel_name ?? chRec.name ?? channel_id);
26
+ const channel_name = String(ch.channel_name ?? channel_id);
35
27
  this.channels.set(channel_id, {
36
28
  channel_id,
37
29
  channel_name,
@@ -79,7 +71,7 @@ export class IcqqGuildCatalog {
79
71
  return {};
80
72
  }
81
73
  }
82
- export function isIcqqGuildIpcEvent(eventName) {
74
+ export function isIcqqGuildEvent(eventName) {
83
75
  return typeof eventName === "string" && eventName.startsWith("message.guild");
84
76
  }
85
77
  export function normalizeIcqqGuildInboundMessage(data) {
@@ -1,15 +1,15 @@
1
1
  /**
2
- * icqq 守护进程 IPC 入站事件归一化(post_type / message_type / message 段)
2
+ * icqq 入站事件归一化(post_type / message_type / message 段)
3
3
  */
4
4
  import { type MessageSegment, type QuotedMessagePayload } from "zhin.js";
5
5
  import type { GroupRole } from "./types.js";
6
6
  /** 守护进程推送的通用事件壳 */
7
- export interface IcqqIpcEventBase {
7
+ export interface IcqqEventBase {
8
8
  post_type?: string;
9
9
  self_id?: number;
10
10
  }
11
11
  /** post_type=message 时的消息体(字段随 icqqjs/cli 演进,未知字段保留) */
12
- export interface IcqqIpcMessageEvent extends IcqqIpcEventBase {
12
+ export interface IcqqMessageEvent extends IcqqEventBase {
13
13
  post_type: "message";
14
14
  message_id?: string;
15
15
  msg_id?: string;
@@ -28,7 +28,7 @@ export interface IcqqIpcMessageEvent extends IcqqIpcEventBase {
28
28
  card?: string;
29
29
  /** 群临时会话来源群号 */
30
30
  group_id?: number;
31
- /** NT/IPC 群成员角色:owner | admin | member */
31
+ /** 群成员角色:owner | admin | member */
32
32
  role?: GroupRole | string;
33
33
  };
34
34
  from_id?: number;
@@ -36,7 +36,7 @@ export interface IcqqIpcMessageEvent extends IcqqIpcEventBase {
36
36
  group_id?: number;
37
37
  to_id?: number;
38
38
  nickname?: string;
39
- /** 旧版 IPC 仅有 type 无 message_type */
39
+ /** 旧版仅有 type 无 message_type */
40
40
  type?: "group" | "private";
41
41
  /** oicq Message#source:被引用回复的源消息 */
42
42
  source?: IcqqMessageSource;
@@ -80,14 +80,14 @@ export interface NormalizedIcqqInbound {
80
80
  channelParentGroupId?: string;
81
81
  userId: string;
82
82
  nickname: string;
83
- /** 群聊时来自 IPC sender.role(私聊无) */
83
+ /** 群聊时来自 sender.role(私聊无) */
84
84
  senderRole?: GroupRole;
85
85
  content: MessageSegment[];
86
86
  rawMessage: string;
87
87
  timestampMs: number;
88
- raw: IcqqIpcMessageEvent;
88
+ raw: IcqqMessageEvent;
89
89
  }
90
- /** 从 IPC sender.role 解析群成员角色(供 Message.$sender → resolveSenderRoles) */
90
+ /** 从 sender.role 解析群成员角色(供 Message.$sender → resolveSenderRoles) */
91
91
  export declare function parseIcqqSenderGroupRole(sender: {
92
92
  role?: unknown;
93
93
  } | undefined): GroupRole | undefined;
@@ -101,36 +101,36 @@ export declare function isIcqqBotMentioned(input: {
101
101
  readonly content?: readonly MessageSegment[] | null;
102
102
  readonly rawMessage?: string;
103
103
  }): boolean;
104
- /** 从 IPC 事件壳中取出 OneBot/icqq 载荷(兼容 data 嵌套或字段在根级) */
105
- export declare function unwrapIcqqIpcEventPayload(event: {
104
+ /** 从事件壳中取出 OneBot/icqq 载荷(兼容 data 嵌套或字段在根级) */
105
+ export declare function unwrapIcqqEventPayload(event: {
106
106
  data?: unknown;
107
107
  [key: string]: unknown;
108
108
  }): unknown;
109
109
  export declare function resolveIcqqInboundUserId(data: Record<string, unknown>): number | undefined;
110
- export declare function isIcqqMessagePostType(data: unknown): data is IcqqIpcMessageEvent;
111
- export declare function shouldSkipSelfInboundMessage(data: IcqqIpcMessageEvent): boolean;
110
+ export declare function isIcqqMessagePostType(data: unknown): data is IcqqMessageEvent;
111
+ export declare function shouldSkipSelfInboundMessage(data: IcqqMessageEvent): boolean;
112
112
  /** 群临时会话私聊:icqq message_type=private & sub_type=group */
113
- export declare function isIcqqGroupTempPrivateMessage(data: IcqqIpcMessageEvent): boolean;
114
- export declare function resolveChannelFromIcqqMessage(data: IcqqIpcMessageEvent): {
113
+ export declare function isIcqqGroupTempPrivateMessage(data: IcqqMessageEvent): boolean;
114
+ export declare function resolveChannelFromIcqqMessage(data: IcqqMessageEvent): {
115
115
  channelType: "group" | "private";
116
116
  channelId: string;
117
117
  channelParentGroupId?: string;
118
118
  };
119
- export declare function resolveIcqqInboundMessageId(data: IcqqIpcMessageEvent, channelId: string): {
119
+ export declare function resolveIcqqInboundMessageId(data: IcqqMessageEvent, channelId: string): {
120
120
  id: string;
121
121
  source: "message_id" | "msg_id" | "seq" | "synthetic";
122
122
  };
123
123
  export declare function icqqElementsToSegments(elements: IcqqMessageElement[] | undefined): MessageSegment[] | null;
124
- /** IPC 载荷可能把 source 嵌在 data / event 等字段,深度查找 */
124
+ /** 载荷可能把 source 嵌在 data / event 等字段,深度查找 */
125
125
  export declare function findIcqqNestedMessageSource(root: unknown, maxDepth?: number): IcqqMessageSource | undefined;
126
126
  /** 从 oicq MessageEvent.source 解析被引用消息的 message_id */
127
127
  export declare function resolveQuoteIdFromIcqqSource(source: unknown): string | undefined;
128
128
  /** 将 source 转为 QuotedMessagePayload(供 $getMsg 缓存,避免重复拉取) */
129
129
  export declare function quotedPayloadFromIcqqSource(source: unknown): QuotedMessagePayload | null;
130
- /** 从 IPC 事件顶层字段解析引用 message_id(与 message 段互补) */
131
- export declare function resolveIcqqQuoteIdFromEvent(data: IcqqIpcMessageEvent): string | undefined;
132
- export declare function resolveInboundContent(data: IcqqIpcMessageEvent): MessageSegment[];
133
- export declare function normalizeIcqqInboundMessage(data: IcqqIpcMessageEvent): NormalizedIcqqInbound | null;
130
+ /** 从事件顶层字段解析引用 message_id(与 message 段互补) */
131
+ export declare function resolveIcqqQuoteIdFromEvent(data: IcqqMessageEvent): string | undefined;
132
+ export declare function resolveInboundContent(data: IcqqMessageEvent): MessageSegment[];
133
+ export declare function normalizeIcqqInboundMessage(data: IcqqMessageEvent): NormalizedIcqqInbound | null;
134
134
  /** 按 message_id 去重(多路 subscribe 会收到同一消息多次) */
135
135
  export declare class InboundMessageDeduper {
136
136
  private readonly seen;
@@ -1,12 +1,12 @@
1
1
  /**
2
- * icqq 守护进程 IPC 入站事件归一化(post_type / message_type / message 段)
2
+ * icqq 入站事件归一化(post_type / message_type / message 段)
3
3
  */
4
4
  import { Message, toCanonicalSegments } from "zhin.js";
5
5
  import { parseCqMessage, icqqMediaRefFromString } from "./cq-message.js";
6
6
  import { extractForwardResidFromJsonElement } from "./forward-msg.js";
7
7
  const DEDUPE_TTL_MS = 120_000;
8
8
  const ICQQ_GROUP_ROLES = new Set(["owner", "admin", "member"]);
9
- /** 从 IPC sender.role 解析群成员角色(供 Message.$sender → resolveSenderRoles) */
9
+ /** 从 sender.role 解析群成员角色(供 Message.$sender → resolveSenderRoles) */
10
10
  export function parseIcqqSenderGroupRole(sender) {
11
11
  const raw = sender?.role;
12
12
  if (typeof raw !== "string" || !raw.trim())
@@ -49,12 +49,12 @@ function isMessagePostType(postType) {
49
49
  // 如 message.private / message.group
50
50
  return postType.startsWith("message.");
51
51
  }
52
- /** 从 IPC 事件壳中取出 OneBot/icqq 载荷(兼容 data 嵌套或字段在根级) */
53
- export function unwrapIcqqIpcEventPayload(event) {
52
+ /** 从事件壳中取出 OneBot/icqq 载荷(兼容 data 嵌套或字段在根级) */
53
+ export function unwrapIcqqEventPayload(event) {
54
54
  const nested = event.data;
55
55
  if (nested && typeof nested === "object" && !Array.isArray(nested)) {
56
56
  const d = nested;
57
- if (isRecognizedIcqqIpcPayload(d)) {
57
+ if (isRecognizedIcqqPayload(d)) {
58
58
  return nested;
59
59
  }
60
60
  for (const key of ["data", "detail", "payload", "event"]) {
@@ -65,12 +65,12 @@ export function unwrapIcqqIpcEventPayload(event) {
65
65
  }
66
66
  }
67
67
  const { id: _id, event: _ev, data: _data, ok: _ok, ...rest } = event;
68
- if (isRecognizedIcqqIpcPayload(rest)) {
68
+ if (isRecognizedIcqqPayload(rest)) {
69
69
  return rest;
70
70
  }
71
71
  return nested;
72
72
  }
73
- function isRecognizedIcqqIpcPayload(d) {
73
+ function isRecognizedIcqqPayload(d) {
74
74
  const pt = d.post_type;
75
75
  if (typeof pt === "string") {
76
76
  if (isMessagePostType(pt) ||
@@ -359,7 +359,7 @@ function looksLikeIcqqMessageSource(value) {
359
359
  return false;
360
360
  return !!resolveQuoteIdFromIcqqSource(value);
361
361
  }
362
- /** IPC 载荷可能把 source 嵌在 data / event 等字段,深度查找 */
362
+ /** 载荷可能把 source 嵌在 data / event 等字段,深度查找 */
363
363
  export function findIcqqNestedMessageSource(root, maxDepth = MAX_SOURCE_WALK_DEPTH) {
364
364
  const seen = new Set();
365
365
  function walk(node, depth) {
@@ -453,7 +453,7 @@ export function quotedPayloadFromIcqqSource(source) {
453
453
  time: typeof s.time === "number" ? s.time : undefined,
454
454
  };
455
455
  }
456
- /** 从 IPC 事件顶层字段解析引用 message_id(与 message 段互补) */
456
+ /** 从事件顶层字段解析引用 message_id(与 message 段互补) */
457
457
  export function resolveIcqqQuoteIdFromEvent(data) {
458
458
  const fromSource = resolveQuoteIdFromIcqqSource(data.source) ??
459
459
  resolveQuoteIdFromIcqqSource(findIcqqNestedMessageSource(data));
@@ -1,12 +1,4 @@
1
- /**
2
- * icqq IPC request/notice 事件 → 统一收件箱行(unified_inbox_request / unified_inbox_notice)。
3
- *
4
- * daemon 经 IpcEvent 推送 icqq client.em 分发的全部事件(见 protocol.ts),
5
- * 好友/群请求(request.friend.add、request.group.add、request.group.invite)
6
- * 与通知(notice.friend.*、notice.group.*)随事件流实时到达,无需轮询;
7
- * endpoint 启动时补一次 GET_SYSTEM_MSG 拉取离线期间积存的待处理请求。
8
- */
9
- import type { IpcSystemMessage } from './types.js';
1
+ import type { SystemMessage } from './types.js';
10
2
  /** 行级公共前缀:adapter 槽 localName + endpoint live 名(uin)。 */
11
3
  export interface IcqqInboxBase {
12
4
  readonly adapter: string;
@@ -30,4 +22,4 @@ export declare function buildIcqqInboxNoticeRow(payload: Record<string, unknown>
30
22
  * GET_SYSTEM_MSG 返回项 → unified_inbox_request 行(启动时首次拉取)。
31
23
  * friend 列表项 type 语义即好友请求;group 列表项 type 为 add/invite(记 sub_type)。
32
24
  */
33
- export declare function buildIcqqSystemRequestRow(message: IpcSystemMessage, kind: 'friend' | 'group', base: IcqqInboxBase): Record<string, unknown> | null;
25
+ export declare function buildIcqqSystemRequestRow(message: SystemMessage, kind: 'friend' | 'group', base: IcqqInboxBase): Record<string, unknown> | null;
package/lib/index.d.ts CHANGED
@@ -1,6 +1,5 @@
1
- export { Actions, formatInboundContent, formatOutboundBody, icqqInboundConversation, icqqOutboundTarget, resolveIcqqConfig, type IcqqAdapterConfig, type IcqqInboundMessage, type IcqqWireSegment, type IpcEvent, type IpcMessage, type IpcRequest, type IpcResponse, type ParsedIcqqSendTarget, type ResolvedIcqqConfig, } from './protocol.js';
2
- export { IcqqIpcEndpoint, type CreateIcqqIpc, type IcqqEndpointOptions, type IcqqInboxHooks, type IcqqIpcTransport, } from './endpoint.js';
1
+ export { Actions, formatInboundContent, formatOutboundBody, icqqInboundConversation, icqqOutboundTarget, type ActionResult, type IcqqAdapterConfig, type IcqqInboundMessage, type IcqqWireSegment, type ParsedIcqqSendTarget, type ResolvedIcqqConfig, } from './protocol.js';
2
+ export { IcqqEndpoint, type IcqqEndpointOptions, type IcqqInboxHooks, } from './endpoint.js';
3
3
  export * from './types.js';
4
4
  export { getIcqqAgentDeps, registerIcqqAgentEndpoint, setIcqqAgentDeps, type IcqqAgentDeps, type IcqqAgentEndpoint, } from './icqq-agent-deps.js';
5
- export { IpcClient } from './ipc-client.js';
6
5
  export { resolveIcqqInboundMessageId, } from './icqq-inbound.js';
package/lib/index.js CHANGED
@@ -1,6 +1,5 @@
1
- export { Actions, formatInboundContent, formatOutboundBody, icqqInboundConversation, icqqOutboundTarget, resolveIcqqConfig, } from './protocol.js';
2
- export { IcqqIpcEndpoint, } from './endpoint.js';
1
+ export { Actions, formatInboundContent, formatOutboundBody, icqqInboundConversation, icqqOutboundTarget, } from './protocol.js';
2
+ export { IcqqEndpoint, } from './endpoint.js';
3
3
  export * from './types.js';
4
4
  export { getIcqqAgentDeps, registerIcqqAgentEndpoint, setIcqqAgentDeps, } from './icqq-agent-deps.js';
5
- export { IpcClient } from './ipc-client.js';
6
5
  export { resolveIcqqInboundMessageId, } from './icqq-inbound.js';
@@ -1,15 +1,10 @@
1
1
  import type { SendContent } from "zhin.js";
2
2
  import type { IcqqEndpointConfig } from "./types.js";
3
3
  export type IcqqOutboundMediaMode = "file" | "base64";
4
- /**
5
- * 出站媒体模式:file=本机落盘后 CQ [image:path](与 icqq 同机时可用);
6
- * base64=保留 MediaRef base64,CQ 编码为 [image:base64://...] 经 IPC 交给守护进程解码(异机 RPC 默认)。
7
- */
8
- export declare function resolveIcqqOutboundMediaMode(config: Pick<IcqqEndpointConfig, "rpc" | "outboundMedia">): IcqqOutboundMediaMode;
4
+ export declare function resolveIcqqOutboundMediaMode(config: Pick<IcqqEndpointConfig, "outboundMedia">): IcqqOutboundMediaMode;
9
5
  /**
10
6
  * file 模式:将 canonical MediaRef(`data.media`,kind=base64)物化为本机路径,
11
- * 并把 media 改写为 path 引用(与 icqq 同机时守护进程直接读盘)。
12
- * base64 模式:不改动(由 toCqString/formatOutboundBody 生成 base64://,供异机守护进程解码)。
13
- * 无 canonical MediaRef 的段原样保留(不可投递,由下游 CQ 序列化 warn + 丢弃)。
7
+ * 并把 media 改写为 path 引用(icqq 客户端直接读盘)。
8
+ * base64 模式:不改动(由 toCqString/formatOutboundBody 生成 base64://)。
14
9
  */
15
10
  export declare function materializeOutboundBase64(content: SendContent, mode?: IcqqOutboundMediaMode): SendContent;
@@ -23,21 +23,16 @@ function spoolBase64ToFile(base64, mime, kind) {
23
23
  fs.writeFileSync(filePath, Buffer.from(base64, "base64"));
24
24
  return filePath;
25
25
  }
26
- /**
27
- * 出站媒体模式:file=本机落盘后 CQ [image:path](与 icqq 同机时可用);
28
- * base64=保留 MediaRef base64,CQ 编码为 [image:base64://...] 经 IPC 交给守护进程解码(异机 RPC 默认)。
29
- */
30
26
  export function resolveIcqqOutboundMediaMode(config) {
31
27
  if (config.outboundMedia === "base64" || config.outboundMedia === "file") {
32
28
  return config.outboundMedia;
33
29
  }
34
- return config.rpc ? "base64" : "file";
30
+ return "file";
35
31
  }
36
32
  /**
37
33
  * file 模式:将 canonical MediaRef(`data.media`,kind=base64)物化为本机路径,
38
- * 并把 media 改写为 path 引用(与 icqq 同机时守护进程直接读盘)。
39
- * base64 模式:不改动(由 toCqString/formatOutboundBody 生成 base64://,供异机守护进程解码)。
40
- * 无 canonical MediaRef 的段原样保留(不可投递,由下游 CQ 序列化 warn + 丢弃)。
34
+ * 并把 media 改写为 path 引用(icqq 客户端直接读盘)。
35
+ * base64 模式:不改动(由 toCqString/formatOutboundBody 生成 base64://)。
41
36
  */
42
37
  export function materializeOutboundBase64(content, mode = "file") {
43
38
  if (mode === "base64")