@zhin.js/adapter-napcat 1.0.0 → 1.1.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 (159) hide show
  1. package/CHANGELOG.md +674 -0
  2. package/README.md +60 -95
  3. package/adapters/napcat.js +47 -0
  4. package/adapters/napcat.ts +64 -0
  5. package/agent/PERMITS.md +19 -0
  6. package/{skills/napcat/SKILL.md → agent/skills/napcat.md} +6 -6
  7. package/agent/tools/ai_tts.ts +19 -0
  8. package/agent/tools/del_group_notice.ts +20 -0
  9. package/agent/tools/delete_essence_msg.ts +19 -0
  10. package/agent/tools/delete_friend.ts +18 -0
  11. package/agent/tools/download_file.ts +17 -0
  12. package/agent/tools/forward_single_msg.ts +28 -0
  13. package/agent/tools/get_ai_characters.ts +17 -0
  14. package/agent/tools/get_essence_list.ts +17 -0
  15. package/agent/tools/get_friend_msg_history.ts +18 -0
  16. package/agent/tools/get_group_file_url.ts +19 -0
  17. package/agent/tools/get_group_info_ex.ts +17 -0
  18. package/agent/tools/get_group_msg_history.ts +19 -0
  19. package/agent/tools/get_group_notice.ts +17 -0
  20. package/agent/tools/get_group_root_files.ts +17 -0
  21. package/agent/tools/get_group_shut_list.ts +17 -0
  22. package/agent/tools/get_mini_app_ark.ts +20 -0
  23. package/agent/tools/get_user_status.ts +16 -0
  24. package/agent/tools/group_sign.ts +18 -0
  25. package/agent/tools/mark_msg_as_read.ts +17 -0
  26. package/agent/tools/ocr_image.ts +16 -0
  27. package/agent/tools/send_forward_msg.ts +27 -0
  28. package/agent/tools/send_group_notice.ts +21 -0
  29. package/agent/tools/send_like.ts +18 -0
  30. package/agent/tools/send_poke.ts +18 -0
  31. package/agent/tools/set_avatar.ts +17 -0
  32. package/agent/tools/set_emoji_reaction.ts +18 -0
  33. package/agent/tools/set_essence_msg.ts +19 -0
  34. package/agent/tools/set_group_portrait.ts +20 -0
  35. package/agent/tools/set_online_status.ts +18 -0
  36. package/agent/tools/set_profile.ts +21 -0
  37. package/agent/tools/set_signature.ts +17 -0
  38. package/agent/tools/set_title.ts +21 -0
  39. package/agent/tools/translate.ts +16 -0
  40. package/agent/tools/upload_group_file.ts +21 -0
  41. package/commands/endpoint/add/[id].js +3 -0
  42. package/commands/endpoint/add/[id].ts +3 -0
  43. package/commands/endpoint/list.js +3 -0
  44. package/commands/endpoint/list.ts +3 -0
  45. package/commands/endpoint/remove/[id].js +3 -0
  46. package/commands/endpoint/remove/[id].ts +3 -0
  47. package/lib/client.d.ts +52 -0
  48. package/lib/client.js +62 -0
  49. package/lib/endpoint-management.d.ts +15 -0
  50. package/lib/endpoint-management.js +47 -0
  51. package/lib/http-endpoint.d.ts +27 -0
  52. package/lib/http-endpoint.js +177 -0
  53. package/lib/index.d.ts +11 -22
  54. package/lib/index.js +10 -58
  55. package/lib/napcat-endpoint-commands.d.ts +1 -0
  56. package/lib/napcat-endpoint-commands.js +28 -0
  57. package/lib/napcat-inbound.d.ts +12 -5
  58. package/lib/napcat-inbound.js +28 -13
  59. package/lib/napcat-runtime-state.d.ts +1 -0
  60. package/lib/napcat-runtime-state.js +6 -0
  61. package/lib/onebot-get-msg.d.ts +16 -3
  62. package/lib/onebot-get-msg.js +53 -1
  63. package/lib/protocol.d.ts +165 -0
  64. package/lib/protocol.js +305 -0
  65. package/lib/side-event-dispatch.d.ts +7 -0
  66. package/lib/side-event-dispatch.js +36 -0
  67. package/lib/webhook.d.ts +2 -0
  68. package/lib/webhook.js +14 -0
  69. package/lib/ws-endpoint.d.ts +27 -0
  70. package/lib/ws-endpoint.js +241 -0
  71. package/lib/ws-transport.d.ts +13 -0
  72. package/lib/ws-transport.js +75 -0
  73. package/lib/ws-types.d.ts +17 -0
  74. package/lib/ws-types.js +1 -0
  75. package/lib/wss-auth.d.ts +2 -0
  76. package/lib/wss-auth.js +16 -0
  77. package/lib/wss-endpoint.d.ts +26 -0
  78. package/lib/wss-endpoint.js +187 -0
  79. package/package.json +62 -30
  80. package/plugin.js +18 -0
  81. package/schema.json +110 -0
  82. package/src/client.ts +79 -0
  83. package/src/endpoint-management.ts +72 -0
  84. package/src/http-endpoint.ts +234 -0
  85. package/src/index.ts +63 -85
  86. package/src/napcat-endpoint-commands.ts +26 -0
  87. package/src/napcat-inbound.ts +34 -10
  88. package/src/napcat-runtime-state.ts +7 -0
  89. package/src/onebot-get-msg.ts +69 -5
  90. package/src/protocol.ts +468 -0
  91. package/src/side-event-dispatch.ts +48 -0
  92. package/src/webhook.ts +16 -0
  93. package/src/ws-endpoint.ts +301 -0
  94. package/src/ws-transport.ts +105 -0
  95. package/src/ws-types.ts +20 -0
  96. package/src/wss-auth.ts +17 -0
  97. package/src/wss-endpoint.ts +242 -0
  98. package/client/NapCatManagement.tsx +0 -113
  99. package/client/index.tsx +0 -11
  100. package/client/tsconfig.json +0 -7
  101. package/client/utils/api.ts +0 -30
  102. package/dist/index.js +0 -27
  103. package/lib/adapter.d.ts +0 -27
  104. package/lib/adapter.d.ts.map +0 -1
  105. package/lib/adapter.js +0 -93
  106. package/lib/adapter.js.map +0 -1
  107. package/lib/agent-prompt.d.ts +0 -3
  108. package/lib/agent-prompt.d.ts.map +0 -1
  109. package/lib/agent-prompt.js +0 -105
  110. package/lib/agent-prompt.js.map +0 -1
  111. package/lib/bot-base.d.ts +0 -143
  112. package/lib/bot-base.d.ts.map +0 -1
  113. package/lib/bot-base.js +0 -334
  114. package/lib/bot-base.js.map +0 -1
  115. package/lib/bot-http.d.ts +0 -18
  116. package/lib/bot-http.d.ts.map +0 -1
  117. package/lib/bot-http.js +0 -119
  118. package/lib/bot-http.js.map +0 -1
  119. package/lib/bot-ws-client.d.ts +0 -21
  120. package/lib/bot-ws-client.d.ts.map +0 -1
  121. package/lib/bot-ws-client.js +0 -165
  122. package/lib/bot-ws-client.js.map +0 -1
  123. package/lib/bot-ws-server.d.ts +0 -21
  124. package/lib/bot-ws-server.d.ts.map +0 -1
  125. package/lib/bot-ws-server.js +0 -150
  126. package/lib/bot-ws-server.js.map +0 -1
  127. package/lib/index.d.ts.map +0 -1
  128. package/lib/index.js.map +0 -1
  129. package/lib/napcat-inbound.d.ts.map +0 -1
  130. package/lib/napcat-inbound.js.map +0 -1
  131. package/lib/onebot-get-msg.d.ts.map +0 -1
  132. package/lib/onebot-get-msg.js.map +0 -1
  133. package/lib/routes.d.ts +0 -4
  134. package/lib/routes.d.ts.map +0 -1
  135. package/lib/routes.js +0 -61
  136. package/lib/routes.js.map +0 -1
  137. package/lib/tools.d.ts +0 -8
  138. package/lib/tools.d.ts.map +0 -1
  139. package/lib/tools.js +0 -605
  140. package/lib/tools.js.map +0 -1
  141. package/lib/types.d.ts +0 -293
  142. package/lib/types.d.ts.map +0 -1
  143. package/lib/types.js +0 -6
  144. package/lib/types.js.map +0 -1
  145. package/lib/typing-indicator.d.ts +0 -45
  146. package/lib/typing-indicator.d.ts.map +0 -1
  147. package/lib/typing-indicator.js +0 -132
  148. package/lib/typing-indicator.js.map +0 -1
  149. package/plugin.yml +0 -3
  150. package/src/adapter.ts +0 -99
  151. package/src/agent-prompt.ts +0 -114
  152. package/src/bot-base.ts +0 -376
  153. package/src/bot-http.ts +0 -109
  154. package/src/bot-ws-client.ts +0 -164
  155. package/src/bot-ws-server.ts +0 -150
  156. package/src/routes.ts +0 -61
  157. package/src/tools.ts +0 -632
  158. package/src/types.ts +0 -279
  159. package/src/typing-indicator.ts +0 -184
