@zhin.js/adapter-napcat 3.0.1 → 4.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 (140) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/README.md +43 -96
  3. package/adapters/napcat.ts +39 -0
  4. package/agent/tools/ai_tts.ts +21 -0
  5. package/agent/tools/del_group_notice.ts +22 -0
  6. package/agent/tools/delete_essence_msg.ts +21 -0
  7. package/agent/tools/delete_friend.ts +20 -0
  8. package/agent/tools/download_file.ts +19 -0
  9. package/agent/tools/forward_single_msg.ts +32 -0
  10. package/agent/tools/get_ai_characters.ts +19 -0
  11. package/agent/tools/get_essence_list.ts +19 -0
  12. package/agent/tools/get_friend_msg_history.ts +20 -0
  13. package/agent/tools/get_group_file_url.ts +21 -0
  14. package/agent/tools/get_group_info_ex.ts +19 -0
  15. package/agent/tools/get_group_msg_history.ts +21 -0
  16. package/agent/tools/get_group_notice.ts +19 -0
  17. package/agent/tools/get_group_root_files.ts +19 -0
  18. package/agent/tools/get_group_shut_list.ts +19 -0
  19. package/agent/tools/get_mini_app_ark.ts +22 -0
  20. package/agent/tools/get_user_status.ts +18 -0
  21. package/agent/tools/group_sign.ts +20 -0
  22. package/agent/tools/mark_msg_as_read.ts +19 -0
  23. package/agent/tools/ocr_image.ts +18 -0
  24. package/agent/tools/send_forward_msg.ts +31 -0
  25. package/agent/tools/send_group_notice.ts +23 -0
  26. package/agent/tools/send_like.ts +20 -0
  27. package/agent/tools/send_poke.ts +20 -0
  28. package/agent/tools/set_avatar.ts +19 -0
  29. package/agent/tools/set_emoji_reaction.ts +20 -0
  30. package/agent/tools/set_essence_msg.ts +21 -0
  31. package/agent/tools/set_group_portrait.ts +22 -0
  32. package/agent/tools/set_online_status.ts +20 -0
  33. package/agent/tools/set_profile.ts +23 -0
  34. package/agent/tools/set_signature.ts +19 -0
  35. package/agent/tools/set_title.ts +23 -0
  36. package/agent/tools/translate.ts +18 -0
  37. package/agent/tools/upload_group_file.ts +23 -0
  38. package/lib/http-endpoint.d.ts +26 -0
  39. package/lib/http-endpoint.js +147 -0
  40. package/lib/index.d.ts +11 -21
  41. package/lib/index.js +10 -59
  42. package/lib/napcat-agent-deps.d.ts +51 -0
  43. package/lib/napcat-agent-deps.js +33 -0
  44. package/lib/napcat-inbound.d.ts +12 -5
  45. package/lib/napcat-inbound.js +28 -13
  46. package/lib/onebot-get-msg.d.ts +13 -2
  47. package/lib/onebot-get-msg.js +0 -1
  48. package/lib/protocol.d.ts +151 -0
  49. package/lib/protocol.js +217 -0
  50. package/lib/webhook.d.ts +2 -0
  51. package/lib/webhook.js +14 -0
  52. package/lib/ws-endpoint.d.ts +61 -0
  53. package/lib/ws-endpoint.js +357 -0
  54. package/lib/ws-transport.d.ts +13 -0
  55. package/lib/ws-transport.js +75 -0
  56. package/lib/ws-types.d.ts +17 -0
  57. package/lib/ws-types.js +1 -0
  58. package/lib/wss-auth.d.ts +2 -0
  59. package/lib/wss-auth.js +16 -0
  60. package/lib/wss-endpoint.d.ts +25 -0
  61. package/lib/wss-endpoint.js +157 -0
  62. package/package.json +48 -32
  63. package/plugin.ts +13 -0
  64. package/schema.json +48 -0
  65. package/src/http-endpoint.ts +197 -0
  66. package/src/index.ts +66 -82
  67. package/src/napcat-agent-deps.ts +95 -0
  68. package/src/napcat-inbound.ts +34 -10
  69. package/src/onebot-get-msg.ts +8 -2
  70. package/src/protocol.ts +373 -0
  71. package/src/webhook.ts +16 -0
  72. package/src/ws-endpoint.ts +452 -0
  73. package/src/ws-transport.ts +105 -0
  74. package/src/ws-types.ts +20 -0
  75. package/src/wss-auth.ts +17 -0
  76. package/src/wss-endpoint.ts +205 -0
  77. package/client/NapCatManagement.tsx +0 -113
  78. package/client/index.tsx +0 -11
  79. package/client/tsconfig.json +0 -7
  80. package/client/utils/api.ts +0 -30
  81. package/dist/index.js +0 -27
  82. package/lib/adapter.d.ts +0 -36
  83. package/lib/adapter.d.ts.map +0 -1
  84. package/lib/adapter.js +0 -102
  85. package/lib/adapter.js.map +0 -1
  86. package/lib/agent-prompt.d.ts +0 -3
  87. package/lib/agent-prompt.d.ts.map +0 -1
  88. package/lib/agent-prompt.js +0 -106
  89. package/lib/agent-prompt.js.map +0 -1
  90. package/lib/endpoint-base.d.ts +0 -144
  91. package/lib/endpoint-base.d.ts.map +0 -1
  92. package/lib/endpoint-base.js +0 -341
  93. package/lib/endpoint-base.js.map +0 -1
  94. package/lib/endpoint-http.d.ts +0 -17
  95. package/lib/endpoint-http.d.ts.map +0 -1
  96. package/lib/endpoint-http.js +0 -106
  97. package/lib/endpoint-http.js.map +0 -1
  98. package/lib/endpoint-ws-client.d.ts +0 -20
  99. package/lib/endpoint-ws-client.d.ts.map +0 -1
  100. package/lib/endpoint-ws-client.js +0 -139
  101. package/lib/endpoint-ws-client.js.map +0 -1
  102. package/lib/endpoint-ws-server.d.ts +0 -20
  103. package/lib/endpoint-ws-server.d.ts.map +0 -1
  104. package/lib/endpoint-ws-server.js +0 -137
  105. package/lib/endpoint-ws-server.js.map +0 -1
  106. package/lib/index.d.ts.map +0 -1
  107. package/lib/index.js.map +0 -1
  108. package/lib/napcat-inbound.d.ts.map +0 -1
  109. package/lib/napcat-inbound.js.map +0 -1
  110. package/lib/onebot-get-msg.d.ts.map +0 -1
  111. package/lib/onebot-get-msg.js.map +0 -1
  112. package/lib/routes.d.ts +0 -4
  113. package/lib/routes.d.ts.map +0 -1
  114. package/lib/routes.js +0 -61
  115. package/lib/routes.js.map +0 -1
  116. package/lib/segment-mapper.d.ts +0 -2
  117. package/lib/segment-mapper.d.ts.map +0 -1
  118. package/lib/segment-mapper.js +0 -2
  119. package/lib/segment-mapper.js.map +0 -1
  120. package/lib/tools.d.ts +0 -8
  121. package/lib/tools.d.ts.map +0 -1
  122. package/lib/tools.js +0 -605
  123. package/lib/tools.js.map +0 -1
  124. package/lib/types.d.ts +0 -275
  125. package/lib/types.d.ts.map +0 -1
  126. package/lib/types.js +0 -6
  127. package/lib/types.js.map +0 -1
  128. package/plugin.yml +0 -3
  129. package/src/adapter.ts +0 -109
  130. package/src/agent-prompt.ts +0 -116
  131. package/src/endpoint-base.ts +0 -386
  132. package/src/endpoint-http.ts +0 -95
  133. package/src/endpoint-ws-client.ts +0 -137
  134. package/src/endpoint-ws-server.ts +0 -136
  135. package/src/routes.ts +0 -61
  136. package/src/segment-mapper.ts +0 -1
  137. package/src/tools.ts +0 -632
  138. package/src/types.ts +0 -266
  139. /package/{skills/napcat → agent}/PERMITS.md +0 -0
  140. /package/{skills/napcat/SKILL.md → agent/skills/napcat.md} +0 -0
