dsh-skin-galactic-opera 0.1.0 → 0.1.2
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/CHANGELOG.md +18 -0
- package/README.md +28 -9
- package/lib/client.js +281 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this package will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## 0.1.2 - 2026-08-27
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Keeps model/context popovers above the skin overlay layer.
|
|
10
|
+
- Prevents the telemetry mirror from treating input-bar buttons, popovers, listboxes, and menus as telemetry sources.
|
|
11
|
+
|
|
12
|
+
## 0.1.1 - 2026-08-27
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- Bottom-right HUD telemetry panel that mirrors global DSH session status in a fixed five-line layout: rounds/steps, LLM/tool time, first-token average and throughput, cache hit rate, and input/output token usage.
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- Preserves pipe-separated telemetry segments as complete information blocks.
|
|
21
|
+
- Filters nearby message-level timing and settings/menu text from the telemetry panel.
|
|
22
|
+
|
|
5
23
|
## 0.1.0 - 2026-08-27
|
|
6
24
|
|
|
7
25
|
Initial public package version.
|
package/README.md
CHANGED
|
@@ -24,20 +24,47 @@ This package does not include or recreate any official franchise logos, characte
|
|
|
24
24
|
- Subtle mouse parallax.
|
|
25
25
|
- Click energy pulse.
|
|
26
26
|
- Hover energy outlines on buttons, inputs, messages, and code blocks.
|
|
27
|
+
- Bottom telemetry/status information is mirrored into a fixed bottom-right sci-fi panel.
|
|
27
28
|
- Scanner target dot projected from the pointer direction relative to the viewport center; the target lights only when the scanner sweep passes it.
|
|
28
29
|
- Automatic hyperspace burst after submitting a new instruction or message.
|
|
29
30
|
- Respects `prefers-reduced-motion: reduce` by disabling major animations.
|
|
30
31
|
|
|
32
|
+
## Telemetry panel
|
|
33
|
+
|
|
34
|
+
When DSH Web exposes bottom status/usage data, the skin keeps the original UI layout in place and mirrors the detected global telemetry into a non-interactive bottom-right HUD panel. The panel is intended to show a consistent five-line status block:
|
|
35
|
+
|
|
36
|
+
```text
|
|
37
|
+
312 轮 · 8732 步
|
|
38
|
+
LLM 2253m42s · 工具调用 972m8s
|
|
39
|
+
首 token 平均 10.5s · 58 tok/s
|
|
40
|
+
缓存命中 97%
|
|
41
|
+
输入 1369M tok · 输出 2.5M tok
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The skin treats each original pipe-separated bottom-bar segment as a complete information block, so combined items such as `首 token 平均 ... · ... tok/s` and `输入 ... · 输出 ...` remain intact. It also filters nearby message-level timing text and settings/menu text so the panel stays focused on global session telemetry.
|
|
45
|
+
|
|
31
46
|
## Installation
|
|
32
47
|
|
|
33
48
|
### From npm
|
|
34
49
|
|
|
35
|
-
|
|
50
|
+
Recommended for most users:
|
|
36
51
|
|
|
37
52
|
```powershell
|
|
38
53
|
dsh plugin --profile web add dsh-skin-galactic-opera
|
|
39
54
|
```
|
|
40
55
|
|
|
56
|
+
npm package page:
|
|
57
|
+
|
|
58
|
+
```text
|
|
59
|
+
https://www.npmjs.com/package/dsh-skin-galactic-opera
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### From GitHub
|
|
63
|
+
|
|
64
|
+
```powershell
|
|
65
|
+
dsh plugin --profile web add https://github.com/xmnathan/dsh-skin-galactic-opera.git
|
|
66
|
+
```
|
|
67
|
+
|
|
41
68
|
### From a local checkout
|
|
42
69
|
|
|
43
70
|
From the parent directory of this package:
|
|
@@ -111,14 +138,6 @@ dsh-skin-galactic-opera/
|
|
|
111
138
|
- `lib/index.js`: host-side no-op entry.
|
|
112
139
|
- `lib/client.js`: browser-side theme, decoration, and interaction implementation.
|
|
113
140
|
|
|
114
|
-
## GitHub topics
|
|
115
|
-
|
|
116
|
-
Recommended repository topics:
|
|
117
|
-
|
|
118
|
-
```text
|
|
119
|
-
dsh deepseek-harness dsh-plugin dsh-skin dsh-theme space-opera sci-fi dark-theme hud web-ui
|
|
120
|
-
```
|
|
121
|
-
|
|
122
141
|
## License
|
|
123
142
|
|
|
124
143
|
MIT
|
package/lib/client.js
CHANGED
|
@@ -148,6 +148,10 @@ body.dsh-skin-galactic-opera [class*="Frame"] {
|
|
|
148
148
|
background-color: transparent !important;
|
|
149
149
|
}
|
|
150
150
|
|
|
151
|
+
body.dsh-skin-galactic-opera :is([role="dialog"], [role="menu"], [role="listbox"], [role="tooltip"], [popover], [data-radix-popper-content-wrapper]) {
|
|
152
|
+
z-index: 2147483647 !important;
|
|
153
|
+
}
|
|
154
|
+
|
|
151
155
|
body.dsh-skin-galactic-opera [class*="sidebar"],
|
|
152
156
|
body.dsh-skin-galactic-opera [class*="Sidebar"] {
|
|
153
157
|
background:
|
|
@@ -619,6 +623,100 @@ body.dsh-skin-galactic-opera * {
|
|
|
619
623
|
scrollbar-color: rgba(125, 227, 255, 0.42) rgba(5, 7, 17, 0.40);
|
|
620
624
|
}
|
|
621
625
|
|
|
626
|
+
body.dsh-skin-galactic-opera .dsh-skin-telemetry-source-hidden {
|
|
627
|
+
opacity: 0 !important;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
body.dsh-skin-galactic-opera .dsh-skin-telemetry-panel[hidden] {
|
|
631
|
+
display: none !important;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
body.dsh-skin-galactic-opera .dsh-skin-telemetry-panel {
|
|
635
|
+
position: fixed;
|
|
636
|
+
right: max(18px, 2.4vmin);
|
|
637
|
+
bottom: max(18px, 2.4vmin);
|
|
638
|
+
z-index: 2147483644;
|
|
639
|
+
display: flex;
|
|
640
|
+
flex-direction: column;
|
|
641
|
+
gap: 4px;
|
|
642
|
+
width: min(260px, 36vw);
|
|
643
|
+
max-height: none;
|
|
644
|
+
overflow: visible;
|
|
645
|
+
padding: 19px 12px 12px;
|
|
646
|
+
border: 1px solid rgba(125,227,255,0.48);
|
|
647
|
+
border-left-color: rgba(255,207,92,0.62);
|
|
648
|
+
border-bottom-color: rgba(255,71,120,0.36);
|
|
649
|
+
clip-path: polygon(14px 0, 100% 0, 100% calc(100% - 13px), calc(100% - 13px) 100%, 0 100%, 0 14px);
|
|
650
|
+
color: rgba(248,251,255,0.92);
|
|
651
|
+
background:
|
|
652
|
+
linear-gradient(135deg, rgba(255,207,92,0.20) 0 10px, transparent 11px),
|
|
653
|
+
linear-gradient(315deg, rgba(125,227,255,0.18) 0 12px, transparent 13px),
|
|
654
|
+
linear-gradient(180deg, rgba(6,10,26,0.92), rgba(10,17,42,0.84));
|
|
655
|
+
box-shadow:
|
|
656
|
+
inset 0 0 0 1px rgba(255,255,255,0.07),
|
|
657
|
+
inset 0 0 24px rgba(125,227,255,0.09),
|
|
658
|
+
0 0 28px rgba(125,227,255,0.22),
|
|
659
|
+
0 0 52px rgba(255,71,120,0.10);
|
|
660
|
+
backdrop-filter: blur(12px) saturate(1.35);
|
|
661
|
+
-webkit-backdrop-filter: blur(12px) saturate(1.35);
|
|
662
|
+
pointer-events: none;
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
body.dsh-skin-galactic-opera .dsh-skin-telemetry-panel::before {
|
|
666
|
+
content: "TELEMETRY";
|
|
667
|
+
position: absolute;
|
|
668
|
+
left: 14px;
|
|
669
|
+
top: 5px;
|
|
670
|
+
color: rgba(255,207,92,0.82);
|
|
671
|
+
font: 800 8px/1 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
672
|
+
letter-spacing: 0.20em;
|
|
673
|
+
text-shadow: 0 0 10px rgba(255,207,92,0.42);
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
body.dsh-skin-galactic-opera .dsh-skin-telemetry-panel::after {
|
|
677
|
+
content: "";
|
|
678
|
+
position: absolute;
|
|
679
|
+
inset: 4px;
|
|
680
|
+
border: 1px solid rgba(125,227,255,0.16);
|
|
681
|
+
clip-path: polygon(11px 0, 100% 0, 100% calc(100% - 10px), calc(100% - 10px) 100%, 0 100%, 0 11px);
|
|
682
|
+
background:
|
|
683
|
+
repeating-linear-gradient(90deg, transparent 0 18px, rgba(125,227,255,0.045) 19px, transparent 20px 36px),
|
|
684
|
+
linear-gradient(90deg, rgba(125,227,255,0.10), transparent 30%, rgba(255,71,120,0.06));
|
|
685
|
+
pointer-events: none;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
body.dsh-skin-galactic-opera .dsh-skin-telemetry-row {
|
|
689
|
+
position: relative;
|
|
690
|
+
z-index: 1;
|
|
691
|
+
display: flex;
|
|
692
|
+
flex-direction: row;
|
|
693
|
+
align-items: baseline;
|
|
694
|
+
justify-content: flex-start;
|
|
695
|
+
gap: 0;
|
|
696
|
+
min-width: 0;
|
|
697
|
+
padding: 3px 0 3px 9px;
|
|
698
|
+
border-left: 2px solid rgba(125,227,255,0.46);
|
|
699
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
700
|
+
text-shadow: 0 0 10px rgba(125,227,255,0.30);
|
|
701
|
+
white-space: nowrap;
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
|
|
705
|
+
body.dsh-skin-galactic-opera .dsh-skin-telemetry-value {
|
|
706
|
+
flex: 0 0 auto;
|
|
707
|
+
color: rgba(248,251,255,0.96);
|
|
708
|
+
font-size: 10.5px;
|
|
709
|
+
line-height: 1.25;
|
|
710
|
+
letter-spacing: 0.035em;
|
|
711
|
+
text-align: right;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
body.dsh-skin-galactic-opera .dsh-skin-telemetry-value-full {
|
|
715
|
+
flex: 1 1 auto;
|
|
716
|
+
text-align: left;
|
|
717
|
+
white-space: nowrap;
|
|
718
|
+
}
|
|
719
|
+
|
|
622
720
|
@keyframes dsh-skin-stars-drift {
|
|
623
721
|
from { transform: translate3d(0, 0, 0); }
|
|
624
722
|
to { transform: translate3d(-115px, 115px, 0); }
|
|
@@ -957,6 +1055,187 @@ body.dsh-skin-galactic-opera * {
|
|
|
957
1055
|
};
|
|
958
1056
|
}
|
|
959
1057
|
|
|
1058
|
+
function installTelemetryPanel() {
|
|
1059
|
+
if (typeof document === "undefined" || typeof window === "undefined") return () => {};
|
|
1060
|
+
const telemetryPattern = /(?:\d[\d.,KkMm%/]*\s*轮\s*[·•]?\s*\d[\d.,KkMm%/]*\s*步)|(?:\d[\d.,KkMm%/]*\s*(?:rounds?|turns?)\s*[·•]?\s*\d[\d.,KkMm%/]*\s*steps?)|LLM\b|工具调用|(?:首\s*)?(?:token|tokens|tok|toks)\s*平均|(?:token|tokens|tok|toks)\/s|缓存命中|缓存|cache\b|cached\b|输入|输出|prompt\b|completion\b/i;
|
|
1061
|
+
const skipSelector = `#${DECOR_ID}, style, script, textarea, input, select, button, [role=button], [aria-haspopup], [contenteditable=true], [role=dialog], [role=menu], [role=listbox], [role=tooltip], [popover], .dsh-skin-pulse, .dsh-skin-telemetry-panel`;
|
|
1062
|
+
const editableDescendantSelector = "textarea, input, select, [contenteditable=true]";
|
|
1063
|
+
let currentSources = new Set();
|
|
1064
|
+
let lastText = "";
|
|
1065
|
+
let frame = 0;
|
|
1066
|
+
const panel = document.createElement("div");
|
|
1067
|
+
panel.className = "dsh-skin-telemetry-panel";
|
|
1068
|
+
panel.setAttribute("aria-hidden", "true");
|
|
1069
|
+
panel.hidden = true;
|
|
1070
|
+
document.body.appendChild(panel);
|
|
1071
|
+
const isSkippable = (element) => element.closest(skipSelector) !== null;
|
|
1072
|
+
const hasEditableDescendant = (element) => element.querySelector(editableDescendantSelector) !== null;
|
|
1073
|
+
const getTelemetryText = (element) => (element.innerText || element.textContent || "").replace(/\s+/g, " ").trim();
|
|
1074
|
+
const scoreCandidate = (element) => {
|
|
1075
|
+
if (!(element instanceof HTMLElement) || isSkippable(element) || hasEditableDescendant(element)) return 0;
|
|
1076
|
+
const rect = element.getBoundingClientRect();
|
|
1077
|
+
const compactBottomBar = rect.height <= 46 && rect.width <= window.innerWidth && rect.bottom > window.innerHeight - 150;
|
|
1078
|
+
if (rect.width < 12 || rect.height < 8 || (!compactBottomBar && rect.width > Math.min(620, window.innerWidth * 0.72)) || rect.height > 86) return 0;
|
|
1079
|
+
if (rect.bottom < window.innerHeight - 170) return 0;
|
|
1080
|
+
const text = getTelemetryText(element);
|
|
1081
|
+
if (text.length < 2 || text.length > 360 || !telemetryPattern.test(text) || !/\d/.test(text)) return 0;
|
|
1082
|
+
if (/设置\s+设置\s+通用设置|Cmd\/Ctrl\+Enter|使用另一行|排队发送|Agent\s+预设/i.test(text)) return 0;
|
|
1083
|
+
let score = compactBottomBar ? 4 : 1;
|
|
1084
|
+
if (rect.bottom > window.innerHeight - 72) score += 3;
|
|
1085
|
+
if (rect.right > window.innerWidth * 0.45) score += 1;
|
|
1086
|
+
if (/token|tokens|tok|toks/i.test(text)) score += 3;
|
|
1087
|
+
if (/调用|消耗|上下文|usage|context|缓存|命中|输入|输出/i.test(text)) score += 2;
|
|
1088
|
+
if (/轮次|轮|步骤|步数|步|steps?|rounds?|turns?/i.test(text)) score += 2;
|
|
1089
|
+
if (/[·•|;;]/.test(text)) score += 2;
|
|
1090
|
+
if (/button|input|textarea|select/i.test(element.tagName)) score -= 4;
|
|
1091
|
+
return score;
|
|
1092
|
+
};
|
|
1093
|
+
const chooseTelemetryElements = () => {
|
|
1094
|
+
const xs = [0.10, 0.22, 0.34, 0.46, 0.58, 0.70, 0.82, 0.94];
|
|
1095
|
+
const ys = [18, 38, 62, 90, 122, 150];
|
|
1096
|
+
const candidates = new Map();
|
|
1097
|
+
for (const xRatio of xs) for (const yOffset of ys) {
|
|
1098
|
+
const x = window.innerWidth * xRatio;
|
|
1099
|
+
const y = window.innerHeight - yOffset;
|
|
1100
|
+
if (y < 0) continue;
|
|
1101
|
+
for (const base of document.elementsFromPoint(x, y)) {
|
|
1102
|
+
let element = base;
|
|
1103
|
+
for (let depth = 0; element instanceof HTMLElement && depth < 8; depth += 1, element = element.parentElement) {
|
|
1104
|
+
const score = scoreCandidate(element);
|
|
1105
|
+
if (score > 0) candidates.set(element, Math.max(candidates.get(element) ?? 0, score));
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
return [...candidates]
|
|
1110
|
+
.sort(([a, aScore], [b, bScore]) => {
|
|
1111
|
+
if (bScore !== aScore) return bScore - aScore;
|
|
1112
|
+
const ar = a.getBoundingClientRect();
|
|
1113
|
+
const br = b.getBoundingClientRect();
|
|
1114
|
+
return ar.top - br.top || ar.left - br.left;
|
|
1115
|
+
})
|
|
1116
|
+
.filter(([element], index, entries) => !entries.slice(0, index).some(([selected]) => selected.contains(element) || element.contains(selected)))
|
|
1117
|
+
.slice(0, 10)
|
|
1118
|
+
.map(([element]) => element)
|
|
1119
|
+
.sort((a, b) => {
|
|
1120
|
+
const ar = a.getBoundingClientRect();
|
|
1121
|
+
const br = b.getBoundingClientRect();
|
|
1122
|
+
return ar.top - br.top || ar.left - br.left;
|
|
1123
|
+
});
|
|
1124
|
+
};
|
|
1125
|
+
const splitTelemetryRows = (text) => {
|
|
1126
|
+
const normalized = text
|
|
1127
|
+
.replace(/\s*([|;;])\s*/g, " | ")
|
|
1128
|
+
.replace(/\s*([·•])\s*/g, " $1 ")
|
|
1129
|
+
.replace(/\s{2,}/g, " ")
|
|
1130
|
+
.trim();
|
|
1131
|
+
const hasExplicitBlocks = /[|;;]/.test(normalized);
|
|
1132
|
+
const strongParts = normalized.split(/\s+\|\s+|\s*;\s*|\s*;\s*/).map((part) => part.trim()).filter(Boolean);
|
|
1133
|
+
const labelBoundary = /\s+(?=(?:LLM\b|工具调用|缓存命中|缓存|命中|模型|费用|上下文|输入|context\b|usage\b|model\b|cost\b|cache\b|cached\b|prompt\b))/gi;
|
|
1134
|
+
const parts = hasExplicitBlocks ? strongParts : strongParts.flatMap((part) => part
|
|
1135
|
+
.replace(labelBoundary, " | ")
|
|
1136
|
+
.split(/\s+\|\s+/)
|
|
1137
|
+
.map((item) => item.trim())
|
|
1138
|
+
.filter(Boolean));
|
|
1139
|
+
const rows = [];
|
|
1140
|
+
const isRoundOnly = (value) => /^[\d.,KkMm%/]+\s*(?:轮|rounds?|turns?)$/i.test(value);
|
|
1141
|
+
const isStepOnly = (value) => /^[\d.,KkMm%/]+\s*(?:步|steps?)$/i.test(value);
|
|
1142
|
+
const isFirstTokenPrefix = (value) => /^首$/i.test(value);
|
|
1143
|
+
const isTokenAverage = (value) => /^(?:首\s*)?(?:token|tokens|tok|toks)\s*平均(?:\s|[::]|\d|$)/i.test(value);
|
|
1144
|
+
const isTokenSpeedUnit = (value) => /^(?:token|tokens|tok|toks)\/s$/i.test(value);
|
|
1145
|
+
const isInputOnly = (value) => /^(?:输入|prompt\b)/i.test(value);
|
|
1146
|
+
const isOutputOnly = (value) => /^(?:输出|completion\b)/i.test(value);
|
|
1147
|
+
const isTelemetryRow = (value) => {
|
|
1148
|
+
if (!/\d/.test(value)) return false;
|
|
1149
|
+
if (/^\d{1,2}:\d{2}\b|\b\d{1,2}:\d{2}\b\s*[·•]|用时|发送|排队|Cmd\/Ctrl/i.test(value)) return false;
|
|
1150
|
+
return /(?:\d[\d.,KkMm%/]*\s*轮\s*[·•]?\s*\d[\d.,KkMm%/]*\s*步)|(?:\d[\d.,KkMm%/]*\s*(?:rounds?|turns?)\s*[·•]?\s*\d[\d.,KkMm%/]*\s*steps?)|^LLM\b|^工具调用|^(?:首\s*)?(?:token|tokens|tok|toks)\s*平均(?:\s|[::]|\d|$)|^(?:缓存命中|缓存|cache\b|cached\b)|^(?:输入|输出|prompt\b|completion\b)/i.test(value);
|
|
1151
|
+
};
|
|
1152
|
+
for (let index = 0; index < parts.length; index += 1) {
|
|
1153
|
+
const part = parts[index];
|
|
1154
|
+
const next = parts[index + 1];
|
|
1155
|
+
const afterNext = parts[index + 2];
|
|
1156
|
+
if (next !== undefined && isFirstTokenPrefix(part) && isTokenAverage(next)) {
|
|
1157
|
+
if (afterNext !== undefined && isTokenSpeedUnit(afterNext)) {
|
|
1158
|
+
rows.push(`${part} ${next} ${afterNext}`);
|
|
1159
|
+
index += 2;
|
|
1160
|
+
} else {
|
|
1161
|
+
rows.push(`${part} ${next}`);
|
|
1162
|
+
index += 1;
|
|
1163
|
+
}
|
|
1164
|
+
continue;
|
|
1165
|
+
}
|
|
1166
|
+
if (next !== undefined && isTokenAverage(part) && isTokenSpeedUnit(next)) {
|
|
1167
|
+
rows.push(`${part} ${next}`);
|
|
1168
|
+
index += 1;
|
|
1169
|
+
continue;
|
|
1170
|
+
}
|
|
1171
|
+
if (next !== undefined && isRoundOnly(part) && isStepOnly(next)) {
|
|
1172
|
+
rows.push(`${part} · ${next}`);
|
|
1173
|
+
index += 1;
|
|
1174
|
+
continue;
|
|
1175
|
+
}
|
|
1176
|
+
if (next !== undefined && isInputOnly(part) && isOutputOnly(next)) {
|
|
1177
|
+
rows.push(`${part} · ${next}`);
|
|
1178
|
+
index += 1;
|
|
1179
|
+
continue;
|
|
1180
|
+
}
|
|
1181
|
+
rows.push(part);
|
|
1182
|
+
}
|
|
1183
|
+
const firstMatch = (predicate) => rows.find((row) => isTelemetryRow(row) && predicate(row));
|
|
1184
|
+
const roundRow = firstMatch((row) => /(?:\d[\d.,KkMm%/]*\s*轮\s*[·•]?\s*\d[\d.,KkMm%/]*\s*步)|(?:\d[\d.,KkMm%/]*\s*(?:rounds?|turns?)\s*[·•]?\s*\d[\d.,KkMm%/]*\s*steps?)/i.test(row));
|
|
1185
|
+
const llmRow = firstMatch((row) => /^LLM\b/i.test(row));
|
|
1186
|
+
const toolRow = firstMatch((row) => /^工具调用/i.test(row));
|
|
1187
|
+
const durationRow = llmRow !== undefined && toolRow !== undefined && !/工具调用/i.test(llmRow) ? `${llmRow} · ${toolRow}` : llmRow ?? toolRow;
|
|
1188
|
+
const firstTokenRow = firstMatch((row) => /^(?:首\s*)?(?:token|tokens|tok|toks)\s*平均(?:\s|[::]|\d|$)/i.test(row));
|
|
1189
|
+
const cacheRow = firstMatch((row) => /^(?:缓存命中|缓存|cache\b|cached\b)/i.test(row));
|
|
1190
|
+
const inputOutputRow = firstMatch((row) => /^(?:输入|prompt\b)/i.test(row) && /(?:输出|completion\b)/i.test(row))
|
|
1191
|
+
?? (() => {
|
|
1192
|
+
const inputRow = firstMatch((row) => /^(?:输入|prompt\b)/i.test(row));
|
|
1193
|
+
const outputRow = firstMatch((row) => /^(?:输出|completion\b)/i.test(row));
|
|
1194
|
+
return inputRow !== undefined && outputRow !== undefined ? `${inputRow} · ${outputRow}` : inputRow ?? outputRow;
|
|
1195
|
+
})();
|
|
1196
|
+
const fixedRows = [roundRow, durationRow, firstTokenRow, cacheRow, inputOutputRow].filter(Boolean);
|
|
1197
|
+
return fixedRows.slice(0, 5);
|
|
1198
|
+
};
|
|
1199
|
+
const renderPanel = (text) => {
|
|
1200
|
+
const rows = splitTelemetryRows(text);
|
|
1201
|
+
panel.hidden = rows.length === 0;
|
|
1202
|
+
panel.replaceChildren(...rows.map((text) => {
|
|
1203
|
+
const row = document.createElement("div");
|
|
1204
|
+
row.className = "dsh-skin-telemetry-row";
|
|
1205
|
+
const metric = document.createElement("span");
|
|
1206
|
+
metric.className = "dsh-skin-telemetry-value dsh-skin-telemetry-value-full";
|
|
1207
|
+
metric.textContent = text;
|
|
1208
|
+
row.append(metric);
|
|
1209
|
+
return row;
|
|
1210
|
+
}));
|
|
1211
|
+
};
|
|
1212
|
+
const update = () => {
|
|
1213
|
+
frame = 0;
|
|
1214
|
+
const nextSources = new Set(chooseTelemetryElements());
|
|
1215
|
+
const text = [...nextSources].map(getTelemetryText).filter(Boolean).join(" | ");
|
|
1216
|
+
for (const source of currentSources) if (!nextSources.has(source)) source.classList.remove("dsh-skin-telemetry-source-hidden");
|
|
1217
|
+
for (const source of nextSources) if (!currentSources.has(source)) source.classList.add("dsh-skin-telemetry-source-hidden");
|
|
1218
|
+
currentSources = nextSources;
|
|
1219
|
+
if (text === lastText) return;
|
|
1220
|
+
lastText = text;
|
|
1221
|
+
renderPanel(text);
|
|
1222
|
+
};
|
|
1223
|
+
const schedule = () => {
|
|
1224
|
+
if (frame === 0) frame = requestAnimationFrame(update);
|
|
1225
|
+
};
|
|
1226
|
+
const observer = typeof MutationObserver === "undefined" ? undefined : new MutationObserver(schedule);
|
|
1227
|
+
schedule();
|
|
1228
|
+
observer?.observe(document.body, { childList: true, subtree: true, characterData: true });
|
|
1229
|
+
window.addEventListener("resize", schedule, { passive: true });
|
|
1230
|
+
return () => {
|
|
1231
|
+
observer?.disconnect();
|
|
1232
|
+
window.removeEventListener("resize", schedule);
|
|
1233
|
+
if (frame !== 0) cancelAnimationFrame(frame);
|
|
1234
|
+
for (const source of currentSources) source.classList.remove("dsh-skin-telemetry-source-hidden");
|
|
1235
|
+
panel.remove();
|
|
1236
|
+
};
|
|
1237
|
+
}
|
|
1238
|
+
|
|
960
1239
|
const inject = ["theme"];
|
|
961
1240
|
|
|
962
1241
|
function apply(ctx) {
|
|
@@ -965,7 +1244,9 @@ body.dsh-skin-galactic-opera * {
|
|
|
965
1244
|
if (typeof document !== "undefined") document.body.classList.add("dsh-skin-galactic-opera");
|
|
966
1245
|
const decor = ensureDecor();
|
|
967
1246
|
const disposeInteractions = installInteractions(decor);
|
|
1247
|
+
const disposeTelemetryPanel = installTelemetryPanel();
|
|
968
1248
|
return () => {
|
|
1249
|
+
disposeTelemetryPanel();
|
|
969
1250
|
disposeInteractions();
|
|
970
1251
|
if (typeof document !== "undefined") document.body.classList.remove("dsh-skin-galactic-opera");
|
|
971
1252
|
decor?.remove();
|