mioku-plugin-admin 2.3.5 → 3.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.
- package/commands/group.ts +463 -473
- package/commands/notice.ts +3 -3
- package/commands/personal.ts +234 -276
- package/commands/verify.ts +325 -308
- package/config.ts +29 -17
- package/index.ts +5 -7
- package/notify/index.ts +110 -140
- package/notify/welcome.ts +52 -44
- package/package.json +4 -283
- package/skills/group.ts +87 -143
- package/skills/message-image.ts +8 -9
- package/skills/personal.ts +72 -98
- package/verify/chiral.ts +4 -4
- package/verify/index.ts +59 -45
- package/verify/number.ts +4 -4
- package/verify/reaction.ts +62 -14
- package/verify/state.ts +1 -1
- package/verify/types.ts +18 -8
package/skills/group.ts
CHANGED
|
@@ -1,25 +1,42 @@
|
|
|
1
|
-
import type { AISkill } from "mioku";
|
|
1
|
+
import type { AISkill, Bot, MessageEvent } from "mioku";
|
|
2
|
+
|
|
2
3
|
import { getMemberRole } from "../config";
|
|
3
4
|
import { getImageUrlByMessageId } from "./message-image";
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
interface GroupRuntime {
|
|
7
|
+
ctx: { logger?: { error?: (...args: unknown[]) => void } };
|
|
8
|
+
event: MessageEvent;
|
|
9
|
+
bot: Bot;
|
|
10
|
+
groupId: number;
|
|
11
|
+
selfId: number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface SkillRuntimeContext {
|
|
15
|
+
ctx?: GroupRuntime["ctx"];
|
|
16
|
+
event?: MessageEvent;
|
|
17
|
+
rawEvent?: MessageEvent;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function resolveGroupRuntime(runtimeCtx: SkillRuntimeContext | undefined):
|
|
21
|
+
| GroupRuntime
|
|
22
|
+
| { error: string } {
|
|
6
23
|
const ctx = runtimeCtx?.ctx;
|
|
7
24
|
if (!ctx) return { error: "无法获取上下文" };
|
|
8
25
|
|
|
9
|
-
const event = runtimeCtx?.event
|
|
10
|
-
const groupId = Number(event?.group_id
|
|
26
|
+
const event = runtimeCtx?.event ?? runtimeCtx?.rawEvent;
|
|
27
|
+
const groupId = Number(event?.group_id ?? 0);
|
|
11
28
|
if (!groupId) return { error: "这个工具只能在群聊中使用" };
|
|
12
29
|
|
|
13
|
-
const selfId =
|
|
30
|
+
const selfId = Number(event?.self_id ?? 0);
|
|
14
31
|
if (!selfId) return { error: "无法获取Bot ID" };
|
|
15
32
|
|
|
16
|
-
const bot =
|
|
33
|
+
const bot = event?.bot;
|
|
17
34
|
if (!bot) return { error: "Bot不可用" };
|
|
18
35
|
|
|
19
|
-
return { ctx,
|
|
36
|
+
return { ctx, event: event!, bot, groupId, selfId };
|
|
20
37
|
}
|
|
21
38
|
|
|
22
|
-
function logAdminSkillError(runtimeCtx:
|
|
39
|
+
function logAdminSkillError(runtimeCtx: SkillRuntimeContext | undefined, toolName: string, err: unknown) {
|
|
23
40
|
runtimeCtx?.ctx?.logger?.error?.(
|
|
24
41
|
`[admin skills] ${toolName} failed: ${String(err)}`,
|
|
25
42
|
);
|
|
@@ -32,22 +49,16 @@ function formatGroupRole(role: string): string {
|
|
|
32
49
|
}
|
|
33
50
|
|
|
34
51
|
async function checkDangerousTargetPermission(
|
|
35
|
-
runtime:
|
|
52
|
+
runtime: GroupRuntime,
|
|
36
53
|
targetUserId: number,
|
|
37
54
|
): Promise<string | null> {
|
|
38
|
-
const operatorUserId = Number(runtime.event
|
|
55
|
+
const operatorUserId = Number(runtime.event.user_id ?? 0);
|
|
39
56
|
if (!operatorUserId) return "无法获取当前操作人ID";
|
|
40
57
|
|
|
41
|
-
const operatorRole = await
|
|
42
|
-
runtime.bot,
|
|
43
|
-
runtime.groupId,
|
|
44
|
-
|
|
45
|
-
);
|
|
46
|
-
const targetRole = await getMemberRole(
|
|
47
|
-
runtime.bot,
|
|
48
|
-
runtime.groupId,
|
|
49
|
-
targetUserId,
|
|
50
|
-
);
|
|
58
|
+
const [operatorRole, targetRole] = await Promise.all([
|
|
59
|
+
getMemberRole(runtime.bot, runtime.groupId, operatorUserId),
|
|
60
|
+
getMemberRole(runtime.bot, runtime.groupId, targetUserId),
|
|
61
|
+
]);
|
|
51
62
|
if (operatorRole !== targetRole) return null;
|
|
52
63
|
|
|
53
64
|
return `无权操作同级成员:操作人与被操作人均为${formatGroupRole(operatorRole)}`;
|
|
@@ -94,108 +105,74 @@ const groupAdminSkill: AISkill = {
|
|
|
94
105
|
},
|
|
95
106
|
required: ["action"],
|
|
96
107
|
},
|
|
97
|
-
handler: async (args:
|
|
98
|
-
const runtime =
|
|
108
|
+
handler: async (args: unknown, runtimeCtx?: SkillRuntimeContext) => {
|
|
109
|
+
const runtime = resolveGroupRuntime(runtimeCtx);
|
|
99
110
|
if ("error" in runtime) return { error: runtime.error };
|
|
100
|
-
const { bot,
|
|
101
|
-
const action = String(args?.action
|
|
111
|
+
const { bot, groupId, event } = runtime;
|
|
112
|
+
const action = String((args as { action?: unknown })?.action ?? "");
|
|
102
113
|
|
|
103
114
|
try {
|
|
104
115
|
switch (action) {
|
|
105
116
|
case "kick": {
|
|
106
|
-
const userId = Number(args?.user_id);
|
|
117
|
+
const userId = Number((args as { user_id?: unknown })?.user_id);
|
|
107
118
|
if (!userId) return { error: "kick 需要提供 user_id" };
|
|
108
|
-
const permErr = await checkDangerousTargetPermission(
|
|
109
|
-
runtime,
|
|
110
|
-
userId,
|
|
111
|
-
);
|
|
119
|
+
const permErr = await checkDangerousTargetPermission(runtime, userId);
|
|
112
120
|
if (permErr) return { error: permErr };
|
|
113
|
-
await bot.
|
|
114
|
-
group_id: groupId,
|
|
115
|
-
user_id: userId,
|
|
116
|
-
});
|
|
121
|
+
await bot.kickMember(groupId, userId);
|
|
117
122
|
return { success: true, message: `已将 ${userId} 移出当前群` };
|
|
118
123
|
}
|
|
119
124
|
case "mute": {
|
|
120
|
-
const userId = Number(args?.user_id);
|
|
125
|
+
const userId = Number((args as { user_id?: unknown })?.user_id);
|
|
121
126
|
if (!userId) return { error: "mute 需要提供 user_id" };
|
|
122
|
-
const permErr = await checkDangerousTargetPermission(
|
|
123
|
-
runtime,
|
|
124
|
-
userId,
|
|
125
|
-
);
|
|
127
|
+
const permErr = await checkDangerousTargetPermission(runtime, userId);
|
|
126
128
|
if (permErr) return { error: permErr };
|
|
127
129
|
const duration =
|
|
128
|
-
Number(args
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
};
|
|
130
|
+
Number((args as { duration?: unknown })?.duration) > 0
|
|
131
|
+
? Number((args as { duration?: unknown }).duration)
|
|
132
|
+
: 10 * 60;
|
|
133
|
+
await bot.banMember(groupId, userId, duration);
|
|
134
|
+
return { success: true, message: `已禁言 ${userId} ${duration}秒` };
|
|
134
135
|
}
|
|
135
136
|
case "unmute": {
|
|
136
|
-
const userId = Number(args?.user_id);
|
|
137
|
+
const userId = Number((args as { user_id?: unknown })?.user_id);
|
|
137
138
|
if (!userId) return { error: "unmute 需要提供 user_id" };
|
|
138
|
-
await bot.
|
|
139
|
+
await bot.banMember(groupId, userId, 0);
|
|
139
140
|
return { success: true, message: `已解除 ${userId} 的禁言` };
|
|
140
141
|
}
|
|
141
142
|
case "set_admin": {
|
|
142
|
-
const userId = Number(args?.user_id);
|
|
143
|
+
const userId = Number((args as { user_id?: unknown })?.user_id);
|
|
143
144
|
if (!userId) return { error: "set_admin 需要提供 user_id" };
|
|
144
|
-
await bot.
|
|
145
|
-
|
|
146
|
-
user_id: userId,
|
|
147
|
-
enable: true,
|
|
148
|
-
});
|
|
149
|
-
return {
|
|
150
|
-
success: true,
|
|
151
|
-
message: `已将 ${userId} 设为当前群的管理员`,
|
|
152
|
-
};
|
|
145
|
+
await bot.setMemberAdmin(groupId, userId, true);
|
|
146
|
+
return { success: true, message: `已将 ${userId} 设为当前群的管理员` };
|
|
153
147
|
}
|
|
154
148
|
case "unset_admin": {
|
|
155
|
-
const userId = Number(args?.user_id);
|
|
149
|
+
const userId = Number((args as { user_id?: unknown })?.user_id);
|
|
156
150
|
if (!userId) return { error: "unset_admin 需要提供 user_id" };
|
|
157
|
-
await bot.
|
|
158
|
-
|
|
159
|
-
user_id: userId,
|
|
160
|
-
enable: false,
|
|
161
|
-
});
|
|
162
|
-
return {
|
|
163
|
-
success: true,
|
|
164
|
-
message: `已取消 ${userId} 在当前群的管理员`,
|
|
165
|
-
};
|
|
151
|
+
await bot.setMemberAdmin(groupId, userId, false);
|
|
152
|
+
return { success: true, message: `已取消 ${userId} 在当前群的管理员` };
|
|
166
153
|
}
|
|
167
154
|
case "set_title": {
|
|
168
|
-
const userId = Number(args?.user_id);
|
|
169
|
-
const title = String(args?.title
|
|
155
|
+
const userId = Number((args as { user_id?: unknown })?.user_id);
|
|
156
|
+
const title = String((args as { title?: unknown })?.title ?? "").trim();
|
|
170
157
|
if (!userId || !title) {
|
|
171
158
|
return { error: "set_title 需要提供 user_id 和 title" };
|
|
172
159
|
}
|
|
173
|
-
await
|
|
174
|
-
return {
|
|
175
|
-
success: true,
|
|
176
|
-
message: `已将 ${userId} 的头衔设为 "${title}"`,
|
|
177
|
-
};
|
|
160
|
+
await bot.setMemberTitle(groupId, userId, title);
|
|
161
|
+
return { success: true, message: `已将 ${userId} 的头衔设为 "${title}"` };
|
|
178
162
|
}
|
|
179
163
|
case "set_self_title": {
|
|
180
|
-
const userId = Number(event
|
|
164
|
+
const userId = Number(event.user_id);
|
|
181
165
|
if (!userId) return { error: "无法获取当前用户ID" };
|
|
182
|
-
const title = String(args?.title
|
|
166
|
+
const title = String((args as { title?: unknown })?.title ?? "").trim();
|
|
183
167
|
if (!title) return { error: "set_self_title 需要提供 title" };
|
|
184
|
-
await
|
|
185
|
-
return {
|
|
186
|
-
success: true,
|
|
187
|
-
message: `已将你的头衔设为 "${title}"`,
|
|
188
|
-
};
|
|
168
|
+
await bot.setMemberTitle(groupId, userId, title);
|
|
169
|
+
return { success: true, message: `已将你的头衔设为 "${title}"` };
|
|
189
170
|
}
|
|
190
171
|
default:
|
|
191
172
|
return { error: `未知的 action: ${action}` };
|
|
192
173
|
}
|
|
193
174
|
} catch (err) {
|
|
194
|
-
logAdminSkillError(
|
|
195
|
-
runtimeCtx,
|
|
196
|
-
`admin_group.manage_member.${action}`,
|
|
197
|
-
err,
|
|
198
|
-
);
|
|
175
|
+
logAdminSkillError(runtimeCtx, `admin_group.manage_member.${action}`, err);
|
|
199
176
|
return { error: `执行 ${action} 失败: ${err}` };
|
|
200
177
|
}
|
|
201
178
|
},
|
|
@@ -240,87 +217,58 @@ const groupAdminSkill: AISkill = {
|
|
|
240
217
|
},
|
|
241
218
|
required: ["action"],
|
|
242
219
|
},
|
|
243
|
-
handler: async (args:
|
|
244
|
-
const runtime =
|
|
220
|
+
handler: async (args: unknown, runtimeCtx?: SkillRuntimeContext) => {
|
|
221
|
+
const runtime = resolveGroupRuntime(runtimeCtx);
|
|
245
222
|
if ("error" in runtime) return { error: runtime.error };
|
|
246
|
-
const { bot,
|
|
247
|
-
const action = String(args?.action
|
|
223
|
+
const { bot, groupId, selfId } = runtime;
|
|
224
|
+
const action = String((args as { action?: unknown })?.action ?? "");
|
|
248
225
|
|
|
249
226
|
try {
|
|
250
227
|
switch (action) {
|
|
251
228
|
case "set_whole_ban":
|
|
252
|
-
await bot.
|
|
253
|
-
group_id: groupId,
|
|
254
|
-
enable: true,
|
|
255
|
-
});
|
|
229
|
+
await bot.setGroupWholeBan(groupId, true);
|
|
256
230
|
return { success: true, message: "当前群已开启全体禁言" };
|
|
257
231
|
case "unset_whole_ban":
|
|
258
|
-
await bot.
|
|
259
|
-
group_id: groupId,
|
|
260
|
-
enable: false,
|
|
261
|
-
});
|
|
232
|
+
await bot.setGroupWholeBan(groupId, false);
|
|
262
233
|
return { success: true, message: "当前群已关闭全体禁言" };
|
|
263
234
|
case "set_group_name": {
|
|
264
|
-
const groupName = String(args?.group_name
|
|
265
|
-
if (!groupName)
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
group_id: groupId,
|
|
269
|
-
group_name: groupName,
|
|
270
|
-
});
|
|
271
|
-
return {
|
|
272
|
-
success: true,
|
|
273
|
-
message: `当前群名称已修改为 ${groupName}`,
|
|
274
|
-
};
|
|
235
|
+
const groupName = String((args as { group_name?: unknown })?.group_name ?? "").trim();
|
|
236
|
+
if (!groupName) return { error: "set_group_name 需要提供 group_name" };
|
|
237
|
+
await bot.setGroupName(groupId, groupName);
|
|
238
|
+
return { success: true, message: `当前群名称已修改为 ${groupName}` };
|
|
275
239
|
}
|
|
276
240
|
case "set_self_card": {
|
|
277
|
-
const card = String(args?.card
|
|
241
|
+
const card = String((args as { card?: unknown })?.card ?? "").trim();
|
|
278
242
|
if (!card) return { error: "set_self_card 需要提供 card" };
|
|
279
|
-
await bot.
|
|
280
|
-
return {
|
|
281
|
-
success: true,
|
|
282
|
-
message: `Bot在当前群的群名片已修改为 ${card}`,
|
|
283
|
-
};
|
|
243
|
+
await bot.setMemberCard(groupId, selfId, card);
|
|
244
|
+
return { success: true, message: `Bot在当前群的群名片已修改为 ${card}` };
|
|
284
245
|
}
|
|
285
246
|
case "set_group_avatar": {
|
|
286
|
-
const messageId = Number(args?.message_id);
|
|
247
|
+
const messageId = Number((args as { message_id?: unknown })?.message_id);
|
|
287
248
|
if (!Number.isFinite(messageId) || messageId <= 0) {
|
|
288
249
|
return { error: "set_group_avatar 需要提供有效的 message_id" };
|
|
289
250
|
}
|
|
290
251
|
const imageUrl = await getImageUrlByMessageId(bot, messageId);
|
|
291
|
-
if (!imageUrl) {
|
|
292
|
-
|
|
293
|
-
}
|
|
294
|
-
await bot.api("set_group_portrait", {
|
|
295
|
-
group_id: groupId,
|
|
296
|
-
file: imageUrl,
|
|
297
|
-
});
|
|
252
|
+
if (!imageUrl) return { error: "指定 message_id 中未找到图片" };
|
|
253
|
+
await bot.setGroupPortrait(groupId, imageUrl);
|
|
298
254
|
return { success: true, message: "当前群头像已修改" };
|
|
299
255
|
}
|
|
300
256
|
case "recall_messages": {
|
|
301
|
-
const ids = Array.isArray(args?.message_ids)
|
|
302
|
-
? args.message_ids
|
|
303
|
-
.map((v
|
|
304
|
-
.filter((n
|
|
257
|
+
const ids = Array.isArray((args as { message_ids?: unknown })?.message_ids)
|
|
258
|
+
? ((args as { message_ids: unknown[] }).message_ids)
|
|
259
|
+
.map((v) => Number(v))
|
|
260
|
+
.filter((n) => Number.isFinite(n) && n !== 0)
|
|
305
261
|
: [];
|
|
306
262
|
if (ids.length === 0) {
|
|
307
263
|
return { error: "recall_messages 需要提供至少一个 message_id" };
|
|
308
264
|
}
|
|
309
|
-
const results: Array<{
|
|
310
|
-
message_id: number;
|
|
311
|
-
success: boolean;
|
|
312
|
-
error?: string;
|
|
313
|
-
}> = [];
|
|
265
|
+
const results: Array<{ message_id: number; success: boolean; error?: string }> = [];
|
|
314
266
|
for (const id of ids) {
|
|
315
267
|
try {
|
|
316
|
-
await bot.
|
|
268
|
+
await bot.recallMessage(id);
|
|
317
269
|
results.push({ message_id: id, success: true });
|
|
318
270
|
} catch (err) {
|
|
319
|
-
results.push({
|
|
320
|
-
message_id: id,
|
|
321
|
-
success: false,
|
|
322
|
-
error: String(err),
|
|
323
|
-
});
|
|
271
|
+
results.push({ message_id: id, success: false, error: String(err) });
|
|
324
272
|
}
|
|
325
273
|
}
|
|
326
274
|
const ok = results.filter((r) => r.success).length;
|
|
@@ -334,11 +282,7 @@ const groupAdminSkill: AISkill = {
|
|
|
334
282
|
return { error: `未知的 action: ${action}` };
|
|
335
283
|
}
|
|
336
284
|
} catch (err) {
|
|
337
|
-
logAdminSkillError(
|
|
338
|
-
runtimeCtx,
|
|
339
|
-
`admin_group.manage_group.${action}`,
|
|
340
|
-
err,
|
|
341
|
-
);
|
|
285
|
+
logAdminSkillError(runtimeCtx, `admin_group.manage_group.${action}`, err);
|
|
342
286
|
return { error: `执行 ${action} 失败: ${err}` };
|
|
343
287
|
}
|
|
344
288
|
},
|
|
@@ -346,4 +290,4 @@ const groupAdminSkill: AISkill = {
|
|
|
346
290
|
],
|
|
347
291
|
};
|
|
348
292
|
|
|
349
|
-
export default groupAdminSkill;
|
|
293
|
+
export default groupAdminSkill;
|
package/skills/message-image.ts
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
|
+
import type { Bot } from "mioku";
|
|
2
|
+
|
|
1
3
|
export async function getImageUrlByMessageId(
|
|
2
|
-
bot:
|
|
4
|
+
bot: Bot,
|
|
3
5
|
messageId: number,
|
|
4
6
|
): Promise<string | null> {
|
|
5
7
|
try {
|
|
6
|
-
const msg =
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
: await bot.api("get_msg", { message_id: messageId });
|
|
8
|
+
const msg = await bot.sendApi<{
|
|
9
|
+
message?: Array<{ type?: string; url?: string; file?: string }>;
|
|
10
|
+
}>("get_msg", { message_id: messageId });
|
|
10
11
|
const segments = Array.isArray(msg?.message) ? msg.message : [];
|
|
11
|
-
const imageSeg = segments.find((seg
|
|
12
|
-
if (!imageSeg)
|
|
13
|
-
return null;
|
|
14
|
-
}
|
|
12
|
+
const imageSeg = segments.find((seg) => seg?.type === "image");
|
|
13
|
+
if (!imageSeg) return null;
|
|
15
14
|
|
|
16
15
|
return imageSeg.url || imageSeg.file || null;
|
|
17
16
|
} catch {
|
package/skills/personal.ts
CHANGED
|
@@ -1,18 +1,30 @@
|
|
|
1
|
-
import type { AISkill } from "mioku";
|
|
1
|
+
import type { AISkill, Bot, MessageEvent } from "mioku";
|
|
2
|
+
|
|
2
3
|
import { getImageUrlByMessageId } from "./message-image";
|
|
3
4
|
|
|
5
|
+
import type { MessageSegment } from "mioku";
|
|
6
|
+
|
|
7
|
+
interface SkillRuntimeContext {
|
|
8
|
+
ctx?: {
|
|
9
|
+
segment: { text(text: string): MessageSegment };
|
|
10
|
+
logger?: { error?: (...args: unknown[]) => void };
|
|
11
|
+
};
|
|
12
|
+
event?: MessageEvent;
|
|
13
|
+
rawEvent?: MessageEvent;
|
|
14
|
+
}
|
|
15
|
+
|
|
4
16
|
function parseProfileSex(value: string): 0 | 1 | 2 {
|
|
5
|
-
const normalized = String(value || "")
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
if (normalized === "男" || normalized === "male" || normalized === "1")
|
|
9
|
-
return 1;
|
|
10
|
-
if (normalized === "女" || normalized === "female" || normalized === "2")
|
|
11
|
-
return 2;
|
|
17
|
+
const normalized = String(value || "").trim().toLowerCase();
|
|
18
|
+
if (normalized === "男" || normalized === "male" || normalized === "1") return 1;
|
|
19
|
+
if (normalized === "女" || normalized === "female" || normalized === "2") return 2;
|
|
12
20
|
return 0;
|
|
13
21
|
}
|
|
14
22
|
|
|
15
|
-
function logAdminSkillError(
|
|
23
|
+
function logAdminSkillError(
|
|
24
|
+
runtimeCtx: SkillRuntimeContext | undefined,
|
|
25
|
+
toolName: string,
|
|
26
|
+
err: unknown,
|
|
27
|
+
) {
|
|
16
28
|
runtimeCtx?.ctx?.logger?.error?.(
|
|
17
29
|
`[admin skills] ${toolName} failed: ${String(err)}`,
|
|
18
30
|
);
|
|
@@ -51,10 +63,7 @@ const personalSkill: AISkill = {
|
|
|
51
63
|
type: "number",
|
|
52
64
|
description: "包含图片的消息 message_id,仅 set_avatar 需要",
|
|
53
65
|
},
|
|
54
|
-
nickname: {
|
|
55
|
-
type: "string",
|
|
56
|
-
description: "新昵称,仅 set_nickname 需要",
|
|
57
|
-
},
|
|
66
|
+
nickname: { type: "string", description: "新昵称,仅 set_nickname 需要" },
|
|
58
67
|
personal_note: {
|
|
59
68
|
type: "string",
|
|
60
69
|
description: "新个性签名,仅 set_signature 需要",
|
|
@@ -79,94 +88,72 @@ const personalSkill: AISkill = {
|
|
|
79
88
|
},
|
|
80
89
|
required: ["action"],
|
|
81
90
|
},
|
|
82
|
-
handler: async (args:
|
|
91
|
+
handler: async (args: unknown, runtimeCtx?: SkillRuntimeContext) => {
|
|
83
92
|
const ctx = runtimeCtx?.ctx;
|
|
84
93
|
if (!ctx) return { error: "无法获取上下文" };
|
|
85
|
-
const event = runtimeCtx?.event
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
const bot = ctx.pickBot(selfId);
|
|
94
|
+
const event = runtimeCtx?.event ?? runtimeCtx?.rawEvent;
|
|
95
|
+
if (!event) return { error: "无法获取事件" };
|
|
96
|
+
const bot = event.bot;
|
|
89
97
|
if (!bot) return { error: "Bot不可用" };
|
|
90
|
-
const
|
|
98
|
+
const a = args as Record<string, unknown>;
|
|
99
|
+
const action = String(a?.action ?? "");
|
|
91
100
|
|
|
92
101
|
try {
|
|
93
102
|
switch (action) {
|
|
94
103
|
case "set_avatar": {
|
|
95
|
-
const messageId = Number(
|
|
104
|
+
const messageId = Number(a?.message_id);
|
|
96
105
|
if (!Number.isFinite(messageId) || messageId <= 0) {
|
|
97
106
|
return { error: "set_avatar 需要提供有效的 message_id" };
|
|
98
107
|
}
|
|
99
108
|
const imageUrl = await getImageUrlByMessageId(bot, messageId);
|
|
100
|
-
if (!imageUrl) {
|
|
101
|
-
|
|
102
|
-
}
|
|
103
|
-
await bot.api("set_qq_avatar", { file: imageUrl });
|
|
109
|
+
if (!imageUrl) return { error: "指定 message_id 中未找到图片" };
|
|
110
|
+
await bot.setAvatar(imageUrl);
|
|
104
111
|
return { success: true, message: "Bot头像已修改" };
|
|
105
112
|
}
|
|
106
113
|
case "set_nickname": {
|
|
107
|
-
const nickname = String(
|
|
108
|
-
if (!nickname) {
|
|
109
|
-
|
|
110
|
-
}
|
|
111
|
-
await bot.api("set_qq_profile", { nickname });
|
|
112
|
-
return {
|
|
113
|
-
success: true,
|
|
114
|
-
message: `Bot昵称已修改为: ${nickname}`,
|
|
115
|
-
};
|
|
114
|
+
const nickname = String(a?.nickname ?? "").trim();
|
|
115
|
+
if (!nickname) return { error: "set_nickname 需要提供 nickname" };
|
|
116
|
+
await bot.setProfile({ nickname });
|
|
117
|
+
return { success: true, message: `Bot昵称已修改为: ${nickname}` };
|
|
116
118
|
}
|
|
117
119
|
case "set_signature": {
|
|
118
|
-
const personalNote = String(
|
|
119
|
-
if (!personalNote) {
|
|
120
|
-
|
|
121
|
-
}
|
|
122
|
-
await bot.api("set_qq_profile", { personal_note: personalNote });
|
|
120
|
+
const personalNote = String(a?.personal_note ?? "").trim();
|
|
121
|
+
if (!personalNote) return { error: "set_signature 需要提供 personal_note" };
|
|
122
|
+
await bot.setProfile({ personal_note: personalNote });
|
|
123
123
|
return { success: true, message: "Bot个性签名已修改" };
|
|
124
124
|
}
|
|
125
125
|
case "set_gender": {
|
|
126
|
-
const sex = parseProfileSex(
|
|
127
|
-
await bot.
|
|
128
|
-
const genderMap: Record<number, string> = {
|
|
129
|
-
|
|
130
|
-
1: "男",
|
|
131
|
-
2: "女",
|
|
132
|
-
};
|
|
133
|
-
return {
|
|
134
|
-
success: true,
|
|
135
|
-
message: `Bot性别已修改为: ${genderMap[sex]}`,
|
|
136
|
-
};
|
|
126
|
+
const sex = parseProfileSex(String(a?.gender ?? ""));
|
|
127
|
+
await bot.setProfile({ sex });
|
|
128
|
+
const genderMap: Record<number, string> = { 0: "无", 1: "男", 2: "女" };
|
|
129
|
+
return { success: true, message: `Bot性别已修改为: ${genderMap[sex]}` };
|
|
137
130
|
}
|
|
138
131
|
case "send_private": {
|
|
139
|
-
const userId = Number(
|
|
140
|
-
const content = String(
|
|
141
|
-
if (!userId || !content) {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
message: `已发送私聊消息给 ${userId}`,
|
|
148
|
-
};
|
|
132
|
+
const userId = Number(a?.user_id);
|
|
133
|
+
const content = String(a?.content ?? "");
|
|
134
|
+
if (!userId || !content) return { error: "send_private 需要提供 user_id 和 content" };
|
|
135
|
+
await bot.sendMessage(
|
|
136
|
+
{ type: "private", user_id: userId},
|
|
137
|
+
[ctx.segment.text(content)],
|
|
138
|
+
);
|
|
139
|
+
return { success: true, message: `已发送私聊消息给 ${userId}` };
|
|
149
140
|
}
|
|
150
141
|
case "send_group": {
|
|
151
|
-
const groupId = Number(
|
|
152
|
-
const content = String(
|
|
153
|
-
if (!groupId || !content) {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
message: `已发送群消息到 ${groupId}`,
|
|
160
|
-
};
|
|
142
|
+
const groupId = Number(a?.group_id);
|
|
143
|
+
const content = String(a?.content ?? "");
|
|
144
|
+
if (!groupId || !content) return { error: "send_group 需要提供 group_id 和 content" };
|
|
145
|
+
await bot.sendMessage(
|
|
146
|
+
{ type: "group", group_id: groupId},
|
|
147
|
+
[ctx.segment.text(content)],
|
|
148
|
+
);
|
|
149
|
+
return { success: true, message: `已发送群消息到 ${groupId}` };
|
|
161
150
|
}
|
|
162
151
|
case "list_friends": {
|
|
163
|
-
if (event?.message_type === "group") {
|
|
164
|
-
|
|
165
|
-
}
|
|
166
|
-
const friendList: any[] = await bot.api("get_friend_list");
|
|
152
|
+
if (event?.message_type === "group") return { error: "在私聊使用试试看吧~" };
|
|
153
|
+
const friendList = await bot.getFriendList();
|
|
167
154
|
if (!Array.isArray(friendList)) return { friends: [] };
|
|
168
155
|
return {
|
|
169
|
-
friends: friendList.map((f) => ({
|
|
156
|
+
friends: friendList.map((f: { user_id?: unknown; nickname?: unknown; remark?: unknown }) => ({
|
|
170
157
|
user_id: f.user_id,
|
|
171
158
|
nickname: f.nickname,
|
|
172
159
|
remark: f.remark,
|
|
@@ -174,13 +161,11 @@ const personalSkill: AISkill = {
|
|
|
174
161
|
};
|
|
175
162
|
}
|
|
176
163
|
case "list_groups": {
|
|
177
|
-
if (event?.message_type === "group") {
|
|
178
|
-
|
|
179
|
-
}
|
|
180
|
-
const groupList: any[] = await bot.api("get_group_list");
|
|
164
|
+
if (event?.message_type === "group") return { error: "在私聊使用试试看吧~" };
|
|
165
|
+
const groupList = await bot.getGroupList();
|
|
181
166
|
if (!Array.isArray(groupList)) return { groups: [] };
|
|
182
167
|
return {
|
|
183
|
-
groups: groupList.map((g) => ({
|
|
168
|
+
groups: groupList.map((g: { group_id?: unknown; group_name?: unknown; member_count?: unknown }) => ({
|
|
184
169
|
group_id: g.group_id,
|
|
185
170
|
group_name: g.group_name,
|
|
186
171
|
member_count: g.member_count,
|
|
@@ -188,33 +173,22 @@ const personalSkill: AISkill = {
|
|
|
188
173
|
};
|
|
189
174
|
}
|
|
190
175
|
case "delete_friend": {
|
|
191
|
-
const userId = Number(
|
|
192
|
-
if (!userId) {
|
|
193
|
-
|
|
194
|
-
}
|
|
195
|
-
await bot.api("delete_friend", { user_id: userId });
|
|
176
|
+
const userId = Number(a?.user_id);
|
|
177
|
+
if (!userId) return { error: "delete_friend 需要提供 user_id" };
|
|
178
|
+
await bot.deleteFriend(userId);
|
|
196
179
|
return { success: true, message: `已删除好友 ${userId}` };
|
|
197
180
|
}
|
|
198
181
|
case "leave_group": {
|
|
199
|
-
const groupId = Number(
|
|
200
|
-
if (!groupId) {
|
|
201
|
-
|
|
202
|
-
}
|
|
203
|
-
await bot.api("set_group_leave", {
|
|
204
|
-
group_id: groupId,
|
|
205
|
-
is_dismiss: false,
|
|
206
|
-
});
|
|
182
|
+
const groupId = Number(a?.group_id);
|
|
183
|
+
if (!groupId) return { error: "leave_group 需要提供 group_id" };
|
|
184
|
+
await bot.leaveGroup(groupId, false);
|
|
207
185
|
return { success: true, message: `已退出群 ${groupId}` };
|
|
208
186
|
}
|
|
209
187
|
default:
|
|
210
188
|
return { error: `未知的 action: ${action}` };
|
|
211
189
|
}
|
|
212
190
|
} catch (err) {
|
|
213
|
-
logAdminSkillError(
|
|
214
|
-
runtimeCtx,
|
|
215
|
-
`admin_personal.manage_personal.${action}`,
|
|
216
|
-
err,
|
|
217
|
-
);
|
|
191
|
+
logAdminSkillError(runtimeCtx, `admin_personal.manage_personal.${action}`, err);
|
|
218
192
|
return { error: `执行 ${action} 失败: ${err}` };
|
|
219
193
|
}
|
|
220
194
|
},
|
|
@@ -222,4 +196,4 @@ const personalSkill: AISkill = {
|
|
|
222
196
|
],
|
|
223
197
|
};
|
|
224
198
|
|
|
225
|
-
export default personalSkill;
|
|
199
|
+
export default personalSkill;
|
package/verify/chiral.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { MiokuContext } from "mioku";
|
|
2
2
|
import type { VerifyConfig } from "./config";
|
|
3
3
|
import type { PendingVerify } from "./types";
|
|
4
4
|
|
|
@@ -41,11 +41,11 @@ async function fetchChiralCaptcha(
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
export async function prepareChiral(
|
|
44
|
-
ctx:
|
|
44
|
+
ctx: MiokuContext,
|
|
45
45
|
cfg: VerifyConfig,
|
|
46
46
|
p: PendingVerify,
|
|
47
47
|
): Promise<boolean> {
|
|
48
|
-
const bot =
|
|
48
|
+
const bot = p.bot;
|
|
49
49
|
if (!bot) return false;
|
|
50
50
|
try {
|
|
51
51
|
const captcha = await fetchChiralCaptcha(cfg.chiralApiUrl, cfg.chiralDifficulty);
|
|
@@ -55,7 +55,7 @@ export async function prepareChiral(
|
|
|
55
55
|
"{count}",
|
|
56
56
|
String(captcha.regions.length),
|
|
57
57
|
);
|
|
58
|
-
await bot.
|
|
58
|
+
await bot.sendMessage({ type: "group", group_id: p.groupId}, [
|
|
59
59
|
ctx.segment.at(String(p.userId)),
|
|
60
60
|
ctx.segment.text(` ${prompt}`),
|
|
61
61
|
ctx.segment.image(captcha.imageDataUrl),
|