package/src/index.ts CHANGED
@@ -1,92 +1,76 @@
1
- /**
2
- * NapCat 适配器入口
3
- * 支持 OneBot11 标准 + go-cqhttp 扩展 + NapCat 独有 API
4
- * 连接方式:正向 WS / 反向 WS / HTTP
5
- */
6
- import path from 'path';
7
- import {
8
- usePlugin,
9
- type Plugin,
10
- type Context,
11
- type ISceneManagement,
12
- createSceneManagementTools,
13
- registerDefaultScenePlatformPermitChecker,
14
- type ToolFeature,
15
- } from 'zhin.js';
16
- import { registerAgentPromptContributor, unregisterAgentPromptContributor } from 'zhin.js/agent';
17
- import type { Router } from '@zhin.js/host-router';
18
- import { PageManager } from '@zhin.js/host-api';
19
- import { NapCatAdapter } from './adapter.js';
20
- import { createNapCatTools } from './tools.js';
21
- import { createNapCatAgentPromptContributor } from './agent-prompt.js';
22
- import { registerRoutes } from './routes.js';
1
+ export {
2
+ buildSendAction,
3
+ buildWsConnectOptions,
4
+ callNapCatHttpAction,
5
+ formatInboundContent,
6
+ formatInboundTarget,
7
+ formatOutboundSegments,
8
+ getChannelId,
9
+ isMessageEvent,
10
+ parseSendTarget,
11
+ resolveNapCatConfig,
12
+ senderNickname,
13
+ senderUserId,
14
+ type MessageSegment,
15
+ type NapCatActionRequest,
16
+ type NapCatActionResponse,
17
+ type NapCatAdapterConfig,
18
+ type NapCatConfigBase,
19
+ type NapCatEndpointConfig,
20
+ type NapCatEvent,
21
+ type NapCatHttpConfig,
22
+ type NapCatMessageEvent,
23
+ type NapCatSender,
24
+ type NapCatWireSegment,
25
+ type NapCatWsConfig,
26
+ type NapCatWssConfig,
27
+ type ParsedSendTarget,
28
+ type ResolvedNapCatConfig,
29
+ } from './protocol.js';
23
30
 
