@zhin.js/adapter-icqq 4.0.0 → 5.0.0

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 (56) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +30 -30
  3. package/client/ICQQManagement.tsx +15 -15
  4. package/client/LoginAssistPanel.tsx +2 -2
  5. package/dist/index.js +1 -2
  6. package/lib/adapter.d.ts +14 -13
  7. package/lib/adapter.d.ts.map +1 -1
  8. package/lib/adapter.js +31 -30
  9. package/lib/adapter.js.map +1 -1
  10. package/lib/{bot.d.ts → endpoint.d.ts} +9 -9
  11. package/lib/endpoint.d.ts.map +1 -0
  12. package/lib/{bot.js → endpoint.js} +30 -41
  13. package/lib/endpoint.js.map +1 -0
  14. package/lib/icqq-side-events.d.ts +2 -2
  15. package/lib/icqq-side-events.d.ts.map +1 -1
  16. package/lib/icqq-side-events.js +4 -4
  17. package/lib/icqq-side-events.js.map +1 -1
  18. package/lib/index.d.ts +1 -1
  19. package/lib/index.d.ts.map +1 -1
  20. package/lib/index.js +1 -1
  21. package/lib/index.js.map +1 -1
  22. package/lib/ipc-client.js +2 -2
  23. package/lib/ipc-client.js.map +1 -1
  24. package/lib/outbound-media.d.ts +2 -2
  25. package/lib/outbound-media.d.ts.map +1 -1
  26. package/lib/outbound-media.js.map +1 -1
  27. package/lib/routes.js +14 -14
  28. package/lib/routes.js.map +1 -1
  29. package/lib/tools/index.d.ts.map +1 -1
  30. package/lib/tools/index.js +80 -75
  31. package/lib/tools/index.js.map +1 -1
  32. package/lib/types.d.ts +2 -2
  33. package/lib/types.d.ts.map +1 -1
  34. package/lib/typing-indicator-example.d.ts +10 -10
  35. package/lib/typing-indicator-example.d.ts.map +1 -1
  36. package/lib/typing-indicator-example.js +24 -24
  37. package/lib/typing-indicator-example.js.map +1 -1
  38. package/lib/typing-indicator.d.ts +10 -10
  39. package/lib/typing-indicator.d.ts.map +1 -1
  40. package/lib/typing-indicator.js +37 -37
  41. package/lib/typing-indicator.js.map +1 -1
  42. package/package.json +15 -11
  43. package/skills/icqq/PERMITS.md +22 -0
  44. package/src/adapter.ts +33 -31
  45. package/src/{bot.ts → endpoint.ts} +30 -40
  46. package/src/icqq-side-events.ts +4 -4
  47. package/src/index.ts +1 -1
  48. package/src/ipc-client.ts +2 -2
  49. package/src/outbound-media.ts +2 -2
  50. package/src/routes.ts +14 -14
  51. package/src/tools/index.ts +68 -63
  52. package/src/types.ts +2 -2
  53. package/src/typing-indicator-example.ts +25 -25
  54. package/src/typing-indicator.ts +40 -40
  55. package/lib/bot.d.ts.map +0 -1
  56. package/lib/bot.js.map +0 -1
@@ -1,12 +1,12 @@
1
1
  /**
2
- * ICQQ Bot:通过 @icqqjs/cli 守护进程 IPC 通信,实现 zhin Bot 接口
2
+ * ICQQ Bot:通过 @icqqjs/cli 守护进程 IPC 通信,实现 zhin Endpoint 接口
3
3
  *
4
4
  * 不再直接依赖 @icqqjs/icqq 协议库。
5
- * 登录由 `icqq login` 完成,本 Bot 只负责连接守护进程并收发消息。
5
+ * 登录由 `icqq login` 完成,本 Endpoint 只负责连接守护进程并收发消息。
6
6
  */
