@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
package/src/protocol.ts CHANGED
@@ -1,61 +1,20 @@
1
- /**
2
- * IPC 协议类型定义与 Action 常量 (ported from @icqqjs/cli)
3
- *
4
- * CLI 与守护进程通过 Unix Domain Socket 通信,
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.*`)。
13
- */
14
-
15
1
  import { pickCredential } from '@zhin.js/adapter';
16
2
  import type { ConversationRef } from '@zhin.js/im-contract';
17
3
  import type { MessageSegment } from "zhin.js";
18
4
  import { resolveCqMediaArg } from "./cq-message.js";
19
5
 
20
- /** CLI → Daemon 请求 */
21
- export type IpcRequest = {
22
- id: string;
23
- action: string;
24
- params: Record<string, unknown>;
25
- };
26
-
27
- /** Daemon → CLI 响应 */
28
- export type IpcResponse = {
6
+ export type ActionResult = {
29
7
  id: string;
30
8
  ok: boolean;
31
9
  data?: unknown;
32
10
  error?: string;
33
11
  };
34
12
 
35
- /**
36
- * Daemon → CLI 事件推送(icqq client.em 分发的全部事件)
37
- *
38
- * 登录/重连时推送 `system.login.*`(如 `system.login.auth` 含 url + device),
39
- * 语义在 `event` 字段,不在 OneBot 式 `post_type` 里。
40
- */
41
- export type IpcEvent = {
42
- /** 固定为 `"*"`,客户端应忽略,由本地 handler 按 `event` 过滤 */
43
- id: string;
44
- /** icqq 事件名,如 `system.login.auth`、`message.group.normal` */
45
- event: string;
46
- /** icqq 事件 toJSON 后的 plain object */
47
- data: unknown;
48
- };
49
-
50
- export type IpcMessage = IpcResponse | IpcEvent;
51
-
52
- export type { IcqqIpcMessageEvent } from "./icqq-inbound.js";
13
+ export type { IcqqMessageEvent } from "./icqq-inbound.js";
53
14
 
54
- /** 从 IPC 入站 payload 解析可用于引用/撤回的消息 ID */
55
15
  export { resolveIcqqInboundMessageId } from "./icqq-inbound.js";
56
16
 
57
- /** Guild 消息事件数据 */
58
- export interface IpcGuildMessageEventData {
17
+ export interface GuildMessageEventData {
59
18
  type: "guild";
60
19
  guild_id: string;
61
20
  guild_name: string;
@@ -69,7 +28,7 @@ export interface IpcGuildMessageEventData {
69
28
  }
70
29
 
71
30
  /**
72
- * 所有 IPC 操作常量 (from @icqqjs/cli)
31
+ * 所有操作常量(@icqqjs/icqq)
73
32
  */
74
33
  export const Actions = {
75
34
  PING: "ping",
@@ -276,22 +235,34 @@ export interface IcqqAdapterConfig {
276
235
  readonly id?: string;
277
236
  readonly autoReconnect?: boolean;
278
237
  readonly outboundMedia?: 'file' | 'base64';
279
- readonly rpc?: {
280
- readonly host?: string;
281
- readonly port?: number;
282
- readonly token?: string;
283
- };
238
+ readonly password?: string;
239
+ readonly platform?: number;
240
+ readonly ver?: string;
241
+ readonly dataDir?: string;
242
+ readonly signApiAddr?: string;
243
+ readonly ignoreSelf?: boolean;
244
+ readonly resend?: boolean;
245
+ readonly cacheGroupMember?: boolean;
246
+ readonly autoServer?: boolean;
247
+ readonly qqnt?: boolean;
248
+ readonly ntLogin?: boolean;
284
249
  /** Transitional: legacy root `endpoints[]` with `context: icqq`. */
285
250
  readonly endpoints?: ReadonlyArray<{
286
251
  readonly context?: string;
287
252
  readonly id?: string;
288
253
  readonly autoReconnect?: boolean;
289
254
  readonly outboundMedia?: 'file' | 'base64';
290
- readonly rpc?: {
291
- readonly host?: string;
292
- readonly port?: number;
293
- readonly token?: string;
294
- };
255
+ readonly password?: string;
256
+ readonly platform?: number;
257
+ readonly ver?: string;
258
+ readonly dataDir?: string;
259
+ readonly signApiAddr?: string;
260
+ readonly ignoreSelf?: boolean;
261
+ readonly resend?: boolean;
262
+ readonly cacheGroupMember?: boolean;
263
+ readonly autoServer?: boolean;
264
+ readonly qqnt?: boolean;
265
+ readonly ntLogin?: boolean;
295
266
  }>;
296
267
  }
297
268
 
@@ -300,11 +271,17 @@ export interface ResolvedIcqqConfig {
300
271
  readonly id: string;
301
272
  readonly autoReconnect: boolean;
302
273
  readonly outboundMedia?: 'file' | 'base64';
303
- readonly rpc?: {
304
- readonly host: string;
305
- readonly port: number;
306
- readonly token: string;
307
- };
274
+ readonly password?: string;
275
+ readonly platform?: number;
276
+ readonly ver?: string;
277
+ readonly dataDir?: string;
278
+ readonly signApiAddr?: string;
279
+ readonly ignoreSelf?: boolean;
280
+ readonly resend?: boolean;
281
+ readonly cacheGroupMember?: boolean;
282
+ readonly autoServer?: boolean;
283
+ readonly qqnt?: boolean;
284
+ readonly ntLogin?: boolean;
308
285
  }
309
286
 
310
287
  export interface IcqqWireSegment {
@@ -342,16 +319,33 @@ export function resolveIcqqConfig(config: IcqqAdapterConfig = {}): ResolvedIcqqC
342
319
  }
343
320
  const autoReconnect = config.autoReconnect ?? entry?.autoReconnect ?? true;
344
321
  const outboundMedia = config.outboundMedia ?? entry?.outboundMedia;
345
- const rpcRaw = config.rpc ?? entry?.rpc;
346
- const rpc = rpcRaw?.host && rpcRaw.port != null && rpcRaw.token
347
- ? { host: rpcRaw.host, port: Number(rpcRaw.port), token: rpcRaw.token }
348
- : undefined;
322
+ const password = entry?.password;
323
+ const platform = config.platform ?? entry?.platform ?? 2;
324
+ const ver = config.ver ?? entry?.ver ?? '9.1.70';
325
+ const dataDir = config.dataDir ?? entry?.dataDir ?? `data/icqq/${id}`;
326
+ const signApiAddr = config.signApiAddr ?? entry?.signApiAddr;
327
+ const ignoreSelf = config.ignoreSelf ?? entry?.ignoreSelf ?? true;
328
+ const resend = config.resend ?? entry?.resend;
329
+ const cacheGroupMember = config.cacheGroupMember ?? entry?.cacheGroupMember ?? true;
330
+ const autoServer = config.autoServer ?? entry?.autoServer ?? true;
331
+ const qqnt = config.qqnt ?? entry?.qqnt;
332
+ const ntLogin = config.ntLogin ?? entry?.ntLogin;
349
333
  return {
350
334
  context: 'icqq',
351
335
  id,
352
336
  autoReconnect,
353
337
  ...(outboundMedia ? { outboundMedia } : {}),
354
- ...(rpc ? { rpc } : {}),
338
+ ...(password ? { password } : {}),
339
+ ...(platform != null ? { platform: Number(platform) } : {}),
340
+ ...(ver ? { ver } : {}),
341
+ ...(dataDir ? { dataDir } : {}),
342
+ ...(signApiAddr ? { signApiAddr } : {}),
343
+ ...(ignoreSelf != null ? { ignoreSelf } : {}),
344
+ ...(resend != null ? { resend } : {}),
345
+ ...(cacheGroupMember != null ? { cacheGroupMember } : {}),
346
+ ...(autoServer != null ? { autoServer } : {}),
347
+ ...(qqnt != null ? { qqnt } : {}),
348
+ ...(ntLogin != null ? { ntLogin } : {}),
355
349
  };
356
350
  }
357
351
 
@@ -386,7 +380,7 @@ export function icqqInboundConversation(endpointKey: string, input: {
386
380
  }
387
381
 
388
382
  /**
389
- * 出站:从 ConversationRef 派生 IPC action 路由。
383
+ * 出站:从 ConversationRef 派生 action 路由。
390
384
  * 群容器(parent kind 'group')内的 private 会话即 ICQQ 群临时会话(temp)。
391
385
  */
392
386
  export function icqqOutboundTarget(conversation: ConversationRef): ParsedIcqqSendTarget {
@@ -454,6 +448,8 @@ export function formatOutboundBody(payload: unknown): string {
454
448
  const arg = resolveCqMediaArg('video', item.data);
455
449
  return arg ? `[video:${arg}]` : '';
456
450
  }
451
+ case 'share':
452
+ return formatMusicShareJson(item.data);
457
453
  default:
458
454
  return String(item.data?.text ?? '');
459
455
  }
@@ -471,3 +467,49 @@ function isWireSegment(value: unknown): value is IcqqWireSegment {
471
467
  && value !== null
472
468
  && typeof (value as { type?: unknown }).type === 'string';
473
469
  }
470
+
471
+ function formatMusicShareJson(data: Record<string, unknown> | undefined): string {
472
+ if (!data) return '';
473
+ const config = data.config as {
474
+ appid?: number;
475
+ package?: string;
476
+ icon?: string;
477
+ sign?: string;
478
+ } | undefined;
479
+ const title = String(data.title ?? '');
480
+ const desc = String(data.artist ?? '');
481
+ const jumpUrl = String(data.url ?? '');
482
+ const musicUrl = String(data.audio ?? '');
483
+ const preview = String(data.image ?? '');
484
+ const tag = config?.appid === 100497308 ? 'QQ音乐'
485
+ : config?.appid === 100495085 ? '网易云音乐'
486
+ : config?.appid === 100243533 ? '酷我音乐'
487
+ : config?.appid === 205141 ? '酷狗音乐'
488
+ : '音乐';
489
+ const json = {
490
+ app: 'com.tencent.structmsg',
491
+ view: 'music',
492
+ ver: '0.0.0.1',
493
+ desc: 'music',
494
+ prompt: `[分享]${title}`,
495
+ meta: {
496
+ music: {
497
+ action: '',
498
+ android_pkg_name: config?.package ?? '',
499
+ app_type: 1,
500
+ appid: config?.appid ?? 0,
501
+ ctime: 0,
502
+ desc,
503
+ jumpUrl,
504
+ musicUrl,
505
+ preview,
506
+ sourceMsgId: '0',
507
+ source_icon: config?.icon ?? '',
508
+ source_url: '',
509
+ tag,
510
+ title,
511
+ },
512
+ },
513
+ };
514
+ return `[json:${JSON.stringify(json)}]`;
515
+ }
package/src/types.ts CHANGED
@@ -1,9 +1,3 @@
1
- /**
2
- * ICQQ 适配器类型与配置
3
- *
4
- * 不再直接依赖 @icqqjs/icqq,通过 @icqqjs/cli 守护进程 IPC 通信。
5
- */
6
-
7
1
  export type GroupRole = "owner" | "admin" | "member";
8
2
 
9
3
  export interface IcqqSenderInfo {
@@ -17,47 +11,21 @@ export interface IcqqSenderInfo {
17
11
  title?: string;
18
12
  }
19
13
 
20
- /**
21
- * Endpoint 配置:支持本地 IPC 和远程 RPC 两种连接模式。
22
- *
23
- * - 本地模式(默认):只需 name(QQ号),自动连接 ~/.icqq/<uin>/daemon.sock
24
- * - 远程模式:额外配置 rpc.host / rpc.port / rpc.token
25
- */
26
14
  export interface IcqqEndpointConfig {
27
15
  context: "icqq";
28
- /** QQ 号码字符串 */
29
16
  name: `${number}`;
30
- /** RPC 远程连接配置(不配置则使用本地 IPC) */
31
- rpc?: {
32
- /** 远程主机地址 */
33
- host: string;
34
- /** 远程端口 */
35
- port: number;
36
- /** 认证 token(用于 HMAC-SHA256 挑战-响应,不会明文传输) */
37
- token: string;
38
- };
39
- /**
40
- * IPC/RPC 与守护进程连接意外断开时是否自动重连(指数退避,上限约 30s)。
41
- * 默认 true;设为 false 则断开后仅将 `$connected` 置为 false,需手动重连。
42
- */
43
17
  autoReconnect?: boolean;
44
- /**
45
- * 出站图片/语音/视频:file=本机临时文件路径(需与 icqq 守护进程同机可读);
46
- * base64=经 CQ `base64://` 交给守护进程解码(Zhin 与 icqq 异进程/异机时用,配置 rpc 时默认 base64)。
47
- */
48
18
  outboundMedia?: "file" | "base64";
49
19
  }
50
20
 
51
- /** IPC 返回的好友信息 */
52
- export interface IpcFriendInfo {
21
+ export interface FriendInfo {
53
22
  user_id: number;
54
23
  nickname: string;
55
24
  remark?: string;
56
25
  class_id?: number;
57
26
  }
58
27
 
59
- /** IPC 返回的群信息 */
60
- export interface IpcGroupInfo {
28
+ export interface GroupInfo {
61
29
  group_id: number;
62
30
  group_name: string;
63
31
  member_count: number;
@@ -65,8 +33,7 @@ export interface IpcGroupInfo {
65
33
  owner_id?: number;
66
34
  }
67
35
 
68
- /** IPC 返回的群成员信息 */
69
- export interface IpcMemberInfo {
36
+ export interface MemberInfo {
70
37
  user_id: number;
71
38
  nickname: string;
72
39
  card: string;
@@ -77,11 +44,7 @@ export interface IpcMemberInfo {
77
44
  shutup_time?: number;
78
45
  }
79
46
 
80
- /**
81
- * GET_SYSTEM_MSG 归一后的待处理请求(@icqqjs/cli NormalizedSystemMessage)。
82
- * friendRequests 与 groupRequests 均为该形状,按 flag 处理。
83
- */
84
- export interface IpcSystemMessage {
47
+ export interface SystemMessage {
85
48
  type: string;
86
49
  user_id?: number;
87
50
  nickname?: string;
@@ -0,0 +1,19 @@
1
+ // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ import { defineAgentTool } from '@zhin.js/tool';
3
+ import { z } from 'zod';
4
+ import { getIcqqAgentDeps } from "../lib/icqq-agent-deps.js";
5
+ export default defineAgentTool({
6
+ description: '发送 QQ 群公告(需要管理员权限)',
7
+ inputSchema: z.object({
8
+ endpoint_id: z.string().describe('Endpoint QQ号'),
9
+ group_id: z.number().describe('目标群号'),
10
+ content: z.string().describe('公告内容'),
11
+ }),
12
+ platforms: ['icqq'],
13
+ permissions: ['platform(icqq,scene_admin)'],
14
+ async execute({ endpoint_id, group_id, content }) {
15
+ const endpoint = getIcqqAgentDeps().getEndpoint(endpoint_id);
16
+ await endpoint.sendGroupNotice(group_id, content);
17
+ return { success: true, message: '群公告已发送' };
18
+ },
19
+ });
@@ -0,0 +1,18 @@
1
+ import { defineAgentTool } from '@zhin.js/tool';
2
+ import { z } from 'zod';
3
+ import { getIcqqAgentDeps } from '../src/icqq-agent-deps.js';
4
+ export default defineAgentTool<{ endpoint_id: string; group_id: number; content: string }>({
5
+ description: '发送 QQ 群公告(需要管理员权限)',
6
+ inputSchema: z.object({
7
+ endpoint_id: z.string().describe('Endpoint QQ号'),
8
+ group_id: z.number().describe('目标群号'),
9
+ content: z.string().describe('公告内容'),
10
+ }),
11
+ platforms: ['icqq'],
12
+ permissions: ['platform(icqq,scene_admin)'],
13
+ async execute({ endpoint_id, group_id, content }: { endpoint_id: string; group_id: number; content: string }) {
14
+ const endpoint = getIcqqAgentDeps().getEndpoint(endpoint_id);
15
+ await endpoint.sendGroupNotice(group_id, content);
16
+ return { success: true, message: '群公告已发送' };
17
+ },
18
+ });
@@ -0,0 +1,24 @@
1
+ // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ import { defineAgentTool } from '@zhin.js/tool';
3
+ import { z } from 'zod';
4
+ import { getIcqqAgentDeps } from "../lib/icqq-agent-deps.js";
5
+ export default defineAgentTool({
6
+ description: '设置或移除 QQ 群精华消息',
7
+ inputSchema: z.object({
8
+ endpoint_id: z.string().describe('Endpoint QQ号'),
9
+ message_id: z.string().describe('消息 ID'),
10
+ action: z.enum(['add', 'remove']).describe('add=设为精华, remove=移除精华'),
11
+ }),
12
+ platforms: ['icqq'],
13
+ permissions: ['platform(icqq,scene_admin)'],
14
+ async execute({ endpoint_id, message_id, action }) {
15
+ const endpoint = getIcqqAgentDeps().getEndpoint(endpoint_id);
16
+ if (action === 'add') {
17
+ await endpoint.setEssenceMessage(message_id);
18
+ }
19
+ else {
20
+ await endpoint.removeEssenceMessage(message_id);
21
+ }
22
+ return { success: true, message: action === 'add' ? '已设为精华' : '已移除精华' };
23
+ },
24
+ });
@@ -1,6 +1,6 @@
1
- import { defineAgentTool } from '@zhin.js/agent/tools';
1
+ import { defineAgentTool } from '@zhin.js/tool';
2
2
  import { z } from 'zod';
3
- import { getIcqqAgentDeps } from '../../src/icqq-agent-deps.js';
3
+ import { getIcqqAgentDeps } from '../src/icqq-agent-deps.js';
4
4
  export default defineAgentTool<{ endpoint_id: string; message_id: string; action: 'add' | 'remove' }>({
5
5
  description: '设置或移除 QQ 群精华消息',
6
6
  inputSchema: z.object({
@@ -9,14 +9,14 @@ export default defineAgentTool<{ endpoint_id: string; message_id: string; action
9
9
  action: z.enum(['add', 'remove']).describe('add=设为精华, remove=移除精华'),
10
10
  }),
11
11
  platforms: ['icqq'],
12
- tags: ['icqq'],
13
12
  permissions: ['platform(icqq,scene_admin)'],
14
13
  async execute({ endpoint_id, message_id, action }: { endpoint_id: string; message_id: string; action: 'add' | 'remove' }) {
15
- const { Actions } = await import('../../src/protocol.js');
16
14
  const endpoint = getIcqqAgentDeps().getEndpoint(endpoint_id);
17
- const act = action === 'add' ? Actions.GROUP_ESSENCE_ADD : Actions.GROUP_ESSENCE_REMOVE;
18
- const resp = await endpoint.ipc.request(act, { message_id });
19
- return { success: resp.ok, message: resp.ok ? (action === 'add' ? '已设为精华' : '已移除精华') : (resp.error ?? '操作失败') };
15
+ if (action === 'add') {
16
+ await endpoint.setEssenceMessage(message_id);
17
+ } else {
18
+ await endpoint.removeEssenceMessage(message_id);
19
+ }
20
+ return { success: true, message: action === 'add' ? '已设为精华' : '已移除精华' };
20
21
  },
21
22
  });
22
-
@@ -0,0 +1,20 @@
1
+ // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ import { defineAgentTool } from '@zhin.js/tool';
3
+ import { z } from 'zod';
4
+ import { getIcqqAgentDeps } from "../lib/icqq-agent-deps.js";
5
+ export default defineAgentTool({
6
+ description: '获取 QQ 好友列表',
7
+ inputSchema: z.object({
8
+ endpoint_id: z.string().describe('Endpoint 名称'),
9
+ }),
10
+ platforms: ['icqq'],
11
+ approval: 'never',
12
+ async execute({ endpoint_id }) {
13
+ const endpoint = getIcqqAgentDeps().getEndpoint(endpoint_id);
14
+ const fl = endpoint.fl;
15
+ const friends = Array.from(fl.values()).map((f) => ({
16
+ user_id: f.user_id, nickname: f.nickname, remark: f.remark,
17
+ }));
18
+ return { friends: friends.slice(0, 50), count: fl.size };
19
+ },
20
+ });
@@ -1,19 +1,19 @@
1
- import { defineAgentTool } from '@zhin.js/agent/tools';
1
+ import { defineAgentTool } from '@zhin.js/tool';
2
2
  import { z } from 'zod';
3
- import { getIcqqAgentDeps } from '../../src/icqq-agent-deps.js';
3
+ import { getIcqqAgentDeps } from '../src/icqq-agent-deps.js';
4
4
  export default defineAgentTool<{ endpoint_id: string }>({
5
5
  description: '获取 QQ 好友列表',
6
6
  inputSchema: z.object({
7
7
  endpoint_id: z.string().describe('Endpoint 名称'),
8
8
  }),
9
9
  platforms: ['icqq'],
10
- tags: ['icqq'],
11
- async execute({ endpoint_id }: { endpoint_id: string }) {
10
+ approval: 'never',
11
+ async execute({ endpoint_id }: { endpoint_id: string }) {
12
12
  const endpoint = getIcqqAgentDeps().getEndpoint(endpoint_id);
13
- const friends = Array.from(endpoint.friends.values()).map((f) => ({
13
+ const fl = endpoint.fl;
14
+ const friends = Array.from(fl.values()).map((f) => ({
14
15
  user_id: f.user_id, nickname: f.nickname, remark: f.remark,
15
16
  }));
16
- return { friends: friends.slice(0, 50), count: endpoint.friends.size };
17
+ return { friends: friends.slice(0, 50), count: fl.size };
17
18
  },
18
19
  });
19
-
@@ -0,0 +1,25 @@
1
+ // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ import { defineAgentTool } from '@zhin.js/tool';
3
+ import { z } from 'zod';
4
+ import { getIcqqAgentDeps } from "../lib/icqq-agent-deps.js";
5
+ export default defineAgentTool({
6
+ description: '获取 QQ 群的群文件列表',
7
+ inputSchema: z.object({
8
+ endpoint_id: z.string().describe('Endpoint 名称'),
9
+ group_id: z.number().describe('群号'),
10
+ }),
11
+ platforms: ['icqq'],
12
+ approval: 'never',
13
+ async execute({ endpoint_id, group_id }) {
14
+ const endpoint = getIcqqAgentDeps().getEndpoint(endpoint_id);
15
+ const files = await endpoint.acquireGfs(group_id).ls('/');
16
+ if (!files.length)
17
+ return { files: [], message: '群文件为空' };
18
+ return {
19
+ files: files.slice(0, 30).map((f) => 'size' in f
20
+ ? { name: f.name, is_dir: false, size: f.size, uploader: f.user_id, upload_time: f.create_time }
21
+ : { name: f.name, is_dir: true, file_count: f.file_count }),
22
+ count: files.length,
23
+ };
24
+ },
25
+ });
@@ -0,0 +1,23 @@
1
+ import { defineAgentTool } from '@zhin.js/tool';
2
+ import { z } from 'zod';
3
+ import { getIcqqAgentDeps } from '../src/icqq-agent-deps.js';
4
+ export default defineAgentTool<{ endpoint_id: string; group_id: number }>({
5
+ description: '获取 QQ 群的群文件列表',
6
+ inputSchema: z.object({
7
+ endpoint_id: z.string().describe('Endpoint 名称'),
8
+ group_id: z.number().describe('群号'),
9
+ }),
10
+ platforms: ['icqq'],
11
+ approval: 'never',
12
+ async execute({ endpoint_id, group_id }: { endpoint_id: string; group_id: number }) {
13
+ const endpoint = getIcqqAgentDeps().getEndpoint(endpoint_id);
14
+ const files = await endpoint.acquireGfs(group_id).ls('/');
15
+ if (!files.length) return { files: [], message: '群文件为空' };
16
+ return {
17
+ files: files.slice(0, 30).map((f) => 'size' in f
18
+ ? { name: f.name, is_dir: false, size: f.size, uploader: f.user_id, upload_time: f.create_time }
19
+ : { name: f.name, is_dir: true, file_count: f.file_count }),
20
+ count: files.length,
21
+ };
22
+ },
23
+ });
@@ -0,0 +1,25 @@
1
+ // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ import { defineAgentTool } from '@zhin.js/tool';
3
+ import { z } from 'zod';
4
+ import { getIcqqAgentDeps } from "../lib/icqq-agent-deps.js";
5
+ export default defineAgentTool({
6
+ description: '邀请好友加入 QQ 群',
7
+ inputSchema: z.object({
8
+ endpoint_id: z.string().describe('Endpoint QQ号'),
9
+ group_id: z.number().describe('目标群号'),
10
+ user_id: z.number().describe('要邀请的 QQ号'),
11
+ }),
12
+ platforms: ['icqq'],
13
+ approval: 'never',
14
+ async execute({ endpoint_id, group_id, user_id }) {
15
+ const endpoint = getIcqqAgentDeps().getEndpoint(endpoint_id);
16
+ const groupInfo = endpoint.pickGroup(group_id);
17
+ if (!groupInfo)
18
+ return { success: false, message: '目标群不存在' };
19
+ const memberInfo = endpoint.pickMember(group_id, user_id);
20
+ if (memberInfo)
21
+ return { success: false, message: '目标成员已加入群' };
22
+ await endpoint.inviteFriend(group_id, user_id);
23
+ return { success: true, message: `已尝试邀请 ${user_id} 加入群 ${group_id}` };
24
+ },
25
+ });
@@ -0,0 +1,22 @@
1
+ import { defineAgentTool } from '@zhin.js/tool';
2
+ import { z } from 'zod';
3
+ import { getIcqqAgentDeps } from '../src/icqq-agent-deps.js';
4
+ export default defineAgentTool<{ endpoint_id: string; group_id: number; user_id: number }>({
5
+ description: '邀请好友加入 QQ 群',
6
+ inputSchema: z.object({
7
+ endpoint_id: z.string().describe('Endpoint QQ号'),
8
+ group_id: z.number().describe('目标群号'),
9
+ user_id: z.number().describe('要邀请的 QQ号'),
10
+ }),
11
+ platforms: ['icqq'],
12
+ approval: 'never',
13
+ async execute({ endpoint_id, group_id, user_id }: { endpoint_id: string; group_id: number; user_id: number }) {
14
+ const endpoint = getIcqqAgentDeps().getEndpoint(endpoint_id);
15
+ const groupInfo= endpoint.pickGroup(group_id);
16
+ if(!groupInfo) return { success: false, message: '目标群不存在' };
17
+ const memberInfo= endpoint.pickMember(group_id,user_id);
18
+ if(memberInfo) return { success: false, message: '目标成员已加入群' };
19
+ await endpoint.inviteFriend(group_id, user_id);
20
+ return { success: true, message: `已尝试邀请 ${user_id} 加入群 ${group_id}` };
21
+ },
22
+ });
@@ -0,0 +1,28 @@
1
+ // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ import { defineAgentTool } from '@zhin.js/tool';
3
+ import { z } from 'zod';
4
+ import { getIcqqAgentDeps } from "../lib/icqq-agent-deps.js";
5
+ export default defineAgentTool({
6
+ description: '踢出 QQ 群中的某个成员',
7
+ inputSchema: z.object({
8
+ endpoint_id: z.string().describe('Endpoint QQ号'),
9
+ group_id: z.number().describe('目标群号'),
10
+ user_id: z.number().describe('要踢出的成员 QQ号'),
11
+ }),
12
+ platforms: ['icqq'],
13
+ permissions: ['role(master,admin,trusted,owner)'],
14
+ approval: 'never',
15
+ async execute({ endpoint_id, group_id, user_id }) {
16
+ const endpoint = getIcqqAgentDeps().getEndpoint(endpoint_id);
17
+ const selfInfo = endpoint.pickMember(group_id, endpoint.uin);
18
+ if (!selfInfo.is_admin && !selfInfo.is_owner)
19
+ return { success: false, message: '我不是群主或管理员,无法踢出成员' };
20
+ if (selfInfo.user_id === user_id)
21
+ return { success: false, message: '我不能踢出自己' };
22
+ const memberInfo = endpoint.pickMember(group_id, user_id);
23
+ if (!memberInfo)
24
+ return { success: false, message: '目标成员不存在' };
25
+ await endpoint.setGroupKick(group_id, user_id);
26
+ return { success: true, message: `已踢出 ${user_id} 成员` };
27
+ },
28
+ });
@@ -0,0 +1,24 @@
1
+ import { defineAgentTool } from '@zhin.js/tool';
2
+ import { z } from 'zod';
3
+ import { getIcqqAgentDeps } from '../src/icqq-agent-deps.js';
4
+ export default defineAgentTool<{ endpoint_id: string; group_id: number; user_id: number }>({
5
+ description: '踢出 QQ 群中的某个成员',
6
+ inputSchema: z.object({
7
+ endpoint_id: z.string().describe('Endpoint QQ号'),
8
+ group_id: z.number().describe('目标群号'),
9
+ user_id: z.number().describe('要踢出的成员 QQ号'),
10
+ }),
11
+ platforms: ['icqq'],
12
+ permissions: ['role(master,admin,trusted,owner)'],
13
+ approval: 'never',
14
+ async execute({ endpoint_id, group_id, user_id }: { endpoint_id: string; group_id: number; user_id: number }) {
15
+ const endpoint = getIcqqAgentDeps().getEndpoint(endpoint_id);
16
+ const selfInfo= endpoint.pickMember(group_id,endpoint.uin);
17
+ if(!selfInfo.is_admin && !selfInfo.is_owner) return { success: false, message: '我不是群主或管理员,无法踢出成员' };
18
+ if(selfInfo.user_id === user_id) return { success: false, message: '我不能踢出自己' };
19
+ const memberInfo= endpoint.pickMember(group_id,user_id);
20
+ if(!memberInfo) return { success: false, message: '目标成员不存在' };
21
+ await endpoint.setGroupKick(group_id, user_id);
22
+ return { success: true, message: `已踢出 ${user_id} 成员` };
23
+ },
24
+ });
@@ -0,0 +1,21 @@
1
+ // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ import { defineAgentTool } from '@zhin.js/tool';
3
+ import { z } from 'zod';
4
+ import { getIcqqAgentDeps } from "../lib/icqq-agent-deps.js";
5
+ export default defineAgentTool({
6
+ description: '获取 Endpoint 的 QQ 群列表',
7
+ inputSchema: z.object({
8
+ endpoint_id: z.string().describe('Endpoint 名称'),
9
+ }),
10
+ platforms: ['icqq'],
11
+ approval: 'never',
12
+ async execute({ endpoint_id }) {
13
+ const endpoint = getIcqqAgentDeps().getEndpoint(endpoint_id);
14
+ const gl = endpoint.gl;
15
+ const groups = Array.from(gl.values()).map((g) => ({
16
+ group_id: g.group_id, group_name: g.group_name,
17
+ member_count: g.member_count, max_member_count: g.max_member_count,
18
+ }));
19
+ return { groups: groups.slice(0, 50), count: gl.size };
20
+ },
21
+ });