24
- export * from './types.js';
25
- export { NapCatWsClient } from './endpoint-ws-client.js';
26
- export { NapCatWsServer } from './endpoint-ws-server.js';
27
- export { NapCatHttpEndpoint } from './endpoint-http.js';
28
- export { NapCatAdapter, type NapCatEndpoint } from './adapter.js';
29
- export { NapCatEndpointBase } from './endpoint-base.js';
31
+ export {
32
+ InboundMessageDeduper,
33
+ isNapCatBotMentioned,
34
+ isSelfMessage,
35
+ normalizeMessage,
36
+ } from './napcat-inbound.js';
30
37
 
31
- declare module 'zhin.js' {
32
- namespace Plugin {
33
- interface Contexts {
34
- web: PageManager;
35
- router: Router;
36
- }
37
- }
38
- interface Adapters {
39
- napcat: NapCatAdapter;
40
- }
41
- }
38
+ export {
39
+ getEndpoint,
40
+ getNapcatAgentDeps,
41
+ registerNapcatAgentEndpoint,
42
+ setNapcatAgentDeps,
43
+ type NapcatAgentDeps,
44
+ type NapcatAgentEndpoint,
45
+ } from './napcat-agent-deps.js';
42
46
 
43
- const plugin = usePlugin();
44
- const { provide, useContext } = plugin;
47
+ export { parseOneBotGetMsgResponse } from './onebot-get-msg.js';
45
48
 
