mioku-plugin-help 3.0.4 → 3.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/help/image.ts +22 -6
- package/help/intent.ts +4 -4
- package/help/role.ts +7 -6
- package/index.ts +4 -4
- package/package.json +1 -1
- package/skills/help.ts +1 -1
- package/skills/status.ts +1 -1
- package/status/data-collector.ts +9 -1
- package/status/intent.ts +2 -2
package/help/image.ts
CHANGED
|
@@ -108,24 +108,40 @@ export async function generateHelpImage(options: {
|
|
|
108
108
|
* Pick a bot's nickname + avatar URL. Used so the help card can greet
|
|
109
109
|
* the user with their bot's identity rather than a generic string.
|
|
110
110
|
*/
|
|
111
|
-
export function resolveHelpBotProfile(
|
|
111
|
+
export async function resolveHelpBotProfile(
|
|
112
112
|
ctx: any,
|
|
113
113
|
event?: any,
|
|
114
|
-
): { botNickname: string; botAvatarUrl?: string } {
|
|
114
|
+
): Promise<{ botNickname: string; botAvatarUrl?: string }> {
|
|
115
115
|
const fallbackNickname = "Mioku Bot";
|
|
116
116
|
const selfId = event?.self_id;
|
|
117
117
|
const bot =
|
|
118
118
|
event?.bot ??
|
|
119
119
|
(ctx?.bots instanceof Map ? Array.from(ctx.bots.values())[0] : null);
|
|
120
|
-
const botId = selfId
|
|
120
|
+
const botId = String(selfId ?? bot?.bot_id ?? "").trim();
|
|
121
121
|
const botNickname = bot?.nickname || bot?.name || fallbackNickname;
|
|
122
|
-
const botAvatarUrl = botId
|
|
123
|
-
? `https://q1.qlogo.cn/g?b=qq&nk=${botId}&s=640`
|
|
124
|
-
: undefined;
|
|
122
|
+
const botAvatarUrl = await resolveBotAvatar(bot, botId);
|
|
125
123
|
|
|
126
124
|
return { botNickname, botAvatarUrl };
|
|
127
125
|
}
|
|
128
126
|
|
|
127
|
+
/** QQ 系的 qlogo 头像服务只认数字 QQ 号,openid/AppID 一律走平台接口 */
|
|
128
|
+
export async function resolveBotAvatar(
|
|
129
|
+
bot: any,
|
|
130
|
+
botId: string,
|
|
131
|
+
): Promise<string | undefined> {
|
|
132
|
+
try {
|
|
133
|
+
const avatar = await bot?.getAvatar?.();
|
|
134
|
+
if (typeof avatar === "string" && avatar) return avatar;
|
|
135
|
+
} catch {
|
|
136
|
+
// 平台不支持时回退
|
|
137
|
+
}
|
|
138
|
+
const adapter = String(bot?.adapter ?? "");
|
|
139
|
+
if ((adapter === "onebotv11" || adapter === "icqq") && /^\d+$/.test(botId)) {
|
|
140
|
+
return `https://q1.qlogo.cn/g?b=qq&nk=${botId}&s=640`;
|
|
141
|
+
}
|
|
142
|
+
return undefined;
|
|
143
|
+
}
|
|
144
|
+
|
|
129
145
|
/**
|
|
130
146
|
* Reply to a chat event with a local image file. Falls back to base64
|
|
131
147
|
* encoding if the network adapter can't send a raw file path.
|
package/help/intent.ts
CHANGED
|
@@ -23,7 +23,7 @@ import type {
|
|
|
23
23
|
function sanitizeKeyword(value: string): string {
|
|
24
24
|
return String(value || "")
|
|
25
25
|
.trim()
|
|
26
|
-
.replace(/^[
|
|
26
|
+
.replace(/^[#/.\s]+/, "")
|
|
27
27
|
.replace(/[。.!!??,,::;);]+$/g, "");
|
|
28
28
|
}
|
|
29
29
|
|
|
@@ -55,15 +55,15 @@ function extractMatchTokens(text: string): string[] {
|
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
/**
|
|
58
|
-
* The first whitespace-separated token of a command, with the `#` /
|
|
59
|
-
* prefix removed. Used as an additional alias when matching plugin
|
|
58
|
+
* The first whitespace-separated token of a command, with the `.` / `#` /
|
|
59
|
+
* `/` prefix removed. Used as an additional alias when matching plugin
|
|
60
60
|
* commands. Returns null if the first token is empty, contains `<>` (a
|
|
61
61
|
* placeholder), or has no alphanumeric characters.
|
|
62
62
|
*/
|
|
63
63
|
function extractCommandAlias(command: string): string | null {
|
|
64
64
|
const value = String(command || "")
|
|
65
65
|
.trim()
|
|
66
|
-
.replace(/^[
|
|
66
|
+
.replace(/^[#/.]+/, "");
|
|
67
67
|
if (!value) {
|
|
68
68
|
return null;
|
|
69
69
|
}
|
package/help/role.ts
CHANGED
|
@@ -65,19 +65,20 @@ export async function resolveViewerRole(
|
|
|
65
65
|
return "admin";
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
const groupId = String(event?.group_id ?? "").trim();
|
|
69
|
+
const userId = String(event?.user_id ?? "").trim();
|
|
70
|
+
if (groupId && userId) {
|
|
69
71
|
const bot = event?.bot;
|
|
70
72
|
if (bot) {
|
|
71
73
|
try {
|
|
72
|
-
const info = await bot.getMemberInfo(
|
|
73
|
-
event.group_id,
|
|
74
|
-
event.user_id,
|
|
75
|
-
);
|
|
74
|
+
const info = await bot.getMemberInfo(groupId, userId);
|
|
76
75
|
if (info?.role === "owner" || info?.role === "admin") {
|
|
77
76
|
return "admin";
|
|
78
77
|
}
|
|
78
|
+
// 拿不到成员信息(null/空)时不能断言对方是普通成员,保守给 admin
|
|
79
|
+
if (!info?.role) return "admin";
|
|
79
80
|
} catch {
|
|
80
|
-
|
|
81
|
+
return "admin";
|
|
81
82
|
}
|
|
82
83
|
}
|
|
83
84
|
}
|
package/index.ts
CHANGED
|
@@ -87,7 +87,7 @@ const helpPlugin = definePlugin({
|
|
|
87
87
|
return;
|
|
88
88
|
}
|
|
89
89
|
try {
|
|
90
|
-
const { botNickname, botAvatarUrl } = resolveHelpBotProfile(
|
|
90
|
+
const { botNickname, botAvatarUrl } = await resolveHelpBotProfile(
|
|
91
91
|
ctx,
|
|
92
92
|
event,
|
|
93
93
|
);
|
|
@@ -129,7 +129,7 @@ const helpPlugin = definePlugin({
|
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
try {
|
|
132
|
-
const { botNickname, botAvatarUrl } = resolveHelpBotProfile(ctx, event);
|
|
132
|
+
const { botNickname, botAvatarUrl } = await resolveHelpBotProfile(ctx, event);
|
|
133
133
|
const viewerRole = await resolveViewerRole(ctx, event);
|
|
134
134
|
const imagePath = await generateHelpImage({
|
|
135
135
|
helpService,
|
|
@@ -160,7 +160,7 @@ const helpPlugin = definePlugin({
|
|
|
160
160
|
name: "help",
|
|
161
161
|
aliases: ["帮助", "菜单"],
|
|
162
162
|
match: /^(?:help|帮助|菜单)(?:\s|$)/i,
|
|
163
|
-
prefixes: ["#", "/", ""],
|
|
163
|
+
prefixes: [".", "#", "/", ""],
|
|
164
164
|
description: "生成帮助图片",
|
|
165
165
|
handler: ({ event }) => handleHelpMessage(event),
|
|
166
166
|
});
|
|
@@ -169,7 +169,7 @@ const helpPlugin = definePlugin({
|
|
|
169
169
|
name: "status",
|
|
170
170
|
aliases: ["状态", "zt"],
|
|
171
171
|
match: /^(?:status|状态|zt)(?:\s|$)/i,
|
|
172
|
-
prefixes: ["#", "/", ""],
|
|
172
|
+
prefixes: [".", "#", "/", ""],
|
|
173
173
|
description: "生成系统状态图片",
|
|
174
174
|
handler: ({ event }) => handleHelpMessage(event),
|
|
175
175
|
});
|
package/package.json
CHANGED
package/skills/help.ts
CHANGED
package/skills/status.ts
CHANGED
package/status/data-collector.ts
CHANGED
|
@@ -205,6 +205,14 @@ async function collectBots(
|
|
|
205
205
|
return collectBotStatuses(sorted, ctx, stdinAvatar);
|
|
206
206
|
}
|
|
207
207
|
|
|
208
|
+
/** QQ 系适配器的 bot_id 才是数字 QQ 号,qlogo 服务对 openid/AppID 无效 */
|
|
209
|
+
function qlogoAvatarUrl(adapter: string, botId: string): string {
|
|
210
|
+
if ((adapter === "onebotv11" || adapter === "icqq") && /^\d+$/.test(botId)) {
|
|
211
|
+
return `https://q1.qlogo.cn/g?b=qq&nk=${botId}&s=160`;
|
|
212
|
+
}
|
|
213
|
+
return "";
|
|
214
|
+
}
|
|
215
|
+
|
|
208
216
|
/** 把本地绝对路径 / http(s) / file:// 统一成可被截图服务加载的图片地址 */
|
|
209
217
|
function toImageSrc(value: string): string {
|
|
210
218
|
if (/^(https?:|file:|data:)/i.test(value)) return value;
|
|
@@ -274,7 +282,7 @@ async function collectBotStatuses(
|
|
|
274
282
|
? toImageSrc(stdinAvatar || "")
|
|
275
283
|
: avatarFromBot
|
|
276
284
|
? toImageSrc(avatarFromBot)
|
|
277
|
-
:
|
|
285
|
+
: qlogoAvatarUrl(adapter, uin),
|
|
278
286
|
adapter,
|
|
279
287
|
implLabel,
|
|
280
288
|
framework: isStdin ? adapter : framework,
|
package/status/intent.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { StatusIntent } from "./types";
|
|
|
3
3
|
/**
|
|
4
4
|
* Parse a user message into a `StatusIntent`.
|
|
5
5
|
*
|
|
6
|
-
* Recognized prefixes:
|
|
6
|
+
* Recognized prefixes: `.状态` / `/状态` / `#状态` / 裸 `状态` (also the
|
|
7
7
|
* Latin aliases `zt` / `status`). Anything trailing the leading token is
|
|
8
8
|
* ignored — the panel always renders the full sheet.
|
|
9
9
|
*
|
|
@@ -14,7 +14,7 @@ import type { StatusIntent } from "./types";
|
|
|
14
14
|
function stripStopword(input: string): string {
|
|
15
15
|
return String(input || "")
|
|
16
16
|
.trim()
|
|
17
|
-
.replace(/^[
|
|
17
|
+
.replace(/^[#/.\s]+/, "")
|
|
18
18
|
.replace(/[。.!!??,,::;);]+$/g, "");
|
|
19
19
|
}
|
|
20
20
|
|