agentcss 0.24.2 → 0.25.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/01-tokens/README.md +1 -1
- package/01-tokens/tokens.css +67 -1
- package/01-tokens/typography.css +1 -1
- package/02-primitives/button/demo.html +8 -0
- package/02-primitives/card/README.md +15 -0
- package/02-primitives/choice/README.md +30 -0
- package/02-primitives/choice/choice.css +1 -1
- package/02-primitives/input/README.md +1 -0
- package/02-primitives/select/README.md +42 -2
- package/02-primitives/select/demo.html +11 -6
- package/02-primitives/select/select.js +184 -94
- package/02-primitives/timeline/demo.html +2 -2
- package/02-primitives/timeline/timeline.css +1 -1
- package/03-patterns/accordion/README.md +15 -0
- package/03-patterns/content/README.md +11 -0
- package/03-patterns/drawer/README.md +1 -1
- package/03-patterns/dropdown/demo.html +1 -1
- package/03-patterns/form-validation/README.md +18 -0
- package/03-patterns/form-validation/form-validation.css +12 -1
- package/03-patterns/list/README.md +11 -0
- package/03-patterns/overlay/README.md +26 -6
- package/03-patterns/overlay/overlay.css +22 -3
- package/03-patterns/overlay/overlay.js +63 -17
- package/03-patterns/states/README.md +15 -0
- package/03-patterns/states/states.css +18 -1
- package/03-patterns/tooltip/README.md +12 -0
- package/04-recipes/longform/longform.html +3 -3
- package/04-recipes/report/README.md +9 -0
- package/04-recipes/report/report.css +5 -0
- package/04-recipes/table/README.md +16 -0
- package/04-recipes/tierA-tokens.css +3 -3
- package/09-assets/README.md +18 -0
- package/09-assets/bar/bar.css +25 -10
- package/09-assets/echarts-adapter/demo.html +3 -1
- package/09-assets/echarts-adapter/echarts-adapter.js +107 -34
- package/09-assets/scientific-plot/README.md +2 -1
- package/09-assets/scientific-plot/scientific-plot.js +0 -7
- package/AGENTS.md +2 -1
- package/CHANGELOG.md +379 -18
- package/CONTRIBUTING.md +6 -5
- package/README.md +6 -2
- package/README.zh-CN.md +19 -7
- package/SECURITY.md +5 -2
- package/START-HERE.md +7 -7
- package/SUPPORT.md +86 -24
- package/ai/START-HERE.md +3 -2
- package/ai/cli.js +126 -6
- package/ai/components.json +258 -2
- package/ai/components.meta.json +257 -40
- package/ai/components.schema.json +96 -0
- package/ai/contract.schema.json +11 -0
- package/ai/pdf-pages.js +107 -0
- package/ai/pdf.js +354 -0
- package/ai/tokens.json +2 -2
- package/ai/validate.js +48 -1
- package/dist/01-tokens/tokens.css +1 -1
- package/dist/02-primitives/select/select.js +158 -71
- package/dist/03-patterns/form-validation/form-validation.css +1 -1
- package/dist/03-patterns/overlay/overlay.css +1 -1
- package/dist/03-patterns/overlay/overlay.js +40 -11
- package/dist/03-patterns/states/states.css +1 -1
- package/dist/04-recipes/report/report.css +1 -1
- package/dist/04-recipes/tierA-tokens.css +1 -1
- package/dist/09-assets/bar/bar.css +1 -1
- package/dist/09-assets/echarts-adapter/echarts-adapter.js +75 -33
- package/dist/09-assets/scientific-plot/scientific-plot.js +0 -7
- package/dist/COSTS.md +37 -37
- package/docs/ACCESSIBILITY.md +3 -3
- package/docs/FACTS.md +1 -1
- package/docs/LAYER-BASELINE.md +28 -3
- package/docs/PRINT.md +450 -0
- package/docs/RELEASE-PROCESS.md +78 -3
- package/index.html +1 -1
- package/llms-full.txt +7 -7
- package/llms.txt +5 -0
- package/package.json +6 -1
package/CHANGELOG.md
CHANGED
|
@@ -16,6 +16,368 @@
|
|
|
16
16
|
|
|
17
17
|
(无)
|
|
18
18
|
|
|
19
|
+
## [0.25.1] - 2026-11-03
|
|
20
|
+
|
|
21
|
+
**修订版:修 `agentcss pdf` 在**长文档**上的一处误判 —— 50 页的文档会被报
|
|
22
|
+
「无法判定预算」(退出码 4),哪怕预算够、文件也没坏。不改类名、不改令牌、不改 API。**
|
|
23
|
+
|
|
24
|
+
### 修复:长文档的页树根 `Count` 被读成了叶节点的数
|
|
25
|
+
|
|
26
|
+
`agentcss pdf <page> --max-pages=N` 会交叉核对两个页数:`/Type /Page` 对象数
|
|
27
|
+
与页树根的 `/Count`。两者不一致时**拒绝判定预算**(这是对的 —— 预算判错的代价是
|
|
28
|
+
"多印 40 页纸,而工具说通过")。
|
|
29
|
+
|
|
30
|
+
问题出在"页树根"的读法:旧实现取的是**文件里第一个** `/Count`。
|
|
31
|
+
而 Chromium 的页树是**分层**的,实测一份 50 页产物里有 8 个 `/Count`:
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
8, 8, 8, 8, 8, 8, 2, 50 ← 只有最后一个是根
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
第一个是叶节点的 8。于是"页对象 50"和"页树 8"打架,工具据此报
|
|
38
|
+
`unreadable` —— **一份完全正常的 50 页文档被读法错误挡在门外**,
|
|
39
|
+
使用者会以为是自己的 PDF 坏了。
|
|
40
|
+
|
|
41
|
+
现在顺引用走:`/Type /Catalog` → 它的 `/Pages N 0 R` → 对象 N 的 `/Count`。
|
|
42
|
+
对象内键序不保证,所以两侧各开一个窗口找;解析不到时返回 `null`
|
|
43
|
+
(= 不做交叉核对),**不退回"第一个匹配"** —— 宁可少一道核对,
|
|
44
|
+
也不能拿一个错数字去否决用户的文件。
|
|
45
|
+
|
|
46
|
+
反向控制:把旧读法放回去,同一份样本立刻读成 8,两条端到端断言同时转红。
|
|
47
|
+
|
|
48
|
+
### 新增:打印门禁的六个对抗夹具(12 条断言)
|
|
49
|
+
|
|
50
|
+
此前的反向控制喂的是**合成数字**,证明不了"判据拿到真实极端页面还认得出来"。
|
|
51
|
+
新增 `05-audit/fixtures/print-adversarial/`(生成器 `_gen.py`,改规模只改常量):
|
|
52
|
+
|
|
53
|
+
| 面 | 断言 |
|
|
54
|
+
|---|---|
|
|
55
|
+
| 50 页 | 页数正好 50(多一页 = 尾部空页);文本流与页数**逐个**对上 |
|
|
56
|
+
| 一行表 | 整表落在 1 页(`thead` 被重复到第二页会变 2 页) |
|
|
57
|
+
| 200 列 | 判出横向溢出;配一份压进纸面的对照,证明不是"见大表就红" |
|
|
58
|
+
| 嵌套浮层 | 打印态下两层遮罩都落回正常流、不铺底色,正文与两层弹窗的字都在 |
|
|
59
|
+
| 近空白页 | 一个字符也算字;首屏无字、**三页文档中间一页无字**都必须报出来 |
|
|
60
|
+
| 单块超一页 | 与"同内容可拆分"的对照组比 run 数,少了就是静默丢字 |
|
|
61
|
+
|
|
62
|
+
12 条都做过变异验证:拆掉 `overlay.css` 的 `@media print` ⇒ ④ 转红;
|
|
63
|
+
夹具从 50 页改成 51 页 ⇒ ① 转红;夹具目录改名 ⇒ 报"缺 10/10 个"并退出非 0
|
|
64
|
+
(缺测不许算过)。
|
|
65
|
+
|
|
66
|
+
### 修复:`pagesWithoutText` 的计数会被二进制噪声抵掉
|
|
67
|
+
|
|
68
|
+
⑫ 算的是 `无字页 = 页数 − 文本流数`,而"文本流"只要求流里出现 `BT` 两个字节 ——
|
|
69
|
+
字体 / cmap / ICC 的二进制里会**偶然**出现它。实测同一批夹具 10 个里有 6 个多计
|
|
70
|
+
(50 页数出 51 个流、1 页数出 2 个)。而差是**没有位置信息**的:
|
|
71
|
+
多出来的那一个流,正好抵掉一张真没字的纸 ⇒ ⑫ 报 0,安静地通过。
|
|
72
|
+
|
|
73
|
+
现在要求同一流里同时有 `BT`(开始文本)+ `Tf`(选字体)+ `Tj`/`TJ`(真的写出来)。
|
|
74
|
+
实测 10 个夹具逐个精确。副作用是真实页面的 run 数各少了 1–3 个
|
|
75
|
+
(`recipe-report` 1071→1070、`type-wide-table` 1526→1523、`type-form` 578→576、
|
|
76
|
+
`type-grid-media` 517→516,页数一个没变)—— 那些 run 是二进制里的假算子,
|
|
77
|
+
基线按新口径重录。
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## [0.25.0] - 2026-11-03
|
|
82
|
+
|
|
83
|
+
**次版本:新增一个子命令(`agentcss pdf`)+ 新增契约字段(`printPolicy` / `pageBudget`)
|
|
84
|
+
+ 修一处打印行为(模态遮罩)。不改类名、不改令牌、不改既有 JS 的调用方式 ——
|
|
85
|
+
下游不改代码即可升级;不打印的话,`@media print` 之外一个字节都没变。**
|
|
86
|
+
|
|
87
|
+
### 修复:`coverage-gate` 的 CSS 覆盖率从"写在注释里"变成"真的算"
|
|
88
|
+
|
|
89
|
+
docstring 承诺了「每个组件 CSS 里的 class,是否至少被一个契约或 demo 引用到」,
|
|
90
|
+
但代码里**没有任何提取 CSS class 的逻辑** —— 实际只判"有没有 demo、契约里提没提路径"。
|
|
91
|
+
现在实装成四条机械判据,全部 100% 硬门禁:
|
|
92
|
+
|
|
93
|
+
| 判据 | 含义 | 现状 |
|
|
94
|
+
|---|---|---|
|
|
95
|
+
| **孤儿类** | CSS 里定义了,demo / 组件 JS / 契约 / README 四处都没提 | 0(原有 25 个,全部补文档或删规则) |
|
|
96
|
+
| **幻影类** | README 写到、全库却没有这个类 | 0(3 个历史警告性提及显式豁免) |
|
|
97
|
+
| **未渲染类** | 只被 README 认领,demo / JS / 契约一次没碰 | 41 / 472(棘轮钉住,不得变多) |
|
|
98
|
+
| **跨组件同名主体** | 同一类名被两个组件声明为规则主体 | 5 条,全部登记在 `css-ownership.json` |
|
|
99
|
+
|
|
100
|
+
⚠️ 三处**判据口径**是踩过坑才定下来的,写在这里免得后人改回去:
|
|
101
|
+
|
|
102
|
+
- **剥注释、`url(...)`、字符串**再取类名。否则 `data:image/svg+xml,...http://www.w3.org/`
|
|
103
|
+
能读出 `.org` / `.w3` 这种假类名(实测 2 处)。
|
|
104
|
+
- **"定义"用全部选择器,"占用类名"只用规则主体。** `.switch--lg .switch__track` 这种
|
|
105
|
+
修饰符没有自己的规则,只看主体会把它误判成"CSS 里不存在"(实测多报 12 条幻影);
|
|
106
|
+
反过来 `.list__actions .btn` 是 list 在上下文里覆盖 button,不是 list 占用了 `.btn`
|
|
107
|
+
(按"任意出现"判重名会多报 9 条噪音)。
|
|
108
|
+
- **幻影要排除交叉引用**:form-validation 的 README 写 `.field`(那是 input 的)。
|
|
109
|
+
判据改成"别处也没有才算幻影",并且**存在于本组件 JS 里也算真实存在**
|
|
110
|
+
(`.accordion--many` 是纯行为开关,一行样式都没有)。
|
|
111
|
+
|
|
112
|
+
反向控制 5 条(孤儿 / 幻影 / 未登记重名 / 登记过期 / 水位上涨)全部在
|
|
113
|
+
`--selftest` 里,另在真仓库上逐条注入验证过会红。
|
|
114
|
+
|
|
115
|
+
### 修复:三处样式缺陷(都是上面这把尺子量出来的)
|
|
116
|
+
|
|
117
|
+
| 缺陷 | 实测症状 | 修法 |
|
|
118
|
+
|---|---|---|
|
|
119
|
+
| `.field__error` 的"该不该显示"取决于 CSS 加载顺序 | input.css 先 → `display:none` ✅;form-validation.css 先 → `display:flex`,**首屏把全部错误提示挂出来** | 把默认隐藏抬成 `.field .field__error`(0,2,0),顺序不再是变量。错误元素必须在 `.field` 内(结构契约本来就如此) |
|
|
120
|
+
| `states.css` 里的骨架屏动画**无视** `prefers-reduced-motion` | 该文件自带一份完整的 `.skeleton` 实现,`:after` 的 `animation` 无条件生效;而 states 的 demo 没引 skeleton.css ⇒ 减少动态效果的用户照样看到闪烁 | 包进 `@media (prefers-reduced-motion: no-preference)` + 补 `reduce` 档 |
|
|
121
|
+
| `.select` 同名不同义(choice vs select) | choice 的是**原生 `<select>` 外壳**(`inline-flex`+`align-items:center`),select 的是**自定义下拉根**(`inline-block`+`min-width:12rem`)。实测两序结果不同:先 choice 后 select 时原生外壳丢垂直居中 | **未改**(改名是破坏性变更)。登记在 `css-ownership.json`,0.26.0 处理 |
|
|
122
|
+
|
|
123
|
+
另:`.skeleton*` 两份实现已分叉(底色令牌、高度、变体集合、reduced-motion 全不同),
|
|
124
|
+
同样登记待去重。
|
|
125
|
+
|
|
126
|
+
### 文档:25 个类从"代码里有、文档里没有"变成能查到
|
|
127
|
+
|
|
128
|
+
它们都是真实公开 API,只是从没写进 README —— 照着旧文档用的人根本不知道有这些能力。
|
|
129
|
+
补齐的包括 `.card__footer`、`.choice__hint`、`.select__control--auto`、
|
|
130
|
+
`.field__input--textarea`、`.accordion--flush` / `.accordion__hint` / `cols-*` / `.acc-table`、
|
|
131
|
+
`.task-list-item`、`.drawer--left` / `--top` / `--bottom`、
|
|
132
|
+
`.field--checking` / `.field__checking-hint`、`.list__note`、`.skeleton--avatar`、
|
|
133
|
+
`.tooltip--bottom` / `--inset-inline-start` / `--inset-inline-end`、
|
|
134
|
+
`.rep__lede`、`.cell--na`、`.table--compact`。
|
|
135
|
+
|
|
136
|
+
顺带修掉 **BEM 简写**:drawer 的 `--left` / overlay 的 `--warning` 这类写法
|
|
137
|
+
没法直接抄进 `class=""`,一律改成完整类名。
|
|
138
|
+
|
|
139
|
+
### 新增:`05-audit/css-ownership.json` 与 `05-audit/css-coverage-baseline.json`
|
|
140
|
+
|
|
141
|
+
前者登记跨组件同名类的归属与理由(`kind: split` = 有意拆分,`kind: conflict` = 真冲突待改),
|
|
142
|
+
**登记过期也判失败**(现实中不再重名就必须删掉,白条不许腐烂)。
|
|
143
|
+
后者是"文档有、demo 没渲染"的水位,只能降不能升,`--record` 显式重录。
|
|
144
|
+
|
|
145
|
+
### 修复:外部审计查出的交互缺陷(select / overlay)
|
|
146
|
+
|
|
147
|
+
对一个公开版本做外部抽查后,逐条复现并修掉。**都是行为修正,不改类名、不改 API 形状**
|
|
148
|
+
(只新增:`select.values`、`select.destroy()`)。
|
|
149
|
+
|
|
150
|
+
**select**
|
|
151
|
+
|
|
152
|
+
| 缺陷 | 实测症状 | 修法 |
|
|
153
|
+
|---|---|---|
|
|
154
|
+
| 按钮上挂了**两个** `keydown` | 按一次 `↓` 走**两格**;关闭态按 `Enter` 打开后立刻被第二个处理器提交关闭;多选 `Enter` 选上又取消 | 合并成一个处理器,`Enter` 在关闭态只负责打开 |
|
|
155
|
+
| 多选只有一个字符串状态 | `aria-multiselectable="true"` 是**谎报**;点第二项会把第一项顶掉 | 内部改成数组,`aria-selected`、按钮文本、提交值三处同源 |
|
|
156
|
+
| 空选项列表 | 初始化抛 `Cannot read properties of undefined (reading 'querySelector')` | `optText(null)` 返回空串,绘制/取值全部兜底 |
|
|
157
|
+
| 没有 `destroy()` | 动态移除组件后,`document` 上的 dismissable 监听与 typeahead 缓冲全留着 | 对外暴露 `destroy()`,摘 keydown/click/dismissable/typeahead 并删掉自己补的 hidden |
|
|
158
|
+
| 表单集成半截 | 根里没有 `hidden` 时不建;改值不发原生事件 | 没 hidden 就按 `name` → `data-name` → 根 `id` 兜底自建;每次变值在根上派发原生 `change` |
|
|
159
|
+
| 多选提交 | 一个 `hidden` 只能带一个值 | **一个值一个同名 `input[type=hidden]`**(`name="sector"` × N) |
|
|
160
|
+
|
|
161
|
+
同时把「一次按键只走一格 / 关闭态 Enter 只打开 / 多选 Enter 只切一次 / 空列表不抛 /
|
|
162
|
+
destroy 后不再响应 / 无 hidden 自建并派发 change」写成**精确断言**。
|
|
163
|
+
旧断言只判"序列有变化",所以「一次走两格」能从门禁底下过去。
|
|
164
|
+
|
|
165
|
+
**overlay**
|
|
166
|
+
|
|
167
|
+
| 缺陷 | 实测症状 | 修法 |
|
|
168
|
+
|---|---|---|
|
|
169
|
+
| `inert` 释放固定写 `false` | 页面原本 `inert` 的区域,开关一次弹层就被**误解锁** | 引用计数条目里记 `prev`,降为 0 时还原原值 |
|
|
170
|
+
| 嵌套时跳过所有 `.dialog-backdrop` | 开 A 再开 B,A 既没 `inert` 也没 `aria-hidden` ⇒ **两个 dialog 同时暴露给读屏** | 只跳过自己这一层,别的弹层照常隔离 |
|
|
171
|
+
| 背景只快照一次 | 弹层开着时插入 `body` 的节点(toast / portal / 埋点 iframe)不受隔离 | `MutationObserver` 盯 `body` 直接子节点;backdrop 被外部摘掉时**自愈回收**(防幽灵观察器锁死后续焦点) |
|
|
172
|
+
| `focusIsMine` 是死变量 | 关外层时会把焦点从内层抢走 | 真的用它把关:不是我的焦点就不还原 |
|
|
173
|
+
|
|
174
|
+
### 修复:探针把「端口有人应答」当成「服务是我们的」
|
|
175
|
+
|
|
176
|
+
发布工作流在 CI 上报过一句很吓人的话:
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
🔴 ai/components.json 声明了浏览器里不存在的 global:(16 个全部"探不到")
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
16 个组件同时消失,显然不是实现坏了。根因在量具:`_probe.py` 复用静态服务的
|
|
183
|
+
判据是「8000 端口有人应答」,而 8000 上可能跑着**别的目录**的服务 ⇒ 每个 demo
|
|
184
|
+
页 404 ⇒ 探针把"页面没加载"记成"全局不存在"。
|
|
185
|
+
|
|
186
|
+
本地可复现(在 8000 起一个服务别的目录的 `http.server`,输出一模一样),
|
|
187
|
+
修法是三条:canary 验身份(`/01-tokens/tokens.css` 200 且够大)、
|
|
188
|
+
不复用就换空闲端口自己起、地址通过 `BASE` 传给探测脚本。
|
|
189
|
+
另加一条判据:**全部 absent ⇒ 报"没有取证"**,不许把量具问题说成实现问题。
|
|
190
|
+
|
|
191
|
+
### 新增:`agentcss pdf` —— 真的把页面导出成 PDF(零依赖)
|
|
192
|
+
|
|
193
|
+
在这之前,本库能证明"按 Ctrl+P 印出来是合格的",但**产不出一份文件**。
|
|
194
|
+
这两件事之间差一个 `@page`,而 `@page` 属于导出方、不属于组件库 ——
|
|
195
|
+
库一旦声明它,使用者的边距控制会静默失效(实测同一页面 943 → 978 runs)。
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
npx agentcss pdf report.html --out report.pdf --paper=a4 --margin="18mm 15mm" --max-pages=8
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
| 参数 | 默认 | 说明 |
|
|
202
|
+
|---|---|---|
|
|
203
|
+
| `--paper` | `a4` | `a4` / `letter` / `a5` / `a3` / `legal` |
|
|
204
|
+
| `--margin` | `18mm 15mm` | CSS 简写(`18mm` / `"18mm 15mm"` / 四段) |
|
|
205
|
+
| `--max-pages` | 无 | 页数上限。**没有全局默认值**:页数取决于内容,猜一个数字比不给更坏 |
|
|
206
|
+
| `--chrome` | 自动探测 | 也可用 `AGENTCSS_CHROME` / `CHROME_PATH` |
|
|
207
|
+
|
|
208
|
+
**零运行时依赖**:用使用者已装好的 Chrome / Chromium / Edge(`--print-to-pdf`)。
|
|
209
|
+
为了 5% 的导出需求让 95% 的人多装 300 MB 浏览器,是这条承诺唯一实质的内容。
|
|
210
|
+
找不到浏览器 ⇒ 退出码 3 + 一句人话,不静默降级成空文件。
|
|
211
|
+
|
|
212
|
+
超预算 ⇒ **退出码 5**,产物保留,并给出三条出路(拆文档 / 进附录 / 截断)。
|
|
213
|
+
`truncate` **故意不实现**:一个会替你悄悄删掉后半份报告的工具,比报错停下更危险。
|
|
214
|
+
|
|
215
|
+
⚠️ 一条必须知道的差异:导出产物**包含底色**(headless 打印的默认),
|
|
216
|
+
浏览器打印对话框默认**不勾**"背景图形"。所以同一页面在"导出"与"Ctrl+P"下,
|
|
217
|
+
彩色块上的观感不同 —— 这不是 bug,是两个产品。
|
|
218
|
+
|
|
219
|
+
### 新增:`--medium=screen|paper` 与 `pageBudget`
|
|
220
|
+
|
|
221
|
+
`ai check` 多了一根**与档位正交**的轴(`strict+paper` 与 `creative+paper` 都必须合法,
|
|
222
|
+
所以不做成第四个 profile):
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
npx agentcss ai check doc.json --medium=paper
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
`screen`(默认)下行为完全不变 —— 95% 的人不该为打印付注意力。
|
|
229
|
+
`paper` 下追加三条义务:必须声明 `pageBudget`(错)、
|
|
230
|
+
不允许 `pagination:"server"` 的组件(错,纸上只有当前一页而文件看起来完整)、
|
|
231
|
+
用了 `printPolicy:"omit"` 的组件给提示(那部分不会印,作者得知道)。
|
|
232
|
+
|
|
233
|
+
`contract.schema.json` 新增可选字段 `pageBudget`(正整数,无默认值)。
|
|
234
|
+
|
|
235
|
+
### 新增:`05-audit/pdf-export-gate.js` —— 导出路径的 15 条断言
|
|
236
|
+
|
|
237
|
+
`print-gate` 判的是 **CDP `page.pdf()`**(我们自己的渲染),
|
|
238
|
+
使用者走的是 **Chrome 命令行 `--print-to-pdf`**(另一条路)——
|
|
239
|
+
`@page` 来源与底色默认都不同,所以前者全绿推不出后者能用。
|
|
240
|
+
|
|
241
|
+
```
|
|
242
|
+
E1 真产出 / E2 确定性 / E3 纸幅 / E4 预算以内 / E5 预算超限 / E6 打印规则到产物
|
|
243
|
+
E7 边距生效 / E8 无浏览器 / E8′ 零候选 / E9 参数校验 / E9″ 报错回显原始输入
|
|
244
|
+
E10 默认输出 / E11 产物过分析器 / E12 定位一致
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
反向控制实测:把 `@page` 注入那行注释掉 ⇒ E3 报 `a4=612×792pt`(回落成 Letter)、
|
|
248
|
+
E7 报 `10mm=2 页 / 60mm=2 页`;把 `tokens.css` 里 `.tabs__panel[hidden]` 那条删掉 ⇒
|
|
249
|
+
E6 报 `runs on=4 off=4`。全部约 11s,不需要静态服务(走 file://)。
|
|
250
|
+
|
|
251
|
+
### 新增:`print-gate` 判据 ⑬ —— 页数预算写在源码里
|
|
252
|
+
|
|
253
|
+
③ 是"和上次比有没有变",⑬ 是"和该有的页数比"。两者缺一不可:
|
|
254
|
+
CSS 改动让 7 页变 13 页,跑一次 `--update` 之后 ③ 就绿了,
|
|
255
|
+
而 ⑬ 不会 —— 预算**不经 `--update` 重录**(写进基线就等于把证据洗掉)。
|
|
256
|
+
预算 = 基线页数 × 1.4(实测分页通胀断崖是 +92%,1.4 倍抓得住)。
|
|
257
|
+
|
|
258
|
+
### 新增:打印契约 `printPolicy`(机器可读,进 `ai/components.json`)
|
|
259
|
+
|
|
260
|
+
打印行为此前只存在于 `tokens.css` 的一个 `@media print` 块里,没有任何东西
|
|
261
|
+
能回答三个问题:契约写的实现了吗、CSS 里每条隐藏都声明了吗、声明了真的生效吗。
|
|
262
|
+
|
|
263
|
+
现在每个组件在 `ai/components.json` 里有一条 `printPolicy`,`policy` 是
|
|
264
|
+
**有限枚举**,每个值对应一组能在浏览器里量的断言:
|
|
265
|
+
|
|
266
|
+
| policy | 含义 | 断言 |
|
|
267
|
+
|---|---|---|
|
|
268
|
+
| `omit` | 内容不上纸 | 打印态 `display: none` |
|
|
269
|
+
| `expand` | 放开屏幕上的限制(隐藏 / 收起 / 限高 / 固定定位) | `display≠none`、`visibility≠hidden`、`position≠fixed`、`max-height:none`、`overflow` 不裁、有文字时高度 > 0 |
|
|
270
|
+
| `reveal` | 只在纸上出现 | 屏幕 `display:none` 且打印态不是 `none` |
|
|
271
|
+
| `keep-together` | 不跨页切断 | `break-inside: avoid` |
|
|
272
|
+
| `allow-break` | 退出 `keep-together` | `break-inside: auto` |
|
|
273
|
+
|
|
274
|
+
- 规则 31 条:库级 7(`printDefaults`)+ 组件 24(16 个组件)。
|
|
275
|
+
- `printPolicy: []` 是明确值「原样保留」;**缺字段才算漏**(门禁红)。
|
|
276
|
+
- 新增 `pagination`(`none` / `client` / `server`)。`server` 与 `expand`
|
|
277
|
+
不能同时成立:服务端分页只有当前一页,展开它 = 印出一页却看起来完整。
|
|
278
|
+
今天没有组件声明 `server`,这条规则处于守夜状态,由反向控制证明它能开火。
|
|
279
|
+
- 生成器(`gen-ai-contract.py`)在**写出契约之前**校验枚举、选择器形状、
|
|
280
|
+
`why` 不能是空话、同一选择器不许被认领两次。
|
|
281
|
+
|
|
282
|
+
`ai/components.json` 53.2 KB → 61.1 KB(+7.8 KB)。
|
|
283
|
+
|
|
284
|
+
### 新增:`05-audit/print-policy-gate.js` —— 契约 / 实现 / 运行时三向核对
|
|
285
|
+
|
|
286
|
+
四条腿,各抓一类失效:
|
|
287
|
+
|
|
288
|
+
| 腿 | 它问什么 | 实测抓到过什么 |
|
|
289
|
+
|---|---|---|
|
|
290
|
+
| L0 归属 | 选择器在库里真的存在吗 | `.overlay`(见下) |
|
|
291
|
+
| L1 声明→实现 | 契约里的规则在 print 块里有相符声明吗 | 故意删一条即红 |
|
|
292
|
+
| L2 实现→声明 | 每条会丢内容的声明都有规则认领吗 | 塞一条裸 `display:none` 即红 |
|
|
293
|
+
| L3 声明→生效 | 真浏览器 print 媒体下真的生效吗 | 自己刚写的规则被同特异性盖掉(E258) |
|
|
294
|
+
|
|
295
|
+
**反向控制 7 条(覆盖四条腿),全绿**,其中两条是历史事故的逐字复刻:
|
|
296
|
+
E254(去掉 `.tabs ` 前缀让组件 CSS 盖掉它)、E255(只删 `visibility: visible`,
|
|
297
|
+
display 与高度全对、一个字不印)。全量门禁从 223 → 225 道。
|
|
298
|
+
|
|
299
|
+
### 修复:屏幕上开着 dialog 时打印,整页 40% 黑
|
|
300
|
+
|
|
301
|
+
`tokens.css` 的隐藏清单里有 `.overlay`,而**全库没有任何 CSS 定义过这个类**
|
|
302
|
+
(`grep -rn '\.overlay' --include=*.css` 只命中 tokens 自己那一行)。
|
|
303
|
+
真正的遮罩叫 `.dialog-backdrop`,它不在清单里,于是照印:computed 是
|
|
304
|
+
`position: fixed; inset: 0; background: rgba(21,24,28,.4)`。
|
|
305
|
+
|
|
306
|
+
现在**不隐藏遮罩,而是拉回正常流**(`position: static` / 无 padding / 无底色;
|
|
307
|
+
`.dialog` 取消 100vh 限高)。隐藏会让 `.dialog`(它是遮罩的子节点)里的字
|
|
308
|
+
一起消失 —— 那正是本轮在修的静默截断,不能自己再造一个。
|
|
309
|
+
|
|
310
|
+
规则写在 `03-patterns/overlay/overlay.css`,**不能**写进 `tokens.css`:
|
|
311
|
+
tokens 先加载、同特异性,会被 `position: fixed` 盖掉(写完当场被 L3 抓到)。
|
|
312
|
+
|
|
313
|
+
### 修复:`03-patterns/overlay/README.md` 的三行假类名
|
|
314
|
+
|
|
315
|
+
`.overlay`、`.toast__icon`、`.dialog__body` 三个类在库里都不存在
|
|
316
|
+
(真实名字分别是 `.dialog-backdrop`、不存在、`.dialog__desc`)。
|
|
317
|
+
照着写的人会得到「样式没生效,但也不报错」。
|
|
318
|
+
|
|
319
|
+
### 新增:内容完整性审计转**硬判据**(`print-content-audit`)
|
|
320
|
+
|
|
321
|
+
之前它只报告不判红,理由是「先出清单 → 写进 printPolicy → 再转硬判据」。
|
|
322
|
+
printPolicy 落地之后这一步做了,而且**没有引入白名单**:
|
|
323
|
+
|
|
324
|
+
| 判据 | 条件 |
|
|
325
|
+
|---|---|
|
|
326
|
+
| ① 契约违约 | 命中 `expand` 的字,打印仍不印 ⇒ 红 |
|
|
327
|
+
| ② 静默消失 | 屏幕可见 → 纸上消失,且无 `omit` 声明 ⇒ 红 |
|
|
328
|
+
| ③ 不算 | 屏幕也看不见 ⇒ 交互状态 / 未触发的空态 / a11y 反例 |
|
|
329
|
+
|
|
330
|
+
判据① 咬的是「藏起它的**正是**契约承诺要展开的那个元素」—— 所以
|
|
331
|
+
`tabs` 的未选中面板(屏幕上也隐藏)照样能抓到,而那正是少印 68% 的那一次。
|
|
332
|
+
实测:13 页采样集 / 47 页全站都是 0 违约;把 `tokens.css` 里那条
|
|
333
|
+
`.tabs .tabs__panel[hidden]` 临时删掉,`pattern-tabs` 立刻红出 **7 条契约违约
|
|
334
|
+
/ 84 字**,并逐条指出是哪个 `#panel` 把字藏起来了。
|
|
335
|
+
|
|
336
|
+
反向控制 14 条:判定表 + 真 DOM 扫描 + 一个 `data:` 页走完整管线,
|
|
337
|
+
同时抓出 `silent` 与 `contract`。
|
|
338
|
+
|
|
339
|
+
### 新增:消费者实装冒烟(`consumer-smoke`)
|
|
340
|
+
|
|
341
|
+
`pack-smoke.sh` 判的全是**结构**:包里有那些文件、exports 解析得出来、JS 语法对。
|
|
342
|
+
结构对 ≠ 能用。新加的第 8 步真开一次浏览器,六条判据:
|
|
343
|
+
|
|
344
|
+
```
|
|
345
|
+
C1 零 404 页面引的每个包内文件都在
|
|
346
|
+
C2 样式生效 --accent 解析得出、.btn 背景不是透明
|
|
347
|
+
C3 行为生效 tabs.js 自动初始化,点第二个 tab 真的切过去
|
|
348
|
+
C4 打印生效 打印态未选中面板被展开(引了 tokens.css 才成立)
|
|
349
|
+
C5 契约可查 npx agentcss ai components --json → 40 个组件、40 条 printPolicy
|
|
350
|
+
C6 A 档在包 04-recipes/tierA-tokens.css 在包里
|
|
351
|
+
C7 导出可用 npx agentcss pdf 在装好的包上产出一份真 PDF(1 页 / 注入 @page)
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
反向控制 4 条(少一个文件 / 不引 tokens 各自都必须红)。C7 是「下载之后能不能用」
|
|
355
|
+
最后一块拼图:它跑的是 `node_modules/agentcss/ai/pdf.js`,不是仓库里的那份。全量门禁里也跑它
|
|
356
|
+
(自己 pack 一遍),`pack-smoke.sh` 则复用已经装好的目录 —— 判据只有一份。
|
|
357
|
+
|
|
358
|
+
### 修复:文档里最靠前的那条命令不能用
|
|
359
|
+
|
|
360
|
+
`AGENTS.md` / `llms.txt` / `docs/STABILITY.md` / `docs/VERIFY-RELEASE.md` 与
|
|
361
|
+
CLI 自己的帮助都教 `npx agentcss ai components --json`,而分发器只认
|
|
362
|
+
`components` ⇒ 照抄第一条命令得到「未知子命令:ai」。
|
|
363
|
+
|
|
364
|
+
现在 `ai` 是可选的**前缀别名**,两种写法都通;帮助里也写明了这一点。
|
|
365
|
+
这是消费者视角最贵的一类错误:文档第一条就打脸,后面写得再准也读不到。
|
|
366
|
+
|
|
367
|
+
### 体积
|
|
368
|
+
|
|
369
|
+
`overlay.css` 5.1 → 5.4 KB(+969 B,其中约 600 B 是注释)。
|
|
370
|
+
全量 raw +1,331 B / gzip +504 B(+0.16%)。按惯例重录基线,数字在这里写明。
|
|
371
|
+
|
|
372
|
+
### 屏幕零影响
|
|
373
|
+
|
|
374
|
+
109 张截图**逐字节一致**(47 浅色 + 47 暗色 + 15 RTL)。只有 3 个
|
|
375
|
+
`_stamp.json` 变了 —— 因为渲染指纹含 CSS 全集,改了 CSS 就必然要重录戳。
|
|
376
|
+
`print-gate` 的 18 份 PDF 页数与 run 数**与改动前完全相同**(没有任何采样页
|
|
377
|
+
开着 dialog,这正好是「无对话时改动是惰性的」那条控制)。
|
|
378
|
+
|
|
379
|
+
---
|
|
380
|
+
|
|
19
381
|
## [0.24.2] - 2026-11-01
|
|
20
382
|
|
|
21
383
|
**纯修订版:没有 CSS / JS / 类名 / 令牌的变更,下游不需要改任何代码。**
|
|
@@ -947,8 +1309,7 @@ combobox 的 `role`/`aria-haspopup` 是脚本后期设上去的 ⇒ 加载慢半
|
|
|
947
1309
|
|
|
948
1310
|
`docs/CONVENTIONS.md` 第七节与 `docs/LAYER-BASELINE.md` 早有结论:7 行真机实测里
|
|
949
1311
|
Android 14 · 百度浏览器(Chromium 97)**缺 `@layer`**,而 `@layer { … }` 不支持时是
|
|
950
|
-
**整块丢弃** ⇒
|
|
951
|
-
记进 `internal/ERRORS.md` E167:**"0 处"只说明现状,不说明原因;有门禁守着的"没有",
|
|
1312
|
+
**整块丢弃** ⇒ 那一层样式直接消失。切层在这个库里不是改进,是会让部分浏览器变白屏。教训是:**"0 处"只说明现状,不说明原因;有门禁守着的"没有",
|
|
952
1313
|
几乎都是决定。**
|
|
953
1314
|
|
|
954
1315
|
### 体积
|
|
@@ -1281,7 +1642,7 @@ Actions → release → Run workflow → 勾 `shoot_baseline`,
|
|
|
1281
1642
|
(**不是门禁发现的** —— 门禁只验它写了判据的东西。这条是有人顺着 demo 源码
|
|
1282
1643
|
读下来才看见的,记在这里提醒自己:判据的边界就是视野的边界。)
|
|
1283
1644
|
|
|
1284
|
-
###
|
|
1645
|
+
### 本轮流程上踩的坑
|
|
1285
1646
|
|
|
1286
1647
|
- **E146** 新判据 F7 的豁免条件第一版用 `or` 连接「版本号」与「过去时语汇」,
|
|
1287
1648
|
结果 `docs/ACCESSIBILITY.md` 表格行里的 WCAG 编号「**4.1.2**」被当成版本号
|
|
@@ -1490,7 +1851,7 @@ CSS 体积预算 125 → **132 KB**(剥注释后口径):两个新组件 +
|
|
|
1490
1851
|
| 把 `fl-nav-open` 改成 `fl-nav-opened` | 🔴 `fl-nav-open:基线里有、现在没了` |
|
|
1491
1852
|
| 把 `TocApi.init` 改名 | 🔴 `TocApi.init:基线里有、现在没了` |
|
|
1492
1853
|
|
|
1493
|
-
|
|
1854
|
+
过程中自己踩了两个洞:
|
|
1494
1855
|
|
|
1495
1856
|
- **E131**:扩了 `KINDS`,但汇总行还写死 `cur_by['token'] | cur_by['class']`
|
|
1496
1857
|
⇒ ⑦(未登记的移除)只对前两类算差集,新加的两类删了也不报。
|
|
@@ -1798,7 +2159,7 @@ switch :一块改成了 cmp(div vs 原生),另一块(label)改不
|
|
|
1798
2159
|
|
|
1799
2160
|
自检从 10 条加打到 32 条(21 条必须红 + 11 条必须绿)。
|
|
1800
2161
|
|
|
1801
|
-
###
|
|
2162
|
+
### 判据本身走过的两条错路
|
|
1802
2163
|
|
|
1803
2164
|
- 第一版按「类名是否定义在组件样式里」判标本 → `sparkline.css` 里
|
|
1804
2165
|
`.row > .sparkline` 这种后代选择器把排版类收进了类名表(假绿);
|
|
@@ -1833,7 +2194,7 @@ Tab 的链接)、`tabs` ×2(div 当 tab、三个 `tabindex="0"`)、`badge`
|
|
|
1833
2194
|
原因是新加的反例真的写了 `aria-checked`(那一块讲的就是"手写这个属性"),
|
|
1834
2195
|
而抽取器只取 `aria-` 后面的名字(与 `expanded` 同约定)。原生
|
|
1835
2196
|
`<input role="switch">` 并不需要它 —— 这条是**反例带进契约**的。
|
|
1836
|
-
选择保留并写在这里,而不是悄悄让它躺在 diff
|
|
2197
|
+
选择保留并写在这里,而不是悄悄让它躺在 diff 里。
|
|
1837
2198
|
|
|
1838
2199
|
### 门禁
|
|
1839
2200
|
|
|
@@ -1851,7 +2212,7 @@ Tab 的链接)、`tabs` ×2(div 当 tab、三个 `tabindex="0"`)、`badge`
|
|
|
1851
2212
|
`tablist "基本信息 高级设置"`,`「文件已删除」` 那条 toast 会被念成
|
|
1852
2213
|
`status [live=polite atomic=true]`。三处都逐条核过,不是照单全收。
|
|
1853
2214
|
|
|
1854
|
-
###
|
|
2215
|
+
### 自己踩的坑
|
|
1855
2216
|
|
|
1856
2217
|
- **E119/E120**:判"有没有标本"的两条错路(类名定义表 / 边框底色),
|
|
1857
2218
|
两头都有误判实例,都留在代码注释里。
|
|
@@ -1878,7 +2239,7 @@ Tab 的链接)、`tabs` ×2(div 当 tab、三个 `tabindex="0"`)、`badge`
|
|
|
1878
2239
|
恰好绕开了 `<li>` 的真实 24px 坑。
|
|
1879
2240
|
|
|
1880
2241
|
前两处已改成「两栏用同一句长文本,反例真的折行、正例真的省略」。
|
|
1881
|
-
|
|
2242
|
+
第三处的教训:反例的坏必须来自**量过的**坑。
|
|
1882
2243
|
|
|
1883
2244
|
### 新增
|
|
1884
2245
|
|
|
@@ -3942,11 +4303,11 @@ B 还开着,背景却能点了 —— 用户看到的是「弹窗明明还在
|
|
|
3942
4303
|
|
|
3943
4304
|
## [0.7.9] - 2026-10-09
|
|
3944
4305
|
|
|
3945
|
-
>
|
|
3946
|
-
> 9+4 项成立(已修),2
|
|
4306
|
+
> 依据两份外部严格工程审计。⚠️ 12 项问题**逐条对着源码核过**:
|
|
4307
|
+
> 9+4 项成立(已修),2 项不成立(未改,理由见下),另外自查出 3 项审计没提到的新缺陷。
|
|
3947
4308
|
> ⚠️ 本版本起,门禁注册数由 `doc-facts-gate` 自动核对,文档里写错就红。
|
|
3948
4309
|
|
|
3949
|
-
### 修:CI 工作流的 YAML
|
|
4310
|
+
### 修:CI 工作流的 YAML 语法错误
|
|
3950
4311
|
|
|
3951
4312
|
`.github/workflows/gate.yml` 里躺着一行:
|
|
3952
4313
|
|
|
@@ -3973,7 +4334,7 @@ YAML 规范要求注释标记 `#` 必须与前面的内容由**空白**分隔。
|
|
|
3973
4334
|
剥完留下的空格会让 `check.js` 重新变成独立 token。
|
|
3974
4335
|
正确规则是「路径必须是**独立参数**」(前一个字符只能是空白/引号/行首)。
|
|
3975
4336
|
|
|
3976
|
-
###
|
|
4337
|
+
### 修:浏览器矩阵**没有真的切换引擎**(这一版最严重的一条)
|
|
3977
4338
|
|
|
3978
4339
|
矩阵声明了 chromium / webkit / firefox 三个引擎,
|
|
3979
4340
|
但 `matrix.engine` **只用在 `npx playwright install` 那一步**,
|
|
@@ -3981,7 +4342,7 @@ YAML 规范要求注释标记 `#` 必须与前面的内容由**空白**分隔。
|
|
|
3981
4342
|
硬编码的 Chromium 路径。⇒ **三个作业跑的都是 Chromium**。
|
|
3982
4343
|
|
|
3983
4344
|
⚠️ 这比"没做跨浏览器"更坏:它产生了一份**看起来存在**的证据。
|
|
3984
|
-
|
|
4345
|
+
审计会拿它当覆盖率,使用者会拿它当兼容承诺,而它一次都没测过
|
|
3985
4346
|
(与 I-10「报告通过却什么也没查」同一类失效)。
|
|
3986
4347
|
|
|
3987
4348
|
⇒ 三处改动:
|
|
@@ -3989,7 +4350,7 @@ YAML 规范要求注释标记 `#` 必须与前面的内容由**空白**分隔。
|
|
|
3989
4350
|
写错引擎名**立刻报错**(不许静默退回 —— 退回就等于没选)。
|
|
3990
4351
|
缺 playwright 也报错,**绝不退回 Chromium**。
|
|
3991
4352
|
2. 新增 `05-audit/engine-probe.js`:每个作业**自己站起来报 UA**,
|
|
3992
|
-
并校验 UA
|
|
4353
|
+
并校验 UA 属于声明的引擎族(验收标准)。
|
|
3993
4354
|
🔴 Chromium 的 UA 里**也含** `AppleWebKit`(它本是 WebKit 分叉)
|
|
3994
4355
|
⇒ 只判子串会把 Chromium 认成 WebKit —— 而那正是原来那个 bug 的形态。
|
|
3995
4356
|
3. 新增 `05-audit/engine-gate.js`:逐个引擎启动,要求
|
|
@@ -4015,7 +4376,7 @@ YAML 规范要求注释标记 `#` 必须与前面的内容由**空白**分隔。
|
|
|
4015
4376
|
不等于 iOS WKWebView / Android WebView 真机(软键盘、安全区、
|
|
4016
4377
|
`100vh`、页面回弹、VoiceOver 一项都没覆盖)。真机仍是 ❌,见 `SUPPORT.md`。
|
|
4017
4378
|
|
|
4018
|
-
### 修:popover
|
|
4379
|
+
### 修:popover 在移动端真的横向溢出(开真引擎后**新发现**,审计没提)
|
|
4019
4380
|
|
|
4020
4381
|
开 WebKit 后 popover 契约红了一条:`483 ≤ 393`。
|
|
4021
4382
|
逐元素量下来两引擎**布局完全一致**,差别只在 `window.innerWidth`:
|
|
@@ -4026,14 +4387,14 @@ YAML 规范要求注释标记 `#` 必须与前面的内容由**空白**分隔。
|
|
|
4026
4387
|
| webkit | 483 | 393 | 判据红 |
|
|
4027
4388
|
|
|
4028
4389
|
⇒ **溢出是真的,Chromium 只是用"视口被内容撑大"的方式把它量成了没溢出。**
|
|
4029
|
-
|
|
4390
|
+
这正是"错误的矩阵会掩盖真问题"的实例。
|
|
4030
4391
|
|
|
4031
4392
|
修法是让四个方向的演示**竖排**(`.row--stack`)——
|
|
4032
4393
|
`end` 方向浮层挂在锚点右侧(`inset-inline-start: 100%`),横排时必然顶出视口。
|
|
4033
4394
|
⚠️ 这不是"改测试让它过":溢出是真的;竖排后演示成立。
|
|
4034
4395
|
但**组件本身不会碰撞翻转**这件事没有变 ⇒ 已写进 `SUPPORT.md` 的「已知限制」。
|
|
4035
4396
|
|
|
4036
|
-
###
|
|
4397
|
+
### 修:锁文件版本漂移
|
|
4037
4398
|
|
|
4038
4399
|
`package.json` = 0.7.7,`package-lock.json` 根包 = **0.3.0**。
|
|
4039
4400
|
|
|
@@ -4046,7 +4407,7 @@ YAML 规范要求注释标记 `#` 必须与前面的内容由**空白**分隔。
|
|
|
4046
4407
|
(lockfile 的 `version` 与 `packages[""].version` 两处都查,连带 name)。
|
|
4047
4408
|
突变体证明它是活的:把锁文件改回 0.3.0 ⇒ EXIT=1。
|
|
4048
4409
|
|
|
4049
|
-
### 修:`SUPPORT.md`
|
|
4410
|
+
### 修:`SUPPORT.md` 里三句假话(这一版**新发现**,审计没提)
|
|
4050
4411
|
|
|
4051
4412
|
| 原文 | 事实 |
|
|
4052
4413
|
|---|---|
|
package/CONTRIBUTING.md
CHANGED
|
@@ -29,8 +29,9 @@ npm run gate # 全量:含浏览器类
|
|
|
29
29
|
npm run gate:fast # 只跑静态层,不用装浏览器
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
-
全量是 **
|
|
33
|
-
|
|
32
|
+
全量是 **233 道门禁**(默认 `min(核数, 6)` 路并发,实测 583 秒 / 退出码 0;
|
|
33
|
+
单道耗时累加 1658 秒,并发效率约 2.8×。组件层要起浏览器,还要逐张比 **109 张**视觉截图 ——
|
|
34
|
+
47 浅色 + 47 暗色 + 15 RTL,按平台分集,只比本平台那套)。
|
|
34
35
|
只想确认没改坏静态契约的话用 `gate:fast`,几秒到几分钟。
|
|
35
36
|
|
|
36
37
|
### 全量为什么**不**在 CI 上跑(这不是缺口,是结论)
|
|
@@ -69,7 +70,7 @@ shallow clone ⇒ 依赖 git 状态的判据语义不同;浏览器版本不同
|
|
|
69
70
|
|
|
70
71
|
**`2` 不是跳过**:已有 9 个门禁用它表示「参数错 / 前置条件不满足」,往 2 上加语义会把真错误
|
|
71
72
|
静默降级成跳过。**更不要 `return 0` 冒充跳过**——`rc=0` 天然等于通过,那正是假绿
|
|
72
|
-
|
|
73
|
+
。有未判定项时,汇总**不会**打印「全部通过」。
|
|
73
74
|
|
|
74
75
|
环境依赖只有一套(Node + Chromium),缺了对应的门禁会**跳过**(跳过不算通过):
|
|
75
76
|
|
|
@@ -84,8 +85,8 @@ Pillow 只在你想复核那次对齐时才有用,装了不加分、不装也
|
|
|
84
85
|
RTL 有**两套**证据,需要分别跑、分别更新:
|
|
85
86
|
|
|
86
87
|
```bash
|
|
87
|
-
node 05-audit/rtl-render.js # 渲染判据(
|
|
88
|
-
python 05-audit/shot-baseline.py --check --dir rtl # 视觉基线(
|
|
88
|
+
node 05-audit/rtl-render.js # 渲染判据(42 页)
|
|
89
|
+
python 05-audit/shot-baseline.py --check --dir rtl # 视觉基线(15 页,默认已随全量一起拍)
|
|
89
90
|
```
|
|
90
91
|
|
|
91
92
|
**视觉基线按平台分集**:目录名是 `_baseline-<平台>[-<scheme>][-rtl]`,
|
package/README.md
CHANGED
|
@@ -62,7 +62,8 @@ Two more paths that resolve to the same content:
|
|
|
62
62
|
|
|
63
63
|
```bash
|
|
64
64
|
# Pin an exact version and get a tarball byte-identical to the published one
|
|
65
|
-
npm
|
|
65
|
+
# (把 <版本> 换成 `npm view agentcss version` 的输出 —— 不写死,免得又过期)
|
|
66
|
+
npm install https://github.com/owain323/frontend-lib/releases/download/v<版本>/agentcss-<版本>.tgz
|
|
66
67
|
|
|
67
68
|
# Track master (unreleased commits)
|
|
68
69
|
npm install github:owain323/frontend-lib
|
|
@@ -266,11 +267,14 @@ not — is in [`docs/STABILITY.md`](docs/STABILITY.md).
|
|
|
266
267
|
|
|
267
268
|
## Browser support
|
|
268
269
|
|
|
269
|
-
[`SUPPORT.md`](SUPPORT.md) lists every engine with the evidence behind its status.
|
|
270
|
+
[`SUPPORT.md`](SUPPORT.md) lists every engine with the evidence behind its status. Three conventions matter there:
|
|
270
271
|
|
|
271
272
|
- **Verified** means an automated check runs **in that engine** and the job reports its own user agent as proof.
|
|
273
|
+
- **Tested once** (`🔍`) means exactly that: one manual run on a real device, with a full UA and a per-capability result, but **no automated check watching it**. A browser update will not turn anything red. It never counts as verified, and the two never add up.
|
|
272
274
|
- **Not claimed** means exactly that. A row that has not been tested is not written as supported.
|
|
273
275
|
|
|
276
|
+
Mobile WebView support is where that distinction bites. Seven entry points have been probed by hand — per-capability results in [`10-review/webview/RESULTS.md`](10-review/webview/RESULTS.md) — while Android System WebView still has **no data at all**. None of the seven was checked for soft-keyboard, safe-area, scroll-bounce or 200 % text behaviour: "15/15 capabilities" is not "the page works on a phone".
|
|
277
|
+
|
|
274
278
|
## Theming
|
|
275
279
|
|
|
276
280
|
Themes are switched by a `data-theme` attribute on any container, not only on the root — a dark card can sit inside a light page.
|
package/README.zh-CN.md
CHANGED
|
@@ -64,7 +64,7 @@ npm install agentcss
|
|
|
64
64
|
|
|
65
65
|
```bash
|
|
66
66
|
# ① 钉住某一版、且拿到与我们验证过的那一份**逐字节一致**的 tarball
|
|
67
|
-
npm install https://github.com/owain323/frontend-lib/releases/download/
|
|
67
|
+
npm install https://github.com/owain323/frontend-lib/releases/download/v<版本>/agentcss-<版本>.tgz
|
|
68
68
|
|
|
69
69
|
# ② 想跟着 master 走(未发布的最新提交)
|
|
70
70
|
npm install github:owain323/frontend-lib
|
|
@@ -412,7 +412,8 @@ bash 05-audit/check-all.sh # 全量门禁约 130 项,本机约 8 分钟
|
|
|
412
412
|
|
|
413
413
|
### 明确不承诺的
|
|
414
414
|
|
|
415
|
-
-
|
|
415
|
+
- **不承诺「移动 WebView 支持」**:只在 7 个具体入口上人工跑过能力探针,
|
|
416
|
+
没有自动化守着,也没做过真机整页验收(见下一节)。Android 系统 WebView **没有任何数据**。
|
|
416
417
|
- 不做虚拟滚动:大表格的行数上限交给调用方判断。
|
|
417
418
|
- 不提供 React / Vue 组件,只提供 CSS 类与可选的行为脚本。
|
|
418
419
|
- `scientific-plot` 不做插值、回归或任何统计计算,也不宣称显著性。
|
|
@@ -422,13 +423,24 @@ bash 05-audit/check-all.sh # 全量门禁约 130 项,本机约 8 分钟
|
|
|
422
423
|
|
|
423
424
|
| 环境 | 状态 |
|
|
424
425
|
|---|---|
|
|
425
|
-
| Chrome / Edge(桌面) |
|
|
426
|
-
| Firefox(桌面) |
|
|
427
|
-
| iOS Safari /
|
|
428
|
-
| Android
|
|
426
|
+
| Chrome / Edge(桌面) | ✅ 已验证(自动化) |
|
|
427
|
+
| Firefox(桌面) | ✅ 已验证(自动化) |
|
|
428
|
+
| iOS Safari / 微信 / 企微 / QQ 浏览器 | 🔍 人工实测 15/15(无自动化) |
|
|
429
|
+
| Android 微信 | 🔍 人工实测 14/15(缺 `scrollbar-width`,有私有回退) |
|
|
430
|
+
| Android 百度浏览器 | 🔍 人工实测 11/15(缺 `@layer`,阻塞切层) |
|
|
431
|
+
| Android 系统 WebView | ❌ 无数据 |
|
|
432
|
+
| Android Chrome(移动版) | ⚠️ 仅桌面引擎模拟移动视口 |
|
|
433
|
+
|
|
434
|
+
**`✅` 与 `🔍` 不能相加。** `✅` 是「有自动化检查在这个引擎里跑,有人守着」;
|
|
435
|
+
`🔍` 是「在真实设备上人工试过一次,之后没人再看」——
|
|
436
|
+
浏览器升级只会被前者发现。逐项结果、完整 UA 与复核方法见
|
|
437
|
+
[`docs/LAYER-BASELINE.md`](docs/LAYER-BASELINE.md) 与
|
|
438
|
+
[`10-review/webview/RESULTS.md`](10-review/webview/RESULTS.md)。
|
|
429
439
|
|
|
430
440
|
⚠️ 定位里写「移动 Web」指的是**设计取向**(触控优先、命中区不小于 44px),
|
|
431
|
-
|
|
441
|
+
不代表已被自动化覆盖,更不代表页面在真机上就能用:
|
|
442
|
+
软键盘、安全区、回弹、200% 字号、读屏这些**一项都没验过**。
|
|
443
|
+
生产前请在自己的目标环境验证 —— 尤其是 Android 系统 WebView,那是目前唯一 0 数据的入口。
|
|
432
444
|
|
|
433
445
|
## 主题定制
|
|
434
446
|
|
package/SECURITY.md
CHANGED
|
@@ -48,8 +48,11 @@ combobox 那处 `innerHTML` 当前是安全的(已转义),但缺一道门
|
|
|
48
48
|
| 打过的 tag(`v0.8.8` 起) | ✅ 修安全相关缺陷并回移植 |
|
|
49
49
|
| `v0.8.8` 之前 | ❌ 无 tag、无锚点,无法可靠回溯 |
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
**本库已发布到 npm**:包名 `agentcss`,首次发布 2026-10-18(`0.0.0-stage`),
|
|
52
|
+
`dist-tags.latest` 指向最新稳定版;从 `0.16.0` 起的版本带 **SLSA provenance**
|
|
53
|
+
(`npm view agentcss@<版本> dist.attestations` 可查,证明产物由本仓库的
|
|
54
|
+
release 工作流构建,不是本地 `npm publish` 上传的)。
|
|
55
|
+
安装方式见 `README.md` 的「安装」一节;装哪个版本可以 `npm view agentcss version` 查。
|
|
53
56
|
|
|
54
57
|
### 版本与提交点的锚点
|
|
55
58
|
|