46
- // ── 适配器注册 ─────────────────────────────────────────────────────
47
- provide({
48
- name: 'napcat',
49
- description: 'NapCatQQ 适配器(OneBot11 + go-cqhttp + NapCat 扩展,正向/反向 WS + HTTP)',
50
- mounted: async (p: Plugin) => {
51
- registerAgentPromptContributor(createNapCatAgentPromptContributor());
52
- const adapter = new NapCatAdapter(p);
53
- await adapter.start();
54
- return adapter;
55
- },
56
- dispose: async (adapter: NapCatAdapter) => {
57
- unregisterAgentPromptContributor('napcat');
58
- await adapter.stop();
59
- },
60
- } as unknown as Context<'napcat'>);
49
+ export {
50
+ NapCatWsEndpoint,
51
+ type NapCatWsEndpointOptions,
52
+ } from './ws-endpoint.js';
61
53
 
62
- // ── AI 工具注册 ────────────────────────────────────────────────────
63
- useContext('tool', 'napcat', (toolService: ToolFeature, napcat: NapCatAdapter) => {
64
- const disposers: (() => void)[] = [];
65
- disposers.push(registerDefaultScenePlatformPermitChecker('napcat'));
54
+ export {
55
+ NapCatWssEndpoint,
56
+ type NapCatWssEndpointOptions,
57
+ } from './wss-endpoint.js';
66
58
 
67
- const sceneTools = createSceneManagementTools(
68
- napcat as unknown as ISceneManagement,
69
- 'napcat',
70
- );
71
- disposers.push(...sceneTools.map(t => toolService.addTool(t, plugin.name)));
59
+ export {
60
+ NapCatHttpEndpoint,
61
+ type NapCatHttpEndpointOptions,
62
+ } from './http-endpoint.js';
72
63
 
73
- const napcatTools = createNapCatTools(napcat);
74
- disposers.push(...napcatTools.map(t => toolService.addTool(t, plugin.name)));
64
+ export type { NapCatWsSocket, NapCatWsCreateOptions } from './ws-types.js';
75
65
 
76
- return () => disposers.forEach(d => d());
77
- });
66
+ export {
67
+ callNapCatWsAction,
68
+ decodeWsPayload,
69
+ handleNapCatWsMessage,
70
+ rejectAllPending,
71
+ startNapCatHeartbeat,
72
+ } from './ws-transport.js';
78
73
 
79
- // ── Web 控制台入口 ─────────────────────────────────────────────────
80
- useContext('web', (pageManager) => {
81
- pageManager.addEntry({
82
- id: 'napcat',
83
- development: path.resolve(import.meta.dirname, '../client/index.tsx'),
84
- production: path.resolve(import.meta.dirname, '../dist/index.js'),
85
- meta: { name: 'NapCat' },
86
- });
87
- });
74
+ export { verifyNapCatAccessToken } from './wss-auth.js';
88
75
 
