@lmzhen/dsh-evolution-skill-health 0.32.5 → 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/README.md CHANGED
@@ -1,19 +1,9 @@
1
1
  # @lmzhen/dsh-evolution-skill-health
2
2
 
3
- > 技能健康面板(可选)。
3
+ Optional read-only skill-health route and a view inside the shared evolution workbench. The `all` bundle ships it disabled by default.
4
4
 
5
- ## 你会看到
5
+ The view projects curator health findings, proposal reports, protection markers, hard-cap hits, and available dimensions such as body size, support files, churn, and stamp density. It reports structural problems and duplicates; it does not repair skills. The by-skill queue is the only skill list; history and copy actions live on each row, and proposal provenance is under a details disclosure.
6
6
 
7
- `/evolution skills health`;侧栏「技能健康」。
7
+ Unreadable skills are not presented as healthy. An unavailable scan or proposal read is marked unavailable/truncated rather than returned as a clean empty result. The `references-sprawl` rule is named but its count is suppressed until its threshold is calibrated.
8
8
 
9
- ## 什么时候会用到
10
-
11
- 你想看结构问题/重复/超长时。
12
-
13
- ## 默认 / 前提
14
-
15
- 完整包里默认关闭。
16
-
17
- ## 边界
18
-
19
- 不修技能,只报告。
9
+ The host package owns one GET route. The browser package registers the view into `evolution.workbench.view`; applying fixes requires the relevant curator or skill-management surface, not this view.
package/lib/client.js CHANGED
@@ -5,28 +5,24 @@ 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 ../evolution-client-kit/src/panel.ts
9
- function interpolate(text, values) {
10
- if (values === void 0) return text;
11
- return text.replace(/\{(\w+)\}/g, (_match, key) => String(values[key] ?? ""));
12
- }
8
+ //#region ../evolution-client-kit/src/workbench-view.ts
13
9
  function injectStyles(doc, css, tagId) {
14
10
  if (doc === void 0) return () => {};
15
11
  doc.querySelector("style[data-plugin-css=\"" + tagId + "\"]")?.remove();
16
12
  const tag = doc.createElement("style");
17
13
  tag.setAttribute("data-plugin-css", tagId);
18
14
  tag.textContent = css;
19
- doc.head.append(tag);
15
+ doc.head.appendChild(tag);
20
16
  return () => {
21
17
  tag.remove();
22
18
  };
23
19
  }
24
20
  /**
25
- * Register one sidebar row and its main body under one lifecycle.
26
- * @param ctx - the client context carrying the slots and locale seats.
27
- * @param spec - the feature-specific row/body descriptor.
21
+ * Register one view into `evolution.workbench.view`.
22
+ * @param ctx - client cordis context.
23
+ * @param spec - view identity, copy, styles, component and face factory.
28
24
  */