@@ -0,0 +1,75 @@
1
+ import { clearInterval, clearTimeout, setInterval, setTimeout } from 'node:timers';
2
+ import { formatCompact, getLogger } from '@zhin.js/logger';
3
+ import { WS_OPEN, } from './ws-types.js';
4
+ const logger = getLogger('napcat');
5
+ export function decodeWsPayload(data) {
6
+ if (typeof data === 'string')
7
+ return data;
8
+ if (Buffer.isBuffer(data))
9
+ return data.toString();
10
+ if (data instanceof ArrayBuffer)
11
+ return new TextDecoder().decode(data);
12
+ return String(data ?? '');
13
+ }
14
+ export function handleNapCatWsMessage(data, options) {
15
+ try {
16
+ const raw = decodeWsPayload(data);
17
+ const msg = JSON.parse(raw);
18
+ if ('echo' in msg && typeof msg.echo === 'string') {
19
+ const resp = msg;
20
+ const pending = options.pending.get(resp.echo);
21
+ if (pending) {
22
+ options.pending.delete(resp.echo);
23
+ clearTimeout(pending.timeout);
24
+ if (resp.status === 'ok')
25
+ pending.resolve(resp.data);
26
+ else {
27
+ pending.reject(new Error(`API error [${resp.retcode}]: ${resp.message || resp.wording || 'unknown'}`));
28
+ }
29
+ }
30
+ return;
31
+ }
32
+ options.admit(msg);
33
+ }
34
+ catch (error) {
35
+ logger.warn(formatCompact({
36
+ op: 'napcat_parse_failed',
37
+ endpoint: options.endpointId,
38
+ error: error instanceof Error ? error.message : String(error),
39
+ }));
40
+ }
41
+ }
42
+ export function callNapCatWsAction(ws, pending, requestId, action, params) {
43
+ if (!ws || ws.readyState !== WS_OPEN) {
44
+ return Promise.reject(new Error('WebSocket is not connected'));
45
+ }
46
+ const echo = `req_${++requestId.value}`;
47
+ const req = { action, params, echo };
48
+ return new Promise((resolve, reject) => {
49
+ const timeout = setTimeout(() => {
50
+ pending.delete(echo);
51
+ reject(new Error(`API call timeout: ${action}`));
52
+ }, 30_000);
53
+ pending.set(echo, { resolve, reject, timeout });
54
+ ws.send(JSON.stringify(req));
55
+ });
56
+ }
57
+ export function startNapCatHeartbeat(ws, intervalMs, existingTimer) {
58
+ if (existingTimer)
59
+ clearInterval(existingTimer);
60
+ return setInterval(() => {
61
+ try {
62
+ ws?.ping?.();
63
+ }
64
+ catch {
65
+ /* ignore */
66
+ }
67
+ }, intervalMs);
68
+ }
69
+ export function rejectAllPending(pending, message = 'Connection closed') {
70
+ for (const [, entry] of pending) {
71
+ clearTimeout(entry.timeout);
72
+ entry.reject(new Error(message));
73
+ }
74
+ pending.clear();
75
+ }
@@ -0,0 +1,17 @@
1
+ /** Minimal WS surface used by the endpoint (real `ws` or test mock). */
2
+ export interface NapCatWsSocket {
3
+ readonly readyState: number;
4
+ send(data: string): void;
5
+ close(code?: number, reason?: string): void;
6
+ ping?(): void;
7
+ on(event: 'open' | 'message' | 'close' | 'error', listener: (...args: unknown[]) => void): void;
8
+ }
9
+ export interface NapCatWsCreateOptions {
10
+ readonly headers?: Record<string, string>;
11
+ }
12
+ export declare const WS_OPEN = 1;
13
+ export interface NapCatPendingAction {
14
+ resolve: (value: unknown) => void;
15
+ reject: (err: Error) => void;
16
+ timeout: NodeJS.Timeout;
17
+ }
@@ -0,0 +1 @@
1
+ export const WS_OPEN = 1;
@@ -0,0 +1,2 @@
1
+ import type { IncomingMessage } from 'node:http';
2
+ export declare function verifyNapCatAccessToken(accessToken: string | undefined, request: IncomingMessage): boolean;
@@ -0,0 +1,16 @@
1
+ export function verifyNapCatAccessToken(accessToken, request) {
2
+ if (!accessToken)
3
+ return true;
4
+ const auth = request.headers.authorization ?? '';
5
+ if (auth === `Bearer ${accessToken}`)
6
+ return true;
7
+ try {
8
+ const url = new URL(request.url ?? '/', 'http://localhost');
9
+ if (url.searchParams.get('access_token') === accessToken)
10
+ return true;
11
+ }
12
+ catch {
13
+ /* ignore */
14
+ }
15
+ return false;
16
+ }
@@ -0,0 +1,26 @@
1
+ import { Endpoint } from 'zhin.js/adapter';
2
+ import { type EndpointControl, type EndpointManagement, type EndpointSendRequest } from 'zhin.js/adapter';
3
+ import type { HttpHost } from '@zhin.js/host-http';
4
+ import type { CapabilityId } from 'zhin.js';
5
+ import { type NapCatEvent, type NapCatWssConfig } from './protocol.js';
6
+ import { NapcatClient } from './client.js';
7
+ export interface NapCatWssEndpointOptions {
8
+ readonly id: CapabilityId;
9
+ readonly http: HttpHost;
10
+ readonly config: NapCatWssConfig;
11
+ }
12
+ export declare class NapCatWssEndpoint extends Endpoint<NapcatClient> {
13
+ #private;
14
+ readonly client: NapcatClient;
15
+ readonly management: EndpointManagement;
16
+ readonly control: EndpointControl;
17
+ readonly content: import("@zhin.js/adapter").EndpointContentPort;
18
+ constructor(options: NapCatWssEndpointOptions);
19
+ start(): Promise<void>;
20
+ open(): void;
21
+ close(): void;
22
+ stop(): Promise<void>;
23
+ send({ conversation, payload }: EndpointSendRequest): Promise<string>;
24
+ recallMessage(messageId: string): Promise<void>;
25
+ admit(ev: NapCatEvent): void;
26
+ }
@@ -0,0 +1,187 @@
1
+ import { Endpoint } from 'zhin.js/adapter';
2
+ /**
3
+ * NapCat reverse WSS endpoint — accepts inbound WebSocket from NapCat.
4
+ */
5
+ import { clearInterval } from 'node:timers';
6
+ import { createRecallEndpointControl, } from 'zhin.js/adapter';
7
+ import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
8
+ import { createNapCatEndpointManagement } from './endpoint-management.js';
9
+ import { InboundMessageDeduper, isNapCatBotMentioned, isSelfMessage, normalizeMessage, } from './napcat-inbound.js';
10
+ import { buildSendAction, formatInboundContent, formatOutboundSegments, isMessageEvent, napcatInboundConversation, napcatOutboundTarget, senderNickname, senderUserId, } from './protocol.js';
11
+ import { receiveNapCatSideEvent } from './side-event-dispatch.js';
12
+ import { createNapCatContentPort } from './onebot-get-msg.js';
13
+ import { NapcatClient } from './client.js';
14
+ import { callNapCatWsAction, handleNapCatWsMessage, rejectAllPending, startNapCatHeartbeat, } from './ws-transport.js';
15
+ import { verifyNapCatAccessToken } from './wss-auth.js';
16
+ export class NapCatWssEndpoint extends Endpoint {
17
+ client = new NapcatClient((action, params) => this.#callApi(action, params));
18
+ #logger;
19
+ #options;
20
+ #inboundDeduper = new InboundMessageDeduper();
21
+ management = createNapCatEndpointManagement(this.client);
22
+ control = createRecallEndpointControl((id) => this.recallMessage(id));
23
+ content = createNapCatContentPort((action, params) => this.client.callApi(action, params));
24
+ #ws;
25
+ #wsRelease;
26
+ #heartbeatTimer;
27
+ #requestId = { value: 0 };
28
+ #pending = new Map();
29
+ #open = false;
30
+ #started = false;
31
+ constructor(options) {
32
+ super();
33
+ this.#logger = getAdapterLogger('napcat', options.config.id);
34
+ this.#options = options;
35
+ }
36
+ async start() {
37
+ if (this.#started)
38
+ return;
39
+ this.#started = true;
40
+ const handle = this.#options.http.ws(this.#options.config.path);
41
+ this.#wsRelease = handle.onConnection((connection) => {
42
+ this.#acceptConnection(connection);
43
+ });
44
+ this.#logger.info(formatCompact({
45
+ op: 'listen',
46
+ endpoint: this.#options.config.id,
47
+ mode: 'wss',
48
+ path: this.#options.config.path,
49
+ }));
50
+ }
51
+ open() {
52
+ this.#open = true;
53
+ }
54
+ close() {
55
+ this.#open = false;
56
+ }
57
+ async stop() {
58
+ this.#open = false;
59
+ this.#wsRelease?.();
60
+ this.#wsRelease = undefined;
61
+ if (this.#heartbeatTimer) {
62
+ clearInterval(this.#heartbeatTimer);
63
+ this.#heartbeatTimer = undefined;
64
+ }
65
+ rejectAllPending(this.#pending);
66
+ this.#inboundDeduper.clear();
67
+ if (this.#ws) {
68
+ try {
69
+ this.#ws.close();
70
+ }
71
+ catch {
72
+ /* ignore */
73
+ }
74
+ this.#ws = undefined;
75
+ }
76
+ this.#started = false;
77
+ }
78
+ async send({ conversation, payload }) {
79
+ const message = formatOutboundSegments(payload);
80
+ const { action, params } = buildSendAction(napcatOutboundTarget(conversation), message);
81
+ const data = await this.client.callApi(action, params);
82
+ return data?.message_id != null ? String(data.message_id) : '';
83
+ }
84
+ async recallMessage(messageId) {
85
+ if (!messageId)
86
+ return;
87
+ await this.client.callApi('delete_msg', { message_id: Number(messageId) });
88
+ }
89
+ #callApi(action, params = {}) {
90
+ return callNapCatWsAction(this.#ws, this.#pending, this.#requestId, action, params);
91
+ }
92
+ admit(ev) {
93
+ if (!this.#open)
94
+ return;
95
+ void this.emitPlatform(napCatPlatformEventName(ev), ev).catch((error) => {
96
+ this.#logger.warn(formatCompact({
97
+ op: 'napcat_platform_event_failed',
98
+ error: error instanceof Error ? error.message : String(error),
99
+ }));
100
+ });
101
+ if (!isMessageEvent(ev)) {
102
+ receiveNapCatSideEvent((name, payload) => this.emit(name, payload), this.#options.config.id, this.client, ev, this.#logger);
103
+ return;
104
+ }
105
+ if (isSelfMessage(ev))
106
+ return;
107
+ const msgId = String(ev.message_id);
108
+ if (!this.#inboundDeduper.shouldProcess(msgId))
109
+ return;
110
+ if (Array.isArray(ev.message) || typeof ev.message === 'string') {
111
+ ev = { ...ev, message: normalizeMessage(ev.message) };
112
+ }
113
+ const conversation = napcatInboundConversation(String(this.#options.id), ev);
114
+ const nickname = senderNickname(ev);
115
+ const mentioned = isNapCatBotMentioned(ev);
116
+ void this.emit('message.receive', {
117
+ conversation,
118
+ message: { conversation, id: msgId },
119
+ content: formatInboundContent(ev),
120
+ sender: {
121
+ id: senderUserId(ev),
122
+ name: nickname,
123
+ ...(ev.sender?.role ? { roles: [ev.sender.role] } : {}),
124
+ },
125
+ endpointId: this.#options.config.id,
126
+ ...(mentioned ? { mentioned: true } : {}),
127
+ metadata: Object.freeze({
128
+ message_type: ev.message_type,
129
+ user_id: ev.user_id != null ? String(ev.user_id) : undefined,
130
+ group_id: ev.group_id != null ? String(ev.group_id) : undefined,
131
+ time: ev.time,
132
+ self_id: ev.self_id != null ? String(ev.self_id) : undefined,
133
+ role: ev.sender?.role,
134
+ ...(nickname ? { nickname } : {}),
135
+ }),
136
+ }).catch((err) => {
137
+ this.#logger.warn(formatCompact({
138
+ op: 'napcat_gateway_receive_failed',
139
+ target: `${conversation.kind}:${conversation.id}`,
140
+ error: err instanceof Error ? err.message : String(err),
141
+ }));
142
+ });
143
+ }
144
+ #acceptConnection(connection) {
145
+ if (!verifyNapCatAccessToken(this.#options.config.access_token, connection.request)) {
146
+ connection.socket.close(4003, 'Unauthorized');
147
+ return;
148
+ }
149
+ const socket = connection.socket;
150
+ if (this.#ws) {
151
+ try {
152
+ this.#ws.close();
153
+ }
154
+ catch {
155
+ /* ignore */
156
+ }
157
+ }
158
+ this.#ws = socket;
159
+ this.#heartbeatTimer = startNapCatHeartbeat(this.#ws, this.#options.config.heartbeat_interval, this.#heartbeatTimer);
160
+ socket.on('message', (data) => {
161
+ handleNapCatWsMessage(data, {
162
+ endpointId: this.#options.config.id,
163
+ pending: this.#pending,
164
+ admit: (event) => this.admit(event),
165
+ });
166
+ });
167
+ socket.on('close', () => {
168
+ if (this.#ws === socket) {
169
+ this.#ws = undefined;
170
+ if (this.#heartbeatTimer) {
171
+ clearInterval(this.#heartbeatTimer);
172
+ this.#heartbeatTimer = undefined;
173
+ }
174
+ }
175
+ });
176
+ this.#logger.debug(formatCompact({
177
+ endpoint: this.#options.config.id,
178
+ mode: 'wss',
179
+ peer: connection.request.socket.remoteAddress,
180
+ }));
181
+ }
182
+ }
183
+ function napCatPlatformEventName(ev) {
184
+ return [ev.post_type, ev.message_type ?? ev.notice_type ?? ev.request_type, ev.sub_type]
185
+ .filter(Boolean)
186
+ .join('.');
187
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@zhin.js/adapter-napcat",
3
- "version": "1.0.0",
4
- "description": "Zhin.js adapter for NapCatQQ (OneBot11 superset with go-cqhttp & NapCat extensions)",
3
+ "version": "1.1.0",
4
+ "description": "Zhin.js NapCat adapter for Plugin Runtime (WebSocket client, OneBot11 + NapCat extensions)",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
7
7
  "types": "./lib/index.d.ts",
@@ -13,12 +13,13 @@
13
13
  }
