@zhin.js/adapter-napcat 1.1.0 → 1.1.3
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 +112 -0
- package/README.md +11 -8
- package/adapters/{napcat.js → napcat/index.js} +10 -10
- package/adapters/{napcat.ts → napcat/index.ts} +13 -13
- package/agents/napcat/agent.json +20 -0
- package/agents/napcat/boundaries.md +3 -0
- package/agents/napcat/conventions.md +3 -0
- package/agents/napcat/skills/napcat-account/SKILL.md +25 -0
- package/agents/napcat/skills/napcat-account/tools/delete_friend/index.js +18 -0
- package/{agent/tools/delete_friend.ts → agents/napcat/skills/napcat-account/tools/delete_friend/index.ts} +1 -1
- package/agents/napcat/skills/napcat-account/tools/get_user_status/index.js +16 -0
- package/{agent/tools/get_user_status.ts → agents/napcat/skills/napcat-account/tools/get_user_status/index.ts} +1 -1
- package/agents/napcat/skills/napcat-account/tools/send_like/index.js +18 -0
- package/{agent/tools/send_like.ts → agents/napcat/skills/napcat-account/tools/send_like/index.ts} +1 -1
- package/agents/napcat/skills/napcat-account/tools/set_avatar/index.js +17 -0
- package/{agent/tools/set_avatar.ts → agents/napcat/skills/napcat-account/tools/set_avatar/index.ts} +1 -1
- package/agents/napcat/skills/napcat-account/tools/set_online_status/index.js +18 -0
- package/{agent/tools/set_online_status.ts → agents/napcat/skills/napcat-account/tools/set_online_status/index.ts} +1 -1
- package/agents/napcat/skills/napcat-account/tools/set_profile/index.js +21 -0
- package/{agent/tools/set_profile.ts → agents/napcat/skills/napcat-account/tools/set_profile/index.ts} +1 -1
- package/agents/napcat/skills/napcat-account/tools/set_signature/index.js +17 -0
- package/{agent/tools/set_signature.ts → agents/napcat/skills/napcat-account/tools/set_signature/index.ts} +1 -1
- package/agents/napcat/skills/napcat-files-history/SKILL.md +22 -0
- package/agents/napcat/skills/napcat-files-history/tools/download_file/index.js +17 -0
- package/{agent/tools/download_file.ts → agents/napcat/skills/napcat-files-history/tools/download_file/index.ts} +1 -1
- package/agents/napcat/skills/napcat-files-history/tools/get_friend_msg_history/index.js +18 -0
- package/{agent/tools/get_friend_msg_history.ts → agents/napcat/skills/napcat-files-history/tools/get_friend_msg_history/index.ts} +1 -1
- package/agents/napcat/skills/napcat-files-history/tools/get_group_file_url/index.js +19 -0
- package/{agent/tools/get_group_file_url.ts → agents/napcat/skills/napcat-files-history/tools/get_group_file_url/index.ts} +1 -1
- package/agents/napcat/skills/napcat-files-history/tools/get_group_msg_history/index.js +19 -0
- package/{agent/tools/get_group_msg_history.ts → agents/napcat/skills/napcat-files-history/tools/get_group_msg_history/index.ts} +1 -1
- package/agents/napcat/skills/napcat-files-history/tools/get_group_root_files/index.js +17 -0
- package/{agent/tools/get_group_root_files.ts → agents/napcat/skills/napcat-files-history/tools/get_group_root_files/index.ts} +1 -1
- package/agents/napcat/skills/napcat-files-history/tools/upload_group_file/index.js +21 -0
- package/{agent/tools/upload_group_file.ts → agents/napcat/skills/napcat-files-history/tools/upload_group_file/index.ts} +1 -1
- package/agents/napcat/skills/napcat-group-content/SKILL.md +21 -0
- package/agents/napcat/skills/napcat-group-content/tools/del_group_notice/index.js +20 -0
- package/{agent/tools/del_group_notice.ts → agents/napcat/skills/napcat-group-content/tools/del_group_notice/index.ts} +1 -1
- package/agents/napcat/skills/napcat-group-content/tools/delete_essence_msg/index.js +19 -0
- package/{agent/tools/delete_essence_msg.ts → agents/napcat/skills/napcat-group-content/tools/delete_essence_msg/index.ts} +1 -1
- package/agents/napcat/skills/napcat-group-content/tools/get_essence_list/index.js +17 -0
- package/{agent/tools/get_essence_list.ts → agents/napcat/skills/napcat-group-content/tools/get_essence_list/index.ts} +1 -1
- package/agents/napcat/skills/napcat-group-content/tools/get_group_notice/index.js +17 -0
- package/{agent/tools/get_group_notice.ts → agents/napcat/skills/napcat-group-content/tools/get_group_notice/index.ts} +1 -1
- package/agents/napcat/skills/napcat-group-content/tools/send_group_notice/index.js +21 -0
- package/{agent/tools/send_group_notice.ts → agents/napcat/skills/napcat-group-content/tools/send_group_notice/index.ts} +1 -1
- package/agents/napcat/skills/napcat-group-content/tools/set_essence_msg/index.js +19 -0
- package/{agent/tools/set_essence_msg.ts → agents/napcat/skills/napcat-group-content/tools/set_essence_msg/index.ts} +1 -1
- package/agents/napcat/skills/napcat-group-settings/SKILL.md +23 -0
- package/agents/napcat/skills/napcat-group-settings/tools/get_group_info_ex/index.js +17 -0
- package/{agent/tools/get_group_info_ex.ts → agents/napcat/skills/napcat-group-settings/tools/get_group_info_ex/index.ts} +1 -1
- package/agents/napcat/skills/napcat-group-settings/tools/get_group_shut_list/index.js +17 -0
- package/{agent/tools/get_group_shut_list.ts → agents/napcat/skills/napcat-group-settings/tools/get_group_shut_list/index.ts} +1 -1
- package/agents/napcat/skills/napcat-group-settings/tools/group_sign/index.js +18 -0
- package/{agent/tools/group_sign.ts → agents/napcat/skills/napcat-group-settings/tools/group_sign/index.ts} +1 -1
- package/agents/napcat/skills/napcat-group-settings/tools/set_group_portrait/index.js +20 -0
- package/{agent/tools/set_group_portrait.ts → agents/napcat/skills/napcat-group-settings/tools/set_group_portrait/index.ts} +1 -1
- package/agents/napcat/skills/napcat-group-settings/tools/set_title/index.js +21 -0
- package/{agent/tools/set_title.ts → agents/napcat/skills/napcat-group-settings/tools/set_title/index.ts} +1 -1
- package/agents/napcat/skills/napcat-media/SKILL.md +23 -0
- package/agents/napcat/skills/napcat-media/tools/ai_tts/index.js +19 -0
- package/{agent/tools/ai_tts.ts → agents/napcat/skills/napcat-media/tools/ai_tts/index.ts} +1 -1
- package/agents/napcat/skills/napcat-media/tools/get_ai_characters/index.js +17 -0
- package/{agent/tools/get_ai_characters.ts → agents/napcat/skills/napcat-media/tools/get_ai_characters/index.ts} +1 -1
- package/agents/napcat/skills/napcat-media/tools/get_mini_app_ark/index.js +20 -0
- package/{agent/tools/get_mini_app_ark.ts → agents/napcat/skills/napcat-media/tools/get_mini_app_ark/index.ts} +1 -1
- package/agents/napcat/skills/napcat-media/tools/ocr_image/index.js +16 -0
- package/{agent/tools/ocr_image.ts → agents/napcat/skills/napcat-media/tools/ocr_image/index.ts} +1 -1
- package/agents/napcat/skills/napcat-media/tools/translate/index.js +16 -0
- package/{agent/tools/translate.ts → agents/napcat/skills/napcat-media/tools/translate/index.ts} +1 -1
- package/agents/napcat/skills/napcat-messaging/SKILL.md +22 -0
- package/agents/napcat/skills/napcat-messaging/tools/forward_single_msg/index.js +22 -0
- package/{agent/tools/forward_single_msg.ts → agents/napcat/skills/napcat-messaging/tools/forward_single_msg/index.ts} +1 -1
- package/agents/napcat/skills/napcat-messaging/tools/mark_msg_as_read/index.js +17 -0
- package/{agent/tools/mark_msg_as_read.ts → agents/napcat/skills/napcat-messaging/tools/mark_msg_as_read/index.ts} +1 -1
- package/agents/napcat/skills/napcat-messaging/tools/send_forward_msg/index.js +19 -0
- package/{agent/tools/send_forward_msg.ts → agents/napcat/skills/napcat-messaging/tools/send_forward_msg/index.ts} +1 -1
- package/agents/napcat/skills/napcat-messaging/tools/send_poke/index.js +18 -0
- package/{agent/tools/send_poke.ts → agents/napcat/skills/napcat-messaging/tools/send_poke/index.ts} +1 -1
- package/agents/napcat/skills/napcat-messaging/tools/set_emoji_reaction/index.js +18 -0
- package/{agent/tools/set_emoji_reaction.ts → agents/napcat/skills/napcat-messaging/tools/set_emoji_reaction/index.ts} +1 -1
- package/agents/napcat/system.md +3 -0
- package/commands/{endpoint/add/[id].js → napcat/endpoint/add/[id]/index.js} +1 -1
- package/commands/napcat/endpoint/add/[id]/index.ts +3 -0
- package/{lib/napcat-endpoint-commands.js → commands/napcat/endpoint/definition.js} +4 -3
- package/{src/napcat-endpoint-commands.ts → commands/napcat/endpoint/definition.ts} +3 -3
- package/commands/{endpoint/list.js → napcat/endpoint/list/index.js} +1 -1
- package/commands/napcat/endpoint/list/index.ts +3 -0
- package/commands/{endpoint/remove/[id].js → napcat/endpoint/remove/[id]/index.js} +1 -1
- package/commands/napcat/endpoint/remove/[id]/index.ts +3 -0
- package/lib/index.d.ts +1 -1
- package/lib/napcat-runtime-state.js +1 -1
- package/lib/protocol.d.ts +5 -23
- package/lib/protocol.js +40 -27
- package/lib/wss-endpoint.d.ts +3 -0
- package/lib/wss-endpoint.js +51 -42
- package/package.json +33 -21
- package/schema.json +22 -1
- package/src/index.ts +0 -1
- package/src/napcat-runtime-state.ts +1 -1
- package/src/protocol.ts +47 -50
- package/src/wss-endpoint.ts +48 -43
- package/agent/skills/napcat.md +0 -311
- package/commands/endpoint/add/[id].ts +0 -3
- package/commands/endpoint/list.ts +0 -3
- package/commands/endpoint/remove/[id].ts +0 -3
- package/lib/napcat-endpoint-commands.d.ts +0 -1
- /package/{agent/PERMITS.md → PERMITS.md} +0 -0
|
@@ -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
|
+
export default defineAgentTool({
|
|
5
|
+
description: '发送合并转发消息(群聊或私聊)。messages 为转发节点数组。',
|
|
6
|
+
inputSchema: z.object({
|
|
7
|
+
message_type: z.enum(['private', 'group']).describe('private 或 group'),
|
|
8
|
+
id: z.number().describe('群号或 QQ 号'),
|
|
9
|
+
messages: z.string().describe('转发节点 JSON(node 数组)'),
|
|
10
|
+
}),
|
|
11
|
+
adapter: 'napcat',
|
|
12
|
+
tags: ['napcat', 'qq'],
|
|
13
|
+
keywords: ['合并转发', 'forward', '转发消息'],
|
|
14
|
+
async execute({ message_type, id, messages }, context) {
|
|
15
|
+
const endpoint = context.$client;
|
|
16
|
+
const nodes = typeof messages === 'string' ? JSON.parse(messages) : messages;
|
|
17
|
+
return endpoint.sendForwardMsg(message_type, id, nodes);
|
|
18
|
+
},
|
|
19
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
+
import { defineAgentTool } from '@zhin.js/tool';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
export default defineAgentTool({
|
|
5
|
+
description: '戳一戳(群聊或私聊)。group_id 不传时为私聊戳一戳。',
|
|
6
|
+
inputSchema: z.object({
|
|
7
|
+
user_id: z.number().describe('目标用户 QQ 号'),
|
|
8
|
+
group_id: z.number().optional().describe('群号(不传则为私聊戳一戳)'),
|
|
9
|
+
}),
|
|
10
|
+
adapter: 'napcat',
|
|
11
|
+
tags: ['napcat', 'qq'],
|
|
12
|
+
keywords: ['戳一戳', 'poke', '戳', '拍一拍'],
|
|
13
|
+
async execute({ user_id, group_id }, context) {
|
|
14
|
+
const endpoint = context.$client;
|
|
15
|
+
await endpoint.sendPoke(user_id, group_id);
|
|
16
|
+
return { success: true, message: `已戳 ${user_id}` };
|
|
17
|
+
},
|
|
18
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
+
import { defineAgentTool } from '@zhin.js/tool';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
export default defineAgentTool({
|
|
5
|
+
description: '为消息添加表情回应(贴表情)。',
|
|
6
|
+
inputSchema: z.object({
|
|
7
|
+
message_id: z.number().describe('消息 ID'),
|
|
8
|
+
emoji_id: z.string().describe('表情 ID'),
|
|
9
|
+
}),
|
|
10
|
+
adapter: 'napcat',
|
|
11
|
+
tags: ['napcat', 'qq'],
|
|
12
|
+
keywords: ['表情回应', 'reaction', '贴表情', 'emoji'],
|
|
13
|
+
async execute({ message_id, emoji_id }, context) {
|
|
14
|
+
const endpoint = context.$client;
|
|
15
|
+
await endpoint.setMsgEmojiLike(message_id, emoji_id);
|
|
16
|
+
return { success: true };
|
|
17
|
+
},
|
|
18
|
+
});
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
1
2
|
/**
|
|
2
|
-
* `napcat
|
|
3
|
-
* commands/endpoint/ 下的 list / add / remove 直接默认导出这三项。
|
|
3
|
+
* `napcat endpoint` 命令族:由 @zhin.js/adapter 的 createEndpointCommands 套件生成。
|
|
4
|
+
* commands/napcat/endpoint/ 下的 list / add / remove 直接默认导出这三项。
|
|
4
5
|
*/
|
|
5
6
|
import { createEndpointCommands } from 'zhin.js/adapter';
|
|
6
7
|
import { defineCommand } from 'zhin.js/command';
|
|
7
|
-
import { napcatRuntimeStateToken } from
|
|
8
|
+
import { napcatRuntimeStateToken } from "../../../lib/napcat-runtime-state.js";
|
|
8
9
|
export const napcatEndpointCommands = createEndpointCommands({
|
|
9
10
|
adapterKey: 'napcat',
|
|
10
11
|
adapterDisplayName: 'NapCat',
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `napcat
|
|
3
|
-
* commands/endpoint/ 下的 list / add / remove 直接默认导出这三项。
|
|
2
|
+
* `napcat endpoint` 命令族:由 @zhin.js/adapter 的 createEndpointCommands 套件生成。
|
|
3
|
+
* commands/napcat/endpoint/ 下的 list / add / remove 直接默认导出这三项。
|
|
4
4
|
*/
|
|
5
5
|
import { createEndpointCommands } from 'zhin.js/adapter';
|
|
6
6
|
import { defineCommand } from 'zhin.js/command';
|
|
7
|
-
import { napcatRuntimeStateToken } from '
|
|
7
|
+
import { napcatRuntimeStateToken } from '../../../src/napcat-runtime-state.js';
|
|
8
8
|
|
|
9
9
|
export const napcatEndpointCommands = createEndpointCommands({
|
|
10
10
|
adapterKey: 'napcat',
|
package/lib/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { buildSendAction, buildWsConnectOptions, callNapCatHttpAction, formatInboundContent, formatOutboundSegments, getChannelId, isMessageEvent, mediaRefToOneBotFile, napcatInboundConversation, napcatOutboundTarget, resolveNapCatConfig, senderNickname, senderUserId, type MessageSegment, type NapCatActionRequest, type NapCatActionResponse, type
|
|
1
|
+
export { buildSendAction, buildWsConnectOptions, callNapCatHttpAction, formatInboundContent, formatOutboundSegments, getChannelId, isMessageEvent, mediaRefToOneBotFile, napcatInboundConversation, napcatOutboundTarget, resolveNapCatConfig, senderNickname, senderUserId, type MessageSegment, type NapCatActionRequest, type NapCatActionResponse, type NapCatConfigBase, type NapCatEndpointConfig, type NapCatEvent, type NapCatHttpConfig, type NapCatMessageEvent, type NapCatSender, type NapCatWireSegment, type NapCatWsConfig, type NapCatWssConfig, type ParsedSendTarget, type ResolvedNapCatConfig, } from './protocol.js';
|
|
2
2
|
export { InboundMessageDeduper, isNapCatBotMentioned, isSelfMessage, normalizeMessage, } from './napcat-inbound.js';
|
|
3
3
|
export { napcatClient, type NapcatClient, type NapcatClientEventMap, } from './client.js';
|
|
4
4
|
export { parseOneBotGetMsgResponse } from './onebot-get-msg.js';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* NapCat 插件实例的运行时状态:adapter create() 注册的 endpoint 列表。
|
|
3
|
-
* 由 plugin.ts setup() provide,adapter create 与 `napcat
|
|
3
|
+
* 由 plugin.ts setup() provide,adapter create 与 `napcat endpoint` 命令共享(同一 owner generation)。
|
|
4
4
|
*/
|
|
5
5
|
import { defineEndpointRuntimeStateToken } from 'zhin.js/adapter';
|
|
6
6
|
export const napcatRuntimeStateToken = defineEndpointRuntimeStateToken('napcat');
|
package/lib/protocol.d.ts
CHANGED
|
@@ -3,26 +3,11 @@
|
|
|
3
3
|
* No legacy Adapter/Endpoint / segment-mapper.
|
|
4
4
|
* Canonicalization is owned by gateway/core before endpoint.send.
|
|
5
5
|
*/
|
|
6
|
-
import { type MediaRef } from '@zhin.js/
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
export interface NapCatLegacyEndpointRow {
|
|
10
|
-
readonly context?: string;
|
|
6
|
+
import { type MediaRef, type ConversationRef } from '@zhin.js/im-contract';
|
|
7
|
+
/** One endpoint config after AdapterIndex expands `plugins.<instanceKey>.endpoints`. */
|
|
8
|
+
export interface NapCatEndpointConfig {
|
|
11
9
|
readonly connection?: 'ws' | 'wss' | 'http';
|
|
12
|
-
readonly id
|
|
13
|
-
readonly access_token?: string;
|
|
14
|
-
readonly url?: string;
|
|
15
|
-
readonly path?: string;
|
|
16
|
-
readonly http_url?: string;
|
|
17
|
-
readonly post_path?: string;
|
|
18
|
-
readonly reconnect_interval?: number;
|
|
19
|
-
readonly heartbeat_interval?: number;
|
|
20
|
-
readonly poll_interval?: number;
|
|
21
|
-
}
|
|
22
|
-
/** Plugin Runtime owner config (`plugins.<instanceKey>` / schema.json). */
|
|
23
|
-
export interface NapCatAdapterConfig {
|
|
24
|
-
readonly connection?: 'ws' | 'wss' | 'http';
|
|
25
|
-
readonly id?: string;
|
|
10
|
+
readonly id: string;
|
|
26
11
|
readonly access_token?: string;
|
|
27
12
|
readonly url?: string;
|
|
28
13
|
readonly path?: string;
|
|
@@ -31,8 +16,6 @@ export interface NapCatAdapterConfig {
|
|
|
31
16
|
readonly reconnect_interval?: number;
|
|
32
17
|
readonly heartbeat_interval?: number;
|
|
33
18
|
readonly poll_interval?: number;
|
|
34
|
-
/** Transitional: legacy root `endpoints[]` with `context: napcat`. */
|
|
35
|
-
readonly endpoints?: ReadonlyArray<NapCatLegacyEndpointRow>;
|
|
36
19
|
}
|
|
37
20
|
export interface NapCatConfigBase {
|
|
38
21
|
readonly context: 'napcat';
|
|
@@ -60,7 +43,6 @@ export interface NapCatHttpConfig extends NapCatConfigBase {
|
|
|
60
43
|
readonly poll_interval: number;
|
|
61
44
|
}
|
|
62
45
|
export type ResolvedNapCatConfig = NapCatWsConfig | NapCatWssConfig | NapCatHttpConfig;
|
|
63
|
-
export type NapCatEndpointConfig = ResolvedNapCatConfig;
|
|
64
46
|
export interface NapCatSender {
|
|
65
47
|
readonly role?: string;
|
|
66
48
|
readonly nickname?: string;
|
|
@@ -114,7 +96,7 @@ export interface ParsedSendTarget {
|
|
|
114
96
|
readonly message_type: 'private' | 'group';
|
|
115
97
|
readonly id: string;
|
|
116
98
|
}
|
|
117
|
-
export declare function resolveNapCatConfig(config
|
|
99
|
+
export declare function resolveNapCatConfig(config: NapCatEndpointConfig): ResolvedNapCatConfig;
|
|
118
100
|
export declare function isMessageEvent(ev: NapCatEvent): ev is NapCatMessageEvent;
|
|
119
101
|
export declare function getChannelId(ev: NapCatEvent): string;
|
|
120
102
|
/**
|
package/lib/protocol.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* No legacy Adapter/Endpoint / segment-mapper.
|
|
4
4
|
* Canonicalization is owned by gateway/core before endpoint.send.
|
|
5
5
|
*/
|
|
6
|
-
import { isMediaRef } from '@zhin.js/
|
|
6
|
+
import { isMediaRef } from '@zhin.js/im-contract';
|
|
7
7
|
import { formatCompact, getLogger } from '@zhin.js/logger';
|
|
8
8
|
const logger = getLogger('napcat');
|
|
9
9
|
function normalizeConnection(connection) {
|
|
@@ -11,48 +11,36 @@ function normalizeConnection(connection) {
|
|
|
11
11
|
return connection;
|
|
12
12
|
return 'ws';
|
|
13
13
|
}
|
|
14
|
-
export function resolveNapCatConfig(config
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
|| (typeof entry?.id === 'string' && entry.id)
|
|
19
|
-
|| process.env.NAPCAT_BOT_NAME
|
|
20
|
-
|| 'napcat-bot';
|
|
21
|
-
const access_token = config.access_token ?? entry?.access_token;
|
|
14
|
+
export function resolveNapCatConfig(config) {
|
|
15
|
+
const connection = normalizeConnection(config.connection);
|
|
16
|
+
const id = requiredEndpointField(config.id, 'id');
|
|
17
|
+
const access_token = optionalEndpointField(config.access_token);
|
|
22
18
|
if (connection === 'ws') {
|
|
23
|
-
const url = config.url
|
|
24
|
-
if (!url) {
|
|
25
|
-
throw new TypeError('NapCat connection:ws requires url (plugins.<key>.url or endpoints with context: napcat)');
|
|
26
|
-
}
|
|
19
|
+
const url = requiredEndpointField(config.url, 'url');
|
|
27
20
|
return {
|
|
28
21
|
context: 'napcat',
|
|
29
22
|
connection: 'ws',
|
|
30
23
|
id,
|
|
31
24
|
access_token,
|
|
32
25
|
url,
|
|
33
|
-
reconnect_interval: config.reconnect_interval ??
|
|
34
|
-
heartbeat_interval: config.heartbeat_interval ??
|
|
26
|
+
reconnect_interval: config.reconnect_interval ?? 5000,
|
|
27
|
+
heartbeat_interval: config.heartbeat_interval ?? 30_000,
|
|
35
28
|
};
|
|
36
29
|
}
|
|
37
30
|
if (connection === 'wss') {
|
|
38
|
-
const path = config.path
|
|
39
|
-
if (!path)
|
|
40
|
-
throw new TypeError('NapCat connection:wss requires path');
|
|
31
|
+
const path = requiredEndpointField(config.path, 'path');
|
|
41
32
|
return {
|
|
42
33
|
context: 'napcat',
|
|
43
34
|
connection: 'wss',
|
|
44
35
|
id,
|
|
45
36
|
access_token,
|
|
46
37
|
path,
|
|
47
|
-
heartbeat_interval: config.heartbeat_interval ??
|
|
38
|
+
heartbeat_interval: config.heartbeat_interval ?? 30_000,
|
|
48
39
|
};
|
|
49
40
|
}
|
|
50
41
|
if (connection === 'http') {
|
|
51
|
-
const http_url = config.http_url
|
|
52
|
-
const post_path = config.post_path
|
|
53
|
-
if (!http_url || !post_path) {
|
|
54
|
-
throw new TypeError('NapCat connection:http requires http_url and post_path');
|
|
55
|
-
}
|
|
42
|
+
const http_url = requiredEndpointField(config.http_url, 'http_url');
|
|
43
|
+
const post_path = requiredEndpointField(config.post_path, 'post_path');
|
|
56
44
|
return {
|
|
57
45
|
context: 'napcat',
|
|
58
46
|
connection: 'http',
|
|
@@ -60,11 +48,21 @@ export function resolveNapCatConfig(config = {}) {
|
|
|
60
48
|
access_token,
|
|
61
49
|
http_url,
|
|
62
50
|
post_path,
|
|
63
|
-
poll_interval: config.poll_interval ??
|
|
51
|
+
poll_interval: config.poll_interval ?? 30_000,
|
|
64
52
|
};
|
|
65
53
|
}
|
|
66
54
|
throw new TypeError(`Unknown NapCat connection: ${String(connection)}`);
|
|
67
55
|
}
|
|
56
|
+
function requiredEndpointField(value, field) {
|
|
57
|
+
const resolved = optionalEndpointField(value);
|
|
58
|
+
if (!resolved) {
|
|
59
|
+
throw new TypeError(`NapCat endpoint requires a non-empty ${field}`);
|
|
60
|
+
}
|
|
61
|
+
return resolved;
|
|
62
|
+
}
|
|
63
|
+
function optionalEndpointField(value) {
|
|
64
|
+
return typeof value === 'string' && value.trim() ? value.trim() : undefined;
|
|
65
|
+
}
|
|
68
66
|
export function isMessageEvent(ev) {
|
|
69
67
|
return (ev.post_type === 'message' || ev.post_type === 'message_sent')
|
|
70
68
|
&& ev.message_id != null;
|
|
@@ -112,11 +110,26 @@ export function formatInboundContent(ev) {
|
|
|
112
110
|
.join('');
|
|
113
111
|
}
|
|
114
112
|
if (typeof ev.message === 'string')
|
|
115
|
-
return ev.message
|
|
113
|
+
return stripCqCodes(ev.message).trim();
|
|
116
114
|
return typeof ev.raw_message === 'string'
|
|
117
|
-
? ev.raw_message
|
|
115
|
+
? stripCqCodes(ev.raw_message).trim()
|
|
118
116
|
: '';
|
|
119
117
|
}
|
|
118
|
+
function stripCqCodes(input) {
|
|
119
|
+
let result = '';
|
|
120
|
+
let cursor = 0;
|
|
121
|
+
while (cursor < input.length) {
|
|
122
|
+
const start = input.indexOf('[CQ:', cursor);
|
|
123
|
+
if (start < 0)
|
|
124
|
+
return result + input.slice(cursor);
|
|
125
|
+
result += input.slice(cursor, start);
|
|
126
|
+
const end = input.indexOf(']', start + 4);
|
|
127
|
+
if (end < 0)
|
|
128
|
+
return result + input.slice(start);
|
|
129
|
+
cursor = end + 1;
|
|
130
|
+
}
|
|
131
|
+
return result;
|
|
132
|
+
}
|
|
120
133
|
/**
|
|
121
134
|
* 入站 sender 语义:必须是用户 ID(Runtime Message contract)。
|
|
122
135
|
* 显示名走 metadata.nickname,见 senderNickname。
|
package/lib/wss-endpoint.d.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { Endpoint } from 'zhin.js/adapter';
|
|
2
|
+
/**
|
|
3
|
+
* NapCat reverse WSS endpoint — accepts inbound WebSocket from NapCat.
|
|
4
|
+
*/
|
|
2
5
|
import { type EndpointControl, type EndpointManagement, type EndpointSendRequest } from 'zhin.js/adapter';
|
|
3
6
|
import type { HttpHost } from '@zhin.js/host-http';
|
|
4
7
|
import type { CapabilityId } from 'zhin.js';
|
package/lib/wss-endpoint.js
CHANGED
|
@@ -2,8 +2,7 @@ import { Endpoint } from 'zhin.js/adapter';
|
|
|
2
2
|
/**
|
|
3
3
|
* NapCat reverse WSS endpoint — accepts inbound WebSocket from NapCat.
|
|
4
4
|
*/
|
|
5
|
-
import {
|
|
6
|
-
import { createRecallEndpointControl, } from 'zhin.js/adapter';
|
|
5
|
+
import { createEndpointLifecycle, createRecallEndpointControl, } from 'zhin.js/adapter';
|
|
7
6
|
import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
|
|
8
7
|
import { createNapCatEndpointManagement } from './endpoint-management.js';
|
|
9
8
|
import { InboundMessageDeduper, isNapCatBotMentioned, isSelfMessage, normalizeMessage, } from './napcat-inbound.js';
|
|
@@ -11,7 +10,7 @@ import { buildSendAction, formatInboundContent, formatOutboundSegments, isMessag
|
|
|
11
10
|
import { receiveNapCatSideEvent } from './side-event-dispatch.js';
|
|
12
11
|
import { createNapCatContentPort } from './onebot-get-msg.js';
|
|
13
12
|
import { NapcatClient } from './client.js';
|
|
14
|
-
import { callNapCatWsAction, handleNapCatWsMessage, rejectAllPending,
|
|
13
|
+
import { callNapCatWsAction, handleNapCatWsMessage, rejectAllPending, } from './ws-transport.js';
|
|
15
14
|
import { verifyNapCatAccessToken } from './wss-auth.js';
|
|
16
15
|
export class NapCatWssEndpoint extends Endpoint {
|
|
17
16
|
client = new NapcatClient((action, params) => this.#callApi(action, params));
|
|
@@ -21,9 +20,10 @@ export class NapCatWssEndpoint extends Endpoint {
|
|
|
21
20
|
management = createNapCatEndpointManagement(this.client);
|
|
22
21
|
control = createRecallEndpointControl((id) => this.recallMessage(id));
|
|
23
22
|
content = createNapCatContentPort((action, params) => this.client.callApi(action, params));
|
|
23
|
+
#connectionLifecycle;
|
|
24
24
|
#ws;
|
|
25
25
|
#wsRelease;
|
|
26
|
-
#
|
|
26
|
+
#connectionTask = Promise.resolve();
|
|
27
27
|
#requestId = { value: 0 };
|
|
28
28
|
#pending = new Map();
|
|
29
29
|
#open = false;
|
|
@@ -32,6 +32,10 @@ export class NapCatWssEndpoint extends Endpoint {
|
|
|
32
32
|
super();
|
|
33
33
|
this.#logger = getAdapterLogger('napcat', options.config.id);
|
|
34
34
|
this.#options = options;
|
|
35
|
+
this.#connectionLifecycle = createEndpointLifecycle({
|
|
36
|
+
name: `${options.config.id}:inbound`,
|
|
37
|
+
reconnect: false,
|
|
38
|
+
});
|
|
35
39
|
}
|
|
36
40
|
async start() {
|
|
37
41
|
if (this.#started)
|
|
@@ -39,7 +43,15 @@ export class NapCatWssEndpoint extends Endpoint {
|
|
|
39
43
|
this.#started = true;
|
|
40
44
|
const handle = this.#options.http.ws(this.#options.config.path);
|
|
41
45
|
this.#wsRelease = handle.onConnection((connection) => {
|
|
42
|
-
this.#
|
|
46
|
+
this.#connectionTask = this.#connectionTask
|
|
47
|
+
.then(() => this.#acceptConnection(connection))
|
|
48
|
+
.catch((error) => {
|
|
49
|
+
this.#logger.warn(formatCompact({
|
|
50
|
+
op: 'wss_connection_failed',
|
|
51
|
+
endpoint: this.#options.config.id,
|
|
52
|
+
error: error instanceof Error ? error.message : String(error),
|
|
53
|
+
}));
|
|
54
|
+
});
|
|
43
55
|
});
|
|
44
56
|
this.#logger.info(formatCompact({
|
|
45
57
|
op: 'listen',
|
|
@@ -58,21 +70,11 @@ export class NapCatWssEndpoint extends Endpoint {
|
|
|
58
70
|
this.#open = false;
|
|
59
71
|
this.#wsRelease?.();
|
|
60
72
|
this.#wsRelease = undefined;
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
this.#heartbeatTimer = undefined;
|
|
64
|
-
}
|
|
73
|
+
await this.#connectionTask;
|
|
74
|
+
await this.#connectionLifecycle.stop();
|
|
65
75
|
rejectAllPending(this.#pending);
|
|
66
76
|
this.#inboundDeduper.clear();
|
|
67
|
-
|
|
68
|
-
try {
|
|
69
|
-
this.#ws.close();
|
|
70
|
-
}
|
|
71
|
-
catch {
|
|
72
|
-
/* ignore */
|
|
73
|
-
}
|
|
74
|
-
this.#ws = undefined;
|
|
75
|
-
}
|
|
77
|
+
this.#ws = undefined;
|
|
76
78
|
this.#started = false;
|
|
77
79
|
}
|
|
78
80
|
async send({ conversation, payload }) {
|
|
@@ -141,37 +143,44 @@ export class NapCatWssEndpoint extends Endpoint {
|
|
|
141
143
|
}));
|
|
142
144
|
});
|
|
143
145
|
}
|
|
144
|
-
#acceptConnection(connection) {
|
|
146
|
+
async #acceptConnection(connection) {
|
|
145
147
|
if (!verifyNapCatAccessToken(this.#options.config.access_token, connection.request)) {
|
|
146
148
|
connection.socket.close(4003, 'Unauthorized');
|
|
147
149
|
return;
|
|
148
150
|
}
|
|
149
151
|
const socket = connection.socket;
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
socket.on('message', (data) => {
|
|
161
|
-
handleNapCatWsMessage(data, {
|
|
162
|
-
endpointId: this.#options.config.id,
|
|
163
|
-
pending: this.#pending,
|
|
164
|
-
admit: (event) => this.admit(event),
|
|
152
|
+
await this.#connectionLifecycle.stop();
|
|
153
|
+
await this.#connectionLifecycle.start(async (lifecycleHandle) => {
|
|
154
|
+
this.#ws = socket;
|
|
155
|
+
lifecycleHandle.onForceClose(() => {
|
|
156
|
+
try {
|
|
157
|
+
socket.close();
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
/* ignore */
|
|
161
|
+
}
|
|
165
162
|
});
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
this.#heartbeatTimer = undefined;
|
|
163
|
+
this.#connectionLifecycle.startHeartbeat(() => {
|
|
164
|
+
try {
|
|
165
|
+
socket.ping?.();
|
|
166
|
+
}
|
|
167
|
+
catch {
|
|
168
|
+
/* ignore */
|
|
173
169
|
}
|
|
174
|
-
}
|
|
170
|
+
}, this.#options.config.heartbeat_interval);
|
|
171
|
+
socket.on('message', (data) => {
|
|
172
|
+
this.#connectionLifecycle.notifyHeartbeatAck();
|
|
173
|
+
handleNapCatWsMessage(data, {
|
|
174
|
+
endpointId: this.#options.config.id,
|
|
175
|
+
pending: this.#pending,
|
|
176
|
+
admit: (event) => this.admit(event),
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
socket.on('close', () => {
|
|
180
|
+
if (this.#ws === socket)
|
|
181
|
+
this.#ws = undefined;
|
|
182
|
+
lifecycleHandle.notifyClosed(new Error('NapCat reverse WebSocket closed'));
|
|
183
|
+
});
|
|
175
184
|
});
|
|
176
185
|
this.#logger.debug(formatCompact({
|
|
177
186
|
endpoint: this.#options.config.id,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/adapter-napcat",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.3",
|
|
4
4
|
"description": "Zhin.js NapCat adapter for Plugin Runtime (WebSocket client, OneBot11 + NapCat extensions)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -19,9 +19,11 @@
|
|
|
19
19
|
"schema.json",
|
|
20
20
|
"src",
|
|
21
21
|
"lib",
|
|
22
|
-
"
|
|
22
|
+
"tools",
|
|
23
|
+
"agents",
|
|
23
24
|
"README.md",
|
|
24
|
-
"CHANGELOG.md"
|
|
25
|
+
"CHANGELOG.md",
|
|
26
|
+
"PERMITS.md"
|
|
25
27
|
],
|
|
26
28
|
"keywords": [
|
|
27
29
|
"zhin",
|
|
@@ -43,13 +45,16 @@
|
|
|
43
45
|
},
|
|
44
46
|
"dependencies": {
|
|
45
47
|
"ws": "^8.21.1",
|
|
46
|
-
"@zhin.js/adapter": "1.1.
|
|
47
|
-
"@zhin.js/
|
|
48
|
-
"@zhin.js/
|
|
49
|
-
"@zhin.js/
|
|
50
|
-
"@zhin.js/
|
|
51
|
-
"@zhin.js/
|
|
52
|
-
"@zhin.js/
|
|
48
|
+
"@zhin.js/adapter": "1.1.15",
|
|
49
|
+
"@zhin.js/agent-feature": "1.1.2",
|
|
50
|
+
"@zhin.js/core": "1.1.38",
|
|
51
|
+
"@zhin.js/feature-kit": "1.1.2",
|
|
52
|
+
"@zhin.js/host-http": "1.1.2",
|
|
53
|
+
"@zhin.js/im-contract": "1.1.2",
|
|
54
|
+
"@zhin.js/logger": "1.1.1",
|
|
55
|
+
"@zhin.js/permission": "1.1.2",
|
|
56
|
+
"@zhin.js/skill": "1.1.2",
|
|
57
|
+
"@zhin.js/tool": "1.1.2"
|
|
53
58
|
},
|
|
54
59
|
"devDependencies": {
|
|
55
60
|
"@types/node": "^26.1.2",
|
|
@@ -57,22 +62,17 @@
|
|
|
57
62
|
"typescript": "^6.0.3",
|
|
58
63
|
"vitest": "^4.1.10",
|
|
59
64
|
"zod": "^4.4.3",
|
|
60
|
-
"@zhin.js/
|
|
61
|
-
"
|
|
62
|
-
"zhin.js": "1.1.0"
|
|
65
|
+
"@zhin.js/host-http": "1.1.2",
|
|
66
|
+
"zhin.js": "1.1.3"
|
|
63
67
|
},
|
|
64
68
|
"peerDependencies": {
|
|
65
69
|
"zod": "^4.0.0",
|
|
66
|
-
"@zhin.js/adapter": "^1.1.
|
|
67
|
-
"@zhin.js/
|
|
68
|
-
"@zhin.js/
|
|
69
|
-
"
|
|
70
|
-
"zhin.js": "^1.1.0"
|
|
70
|
+
"@zhin.js/adapter": "^1.1.15",
|
|
71
|
+
"@zhin.js/command": "^1.1.2",
|
|
72
|
+
"@zhin.js/core": "^1.1.38",
|
|
73
|
+
"zhin.js": "^1.1.3"
|
|
71
74
|
},
|
|
72
75
|
"peerDependenciesMeta": {
|
|
73
|
-
"@zhin.js/agent": {
|
|
74
|
-
"optional": true
|
|
75
|
-
},
|
|
76
76
|
"@zhin.js/command": {
|
|
77
77
|
"optional": true
|
|
78
78
|
},
|
|
@@ -109,6 +109,18 @@
|
|
|
109
109
|
{
|
|
110
110
|
"package": "@zhin.js/command",
|
|
111
111
|
"api": "^1.0.0"
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
"package": "@zhin.js/tool",
|
|
115
|
+
"api": "^1.0.0"
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"package": "@zhin.js/skill",
|
|
119
|
+
"api": "^1.0.0"
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"package": "@zhin.js/agent-feature",
|
|
123
|
+
"api": "^1.0.0"
|
|
112
124
|
}
|
|
113
125
|
],
|
|
114
126
|
"plugins": []
|
package/schema.json
CHANGED
|
@@ -45,10 +45,11 @@
|
|
|
45
45
|
},
|
|
46
46
|
"endpoints": {
|
|
47
47
|
"type": "array",
|
|
48
|
+
"minItems": 1,
|
|
48
49
|
"description": "多账号:一个插件实例挂多个 endpoint。每项与顶层字段同构(id 必填,其余覆盖顶层)",
|
|
49
50
|
"items": {
|
|
50
51
|
"type": "object",
|
|
51
|
-
"additionalProperties":
|
|
52
|
+
"additionalProperties": false,
|
|
52
53
|
"properties": {
|
|
53
54
|
"master": {
|
|
54
55
|
"type": [
|
|
@@ -68,6 +69,14 @@
|
|
|
68
69
|
},
|
|
69
70
|
"description": "本 endpoint 的 trusted 列表"
|
|
70
71
|
},
|
|
72
|
+
"connection": {
|
|
73
|
+
"type": "string",
|
|
74
|
+
"enum": [
|
|
75
|
+
"ws",
|
|
76
|
+
"wss",
|
|
77
|
+
"http"
|
|
78
|
+
]
|
|
79
|
+
},
|
|
71
80
|
"url": {
|
|
72
81
|
"type": "string",
|
|
73
82
|
"description": "NapCat WebSocket URL (required for connection: ws)"
|
|
@@ -88,6 +97,18 @@
|
|
|
88
97
|
"type": "string",
|
|
89
98
|
"description": "NapCat access token"
|
|
90
99
|
},
|
|
100
|
+
"reconnect_interval": {
|
|
101
|
+
"type": "number"
|
|
102
|
+
},
|
|
103
|
+
"heartbeat_interval": {
|
|
104
|
+
"type": "number"
|
|
105
|
+
},
|
|
106
|
+
"poll_interval": {
|
|
107
|
+
"type": "number"
|
|
108
|
+
},
|
|
109
|
+
"commandPrefix": {
|
|
110
|
+
"type": "string"
|
|
111
|
+
},
|
|
91
112
|
"id": {
|
|
92
113
|
"type": "string",
|
|
93
114
|
"description": "NapCat bot name"
|