@lmzhen/dsh-evolution-skill-health 0.25.5 → 0.25.7
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/lib/client.js +107 -21
- package/lib/types/client/Panel.d.ts +3 -5
- package/lib/types/client/styles.d.ts +19 -1
- package/package.json +3 -3
package/lib/client.js
CHANGED
|
@@ -74,10 +74,12 @@ window.__ModuleLoader__.load({
|
|
|
74
74
|
"line": "位置:{path}",
|
|
75
75
|
"line.unknown": "位置:未知",
|
|
76
76
|
"unreadable.note": "读不到内容,因此无法判断(不是「通过」)。",
|
|
77
|
-
"loading.failed": "读取失败——现在判断不了;点「刷新」重试。"
|
|
77
|
+
"loading.failed": "读取失败——现在判断不了;点「刷新」重试。",
|
|
78
|
+
"read.failed": "这次没读到数据(下面一行是原始信息):"
|
|
78
79
|
};
|
|
79
80
|
/** English dictionary. */
|
|
80
81
|
const en = {
|
|
82
|
+
"read.failed": "This read failed (raw message below):",
|
|
81
83
|
"entry.label": "Skill Health",
|
|
82
84
|
"title": "Skill Health",
|
|
83
85
|
"hint": "What the health engine found, aggregated by rule. A rule whose threshold is not calibrated yet is named without a number; skills that cannot be read are listed as unreadable, never as fine.",
|
|
@@ -134,28 +136,58 @@ window.__ModuleLoader__.load({
|
|
|
134
136
|
}
|
|
135
137
|
return [...table.values()].sort((a, b) => b.skills.length - a.skills.length || a.rule.localeCompare(b.rule));
|
|
136
138
|
}
|
|
137
|
-
/** The rule
|
|
139
|
+
/** The verdict a rule's row speaks in: the worst one among the skills that carry it. */
|
|
140
|
+
function worstVerdict(face, skills) {
|
|
141
|
+
const order = [
|
|
142
|
+
"error",
|
|
143
|
+
"warn",
|
|
144
|
+
"unreadable",
|
|
145
|
+
"ok"
|
|
146
|
+
];
|
|
147
|
+
let worst = "ok";
|
|
148
|
+
for (const row of face.rows) {
|
|
149
|
+
if (!skills.includes(row.name)) continue;
|
|
150
|
+
if (order.indexOf(row.verdict) < order.indexOf(worst)) worst = row.verdict;
|
|
151
|
+
}
|
|
152
|
+
return worst;
|
|
153
|
+
}
|
|
154
|
+
/** The rule table: a grid so counts line up, with a tone bar per row and skill pills. */
|
|
138
155
|
function ruleTable(face, t) {
|
|
139
156
|
const rows = byRule(face.rows);
|
|
140
|
-
|
|
157
|
+
const cell = (role, children, key) => (0, react.createElement)("div", key === void 0 ? { "data-role": role } : {
|
|
158
|
+
"data-role": role,
|
|
159
|
+
key
|
|
160
|
+
}, children);
|
|
161
|
+
return (0, react.createElement)("div", { "data-role": "rule-table" }, (0, react.createElement)("div", {
|
|
162
|
+
"data-role": "rule-row",
|
|
163
|
+
"data-role-head": "true"
|
|
164
|
+
}, (0, react.createElement)("div", { "data-role": "rule-name" }, t("col.rule")), (0, react.createElement)("div", { "data-role": "skills" }, t("col.skills")), (0, react.createElement)("div", { "data-role": "rule-count" }, t("col.count"))), rows.map((entry) => (0, react.createElement)("div", {
|
|
165
|
+
key: entry.rule,
|
|
166
|
+
"data-role": "rule-row",
|
|
167
|
+
"data-tone": worstVerdict(face, entry.skills)
|
|
168
|
+
}, cell("rule-name", entry.rule), cell("skills", entry.skills.map((name, i) => (0, react.createElement)("span", {
|
|
169
|
+
"data-role": "skill-pill",
|
|
170
|
+
key: name + ":" + String(i),
|
|
171
|
+
title: name
|
|
172
|
+
}, name))), cell("rule-count", entry.count === 0 ? t("count.notCalibrated") : String(entry.count)))));
|
|
141
173
|
}
|
|
142
174
|
/**
|
|
143
175
|
* Render the panel.
|
|
144
176
|
* @param props - the face (`{ rows, truncated, openHistory? }`) and the locale seat's translator.
|
|
145
177
|
* @returns the panel body.
|
|
146
178
|
*/
|
|
147
|
-
function SkillHealthPanel(
|
|
148
|
-
const t =
|
|
149
|
-
const [
|
|
179
|
+
function SkillHealthPanel(face) {
|
|
180
|
+
const t = face.t;
|
|
181
|
+
const [view, setView] = (0, react.useState)(face);
|
|
150
182
|
const [failed, setFailed] = (0, react.useState)(void 0);
|
|
151
183
|
(0, react.useEffect)(() => {
|
|
152
|
-
const load =
|
|
184
|
+
const load = face.loadRows;
|
|
153
185
|
if (load === void 0) return;
|
|
154
186
|
let live = true;
|
|
155
187
|
load().then((outcome) => {
|
|
156
188
|
if (!live) return;
|
|
157
|
-
if (outcome.ok)
|
|
158
|
-
...
|
|
189
|
+
if (outcome.ok) setView({
|
|
190
|
+
...face,
|
|
159
191
|
rows: outcome.payload.rows,
|
|
160
192
|
truncated: outcome.payload.truncated
|
|
161
193
|
});
|
|
@@ -166,9 +198,17 @@ window.__ModuleLoader__.load({
|
|
|
166
198
|
return () => {
|
|
167
199
|
live = false;
|
|
168
200
|
};
|
|
169
|
-
}, [
|
|
170
|
-
const counts = new Map(KINDS.map((kind) => [kind,
|
|
171
|
-
|
|
201
|
+
}, [face]);
|
|
202
|
+
const counts = new Map(KINDS.map((kind) => [kind, view.rows.filter((row) => row.verdict === kind).length]));
|
|
203
|
+
const stats = (0, react.createElement)("div", { "data-role": "stats" }, KINDS.map((kind) => (0, react.createElement)("div", {
|
|
204
|
+
key: kind,
|
|
205
|
+
"data-role": "stat",
|
|
206
|
+
"data-tone": kind
|
|
207
|
+
}, (0, react.createElement)("div", { "data-role": "stat-value" }, String(counts.get(kind) ?? 0)), (0, react.createElement)("div", { "data-role": "stat-label" }, t("verdict." + kind)))));
|
|
208
|
+
return (0, react.createElement)("section", null, (0, react.createElement)("p", { "data-role": "hint" }, t("hint")), stats, view.truncated ? (0, react.createElement)("p", { "data-role": "note" }, t("loading.failed")) : null, failed === void 0 ? null : (0, react.createElement)("p", { "data-role": "note" }, t("read.failed") + " " + failed), view.rows.length === 0 ? (0, react.createElement)("p", { "data-role": "note" }, t("empty.noneReported")) : null, (0, react.createElement)("h3", { "data-role": "group-title" }, t("group.byRule")), ruleTable(view, t), view.rows.filter((row) => row.verdict === "unreadable").map((row) => (0, react.createElement)("p", {
|
|
209
|
+
key: row.name + ":unreadable",
|
|
210
|
+
"data-role": "note"
|
|
211
|
+
}, row.name + " — " + t("unreadable.note"))));
|
|
172
212
|
}
|
|
173
213
|
//#endregion
|
|
174
214
|
//#region src/client/styles.ts
|
|
@@ -177,17 +217,56 @@ window.__ModuleLoader__.load({
|
|
|
177
217
|
* the text itself and injects one tagged <style> element; the tag id keeps a hot reload from stacking
|
|
178
218
|
* copies. Only the panel body is styled — the sidebar owns the row and its glyph slot.
|
|
179
219
|
*
|
|
180
|
-
*
|
|
220
|
+
* Token discipline (the family gate `verify-client-tokens --strict` enforces it): every `--evo-*` name
|
|
221
|
+
* below is DECLARED in `packages/scripts/client-tokens.json` — the family scale — and every `--dsw-*`
|
|
222
|
+
* name is a platform semantic alias (packages/client/ui-theme/src/styles). No type step, space, radius,
|
|
223
|
+
* hairline or colour is invented here, and no pixel geometry literal appears.
|
|
224
|
+
*
|
|
225
|
+
* Metrics are COPIED from the platform’s own components rather than invented, each cited here:
|
|
226
|
+
*
|
|
227
|
+
* - hover and current-row fills (`--dsw-alias-interactive-bg-hover`) follow the platform sidebar row
|
|
228
|
+
* (client/ui-sidebar/…/SidebarRoot.module.css), as the sibling panel does;
|
|
229
|
+
* - label steps (`--dsw-alias-label-primary/secondary/tertiary`) and the card hairline
|
|
230
|
+
* (`--evo-hairline-width`, the scale’s copy of the platform’s 0.5px card border) come from
|
|
231
|
+
* client/ui-chat/…/GenericCommandCard.module.css;
|
|
232
|
+
* - the control radius (`--evo-radius-control`, the scale’s copy of the platform field radius) comes
|
|
233
|
+
* from client/ui-primitives/Input.module.css; the capsule uses `--evo-radius-pill`;
|
|
234
|
+
* - verdict colours are the platform STATE aliases (state-success / state-warn / state-error) plus the
|
|
235
|
+
* scale’s `--evo-tone-quiet`; the validity bar is an inset shadow, not a border-width literal.
|
|
236
|
+
*
|
|
237
|
+
* Layout: four verdict cards, then the by-rule table as a grid (rule / skills / count) so numbers sit
|
|
238
|
+
* on tabular figures and long skill lists wrap into pills instead of ragged comma text.
|
|
181
239
|
* @module @lmzhen/dsh-evolution-skill-health/client
|
|
182
240
|
*/
|
|
183
241
|
/** Tag id for the injected <style>, so a hot reload replaces rather than stacks it. */
|
|
184
242
|
const CSS_TAG_ID = "dsh-evolution-skill-health";
|
|
185
243
|
/** The panel stylesheet text. */
|
|
186
244
|
const CSS = [
|
|
187
|
-
":where(.dsh-evolution-skill-health) { display: flex; flex-direction: column; gap: var(--evo-space-8); padding: var(--evo-space-12); }",
|
|
188
245
|
":where(.dsh-evolution-skill-health) { --evo-type-lg:calc(1em + 2px);--evo-type-body:1em;--evo-type-sm:calc(1em - 1px);--evo-type-xs:calc(1em - 2px);--evo-space-2:2px;--evo-space-4:4px;--evo-space-6:6px;--evo-space-8:8px;--evo-space-10:10px;--evo-space-12:12px;--evo-space-14:14px;--evo-space-16:16px;--evo-space-20:20px;--evo-radius-chip:4px;--evo-radius-control:8px;--evo-radius-surface:12px;--evo-radius-pill:999px;--evo-hairline-width:.5px;--evo-hairline-marker:2px;--evo-measure-read:80ch;--evo-leading-base:1.5;--evo-tone-quiet:var(--dsw-alias-label-secondary);--evo-tone-primary:var(--dsw-alias-brand-primary);--evo-tone-danger:var(--dsw-alias-state-error-primary);--evo-tone-success:var(--dsw-alias-state-success-primary);--evo-focus-ring:2px solid var(--dsw-alias-label-primary);--evo-focus-offset:-2px;--evo-cap-aside:280px;--evo-cap-block:260px }",
|
|
189
|
-
":where(.dsh-evolution-skill-health
|
|
190
|
-
":where(.dsh-evolution-skill-health [data-role=\"
|
|
246
|
+
":where(.dsh-evolution-skill-health) { display: flex; flex-direction: column; gap: var(--evo-space-12); padding: var(--evo-space-16); color: var(--dsw-alias-label-primary); font-size: var(--evo-type-sm); line-height: var(--evo-leading-base); }",
|
|
247
|
+
":where(.dsh-evolution-skill-health [data-role=\"hint\"]) { margin: 0; color: var(--dsw-alias-label-secondary); }",
|
|
248
|
+
":where(.dsh-evolution-skill-health [data-role=\"stats\"]) { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--evo-space-8); }",
|
|
249
|
+
":where(.dsh-evolution-skill-health [data-role=\"stat\"]) { display: flex; flex-direction: column; gap: var(--evo-space-2); padding: var(--evo-space-8) var(--evo-space-10); border: var(--evo-hairline-width) solid var(--dsw-alias-border-l); border-radius: var(--evo-radius-control); }",
|
|
250
|
+
":where(.dsh-evolution-skill-health [data-role=\"stat\"][data-tone=\"ok\"]) { box-shadow: inset 2px 0 0 var(--dsw-alias-state-success-primary); }",
|
|
251
|
+
":where(.dsh-evolution-skill-health [data-role=\"stat\"][data-tone=\"warn\"]) { box-shadow: inset 2px 0 0 var(--dsw-alias-state-warn-primary); }",
|
|
252
|
+
":where(.dsh-evolution-skill-health [data-role=\"stat\"][data-tone=\"error\"]) { box-shadow: inset 2px 0 0 var(--dsw-alias-state-error-primary); }",
|
|
253
|
+
":where(.dsh-evolution-skill-health [data-role=\"stat\"][data-tone=\"unreadable\"]) { box-shadow: inset 2px 0 0 var(--evo-tone-quiet); }",
|
|
254
|
+
":where(.dsh-evolution-skill-health [data-role=\"stat-value\"]) { font-size: var(--evo-type-lg); font-variant-numeric: tabular-nums; line-height: 1; }",
|
|
255
|
+
":where(.dsh-evolution-skill-health [data-role=\"stat-label\"]) { color: var(--dsw-alias-label-tertiary); }",
|
|
256
|
+
":where(.dsh-evolution-skill-health [data-role=\"group-title\"]) { margin: 0; font-weight: 500; }",
|
|
257
|
+
":where(.dsh-evolution-skill-health [data-role=\"rule-table\"]) { display: flex; flex-direction: column; border: var(--evo-hairline-width) solid var(--dsw-alias-border-l); border-radius: var(--evo-radius-control); overflow: hidden; }",
|
|
258
|
+
":where(.dsh-evolution-skill-health [data-role=\"rule-row\"]) { display: grid; grid-template-columns: minmax(9rem, 13rem) minmax(0, 1fr) 4rem; gap: var(--evo-space-10); align-items: center; padding: var(--evo-space-6) var(--evo-space-10); border-top: var(--evo-hairline-width) solid var(--dsw-alias-border-l); }",
|
|
259
|
+
":where(.dsh-evolution-skill-health [data-role=\"rule-row\"][data-tone=\"warn\"]) { box-shadow: inset var(--evo-hairline-marker) 0 0 var(--dsw-alias-state-warn-primary); }",
|
|
260
|
+
":where(.dsh-evolution-skill-health [data-role=\"rule-row\"][data-tone=\"error\"]) { box-shadow: inset var(--evo-hairline-marker) 0 0 var(--dsw-alias-state-error-primary); }",
|
|
261
|
+
":where(.dsh-evolution-skill-health [data-role=\"rule-row\"][data-tone=\"unreadable\"]) { box-shadow: inset var(--evo-hairline-marker) 0 0 var(--evo-tone-quiet); }",
|
|
262
|
+
":where(.dsh-evolution-skill-health [data-role=\"rule-row\"]:hover) { background: var(--dsw-alias-interactive-bg-hover); }",
|
|
263
|
+
":where(.dsh-evolution-skill-health [data-role=\"rule-row\"]:focus-visible) { outline: var(--evo-focus-ring); outline-offset: var(--evo-focus-offset); }",
|
|
264
|
+
":where(.dsh-evolution-skill-health [data-role=\"rule-head\"]) { border-top: 0; color: var(--dsw-alias-label-tertiary); }",
|
|
265
|
+
":where(.dsh-evolution-skill-health [data-role=\"rule-name\"]) { overflow-wrap: anywhere; }",
|
|
266
|
+
":where(.dsh-evolution-skill-health [data-role=\"rule-count\"]) { text-align: right; font-variant-numeric: tabular-nums; color: var(--dsw-alias-label-secondary); }",
|
|
267
|
+
":where(.dsh-evolution-skill-health [data-role=\"skills\"]) { display: flex; flex-wrap: wrap; gap: var(--evo-space-4); }",
|
|
268
|
+
":where(.dsh-evolution-skill-health [data-role=\"skill-pill\"]) { padding: 0 var(--evo-space-6); border: var(--evo-hairline-width) solid var(--dsw-alias-border-l); border-radius: var(--evo-radius-pill); color: var(--dsw-alias-label-secondary); white-space: nowrap; }",
|
|
269
|
+
":where(.dsh-evolution-skill-health [data-role=\"note\"]) { margin: 0; color: var(--dsw-alias-label-secondary); }"
|
|
191
270
|
].join(String.fromCharCode(10));
|
|
192
271
|
//#endregion
|
|
193
272
|
//#region src/client/index.ts
|
|
@@ -254,6 +333,15 @@ window.__ModuleLoader__.load({
|
|
|
254
333
|
return fallback;
|
|
255
334
|
}
|
|
256
335
|
};
|
|
336
|
+
const t = (key) => {
|
|
337
|
+
const fallback = zh[key] ?? key;
|
|
338
|
+
if (!registered) return fallback;
|
|
339
|
+
try {
|
|
340
|
+
return seam.locale.bind(NS)(key);
|
|
341
|
+
} catch {
|
|
342
|
+
return fallback;
|
|
343
|
+
}
|
|
344
|
+
};
|
|
257
345
|
seam.slots.inject("sidebar.panellist", function* () {
|
|
258
346
|
yield seam.slots.register({
|
|
259
347
|
name: "sidebar.panellist",
|
|
@@ -267,12 +355,10 @@ window.__ModuleLoader__.load({
|
|
|
267
355
|
inject: () => ({
|
|
268
356
|
rows: [],
|
|
269
357
|
truncated: false,
|
|
270
|
-
loadRows: rows
|
|
358
|
+
loadRows: rows,
|
|
359
|
+
t
|
|
271
360
|
})
|
|
272
|
-
},
|
|
273
|
-
face: props.face,
|
|
274
|
-
locale: seam.locale
|
|
275
|
-
}));
|
|
361
|
+
}, SkillHealthPanel);
|
|
276
362
|
});
|
|
277
363
|
}
|
|
278
364
|
//#endregion
|
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { type ReactNode } from 'react';
|
|
11
11
|
import type { HealthOutcome } from './api.ts';
|
|
12
|
-
import type { LocaleSeat } from './seam.ts';
|
|
13
12
|
/** One finding, as the host reports it: `line` is null when the position cannot be named. */
|
|
14
13
|
export interface HealthFinding {
|
|
15
14
|
rule: string;
|
|
@@ -33,14 +32,13 @@ export interface HealthFace {
|
|
|
33
32
|
openHistory?: (name: string) => void;
|
|
34
33
|
/** Reads the scan result from the host route. Absent faces render their seeded rows unchanged. */
|
|
35
34
|
loadRows?: () => Promise<HealthOutcome>;
|
|
35
|
+
/** The seat's translator for this bundle's dictionary — the panel never reaches for a service. */
|
|
36
|
+
t: (key: string) => string;
|
|
36
37
|
}
|
|
37
38
|
/**
|
|
38
39
|
* Render the panel.
|
|
39
40
|
* @param props - the face (`{ rows, truncated, openHistory? }`) and the locale seat's translator.
|
|
40
41
|
* @returns the panel body.
|
|
41
42
|
*/
|
|
42
|
-
export declare function SkillHealthPanel(
|
|
43
|
-
face: HealthFace;
|
|
44
|
-
locale: LocaleSeat;
|
|
45
|
-
}): ReactNode;
|
|
43
|
+
export declare function SkillHealthPanel(face: HealthFace): ReactNode;
|
|
46
44
|
//# sourceMappingURL=Panel.d.ts.map
|
|
@@ -3,7 +3,25 @@
|
|
|
3
3
|
* the text itself and injects one tagged <style> element; the tag id keeps a hot reload from stacking
|
|
4
4
|
* copies. Only the panel body is styled — the sidebar owns the row and its glyph slot.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
6
|
+
* Token discipline (the family gate `verify-client-tokens --strict` enforces it): every `--evo-*` name
|
|
7
|
+
* below is DECLARED in `packages/scripts/client-tokens.json` — the family scale — and every `--dsw-*`
|
|
8
|
+
* name is a platform semantic alias (packages/client/ui-theme/src/styles). No type step, space, radius,
|
|
9
|
+
* hairline or colour is invented here, and no pixel geometry literal appears.
|
|
10
|
+
*
|
|
11
|
+
* Metrics are COPIED from the platform’s own components rather than invented, each cited here:
|
|
12
|
+
*
|
|
13
|
+
* - hover and current-row fills (`--dsw-alias-interactive-bg-hover`) follow the platform sidebar row
|
|
14
|
+
* (client/ui-sidebar/…/SidebarRoot.module.css), as the sibling panel does;
|
|
15
|
+
* - label steps (`--dsw-alias-label-primary/secondary/tertiary`) and the card hairline
|
|
16
|
+
* (`--evo-hairline-width`, the scale’s copy of the platform’s 0.5px card border) come from
|
|
17
|
+
* client/ui-chat/…/GenericCommandCard.module.css;
|
|
18
|
+
* - the control radius (`--evo-radius-control`, the scale’s copy of the platform field radius) comes
|
|
19
|
+
* from client/ui-primitives/Input.module.css; the capsule uses `--evo-radius-pill`;
|
|
20
|
+
* - verdict colours are the platform STATE aliases (state-success / state-warn / state-error) plus the
|
|
21
|
+
* scale’s `--evo-tone-quiet`; the validity bar is an inset shadow, not a border-width literal.
|
|
22
|
+
*
|
|
23
|
+
* Layout: four verdict cards, then the by-rule table as a grid (rule / skills / count) so numbers sit
|
|
24
|
+
* on tabular figures and long skill lists wrap into pills instead of ragged comma text.
|
|
7
25
|
* @module @lmzhen/dsh-evolution-skill-health/client
|
|
8
26
|
*/
|
|
9
27
|
/** Tag id for the injected <style>, so a hot reload replaces rather than stacks it. */
|
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
]
|
|
12
12
|
}
|
|
13
13
|
},
|
|
14
|
-
"version": "0.25.
|
|
14
|
+
"version": "0.25.7",
|
|
15
15
|
"publishConfig": {
|
|
16
16
|
"access": "public"
|
|
17
17
|
},
|
|
@@ -43,13 +43,13 @@
|
|
|
43
43
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
44
44
|
"@deepseek-ai/dsh-host-webserver": "^0.2.0-rc.1",
|
|
45
45
|
"react": "^18.2.0",
|
|
46
|
-
"@lmzhen/dsh-evolution-curator": "^0.25.
|
|
46
|
+
"@lmzhen/dsh-evolution-curator": "^0.25.7"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
50
50
|
"@deepseek-ai/dsh-host-webserver": "^0.2.0-rc.1",
|
|
51
51
|
"@types/react": "~18.3.1",
|
|
52
52
|
"react": "^18.2.0",
|
|
53
|
-
"@lmzhen/dsh-evolution-curator": "^0.25.
|
|
53
|
+
"@lmzhen/dsh-evolution-curator": "^0.25.7"
|
|
54
54
|
}
|
|
55
55
|
}
|