dsh-background-by-model 0.4.5 → 0.5.1
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/README.md +6 -20
- package/README.zh.md +6 -20
- package/lib/client.js +2 -1665
- package/lib/client.js.map +1 -1
- package/lib/index.js +0 -24
- package/package.json +4 -9
- package/lib/host-scan-C6rdxkf8.js +0 -1186
- package/lib/host-scan.js +0 -2
- package/lib/testing.js +0 -632
- package/scripts/host-contract-scan.mjs +0 -182
- package/test/host-check.test.mjs +0 -581
package/lib/host-scan.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import { a as thisPluginDir, c as DSH_FLOOR, i as resolveHostRoots, l as HOST_CONTRACTS, n as listHostPackages, o as versionOf, r as meetsFloor, t as checkHostOnDisk } from "./host-scan-C6rdxkf8.js";
|
|
2
|
-
export { DSH_FLOOR, HOST_CONTRACTS, checkHostOnDisk, listHostPackages, meetsFloor, resolveHostRoots, thisPluginDir, versionOf };
|
package/lib/testing.js
DELETED
|
@@ -1,632 +0,0 @@
|
|
|
1
|
-
import { c as DSH_FLOOR, d as reportToMarkdown, f as symptomOf, i as resolveHostRoots, l as HOST_CONTRACTS, o as versionOf, p as verdictOf, r as meetsFloor, s as CONTRACT_GROUPS, t as checkHostOnDisk, u as labelOf } from "./host-scan-C6rdxkf8.js";
|
|
2
|
-
const UI_CSS = `
|
|
3
|
-
/* The section is rendered INLINE inside the host settings dialog's content
|
|
4
|
-
* column: the host provides the modal chrome (backdrop, centering, closing).
|
|
5
|
-
* These classes style only the embedded shell; transient fixed layers (toast,
|
|
6
|
-
* color picker, background editor) escape through Portals on <html>. */
|
|
7
|
-
.dab-root{position:relative;color:var(--dsw-alias-label-primary);animation:dab-fade-in .35s ease both;container-type:inline-size;display:flex;flex-direction:column;align-items:center;width:100%;min-width:0;--dab-mono:ui-monospace,"Cascadia Mono","SF Mono",Consolas,"Courier New",monospace}
|
|
8
|
-
.dab-root *,.dab-root *::before,.dab-root *::after{box-sizing:border-box}
|
|
9
|
-
.dab-root button{font-family:inherit}
|
|
10
|
-
|
|
11
|
-
/* ── shell: nav rail + page body ─────────────────────────────────────────── */
|
|
12
|
-
.dab-shell{display:grid;grid-template-columns:158px minmax(0,1fr);gap:26px;align-items:start;padding-bottom:8px;width:100%;max-width:980px;margin:0 auto}
|
|
13
|
-
.dab-nav{position:sticky;top:0;display:flex;flex-direction:column;gap:18px}
|
|
14
|
-
.dab-brand{display:flex;align-items:center;gap:10px;padding:2px 6px}
|
|
15
|
-
.dab-brand-tile{width:30px;height:30px;flex:none;border-radius:9px;display:grid;place-items:center;color:var(--dsw-alias-brand-text);background:var(--dsw-alias-brand-primary);box-shadow:0 4px 14px -4px var(--dsw-alias-brand-primary)}
|
|
16
|
-
.dab-brand-name{font-size:13px;font-weight:650;letter-spacing:.01em;line-height:1.25}
|
|
17
|
-
.dab-brand-tag{font-size:9px;letter-spacing:.16em;font-weight:600;color:var(--dsw-alias-label-quaternary,var(--dsw-alias-label-tertiary));text-transform:uppercase}
|
|
18
|
-
.dab-nav-list{position:relative;display:flex;flex-direction:column;gap:4px}
|
|
19
|
-
.dab-nav-ind{position:absolute;left:0;right:0;top:0;height:38px;border-radius:11px;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);background:color-mix(in srgb,var(--dsw-alias-brand-primary) 13%,transparent);border-color:color-mix(in srgb,var(--dsw-alias-brand-primary) 25%,transparent);transition:transform .38s cubic-bezier(.22,1,.36,1)}
|
|
20
|
-
.dab-nav-item{position:relative;z-index:1;display:flex;align-items:center;gap:10px;height:38px;padding:0 12px;border:0;background:none;border-radius:11px;color:var(--dsw-alias-label-tertiary);font-size:13px;cursor:pointer;text-align:left;transition:color .22s ease}
|
|
21
|
-
.dab-nav-item:hover{color:var(--dsw-alias-label-primary)}
|
|
22
|
-
.dab-nav-item.is-active{color:var(--dsw-alias-brand-primary);font-weight:600}
|
|
23
|
-
.dab-nav-item svg{flex:none;transition:transform .3s cubic-bezier(.34,1.56,.64,1)}
|
|
24
|
-
.dab-nav-item:hover svg{transform:scale(1.14) rotate(-5deg)}
|
|
25
|
-
|
|
26
|
-
/* ── page chrome ─────────────────────────────────────────────────────────── */
|
|
27
|
-
.dab-page{animation:dab-page-in .4s cubic-bezier(.22,1,.36,1) both;min-width:0;display:flex;flex-direction:column;gap:13px}
|
|
28
|
-
.dab-head{margin:2px 0 5px}
|
|
29
|
-
.dab-overline{font-size:10.5px;font-weight:700;letter-spacing:.18em;text-transform:uppercase;color:var(--dsw-alias-brand-primary);opacity:.9}
|
|
30
|
-
.dab-h1{margin:4px 0 0;font-size:21px;font-weight:700;letter-spacing:-.01em}
|
|
31
|
-
.dab-desc{margin:6px 0 0;font-size:12.5px;line-height:1.55;color:var(--dsw-alias-label-tertiary);max-width:56ch}
|
|
32
|
-
.dab-card{background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);border-radius:16px;padding:18px}
|
|
33
|
-
.dab-card-hover{transition:transform .28s ease,box-shadow .28s ease,border-color .28s ease}
|
|
34
|
-
.dab-card-hover:hover{transform:translateY(-2px);box-shadow:0 10px 28px -12px rgba(0,0,0,.28)}
|
|
35
|
-
.dab-rise{animation:dab-rise-in .55s cubic-bezier(.22,1,.36,1) both;animation-delay:calc(var(--d,0) * 62ms)}
|
|
36
|
-
|
|
37
|
-
/* ── accent hero (color orb) ─────────────────────────────────────────────── */
|
|
38
|
-
.dab-hero-accent{display:flex;align-items:center;gap:24px;flex-wrap:wrap}
|
|
39
|
-
.dab-orb-wrap{position:relative;width:118px;height:118px;flex:none}
|
|
40
|
-
.dab-orb{position:absolute;inset:11px;border-radius:50%;background:radial-gradient(circle at 32% 28%,rgba(255,255,255,.5),rgba(255,255,255,0) 44%),var(--c,#888);box-shadow:0 16px 36px -10px var(--c-soft,transparent),inset 0 -10px 20px rgba(0,0,0,.16);animation:dab-orb-in .7s cubic-bezier(.22,1,.36,1) both}
|
|
41
|
-
.dab-orb-ring{position:absolute;inset:0;border-radius:50%;background:conic-gradient(from 0deg,transparent 0 30%,var(--c,#888) 46%,transparent 62%,transparent 76%,var(--c,#888) 90%,transparent 100%);-webkit-mask:radial-gradient(farthest-side,transparent calc(100% - 3.5px),#000 calc(100% - 2.5px));mask:radial-gradient(farthest-side,transparent calc(100% - 3.5px),#000 calc(100% - 2.5px));animation:dab-spin 7s linear infinite;opacity:.9}
|
|
42
|
-
.dab-hex-caption{font-size:11px;color:var(--dsw-alias-label-tertiary);letter-spacing:.04em}
|
|
43
|
-
.dab-hex{font-family:var(--dab-mono);font-size:24px;font-weight:600;letter-spacing:.02em;line-height:1.2;margin-top:2px}
|
|
44
|
-
.dab-hsl-row{display:flex;gap:16px;margin-top:7px;font-family:var(--dab-mono);font-size:11px;color:var(--dsw-alias-label-tertiary)}
|
|
45
|
-
.dab-hsl-row b{font-weight:600;color:var(--dsw-alias-label-secondary,var(--dsw-alias-label-tertiary))}
|
|
46
|
-
|
|
47
|
-
/* ── swatches ────────────────────────────────────────────────────────────── */
|
|
48
|
-
.dab-swatch-title{font-size:12px;font-weight:600;margin-bottom:10px;color:var(--dsw-alias-label-secondary,var(--dsw-alias-label-tertiary))}
|
|
49
|
-
.dab-swatches{display:flex;flex-wrap:wrap;gap:9px}
|
|
50
|
-
.dab-swatch{width:25px;height:25px;border-radius:50%;border:0;padding:0;cursor:pointer;box-shadow:inset 0 0 0 1px rgba(0,0,0,.1);transition:transform .22s cubic-bezier(.34,1.56,.64,1),box-shadow .22s ease}
|
|
51
|
-
.dab-swatch:hover{transform:scale(1.2)}
|
|
52
|
-
.dab-swatch.is-on{box-shadow:0 0 0 2px var(--dsw-alias-bg-layer-1),0 0 0 4px var(--dsw-alias-brand-primary)}
|
|
53
|
-
|
|
54
|
-
/* ── wheel card ──────────────────────────────────────────────────────────── */
|
|
55
|
-
.dab-wheel-card{position:relative;display:flex;align-items:center;justify-content:center;gap:28px;flex-wrap:wrap;padding:24px 18px}
|
|
56
|
-
.dab-wheel-glow{position:absolute;width:230px;height:230px;border-radius:50%;filter:blur(48px);opacity:.2;background:var(--c,#888);pointer-events:none;transition:background .4s ease}
|
|
57
|
-
.dab-wheel{position:relative;cursor:crosshair;border-radius:50%;box-shadow:0 12px 32px -14px rgba(0,0,0,.4)}
|
|
58
|
-
.dab-hint{font-size:11.5px;line-height:1.55;color:var(--dsw-alias-label-tertiary);padding:0 4px}
|
|
59
|
-
|
|
60
|
-
/* ── precise color inputs ────────────────────────────────────────────────── */
|
|
61
|
-
.dab-inputs{display:flex;flex-direction:column;gap:10px;min-width:172px}
|
|
62
|
-
.dab-field{display:flex;align-items:center;gap:8px}
|
|
63
|
-
.dab-field-label{width:14px;text-align:center;font-family:var(--dab-mono);font-size:11px;font-weight:600;color:var(--dsw-alias-label-tertiary)}
|
|
64
|
-
.dab-num{flex:1;min-width:0;height:30px;padding:0 10px;border-radius:9px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);font-family:var(--dab-mono);font-size:12px;outline:none;transition:border-color .2s,box-shadow .2s}
|
|
65
|
-
.dab-num:focus{border-color:var(--dsw-alias-brand-primary);box-shadow:0 0 0 3px color-mix(in srgb,var(--dsw-alias-brand-primary) 18%,transparent)}
|
|
66
|
-
.dab-num::-webkit-outer-spin-button,.dab-num::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
|
|
67
|
-
.dab-num{-moz-appearance:textfield;appearance:textfield}
|
|
68
|
-
.dab-urlinput{flex:1;min-width:180px;height:34px;padding:0 12px;border-radius:10px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);font-size:12.5px;outline:none;transition:border-color .2s}
|
|
69
|
-
.dab-urlinput::placeholder{color:var(--dsw-alias-label-quaternary)}
|
|
70
|
-
.dab-urlinput:focus{border-color:var(--dsw-alias-brand-primary);box-shadow:0 0 0 3px color-mix(in srgb,var(--dsw-alias-brand-primary) 18%,transparent)}
|
|
71
|
-
.dab-swatch-lg{height:38px;border-radius:10px;border:1px solid var(--dsw-alias-border-l2);box-shadow:inset 0 0 14px rgba(0,0,0,.1);transition:transform .3s ease}
|
|
72
|
-
.dab-swatch-lg:hover{transform:scale(1.02)}
|
|
73
|
-
|
|
74
|
-
/* ── buttons & chips ─────────────────────────────────────────────────────── */
|
|
75
|
-
.dab-btn{display:inline-flex;align-items:center;justify-content:center;gap:7px;height:34px;padding:0 14px;border-radius:10px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-button-elevated-fill);color:var(--dsw-alias-label-primary);font-size:12.5px;font-weight:550;cursor:pointer;transition:transform .18s ease,box-shadow .18s ease,border-color .18s ease,opacity .18s ease,background .18s ease}
|
|
76
|
-
.dab-btn:hover:not(:disabled){transform:translateY(-1px);box-shadow:0 5px 14px -6px rgba(0,0,0,.32)}
|
|
77
|
-
.dab-btn:active:not(:disabled){transform:translateY(0) scale(.97);box-shadow:none}
|
|
78
|
-
.dab-btn:disabled{opacity:.5;cursor:not-allowed}
|
|
79
|
-
.dab-btn-primary{background:var(--dsw-alias-brand-primary);color:var(--dsw-alias-brand-text);border-color:transparent}
|
|
80
|
-
.dab-btn-danger{color:var(--dsw-alias-state-error-primary)}
|
|
81
|
-
.dab-btn-ghost{background:transparent;border-color:transparent;color:var(--dsw-alias-label-secondary,var(--dsw-alias-label-tertiary))}
|
|
82
|
-
.dab-btn-ghost:hover:not(:disabled){background:var(--dsw-alias-bg-layer-2);box-shadow:none}
|
|
83
|
-
.dab-btn:focus-visible,.dab-nav-item:focus-visible,.dab-seg-item:focus-visible,.dab-swatch:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}
|
|
84
|
-
.dab-chip-row{display:flex;flex-wrap:wrap;gap:8px}
|
|
85
|
-
.dab-chip{height:30px;padding:0 14px;border-radius:99px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-secondary,var(--dsw-alias-label-tertiary));font-size:12px;cursor:pointer;display:inline-flex;align-items:center;gap:6px;transition:all .22s ease}
|
|
86
|
-
.dab-chip:hover{border-color:var(--dsw-alias-brand-primary);color:var(--dsw-alias-label-primary)}
|
|
87
|
-
.dab-chip.is-active{background:var(--dsw-alias-brand-primary);color:var(--dsw-alias-brand-text);border-color:transparent}
|
|
88
|
-
|
|
89
|
-
/* ── sliders ─────────────────────────────────────────────────────────────── */
|
|
90
|
-
.dab-slider-block{display:flex;flex-direction:column;gap:6px}
|
|
91
|
-
.dab-slider-block + .dab-slider-block{margin-top:13px}
|
|
92
|
-
.dab-slider-label{font-size:12px;font-weight:550;color:var(--dsw-alias-label-secondary,var(--dsw-alias-label-tertiary))}
|
|
93
|
-
.dab-slider-val{font-family:var(--dab-mono);font-size:11px;color:var(--dsw-alias-label-tertiary);min-width:44px;text-align:right}
|
|
94
|
-
.dab-slider{-webkit-appearance:none;appearance:none;flex:1;min-width:0;height:4px;border-radius:99px;outline:none;cursor:pointer;margin:5px 0;background:linear-gradient(to right,var(--dsw-alias-brand-primary) calc(var(--pct,50) * 1%),var(--dsw-alias-border-l2) calc(var(--pct,50) * 1%));transition:height .15s ease}
|
|
95
|
-
.dab-slider:hover{height:5px}
|
|
96
|
-
.dab-slider::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:15px;height:15px;border-radius:50%;background:var(--dsw-alias-button-elevated-fill,#fff);border:2px solid var(--dsw-alias-brand-primary);box-shadow:0 1px 5px rgba(0,0,0,.28);transition:transform .16s cubic-bezier(.34,1.56,.64,1)}
|
|
97
|
-
.dab-slider:hover::-webkit-slider-thumb,.dab-slider:focus-visible::-webkit-slider-thumb{transform:scale(1.22)}
|
|
98
|
-
.dab-slider:active::-webkit-slider-thumb{transform:scale(1.34)}
|
|
99
|
-
.dab-slider::-moz-range-thumb{width:13px;height:13px;border-radius:50%;background:var(--dsw-alias-button-elevated-fill,#fff);border:2px solid var(--dsw-alias-brand-primary)}
|
|
100
|
-
|
|
101
|
-
/* ── interface part cards ────────────────────────────────────────────────── */
|
|
102
|
-
.dab-grid-parts{display:grid;grid-template-columns:repeat(auto-fill,minmax(256px,1fr));gap:13px}
|
|
103
|
-
.dab-part-head{display:flex;align-items:center;gap:11px;margin-bottom:14px}
|
|
104
|
-
.dab-part-ico{width:32px;height:32px;flex:none;border-radius:10px;display:grid;place-items:center;color:var(--dsw-alias-brand-primary);background:var(--dsw-alias-bg-layer-2);background:color-mix(in srgb,var(--dsw-alias-brand-primary) 12%,transparent)}
|
|
105
|
-
.dab-part-name{font-size:13.5px;font-weight:600}
|
|
106
|
-
.dab-part-badge{margin-left:auto;font-family:var(--dab-mono);font-size:11px;color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-bg-layer-2);border-radius:99px;padding:3px 9px}
|
|
107
|
-
|
|
108
|
-
/* ── segmented control ───────────────────────────────────────────────────── */
|
|
109
|
-
.dab-seg{position:relative;display:inline-flex;padding:3px;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:11px}
|
|
110
|
-
.dab-seg-thumb{position:absolute;top:3px;bottom:3px;left:3px;width:var(--w,96px);border-radius:8px;background:var(--dsw-alias-button-elevated-fill);box-shadow:0 2px 8px -2px rgba(0,0,0,.28);transition:transform .32s cubic-bezier(.22,1,.36,1)}
|
|
111
|
-
.dab-seg-item{position:relative;z-index:1;display:inline-flex;align-items:center;justify-content:center;gap:6px;width:var(--w,96px);height:30px;border:0;background:none;border-radius:8px;color:var(--dsw-alias-label-tertiary);font-size:12.5px;cursor:pointer;transition:color .25s ease}
|
|
112
|
-
.dab-seg-item.is-active{color:var(--dsw-alias-label-primary);font-weight:600}
|
|
113
|
-
|
|
114
|
-
/* ── toggle switch ───────────────────────────────────────────────────────── */
|
|
115
|
-
.dab-toggle{position:relative;width:42px;height:24px;flex:none;border-radius:99px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);cursor:pointer;padding:0;transition:background .28s ease,border-color .28s ease}
|
|
116
|
-
.dab-toggle-knob{position:absolute;top:2.5px;left:2.5px;width:17px;height:17px;border-radius:50%;background:var(--dsw-alias-label-secondary,#999);box-shadow:0 1px 3px rgba(0,0,0,.3);transition:transform .28s cubic-bezier(.22,1,.36,1),background .28s ease}
|
|
117
|
-
.dab-toggle.is-on{background:var(--dsw-alias-brand-primary);border-color:var(--dsw-alias-brand-primary)}
|
|
118
|
-
.dab-toggle.is-on .dab-toggle-knob{transform:translateX(18px);background:#fff}
|
|
119
|
-
|
|
120
|
-
/* ── background preview hero ─────────────────────────────────────────────── */
|
|
121
|
-
.dab-hero{position:relative;border-radius:16px;overflow:hidden;aspect-ratio:16/9;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2)}
|
|
122
|
-
.dab-hero-img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;transition:transform .5s cubic-bezier(.22,1,.36,1)}
|
|
123
|
-
.dab-hero:hover .dab-hero-img{transform:scale(1.03)}
|
|
124
|
-
.dab-hero-empty{position:absolute;inset:6px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;color:var(--dsw-alias-label-tertiary);font-size:12.5px;border:1.5px dashed var(--dsw-alias-border-l2);border-radius:12px;cursor:pointer;background:transparent;transition:border-color .25s,color .25s,background .25s;width:auto;height:auto}
|
|
125
|
-
.dab-hero-empty:hover{border-color:var(--dsw-alias-brand-primary);color:var(--dsw-alias-brand-primary)}
|
|
126
|
-
.dab-hero-empty.is-over{border-color:var(--dsw-alias-brand-primary);color:var(--dsw-alias-brand-primary);background:color-mix(in srgb,var(--dsw-alias-brand-primary) 8%,transparent)}
|
|
127
|
-
.dab-hero-badge{position:absolute;top:10px;left:10px;display:inline-flex;align-items:center;gap:5px;height:24px;padding:0 11px;border-radius:99px;background:rgba(0,0,0,.45);color:#fff;font-size:11px;backdrop-filter:blur(6px);pointer-events:none}
|
|
128
|
-
.dab-hero-veil{position:absolute;left:0;right:0;bottom:0;padding:34px 12px 12px;display:flex;align-items:flex-end;justify-content:flex-end;gap:8px;background:linear-gradient(to top,rgba(0,0,0,.55),rgba(0,0,0,0));opacity:0;transform:translateY(6px);transition:opacity .3s ease,transform .3s ease}
|
|
129
|
-
.dab-hero:hover .dab-hero-veil{opacity:1;transform:none}
|
|
130
|
-
.dab-hero-veil .dab-btn{background:rgba(255,255,255,.94);color:#14161a;border-color:transparent;height:30px;font-size:12px}
|
|
131
|
-
.dab-hero-veil .dab-btn-danger{color:#dc2626}
|
|
132
|
-
|
|
133
|
-
/* ── profile page ────────────────────────────────────────────────────────── */
|
|
134
|
-
.dab-profile-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(238px,1fr));gap:13px}
|
|
135
|
-
.dab-profile-ico{width:38px;height:38px;border-radius:11px;display:grid;place-items:center;margin-bottom:13px;color:var(--dsw-alias-brand-primary);background:var(--dsw-alias-bg-layer-2);background:color-mix(in srgb,var(--dsw-alias-brand-primary) 12%,transparent)}
|
|
136
|
-
.dab-profile-title{font-size:14px;font-weight:650}
|
|
137
|
-
.dab-profile-desc{font-size:12px;color:var(--dsw-alias-label-tertiary);line-height:1.55;margin:5px 0 15px}
|
|
138
|
-
.dab-footer{margin-top:6px;padding:14px 4px 0;border-top:1px solid var(--dsw-alias-border-l2);display:flex;align-items:center;justify-content:space-between;font-size:11px;color:var(--dsw-alias-label-tertiary)}
|
|
139
|
-
.dab-footer-mono{font-family:var(--dab-mono);letter-spacing:.02em}
|
|
140
|
-
|
|
141
|
-
/* ── toast ───────────────────────────────────────────────────────────────── */
|
|
142
|
-
.dab-toast{position:fixed;left:50%;bottom:30px;transform:translateX(-50%);display:flex;align-items:center;gap:8px;height:38px;padding:0 16px;border-radius:99px;background:var(--dsw-alias-bg-layer-3,var(--dsw-alias-bg-layer-2));border:1px solid var(--dsw-alias-border-l2);box-shadow:0 10px 30px -8px rgba(0,0,0,.38);font-size:12.5px;z-index:10001;animation:dab-toast-in .32s cubic-bezier(.22,1,.36,1) both}
|
|
143
|
-
.dab-toast-ok{color:var(--dsw-alias-brand-primary);display:grid;place-items:center}
|
|
144
|
-
.dab-toast-err{color:var(--dsw-alias-state-error-primary);display:grid;place-items:center}
|
|
145
|
-
|
|
146
|
-
/* ── modals (editor / eyedropper / crash) ────────────────────────────────── */
|
|
147
|
-
/* Pin to the viewport explicitly with vw/vh so ancestor padding/margins on
|
|
148
|
-
* body cannot shift or clip the overlay; keep it above host sidebar chrome.
|
|
149
|
-
* pointer-events:auto re-enables interaction: these overlays render inside a
|
|
150
|
-
* Portal root that is pointer-events:none so it never blocks the page alone. */
|
|
151
|
-
.dab-overlay{position:fixed;left:0;top:0;width:100vw;height:100vh;z-index:999999;background:rgba(8,10,14,.62);backdrop-filter:blur(8px);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:14px;animation:dab-fade-in .25s ease both;pointer-events:auto}
|
|
152
|
-
.dab-overlay-title{color:#fff;font-size:15px;font-weight:600}
|
|
153
|
-
.dab-overlay-hint{color:rgba(255,255,255,.62);font-size:12px}
|
|
154
|
-
.dab-modal-card{animation:dab-zoom-in .3s cubic-bezier(.22,1,.36,1) both;max-width:calc(100vw - 40px);max-height:calc(100vh - 120px);overflow:auto}
|
|
155
|
-
.dab-overlay .dab-btn{background:rgba(255,255,255,.94);color:#14161a;border-color:transparent}
|
|
156
|
-
.dab-overlay .dab-btn-primary{background:var(--dsw-alias-brand-primary);color:var(--dsw-alias-brand-text)}
|
|
157
|
-
.dab-crash{display:flex;flex-direction:column;gap:10px;align-items:center;padding:28px 18px;border:1px solid var(--dsw-alias-border-l2);border-radius:16px}
|
|
158
|
-
.dab-crash-title{font-size:15px;font-weight:650}
|
|
159
|
-
.dab-crash-desc{font-size:12px;color:var(--dsw-alias-label-tertiary);text-align:center;line-height:1.5}
|
|
160
|
-
|
|
161
|
-
/* ── model rules ─────────────────────────────────────────────────────────── */
|
|
162
|
-
.dab-rules{display:flex;flex-direction:column;gap:12px}
|
|
163
|
-
.dab-rule{background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);border-radius:16px;padding:14px;transition:border-color .25s,box-shadow .25s,opacity .25s}
|
|
164
|
-
.dab-rule.is-active{border-color:var(--dsw-alias-brand-primary);box-shadow:0 0 0 3px color-mix(in srgb,var(--dsw-alias-brand-primary) 16%,transparent)}
|
|
165
|
-
.dab-rule.is-off{opacity:.55}
|
|
166
|
-
.dab-rule-head{display:flex;align-items:center;gap:9px;flex-wrap:wrap}
|
|
167
|
-
.dab-rule-num{font-family:var(--dab-mono);font-size:11px;font-weight:700;color:var(--dsw-alias-label-tertiary);min-width:16px}
|
|
168
|
-
.dab-rule-badge{font-size:10px;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--dsw-alias-brand-primary);background:color-mix(in srgb,var(--dsw-alias-brand-primary) 14%,transparent);border-radius:99px;padding:2px 8px}
|
|
169
|
-
.dab-rule-match{flex:1;min-width:150px;height:32px;padding:0 11px;border-radius:9px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);font-family:var(--dab-mono);font-size:12.5px;outline:none;transition:border-color .2s,box-shadow .2s}
|
|
170
|
-
.dab-rule-match::placeholder{color:var(--dsw-alias-label-quaternary)}
|
|
171
|
-
.dab-rule-match:focus{border-color:var(--dsw-alias-brand-primary);box-shadow:0 0 0 3px color-mix(in srgb,var(--dsw-alias-brand-primary) 18%,transparent)}
|
|
172
|
-
.dab-icon-btn{width:28px;height:28px;flex:none;display:grid;place-items:center;border-radius:8px;border:1px solid var(--dsw-alias-border-l2);background:transparent;color:var(--dsw-alias-label-tertiary);cursor:pointer;transition:color .2s,border-color .2s,background .2s}
|
|
173
|
-
.dab-icon-btn:hover:not(:disabled){color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-brand-primary)}
|
|
174
|
-
.dab-icon-btn:disabled{opacity:.35;cursor:not-allowed}
|
|
175
|
-
.dab-icon-btn-danger:hover:not(:disabled){color:var(--dsw-alias-state-error-primary);border-color:var(--dsw-alias-state-error-primary)}
|
|
176
|
-
.dab-rule-body{margin-top:13px;display:flex;flex-direction:column;gap:13px}
|
|
177
|
-
.dab-rule-thumb{position:relative;border-radius:12px;overflow:hidden;aspect-ratio:16/9;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);cursor:pointer}
|
|
178
|
-
.dab-rule-thumb img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
|
|
179
|
-
.dab-rule-thumb-empty{position:absolute;inset:5px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;border:1.5px dashed var(--dsw-alias-border-l2);border-radius:9px;color:var(--dsw-alias-label-tertiary);font-size:12px;text-align:center;padding:0 10px}
|
|
180
|
-
.dab-rule-thumb.is-over .dab-rule-thumb-empty{border-color:var(--dsw-alias-brand-primary);color:var(--dsw-alias-brand-primary)}
|
|
181
|
-
.dab-rule-cols{display:grid;grid-template-columns:minmax(0,1.15fr) minmax(0,1fr);gap:18px;align-items:start}
|
|
182
|
-
.dab-rule-section-title{font-size:12px;font-weight:600;margin-bottom:9px;color:var(--dsw-alias-label-secondary,var(--dsw-alias-label-tertiary))}
|
|
183
|
-
@container (max-width:760px){.dab-rule-cols{grid-template-columns:1fr}}
|
|
184
|
-
|
|
185
|
-
/* ── host self-check ─────────────────────────────────────────────────────── */
|
|
186
|
-
.dab-verdict{display:flex;flex-direction:column;gap:14px;position:relative;overflow:hidden}
|
|
187
|
-
.dab-verdict::after{content:'';position:absolute;inset:0;pointer-events:none;opacity:.5;background:linear-gradient(120deg,transparent 55%,color-mix(in srgb,var(--dab-verdict-tone,transparent) 26%,transparent))}
|
|
188
|
-
.dab-verdict-ok{--dab-verdict-tone:var(--dsw-alias-state-success-primary,var(--dsw-alias-brand-primary));border-color:color-mix(in srgb,var(--dsw-alias-state-success-primary,var(--dsw-alias-brand-primary)) 38%,var(--dsw-alias-border-l2))}
|
|
189
|
-
.dab-verdict-partial,.dab-verdict-broken{--dab-verdict-tone:var(--dsw-alias-state-error-primary);border-color:color-mix(in srgb,var(--dsw-alias-state-error-primary) 40%,var(--dsw-alias-border-l2))}
|
|
190
|
-
.dab-verdict-unknown{--dab-verdict-tone:var(--dsw-alias-label-tertiary)}
|
|
191
|
-
.dab-verdict-head{display:flex;align-items:center;gap:13px;flex-wrap:wrap}
|
|
192
|
-
.dab-verdict-ico{width:34px;height:34px;flex:none;border-radius:11px;display:grid;place-items:center;color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-bg-layer-2)}
|
|
193
|
-
.dab-verdict-ico-ok{color:var(--dsw-alias-state-success-primary,var(--dsw-alias-brand-primary));background:color-mix(in srgb,var(--dsw-alias-state-success-primary,var(--dsw-alias-brand-primary)) 14%,transparent)}
|
|
194
|
-
.dab-verdict-ico-partial,.dab-verdict-ico-broken{color:var(--dsw-alias-state-error-primary);background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 14%,transparent)}
|
|
195
|
-
.dab-verdict-text{flex:1;min-width:170px}
|
|
196
|
-
.dab-verdict-title{font-size:14.5px;font-weight:650}
|
|
197
|
-
.dab-verdict-sub{margin-top:4px;font-size:12px;color:var(--dsw-alias-label-tertiary)}
|
|
198
|
-
.dab-verdict-actions{display:flex;gap:8px;flex-wrap:wrap;margin-left:auto}
|
|
199
|
-
.dab-facts{display:flex;flex-wrap:wrap;gap:8px;position:relative;z-index:1}
|
|
200
|
-
.dab-fact{display:inline-flex;align-items:center;gap:7px;height:27px;padding:0 11px;border-radius:99px;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);max-width:100%}
|
|
201
|
-
.dab-fact.is-bad{border-color:color-mix(in srgb,var(--dsw-alias-state-error-primary) 45%,transparent);background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,transparent)}
|
|
202
|
-
.dab-fact-k{font-size:10.5px;font-weight:650;letter-spacing:.06em;text-transform:uppercase;color:var(--dsw-alias-label-tertiary);white-space:nowrap}
|
|
203
|
-
.dab-fact-v{font-family:var(--dab-mono);font-size:11.5px;color:var(--dsw-alias-label-primary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:32ch}
|
|
204
|
-
.dab-check-group-title{display:flex;align-items:center;gap:9px;font-size:12.5px;font-weight:650;margin-bottom:11px}
|
|
205
|
-
.dab-check-group-count{margin-left:auto;font-family:var(--dab-mono);font-size:11px;font-weight:500;color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-bg-layer-2);border-radius:99px;padding:3px 9px}
|
|
206
|
-
.dab-checks{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:2px}
|
|
207
|
-
.dab-check{display:flex;gap:10px;padding:9px 10px;border-radius:11px;transition:background .2s ease}
|
|
208
|
-
.dab-check:hover{background:var(--dsw-alias-bg-layer-2)}
|
|
209
|
-
.dab-check-ico{width:19px;height:19px;flex:none;margin-top:1px;border-radius:50%;display:grid;place-items:center;color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-bg-layer-2)}
|
|
210
|
-
.dab-check-ico-pass{color:var(--dsw-alias-state-success-primary,var(--dsw-alias-brand-primary));background:color-mix(in srgb,var(--dsw-alias-state-success-primary,var(--dsw-alias-brand-primary)) 15%,transparent)}
|
|
211
|
-
.dab-check-ico-fail{color:var(--dsw-alias-state-error-primary);background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 15%,transparent)}
|
|
212
|
-
.dab-check-dot{width:5px;height:5px;border-radius:50%;background:currentColor;opacity:.65}
|
|
213
|
-
.dab-check-body{min-width:0;flex:1;display:flex;flex-direction:column;gap:3px}
|
|
214
|
-
.dab-check-head{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}
|
|
215
|
-
.dab-check-label{font-size:12.5px;font-weight:600}
|
|
216
|
-
.dab-check-status{font-size:10px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;padding:1px 7px;border-radius:99px;background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-tertiary)}
|
|
217
|
-
.dab-check-status-pass{color:var(--dsw-alias-state-success-primary,var(--dsw-alias-brand-primary));background:color-mix(in srgb,var(--dsw-alias-state-success-primary,var(--dsw-alias-brand-primary)) 14%,transparent)}
|
|
218
|
-
.dab-check-status-fail{color:var(--dsw-alias-state-error-primary);background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 14%,transparent)}
|
|
219
|
-
.dab-check-target{font-family:var(--dab-mono);font-size:10.5px;color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-bg-layer-2);border-radius:6px;padding:1px 6px;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
220
|
-
.dab-check-detail{font-family:var(--dab-mono);font-size:11px;color:var(--dsw-alias-label-tertiary);line-height:1.5;overflow-wrap:anywhere}
|
|
221
|
-
.dab-check-reason{display:flex;flex-direction:column;gap:5px;font-size:12px;line-height:1.55;color:var(--dsw-alias-label-secondary,var(--dsw-alias-label-tertiary))}
|
|
222
|
-
.dab-check-symptom{color:var(--dsw-alias-state-error-primary)}
|
|
223
|
-
.dab-check-where{display:flex;gap:7px;align-items:baseline;flex-wrap:wrap;font-size:11px;color:var(--dsw-alias-label-tertiary)}
|
|
224
|
-
.dab-check-where code{font-family:var(--dab-mono);font-size:10.5px;overflow-wrap:anywhere}
|
|
225
|
-
.dab-check-note{margin:12px 0 0;font-size:11.5px;line-height:1.55;color:var(--dsw-alias-label-tertiary);position:relative;z-index:1}
|
|
226
|
-
|
|
227
|
-
/* ── keyframes ───────────────────────────────────────────────────────────── */
|
|
228
|
-
@keyframes dab-fade-in{from{opacity:0}to{opacity:1}}
|
|
229
|
-
@keyframes dab-page-in{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:none}}
|
|
230
|
-
@keyframes dab-rise-in{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}
|
|
231
|
-
@keyframes dab-orb-in{from{opacity:0;transform:scale(.82)}to{opacity:1;transform:none}}
|
|
232
|
-
@keyframes dab-spin{to{transform:rotate(360deg)}}
|
|
233
|
-
@keyframes dab-rotate{to{transform:rotate(360deg)}}
|
|
234
|
-
@keyframes dab-toast-in{from{opacity:0;transform:translate(-50%,10px)}to{opacity:1;transform:translate(-50%,0)}}
|
|
235
|
-
@keyframes dab-zoom-in{from{opacity:0;transform:scale(.94) translateY(8px)}to{opacity:1;transform:none}}
|
|
236
|
-
@keyframes dab-flow{to{background-position:300% 50%}}
|
|
237
|
-
|
|
238
|
-
/* ── responsive & motion preferences ─────────────────────────────────────── */
|
|
239
|
-
@container (max-width:620px){
|
|
240
|
-
.dab-shell{grid-template-columns:1fr;gap:14px}
|
|
241
|
-
.dab-nav{position:static;flex-direction:row;align-items:center;justify-content:space-between;gap:10px}
|
|
242
|
-
.dab-nav-list{flex-direction:row;overflow-x:auto;scrollbar-width:none}
|
|
243
|
-
.dab-nav-list::-webkit-scrollbar{display:none}
|
|
244
|
-
.dab-nav-ind{display:none}
|
|
245
|
-
.dab-nav-item{flex:none;padding:0 10px}
|
|
246
|
-
.dab-nav-item.is-active{background:var(--dsw-alias-bg-layer-2)}
|
|
247
|
-
.dab-types{grid-template-columns:1fr}
|
|
248
|
-
.dab-verdict-actions{margin-left:0;width:100%}
|
|
249
|
-
.dab-verdict-actions .dab-btn{flex:1}
|
|
250
|
-
}
|
|
251
|
-
@container (min-width:621px){
|
|
252
|
-
.dab-shell{grid-template-columns:158px minmax(0,1fr);gap:26px}
|
|
253
|
-
}
|
|
254
|
-
@media (prefers-reduced-motion:reduce){
|
|
255
|
-
.dab-root *,.dab-root *::before,.dab-root *::after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}
|
|
256
|
-
}
|
|
257
|
-
`;
|
|
258
|
-
/**
|
|
259
|
-
* The attribute that marks a `<style>` element as OURS.
|
|
260
|
-
*
|
|
261
|
-
* The host's own CSS modules also set `data-plugin` on their `<style>` elements
|
|
262
|
-
* (every one of them), so `data-plugin` cannot distinguish this plugin's sheets
|
|
263
|
-
* from the host's — and the host-contract probe has to make exactly that
|
|
264
|
-
* distinction: a token this plugin re-emits must never be allowed to make a
|
|
265
|
-
* *host* check pass. This attribute is the honest marker, and it is set on every
|
|
266
|
-
* stylesheet this plugin injects.
|
|
267
|
-
*/
|
|
268
|
-
const OWN_SHEET_ATTR = "data-dab-side";
|
|
269
|
-
/** Mark a stylesheet this plugin injected, so the host probe can tell it apart. */
|
|
270
|
-
function markOwnSheet(el) {
|
|
271
|
-
el.setAttribute(OWN_SHEET_ATTR, "own");
|
|
272
|
-
return el;
|
|
273
|
-
}
|
|
274
|
-
//#endregion
|
|
275
|
-
//#region src/client/judge.ts
|
|
276
|
-
/** The real browser environment. */
|
|
277
|
-
function browserEnv(ctx) {
|
|
278
|
-
const tokenRoot = () => {
|
|
279
|
-
if (typeof document === "undefined") return null;
|
|
280
|
-
return document.body ?? document.documentElement ?? null;
|
|
281
|
-
};
|
|
282
|
-
return {
|
|
283
|
-
querySelector: (selector) => document.querySelector(selector),
|
|
284
|
-
tokenRoot,
|
|
285
|
-
computedValue: (token, on) => {
|
|
286
|
-
if (typeof document === "undefined") return "";
|
|
287
|
-
const host = on ?? tokenRoot();
|
|
288
|
-
if (host === null) return "";
|
|
289
|
-
return getComputedStyle(host).getPropertyValue(token).trim();
|
|
290
|
-
},
|
|
291
|
-
visible: (el) => {
|
|
292
|
-
if (el === null || typeof getComputedStyle !== "function") return true;
|
|
293
|
-
try {
|
|
294
|
-
return getComputedStyle(el).visibility !== "hidden";
|
|
295
|
-
} catch {
|
|
296
|
-
return true;
|
|
297
|
-
}
|
|
298
|
-
},
|
|
299
|
-
styleSheets: () => typeof document === "undefined" ? [] : Array.from(document.styleSheets),
|
|
300
|
-
ctx
|
|
301
|
-
};
|
|
302
|
-
}
|
|
303
|
-
const ANCHORS = {
|
|
304
|
-
chatHasMessages: "[data-chat-turn]",
|
|
305
|
-
trajectoryMounted: "[data-conversation-composer-overlay]",
|
|
306
|
-
rightPanelMounted: "div[data-sidebar-right-panel],[data-dockkit-strip],[data-dockkit-pane]",
|
|
307
|
-
cordisMounted: "[data-cordis-panel]",
|
|
308
|
-
dockHasTab: "[data-dockkit-tab]",
|
|
309
|
-
dockHasNoTab: "[data-dockkit-empty],[data-dockkit-add-tab]",
|
|
310
|
-
paneFloated: "[data-dockkit-float],[data-sidebar-right-mode=\"float\"]",
|
|
311
|
-
settingsOpen: "div[role=\"dialog\"][aria-modal=\"true\"][aria-labelledby]"
|
|
312
|
-
};
|
|
313
|
-
/**
|
|
314
|
-
* Whether an anchor's surface is on screen.
|
|
315
|
-
*
|
|
316
|
-
* `optionalWhen: X` skips the check while this is FALSE — "the feature is not
|
|
317
|
-
* observable right now", which is what the field name promises. Every anchor is
|
|
318
|
-
* therefore written as a POSITIVE predicate (`dockHasTab`, `chatHasMessages`), and
|
|
319
|
-
* an anchor whose name reads as an absence would silently invert its check.
|
|
320
|
-
*/
|
|
321
|
-
function anchorMounted(env, anchorId) {
|
|
322
|
-
const sel = ANCHORS[anchorId];
|
|
323
|
-
if (sel === void 0) return true;
|
|
324
|
-
try {
|
|
325
|
-
return env.querySelector(sel) !== null;
|
|
326
|
-
} catch {
|
|
327
|
-
return true;
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
/** Walk a dotted path off a root object, tolerating a missing first hop. */
|
|
331
|
-
function walkPath(root, path) {
|
|
332
|
-
let cur = root;
|
|
333
|
-
for (const key of path.split(".")) {
|
|
334
|
-
if (cur === null || cur === void 0) return void 0;
|
|
335
|
-
cur = cur[key];
|
|
336
|
-
}
|
|
337
|
-
return cur;
|
|
338
|
-
}
|
|
339
|
-
function looksObservable(v) {
|
|
340
|
-
return typeof v === "object" && v !== null && typeof v.subscribe === "function" && typeof v.getSnapshot === "function";
|
|
341
|
-
}
|
|
342
|
-
/** The camel-cased key `data-dab-side` becomes on a real element's `dataset`. */
|
|
343
|
-
const OWN_SHEET_DATASET = "dabSide";
|
|
344
|
-
/**
|
|
345
|
-
* Whether a stylesheet belongs to THIS plugin.
|
|
346
|
-
*
|
|
347
|
-
* `data-plugin` cannot answer this: the host's own CSS modules set it on every
|
|
348
|
-
* `<style>` they inject (`@deepseek-ai/dsh-client-ui-theme` and its peers). Only
|
|
349
|
-
* the marker written by this plugin's `markOwnSheet` can, and getting this wrong
|
|
350
|
-
* in the "skip our own sheets" direction skips the host's whole theme.
|
|
351
|
-
*
|
|
352
|
-
* Read via `getAttribute` (the browser's own spelling) and fall back to the
|
|
353
|
-
* camel-cased `dataset` key, which is what a plain-object test fixture exposes.
|
|
354
|
-
*/
|
|
355
|
-
function isOwnSheet(sheet) {
|
|
356
|
-
const owner = sheet.ownerNode;
|
|
357
|
-
if (owner === null || owner === void 0) return false;
|
|
358
|
-
if (typeof owner.getAttribute === "function") return owner.getAttribute(OWN_SHEET_ATTR) !== null;
|
|
359
|
-
const ds = owner.dataset;
|
|
360
|
-
return ds !== void 0 && (ds["data-dab-side"] !== void 0 || ds["dabSide"] !== void 0);
|
|
361
|
-
}
|
|
362
|
-
/**
|
|
363
|
-
* A stylesheet mention of a literal, on the requested side.
|
|
364
|
-
*
|
|
365
|
-
* The host's rules are the only place a renamed token still answers honestly:
|
|
366
|
-
* a token can be *declared* by this plugin while the host's rule that gave it a
|
|
367
|
-
* value is gone. Cross-origin sheets (none on a local dsh, but the probe must
|
|
368
|
-
* not throw if one ever appears) are skipped.
|
|
369
|
-
*/
|
|
370
|
-
function ruleMentioned(env, literal, side) {
|
|
371
|
-
for (const sheet of env.styleSheets()) {
|
|
372
|
-
if (isOwnSheet(sheet) !== (side === "own")) continue;
|
|
373
|
-
let rules = null;
|
|
374
|
-
try {
|
|
375
|
-
rules = sheet.cssRules;
|
|
376
|
-
} catch {
|
|
377
|
-
continue;
|
|
378
|
-
}
|
|
379
|
-
if (rules === null) continue;
|
|
380
|
-
for (const rule of Array.from(rules)) {
|
|
381
|
-
const text = rule.cssText;
|
|
382
|
-
if (typeof text === "string" && text.includes(literal)) return true;
|
|
383
|
-
const inner = rule.cssRules;
|
|
384
|
-
if (inner === void 0 || inner === null) continue;
|
|
385
|
-
for (const child of Array.from(inner)) {
|
|
386
|
-
const childText = child.cssText;
|
|
387
|
-
if (typeof childText === "string" && childText.includes(literal)) return true;
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
return false;
|
|
392
|
-
}
|
|
393
|
-
/**
|
|
394
|
-
* Which sides of stylesheet the probe can actually read (a blind check must not fail).
|
|
395
|
-
*/
|
|
396
|
-
function readability(env) {
|
|
397
|
-
const out = {
|
|
398
|
-
host: false,
|
|
399
|
-
own: false
|
|
400
|
-
};
|
|
401
|
-
for (const sheet of env.styleSheets()) try {
|
|
402
|
-
if (sheet.cssRules !== null) {
|
|
403
|
-
if (isOwnSheet(sheet)) out.own = true;
|
|
404
|
-
else out.host = true;
|
|
405
|
-
}
|
|
406
|
-
} catch {}
|
|
407
|
-
return out;
|
|
408
|
-
}
|
|
409
|
-
function evaluate(env, check) {
|
|
410
|
-
switch (check.kind) {
|
|
411
|
-
case "service": {
|
|
412
|
-
let svc;
|
|
413
|
-
try {
|
|
414
|
-
svc = env.ctx.get(check.id);
|
|
415
|
-
} catch {
|
|
416
|
-
svc = void 0;
|
|
417
|
-
}
|
|
418
|
-
return svc === void 0 || svc === null ? {
|
|
419
|
-
status: "fail",
|
|
420
|
-
name: `ctx.get('${check.id}')`,
|
|
421
|
-
detail: "service not published",
|
|
422
|
-
reason: `the host does not publish the "${check.id}" service`
|
|
423
|
-
} : {
|
|
424
|
-
status: "pass",
|
|
425
|
-
name: `ctx.get('${check.id}')`,
|
|
426
|
-
detail: "service present"
|
|
427
|
-
};
|
|
428
|
-
}
|
|
429
|
-
case "path": {
|
|
430
|
-
let svc;
|
|
431
|
-
try {
|
|
432
|
-
svc = env.ctx.get(check.service);
|
|
433
|
-
} catch {
|
|
434
|
-
svc = void 0;
|
|
435
|
-
}
|
|
436
|
-
if (svc === void 0 || svc === null) return {
|
|
437
|
-
status: "skip",
|
|
438
|
-
name: `${check.service}.${check.path}`,
|
|
439
|
-
detail: "service not published yet"
|
|
440
|
-
};
|
|
441
|
-
const value = walkPath(svc, check.path);
|
|
442
|
-
const name = `${check.service}.${check.path}`;
|
|
443
|
-
if (check.expect === "function") return typeof value === "function" ? {
|
|
444
|
-
status: "pass",
|
|
445
|
-
name,
|
|
446
|
-
detail: "is a function"
|
|
447
|
-
} : {
|
|
448
|
-
status: "fail",
|
|
449
|
-
name,
|
|
450
|
-
detail: `expected a function, got ${typeof value}`,
|
|
451
|
-
reason: `"${name}" is not a function on this host`
|
|
452
|
-
};
|
|
453
|
-
if (check.expect === "observable") return looksObservable(value) ? {
|
|
454
|
-
status: "pass",
|
|
455
|
-
name,
|
|
456
|
-
detail: "is an observable face"
|
|
457
|
-
} : {
|
|
458
|
-
status: "fail",
|
|
459
|
-
name,
|
|
460
|
-
detail: "not an observable face",
|
|
461
|
-
reason: `"${name}" no longer exposes subscribe()/getSnapshot()`
|
|
462
|
-
};
|
|
463
|
-
return value === void 0 ? {
|
|
464
|
-
status: "fail",
|
|
465
|
-
name,
|
|
466
|
-
detail: "undefined",
|
|
467
|
-
reason: `"${name}" is gone`
|
|
468
|
-
} : {
|
|
469
|
-
status: "pass",
|
|
470
|
-
name,
|
|
471
|
-
detail: typeof value
|
|
472
|
-
};
|
|
473
|
-
}
|
|
474
|
-
case "selector": {
|
|
475
|
-
const el = env.querySelector(check.selector);
|
|
476
|
-
const name = `querySelector(${JSON.stringify(check.selector)})`;
|
|
477
|
-
if (el !== null && (check.visible !== true || env.visible(el))) return {
|
|
478
|
-
status: "pass",
|
|
479
|
-
name,
|
|
480
|
-
detail: "element found"
|
|
481
|
-
};
|
|
482
|
-
if (check.optionalWhen !== void 0 && !anchorMounted(env, check.optionalWhen)) return {
|
|
483
|
-
status: "skip",
|
|
484
|
-
name,
|
|
485
|
-
detail: "not on screen right now"
|
|
486
|
-
};
|
|
487
|
-
return {
|
|
488
|
-
status: "fail",
|
|
489
|
-
name,
|
|
490
|
-
detail: el === null ? "no element matches" : "the element is hidden",
|
|
491
|
-
reason: el === null ? `no element matches ${check.selector} while its surface is on screen` : `${check.selector} is in the DOM but hidden while its surface is on screen`
|
|
492
|
-
};
|
|
493
|
-
}
|
|
494
|
-
case "attr": {
|
|
495
|
-
const present = env.querySelector(`[${check.attr}]`) !== null;
|
|
496
|
-
const name = `querySelector([${check.attr}])`;
|
|
497
|
-
if (present) return {
|
|
498
|
-
status: "pass",
|
|
499
|
-
name,
|
|
500
|
-
detail: "attribute found"
|
|
501
|
-
};
|
|
502
|
-
if (check.optionalWhen !== void 0 && !anchorMounted(env, check.optionalWhen)) return {
|
|
503
|
-
status: "skip",
|
|
504
|
-
name,
|
|
505
|
-
detail: "not on screen right now"
|
|
506
|
-
};
|
|
507
|
-
return {
|
|
508
|
-
status: "fail",
|
|
509
|
-
name,
|
|
510
|
-
detail: "no element carries it",
|
|
511
|
-
reason: `nothing in the DOM carries ${check.attr} while its surface is on screen`
|
|
512
|
-
};
|
|
513
|
-
}
|
|
514
|
-
case "computed": {
|
|
515
|
-
const host = check.on !== void 0 ? env.querySelector(check.on) : null;
|
|
516
|
-
const name = `computed(${check.token}${check.on !== void 0 ? ` on ${check.on}` : ""})`;
|
|
517
|
-
if (check.on !== void 0 && host === null) return {
|
|
518
|
-
status: "skip",
|
|
519
|
-
name,
|
|
520
|
-
detail: `${check.on} not mounted`
|
|
521
|
-
};
|
|
522
|
-
const value = env.computedValue(check.token, host);
|
|
523
|
-
return value !== "" ? {
|
|
524
|
-
status: "pass",
|
|
525
|
-
name,
|
|
526
|
-
detail: value
|
|
527
|
-
} : {
|
|
528
|
-
status: "fail",
|
|
529
|
-
name,
|
|
530
|
-
detail: "resolves to nothing",
|
|
531
|
-
reason: `${check.token} resolves to an empty value`
|
|
532
|
-
};
|
|
533
|
-
}
|
|
534
|
-
case "rule": {
|
|
535
|
-
const side = check.side ?? "host";
|
|
536
|
-
const name = `${side === "host" ? "host" : "plugin"} stylesheet includes ${JSON.stringify(check.match)}`;
|
|
537
|
-
if (!readability(env)[side]) return {
|
|
538
|
-
status: "skip",
|
|
539
|
-
name,
|
|
540
|
-
detail: side === "host" ? "no host stylesheet is readable" : "this plugin's sheet is not mounted"
|
|
541
|
-
};
|
|
542
|
-
return ruleMentioned(env, check.match, side) ? {
|
|
543
|
-
status: "pass",
|
|
544
|
-
name,
|
|
545
|
-
detail: side === "host" ? "declared by a host rule" : "declared by this plugin's own sheet"
|
|
546
|
-
} : {
|
|
547
|
-
status: "fail",
|
|
548
|
-
name,
|
|
549
|
-
detail: "no rule mentions it",
|
|
550
|
-
reason: side === "host" ? `no host stylesheet declares ${check.match}` : `this plugin's own stylesheet does not declare ${check.match} — it was not injected`
|
|
551
|
-
};
|
|
552
|
-
}
|
|
553
|
-
default: return {
|
|
554
|
-
status: "fail",
|
|
555
|
-
name: "unknown check",
|
|
556
|
-
detail: String(check)
|
|
557
|
-
};
|
|
558
|
-
}
|
|
559
|
-
}
|
|
560
|
-
/** A contract with no checks is documentation only (a legacy alias we still accept). */
|
|
561
|
-
function noChecks(c, lang) {
|
|
562
|
-
return {
|
|
563
|
-
id: c.id,
|
|
564
|
-
label: labelOf(c, lang),
|
|
565
|
-
symptom: symptomOf(c, lang),
|
|
566
|
-
status: "info",
|
|
567
|
-
detail: lang === "zh" ? "无需运行时检查 —— 仅记录兼容用法" : "no runtime check — accepted for compatibility",
|
|
568
|
-
target: c.target,
|
|
569
|
-
sources: c.sources,
|
|
570
|
-
usedBy: c.usedBy,
|
|
571
|
-
checks: []
|
|
572
|
-
};
|
|
573
|
-
}
|
|
574
|
-
/**
|
|
575
|
-
* Run every contract against a probe environment.
|
|
576
|
-
*
|
|
577
|
-
* Only the FIRST failing check of a contract is reported: the later ones usually
|
|
578
|
-
* depend on it (no service ⇒ no methods on it), so listing them all would turn
|
|
579
|
-
* one rename into five red lines.
|
|
580
|
-
*/
|
|
581
|
-
function probeContracts(env, lang) {
|
|
582
|
-
return HOST_CONTRACTS.map((c) => {
|
|
583
|
-
const result = {
|
|
584
|
-
id: c.id,
|
|
585
|
-
label: labelOf(c, lang),
|
|
586
|
-
symptom: symptomOf(c, lang),
|
|
587
|
-
status: "pass",
|
|
588
|
-
detail: "",
|
|
589
|
-
target: c.target,
|
|
590
|
-
sources: c.sources,
|
|
591
|
-
usedBy: c.usedBy,
|
|
592
|
-
checks: []
|
|
593
|
-
};
|
|
594
|
-
if (c.checks.length === 0) return noChecks(c, lang);
|
|
595
|
-
const outcomes = [];
|
|
596
|
-
let firstFail;
|
|
597
|
-
for (const check of c.checks) {
|
|
598
|
-
let outcome;
|
|
599
|
-
try {
|
|
600
|
-
outcome = evaluate(env, check);
|
|
601
|
-
} catch (e) {
|
|
602
|
-
outcome = {
|
|
603
|
-
status: "fail",
|
|
604
|
-
name: check.kind,
|
|
605
|
-
detail: String(e),
|
|
606
|
-
reason: `${check.kind} check threw`
|
|
607
|
-
};
|
|
608
|
-
}
|
|
609
|
-
outcomes.push(outcome);
|
|
610
|
-
if (outcome.status === "fail" && firstFail === void 0) firstFail = outcome;
|
|
611
|
-
}
|
|
612
|
-
result.checks = outcomes.map((o) => `${o.status} · ${o.name} — ${o.detail}`);
|
|
613
|
-
if (firstFail !== void 0) {
|
|
614
|
-
result.status = "fail";
|
|
615
|
-
result.detail = `${firstFail.name} — ${firstFail.detail}`;
|
|
616
|
-
result.reason = firstFail.reason;
|
|
617
|
-
return result;
|
|
618
|
-
}
|
|
619
|
-
const ran = outcomes.filter((o) => o.status !== "skip");
|
|
620
|
-
if (ran.length === 0) {
|
|
621
|
-
result.status = "skip";
|
|
622
|
-
result.detail = outcomes.map((o) => `${o.name} — ${o.detail}`).join("; ");
|
|
623
|
-
return result;
|
|
624
|
-
}
|
|
625
|
-
result.status = ran.some((o) => o.status === "info") && ran.every((o) => o.status === "info") ? "info" : "pass";
|
|
626
|
-
const last = ran[ran.length - 1];
|
|
627
|
-
result.detail = `${last.name} — ${last.detail}`;
|
|
628
|
-
return result;
|
|
629
|
-
});
|
|
630
|
-
}
|
|
631
|
-
//#endregion
|
|
632
|
-
export { CONTRACT_GROUPS, DSH_FLOOR, HOST_CONTRACTS, OWN_SHEET_ATTR, OWN_SHEET_DATASET, UI_CSS, browserEnv, checkHostOnDisk, labelOf, markOwnSheet, meetsFloor, probeContracts, reportToMarkdown, resolveHostRoots, symptomOf, verdictOf, versionOf };
|