14
14
  },
15
15
  "files": [
16
+ "adapters",
17
+ "commands",
18
+ "plugin.js",
19
+ "schema.json",
16
20
  "src",
17
21
  "lib",
18
- "client",
19
- "dist",
20
- "skills",
21
- "plugin.yml",
22
+ "agent",
22
23
  "README.md",
23
24
  "CHANGELOG.md"
24
25
  ],
@@ -34,56 +35,87 @@
34
35
  "qq",
35
36
  "chatbot"
36
37
  ],
37
- "author": {
38
- "name": "lc-cn",
39
- "email": "admin@liucl.cn",
40
- "url": "https://github.com/lc-cn"
41
- },
42
38
  "license": "MIT",
43
39
  "repository": {
44
- "url": "git+https://github.com/zhinjs/zhin.git",
45
40
  "type": "git",
41
+ "url": "https://github.com/zhinjs/zhin",
46
42
  "directory": "plugins/adapters/napcat"
47
43
  },
48
44
  "dependencies": {
49
- "ws": "^8.21.0"
45
+ "ws": "^8.21.1",
46
+ "@zhin.js/adapter": "1.1.12",
47
+ "@zhin.js/core": "1.1.35",
48
+ "@zhin.js/feature-kit": "1.1.0",
49
+ "@zhin.js/host-http": "1.1.0",
50
+ "@zhin.js/im-contract": "1.1.0",
51
+ "@zhin.js/logger": "1.1.0",
52
+ "@zhin.js/permission": "1.1.0"
50
53
  },