7
- import { formatCompact, Bot, Message, segment, SendContent, SendOptions, type QuotedMessagePayload } from 'zhin.js';
7
+ import { formatCompact, Endpoint, Message, segment, SendContent, SendOptions, type QuotedMessagePayload } from 'zhin.js';
8
8
  import type {
9
- IcqqBotConfig,
9
+ IcqqEndpointConfig,
10
10
  IcqqSenderInfo,
11
11
  IpcFriendInfo,
12
12
  IpcGroupInfo,
@@ -53,9 +53,9 @@ import { enableTypingIndicator, type ICQQTypingIndicatorManager } from "./typing
53
53
  import { parseIcqqGetMsgResponse } from "./get-msg.js";
54
54
  import { enrichQuotedPayloadWithForward, isForwardPlaceholderPayload } from "./forward-msg.js";
55
55
 
56
- export class IcqqBot implements Bot<IcqqBotConfig, IcqqIpcMessageEvent> {
56
+ export class IcqqEndpoint implements Endpoint<IcqqEndpointConfig, IcqqIpcMessageEvent> {
57
57
  $connected = false;
58
- $config: IcqqBotConfig;
58
+ $config: IcqqEndpointConfig;
59
59
  ipc!: IpcClient;
60
60
 
61
61
  /** 缓存的好友列表 */
@@ -86,7 +86,7 @@ export class IcqqBot implements Bot<IcqqBotConfig, IcqqIpcMessageEvent> {
86
86
 
87
87
  constructor(
88
88
  public adapter: IcqqAdapter,
89
- config: IcqqBotConfig,
89
+ config: IcqqEndpointConfig,
90
90
  ) {
91
91
  this.$config = config;
92
92
  }
@@ -127,7 +127,7 @@ export class IcqqBot implements Bot<IcqqBotConfig, IcqqIpcMessageEvent> {
127
127
  // 如果配置中明确设置为 false,则不启用
128
128
  if (typingConfig?.enabled === false) {
129
129
  this.logger.debug(formatCompact({
130
- bot: this.$id,
130
+ endpoint: this.$id,
131
131
  typingIndicator: 'disabled_by_config',
132
132
  }));
133
133
  return;
@@ -137,13 +137,13 @@ export class IcqqBot implements Bot<IcqqBotConfig, IcqqIpcMessageEvent> {
137
137
  try {
138
138
  this.$typingIndicator = enableTypingIndicator(this, typingConfig);
139
139
  this.logger.debug(formatCompact({
140
- bot: this.$id,
140
+ endpoint: this.$id,
141
141
  typingIndicator: 'enabled',
142
142
  emoji: typingConfig?.defaultEmoji || '⏳',
143
143
  }));
144
144
  } catch (error) {
145
145
  this.logger.warn(formatCompact({
146
- bot: this.$id,
146
+ endpoint: this.$id,
147
147
  typingIndicator: 'failed',
148
148
  error: error instanceof Error ? error.message : String(error),
149
149
  }));
@@ -209,7 +209,7 @@ export class IcqqBot implements Bot<IcqqBotConfig, IcqqIpcMessageEvent> {
209
209
  this.$connected = false;
210
210
  this.logger.warn(formatCompact( {
211
211
  op: "disconnect",
212
- bot: this.$id,
212
+ endpoint: this.$id,
213
213
  ok: false,
214
214
  delay_ms: delayMs,
215
215
  attempt: attempt + 1,
@@ -222,17 +222,17 @@ export class IcqqBot implements Bot<IcqqBotConfig, IcqqIpcMessageEvent> {
222
222
  await this.rebindIpcSession();
223
223
  this.logger.info(formatCompact( {
224
224
  op: "reconnect",
225
- bot: this.$id,
225
+ endpoint: this.$id,
226
226
  friends: this.friends.size,
227
227
  groups: this.groups.size,
228
228
  }));
229
229
  break;
230
- } catch (e: any) {
230
+ } catch (e: unknown) {
231
231
  this.logger.warn(formatCompact( {
232
232
  op: "reconnect",
233
- bot: this.$id,
233
+ endpoint: this.$id,
234
234
  ok: false,
235
- error: e?.message ?? String(e),
235
+ error: e instanceof Error ? e.message : String(e),
236
236
  }));
237
237
  }
238
238
  }
@@ -282,7 +282,7 @@ export class IcqqBot implements Bot<IcqqBotConfig, IcqqIpcMessageEvent> {
282
282
  this.inboundDeduper.clear();
283
283
  this.ipc?.close();
284
284
  this.$connected = false;
285
- this.logger.info(formatCompact( { op: "disconnect", bot: this.$id }));
285
+ this.logger.info(formatCompact( { op: "disconnect", endpoint: this.$id }));
286
286
  }
287
287
 
288
288
  // ── 消息处理 ───────────────────────────────────────────────────────
@@ -394,7 +394,7 @@ export class IcqqBot implements Bot<IcqqBotConfig, IcqqIpcMessageEvent> {
394
394
  formatCompact({
395
395
  notice: notice.$type,
396
396
  channel: `${notice.$channel.type}(${notice.$channel.id})`,
397
- bot: this.$id,
397
+ endpoint: this.$id,
398
398
  sub_type: notice.$subType,
399
399
  }),
400
400
  );
@@ -414,7 +414,7 @@ export class IcqqBot implements Bot<IcqqBotConfig, IcqqIpcMessageEvent> {
414
414
  formatCompact({
415
415
  request: request.$type,
416
416
  channel: `${request.$channel.type}(${request.$channel.id})`,
417
- bot: this.$id,
417
+ endpoint: this.$id,
418
418
  from: request.$sender.id,
419
419
  }),
420
420
  );
@@ -489,16 +489,6 @@ export class IcqqBot implements Bot<IcqqBotConfig, IcqqIpcMessageEvent> {
489
489
  senderInfo.permissions = ["admin"];
490
490
  }
491
491
  }
492
- if (normalized.senderRole && normalized.senderRole !== "member") {
493
- senderInfo.role = normalized.senderRole;
494
- if (normalized.senderRole === "owner") {
495
- senderInfo.isOwner = true;
496
- senderInfo.permissions = ["owner"];
497
- } else if (normalized.senderRole === "admin") {
498
- senderInfo.isAdmin = true;
499
- senderInfo.permissions = ["admin"];
500
- }
501
- }
502
492
 
503
493
  const quoteId =
504
494
  Message.quoteIdFromContent(normalized.content) ??
@@ -508,7 +498,7 @@ export class IcqqBot implements Bot<IcqqBotConfig, IcqqIpcMessageEvent> {
508
498
  const result = Message.from(raw, {
509
499
  $id: normalized.messageId,
510
500
  $adapter: "icqq" as const,
511
- $bot: this.$config.name,
501
+ $endpoint: this.$config.name,
512
502
  $sender: senderInfo,
513
503
  $channel: {
514
504
  id: normalized.channelId,
@@ -522,7 +512,7 @@ export class IcqqBot implements Bot<IcqqBotConfig, IcqqIpcMessageEvent> {
522
512
  if (normalized.idSource === "synthetic") {
523
513
  this.logger.warn(formatCompact( {
524
514
  op: "recall",
525
- bot: this.$id,
515
+ endpoint: this.$id,
526
516
  ok: false,
527
517
  error: "no message_id in push",
528
518
  }));
@@ -544,7 +534,7 @@ export class IcqqBot implements Bot<IcqqBotConfig, IcqqIpcMessageEvent> {
544
534
  return await this.adapter.sendMessage({
545
535
  ...result.$channel,
546
536
  context: "icqq",
547
- bot: this.$config.name,
537
+ endpoint: this.$config.name,
548
538
  content,
549
539
  });
550
540
  },
@@ -640,7 +630,7 @@ export class IcqqBot implements Bot<IcqqBotConfig, IcqqIpcMessageEvent> {
640
630
  if (!resp.ok) {
641
631
  this.logger.warn(formatCompact( {
642
632
  op: "recall",
643
- bot: this.$id,
633
+ endpoint: this.$id,
644
634
  ok: false,
645
635
  error: resp.error,
646
636
  }));
@@ -717,7 +707,7 @@ export class IcqqBot implements Bot<IcqqBotConfig, IcqqIpcMessageEvent> {
717
707
  }
718
708
 
719
709
  // 从映射中查找
720
- const id = IcqqBot.EMOJI_MAP[emoji];
710
+ const id = IcqqEndpoint.EMOJI_MAP[emoji];
721
711
  if (id) {
722
712
  return id;
723
713
  }
@@ -745,7 +735,7 @@ export class IcqqBot implements Bot<IcqqBotConfig, IcqqIpcMessageEvent> {
745
735
  if (!resp.ok) {
746
736
  this.logger.warn(formatCompact({
747
737
  op: "add_reaction",
748
- bot: this.$id,
738
+ endpoint: this.$id,
749
739
  message_id: messageId,
750
740
  emoji,
751
741
  id: emojiId,
@@ -757,7 +747,7 @@ export class IcqqBot implements Bot<IcqqBotConfig, IcqqIpcMessageEvent> {
757
747
 
758
748
  this.logger.debug(formatCompact({
759
749
  op: "add_reaction",
760
- bot: this.$id,
750
+ endpoint: this.$id,
761
751
  message_id: messageId,
762
752
  emoji,
763
753
  id: emojiId,
@@ -769,7 +759,7 @@ export class IcqqBot implements Bot<IcqqBotConfig, IcqqIpcMessageEvent> {
769
759
  } catch (error) {
770
760
  this.logger.warn(formatCompact({
771
761
  op: "add_reaction",
772
- bot: this.$id,
762
+ endpoint: this.$id,
773
763
  message_id: messageId,
774
764
  emoji,
775
765
  ok: false,
@@ -801,7 +791,7 @@ export class IcqqBot implements Bot<IcqqBotConfig, IcqqIpcMessageEvent> {
801
791
  if (!resp.ok) {
802
792
  this.logger.warn(formatCompact({
803
793
  op: "remove_reaction",
804
- bot: this.$id,
794
+ endpoint: this.$id,
805
795
  message_id: messageId,
806
796
  reaction_id: reactionId,
807
797
  id: emojiId,
@@ -811,7 +801,7 @@ export class IcqqBot implements Bot<IcqqBotConfig, IcqqIpcMessageEvent> {
811
801
  } else {
812
802
  this.logger.debug(formatCompact({
813
803
  op: "remove_reaction",
814
- bot: this.$id,
804
+ endpoint: this.$id,
815
805
  message_id: messageId,
816
806
  reaction_id: reactionId,
817
807
  id: emojiId,
@@ -821,7 +811,7 @@ export class IcqqBot implements Bot<IcqqBotConfig, IcqqIpcMessageEvent> {
821
811
  } catch (error) {
822
812
  this.logger.warn(formatCompact({
823
813
  op: "remove_reaction",
824
- bot: this.$id,
814
+ endpoint: this.$id,
825
815
  message_id: messageId,
826
816
  reaction_id: reactionId,
827
817
  ok: false,
@@ -832,7 +822,7 @@ export class IcqqBot implements Bot<IcqqBotConfig, IcqqIpcMessageEvent> {
832
822
  }
833
823
 
834
824
  /** @deprecated 使用 `./cq-message.js` 导出 */
835
- export namespace IcqqBot {
825
+ export namespace IcqqEndpoint {
836
826
  export const parseCqMessage = parseCqMessageImpl;
837
827
  export const buildIcqqIpcMessage = buildIcqqIpcMessageImpl;
838
828
  export const toCqString = toCqStringImpl;
@@ -116,7 +116,7 @@ function senderFromId(id: unknown, name?: string) {
116
116
 
117
117
  export function formatIcqqNotice(
118
118
  event: IcqqIpcRawEvent,
119
- botName: string,
119
+ endpointName: string,
120
120
  ): ReturnType<typeof Notice.from<IcqqIpcRawEvent>> {
121
121
  const $type = resolveNoticeZhinType(event);
122
122
  const isGroup = event.group_id != null;
@@ -128,7 +128,7 @@ export function formatIcqqNotice(
128
128
  return Notice.from(event, {
129
129
  $id: resolveSideEventDedupeKey(event, "notice"),
130
130
  $adapter: "icqq",
131
- $bot: botName,
131
+ $endpoint: endpointName,
132
132
  $type,
133
133
  $subType: event.sub_type,
134
134
  $channel: {
@@ -152,7 +152,7 @@ function resolveRequestZhinType(event: IcqqIpcRawEvent): RequestType {
152
152
 
153
153
  export function formatIcqqRequest(
154
154
  event: IcqqIpcRawEvent,
155
- botName: string,
155
+ endpointName: string,
156
156
  ipc: IpcClient,
157
157
  ): ReturnType<typeof Request.from<IcqqIpcRawEvent>> {
158
158
  const $type = resolveRequestZhinType(event);
@@ -169,7 +169,7 @@ export function formatIcqqRequest(
169
169
  return Request.from(event, {
170
170
  $id: String(flag),
171
171
  $adapter: "icqq",
172
- $bot: botName,
172
+ $endpoint: endpointName,
173
173
  $type,
174
174
  $subType: event.sub_type,
175
175
  $channel: {
package/src/index.ts CHANGED
@@ -29,7 +29,7 @@ declare module "zhin.js" {
29
29
  }
30
30
 
31
31
  export * from "./types.js";
32
- export { IcqqBot } from "./bot.js";
32
+ export { IcqqEndpoint } from "./endpoint.js";
33
33
  export { IcqqAdapter } from "./adapter.js";
34
34
  export {
35
35
  ICQQTypingIndicatorManager,
package/src/ipc-client.ts CHANGED
@@ -162,7 +162,7 @@ export class IpcClient {
162
162
  sock.on("error", (err) =>
163
163
  reject(
164
164
  new Error(
165
- `无法连接 icqq 守护进程 (${getSocketPath(uin)}): ${err.message}。请先执行: icqq login`,
165
+ `无法连接 icqq 守护进程 (${getSocketPath(uin)}): ${err instanceof Error ? err.message : String(err)}。请先执行: icqq login`,
166
166
  ),
167
167
  ),
168
168
  );
@@ -204,7 +204,7 @@ export class IpcClient {
204
204
  sock.on("connect", () => resolve(new IpcClient(sock, true)));
205
205
  sock.on("error", (err) =>
206
206
  reject(
207
- new Error(`无法连接 icqq RPC 服务 (${host}:${port}): ${err.message}`),
207
+ new Error(`无法连接 icqq RPC 服务 (${host}:${port}): ${err instanceof Error ? err.message : String(err)}`),
208
208
  ),
209
209
  );
210
210
  });
@@ -3,7 +3,7 @@ import * as os from "node:os";
3
3
  import * as path from "node:path";
4
4
  import * as crypto from "node:crypto";
5
5
  import type { MessageSegment, SendContent } from "zhin.js";
6
- import type { IcqqBotConfig } from "./types.js";
6
+ import type { IcqqEndpointConfig } from "./types.js";
7
7
 
8
8
  export type IcqqOutboundMediaMode = "file" | "base64";
9
9
 
@@ -38,7 +38,7 @@ function spoolBase64ToFile(
38
38
  * base64=保留 segment.base64,CQ 编码为 [image:base64://...] 经 IPC 交给守护进程解码(异机 RPC 默认)。
39
39
  */
40
40
  export function resolveIcqqOutboundMediaMode(
41
- config: Pick<IcqqBotConfig, "rpc" | "outboundMedia">,
41
+ config: Pick<IcqqEndpointConfig, "rpc" | "outboundMedia">,
42
42
  ): IcqqOutboundMediaMode {
43
43
  if (config.outboundMedia === "base64" || config.outboundMedia === "file") {
44
44
  return config.outboundMedia;
package/src/routes.ts CHANGED
@@ -11,29 +11,29 @@ export function registerRoutes(
11
11
  icqq: IcqqAdapter,
12
12
  _root: Plugin,
13
13
  ) {
14
- router.get("/api/icqq/bots", async (ctx) => {
14
+ router.get("/api/icqq/endpoints", async (ctx) => {
15
15
  try {
16
- const bots = Array.from(icqq.bots.values());
17
- if (bots.length === 0) {
18
- ctx.body = { success: true, data: [], message: "暂无ICQQ机器人实例" };
16
+ const endpoints = Array.from(icqq.endpoints.values());
17
+ if (endpoints.length === 0) {
18
+ ctx.body = { success: true, data: [], message: "暂无ICQQEndpoint 实例" };
19
19
  return;
20
20
  }
21
21
  const result = await Promise.all(
22
- bots.map(async (bot) => {
22
+ endpoints.map(async (endpoint) => {
23
23
  try {
24
24
  const base: Record<string, unknown> = {
25
- name: bot.$config.name,
26
- connected: bot.$connected || false,
27
- groupCount: bot.groups.size,
28
- friendCount: bot.friends.size,
29
- status: bot.$connected ? "online" : "offline",
25
+ name: endpoint.$config.name,
26
+ connected: endpoint.$connected || false,
27
+ groupCount: endpoint.groups.size,
28
+ friendCount: endpoint.friends.size,
29
+ status: endpoint.$connected ? "online" : "offline",
30
30
  lastActivity: new Date().toISOString(),
31
31
  };
32
32
 
33
33
  // 尝试从守护进程获取详细状态
34
- if (bot.$connected && bot.ipc && !bot.ipc.closed) {
34
+ if (endpoint.$connected && endpoint.ipc && !endpoint.ipc.closed) {
35
35
  try {
36
- const statusResp = await bot.ipc.request(
36
+ const statusResp = await endpoint.ipc.request(
37
37
  Actions.GET_STATUS,
38
38
  {},
39
39
  5000,
@@ -51,7 +51,7 @@ export function registerRoutes(
51
51
  return base;
52
52
  } catch {
53
53
  return {
54
- name: bot.$config.name,
54
+ name: endpoint.$config.name,
55
55
  connected: false,
56
56
  groupCount: 0,
57
57
  friendCount: 0,
@@ -71,7 +71,7 @@ export function registerRoutes(
71
71
  ctx.body = {
72
72
  success: false,
73
73
  error: "ICQQ_API_ERROR",
74
- message: "获取机器人数据失败",
74
+ message: "获取 Endpoint 数据失败",
75
75
  details:
76
76
  process.env.NODE_ENV === "development"
77
77
  ? (error as Error).message