29
- function registerSidebarPanel(ctx, spec) {
25
+ function registerWorkbenchView(ctx, spec) {
30
26
  const seam = ctx;
31
27
  let registered = false;
32
28
  ctx.effect(() => {
@@ -35,12 +31,12 @@ window.__ModuleLoader__.load({
35
31
  registered = true;
36
32
  return dispose;
37
33
  } catch (error) {
38
- ctx.logger.warn(spec.namespace + ": the locale seat refused the dictionary (" + String(error) + "); the panel falls back to the bundle copy");
34
+ ctx.logger.warn(spec.namespace + ": locale refused (" + String(error) + "); the view falls back to the bundle copy");
39
35
  return () => {};
40
36
  }
41
37
  }, spec.namespace + ": locale");
42
38
  ctx.effect(() => injectStyles(typeof document === "undefined" ? void 0 : document, spec.styles.css, spec.styles.tagId), spec.namespace + ": styles");
43
- const fallback = spec.dictionaries[spec.fallback ?? "zh"];
39
+ const fallback = spec.dictionaries.zh;
44
40
  const lookup = (key) => {
45
41
  const own = fallback[key] ?? key;
46
42
  if (!registered) return own;
@@ -50,19 +46,18 @@ window.__ModuleLoader__.load({
50
46
  return own;
51
47
  }
52
48
  };
53
- const t = (key, values) => interpolate(lookup(key), values);
54
- const label = () => lookup("entry.label");
55
- seam.slots.inject("sidebar.panellist", function* () {
49
+ const t = (key, values) => {
50
+ const template = lookup(key);
51
+ if (values === void 0) return template;
52
+ return template.replace(/\{(\w+)\}/g, (match, slot) => values[slot] === void 0 ? match : String(values[slot]));
53
+ };
54
+ seam.slots.inject("evolution.workbench.view", function* () {
56
55
  yield seam.slots.register({
57
- name: "sidebar.panellist",
56
+ name: "evolution.workbench.view",
58
57
  id: spec.id,
59
58
  order: spec.order,
60
- label
61
- }, spec.icon);
62
- yield seam.slots.register({
63
- name: "main",
64
- key: spec.id,
65
- inject: () => spec.body(t)
59
+ label: () => t("entry.label"),
60
+ inject: () => spec.face(t)
66
61
  }, spec.component);
67
62
  });
68
63
  }
@@ -79,7 +74,8 @@ window.__ModuleLoader__.load({
79
74
  pending: "/api/dsh-evolution/approval/pending",
80
75
  preview: "/api/dsh-evolution/approval/preview",
81
76
  approve: "/api/dsh-evolution/approval/approve",
82
- reject: "/api/dsh-evolution/approval/reject"
77
+ reject: "/api/dsh-evolution/approval/reject",
78
+ release: "/api/dsh-evolution/approval/release"
83
79
  },
84
80
  "skill-history": {
85
81
  skills: "/api/dsh-evolution/skill-history/skills",
@@ -98,8 +94,30 @@ window.__ModuleLoader__.load({
98
94
  body: "/api/dsh-evolution/merge/body",
99
95
  history: "/api/dsh-evolution/merge/history"
100
96
  },
101
- diagnostics: { view: "/api/dsh-evolution/diagnostics" }
97
+ diagnostics: { view: "/api/dsh-evolution/diagnostics" },
98
+ settings: {
99
+ describe: "/api/dsh-evolution/settings/describe",
100
+ mutate: "/api/dsh-evolution/settings/mutate"
101
+ }
102
102
  };
103
+ ROUTES.settings.describe;
104
+ ROUTES.settings.mutate;
105
+ Object.freeze({
106
+ status: "unavailable",
107
+ value: void 0,
108
+ user: void 0,
109
+ writable: false,
110
+ base: void 0,
111
+ revision: void 0,
112
+ reason: "transport"
113
+ });
114
+ //#endregion
115
+ //#region ../evolution-client-kit/src/action.ts
116
+ /**
117
+ * Command-only actions. Approval decisions are a separate host API and must never
118
+ * be represented as a copyable command here.
119
+ * @module @lmzhen/dsh-evolution-client-kit
120
+ */
103
121
  //#endregion
104
122
  //#region ../evolution-client-kit/src/generated/fallbacks.generated.ts
105
123
  /**
@@ -109,13 +127,14 @@ window.__ModuleLoader__.load({
109
127
  */
110
128
  const FALLBACKS = {
111
129
  approval: { command: "/evolution pending … /evolution approve <id> … /evolution reject <id> … /evolution release <id>" },
112
- "skill-history": { command: "/evolution restore <name> [v](查看:/evolution skills history <name>)" },
130
+ "skill-history": { command: "/evolution skill undo <name> [--to v<N>](查看:/evolution skill history <name>)" },
113
131
  "skill-health": { command: "/evolution skills refresh(健康行:/evolution doctor)" },
114
132
  merge: { command: "/evolution merge status / pending / approve <id> / report" },
115
133
  diagnostics: {
116
134
  command: "/evolution doctor",
117
135
  platformCli: "dsh --json /evolution doctor"
118
- }
136
+ },
137
+ settings: { command: "/evolution policy set <id> <value>(查看:/evolution policy)" }
119
138
  };
120
139
  //#endregion
121
140
  //#region ../evolution-client-kit/src/generated/states.generated.ts
@@ -302,12 +321,22 @@ window.__ModuleLoader__.load({
302
321
  "verdict.unreadable": "不可读",
303
322
  "group.proposals": "语义提议",
304
323
  "proposal.unavailable": "提议源未挂载;这不是「没有可拆项」。",
324
+ "proposal.stale": "提议通道的数据已过期;这不是「没有可整理内容」,请刷新后重试。",
325
+ "proposal.owner": "归属",
305
326
  "proposal.outcome.keep": "保持",
306
327
  "proposal.outcome.extract": "提取",
307
328
  "proposal.outcome.mixed": "混合",
308
- "proposal.outcome.owner-gap": "owner 缺口",
309
- "proposal.owner.covered": "有覆盖 owner",
310
- "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": "只写不读",
311
340
  "proposal.status.proposed": "状态:提议",
312
341
  "proposal.status.previewed": "状态:已预览",
313
342
  "proposal.status.stale": "状态:已过期",
@@ -316,6 +345,7 @@ window.__ModuleLoader__.load({
316
345
  "proposal.kept": "保留正文",
317
346
  "proposal.warnings": "警告",
318
347
  "proposal.copy": "复制命令",
348
+ "proposal.provenance": "生成来源",
319
349
  "counts": "{ok} 正常 · {warn} 警告 · {error} 错误 · {unreadable} 不可读",
320
350
  "col.skill": "技能",
321
351
  "col.findings": "证据",
@@ -340,8 +370,15 @@ window.__ModuleLoader__.load({
340
370
  "failure.unmounted": "该功能没有挂载。",
341
371
  "failure.server": "读取失败,可以重试。",
342
372
  "fallback.hint": "可以改用命令:{command}",
373
+ "failureUnauthorized": "需要登录:重新打开这个页面完成登录后再试。",
374
+ "failureForbidden": "平台拒绝了这个请求(身份不是 owner)。",
375
+ "failureUnmounted": "该功能没有挂载。",
376
+ "failureServer": "读取失败,可以重试。",
377
+ "fallbackHint": "可以改用命令:{command}",
343
378
  "action.history": "查看历史",
344
379
  "action.copy": "复制命令",
380
+ "copy.copied": "已复制",
381
+ "copy.failed": "复制失败",
345
382
  "action.extract": "提取",
346
383
  "action.extract.reason": "命令/预览面未就绪,暂不可用。"
347
384
  };
@@ -366,12 +403,22 @@ window.__ModuleLoader__.load({
366
403
  "verdict.unreadable": "Unreadable",
367
404
  "group.proposals": "Semantic proposals",
368
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",
369
408
  "proposal.outcome.keep": "keep",
370
409
  "proposal.outcome.extract": "extract",
371
410
  "proposal.outcome.mixed": "mixed",
372
411
  "proposal.outcome.owner-gap": "owner-gap",
373
- "proposal.owner.covered": "covered owner",
374
- "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",
375
422
  "proposal.status.proposed": "status: proposed",
376
423
  "proposal.status.previewed": "status: previewed",
377
424
  "proposal.status.stale": "status: stale",
@@ -380,6 +427,7 @@ window.__ModuleLoader__.load({
380
427
  "proposal.kept": "kept body",
381
428
  "proposal.warnings": "warnings",
382
429
  "proposal.copy": "Copy command",
430
+ "proposal.provenance": "Provenance",
383
431
  "counts": "{ok} ok · {warn} warn · {error} error · {unreadable} unreadable",
384
432
  "col.skill": "Skill",
385
433
  "col.findings": "Evidence",
@@ -403,8 +451,15 @@ window.__ModuleLoader__.load({
403
451
  "failure.unmounted": "This feature is not mounted.",
404
452
  "failure.server": "The read failed; you can retry.",
405
453
  "fallback.hint": "Command fallback: {command}",
454
+ "failureUnauthorized": "Sign-in is required: reopen this page and sign in, then retry.",
455
+ "failureForbidden": "The platform refused this request (not the owner principal).",
456
+ "failureUnmounted": "This feature is not mounted.",
457
+ "failureServer": "The read failed; you can retry.",
458
+ "fallbackHint": "Command fallback: {command}",
406
459
  "action.history": "History",
407
460
  "action.copy": "Copy command",
461
+ "copy.copied": "Copied",
462
+ "copy.failed": "Copy failed",
408
463
  "action.extract": "Extract",
409
464
  "action.extract.reason": "The command/preview surface is not ready yet."
410
465
  };
@@ -443,7 +498,7 @@ window.__ModuleLoader__.load({
443
498
  ":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 }",
444
499
  ":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); }",
445
500
  ":where(.dsh-evolution-skill-health [data-role=\"hint\"]) { margin: 0; color: var(--dsw-alias-label-secondary); }",
446
- ":where(.dsh-evolution-skill-health [data-role=\"stats\"]) { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--evo-space-8); }",
501
+ ":where(.dsh-evolution-skill-health [data-role=\"stats\"]) { display: grid; grid-template-columns: repeat(auto-fit, minmax(136px, 1fr)); gap: var(--evo-space-8); }",
447
502
  ":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-l1); border-radius: var(--evo-radius-control); }",
448
503
  ":where(.dsh-evolution-skill-health [data-role=\"stat\"][data-tone=\"ok\"]) { box-shadow: inset 2px 0 0 var(--dsw-alias-state-success-primary); }",
449
504
  ":where(.dsh-evolution-skill-health [data-role=\"stat\"][data-tone=\"warn\"]) { box-shadow: inset 2px 0 0 var(--dsw-alias-state-warn-primary); }",
@@ -452,8 +507,20 @@ window.__ModuleLoader__.load({
452
507
  ":where(.dsh-evolution-skill-health [data-role=\"stat-value\"]) { font-size: var(--evo-type-lg); font-variant-numeric: tabular-nums; line-height: 1; }",
453
508
  ":where(.dsh-evolution-skill-health [data-role=\"stat-label\"]) { color: var(--dsw-alias-label-tertiary); }",
454
509
  ":where(.dsh-evolution-skill-health [data-role=\"group-title\"]) { margin: 0; font-weight: 500; }",
455
- ":where(.dsh-evolution-skill-health [data-role=\"rule-table\"]) { display: flex; flex-direction: column; border: var(--evo-hairline-width) solid var(--dsw-alias-border-l1); border-radius: var(--evo-radius-control); overflow: hidden; }",
456
- ":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-l1); }",
510
+ ":where(.dsh-evolution-skill-health [data-role=\"rule-table\"]) { display: table; width: 100%; border-collapse: collapse; border: var(--evo-hairline-width) solid var(--dsw-alias-border-l1); border-radius: var(--evo-radius-control); overflow: hidden; }",
511
+ ":where(.dsh-evolution-skill-health [data-role=\"rule-row\"]) { border-top: var(--evo-hairline-width) solid var(--dsw-alias-border-l1); }",
512
+ ":where(.dsh-evolution-skill-health [data-role=\"rule-row\"] > th, .dsh-evolution-skill-health [data-role=\"rule-row\"] > td) { padding: var(--evo-space-6) var(--evo-space-10); text-align: left; vertical-align: top; }",
513
+ ":where(.dsh-evolution-skill-health [data-role=\"rule-row\"] > th:first-child) { width: minmax(9rem, 13rem); }",
514
+ ":where(.dsh-evolution-skill-health [data-role=\"rule-row\"] > th:last-child, .dsh-evolution-skill-health [data-role=\"rule-row\"] > td:last-child) { width: 4rem; text-align: right; }",
515
+ ":where(.dsh-evolution-skill-health [data-role=\"rule-row\"][data-tone=\"ok\"]) { box-shadow: inset var(--evo-hairline-marker) 0 0 var(--dsw-alias-state-success-primary); }",
516
+ ":where(.dsh-evolution-skill-health [data-role=\"skill-queue\"]) { display: flex; flex-direction: column; gap: var(--evo-space-6); }",
517
+ ":where(.dsh-evolution-skill-health [data-role=\"skill-row\"]) { display: grid; grid-template-columns: minmax(8rem, 12rem) 6rem minmax(0, 1fr) auto; gap: var(--evo-space-8); align-items: center; padding: var(--evo-space-6) var(--evo-space-10); border: var(--evo-hairline-width) solid var(--dsw-alias-border-l1); border-radius: var(--evo-radius-control); }",
518
+ ":where(.dsh-evolution-skill-health [data-role=\"skill-name\"]) { overflow-wrap: anywhere; font-weight: 500; }",
519
+ ":where(.dsh-evolution-skill-health [data-role=\"skill-verdict\"], .dsh-evolution-skill-health [data-role=\"skill-dims\"], .dsh-evolution-skill-health [data-role=\"skill-findings\"]) { color: var(--dsw-alias-label-secondary); font-size: var(--evo-type-xs); }",
520
+ ":where(.dsh-evolution-skill-health [data-role=\"skill-row-actions\"]) { display: flex; gap: var(--evo-space-4); }",
521
+ ":where(.dsh-evolution-skill-health [data-role=\"proposals\"]) { display: flex; flex-direction: column; gap: var(--evo-space-8); }",
522
+ ":where(.dsh-evolution-skill-health [data-role=\"proposal\"]) { padding: var(--evo-space-8) var(--evo-space-10); border: var(--evo-hairline-width) solid var(--dsw-alias-border-l1); border-radius: var(--evo-radius-control); }",
523
+ ":where(.dsh-evolution-skill-health [data-role=\"proposal\"] p) { margin: var(--evo-space-2) 0; }",
457
524
  ":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); }",
458
525
  ":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); }",
459
526
  ":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); }",
@@ -467,6 +534,21 @@ window.__ModuleLoader__.load({
467
534
  ":where(.dsh-evolution-skill-health [data-role=\"note\"]) { margin: 0; color: var(--dsw-alias-label-secondary); }"
468
535
  ].join(String.fromCharCode(10));
469
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
470
552
  //#region src/client/Panel.ts
471
553
  /**
472
554
  * The panel body: a four-state summary plus the list aggregated BY RULE.
@@ -485,6 +567,31 @@ window.__ModuleLoader__.load({
485
567
  "error",
486
568
  "unreadable"
487
569
  ];
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
+ }
588
+ const TONE = Object.freeze({
589
+ healthy: "ok",
590
+ warn: "warn",
591
+ "needs-restructure": "warn",
592
+ error: "error",
593
+ unreadable: "unreadable"
594
+ });
488
595
  /** One row per rule, with the skills that carry it — the view the report is actually read in. */
489
596
  function byRule(rows) {
490
597
  const table = /* @__PURE__ */ new Map();
@@ -516,6 +623,28 @@ window.__ModuleLoader__.load({
516
623
  }
517
624
  return worst;
518
625
  }
626
+ /** A copy button that reports the clipboard verdict instead of swallowing it. */
627
+ function CopyButton(props) {
628
+ const [state, setState] = (0, react.useState)("idle");
629
+ const copy = async () => {
630
+ try {
631
+ if (typeof navigator === "undefined" || navigator.clipboard === void 0) throw new Error("clipboard unavailable");
632
+ await navigator.clipboard.writeText(props.command);
633
+ setState("ok");
634
+ } catch {
635
+ setState("fail");
636
+ }
637
+ };
638
+ const text = state === "ok" ? props.t("copy.copied") : state === "fail" ? props.t("copy.failed") : props.label;
639
+ return (0, react.createElement)("button", {
640
+ type: "button",
641
+ "data-role": props.role,
642
+ "data-copy-state": state,
643
+ onClick: () => {
644
+ copy();
645
+ }
646
+ }, text);
647
+ }
519
648
  /** H4: the evidence queue by skill, before the by-rule summary. */
520
649
  function skillQueue(face, t) {
521
650
  const order = [
@@ -530,52 +659,45 @@ window.__ModuleLoader__.load({
530
659
  key: row.name,
531
660
  "data-role": "skill-row",
532
661
  "data-tone": row.verdict
533
- }, (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"))))));
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", {
663
+ type: "button",
664
+ "data-role": "action-history",
665
+ disabled: face.openHistory === void 0,
666
+ onClick: () => {
667
+ face.openHistory?.(row.name);
668
+ }
669
+ }, t("action.history")), (0, react.createElement)(CopyButton, {
670
+ command: "/evolution skill history " + row.name,
671
+ t,
672
+ role: "action-copy",
673
+ label: t("action.copy")
674
+ })))));
534
675
  }
535
676
  /** The rule table: a grid so counts line up, with a tone bar per row and skill pills. */
536
677
  function ruleTable(face, t) {
537
678
  const rows = byRule(face.rows);
538
- const cell = (role, children, key) => (0, react.createElement)("div", key === void 0 ? { "data-role": role } : {
679
+ const cell = (role, children, key) => (0, react.createElement)("td", key === void 0 ? { "data-role": role } : {
539
680
  "data-role": role,
540
681
  key
541
682
  }, children);
542
- return (0, react.createElement)("div", { "data-role": "rule-table" }, (0, react.createElement)("div", {
543
- "data-role": "rule-row",
544
- "data-role-head": "true"
545
- }, (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", {
683
+ return (0, react.createElement)("table", { "data-role": "rule-table" }, (0, react.createElement)("thead", null, (0, react.createElement)("tr", { "data-role": "rule-head" }, (0, react.createElement)("th", {
684
+ scope: "col",
685
+ "data-role": "rule-name"
686
+ }, t("col.rule")), (0, react.createElement)("th", {
687
+ scope: "col",
688
+ "data-role": "skills"
689
+ }, t("col.skills")), (0, react.createElement)("th", {
690
+ scope: "col",
691
+ "data-role": "rule-count"
692
+ }, t("col.count")))), (0, react.createElement)("tbody", null, rows.map((entry) => (0, react.createElement)("tr", {
546
693
  key: entry.rule,
547
694
  "data-role": "rule-row",
548
- "data-tone": worstVerdict(face, entry.skills)
549
- }, cell("rule-name", entry.rule), cell("skills", entry.skills.map((name, i) => (0, react.createElement)("span", {
695
+ "data-tone": TONE[worstVerdict(face, entry.skills)]
696
+ }, cell("rule-name", ruleName(t, entry.rule)), cell("skills", entry.skills.map((name, i) => (0, react.createElement)("span", {
550
697
  "data-role": "skill-pill",
551
698
  key: name + ":" + String(i),
552
699
  title: name
553
- }, name))), cell("rule-count", entry.count === 0 ? t("count.notCalibrated") : String(entry.count)))));
554
- }
555
- /** Per-skill actions: open history, copy the CLI command, and the disabled extract entry. */
556
- function skillActions(face, t) {
557
- const names = [...new Set(face.rows.map((row) => row.name))];
558
- const copy = (name) => {
559
- const text = "/evolution skill history " + name;
560
- if (typeof navigator !== "undefined" && navigator.clipboard !== void 0) navigator.clipboard.writeText(text).catch(() => {});
561
- };
562
- return (0, react.createElement)("div", { "data-role": "skill-actions" }, ...names.map((name) => (0, react.createElement)("div", {
563
- key: name,
564
- "data-role": "skill-action-row"
565
- }, (0, react.createElement)("span", { "data-role": "skill-action-name" }, name), (0, react.createElement)("button", {
566
- type: "button",
567
- "data-role": "action-history",
568
- disabled: face.openHistory === void 0,
569
- onClick: () => {
570
- face.openHistory?.(name);
571
- }
572
- }, t("action.history")), (0, react.createElement)("button", {
573
- type: "button",
574
- "data-role": "action-copy",
575
- onClick: () => {
576
- copy(name);
577
- }
578
- }, t("action.copy")))));
700
+ }, name))), cell("rule-count", entry.count === 0 ? t("count.notCalibrated") : String(entry.count))))));
579
701
  }
580
702
  /**
581
703
  * Render the panel.
@@ -608,6 +730,8 @@ window.__ModuleLoader__.load({
608
730
  const [loading, setLoading] = (0, react.useState)(face.loadRows !== void 0 && face.loaded !== true);
609
731
  const [lastReadAt, setLastReadAt] = (0, react.useState)(face.readAt);
610
732
  const [scan, setScan] = (0, react.useState)(face.scan);
733
+ const [viewMode, setViewMode] = (0, react.useState)("skills");
734
+ const firstLoad = (0, react.useRef)(false);
611
735
  /** One read trigger for first paint and the refresh button; the latest answer wins. */
612
736
  const load = () => {
613
737
  const read = face.loadRows;
@@ -628,6 +752,7 @@ window.__ModuleLoader__.load({
628
752
  });
629
753
  setLastReadAt(payload.readAt);
630
754
  setScan(payload.scan);
755
+ setFailed(void 0);
631
756
  } else setFailed(outcome.failure);
632
757
  }).catch(() => {
633
758
  if (live) setFailed({
@@ -641,12 +766,16 @@ window.__ModuleLoader__.load({
641
766
  live = false;
642
767
  };
643
768
  };
644
- (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]);
645
774
  const counts = new Map(KINDS.map((kind) => [kind, view.rows.filter((row) => row.verdict === kind).length]));
646
775
  const stats = (0, react.createElement)("div", { "data-role": "stats" }, KINDS.map((kind) => (0, react.createElement)("div", {
647
776
  key: kind,
648
777
  "data-role": "stat",
649
- "data-tone": kind
778
+ "data-tone": TONE[kind]
650
779
  }, (0, react.createElement)("div", { "data-role": "stat-value" }, String(counts.get(kind) ?? 0)), (0, react.createElement)("div", { "data-role": "stat-label" }, t("verdict." + kind)))));
651
780
  return (0, react.createElement)("section", { className: CSS_TAG_ID }, (0, react.createElement)("div", { "data-role": "header" }, (0, react.createElement)("span", { "data-role": "read-at" }, lastReadAt === void 0 ? t("readAt.unknown") : new Date(lastReadAt).toLocaleString()), (0, react.createElement)("span", { "data-role": "scan-status" }, t("scan." + (scan?.status ?? "unavailable"))), (0, react.createElement)("button", {
652
781
  type: "button",
@@ -655,28 +784,61 @@ window.__ModuleLoader__.load({
655
784
  onClick: () => {
656
785
  load();
657
786
  }
658
- }, t("refresh"))), (0, react.createElement)("p", { "data-role": "hint" }, t("hint")), 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) => {
659
788
  const heading = proposal.parts?.[0]?.heading;
660
789
  const target = proposal.owner.mode === "covered" ? proposal.owner.name : proposal.owner.neededOwner;
661
790
  const command = heading === void 0 || target === void 0 ? void 0 : "/evolution extract " + proposal.source + " " + target + " \"" + heading + "\" --plan";
662
- const copyCommand = () => {
663
- if (command !== void 0 && typeof navigator !== "undefined" && navigator.clipboard !== void 0) navigator.clipboard.writeText(command).catch(() => {});
664
- };
665
791
  return (0, react.createElement)("div", {
666
792
  key: proposal.id,
667
793
  "data-role": "proposal"
668
- }, (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)("p", { "data-role": "proposal-provenance" }, 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)("button", {
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, {
795
+ command,
796
+ t,
797
+ role: "proposal-copy",
798
+ label: t("proposal.copy")
799
+ })));
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,
669
826
  type: "button",
670
- "data-role": "proposal-copy",
671
- onClick: copyCommand
672
- }, t("proposal.copy"))));
673
- })) : null, skillQueue(view, t), (0, react.createElement)("h3", { "data-role": "group-title" }, t("group.byRule")), ruleTable(view, t), skillActions(view, t), view.rows.filter((row) => row.verdict === "unreadable").map((row) => (0, react.createElement)("p", {
674
- key: row.name + ":unreadable",
675
- "data-role": "note"
676
- }, row.name + " — " + t("unreadable.note"))), view.rows.filter((row) => row.protection !== void 0 && row.protection !== null).map((row) => (0, react.createElement)("p", {
677
- key: row.name + ":protected",
678
- "data-role": "note"
679
- }, row.name + " — " + t("protected"))));
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)));
680
842
  }
681
843
  //#endregion
682
844
  //#region src/client/seats.ts
@@ -684,39 +846,25 @@ window.__ModuleLoader__.load({
684
846
  function requireHealthSeats(ctx) {
685
847
  if (ctx.slots === void 0) throw new Error("skill-health: the client slots seat is not mounted");
686
848
  }
687
- /** The one place the panel crosses into the platform layout seat. */
688
- function openSkillHistory(ctx) {
689
- ctx.layout.selectPanel("skill-history");
690
- }
691
849
  //#endregion
692
850
  //#region src/client/index.ts
693
- /** Required client services: the slot registry and the locale seat. */
694
- const inject = [
695
- "slots",
696
- "locale",
697
- "layout"
698
- ];
699
- function PanelIcon(props = {}) {
700
- const size = typeof props.size === "number" && props.size > 0 ? props.size : 16;
701
- return (0, react.createElement)("svg", {
702
- "aria-hidden": "true",
703
- width: String(size),
704
- height: String(size),
705
- viewBox: "0 0 16 16",
706
- fill: "none",
707
- stroke: "currentColor",
708
- strokeWidth: "1.5",
709
- strokeLinecap: "round",
710
- strokeLinejoin: "round"
711
- }, (0, react.createElement)("path", { d: "M2 8h3l1.5-3.5L9 11.5 10.5 8H14" }));
851
+ /** Required client services: the slot registry, locale seat and page navigation. */
852
+ const inject = ["slots", "locale"];
853
+ /** The view component receives the workbench's activeView marker alongside its face. */
854
+ function HealthView(props) {
855
+ if (props.activeView !== "health") return null;
856
+ return props.openHistory === void 0 ? SkillHealthPanel(props) : SkillHealthPanel({
857
+ ...props,
858
+ openHistory: props.openHistory
859
+ });
712
860
  }
713
861
  /**
714
- * Register the row and the body through the shared panel lifecycle.
715
- * @param ctx - the client context; it must carry the two seats above.
862
+ * Register the health view on the workbench page.
863
+ * @param ctx - the client context; it must carry the seats above.
716
864
  */
717
865
  function apply(ctx) {
718
866
  requireHealthSeats(ctx);
719
- registerSidebarPanel(ctx, {
867
+ registerWorkbenchView(ctx, {
720
868
  id: PANEL_ID,
721
869
  order: 40,
722
870
  namespace: NS,
@@ -728,18 +876,14 @@ window.__ModuleLoader__.load({
728
876
  css: CSS,
729
877
  tagId: CSS_TAG_ID
730
878
  },
731
- icon: PanelIcon,
732
- component: SkillHealthPanel,
733
- body: (t) => ({
879
+ component: HealthView,
880
+ face: (t) => ({
734
881
  rows: [],
735
882
  proposals: [],
736
883
  truncated: false,
737
884
  loaded: false,
738
885
  proposalStatus: "unavailable",
739
886
  loadRows: rows,
740
- openHistory: () => {
741
- openSkillHistory(ctx);
742
- },
743
887
  t
744
888
  })
745
889
  });
@@ -1,18 +1,18 @@
1
1
  /**
2
- * Browser half: one left-sidebar row (技能健康) and the main-column body it opens.
2
+ * Browser half: the health view inside the shared evolution workbench.
3
3
  * @module @lmzhen/dsh-evolution-skill-health/client
4
4
  */
5
5
  import type { Context as ClientContext } from '@deepseek-ai/cordis';
6
6
  import { PANEL_ID, PANEL_ORDER } from './ids.ts';
7
7
  import { type HealthFace } from './Panel.ts';
8
- /** Required client services: the slot registry and the locale seat. */
8
+ /** Required client services: the slot registry, locale seat and page navigation. */
9
9
  export declare const inject: string[];
10
10
  /** The host half hands the panel a way to read its rows (a read-only route on the host side). */
11
11
  export type HealthFaceLoader = () => Promise<HealthFace>;
12
12
  export { PANEL_ID, PANEL_ORDER };
13
13
  /**
14
- * Register the row and the body through the shared panel lifecycle.
15
- * @param ctx - the client context; it must carry the two seats above.
14
+ * Register the health view on the workbench page.
15
+ * @param ctx - the client context; it must carry the seats above.
16
16
  */
17
17
  export declare function apply(ctx: ClientContext): void;
18
18
  //# sourceMappingURL=index.d.ts.map
@@ -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): 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.5",
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.5",
46
- "@lmzhen/dsh-evolution-curator": "^0.32.5"
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.5",
53
- "@lmzhen/dsh-evolution-curator": "^0.32.5"
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.5"
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"