89
- // ── HTTP 路由 ──────────────────────────────────────────────────────
90
- useContext('router', 'napcat', async (router: Router, napcat: NapCatAdapter) => {
91
- registerRoutes(router, napcat);
92
- });
76
+ export { readRequestBody } from './webhook.js';
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Agent tool deps for napcat.
3
+ * Endpoints register themselves on start; tools look up by config name / endpoint id.
4
+ */
5
+
6
+ export interface NapcatAgentEndpoint {
7
+ callApi(action: string, params?: Record<string, unknown>): Promise<unknown>;
8
+ setTitle(groupId: number, userId: number, title: string, duration?: number): Promise<boolean>;
9
+ sendLike(userId: number, times?: number): Promise<unknown>;
10
+ deleteFriend(userId: number): Promise<unknown>;
11
+ markMsgAsRead(messageId: number): Promise<unknown>;
12
+ ocrImage(image: string): Promise<unknown>;
13
+ setQQProfile(
14
+ nickname: string,
15
+ company?: string,
16
+ email?: string,
17
+ college?: string,
18
+ personalNote?: string,
19
+ ): Promise<unknown>;
20
+ setGroupPortrait(groupId: number, file: string): Promise<unknown>;
21
+ setEssenceMsg(messageId: number): Promise<unknown>;
22
+ deleteEssenceMsg(messageId: number): Promise<unknown>;
23
+ getEssenceMsgList(groupId: number): Promise<unknown>;
24
+ sendGroupSign(groupId: number): Promise<unknown>;
25
+ sendGroupNotice(groupId: number, content: string, image?: string): Promise<unknown>;
26
+ getGroupNotice(groupId: number): Promise<unknown>;
27
+ deleteGroupNotice(groupId: number, noticeId: string): Promise<unknown>;
28
+ uploadGroupFile(groupId: number, file: string, name: string, folder?: string): Promise<unknown>;
29
+ getGroupRootFiles(groupId: number): Promise<unknown>;
30
+ getGroupFileUrl(groupId: number, fileId: string, busid: number): Promise<unknown>;
31
+ downloadFile(url: string, threadCount?: number, headers?: string[]): Promise<unknown>;
32
+ setOnlineStatus(status: number, extStatus: number): Promise<unknown>;
33
+ setQQAvatar(file: string): Promise<unknown>;
34
+ forwardFriendSingleMsg(userId: number, messageId: number): Promise<unknown>;
35
+ forwardGroupSingleMsg(groupId: number, messageId: number): Promise<unknown>;
36
+ translateEn2Zh(sourceText: string): Promise<unknown>;
37
+ setMsgEmojiLike(messageId: number, emojiId: string): Promise<unknown>;
38
+ sendForwardMsg(messageType: 'private' | 'group', id: number, messages: unknown[]): Promise<unknown>;
39
+ getFriendMsgHistory(userId: number, messageSeq?: number, count?: number): Promise<unknown>;
40
+ getGroupMsgHistory(groupId: number, messageSeq?: number, count?: number): Promise<unknown>;
41
+ setSelfLongnick(longnick: string): Promise<unknown>;
42
+ getGroupInfoEx(groupId: number): Promise<unknown>;
43
+ sendPoke(userId: number, groupId?: number): Promise<unknown>;
44
+ ncGetUserStatus(userId: number): Promise<unknown>;
45
+ getGroupShutList(groupId: number): Promise<unknown>;
46
+ getMiniAppArk(
47
+ type: string,
48
+ title: string,
49
+ desc: string,
50
+ picUrl: string,
51
+ jumpUrl: string,
52
+ ): Promise<unknown>;
53
+ getAiCharacters(groupId: number): Promise<unknown>;
54
+ sendGroupAiRecord(groupId: number, characterId: string, text: string): Promise<unknown>;
55
+ }
56
+
57
+ export interface NapcatAgentDeps {
58
+ getEndpoint: (endpointId: string) => NapcatAgentEndpoint;
59
+ }
60
+
61
+ const endpoints = new Map<string, NapcatAgentEndpoint>();
62
+ let override: NapcatAgentDeps | null = null;
63
+
64
+ export function registerNapcatAgentEndpoint(
65
+ endpointId: string,
66
+ endpoint: NapcatAgentEndpoint,
67
+ ): () => void {
68
+ endpoints.set(endpointId, endpoint);
69
+ return () => {
70
+ if (endpoints.get(endpointId) === endpoint) {
71
+ endpoints.delete(endpointId);
72
+ }
73
+ };
74
+ }
75
+
76
+ /** Optional override used by tests / transitional callers. Pass `null` to clear. */
77
+ export function setNapcatAgentDeps(deps: NapcatAgentDeps | null): void {
78
+ override = deps;
79
+ }
80
+
81
+ function lookup(endpointId: string): NapcatAgentEndpoint {
82
+ const registered = endpoints.get(endpointId);
83
+ if (!registered) throw new Error(`Endpoint ${endpointId} not found`);
84
+ return registered;
85
+ }
86
+
87
+ export function getNapcatAgentDeps(): NapcatAgentDeps {
88
+ if (override) return override;
89
+ return { getEndpoint: lookup };
90
+ }
91
+
92
+ /** Convenience for agent/tools (unchanged call sites). */
93
+ export function getEndpoint(endpointId: string): NapcatAgentEndpoint {
94
+ return getNapcatAgentDeps().getEndpoint(endpointId);
95
+ }
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * NapCat 入站消息治理:去重、自发过滤、消息归一化
3
3
  */
4
- import type { NapCatMessageEvent, MessageSegment } from './types.js';
4
+ import type { NapCatMessageEvent, MessageSegment } from './protocol.js';
5
5
 