51
54
  "devDependencies": {
52
- "@types/node": "^25.9.1",
53
- "@types/react": "^19.2.15",
54
- "@types/react-dom": "^19.2.3",
55
+ "@types/node": "^26.1.2",
55
56
  "@types/ws": "^8.18.1",
56
- "lucide-react": "^1.17.0",
57
57
  "typescript": "^6.0.3",
58
- "@zhin.js/cli": "1.0.88",
59
- "@zhin.js/host-api": "1.0.0",
60
- "@zhin.js/contract": "1.0.1",
61
- "zhin.js": "2.0.0"
58
+ "vitest": "^4.1.10",
59
+ "zod": "^4.4.3",
60
+ "@zhin.js/agent": "1.1.23",
61
+ "@zhin.js/host-http": "1.1.0",
62
+ "zhin.js": "1.1.0"
62
63
  },
63
64
  "peerDependencies": {
64
- "@zhin.js/agent": "0.2.0",
65
- "@zhin.js/host-api": "1.0.0",
66
- "@zhin.js/host-router": "1.0.0",
67
- "@zhin.js/contract": "1.0.1",
68
- "zhin.js": "2.0.0"
65
+ "zod": "^4.0.0",
66
+ "@zhin.js/adapter": "^1.1.12",
67
+ "@zhin.js/agent": "^1.1.23",
68
+ "@zhin.js/command": "^1.1.0",
69
+ "@zhin.js/core": "^1.1.35",
70
+ "zhin.js": "^1.1.0"
69
71
  },
