@zhin.js/adapter-napcat 3.0.2 → 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.
- package/CHANGELOG.md +62 -0
- package/README.md +47 -98
- package/adapters/napcat.ts +39 -0
- package/agent/tools/ai_tts.ts +2 -2
- package/agent/tools/del_group_notice.ts +2 -2
- package/agent/tools/delete_essence_msg.ts +2 -2
- package/agent/tools/delete_friend.ts +2 -2
- package/agent/tools/download_file.ts +2 -2
- package/agent/tools/forward_single_msg.ts +2 -2
- package/agent/tools/get_ai_characters.ts +2 -2
- package/agent/tools/get_essence_list.ts +2 -2
- package/agent/tools/get_friend_msg_history.ts +2 -2
- package/agent/tools/get_group_file_url.ts +2 -2
- package/agent/tools/get_group_info_ex.ts +2 -2
- package/agent/tools/get_group_msg_history.ts +2 -2
- package/agent/tools/get_group_notice.ts +2 -2
- package/agent/tools/get_group_root_files.ts +2 -2
- package/agent/tools/get_group_shut_list.ts +2 -2
- package/agent/tools/get_mini_app_ark.ts +2 -2
- package/agent/tools/get_user_status.ts +2 -2
- package/agent/tools/group_sign.ts +2 -2
- package/agent/tools/mark_msg_as_read.ts +2 -2
- package/agent/tools/ocr_image.ts +2 -2
- package/agent/tools/send_forward_msg.ts +2 -2
- package/agent/tools/send_group_notice.ts +2 -2
- package/agent/tools/send_like.ts +2 -2
- package/agent/tools/send_poke.ts +2 -2
- package/agent/tools/set_avatar.ts +2 -2
- package/agent/tools/set_emoji_reaction.ts +2 -2
- package/agent/tools/set_essence_msg.ts +2 -2
- package/agent/tools/set_group_portrait.ts +2 -2
- package/agent/tools/set_online_status.ts +2 -2
- package/agent/tools/set_profile.ts +2 -2
- package/agent/tools/set_signature.ts +2 -2
- package/agent/tools/set_title.ts +2 -2
- package/agent/tools/translate.ts +2 -2
- package/agent/tools/upload_group_file.ts +2 -2
- package/lib/http-endpoint.d.ts +26 -0
- package/lib/http-endpoint.js +147 -0
- package/lib/index.d.ts +11 -0
- package/lib/index.js +10 -0
- package/lib/napcat-agent-deps.d.ts +51 -0
- package/lib/napcat-agent-deps.js +33 -0
- package/lib/napcat-inbound.d.ts +28 -0
- package/lib/{src/napcat-inbound.js → napcat-inbound.js} +28 -13
- package/lib/onebot-get-msg.d.ts +14 -0
- package/lib/{src/onebot-get-msg.js → onebot-get-msg.js} +0 -1
- package/lib/protocol.d.ts +151 -0
- package/lib/protocol.js +217 -0
- package/lib/webhook.d.ts +2 -0
- package/lib/webhook.js +14 -0
- package/lib/ws-endpoint.d.ts +61 -0
- package/lib/ws-endpoint.js +357 -0
- package/lib/ws-transport.d.ts +13 -0
- package/lib/ws-transport.js +75 -0
- package/lib/ws-types.d.ts +17 -0
- package/lib/ws-types.js +1 -0
- package/lib/wss-auth.d.ts +2 -0
- package/lib/wss-auth.js +16 -0
- package/lib/wss-endpoint.d.ts +25 -0
- package/lib/wss-endpoint.js +157 -0
- package/package.json +44 -33
- package/plugin.ts +13 -0
- package/schema.json +74 -0
- package/src/http-endpoint.ts +197 -0
- package/src/index.ts +66 -81
- package/src/napcat-agent-deps.ts +81 -15
- package/src/napcat-inbound.ts +34 -10
- package/src/onebot-get-msg.ts +8 -2
- package/src/protocol.ts +373 -0
- package/src/webhook.ts +16 -0
- package/src/ws-endpoint.ts +452 -0
- package/src/ws-transport.ts +105 -0
- package/src/ws-types.ts +20 -0
- package/src/wss-auth.ts +17 -0
- package/src/wss-endpoint.ts +205 -0
- package/client/NapCatManagement.tsx +0 -113
- package/client/index.tsx +0 -11
- package/client/tsconfig.json +0 -7
- package/client/utils/api.ts +0 -30
- package/dist/index.js +0 -27
- package/lib/agent/tools/ai_tts.js +0 -21
- package/lib/agent/tools/ai_tts.js.map +0 -1
- package/lib/agent/tools/del_group_notice.js +0 -22
- package/lib/agent/tools/del_group_notice.js.map +0 -1
- package/lib/agent/tools/delete_essence_msg.js +0 -21
- package/lib/agent/tools/delete_essence_msg.js.map +0 -1
- package/lib/agent/tools/delete_friend.js +0 -20
- package/lib/agent/tools/delete_friend.js.map +0 -1
- package/lib/agent/tools/download_file.js +0 -19
- package/lib/agent/tools/download_file.js.map +0 -1
- package/lib/agent/tools/forward_single_msg.js +0 -24
- package/lib/agent/tools/forward_single_msg.js.map +0 -1
- package/lib/agent/tools/get_ai_characters.js +0 -19
- package/lib/agent/tools/get_ai_characters.js.map +0 -1
- package/lib/agent/tools/get_essence_list.js +0 -19
- package/lib/agent/tools/get_essence_list.js.map +0 -1
- package/lib/agent/tools/get_friend_msg_history.js +0 -20
- package/lib/agent/tools/get_friend_msg_history.js.map +0 -1
- package/lib/agent/tools/get_group_file_url.js +0 -21
- package/lib/agent/tools/get_group_file_url.js.map +0 -1
- package/lib/agent/tools/get_group_info_ex.js +0 -19
- package/lib/agent/tools/get_group_info_ex.js.map +0 -1
- package/lib/agent/tools/get_group_msg_history.js +0 -21
- package/lib/agent/tools/get_group_msg_history.js.map +0 -1
- package/lib/agent/tools/get_group_notice.js +0 -19
- package/lib/agent/tools/get_group_notice.js.map +0 -1
- package/lib/agent/tools/get_group_root_files.js +0 -19
- package/lib/agent/tools/get_group_root_files.js.map +0 -1
- package/lib/agent/tools/get_group_shut_list.js +0 -19
- package/lib/agent/tools/get_group_shut_list.js.map +0 -1
- package/lib/agent/tools/get_mini_app_ark.js +0 -22
- package/lib/agent/tools/get_mini_app_ark.js.map +0 -1
- package/lib/agent/tools/get_user_status.js +0 -18
- package/lib/agent/tools/get_user_status.js.map +0 -1
- package/lib/agent/tools/group_sign.js +0 -20
- package/lib/agent/tools/group_sign.js.map +0 -1
- package/lib/agent/tools/mark_msg_as_read.js +0 -19
- package/lib/agent/tools/mark_msg_as_read.js.map +0 -1
- package/lib/agent/tools/ocr_image.js +0 -18
- package/lib/agent/tools/ocr_image.js.map +0 -1
- package/lib/agent/tools/send_forward_msg.js +0 -21
- package/lib/agent/tools/send_forward_msg.js.map +0 -1
- package/lib/agent/tools/send_group_notice.js +0 -23
- package/lib/agent/tools/send_group_notice.js.map +0 -1
- package/lib/agent/tools/send_like.js +0 -20
- package/lib/agent/tools/send_like.js.map +0 -1
- package/lib/agent/tools/send_poke.js +0 -20
- package/lib/agent/tools/send_poke.js.map +0 -1
- package/lib/agent/tools/set_avatar.js +0 -19
- package/lib/agent/tools/set_avatar.js.map +0 -1
- package/lib/agent/tools/set_emoji_reaction.js +0 -20
- package/lib/agent/tools/set_emoji_reaction.js.map +0 -1
- package/lib/agent/tools/set_essence_msg.js +0 -21
- package/lib/agent/tools/set_essence_msg.js.map +0 -1
- package/lib/agent/tools/set_group_portrait.js +0 -22
- package/lib/agent/tools/set_group_portrait.js.map +0 -1
- package/lib/agent/tools/set_online_status.js +0 -20
- package/lib/agent/tools/set_online_status.js.map +0 -1
- package/lib/agent/tools/set_profile.js +0 -23
- package/lib/agent/tools/set_profile.js.map +0 -1
- package/lib/agent/tools/set_signature.js +0 -19
- package/lib/agent/tools/set_signature.js.map +0 -1
- package/lib/agent/tools/set_title.js +0 -23
- package/lib/agent/tools/set_title.js.map +0 -1
- package/lib/agent/tools/translate.js +0 -18
- package/lib/agent/tools/translate.js.map +0 -1
- package/lib/agent/tools/upload_group_file.js +0 -23
- package/lib/agent/tools/upload_group_file.js.map +0 -1
- package/lib/src/adapter.js +0 -102
- package/lib/src/adapter.js.map +0 -1
- package/lib/src/agent-prompt.js +0 -106
- package/lib/src/agent-prompt.js.map +0 -1
- package/lib/src/endpoint-base.js +0 -315
- package/lib/src/endpoint-base.js.map +0 -1
- package/lib/src/endpoint-http.js +0 -106
- package/lib/src/endpoint-http.js.map +0 -1
- package/lib/src/endpoint-ws-client.js +0 -139
- package/lib/src/endpoint-ws-client.js.map +0 -1
- package/lib/src/endpoint-ws-server.js +0 -137
- package/lib/src/endpoint-ws-server.js.map +0 -1
- package/lib/src/index.js +0 -58
- package/lib/src/index.js.map +0 -1
- package/lib/src/napcat-agent-deps.js +0 -19
- package/lib/src/napcat-agent-deps.js.map +0 -1
- package/lib/src/napcat-inbound.js.map +0 -1
- package/lib/src/onebot-get-msg.js.map +0 -1
- package/lib/src/routes.js +0 -61
- package/lib/src/routes.js.map +0 -1
- package/lib/src/segment-mapper.js +0 -2
- package/lib/src/segment-mapper.js.map +0 -1
- package/lib/src/types.js +0 -6
- package/lib/src/types.js.map +0 -1
- package/plugin.yml +0 -3
- package/src/adapter.ts +0 -109
- package/src/agent-prompt.ts +0 -115
- package/src/endpoint-base.ts +0 -362
- package/src/endpoint-http.ts +0 -95
- package/src/endpoint-ws-client.ts +0 -137
- package/src/endpoint-ws-server.ts +0 -136
- package/src/routes.ts +0 -61
- package/src/segment-mapper.ts +0 -1
- package/src/types.ts +0 -266
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NapCat HTTP endpoint — POST inbound events + HTTP API outbound.
|
|
3
|
+
*/
|
|
4
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
5
|
+
import type { EndpointInstance } from '@zhin.js/adapter';
|
|
6
|
+
import type { MessageGateway } from '@zhin.js/core/runtime';
|
|
7
|
+
import type { HttpHost, HttpRouteRegistration } from '@zhin.js/host-http';
|
|
8
|
+
import { formatCompact, getLogger } from '@zhin.js/logger';
|
|
9
|
+
import type { CapabilityId } from '@zhin.js/plugin-runtime';
|
|
10
|
+
import { registerNapcatAgentEndpoint } from './napcat-agent-deps.js';
|
|
11
|
+
import {
|
|
12
|
+
InboundMessageDeduper,
|
|
13
|
+
isNapCatBotMentioned,
|
|
14
|
+
isSelfMessage,
|
|
15
|
+
normalizeMessage,
|
|
16
|
+
} from './napcat-inbound.js';
|
|
17
|
+
import {
|
|
18
|
+
buildSendAction,
|
|
19
|
+
callNapCatHttpAction,
|
|
20
|
+
formatInboundContent,
|
|
21
|
+
formatInboundTarget,
|
|
22
|
+
formatOutboundSegments,
|
|
23
|
+
isMessageEvent,
|
|
24
|
+
senderNickname,
|
|
25
|
+
senderUserId,
|
|
26
|
+
type NapCatEvent,
|
|
27
|
+
type NapCatHttpConfig,
|
|
28
|
+
} from './protocol.js';
|
|
29
|
+
import { readRequestBody } from './webhook.js';
|
|
30
|
+
import { NapCatWsEndpoint } from './ws-endpoint.js';
|
|
31
|
+
import { verifyNapCatAccessToken } from './wss-auth.js';
|
|
32
|
+
|
|
33
|
+
const logger = getLogger('napcat');
|
|
34
|
+
|
|
35
|
+
export interface NapCatHttpEndpointOptions {
|
|
36
|
+
readonly id: CapabilityId;
|
|
37
|
+
readonly gateway: MessageGateway;
|
|
38
|
+
readonly http: HttpHost;
|
|
39
|
+
readonly config: NapCatHttpConfig;
|
|
40
|
+
readonly callHttpAction?: typeof callNapCatHttpAction;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export class NapCatHttpEndpoint implements EndpointInstance {
|
|
44
|
+
readonly #options: NapCatHttpEndpointOptions;
|
|
45
|
+
readonly #inboundDeduper = new InboundMessageDeduper();
|
|
46
|
+
readonly #callHttpAction: typeof callNapCatHttpAction;
|
|
47
|
+
#routeReleases: HttpRouteRegistration[] = [];
|
|
48
|
+
#open = false;
|
|
49
|
+
#started = false;
|
|
50
|
+
#unregisterAgent?: () => void;
|
|
51
|
+
|
|
52
|
+
constructor(options: NapCatHttpEndpointOptions) {
|
|
53
|
+
this.#options = options;
|
|
54
|
+
this.#callHttpAction = options.callHttpAction ?? callNapCatHttpAction;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async start(): Promise<void> {
|
|
58
|
+
if (this.#started) return;
|
|
59
|
+
this.#started = true;
|
|
60
|
+
this.#unregisterAgent = registerNapcatAgentEndpoint(
|
|
61
|
+
this.#options.config.name,
|
|
62
|
+
this as unknown as NapCatWsEndpoint,
|
|
63
|
+
);
|
|
64
|
+
this.#setupRoutes();
|
|
65
|
+
logger.info(formatCompact({
|
|
66
|
+
op: 'listen',
|
|
67
|
+
endpoint: this.#options.config.name,
|
|
68
|
+
mode: 'http',
|
|
69
|
+
path: this.#options.config.post_path,
|
|
70
|
+
}));
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
open(): void {
|
|
74
|
+
this.#open = true;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
close(): void {
|
|
78
|
+
this.#open = false;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async stop(): Promise<void> {
|
|
82
|
+
this.#open = false;
|
|
83
|
+
for (const release of this.#routeReleases.splice(0)) release();
|
|
84
|
+
this.#unregisterAgent?.();
|
|
85
|
+
this.#unregisterAgent = undefined;
|
|
86
|
+
this.#inboundDeduper.clear();
|
|
87
|
+
this.#started = false;
|
|
88
|
+
logger.debug(formatCompact({ op: 'disconnect', endpoint: this.#options.config.name }));
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async send({ target, payload }: { readonly target: string; readonly payload: unknown }): Promise<string> {
|
|
92
|
+
const message = formatOutboundSegments(payload);
|
|
93
|
+
const { action, params } = buildSendAction(target, message);
|
|
94
|
+
const resp = await this.#callHttpAction(
|
|
95
|
+
{
|
|
96
|
+
http_url: this.#options.config.http_url,
|
|
97
|
+
access_token: this.#options.config.access_token,
|
|
98
|
+
},
|
|
99
|
+
action,
|
|
100
|
+
params,
|
|
101
|
+
);
|
|
102
|
+
const data = resp.data as { message_id?: number | string } | undefined;
|
|
103
|
+
const messageId = data?.message_id != null ? String(data.message_id) : '';
|
|
104
|
+
logger.debug(formatCompact({
|
|
105
|
+
op: 'napcat_send',
|
|
106
|
+
endpoint: this.#options.config.name,
|
|
107
|
+
target,
|
|
108
|
+
messageId,
|
|
109
|
+
}));
|
|
110
|
+
return messageId;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
callApi(action: string, params: Record<string, unknown> = {}): Promise<unknown> {
|
|
114
|
+
return this.#callHttpAction(
|
|
115
|
+
{
|
|
116
|
+
http_url: this.#options.config.http_url,
|
|
117
|
+
access_token: this.#options.config.access_token,
|
|
118
|
+
},
|
|
119
|
+
action,
|
|
120
|
+
params,
|
|
121
|
+
).then((resp) => resp.data);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
admit(ev: NapCatEvent): void {
|
|
125
|
+
if (!this.#open || !isMessageEvent(ev)) return;
|
|
126
|
+
if (isSelfMessage(ev)) return;
|
|
127
|
+
const msgId = String(ev.message_id);
|
|
128
|
+
if (!this.#inboundDeduper.shouldProcess(msgId)) return;
|
|
129
|
+
if (Array.isArray(ev.message) || typeof ev.message === 'string') {
|
|
130
|
+
ev = { ...ev, message: normalizeMessage(ev.message) };
|
|
131
|
+
}
|
|
132
|
+
const target = formatInboundTarget(ev);
|
|
133
|
+
const nickname = senderNickname(ev);
|
|
134
|
+
const mentioned = isNapCatBotMentioned(ev);
|
|
135
|
+
void this.#options.gateway.receive({
|
|
136
|
+
adapter: this.#options.id,
|
|
137
|
+
target,
|
|
138
|
+
content: formatInboundContent(ev),
|
|
139
|
+
sender: senderUserId(ev),
|
|
140
|
+
id: msgId,
|
|
141
|
+
metadata: Object.freeze({
|
|
142
|
+
message_type: ev.message_type,
|
|
143
|
+
user_id: ev.user_id != null ? String(ev.user_id) : undefined,
|
|
144
|
+
group_id: ev.group_id != null ? String(ev.group_id) : undefined,
|
|
145
|
+
endpoint: this.#options.config.name,
|
|
146
|
+
time: ev.time,
|
|
147
|
+
self_id: ev.self_id != null ? String(ev.self_id) : undefined,
|
|
148
|
+
role: ev.sender?.role,
|
|
149
|
+
...(nickname ? { nickname } : {}),
|
|
150
|
+
...(mentioned ? { mentioned: true } : {}),
|
|
151
|
+
}),
|
|
152
|
+
}).catch((err) => {
|
|
153
|
+
logger.warn(formatCompact({
|
|
154
|
+
op: 'napcat_gateway_receive_failed',
|
|
155
|
+
target,
|
|
156
|
+
error: err instanceof Error ? err.message : String(err),
|
|
157
|
+
}));
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
#setupRoutes(): void {
|
|
162
|
+
const path = this.#options.config.post_path;
|
|
163
|
+
this.#routeReleases.push(
|
|
164
|
+
this.#options.http.route('POST', path, async (request, response) => {
|
|
165
|
+
await this.#handlePost(request, response);
|
|
166
|
+
}, { summary: 'NapCat HTTP event callback', tags: ['napcat'] }),
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
async #handlePost(request: IncomingMessage, response: ServerResponse): Promise<void> {
|
|
171
|
+
try {
|
|
172
|
+
if (!verifyNapCatAccessToken(this.#options.config.access_token, request)) {
|
|
173
|
+
response.writeHead(403, { 'Content-Type': 'application/json' });
|
|
174
|
+
response.end(JSON.stringify({ message: 'Unauthorized' }));
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
const raw = await readRequestBody(request);
|
|
178
|
+
let ev: NapCatEvent;
|
|
179
|
+
try {
|
|
180
|
+
ev = JSON.parse(raw) as NapCatEvent;
|
|
181
|
+
} catch {
|
|
182
|
+
response.writeHead(400, { 'Content-Type': 'application/json' });
|
|
183
|
+
response.end(JSON.stringify({ message: 'Invalid JSON' }));
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
if (this.#open) this.admit(ev);
|
|
187
|
+
response.writeHead(200, { 'Content-Type': 'application/json' });
|
|
188
|
+
response.end(JSON.stringify({ status: 'ok' }));
|
|
189
|
+
} catch (error) {
|
|
190
|
+
logger.error('NapCat HTTP webhook error:', error);
|
|
191
|
+
if (!response.headersSent) {
|
|
192
|
+
response.writeHead(500, { 'Content-Type': 'application/json' });
|
|
193
|
+
response.end(JSON.stringify({ message: 'Internal Server Error' }));
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,91 +1,76 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
type
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
31
|
+
export {
|
|
32
|
+
InboundMessageDeduper,
|
|
33
|
+
isNapCatBotMentioned,
|
|
34
|
+
isSelfMessage,
|
|
35
|
+
normalizeMessage,
|
|
36
|
+
} from './napcat-inbound.js';
|
|
30
37
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
-
|
|
44
|
-
const { provide, useContext } = plugin;
|
|
47
|
+
export { parseOneBotGetMsgResponse } from './onebot-get-msg.js';
|
|
45
48
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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
|
-
|
|
63
|
-
|
|
64
|
-
|
|
54
|
+
export {
|
|
55
|
+
NapCatWssEndpoint,
|
|
56
|
+
type NapCatWssEndpointOptions,
|
|
57
|
+
} from './wss-endpoint.js';
|
|
65
58
|
|
|
66
|
-
|
|
67
|
-
|
|
59
|
+
export {
|
|
60
|
+
NapCatHttpEndpoint,
|
|
61
|
+
type NapCatHttpEndpointOptions,
|
|
62
|
+
} from './http-endpoint.js';
|
|
68
63
|
|
|
69
|
-
|
|
70
|
-
napcat as unknown as ISceneManagement,
|
|
71
|
-
'napcat',
|
|
72
|
-
);
|
|
73
|
-
disposers.push(...sceneTools.map(t => toolService.addTool(t, plugin.name)));
|
|
64
|
+
export type { NapCatWsSocket, NapCatWsCreateOptions } from './ws-types.js';
|
|
74
65
|
|
|
75
|
-
|
|
76
|
-
|
|
66
|
+
export {
|
|
67
|
+
callNapCatWsAction,
|
|
68
|
+
decodeWsPayload,
|
|
69
|
+
handleNapCatWsMessage,
|
|
70
|
+
rejectAllPending,
|
|
71
|
+
startNapCatHeartbeat,
|
|
72
|
+
} from './ws-transport.js';
|
|
77
73
|
|
|
78
|
-
|
|
79
|
-
useContext('web', (pageManager) => {
|
|
80
|
-
pageManager.addEntry({
|
|
81
|
-
id: 'napcat',
|
|
82
|
-
development: path.resolve(import.meta.dirname, '../client/index.tsx'),
|
|
83
|
-
production: path.resolve(import.meta.dirname, '../dist/index.js'),
|
|
84
|
-
meta: { name: 'NapCat' },
|
|
85
|
-
});
|
|
86
|
-
});
|
|
74
|
+
export { verifyNapCatAccessToken } from './wss-auth.js';
|
|
87
75
|
|
|
88
|
-
|
|
89
|
-
useContext('router', 'napcat', async (router: Router, napcat: NapCatAdapter) => {
|
|
90
|
-
registerRoutes(router, napcat);
|
|
91
|
-
});
|
|
76
|
+
export { readRequestBody } from './webhook.js';
|
package/src/napcat-agent-deps.ts
CHANGED
|
@@ -1,29 +1,95 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Agent tool deps for napcat.
|
|
3
|
+
* Endpoints register themselves on start; tools look up by config name / endpoint id.
|
|
3
4
|
*/
|
|
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
|
+
}
|
|
5
56
|
|
|
6
57
|
export interface NapcatAgentDeps {
|
|
7
|
-
|
|
58
|
+
getEndpoint: (endpointId: string) => NapcatAgentEndpoint;
|
|
8
59
|
}
|
|
9
60
|
|
|
10
|
-
|
|
61
|
+
const endpoints = new Map<string, NapcatAgentEndpoint>();
|
|
62
|
+
let override: NapcatAgentDeps | null = null;
|
|
11
63
|
|
|
12
|
-
export function
|
|
13
|
-
|
|
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
|
+
};
|
|
14
74
|
}
|
|
15
75
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
76
|
+
/** Optional override used by tests / transitional callers. Pass `null` to clear. */
|
|
77
|
+
export function setNapcatAgentDeps(deps: NapcatAgentDeps | null): void {
|
|
78
|
+
override = deps;
|
|
19
79
|
}
|
|
20
80
|
|
|
21
|
-
|
|
22
|
-
|
|
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 };
|
|
23
90
|
}
|
|
24
91
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
return endpoint;
|
|
92
|
+
/** Convenience for agent/tools (unchanged call sites). */
|
|
93
|
+
export function getEndpoint(endpointId: string): NapcatAgentEndpoint {
|
|
94
|
+
return getNapcatAgentDeps().getEndpoint(endpointId);
|
|
29
95
|
}
|
package/src/napcat-inbound.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* NapCat 入站消息治理:去重、自发过滤、消息归一化
|
|
3
3
|
*/
|
|
4
|
-
import type { NapCatMessageEvent, MessageSegment } from './
|
|
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
|
|
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
|
-
*
|
|
59
|
+
* OneBot11 mentioned 判定:消息段 {type:'at', data:{qq}} 的 qq 等于本机 uin
|
|
60
|
+
* (事件 self_id)时为 true;`qq === 'all'` 不算。兼容 CQ 字符串形式。
|
|
49
61
|
*/
|
|
50
|
-
export function
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
if (
|
|
55
|
-
|
|
56
|
-
|
|
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
|
}
|
package/src/onebot-get-msg.ts
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
|
|
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
|
|
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
|
}
|