@zhin.js/adapter-napcat 1.0.0 → 1.0.1

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