mioku-plugin-admin 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,376 @@
1
+ import type { AISkill } from "../../../src";
2
+ import { getImageUrlByMessageId } from "./message-image";
3
+
4
+ function parseProfileSex(value: string): 0 | 1 | 2 {
5
+ const normalized = String(value || "")
6
+ .trim()
7
+ .toLowerCase();
8
+ if (normalized === "男" || normalized === "male" || normalized === "1")
9
+ return 1;
10
+ if (normalized === "女" || normalized === "female" || normalized === "2")
11
+ return 2;
12
+ return 0;
13
+ }
14
+
15
+ function logAdminSkillError(runtimeCtx: any, toolName: string, err: unknown) {
16
+ runtimeCtx?.ctx?.logger?.error?.(
17
+ `[admin skills] ${toolName} failed: ${String(err)}`,
18
+ );
19
+ }
20
+
21
+ const personalSkill: AISkill = {
22
+ name: "admin_personal",
23
+ description:
24
+ "个人账号管理工具,提供修改自己头像、昵称、个性签名、性别、发送消息、查看好友/群列表等操作",
25
+ permission: "owner",
26
+ tools: [
27
+ {
28
+ name: "set_bot_avatar",
29
+ description: "修改Bot头像",
30
+ parameters: {
31
+ type: "object",
32
+ properties: {
33
+ message_id: {
34
+ type: "number",
35
+ description: "包含图片的消息 message_id",
36
+ },
37
+ },
38
+ required: ["message_id"],
39
+ },
40
+ handler: async (args: any, runtimeCtx?: any) => {
41
+ const ctx = runtimeCtx?.ctx;
42
+ if (!ctx) return { error: "无法获取上下文" };
43
+ const selfId =
44
+ runtimeCtx?.event?.self_id || runtimeCtx?.rawEvent?.self_id;
45
+ if (!selfId) return { error: "无法获取Bot ID" };
46
+ const bot = ctx.pickBot(selfId);
47
+ if (!bot) return { error: "Bot不可用" };
48
+ const messageId = Number(args?.message_id);
49
+ if (!Number.isFinite(messageId) || messageId <= 0) {
50
+ return { error: "请提供有效的 message_id" };
51
+ }
52
+ const imageUrl = await getImageUrlByMessageId(bot, messageId);
53
+ if (!imageUrl) {
54
+ return { error: "指定 message_id 中未找到图片" };
55
+ }
56
+ try {
57
+ await bot.api("set_qq_avatar", { file: imageUrl });
58
+ return { success: true, message: "Bot头像已修改" };
59
+ } catch (err) {
60
+ logAdminSkillError(runtimeCtx, "admin_personal.set_bot_avatar", err);
61
+ return { error: `修改头像失败: ${err}` };
62
+ }
63
+ },
64
+ },
65
+ {
66
+ name: "set_bot_nickname",
67
+ description: "修改Bot昵称",
68
+ parameters: {
69
+ type: "object",
70
+ properties: { nickname: { type: "string", description: "新昵称" } },
71
+ required: ["nickname"],
72
+ },
73
+ handler: async (args: any, runtimeCtx?: any) => {
74
+ const ctx = runtimeCtx?.ctx;
75
+ if (!ctx) return { error: "无法获取上下文" };
76
+ const selfId =
77
+ runtimeCtx?.event?.self_id || runtimeCtx?.rawEvent?.self_id;
78
+ if (!selfId) return { error: "无法获取Bot ID" };
79
+ const bot = ctx.pickBot(selfId);
80
+ if (!bot) return { error: "Bot不可用" };
81
+ try {
82
+ await bot.api("set_qq_profile", {
83
+ nickname: String(args.nickname || "").trim(),
84
+ });
85
+ return {
86
+ success: true,
87
+ message: `Bot昵称已修改为: ${args.nickname}`,
88
+ };
89
+ } catch (err) {
90
+ logAdminSkillError(
91
+ runtimeCtx,
92
+ "admin_personal.set_bot_nickname",
93
+ err,
94
+ );
95
+ return { error: `修改昵称失败: ${err}` };
96
+ }
97
+ },
98
+ },
99
+ {
100
+ name: "set_bot_signature",
101
+ description: "修改Bot个性签名",
102
+ parameters: {
103
+ type: "object",
104
+ properties: {
105
+ personal_note: { type: "string", description: "新个性签名" },
106
+ },
107
+ required: ["personal_note"],
108
+ },
109
+ handler: async (args: any, runtimeCtx?: any) => {
110
+ const ctx = runtimeCtx?.ctx;
111
+ if (!ctx) return { error: "无法获取上下文" };
112
+ const selfId =
113
+ runtimeCtx?.event?.self_id || runtimeCtx?.rawEvent?.self_id;
114
+ if (!selfId) return { error: "无法获取Bot ID" };
115
+ const bot = ctx.pickBot(selfId);
116
+ if (!bot) return { error: "Bot不可用" };
117
+ const personalNote = String(args?.personal_note || "").trim();
118
+ if (!personalNote) return { error: "personal_note 不能为空" };
119
+ try {
120
+ await bot.api("set_qq_profile", { personal_note: personalNote });
121
+ return { success: true, message: "Bot个性签名已修改" };
122
+ } catch (err) {
123
+ logAdminSkillError(
124
+ runtimeCtx,
125
+ "admin_personal.set_bot_signature",
126
+ err,
127
+ );
128
+ return { error: `修改个性签名失败: ${err}` };
129
+ }
130
+ },
131
+ },
132
+ {
133
+ name: "set_bot_gender",
134
+ description: "修改Bot性别",
135
+ parameters: {
136
+ type: "object",
137
+ properties: {
138
+ gender: {
139
+ type: "string",
140
+ description: "性别:男/女/无 或 male/female/unknown",
141
+ enum: [
142
+ "male",
143
+ "female",
144
+ "unknown",
145
+ "男",
146
+ "女",
147
+ "无",
148
+ "0",
149
+ "1",
150
+ "2",
151
+ ],
152
+ },
153
+ },
154
+ required: ["gender"],
155
+ },
156
+ handler: async (args: any, runtimeCtx?: any) => {
157
+ const ctx = runtimeCtx?.ctx;
158
+ if (!ctx) return { error: "无法获取上下文" };
159
+ const selfId =
160
+ runtimeCtx?.event?.self_id || runtimeCtx?.rawEvent?.self_id;
161
+ if (!selfId) return { error: "无法获取Bot ID" };
162
+ const bot = ctx.pickBot(selfId);
163
+ if (!bot) return { error: "Bot不可用" };
164
+ try {
165
+ const sex = parseProfileSex(args.gender);
166
+ await bot.api("set_qq_profile", { sex });
167
+ const genderMap: Record<number, string> = {
168
+ 0: "无",
169
+ 1: "男",
170
+ 2: "女",
171
+ };
172
+ return {
173
+ success: true,
174
+ message: `Bot性别已修改为: ${genderMap[sex]}`,
175
+ };
176
+ } catch (err) {
177
+ logAdminSkillError(runtimeCtx, "admin_personal.set_bot_gender", err);
178
+ return { error: `修改性别失败: ${err}` };
179
+ }
180
+ },
181
+ },
182
+ {
183
+ name: "send_private_message",
184
+ description: "给指定QQ号发送私聊消息",
185
+ parameters: {
186
+ type: "object",
187
+ properties: {
188
+ user_id: { type: "number", description: "目标QQ号" },
189
+ content: { type: "string", description: "消息内容" },
190
+ },
191
+ required: ["user_id", "content"],
192
+ },
193
+ handler: async (args: any, runtimeCtx?: any) => {
194
+ const ctx = runtimeCtx?.ctx;
195
+ if (!ctx) return { error: "无法获取上下文" };
196
+ const selfId =
197
+ runtimeCtx?.event?.self_id || runtimeCtx?.rawEvent?.self_id;
198
+ if (!selfId) return { error: "无法获取Bot ID" };
199
+ const bot = ctx.pickBot(selfId);
200
+ if (!bot) return { error: "Bot不可用" };
201
+ try {
202
+ await bot.sendPrivateMsg(args.user_id, [
203
+ ctx.segment.text(args.content),
204
+ ]);
205
+ return { success: true, message: `已发送私聊消息给 ${args.user_id}` };
206
+ } catch (err) {
207
+ logAdminSkillError(
208
+ runtimeCtx,
209
+ "admin_personal.send_private_message",
210
+ err,
211
+ );
212
+ return { error: `发送私聊失败: ${err}` };
213
+ }
214
+ },
215
+ },
216
+ {
217
+ name: "send_group_message",
218
+ description: "给指定群发送消息",
219
+ parameters: {
220
+ type: "object",
221
+ properties: {
222
+ group_id: { type: "number", description: "目标群号" },
223
+ content: { type: "string", description: "消息内容" },
224
+ },
225
+ required: ["group_id", "content"],
226
+ },
227
+ handler: async (args: any, runtimeCtx?: any) => {
228
+ const ctx = runtimeCtx?.ctx;
229
+ if (!ctx) return { error: "无法获取上下文" };
230
+ const selfId =
231
+ runtimeCtx?.event?.self_id || runtimeCtx?.rawEvent?.self_id;
232
+ if (!selfId) return { error: "无法获取Bot ID" };
233
+ const bot = ctx.pickBot(selfId);
234
+ if (!bot) return { error: "Bot不可用" };
235
+ try {
236
+ await bot.sendGroupMsg(args.group_id, [
237
+ ctx.segment.text(args.content),
238
+ ]);
239
+ return { success: true, message: `已发送群消息到 ${args.group_id}` };
240
+ } catch (err) {
241
+ logAdminSkillError(
242
+ runtimeCtx,
243
+ "admin_personal.send_group_message",
244
+ err,
245
+ );
246
+ return { error: `发送群消息失败: ${err}` };
247
+ }
248
+ },
249
+ },
250
+ {
251
+ name: "get_friend_list",
252
+ description:
253
+ "获取Bot的全部好友列表,对应/全部好友命令,仅适合在私聊场景调用",
254
+ parameters: { type: "object", properties: {}, required: [] },
255
+ handler: async (_args: any, runtimeCtx?: any) => {
256
+ const ctx = runtimeCtx?.ctx;
257
+ if (!ctx) return { error: "无法获取上下文" };
258
+ const event = runtimeCtx?.event || runtimeCtx?.rawEvent;
259
+ if (event?.message_type === "group") {
260
+ return { error: "在私聊使用试试看吧~" };
261
+ }
262
+ const selfId =
263
+ runtimeCtx?.event?.self_id || runtimeCtx?.rawEvent?.self_id;
264
+ if (!selfId) return { error: "无法获取Bot ID" };
265
+ const bot = ctx.pickBot(selfId);
266
+ if (!bot) return { error: "Bot不可用" };
267
+ try {
268
+ const friendList: any[] = await bot.api("get_friend_list");
269
+ if (!Array.isArray(friendList)) return { friends: [] };
270
+ return {
271
+ friends: friendList.map((f) => ({
272
+ user_id: f.user_id,
273
+ nickname: f.nickname,
274
+ remark: f.remark,
275
+ })),
276
+ };
277
+ } catch (err) {
278
+ logAdminSkillError(runtimeCtx, "admin_personal.get_friend_list", err);
279
+ return { error: `获取好友列表失败: ${err}` };
280
+ }
281
+ },
282
+ },
283
+ {
284
+ name: "get_group_list",
285
+ description:
286
+ "获取Bot的全部群聊列表,对应/全部群聊命令,仅适合在私聊场景调用",
287
+ parameters: { type: "object", properties: {}, required: [] },
288
+ handler: async (_args: any, runtimeCtx?: any) => {
289
+ const ctx = runtimeCtx?.ctx;
290
+ if (!ctx) return { error: "无法获取上下文" };
291
+ const event = runtimeCtx?.event || runtimeCtx?.rawEvent;
292
+ if (event?.message_type === "group") {
293
+ return { error: "在私聊使用试试看吧~" };
294
+ }
295
+ const selfId =
296
+ runtimeCtx?.event?.self_id || runtimeCtx?.rawEvent?.self_id;
297
+ if (!selfId) return { error: "无法获取Bot ID" };
298
+ const bot = ctx.pickBot(selfId);
299
+ if (!bot) return { error: "Bot不可用" };
300
+ try {
301
+ const groupList: any[] = await bot.api("get_group_list");
302
+ if (!Array.isArray(groupList)) return { groups: [] };
303
+ return {
304
+ groups: groupList.map((g) => ({
305
+ group_id: g.group_id,
306
+ group_name: g.group_name,
307
+ member_count: g.member_count,
308
+ })),
309
+ };
310
+ } catch (err) {
311
+ logAdminSkillError(runtimeCtx, "admin_personal.get_group_list", err);
312
+ return { error: `获取群聊列表失败: ${err}` };
313
+ }
314
+ },
315
+ },
316
+ {
317
+ name: "delete_friend",
318
+ description: "删除好友",
319
+ parameters: {
320
+ type: "object",
321
+ properties: {
322
+ user_id: { type: "number", description: "要删除的好友QQ号" },
323
+ },
324
+ required: ["user_id"],
325
+ },
326
+ handler: async (args: any, runtimeCtx?: any) => {
327
+ const ctx = runtimeCtx?.ctx;
328
+ if (!ctx) return { error: "无法获取上下文" };
329
+ const selfId =
330
+ runtimeCtx?.event?.self_id || runtimeCtx?.rawEvent?.self_id;
331
+ if (!selfId) return { error: "无法获取Bot ID" };
332
+ const bot = ctx.pickBot(selfId);
333
+ if (!bot) return { error: "Bot不可用" };
334
+ try {
335
+ await bot.api("delete_friend", { user_id: args.user_id });
336
+ return { success: true, message: `已删除好友 ${args.user_id}` };
337
+ } catch (err) {
338
+ logAdminSkillError(runtimeCtx, "admin_personal.delete_friend", err);
339
+ return { error: `删除好友失败: ${err}` };
340
+ }
341
+ },
342
+ },
343
+ {
344
+ name: "leave_group",
345
+ description: "退出群聊",
346
+ parameters: {
347
+ type: "object",
348
+ properties: {
349
+ group_id: { type: "number", description: "要退出的群号" },
350
+ },
351
+ required: ["group_id"],
352
+ },
353
+ handler: async (args: any, runtimeCtx?: any) => {
354
+ const ctx = runtimeCtx?.ctx;
355
+ if (!ctx) return { error: "无法获取上下文" };
356
+ const selfId =
357
+ runtimeCtx?.event?.self_id || runtimeCtx?.rawEvent?.self_id;
358
+ if (!selfId) return { error: "无法获取Bot ID" };
359
+ const bot = ctx.pickBot(selfId);
360
+ if (!bot) return { error: "Bot不可用" };
361
+ try {
362
+ await bot.api("set_group_leave", {
363
+ group_id: args.group_id,
364
+ is_dismiss: false,
365
+ });
366
+ return { success: true, message: `已退出群 ${args.group_id}` };
367
+ } catch (err) {
368
+ logAdminSkillError(runtimeCtx, "admin_personal.leave_group", err);
369
+ return { error: `退群失败: ${err}` };
370
+ }
371
+ },
372
+ },
373
+ ],
374
+ };
375
+
376
+ export default personalSkill;
package/skills.ts ADDED
@@ -0,0 +1,7 @@
1
+ import type { AISkill } from "../../src";
2
+ import groupAdminSkill from "./skills/group";
3
+ import personalSkill from "./skills/personal";
4
+
5
+ const adminSkills: AISkill[] = [groupAdminSkill, personalSkill];
6
+
7
+ export default adminSkills;