70
72
  "peerDependenciesMeta": {
71
73
  "@zhin.js/agent": {
72
74
  "optional": true
73
75
  },
74
- "@zhin.js/host-api": {
76
+ "@zhin.js/command": {
77
+ "optional": true
78
+ },
79
+ "zhin.js": {
75
80
  "optional": true
76
81
  },
77
- "@zhin.js/host-router": {
82
+ "zod": {
78
83
  "optional": true
79
84
  }
80
85
  },
86
+ "author": {
87
+ "name": "lc-cn",
88
+ "email": "admin@liucl.cn",
89
+ "url": "https://github.com/lc-cn"
90
+ },
81
91
  "publishConfig": {
82
92
  "access": "public",
83
93
  "registry": "https://registry.npmjs.org"
84
94
  },
95
+ "engines": {
96
+ "node": "^20.19.0 || >=22.12.0"
97
+ },
98
+ "zhin": {
99
+ "protocol": 1,
100
+ "type": "plugin",
101
+ "entry": "./plugin.js",
102
+ "engine": "^1.0.0",
103
+ "runtime": "trusted",
104
+ "features": [
105
+ {
106
+ "package": "@zhin.js/adapter",
107
+ "api": "^1.0.0"
108
+ },
109
+ {
110
+ "package": "@zhin.js/command",
111
+ "api": "^1.0.0"
112
+ }
113
+ ],
114
+ "plugins": []
115
+ },
85
116
  "scripts": {
86
- "build": "zhin build",
87
- "clean": "rimraf lib"
117
+ "build": "tsc",
118
+ "clean": "rimraf lib",
119
+ "test": "NODE_OPTIONS=--experimental-strip-types vitest run --root ../../.. plugins/adapters/napcat/tests"
88
120
  }
89
121
  }
package/plugin.js ADDED
@@ -0,0 +1,18 @@
1
+ // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ import { createEndpointRuntimeState } from 'zhin.js/adapter';
3
+ import { definePlugin } from 'zhin.js';
4
+ import { permissionHostToken, createSceneRolePlatformChecker } from '@zhin.js/permission';
5
+ import { napcatRuntimeStateToken } from "./lib/napcat-runtime-state.js";
6
+ export default definePlugin({
7
+ name: 'napcat',
8
+ metadata: {
9
+ displayName: 'NapCat Adapter',
10
+ },
11
+ setup(context) {
12
+ context.resources.provide(napcatRuntimeStateToken, createEndpointRuntimeState());
13
+ if (context.resources.has(permissionHostToken)) {
14
+ const host = context.resources.use(permissionHostToken);
15
+ return host.registerPlatform('napcat', createSceneRolePlatformChecker());
16
+ }
17
+ },
18
+ });
package/schema.json ADDED
@@ -0,0 +1,110 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "type": "object",
4
+ "additionalProperties": false,
5
+ "properties": {
6
+ "connection": {
7
+ "type": "string",
8
+ "enum": [
9
+ "ws",
10
+ "wss",
11
+ "http"
12
+ ],
13
+ "default": "ws",
14
+ "description": "ws (default), wss (reverse WS), or http (POST webhook + HTTP API outbound)"
15
+ },
16
+ "reconnect_interval": {
17
+ "type": "number",
18
+ "default": 5000
19
+ },
20
+ "heartbeat_interval": {
21
+ "type": "number",
22
+ "default": 30000
23
+ },
24
+ "poll_interval": {
25
+ "type": "number",
26
+ "default": 30000
27
+ },
28
+ "master": {
29
+ "type": [
30
+ "string",
31
+ "number"
32
+ ],
33
+ "description": "框架 master(QQ uin;AI/工具权限、endpoint 管理)。endpoints[i].master 可逐项覆盖"
34
+ },
35
+ "trusted": {
36
+ "type": "array",
37
+ "items": {
38
+ "type": [
39
+ "string",
40
+ "number"
41
+ ],
42
+ "description": "Trusted QQ uin"
43
+ },
44
+ "description": "框架 trusted 用户列表(弱于 master)。endpoints[i].trusted 可逐项追加"
45
+ },
46
+ "endpoints": {
47
+ "type": "array",
48
+ "description": "多账号:一个插件实例挂多个 endpoint。每项与顶层字段同构(id 必填,其余覆盖顶层)",
49
+ "items": {
50
+ "type": "object",
51
+ "additionalProperties": true,
52
+ "properties": {
53
+ "master": {
54
+ "type": [
55
+ "string",
56
+ "number"
57
+ ],
58
+ "description": "本 endpoint 的框架 master(QQ uin);覆盖顶层 master"
59
+ },
60
+ "trusted": {
61
+ "type": "array",
62
+ "items": {
63
+ "type": [
64
+ "string",
65
+ "number"
66
+ ],
67
+ "description": "Trusted QQ uin"
68
+ },
69
+ "description": "本 endpoint 的 trusted 列表"
70
+ },
71
+ "url": {
72
+ "type": "string",
73
+ "description": "NapCat WebSocket URL (required for connection: ws)"
74
+ },
75
+ "path": {
76
+ "type": "string",
77
+ "description": "WS path for reverse-wss"
78
+ },
79
+ "http_url": {
80
+ "type": "string",
81
+ "description": "HTTP API base URL (connection: http outbound)"
82
+ },
83
+ "post_path": {
84
+ "type": "string",
85
+ "description": "HTTP POST event path (connection: http inbound)"
86
+ },
87
+ "access_token": {
88
+ "type": "string",
89
+ "description": "NapCat access token"
90
+ },
91
+ "id": {
92
+ "type": "string",
93
+ "description": "NapCat bot name"
94
+ }
95
+ },
96
+ "required": [
97
+ "id"
98
+ ]
99
+ }
100
+ },
101
+ "commandPrefix": {
102
+ "type": "string",
103
+ "default": "",
104
+ "description": "命令前缀(默认 '' 无前缀,任意文本按命令匹配;如 '/' 要求 / 开头)。endpoints[i] 可逐项覆盖"
105
+ }
106
+ },
107
+ "required": [
108
+ "endpoints"
109
+ ]
110
+ }