6
6
  const DEDUPE_TTL_MS = 120_000;
7
7
 
@@ -24,7 +24,11 @@ export class InboundMessageDeduper {
24
24
  }
25
25
 
26
26
  /** 判断是否为 bot 自身发出的消息 */
27
- export function isSelfMessage(event: NapCatMessageEvent): boolean {
27
+ export function isSelfMessage(event: NapCatMessageEvent | {
28
+ post_type?: string;
29
+ self_id?: number | string;
30
+ user_id?: number | string;
31
+ }): boolean {
28
32
  if (event.post_type === 'message_sent') return true;
29
33
  if (event.self_id != null && event.user_id != null) {
30
34
  return Number(event.self_id) === Number(event.user_id);
@@ -44,14 +48,34 @@ export function normalizeMessage(message: MessageSegment[] | string): MessageSeg
44
48
  return [];
45
49
  }
46
50
 
51
+ const CQ_AT_RE = /\[CQ:at,qq=([^\],\s]+)\]/g;
52
+
53
+ function atTargetMatchesUin(target: unknown, uin: string): boolean {
54
+ const qq = String(target ?? '').trim();
55
+ return Boolean(qq) && qq !== 'all' && Number(qq) === Number(uin);
56
+ }
57
+
47
58
  /**
48
- * 生成用于 notice / request 事件的去重 key
59
+ * OneBot11 mentioned 判定:消息段 {type:'at', data:{qq}} 的 qq 等于本机 uin
60
+ * (事件 self_id)时为 true;`qq === 'all'` 不算。兼容 CQ 字符串形式。
49
61
  */
50
- export function resolveSideEventDedupeKey(event: any, prefix: string): string {
51
- const parts = [prefix, event.time, event.notice_type || event.request_type];
52
- if (event.group_id) parts.push(event.group_id);
53
- if (event.user_id) parts.push(event.user_id);
54
- if (event.message_id) parts.push(event.message_id);
55
- if (event.flag) parts.push(event.flag);
56
- return parts.join(':');
62
+ export function isNapCatBotMentioned(ev: {
63
+ self_id?: number | string;
64
+ message?: MessageSegment[] | string;
65
+ }): boolean {
66
+ if (ev.self_id == null) return false;
67
+ const uin = String(ev.self_id).trim();
68
+ if (!uin) return false;
69
+ const segments = normalizeMessage(ev.message ?? []);
70
+ for (const seg of segments) {
71
+ if (seg.type === 'at' && atTargetMatchesUin(seg.data?.qq, uin)) return true;
72
+ }
73
+ const text = segments
74
+ .map((seg) => (seg.type === 'text' ? String(seg.data?.text ?? '') : ''))
75
+ .join('');
76
+ if (!text) return false;
77
+ for (const match of text.matchAll(CQ_AT_RE)) {
78
+ if (atTargetMatchesUin(match[1], uin)) return true;
79
+ }
80
+ return false;
57
81
  }
@@ -1,4 +1,10 @@
1
- import type { MessageSegment, QuotedMessagePayload } from 'zhin.js';
1
+ export interface QuotedMessagePayload {
2
+ messageId: string;
3
+ sender?: { id: string; name: string };
4
+ content: Array<{ type: string; data?: Record<string, unknown> }>;
5
+ raw?: string;
6
+ time?: number;
7
+ }
2
8
 
3
9
  export function parseOneBotGetMsgResponse(
4
10
  messageId: string,
@@ -8,7 +14,7 @@ export function parseOneBotGetMsgResponse(
8
14
  data && typeof data === 'object' ? (data as Record<string, unknown>) : {};
9
15
  let content: QuotedMessagePayload['content'] = [];
10
16
  if (Array.isArray(record.message)) {
11
- content = record.message as MessageSegment[];
17
+ content = record.message as QuotedMessagePayload['content'];
12
18
  } else if (typeof record.raw_message === 'string' && record.raw_message) {
13
19
  content = [{ type: 'text', data: { text: record.raw_message } }];
14
20
  }