@lmzhen/dsh-evolution-ui 0.35.0 → 0.36.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
@@ -831,9 +831,12 @@ window.__ModuleLoader__.load({
831
831
  /** Chinese copy (the family's primary language). */
832
832
  const zh$1 = {
833
833
  title: "自进化",
834
+ "group.write": "写入与审批",
835
+ "group.organize": "自动整理",
836
+ "group.memory": "记忆与回顾",
834
837
  subtitle: "待你决定的写入在最上面;下面按功能列出你能改的参数,没有列出的由安装时的配置决定。",
835
838
  aboutPurpose: "自进化设置与技能历史",
836
- overridden: "已覆盖",
839
+ overridden: "已修改",
837
840
  deployment: "默认",
838
841
  loading: "正在读取设置…",
839
842
  unavailable: "这个功能没有启动(对应的插件没有安装)",
@@ -843,7 +846,7 @@ window.__ModuleLoader__.load({
843
846
  apply: "保存",
844
847
  reset: "复位",
845
848
  empty: "这里没有可改项",
846
- changed: "{n} 项已覆盖",
849
+ changed: "{n} 项已修改",
847
850
  discard: "放弃修改",
848
851
  saving: "保存中…",
849
852
  resetting: "复位中…",
@@ -875,7 +878,12 @@ window.__ModuleLoader__.load({
875
878
  mergeCardHint: "写入审批=使用中生成/修改;合并审批=两轮工作流。",
876
879
  approvalTitle: "待批写入",
877
880
  approvalLoading: "正在读取待批项…",
878
- approvalEmpty: "没有待批的写入",
881
+ approvalEmpty: "没有待处理的写入",
882
+ approvalEmptyDescription: "当前没有需要你确认的技能变更。新的写入会在这里显示来源、内容和影响范围。",
883
+ approvalHistory: "查看技能历史",
884
+ approvalFactKind: "类型",
885
+ approvalFactAge: "时间",
886
+ approvalFactTarget: "对象",
879
887
  approvalFailed: "待批项读取失败",
880
888
  approvalRetry: "重试",
881
889
  approvalApprove: "批准",
@@ -915,6 +923,9 @@ window.__ModuleLoader__.load({
915
923
  diagTitle: "诊断",
916
924
  diagSubtitle: "运行状态的只读自查;不会改动任何东西。",
917
925
  diagRuntimeTitle: "运行状态",
926
+ diagComplete: "没有需要处理的异常",
927
+ diagOtherIssues: "其他 {n} 项异常",
928
+ diagNormal: "其他 {n} 项正常",
918
929
  diagSummaryOk: "运行正常",
919
930
  diagSummaryWarn: "{n} 项需要注意",
920
931
  diagSummaryFail: "{n} 项异常",
@@ -939,9 +950,12 @@ window.__ModuleLoader__.load({
939
950
  /** English copy, key for key with {@link zh}. */
940
951
  const en$1 = {
941
952
  title: "Self-evolution",
953
+ "group.write": "Writes and approval",
954
+ "group.organize": "Automatic tidy-up",
955
+ "group.memory": "Memory and review",
942
956
  subtitle: "Writes waiting for your decision come first; the changeable parameters are listed by feature below, and anything not listed comes from the deployment configuration.",
943
957
  aboutPurpose: "Self-evolution settings and skill history",
944
- overridden: "Overridden",
958
+ overridden: "Modified",
945
959
  deployment: "default",
946
960
  loading: "reading settings…",
947
961
  unavailable: "this feature is not running (its plugin is not installed)",
@@ -951,7 +965,7 @@ window.__ModuleLoader__.load({
951
965
  apply: "Save",
952
966
  reset: "Reset",
953
967
  empty: "nothing to change here",
954
- changed: "{n} overridden",
968
+ changed: "{n} modified",
955
969
  discard: "Discard",
956
970
  saving: "Saving…",
957
971
  resetting: "Resetting…",
@@ -983,7 +997,12 @@ window.__ModuleLoader__.load({
983
997
  mergeCardHint: "Write approval = generate/modify while in use; merge approval = the two-round workflow.",
984
998
  approvalTitle: "Writes awaiting approval",
985
999
  approvalLoading: "reading the pending window…",
986
- approvalEmpty: "nothing is waiting for a decision",
1000
+ approvalEmpty: "Nothing is waiting",
1001
+ approvalEmptyDescription: "There are no skill changes to confirm. New writes will show their source, content and impact here.",
1002
+ approvalHistory: "View skill history",
1003
+ approvalFactKind: "Kind",
1004
+ approvalFactAge: "Time",
1005
+ approvalFactTarget: "Target",
987
1006
  approvalFailed: "the pending window could not be read",
988
1007
  approvalRetry: "Retry",
989
1008
  approvalApprove: "Approve",
@@ -1023,6 +1042,9 @@ window.__ModuleLoader__.load({
1023
1042
  diagTitle: "Diagnostics",
1024
1043
  diagSubtitle: "A read-only check of the runtime state; nothing here changes anything.",
1025
1044
  diagRuntimeTitle: "Runtime status",
1045
+ diagComplete: "Nothing needs attention",
1046
+ diagOtherIssues: "Other {n} issues",
1047
+ diagNormal: "Other {n} normal checks",
1026
1048
  diagSummaryOk: "All healthy",
1027
1049
  diagSummaryWarn: "{n} need attention",
1028
1050
  diagSummaryFail: "{n} failing",
@@ -1262,20 +1284,20 @@ window.__ModuleLoader__.load({
1262
1284
  return (0, react.createElement)("div", { className: "evolution-param-field" }, (0, react.createElement)("div", { className: "evolution-param-label" }, (0, react.createElement)("label", { htmlFor: controlId(field) }, labelOf(field, lang) === "" ? field.id : labelOf(field, lang)), unit, props.overridden ? (0, react.createElement)("span", {
1263
1285
  className: "evolution-param-source",
1264
1286
  "data-user": "true"
1265
- }, t("overridden")) : null), FieldControl(props), (0, react.createElement)("p", { className: "evolution-param-hint" }, hintOf(field, lang) === "" ? field.doc : hintOf(field, lang)), props.invalid === null ? null : (0, react.createElement)("p", {
1266
- id: controlId(field) + "-invalid",
1267
- className: "evolution-param-error",
1268
- role: "status"
1269
- }, props.invalid), props.overridden ? (0, react.createElement)("div", { className: "evolution-param-actions" }, (0, react.createElement)("button", {
1287
+ }, t("overridden")) : null, props.overridden ? (0, react.createElement)("button", {
1270
1288
  type: "button",
1271
- className: "evolution-param-button",
1289
+ className: "evolution-param-reset",
1272
1290
  disabled: props.disabled || props.clearing,
1273
1291
  "data-role": "reset",
1274
1292
  title: props.resetTo === null ? void 0 : t("resetTo", { value: props.resetTo }),
1275
1293
  onClick: () => {
1276
1294
  props.onClear(field.id);
1277
1295
  }
1278
- }, props.clearing ? t("resetting") : t("reset"))) : null);
1296
+ }, props.clearing ? t("resetting") : t("reset")) : null), FieldControl(props), (0, react.createElement)("p", { className: "evolution-param-hint" }, hintOf(field, lang) === "" ? field.doc : hintOf(field, lang)), props.invalid === null ? null : (0, react.createElement)("p", {
1297
+ id: controlId(field) + "-invalid",
1298
+ className: "evolution-param-error",
1299
+ role: "status"
1300
+ }, props.invalid));
1279
1301
  }
1280
1302
  /**
1281
1303
  * Render one row's card body from a supplied snapshot.
@@ -1524,6 +1546,36 @@ window.__ModuleLoader__.load({
1524
1546
  });
1525
1547
  }
1526
1548
  //#endregion
1549
+ //#region src/panels/settings/settings-groups.ts
1550
+ const GROUP_OF = Object.freeze({
1551
+ "evolution-approval": "write",
1552
+ "evolution-merge": "write",
1553
+ "tool-skill-manage": "write",
1554
+ "evolution-curator": "organize",
1555
+ "evolution-commands": "organize",
1556
+ "memory-files": "memory",
1557
+ "tool-memory": "memory",
1558
+ "evolution-review": "memory"
1559
+ });
1560
+ /** Stable display order for the three task groups. */
1561
+ const SETTINGS_GROUP_ORDER = [
1562
+ "write",
1563
+ "organize",
1564
+ "memory"
1565
+ ];
1566
+ /**
1567
+ * Partition existing parameter cards by task. Unknown namespaces fall into organize so a future row
1568
+ * is visible rather than silently dropped.
1569
+ * @param cards - cards carrying only their namespace and payload.
1570
+ * @returns groups in display order, omitting empty groups.
1571
+ */
1572
+ function groupParamCards(cards) {
1573
+ return SETTINGS_GROUP_ORDER.map((group) => ({
1574
+ group,
1575
+ items: cards.filter((card) => (GROUP_OF[card.namespace] ?? "organize") === group)
1576
+ })).filter((entry) => entry.items.length > 0);
1577
+ }
1578
+ //#endregion
1527
1579
  //#region ../evolution-client-kit/src/panel.ts
1528
1580
  function interpolate(text, values) {
1529
1581
  if (values === void 0) return text;
@@ -1804,6 +1856,105 @@ window.__ModuleLoader__.load({
1804
1856
  //#region ../evolution-client-kit/src/notice.ts
1805
1857
  /** One inline state notice: semantic tone plus text, no surface-specific styling. */
1806
1858
  //#endregion
1859
+ //#region ../evolution-client-kit/src/presentation/decision-frame.ts
1860
+ /** One decision card: title, facts, at most one primary, secondary actions and details. */
1861
+ function actionButton$1(action, role) {
1862
+ return (0, react.createElement)("button", {
1863
+ key: action.id,
1864
+ type: "button",
1865
+ "data-role": role === "primary" ? "decision-primary" : "decision-secondary",
1866
+ "data-action": action.id,
1867
+ "aria-busy": action.busy === true ? "true" : void 0,
1868
+ ...action.attributes ?? {},
1869
+ disabled: action.disabled === true || action.busy === true,
1870
+ title: action.title ?? action.label,
1871
+ onClick: () => {
1872
+ if (action.disabled !== true && action.busy !== true) action.onSelect();
1873
+ }
1874
+ }, action.label);
1875
+ }
1876
+ /**
1877
+ * Render the one-card decision surface. The model has a singular primary on purpose.
1878
+ * @param props - decision model and optional surface class.
1879
+ * @returns the decision frame.
1880
+ */
1881
+ function DecisionFrame({ decision, className }) {
1882
+ const secondary = decision.secondary ?? [];
1883
+ return (0, react.createElement)("section", {
1884
+ "data-role": "decision-frame",
1885
+ ...className === void 0 ? {} : { className }
1886
+ }, (0, react.createElement)("h2", { "data-role": "decision-title" }, decision.title), decision.summary === void 0 || decision.summary === "" ? null : (0, react.createElement)("p", { "data-role": "decision-summary" }, decision.summary), decision.facts.length === 0 ? null : (0, react.createElement)("dl", { "data-role": "decision-facts" }, decision.facts.map((fact) => (0, react.createElement)("div", {
1887
+ key: fact.label,
1888
+ "data-role": "decision-fact"
1889
+ }, (0, react.createElement)("dt", null, fact.label), (0, react.createElement)("dd", null, fact.value)))), decision.details === void 0 ? null : (0, react.createElement)("div", { "data-role": "decision-details" }, decision.details), decision.primary === void 0 && secondary.length === 0 ? null : (0, react.createElement)("div", { "data-role": "decision-actions" }, decision.primary === void 0 ? null : actionButton$1(decision.primary, "primary"), secondary.map((action) => actionButton$1(action, "secondary"))));
1890
+ }
1891
+ //#endregion
1892
+ //#region ../evolution-client-kit/src/presentation/task-banner.ts
1893
+ /** A read-only task hint; it deliberately has no primary action. */
1894
+ //#endregion
1895
+ //#region ../evolution-client-kit/src/presentation/chips.ts
1896
+ /** Read-only status chips and toggleable filter chips. */
1897
+ //#endregion
1898
+ //#region ../evolution-client-kit/src/presentation/empty-state.ts
1899
+ /** A compact completed/empty state with at most one primary next step. */
1900
+ function actionButton(action, role) {
1901
+ return (0, react.createElement)("button", {
1902
+ key: action.id,
1903
+ type: "button",
1904
+ "data-role": role === "primary" ? "empty-primary" : "empty-secondary",
1905
+ "data-action": action.id,
1906
+ ...action.attributes ?? {},
1907
+ disabled: action.disabled === true || action.busy === true,
1908
+ title: action.title ?? action.label,
1909
+ onClick: () => {
1910
+ if (action.disabled !== true && action.busy !== true) action.onSelect();
1911
+ }
1912
+ }, action.label);
1913
+ }
1914
+ /** Render a quiet empty state; loading/failure remain the caller's separate states. */
1915
+ function EmptyState({ title, description, tone = "neutral", primary, secondary, className }) {
1916
+ const actions = primary === void 0 && secondary === void 0 ? null : (0, react.createElement)("div", { "data-role": "empty-actions" }, primary === void 0 ? null : actionButton(primary, "primary"), secondary === void 0 ? null : actionButton(secondary, "secondary"));
1917
+ return (0, react.createElement)("section", {
1918
+ "data-role": "empty-state",
1919
+ "data-tone": tone,
1920
+ ...className === void 0 ? {} : { className }
1921
+ }, (0, react.createElement)("h2", { "data-role": "empty-title" }, title), description === void 0 || description === "" ? null : (0, react.createElement)("p", { "data-role": "empty-description" }, description), actions);
1922
+ }
1923
+ //#endregion
1924
+ //#region ../evolution-client-kit/src/presentation/disclosure-group.ts
1925
+ /** A native details group for normal/secondary facts. */
1926
+ //#endregion
1927
+ //#region ../evolution-client-kit/src/presentation/time-text.ts
1928
+ /** The one local-time presentation used by reading surfaces. */
1929
+ //#endregion
1930
+ //#region ../evolution-client-kit/src/presentation/action-menu.ts
1931
+ /**
1932
+ * The one seam onto the platform's menu material, plus a small fallback for deployments
1933
+ * without the primitive row. No page owns a second menu implementation.
1934
+ */
1935
+ const PLATFORM_UI_MODULE$1 = "@deepseek-ai/dsh-client-ui-primitives";
1936
+ /**
1937
+ * Accept only the two component functions; a namespace row without them is not a menu.
1938
+ * @param row - the module row's exports.
1939
+ * @returns the two components, or undefined.
1940
+ */
1941
+ function menuPrimitivesFrom(row) {
1942
+ const surface = row.MenuSurface;
1943
+ const item = row.MenuItemButton;
1944
+ if (typeof surface !== "function" || typeof item !== "function") return void 0;
1945
+ return {
1946
+ MenuSurface: surface,
1947
+ MenuItemButton: item
1948
+ };
1949
+ }
1950
+ (() => {
1951
+ try {
1952
+ return menuPrimitivesFrom(require(PLATFORM_UI_MODULE$1));
1953
+ } catch {
1954
+ return;
1955
+ }
1956
+ })();
1957
+ //#endregion
1807
1958
  //#region ../evolution-client-kit/src/action.ts
1808
1959
  /**
1809
1960
  * Command-only actions. Approval decisions are a separate host API and must never
@@ -2113,6 +2264,8 @@ window.__ModuleLoader__.load({
2113
2264
  const CSS$1 = [
2114
2265
  tokenVars(".evolution-params,.evolution-param-card"),
2115
2266
  ".evolution-params{display:flex;flex-direction:column}",
2267
+ ".evolution-settings-tab{display:flex;flex-direction:column;gap:var(--evo-space-8)}",
2268
+ ".evolution-settings-group{margin:var(--evo-space-12) 0 0;font-size:var(--evo-type-sm);font-weight:600;color:var(--dsw-alias-label-secondary)}",
2116
2269
  ".evolution-params-title{margin:0 0 var(--evo-space-4);color:var(--dsw-alias-label-primary);font-size:var(--evo-type-lg);font-weight:600;line-height:var(--evo-leading-base)}",
2117
2270
  ".evolution-params-subtitle{margin:0 0 var(--evo-space-16);color:var(--dsw-alias-label-tertiary);font-size:var(--evo-type-xs);line-height:var(--evo-leading-base)}",
2118
2271
  ".evolution-params-about{margin:0 0 var(--evo-space-16);color:var(--dsw-alias-label-tertiary);font-size:var(--evo-type-xs)}",
@@ -2120,7 +2273,7 @@ window.__ModuleLoader__.load({
2120
2273
  ".evolution-param-head{display:flex;align-items:center;gap:var(--evo-space-8);width:100%;padding:var(--evo-space-12) var(--evo-space-14);background:none;border:0;text-align:left;cursor:pointer;color:inherit;font:inherit}",
2121
2274
  ".evolution-param-head:hover{background:var(--dsw-alias-interactive-bg-hover)}",
2122
2275
  ".evolution-param-card-title{flex:1;min-width:0;color:var(--dsw-alias-label-primary);font-size:var(--evo-type-sm);font-weight:500;line-height:var(--evo-leading-base)}",
2123
- ".evolution-param-count{color:var(--dsw-alias-brand-primary);font-size:var(--evo-type-xs);line-height:var(--evo-leading-base)}",
2276
+ ".evolution-param-count{color:var(--dsw-alias-label-tertiary);font-size:var(--evo-type-xs);line-height:var(--evo-leading-base)}",
2124
2277
  ".evolution-param-chevron{color:var(--dsw-alias-label-tertiary);font-size:var(--evo-type-xs);line-height:var(--evo-leading-base)}",
2125
2278
  ".evolution-param-body{padding:0 var(--evo-space-14) var(--evo-space-12);border-top:var(--evo-hairline-width) solid var(--dsw-alias-border-l2)}",
2126
2279
  ".evolution-param-dest{color:var(--dsw-alias-label-tertiary);font-size:var(--evo-type-xs)}",
@@ -2135,7 +2288,10 @@ window.__ModuleLoader__.load({
2135
2288
  ".evolution-param-input:focus-visible{outline:var(--evo-focus-ring);outline-offset:var(--evo-focus-offset)}",
2136
2289
  ".evolution-param-input:disabled{color:var(--dsw-alias-label-dimmed);cursor:default}",
2137
2290
  ".evolution-param-source{display:inline-flex;align-items:center;height:var(--evo-space-20);padding:0 var(--evo-space-6);border-radius:var(--evo-radius-chip);background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-secondary);font-size:var(--evo-type-xs);line-height:var(--evo-space-20)}",
2138
- ".evolution-param-source[data-user=\"true\"]{background:var(--dsw-alias-brand-primary);color:var(--dsw-alias-label-primary-foreground)}",
2291
+ ".evolution-param-source[data-user=\"true\"]{background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-secondary);font-size:var(--evo-type-xs)}",
2292
+ ".evolution-param-reset{margin-left:auto;padding:0;border:0;background:transparent;color:var(--dsw-alias-label-tertiary);font:inherit;font-size:var(--evo-type-xs);cursor:pointer}",
2293
+ ".evolution-param-reset:hover:not(:disabled){color:var(--dsw-alias-label-primary)}",
2294
+ ".evolution-param-reset:disabled{color:var(--dsw-alias-label-dimmed);cursor:default}",
2139
2295
  ".evolution-param-actions{display:flex;justify-content:flex-end;gap:var(--evo-space-8);padding-top:var(--evo-space-12)}",
2140
2296
  ".evolution-param-button{padding:var(--evo-space-6) var(--evo-space-12);border:var(--evo-hairline-width) solid var(--dsw-alias-border-l2);border-radius:var(--evo-radius-control);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);font-size:var(--evo-type-sm);line-height:var(--evo-leading-base);cursor:pointer}",
2141
2297
  ".evolution-param-button:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}",
@@ -2144,6 +2300,32 @@ window.__ModuleLoader__.load({
2144
2300
  ".evolution-param-button[data-primary=\"true\"]{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground);border-color:transparent}",
2145
2301
  ".evolution-param-button[data-primary=\"true\"]:hover:not(:disabled){background:var(--dsw-alias-button-primary-hover)}",
2146
2302
  ".evolution-param-button:disabled{color:var(--dsw-alias-label-dimmed);cursor:default}",
2303
+ ".evolution-approval-item{padding:var(--evo-space-10) 0;border-top:var(--evo-hairline-width) solid var(--dsw-alias-border-l2)}",
2304
+ ".evolution-approval-item:first-of-type{border-top:0}",
2305
+ ".evolution-approval-decision{display:flex;flex-direction:column;gap:var(--evo-space-8);padding:var(--evo-space-12);border:var(--evo-hairline-width) solid var(--dsw-alias-border-l2);border-radius:var(--evo-radius-control);background:var(--dsw-alias-bg-layer-1)}",
2306
+ ".evolution-approval-decision [data-role=\"decision-title\"]{margin:0;font-size:var(--evo-type-sm);font-weight:600;line-height:var(--evo-leading-base)}",
2307
+ ".evolution-approval-decision [data-role=\"decision-summary\"]{margin:0;color:var(--dsw-alias-label-secondary);font-size:var(--evo-type-xs)}",
2308
+ ".evolution-approval-decision [data-role=\"decision-facts\"]{display:grid;grid-template-columns:max-content minmax(0,1fr);gap:var(--evo-space-4) var(--evo-space-12);margin:0;font-size:var(--evo-type-xs)}",
2309
+ ".evolution-approval-decision [data-role=\"decision-fact\"]{display:contents}",
2310
+ ".evolution-approval-decision dt{color:var(--dsw-alias-label-tertiary)}",
2311
+ ".evolution-approval-decision dd{margin:0;color:var(--dsw-alias-label-primary);min-width:0;overflow-wrap:anywhere}",
2312
+ ".evolution-approval-decision [data-role=\"decision-actions\"]{display:flex;flex-wrap:wrap;align-items:center;gap:var(--evo-space-8);padding-top:var(--evo-space-8)}",
2313
+ ".evolution-approval-decision [data-role=\"decision-primary\"],.evolution-approval-decision [data-role=\"decision-secondary\"]{padding:var(--evo-space-6) var(--evo-space-12);border:var(--evo-hairline-width) solid var(--dsw-alias-border-l2);border-radius:var(--evo-radius-control);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);font-size:var(--evo-type-sm);cursor:pointer}",
2314
+ ".evolution-approval-decision [data-role=\"decision-primary\"]{background:var(--dsw-alias-button-primary-fill);border-color:transparent;color:var(--dsw-alias-label-primary-foreground)}",
2315
+ ".evolution-approval-decision [data-role=\"decision-primary\"]:disabled,.evolution-approval-decision [data-role=\"decision-secondary\"]:disabled{color:var(--dsw-alias-label-dimmed);cursor:default}",
2316
+ ".evolution-approval-decision [data-role=\"decision-details\"] details{margin:0}",
2317
+ ".evolution-approval-decision [data-role=\"decision-details\"] summary{cursor:pointer;color:var(--dsw-alias-label-tertiary);font-size:var(--evo-type-xs)}",
2318
+ ".evolution-approval-item [data-role=\"empty-state\"]{padding:var(--evo-space-20) var(--evo-space-16);text-align:center}",
2319
+ ".evolution-approval-item [data-role=\"empty-title\"]{margin:0 0 var(--evo-space-6);font-size:var(--evo-type-lg)}",
2320
+ ".evolution-approval-item [data-role=\"empty-description\"]{margin:0 auto var(--evo-space-12);max-width:34em;color:var(--dsw-alias-label-secondary);font-size:var(--evo-type-sm)}",
2321
+ ".evolution-approval-item [data-role=\"empty-actions\"]{display:flex;justify-content:center;gap:var(--evo-space-8)}",
2322
+ ".evolution-approval-item [data-role=\"empty-primary\"]{padding:var(--evo-space-6) var(--evo-space-12);border:0;border-radius:var(--evo-radius-control);background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground);font-size:var(--evo-type-sm);cursor:pointer}",
2323
+ ".evolution-approval-item [data-role=\"empty-secondary\"]{padding:var(--evo-space-6) var(--evo-space-12);border:var(--evo-hairline-width) solid var(--dsw-alias-border-l2);border-radius:var(--evo-radius-control);background:transparent;color:var(--dsw-alias-label-primary);font:inherit;font-size:var(--evo-type-sm);cursor:pointer}",
2324
+ ".evo-diag-issue{padding:var(--evo-space-10) var(--evo-space-12);border:var(--evo-hairline-width) solid var(--dsw-alias-state-warn-primary);border-radius:var(--evo-radius-control);background:var(--dsw-alias-bg-layer-1)}",
2325
+ ".evo-diag-issue[data-status=\"fail\"]{border-color:var(--dsw-alias-state-error-primary)}",
2326
+ ".evo-diag-complete{padding:var(--evo-space-10) var(--evo-space-12);border:var(--evo-hairline-width) solid var(--dsw-alias-state-success-primary);border-radius:var(--evo-radius-control);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-state-success-primary)}",
2327
+ ".evo-diag-group{display:flex;flex-direction:column;gap:var(--evo-space-4);margin-top:var(--evo-space-8)}",
2328
+ ".evo-diag-group>summary{cursor:pointer;color:var(--dsw-alias-label-tertiary);font-size:var(--evo-type-xs)}",
2147
2329
  ".evolution-param-select{width:100%;box-sizing:border-box;padding:var(--evo-space-8) var(--evo-space-10);border:var(--evo-hairline-width) solid var(--dsw-alias-border-l2);border-radius:var(--evo-radius-control);background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);font-size:var(--evo-type-sm);line-height:var(--evo-leading-base)}",
2148
2330
  ".evolution-param-select:focus-visible{outline:var(--evo-focus-ring);outline-offset:var(--evo-focus-offset)}",
2149
2331
  ".evolution-param-select:disabled{color:var(--dsw-alias-label-dimmed);cursor:default}",
@@ -2279,10 +2461,14 @@ window.__ModuleLoader__.load({
2279
2461
  }
2280
2462
  /** One family tab: every parameter card lives inside the platform's Plugins page. */
2281
2463
  function EvolutionSettingsTab(props) {
2282
- return (0, react.createElement)("div", { className: "evolution-settings-tab" }, ...props.cards.map((face, index) => (0, react.createElement)(PluginParamCard, {
2464
+ return (0, react.createElement)("div", { className: "evolution-settings-tab" }, ...groupParamCards(props.cards).flatMap(({ group, items }) => [(0, react.createElement)("h3", {
2465
+ key: "group-" + group,
2466
+ className: "evolution-settings-group",
2467
+ "data-role": "settings-group"
2468
+ }, message("group." + group)), ...items.map((face, index) => (0, react.createElement)(PluginParamCard, {
2283
2469
  key: face.namespace + ":" + String(index),
2284
2470
  ...face
2285
- })));
2471
+ }))]));
2286
2472
  }
2287
2473
  //#endregion
2288
2474
  //#region ../evolution-client-kit/src/generated/route-client.generated.ts
@@ -2626,7 +2812,7 @@ window.__ModuleLoader__.load({
2626
2812
  const viewKind = state.view.kind;
2627
2813
  const rowCount = state.view.kind === "ready" ? state.view.rows.length : 0;
2628
2814
  (0, react.useEffect)(() => {
2629
- if (viewKind === "empty") setOpen(false);
2815
+ if (viewKind === "empty") setOpen(true);
2630
2816
  else if (viewKind === "ready" && rowCount > 0) setOpen(true);
2631
2817
  }, [viewKind, rowCount]);
2632
2818
  const latest = (0, react.useRef)(state);
@@ -2778,81 +2964,115 @@ window.__ModuleLoader__.load({
2778
2964
  };
2779
2965
  const summaryLine = (entry) => entry.verb === void 0 || entry.target === void 0 ? entry.summary : t(VERB_KEYS[entry.verb] ?? "approvalVerbUpdate") + " " + entry.target + (entry.operationCount !== void 0 && entry.operationCount > 1 ? " ×" + String(entry.operationCount) : "");
2780
2966
  const row = (entry) => {
2781
- if (entry.status === "executing") return (0, react.createElement)("div", {
2782
- className: "evolution-param-field",
2783
- key: entry.id
2784
- }, (0, react.createElement)("div", { className: "evolution-param-label" }, (0, react.createElement)("span", { className: "evolution-param-source" }, t(KIND_KEYS[entry.kind])), (0, react.createElement)("span", {
2785
- className: "evolution-param-value",
2786
- title: entry.summary
2787
- }, summaryLine(entry))), (0, react.createElement)("p", { className: "evolution-param-hint" }, age(entry)), (0, react.createElement)("p", {
2788
- className: "evolution-param-note",
2789
- role: "status"
2790
- }, t("approvalExecuting")), entry.claimedBy === void 0 ? null : (0, react.createElement)("p", { className: "evolution-param-hint" }, entry.claimedBy), (0, react.createElement)("div", { className: "evolution-param-actions" }, (0, react.createElement)("button", {
2791
- className: "evolution-param-button",
2792
- type: "button",
2793
- disabled: state.busy.includes(entry.id),
2794
- onClick: () => {
2967
+ const busy = state.busy.includes(entry.id);
2968
+ const executing = entry.status === "executing";
2969
+ const confirming = armed === entry.id;
2970
+ const title = summaryLine(entry);
2971
+ const facts = [
2972
+ {
2973
+ label: t("approvalFactKind"),
2974
+ value: t(KIND_KEYS[entry.kind])
2975
+ },
2976
+ {
2977
+ label: t("approvalFactAge"),
2978
+ value: age(entry)
2979
+ },
2980
+ ...entry.target === void 0 ? [] : [{
2981
+ label: t("approvalFactTarget"),
2982
+ value: entry.target
2983
+ }]
2984
+ ];
2985
+ const raw = title === entry.summary ? void 0 : (0, react.createElement)("details", { className: "evolution-param-details" }, (0, react.createElement)("summary", null, t("approvalRawSummary")), (0, react.createElement)("p", { className: "evolution-param-hint" }, entry.summary));
2986
+ const previewAction = {
2987
+ id: "preview-" + entry.id,
2988
+ label: state.open === entry.id ? t("approvalPreviewClose") : t("approvalPreview"),
2989
+ onSelect: () => {
2990
+ togglePreview(entry.id);
2991
+ }
2992
+ };
2993
+ const primary = executing ? {
2994
+ id: "release-" + entry.id,
2995
+ label: busy ? t("approvalReleasing") : t("approvalRelease"),
2996
+ disabled: busy,
2997
+ onSelect: () => {
2795
2998
  decide(entry.id, "release");
2796
2999
  }
2797
- }, state.busy.includes(entry.id) ? t("approvalReleasing") : t("approvalRelease"))));
2798
- const busy = state.busy.includes(entry.id);
2799
- const button = (label, action, tone) => (0, react.createElement)("button", {
2800
- className: "evolution-param-button",
2801
- type: "button",
3000
+ } : confirming ? {
3001
+ id: "confirm-" + entry.id,
3002
+ label: t("approvalConfirmYes"),
3003
+ attributes: { "data-confirm": "yes" },
3004
+ onSelect: () => {
3005
+ setArmed(null);
3006
+ decide(entry.id, "approve");
3007
+ }
3008
+ } : {
3009
+ id: "approve-" + entry.id,
3010
+ label: busy ? t("approvalApproving") : t("approvalApprove"),
2802
3011
  disabled: busy,
2803
- ...tone === "primary" ? { "data-primary": "true" } : { "data-tone": tone },
2804
- onClick: () => {
2805
- if (action === "approve" && confirmMode === "ask" && armed !== entry.id) {
3012
+ onSelect: () => {
3013
+ if (confirmMode === "ask") {
2806
3014
  setArmed(entry.id);
2807
3015
  return;
2808
3016
  }
2809
- setArmed(null);
2810
- decide(entry.id, action);
2811
- }
2812
- }, busy ? t(action === "approve" ? "approvalApproving" : "approvalRejecting") : t(label));
2813
- return (0, react.createElement)("div", {
2814
- className: "evolution-param-field",
2815
- key: entry.id
2816
- }, (0, react.createElement)("div", { className: "evolution-param-label" }, (0, react.createElement)("span", { className: "evolution-param-source" }, t(KIND_KEYS[entry.kind])), (0, react.createElement)("span", {
2817
- className: "evolution-param-value",
2818
- title: entry.summary
2819
- }, summaryLine(entry))), (0, react.createElement)("p", { className: "evolution-param-hint" }, age(entry)), summaryLine(entry) === entry.summary ? null : (0, react.createElement)("details", { className: "evolution-param-details" }, (0, react.createElement)("summary", null, t("approvalRawSummary")), (0, react.createElement)("p", { className: "evolution-param-hint" }, entry.summary)), armed === entry.id ? (0, react.createElement)("p", {
2820
- className: "evolution-param-note",
2821
- role: "status"
2822
- }, (0, react.createElement)("span", { className: "evolution-param-value" }, t("approvalConfirmNamed", { n: summaryLine(entry) })), (0, react.createElement)("button", {
2823
- className: "evolution-param-button",
2824
- type: "button",
2825
- "data-confirm": "yes",
2826
- "data-primary": "true",
2827
- onClick: () => {
2828
- setArmed(null);
2829
3017
  decide(entry.id, "approve");
2830
3018
  }
2831
- }, t("approvalConfirmYes")), (0, react.createElement)("button", {
2832
- className: "evolution-param-button",
2833
- type: "button",
2834
- "data-tone": "ghost",
2835
- onClick: () => {
3019
+ };
3020
+ const secondary = executing ? [] : confirming ? [{
3021
+ id: "cancel-" + entry.id,
3022
+ label: t("approvalConfirmNo"),
3023
+ onSelect: () => {
2836
3024
  setArmed(null);
2837
3025
  }
2838
- }, t("approvalConfirmNo"))) : null, (0, react.createElement)("div", { className: "evolution-param-actions" }, button("approvalApprove", "approve", "primary"), button("approvalReject", "reject", "outline"), (0, react.createElement)("button", {
2839
- className: "evolution-param-button",
2840
- type: "button",
2841
- "data-tone": "ghost",
2842
- onClick: () => {
2843
- togglePreview(entry.id);
3026
+ }] : [{
3027
+ id: "reject-" + entry.id,
3028
+ label: busy ? t("approvalRejecting") : t("approvalReject"),
3029
+ disabled: busy,
3030
+ onSelect: () => {
3031
+ decide(entry.id, "reject");
3032
+ }
3033
+ }, previewAction];
3034
+ const summary = executing ? t("approvalExecuting") : confirming ? t("approvalConfirmNamed", { n: title }) : void 0;
3035
+ return (0, react.createElement)("div", {
3036
+ className: "evolution-approval-item",
3037
+ key: entry.id
3038
+ }, (0, react.createElement)(DecisionFrame, {
3039
+ className: "evolution-approval-decision",
3040
+ decision: {
3041
+ title,
3042
+ ...summary === void 0 ? {} : { summary },
3043
+ facts,
3044
+ primary,
3045
+ ...secondary.length === 0 ? {} : { secondary },
3046
+ ...raw === void 0 ? {} : { details: raw }
2844
3047
  }
2845
- }, state.open === entry.id ? t("approvalPreviewClose") : t("approvalPreview"))), state.open === entry.id && state.preview !== null ? preview(state.preview) : null);
3048
+ }), state.open === entry.id && state.preview !== null ? preview(state.preview) : null);
2846
3049
  };
2847
3050
  const body = () => {
2848
3051
  if (state.view.kind === "loading") return (0, react.createElement)("p", {
2849
3052
  className: "evolution-param-note",
2850
3053
  role: "status"
2851
3054
  }, t("approvalLoading"));
2852
- if (state.view.kind === "empty") return (0, react.createElement)("p", {
2853
- className: "evolution-param-note",
2854
- role: "status"
2855
- }, t("approvalEmpty"));
3055
+ if (state.view.kind === "empty") {
3056
+ const primary = props.onHistory === void 0 ? void 0 : {
3057
+ id: "approval-history",
3058
+ label: t("approvalHistory"),
3059
+ onSelect: props.onHistory
3060
+ };
3061
+ return (0, react.createElement)("div", { role: "status" }, (0, react.createElement)(EmptyState, {
3062
+ title: t("approvalEmpty"),
3063
+ description: t("approvalEmptyDescription"),
3064
+ tone: "ok",
3065
+ ...primary === void 0 ? {} : { primary },
3066
+ secondary: {
3067
+ id: "approval-refresh",
3068
+ label: state.refreshing ? t("diagRefreshing") : t("approvalRefresh"),
3069
+ busy: state.refreshing,
3070
+ onSelect: () => {
3071
+ load();
3072
+ }
3073
+ }
3074
+ }));
3075
+ }
2856
3076
  if (state.view.kind === "failed") return (0, react.createElement)("div", { className: "evolution-param-actions" }, FailureBlock({
2857
3077
  failure: state.view.failure,
2858
3078
  t: translate,
@@ -2882,10 +3102,7 @@ window.__ModuleLoader__.load({
2882
3102
  setOpen(!open);
2883
3103
  },
2884
3104
  "aria-expanded": open
2885
- }, (0, react.createElement)("span", { className: "evolution-param-card-title" }, t("approvalTitle")), state.view.kind === "empty" ? (0, react.createElement)("span", {
2886
- className: "evolution-param-count",
2887
- role: "status"
2888
- }, t("approvalEmpty")) : null, waiting === 0 ? null : (0, react.createElement)("span", { className: "evolution-param-count" }, t("approvalCount", { n: waiting })), running === 0 ? null : (0, react.createElement)("span", { className: "evolution-param-count" }, t("approvalRunningCount", { n: running })), (0, react.createElement)("span", { className: "evolution-param-chevron" }, open ? "▲" : "▼")), (0, react.createElement)("div", { className: "evolution-param-actions" }, (0, react.createElement)("button", {
3105
+ }, (0, react.createElement)("span", { className: "evolution-param-card-title" }, t("approvalTitle")), waiting === 0 ? null : (0, react.createElement)("span", { className: "evolution-param-count" }, t("approvalCount", { n: waiting })), running === 0 ? null : (0, react.createElement)("span", { className: "evolution-param-count" }, t("approvalRunningCount", { n: running })), (0, react.createElement)("span", { className: "evolution-param-chevron" }, open ? "▲" : "▼")), state.view.kind === "empty" ? null : (0, react.createElement)("div", { className: "evolution-param-actions" }, (0, react.createElement)("button", {
2889
3106
  className: "evolution-param-button",
2890
3107
  type: "button",
2891
3108
  disabled: state.refreshing,
@@ -2928,6 +3145,7 @@ window.__ModuleLoader__.load({
2928
3145
  "entry.label": "技能历史",
2929
3146
  title: "技能历史",
2930
3147
  bodyTitle: "正文版本",
3148
+ "workbench.title": "自进化",
2931
3149
  "workbench.history": "技能历史",
2932
3150
  "workbench.pending": "待批",
2933
3151
  "workbench.merge": "合并",
@@ -2937,6 +3155,8 @@ window.__ModuleLoader__.load({
2937
3155
  search: "按名字或描述筛选",
2938
3156
  "search.none": "没有匹配的技能。",
2939
3157
  "group.content": "正文版本",
3158
+ "group.current": "当前版本",
3159
+ "group.history": "历史版本",
2940
3160
  "group.support": "文件版本(不可回退)",
2941
3161
  "group.support.note": "附带文件的字节与正文共用一份索引;回退不恢复它们。",
2942
3162
  "empty.skills": "还没有技能留下过内容版本。",
@@ -2959,6 +3179,7 @@ window.__ModuleLoader__.load({
2959
3179
  "undo.confirm": "确认回退(会写入一版,可再回退)",
2960
3180
  "undo.confirmUnit": "确认回退整个跨技能写入单元(会写入一版,可再回退)",
2961
3181
  "undo.no": "取消",
3182
+ more: "更多",
2962
3183
  current: "当前",
2963
3184
  "versions.count": "{n} 个版本",
2964
3185
  "row.version": "v{n}",
@@ -2968,8 +3189,8 @@ window.__ModuleLoader__.load({
2968
3189
  "row.delta.down": "(-{n} 字符)",
2969
3190
  "diff.show": "差异",
2970
3191
  "diff.source": "源码",
2971
- "preview.show": "预览",
2972
- "preview.hide": "收起预览",
3192
+ "preview.show": "查看正文",
3193
+ "preview.hide": "收起正文",
2973
3194
  "preview.truncated": "正文过长:只显示前 {shown} 个字符(共 {total} 个)",
2974
3195
  "path.unrecorded": "(路径未记录)",
2975
3196
  "diff.rendered": "渲染",
@@ -3023,6 +3244,7 @@ window.__ModuleLoader__.load({
3023
3244
  "entry.label": "Skill history",
3024
3245
  title: "Skill history",
3025
3246
  bodyTitle: "Body versions",
3247
+ "workbench.title": "Self-evolution",
3026
3248
  "workbench.history": "Skill history",
3027
3249
  "workbench.pending": "Pending",
3028
3250
  "workbench.merge": "Merge",
@@ -3032,6 +3254,8 @@ window.__ModuleLoader__.load({
3032
3254
  search: "Filter by name or description",
3033
3255
  "search.none": "No skill matches.",
3034
3256
  "group.content": "Body versions",
3257
+ "group.current": "Current version",
3258
+ "group.history": "History",
3035
3259
  "group.support": "File versions (not restorable)",
3036
3260
  "group.support.note": "Support-file bytes share this index with the body; restoring the body does not bring them back.",
3037
3261
  "empty.skills": "No skill has recorded a content version yet.",
@@ -3054,6 +3278,7 @@ window.__ModuleLoader__.load({
3054
3278
  "undo.confirm": "Confirm restore (writes a new version; can be undone)",
3055
3279
  "undo.confirmUnit": "Confirm restoring the whole cross-skill unit (writes a new version; can be undone)",
3056
3280
  "undo.no": "Cancel",
3281
+ more: "More",
3057
3282
  current: "Current",
3058
3283
  "versions.count": "{n} versions",
3059
3284
  "row.version": "v{n}",
@@ -3063,8 +3288,8 @@ window.__ModuleLoader__.load({
3063
3288
  "row.delta.down": "(-{n} chars)",
3064
3289
  "diff.show": "Diff",
3065
3290
  "diff.source": "Source",
3066
- "preview.show": "Preview",
3067
- "preview.hide": "Hide preview",
3291
+ "preview.show": "View body",
3292
+ "preview.hide": "Hide body",
3068
3293
  "preview.truncated": "the body is long: showing the first {shown} of {total} characters",
3069
3294
  "path.unrecorded": "(path not recorded)",
3070
3295
  "diff.rendered": "Rendered",
@@ -3177,12 +3402,23 @@ window.__ModuleLoader__.load({
3177
3402
  ".evo-hist-note[data-error=\"true\"]{color:var(--evo-tone-danger);background:var(--dsw-alias-bg-layer-2);border:var(--evo-hairline-width) solid var(--evo-tone-danger);border-radius:var(--evo-radius-control);padding:var(--evo-space-8) var(--evo-space-10)}",
3178
3403
  ".evo-hist-icon{flex:none;margin-top:.15em}",
3179
3404
  ".evo-hist-group{margin:var(--evo-space-16) 0 var(--evo-space-4);font-size:var(--evo-type-sm);font-weight:600;color:var(--dsw-alias-label-secondary)}",
3180
- ".evo-hist-row{display:flex;align-items:flex-start;gap:var(--evo-space-8);padding:var(--evo-space-8) 0;border-top:var(--evo-hairline-width) solid var(--dsw-alias-border-l2);max-width:calc(var(--evo-measure-read) * 1.5);color:var(--dsw-alias-label-primary)}",
3405
+ ".evo-hist-reader{max-width:calc(var(--evo-measure-read) * 1.5);margin-top:var(--evo-space-8);padding:var(--evo-space-12);border:var(--evo-hairline-width) solid var(--dsw-alias-border-l2);border-radius:var(--evo-radius-control);background:var(--dsw-alias-bg-layer-1)}",
3406
+ ".evo-hist-current{padding-bottom:var(--evo-space-6)}",
3407
+ ".evo-hist-current .evo-hist-group{margin-top:0}",
3408
+ ".evo-hist-current .evo-hist-row{max-width:none}",
3409
+ ".evo-hist-reader .evo-hist-group{margin-top:var(--evo-space-12)}",
3410
+ ".evo-hist-row{display:grid;grid-template-columns:minmax(0,1fr) auto;grid-template-areas:\"body actions\" \"expanded expanded\";align-items:start;gap:var(--evo-space-4) var(--evo-space-8);padding:var(--evo-space-8) 0;border-top:var(--evo-hairline-width) solid var(--dsw-alias-border-l2);max-width:calc(var(--evo-measure-read) * 1.5);color:var(--dsw-alias-label-primary)}",
3181
3411
  ".evo-hist-row:first-of-type{border-top:0}",
3182
- ".evo-hist-row-body{flex:1 1 auto;min-width:0}",
3412
+ ".evo-hist-row-body{grid-area:body;min-width:0}",
3183
3413
  ".evo-hist-row-title{display:flex;align-items:baseline;gap:var(--evo-space-8);min-width:0}",
3184
3414
  ".evo-hist-row-summary{margin-top:var(--evo-space-2);line-height:var(--evo-leading-base)}",
3185
- ".evo-hist-actions{display:flex;flex:none;align-items:center;gap:var(--evo-space-6)}",
3415
+ ".evo-hist-actions{grid-area:actions;display:flex;align-items:center;gap:var(--evo-space-6)}",
3416
+ ".evo-hist-row-expanded{grid-area:expanded;min-width:0}",
3417
+ ".evo-hist-more{position:relative;display:inline-flex;align-items:center}",
3418
+ ".evo-hist-more>summary{list-style:none;cursor:pointer;color:var(--dsw-alias-label-tertiary);font-size:var(--evo-type-xs);padding:var(--evo-space-2) var(--evo-space-4)}",
3419
+ ".evo-hist-more>summary::-webkit-details-marker{display:none}",
3420
+ ".evo-hist-more[open]>summary{color:var(--dsw-alias-label-secondary)}",
3421
+ ".evo-hist-more>button{margin-left:var(--evo-space-2)}",
3186
3422
  ".evo-hist-chip{flex:none;padding:var(--evo-space-2) var(--evo-space-8);border-radius:var(--evo-radius-pill);background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-secondary)}",
3187
3423
  ".evo-hist-button{display:inline-flex;flex:none;align-items:center;gap:var(--evo-space-2);font:inherit;padding:var(--evo-space-4) var(--evo-space-10);border:var(--evo-hairline-width) solid var(--dsw-alias-border-l2);border-radius:var(--evo-radius-control);background:transparent;color:var(--evo-tone-quiet);cursor:pointer}",
3188
3424
  ".evo-hist-button[data-kind=\"toggle\"],.evo-hist-button[data-kind=\"switch\"]{padding:var(--evo-space-2) var(--evo-space-4);border-color:transparent;color:var(--evo-tone-quiet)}",
@@ -3204,6 +3440,7 @@ window.__ModuleLoader__.load({
3204
3440
  ".evo-doc-tag{position:absolute;left:var(--evo-space-8);top:var(--evo-space-8);color:var(--dsw-alias-label-tertiary)}",
3205
3441
  ".evo-doc-line-add{color:var(--evo-tone-success)}",
3206
3442
  ".evo-doc-line-del{color:var(--evo-tone-danger)}",
3443
+ "@media (max-width:1100px){.evo-hist-row{grid-template-columns:minmax(0,1fr);grid-template-areas:\"body\" \"actions\" \"expanded\"}.evo-hist-actions{flex-wrap:wrap;justify-content:flex-start}}",
3207
3444
  "@media (max-width:900px){.evo-hist-root{flex-direction:column}.evo-hist-aside{flex:0 0 auto;width:100%;max-height:42%;border-right:0;border-bottom:var(--evo-hairline-width) solid var(--dsw-alias-border-l2)}.evo-hist-row{max-width:none}}"
3208
3445
  ].join("\n");
3209
3446
  //#endregion
@@ -3378,46 +3615,73 @@ window.__ModuleLoader__.load({
3378
3615
  */
3379
3616
  function versionRow(props) {
3380
3617
  const { copy, row, confirming, open, expanded, onRestore, onCancel, onToggle } = props;
3618
+ const current = row.undoable === false;
3381
3619
  const actions = [];
3382
- if (row.undoable === false) actions.push(chip({
3620
+ if (current) actions.push(chip({
3383
3621
  key: "current",
3384
3622
  children: copy.t("current")
3385
3623
  }));
3386
- if (row.undoable === true) {
3387
- if (confirming) actions.push(button({
3388
- key: "cancel",
3389
- onClick: onCancel,
3390
- children: copy.t("undo.no")
3391
- }));
3392
- actions.push(button({
3393
- key: "undo",
3394
- tone: confirming ? "primary" : "quiet",
3395
- onClick: onRestore,
3396
- children: confirming ? copy.t(row.unitId === void 0 ? "undo.confirm" : "undo.confirmUnit") : copy.t("undo")
3397
- }));
3398
- }
3399
- if (row.undoable === true || row.charsDelta !== void 0) actions.push(button({
3400
- key: "diff",
3401
- kind: "toggle",
3402
- expanded: open === "diff",
3403
- onClick: () => {
3404
- onToggle("diff");
3405
- },
3406
- children: open === "diff" ? copy.t("diff.hide") : copy.t("diff.show")
3407
- }));
3408
- actions.push(button({
3624
+ if (current) actions.push(button({
3409
3625
  key: "preview",
3410
3626
  kind: "toggle",
3627
+ tone: "primary",
3411
3628
  expanded: open === "preview",
3412
3629
  onClick: () => {
3413
3630
  onToggle("preview");
3414
3631
  },
3415
3632
  children: open === "preview" ? copy.t("preview.hide") : copy.t("preview.show")
3416
3633
  }));
3634
+ if (current && row.charsDelta !== void 0) actions.push(button({
3635
+ key: "diff",
3636
+ kind: "toggle",
3637
+ expanded: open === "diff",
3638
+ onClick: () => {
3639
+ onToggle("diff");
3640
+ },
3641
+ children: open === "diff" ? copy.t("diff.hide") : copy.t("diff.show")
3642
+ }));
3643
+ if (!current) {
3644
+ actions.push(button({
3645
+ key: "preview",
3646
+ kind: "toggle",
3647
+ expanded: open === "preview",
3648
+ onClick: () => {
3649
+ onToggle("preview");
3650
+ },
3651
+ children: open === "preview" ? copy.t("preview.hide") : copy.t("preview.show")
3652
+ }));
3653
+ const more = [];
3654
+ if (row.undoable === true) {
3655
+ if (confirming) more.push(button({
3656
+ key: "cancel",
3657
+ onClick: onCancel,
3658
+ children: copy.t("undo.no")
3659
+ }));
3660
+ more.push(button({
3661
+ key: "undo",
3662
+ tone: confirming ? "primary" : "quiet",
3663
+ onClick: onRestore,
3664
+ children: confirming ? copy.t(row.unitId === void 0 ? "undo.confirm" : "undo.confirmUnit") : copy.t("undo")
3665
+ }));
3666
+ }
3667
+ if (row.undoable === true || row.charsDelta !== void 0) more.push(button({
3668
+ key: "diff",
3669
+ kind: "toggle",
3670
+ expanded: open === "diff",
3671
+ onClick: () => {
3672
+ onToggle("diff");
3673
+ },
3674
+ children: open === "diff" ? copy.t("diff.hide") : copy.t("diff.show")
3675
+ }));
3676
+ if (more.length > 0) actions.push((0, react.createElement)("details", {
3677
+ key: "more",
3678
+ className: "evo-hist-more"
3679
+ }, (0, react.createElement)("summary", null, copy.t("more")), ...more));
3680
+ }
3417
3681
  return (0, react.createElement)("div", {
3418
3682
  key: String(row.v),
3419
3683
  className: "evo-hist-row"
3420
- }, (0, react.createElement)("div", { className: "evo-hist-row-body" }, cellLine(row.cells.title, copy, "evo-hist-row-title", { time: localTime(row.at) }), row.cells.meta.length === 0 ? null : cellLine(row.cells.meta, copy, "evo-hist-row-summary"), expanded), (0, react.createElement)("div", { className: "evo-hist-actions" }, actions));
3684
+ }, (0, react.createElement)("div", { className: "evo-hist-row-body" }, cellLine(row.cells.title, copy, "evo-hist-row-title", { time: localTime(row.at) }), row.cells.meta.length === 0 ? null : cellLine(row.cells.meta, copy, "evo-hist-row-summary")), (0, react.createElement)("div", { className: "evo-hist-actions" }, actions), expanded === null || expanded === void 0 ? null : (0, react.createElement)("div", { className: "evo-hist-row-expanded" }, expanded));
3421
3685
  }
3422
3686
  /**
3423
3687
  * One group's heading, and the note that explains the group.
@@ -3715,6 +3979,25 @@ window.__ModuleLoader__.load({
3715
3979
  ] }), toggle), diffView(face, diff.diff, mode));
3716
3980
  }
3717
3981
  //#endregion
3982
+ //#region src/panels/history/client/history-presentation.ts
3983
+ /**
3984
+ * Split a version payload without inventing a version. The host marks current rows with
3985
+ * `undoable: false`; if an older payload lacks that marker, the first content row is the current one.
3986
+ * @param payload - content and support chains from the host.
3987
+ * @returns the display model.
3988
+ */
3989
+ function historyViewModel(payload) {
3990
+ const marked = payload.content.filter((row) => row.undoable === false);
3991
+ const current = marked.length > 0 ? marked : payload.content.slice(0, 1);
3992
+ const currentVersions = new Set(current.map((row) => row.v));
3993
+ return {
3994
+ current,
3995
+ older: payload.content.filter((row) => !currentVersions.has(row.v)),
3996
+ support: payload.support,
3997
+ hasAny: payload.content.length > 0 || payload.support.length > 0
3998
+ };
3999
+ }
4000
+ //#endregion
3718
4001
  //#region src/panels/history/client/Panel.ts
3719
4002
  /**
3720
4003
  * The panel: one read, one open skill, one open row — and the faces that draw them.
@@ -3790,6 +4073,36 @@ window.__ModuleLoader__.load({
3790
4073
  };
3791
4074
  /** The sentence one failed read carries, in ONE place: every reader below reports the same way. */
3792
4075
  const failedMessage = (error) => face.t("error") + ": " + (error instanceof Error ? error.message : String(error));
4076
+ /** Load one version body under the shared read ticket; used by the current default and the toggle. */
4077
+ const loadPreview = (name, v) => {
4078
+ const ticket = readTicket.current + 1;
4079
+ readTicket.current = ticket;
4080
+ setBodies((current) => new Map(current).set(v, {
4081
+ kind: "loading",
4082
+ ticket
4083
+ }));
4084
+ face.loadBody(name, v).then((body) => {
4085
+ if (readTicket.current !== ticket) {
4086
+ setBodies((current) => dropIfTicket(current, v, ticket));
4087
+ return;
4088
+ }
4089
+ setBodies((current) => new Map(current).set(v, {
4090
+ kind: "ready",
4091
+ body,
4092
+ ticket
4093
+ }));
4094
+ }).catch((error) => {
4095
+ if (readTicket.current !== ticket) {
4096
+ setBodies((current) => dropIfTicket(current, v, ticket));
4097
+ return;
4098
+ }
4099
+ setBodies((current) => new Map(current).set(v, {
4100
+ kind: "failed",
4101
+ message: failedMessage(error),
4102
+ ticket
4103
+ }));
4104
+ });
4105
+ };
3793
4106
  /** Read the skills again, keeping the sentence: a re-read is not an answer to anything. */
3794
4107
  const reloadSkills = () => {
3795
4108
  face.loadSkills().then((next) => {
@@ -3818,9 +4131,17 @@ window.__ModuleLoader__.load({
3818
4131
  setBodies(/* @__PURE__ */ new Map());
3819
4132
  }
3820
4133
  face.loadVersions(name).then((next) => {
3821
- if (readTicket.current === ticket) {
3822
- setPayload(next);
3823
- clearReadFailure();
4134
+ if (readTicket.current !== ticket) return;
4135
+ setPayload(next);
4136
+ clearReadFailure();
4137
+ if (keepContent) return;
4138
+ const current = historyViewModel(next).current[0];
4139
+ if (current !== void 0) {
4140
+ setExpanded({
4141
+ v: current.v,
4142
+ kind: "preview"
4143
+ });
4144
+ loadPreview(name, current.v);
3824
4145
  }
3825
4146
  }).catch((error) => {
3826
4147
  if (readTicket.current !== ticket) return;
@@ -3910,36 +4231,13 @@ window.__ModuleLoader__.load({
3910
4231
  });
3911
4232
  return;
3912
4233
  }
3913
- setBodies((current) => new Map(current).set(v, {
3914
- kind: "loading",
3915
- ticket
3916
- }));
3917
- face.loadBody(name, v).then((body) => {
3918
- if (readTicket.current !== ticket) {
3919
- setBodies((current) => dropIfTicket(current, v, ticket));
3920
- return;
3921
- }
3922
- setBodies((current) => new Map(current).set(v, {
3923
- kind: "ready",
3924
- body,
3925
- ticket
3926
- }));
3927
- }).catch((error) => {
3928
- if (readTicket.current !== ticket) {
3929
- setBodies((current) => dropIfTicket(current, v, ticket));
3930
- return;
3931
- }
3932
- setBodies((current) => new Map(current).set(v, {
3933
- kind: "failed",
3934
- message: failedMessage(error),
3935
- ticket
3936
- }));
3937
- });
4234
+ loadPreview(name, v);
3938
4235
  };
3939
4236
  (0, react.useEffect)(reloadSkills, []);
3940
4237
  const needle = query.trim().toLowerCase();
3941
4238
  const visible = (0, react.useMemo)(() => needle === "" ? skills : skills.filter((skill) => skill.name.toLowerCase().includes(needle) || skill.description.toLowerCase().includes(needle)), [skills, needle]);
3942
4239
  const loaded = payload !== void 0;
4240
+ const model = payload === void 0 ? void 0 : historyViewModel(payload);
3943
4241
  /** Drop the pending confirmation: the control that opened it must not be the only way out. */
3944
4242
  const cancelRestore = () => {
3945
4243
  setPending(void 0);
@@ -3983,7 +4281,23 @@ window.__ModuleLoader__.load({
3983
4281
  })))), (0, react.createElement)("div", { className: "evo-hist-main" }, panelHead(face, refresh, selected ?? face.t("bodyTitle")), notice(noteText, noteError), failure === void 0 ? null : (0, react.createElement)("div", { className: "evo-hist-failure" }, failureBlock(face.t, failure)), selected === void 0 ? [emptyState(face.t(skills.length === 0 ? skillsLoaded ? "empty.skills" : "loading" : "empty.pick"), "empty"), (0, react.createElement)("p", {
3984
4282
  key: "hint",
3985
4283
  className: "evo-hist-hint"
3986
- }, face.t("hint"))] : loaded ? null : emptyState(versionsFailed === void 0 ? face.t("loading") : `${face.t("empty.versions.failed")} — ${versionsFailed}`), loaded ? (0, react.createElement)("div", null, group(face.t("group.content"), payload.content, void 0), group(face.t("group.support"), payload.support, face.t("group.support.note")), payload.content.length === 0 && payload.support.length === 0 ? (0, react.createElement)("p", { className: "evo-hist-hint" }, face.t("empty.versions")) : null) : null));
4284
+ }, face.t("hint"))] : loaded ? null : emptyState(versionsFailed === void 0 ? face.t("loading") : `${face.t("empty.versions.failed")} — ${versionsFailed}`), loaded && model !== void 0 ? (0, react.createElement)("div", { className: "evo-hist-reader" }, model.current.length === 0 ? null : (0, react.createElement)("section", {
4285
+ key: "current",
4286
+ className: "evo-hist-current"
4287
+ }, ...groupHeading(face.t("group.current"), void 0), ...model.current.map((row) => versionRow({
4288
+ copy: face,
4289
+ row,
4290
+ confirming: pending === row.v,
4291
+ open: expanded !== void 0 && expanded.v === row.v ? expanded.kind : void 0,
4292
+ expanded: expandedOf(row),
4293
+ onRestore: () => {
4294
+ restore(row.v, row.unitId);
4295
+ },
4296
+ onCancel: cancelRestore,
4297
+ onToggle: (kind) => {
4298
+ toggle(row.v, kind);
4299
+ }
4300
+ }))), group(face.t("group.history"), model.older, void 0), model.support.length === 0 ? null : group(face.t("group.support"), model.support, face.t("group.support.note")), model.hasAny ? null : (0, react.createElement)("p", { className: "evo-hist-hint" }, face.t("empty.versions"))) : null));
3987
4301
  }
3988
4302
  /**
3989
4303
  * Drop a superseded lazy read ONLY if the entry still belongs to that read.
@@ -4031,6 +4345,24 @@ window.__ModuleLoader__.load({
4031
4345
  fail: "diagSummaryFail",
4032
4346
  unknown: "diagSummaryUnknown"
4033
4347
  });
4348
+ /**
4349
+ * Split the frozen runtime rows without dropping one. The top issue follows the same fail > warn > unknown order.
4350
+ * @param rows - runtime rows from the host view.
4351
+ * @returns the reading shape used by the card.
4352
+ */
4353
+ function diagnosticsReading(rows) {
4354
+ const order = [
4355
+ "fail",
4356
+ "warn",
4357
+ "unknown"
4358
+ ];
4359
+ const issues = [...rows].filter((row) => row.status !== "ok").sort((a, b) => order.indexOf(a.status) - order.indexOf(b.status));
4360
+ return {
4361
+ topIssue: issues[0],
4362
+ otherIssues: issues.slice(1),
4363
+ normal: rows.filter((row) => row.status === "ok")
4364
+ };
4365
+ }
4034
4366
  /** The one status the card leads with: fail > warn > unknown > ok. */
4035
4367
  function summaryOf(rows) {
4036
4368
  const count = (status) => rows.filter((row) => row.status === status).length;
@@ -4106,12 +4438,30 @@ window.__ModuleLoader__.load({
4106
4438
  className: "evo-diag-badge",
4107
4439
  "data-status": summary.status
4108
4440
  }, t(SUMMARY_KEYS[summary.status], summary.count === 0 ? void 0 : { n: summary.count })), focusRow === void 0 ? null : (0, react.createElement)("span", { "data-role": "diag-focus" }, focusRow.label), (0, react.createElement)("span", { className: "evolution-param-chevron" }, open ? "▲" : "▼"));
4109
- const runtime = (view) => view.runtime.length === 0 ? null : (0, react.createElement)("div", {}, (0, react.createElement)("h3", { className: "evolution-param-group" }, t("diagRuntimeTitle")), (0, react.createElement)("div", { className: "evo-diag-list" }, ...view.runtime.map((row) => (0, react.createElement)("div", {
4110
- key: "runtime-" + row.key,
4111
- className: "evo-diag-item",
4112
- "data-kind": "runtime",
4113
- "data-status": row.status
4114
- }, (0, react.createElement)("div", { className: "evo-diag-row-head" }, (0, react.createElement)("span", { className: "evo-diag-dot" }), (0, react.createElement)("span", { className: "evo-diag-label" }, row.label), (0, react.createElement)("span", { className: "evo-diag-status" }, t(STATUS_KEYS[row.status]))), row.detail === void 0 ? null : (0, react.createElement)("span", { className: "evo-diag-detail" }, row.detail), row.remedy === void 0 ? null : (0, react.createElement)("span", { className: "evo-diag-remedy" }, t("diagRemedy") + row.remedy)))));
4441
+ const runtime = (view) => {
4442
+ if (view.runtime.length === 0) return null;
4443
+ const reading = diagnosticsReading(view.runtime);
4444
+ const rowNode = (row) => (0, react.createElement)("div", {
4445
+ key: "runtime-" + row.key,
4446
+ className: "evo-diag-item",
4447
+ "data-kind": "runtime",
4448
+ "data-status": row.status
4449
+ }, (0, react.createElement)("div", { className: "evo-diag-row-head" }, (0, react.createElement)("span", { className: "evo-diag-dot" }), (0, react.createElement)("span", { className: "evo-diag-label" }, row.label), (0, react.createElement)("span", { className: "evo-diag-status" }, t(STATUS_KEYS[row.status]))), row.detail === void 0 ? null : (0, react.createElement)("span", { className: "evo-diag-detail" }, row.detail), row.remedy === void 0 ? null : (0, react.createElement)("span", { className: "evo-diag-remedy" }, t("diagRemedy") + row.remedy));
4450
+ return (0, react.createElement)("div", {}, (0, react.createElement)("h3", { className: "evolution-param-group" }, t("diagRuntimeTitle")), reading.topIssue === void 0 ? (0, react.createElement)("div", {
4451
+ className: "evo-diag-complete",
4452
+ "data-role": "diag-complete"
4453
+ }, t("diagComplete")) : (0, react.createElement)("div", {
4454
+ className: "evo-diag-issue",
4455
+ "data-role": "diag-issue",
4456
+ "data-status": reading.topIssue.status
4457
+ }, rowNode(reading.topIssue)), reading.otherIssues.length === 0 ? null : (0, react.createElement)("details", {
4458
+ className: "evo-diag-group",
4459
+ "data-role": "diag-other-issues"
4460
+ }, (0, react.createElement)("summary", null, t("diagOtherIssues", { n: reading.otherIssues.length })), ...reading.otherIssues.map(rowNode)), reading.normal.length === 0 ? null : (0, react.createElement)("details", {
4461
+ className: "evo-diag-group",
4462
+ "data-role": "diag-normal"
4463
+ }, (0, react.createElement)("summary", null, t("diagNormal", { n: reading.normal.length })), ...reading.normal.map(rowNode)));
4464
+ };
4115
4465
  const body = () => {
4116
4466
  if (state.phase === "loading") return (0, react.createElement)("p", { className: "evolution-param-loading" }, t("stateLoading"));
4117
4467
  if (state.phase === "failed") return FailureBlock({
@@ -4147,6 +4497,69 @@ window.__ModuleLoader__.load({
4147
4497
  }, header, open ? (0, react.createElement)("div", { className: "evolution-param-body" }, body()) : null);
4148
4498
  }
4149
4499
  //#endregion
4500
+ //#region src/panels/history/client/WorkbenchStore.ts
4501
+ /**
4502
+ * Resolve the first landing from task counts. Pending outranks merge; no task lands on history.
4503
+ * @param counts - read-only task counts.
4504
+ * @param hasMerge - whether the merge view is mounted.
4505
+ * @returns the view to open when the user has not chosen one.
4506
+ */
4507
+ function resolveDefaultView(counts, hasMerge) {
4508
+ if (counts.pending > 0) return "pending";
4509
+ if (hasMerge && counts.merge > 0) return "merge";
4510
+ return "history";
4511
+ }
4512
+ function createWorkbenchStore(initial = {
4513
+ view: "history",
4514
+ focusRevision: 0,
4515
+ explicitView: false
4516
+ }) {
4517
+ let state = initial;
4518
+ const listeners = /* @__PURE__ */ new Set();
4519
+ const emit = (next) => {
4520
+ state = next;
4521
+ for (const listener of listeners) listener();
4522
+ };
4523
+ return {
4524
+ getState: () => state,
4525
+ subscribe(listener) {
4526
+ listeners.add(listener);
4527
+ return () => {
4528
+ listeners.delete(listener);
4529
+ };
4530
+ },
4531
+ setView(view) {
4532
+ if (state.view !== view || state.explicitView !== true) emit({
4533
+ ...state,
4534
+ view,
4535
+ explicitView: true
4536
+ });
4537
+ },
4538
+ setDefaultView(view) {
4539
+ if (state.explicitView !== true && state.view !== view) emit({
4540
+ ...state,
4541
+ view,
4542
+ explicitView: false
4543
+ });
4544
+ },
4545
+ openHistory(skill) {
4546
+ emit({
4547
+ view: "history",
4548
+ ...skill === void 0 ? {} : { selectedSkill: skill },
4549
+ focusRevision: state.focusRevision + 1,
4550
+ explicitView: true
4551
+ });
4552
+ },
4553
+ clearSelection() {
4554
+ const { selectedSkill: _selected, ...rest } = state;
4555
+ emit({
4556
+ ...rest,
4557
+ focusRevision: state.focusRevision + 1
4558
+ });
4559
+ }
4560
+ };
4561
+ }
4562
+ //#endregion
4150
4563
  //#region src/panels/history/client/Workbench.ts
4151
4564
  /**
4152
4565
  * The family's one task page. G3 owns the history view; later groups add health
@@ -4172,13 +4585,29 @@ window.__ModuleLoader__.load({
4172
4585
  const hasMerge = props.hasView?.("merge") ?? true;
4173
4586
  const hasHealth = props.hasView?.("health") ?? true;
4174
4587
  (0, react.useEffect)(() => {
4175
- if (view === "merge" && !hasMerge || view === "health" && !hasHealth) props.store.setView("history");
4588
+ if (view === "merge" && !hasMerge || view === "health" && !hasHealth) props.store.setDefaultView("history");
4176
4589
  }, [
4177
4590
  view,
4178
4591
  hasMerge,
4179
4592
  hasHealth,
4180
4593
  props.store
4181
4594
  ]);
4595
+ (0, react.useEffect)(() => {
4596
+ const load = props.loadTaskCounts;
4597
+ if (load === void 0 || state.explicitView === true) return;
4598
+ let live = true;
4599
+ load().then((counts) => {
4600
+ if (live) props.store.setDefaultView(resolveDefaultView(counts, hasMerge));
4601
+ }).catch(() => {});
4602
+ return () => {
4603
+ live = false;
4604
+ };
4605
+ }, [
4606
+ props.loadTaskCounts,
4607
+ state.explicitView,
4608
+ hasMerge,
4609
+ props.store
4610
+ ]);
4182
4611
  const viewOrder = [
4183
4612
  "history",
4184
4613
  "pending",
@@ -4200,7 +4629,10 @@ window.__ModuleLoader__.load({
4200
4629
  return (0, react.createElement)("section", {
4201
4630
  className: "evolution-page-surface evo-workbench",
4202
4631
  "data-page": view
4203
- }, (0, react.createElement)("div", { className: "evo-workbench-head" }, (0, react.createElement)("h1", { className: "evo-workbench-title" }, props.t("entry.label")), (0, react.createElement)("div", {
4632
+ }, (0, react.createElement)("div", { className: "evo-workbench-head" }, (0, react.createElement)("h1", {
4633
+ className: "evo-workbench-title",
4634
+ "data-view": view
4635
+ }, props.t("workbench.title")), (0, react.createElement)("div", {
4204
4636
  className: "evo-workbench-tabs",
4205
4637
  role: "tablist",
4206
4638
  "aria-label": props.t("entry.label")
@@ -4282,7 +4714,12 @@ window.__ModuleLoader__.load({
4282
4714
  ...props.history,
4283
4715
  focusSkill: selectedSkill,
4284
4716
  focusRevision
4285
- }) : view === "pending" ? (0, react.createElement)(PendingCard, props.pending) : view === "diagnostics" ? (0, react.createElement)(DiagnosticsCard, props.diagnostics) : null, (0, react.createElement)("div", {
4717
+ }) : view === "pending" ? (0, react.createElement)(PendingCard, {
4718
+ ...props.pending,
4719
+ onHistory: () => {
4720
+ openHistory(void 0);
4721
+ }
4722
+ }) : view === "diagnostics" ? (0, react.createElement)(DiagnosticsCard, props.diagnostics) : null, (0, react.createElement)("div", {
4286
4723
  hidden: view !== "merge" && view !== "health",
4287
4724
  className: "evo-workbench-feature"
4288
4725
  }, props.renderSlot?.("evolution.workbench.view", {
@@ -4318,52 +4755,14 @@ window.__ModuleLoader__.load({
4318
4755
  ".evo-workbench-tabs button:focus-visible{outline:var(--evo-focus-ring);outline-offset:var(--evo-focus-offset)}",
4319
4756
  ".evo-workbench-title{margin:0;font-size:var(--evo-type-lg);font-weight:600;line-height:var(--evo-leading-base)}",
4320
4757
  ".evo-workbench-body{display:flex;flex:1;min-height:0;min-width:0;overflow:hidden}",
4758
+ ".evo-workbench-feature{display:flex;flex:1;min-width:0;min-height:0}",
4759
+ ".evo-workbench-feature[hidden]{display:none}",
4760
+ ".evo-workbench-feature>*{flex:1;min-width:0}",
4761
+ ".evo-workbench-feature .evolution-merge-panel,.evo-workbench-feature .evolution-skill-health-panel{flex:1 1 auto;min-width:0}",
4321
4762
  ".evo-workbench-body>.evolution-param-card{flex:1;min-width:0;overflow:auto}",
4322
4763
  "@media (max-width:720px){.evo-workbench-head{flex-wrap:wrap}.evo-workbench-tabs{flex-wrap:wrap}}"
4323
4764
  ].join("");
4324
4765
  //#endregion
4325
- //#region src/panels/history/client/WorkbenchStore.ts
4326
- function createWorkbenchStore(initial = {
4327
- view: "history",
4328
- focusRevision: 0
4329
- }) {
4330
- let state = initial;
4331
- const listeners = /* @__PURE__ */ new Set();
4332
- const emit = (next) => {
4333
- state = next;
4334
- for (const listener of listeners) listener();
4335
- };
4336
- return {
4337
- getState: () => state,
4338
- subscribe(listener) {
4339
- listeners.add(listener);
4340
- return () => {
4341
- listeners.delete(listener);
4342
- };
4343
- },
4344
- setView(view) {
4345
- if (state.view !== view) emit({
4346
- ...state,
4347
- view
4348
- });
4349
- },
4350
- openHistory(skill) {
4351
- emit({
4352
- view: "history",
4353
- ...skill === void 0 ? {} : { selectedSkill: skill },
4354
- focusRevision: state.focusRevision + 1
4355
- });
4356
- },
4357
- clearSelection() {
4358
- const { selectedSkill: _selected, ...rest } = state;
4359
- emit({
4360
- ...rest,
4361
- focusRevision: state.focusRevision + 1
4362
- });
4363
- }
4364
- };
4365
- }
4366
- //#endregion
4367
4766
  //#region src/panels/history/client/index.ts
4368
4767
  /**
4369
4768
  * Register the locale namespace, the workbench main occupant and its sidebar row.
@@ -4412,9 +4811,10 @@ window.__ModuleLoader__.load({
4412
4811
  footnotes: t("markdown.footnotes")
4413
4812
  }
4414
4813
  });
4814
+ const approvalApi = createApprovalApi((input, init) => fetch(input, init));
4415
4815
  const pendingFace = () => ({
4416
4816
  t: pendingT,
4417
- api: createApprovalApi((input, init) => fetch(input, init)),
4817
+ api: approvalApi,
4418
4818
  confirmMode,
4419
4819
  fallback: FALLBACKS.approval
4420
4820
  });
@@ -4423,6 +4823,26 @@ window.__ModuleLoader__.load({
4423
4823
  api: createDiagnosticsApi((input, init) => fetch(input, init)),
4424
4824
  fallback: FALLBACKS.diagnostics
4425
4825
  });
4826
+ const loadTaskCounts = async () => {
4827
+ const pending = approvalApi.pending().then((answer) => answer.ok ? answer.data.length : 0).catch(() => 0);
4828
+ const merge = (async () => {
4829
+ try {
4830
+ const response = await fetch(ROUTES.merge.view, { headers: { accept: "application/json" } });
4831
+ if (!response.ok) return 0;
4832
+ const body = await response.json();
4833
+ const raw = body.ok === true ? body.data : body;
4834
+ const count = Number(raw?.counts?.active?.pending ?? raw?.counts?.pending ?? 0);
4835
+ return Number.isFinite(count) && count > 0 ? count : 0;
4836
+ } catch {
4837
+ return 0;
4838
+ }
4839
+ })();
4840
+ const [pendingCount, mergeCount] = await Promise.all([pending, merge]);
4841
+ return {
4842
+ pending: pendingCount,
4843
+ merge: mergeCount
4844
+ };
4845
+ };
4426
4846
  const workbenchStore = createWorkbenchStore();
4427
4847
  registerSidebarPanel(ctx, {
4428
4848
  id: WORKBENCH_ID,
@@ -4444,7 +4864,8 @@ window.__ModuleLoader__.load({
4444
4864
  history: historyFace(t),
4445
4865
  pending: pendingFace(),
4446
4866
  diagnostics: diagnosticsFace(),
4447
- hasView
4867
+ hasView,
4868
+ loadTaskCounts
4448
4869
  }),
4449
4870
  children: { "evolution.workbench.view": {
4450
4871
  kind: "list",