mioku-plugin-help 2.3.0 → 2.3.3
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/role.ts +15 -4
- package/index.ts +14 -16
- package/package.json +1 -1
- package/skills/help.ts +93 -0
- package/skills/index.ts +7 -0
- package/skills/status.ts +63 -0
- package/runtime.ts +0 -25
- package/skills.ts +0 -149
package/help/role.ts
CHANGED
|
@@ -36,8 +36,14 @@ export function canInvokeCommand(
|
|
|
36
36
|
* mioki's `isOwner` allowlist.
|
|
37
37
|
* - Private chat skips the `isAdmin` check and defaults to `admin`,
|
|
38
38
|
* so anyone DM-ing the bot can see admin-level commands.
|
|
39
|
-
* - Group chat
|
|
40
|
-
* owner (group
|
|
39
|
+
* - Group chat resolves bot admin (mioki `isAdmin` allowlist), group
|
|
40
|
+
* owner (群主) and group admin (群管理) all to `admin`. This mirrors
|
|
41
|
+
* the admin plugin's execution gating (`isMaster || senderRole ===
|
|
42
|
+
* "owner" || senderRole === "admin"`) so the help image only hides
|
|
43
|
+
* commands the viewer genuinely can't run. `sender.role` is checked
|
|
44
|
+
* first (populated by OneBot on group events), with
|
|
45
|
+
* `getGroupMemberInfo` as a fallback when it's missing. Everyone else
|
|
46
|
+
* is `member`.
|
|
41
47
|
*/
|
|
42
48
|
export async function resolveViewerRole(
|
|
43
49
|
ctx: any,
|
|
@@ -54,6 +60,11 @@ export async function resolveViewerRole(
|
|
|
54
60
|
return "admin";
|
|
55
61
|
}
|
|
56
62
|
|
|
63
|
+
const senderRole = event?.sender?.role;
|
|
64
|
+
if (senderRole === "owner" || senderRole === "admin") {
|
|
65
|
+
return "admin";
|
|
66
|
+
}
|
|
67
|
+
|
|
57
68
|
if (event?.group_id != null && event?.user_id != null) {
|
|
58
69
|
const selfId =
|
|
59
70
|
event?.self_id != null ? Number(event.self_id) : undefined;
|
|
@@ -67,8 +78,8 @@ export async function resolveViewerRole(
|
|
|
67
78
|
event.group_id,
|
|
68
79
|
event.user_id,
|
|
69
80
|
);
|
|
70
|
-
if (info?.role === "owner") {
|
|
71
|
-
return "
|
|
81
|
+
if (info?.role === "owner" || info?.role === "admin") {
|
|
82
|
+
return "admin";
|
|
72
83
|
}
|
|
73
84
|
} catch {
|
|
74
85
|
// fall through to member
|
package/index.ts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import type { ConfigService } from "mioku";
|
|
2
|
-
import type { HelpService } from "mioku";
|
|
3
|
-
import type { ScreenshotService } from "mioku";
|
|
4
1
|
import { definePlugin, type MiokiContext } from "mioki";
|
|
2
|
+
import { getService, Services } from "mioku";
|
|
5
3
|
import * as path from "path";
|
|
6
4
|
import { HELP_DEMO_CONFIG } from "./demo-config";
|
|
7
5
|
import {
|
|
@@ -12,13 +10,13 @@ import {
|
|
|
12
10
|
resolveViewerRole,
|
|
13
11
|
} from "./help";
|
|
14
12
|
import { getRenderVersions } from "./utils";
|
|
15
|
-
import { resetHelpRuntimeState, setHelpRuntimeState } from "./runtime";
|
|
16
13
|
import {
|
|
17
14
|
generateStatusImage,
|
|
18
15
|
networkSampler,
|
|
19
16
|
perfMonitor,
|
|
20
17
|
resolveStatusIntent,
|
|
21
18
|
} from "./status";
|
|
19
|
+
import { createHelpSkills } from "./skills";
|
|
22
20
|
|
|
23
21
|
const helpPlugin = definePlugin({
|
|
24
22
|
name: "help",
|
|
@@ -30,18 +28,16 @@ const helpPlugin = definePlugin({
|
|
|
30
28
|
networkSampler.start();
|
|
31
29
|
perfMonitor.start();
|
|
32
30
|
|
|
33
|
-
const configService = ctx.
|
|
34
|
-
const helpService = ctx.
|
|
35
|
-
const screenshotService = ctx.
|
|
36
|
-
|
|
37
|
-
| undefined;
|
|
31
|
+
const configService = getService(ctx, Services.Config);
|
|
32
|
+
const helpService = getService(ctx, Services.Help);
|
|
33
|
+
const screenshotService = getService(ctx, Services.Screenshot);
|
|
34
|
+
const aiService = getService(ctx, Services.AI);
|
|
38
35
|
|
|
39
36
|
if (!helpService) {
|
|
40
37
|
ctx.logger.warn("help-service 未加载,帮助插件无法运行");
|
|
41
38
|
return () => {
|
|
42
39
|
networkSampler.stop();
|
|
43
40
|
perfMonitor.stop();
|
|
44
|
-
resetHelpRuntimeState();
|
|
45
41
|
ctx.logger.info("帮助插件已卸载");
|
|
46
42
|
};
|
|
47
43
|
}
|
|
@@ -69,12 +65,11 @@ const helpPlugin = definePlugin({
|
|
|
69
65
|
|
|
70
66
|
const { miokiVersion, miokuVersion } = await getRenderVersions();
|
|
71
67
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
});
|
|
68
|
+
if (aiService) {
|
|
69
|
+
for (const skill of createHelpSkills()) aiService.registerSkill(skill);
|
|
70
|
+
}
|
|
76
71
|
|
|
77
|
-
ctx.handle("message", async (event
|
|
72
|
+
ctx.handle("message", async (event) => {
|
|
78
73
|
const text = ctx.text(event);
|
|
79
74
|
if (!text) {
|
|
80
75
|
return;
|
|
@@ -159,7 +154,10 @@ const helpPlugin = definePlugin({
|
|
|
159
154
|
return () => {
|
|
160
155
|
networkSampler.stop();
|
|
161
156
|
perfMonitor.stop();
|
|
162
|
-
|
|
157
|
+
if (aiService) {
|
|
158
|
+
aiService.removeSkill("help");
|
|
159
|
+
aiService.removeSkill("status");
|
|
160
|
+
}
|
|
163
161
|
ctx.logger.info("帮助插件已卸载");
|
|
164
162
|
};
|
|
165
163
|
},
|
package/package.json
CHANGED
package/skills/help.ts
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import type { AISkill, AITool } from "mioku";
|
|
2
|
+
import type { HelpService, ScreenshotService } from "mioku";
|
|
3
|
+
import {
|
|
4
|
+
buildHelpInfoText,
|
|
5
|
+
generateHelpImage,
|
|
6
|
+
resolveHelpBotProfile,
|
|
7
|
+
resolveViewerRole,
|
|
8
|
+
sendImageFromSkillContext,
|
|
9
|
+
} from "../help";
|
|
10
|
+
import { getRenderVersions } from "../utils";
|
|
11
|
+
|
|
12
|
+
export function createHelpSkill(): AISkill {
|
|
13
|
+
return {
|
|
14
|
+
name: "help",
|
|
15
|
+
description: "获取插件帮助信息和发送帮助图片",
|
|
16
|
+
permission: "member",
|
|
17
|
+
tools: [
|
|
18
|
+
{
|
|
19
|
+
name: "get_help_info",
|
|
20
|
+
description:
|
|
21
|
+
"获取所有插件的帮助信息文本,这个仅用于用户向你询问某个功能的具体用法时使用",
|
|
22
|
+
parameters: {
|
|
23
|
+
type: "object",
|
|
24
|
+
properties: {},
|
|
25
|
+
required: [],
|
|
26
|
+
},
|
|
27
|
+
handler: async (_args: any, runtimeCtx?: any) => {
|
|
28
|
+
const ctx = runtimeCtx?.ctx;
|
|
29
|
+
const helpService = ctx?.services?.help as HelpService | undefined;
|
|
30
|
+
if (!helpService) {
|
|
31
|
+
return "help-service 未加载,无法获取帮助信息";
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return buildHelpInfoText(helpService.getAllHelp());
|
|
35
|
+
},
|
|
36
|
+
} as AITool,
|
|
37
|
+
{
|
|
38
|
+
name: "send_help_image",
|
|
39
|
+
description:
|
|
40
|
+
"生成并发送帮助图片到群聊,如果有人说他想看帮助,优先调用图片发送而不是自己查看帮助。",
|
|
41
|
+
parameters: {
|
|
42
|
+
type: "object",
|
|
43
|
+
properties: {},
|
|
44
|
+
required: [],
|
|
45
|
+
},
|
|
46
|
+
handler: async (_args: any, runtimeCtx?: any) => {
|
|
47
|
+
const ctx = runtimeCtx?.ctx;
|
|
48
|
+
const event = runtimeCtx?.event || runtimeCtx?.rawEvent;
|
|
49
|
+
const helpService = ctx?.services?.help as HelpService | undefined;
|
|
50
|
+
const screenshotService = ctx?.services?.screenshot as
|
|
51
|
+
| ScreenshotService
|
|
52
|
+
| undefined;
|
|
53
|
+
const { miokiVersion, miokuVersion } = await getRenderVersions();
|
|
54
|
+
|
|
55
|
+
if (!screenshotService) {
|
|
56
|
+
return "screenshot 服务未加载,无法生成帮助图片";
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
const { botNickname, botAvatarUrl } = resolveHelpBotProfile(
|
|
61
|
+
ctx,
|
|
62
|
+
event,
|
|
63
|
+
);
|
|
64
|
+
const viewerRole = await resolveViewerRole(ctx, event);
|
|
65
|
+
const imagePath = await generateHelpImage({
|
|
66
|
+
helpService,
|
|
67
|
+
screenshotService,
|
|
68
|
+
miokiVersion,
|
|
69
|
+
miokuVersion,
|
|
70
|
+
botNickname,
|
|
71
|
+
botAvatarUrl,
|
|
72
|
+
viewerRole,
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
if (!imagePath) {
|
|
76
|
+
return "生成帮助图片失败";
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
await sendImageFromSkillContext({
|
|
80
|
+
ctx,
|
|
81
|
+
event,
|
|
82
|
+
imagePath,
|
|
83
|
+
quoteReply: false,
|
|
84
|
+
});
|
|
85
|
+
return "已发送帮助图片";
|
|
86
|
+
} catch (error) {
|
|
87
|
+
return `生成帮助图片失败: ${error}`;
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
} as AITool,
|
|
91
|
+
],
|
|
92
|
+
};
|
|
93
|
+
}
|
package/skills/index.ts
ADDED
package/skills/status.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { AISkill, AITool } from "mioku";
|
|
2
|
+
import type { ScreenshotService } from "mioku";
|
|
3
|
+
import {
|
|
4
|
+
resolveHelpBotProfile,
|
|
5
|
+
sendImageFromSkillContext,
|
|
6
|
+
} from "../help";
|
|
7
|
+
import { generateStatusImage } from "../status";
|
|
8
|
+
|
|
9
|
+
export function createStatusSkill(): AISkill {
|
|
10
|
+
return {
|
|
11
|
+
name: "status",
|
|
12
|
+
description:
|
|
13
|
+
"系统状态查询,生成完整的系统状态图片",
|
|
14
|
+
permission: "member",
|
|
15
|
+
tools: [
|
|
16
|
+
{
|
|
17
|
+
name: "send_status_image",
|
|
18
|
+
description:
|
|
19
|
+
"生成并发送完整的系统状态图片。当用户问「看看状态」「机器人怎么样」「服务器忙吗」「资源还够吗」「看看 AI 用了多少」时优先使用。",
|
|
20
|
+
parameters: {
|
|
21
|
+
type: "object",
|
|
22
|
+
properties: {},
|
|
23
|
+
required: [],
|
|
24
|
+
},
|
|
25
|
+
handler: async (_args: any, runtimeCtx?: any) => {
|
|
26
|
+
const ctx = runtimeCtx?.ctx;
|
|
27
|
+
const event = runtimeCtx?.event || runtimeCtx?.rawEvent;
|
|
28
|
+
const screenshotService = ctx?.services?.screenshot as
|
|
29
|
+
| ScreenshotService
|
|
30
|
+
| undefined;
|
|
31
|
+
if (!screenshotService) {
|
|
32
|
+
return "screenshot 服务未加载";
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
const { botNickname, botAvatarUrl } = resolveHelpBotProfile(
|
|
36
|
+
ctx,
|
|
37
|
+
event,
|
|
38
|
+
);
|
|
39
|
+
const result = await generateStatusImage({
|
|
40
|
+
ctx,
|
|
41
|
+
event,
|
|
42
|
+
intent: { type: "full" },
|
|
43
|
+
botNickname,
|
|
44
|
+
botAvatarUrl,
|
|
45
|
+
});
|
|
46
|
+
if (!result.ok || !result.imagePath) {
|
|
47
|
+
return `生成状态图片失败: ${result.error || "未知错误"}`;
|
|
48
|
+
}
|
|
49
|
+
await sendImageFromSkillContext({
|
|
50
|
+
ctx,
|
|
51
|
+
event,
|
|
52
|
+
imagePath: result.imagePath,
|
|
53
|
+
quoteReply: false,
|
|
54
|
+
});
|
|
55
|
+
return "已发送状态图片";
|
|
56
|
+
} catch (error) {
|
|
57
|
+
return `生成状态图片失败: ${error}`;
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
} as AITool,
|
|
61
|
+
],
|
|
62
|
+
};
|
|
63
|
+
}
|
package/runtime.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
export interface HelpPluginRuntimeState {
|
|
2
|
-
miokiVersion?: string;
|
|
3
|
-
miokuVersion?: string;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
const runtimeState: HelpPluginRuntimeState = {};
|
|
7
|
-
|
|
8
|
-
export function setHelpRuntimeState(
|
|
9
|
-
nextState: HelpPluginRuntimeState,
|
|
10
|
-
): HelpPluginRuntimeState {
|
|
11
|
-
Object.assign(runtimeState, nextState);
|
|
12
|
-
return runtimeState;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export function getHelpRuntimeState(): HelpPluginRuntimeState {
|
|
16
|
-
return runtimeState;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export function resetHelpRuntimeState(): void {
|
|
20
|
-
for (const key of Object.keys(runtimeState) as Array<
|
|
21
|
-
keyof HelpPluginRuntimeState
|
|
22
|
-
>) {
|
|
23
|
-
delete runtimeState[key];
|
|
24
|
-
}
|
|
25
|
-
}
|
package/skills.ts
DELETED
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
import type { AISkill, AITool } from "mioku";
|
|
2
|
-
import type { HelpService } from "mioku";
|
|
3
|
-
import type { ScreenshotService } from "mioku";
|
|
4
|
-
import {
|
|
5
|
-
buildHelpInfoText,
|
|
6
|
-
generateHelpImage,
|
|
7
|
-
resolveHelpBotProfile,
|
|
8
|
-
sendImageFromSkillContext,
|
|
9
|
-
} from "./help";
|
|
10
|
-
import { getRenderVersions } from "./utils";
|
|
11
|
-
import { generateStatusImage } from "./status";
|
|
12
|
-
|
|
13
|
-
const helpSkill: AISkill = {
|
|
14
|
-
name: "help",
|
|
15
|
-
description: "帮助系统,获取插件帮助信息和发送帮助图片",
|
|
16
|
-
permission: "member",
|
|
17
|
-
tools: [
|
|
18
|
-
{
|
|
19
|
-
name: "get_help_info",
|
|
20
|
-
description:
|
|
21
|
-
"获取所有插件的帮助信息文本,这个仅用于用户向你询问某个功能的具体用法时使用",
|
|
22
|
-
parameters: {
|
|
23
|
-
type: "object",
|
|
24
|
-
properties: {},
|
|
25
|
-
required: [],
|
|
26
|
-
},
|
|
27
|
-
handler: async (_args: any, runtimeCtx?: any) => {
|
|
28
|
-
const ctx = runtimeCtx?.ctx;
|
|
29
|
-
const helpService = ctx?.services?.help as HelpService | undefined;
|
|
30
|
-
if (!helpService) {
|
|
31
|
-
return "help-service 未加载,无法获取帮助信息";
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
return buildHelpInfoText(helpService.getAllHelp());
|
|
35
|
-
},
|
|
36
|
-
} as AITool,
|
|
37
|
-
{
|
|
38
|
-
name: "send_help_image",
|
|
39
|
-
description:
|
|
40
|
-
"生成并发送帮助图片到群聊,如果有人说他想看帮助,优先调用图片发送而不是自己查看帮助。",
|
|
41
|
-
parameters: {
|
|
42
|
-
type: "object",
|
|
43
|
-
properties: {},
|
|
44
|
-
required: [],
|
|
45
|
-
},
|
|
46
|
-
handler: async (_args: any, runtimeCtx?: any) => {
|
|
47
|
-
const ctx = runtimeCtx?.ctx;
|
|
48
|
-
const event = runtimeCtx?.event || runtimeCtx?.rawEvent;
|
|
49
|
-
const helpService = ctx?.services?.help as HelpService | undefined;
|
|
50
|
-
const screenshotService = ctx?.services?.screenshot as
|
|
51
|
-
| ScreenshotService
|
|
52
|
-
| undefined;
|
|
53
|
-
const { miokiVersion, miokuVersion } = await getRenderVersions();
|
|
54
|
-
|
|
55
|
-
if (!screenshotService) {
|
|
56
|
-
return "screenshot 服务未加载,无法生成帮助图片";
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
try {
|
|
60
|
-
const { botNickname, botAvatarUrl } = resolveHelpBotProfile(
|
|
61
|
-
ctx,
|
|
62
|
-
event,
|
|
63
|
-
);
|
|
64
|
-
const imagePath = await generateHelpImage({
|
|
65
|
-
helpService,
|
|
66
|
-
screenshotService,
|
|
67
|
-
miokiVersion,
|
|
68
|
-
miokuVersion,
|
|
69
|
-
botNickname,
|
|
70
|
-
botAvatarUrl,
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
if (!imagePath) {
|
|
74
|
-
return "生成帮助图片失败";
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// Help skill defaults to normal send instead of quote-reply.
|
|
78
|
-
await sendImageFromSkillContext({
|
|
79
|
-
ctx,
|
|
80
|
-
event,
|
|
81
|
-
imagePath,
|
|
82
|
-
quoteReply: false,
|
|
83
|
-
});
|
|
84
|
-
return "已发送帮助图片";
|
|
85
|
-
} catch (error) {
|
|
86
|
-
return `生成帮助图片失败: ${error}`;
|
|
87
|
-
}
|
|
88
|
-
},
|
|
89
|
-
} as AITool,
|
|
90
|
-
],
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
const statusSkill: AISkill = {
|
|
94
|
-
name: "status",
|
|
95
|
-
description:
|
|
96
|
-
"系统状态查询,生成完整的系统状态图片(账号、资源、网络、磁盘、AI 统计、运行时、系统信息)",
|
|
97
|
-
permission: "member",
|
|
98
|
-
tools: [
|
|
99
|
-
{
|
|
100
|
-
name: "send_status_image",
|
|
101
|
-
description:
|
|
102
|
-
"生成并发送完整的系统状态图片。当用户问「看看状态」「机器人怎么样」「服务器忙吗」「资源还够吗」「看看 AI 用了多少」时优先使用。",
|
|
103
|
-
parameters: {
|
|
104
|
-
type: "object",
|
|
105
|
-
properties: {},
|
|
106
|
-
required: [],
|
|
107
|
-
},
|
|
108
|
-
handler: async (_args: any, runtimeCtx?: any) => {
|
|
109
|
-
const ctx = runtimeCtx?.ctx;
|
|
110
|
-
const event = runtimeCtx?.event || runtimeCtx?.rawEvent;
|
|
111
|
-
const screenshotService = ctx?.services?.screenshot as
|
|
112
|
-
| ScreenshotService
|
|
113
|
-
| undefined;
|
|
114
|
-
if (!screenshotService) {
|
|
115
|
-
return "screenshot 服务未加载";
|
|
116
|
-
}
|
|
117
|
-
try {
|
|
118
|
-
const { botNickname, botAvatarUrl } = resolveHelpBotProfile(
|
|
119
|
-
ctx,
|
|
120
|
-
event,
|
|
121
|
-
);
|
|
122
|
-
const result = await generateStatusImage({
|
|
123
|
-
ctx,
|
|
124
|
-
event,
|
|
125
|
-
intent: { type: "full" },
|
|
126
|
-
botNickname,
|
|
127
|
-
botAvatarUrl,
|
|
128
|
-
});
|
|
129
|
-
if (!result.ok || !result.imagePath) {
|
|
130
|
-
return `生成状态图片失败: ${result.error || "未知错误"}`;
|
|
131
|
-
}
|
|
132
|
-
await sendImageFromSkillContext({
|
|
133
|
-
ctx,
|
|
134
|
-
event,
|
|
135
|
-
imagePath: result.imagePath,
|
|
136
|
-
quoteReply: false,
|
|
137
|
-
});
|
|
138
|
-
return "已发送状态图片";
|
|
139
|
-
} catch (error) {
|
|
140
|
-
return `生成状态图片失败: ${error}`;
|
|
141
|
-
}
|
|
142
|
-
},
|
|
143
|
-
} as AITool,
|
|
144
|
-
],
|
|
145
|
-
};
|
|
146
|
-
|
|
147
|
-
const helpSkills: AISkill[] = [helpSkill, statusSkill];
|
|
148
|
-
|
|
149
|
-
export default helpSkills;
|