@lmzhen/dsh-evolution-skill-health 0.25.4 → 0.25.6

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 CHANGED
@@ -5,6 +5,36 @@ window.__ModuleLoader__.load({
5
5
  var exports = module.exports;
6
6
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
7
  let react = require("react");
8
+ //#region src/client/api.ts
9
+ /** Route paths, mirrored from the host half. */
10
+ const HOST_ROUTES = { rows: "/api/dsh-evolution/skill-health/rows" };
11
+ /**
12
+ * Read the scan result.
13
+ * @returns the payload, or the host's own refusal sentence.
14
+ */
15
+ async function rows() {
16
+ try {
17
+ const response = await fetch(HOST_ROUTES.rows, { headers: { accept: "application/json" } });
18
+ const body = await response.json();
19
+ if (!response.ok) return {
20
+ ok: false,
21
+ message: body.message ?? "skill-health: the route refused the request"
22
+ };
23
+ return {
24
+ ok: true,
25
+ payload: {
26
+ rows: body.rows ?? [],
27
+ truncated: body.truncated === true
28
+ }
29
+ };
30
+ } catch (error) {
31
+ return {
32
+ ok: false,
33
+ message: "skill-health: " + String(error)
34
+ };
35
+ }
36
+ }
37
+ //#endregion
8
38
  //#region src/client/seam.ts
9
39
  /** The panel id. The row and the `main` body MUST share it: the sidebar resolves the body by it. */
10
40
  const PANEL_ID = "skill-health";
@@ -114,10 +144,31 @@ window.__ModuleLoader__.load({
114
144
  * @param props - the face (`{ rows, truncated, openHistory? }`) and the locale seat's translator.
115
145
  * @returns the panel body.
116
146
  */
117
- function SkillHealthPanel(props) {
118
- const t = props.locale.bind("evolution-skill-health");
119
- const counts = new Map(KINDS.map((kind) => [kind, props.face.rows.filter((row) => row.verdict === kind).length]));
120
- return (0, react.createElement)("section", null, (0, react.createElement)("p", null, t("counts").replace("{ok}", String(counts.get("ok") ?? 0)).replace("{warn}", String(counts.get("warn") ?? 0)).replace("{error}", String(counts.get("error") ?? 0)).replace("{unreadable}", String(counts.get("unreadable") ?? 0))), props.face.truncated ? (0, react.createElement)("p", null, t("loading.failed")) : null, props.face.rows.length === 0 ? (0, react.createElement)("p", null, t("empty.noneReported")) : null, (0, react.createElement)("h3", null, t("group.byRule")), ruleTable(props.face, t), props.face.rows.filter((row) => row.verdict === "unreadable").map((row) => (0, react.createElement)("p", { key: row.name + ":unreadable" }, row.name + " — " + t("unreadable.note"))));
147
+ function SkillHealthPanel(face) {
148
+ const t = face.t;
149
+ const [view, setView] = (0, react.useState)(face);
150
+ const [failed, setFailed] = (0, react.useState)(void 0);
151
+ (0, react.useEffect)(() => {
152
+ const load = face.loadRows;
153
+ if (load === void 0) return;
154
+ let live = true;
155
+ load().then((outcome) => {
156
+ if (!live) return;
157
+ if (outcome.ok) setView({
158
+ ...face,
159
+ rows: outcome.payload.rows,
160
+ truncated: outcome.payload.truncated
161
+ });
162
+ else setFailed(outcome.message);
163
+ }).catch((error) => {
164
+ if (live) setFailed(String(error));
165
+ });
166
+ return () => {
167
+ live = false;
168
+ };
169
+ }, [face]);
170
+ const counts = new Map(KINDS.map((kind) => [kind, view.rows.filter((row) => row.verdict === kind).length]));
171
+ return (0, react.createElement)("section", null, (0, react.createElement)("p", null, t("counts").replace("{ok}", String(counts.get("ok") ?? 0)).replace("{warn}", String(counts.get("warn") ?? 0)).replace("{error}", String(counts.get("error") ?? 0)).replace("{unreadable}", String(counts.get("unreadable") ?? 0))), view.truncated ? (0, react.createElement)("p", null, t("loading.failed")) : null, failed === void 0 ? null : (0, react.createElement)("p", null, failed), view.rows.length === 0 ? (0, react.createElement)("p", null, t("empty.noneReported")) : null, (0, react.createElement)("h3", null, t("group.byRule")), ruleTable(view, t), view.rows.filter((row) => row.verdict === "unreadable").map((row) => (0, react.createElement)("p", { key: row.name + ":unreadable" }, row.name + " — " + t("unreadable.note"))));
121
172
  }
122
173
  //#endregion
123
174
  //#region src/client/styles.ts
@@ -203,6 +254,15 @@ window.__ModuleLoader__.load({
203
254
  return fallback;
204
255
  }
205
256
  };
257
+ const t = (key) => {
258
+ const fallback = zh[key] ?? key;
259
+ if (!registered) return fallback;
260
+ try {
261
+ return seam.locale.bind(NS)(key);
262
+ } catch {
263
+ return fallback;
264
+ }
265
+ };
206
266
  seam.slots.inject("sidebar.panellist", function* () {
207
267
  yield seam.slots.register({
208
268
  name: "sidebar.panellist",
@@ -215,12 +275,11 @@ window.__ModuleLoader__.load({
215
275
  key: PANEL_ID,
216
276
  inject: () => ({
217
277
  rows: [],
218
- truncated: false
278
+ truncated: false,
279
+ loadRows: rows,
280
+ t
219
281
  })
220
- }, (props) => (0, react.createElement)(SkillHealthPanel, {
221
- face: props.face,
222
- locale: seam.locale
223
- }));
282
+ }, SkillHealthPanel);
224
283
  });
225
284
  }
226
285
  //#endregion
@@ -8,7 +8,7 @@
8
8
  * @module @lmzhen/dsh-evolution-skill-health/client
9
9
  */
10
10
  import { type ReactNode } from 'react';
11
- import type { LocaleSeat } from './seam.ts';
11
+ import type { HealthOutcome } from './api.ts';
12
12
  /** One finding, as the host reports it: `line` is null when the position cannot be named. */
13
13
  export interface HealthFinding {
14
14
  rule: string;
@@ -30,14 +30,15 @@ export interface HealthFace {
30
30
  truncated: boolean;
31
31
  /** Opens the skill-history panel for one skill, when that panel is present. */
32
32
  openHistory?: (name: string) => void;
33
+ /** Reads the scan result from the host route. Absent faces render their seeded rows unchanged. */
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;
33
37
  }
34
38
  /**
35
39
  * Render the panel.
36
40
  * @param props - the face (`{ rows, truncated, openHistory? }`) and the locale seat's translator.
37
41
  * @returns the panel body.
38
42
  */
39
- export declare function SkillHealthPanel(props: {
40
- face: HealthFace;
41
- locale: LocaleSeat;
42
- }): ReactNode;
43
+ export declare function SkillHealthPanel(face: HealthFace): ReactNode;
43
44
  //# sourceMappingURL=Panel.d.ts.map
@@ -0,0 +1,33 @@
1
+ /**
2
+ * The host route this bundle reads, and the ONE place a request is made.
3
+ *
4
+ * The path mirrors the host half's `ROUTES.rows` in `src/routes.ts` (a spec asserts the two sides
5
+ * agree). A refusal arrives as `ok:false` with the host's own sentence, so the panel shows what the
6
+ * route actually said instead of inventing a second vocabulary.
7
+ * @module @lmzhen/dsh-evolution-skill-health/client
8
+ */
9
+ import type { HealthRow } from './Panel.ts';
10
+ /** Route paths, mirrored from the host half. */
11
+ export declare const HOST_ROUTES: {
12
+ readonly rows: "/api/dsh-evolution/skill-health/rows";
13
+ };
14
+ /** One scan result, as the route reports it. */
15
+ export interface HealthPayload {
16
+ rows: HealthRow[];
17
+ /** True when the host could not finish the scan: the counts below are then a lower bound. */
18
+ truncated: boolean;
19
+ }
20
+ /** Either the payload or the host's refusal sentence — never a thrown error the panel must guess at. */
21
+ export type HealthOutcome = {
22
+ ok: true;
23
+ payload: HealthPayload;
24
+ } | {
25
+ ok: false;
26
+ message: string;
27
+ };
28
+ /**
29
+ * Read the scan result.
30
+ * @returns the payload, or the host's own refusal sentence.
31
+ */
32
+ export declare function rows(): Promise<HealthOutcome>;
33
+ //# sourceMappingURL=api.d.ts.map
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  ]
12
12
  }
13
13
  },
14
- "version": "0.25.4",
14
+ "version": "0.25.6",
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.4"
46
+ "@lmzhen/dsh-evolution-curator": "^0.25.6"
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.4"
53
+ "@lmzhen/dsh-evolution-curator": "^0.25.6"
54
54
  }
55
55
  }