@zhin.js/adapter-napcat 0.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.
package/src/index.ts ADDED
@@ -0,0 +1,57 @@
1
+ /**
2
+ * NapCat 适配器入口
3
+ * 支持 OneBot11 标准 + go-cqhttp 扩展 + NapCat 独有 API
4
+ * 连接方式:正向 WS / 反向 WS / HTTP
5
+ */
6
+ import { usePlugin, type Plugin, type Context, type IGroupManagement, createGroupManagementTools, type ToolFeature } from 'zhin.js';
7
+ import { NapCatAdapter } from './adapter.js';
8
+ import { createNapCatTools } from './tools.js';
9
+
10
+ export * from './types.js';
11
+ export { NapCatWsClient } from './bot-ws-client.js';
12
+ export { NapCatWsServer } from './bot-ws-server.js';
13
+ export { NapCatHttpBot } from './bot-http.js';
14
+ export { NapCatAdapter, type NapCatBot } from './adapter.js';
15
+ export { NapCatBotBase } from './bot-base.js';
16
+
17
+ declare module 'zhin.js' {
18
+ namespace Plugin {
19
+ interface Contexts {
20
+ router: import('@zhin.js/http').Router;
21
+ }
22
+ }
23
+ interface Adapters {
24
+ napcat: NapCatAdapter;
25
+ }
26
+ }
27
+
28
+ const plugin = usePlugin();
29
+ const { provide, useContext } = plugin;
30
+
31
+ provide({
32
+ name: 'napcat',
33
+ description: 'NapCatQQ 适配器(OneBot11 + go-cqhttp + NapCat 扩展,正向/反向 WS + HTTP)',
34
+ mounted: async (p: Plugin) => {
35
+ const adapter = new NapCatAdapter(p);
36
+ await adapter.start();
37
+ return adapter;
38
+ },
39
+ dispose: async (adapter: NapCatAdapter) => {
40
+ await adapter.stop();
41
+ },
42
+ } as unknown as Context<'napcat'>);
43
+
44
+ useContext('tool', 'napcat', (toolService: ToolFeature, napcat: NapCatAdapter) => {
45
+ const disposers: (() => void)[] = [];
46
+
47
+ const groupTools = createGroupManagementTools(
48
+ napcat as unknown as IGroupManagement,
49
+ 'napcat',
50
+ );
51
+ disposers.push(...groupTools.map(t => toolService.addTool(t, plugin.name)));
52
+
53
+ const napcatTools = createNapCatTools(napcat);
54
+ disposers.push(...napcatTools.map(t => toolService.addTool(t, plugin.name)));
55
+
56
+ return () => disposers.forEach(d => d());
57
+ });
package/src/tools.ts ADDED
@@ -0,0 +1,633 @@
1
+ /**
2
+ * NapCat 扩展 Tool 注册
3
+ * 覆盖 go-cqhttp 扩展与 NapCat 独有 API,全部通过 AI Tool 系统暴露。
4
+ */
5
+ import type { Tool, ToolScope, ToolPermissionLevel } from 'zhin.js';
6
+ import type { NapCatAdapter, NapCatBot } from './adapter.js';
7
+
8
+ function getBot(adapter: NapCatAdapter, botId: string): NapCatBot {
9
+ const bot = adapter.bots.get(botId);
10
+ if (!bot) throw new Error(`Bot ${botId} not found`);
11
+ return bot;
12
+ }
13
+
14
+ type PropertyType = 'string' | 'number' | 'boolean' | 'object' | 'array';
15
+
16
+ interface ToolSpec {
17
+ name: string;
18
+ description: string;
19
+ params: Record<string, { type: PropertyType; description: string; default?: any; enum?: string[] }>;
20
+ required: string[];
21
+ execute: (adapter: NapCatAdapter, args: Record<string, any>) => Promise<any>;
22
+ keywords: string[];
23
+ permissionLevel?: ToolPermissionLevel;
24
+ scopes?: ToolScope[];
25
+ preExecutable?: boolean;
26
+ }
27
+
28
+ const NAPCAT_TOOL_SPECS: ToolSpec[] = [
29
+ // ── 消息与社交 ──────────────────────────────────────────────────
30
+ {
31
+ name: 'napcat_send_poke',
32
+ description: '戳一戳(群聊或私聊)。group_id 不传时为私聊戳一戳。',
33
+ params: {
34
+ bot: { type: 'string', description: 'Bot 名称' },
35
+ user_id: { type: 'number', description: '目标用户 QQ 号' },
36
+ group_id: { type: 'number', description: '群号(不传则为私聊戳一戳)' },
37
+ },
38
+ required: ['bot', 'user_id'],
39
+ keywords: ['戳一戳', 'poke', '戳', '拍一拍'],
40
+ execute: async (adapter, args) => {
41
+ const bot = getBot(adapter, args.bot);
42
+ await bot.sendPoke(args.user_id, args.group_id);
43
+ return { success: true, message: `已戳 ${args.user_id}` };
44
+ },
45
+ },
46
+ {
47
+ name: 'napcat_set_emoji_reaction',
48
+ description: '为消息添加表情回应(贴表情)。',
49
+ params: {
50
+ bot: { type: 'string', description: 'Bot 名称' },
51
+ message_id: { type: 'number', description: '消息 ID' },
52
+ emoji_id: { type: 'string', description: '表情 ID' },
53
+ },
54
+ required: ['bot', 'message_id', 'emoji_id'],
55
+ keywords: ['表情回应', 'reaction', '贴表情', 'emoji'],
56
+ execute: async (adapter, args) => {
57
+ const bot = getBot(adapter, args.bot);
58
+ await bot.setMsgEmojiLike(args.message_id, args.emoji_id);
59
+ return { success: true };
60
+ },
61
+ },
62
+ {
63
+ name: 'napcat_send_forward_msg',
64
+ description: '发送合并转发消息(群聊或私聊)。messages 为转发节点数组。',
65
+ params: {
66
+ bot: { type: 'string', description: 'Bot 名称' },
67
+ message_type: { type: 'string', description: 'private 或 group', enum: ['private', 'group'] },
68
+ id: { type: 'number', description: '群号或 QQ 号' },
69
+ messages: { type: 'string', description: '转发节点 JSON(node 数组)' },
70
+ },
71
+ required: ['bot', 'message_type', 'id', 'messages'],
72
+ keywords: ['合并转发', 'forward', '转发消息'],
73
+ execute: async (adapter, args) => {
74
+ const bot = getBot(adapter, args.bot);
75
+ const messages = typeof args.messages === 'string' ? JSON.parse(args.messages) : args.messages;
76
+ const result = await bot.sendForwardMsg(args.message_type, args.id, messages);
77
+ return result;
78
+ },
79
+ },
80
+ {
81
+ name: 'napcat_forward_single_msg',
82
+ description: '转发单条消息到指定好友或群。',
83
+ params: {
84
+ bot: { type: 'string', description: 'Bot 名称' },
85
+ target_type: { type: 'string', description: 'friend 或 group', enum: ['friend', 'group'] },
86
+ target_id: { type: 'number', description: '目标好友 QQ 号或群号' },
87
+ message_id: { type: 'number', description: '要转发的消息 ID' },
88
+ },
89
+ required: ['bot', 'target_type', 'target_id', 'message_id'],
90
+ keywords: ['转发', 'forward', '单条转发'],
91
+ execute: async (adapter, args) => {
92
+ const bot = getBot(adapter, args.bot);
93
+ if (args.target_type === 'friend') await bot.forwardFriendSingleMsg(args.target_id, args.message_id);
94
+ else await bot.forwardGroupSingleMsg(args.target_id, args.message_id);
95
+ return { success: true };
96
+ },
97
+ },
98
+ {
99
+ name: 'napcat_send_like',
100
+ description: '给好友点赞(每人每天最多 10 次)。',
101
+ params: {
102
+ bot: { type: 'string', description: 'Bot 名称' },
103
+ user_id: { type: 'number', description: '目标 QQ 号' },
104
+ times: { type: 'number', description: '点赞次数(1-10)', default: 1 },
105
+ },
106
+ required: ['bot', 'user_id'],
107
+ keywords: ['点赞', 'like', '赞', '好友赞'],
108
+ execute: async (adapter, args) => {
109
+ const bot = getBot(adapter, args.bot);
110
+ await bot.sendLike(args.user_id, args.times || 1);
111
+ return { success: true, message: `已给 ${args.user_id} 点赞 ${args.times || 1} 次` };
112
+ },
113
+ },
114
+
115
+ // ── 精华消息 ────────────────────────────────────────────────────
116
+ {
117
+ name: 'napcat_set_essence_msg',
118
+ description: '设置群精华消息。',
119
+ params: {
120
+ bot: { type: 'string', description: 'Bot 名称' },
121
+ message_id: { type: 'number', description: '消息 ID' },
122
+ },
123
+ required: ['bot', 'message_id'],
124
+ keywords: ['精华', 'essence', '设精', '加精'],
125
+ permissionLevel: 'group_admin',
126
+ scopes: ['group'],
127
+ execute: async (adapter, args) => {
128
+ const bot = getBot(adapter, args.bot);
129
+ await bot.setEssenceMsg(args.message_id);
130
+ return { success: true };
131
+ },
132
+ },
133
+ {
134
+ name: 'napcat_delete_essence_msg',
135
+ description: '移除群精华消息。',
136
+ params: {
137
+ bot: { type: 'string', description: 'Bot 名称' },
138
+ message_id: { type: 'number', description: '消息 ID' },
139
+ },
140
+ required: ['bot', 'message_id'],
141
+ keywords: ['取消精华', '移除精华', 'delete essence'],
142
+ permissionLevel: 'group_admin',
143
+ scopes: ['group'],
144
+ execute: async (adapter, args) => {
145
+ const bot = getBot(adapter, args.bot);
146
+ await bot.deleteEssenceMsg(args.message_id);
147
+ return { success: true };
148
+ },
149
+ },
150
+ {
151
+ name: 'napcat_get_essence_list',
152
+ description: '获取群精华消息列表。',
153
+ params: {
154
+ bot: { type: 'string', description: 'Bot 名称' },
155
+ group_id: { type: 'number', description: '群号' },
156
+ },
157
+ required: ['bot', 'group_id'],
158
+ keywords: ['精华列表', 'essence list'],
159
+ preExecutable: true,
160
+ scopes: ['group'],
161
+ execute: async (adapter, args) => {
162
+ const bot = getBot(adapter, args.bot);
163
+ return bot.getEssenceMsgList(args.group_id);
164
+ },
165
+ },
166
+
167
+ // ── 群公告 ──────────────────────────────────────────────────────
168
+ {
169
+ name: 'napcat_send_group_notice',
170
+ description: '发送群公告。',
171
+ params: {
172
+ bot: { type: 'string', description: 'Bot 名称' },
173
+ group_id: { type: 'number', description: '群号' },
174
+ content: { type: 'string', description: '公告内容' },
175
+ image: { type: 'string', description: '图片(URL 或 base64,可选)' },
176
+ },
177
+ required: ['bot', 'group_id', 'content'],
178
+ keywords: ['群公告', 'notice', '公告', '发公告'],
179
+ permissionLevel: 'group_admin',
180
+ scopes: ['group'],
181
+ execute: async (adapter, args) => {
182
+ const bot = getBot(adapter, args.bot);
183
+ await bot.sendGroupNotice(args.group_id, args.content, args.image);
184
+ return { success: true };
185
+ },
186
+ },
187
+ {
188
+ name: 'napcat_get_group_notice',
189
+ description: '获取群公告列表。',
190
+ params: {
191
+ bot: { type: 'string', description: 'Bot 名称' },
192
+ group_id: { type: 'number', description: '群号' },
193
+ },
194
+ required: ['bot', 'group_id'],
195
+ keywords: ['群公告', '获取公告', 'get notice'],
196
+ preExecutable: true,
197
+ scopes: ['group'],
198
+ execute: async (adapter, args) => {
199
+ const bot = getBot(adapter, args.bot);
200
+ return bot.getGroupNotice(args.group_id);
201
+ },
202
+ },
203
+ {
204
+ name: 'napcat_del_group_notice',
205
+ description: '删除群公告。',
206
+ params: {
207
+ bot: { type: 'string', description: 'Bot 名称' },
208
+ group_id: { type: 'number', description: '群号' },
209
+ notice_id: { type: 'string', description: '公告 ID' },
210
+ },
211
+ required: ['bot', 'group_id', 'notice_id'],
212
+ keywords: ['删除公告', 'delete notice'],
213
+ permissionLevel: 'group_admin',
214
+ scopes: ['group'],
215
+ execute: async (adapter, args) => {
216
+ const bot = getBot(adapter, args.bot);
217
+ await bot.deleteGroupNotice(args.group_id, args.notice_id);
218
+ return { success: true };
219
+ },
220
+ },
221
+
222
+ // ── 群文件 ──────────────────────────────────────────────────────
223
+ {
224
+ name: 'napcat_upload_group_file',
225
+ description: '上传文件到群。file 为本地路径或 URL。',
226
+ params: {
227
+ bot: { type: 'string', description: 'Bot 名称' },
228
+ group_id: { type: 'number', description: '群号' },
229
+ file: { type: 'string', description: '文件路径或 URL' },
230
+ name: { type: 'string', description: '文件名' },
231
+ folder: { type: 'string', description: '目标文件夹 ID(可选)' },
232
+ },
233
+ required: ['bot', 'group_id', 'file', 'name'],
234
+ keywords: ['上传文件', 'upload file', '群文件'],
235
+ permissionLevel: 'user',
236
+ scopes: ['group'],
237
+ execute: async (adapter, args) => {
238
+ const bot = getBot(adapter, args.bot);
239
+ await bot.uploadGroupFile(args.group_id, args.file, args.name, args.folder);
240
+ return { success: true };
241
+ },
242
+ },
243
+ {
244
+ name: 'napcat_get_group_file_url',
245
+ description: '获取群文件下载链接。',
246
+ params: {
247
+ bot: { type: 'string', description: 'Bot 名称' },
248
+ group_id: { type: 'number', description: '群号' },
249
+ file_id: { type: 'string', description: '文件 ID' },
250
+ busid: { type: 'number', description: '文件类型 ID' },
251
+ },
252
+ required: ['bot', 'group_id', 'file_id', 'busid'],
253
+ keywords: ['文件链接', 'file url', '下载文件'],
254
+ preExecutable: true,
255
+ scopes: ['group'],
256
+ execute: async (adapter, args) => {
257
+ const bot = getBot(adapter, args.bot);
258
+ return bot.getGroupFileUrl(args.group_id, args.file_id, args.busid);
259
+ },
260
+ },
261
+ {
262
+ name: 'napcat_get_group_root_files',
263
+ description: '获取群根目录文件列表。',
264
+ params: {
265
+ bot: { type: 'string', description: 'Bot 名称' },
266
+ group_id: { type: 'number', description: '群号' },
267
+ },
268
+ required: ['bot', 'group_id'],
269
+ keywords: ['群文件列表', 'group files'],
270
+ preExecutable: true,
271
+ scopes: ['group'],
272
+ execute: async (adapter, args) => {
273
+ const bot = getBot(adapter, args.bot);
274
+ return bot.getGroupRootFiles(args.group_id);
275
+ },
276
+ },
277
+
278
+ // ── 群管理增强 ──────────────────────────────────────────────────
279
+ {
280
+ name: 'napcat_get_group_shut_list',
281
+ description: '获取群禁言列表。',
282
+ params: {
283
+ bot: { type: 'string', description: 'Bot 名称' },
284
+ group_id: { type: 'number', description: '群号' },
285
+ },
286
+ required: ['bot', 'group_id'],
287
+ keywords: ['禁言列表', 'shut list', '被禁言'],
288
+ preExecutable: true,
289
+ scopes: ['group'],
290
+ execute: async (adapter, args) => {
291
+ const bot = getBot(adapter, args.bot);
292
+ return bot.getGroupShutList(args.group_id);
293
+ },
294
+ },
295
+ {
296
+ name: 'napcat_set_group_portrait',
297
+ description: '设置群头像。file 为图片 URL 或 base64。',
298
+ params: {
299
+ bot: { type: 'string', description: 'Bot 名称' },
300
+ group_id: { type: 'number', description: '群号' },
301
+ file: { type: 'string', description: '图片(URL 或 base64)' },
302
+ },
303
+ required: ['bot', 'group_id', 'file'],
304
+ keywords: ['群头像', 'group portrait', '设置群头像'],
305
+ permissionLevel: 'group_admin',
306
+ scopes: ['group'],
307
+ execute: async (adapter, args) => {
308
+ const bot = getBot(adapter, args.bot);
309
+ await bot.setGroupPortrait(args.group_id, args.file);
310
+ return { success: true };
311
+ },
312
+ },
313
+ {
314
+ name: 'napcat_set_title',
315
+ description: '设置群成员专属头衔。需要群主权限。',
316
+ params: {
317
+ bot: { type: 'string', description: 'Bot 名称' },
318
+ group_id: { type: 'number', description: '群号' },
319
+ user_id: { type: 'number', description: '目标成员 QQ 号' },
320
+ title: { type: 'string', description: '头衔文字' },
321
+ },
322
+ required: ['bot', 'group_id', 'user_id', 'title'],
323
+ keywords: ['头衔', 'title', '专属头衔', '设置头衔'],
324
+ permissionLevel: 'group_owner',
325
+ scopes: ['group'],
326
+ execute: async (adapter, args) => {
327
+ const bot = getBot(adapter, args.bot);
328
+ await bot.setTitle(args.group_id, args.user_id, args.title);
329
+ return { success: true, message: `已设置 ${args.user_id} 头衔为 "${args.title}"` };
330
+ },
331
+ },
332
+ {
333
+ name: 'napcat_group_sign',
334
+ description: '群签到/群打卡。',
335
+ params: {
336
+ bot: { type: 'string', description: 'Bot 名称' },
337
+ group_id: { type: 'number', description: '群号' },
338
+ },
339
+ required: ['bot', 'group_id'],
340
+ keywords: ['签到', '打卡', 'sign', 'check in'],
341
+ scopes: ['group'],
342
+ execute: async (adapter, args) => {
343
+ const bot = getBot(adapter, args.bot);
344
+ await bot.sendGroupSign(args.group_id);
345
+ return { success: true };
346
+ },
347
+ },
348
+
349
+ // ── AI 与多媒体 ────────────────────────────────────────────────
350
+ {
351
+ name: 'napcat_ai_tts',
352
+ description: 'AI 文字转语音,在群聊中发送 AI 语音消息。',
353
+ params: {
354
+ bot: { type: 'string', description: 'Bot 名称' },
355
+ group_id: { type: 'number', description: '群号' },
356
+ character: { type: 'string', description: 'AI 语音角色 ID(可先用 napcat_get_ai_characters 查询)' },
357
+ text: { type: 'string', description: '要转为语音的文字' },
358
+ },
359
+ required: ['bot', 'group_id', 'character', 'text'],
360
+ keywords: ['AI语音', 'TTS', '文字转语音', 'ai record'],
361
+ scopes: ['group'],
362
+ execute: async (adapter, args) => {
363
+ const bot = getBot(adapter, args.bot);
364
+ return bot.sendGroupAiRecord(args.group_id, args.character, args.text);
365
+ },
366
+ },
367
+ {
368
+ name: 'napcat_get_ai_characters',
369
+ description: '获取 AI 语音角色列表,用于 napcat_ai_tts 的 character 参数。',
370
+ params: {
371
+ bot: { type: 'string', description: 'Bot 名称' },
372
+ group_id: { type: 'number', description: '群号' },
373
+ },
374
+ required: ['bot', 'group_id'],
375
+ keywords: ['AI角色', 'ai characters', '语音角色'],
376
+ preExecutable: true,
377
+ scopes: ['group'],
378
+ execute: async (adapter, args) => {
379
+ const bot = getBot(adapter, args.bot);
380
+ return bot.getAiCharacters(args.group_id);
381
+ },
382
+ },
383
+ {
384
+ name: 'napcat_ocr_image',
385
+ description: '图片 OCR 文字识别。',
386
+ params: {
387
+ bot: { type: 'string', description: 'Bot 名称' },
388
+ image: { type: 'string', description: '图片 file 参数(收到消息中的 file 字段或 URL)' },
389
+ },
390
+ required: ['bot', 'image'],
391
+ keywords: ['OCR', '文字识别', '图片识别', 'ocr'],
392
+ preExecutable: true,
393
+ execute: async (adapter, args) => {
394
+ const bot = getBot(adapter, args.bot);
395
+ return bot.ocrImage(args.image);
396
+ },
397
+ },
398
+ {
399
+ name: 'napcat_get_mini_app_ark',
400
+ description: '签名小程序卡片(如 B 站分享卡片等)。',
401
+ params: {
402
+ bot: { type: 'string', description: 'Bot 名称' },
403
+ type: { type: 'string', description: '卡片类型' },
404
+ title: { type: 'string', description: '标题' },
405
+ desc: { type: 'string', description: '描述' },
406
+ pic_url: { type: 'string', description: '图片 URL' },
407
+ jump_url: { type: 'string', description: '跳转 URL' },
408
+ },
409
+ required: ['bot', 'type', 'title', 'desc', 'pic_url', 'jump_url'],
410
+ keywords: ['小程序', 'mini app', '卡片', 'ark'],
411
+ execute: async (adapter, args) => {
412
+ const bot = getBot(adapter, args.bot);
413
+ return bot.getMiniAppArk(args.type, args.title, args.desc, args.pic_url, args.jump_url);
414
+ },
415
+ },
416
+
417
+ // ── 消息历史 ────────────────────────────────────────────────────
418
+ {
419
+ name: 'napcat_get_group_msg_history',
420
+ description: '获取群消息历史记录。',
421
+ params: {
422
+ bot: { type: 'string', description: 'Bot 名称' },
423
+ group_id: { type: 'number', description: '群号' },
424
+ message_seq: { type: 'number', description: '起始消息序号(可选,不传从最新开始)' },
425
+ count: { type: 'number', description: '获取条数(可选)' },
426
+ },
427
+ required: ['bot', 'group_id'],
428
+ keywords: ['群消息历史', '聊天记录', 'message history'],
429
+ preExecutable: true,
430
+ scopes: ['group'],
431
+ execute: async (adapter, args) => {
432
+ const bot = getBot(adapter, args.bot);
433
+ return bot.getGroupMsgHistory(args.group_id, args.message_seq, args.count);
434
+ },
435
+ },
436
+ {
437
+ name: 'napcat_get_friend_msg_history',
438
+ description: '获取私聊消息历史记录。',
439
+ params: {
440
+ bot: { type: 'string', description: 'Bot 名称' },
441
+ user_id: { type: 'number', description: 'QQ 号' },
442
+ message_seq: { type: 'number', description: '起始消息序号(可选)' },
443
+ count: { type: 'number', description: '获取条数(可选)' },
444
+ },
445
+ required: ['bot', 'user_id'],
446
+ keywords: ['私聊记录', '好友聊天记录', 'friend history'],
447
+ preExecutable: true,
448
+ execute: async (adapter, args) => {
449
+ const bot = getBot(adapter, args.bot);
450
+ return bot.getFriendMsgHistory(args.user_id, args.message_seq, args.count);
451
+ },
452
+ },
453
+
454
+ // ── 信息查询 ────────────────────────────────────────────────────
455
+ {
456
+ name: 'napcat_get_user_status',
457
+ description: '获取用户在线状态。',
458
+ params: {
459
+ bot: { type: 'string', description: 'Bot 名称' },
460
+ user_id: { type: 'number', description: '目标 QQ 号' },
461
+ },
462
+ required: ['bot', 'user_id'],
463
+ keywords: ['在线状态', '用户状态', 'online status'],
464
+ preExecutable: true,
465
+ execute: async (adapter, args) => {
466
+ const bot = getBot(adapter, args.bot);
467
+ return bot.ncGetUserStatus(args.user_id);
468
+ },
469
+ },
470
+ {
471
+ name: 'napcat_get_group_info_ex',
472
+ description: '获取群组额外详细信息。',
473
+ params: {
474
+ bot: { type: 'string', description: 'Bot 名称' },
475
+ group_id: { type: 'number', description: '群号' },
476
+ },
477
+ required: ['bot', 'group_id'],
478
+ keywords: ['群详情', '群额外信息', 'group info ex'],
479
+ preExecutable: true,
480
+ scopes: ['group'],
481
+ execute: async (adapter, args) => {
482
+ const bot = getBot(adapter, args.bot);
483
+ return bot.getGroupInfoEx(args.group_id);
484
+ },
485
+ },
486
+
487
+ // ── 个人设置 ────────────────────────────────────────────────────
488
+ {
489
+ name: 'napcat_set_profile',
490
+ description: '修改 QQ 资料(昵称等)。',
491
+ params: {
492
+ bot: { type: 'string', description: 'Bot 名称' },
493
+ nickname: { type: 'string', description: '昵称' },
494
+ company: { type: 'string', description: '公司(可选)' },
495
+ email: { type: 'string', description: '邮箱(可选)' },
496
+ college: { type: 'string', description: '学校(可选)' },
497
+ personal_note: { type: 'string', description: '个人说明(可选)' },
498
+ },
499
+ required: ['bot', 'nickname'],
500
+ keywords: ['修改资料', '设置昵称', 'profile', 'set profile'],
501
+ execute: async (adapter, args) => {
502
+ const bot = getBot(adapter, args.bot);
503
+ await bot.setQQProfile(args.nickname, args.company, args.email, args.college, args.personal_note);
504
+ return { success: true };
505
+ },
506
+ },
507
+ {
508
+ name: 'napcat_set_avatar',
509
+ description: '修改 QQ 头像。',
510
+ params: {
511
+ bot: { type: 'string', description: 'Bot 名称' },
512
+ file: { type: 'string', description: '图片(URL 或 base64)' },
513
+ },
514
+ required: ['bot', 'file'],
515
+ keywords: ['头像', 'avatar', '设置头像', '换头像'],
516
+ execute: async (adapter, args) => {
517
+ const bot = getBot(adapter, args.bot);
518
+ await bot.setQQAvatar(args.file);
519
+ return { success: true };
520
+ },
521
+ },
522
+ {
523
+ name: 'napcat_set_online_status',
524
+ description: '设置在线状态(在线、隐身、忙碌等)。',
525
+ params: {
526
+ bot: { type: 'string', description: 'Bot 名称' },
527
+ status: { type: 'number', description: '状态码(11=在线, 21=离开, 31=隐身, 41=忙碌, 50=请勿打扰, 60=Q我吧)' },
528
+ ext_status: { type: 'number', description: '扩展状态码', default: 0 },
529
+ },
530
+ required: ['bot', 'status'],
531
+ keywords: ['在线状态', '隐身', '忙碌', 'online', 'status'],
532
+ execute: async (adapter, args) => {
533
+ const bot = getBot(adapter, args.bot);
534
+ await bot.setOnlineStatus(args.status, args.ext_status || 0);
535
+ return { success: true };
536
+ },
537
+ },
538
+ {
539
+ name: 'napcat_set_signature',
540
+ description: '设置个人签名(个性签名)。',
541
+ params: {
542
+ bot: { type: 'string', description: 'Bot 名称' },
543
+ signature: { type: 'string', description: '签名内容' },
544
+ },
545
+ required: ['bot', 'signature'],
546
+ keywords: ['签名', '个性签名', 'signature', 'longnick'],
547
+ execute: async (adapter, args) => {
548
+ const bot = getBot(adapter, args.bot);
549
+ await bot.setSelfLongnick(args.signature);
550
+ return { success: true };
551
+ },
552
+ },
553
+ {
554
+ name: 'napcat_translate',
555
+ description: '英译中翻译。',
556
+ params: {
557
+ bot: { type: 'string', description: 'Bot 名称' },
558
+ text: { type: 'string', description: '要翻译的英文文本' },
559
+ },
560
+ required: ['bot', 'text'],
561
+ keywords: ['翻译', 'translate', '英译中'],
562
+ preExecutable: true,
563
+ execute: async (adapter, args) => {
564
+ const bot = getBot(adapter, args.bot);
565
+ return bot.translateEn2Zh(args.text);
566
+ },
567
+ },
568
+ {
569
+ name: 'napcat_mark_msg_as_read',
570
+ description: '标记消息为已读。',
571
+ params: {
572
+ bot: { type: 'string', description: 'Bot 名称' },
573
+ message_id: { type: 'number', description: '消息 ID' },
574
+ },
575
+ required: ['bot', 'message_id'],
576
+ keywords: ['已读', 'mark read', '标记已读'],
577
+ execute: async (adapter, args) => {
578
+ const bot = getBot(adapter, args.bot);
579
+ await bot.markMsgAsRead(args.message_id);
580
+ return { success: true };
581
+ },
582
+ },
583
+ {
584
+ name: 'napcat_download_file',
585
+ description: '下载文件到 NapCat 缓存目录,返回本地路径。',
586
+ params: {
587
+ bot: { type: 'string', description: 'Bot 名称' },
588
+ url: { type: 'string', description: '文件 URL' },
589
+ thread_count: { type: 'number', description: '下载线程数(可选,默认 1)', default: 1 },
590
+ },
591
+ required: ['bot', 'url'],
592
+ keywords: ['下载', 'download', '下载文件'],
593
+ execute: async (adapter, args) => {
594
+ const bot = getBot(adapter, args.bot);
595
+ return bot.downloadFile(args.url, args.thread_count || 1);
596
+ },
597
+ },
598
+ {
599
+ name: 'napcat_delete_friend',
600
+ description: '删除好友。',
601
+ params: {
602
+ bot: { type: 'string', description: 'Bot 名称' },
603
+ user_id: { type: 'number', description: '好友 QQ 号' },
604
+ },
605
+ required: ['bot', 'user_id'],
606
+ keywords: ['删除好友', 'delete friend', '删好友'],
607
+ permissionLevel: 'group_admin',
608
+ execute: async (adapter, args) => {
609
+ const bot = getBot(adapter, args.bot);
610
+ await bot.deleteFriend(args.user_id);
611
+ return { success: true };
612
+ },
613
+ },
614
+ ];
615
+
616
+ export function createNapCatTools(adapter: NapCatAdapter): Tool[] {
617
+ return NAPCAT_TOOL_SPECS.map((spec) => ({
618
+ name: spec.name,
619
+ description: spec.description,
620
+ parameters: {
621
+ type: 'object' as const,
622
+ properties: spec.params,
623
+ required: spec.required,
624
+ },
625
+ execute: (args: Record<string, any>) => spec.execute(adapter, args),
626
+ tags: ['napcat', 'qq'],
627
+ keywords: spec.keywords,
628
+ platforms: ['napcat'],
629
+ permissionLevel: spec.permissionLevel || ('user' as ToolPermissionLevel),
630
+ scopes: spec.scopes || (['group', 'private'] as ToolScope[]),
631
+ preExecutable: spec.preExecutable,
632
+ }));
633
+ }