dsh-remote-plugin 0.7.1 → 0.7.3

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.
@@ -645,3 +645,104 @@ input:focus-visible, select:focus-visible, textarea:focus-visible {
645
645
  .ds-overview-metrics { grid-template-columns:repeat(2,minmax(0,1fr)); }
646
646
  .ds-overview-actions .ds-btn { padding-left:5px; padding-right:5px; }
647
647
  }
648
+
649
+ /* 关于页贡献者致谢:随页面提供名单,离线可见,按贡献提交数排序。 */
650
+ .contributors-thanks { margin: 6px 0 12px; color: var(--dsr-muted); font-size: 12px; line-height: 1.6; }
651
+ .contributors-list { display: flex; flex-wrap: wrap; gap: 8px; list-style: none; margin: 0 0 10px; padding: 0; }
652
+ .contributors-list li { min-width: 0; max-width: 100%; }
653
+ .contributors-list a { display: flex; align-items: center; min-height: 44px; box-sizing: border-box; padding: 8px 12px; border: 1px solid var(--dsr-line); border-radius: 10px; background: var(--dsr-bg-2); color: var(--dsr-text); font-size: 13px; overflow-wrap: anywhere; text-decoration: none; }
654
+ .contributors-list a:hover { border-color: var(--dsr-accent-line); color: var(--dsr-accent-strong); }
655
+ .contributors-all { display: inline-flex; align-items: center; min-height: 44px; color: var(--dsr-accent-strong); font-size: 12px; text-underline-offset: 3px; }
656
+ .contributors-section a:focus-visible { outline: 2px solid var(--dsr-accent-strong); outline-offset: 3px; }
657
+
658
+ /* 会话操作统一入口;标题与工作区保持独立阅读空间。 */
659
+ .session-actions-dialog,.session-info-dialog { width:min(420px,calc(100vw - 24px)); max-height:calc(100dvh - 48px); padding:16px; border:1px solid var(--dsr-line); border-radius:18px; background:var(--dsr-bg-2); color:var(--dsr-text); overflow:auto; box-shadow:0 16px 48px var(--dsr-shadow); }
660
+ .session-actions-dialog::backdrop,.session-info-dialog::backdrop { background:var(--dsr-overlay); }
661
+ .session-dialog-head { display:flex; align-items:center; justify-content:space-between; gap:12px; margin-bottom:12px; }
662
+ .session-dialog-head button { min-width:44px; min-height:44px; color:var(--dsr-muted); font:inherit; font-size:24px; border:0; background:transparent; cursor:pointer; }
663
+ .session-actions-dialog>button { display:block; width:100%; min-height:48px; padding:12px; margin:4px 0; border:0; border-radius:10px; background:var(--dsr-panel); color:var(--dsr-text); font:inherit; text-align:left; cursor:pointer; }
664
+ .session-actions-dialog>button:hover { background:var(--dsr-accent-soft); }
665
+ .session-actions-dialog>button svg { display:none; }
666
+ .session-actions-dialog #btn-archive-session { color:var(--dsr-warning); border-top:1px solid var(--dsr-line); margin-top:12px; }
667
+ .session-info-dialog dl { margin:0 0 16px; }
668
+ .session-info-dialog dt { margin-top:14px; color:var(--dsr-muted); font-size:12px; }
669
+ .session-info-dialog dd { margin:4px 0 0; white-space:pre-wrap; overflow-wrap:anywhere; line-height:1.6; }
670
+ .session-info-dialog>button { min-height:44px; padding:8px 14px; border:1px solid var(--dsr-line); border-radius:10px; background:var(--dsr-panel); color:var(--dsr-text); font:inherit; cursor:pointer; }
671
+ .session-actions-dialog button:focus-visible,.session-info-dialog button:focus-visible { outline:2px solid var(--dsr-accent); outline-offset:2px; }
672
+
673
+ .ds-topbar { height:auto; min-height:64px; padding-top:8px; padding-bottom:8px; }
674
+ .ds-title-block { flex:1; min-width:0; }
675
+ .ds-title { display:-webkit-box; -webkit-box-orient:vertical; -webkit-line-clamp:2; width:100%; padding:0; border:0; background:transparent; color:inherit; font:inherit; font-weight:700; text-align:left; white-space:normal; overflow-wrap:anywhere; cursor:pointer; }
676
+ .ds-workspace { display:block; max-width:100%; padding:3px 0 0; border:0; background:transparent; color:var(--dsr-muted); font:inherit; font-size:11px; text-align:left; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; cursor:pointer; }
677
+ @media(max-width:720px) { .ds-top-right .ds-server { display:none; } .ds-title { font-size:14px; } }
678
+
679
+ .session-info-dialog>button:disabled { opacity:.45; cursor:default; }
680
+
681
+ /* 有界历史视图:保留消息节点,窗口外记录不参与布局。 */
682
+ .history-entry { flex:0 0 auto; min-width:0; overflow-anchor:none; display:flow-root; }
683
+ .history-page-control { flex:none; align-self:center; min-height:44px; padding:8px 14px; border:1px solid var(--dsr-line); border-radius:10px; background:var(--dsr-panel); color:var(--dsr-muted); font:inherit; cursor:pointer; }
684
+ .history-page-control[hidden],.history-live:empty { display:none; }
685
+ .history-empty { padding:24px 8px; text-align:center; color:var(--dsr-muted); }
686
+ .history-source { color:var(--dsr-muted); font-size:11px; font-weight:400; letter-spacing:0; }
687
+ .history-meta { display:flex; align-items:center; gap:8px; min-width:0; flex-wrap:wrap; justify-content:flex-end; }
688
+ .history-latest { position:absolute; right:22px; bottom:20px; z-index:8; min-height:44px; padding:8px 12px; border:1px solid var(--dsr-accent-line); border-radius:999px; color:var(--dsr-accent-strong); background:var(--dsr-bg-2); box-shadow:0 4px 16px var(--dsr-shadow); font:inherit; cursor:pointer; }
689
+
690
+ .ds-history-wrap { flex:1; min-height:0; position:relative; display:flex; }
691
+ .ds-history { overflow-anchor:none; }
692
+ #history-source { flex:none; padding:5px 22px; }
693
+
694
+ .crash-preview {margin:10px 0;font-size:13px;}
695
+ .crash-preview summary {cursor:pointer;min-height:44px;display:flex;align-items:center;}
696
+ .crash-preview pre {max-height:200px;overflow:auto;white-space:pre-wrap;overflow-wrap:anywhere;font-size:12px;padding:10px;background:var(--dsr-panel);border-radius:8px;}
697
+ /* Keep feedback fields readable and actions visible when log details expand. */
698
+ #modal-feedback .ds-modal-card { display:flex; flex-direction:column; max-height:calc(100dvh - 48px); overflow:hidden; }
699
+ #modal-feedback .ds-modal-title,#modal-feedback .ds-modal-actions { flex-shrink:0; }
700
+ #modal-feedback .ds-modal-body { min-height:0; max-height:none; overflow-y:auto; overscroll-behavior:contain; }
701
+ #modal-feedback .ds-modal-body>* { flex-shrink:0; }
702
+ #modal-feedback .ds-modal-actions .ds-btn { min-height:44px; }
703
+
704
+ /* Link instrument: persistent geometry, compositor sweep and interruptible state transitions. */
705
+ .ds-overview-pulse-card { --pulse-ease:cubic-bezier(0.23,1,0.32,1); transition:border-color 240ms ease; }
706
+ .ds-overview-pulse-copy,.ds-overview-link { position:relative; }
707
+ .ds-overview-status { line-height:1.25; min-block-size:1.25em; }
708
+ .ds-overview-status-desc { line-height:1.4; min-block-size:2.8em; }
709
+ .ds-overview-pulse-card.status-checking { border-color:var(--dsr-accent-line); }
710
+ .ds-overview-pulse-card.status-checking .ds-overview-primary-action { border-color:var(--dsr-accent-strong); background:var(--dsr-accent-strong); color:var(--dsr-on-accent); }
711
+ .ds-overview-primary-action { transition:transform 160ms var(--pulse-ease),background-color 240ms ease,border-color 240ms ease,color 240ms ease; }
712
+ .ds-system-pulse-ring { width:136px; height:136px; padding:0; background:none; box-shadow:none; isolation:isolate; flex:none; }
713
+ .ds-system-pulse-ring::before { inset:0; border:0; opacity:.7; background:repeating-conic-gradient(var(--dsr-accent-line) 0deg 1deg,transparent 1deg 15deg); -webkit-mask:radial-gradient(farthest-side,transparent calc(100% - 2px),#000 calc(100% - 1px)); mask:radial-gradient(farthest-side,transparent calc(100% - 2px),#000 calc(100% - 1px)); }
714
+ .ds-system-pulse-ring::after { content:""; position:absolute; inset:12%; border-radius:50%; box-shadow:0 0 24px var(--dsr-accent-line); opacity:.12; transform:scale(.96); transition:opacity 240ms var(--pulse-ease),transform 240ms var(--pulse-ease); pointer-events:none; }
715
+ .ds-overview-pulse-card.status-checking .ds-system-pulse-ring::after { opacity:.55; transform:scale(1); }
716
+ .ds-system-pulse-ring .pulse-dial { position:absolute; inset:0; width:100%; height:100%; overflow:visible; fill:none; stroke:var(--dsr-accent); stroke-width:2; stroke-linecap:round; }
717
+ .ds-system-pulse-ring .pulse-dial path { opacity:.15; transition:opacity 240ms var(--pulse-ease),stroke 240ms ease; }
718
+ .ds-system-pulse-ring .pulse-dial [data-confirmed="true"] { opacity:1; }
719
+ .ds-overview-pulse-card.status-nominal .ds-system-pulse-ring .pulse-dial [data-confirmed="true"] { stroke:var(--dsr-success); }
720
+ .ds-system-pulse-ring .pulse-sweep { position:absolute; inset:3%; border-radius:50%; background:conic-gradient(from 0deg,transparent 0deg 278deg,var(--dsr-accent-soft) 306deg,var(--dsr-accent) 350deg,var(--dsr-accent-strong) 358deg,transparent 360deg); -webkit-mask:radial-gradient(farthest-side,transparent calc(100% - 3px),#000 calc(100% - 2px)); mask:radial-gradient(farthest-side,transparent calc(100% - 3px),#000 calc(100% - 2px)); opacity:0; animation:overview-scan 3s linear infinite; animation-play-state:paused; transition:opacity 240ms var(--pulse-ease); pointer-events:none; }
721
+ .ds-overview-pulse-card[data-pulse-running="true"] .pulse-sweep { animation-play-state:running; }
722
+ .ds-overview-pulse-card.status-checking .pulse-sweep { opacity:1; }
723
+ .ds-system-pulse-ring .pulse-reticle { position:absolute; inset:22%; border:1px solid var(--dsr-accent-line); border-radius:50%; opacity:.6; pointer-events:none; transition:border-color 240ms ease; }
724
+ .ds-system-pulse-ring .pulse-reticle::before,.ds-system-pulse-ring .pulse-reticle::after { content:""; position:absolute; width:1px; height:5px; left:50%; background:var(--dsr-accent); opacity:.65; }
725
+ .ds-system-pulse-ring .pulse-reticle::before { top:-3px; }
726
+ .ds-system-pulse-ring .pulse-reticle::after { bottom:-3px; }
727
+ .ds-system-pulse-core { position:absolute; inset:24%; width:auto; height:auto; background:var(--dsr-bg-2); z-index:1; }
728
+ .ds-system-pulse-core strong { font-size:15px; letter-spacing:.6px; transition:color 240ms ease; }
729
+ .ds-system-pulse-core span { font-family:ui-monospace,SFMono-Regular,Consolas,monospace; font-variant-numeric:tabular-nums; font-size:9px; letter-spacing:.5px; }
730
+ .ds-overview-pulse-card.status-nominal .ds-system-pulse-core strong { color:var(--dsr-success); }
731
+ .ds-overview-link i { transition:background-color 240ms ease,box-shadow 240ms ease; }
732
+ .ds-overview-link.pending i { background:var(--dsr-accent); animation:overview-detect 2.5s ease-in-out infinite; }
733
+ .ds-overview-link:nth-child(2) i { animation-delay:-.15s; }
734
+ .ds-overview-link:nth-child(3) i { animation-delay:-.3s; }
735
+ .ds-overview-link:nth-child(4) i { animation-delay:-.45s; }
736
+ .ds-overview-link.pending b { color:var(--dsr-muted); }
737
+ .ds-overview-refresh:disabled { cursor:progress; opacity:.6; }
738
+ .pulse-text-echo { position:absolute!important; pointer-events:none; user-select:none; z-index:2; }
739
+ @keyframes overview-scan { to { transform:rotate(360deg); } }
740
+ @keyframes overview-detect { 50% { opacity:.4; } }
741
+ @media(prefers-reduced-motion:reduce) {
742
+ .ds-overview-pulse-card,.ds-overview-pulse-card .pulse-dial path,.ds-overview-pulse-card .pulse-reticle,.ds-overview-pulse-card .pulse-sweep,.ds-overview-pulse-card .ds-system-pulse-ring::after,.ds-overview-pulse-card .ds-overview-link i,.ds-overview-pulse-card .ds-system-pulse-core strong,.ds-overview-pulse-card .ds-overview-primary-action { transition:none; }
743
+ .ds-overview-pulse-card .pulse-sweep,.ds-overview-pulse-card .ds-overview-link.pending i { animation:none; }
744
+ .ds-overview-pulse-card.status-checking .pulse-sweep { opacity:.4; }
745
+ .ds-overview-pulse-card .pulse-text-echo { display:none; }
746
+ }
747
+
748
+ @media(max-width:600px) { .ds-system-pulse-ring { width:108px; height:108px; } .ds-overview-status { font-size:20px; } html[lang="en"] .ds-overview-status { min-block-size:2.5em; } }
@@ -8,6 +8,7 @@
8
8
  <link rel="stylesheet" href="../theme-vars.css">
9
9
  <link rel="stylesheet" href="desktop.css">
10
10
  <link rel="stylesheet" href="../plugin-center.css">
11
+ <link rel="stylesheet" href="../insights.css">
11
12
  </head>
12
13
  <body>
13
14
  <div class="ds-app" id="ds-app">
@@ -53,6 +54,7 @@
53
54
  </div>
54
55
  <button class="ds-nav-item" data-view="view-overview"><span class="ds-nav-ico">◌</span><span data-i18n="ds.overview">主页</span></button>
55
56
  <button class="ds-nav-item" data-view="view-files"><span class="ds-nav-ico">⇅</span><span data-i18n="ds.files">文件传输</span></button>
57
+ <button class="ds-nav-item" data-view="view-plugins"><span class="ds-nav-ico" aria-hidden="true">▦</span><span data-i18n="ds.plugins">插件</span></button>
56
58
  <button class="ds-nav-item" data-view="view-settings"><span class="ds-nav-ico"><svg class="settings-gear" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.09a2 2 0 0 1 1 1.73v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.38a2 2 0 0 0-.73-2.73l-.15-.09a2 2 0 0 1-1-1.74v-.51a2 2 0 0 1 1-1.73l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2Z"/><circle cx="12" cy="12" r="3"/></svg></span><span data-i18n="ds.settings">设置</span></button>
57
59
  <div class="ds-feedback">
58
60
  <button id="btn-feedback" class="ds-feedback-btn" aria-haspopup="menu" aria-expanded="false" data-i18n-title="ds.feedback" data-i18n-aria="ds.feedback">
@@ -102,15 +104,13 @@
102
104
  <div class="ds-main">
103
105
  <header class="ds-topbar">
104
106
  <button id="btn-mobile-nav" class="ds-icon-btn" aria-controls="ds-sidebar" aria-expanded="false" data-i18n-aria="ds.menu" data-i18n-title="ds.menu"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" aria-hidden="true"><path d="M4 6h16M4 12h16M4 18h16"/></svg></button>
105
- <div class="ds-title" id="ds-title" data-i18n="ds.sessions">会话</div>
107
+ <div class="ds-title-block"><button class="ds-title" id="ds-title" type="button" aria-haspopup="dialog" aria-controls="session-info" data-i18n="ds.sessions">会话</button><button id="ds-workspace" class="ds-workspace hidden" type="button" aria-haspopup="dialog" aria-controls="session-info"></button></div>
106
108
  <span id="ds-session-status" class="ds-session-status hidden"></span>
107
- <button id="btn-rename-session" class="ds-icon-btn hidden" data-i18n-title="ds.sessionRename" data-i18n-aria="ds.sessionRename">✎</button>
108
- <button id="btn-archive-session" class="ds-btn hidden" data-i18n="ds.sessionArchive">归档</button>
109
+
109
110
  <div class="ds-top-right">
111
+ <button id="btn-session-more" class="ds-icon-btn" type="button" aria-haspopup="dialog" aria-controls="session-actions" data-i18n-aria="ds.sessionMore" aria-label="更多操作">⋯</button>
110
112
  <span class="ds-conn" id="conn-badge" title="">●</span>
111
113
  <span class="ds-server" id="server-badge"></span>
112
- <button id="btn-donate" class="ds-icon-btn" data-i18n-aria="ds.donate" data-i18n-title="ds.donate"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 8h11v6a4 4 0 0 1-4 4H10a4 4 0 0 1-4-4Z"/><path d="M17 10h1.5a2.5 2.5 0 0 1 0 5H17M9 4c0 1 1 1.2 1 2M13 4c0 1 1 1.2 1 2M5 20h13"/></svg></button>
113
- <button id="btn-stats-top" class="ds-icon-btn" data-i18n-aria="ds.stats" data-i18n-title="ds.stats"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 19V9M12 19V5M19 19v-7M3 19h18"/></svg></button>
114
114
  </div>
115
115
  </header>
116
116
 
@@ -129,11 +129,11 @@
129
129
  <div class="ds-overview-pulse-card">
130
130
  <div class="ds-overview-pulse-copy">
131
131
  <div class="ds-overview-eyebrow" data-i18n="ds.systemPulse">系统链路</div>
132
- <div id="ds-overview-status" class="ds-overview-status" data-i18n="ds.checking">检查中…</div>
132
+ <div id="ds-overview-status" aria-live="polite" class="ds-overview-status" data-i18n="ds.checking">检查中…</div>
133
133
  <div id="ds-overview-status-desc" class="ds-overview-status-desc">—</div>
134
134
  <button id="ds-overview-primary-action" class="ds-overview-primary-action" type="button" data-i18n="ds.action.openSession">打开最近会话</button>
135
135
  </div>
136
- <div id="ds-overview-pulse-ring" class="ds-system-pulse-ring" style="--pulse-pct:0%"><div class="ds-system-pulse-core"><strong id="ds-overview-health">—</strong><span id="ds-overview-health-caption">—</span></div></div>
136
+ <div id="ds-overview-pulse-ring" class="ds-system-pulse-ring"><svg class="pulse-dial" viewBox="0 0 120 120" aria-hidden="true" focusable="false"><path data-pulse-link="gateway" data-confirmed="false" d="M 66.093 10.373 A 50 50 0 0 1 109.627 53.907"/><path data-pulse-link="dsh" data-confirmed="false" d="M 109.627 66.093 A 50 50 0 0 1 66.093 109.627"/><path data-pulse-link="mux" data-confirmed="false" d="M 53.907 109.627 A 50 50 0 0 1 10.373 66.093"/><path data-pulse-link="host" data-confirmed="false" d="M 10.373 53.907 A 50 50 0 0 1 53.907 10.373"/></svg><span class="pulse-sweep" aria-hidden="true"></span><span class="pulse-reticle" aria-hidden="true"></span><div class="ds-system-pulse-core"><strong id="ds-overview-health">—</strong><span id="ds-overview-health-caption">—</span></div></div>
137
137
  <div class="ds-overview-links">
138
138
  <div class="ds-overview-link" data-ds-overview-link="gateway"><i></i><span data-i18n="ds.gateway">网关</span><b>—</b></div>
139
139
  <div class="ds-overview-link" data-ds-overview-link="dsh"><i></i><span data-i18n="ds.dshUpstream">DSH 上游</span><b>—</b></div>
@@ -168,7 +168,8 @@
168
168
  <div id="session-cards" class="ds-session-cards"></div>
169
169
  <div id="queue-dock" class="ds-queue-dock hidden" aria-live="polite"></div>
170
170
  <section id="session-pending" class="ds-session-pending hidden" aria-live="polite"></section>
171
- <div id="history" class="ds-history" aria-live="polite"></div>
171
+ <div id="history-source" class="history-source" role="status" aria-live="polite"></div>
172
+ <div class="ds-history-wrap"><div id="history" class="ds-history"></div><button id="btn-history-latest" class="history-latest hidden" type="button" data-i18n="ds.historyLatest">回到最新</button></div>
172
173
  <div class="ds-composer">
173
174
  <div id="composer-status" class="ds-composer-status hidden" role="status" aria-live="polite"><span class="ds-composer-status-dot" aria-hidden="true"></span><span id="composer-status-text" data-i18n="ds.composerRunning">运行中…</span></div>
174
175
  <textarea id="composer" rows="1" data-i18n-placeholder="ds.composerPlaceholder" placeholder="输入消息…"></textarea>
@@ -216,10 +217,10 @@
216
217
  </section>
217
218
 
218
219
  <!-- 设置 -->
220
+ <section id="view-plugins" class="ds-view hidden"><div id="desktop-plugin-page"></div></section>
219
221
  <section id="view-settings" class="ds-view hidden">
220
222
  <div class="ds-section-label" data-i18n="ds.settings">设置</div>
221
223
  <div id="settings-home">
222
- <button type="button" id="btn-plugin-center" class="ds-setting-row ds-setting-link"><span>插件中心 · 已安装 / 发现插件</span><span>›</span></button>
223
224
  <div class="ds-settings">
224
225
  <button type="button" class="ds-setting-row ds-setting-link" data-settings-group="general">
225
226
  <div><div class="ds-setting-name" data-i18n="ds.groupGeneral">通用</div><div class="ds-setting-desc" data-i18n="ds.groupGeneralDesc">工具调用、预设提示词</div></div>
@@ -305,6 +306,20 @@
305
306
  <div><div class="ds-setting-name" data-i18n="ds.donate">赞赏支持</div><div class="ds-setting-desc" data-i18n="ds.donateDesc">如果 dsh-remote 帮到了你,欢迎赞赏支持开发 ☕</div></div>
306
307
  <span class="ds-setting-arrow" aria-hidden="true">›</span>
307
308
  </div>
309
+ <section class="ds-setting-row contributors-section" aria-labelledby="contributors-title">
310
+ <div>
311
+ <div id="contributors-title" class="ds-setting-name" data-i18n="ds.contributors">贡献者</div>
312
+ <p class="contributors-thanks" data-i18n="ds.contributorsThanks">感谢每一位让 DSH Remote 变得更好的贡献者。</p>
313
+ <!-- GitHub contributions 降序;同数量按用户名排序。更新名单时核对仓库 contributors API。 -->
314
+ <ul class="contributors-list">
315
+ <li><a href="https://github.com/Blank-not-black" target="_blank" rel="noopener noreferrer">Blank-not-black</a></li>
316
+ <li><a href="https://github.com/wikkd" target="_blank" rel="noopener noreferrer">wikkd</a></li>
317
+ <li><a href="https://github.com/anupamme" target="_blank" rel="noopener noreferrer">anupamme</a></li>
318
+ <li><a href="https://github.com/liuchang-t" target="_blank" rel="noopener noreferrer">liuchang-t</a></li>
319
+ </ul>
320
+ <a class="contributors-all" href="https://github.com/Blank-not-black/dsh-Remote/graphs/contributors" target="_blank" rel="noopener noreferrer" data-i18n="ds.contributorsAll">查看完整贡献记录 ↗</a>
321
+ </div>
322
+ </section>
308
323
  </div>
309
324
  </section>
310
325
 
@@ -345,6 +360,24 @@
345
360
  </div>
346
361
  </div>
347
362
 
363
+
364
+ <dialog id="session-actions" class="session-actions-dialog" aria-labelledby="session-actions-title">
365
+ <div class="session-dialog-head"><strong id="session-actions-title" data-i18n="ds.sessionMore">更多操作</strong><button type="button" data-session-dialog-close aria-label="关闭">×</button></div>
366
+ <button id="btn-rename-session" class="ds-icon-btn hidden" data-i18n-title="ds.sessionRename" data-i18n-aria="ds.sessionRename" data-i18n="ds.sessionRename">✎</button>
367
+ <button id="btn-insights" class="ds-icon-btn hidden" data-i18n-title="ds.insights" data-i18n-aria="ds.insights" data-i18n="ds.insights">上下文与费用</button>
368
+
369
+ <button id="btn-donate" class="ds-icon-btn" data-i18n-aria="ds.donate" data-i18n-title="ds.donate" data-i18n="ds.donate">赞赏支持</button>
370
+
371
+ <button id="btn-stats-top" class="ds-icon-btn" data-i18n-aria="ds.stats" data-i18n-title="ds.stats" data-i18n="ds.stats">统计</button>
372
+
373
+ <button id="btn-session-info" type="button" data-i18n="ds.sessionDetails">会话详情</button>
374
+ <button id="btn-archive-session" class="ds-btn hidden" data-i18n="ds.sessionArchive">归档</button>
375
+ </dialog>
376
+ <dialog id="session-info" class="session-info-dialog" aria-labelledby="session-info-title">
377
+ <div class="session-dialog-head"><strong id="session-info-title" data-i18n="ds.sessionDetails">会话详情</strong><button type="button" data-session-dialog-close aria-label="关闭">×</button></div>
378
+ <dl><dt data-i18n="ds.fullTitle">完整标题</dt><dd id="session-info-name"></dd><dt data-i18n="ds.workspace">工作区</dt><dd id="session-info-path"></dd><dt data-i18n="ds.sessionId">会话 ID</dt><dd id="session-info-id"></dd></dl>
379
+ <button id="btn-copy-session-workspace" type="button" data-i18n="ds.copyWorkspace">复制工作区路径</button>
380
+ </dialog>
348
381
  <div id="modal-rename" class="ds-modal hidden" role="dialog" aria-modal="true" aria-labelledby="rename-session-title">
349
382
  <div class="ds-modal-card">
350
383
  <div id="rename-session-title" class="ds-modal-title" data-i18n="ds.sessionRenameTitle">重命名会话</div>
@@ -371,6 +404,8 @@
371
404
  <textarea id="fb-msg" class="ds-fb-textarea" rows="5" maxlength="2000" data-i18n-placeholder="ds.feedbackMessagePlaceholder" placeholder="请描述遇到的问题或建议(必填,≤2000 字)"></textarea>
372
405
  <input id="fb-contact" class="ds-fb-input" maxlength="200" data-i18n-placeholder="ds.feedbackContactPlaceholder" placeholder="联系方式(可选):邮箱 / 微信 / B站 ID">
373
406
  <label class="ds-fb-diagnostics"><input id="fb-include-diagnostics" type="checkbox"> <span data-i18n="ds.feedbackIncludeDiagnostics">附带兼容性诊断日志(可选)</span><small data-i18n="ds.feedbackDiagnosticsPrivacy">仅上传网关/协议版本、接口失败摘要和实时链路状态;不包含令牌、Cookie、对话内容或文件路径。</small></label>
407
+ <label class="ds-fb-diagnostics"><input id="fb-include-crashes" type="checkbox"> <span data-i18n="ds.feedbackIncludeCrashes">附带崩溃日志摘要(可选)</span><small data-i18n="ds.feedbackCrashPrivacy">默认仅在本机记录。勾选后上传最近 3 条退出、重启和错误位置摘要,不含对话、密钥或完整路径。</small></label>
408
+ <details id="fb-crash-details" class="crash-preview"><summary data-i18n="ds.feedbackCrashPreview">查看拟上传的日志摘要</summary><pre id="fb-crash-preview"></pre></details>
374
409
  </div>
375
410
  <div class="ds-modal-actions">
376
411
  <button id="fb-cancel" class="ds-btn" data-i18n="ds.feedbackCancel">取消</button>
@@ -493,12 +528,13 @@
493
528
  <script>
494
529
  window.DESKTOP_STR = {
495
530
  zh: {
496
- 'ds.repo': 'GitHub 仓库', 'ds.newSession': '+ 新会话', 'ds.sessionUntitled': '新会话', 'ds.newWorkspace': '新建工作区', 'ds.sessions': '会话', 'ds.overview': '主页', 'ds.overviewEyebrow': 'SYSTEM OVERVIEW', 'ds.overviewSubtitle': '实时状态与需要你处理的事项',
497
- 'ds.systemPulse': '系统链路', 'ds.systemNominal': '系统链路正常', 'ds.systemDegraded': '部分链路需要关注', 'ds.systemOffline': '连接已断开', 'ds.checking': '检查中…', 'ds.components': '{n}/4 个模块在线', 'ds.live': 'LIVE', 'ds.allLinked': '全部链路', 'ds.offlineCore': 'OFFLINE',
531
+ 'ds.repo': 'GitHub 仓库', 'ds.newSession': '+ 新会话', 'ds.sessionUntitled': '新会话', 'ds.newWorkspace': '新建工作区', 'ds.sessionMore': '更多操作', 'ds.sessionDetails': '会话详情', 'ds.workspace': '工作区', 'ds.noWorkspace': '未关联工作区', 'ds.copyWorkspace': '复制工作区路径', 'ds.sessionId': '会话 ID', 'ds.fullTitle': '完整标题', 'ds.copied': '已复制', 'ds.sessions': '会话', 'ds.overview': '主页', 'ds.overviewEyebrow': 'SYSTEM OVERVIEW', 'ds.overviewSubtitle': '实时状态与需要你处理的事项',
532
+ 'ds.systemPulse': '系统链路', 'ds.systemNominal': '系统链路正常', 'ds.systemDegraded': '部分链路需要关注', 'ds.systemOffline': '连接已断开', 'ds.checking': '检查中…', 'ds.confirmedShort': '已确认', 'ds.checkingShort': '检测中', 'ds.autoChecking': '正在自动检测,已确认 {n}/4 项', 'ds.autoRetry': '{n}/4 项在线,将自动复查未连接的链路', 'ds.components': '{n}/4 个模块在线', 'ds.live': 'LIVE', 'ds.allLinked': '全部链路', 'ds.offlineCore': 'OFFLINE',
498
533
  'ds.gateway': '网关', 'ds.dshUpstream': 'DSH 上游', 'ds.mux': '实时 mux', 'ds.host': '实时 host', 'ds.online': '在线', 'ds.offlineShort': '离线',
499
534
  'ds.attention': '需要你处理', 'ds.runtime': '运行指标', 'ds.recentActivity': '近期活动', 'ds.dshVersion': 'DSH 版本', 'ds.gatewayStatus': '网关状态', 'ds.activeSessions': '活跃会话', 'ds.connectionMode': '连接模式', 'ds.liveWs': '实时 WS', 'ds.poll': '降级轮询', 'ds.running': '运行中', 'ds.noReason': '无说明', 'ds.noActivity': '暂无后台活动', 'ds.noSessions': '暂无会话', 'ds.refreshOverview': '刷新总览', 'ds.pendingCount': '{n} 项待处理', 'ds.activeCount': '{n} 个活跃会话', 'ds.nothingPending': '暂无事项', 'ds.action.openSession': '打开最近会话', 'ds.action.newSession': '新建会话', 'ds.action.attention': '处理待办', 'ds.action.connect': '去设置连接', 'ds.action.refresh': '重新检查连接',
500
535
  'ds.sortLabel': '会话排序', 'ds.sortTime': '按时间', 'ds.sortWorkspace': '按工作区', 'ds.workspace': '工作区', 'ds.workspaceUnknown': '未指定工作区', 'ds.wbOrderSaved': '顺序已保存到当前设备',
501
- 'ds.files': '文件传输', 'ds.settings': '设置', 'ds.stats': '统计', 'ds.menu': '导航',
536
+ 'ds.insights': '上下文与费用',
537
+ 'ds.files': '文件传输', 'ds.plugins': '插件', 'ds.settings': '设置', 'ds.stats': '统计', 'ds.menu': '导航',
502
538
  'ds.send': '发送', 'ds.composerPlaceholder': '输入消息,Enter 发送…', 'ds.composerRunning': '运行中…', 'ds.presets': '预设', 'ds.sessionRename': '重命名会话', 'ds.sessionRenameTitle': '重命名会话', 'ds.sessionRenamePlaceholder': '输入新的会话名称', 'ds.sessionRenameConfirm': '保存', 'ds.sessionRenameFailed': '重命名失败', 'ds.sessionRenameEmpty': '会话名称不能为空', 'ds.sessionRenamed': '会话名称已更新', 'ds.sessionArchive': '归档', 'ds.sessionArchiveConfirm': '归档这个会话?归档后可在“显示已归档”中打开。', 'ds.sessionArchived': '会话已归档', 'ds.sessionStop': '停止本轮', 'ds.sessionStopConfirm': '停止当前回合?排队中的消息不会被删除。', 'ds.sessionStopFailed': '停止失败', 'ds.sessionStopRequested': '已请求停止本轮', 'ds.sessionRecovering': '恢复会话中…', 'ds.sessionReady': '会话已恢复', 'ds.sessionRecoveryFailed': '会话恢复失败',
503
539
  'ds.commands': '指令',
504
540
  'ds.cmdCompact': '/compact 压缩对话历史', 'ds.cmdExport': '/export 导出会话日志 ZIP', 'ds.commandTimedOut': '命令执行超时,未作为普通消息发送', 'ds.exportStarted': '会话日志已开始下载,请在浏览器下载中查看', 'ds.exportFailed': '无法导出会话日志:{msg}', 'ds.compacting': '正在压缩对话 · 已用时 {elapsed}', 'ds.compactComplete': '对话压缩完成', 'ds.compactFailed': '对话压缩未完成:{msg}', 'ds.commandRunning': '正在执行 /{command} · 已用时 {elapsed}', 'ds.commandComplete': '/{command} 已完成', 'ds.commandFailed': '/{command} 未完成:{msg}',
@@ -510,7 +546,8 @@
510
546
  'ds.groupServers': '服务器', 'ds.groupServersDesc': '服务器地址与令牌',
511
547
  'ds.groupNotify': '通知', 'ds.groupNotifyDesc': '通知与提醒',
512
548
  'ds.groupTheme': '皮肤', 'ds.groupThemeDesc': '配色主题',
513
- 'ds.groupAbout': '关于', 'ds.groupAboutDesc': '版本信息',
549
+ 'ds.contributors': '贡献者', 'ds.contributorsThanks': '感谢每一位让 DSH Remote 变得更好的贡献者。', 'ds.contributorsAll': '查看完整贡献记录 ↗',
550
+ 'ds.groupAbout': '关于', 'ds.groupAboutDesc': '版本信息、贡献者致谢',
514
551
  'ds.donate': '赞赏支持', 'ds.donateDesc': '如果 dsh-remote 帮到了你,欢迎赞赏支持开发 ☕', 'ds.donateThanks': '感谢你的支持 ☕', 'ds.donateClose': '关闭',
515
552
  'ds.notesTitle': '更新内容', 'ds.notesClose': '关闭', 'ds.notesPage': '版本号 {current}/{total}',
516
553
  'ds.back': '‹ 返回', 'ds.emptyGroup': '暂无设置项',
@@ -521,7 +558,7 @@
521
558
  'ds.feedback': '反馈', 'ds.feedbackGithubDesc': '反馈 bug / 提建议', 'ds.feedbackGiteeDesc': '国内镜像,无需代理',
522
559
  'ds.feedbackBiliDesc': 'UP 动态页交流', 'ds.feedbackCopyLink': '复制项目链接', 'ds.feedbackCopyDesc': '手动分享给朋友',
523
560
  'ds.feedbackCopied': '项目链接已复制', 'ds.feedbackCopyFailed': '复制失败,请手动复制',
524
- 'ds.feedbackWrite': '写反馈', 'ds.feedbackWriteDesc': 'App 内直接提交', 'ds.feedbackModalTitle': '写反馈', 'ds.feedbackIncludeDiagnostics': '附带兼容性诊断日志(可选)', 'ds.feedbackDiagnosticsPrivacy': '仅上传网关/协议版本、接口失败摘要和实时链路状态;不包含令牌、Cookie、对话内容或文件路径。',
561
+ 'ds.feedbackWrite': '写反馈', 'ds.feedbackWriteDesc': 'App 内直接提交', 'ds.feedbackModalTitle': '写反馈', 'ds.feedbackIncludeDiagnostics': '附带兼容性诊断日志(可选)', 'ds.feedbackDiagnosticsPrivacy': '仅上传网关/协议版本、接口失败摘要和实时链路状态;不包含令牌、Cookie、对话内容或文件路径。', 'ds.feedbackIncludeCrashes': '附带崩溃日志摘要(可选)', 'ds.feedbackCrashPrivacy': '默认仅在本机记录。勾选后上传最近 3 条退出、重启和错误位置摘要,不含对话、密钥或完整路径。', 'ds.feedbackCrashPreview': '查看拟上传的日志摘要', 'ds.feedbackCrashLoading': '读取本机日志…', 'ds.feedbackCrashUnavailable': '当前网关暂时无法读取日志,请更新网关或稍后重试。',
525
562
  'ds.feedbackTypeBug': 'Bug', 'ds.feedbackTypeSuggestion': '建议', 'ds.feedbackTypeOther': '其他',
526
563
  'ds.feedbackMessagePlaceholder': '请描述遇到的问题或建议(必填,≤2000 字)',
527
564
  'ds.feedbackContactPlaceholder': '联系方式(可选):邮箱 / 微信 / B站 ID',
@@ -537,7 +574,7 @@
537
574
  'ds.toastSent': '已发送', 'ds.toastCopied': '令牌已复制', 'ds.toastAuth': '令牌无效',
538
575
  'ds.toastConnFailed': '连接失败', 'ds.toastOpFailed': '操作失败',
539
576
  'ds.sessionsEmpty': '暂无会话', 'ds.loading': '加载中…',
540
- 'ds.historyLoading': '加载历史…', 'ds.historyEmpty': '暂无消息',
577
+ 'ds.historyCached': '本地缓存', 'ds.historySyncing': '本地缓存 · 正在同步', 'ds.historySynced': '最新记录已同步', 'ds.historySaved': '最新记录 · 已缓存', 'ds.historyOffline': '本地记录 · 网络不可用', 'ds.historyEarlier': '加载更早的记录', 'ds.historyLoadingEarlier': '正在加载更早的记录…', 'ds.historyLatest': '回到最新', 'ds.historyCacheFailed': '已同步 · 本地缓存未保存', 'ds.historyLoading': '加载历史…', 'ds.historyEmpty': '暂无消息', 'ds.historyRetry': '重试',
541
578
  'ds.allow': '允许', 'ds.reject': '拒绝',
542
579
  'ds.approvalTitle': '工具审批', 'ds.questionNotify': '需要回答',
543
580
  'ds.approvalBody': '{tool} · {server}', 'ds.approvalReason': '原因:{reason}',
@@ -598,12 +635,13 @@
598
635
  'menu.modelTitle': '模型切换', 'menu.effortTitle': '思考深度',
599
636
  },
600
637
  en: {
601
- 'ds.repo': 'GitHub repo', 'ds.newSession': '+ New session', 'ds.sessionUntitled': 'New session', 'ds.newWorkspace': 'New workspace', 'ds.sessions': 'Sessions', 'ds.overview': 'Home', 'ds.overviewEyebrow': 'SYSTEM OVERVIEW', 'ds.overviewSubtitle': 'Live status and items needing your attention',
602
- 'ds.systemPulse': 'System pulse', 'ds.systemNominal': 'System nominal', 'ds.systemDegraded': 'Some links need attention', 'ds.systemOffline': 'Connection offline', 'ds.checking': 'Checking…', 'ds.components': '{n}/4 components online', 'ds.live': 'LIVE', 'ds.allLinked': 'ALL LINKED', 'ds.offlineCore': 'OFFLINE',
638
+ 'ds.repo': 'GitHub repo', 'ds.newSession': '+ New session', 'ds.sessionUntitled': 'New session', 'ds.newWorkspace': 'New workspace', 'ds.sessionMore': 'More actions', 'ds.sessionDetails': 'Session details', 'ds.workspace': 'Workspace', 'ds.noWorkspace': 'No workspace', 'ds.copyWorkspace': 'Copy workspace path', 'ds.sessionId': 'Session ID', 'ds.fullTitle': 'Full title', 'ds.copied': 'Copied', 'ds.sessions': 'Sessions', 'ds.overview': 'Home', 'ds.overviewEyebrow': 'SYSTEM OVERVIEW', 'ds.overviewSubtitle': 'Live status and items needing your attention',
639
+ 'ds.systemPulse': 'System pulse', 'ds.systemNominal': 'System nominal', 'ds.systemDegraded': 'Some links need attention', 'ds.systemOffline': 'Connection offline', 'ds.checking': 'Checking…', 'ds.confirmedShort': 'CONFIRMED', 'ds.checkingShort': 'Checking', 'ds.autoChecking': 'Checking automatically · {n}/4 confirmed', 'ds.autoRetry': '{n}/4 online · Automatic retry scheduled', 'ds.components': '{n}/4 components online', 'ds.live': 'LIVE', 'ds.allLinked': 'ALL LINKED', 'ds.offlineCore': 'OFFLINE',
603
640
  'ds.gateway': 'Gateway', 'ds.dshUpstream': 'DSH upstream', 'ds.mux': 'Live mux', 'ds.host': 'Live host', 'ds.online': 'Online', 'ds.offlineShort': 'Offline',
604
641
  'ds.attention': 'Needs attention', 'ds.runtime': 'Runtime metrics', 'ds.recentActivity': 'Recent activity', 'ds.dshVersion': 'DSH version', 'ds.gatewayStatus': 'Gateway status', 'ds.activeSessions': 'Active sessions', 'ds.connectionMode': 'Connection mode', 'ds.liveWs': 'Live WS', 'ds.poll': 'Degraded polling', 'ds.running': 'Running', 'ds.noReason': 'No reason given', 'ds.noActivity': 'No background activity', 'ds.noSessions': 'No sessions yet', 'ds.refreshOverview': 'Refresh overview', 'ds.pendingCount': '{n} pending', 'ds.activeCount': '{n} active sessions', 'ds.nothingPending': 'Nothing pending', 'ds.action.openSession': 'Open recent session', 'ds.action.newSession': 'New session', 'ds.action.attention': 'Review pending', 'ds.action.connect': 'Set up connection', 'ds.action.refresh': 'Check connection',
605
642
  'ds.sortLabel': 'Session sort', 'ds.sortTime': 'By time', 'ds.sortWorkspace': 'By workspace', 'ds.workspace': 'Workspace', 'ds.workspaceUnknown': 'No workspace', 'ds.wbOrderSaved': 'Order saved on this device',
606
- 'ds.files': 'Files', 'ds.settings': 'Settings', 'ds.stats': 'Stats', 'ds.menu': 'Menu',
643
+ 'ds.insights': 'Context & costs',
644
+ 'ds.files': 'Files', 'ds.plugins': 'Plugins', 'ds.settings': 'Settings', 'ds.stats': 'Stats', 'ds.menu': 'Menu',
607
645
  'ds.send': 'Send', 'ds.composerPlaceholder': 'Type a message, Enter to send…', 'ds.composerRunning': 'Running…', 'ds.presets': 'Presets', 'ds.sessionRename': 'Rename session', 'ds.sessionRenameTitle': 'Rename session', 'ds.sessionRenamePlaceholder': 'Enter a new session name', 'ds.sessionRenameConfirm': 'Save', 'ds.sessionRenameFailed': 'Rename failed', 'ds.sessionRenameEmpty': 'Session name cannot be empty', 'ds.sessionRenamed': 'Session name updated', 'ds.sessionArchive': 'Archive', 'ds.sessionArchiveConfirm': 'Archive this session? You can open it from “Show archived”.', 'ds.sessionArchived': 'Session archived', 'ds.sessionStop': 'Stop turn', 'ds.sessionStopConfirm': 'Stop the current turn? Queued messages will be kept.', 'ds.sessionStopFailed': 'Stop failed', 'ds.sessionStopRequested': 'Stop requested', 'ds.sessionRecovering': 'Restoring session…', 'ds.sessionReady': 'Session ready', 'ds.sessionRecoveryFailed': 'Session restore failed',
608
646
  'ds.commands': 'Commands',
609
647
  'ds.cmdCompact': '/compact Compress conversation history', 'ds.cmdExport': '/export Export session log ZIP', 'ds.commandTimedOut': 'Command timed out and was not sent as a chat message', 'ds.exportStarted': 'Session log download started; check your browser downloads', 'ds.exportFailed': 'Could not export session log: {msg}', 'ds.compacting': 'Compressing conversation · {elapsed} elapsed', 'ds.compactComplete': 'Conversation compression complete', 'ds.compactFailed': 'Conversation compression did not finish: {msg}', 'ds.commandRunning': 'Running /{command} · {elapsed} elapsed', 'ds.commandComplete': '/{command} complete', 'ds.commandFailed': '/{command} did not finish: {msg}',
@@ -626,7 +664,8 @@
626
664
  'ds.feedback': 'Feedback', 'ds.feedbackGithubDesc': 'Report bugs · suggest features', 'ds.feedbackGiteeDesc': 'Mirror in China, no proxy needed',
627
665
  'ds.feedbackBiliDesc': 'Chat on the UP\'s Bilibili page', 'ds.feedbackCopyLink': 'Copy project link', 'ds.feedbackCopyDesc': 'Share it manually',
628
666
  'ds.feedbackCopied': 'Project link copied', 'ds.feedbackCopyFailed': 'Copy failed, copy manually',
629
- 'ds.feedbackWrite': 'Write feedback', 'ds.feedbackWriteDesc': 'Submit from the app', 'ds.feedbackModalTitle': 'Write feedback', 'ds.feedbackIncludeDiagnostics': 'Include compatibility diagnostics (optional)', 'ds.feedbackDiagnosticsPrivacy': 'Uploads only gateway/protocol versions, interface failure summaries, and realtime status; no token, cookie, conversation content, or file path.',
667
+ 'ds.contributors': 'Contributors', 'ds.contributorsThanks': 'Thank you to everyone who helps make DSH Remote better.', 'ds.contributorsAll': 'View all contributions ↗',
668
+ 'ds.feedbackWrite': 'Write feedback', 'ds.feedbackWriteDesc': 'Submit from the app', 'ds.feedbackModalTitle': 'Write feedback', 'ds.feedbackIncludeDiagnostics': 'Include compatibility diagnostics (optional)', 'ds.feedbackDiagnosticsPrivacy': 'Uploads only gateway/protocol versions, interface failure summaries, and realtime status; no token, cookie, conversation content, or file path.', 'ds.feedbackIncludeCrashes': 'Include crash summary (optional)', 'ds.feedbackCrashPrivacy': 'Recorded locally by default. Opt in to upload up to 3 recent exit, restart and error-location records. No conversations, credentials or full paths.', 'ds.feedbackCrashPreview': 'Preview the log summary to upload', 'ds.feedbackCrashLoading': 'Reading local logs…', 'ds.feedbackCrashUnavailable': 'Logs are unavailable. Update the gateway or try again later.',
630
669
  'ds.feedbackTypeBug': 'Bug', 'ds.feedbackTypeSuggestion': 'Suggestion', 'ds.feedbackTypeOther': 'Other',
631
670
  'ds.feedbackMessagePlaceholder': 'Describe the bug or suggestion (required, ≤2000 chars)',
632
671
  'ds.feedbackContactPlaceholder': 'Contact (optional): email / WeChat / Bilibili ID',
@@ -642,7 +681,7 @@
642
681
  'ds.toastSent': 'Sent', 'ds.toastCopied': 'Token copied', 'ds.toastAuth': 'Invalid token',
643
682
  'ds.toastConnFailed': 'Connection failed', 'ds.toastOpFailed': 'Operation failed',
644
683
  'ds.sessionsEmpty': 'No sessions', 'ds.loading': 'Loading…',
645
- 'ds.historyLoading': 'Loading history…', 'ds.historyEmpty': 'No messages yet',
684
+ 'ds.historyCached': 'Local cache', 'ds.historySyncing': 'Local cache · Syncing', 'ds.historySynced': 'Latest history synced', 'ds.historySaved': 'Latest history · Cached', 'ds.historyOffline': 'Local history · Offline', 'ds.historyEarlier': 'Load earlier history', 'ds.historyLoadingEarlier': 'Loading earlier history…', 'ds.historyLatest': 'Jump to latest', 'ds.historyCacheFailed': 'Synced · Cache could not be saved', 'ds.historyLoading': 'Loading history…', 'ds.historyEmpty': 'No messages yet', 'ds.historyRetry': 'Retry',
646
685
  'ds.allow': 'Allow', 'ds.reject': 'Reject',
647
686
  'ds.approvalTitle': 'Tool approval', 'ds.questionNotify': 'Question',
648
687
  'ds.approvalBody': '{tool} · {server}', 'ds.approvalReason': 'Reason: {reason}',
@@ -712,6 +751,10 @@
712
751
  <script src="../motion.js"></script>
713
752
  <script type="module" src="../morphicons-init.js"></script>
714
753
  <script src="../plugin-center.js"></script>
754
+ <script src="../insights.js"></script>
755
+ <script src="../sha256.js"></script>
756
+ <script src="../history.js"></script>
757
+ <script src="../link-check.js"></script>
715
758
  <script src="desktop.js"></script>
716
759
  </body>
717
760
  </html>