dsh-remote-panel 0.3.8 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/lib/client.js +83 -44
  2. package/package.json +1 -1
package/lib/client.js CHANGED
@@ -1174,52 +1174,35 @@ window.__ModuleLoader__.load({
1174
1174
  问候语留在屏幕中间(原生居中),输入条钉到底部 */
1175
1175
  /* 输入条下方那排统计(轮次/步数、token、缓存):手机上会撑高输入区,
1176
1176
  按「托盘状态」的思路挪到右上角,做成一行半透明小字,不再占输入条的垂直空间 */
1177
- .uV2eYG_dock {
1178
- position: fixed !important;
1179
- /* 托盘放在顶部安全区里(刘海那一条),靠右、避开「+」按钮:
1180
- 有安全区时就在安全区中线上,没有时贴着顶栏右边 */
1181
- top: max(2px, calc(var(--dsh-safe-top, 0px) - 28px)) !important;
1182
- /* 有安全区时右移贴近屏幕边(此时不会和「+」同高),没有时让开「+」 */
1183
- right: calc(58px - min(48px, var(--dsh-safe-top, 0px))) !important;
1184
- left: auto !important;
1185
- width: auto !important;
1186
- max-width: calc(100vw - 72px) !important;
1187
- display: flex !important;
1188
- flex-wrap: nowrap !important;
1189
- align-items: center !important;
1190
- column-gap: 8px !important;
1191
- margin: 0 !important;
1192
- padding: 3px 9px !important;
1193
- border-radius: 999px !important;
1194
- background: rgba(18, 18, 20, .92) !important;
1195
- box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .08) !important;
1196
- box-sizing: border-box !important;
1197
- font-size: 10.5px !important;
1198
- line-height: 15px !important;
1199
- z-index: 56 !important;
1200
- overflow: hidden !important;
1201
- transform: none !important;
1202
- }
1203
- /* 前两颗外面那层是 display:contents,Chrome 里不参与 flex 计算,实体化才能并排 */
1204
- .uV2eYG_dock > div {
1205
- display: flex !important;
1206
- align-items: center !important;
1207
- gap: 8px !important;
1208
- min-width: 0 !important;
1177
+ /* 原生的统计条藏在输入条下方、文案又长,手机上只能挤;这里整体隐藏,
1178
+ 由 installStatsTray() 读它的文本、精简后放到顶部右上角 */
1179
+ .uV2eYG_dock { display: none !important; }
1180
+
1181
+ /* 顶部状态条:左边分支、右边统计,两端对齐(像手机状态栏的左右两组) */
1182
+ .dsh-stats-tray {
1183
+ position: fixed;
1184
+ top: max(2px, calc(var(--dsh-safe-top, 0px) - 24px));
1185
+ left: 14px;
1186
+ right: 14px;
1187
+ z-index: 57;
1188
+ display: flex;
1189
+ align-items: center;
1190
+ justify-content: space-between;
1191
+ gap: 16px;
1192
+ font-size: 10px;
1193
+ line-height: 16px;
1194
+ font-variant-numeric: tabular-nums;
1195
+ color: rgba(255, 255, 255, .5);
1196
+ pointer-events: none;
1197
+ letter-spacing: .01em;
1209
1198
  }
1210
- .uV2eYG_dock [data-composer-stat] { min-width: 0 !important; }
1211
- /* 胶囊里的 label 自带 max-width,会被截成「2 轮 8 步 · 211 …」;托盘里放开 */
1212
- .uV2eYG_dock [class*="_label"] {
1213
- max-width: none !important;
1214
- overflow: visible !important;
1215
- text-overflow: clip !important;
1216
- white-space: nowrap !important;
1199
+ .dsh-stats-tray > span {
1200
+ overflow: hidden;
1201
+ text-overflow: ellipsis;
1202
+ white-space: nowrap;
1203
+ min-width: 0;
1217
1204
  }
1218
- /* 托盘只留两项:轮次/步数 + token/缓存;分支与占比收掉(面板里可见) */
1219
- [data-composer-stat="git-branch"] { display: none !important; }
1220
- .uV2eYG_dock > span[class*="_root"] { display: none !important; }
1221
- /* 没有统计时不渲染空壳(hero 页就是这样) */
1222
- .uV2eYG_dock:empty { display: none !important; }
1205
+ .dsh-stats-tray > span:last-child { text-align: right; flex: 0 0 auto; }
1223
1206
 
1224
1207
  /* 输入条座位顶部有一段渐隐(DSH 原本渐到 #151517),在纯黑底上会显出一条灰带,
1225
1208
  这里把终点色换成纯黑,观感才对得上;底部那行状态(轮次/token/缓存)同理 */
@@ -1708,6 +1691,60 @@ window.__ModuleLoader__.load({
1708
1691
  }
1709
1692
 
1710
1693
 
1694
+ /**
1695
+ * 顶部统计托盘:DSH 的统计条文案太长(「2 轮 8 步 · 211 tok/s」「1.7M tok · 缓存命中 99%」),
1696
+ * 手机上一行放不下。这里读它的文本、精简成 `2 轮 · 211 tok/s · 缓存 99%` 放到右上角,
1697
+ * 原条隐藏,既省高度又不挤。
1698
+ */
1699
+ function installStatsTray() {
1700
+ if (typeof document === 'undefined' || typeof MutationObserver === 'undefined') return () => {}
1701
+ const tray = document.createElement('div')
1702
+ tray.className = 'dsh-stats-tray'
1703
+ tray.setAttribute('aria-hidden', 'true')
1704
+ const left = document.createElement('span')
1705
+ const right = document.createElement('span')
1706
+ tray.append(left, right)
1707
+ document.body.appendChild(tray)
1708
+
1709
+ let frame = 0
1710
+ let shown = ''
1711
+ const format = (text) => {
1712
+ const rounds = text.match(/(\d+)\s*轮/)
1713
+ const speed = text.match(/([\d.]+)\s*tok\/s/i)
1714
+ const cache = text.match(/(\d+(?:\.\d+)?)\s*%/)
1715
+ const parts = []
1716
+ if (rounds !== null) parts.push(`${rounds[1]} 轮`)
1717
+ if (speed !== null) parts.push(`${speed[1]} tok/s`)
1718
+ if (cache !== null) parts.push(`缓存 ${cache[1]}%`)
1719
+ return parts.join(' · ')
1720
+ }
1721
+ const sync = () => {
1722
+ frame = 0
1723
+ const dock = document.querySelector('.uV2eYG_dock')
1724
+ const raw = dock?.textContent ?? ''
1725
+ const branch = dock?.querySelector('[data-composer-stat="git-branch"]')?.textContent?.trim() ?? ''
1726
+ const stats = raw.trim() === '' ? '' : format(raw)
1727
+ const next = `${branch}|${stats}`
1728
+ if (next === shown) return
1729
+ shown = next
1730
+ left.textContent = branch
1731
+ right.textContent = stats
1732
+ tray.style.display = branch === '' && stats === '' ? 'none' : 'flex'
1733
+ }
1734
+ const schedule = () => {
1735
+ if (frame !== 0) return
1736
+ frame = requestAnimationFrame(sync)
1737
+ }
1738
+ const observer = new MutationObserver(schedule)
1739
+ observer.observe(document.body, { subtree: true, childList: true, characterData: true })
1740
+ sync()
1741
+ return () => {
1742
+ observer.disconnect()
1743
+ if (frame !== 0) cancelAnimationFrame(frame)
1744
+ tray.remove()
1745
+ }
1746
+ }
1747
+
1711
1748
  /**
1712
1749
  * 外壳挂点自检:DSH 升级后这些 hash 类名可能全变,样式就整体失配。
1713
1750
  * 启动后检查一遍 DOM,把结果报给宿主,面板里能直接看到「外壳适配」这盏灯。
@@ -2349,6 +2386,7 @@ window.__ModuleLoader__.load({
2349
2386
  const cleanupFocus = installComposerFocusGuard()
2350
2387
  const cleanupFps = installFpsMeter()
2351
2388
  const cleanupContract = installShellContractReport()
2389
+ const cleanupTray = installStatsTray()
2352
2390
  if (typeof ctx.effect === 'function') ctx.effect(() => cleanupClear, 'remote-panel: workspace clear')
2353
2391
  if (typeof ctx.effect === 'function') ctx.effect(() => cleanupBack, 'remote-panel: back gesture')
2354
2392
  if (typeof ctx.effect === 'function') ctx.effect(() => cleanupAttention, 'remote-panel: attention')
@@ -2357,6 +2395,7 @@ window.__ModuleLoader__.load({
2357
2395
  if (typeof ctx.effect === 'function') ctx.effect(() => cleanupFocus, 'remote-panel: composer focus guard')
2358
2396
  if (typeof ctx.effect === 'function') ctx.effect(() => cleanupFps, 'remote-panel: fps meter')
2359
2397
  if (typeof ctx.effect === 'function') ctx.effect(() => cleanupContract, 'remote-panel: shell contract report')
2398
+ if (typeof ctx.effect === 'function') ctx.effect(() => cleanupTray, 'remote-panel: stats tray')
2360
2399
  if (typeof ctx.effect === 'function') ctx.effect(() => cleanup, 'remote-panel: mobile shell css')
2361
2400
 
2362
2401
  ctx.slots.inject('shell.overlay', () =>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-remote-panel",
3
- "version": "0.3.8",
3
+ "version": "0.4.0",
4
4
  "description": "DSH 远程访问控制面:部署向导、状态面板与一键配对(EasyTier + Caddy),数据面保持进程外。",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",