@lmzhen/dsh-evolution-skill-health 0.32.6 → 0.33.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/lib/client.js CHANGED
@@ -321,12 +321,22 @@ window.__ModuleLoader__.load({
321
321
  "verdict.unreadable": "不可读",
322
322
  "group.proposals": "语义提议",
323
323
  "proposal.unavailable": "提议源未挂载;这不是「没有可拆项」。",
324
+ "proposal.stale": "提议通道的数据已过期;这不是「没有可整理内容」,请刷新后重试。",
325
+ "proposal.owner": "归属",
324
326
  "proposal.outcome.keep": "保持",
325
327
  "proposal.outcome.extract": "提取",
326
328
  "proposal.outcome.mixed": "混合",
327
- "proposal.outcome.owner-gap": "owner 缺口",
328
- "proposal.owner.covered": "有覆盖 owner",
329
- "proposal.owner.owner-gap": "无覆盖 owner",
329
+ "proposal.outcome.owner-gap": "缺少归属技能",
330
+ "proposal.owner.covered": "已有归属技能",
331
+ "proposal.owner.owner-gap": "缺少归属技能",
332
+ "rule.unreadable-skill": "无法读取",
333
+ "rule.body-oversize-2x": "正文超硬线两倍",
334
+ "rule.body-oversize": "正文超过软线",
335
+ "rule.stamp-density": "时间戳密度",
336
+ "rule.body-without-support": "大正文无支撑文件",
337
+ "rule.references-sprawl": "支撑文件过多",
338
+ "rule.scope-overloaded": "范围过载",
339
+ "rule.write-ghost": "只写不读",
330
340
  "proposal.status.proposed": "状态:提议",
331
341
  "proposal.status.previewed": "状态:已预览",
332
342
  "proposal.status.stale": "状态:已过期",
@@ -393,12 +403,22 @@ window.__ModuleLoader__.load({
393
403
  "verdict.unreadable": "Unreadable",
394
404
  "group.proposals": "Semantic proposals",
395
405
  "proposal.unavailable": "No proposal source is mounted; this is not \"nothing to extract\".",
406
+ "proposal.stale": "The proposal lane is stale; refresh and retry. This is not \"nothing to extract\".",
407
+ "proposal.owner": "Owner",
396
408
  "proposal.outcome.keep": "keep",
397
409
  "proposal.outcome.extract": "extract",
398
410
  "proposal.outcome.mixed": "mixed",
399
411
  "proposal.outcome.owner-gap": "owner-gap",
400
- "proposal.owner.covered": "covered owner",
401
- "proposal.owner.owner-gap": "no covering owner",
412
+ "proposal.owner.covered": "owner skill present",
413
+ "proposal.owner.owner-gap": "no owner skill",
414
+ "rule.unreadable-skill": "Unreadable",
415
+ "rule.body-oversize-2x": "Body over hard line ×2",
416
+ "rule.body-oversize": "Body over soft line",
417
+ "rule.stamp-density": "Timestamp density",
418
+ "rule.body-without-support": "Large body, no support files",
419
+ "rule.references-sprawl": "Too many support files",
420
+ "rule.scope-overloaded": "Scope overloaded",
421
+ "rule.write-ghost": "Written, never read",
402
422
  "proposal.status.proposed": "status: proposed",
403
423
  "proposal.status.previewed": "status: previewed",
404
424
  "proposal.status.stale": "status: stale",
@@ -514,6 +534,21 @@ window.__ModuleLoader__.load({
514
534
  ":where(.dsh-evolution-skill-health [data-role=\"note\"]) { margin: 0; color: var(--dsw-alias-label-secondary); }"
515
535
  ].join(String.fromCharCode(10));
516
536
  //#endregion
537
+ //#region src/client/platform-tabs.ts
538
+ const PLATFORM_UI_MODULE = "@deepseek-ai/dsh-client-ui-primitives";
539
+ let cached;
540
+ /** The platform component, or undefined when this deployment has no module row. */
541
+ function platformSegmentedTabs() {
542
+ if (cached !== void 0) return cached ?? void 0;
543
+ try {
544
+ const row = require(PLATFORM_UI_MODULE);
545
+ cached = typeof row.SegmentedTabs === "function" ? row.SegmentedTabs : null;
546
+ } catch {
547
+ cached = null;
548
+ }
549
+ return cached ?? void 0;
550
+ }
551
+ //#endregion
517
552
  //#region src/client/Panel.ts
518
553
  /**
519
554
  * The panel body: a four-state summary plus the list aggregated BY RULE.
@@ -533,6 +568,23 @@ window.__ModuleLoader__.load({
533
568
  "unreadable"
534
569
  ];
535
570
  /** UI tone per verdict; the CSS keys are ok/warn/error/unreadable. */
571
+ const RULE_KEYS = new Set([
572
+ "unreadable-skill",
573
+ "body-oversize-2x",
574
+ "body-oversize",
575
+ "stamp-density",
576
+ "body-without-support",
577
+ "references-sprawl",
578
+ "scope-overloaded",
579
+ "write-ghost"
580
+ ]);
581
+ /** A rule speaks the operator's language; an unknown rule keeps its raw id rather than inventing one. */
582
+ function ruleName(t, rule) {
583
+ if (!RULE_KEYS.has(rule)) return rule;
584
+ const key = "rule." + rule;
585
+ const label = t(key);
586
+ return label === key ? rule : label;
587
+ }
536
588
  const TONE = Object.freeze({
537
589
  healthy: "ok",
538
590
  warn: "warn",
@@ -607,7 +659,7 @@ window.__ModuleLoader__.load({
607
659
  key: row.name,
608
660
  "data-role": "skill-row",
609
661
  "data-tone": row.verdict
610
- }, (0, react.createElement)("span", { "data-role": "skill-name" }, row.name), (0, react.createElement)("span", { "data-role": "skill-verdict" }, t("verdict." + row.verdict)), (0, react.createElement)("span", { "data-role": "skill-findings" }, row.findings.length === 0 ? t("findings.none") : row.findings.map((finding) => finding.rule).join(" / ")), (0, react.createElement)("span", { "data-role": "skill-dims" }, t("dims.body") + ": " + String(row.dims?.bodyChars ?? t("dims.unknown")) + " · " + t("dims.support") + ": " + String(row.dims?.supportFiles ?? t("dims.unknown"))), (0, react.createElement)("span", { "data-role": "skill-row-actions" }, (0, react.createElement)("button", {
662
+ }, (0, react.createElement)("span", { "data-role": "skill-name" }, row.name), (0, react.createElement)("span", { "data-role": "skill-verdict" }, t("verdict." + row.verdict)), (0, react.createElement)("span", { "data-role": "skill-findings" }, row.findings.length === 0 ? t("findings.none") : row.findings.map((finding) => ruleName(t, finding.rule)).join(" / ")), row.verdict === "unreadable" ? (0, react.createElement)("span", { "data-role": "skill-unreadable-note" }, t("unreadable.note")) : null, row.protection === void 0 || row.protection === null ? null : (0, react.createElement)("span", { "data-role": "skill-protection" }, t("protected") + ": " + row.protection), (0, react.createElement)("span", { "data-role": "skill-dims" }, t("dims.body") + ": " + String(row.dims?.bodyChars ?? t("dims.unknown")) + " · " + t("dims.support") + ": " + String(row.dims?.supportFiles ?? t("dims.unknown"))), (0, react.createElement)("span", { "data-role": "skill-row-actions" }, (0, react.createElement)("button", {
611
663
  type: "button",
612
664
  "data-role": "action-history",
613
665
  disabled: face.openHistory === void 0,
@@ -641,7 +693,7 @@ window.__ModuleLoader__.load({
641
693
  key: entry.rule,
642
694
  "data-role": "rule-row",
643
695
  "data-tone": TONE[worstVerdict(face, entry.skills)]
644
- }, cell("rule-name", entry.rule), cell("skills", entry.skills.map((name, i) => (0, react.createElement)("span", {
696
+ }, cell("rule-name", ruleName(t, entry.rule)), cell("skills", entry.skills.map((name, i) => (0, react.createElement)("span", {
645
697
  "data-role": "skill-pill",
646
698
  key: name + ":" + String(i),
647
699
  title: name
@@ -678,6 +730,8 @@ window.__ModuleLoader__.load({
678
730
  const [loading, setLoading] = (0, react.useState)(face.loadRows !== void 0 && face.loaded !== true);
679
731
  const [lastReadAt, setLastReadAt] = (0, react.useState)(face.readAt);
680
732
  const [scan, setScan] = (0, react.useState)(face.scan);
733
+ const [viewMode, setViewMode] = (0, react.useState)("skills");
734
+ const firstLoad = (0, react.useRef)(false);
681
735
  /** One read trigger for first paint and the refresh button; the latest answer wins. */
682
736
  const load = () => {
683
737
  const read = face.loadRows;
@@ -712,7 +766,11 @@ window.__ModuleLoader__.load({
712
766
  live = false;
713
767
  };
714
768
  };
715
- (0, react.useEffect)(() => load(), [face]);
769
+ (0, react.useEffect)(() => {
770
+ if (firstLoad.current || face.loadRows === void 0) return;
771
+ firstLoad.current = true;
772
+ load();
773
+ }, [face]);
716
774
  const counts = new Map(KINDS.map((kind) => [kind, view.rows.filter((row) => row.verdict === kind).length]));
717
775
  const stats = (0, react.createElement)("div", { "data-role": "stats" }, KINDS.map((kind) => (0, react.createElement)("div", {
718
776
  key: kind,
@@ -726,26 +784,61 @@ window.__ModuleLoader__.load({
726
784
  onClick: () => {
727
785
  load();
728
786
  }
729
- }, t("refresh"))), (0, react.createElement)("p", { "data-role": "hint" }, t("hint")), loading || failed !== void 0 || scan?.status === "unavailable" ? null : stats, loading ? (0, react.createElement)("p", { "data-role": "note" }, t("loading")) : null, view.truncated ? (0, react.createElement)("p", { "data-role": "note" }, t("scan.truncated")) : null, failed === void 0 ? null : (0, react.createElement)("div", { "data-role": "note" }, failureBlock(t, failed)), view.loaded === true && view.rows.length === 0 ? (0, react.createElement)("p", { "data-role": "note" }, t("empty.noneReported")) : null, view.proposalStatus === "unavailable" && (view.proposals ?? []).length === 0 ? (0, react.createElement)("p", { "data-role": "note" }, t("proposal.unavailable")) : null, (view.proposals ?? []).length > 0 ? (0, react.createElement)("div", { "data-role": "proposals" }, (0, react.createElement)("h3", { "data-role": "group-title" }, t("group.proposals")), ...(view.proposals ?? []).map((proposal) => {
787
+ }, t("refresh"))), (0, react.createElement)("p", { "data-role": "hint" }, t("hint")), loading || failed !== void 0 || scan?.status === "unavailable" ? null : stats, loading ? (0, react.createElement)("p", { "data-role": "note" }, t("loading")) : null, view.truncated ? (0, react.createElement)("p", { "data-role": "note" }, t("scan.truncated")) : null, failed === void 0 ? null : (0, react.createElement)("div", { "data-role": "note" }, failureBlock(t, failed)), view.loaded === true && view.rows.length === 0 ? (0, react.createElement)("p", { "data-role": "note" }, t("empty.noneReported")) : null, view.proposalStatus === "unavailable" && (view.proposals ?? []).length === 0 ? (0, react.createElement)("p", { "data-role": "note" }, t("proposal.unavailable")) : null, view.proposalStatus === "stale" && (view.proposals ?? []).length === 0 ? (0, react.createElement)("p", { "data-role": "note" }, t("proposal.stale")) : null, (view.proposals ?? []).length > 0 ? (0, react.createElement)("div", { "data-role": "proposals" }, (0, react.createElement)("h3", { "data-role": "group-title" }, t("group.proposals")), ...(view.proposals ?? []).map((proposal) => {
730
788
  const heading = proposal.parts?.[0]?.heading;
731
789
  const target = proposal.owner.mode === "covered" ? proposal.owner.name : proposal.owner.neededOwner;
732
790
  const command = heading === void 0 || target === void 0 ? void 0 : "/evolution extract " + proposal.source + " " + target + " \"" + heading + "\" --plan";
733
791
  return (0, react.createElement)("div", {
734
792
  key: proposal.id,
735
793
  "data-role": "proposal"
736
- }, (0, react.createElement)("p", { "data-role": "proposal-summary" }, proposal.source + " — " + t("proposal.outcome." + proposal.outcome) + " · " + (proposal.owner.mode === "covered" ? t("proposal.owner.covered") + (proposal.owner.name === void 0 ? "" : ": " + proposal.owner.name) : t("proposal.owner.owner-gap") + (proposal.owner.neededOwner === void 0 ? "" : ": " + proposal.owner.neededOwner))), (0, react.createElement)("p", { "data-role": "proposal-status" }, t("proposal.status." + proposal.status)), proposal.provenance === void 0 ? null : (0, react.createElement)("details", { "data-role": "proposal-provenance" }, (0, react.createElement)("summary", null, t("proposal.provenance")), (0, react.createElement)("p", null, proposal.provenance.promptVersion + (proposal.provenance.model === void 0 ? "" : " · " + proposal.provenance.model) + " · " + proposal.provenance.runId + " · " + new Date(proposal.provenance.at).toLocaleString() + (proposal.provenance.promptHash === void 0 ? "" : " · #" + proposal.provenance.promptHash.slice(0, 8)))), proposal.residual === void 0 || proposal.residual.trim() === "" ? null : (0, react.createElement)("p", { "data-role": "proposal-kept" }, t("proposal.kept") + ": " + proposal.residual.trim().slice(0, 160)), (proposal.parts ?? []).length === 0 ? null : (0, react.createElement)("p", { "data-role": "proposal-reusable" }, t("proposal.reusable") + ": " + (proposal.parts ?? []).map((part) => part.heading).join("、")), (proposal.warnings ?? []).length === 0 ? null : (0, react.createElement)("p", { "data-role": "proposal-warnings" }, t("proposal.warnings") + ": " + (proposal.warnings ?? []).join(";")), command === void 0 ? null : (0, react.createElement)("p", { "data-role": "proposal-command" }, (0, react.createElement)("code", {}, command), (0, react.createElement)(CopyButton, {
794
+ }, (0, react.createElement)("p", { "data-role": "proposal-summary" }, proposal.source + " — " + t("proposal.outcome." + proposal.outcome)), (0, react.createElement)("p", { "data-role": "proposal-status" }, t("proposal.status." + proposal.status)), (0, react.createElement)("details", { "data-role": "proposal-provenance" }, (0, react.createElement)("summary", null, t("proposal.provenance")), (0, react.createElement)("p", { "data-role": "proposal-owner" }, t("proposal.owner") + ": " + (proposal.owner.mode === "covered" ? t("proposal.owner.covered") + (proposal.owner.name === void 0 ? "" : ": " + proposal.owner.name) : t("proposal.owner.owner-gap") + (proposal.owner.neededOwner === void 0 ? "" : ": " + proposal.owner.neededOwner))), proposal.provenance === void 0 ? null : (0, react.createElement)("p", null, proposal.provenance.promptVersion + (proposal.provenance.model === void 0 ? "" : " · " + proposal.provenance.model) + " · " + proposal.provenance.runId + " · " + new Date(proposal.provenance.at).toLocaleString() + (proposal.provenance.promptHash === void 0 ? "" : " · #" + proposal.provenance.promptHash.slice(0, 8)))), proposal.residual === void 0 || proposal.residual.trim() === "" ? null : (0, react.createElement)("p", { "data-role": "proposal-kept" }, t("proposal.kept") + ": " + proposal.residual.trim().slice(0, 160)), (proposal.parts ?? []).length === 0 ? null : (0, react.createElement)("p", { "data-role": "proposal-reusable" }, t("proposal.reusable") + ": " + (proposal.parts ?? []).map((part) => part.heading).join("、")), (proposal.warnings ?? []).length === 0 ? null : (0, react.createElement)("p", { "data-role": "proposal-warnings" }, t("proposal.warnings") + ": " + (proposal.warnings ?? []).join(";")), command === void 0 ? null : (0, react.createElement)("p", { "data-role": "proposal-command" }, (0, react.createElement)("code", {}, command), (0, react.createElement)(CopyButton, {
737
795
  command,
738
796
  t,
739
797
  role: "proposal-copy",
740
798
  label: t("proposal.copy")
741
799
  })));
742
- })) : null, skillQueue(view, t), (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", {
743
- key: row.name + ":unreadable",
744
- "data-role": "note"
745
- }, row.name + " — " + t("unreadable.note"))), view.rows.filter((row) => row.protection !== void 0 && row.protection !== null).map((row) => (0, react.createElement)("p", {
746
- key: row.name + ":protected",
747
- "data-role": "note"
748
- }, row.name + " — " + t("protected"))));
800
+ })) : null, (() => {
801
+ const Tabs = platformSegmentedTabs();
802
+ const items = [{
803
+ value: "skills",
804
+ label: t("group.bySkill"),
805
+ id: "evo-health-tab-skills",
806
+ panelId: "evo-health-skills"
807
+ }, {
808
+ value: "rules",
809
+ label: t("group.byRule"),
810
+ id: "evo-health-tab-rules",
811
+ panelId: "evo-health-rules"
812
+ }];
813
+ if (Tabs !== void 0) return (0, react.createElement)(Tabs, {
814
+ items,
815
+ value: viewMode,
816
+ onChange: (next) => {
817
+ setViewMode(next === "rules" ? "rules" : "skills");
818
+ },
819
+ label: t("group.byRule")
820
+ });
821
+ return (0, react.createElement)("div", {
822
+ role: "tablist",
823
+ "data-role": "view-tabs"
824
+ }, items.map((item) => (0, react.createElement)("button", {
825
+ key: item.value,
826
+ type: "button",
827
+ role: "tab",
828
+ "aria-selected": viewMode === item.value ? "true" : "false",
829
+ "aria-controls": item.panelId,
830
+ id: item.id,
831
+ onClick: () => {
832
+ setViewMode(item.value === "rules" ? "rules" : "skills");
833
+ }
834
+ }, item.label)));
835
+ })(), viewMode === "skills" ? (0, react.createElement)("div", {
836
+ id: "evo-health-skills",
837
+ role: "tabpanel"
838
+ }, skillQueue(view, t)) : (0, react.createElement)("div", {
839
+ id: "evo-health-rules",
840
+ role: "tabpanel"
841
+ }, (0, react.createElement)("h3", { "data-role": "group-title" }, t("group.byRule")), ruleTable(view, t)));
749
842
  }
750
843
  //#endregion
751
844
  //#region src/client/seats.ts
@@ -753,24 +846,17 @@ window.__ModuleLoader__.load({
753
846
  function requireHealthSeats(ctx) {
754
847
  if (ctx.slots === void 0) throw new Error("skill-health: the client slots seat is not mounted");
755
848
  }
756
- /** The one place the panel crosses into the platform layout seat. */
757
- function openSkillHistory(ctx, name) {
758
- ctx.layout.openPage("evolution.workbench", name === void 0 ? { view: "history" } : {
759
- view: "history",
760
- skillName: name
761
- });
762
- }
763
849
  //#endregion
764
850
  //#region src/client/index.ts
765
851
  /** Required client services: the slot registry, locale seat and page navigation. */
766
- const inject = [
767
- "slots",
768
- "locale",
769
- "layout"
770
- ];
852
+ const inject = ["slots", "locale"];
771
853
  /** The view component receives the workbench's activeView marker alongside its face. */
772
854
  function HealthView(props) {
773
- return props.activeView === "health" ? SkillHealthPanel(props) : null;
855
+ if (props.activeView !== "health") return null;
856
+ return props.openHistory === void 0 ? SkillHealthPanel(props) : SkillHealthPanel({
857
+ ...props,
858
+ openHistory: props.openHistory
859
+ });
774
860
  }
775
861
  /**
776
862
  * Register the health view on the workbench page.
@@ -798,9 +884,6 @@ window.__ModuleLoader__.load({
798
884
  loaded: false,
799
885
  proposalStatus: "unavailable",
800
886
  loadRows: rows,
801
- openHistory: (name) => {
802
- openSkillHistory(ctx, name);
803
- },
804
887
  t
805
888
  })
806
889
  });
@@ -0,0 +1,17 @@
1
+ /** Platform SegmentedTabs reached through the rc.3 client module table. */
2
+ import type { ReactNode } from 'react';
3
+ export interface SegmentedTabItem {
4
+ readonly value: string;
5
+ readonly label: ReactNode;
6
+ readonly id: string;
7
+ readonly panelId: string;
8
+ }
9
+ export type SegmentedTabsComponent = (props: {
10
+ readonly items: readonly SegmentedTabItem[];
11
+ readonly value: string;
12
+ readonly onChange: (value: string) => void;
13
+ readonly label: string;
14
+ }) => ReactNode;
15
+ /** The platform component, or undefined when this deployment has no module row. */
16
+ export declare function platformSegmentedTabs(): SegmentedTabsComponent | undefined;
17
+ //# sourceMappingURL=platform-tabs.d.ts.map
@@ -1,6 +1,4 @@
1
1
  import type { Context as ClientContext } from '@deepseek-ai/cordis';
2
2
  /** Fail loud when the injected client seats are absent, instead of leaving a PENDING row. */
3
3
  export declare function requireHealthSeats(ctx: ClientContext): void;
4
- /** The one place the panel crosses into the platform layout seat. */
5
- export declare function openSkillHistory(ctx: ClientContext, name?: string): void;
6
4
  //# sourceMappingURL=seats.d.ts.map
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  ]
12
12
  }
13
13
  },
14
- "version": "0.32.6",
14
+ "version": "0.33.0",
15
15
  "publishConfig": {
16
16
  "access": "public"
17
17
  },
@@ -42,18 +42,18 @@
42
42
  "peerDependencies": {
43
43
  "@deepseek-ai/cordis": "^4.0.5",
44
44
  "react": "^18.2.0",
45
- "@lmzhen/dsh-evolution-core": "^0.32.6",
46
- "@lmzhen/dsh-evolution-curator": "^0.32.6"
45
+ "@lmzhen/dsh-evolution-core": "^0.33.0",
46
+ "@lmzhen/dsh-evolution-curator": "^0.33.0"
47
47
  },
48
48
  "devDependencies": {
49
49
  "@deepseek-ai/cordis": "^4.0.5",
50
50
  "@types/react": "~18.3.1",
51
51
  "react": "^18.2.0",
52
- "@lmzhen/dsh-evolution-core": "^0.32.6",
53
- "@lmzhen/dsh-evolution-curator": "^0.32.6"
52
+ "@lmzhen/dsh-evolution-core": "^0.33.0",
53
+ "@lmzhen/dsh-evolution-curator": "^0.33.0"
54
54
  },
55
55
  "dependencies": {
56
- "@lmzhen/dsh-evolution-client-kit": "^0.32.6"
56
+ "@lmzhen/dsh-evolution-client-kit": "^0.33.0"
57
57
  },
58
58
  "engines": {
59
59
  "dsh": ">=0.2.1-rc.2 <0.2.2-0"