dsh-theme-endfield 1.2.3 → 1.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -6
- package/client.js +530 -115
- package/docs/audio-notifications.md +1 -1
- package/docs/design-language.md +1 -1
- package/docs/engineering-notes.md +59 -7
- package/docs/features.md +4 -1
- package/docs/preview.gif +0 -0
- package/docs/testing.md +38 -5
- package/index.js +7 -0
- package/lib/audio.js +30 -5
- package/lib/slots.js +3 -2
- package/package.json +8 -8
|
@@ -103,7 +103,7 @@ node scripts/build-sounds.js --check # 校验生成物与定义一致
|
|
|
103
103
|
|
|
104
104
|
| 平台 | 播放器 |
|
|
105
105
|
| --- | --- |
|
|
106
|
-
| Windows | `
|
|
106
|
+
| Windows | `powershell.exe`(5.1)→ `pwsh.exe`(`-EncodedCommand` + `Media.SoundPlayer`) |
|
|
107
107
|
| macOS | `afplay` |
|
|
108
108
|
| Linux | `paplay` → `aplay` |
|
|
109
109
|
|
package/docs/design-language.md
CHANGED
|
@@ -188,7 +188,7 @@ body:not(.theme-endfield-round) [class$='_iconButton'] { border-radius: 50% !imp
|
|
|
188
188
|
|
|
189
189
|
唯一需要 JS 介入的表面是**等高线画布**——canvas 描边不能是 CSS 变量,所以它由一个监听 `<body>` class 的 `MutationObserver` 触发重绘(顺带让「别的标签页改了配色」也能跟着变)。
|
|
190
190
|
|
|
191
|
-
配色切换后的实测像素占比(`test/verify-shots.js` 解码真实截图统计):
|
|
191
|
+
配色切换后的实测像素占比(`test/tools/verify-shots.js` 解码真实截图统计):
|
|
192
192
|
|
|
193
193
|
| 截图 | 黄色像素 | 青色像素 |
|
|
194
194
|
| --- | --- | --- |
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
|
|
63
63
|
### Host ↔ Client 数据流
|
|
64
64
|
|
|
65
|
-
1. **声明**(Host `index.js`):0.1.7-rc.1 导出 `Config`(`z.object({ 每个字段: z.string().default(...).volatile() })`);同时用 `ctx.inject(['settings'], sctx => sctx.effect(() => sctx.settings.configure({ auto: false }, ctx.fiber)))`
|
|
65
|
+
1. **声明**(Host `index.js`):0.1.7-rc.1 导出 `Config`(`z.object({ 每个字段: z.string().default(...).volatile() })`);同时用 `ctx.inject(['settings'], sctx => sctx.effect(() => sctx.settings.configure({ auto: false }, ctx.fiber)))` 关掉自动生成的设置页(本插件自带五组页面)。旧宿主则在 `settings.register` 存在时执行 `register('dsh-theme-endfield', schema, { applies:'live' })`。schema 每个字段都是**字符串**字段并带 `.default(...)`:default-ON 存 `'1'`(读作 `!== '0'`),default-OFF 存 `'0'`(读作 `=== '1'`);palette/radius/fps/speed 各存一个文档里写明的字面量。字符串化让三代存盘点位的值模型完全一致,client 的键表、面板与测试都不必随 transport 改动。
|
|
66
66
|
2. **写**(浏览器 `client.js`):设置面板每个 toggle 调用内部 `prefsSet(field, value)` → 只有当快照是 **durably served**(`status:'ready' && writable`,且 `mode` 不是显式的 `'memory'`)时才调用 transport 的 `set(field, value)`,Host 收到后原子写盘。`mode` 只是 **0.1.7-rc.\* 才有的可选字段**:`@deepseek-ai/dsh-client-ui-settings` 0.2.1-rc.2 连同 `persistence` 概念一起删掉了它,快照只剩 `{ status, value, base, user, revision, writable }`,写一律经 `remote.settings.mutate()` 落到 Host 文档,所以**缺省 `mode` 必须按可持久化处理**,只有显式的 `mode:'memory'`(0.1.7 非 loopback 页面)才截断写入。这正是 v1.2.2 在新版桌面「改了不保存」的根因:闸门要求 `mode === 'host'`,而新版恒为 `undefined`,于是每次 toggle 都只 held + 有界重试,约 10s 后丢弃,刷新即丢(启动报告即 `boot report … status= ready mode= undefined writable= true`)。只凭 `writable` 判写是另一个坑:host 模式的快照即便本命名空间**尚未被 served** 也会返回 `writable:true` 与 `status:'unavailable'`(`commit radius = round … status= unavailable` 就是这么打出来的)——旧代码照写不误、清了脏标记但什么都没落盘,刷新即丢。现在这种写被**拦下并标脏**(页面内仍生效),等快照在后续 ready 回相(Host 文档提交、镜像重载)时由 subscription 自动补写;`configForms.set()` 明确返回 `false`(Host 拒绝/跳过)时同样重新标脏等待下次回相,而不是假装写成功。
|
|
67
67
|
3. **读 / 生效**:transport 的 `getSnapshot().value` 就是已由 schema 校验并合并默认值的整段(client 再经 `prefsResolveSection()` 归一化到 34 个声明字段);主题层的 `isEnabled()` 与其它 getter 每次调用都 `prefsGet(field)` 现读本段,天然随值变化。
|
|
68
68
|
4. **订阅同步**:`form.subscribe(...)` / `scope.subscribe(...)` 在每次落盘/镜像变化时唤醒,client 再跑一遍 `reconcileFromPrefs()`,把主题开关(enabled → mount/unmount token+样式表)、圆角/配色 class、水印、等高线、雷霆大字重新对齐。这样同 profile 里**另一个窗口/设备**编辑落盘文件(或本轮写入被 Host 回相确认)都不需要刷新即可热生效。订阅返回的 disposer 现在会被保存并在 run 拆除时调用:`ConfigForm` 是 provider 拥有、跨插件共享的实例,漏掉它会把这一个监听器泄漏给同页面的下一次 run。
|
|
@@ -283,7 +283,7 @@ body{font-family:var( --dsw-font-family, -apple-system, … )}
|
|
|
283
283
|
|
|
284
284
|
### 等高线 worker 是特例
|
|
285
285
|
|
|
286
|
-
`src/contour-worker.js` + `src/contour-webgl.js` 由 `npm run build:worker` 把 9 个 kernel 函数抠出来,嵌成 `src/client/21-contour-worker.embed.js` —— **那是生成物,不要手改**。它整块是一行 `JSON.stringify` 出来的字符串,所以 `check.js` 的样式表护栏看不见它;改了 `src/contour-worker.js` 就必须重新生成。
|
|
286
|
+
`src/contour/contour-worker.js` + `src/contour/contour-webgl.js` 由 `npm run build:worker` 把 9 个 kernel 函数抠出来,嵌成 `src/client/21-contour-worker.embed.js` —— **那是生成物,不要手改**。它整块是一行 `JSON.stringify` 出来的字符串,所以 `check.js` 的样式表护栏看不见它;改了 `src/contour/contour-worker.js` 就必须重新生成。
|
|
287
287
|
|
|
288
288
|
### 门禁与报错
|
|
289
289
|
|
|
@@ -470,11 +470,11 @@ client.js is stale (first difference at line 4096); run npm run build:client
|
|
|
470
470
|
|
|
471
471
|
上面所有常量——21 条高度带、22 个凸起——都是**按桌面窗口的观感**调出来的,却按「每面积」施加:窗口缩到手机宽度,同样的线数与岛数挤进一小条竖带,嵌套环密到读作乱线。375×812 实测(暗色):**62 条路径 / 23,890px 墨长**,单屏叠出 8~9 层同心环。
|
|
472
472
|
|
|
473
|
-
杠杆选的是**层级数**:线距 = `span*2/LEVELS`,直接按比例缩放屏幕上的线间距。短边 **<640px** 时层级数从 20 向 10 线性递减(320px 触底,下限 6),凸起数从 22 向
|
|
473
|
+
杠杆选的是**层级数**:线距 = `span*2/LEVELS`,直接按比例缩放屏幕上的线间距。短边 **<640px** 时层级数从 20 向 10 线性递减(320px 触底,下限 6),凸起数从 22 向 10 同步递减(让岛屿保持分离而不是叠成靶心);**≥640px 逐字节回到出厂值**,桌面窗口输出不变。640 这个锚点取在「手机宽(360–430)与窄分屏不再主导短边」之上,320 触底保证最小可用窗口仍是一幅完整地形。
|
|
474
474
|
|
|
475
475
|
三处消费同一组函数(`contourLevelsFor` / `contourBumpsFor`,以视口短边为锚):布隆布局 `contourBuildCandidate`、覆盖率校验 `contourCoverageScore`、抽取 `contourExtract`。其中校验器必须按「该视口**实际将画的**层级数」算墨量代理——若仍按 `CONTOUR_LEVELS` 评分,10 级的小屏会被要求 2 倍墨量,重抽循环每次都触顶。
|
|
476
476
|
|
|
477
|
-
改造后 375×812 实测:路径数降到 ~54(另有种子随机性),最薄分区墨迹 **3.56%**(8×5 网格,0 空白格),嵌套环从 8~9 层降到 3~4 层。回归锁在 `test/contour-density.test.js`(≥640px 断言出厂值逐值相等;小屏断言按公式递减且能完整成图)。注意 worker 内核里 `src/contour-worker.js` 有一份**手工镜像**的同名函数——构建脚本只抠函数不抠常量,闭包名缺失会在 worker 首帧抛 ReferenceError(见 worker 一节的教训)。
|
|
477
|
+
改造后 375×812 实测:路径数降到 ~54(另有种子随机性),最薄分区墨迹 **3.56%**(8×5 网格,0 空白格),嵌套环从 8~9 层降到 3~4 层。回归锁在 `test/contour-density.test.js`(≥640px 断言出厂值逐值相等;小屏断言按公式递减且能完整成图)。注意 worker 内核里 `src/contour/contour-worker.js` 有一份**手工镜像**的同名函数——构建脚本只抠函数不抠常量,闭包名缺失会在 worker 首帧抛 ReferenceError(见 worker 一节的教训)。
|
|
478
478
|
|
|
479
479
|
### 重启动画的首帧曾是空转
|
|
480
480
|
|
|
@@ -924,7 +924,7 @@ div.pI_x6G_centerCol
|
|
|
924
924
|
|
|
925
925
|
**为什么第一次"修完"看起来像没生效。** 在浏览器控制台里量了一次真实 DOM,得到的三个值把三种可能一次分清了:`HASNEW true`(我改的规则**已经到页面**,所以不是缓存/没刷新)、`ACCENT #fff500`(变量有值,不是变量问题)、`BG rgb(36, 38, 36)`(最终仍是上游灰底)+祖先链里那个 `DIV.`。**一条"已经生效但什么都没匹配到"的规则,和一条"根本没送到浏览器"的规则,症状完全一样**;不先在页面里量这三个值,只会在"是不是缓存"和"选择器又写错了"之间来回猜——本次就是这样多花了一整轮。
|
|
926
926
|
|
|
927
|
-
**为什么整套验证都没发现。** `test/shoot.js` 的截图夹具先后把标签直接挂在 `.wSkVaW_header` 和 `.wSkVaW_headerActions` 底下,**两次都是照着当时的选择器搭的**;`test/preset-chip.test.js` 的夹具也一样漏了那层无 class 包裹层。于是选择器在夹具上命中、截图正常、测试全绿,而真实页面一个元素都没匹配到。这是本次最值得记的教训:**夹具一旦是为了"让选择器通过"而搭的,它就从验证退化成了同义反复。**
|
|
927
|
+
**为什么整套验证都没发现。** `test/tools/shoot.js` 的截图夹具先后把标签直接挂在 `.wSkVaW_header` 和 `.wSkVaW_headerActions` 底下,**两次都是照着当时的选择器搭的**;`test/preset-chip.test.js` 的夹具也一样漏了那层无 class 包裹层。于是选择器在夹具上命中、截图正常、测试全绿,而真实页面一个元素都没匹配到。这是本次最值得记的教训:**夹具一旦是为了"让选择器通过"而搭的,它就从验证退化成了同义反复。**
|
|
928
928
|
|
|
929
929
|
**最终修法:不再数层数,改用徽章自身的特征。**
|
|
930
930
|
|
|
@@ -990,10 +990,62 @@ fO69Vq_addButton / _3nPmjq_addButton (旧 `:not()` 排除的两个)
|
|
|
990
990
|
| 输入区 `+` hover(暗色) | 18.31:1(本来正常) | 18.31:1(**未因收敛作用域而丢失**) |
|
|
991
991
|
| 输入区 `+` 常态墨色 | `#fff500` | `#fff500`(作用域仍命中) |
|
|
992
992
|
|
|
993
|
-
`test/hover-check.js` 现在同时守这三面(编辑按钮 / 模型页添加按钮及其容器 / 输入区 `+`),`test/selector-guard.test.js` 新增第三条断言:**任何裸的 `[class*='_add']` 都要报错**,把这条钩子钉在输入区作用域里。
|
|
993
|
+
`test/tools/hover-check.js` 现在同时守这三面(编辑按钮 / 模型页添加按钮及其容器 / 输入区 `+`),`test/selector-guard.test.js` 新增第三条断言:**任何裸的 `[class*='_add']` 都要报错**,把这条钩子钉在输入区作用域里。
|
|
994
994
|
|
|
995
995
|
> 亮色模式本来就不受影响(该规则是 `body[data-ds-dark-theme]` 限定),测试也如实只在暗色下报红——这本身就是"作用域写对了"的证据。
|
|
996
996
|
|
|
997
|
+
### 九类:`will-change` 也建立 containing block(审批白条塌成一条线)
|
|
998
|
+
|
|
999
|
+
审批白条是 `position: fixed; inset: 0` 的全屏遮罩 + 通栏纸带,靠「遮罩只在纸带上下露出」还原参考图。这条设计有一个从未写进铁律的前提:**面板到视口之间,没有祖先构成 containing block**。旧注释其实意识到了这件事,但结论写反了——它说「若将来有祖先带 transform/filter,纸带只是退回文档流,位置降级,不会坏」。
|
|
1000
|
+
|
|
1001
|
+
DSH 0.2.2-rc.1 给 composer seat 加了 `will-change: transform`。按 CSS Will Change 的规定,**会让元素生成 containing block 的属性出现在 `will-change` 里时,元素必须真的生成 containing block**——所以它与真 transform 等价。审批面板替换输入框、正好住在这个 seat 内部,于是 fixed 的参照系从视口变成 seat 的 padding box;fixed 又让面板脱离文档流,seat 唯一在流内的子元素随之消失、高度塌成 0:
|
|
1002
|
+
|
|
1003
|
+
| 量 | 修复前 | 修复后 |
|
|
1004
|
+
| --- | --- | --- |
|
|
1005
|
+
| seat 的计算值 `will-change` | `transform` | `auto` |
|
|
1006
|
+
| 白条(fixed 层)rect | `720×0`(列宽 × 0 高,贴在窗口底边) | `1200×800`(整个视口) |
|
|
1007
|
+
| 卡片 rect | `706..895`,下半截被视口裁掉 | `306..495`,居中 |
|
|
1008
|
+
| 胶囊 rect | 落在视口外,点不到 | `190×41`,`y=430` |
|
|
1009
|
+
|
|
1010
|
+
「退化而不是坏掉」错在**以为 fixed 会失效退回静态定位**。fixed 不会退回:它照旧按 containing block 布局,只是那个盒子刚被自己清空。于是症状不是「位置偏了一点」,而是「整个对话框只剩一行字」。现场为此多花了 152 秒才点下审批(主题关闭时同样的操作 1–2 秒)。
|
|
1011
|
+
|
|
1012
|
+
修法的方向也只能反过来:**CSS 无法从 fixed 后代内部逃出 containing block**,补丁必须打在祖先上,而且只在需要时打——
|
|
1013
|
+
|
|
1014
|
+
```css
|
|
1015
|
+
body:has([data-approval-key]) :is([data-composer-seat], [class$='_composerSeat']) {
|
|
1016
|
+
will-change: auto !important;
|
|
1017
|
+
}
|
|
1018
|
+
```
|
|
1019
|
+
|
|
1020
|
+
`!important` 不是保险,是必需的:上游那条是 `.<hash>_root[data-phase=active] .<hash>_composerSeat`(0,3,0),本规则(0,2,1)压不过。`:has()` 让上游的合成提示只在「没有审批在屏幕上」的帧里失效,代价压到最小。两个钩子取并集的理由同八类:`[class$=]` 在上游给该元素追加第二个类时静默失效,`[data-composer-seat]` 是上游自己声明的 e2e 锚点。
|
|
1021
|
+
|
|
1022
|
+
这同时解释了为什么**报告者给的补丁能修好、但会退化**:把 root 改成 `position: relative` + 透明背景,面板回到文档流,功能立刻恢复,但通栏纸带被收进聊天列宽、上下遮罩一并消失——那是「把设计也一起删了」,不是等价修复。修在祖先上,两样都留着。
|
|
1023
|
+
|
|
1024
|
+
### 十类:兜底按「属性清单」打,不按已知元凶打(自动授权审查的现场报告)
|
|
1025
|
+
|
|
1026
|
+
#41 落地次日,评论区来了第二份白条塌陷报告:开着「自动授权审查」实验性插件,被自动审查拒绝的工具调用要等人工审批,弹窗装上主题后无法显示、无法点击,关主题即恢复。现场截图的形态与 #41 分毫不差——底部只活着一行「● 等待审批」。
|
|
1027
|
+
|
|
1028
|
+
对 0.2.2-rc.1 的安装包逐层核对(ui-approval / ui-conversation / ui-session 的 bundle)后确认:**自动审查走的就是同一条 `approval/request` 瀑布、同一个 composer 座位里的同一个面板**,座位祖先链上除 `will-change` 外也没有第二个元凶。真正能解释现场的是版本:报告者装主题的时间在 v1.2.4 发布之前,手里还是没有 #41 的旧构建。但这条线索指出了 #41 修法的结构性弱点——它只按「已知元凶」释放了 `will-change` 一个属性、座位一个元素,而白条塌陷的充分条件是**任意祖先的任意致产属性**。上游任何一次重构(把 transform 挪到包裹层、给滚动层加 container-type)都会让同一条塌陷回来。
|
|
1029
|
+
|
|
1030
|
+
所以兜底改成按属性清单打:面板在屏期间(`body:has([data-approval-key])`),对座位和它已核实的结构层——`[data-conversation-scroll]`(会话滚动体,JSX 实测属性)、`[data-conversation-content]`(会话根,同)、`_centerCol` / `_frame`(与等高线图纸共用的后缀钩子)——一并释放全部致产属性:`transform`、`filter`、`backdrop-filter`、`perspective`、`container-type`、`content-visibility`、`contain`。这些层在 0.2.2-rc.1 上都没有致产值,规则今天是空操作;代价只存在于「面板在屏」的帧里,而那时应用正被白条遮罩挡着。`test/approval-band-transform.test.js` 为此加了两条白条:座位干净、祖先分别带 `container-type: inline-size` 与 `transform`,配合仍会塌陷的对照组,证明释放真的生效而不是「全页没陷阱」的假阳性。附带修掉一个顺藤摸出来的真钩子:带主体(图标 + 名称)的审批卡类名是 `<hash>_card <hash>_withSubject`,`[class$='_card']` 在第二个类 appended 后静默失配——卡片钩子放宽为 `[class*='_card']`(root 的唯一子元素就是卡,不可能误中)。
|
|
1031
|
+
|
|
1032
|
+
**教训**:防御性规则要么按故障的充分条件枚举(所有致产属性 × 全部结构层),要么干脆别写;只覆盖已知名元的兜底给后来者一种「已经防住了」的错觉,而塌陷的充分条件集合在上游任何一次重构后都会变大。
|
|
1033
|
+
|
|
1034
|
+
### 十一类:高亮不满宽是三层内缩的算术(工作区会话行)
|
|
1035
|
+
|
|
1036
|
+
评论区另一份独立报告:左侧工作区的会话行,选中 / 悬停的强调色洗不满行盒,「两边颜色不是填满的」。对照 0.2.2-rc.1 的 bundle 把行盒到侧栏两缘之间的层全数核出,一共三层:
|
|
1037
|
+
|
|
1038
|
+
1. **行自带 3px 内缩**——`.*_projectRow/. *_sessionRow` 携带 `border-inline: var(--dsh-sidebar-paint-inset) solid transparent`(3px)+ `background-clip: padding-box`,洗色永远画不到描边下面。主题自己的 `background:` 简写会把 clip 重置回 border-box,所以**选中和悬停其实早就贴到了行盒边缘**;没贴边的观感来自下面两层(以及 app 用 longhand 画的 menuOpen 态)。
|
|
1039
|
+
2. **侧栏栏根 8px 内边距**——SidebarRoot 的根节点 `padding: 6px var(--dsh-sidebar-inline-padding)`,行盒从 8px 处才开始。
|
|
1040
|
+
3. **列表右侧滚动条槽**——`.*_list` 的 `margin-right: var(--dsh-session-list-scrollbar-offset)` + `padding-right: calc(var(--dsh-session-list-edge-inset) - var(--dsh-session-list-scrollbar-width) - var(--dsh-session-list-scrollbar-offset))`,行盒右缘距列缘还差 `inline-padding + edge-inset − scrollbar-width`。
|
|
1041
|
+
|
|
1042
|
+
前两版修法都在重排几何、都被打回。第一版把负外边距打在**行**上——几何测试全绿(行盒 rect [0, 232]),现场却是「圆角模式下高亮还是直角」:`getBoundingClientRect` 量不出**裁剪**,会话列表是滚动容器(`overflow-y: auto` 使 `overflow-x` 计算为 auto),在**自己的 padding box** 处裁剪绘制与命中测试,圆角模式(app 原生 12px 圆角)的两端圆弧被齐齐切平,还顺带获得一段横向可拖拽区。第二版把外扩挪到列表上(负 margin + padding 归零 + 全套内层补偿)圆角是保住了,但整座补偿算术(骨架行、空态、显示更多按钮、rail 变体的溢出裁剪、隐藏滚动条)都悬在「裁剪边界恰好等于列缘」这一根独苗上。探针还接连否决了两条「聪明」路:`overflow-clip-margin` 只在元素该轴本身是 `clip` 时才被 Chromium 认(与滚动容器轴混用一律忽略,实测),滚动上移到 listArea 则把坑原样搬到上一层。
|
|
1043
|
+
|
|
1044
|
+
**终版(作者裁定:「直接逆向一下,看下原本是怎么做的,在原本基础上换颜色算了」)回到原生的机制。** 逆向结论:原生高亮**零几何**——每行自带 3px 透明描边框 + `background-clip: padding-box`,选中态就一句 `background-color` 换色;原生淡色下 3px 内缩读作有意的胶囊设计,主题的强高亮色一刷,未上色的描边框把栏底透出来,这才是「两边不满」的显形来源。于是修法留在原生结构内、只动颜色:`border-inline-color` 刷成同一个高亮色,高亮即贴满行盒——栏内边距、滚动条槽、标题线(8+3+9+16=36px)、`--dsh-workspace-indent` 算术全部原样,圆角随原生 border-box 走(圆角模式 12px、方角模式被 blanket pass 归零),绘制全部发生在行盒内、滚动容器裁剪区内,**裁剪问题被结构性地排除而不是被对抗**。app 的 menuOpen 态(longhand 换色)一并纳入主题换色,避免「描边主题色 + 内部原生灰」的割裂。`test/sidebar-row-wash.test.js` 的断言策略是**双 boot 对照**:主题关闭先量原生基线,圆角 / 方角两个主题态再量一次,几何(行左缘 / 行高 / 标题线 / 列表盒与全部 CSS 声明)逐值一致——「换颜色不动几何」的可执行定义;颜色断言描边色 === 背景色,圆角断言 12px 保留 / 归零。
|
|
1045
|
+
|
|
1046
|
+
顺带钉死一条 Blink 怪癖(对照测试差点被它假失配搞挂):**`::-webkit-scrollbar` 的级联不按特异性、不按 `!important`、也不可被后插入的样式表翻转**——页面 `#list::-webkit-scrollbar{width:5px !important}` 输给后注入的主题全局 `::-webkit-scrollbar{width:10px}`,boot 之后再 append 一条 5px 全局规则同样翻不掉(实测 gap 恒 10px)。主题的全局滚动条规则一旦注入就统治文档的全部滚动容器占位,这也解释了真实 app 中列表占位是 10px(app 自己的 `--dsh-session-list-scrollbar-width` 计划值是 5px)——它是主题 v1.2.4 起的既成行为。对照测试因此不跨 boot 比行宽(占位差会假失配),只比滚动条碰不到的左半边,行宽改用列表盒内部一致性断言(行右缘 = 列表 client 右缘 − 右内边距)。
|
|
1047
|
+
|
|
1048
|
+
|
|
997
1049
|
---
|
|
998
1050
|
|
|
999
1051
|
## 验证方法论
|
|
@@ -1026,7 +1078,7 @@ fO69Vq_addButton / _3nPmjq_addButton (旧 `:not()` 排除的两个)
|
|
|
1026
1078
|
|
|
1027
1079
|
`settings-buttons.test.js` 读计算样式,所以它用同特异度的 `.HOVERPROBE` 类替代 `:hover`(类与伪类特异度同为 0,1,0,层叠结果不变)。这是合理的层叠等价,但**反向对照暴露了它的边界**:把主题规则里真正的 `:hover` 那一半删掉,该测试**照样全绿**——因为 `.HOVERPROBE` 那一半独自扛住了。
|
|
1028
1080
|
|
|
1029
|
-
因此补了 `test/hover-check.js`:通过 DevTools 协议**真的移动鼠标**到按钮上,再截图量字形与填充的对比度。同样的反向对照下,它如实报出 1.05:1 / 2.61:1,与反馈截图逐位吻合。
|
|
1081
|
+
因此补了 `test/tools/hover-check.js`:通过 DevTools 协议**真的移动鼠标**到按钮上,再截图量字形与填充的对比度。同样的反向对照下,它如实报出 1.05:1 / 2.61:1,与反馈截图逐位吻合。
|
|
1030
1082
|
|
|
1031
1083
|
### 做「有字 / 无字」差分时要保留一个零宽空格
|
|
1032
1084
|
|
package/docs/features.md
CHANGED
|
@@ -96,7 +96,7 @@
|
|
|
96
96
|
- **线** = marching squares 在 21 个等间距高度上取等值线
|
|
97
97
|
- **连线** = 线段按边 ID 缝合成连续折线,再以二次曲线绘制
|
|
98
98
|
|
|
99
|
-
**密度随视口自适应**:上面的 21 级 / 22 岛是按桌面窗口调的,按「每面积」施加在窄窗口就会读作一堆乱线。短边低于 640px
|
|
99
|
+
**密度随视口自适应**:上面的 21 级 / 22 岛是按桌面窗口调的,按「每面积」施加在窄窗口就会读作一堆乱线。短边低于 640px 时,层级数与岛屿数都向 10 随宽度线性递减(320px 触底),线距随之拉开;**短边 ≥640px 逐字节回到出厂密度**,桌面输出不变。覆盖率验证器(accept-or-reroll)按「该视口实际将画的层级数」评分,小窗的无空白区保证不变。见 `contourLevelsFor` / `contourBumpsFor`。
|
|
100
100
|
算法细节与实测数据见 [engineering-notes.md § 等高线](engineering-notes.md#等高线背景).
|
|
101
101
|
|
|
102
102
|
**图层挂在应用外框内部**,`inset:0; z-index:0`,落在「外框底色之上、所有定位子元素之下」。正文永远在图层之上,前景对比度不受影响。挂载期间会把外框、对话列、右侧栏列(0.1.x 叫详情列)与侧栏的不透明底色置为透明(`:has()` 守卫使功能关闭时全部规则失效)。
|
|
@@ -286,10 +286,13 @@
|
|
|
286
286
|
| 会话头部预设徽章(agent preset,如「创造模式」) | 上游把徽章移进 `_headerActions` 插槽的包裹层里,主题的 `>` 选择器失配,退回默认灰胶囊 | 恢复强调色填充 + 黑字,**尺寸沿用上游**(不撑宽) |
|
|
287
287
|
| 审批弹窗(「等待审批」) | 上游是塞在输入区里的一张圆角描边小卡 | 重绘为**贯穿屏幕左右白条 + 上下遮罩**的居中确认框,按钮改为胶囊(拒绝=深色+✕,允许一次=信号黄+◎),见下 |
|
|
288
288
|
| 完全权限确认框(「确认启用完全权限?」) | 共享 Modal 的居中圆角小卡 | 同款白条 + 上下遮罩,取消/启用胶囊按钮,见下 |
|
|
289
|
+
| 工作区会话行高亮(hover / 选中) | 原生高亮零几何:每行自带 3px 透明描边框(`border-inline` + `background-clip: padding-box`),选中态只换一句 `background-color`;原生淡色下内缩读作有意设计,主题的强高亮色一刷,未上色的描边框把栏底透出来,两侧显缝(「两边颜色不是填满的」) | 在原生结构内只换颜色:`border-inline-color` 刷成同一个高亮色,高亮贴满行盒;栏内边距、滚动条槽、文字线全部保持 app 原生不动,圆角模式保留原生 12px 圆角、方角模式直角;绘制全部在行盒内、滚动容器裁剪区内,圆角不再被切;menuOpen 态一并换色,见下 |
|
|
290
|
+
| 审批白条 containing block 兜底 | #41 只释放了输入区座位的 `will-change`;实测 0.2.2-rc.1 里座位祖先链没有别的元凶,但「自动授权审查」的用户报告证明这类塌陷会真实发生 | 面板挂载期间对座位**及其已核实的结构层**(`[data-conversation-scroll]`、`[data-conversation-content]`、`_centerCol`、`_frame`)一并释放全部产生 containing block 的属性(transform / filter / backdrop-filter / perspective / container-type / content-visibility / contain);附带修复:带主体(图标+名称)的审批卡类名是 `<hash>_card <hash>_withSubject`,卡片钩子从 `$=` 放宽为 `*=` 才能命中 |
|
|
289
291
|
|
|
290
292
|
### 审批弹窗:全屏白条 + 上下遮罩
|
|
291
293
|
|
|
292
294
|
工具越权执行时弹出的 `[data-approval-key]` 面板被重绘成参考图那种形态:**不透明纸色横条从屏幕左缘贯到右缘、垂直居中,页面其余部分只有上下被压暗**——实现上没有加任何 DOM:面板自己的 root 变成 fixed 全屏 flex 层,它的半透明黑底就是遮罩,中间的白条不透明地盖住横带,遮罩自然只剩上下两截。文字居中,「等待审批」保留状态点但去掉警示底色。两个按钮改成终末地胶囊(左取消深灰配白 ✕、右确认信号黄配 ◎,墨字对比度与主题其它实心芯片同一条 AA 约束)。**圆角模式同样保持胶囊**(与余额药丸一致),且所有选择器都钉在语义锚点上(`data-approval-key` + `[class*='_card']` 等 CSS-module 后缀),上游重哈希不会失效——`test/selector-guard.test.js` 钉住这三个钩子。
|
|
295
|
+
**挂载期间的 containing block 兜底(#41 的延伸)**:白条是 `position: fixed`,座位到视口之间的**任何**产生 containing block 的祖先都会把白条重新压扁成一条线(#41 的实测就是输入区座位的 `will-change: transform`)。面板在屏时应用本来就处于模态阻塞,主题因此同时释放座位与已核实结构层上的全部致产属性;`test/approval-band-transform.test.js` 用「座位自身干净、祖先带 container-type / transform」的两个白条夹住这条规则——对照组塌陷、这两条满屏,才证明释放真的生效。
|
|
293
296
|
|
|
294
297
|
### 完全权限确认框:同一形态
|
|
295
298
|
|
package/docs/preview.gif
ADDED
|
Binary file
|
package/docs/testing.md
CHANGED
|
@@ -91,6 +91,38 @@ _centerCol > _header > _titleRow > _titleCluster > _headerActions
|
|
|
91
91
|
|
|
92
92
|
---
|
|
93
93
|
|
|
94
|
+
## 审批白条与祖先的 containing block(issue #41)
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
node test/approval-band-transform.test.js # 真实浏览器:三个座位,同一份白条
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**`approval-band-transform.test.js`** 守的是「CSS 写对了、位置却归浏览器管」这一类失效。审批白条的设计是 `position: fixed; inset: 0` 铺满视口、卡片被压成通栏纸带,两者之差就是「上下有遮罩」;但 fixed 只在**祖先不构成 containing block** 时才落到视口。DSH 0.2.2-rc.1 给 composer seat 加了 `will-change: transform`——按 CSS Will Change 的规定,会让元素生成 containing block 的属性写进 `will-change` 就必须真的生成——而审批面板正好替换输入框、住在这个 seat 里。
|
|
101
|
+
|
|
102
|
+
失效的样子非常安静:fixed 让面板脱离文档流 → seat 的**唯一**在流内子元素消失 → seat 高度塌成 0 → 白条解析成「列宽 × 0 高」的一条线,卡片以这条零高线居中,下半截被视口裁掉,只剩顶部「● 等待审批」。现场反馈是同一台机器上审批从 1–2 秒变成 152 秒。
|
|
103
|
+
|
|
104
|
+
修法只能打在祖先上(CSS 无法从 fixed 后代内部逃出 containing block),且限定在面板存在时生效:
|
|
105
|
+
|
|
106
|
+
```css
|
|
107
|
+
body:has([data-approval-key]) :is([data-composer-seat], [class$='_composerSeat']) {
|
|
108
|
+
will-change: auto !important;
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
夹具同时挂三个座位,**除座位外完全一样**——少一个,断言就会为错误的理由通过:
|
|
113
|
+
|
|
114
|
+
| 座位 | 钩子 | 用途 | 实测 |
|
|
115
|
+
| --- | --- | --- | --- |
|
|
116
|
+
| `#seatRaw` | 带 `will-change`,两个钩子都不匹配 | 反向对照:修复前的形状 | 白条 `720×0`,卡片下沿越界被裁 |
|
|
117
|
+
| `#seat` | `[class$='_composerSeat']` | 类名后缀钩子 | 白条 `1200×800`,胶囊 `190×41` 在视口内 |
|
|
118
|
+
| `#seatAttr` | `[data-composer-seat]` | 上游自己声明的 e2e 锚点 | 同上 |
|
|
119
|
+
|
|
120
|
+
四条断言缺一不可:反向对照必须**仍然塌成一条线**(否则夹具不再复现 #41,其余断言就是空过);两个钩子都要把 `will-change` 降成 `auto` 并让白条回到视口大小;两颗胶囊必须落在视口内且可命中(`≥150×24`);遮罩层必须仍高于纸带(否则「上下有遮罩」这个形状本身没了)。
|
|
121
|
+
|
|
122
|
+
> 变异验证:把规则里的 `will-change: auto` 换成 `transform` → 第 2 段断言红(`got transform`),证明这条测试量的确实是那一条声明,不是纸张颜色或别的巧合。
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
94
126
|
## 样式表投递与幂等
|
|
95
127
|
|
|
96
128
|
```bash
|
|
@@ -126,8 +158,8 @@ npm run test:corners # 源码级:stadium/圆形规则
|
|
|
126
158
|
node test/palette-contrast.test.js # 两套配色每个角色的对比度(从真实 CSS 里读值)
|
|
127
159
|
node test/palette-switch.test.js # 真实浏览器里切换配色,22 项断言
|
|
128
160
|
node test/settings-buttons.test.js # 强调色底上的按钮文字对比度(32 项,含回归守卫)
|
|
129
|
-
node test/hover-check.js
|
|
130
|
-
node test/verify-shots.js
|
|
161
|
+
node test/tools/hover-check.js # 用 CDP 真的移动鼠标,验证真实 :hover 规则(3 个面,24 项)
|
|
162
|
+
node test/tools/verify-shots.js # 解码四张截图统计强调色像素
|
|
131
163
|
```
|
|
132
164
|
|
|
133
165
|
**`palette-contrast.test.js`** 从 `client.js` 的实际样式表里把变量读出来再验算。覆盖 27 项:实心底 + 墨色字达 AA、悬停底同样达标、回合状态四个色标对**两种**可能底色都达 AA、暗色强调色作图标墨色 ≥3、两配色的等高线合成对比度相差 ≤20% 且高于 1.06 感知下限、hero 光晕不比原品牌蓝更响(该 `*_heroGlow` 模块在 0.2 已不存在,规则保留为自愈钩子)、两配色确实不同、强调色写成 6 位十六进制,以及**武陵青的亮度必须落在 45%–56% 区间且留在青碧色轴上**。
|
|
@@ -323,7 +355,7 @@ node test/loader-late-prefs.test.js # 设置节晚于 apply() 到达时,动
|
|
|
323
355
|
|
|
324
356
|
```bash
|
|
325
357
|
node test/thunder-edges.test.js # 边沿/生命周期/样式契约
|
|
326
|
-
node test/thunder-shot.js
|
|
358
|
+
node test/tools/thunder-shot.js # 真实渲染截图 + 像素对比度断言
|
|
327
359
|
node test/thunder-dismiss.test.js # 点击关闭:真实指针事件 + 命中测试 + 监听器核账
|
|
328
360
|
```
|
|
329
361
|
|
|
@@ -356,7 +388,8 @@ node test/contour-perf.test.js # 稳态帧成本(n=80)
|
|
|
356
388
|
node test/contour-density.test.js # 视口密度自适应(≥640px 出厂值不变,小屏递减)
|
|
357
389
|
node test/contour-bounds.test.js # 扫描边界与全扫的逐坐标等价
|
|
358
390
|
node test/contour-worker.test.js # worker 内核与主线程一致
|
|
359
|
-
node test/
|
|
391
|
+
node test/contour-worker-budget.test.js # worker 背板预算:超大视口缩 dpr,普通视口逐位不变
|
|
392
|
+
node test/tools/shoot.js # 输出亮/暗 × 两配色共四张截图供肉眼复核
|
|
360
393
|
```
|
|
361
394
|
|
|
362
395
|
**`contour-render.test.js`** 覆盖:关闭时不创建节点且**不改动应用底色**;开启时画布挂进应用外框、图层确实上色、不透明底色已让位;正文颜色不变且仍可命中测试(图层在其**之下**);动画开启时像素随时间变化、关闭后**完全静止**、**重新开启后再次变化**;暗色仍上色;拆除后节点归零。
|
|
@@ -381,7 +414,7 @@ node test/shoot.js # 输出亮/暗 × 两配色共四张截
|
|
|
381
414
|
|
|
382
415
|
该脚本对 24 / 60 / 120 fps **逐个**比预算,并在第一个超标处失败——所以真正卡住它的门槛是 **8.3ms(120fps)**,不是 41.7ms:报数时别只看「41.7ms 预算」那一行。
|
|
383
416
|
|
|
384
|
-
> **提取到的名字必须跟着 `client.js` 走。** 这些「原样切出」的脚本按名字抓函数与常量,切出来少一个就是页面里的 `ReferenceError`,而它只会表现为 `no result` / 一行 `CONTOUR_... is not defined`。新增或重命名内核里的函数与常量时(例如 `contourStepFor`、`CONTOUR_MAX_CELLS`、`CONTOUR_MIN_BUMPSAMPLES`、`CONTOUR_SMOOTH_*`),要同步 `contour-smoothness` / `contour-cusps` / `contour-bounds` / `contour-perf` 的名单、`scripts/build-contour-worker.js` 的 `names`,以及 `src/contour-worker.js` 顶部手工镜像的常量——worker 里少一个常量同样是运行时 `ReferenceError`。
|
|
417
|
+
> **提取到的名字必须跟着 `client.js` 走。** 这些「原样切出」的脚本按名字抓函数与常量,切出来少一个就是页面里的 `ReferenceError`,而它只会表现为 `no result` / 一行 `CONTOUR_... is not defined`。新增或重命名内核里的函数与常量时(例如 `contourStepFor`、`CONTOUR_MAX_CELLS`、`CONTOUR_MIN_BUMPSAMPLES`、`CONTOUR_SMOOTH_*`),要同步 `contour-smoothness` / `contour-cusps` / `contour-bounds` / `contour-perf` 的名单、`scripts/build-contour-worker.js` 的 `names`,以及 `src/contour/contour-worker.js` 顶部手工镜像的常量——worker 里少一个常量同样是运行时 `ReferenceError`。
|
|
385
418
|
|
|
386
419
|
---
|
|
387
420
|
|
package/index.js
CHANGED
|
@@ -884,6 +884,13 @@ function installAudio(ctx, settingsScope) {
|
|
|
884
884
|
const key = `${sessionId}:${data.turn}`;
|
|
885
885
|
if (hasVisibleText(data.message)) terminals.set(key, true);
|
|
886
886
|
else if (!terminals.has(key)) terminals.set(key, false);
|
|
887
|
+
/* The map is only reaped by agent/turn-stopping, and a turn that ends any
|
|
888
|
+
other way (agent/error, a destroyed session) never fires it — in a host
|
|
889
|
+
process that runs for days those entries would accumulate forever. Bound
|
|
890
|
+
it FIFO like playedDone below: the entries evicted earliest belong to the
|
|
891
|
+
oldest turns, and by the time 512 newer turns have been recorded, a
|
|
892
|
+
turn-stopping for the evicted one is not a live question any more. */
|
|
893
|
+
if (terminals.size > 512) terminals.delete(terminals.keys().next().value);
|
|
887
894
|
});
|
|
888
895
|
|
|
889
896
|
/* The two "a human has to do something" triggers, and the ONLY things that
|
package/lib/audio.js
CHANGED
|
@@ -82,6 +82,20 @@ function pathHash(value) {
|
|
|
82
82
|
return h.toString(16);
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
+
/** Short stable hash of file CONTENT for the cache-file name: the same FNV-1a
|
|
86
|
+
* over the bytes. Content, not just size, has to be in the key — a replaced
|
|
87
|
+
* sound with an identical duration (e.g. a re-rendered bundled wav) is
|
|
88
|
+
* byte-length-identical, and a name-only key would serve the previous file's
|
|
89
|
+
* scaled copy forever. The wavs are a few hundred KB, so this is microseconds. */
|
|
90
|
+
function bytesHash(bytes) {
|
|
91
|
+
let h = 0x811c9dc5;
|
|
92
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
93
|
+
h ^= bytes[i];
|
|
94
|
+
h = Math.imul(h, 0x01000193) >>> 0;
|
|
95
|
+
}
|
|
96
|
+
return h.toString(16);
|
|
97
|
+
}
|
|
98
|
+
|
|
85
99
|
/**
|
|
86
100
|
* The audio runtime: preference view, sound resolution, volume cache, playback
|
|
87
101
|
* and the diagnostic ring the settings page reads.
|
|
@@ -105,6 +119,8 @@ class AudioRuntime {
|
|
|
105
119
|
/** Bounded diagnostic ring: what the plugin saw and what it did about it. */
|
|
106
120
|
this.diag = [];
|
|
107
121
|
this.warnedNoSubprocess = false;
|
|
122
|
+
/** One-shot guard so an unwritable volume cache says so once, not per play. */
|
|
123
|
+
this.warnedCacheDir = false;
|
|
108
124
|
}
|
|
109
125
|
|
|
110
126
|
/** Record one diagnostic line and echo it to the host console. */
|
|
@@ -255,14 +271,23 @@ class AudioRuntime {
|
|
|
255
271
|
if (scaled === bytes) return file; // non-rescalable format: original level
|
|
256
272
|
try {
|
|
257
273
|
fs.mkdirSync(CACHE_DIR, { recursive: true });
|
|
258
|
-
/* The cache key covers the SOURCE DIRECTORY
|
|
259
|
-
|
|
260
|
-
same-named, same-length file from the desktop
|
|
261
|
-
|
|
262
|
-
|
|
274
|
+
/* The cache key covers the SOURCE DIRECTORY (basename + size alone would
|
|
275
|
+
let a turn-done.wav from the custom dir collide with an unrelated
|
|
276
|
+
same-named, same-length file from the desktop) AND the source content
|
|
277
|
+
(a replaced file with an identical duration is byte-length-identical,
|
|
278
|
+
and only the content distinguishes its scaled copy from the old one). */
|
|
279
|
+
const target = path.join(CACHE_DIR,
|
|
280
|
+
`${path.basename(file, path.extname(file))}-v${volume}-${bytes.length}-${bytesHash(bytes)}-${pathHash(file)}.wav`);
|
|
263
281
|
if (!fs.existsSync(target)) fs.writeFileSync(target, scaled);
|
|
264
282
|
return target;
|
|
265
283
|
} catch (error) {
|
|
284
|
+
/* An unwritable cache dir (shared/stale tmp on POSIX) must not disable
|
|
285
|
+
volume scaling SILENTLY — say so once, then keep degrading to the
|
|
286
|
+
unscaled file like every other failure here. */
|
|
287
|
+
if (!this.warnedCacheDir) {
|
|
288
|
+
this.warnedCacheDir = true;
|
|
289
|
+
this.note('volume-cache-unwritable', `serving sounds unscaled; cache dir issue: ${error && error.message ? error.message : error}`);
|
|
290
|
+
}
|
|
266
291
|
return file;
|
|
267
292
|
}
|
|
268
293
|
}
|
package/lib/slots.js
CHANGED
|
@@ -63,9 +63,10 @@ const SLOTS = {
|
|
|
63
63
|
},
|
|
64
64
|
|
|
65
65
|
/**
|
|
66
|
-
* 需要你回应
|
|
66
|
+
* 需要你回应 —— human attention required. Descending minor second
|
|
67
67
|
* with a detuned partial beats against the fundamental: unresolved on
|
|
68
|
-
* purpose, so it does not read as "done".
|
|
68
|
+
* purpose, so it does not read as "done". Wired to approval/request and
|
|
69
|
+
* user-questions/request by the host half.
|
|
69
70
|
*/
|
|
70
71
|
attention: {
|
|
71
72
|
duration: 1.0,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-theme-endfield",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.5",
|
|
4
4
|
"description": "DeepSeek Harness web theme: the industrial editorial look of the Arknights: Endfield official site — cream paper, ink text, signal-yellow accents, zero radius. Settings persist through the DSH volatile Config + configForms transport (0.2.0-rc.2 and 0.1.7+), with a ctx.settingsScope fallback for older hosts.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"deepseek-harness",
|
|
@@ -32,13 +32,13 @@
|
|
|
32
32
|
"test:contour": "node test/contour-render.test.js",
|
|
33
33
|
"test:settings": "node test/settings-rows.test.js && node test/settings-durable-hold.test.js && node test/settings-config-forms.test.js && node test/settings-config-fallback.test.js && node test/settings-namespace.test.js && node test/settings-off.test.js && node test/settings-locale.test.js",
|
|
34
34
|
"test:font": "node test/font-scope.test.js",
|
|
35
|
-
"test:thunder": "node test/thunder-edges.test.js && node test/thunder-shot.js && node test/thunder-dismiss.test.js",
|
|
35
|
+
"test:thunder": "node test/thunder-edges.test.js && node test/tools/thunder-shot.js && node test/thunder-dismiss.test.js",
|
|
36
36
|
"test:palette": "node test/palette-contrast.test.js && node test/palette-switch.test.js",
|
|
37
37
|
"test:menu": "node test/menu-surface.test.js dark && node test/menu-surface.test.js light",
|
|
38
38
|
"test:selector": "node test/selector-guard.test.js && node test/preset-chip.test.js",
|
|
39
|
-
"test:buttons": "node test/settings-buttons.test.js && node test/hover-check.js",
|
|
39
|
+
"test:buttons": "node test/settings-buttons.test.js && node test/tools/hover-check.js",
|
|
40
40
|
"test:balance": "node test/balance-window.test.js && node test/balance-capsule.test.js && node test/credit-capsule.test.js",
|
|
41
|
-
"test:live": "node test/live-check.js",
|
|
41
|
+
"test:live": "node test/tools/live-check.js",
|
|
42
42
|
"test:specks": "node test/contour-specks.test.js",
|
|
43
43
|
"test:watermark": "node test/watermark-stacking.test.js",
|
|
44
44
|
"test:smoothness": "node test/contour-smoothness.test.js",
|
|
@@ -47,10 +47,10 @@
|
|
|
47
47
|
"test:coverage": "node test/contour-coverage.test.js",
|
|
48
48
|
"test:perf": "node test/contour-perf.test.js",
|
|
49
49
|
"test:loader": "node test/loader-performance.test.js && node test/loader-late-prefs.test.js",
|
|
50
|
-
"test": "node check.js && node selftest.js && node test/font-scope.test.js && node test/palette-contrast.test.js && node test/palette-switch.test.js && node test/menu-surface.test.js dark && node test/menu-surface.test.js light && node test/settings-buttons.test.js && node test/hover-check.js && node test/selector-guard.test.js && node test/preset-chip.test.js && node test/balance-window.test.js && node test/balance-capsule.test.js && node test/credit-capsule.test.js && node test/settings-rows.test.js && node test/settings-durable-hold.test.js && node test/settings-config-forms.test.js && node test/settings-config-fallback.test.js && node test/settings-namespace.test.js && node test/settings-off.test.js && node test/settings-locale.test.js && node test/audio-notify.test.js && node test/audio-attention-watch.test.js && node test/host-no-inject.test.js && node scripts/build-sounds.js --check && node test/thunder-edges.test.js && node test/thunder-shot.js && node test/thunder-dismiss.test.js && node test/contour-render.test.js && node test/loader-performance.test.js && node test/loader-late-prefs.test.js && node test/contour-specks.test.js && node test/watermark-stacking.test.js && node test/contour-smoothness.test.js && node test/contour-cusps.test.js && node test/contour-a11y.test.js && node test/contour-coverage.test.js && node test/contour-perf.test.js && node test/contour-density.test.js && node test/contour-bounds.test.js && node scripts/build-host.js --check && node scripts/build-client.js --check && node scripts/build-contour-worker.js --check && node test/worker-eol.test.js && node test/contour-worker.test.js && node test/theme-sheet-refresh.test.js && node test/titlebar-probe.test.js && node test/corner-shape.test.js && node test/glass.test.js && node test/contour-trail.test.js && node test/contour-trail-browser.test.js && node test/scroll-anim.test.js && node test/contour-loop-reentry.test.js",
|
|
51
|
-
"test:ci": "node check.js && node selftest.js && node test/font-scope.test.js && node test/palette-contrast.test.js && node test/palette-switch.test.js && node test/menu-surface.test.js dark && node test/menu-surface.test.js light && node test/settings-buttons.test.js && node test/hover-check.js && node test/selector-guard.test.js && node test/preset-chip.test.js && node test/balance-window.test.js && node test/balance-capsule.test.js && node test/credit-capsule.test.js && node test/settings-rows.test.js && node test/settings-durable-hold.test.js && node test/settings-config-forms.test.js && node test/settings-config-fallback.test.js && node test/settings-namespace.test.js && node test/settings-off.test.js && node test/settings-locale.test.js && node test/audio-notify.test.js && node test/audio-attention-watch.test.js && node test/host-no-inject.test.js && node scripts/build-sounds.js --check && node test/thunder-edges.test.js && node test/thunder-shot.js && node test/thunder-dismiss.test.js && node test/contour-render.test.js && node test/loader-performance.test.js && node test/loader-late-prefs.test.js && node test/contour-specks.test.js && node test/watermark-stacking.test.js && node test/contour-smoothness.test.js && node test/contour-cusps.test.js && node test/contour-a11y.test.js && node test/contour-bounds.test.js && node scripts/build-host.js --check && node scripts/build-client.js --check && node scripts/build-contour-worker.js --check && node test/worker-eol.test.js && node test/contour-worker.test.js && node test/theme-sheet-refresh.test.js && node test/titlebar-probe.test.js && node test/corner-shape.test.js && node test/glass.test.js && node test/contour-trail.test.js && node test/contour-trail-browser.test.js && node test/scroll-anim.test.js && node test/contour-loop-reentry.test.js",
|
|
52
|
-
"shots": "node test/shoot.js",
|
|
53
|
-
"shots:verify": "node test/shoot.js && node test/verify-shots.js",
|
|
50
|
+
"test": "node check.js && node selftest.js && node test/import-probe.test.js && node test/font-scope.test.js && node test/palette-contrast.test.js && node test/palette-switch.test.js && node test/menu-surface.test.js dark && node test/menu-surface.test.js light && node test/settings-buttons.test.js && node test/tools/hover-check.js && node test/selector-guard.test.js && node test/preset-chip.test.js && node test/balance-window.test.js && node test/balance-capsule.test.js && node test/credit-capsule.test.js && node test/settings-rows.test.js && node test/settings-durable-hold.test.js && node test/settings-config-forms.test.js && node test/settings-config-fallback.test.js && node test/settings-namespace.test.js && node test/settings-off.test.js && node test/settings-locale.test.js && node test/audio-notify.test.js && node test/audio-attention-watch.test.js && node test/host-no-inject.test.js && node scripts/build-sounds.js --check && node test/thunder-edges.test.js && node test/tools/thunder-shot.js && node test/thunder-dismiss.test.js && node test/contour-render.test.js && node test/loader-performance.test.js && node test/loader-late-prefs.test.js && node test/contour-specks.test.js && node test/watermark-stacking.test.js && node test/contour-smoothness.test.js && node test/contour-cusps.test.js && node test/contour-a11y.test.js && node test/contour-coverage.test.js && node test/contour-perf.test.js && node test/contour-density.test.js && node test/contour-bounds.test.js && node scripts/build-host.js --check && node scripts/build-client.js --check && node scripts/build-contour-worker.js --check && node test/worker-eol.test.js && node test/contour-worker.test.js && node test/contour-worker-budget.test.js && node test/theme-sheet-refresh.test.js && node test/titlebar-probe.test.js && node test/corner-shape.test.js && node test/approval-band-transform.test.js && node test/sidebar-row-wash.test.js && node test/glass.test.js && node test/contour-trail.test.js && node test/contour-trail-browser.test.js && node test/scroll-anim.test.js && node test/contour-loop-reentry.test.js",
|
|
51
|
+
"test:ci": "node check.js && node selftest.js && node test/import-probe.test.js && node test/font-scope.test.js && node test/palette-contrast.test.js && node test/palette-switch.test.js && node test/menu-surface.test.js dark && node test/menu-surface.test.js light && node test/settings-buttons.test.js && node test/tools/hover-check.js && node test/selector-guard.test.js && node test/preset-chip.test.js && node test/balance-window.test.js && node test/balance-capsule.test.js && node test/credit-capsule.test.js && node test/settings-rows.test.js && node test/settings-durable-hold.test.js && node test/settings-config-forms.test.js && node test/settings-config-fallback.test.js && node test/settings-namespace.test.js && node test/settings-off.test.js && node test/settings-locale.test.js && node test/audio-notify.test.js && node test/audio-attention-watch.test.js && node test/host-no-inject.test.js && node scripts/build-sounds.js --check && node test/thunder-edges.test.js && node test/tools/thunder-shot.js && node test/thunder-dismiss.test.js && node test/contour-render.test.js && node test/loader-performance.test.js && node test/loader-late-prefs.test.js && node test/contour-specks.test.js && node test/watermark-stacking.test.js && node test/contour-smoothness.test.js && node test/contour-cusps.test.js && node test/contour-a11y.test.js && node test/contour-density.test.js && node test/contour-bounds.test.js && node scripts/build-host.js --check && node scripts/build-client.js --check && node scripts/build-contour-worker.js --check && node test/worker-eol.test.js && node test/contour-worker.test.js && node test/contour-worker-budget.test.js && node test/theme-sheet-refresh.test.js && node test/titlebar-probe.test.js && node test/corner-shape.test.js && node test/approval-band-transform.test.js && node test/sidebar-row-wash.test.js && node test/glass.test.js && node test/contour-trail.test.js && node test/contour-trail-browser.test.js && node test/scroll-anim.test.js && node test/contour-loop-reentry.test.js",
|
|
52
|
+
"shots": "node test/tools/shoot.js",
|
|
53
|
+
"shots:verify": "node test/tools/shoot.js && node test/tools/verify-shots.js",
|
|
54
54
|
"test:bounds": "node test/contour-bounds.test.js",
|
|
55
55
|
"build:host": "node scripts/build-host.js",
|
|
56
56
|
"check:host": "node scripts/build-host.js --check",
|