mioku-plugin-help 2.0.0 → 2.1.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/help/html-generator.ts +556 -0
- package/help/image.ts +216 -0
- package/help/index.ts +24 -0
- package/help/info.ts +41 -0
- package/help/intent.ts +379 -0
- package/help/role-config.ts +67 -0
- package/help/types.ts +40 -0
- package/index.ts +69 -11
- package/package.json +4 -3
- package/skills.ts +132 -77
- package/status/data-collector.ts +752 -0
- package/status/html-generator.ts +1202 -0
- package/status/image.ts +81 -0
- package/status/index.ts +28 -0
- package/status/intent.ts +43 -0
- package/status/network-sampler.ts +129 -0
- package/status/performance-monitor.ts +102 -0
- package/status/types.ts +264 -0
- package/theme.ts +138 -0
- package/utils.ts +129 -0
- package/shared.ts +0 -1276
package/theme.ts
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Visual theme shared by the help and status panels.
|
|
3
|
+
*
|
|
4
|
+
* Both panels render the same visual system (760px wide, ACG background
|
|
5
|
+
* image, blurred glass shell, etc.), so they share a single `HelpTheme`
|
|
6
|
+
* object. Callers branch on `isNightMode` to pick the day/night variant.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export interface HelpTheme {
|
|
10
|
+
isNightMode: boolean;
|
|
11
|
+
pageBg: string;
|
|
12
|
+
shellBg: string;
|
|
13
|
+
pageAccent: string;
|
|
14
|
+
pageGrid: string;
|
|
15
|
+
sceneOpacity: string;
|
|
16
|
+
sceneFilter: string;
|
|
17
|
+
sceneMask: string;
|
|
18
|
+
sceneGlow: string;
|
|
19
|
+
shellBorder: string;
|
|
20
|
+
shellShadow: string;
|
|
21
|
+
heroBg: string;
|
|
22
|
+
heroBorder: string;
|
|
23
|
+
heroGlow: string;
|
|
24
|
+
eyebrow: string;
|
|
25
|
+
title: string;
|
|
26
|
+
subtitle: string;
|
|
27
|
+
panelBg: string;
|
|
28
|
+
panelBorder: string;
|
|
29
|
+
panelShadow: string;
|
|
30
|
+
panelTitle: string;
|
|
31
|
+
panelDesc: string;
|
|
32
|
+
commandBg: string;
|
|
33
|
+
commandBorder: string;
|
|
34
|
+
commandTitle: string;
|
|
35
|
+
commandDesc: string;
|
|
36
|
+
tagBg: string;
|
|
37
|
+
tagBorder: string;
|
|
38
|
+
tagText: string;
|
|
39
|
+
emptyText: string;
|
|
40
|
+
footerBg: string;
|
|
41
|
+
footerBorder: string;
|
|
42
|
+
footerLabel: string;
|
|
43
|
+
footerText: string;
|
|
44
|
+
divider: string;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export const HELP_BACKGROUND_IMAGE_URL =
|
|
48
|
+
"https://uapis.cn/api/v1/random/image?category=acg&type=mb";
|
|
49
|
+
|
|
50
|
+
export function getHelpTheme(isNightMode: boolean): HelpTheme {
|
|
51
|
+
if (isNightMode) {
|
|
52
|
+
return {
|
|
53
|
+
isNightMode: true,
|
|
54
|
+
pageBg: "linear-gradient(180deg, #07141c 0%, #0b1c25 52%, #102730 100%)",
|
|
55
|
+
shellBg: "rgba(6, 19, 25, 0.34)",
|
|
56
|
+
pageAccent:
|
|
57
|
+
"radial-gradient(circle at 18% 14%, rgba(76, 201, 191, 0.18), transparent 34%), radial-gradient(circle at 82% 10%, rgba(34, 211, 238, 0.12), transparent 28%), radial-gradient(circle at 50% 100%, rgba(45, 212, 191, 0.1), transparent 42%)",
|
|
58
|
+
pageGrid:
|
|
59
|
+
"linear-gradient(rgba(151, 214, 210, 0.04) 1px, transparent 1px), linear-gradient(90deg, rgba(151, 214, 210, 0.04) 1px, transparent 1px)",
|
|
60
|
+
sceneOpacity: "0.48",
|
|
61
|
+
sceneFilter: "blur(1.5px) saturate(0.96) contrast(1.05) brightness(0.72)",
|
|
62
|
+
sceneMask:
|
|
63
|
+
"linear-gradient(180deg, rgba(3, 11, 15, 0.34), rgba(4, 16, 22, 0.2) 26%, rgba(4, 14, 20, 0.06) 52%, rgba(3, 10, 14, 0.4) 100%)",
|
|
64
|
+
sceneGlow:
|
|
65
|
+
"radial-gradient(circle at 24% 16%, rgba(126, 231, 221, 0.16), transparent 28%), radial-gradient(circle at 78% 10%, rgba(34, 211, 238, 0.14), transparent 26%)",
|
|
66
|
+
shellBorder: "rgba(116, 202, 200, 0.18)",
|
|
67
|
+
shellShadow: "0 32px 70px rgba(1, 11, 16, 0.45)",
|
|
68
|
+
heroBg:
|
|
69
|
+
"linear-gradient(135deg, rgba(16, 40, 50, 0.94), rgba(14, 32, 42, 0.88))",
|
|
70
|
+
heroBorder: "rgba(105, 196, 194, 0.24)",
|
|
71
|
+
heroGlow: "rgba(77, 217, 200, 0.16)",
|
|
72
|
+
eyebrow: "#7ee7dd",
|
|
73
|
+
title: "#ecfeff",
|
|
74
|
+
subtitle: "#b9d7d8",
|
|
75
|
+
panelBg: "rgba(12, 29, 38, 0.86)",
|
|
76
|
+
panelBorder: "rgba(105, 196, 194, 0.16)",
|
|
77
|
+
panelShadow: "0 18px 42px rgba(0, 0, 0, 0.22)",
|
|
78
|
+
panelTitle: "#f0fdff",
|
|
79
|
+
panelDesc: "#a8cdd0",
|
|
80
|
+
commandBg: "rgba(18, 41, 50, 0.92)",
|
|
81
|
+
commandBorder: "rgba(108, 185, 182, 0.14)",
|
|
82
|
+
commandTitle: "#83f0e1",
|
|
83
|
+
commandDesc: "#d8eeed",
|
|
84
|
+
tagBg: "rgba(25, 52, 62, 0.9)",
|
|
85
|
+
tagBorder: "rgba(125, 218, 211, 0.25)",
|
|
86
|
+
tagText: "#9af8eb",
|
|
87
|
+
emptyText: "#78999a",
|
|
88
|
+
footerBg: "rgba(10, 24, 32, 0.82)",
|
|
89
|
+
footerBorder: "rgba(105, 196, 194, 0.16)",
|
|
90
|
+
footerLabel: "#85aeb0",
|
|
91
|
+
footerText: "#dffcf8",
|
|
92
|
+
divider: "rgba(105, 196, 194, 0.18)",
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
isNightMode: false,
|
|
98
|
+
pageBg: "linear-gradient(180deg, #eef6f7 0%, #f6fbfb 48%, #edf5f7 100%)",
|
|
99
|
+
shellBg: "rgba(255, 255, 255, 0.42)",
|
|
100
|
+
pageAccent:
|
|
101
|
+
"radial-gradient(circle at 12% 10%, rgba(45, 212, 191, 0.18), transparent 28%), radial-gradient(circle at 88% 0%, rgba(56, 189, 248, 0.14), transparent 24%), radial-gradient(circle at 50% 100%, rgba(13, 148, 136, 0.08), transparent 44%)",
|
|
102
|
+
pageGrid:
|
|
103
|
+
"linear-gradient(rgba(17, 94, 89, 0.05) 1px, transparent 1px), linear-gradient(90deg, rgba(17, 94, 89, 0.05) 1px, transparent 1px)",
|
|
104
|
+
sceneOpacity: "0.42",
|
|
105
|
+
sceneFilter: "blur(1.5px) saturate(0.98) contrast(1.02) brightness(1.03)",
|
|
106
|
+
sceneMask:
|
|
107
|
+
"linear-gradient(180deg, rgba(244, 250, 251, 0.4), rgba(244, 250, 251, 0.22) 30%, rgba(244, 250, 251, 0.04) 58%, rgba(237, 245, 247, 0.46) 100%)",
|
|
108
|
+
sceneGlow:
|
|
109
|
+
"radial-gradient(circle at 18% 14%, rgba(45, 212, 191, 0.14), transparent 28%), radial-gradient(circle at 82% 8%, rgba(56, 189, 248, 0.12), transparent 24%)",
|
|
110
|
+
shellBorder: "rgba(148, 196, 204, 0.62)",
|
|
111
|
+
shellShadow: "0 26px 60px rgba(12, 50, 59, 0.12)",
|
|
112
|
+
heroBg:
|
|
113
|
+
"linear-gradient(135deg, rgba(255, 255, 255, 0.96), rgba(240, 250, 249, 0.94))",
|
|
114
|
+
heroBorder: "rgba(148, 196, 204, 0.7)",
|
|
115
|
+
heroGlow: "rgba(45, 212, 191, 0.14)",
|
|
116
|
+
eyebrow: "#0f766e",
|
|
117
|
+
title: "#0f172a",
|
|
118
|
+
subtitle: "#335761",
|
|
119
|
+
panelBg: "rgba(255, 255, 255, 0.95)",
|
|
120
|
+
panelBorder: "rgba(148, 196, 204, 0.68)",
|
|
121
|
+
panelShadow: "0 16px 36px rgba(15, 61, 71, 0.08)",
|
|
122
|
+
panelTitle: "#102430",
|
|
123
|
+
panelDesc: "#4b6770",
|
|
124
|
+
commandBg: "rgba(244, 251, 251, 0.98)",
|
|
125
|
+
commandBorder: "rgba(185, 217, 221, 0.82)",
|
|
126
|
+
commandTitle: "#0f766e",
|
|
127
|
+
commandDesc: "#17353f",
|
|
128
|
+
tagBg: "rgba(237, 248, 249, 0.98)",
|
|
129
|
+
tagBorder: "rgba(148, 196, 204, 0.74)",
|
|
130
|
+
tagText: "#0d6a65",
|
|
131
|
+
emptyText: "#6f8b93",
|
|
132
|
+
footerBg: "rgba(255, 255, 255, 0.94)",
|
|
133
|
+
footerBorder: "rgba(148, 196, 204, 0.72)",
|
|
134
|
+
footerLabel: "#5b7680",
|
|
135
|
+
footerText: "#0f172a",
|
|
136
|
+
divider: "rgba(148, 196, 204, 0.78)",
|
|
137
|
+
};
|
|
138
|
+
}
|
package/utils.ts
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Small cross-feature utilities used by both the help and status panels.
|
|
3
|
+
*
|
|
4
|
+
* Kept dependency-free and stateless so it can be imported from anywhere
|
|
5
|
+
* inside the plugin without creating a cycle.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import * as fs from "node:fs/promises";
|
|
9
|
+
import * as path from "node:path";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Escape user-controlled text before embedding it in an HTML template.
|
|
13
|
+
* Covers the five characters that change HTML/attribute semantics.
|
|
14
|
+
*/
|
|
15
|
+
export function escapeHtml(text: string): string {
|
|
16
|
+
const map: Record<string, string> = {
|
|
17
|
+
"&": "&",
|
|
18
|
+
"<": "<",
|
|
19
|
+
">": ">",
|
|
20
|
+
'"': """,
|
|
21
|
+
"'": "'",
|
|
22
|
+
};
|
|
23
|
+
return String(text || "").replace(/[&<>"']/g, (match) => map[match]);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Day/night toggle based on local hour. 19:00–07:00 is night; matches the
|
|
28
|
+
* visual theme's two variants in `theme.ts`.
|
|
29
|
+
*/
|
|
30
|
+
export function checkNightMode(): boolean {
|
|
31
|
+
const hour = new Date().getHours();
|
|
32
|
+
return hour >= 19 || hour < 7;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Read a package's `version` field from a path. Returns "unknown" silently
|
|
37
|
+
* on any error (file not found, invalid JSON, missing field) so callers
|
|
38
|
+
* can render the footer without try/catch boilerplate.
|
|
39
|
+
*/
|
|
40
|
+
export async function getPackageVersion(
|
|
41
|
+
packageJsonPath: string,
|
|
42
|
+
): Promise<string> {
|
|
43
|
+
try {
|
|
44
|
+
const content = await fs.readFile(packageJsonPath, "utf-8");
|
|
45
|
+
const pkg = JSON.parse(content);
|
|
46
|
+
return pkg.version || "unknown";
|
|
47
|
+
} catch {
|
|
48
|
+
return "unknown";
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Same as `getPackageVersion` but also verifies the package's `name`
|
|
54
|
+
* field. Used by `getRenderVersions` to make sure a stray `package.json`
|
|
55
|
+
* at the candidate path doesn't get reported as mioki/mioku.
|
|
56
|
+
*/
|
|
57
|
+
async function readNamedPackageVersion(
|
|
58
|
+
packageJsonPath: string,
|
|
59
|
+
expectedName: string,
|
|
60
|
+
): Promise<string> {
|
|
61
|
+
try {
|
|
62
|
+
const content = await fs.readFile(packageJsonPath, "utf-8");
|
|
63
|
+
const pkg = JSON.parse(content) as { name?: unknown; version?: unknown };
|
|
64
|
+
if (pkg?.name === expectedName && typeof pkg.version === "string") {
|
|
65
|
+
return pkg.version;
|
|
66
|
+
}
|
|
67
|
+
} catch {
|
|
68
|
+
// fall through to "unknown"
|
|
69
|
+
}
|
|
70
|
+
return "unknown";
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
let renderVersionsCache: { miokiVersion: string; miokuVersion: string } | null = null;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Read the installed `mioki` and `mioku` versions from the host project's
|
|
77
|
+
* `node_modules`.
|
|
78
|
+
*
|
|
79
|
+
* In a workspace (Bun / pnpm / yarn) `mioki` is hoisted under
|
|
80
|
+
* `mioku/node_modules/mioki` because mioki is a peer dep of mioku, so a
|
|
81
|
+
* bare `node_modules/mioki` lookup misses. We try the nested path first
|
|
82
|
+
* and fall back to the top-level install path. For `mioku` we look at
|
|
83
|
+
* the host's top-level and one level up (handles monorepo layouts where
|
|
84
|
+
* the plugin is loaded from a workspace root).
|
|
85
|
+
*
|
|
86
|
+
* Result is memoized — versions don't change at runtime, and the help
|
|
87
|
+
* setup, the help skill, and the status snapshot all ask for them.
|
|
88
|
+
*/
|
|
89
|
+
export async function getRenderVersions(): Promise<{
|
|
90
|
+
miokiVersion: string;
|
|
91
|
+
miokuVersion: string;
|
|
92
|
+
}> {
|
|
93
|
+
if (renderVersionsCache) {
|
|
94
|
+
return renderVersionsCache;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const miokiCandidates = [
|
|
98
|
+
// Nested under mioku (the typical workspace case).
|
|
99
|
+
path.join(process.cwd(), "node_modules", "mioku", "node_modules", "mioki", "package.json"),
|
|
100
|
+
// Hoisted top-level (a single-package install).
|
|
101
|
+
path.join(process.cwd(), "node_modules", "mioki", "package.json"),
|
|
102
|
+
];
|
|
103
|
+
const miokuCandidates = [
|
|
104
|
+
path.join(process.cwd(), "node_modules", "mioku", "package.json"),
|
|
105
|
+
path.join(process.cwd(), "..", "node_modules", "mioku", "package.json"),
|
|
106
|
+
];
|
|
107
|
+
|
|
108
|
+
let miokiVersion = "unknown";
|
|
109
|
+
for (const candidate of miokiCandidates) {
|
|
110
|
+
const v = await readNamedPackageVersion(candidate, "mioki");
|
|
111
|
+
if (v !== "unknown") {
|
|
112
|
+
miokiVersion = v;
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
let miokuVersion = "unknown";
|
|
118
|
+
for (const candidate of miokuCandidates) {
|
|
119
|
+
const v = await readNamedPackageVersion(candidate, "mioku");
|
|
120
|
+
if (v !== "unknown") {
|
|
121
|
+
miokuVersion = v;
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
renderVersionsCache = { miokiVersion, miokuVersion };
|
|
127
|
+
return renderVersionsCache;
|
|
128
|
+
}
|
|
129
|
+
|