dsh-plugin-update 0.5.3 → 0.5.5

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/dist/panel.js CHANGED
@@ -9,8 +9,9 @@ import {
9
9
  shouldFetchChangelog,
10
10
  yankedBannerHTML
11
11
  } from "./changelog.js";
12
+ import { LOG_EVENT_CALL, LOG_EVENT_CALL_FAIL, LOG_EVENT_INSTALL_EXEC } from "./log-events.js";
12
13
  function normalizePanelTheme(value) {
13
- return value === "d5-paper" || value === "archive" ? "d5-paper" : "default";
14
+ return value === "archive" || value === "d5-paper" ? "archive" : "default";
14
15
  }
15
16
  const BLOCKED_COPY = {
16
17
  "unknown-profile": {
@@ -510,8 +511,8 @@ const UPDATE_PANEL_CSS = [
510
511
  '.dsh-upd-banner[data-kind="update"]{border-color:var(--dsh-upd-ok-line);background:var(--dsh-upd-ok-bg)}',
511
512
  '.dsh-upd-banner[data-kind="busy"]{border-color:var(--dsh-upd-busy-line);background:var(--dsh-upd-busy-bg)}',
512
513
  ".dsh-upd code{font-family:Consolas,Menlo,monospace;font-size:12px;word-break:break-all}",
513
- ".dsh-upd-manual,.dsh-upd-queue,.dsh-upd-log{margin:8px 0;font-size:13px}",
514
- ".dsh-upd-changelog-wrap{margin:8px 0;font-size:13px;border-top:1px solid var(--dsh-upd-line,#e5e7eb);padding-top:8px}",
514
+ ".dsh-upd-manual,.dsh-upd-queue,.dsh-upd-log{margin:4px 0;font-size:13px}",
515
+ ".dsh-upd-changelog-wrap{margin:4px 0 0;font-size:13px}",
515
516
  ".dsh-upd-changelog-title{font-weight:700;margin:0 0 4px}",
516
517
  ".dsh-upd-changelog-version{margin:6px 0}",
517
518
  ".dsh-upd-changelog-catname{font-weight:600;margin:6px 0 2px}",
@@ -596,7 +597,7 @@ const UPDATE_PANEL_CSS = [
596
597
  ].join("\n");
597
598
  const UPDATE_PANEL_D5_CSS = [
598
599
  "/* D5 \u6863\u6848\u5377\u53EF\u9009\u4E3B\u9898\uFF1A\u53EA\u6362\u989C\u8272/\u5B57\u4F53/\u95F4\u8DDD\uFF1B\u5185\u6838 DOM \u987A\u5E8F\u4E00\u5B57\u4E0D\u52A8\uFF0C\u4E0D\u65AD\u590D\u5236\u8BCA\u65AD\u3002 */",
599
- '.dsh-upd[data-theme="d5-paper"]{--d5-bg:#f7f3ea;--d5-card:#fffdf6;--d5-ink:#1a1a1a;--d5-muted:#6f675a;',
600
+ '.dsh-upd[data-theme="archive"]{--d5-bg:#f7f3ea;--d5-card:#fffdf6;--d5-ink:#1a1a1a;--d5-muted:#6f675a;',
600
601
  "--d5-line:#e3d9c4;--d5-line-strong:#c4b896;--d5-accent:#c8402a;--d5-accent-deep:#9c2e1d;",
601
602
  "--d5-ok:#1a7f37;--d5-ok-bg:#e9f4ea;--d5-warn:#8a5a00;--d5-warn-bg:#fbf0d0;",
602
603
  "--d5-bad:#b3261e;--d5-bad-bg:#fbe9e5;",
@@ -607,116 +608,125 @@ const UPDATE_PANEL_D5_CSS = [
607
608
  "font-family:var(--d5-sans);color:var(--d5-ink);background:var(--d5-card);",
608
609
  "border:1px solid var(--d5-line-strong);border-radius:4px;box-shadow:var(--d5-shadow)}",
609
610
  // 按钮脸自己不透明(宿主底色未知时也读得出;卡片上渲染与 transparent 逐字同色)。
610
- '.dsh-upd[data-theme="d5-paper"] button{border-color:var(--d5-line-strong);background:var(--d5-card);color:var(--d5-ink);border-radius:3px;font-family:var(--d5-sans)}',
611
- '.dsh-upd[data-theme="d5-paper"] button:hover:not(:disabled){border-color:var(--d5-accent);color:var(--d5-accent)}',
612
- '.dsh-upd[data-theme="d5-paper"] button[data-primary="1"]{background:var(--d5-accent);border-color:var(--d5-accent);color:#fff}',
613
- '.dsh-upd[data-theme="d5-paper"] button[data-primary="1"]:hover:not(:disabled){background:var(--d5-accent-deep);color:#fff}',
614
- '.dsh-upd[data-theme="d5-paper"] button:focus-visible{outline:2px solid var(--d5-accent);outline-offset:2px}',
615
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-banner{background:var(--d5-bg);border-color:var(--d5-line-strong)}',
616
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-banner[data-kind="update"]{border-color:var(--d5-ok);background:var(--d5-ok-bg)}',
617
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-banner[data-kind="busy"]{border-color:var(--d5-warn);background:var(--d5-warn-bg)}',
618
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-banner[data-kind="restart"]{border-color:var(--d5-warn);background:var(--d5-warn-bg);font-family:var(--d5-serif);border-width:2px}',
619
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-banner[data-kind="failed"],.dsh-upd[data-theme="d5-paper"] .dsh-upd-banner[data-kind="blocked"]{border-color:var(--d5-bad);background:var(--d5-bad-bg)}',
620
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-banner[data-kind="done"]{border-color:var(--d5-ok);background:var(--d5-ok-bg)}',
621
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-changelog-yanked{border-color:var(--d5-warn);background:var(--d5-warn-bg);color:var(--d5-ink)}',
622
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-breaking-badge{color:var(--d5-accent);border-color:var(--d5-accent)}',
623
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-changelog-count{color:var(--d5-muted)}',
624
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-changelog-more-note{color:var(--d5-muted)}',
611
+ '.dsh-upd[data-theme="archive"] button{border-color:var(--d5-line-strong);background:var(--d5-card);color:var(--d5-ink);border-radius:3px;font-family:var(--d5-sans)}',
612
+ '.dsh-upd[data-theme="archive"] button:hover:not(:disabled){border-color:var(--d5-accent);color:var(--d5-accent)}',
613
+ '.dsh-upd[data-theme="archive"] button[data-primary="1"]{background:var(--d5-accent);border-color:var(--d5-accent);color:#fff}',
614
+ '.dsh-upd[data-theme="archive"] button[data-primary="1"]:hover:not(:disabled){background:var(--d5-accent-deep);color:#fff}',
615
+ '.dsh-upd[data-theme="archive"] button:focus-visible{outline:2px solid var(--d5-accent);outline-offset:2px}',
616
+ '.dsh-upd[data-theme="archive"] .dsh-upd-banner{background:var(--d5-bg);border-color:var(--d5-line-strong)}',
617
+ '.dsh-upd[data-theme="archive"] .dsh-upd-banner[data-kind="update"]{border-color:var(--d5-ok);background:var(--d5-ok-bg)}',
618
+ '.dsh-upd[data-theme="archive"] .dsh-upd-banner[data-kind="busy"]{border-color:var(--d5-warn);background:var(--d5-warn-bg)}',
619
+ '.dsh-upd[data-theme="archive"] .dsh-upd-banner[data-kind="restart"]{border-color:var(--d5-warn);background:var(--d5-warn-bg);font-family:var(--d5-serif);border-width:2px}',
620
+ '.dsh-upd[data-theme="archive"] .dsh-upd-banner[data-kind="failed"],.dsh-upd[data-theme="archive"] .dsh-upd-banner[data-kind="blocked"]{border-color:var(--d5-bad);background:var(--d5-bad-bg)}',
621
+ '.dsh-upd[data-theme="archive"] .dsh-upd-banner[data-kind="done"]{border-color:var(--d5-ok);background:var(--d5-ok-bg)}',
622
+ '.dsh-upd[data-theme="archive"] .dsh-upd-changelog-yanked{border-color:var(--d5-warn);background:var(--d5-warn-bg);color:var(--d5-ink)}',
623
+ '.dsh-upd[data-theme="archive"] .dsh-upd-breaking-badge{color:var(--d5-accent);border-color:var(--d5-accent)}',
624
+ '.dsh-upd[data-theme="archive"] .dsh-upd-changelog-count{color:var(--d5-muted)}',
625
+ '.dsh-upd[data-theme="archive"] .dsh-upd-changelog-more-note{color:var(--d5-muted)}',
625
626
  // —— 大印章(原型 :206 `.seal`:右上 88px、旋转 -7°、双细框;内容与色调来自根属性,不加节点)——
626
- '.dsh-upd[data-theme="d5-paper"]{position:relative;padding:22px 26px 20px}',
627
- '.dsh-upd[data-theme="d5-paper"]::before{content:attr(data-seal);position:absolute;top:20px;right:24px;width:88px;height:88px;',
627
+ '.dsh-upd[data-theme="archive"]{position:relative;padding:16px 20px 14px}',
628
+ '.dsh-upd[data-theme="archive"]::before{content:attr(data-seal);position:absolute;top:20px;right:24px;width:88px;height:88px;',
628
629
  "display:flex;align-items:center;justify-content:center;text-align:center;letter-spacing:.18em;text-indent:.18em;line-height:1.35;",
629
630
  "border:3px solid currentColor;border-radius:14px;transform:rotate(-7deg);font-family:var(--d5-serif);font-weight:700;font-size:21px;",
630
631
  "background:color-mix(in srgb,currentColor 8%,transparent);user-select:none;pointer-events:none;",
631
632
  "box-shadow:inset 0 0 0 5px var(--d5-card),inset 0 0 0 6px currentColor,0 2px 6px rgba(0,0,0,.12)}",
632
- '.dsh-upd[data-theme="d5-paper"][data-seal-tone="ink"]::before{color:var(--d5-muted)}',
633
- '.dsh-upd[data-theme="d5-paper"][data-seal-tone="green"]::before{color:var(--d5-ok)}',
634
- '.dsh-upd[data-theme="d5-paper"][data-seal-tone="yellow"]::before{color:var(--d5-warn)}',
635
- '.dsh-upd[data-theme="d5-paper"][data-seal-tone="red"]::before{color:var(--d5-bad)}',
633
+ '.dsh-upd[data-theme="archive"][data-seal-tone="ink"]::before{color:var(--d5-muted)}',
634
+ '.dsh-upd[data-theme="archive"][data-seal-tone="green"]::before{color:var(--d5-ok)}',
635
+ '.dsh-upd[data-theme="archive"][data-seal-tone="yellow"]::before{color:var(--d5-warn)}',
636
+ '.dsh-upd[data-theme="archive"][data-seal-tone="red"]::before{color:var(--d5-bad)}',
636
637
  // 印章占位:首行(横幅/状态行)右侧留出 120px,文字不许压到印章上(原型 .filehead padding-right:120px)
637
638
  // —— 卷宗抬头(原型 :195-203 的刊头,主题切换按钮按用户口径去掉):只有 D5 档案卷才显示 ——
638
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-masthead{display:block;padding:0 0 10px;margin:0 0 12px;border-bottom:1px solid var(--d5-line)}',
639
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-masthead-kicker{display:block;font-size:11px;letter-spacing:.35em;color:var(--d5-muted);margin-bottom:3px}',
640
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-masthead-title{font-family:var(--d5-serif);font-size:26px;font-weight:700;line-height:1.2}',
641
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-masthead-title i{color:var(--d5-accent);font-style:normal}',
639
+ '.dsh-upd[data-theme="archive"] .dsh-upd-masthead{display:block;padding:0 0 8px;margin:0 0 8px;border-bottom:1px solid var(--d5-line)}',
640
+ '.dsh-upd[data-theme="archive"] .dsh-upd-masthead-kicker{display:block;font-size:11px;letter-spacing:.35em;color:var(--d5-muted);margin-bottom:3px}',
641
+ '.dsh-upd[data-theme="archive"] .dsh-upd-masthead-title{font-family:var(--d5-serif);font-size:26px;font-weight:700;line-height:1.2}',
642
+ '.dsh-upd[data-theme="archive"] .dsh-upd-masthead-title i{color:var(--d5-accent);font-style:normal}',
642
643
  // 横幅不再给大印章留 124px:实测(headless 量盒子)印章盒底边 y=109,横幅正文顶边 y=108、
643
644
  // 状态行那句在 y=159——印章只压到横幅顶部的留白带,压不到正文。留着反而把 27px 那句话挤成两行
644
645
  // (27px 单行需 428px,留白后只剩 366px)。档案头那 120px 保留:那里是真的重叠。
645
646
  // —— 更新队列(03 章)D5 皮肤 ——
646
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-qrow{padding:8px 0}',
647
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-qk{width:66px;letter-spacing:.18em}',
648
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-qv{font-family:var(--d5-serif);font-size:16px}',
649
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-qn{font-family:var(--d5-mono);font-size:11.5px;color:var(--d5-muted)}',
650
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-qseq{color:var(--d5-muted)}',
651
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-chap-note{color:var(--d5-muted)}',
647
+ '.dsh-upd[data-theme="archive"] .dsh-upd-qrow{padding:6px 0}',
648
+ '.dsh-upd[data-theme="archive"] .dsh-upd-qk{width:66px;letter-spacing:.18em}',
649
+ '.dsh-upd[data-theme="archive"] .dsh-upd-qv{font-family:var(--d5-serif);font-size:16px}',
650
+ '.dsh-upd[data-theme="archive"] .dsh-upd-qn{font-family:var(--d5-mono);font-size:11.5px;color:var(--d5-muted)}',
651
+ '.dsh-upd[data-theme="archive"] .dsh-upd-qseq{color:var(--d5-muted)}',
652
+ '.dsh-upd[data-theme="archive"] .dsh-upd-chap-note{color:var(--d5-muted)}',
652
653
  // —— 小印章(原型 :215 `.sealmini`:30px、旋转 -5°、一字)——
653
654
  // 待重启横幅一律不画印章:那一档的标记是左侧手绘 SVG(原型 :446 的 .mark 只有 SVG)。
654
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-banner[data-kind="loading"]::before,.dsh-upd[data-theme="d5-paper"] .dsh-upd-banner[data-kind="idle"]::before,',
655
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-banner[data-kind="update"]::before,.dsh-upd[data-theme="d5-paper"] .dsh-upd-banner[data-kind="busy"]::before,',
656
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-banner[data-kind="blocked"]::before,.dsh-upd[data-theme="d5-paper"] .dsh-upd-banner[data-kind="failed"]::before,',
657
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-banner[data-kind="done"]::before{content:attr(data-mini);display:inline-flex;align-items:center;justify-content:center;',
655
+ '.dsh-upd[data-theme="archive"] .dsh-upd-banner[data-kind="loading"]::before,.dsh-upd[data-theme="archive"] .dsh-upd-banner[data-kind="idle"]::before,',
656
+ '.dsh-upd[data-theme="archive"] .dsh-upd-banner[data-kind="update"]::before,.dsh-upd[data-theme="archive"] .dsh-upd-banner[data-kind="busy"]::before,',
657
+ '.dsh-upd[data-theme="archive"] .dsh-upd-banner[data-kind="blocked"]::before,.dsh-upd[data-theme="archive"] .dsh-upd-banner[data-kind="failed"]::before,',
658
+ '.dsh-upd[data-theme="archive"] .dsh-upd-banner[data-kind="done"]::before{content:attr(data-mini);display:inline-flex;align-items:center;justify-content:center;',
658
659
  "width:30px;height:30px;margin-right:10px;vertical-align:middle;border:2px solid currentColor;border-radius:7px;",
659
660
  "font-family:var(--d5-serif);font-weight:700;font-size:16px;line-height:26px;transform:rotate(-5deg);flex:none;color:var(--d5-muted)}",
660
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-banner[data-kind="update"]::before{color:var(--d5-ok)}',
661
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-banner[data-kind="busy"]::before{color:var(--d5-warn)}',
662
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-banner[data-kind="blocked"]::before,.dsh-upd[data-theme="d5-paper"] .dsh-upd-banner[data-kind="failed"]::before{color:var(--d5-bad)}',
663
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-banner[data-kind="done"]::before{color:var(--d5-ok)}',
664
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-log code{font-family:var(--d5-mono);font-size:11px;color:var(--d5-muted);border:1px solid var(--d5-line-strong);border-radius:3px;padding:0 6px;letter-spacing:.06em}',
665
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-manual code{display:block;background:var(--d5-ink);color:var(--d5-bg);font-family:var(--d5-mono);font-size:12.5px;padding:12px 14px;border-radius:4px;white-space:pre-wrap;word-break:break-all}',
661
+ '.dsh-upd[data-theme="archive"] .dsh-upd-banner[data-kind="update"]::before{color:var(--d5-ok)}',
662
+ '.dsh-upd[data-theme="archive"] .dsh-upd-banner[data-kind="busy"]::before{color:var(--d5-warn)}',
663
+ '.dsh-upd[data-theme="archive"] .dsh-upd-banner[data-kind="blocked"]::before,.dsh-upd[data-theme="archive"] .dsh-upd-banner[data-kind="failed"]::before{color:var(--d5-bad)}',
664
+ '.dsh-upd[data-theme="archive"] .dsh-upd-banner[data-kind="done"]::before{color:var(--d5-ok)}',
665
+ '.dsh-upd[data-theme="archive"] .dsh-upd-log code{font-family:var(--d5-mono);font-size:11px;color:var(--d5-muted);border:1px solid var(--d5-line-strong);border-radius:3px;padding:0 6px;letter-spacing:.06em}',
666
+ '.dsh-upd[data-theme="archive"] .dsh-upd-manual code{display:block;background:var(--d5-ink);color:var(--d5-bg);font-family:var(--d5-mono);font-size:12.5px;padding:12px 14px;border-radius:4px;white-space:pre-wrap;word-break:break-all}',
666
667
  // 待重启标记:手绘 SVG 当**独立 flex 标记**放在文字块左侧(原型 :446 `.mark` 是独立节点),
667
668
  // 不能用行内背景——那样换行时三角会落在句子中间把话劈开(现场回归)。
668
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-banner[data-kind="restart"]>div:first-child{display:flex;gap:10px;align-items:flex-start}',
669
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-banner[data-kind="restart"]>div:first-child::before{content:"";flex:none;width:20px;height:20px;margin-top:3px;',
669
+ '.dsh-upd[data-theme="archive"] .dsh-upd-banner[data-kind="restart"]>div:first-child{display:flex;gap:10px;align-items:flex-start}',
670
+ '.dsh-upd[data-theme="archive"] .dsh-upd-banner[data-kind="restart"]>div:first-child::before{content:"";flex:none;width:20px;height:20px;margin-top:3px;',
670
671
  'background:url("data:image/svg+xml,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 width=%2720%27 height=%2720%27 viewBox=%270 0 24 24%27 fill=%27none%27 stroke=%27%238a5a00%27 stroke-width=%272%27 stroke-linecap=%27round%27 stroke-linejoin=%27round%27%3E%3Cpath d=%27M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z%27/%3E%3Cline x1=%2712%27 y1=%279%27 x2=%2712%27 y2=%2713%27/%3E%3Cline x1=%2712%27 y1=%2717%27 x2=%2712.01%27 y2=%2717%27/%3E%3C/svg%3E") no-repeat center/20px 20px}',
671
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-banner>div:first-child{overflow:hidden;text-overflow:ellipsis}',
672
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-actions{flex-wrap:wrap}',
672
+ '.dsh-upd[data-theme="archive"] .dsh-upd-banner>div:first-child{overflow:hidden;text-overflow:ellipsis}',
673
+ '.dsh-upd[data-theme="archive"] .dsh-upd-actions{flex-wrap:wrap}',
673
674
  // footer 只换肤(#47 定案 A + D5 约束:不换 DOM 顺序;复制诊断永不隐藏,本串不动它)。
674
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-footer{margin-top:26px;padding-top:16px;border-top:1px solid var(--d5-line)}',
675
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-foot-note{color:var(--d5-muted)}',
675
+ '.dsh-upd[data-theme="archive"] .dsh-upd-footer{margin-top:14px;padding-top:10px;border-top:1px solid var(--d5-line)}',
676
+ '.dsh-upd[data-theme="archive"] .dsh-upd-foot-note{color:var(--d5-muted)}',
676
677
  // —— 档案头(原型 :208-211 `.filehead`:serif 插件名 22px + 使用范围 + profile 牌;右侧留章位)——
677
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-head{display:flex;gap:16px;align-items:baseline;flex-wrap:wrap;padding-right:120px}',
678
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-name{font-family:var(--d5-serif);font-size:22px;font-weight:700}',
679
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-meta{width:100%;font-size:12.5px;color:var(--d5-muted)}',
680
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-meta b{color:var(--d5-ink);font-weight:600}',
681
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-proftag{font-family:var(--d5-mono);font-size:11px;color:var(--d5-muted);border:1px solid var(--d5-line-strong);border-radius:3px;padding:0 6px;margin-left:8px;letter-spacing:.06em}',
678
+ '.dsh-upd[data-theme="archive"] .dsh-upd-head{display:flex;gap:16px;align-items:baseline;flex-wrap:wrap;padding-right:120px}',
679
+ '.dsh-upd[data-theme="archive"] .dsh-upd-name{font-family:var(--d5-serif);font-size:22px;font-weight:700}',
680
+ '.dsh-upd[data-theme="archive"] .dsh-upd-meta{width:100%;font-size:12.5px;color:var(--d5-muted)}',
681
+ '.dsh-upd[data-theme="archive"] .dsh-upd-meta b{color:var(--d5-ink);font-weight:600}',
682
+ '.dsh-upd[data-theme="archive"] .dsh-upd-proftag{font-family:var(--d5-mono);font-size:11px;color:var(--d5-muted);border:1px solid var(--d5-line-strong);border-radius:3px;padding:0 6px;margin-left:8px;letter-spacing:.06em}',
682
683
  // —— 版本条(原型 :216 `.strip`:三格,格间一线,左上小写标签 + 等宽值)——
683
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-strip{display:flex;flex-wrap:wrap;margin:10px 0 0;border:1px solid var(--d5-line);border-radius:4px;overflow:hidden;font-size:12.5px}',
684
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-strip>div{flex:1 1 120px;padding:8px 12px;border-left:1px solid var(--d5-line)}',
685
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-strip>div:first-child{border-left:0}',
686
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-strip-k{display:block;font-size:11px;letter-spacing:.2em;color:var(--d5-muted)}',
687
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-strip-v{font-family:var(--d5-mono);font-size:13px}',
684
+ '.dsh-upd[data-theme="archive"] .dsh-upd-strip{display:flex;flex-wrap:wrap;margin:8px 0 0;border:1px solid var(--d5-line);border-radius:4px;overflow:hidden;font-size:12.5px}',
685
+ '.dsh-upd[data-theme="archive"] .dsh-upd-strip>div{flex:1 1 120px;padding:6px 10px;border-left:1px solid var(--d5-line)}',
686
+ '.dsh-upd[data-theme="archive"] .dsh-upd-strip>div:first-child{border-left:0}',
687
+ '.dsh-upd[data-theme="archive"] .dsh-upd-strip-k{display:block;font-size:11px;letter-spacing:.2em;color:var(--d5-muted)}',
688
+ '.dsh-upd[data-theme="archive"] .dsh-upd-strip-v{font-family:var(--d5-mono);font-size:13px}',
688
689
  // —— 章节(原型 :218-245:01–05 编号 + 衬线标题 + 细线)——
689
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-chapter{margin-top:26px;padding-top:16px;border-top:1px solid var(--d5-line)}',
690
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-chap-head{display:flex;align-items:baseline;gap:12px;margin-bottom:10px}',
691
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-chap-no{font-family:var(--d5-serif);font-style:italic;font-size:15px;color:var(--d5-muted)}',
692
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-chap-title{font-family:var(--d5-serif);font-size:17px;margin:0;letter-spacing:.1em}',
693
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-chap-rule{flex:1;border-top:1px solid var(--d5-line);transform:translateY(-4px)}',
690
+ '.dsh-upd[data-theme="archive"] .dsh-upd-chapter{margin-top:16px;padding-top:10px;border-top:1px solid var(--d5-line)}',
691
+ '.dsh-upd[data-theme="archive"] .dsh-upd-chap-head{display:flex;align-items:baseline;gap:12px;margin-bottom:6px}',
692
+ '.dsh-upd[data-theme="archive"] .dsh-upd-chap-no{font-family:var(--d5-serif);font-style:italic;font-size:15px;color:var(--d5-muted)}',
693
+ '.dsh-upd[data-theme="archive"] .dsh-upd-chap-title{font-family:var(--d5-serif);font-size:17px;margin:0;letter-spacing:.1em}',
694
+ '.dsh-upd[data-theme="archive"] .dsh-upd-chap-rule{flex:1;border-top:1px solid var(--d5-line);transform:translateY(-4px)}',
694
695
  // —— 横幅即状态行 / 待重启横幅(原型 :81-85 `.restart-banner`:2px 边框、圆角 4、内边距 12/16、衬线;右侧留章位)——
695
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-banner{border:2px solid var(--d5-line-strong);border-radius:4px;padding:12px 16px;font-size:14.5px;font-family:var(--d5-serif);display:flex;gap:10px;align-items:center;flex-wrap:wrap}',
696
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-banner>div:first-child{flex:1 1 auto;min-width:0}',
696
+ '.dsh-upd[data-theme="archive"] .dsh-upd-banner{border:2px solid var(--d5-line-strong);border-radius:4px;padding:10px 12px;font-size:14.5px;font-family:var(--d5-serif);display:flex;gap:10px;align-items:center;flex-wrap:wrap}',
697
+ '.dsh-upd[data-theme="archive"] .dsh-upd-banner>div:first-child{flex:1 1 auto;min-width:0}',
697
698
  // 状态行字号照原型 .status-line=27px(实测去掉横幅右侧占位后可写 486px > 428px,一行放得下)
698
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-banner>div:first-child strong{font-family:var(--d5-serif);font-size:27px;font-weight:700;line-height:1.35}',
699
+ '.dsh-upd[data-theme="archive"] .dsh-upd-banner>div:first-child strong{font-family:var(--d5-serif);font-size:27px;font-weight:700;line-height:1.25}',
699
700
  // —— 进度条 / 跳过行(原型 :132-133 `.prog`、:129-131 `.skipline .tag`)——
700
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-prog{height:8px;background:var(--d5-line);border-radius:4px;overflow:hidden;margin:10px 0 4px}',
701
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-prog-bar{display:block;height:100%;background:var(--d5-accent);transition:width .3s}',
702
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-progtxt{font-size:12.5px;color:var(--d5-muted)}',
703
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-skipline{font-size:13px;margin-top:8px}',
704
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-tag{display:inline-block;border:1px dashed var(--d5-line-strong);border-radius:3px;padding:1px 8px;margin-right:8px;font-family:var(--d5-mono);font-size:12px}',
705
- '.dsh-upd[data-theme="d5-paper"] .dsh-upd-err{font-size:13px;margin:0 0 6px;color:var(--d5-muted)}',
706
- '@media (max-width:640px){.dsh-upd[data-theme="d5-paper"]{padding:10px 12px}.dsh-upd[data-theme="d5-paper"]::before{top:12px;right:12px;width:56px;height:56px;font-size:15px;box-shadow:inset 0 0 0 4px var(--d5-card),inset 0 0 0 5px currentColor}.dsh-upd[data-theme="d5-paper"] .dsh-upd-masthead-title{font-size:19px}.dsh-upd[data-theme="d5-paper"] .dsh-upd-banner{padding-right:16px}.dsh-upd[data-theme="d5-paper"] .dsh-upd-banner::before{width:24px;height:24px;font-size:14px;line-height:20px;flex:none}.dsh-upd[data-theme="d5-paper"] .dsh-upd-banner>div:first-child{white-space:normal}}',
707
- '@media (prefers-color-scheme: dark){.dsh-upd[data-theme="d5-paper"]{--d5-bg:#141210;--d5-card:#1e1a15;--d5-ink:#ece5d3;--d5-muted:#a89c83;',
701
+ '.dsh-upd[data-theme="archive"] .dsh-upd-prog{height:8px;background:var(--d5-line);border-radius:4px;overflow:hidden;margin:10px 0 4px}',
702
+ '.dsh-upd[data-theme="archive"] .dsh-upd-prog-bar{display:block;height:100%;background:var(--d5-accent);transition:width .3s}',
703
+ '.dsh-upd[data-theme="archive"] .dsh-upd-progtxt{font-size:12.5px;color:var(--d5-muted)}',
704
+ '.dsh-upd[data-theme="archive"] .dsh-upd-skipline{font-size:13px;margin-top:8px}',
705
+ '.dsh-upd[data-theme="archive"] .dsh-upd-tag{display:inline-block;border:1px dashed var(--d5-line-strong);border-radius:3px;padding:1px 8px;margin-right:8px;font-family:var(--d5-mono);font-size:12px}',
706
+ '.dsh-upd[data-theme="archive"] .dsh-upd-err{font-size:13px;margin:0 0 6px;color:var(--d5-muted)}',
707
+ '@media (max-width:640px){.dsh-upd[data-theme="archive"]{padding:10px 12px}.dsh-upd[data-theme="archive"]::before{top:12px;right:12px;width:56px;height:56px;font-size:15px;box-shadow:inset 0 0 0 4px var(--d5-card),inset 0 0 0 5px currentColor}.dsh-upd[data-theme="archive"] .dsh-upd-masthead-title{font-size:19px}.dsh-upd[data-theme="archive"] .dsh-upd-banner{padding-right:16px}.dsh-upd[data-theme="archive"] .dsh-upd-banner::before{width:24px;height:24px;font-size:14px;line-height:20px;flex:none}.dsh-upd[data-theme="archive"] .dsh-upd-banner>div:first-child{white-space:normal}}',
708
+ '@media (prefers-color-scheme: dark){.dsh-upd[data-theme="archive"]{--d5-bg:#141210;--d5-card:#1e1a15;--d5-ink:#ece5d3;--d5-muted:#a89c83;',
708
709
  "--d5-line:#3a3226;--d5-line-strong:#5c4e3b;--d5-accent:#e0684e;--d5-accent-deep:#f0866b;",
709
710
  "--d5-ok:#8fd6a4;--d5-ok-bg:rgba(80,180,120,.12);--d5-warn:#e8c15a;--d5-warn-bg:rgba(232,193,90,.12);",
710
711
  "--d5-bad:#ef8a7d;--d5-bad-bg:rgba(239,138,125,.12);--d5-shadow:0 1px 2px rgba(0,0,0,.4),0 12px 32px rgba(0,0,0,.45)}}",
711
- '@media (prefers-color-scheme: dark){.dsh-upd[data-theme="d5-paper"] button[data-primary="1"]{color:#141210}.dsh-upd[data-theme="d5-paper"] button:focus-visible{outline-color:var(--d5-accent-deep)}}',
712
- '@media (prefers-color-scheme: dark){.dsh-upd[data-theme="d5-paper"] .dsh-upd-banner[data-kind="restart"]>div:first-child::before{background-image:url("data:image/svg+xml,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 width=%2720%27 height=%2720%27 viewBox=%270 0 24 24%27 fill=%27none%27 stroke=%27%23e8c15a%27 stroke-width=%272%27 stroke-linecap=%27round%27 stroke-linejoin=%27round%27%3E%3Cpath d=%27M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z%27/%3E%3Cline x1=%2712%27 y1=%279%27 x2=%2712%27 y2=%2713%27/%3E%3Cline x1=%2712%27 y1=%2717%27 x2=%2712.01%27 y2=%2717%27/%3E%3C/svg%3E")}}',
713
- '@media (forced-colors: active){.dsh-upd[data-theme="d5-paper"]{box-shadow:none}.dsh-upd[data-theme="d5-paper"]::before{background:none;box-shadow:none;border-color:CanvasText;color:CanvasText}.dsh-upd[data-theme="d5-paper"] .dsh-upd-banner{border:1px solid CanvasText}.dsh-upd[data-theme="d5-paper"] .dsh-upd-banner::before{border-color:CanvasText;color:CanvasText;background:Canvas}.dsh-upd[data-theme="d5-paper"] button{border:1px solid ButtonText}.dsh-upd[data-theme="d5-paper"] button[data-primary="1"]{background:ButtonFace;color:ButtonText;border-color:ButtonText}.dsh-upd[data-theme="d5-paper"] .dsh-upd-banner[data-kind="restart"]>div:first-child::before{background-image:none;content:"\u26A0"}}',
714
- '@media (prefers-reduced-motion: reduce){.dsh-upd[data-theme="d5-paper"] *{transition:none !important;animation:none !important}}'
712
+ '@media (prefers-color-scheme: dark){.dsh-upd[data-theme="archive"] button[data-primary="1"]{color:#141210}.dsh-upd[data-theme="archive"] button:focus-visible{outline-color:var(--d5-accent-deep)}}',
713
+ '@media (prefers-color-scheme: dark){.dsh-upd[data-theme="archive"] .dsh-upd-banner[data-kind="restart"]>div:first-child::before{background-image:url("data:image/svg+xml,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 width=%2720%27 height=%2720%27 viewBox=%270 0 24 24%27 fill=%27none%27 stroke=%27%23e8c15a%27 stroke-width=%272%27 stroke-linecap=%27round%27 stroke-linejoin=%27round%27%3E%3Cpath d=%27M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z%27/%3E%3Cline x1=%2712%27 y1=%279%27 x2=%2712%27 y2=%2713%27/%3E%3Cline x1=%2712%27 y1=%2717%27 x2=%2712.01%27 y2=%2717%27/%3E%3C/svg%3E")}}',
714
+ '@media (forced-colors: active){.dsh-upd[data-theme="archive"]{box-shadow:none}.dsh-upd[data-theme="archive"]::before{background:none;box-shadow:none;border-color:CanvasText;color:CanvasText}.dsh-upd[data-theme="archive"] .dsh-upd-banner{border:1px solid CanvasText}.dsh-upd[data-theme="archive"] .dsh-upd-banner::before{border-color:CanvasText;color:CanvasText;background:Canvas}.dsh-upd[data-theme="archive"] button{border:1px solid ButtonText}.dsh-upd[data-theme="archive"] button[data-primary="1"]{background:ButtonFace;color:ButtonText;border-color:ButtonText}.dsh-upd[data-theme="archive"] .dsh-upd-banner[data-kind="restart"]>div:first-child::before{background-image:none;content:"\u26A0"}}',
715
+ '@media (prefers-reduced-motion: reduce){.dsh-upd[data-theme="archive"] *{transition:none !important;animation:none !important}}'
715
716
  ].join("\n");
716
717
  function escapeHtml(text) {
717
718
  return String(text).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
718
719
  }
719
720
  const CHAPTER_TITLES = ["\u68C0\u67E5\u4E0E\u5B89\u88C5", "\u66F4\u65B0\u65E5\u5FD7", "\u66F4\u65B0\u961F\u5217", "\u9519\u8BEF\u4FE1\u606F", "\u624B\u5DE5\u547D\u4EE4"];
721
+ function formatLatchTime(atMs) {
722
+ if (typeof atMs !== "number" || !Number.isFinite(atMs) || atMs <= 0) return null;
723
+ try {
724
+ const s = new Date(atMs).toLocaleTimeString("zh-CN", { hour12: false });
725
+ return s ? s : null;
726
+ } catch {
727
+ return null;
728
+ }
729
+ }
720
730
  function chapterOf(index, inner, note = "") {
721
731
  const no = String(index).padStart(2, "0");
722
732
  const title = CHAPTER_TITLES[index - 1];
@@ -781,6 +791,9 @@ function renderUpdatePanelKernel(input, view) {
781
791
  if (b.kind === "restart") {
782
792
  actions.push(`<button type="button" data-action="restart-hint" data-primary="1" title="\u5BBF\u4E3B\u6CA1\u6709\u81EA\u91CD\u542F\u7535\u8BDD\uFF1A\u8BF7\u624B\u52A8\u91CD\u542F\u5BBF\u4E3B">\u91CD\u542F\u5BBF\u4E3B</button>`);
783
793
  }
794
+ if (b.kind === "failed") {
795
+ actions.push(`<button type="button" data-action="dismiss-failure" title="\u786E\u8BA4\u5DF2\u77E5\u6653\u8BE5\u5931\u8D25\uFF1A\u56DE\u5230\u53EF\u88C5\u9875\uFF0C\u4E0B\u6B21\u67E5/\u88C5\u5C06\u91CD\u65B0\u8BC4\u4F30">\u77E5\u9053\u4E86</button>`);
796
+ }
784
797
  if (snapshot) {
785
798
  actions.push(`<button type="button" data-action="copy-diag" title="\u590D\u5236\u5DF2\u8131\u654F\u8BCA\u65AD\uFF0C\u76F4\u63A5\u7C98\u7ED9\u63D2\u4EF6\u4F5C\u8005">\u590D\u5236\u8BCA\u65AD</button>`);
786
799
  }
@@ -877,14 +890,45 @@ ${changelogHTML}
877
890
  }
878
891
  {
879
892
  const errLines = [];
880
- if (b.kind === "failed" || b.kind === "blocked") {
893
+ const failedNow = b.kind === "failed" || b.kind === "blocked";
894
+ const failRef = input.failure;
895
+ if (failedNow) {
896
+ const shownCode = b.kind === "blocked" ? snapshot?.blockedReason ?? b.kind : typeof input.lastError === "string" && input.lastError.trim() ? input.lastError : "install-failed";
881
897
  errLines.push(
882
- `<div class="dsh-upd-err">\u7A33\u5B9A\u7801 <code>${escapeHtml(String(b.kind === "blocked" ? snapshot?.blockedReason ?? b.kind : "install-failed"))}</code>\uFF1A\u4E0A\u4E00\u6761\u4E2D\u6587\u8BF4\u660E\u5C31\u662F\u8981\u7528\u6237\u505A\u7684\u4E8B\uFF1B\u8981\u5F80\u4E0A\u6E38\u62A5\uFF0C\u7528\u300C\u590D\u5236\u8BCA\u65AD\u300D\u6574\u6BB5\u7C98\uFF08\u5DF2\u8131\u654F\uFF09\u3002</div>`
898
+ `<div class="dsh-upd-err">\u7A33\u5B9A\u7801 <code>${escapeHtml(String(shownCode))}</code>\uFF1A\u4E0A\u4E00\u6761\u4E2D\u6587\u8BF4\u660E\u5C31\u662F\u8981\u7528\u6237\u505A\u7684\u4E8B\uFF1B\u8981\u5F80\u4E0A\u6E38\u62A5\uFF0C\u7528\u300C\u590D\u5236\u8BCA\u65AD\u300D\u6574\u6BB5\u7C98\uFF08\u5DF2\u8131\u654F\uFF09\u3002</div>`
883
899
  );
900
+ if (b.kind === "failed" && failRef) {
901
+ const keys = [];
902
+ if (typeof failRef.requestId === "string" && failRef.requestId) keys.push(`\u8BF7\u6C42 <code>${escapeHtml(failRef.requestId)}</code>`);
903
+ if (typeof failRef.checkId === "string" && failRef.checkId) keys.push(`\u68C0\u67E5 <code>${escapeHtml(failRef.checkId)}</code>`);
904
+ const at = formatLatchTime(failRef.atMs);
905
+ if (at) keys.push(`\u5931\u8D25\u4E8E ${escapeHtml(at)}`);
906
+ if (keys.length > 0) {
907
+ errLines.push(`<div class="dsh-upd-err">\u672C\u6B21\u67E5\u8BE2\u952E\uFF1A${keys.join(" \xB7 ")}\uFF08\u62FF\u7740\u5B83\u4EEC\u53BB\u65E5\u5FD7\u91CC\u5BF9\uFF09\u3002</div>`);
908
+ }
909
+ if (!failRef.volatile) {
910
+ errLines.push(
911
+ `<div class="dsh-upd-err">\u8BC1\u636E\u5DF2\u51BB\u7ED3\uFF1A\u590D\u5236\u8BCA\u65AD\u91CC\u7684\u7801\u3001\u7248\u672C\u3001\u7F16\u53F7\u90FD\u53D6\u81EA\u5931\u8D25\u65F6\u523B\uFF0C\u4E0D\u968F\u8F6E\u8BE2\u5237\u65B0\uFF1B\u4E0B\u4E00\u6B21\u67E5\u65B0\u7248\u6216\u5B89\u88C5\u4F1A\u66F4\u65B0\u5B83\u3002</div>`
912
+ );
913
+ } else {
914
+ errLines.push(
915
+ `<div class="dsh-upd-err">\u8BFB\u6570\u77AC\u6001\u5931\u8D25\uFF1A\u4E0B\u4E00\u6B21\u6210\u529F\u8BFB\u6570\u4F1A\u81EA\u52A8\u89E3\u9664\uFF1B\u4E00\u76F4\u51FA\u73B0\u518D\u6309\u7A33\u5B9A\u7801\u6392\u67E5\u3002</div>`
916
+ );
917
+ }
918
+ }
919
+ } else {
920
+ errLines.push(`<div class="dsh-upd-changelog-neutral">\u6682\u65E0\u5931\u8D25\uFF1A\u6B64\u65F6\u590D\u5236\u8BCA\u65AD\u7ED9\u51FA\u7684\u662F\u5F53\u524D\u72B6\u6001\u5FEB\u7167\u3002</div>`);
921
+ }
922
+ if (input.showLogHint !== false) {
923
+ errLines.push(
924
+ `<div class="dsh-upd-log">\u6DF1\u6316\u770B\u65E5\u5FD7\uFF1A\u6309\u63D2\u4EF6\u6807\u8BC6 <code>${escapeHtml(pluginId)}</code> \u8FC7\u6EE4 <code>${LOG_EVENT_CALL}</code>\u3001<code>${LOG_EVENT_CALL_FAIL}</code>\u3001<code>${LOG_EVENT_INSTALL_EXEC}</code> \u4E09\u4E2A\u4E8B\u4EF6\u3002</div>`
925
+ );
926
+ if (b.kind === "failed" && failRef && (failRef.requestId || failRef.checkId)) {
927
+ errLines.push(
928
+ `<div class="dsh-upd-log">\u51ED\u4E0A\u9762\u7684\u8BF7\u6C42\uFF0F\u68C0\u67E5\u7F16\u53F7\u5728 <code>${LOG_EVENT_CALL_FAIL}</code> \u91CC\u5BF9\u4E0A\uFF1B\u57FA\u7EBF\u8017\u65F6\u770B <code>${LOG_EVENT_CALL}</code>\uFF0C\u6267\u884C\u7ED3\u679C\u770B <code>${LOG_EVENT_INSTALL_EXEC}</code>\u3002</div>`
929
+ );
930
+ }
884
931
  }
885
- errLines.push(
886
- `<div class="dsh-upd-log">\u6DF1\u6316\u770B\u65E5\u5FD7\uFF1A\u6309\u63D2\u4EF6\u6807\u8BC6 <code>${escapeHtml(pluginId)}</code> \u8FC7\u6EE4 <code>host.call</code>\u3001<code>host.call.fail</code>\u3001<code>update.install.exec</code> \u4E09\u4E2A\u4E8B\u4EF6\u3002</div>`
887
- );
888
932
  if (copyNotice) errLines.push(`<div class="dsh-upd-copy" role="status">${escapeHtml(copyNotice)}</div>`);
889
933
  parts.push(chapterOf(4, errLines.join("")));
890
934
  }
@@ -896,7 +940,7 @@ ${changelogHTML}
896
940
  );
897
941
  if (showActions && mode === "dialog") {
898
942
  parts.push(
899
- `<div class="dsh-upd-footer"><span class="dsh-upd-foot-note">\u5B89\u88C5\u5728\u5BBF\u4E3B\u4FA7\u7EE7\u7EED\u8DD1\uFF0C\u91CD\u5F00\u6062\u590D\u663E\u793A</span><button type="button" data-action="close-view" title="\u5173\u95ED\u9762\u677F\uFF08\u5B89\u88C5\u5728\u5BBF\u4E3B\u4FA7\u7EE7\u7EED\u8DD1\uFF0C\u53EF\u91CD\u5F00\u6062\u590D\u663E\u793A\uFF09">\u5173\u95ED</button></div>`
943
+ `<div class="dsh-upd-footer"><span class="dsh-upd-foot-note">\u5173\u95ED\u4E0D\u5F71\u54CD\u66F4\u65B0\uFF0C\u53EF\u968F\u65F6\u56DE\u6765\u67E5\u770B</span><button type="button" data-action="close-view" title="\u5173\u95ED\u7A97\u53E3\uFF0C\u66F4\u65B0\u4E0D\u53D7\u5F71\u54CD">\u5173\u95ED</button></div>`
900
944
  );
901
945
  }
902
946
  return parts.join("\n");
@@ -904,8 +948,8 @@ ${changelogHTML}
904
948
  function renderUpdatePanelHTML(input) {
905
949
  const view = panelViewModel(input);
906
950
  const kernel = renderUpdatePanelKernel(input, view);
907
- const d5 = normalizePanelTheme(input.theme) === "d5-paper";
908
- const attr = d5 ? ' data-theme="d5-paper"' : "";
951
+ const d5 = normalizePanelTheme(input.theme) === "archive";
952
+ const attr = d5 ? ' data-theme="archive"' : "";
909
953
  const sealAttr = ` data-seal="${escapeHtml(view.seal.text)}" data-seal-tone="${view.seal.tone}"`;
910
954
  const body = input.mode === "dialog" ? `<div class="dsh-upd-overlay" data-mode="dialog"><div class="dsh-upd" data-mode="dialog" data-plugin="${escapeHtml(input.pluginId)}"${sealAttr}${attr}>
911
955
  ${kernel}
@@ -917,6 +961,7 @@ ${UPDATE_PANEL_D5_CSS}` : UPDATE_PANEL_CSS;
917
961
  return `<style>${css}</style>
918
962
  ${body}`;
919
963
  }
964
+ const PANEL_FAILURE_LATCHES = /* @__PURE__ */ new Map();
920
965
  function isObject(value) {
921
966
  return !!value && typeof value === "object" && !Array.isArray(value);
922
967
  }
@@ -1019,6 +1064,7 @@ function mountUpdatePanel(container, options) {
1019
1064
  const skipStore = options.skipStore ?? createBrowserSkipStore(pluginId);
1020
1065
  const hostKind = typeof options.hostKind === "string" && options.hostKind ? options.hostKind : null;
1021
1066
  const profileNameOption = typeof options.profileName === "string" && options.profileName ? options.profileName : null;
1067
+ const showLogHintOption = options.showLogHint !== false;
1022
1068
  const diagCopyFormat = options.diagCopyFormat === "line" ? "line" : "block";
1023
1069
  let changelogMarkdown = typeof options.changelogMarkdown === "string" ? options.changelogMarkdown : null;
1024
1070
  let snapshot = null;
@@ -1026,9 +1072,139 @@ function mountUpdatePanel(container, options) {
1026
1072
  let queue = null;
1027
1073
  let receipt = null;
1028
1074
  let requestId = null;
1029
- let lastError = null;
1030
- let lastErrorKind = null;
1031
- let lastDiag = null;
1075
+ const latchKey = `${pluginId}${profileNameOption ?? ""}`;
1076
+ let latch = null;
1077
+ try {
1078
+ latch = PANEL_FAILURE_LATCHES.get(latchKey) ?? null;
1079
+ if (latch?.volatile) latch = null;
1080
+ } catch {
1081
+ latch = null;
1082
+ }
1083
+ function saveLatch() {
1084
+ try {
1085
+ if (latch && !latch.volatile) {
1086
+ if (!PANEL_FAILURE_LATCHES.has(latchKey) && PANEL_FAILURE_LATCHES.size >= 100) {
1087
+ const oldest = PANEL_FAILURE_LATCHES.keys().next();
1088
+ if (!oldest.done) PANEL_FAILURE_LATCHES.delete(oldest.value);
1089
+ }
1090
+ PANEL_FAILURE_LATCHES.set(latchKey, latch);
1091
+ } else PANEL_FAILURE_LATCHES.delete(latchKey);
1092
+ } catch {
1093
+ }
1094
+ }
1095
+ function latchNow() {
1096
+ try {
1097
+ const n = Date.now();
1098
+ return Number.isFinite(n) ? n : null;
1099
+ } catch {
1100
+ return null;
1101
+ }
1102
+ }
1103
+ function setLatch(next) {
1104
+ latch = next;
1105
+ saveLatch();
1106
+ }
1107
+ function clearLatch() {
1108
+ if (!latch) return;
1109
+ latch = null;
1110
+ saveLatch();
1111
+ }
1112
+ function currentEnvPair() {
1113
+ return { hostKind: hostKind ?? envHostKind, profileName: profileNameOption ?? envProfileName };
1114
+ }
1115
+ function latchFromReply(reply, source) {
1116
+ const env = currentEnvPair();
1117
+ return {
1118
+ code: failureCodeOf(
1119
+ { error: reply["error"], errorKind: reply["errorKind"] },
1120
+ source === "install" ? "install-failed" : "check-failed"
1121
+ ),
1122
+ kind: typeof reply["errorKind"] === "string" && reply["errorKind"].trim() ? reply["errorKind"].trim() : null,
1123
+ detail: null,
1124
+ diag: Object.prototype.hasOwnProperty.call(reply, "diag") ? reply["diag"] : null,
1125
+ requestId: source === "install" ? requestId : null,
1126
+ checkId: source === "install" ? receipt?.checkId ?? null : null,
1127
+ runningVersion: snapshot?.runningVersion ?? null,
1128
+ installedVersion: snapshot?.installedVersion ?? null,
1129
+ latestVersion: snapshot?.latestVersion ?? null,
1130
+ hostKind: env.hostKind,
1131
+ profileName: env.profileName,
1132
+ source,
1133
+ volatile: false,
1134
+ jobId: null,
1135
+ atMs: latchNow()
1136
+ };
1137
+ }
1138
+ function latchFromJob(job, snap) {
1139
+ const env = currentEnvPair();
1140
+ const message = typeof job.message === "string" ? job.message : null;
1141
+ const detail = message && message.includes(":") ? message.slice(message.indexOf(":") + 1).trim() || null : message;
1142
+ return {
1143
+ code: messageCodeOf(message) || "install-failed",
1144
+ kind: null,
1145
+ detail,
1146
+ // 快照里没有 diag:保留锁存里既有的(多半是致命安装回包自带的),没有即缺省说人话
1147
+ diag: latch?.diag ?? null,
1148
+ requestId: job.requestId ?? latch?.requestId ?? requestId,
1149
+ checkId: receipt?.checkId ?? latch?.checkId ?? null,
1150
+ runningVersion: snap?.runningVersion ?? snapshot?.runningVersion ?? null,
1151
+ installedVersion: snap?.installedVersion ?? snapshot?.installedVersion ?? null,
1152
+ latestVersion: snap?.latestVersion ?? snapshot?.latestVersion ?? null,
1153
+ hostKind: env.hostKind ?? latch?.hostKind ?? null,
1154
+ profileName: env.profileName ?? latch?.profileName ?? null,
1155
+ source: "install",
1156
+ volatile: false,
1157
+ jobId: typeof job.id === "string" ? job.id : null,
1158
+ atMs: latchNow()
1159
+ };
1160
+ }
1161
+ function volatileLatch(source) {
1162
+ const env = currentEnvPair();
1163
+ return {
1164
+ code: "check-failed",
1165
+ kind: null,
1166
+ detail: null,
1167
+ diag: null,
1168
+ requestId,
1169
+ checkId: receipt?.checkId ?? null,
1170
+ runningVersion: snapshot?.runningVersion ?? null,
1171
+ installedVersion: snapshot?.installedVersion ?? null,
1172
+ latestVersion: snapshot?.latestVersion ?? null,
1173
+ hostKind: env.hostKind,
1174
+ profileName: env.profileName,
1175
+ source,
1176
+ volatile: true,
1177
+ jobId: null,
1178
+ atMs: latchNow()
1179
+ };
1180
+ }
1181
+ function backfillLatch(s) {
1182
+ if (!latch) return;
1183
+ let touched = false;
1184
+ if (latch.runningVersion === null && s.runningVersion) {
1185
+ latch.runningVersion = s.runningVersion;
1186
+ touched = true;
1187
+ }
1188
+ if (latch.installedVersion === null && s.installedVersion) {
1189
+ latch.installedVersion = s.installedVersion;
1190
+ touched = true;
1191
+ }
1192
+ if (latch.latestVersion === null && s.latestVersion) {
1193
+ latch.latestVersion = s.latestVersion;
1194
+ touched = true;
1195
+ }
1196
+ if (touched) saveLatch();
1197
+ }
1198
+ function tripleChanged(s) {
1199
+ if (!latch) return false;
1200
+ backfillLatch(s);
1201
+ const pairs = [
1202
+ [latch.runningVersion, s.runningVersion ?? null],
1203
+ [latch.installedVersion, s.installedVersion ?? null],
1204
+ [latch.latestVersion, s.latestVersion ?? null]
1205
+ ];
1206
+ return pairs.some(([a, b]) => a !== null && b !== null && a !== b);
1207
+ }
1032
1208
  let copyNotice = null;
1033
1209
  let noticeExpiresAt = 0;
1034
1210
  let busyAct = null;
@@ -1061,8 +1237,10 @@ function mountUpdatePanel(container, options) {
1061
1237
  queue,
1062
1238
  busyAct,
1063
1239
  skippedLatest,
1064
- lastError,
1065
- errorKind: lastErrorKind,
1240
+ lastError: latch?.code ?? null,
1241
+ errorKind: latch?.kind ?? null,
1242
+ failure: latch ? { requestId: latch.requestId, checkId: latch.checkId, atMs: latch.atMs, source: latch.source, volatile: latch.volatile } : null,
1243
+ showLogHint: showLogHintOption,
1066
1244
  changelogMarkdown,
1067
1245
  mode,
1068
1246
  showOthers,
@@ -1078,7 +1256,7 @@ function mountUpdatePanel(container, options) {
1078
1256
  container.innerHTML = nextHTML;
1079
1257
  }
1080
1258
  }
1081
- function applyStatusReply(reply) {
1259
+ function applyStatusReply(reply, via) {
1082
1260
  if (!isObject(reply)) return;
1083
1261
  if (reply["ok"] === true) {
1084
1262
  const s = asSnapshot(reply["snapshot"]);
@@ -1096,13 +1274,29 @@ function mountUpdatePanel(container, options) {
1096
1274
  if (typeof pn === "string" && pn.trim()) envProfileName = pn.trim();
1097
1275
  if (typeof hk === "string" && hk.trim()) envHostKind = hk.trim();
1098
1276
  }
1099
- lastError = null;
1100
- lastErrorKind = null;
1101
- lastDiag = Object.prototype.hasOwnProperty.call(reply, "diag") ? reply["diag"] : null;
1277
+ const jobState = snapshot?.job?.state ?? null;
1278
+ if (jobState === "installing" || jobState === "verifying") {
1279
+ clearLatch();
1280
+ } else if (jobState === "completed" || jobState === "restart-required") {
1281
+ clearLatch();
1282
+ } else if ((jobState === "failed" || jobState === "interrupted") && snapshot?.job) {
1283
+ setLatch(latchFromJob(snapshot.job, snapshot));
1284
+ } else if (via === "install") {
1285
+ clearLatch();
1286
+ } else if (snapshot && tripleChanged(snapshot)) {
1287
+ clearLatch();
1288
+ } else if (via === "check" && latch?.source === "check") {
1289
+ clearLatch();
1290
+ } else if (latch?.volatile) {
1291
+ clearLatch();
1292
+ }
1102
1293
  } else {
1103
- lastError = typeof reply["error"] === "string" ? reply["error"] : "check-failed";
1104
- lastErrorKind = typeof reply["errorKind"] === "string" && reply["errorKind"].trim() ? reply["errorKind"].trim() : null;
1105
- lastDiag = Object.prototype.hasOwnProperty.call(reply, "diag") ? reply["diag"] : null;
1294
+ const errText = typeof reply["error"] === "string" ? reply["error"].trim() : "";
1295
+ const kindText = typeof reply["errorKind"] === "string" ? reply["errorKind"].trim() : "";
1296
+ if ((kindText || errText) === "update-busy") {
1297
+ } else {
1298
+ setLatch(latchFromReply(reply, via === "install" ? "install" : "check"));
1299
+ }
1106
1300
  try {
1107
1301
  const env = reply["env"];
1108
1302
  if (isObject(env)) {
@@ -1188,12 +1382,10 @@ function mountUpdatePanel(container, options) {
1188
1382
  try {
1189
1383
  const reply = await call(phoneNames.updateStatus, queueArgs());
1190
1384
  if (!mounted) return;
1191
- applyStatusReply(reply);
1385
+ applyStatusReply(reply, "refresh");
1192
1386
  } catch {
1193
1387
  if (!mounted) return;
1194
- lastError = "check-failed";
1195
- lastErrorKind = null;
1196
- lastDiag = null;
1388
+ setLatch(volatileLatch("check"));
1197
1389
  }
1198
1390
  render();
1199
1391
  maybeAutoChangelog();
@@ -1210,13 +1402,11 @@ function mountUpdatePanel(container, options) {
1210
1402
  try {
1211
1403
  const reply = await call(phoneNames.updateCheck, queueArgs());
1212
1404
  if (!mounted) return;
1213
- applyStatusReply(reply);
1405
+ applyStatusReply(reply, "check");
1214
1406
  changelogFailedAt.clear();
1215
1407
  } catch {
1216
1408
  if (!mounted) return;
1217
- lastError = "check-failed";
1218
- lastErrorKind = null;
1219
- lastDiag = null;
1409
+ setLatch(volatileLatch("check"));
1220
1410
  } finally {
1221
1411
  busyAct = null;
1222
1412
  if (copyNotice === "\u6B63\u5728\u67E5\u65B0\u7248\u2026") copyNotice = null;
@@ -1234,13 +1424,28 @@ function mountUpdatePanel(container, options) {
1234
1424
  if (!receipt) {
1235
1425
  const checked = await call(phoneNames.updateCheck, queueArgs());
1236
1426
  if (!mounted) return;
1237
- applyStatusReply(checked);
1427
+ applyStatusReply(checked, "check");
1238
1428
  }
1239
1429
  if (!mounted) return;
1240
1430
  if (!receipt) {
1241
- lastError = "check-expired";
1242
- lastErrorKind = "check-expired";
1243
- lastDiag = null;
1431
+ const expiredEnv = currentEnvPair();
1432
+ setLatch({
1433
+ code: "check-expired",
1434
+ kind: "check-expired",
1435
+ detail: null,
1436
+ diag: null,
1437
+ requestId,
1438
+ checkId: null,
1439
+ runningVersion: snapshot?.runningVersion ?? null,
1440
+ installedVersion: snapshot?.installedVersion ?? null,
1441
+ latestVersion: snapshot?.latestVersion ?? null,
1442
+ hostKind: expiredEnv.hostKind,
1443
+ profileName: expiredEnv.profileName,
1444
+ source: "install",
1445
+ volatile: false,
1446
+ jobId: null,
1447
+ atMs: latchNow()
1448
+ });
1244
1449
  render();
1245
1450
  return;
1246
1451
  }
@@ -1251,12 +1456,10 @@ function mountUpdatePanel(container, options) {
1251
1456
  ...queueArgs()
1252
1457
  });
1253
1458
  if (!mounted) return;
1254
- applyStatusReply(reply);
1459
+ applyStatusReply(reply, "install");
1255
1460
  } catch {
1256
1461
  if (!mounted) return;
1257
- lastError = "check-failed";
1258
- lastErrorKind = null;
1259
- lastDiag = null;
1462
+ setLatch(volatileLatch("install"));
1260
1463
  } finally {
1261
1464
  busyAct = null;
1262
1465
  if (copyNotice === "\u6B63\u5728\u5B89\u88C5\u2026") copyNotice = null;
@@ -1298,25 +1501,49 @@ function mountUpdatePanel(container, options) {
1298
1501
  }
1299
1502
  case "copy-diag": {
1300
1503
  const jobCode = snapshot?.job?.state === "failed" ? messageCodeOf(snapshot.job.message) || "install-failed" : "";
1301
- const code = failureCodeOf(
1302
- { error: lastError, errorKind: lastErrorKind },
1303
- jobCode || snapshot?.blockedReason || "check-failed"
1304
- );
1305
- const detail = snapshot?.job?.message && snapshot.job.message.includes(":") ? snapshot.job.message.slice(snapshot.job.message.indexOf(":") + 1) : snapshot?.job?.message;
1504
+ if (!latch && !jobCode && !snapshot?.blockedReason && snapshot) {
1505
+ const stateLine = snapshot.canInstall && snapshot.latestVersion ? `\u6709\u65B0\u7248 ${snapshot.latestVersion} \u53EF\u88C5\uFF08\u5F53\u524D ${snapshot.runningVersion}\uFF09` : "\u5DF2\u662F\u6700\u65B0\uFF0C\u65E0\u9700\u66F4\u65B0\u3002";
1506
+ const queueName = queueTextOf(queue?.position ?? null);
1507
+ const envBits = [
1508
+ `\u63D2\u4EF6=${pluginId}`,
1509
+ `\u5BBF\u4E3B=${hostKind ?? envHostKind ?? "\u672A\u77E5"}`,
1510
+ `\u4F7F\u7528\u8303\u56F4=${profileNameOption ?? envProfileName ?? "\u672A\u77E5"}`,
1511
+ `\u961F\u5217=${queueName}`
1512
+ ];
1513
+ if (requestId) envBits.push(`\u8BF7\u6C42=${requestId}`);
1514
+ if (receipt?.checkId) envBits.push(`\u68C0\u67E5=${receipt.checkId}`);
1515
+ const segs = [
1516
+ `[update-diag] \u5F53\u524D\u65E0\u5931\u8D25\uFF1A${stateLine}`,
1517
+ `\u7248\u672C\uFF1A\u8FD0\u884C ${snapshot.runningVersion}\uFF0F\u78C1\u76D8 ${snapshot.installedVersion ?? "\u672A\u77E5"}\uFF0F\u8FDC\u7AEF ${snapshot.latestVersion ?? "\u672A\u67E5\u8FC7"}`,
1518
+ `\u6765\u6E90\uFF1A${envBits.join(" \xB7 ")}`
1519
+ ].map((s) => redactForCopy(s));
1520
+ const text2 = diagCopyFormat === "line" ? segs.join(" \xB7 ") : segs.join("\n");
1521
+ try {
1522
+ await copyText(text2);
1523
+ sayCopy("\u5DF2\u590D\u5236\u5F53\u524D\u72B6\u6001\uFF08\u65E0\u5931\u8D25\uFF09\uFF0C\u76F4\u63A5\u7C98\u7ED9\u63D2\u4EF6\u4F5C\u8005\u5373\u53EF\uFF08\u5DF2\u8131\u654F\uFF09\u3002");
1524
+ } catch {
1525
+ sayCopy("\u590D\u5236\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u9009\u4E2D\u4E0A\u9762\u7684\u4FE1\u606F\u3002");
1526
+ }
1527
+ render();
1528
+ return;
1529
+ }
1530
+ const frozen = latch;
1531
+ const code = frozen?.code ?? failureCodeOf({ error: null, errorKind: null }, jobCode || snapshot?.blockedReason || "check-failed");
1532
+ const detail = frozen?.detail ?? (snapshot?.job?.message && snapshot.job.message.includes(":") ? snapshot.job.message.slice(snapshot.job.message.indexOf(":") + 1) : snapshot?.job?.message);
1306
1533
  const text = buildUpdateDiagCopy({
1307
1534
  pluginId,
1308
1535
  code,
1309
1536
  detail,
1310
- runningVersion: snapshot?.runningVersion ?? null,
1311
- installedVersion: snapshot?.installedVersion ?? null,
1312
- latestVersion: snapshot?.latestVersion ?? null,
1313
- hostKind: hostKind ?? envHostKind,
1314
- profileName: profileNameOption ?? envProfileName,
1537
+ runningVersion: frozen?.runningVersion ?? snapshot?.runningVersion ?? null,
1538
+ installedVersion: frozen?.installedVersion ?? snapshot?.installedVersion ?? null,
1539
+ latestVersion: frozen?.latestVersion ?? snapshot?.latestVersion ?? null,
1540
+ hostKind: frozen?.hostKind ?? hostKind ?? envHostKind,
1541
+ profileName: frozen?.profileName ?? profileNameOption ?? envProfileName,
1315
1542
  queuePosition: queue?.position ?? null,
1316
- requestId,
1317
- checkId: receipt?.checkId ?? null,
1543
+ requestId: frozen?.requestId ?? requestId,
1544
+ checkId: frozen?.checkId ?? receipt?.checkId ?? null,
1318
1545
  route: null,
1319
- diag: lastDiag,
1546
+ diag: frozen?.diag ?? null,
1320
1547
  manual,
1321
1548
  format: diagCopyFormat
1322
1549
  });
@@ -1329,6 +1556,12 @@ function mountUpdatePanel(container, options) {
1329
1556
  render();
1330
1557
  return;
1331
1558
  }
1559
+ case "dismiss-failure": {
1560
+ clearLatch();
1561
+ sayCopy("\u5DF2\u786E\u8BA4\u8BE5\u5931\u8D25\u63D0\u793A\uFF1B\u4E0B\u6B21\u67E5\u65B0\u7248\u6216\u5B89\u88C5\u5C06\u91CD\u65B0\u8BC4\u4F30\u3002");
1562
+ render();
1563
+ return;
1564
+ }
1332
1565
  case "toggle-queue": {
1333
1566
  showOthers = !showOthers;
1334
1567
  await refresh();
@@ -1514,6 +1747,7 @@ export {
1514
1747
  emptyQueueState,
1515
1748
  failureCodeOf,
1516
1749
  failureCopy,
1750
+ formatLatchTime,
1517
1751
  hasVisibleSections,
1518
1752
  isHeadOfQueue,
1519
1753
  isKnownFailureCode,