agentcss 0.24.2 → 0.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/01-tokens/README.md +1 -1
  2. package/01-tokens/tokens.css +67 -1
  3. package/01-tokens/typography.css +1 -1
  4. package/02-primitives/button/demo.html +8 -0
  5. package/02-primitives/card/README.md +15 -0
  6. package/02-primitives/choice/README.md +30 -0
  7. package/02-primitives/choice/choice.css +1 -1
  8. package/02-primitives/input/README.md +1 -0
  9. package/02-primitives/select/README.md +42 -2
  10. package/02-primitives/select/demo.html +11 -6
  11. package/02-primitives/select/select.js +184 -94
  12. package/02-primitives/timeline/demo.html +2 -2
  13. package/02-primitives/timeline/timeline.css +1 -1
  14. package/03-patterns/accordion/README.md +15 -0
  15. package/03-patterns/content/README.md +11 -0
  16. package/03-patterns/drawer/README.md +1 -1
  17. package/03-patterns/dropdown/demo.html +1 -1
  18. package/03-patterns/form-validation/README.md +18 -0
  19. package/03-patterns/form-validation/form-validation.css +12 -1
  20. package/03-patterns/list/README.md +11 -0
  21. package/03-patterns/overlay/README.md +26 -6
  22. package/03-patterns/overlay/overlay.css +22 -3
  23. package/03-patterns/overlay/overlay.js +63 -17
  24. package/03-patterns/states/README.md +15 -0
  25. package/03-patterns/states/states.css +18 -1
  26. package/03-patterns/tooltip/README.md +12 -0
  27. package/04-recipes/longform/longform.html +3 -3
  28. package/04-recipes/report/README.md +9 -0
  29. package/04-recipes/report/report.css +5 -0
  30. package/04-recipes/table/README.md +16 -0
  31. package/04-recipes/tierA-tokens.css +3 -3
  32. package/09-assets/README.md +18 -0
  33. package/09-assets/bar/bar.css +25 -10
  34. package/09-assets/echarts-adapter/demo.html +3 -1
  35. package/09-assets/echarts-adapter/echarts-adapter.js +107 -34
  36. package/09-assets/scientific-plot/README.md +2 -1
  37. package/09-assets/scientific-plot/scientific-plot.js +0 -7
  38. package/AGENTS.md +2 -1
  39. package/CHANGELOG.md +317 -18
  40. package/CONTRIBUTING.md +6 -5
  41. package/README.md +6 -2
  42. package/README.zh-CN.md +19 -7
  43. package/SECURITY.md +5 -2
  44. package/START-HERE.md +7 -7
  45. package/SUPPORT.md +86 -24
  46. package/ai/START-HERE.md +3 -2
  47. package/ai/cli.js +126 -6
  48. package/ai/components.json +258 -2
  49. package/ai/components.meta.json +257 -40
  50. package/ai/components.schema.json +96 -0
  51. package/ai/contract.schema.json +11 -0
  52. package/ai/pdf-pages.js +79 -0
  53. package/ai/pdf.js +354 -0
  54. package/ai/tokens.json +2 -2
  55. package/ai/validate.js +48 -1
  56. package/dist/01-tokens/tokens.css +1 -1
  57. package/dist/02-primitives/select/select.js +158 -71
  58. package/dist/03-patterns/form-validation/form-validation.css +1 -1
  59. package/dist/03-patterns/overlay/overlay.css +1 -1
  60. package/dist/03-patterns/overlay/overlay.js +40 -11
  61. package/dist/03-patterns/states/states.css +1 -1
  62. package/dist/04-recipes/report/report.css +1 -1
  63. package/dist/04-recipes/tierA-tokens.css +1 -1
  64. package/dist/09-assets/bar/bar.css +1 -1
  65. package/dist/09-assets/echarts-adapter/echarts-adapter.js +75 -33
  66. package/dist/09-assets/scientific-plot/scientific-plot.js +0 -7
  67. package/dist/COSTS.md +37 -37
  68. package/docs/ACCESSIBILITY.md +3 -3
  69. package/docs/FACTS.md +1 -1
  70. package/docs/LAYER-BASELINE.md +28 -3
  71. package/docs/PRINT.md +450 -0
  72. package/docs/RELEASE-PROCESS.md +78 -3
  73. package/index.html +1 -1
  74. package/llms-full.txt +7 -7
  75. package/llms.txt +5 -0
  76. package/package.json +6 -1
package/docs/PRINT.md ADDED
@@ -0,0 +1,450 @@
1
+ # 打印与 PDF
2
+
3
+ > 这份文件回答两件事:**打印时库自动做了什么**、**哪些还需要你自己做**。
4
+ > 所有规则都在 `01-tokens/tokens.css` 的 `@media print` 块里,屏幕渲染零影响。
5
+
6
+ ---
7
+
8
+ ## 一、能做什么
9
+
10
+ 把页面交给浏览器打印(`Ctrl/Cmd + P` → 另存为 PDF),或交给无头浏览器
11
+ `page.pdf({ format: 'A4', preferCSSPageSize: true })`,你会得到:
12
+
13
+ | 行为 | 说明 |
14
+ |---|---|
15
+ | **强制浅色** | 屏幕上是暗色主题,纸上照样是深字白纸(`color-scheme: light`) |
16
+ | **浮层不上纸** | toast / tooltip / popover / skeleton 自动隐藏 |
17
+ | **纯导航不上纸** | tabs 标签栏、nav 链接、分页器、汉堡按钮、accordion 箭头 |
18
+ | **表格不散架** | 取消滚动容器(否则只打印可视区那几行);表头每页重复(HTML 默认行为,本库未覆盖) |
19
+ | **不跨页切断** | 表格行、图片、图表、卡片、指标卡整体换页,不从中间切开 |
20
+ | **折叠内容自动展开** | `tabs` 未选中的面板、`accordion` 收起的面板,打印时全部展开。**不展开 = 静默截断**:页数正常、对比度合格、内容少一半,只靠数 runs 抓不到 |
21
+ | **孤行寡行(仅 report 配方)** | `.rep` 内的段落首尾不留单行在另一页。**不全局生效** —— 裸 `p` / `li` 会改掉宿主页面所有段落,那是 `bleed-gate` 的红线 |
22
+ | **字体全嵌入** | 实测 87 个字体名、0 个引用链问题;不依赖阅读方装字体 |
23
+ | **对比度** | 每一段文字对白纸 ≥ 4.5:1(实测最差 5.44:1) |
24
+
25
+ 这些不是"看起来对",是 `05-audit/print-gate.js` 读**真实 PDF 产物**判出来的。
26
+
27
+ > 早期笔记写过「`page.emulateMediaType('print')` 在本环境并不切换媒体类型」——
28
+ > 2026-11-02 复测**这条不成立**:`emulateMediaType('print')` 之后
29
+ > `matchMedia('print').matches === true`,computed `display` 也随之变化。
30
+ > 所以现在可以在浏览器里直接审「打印态会不会显示」(`print-content-audit.js` 默认就跑两次扫描:屏幕一次、打印一次)。
31
+ > 门禁本身仍然读真实 PDF —— 那是最终产物,比任何模拟都可靠。
32
+
33
+ ### 折叠内容为什么要三条规则
34
+
35
+ `.accordion__panel[hidden]` 同时被三样东西挡住,少一条就是"看起来展开了、一个字不印":
36
+
37
+ ```css
38
+ .accordion .accordion__panel[hidden] {
39
+ display: grid !important; /* ① 组件自己写了 display:none !important */
40
+ grid-template-rows: 1fr; /* ② 收起态是 0fr,不改就还是 0 高 */
41
+ visibility: visible; /* ③ 组件还写了 visibility:hidden */
42
+ }
43
+ ```
44
+
45
+ 三条缺任一条的实测后果:`display` 与高度都对了,但内容仍是 `visibility:hidden`,
46
+ PDF 里一个字都不多。`tabs` 只需要第 ① 条(它没有 `!important`、没有 visibility、也不靠 grid 定高)。
47
+
48
+ 还有一条**特异性**的坑:`tokens.css` 在 `<head>` 里最先加载,
49
+ 不加组件根前缀(`.tabs` / `.accordion`)时同特异性的规则会被组件 CSS 覆盖 ——
50
+ 实测:不加前缀时 PDF 与改动前**逐字节相同**,规则完全没生效。
51
+
52
+ ---
53
+
54
+ ## 二、三个工具类
55
+
56
+ ### `.no-print` —— 这个元素不上纸
57
+
58
+ ```html
59
+ <div class="report-actions no-print">
60
+ <button class="btn">导出 Excel</button>
61
+ <button class="btn">分享</button>
62
+ </div>
63
+ ```
64
+
65
+ 页面上照常显示,打印时整块消失。全库唯一的 `!important` 用在这里 ——
66
+ 不加就永远可能被使用者自己写的 `display` 盖掉,等于没提供这个能力。
67
+
68
+ ### `.print-only` —— 只在纸上出现
69
+
70
+ ```html
71
+ <div class="print-only">内部资料 · 请勿外传</div>
72
+ ```
73
+
74
+ 屏幕上 `display: none`,打印时显示。用于打印版专用标题、页眉、落款、水印文字。
75
+ **放在块级元素上**(`div` / `p` / `h2`);行内场景请自己写 `display`。
76
+
77
+ ---
78
+
79
+ ## 三、为什么不自动隐藏按钮
80
+
81
+ `.btn` 和 `.upload` **刻意不在隐藏清单里**。这是实测后改的主意:
82
+
83
+ - `guide/button.html` 是**按钮组件文档页**,也是打印门禁的采样页。
84
+ 把 `.btn` 全局隐藏,打印"按钮组件文档"就只剩标题 —— 组件展示页里的按钮是**内容**。
85
+ - `.upload` 是**带状态的表单控件**(已上传哪个文件),和 `.input` 同类,不是纯操作。
86
+
87
+ ⇒ 业务页要排除操作区,给那个容器加 `.no-print`(见上)。
88
+ 这条边界是"宁可少藏,不可多藏"。
89
+
90
+ ### 模态(`.dialog`):遮罩不隐藏,拉回正常流
91
+
92
+ 屏幕上开着 dialog 时打印,`.dialog-backdrop` 的 computed 是
93
+ `position: fixed; inset: 0; background: rgba(21,24,28,.4)` —— 直接印,
94
+ **整页是 40% 黑**。实测(2026-11-02,`print-policy-gate` 的标本页):
95
+
96
+ | 做法 | 结果 |
97
+ |---|---|
98
+ | 隐藏遮罩 `display: none` | 纸面干净了,但 `.dialog` 是它的子节点 ⇒ **弹窗里的字一起消失**,不报错 |
99
+ | **拉回正常流**(本库的选择) | 没有 fixed 遮罩、没有 `100vh` 限高,内容完整,接在文档末尾 |
100
+
101
+ ```css
102
+ @media print {
103
+ .dialog-backdrop { position: static; inset: auto; display: block;
104
+ padding: 0; background: none; }
105
+ .dialog { max-height: none; overflow: visible; }
106
+ }
107
+ ```
108
+
109
+ 顺带量过一个相关项:dialog 打开时 `overlay.js` 会给 `body` 加
110
+ `data-scroll-locked`(`overflow: hidden`)。**它不会裁掉纸面** ——
111
+ body 高度是 auto,实测打印态 `scrollHeight === clientHeight`(2372 = 2372),
112
+ 页数与不打开 dialog 时相同(都是 2 页)。所以不需要为它加打印规则。
113
+
114
+ 🔴 这条规则写在 `03-patterns/overlay/overlay.css`,**不能**写进 `tokens.css`:
115
+ tokens 先加载,同特异性的 `position: static` 会被这里的 `position: fixed`
116
+ 盖掉 —— 规则写了、不生效、不报错,与下面 §「折叠内容为什么要三条规则」
117
+ 里那条特异性坑是同一个病。这次是写完当场被门禁 L3 抓到的。
118
+
119
+ ### 自动隐藏清单(逐条理由)
120
+
121
+ | 选择器 | 为什么 |
122
+ |---|---|
123
+ | `.toast` `.tooltip` `.popover` | 只在屏幕交互中存在,纸上没有对应物 |
124
+ | `.skeleton` | 加载占位符,纸上永远是"未加载完"的假象 |
125
+ | `.tabs__list` | **只藏标签栏,不藏 `.tabs__panel`**(后者是内容) |
126
+ | `.nav__list` `.nav__toggle` | **只藏链接与汉堡,不藏 `.nav__brand`**(后者可能是页面标题) |
127
+ | `.pagination` | 纯导航 |
128
+ | `.accordion__marker` | **只藏箭头,不藏标题** |
129
+
130
+ **不用裸 `button` 标签选择器**:`.accordion__trigger` 就是个 `<button>`,
131
+ 标题文字装在它里面 —— 按标签选会连正文一起干掉。
132
+
133
+ ---
134
+
135
+ ## 四、分页控制
136
+
137
+ ```css
138
+ tr, img, figure, svg, .card, .metric, .sparkline, .splot { break-inside: avoid; }
139
+ ```
140
+
141
+ **代价(实测)**:高于半页的卡片会被整体推到下一页,`guide/button.html` 因此
142
+ 从 7 页变成 8 页(内容 run 数不变,仍是 1975)。宁可多一页,不要在纸中间切一半。
143
+
144
+ 高于**一整页**的元素,Chrome 会忽略 `avoid` 并强制切断 —— 这是规范行为,不是缺陷。
145
+ **而且它不会报错**:规则写了、看起来生效了、页数一点没变。
146
+
147
+ ### 代价到底多大:标定表
148
+
149
+ 用等高块实测(`node 05-audit/print-pagination-cost.js`,可复跑):
150
+
151
+ | 块高 | 占页 | avoid 页数 | auto 页数 | 通胀 |
152
+ |---|---|---|---|---|
153
+ | 240 px | 0.24 | 23 | 22 | +5% |
154
+ | 330 px | 0.33 | 24 | 24 | 0% |
155
+ | 420 px | 0.42 | 30 | 26 | +15% |
156
+ | **520 px** | **0.53** | **50** | **26** | **+92%** |
157
+ | 700 px | 0.71 | 30 | 21 | +43% |
158
+
159
+ **最坏点不在最高处,在页高一半附近。** 机制:532px 的块、页内可用高约 990px
160
+ ⇒ 每页只塞得下 1 个 ⇒ 每页浪费 46%。432px 的块 ⇒ 每页 2 个,浪费 12%。
161
+
162
+ 读法:
163
+
164
+ - 占页 ≤ 0.35 → `avoid` 几乎免费
165
+ - 占页 0.42 左右 → 一成半的代价
166
+ - **占页 0.5 上下 → 可能翻倍**,这是断崖
167
+ - 占页 0.7 → 四成多(每页 1 块,浪费固定)
168
+
169
+ ### 不想要这个代价:`.print-allow-break`
170
+
171
+ ```html
172
+ <figure class="card print-allow-break"> <!-- 这张图很大,切一刀我能接受 -->
173
+ ```
174
+
175
+ 它把 `break-inside` 改回 `auto`。实测(h=520 的 50 个块):
176
+
177
+ ```
178
+ 默认(avoid) 50 页
179
+ .print-allow-break 26 页 ← 省 48%,与强制 auto 完全相同
180
+ ```
181
+
182
+ **默认仍然是「不切断」**:一份被切开的图往往比多一页更难读。这个类是给
183
+ "我知道它在 500px 左右、我宁可他切开"的场景用的。
184
+
185
+ ### 长文档夹具的两条结论
186
+
187
+ `05-audit/fixtures/print-long/`(8 章 / 960 行表格 / 24 个卡片 / **56 页**)跑出来的:
188
+
189
+ 1. **表格套在 `figure` 里且超过一页时,`avoid` 被忽略** —— `avoid` 与 `auto`
190
+ 页数**完全相同**(85 页时的实测)。这不是 bug,是规范;但意味着
191
+ "给 `figure` 加 avoid 就安全" 是错觉。
192
+ 2. **混排文档里,卡片填进表格留下的空隙,不产生额外代价** —— 所以
193
+ "长文档一定通胀" 也是错的。代价来自**块高与页高的比例**,不来自文档长度。
194
+
195
+ ⇒ 判据应该是「块高 / 页高」,不是「文档页数」。
196
+
197
+ ### 孤行寡行为什么不全局
198
+
199
+ ```css
200
+ /* 04-recipes/report/report.css */
201
+ .rep p, .rep li, .rep blockquote { orphans: 2; widows: 2; }
202
+ ```
203
+
204
+ 只写在 `.rep` 容器内。裸 `p, li, blockquote` 会改掉宿主页面**所有**段落 ——
205
+ `bleed-gate` 把这条列为硬红线("组件只影响自己")。
206
+ 你自己的文档容器需要这一条,抄上面三行、把 `.rep` 换成你的容器类名即可。
207
+
208
+ ### 为什么没写 `thead { display: table-header-group }`
209
+
210
+ 那是 `thead` 的 HTML **默认值**,Chrome 默认就让表头每页重复,而本库没有任何规则
211
+ 覆盖它(已 grep 确认)。写一条与默认值相同的声明,只会让下一个人以为
212
+ "表头重复是我们加的"。
213
+
214
+ ---
215
+
216
+ ## 五、不覆盖什么(这一段比上面都重要)
217
+
218
+ | 缺口 | 现状 |
219
+ |---|---|
220
+ | **裁切检测** | **没有**。Chrome 把内容画在 2250×3275 的矩形里再用 `re W n` 裁到纸面,`bbox` 判不出"看得见的部分有没有被切"。要判得算字形宽度或栅格化比纸色,两者都不在本库 |
221
+ | **页码 / 页眉 / 页脚** | **没有**。CSS 的 `@page` 只能定尺寸与页边,给不了内容;要页码得用浏览器打印对话框的选项,或自己接 `page.pdf({ headerTemplate })` |
222
+ | **目录 / 书签** | **没有**。那是 PDF 生成器(或 PDF 库)的事,不是 CSS |
223
+ | **空白页检测** | 只有间接判据(页数 + run 数),不是直接检测 |
224
+ | **字体回退** | 检测不到。缺字体时 Chromium 会嵌一个回退字体,产物照样"有字" |
225
+
226
+ ⇒ 一句话:**库保证的是"页面能干净地打出来",不是"能出版"**。
227
+ 页码、目录、书签这类出版级需求,要在调用 `page.pdf()` 那一层解决。
228
+
229
+ ---
230
+
231
+ ## 六、怎么自己验
232
+
233
+ ```bash
234
+ # 打印判据(需要静态服务在 8000)
235
+ node 05-audit/print-gate.js
236
+
237
+ # 判定单个已有 PDF 的字体链与文本算子
238
+ node 05-audit/print-gate.js --pdf 某文件.pdf
239
+ ```
240
+
241
+ 判据共 12 条:对比度、暗色一致性、页数、文字 run 数、横向溢出、结构类型覆盖、
242
+ 字体引用链闭合、每页文本算子存在性。9 个采样页 × 2 种屏幕配色 = 18 份 PDF。
243
+
244
+ **屏幕不受影响**由另一道守着:`shot-baseline.py --check` 的 109 张截图逐字节比对。
245
+ 本目录所有规则改完,那 109 张必须一个字节都不变 —— 变了就是规则漏到屏幕了。
246
+
247
+ ---
248
+
249
+ ## 七、这些保证由谁守着
250
+
251
+ 上面每一条都是**可断言的**,不是文档承诺。守它的有五个东西:
252
+
253
+ | 工具 | 它回答的问题 | 它答不了什么 |
254
+ |---|---|---|
255
+ | `ai/components.json` 的 `printPolicy` | 这个组件在纸上会发生什么?(机器可读,AI 消费这一份) | 它只是声明,不等于生效 |
256
+ | `print-policy-gate.js` | 声明的都真的生效了吗?有没有没声明的隐藏? | 它不判"印出来好不好看" |
257
+ | `print-gate.js` | 按 Ctrl+P 印出来的 PDF 合格吗? | 它数得清 run,数不出"少了一半内容" |
258
+ | `print-content-audit.js` | 该印的在不在?(屏幕可见 → 纸上消失?) | 它只在浏览器里量,不读 PDF |
259
+ | `agentcss pdf` + `pdf-export-gate.js` | **导出成文件**这条路能用吗?(§八) | 它不做视觉比对 |
260
+
261
+ 前四个判的是"浏览器里按 Ctrl+P",最后一个判的是"导出一份文件" ——
262
+ **这是两条不同的渲染路径**(CDP `page.pdf()` vs Chrome 命令行 `--print-to-pdf`),
263
+ `@page` 的来源与底色默认都不同。所以前者全绿推不出后者能用,两边各有各的判据。
264
+
265
+ `printPolicy` 是**有限枚举**,每个值对应一组能在浏览器里量的断言:
266
+
267
+ | policy | 含义 | 断言(`print-policy-gate` L3) |
268
+ |---|---|---|
269
+ | `omit` | 内容不上纸 | 打印态 `display: none` |
270
+ | `expand` | 放开屏幕上的限制(隐藏/收起/限高/固定定位) | `display≠none`、`visibility≠hidden`、`position≠fixed`、`max-height:none`、`overflow` 不裁、有文字时高度 > 0 |
271
+ | `reveal` | 只在纸上出现 | 屏幕 `display:none` 且打印态不是 `none` |
272
+ | `keep-together` | 不跨页切断 | `break-inside: avoid` |
273
+ | `allow-break` | 退出 `keep-together` | `break-inside: auto` |
274
+
275
+ ⚠️ **什么叫"没声明"**:`printPolicy: []` 是明确值「原样保留」。缺字段才算漏 ——
276
+ 门禁会红。这条区分很重要:空的数组是结论,缺的字段是疏忽,两者不能长得一样。
277
+
278
+ 门禁分四条腿(少一条就有一类失效看不见):
279
+
280
+ ```
281
+ L0 归属 组件规则的选择器必须在该组件 CSS(打印块之外)里真的存在
282
+ ⇒ 抓「藏一个库里不存在的类」。实测抓到 `.overlay`:
283
+ tokens.css 一直在隐藏它,而全库没有任何 CSS 定义过它,
284
+ 真正的遮罩 `.dialog-backdrop` 反而没被处理
285
+ L1 声明→实现 契约里每条规则,全库 print 块里都要有值相符的声明
286
+ L2 实现→声明 每条会丢内容的声明都要有规则认领(display:none / visibility:hidden /
287
+ max-height:0 / opacity:0 / break-inside …)
288
+ L3 声明→生效 在真浏览器的 print 媒体下量标本页的计算值
289
+ ⇒ 抓「写了不生效」。实测抓到自己刚写的 `.dialog-backdrop`
290
+ 规则被 overlay.css 同特异性盖掉
291
+ ```
292
+
293
+ 反向控制 7 条(覆盖四条腿),其中两条是历史事故的**逐字复刻**:
294
+ E254(去掉 `.tabs ` 前缀,让组件 CSS 同特异性盖掉它)与
295
+ E255(只删 `visibility: visible`,display 与高度全对、一个字不印)。
296
+
297
+ ### 内容完整性是**硬判据**(2026-11-02 起)
298
+
299
+ `print-policy-gate` 管「声明与实现对不对得上」,`print-content-audit` 管
300
+ 「纸上到底少了什么」。后者现在是硬 FAIL,三条判据全部相对**屏幕态**量:
301
+
302
+ | 判据 | 条件 | 为什么要它 |
303
+ |---|---|---|
304
+ | ① 契约违约 | 命中 `expand` 的文字,打印仍不印 | printPolicy 说「要展开」就是承诺 |
305
+ | ② 静默消失 | 屏幕可见 → 纸上消失,且无 `omit` 声明 | 这就是「静默截断」的定义 |
306
+ | ③ 不算 | 屏幕也看不见 | 关闭的菜单 / 未触发的空态 / a11y 反例 —— 不是"被吞掉",是"没发生" |
307
+
308
+ **没有白名单。** 上一版靠手写 `DECLARED` 清单,绝对口径下全站会列出
309
+ 17 条 / 337 字,逐条看全是关闭态菜单和反例 —— 判据太粗,人就不看了,
310
+ 最后只能加白名单把它关掉。判据③ 取代了白名单:闭着的东西两态都闭着,
311
+ 不需要谁批准。
312
+
313
+ ```bash
314
+ node 05-audit/print-content-audit.js # 13 页采样集(门禁跑这一档,22s)
315
+ node 05-audit/print-content-audit.js --all # 47 页全站(发布前扫查,69s)
316
+ ```
317
+
318
+ 想加一个新组件的打印行为,流程是三步,顺序不能换:
319
+
320
+ 1. 在 `ai/components.meta.json` 的该组件下写 `printPolicy`(`why` 必须能回答"不这么做会怎样")
321
+ 2. 在 CSS 里实现;**库级**行为写 `01-tokens/tokens.css`,**组件自己的**写组件 CSS
322
+ (写反了会被同特异性盖掉,且不报错)
323
+ 3. 在 `05-audit/fixtures/print-policy/probe.html` 补标本 —— 没有标本就没有证据,
324
+ L3 会报「命中 0 个元素」
325
+
326
+ ```bash
327
+ python3 05-audit/gen-ai-contract.py # 重新生成 ai/components.json
328
+ node 05-audit/print-policy-gate.js # 四条腿
329
+ node 05-audit/print-policy-gate.js --selftest # 反向控制
330
+ ```
331
+
332
+ ---
333
+
334
+ ## 八、导出一份 PDF:`agentcss pdf`
335
+
336
+ 上面七节讲的是"在浏览器里按 Ctrl+P 会怎样"。这一节讲**产出一份文件**——
337
+ 这中间差一个东西:`@page`。
338
+
339
+ ### 8.1 分工:`@media print` 管行为,`@page` 管版式
340
+
341
+ ```
342
+ 组件库 → @media print 隐藏什么 / 展开什么 / 不跨页切断 (行为)
343
+ 导出器 → @page 纸多大 / 边距多少 (版式)
344
+ ```
345
+
346
+ 🔴 **`@page` 绝不能写进 `tokens.css`。** 实测:同一份页面,库里多一条
347
+ `@page` 规则,产物从 943 runs 变成 978 runs —— 使用者的边距控制会**静默失效**,
348
+ 而且没有任何报错。纸多大、边距多少,是"这份东西交给谁"决定的,
349
+ 不是某个按钮决定的。所以它属于导出路径,不属于组件库。
350
+
351
+ ```bash
352
+ npx agentcss pdf report.html --out report.pdf # 默认 A4 / 18mm 15mm
353
+ npx agentcss pdf report.html --out report.pdf --paper=letter --margin="20mm"
354
+ npx agentcss pdf report.html --out report.pdf --max-pages=8
355
+ ```
356
+
357
+ `--paper` 支持 `a4` / `letter` / `a5` / `a3` / `legal`。边距是 CSS 简写
358
+ (`18mm`、`"18mm 15mm"`、四段都认)。这两个参数靠**注入一条 `@page` 规则**实现,
359
+ 注入位置在使用者样式之后 —— 否则同特异性会被盖掉(E254 的同一个病)。
360
+
361
+ 零运行时依赖:用使用者机器上**已装好的** Chrome / Chromium / Edge。
362
+ 找不到就明确报错(退出码 3),不静默降级成空文件。指定位置:
363
+
364
+ ```bash
365
+ npx agentcss pdf report.html --out report.pdf --chrome="C:/Program Files/Google/Chrome/Application/chrome.exe"
366
+ # 或环境变量 AGENTCSS_CHROME / CHROME_PATH
367
+ ```
368
+
369
+ ### 8.2 页数预算:超了报错,不替你截断
370
+
371
+ ```bash
372
+ npx agentcss pdf report.html --out report.pdf --max-pages=8
373
+ ```
374
+
375
+ ```
376
+ [FAIL] 超出页数预算:12 页 > 8 页(A4,595×842pt,边距 18mm 15mm)
377
+ 产出文件保留在:…/report.pdf
378
+ 三条出路(按代价从低到高):
379
+ ① 拆文档 把一章拆成单独文件分别导出
380
+ ② 进附录 明细移到附录,正文只留汇总 —— 需要作者改内容
381
+ ③ 截断 **本工具不代做**。静默丢内容正是这套判据在防的事
382
+ ```
383
+
384
+ 退出码 `5`。**没有全局默认预算** —— 页数取决于内容,任何默认值都是猜的。
385
+ 不传 `--max-pages` 就是无界,工具会明确说"预算未设(无界)"而不是假装有个上限。
386
+
387
+ 为什么不实现 `--on-exceed=truncate`:一个会替你悄悄删掉后半份报告的工具,
388
+ 比一个报错停下的工具危险得多。真要截断,请删掉要删的段落再导出 ——
389
+ 那样它会出现在 `git diff` 里,有人会看见。
390
+
391
+ ### 8.3 `--medium=paper`:校验时的打印义务
392
+
393
+ `ai check` 多了一根**与档位正交**的轴:
394
+
395
+ ```bash
396
+ npx agentcss ai check doc.json --medium=paper
397
+ ```
398
+
399
+ `screen`(默认)下什么都不变 —— 95% 的人不该看到"打印"两个字。
400
+ `paper` 下追加三条义务:
401
+
402
+ | 判据 | 结果 | 为什么 |
403
+ |---|---|---|
404
+ | 必须声明 `pageBudget` | 错 | 没有它,"印了 40 页"是惊喜不是错误 |
405
+ | 不允许 `pagination:"server"` 的组件 | 错 | 纸上只有当前一页,而文件看起来完整 |
406
+ | 用了 `printPolicy:"omit"` 的组件 | 提示 | 那部分不会出现在纸上,作者得知道 |
407
+
408
+ 为什么不做成第四个 `profile`:档位是"允许多不成熟的东西进来",
409
+ 介质是"这份东西给屏幕还是给纸"。`strict+paper` 与 `creative+paper` 都必须合法,
410
+ 压成一维就会丢掉四种组合里的两种。
411
+
412
+ ### 8.4 一条必须知道的观测差异:底色
413
+
414
+ | | 底色 | 白字压深色块 |
415
+ |---|---|---|
416
+ | 浏览器打印对话框(默认不勾"背景图形") | 丢弃 | 被压成 #ABABAB,看起来发灰 |
417
+ | `agentcss pdf` | **保留** | 白字压深蓝,可读 |
418
+
419
+ 两者不是谁错了,是两个产品。所以 `print-gate` 的对比度判据(对白纸量)
420
+ 只对对话框那一路成立;导出产物走的是 8.5 那套判据,不套用对比度。
421
+
422
+ ### 8.5 这条路谁守着
423
+
424
+ ```bash
425
+ node 05-audit/pdf-export-gate.js # E1–E12 + 三条反向,约 11s,不需要静态服务
426
+ node 05-audit/pdf-export-gate.js --selftest # 只跑"必须红"的几条,约 0.3s
427
+ ```
428
+
429
+ | 判据 | 它问什么 | 实测抓到过什么 |
430
+ |---|---|---|
431
+ | E1 | 真的产出了一份 PDF 吗 | 退出码 0 但文件不存在 |
432
+ | E2 | 同一输入两次导出结果一样吗 | 异步渲染没排完 ⇒ 页数会变 |
433
+ | E3 | `--paper` 真的换纸幅吗 | 注入逻辑被改坏 ⇒ 回落成 Letter 612×792 |
434
+ | E4/E5 | 预算的两向:以内通过、超出报错 | 超限不给退出码 5 |
435
+ | E6 | 库的打印规则到得了产物里吗 | 删掉 `.tabs__panel[hidden]` 那条 ⇒ 隐藏面板的字消失 |
436
+ | E7 | `--margin` 真的影响页数吗 | 不注入 `@page` 时 60mm 与 10mm 页数相同 |
437
+ | E8/E9″ | 没有浏览器时说人话吗;报错回显原始输入吗 | 退出码不对 / `abc` 被报成 `null` |
438
+ | E11 | 产物本身合格吗(字体链 / 每页有文本) | 交给 `print-gate --pdf` 的分析器判,不重复实现解析 |
439
+
440
+ 🔴 E3 与 E7 是同一件事的两面:`@page` 注入是这套东西唯一的技术前提。
441
+ 把它改坏,门禁必须红 —— 实测过:注释掉注入那行,E3 报
442
+ `a4=612×792pt`(回落成 Letter),E7 报 `10mm=2 页 / 60mm=2 页`。
443
+
444
+ ### 8.6 不覆盖什么
445
+
446
+ - **远程 URL 不注入 `@page`**:拿不到远程页面的字节,硬注入等于假装改了它。
447
+ 这类导出会明确打印"(远程页面:未注入 @page)",纸幅由页面自己的 CSS 决定。
448
+ - **视觉正确**:底色位置、边框粗细、图片裁切 —— 要栅格化比对,没做。
449
+ - **页眉页脚 / 页码**:`--no-pdf-header-footer` 已关掉 Chrome 的默认页眉页脚,
450
+ 但本工具不生成自己的。需要页码请用 `@page` + `counter(page)` 自己写。
@@ -49,7 +49,7 @@ git push origin v0.24.2 # 只推这一个,不要 git push --tags
49
49
  - `source-commit` 必须是**完整 40 位**:短 SHA 有歧义空间,而这条记录的全部价值就是"没有歧义地指认一个提交"。
50
50
  - 发布门禁会核三件事:tag 消息里的声明 == tag 实际指向的提交;该提交被至少一个远端分支包含;tag 内 `VERSION` 与当前版本一致。
51
51
  - 从 `0.24.2` 起这是**硬性要求**;更早的 tag 没有该字段是历史事实,门禁对它们走兼容判据(只核"是否属于某个远端分支")。
52
- - 它**不能**证明"这个提交是当时最合适的发布提交"。那条判断属于评审,不属于门禁。
52
+ - 它**不能**证明"这个提交是当时最合适的发布提交"。那条判断属于人,不属于门禁。
53
53
 
54
54
  ---
55
55
 
@@ -154,6 +154,16 @@ pack-smoke.sh # npm pack → 装进空项目 → 解析入口
154
154
 
155
155
  第 3 步之所以不能只看「版本存在」:`npm view` 只能回答「这个版本在不在」,不能回答「它是不是我们发的」。probe 会取 attestation 里的 `gitCommit` 与 tag 指向比对;不一致就判失败,而不是跳过。
156
156
 
157
+ ⚠️ 第 8 步的回执必须**等 registry 索引**。`npm publish` 返回 0 之后,版本端点还要几十秒才可见;
158
+ 回执在发布后立刻跑,会拿到 `npm=absent` 并把一次成功的发布报成「未完成」。
159
+ `release-run.sh verify` 现在对 `absent` 重试(默认 18 次 × 10 秒),
160
+ 对 `unreadable` **不重试**(那是接口/网络问题,等下去也不会变)。
161
+
162
+ 这条不是推演,是 `v0.24.2` 第三次运行的现场:npm 与 Release 都建好了,
163
+ 只有回执红。事后人工复核——`gitHead`、provenance 的 `gitCommit`、
164
+ registry `integrity` 与 attestation `subject` 全部一致——产物是对的,
165
+ 错的是**回执比索引快**。
166
+
157
167
  ### 5.2 站点链(主分支触发)
158
168
 
159
169
  | 态 | 含义 | 探测方式 |
@@ -204,8 +214,73 @@ npm 与 Release 都是 absent ⇒ 删 tag、修夹具、在同一提交树上重
204
214
 
205
215
  ---
206
216
 
207
- ## 7. 本文档的边界
217
+ ## 7. 发布记录
218
+
219
+ 记录的作用不是复盘情绪,是把三类**不同**的事实分开:改造做完了没有 / 产物对不对 / 流程走通了没有。
220
+ 三者可以同时成立两个而第三个不成立——`0.24.2` 就是这种情况。
221
+
222
+ ### 7.1 `0.24.2` 的三层状态
223
+
224
+ | 层次 | 状态 |
225
+ |---|---|
226
+ | 改造实施(十项) | 完成,十项都有落点 |
227
+ | `0.24.2` 产物 | **有效**:registry 有版本、provenance 与 tag 提交一致、包内文档与仓库逐字节相同、站点抽样一致 |
228
+ | 这一次的发布运行 | **未通过**:CI 在最后一步回执上失败,红叉保留 |
229
+
230
+ **这三句话不能互相代替。** 不能因为回执误判就把前面的发布抹掉;也不能因为产物有效就把那次运行改判为成功。
231
+
232
+ ### 7.1.1 关闭登记
233
+
234
+ | 项 | 结论 |
235
+ |---|---|
236
+ | 改造项 | 十项全部落地,无新增注册门禁(结构断言并进既有 `workflow-gate`) |
237
+ | 产物 | `0.24.2` 有效,独立核验通过(见上表第二行) |
238
+ | 发布运行 | **未通过,红叉保留**。回执重试修复(`e837d52`)**不重发**同版本 |
239
+ | 回执重试 | 已修、**未被真实发布走过** ⇒ 转入待验清单,按 §7.3 六条验 |
240
+ | 遗留 | 无"待修但没人管"的项;`0.24.2` 那次运行的红叉是历史事实,不是待办 |
241
+
242
+ ⇒ **这一轮关闭。** 关闭不等于"发布流程全绿",只等于"这一轮要做的十件事做完了、
243
+ 产物可信、剩下的不确定性已经被明确登记"。CI 侧的稳定性由定时运行连续观察
244
+ (`05-audit/nightly-observe.py` 提供判据:连续若干次定时运行全绿才算稳定)。
245
+
246
+ 那一次运行的事实,按来源分列:
247
+
248
+ - 来自**运行记录**:`npm publish` 步骤退出码 0;GitHub Release 已创建;失败步骤 = 回执
249
+ - 来自**事后独立核验**:registry 的 `gitHead`、provenance 的 `gitCommit`、attestation `subject` 与 registry `integrity` 解码后相等、包内 `llms-full.txt` 与仓库同哈希、站点三个文件抽样同哈希
250
+ - 失败原因:回执在 `npm publish` 返回后立刻查询,版本端点尚未索引 ⇒ `npm=absent` ⇒ 判"未完成"。**是回执早了,不是发布失败**
251
+ - 后续修复:回执对 `absent` 重试、对 `unreadable` 不重试。该修复**不在那个 tag 的代码里**,重跑同 tag 不会生效
252
+
253
+ ⇒ **不为了一个绿叉重发同版本**。CI 运行记录是历史事实,不是可以修辞的状态。
254
+
255
+ ### 7.2 三类故障分开登记
256
+
257
+ 同一次失败里混着三种**故障模型**,防护手段完全不同。合成一句"发布失败"会让下一个人修错地方:
258
+
259
+ | 类型 | 表现 | 防护 |
260
+ |---|---|---|
261
+ | 测试环境失真 | 夹具里的临时仓库缺 `.gitignore`,`__pycache__` 让"工作区干净"正确地变红 | 夹具必须复刻真实环境的**全部**约束;要修夹具,不改判据 |
262
+ | 观测条件缺失 | 浏览器判据没起 `:8000` 静态服务,21 个组件全是 `ERR_CONNECTION_REFUSED` | 浏览器判据自带观测条件;失败信息要能区分"没测成"与"结论为假" |
263
+ | 外部系统最终一致性 | `npm publish` 成功,版本端点数十秒后才可见 | 只对 `absent` 重试,对 `unreadable` 不重试;上界用**次数**不用累计秒数 |
264
+
265
+ ### 7.3 下一次真实发布要验的六条(提前固定,不许事后放宽)
266
+
267
+ 回执的重试逻辑还没被真实发布走过。下一次打 tag 时,按这张表逐条判定:
268
+
269
+ | # | 场景 | 通过条件 |
270
+ |---|---|---|
271
+ | 1 | npm 立即可见 | `verify` 一次就输出 `npm=present`,退出码 0 |
272
+ | 2 | npm 延迟可见 | 首次 `absent` 后继续等,最终 `present`,退出码 0 |
273
+ | 3 | npm 始终 `absent` | 重试次数用尽后失败,且输出点名"重试 N 次仍未见版本端点" |
274
+ | 4 | npm `unreadable` | **不进入** `absent` 重试路径,立即报查询错误(接口/网络问题重试也不会变) |
275
+ | 5 | npm 已存在、Release 不存在 | 先核已有包的 provenance `gitCommit` 与 tag 指向一致,再继续建 Release |
276
+ | 6 | npm 已存在、provenance 不匹配 | 停止。**"版本存在"不等于"发布正确"** |
277
+
278
+ 第 5、6 条是同一条原则的两面:幂等不是跳过已完成的步骤,而是确认已完成的步骤与本次预期一致。
279
+
280
+ ---
281
+
282
+ ## 8. 本文档的边界
208
283
 
209
- 本文覆盖:渠道语义、版本不可变、生成链顺序、冻结点范围、发布状态机、恢复步骤。
284
+ 本文覆盖:渠道语义、版本不可变、生成链顺序、冻结点范围、发布状态机、恢复步骤、发布记录。
210
285
 
211
286
  本文**不**覆盖:视觉回归基线、体积预算、组件行为契约等与"发布身份"无关的门禁;也不承诺对发布物做逐文件完整性校验(见 [VERIFY-RELEASE.md](VERIFY-RELEASE.md) 第 4 节)。
package/index.html CHANGED
@@ -97,7 +97,7 @@ li a:active { background: var(--surface-sunken); }
97
97
  </p>
98
98
  </main>
99
99
  <footer class="wrap">
100
- <p class="note">0.24.2 · 零第三方运行时依赖</p>
100
+ <p class="note">0.25.0 · 零第三方运行时依赖</p>
101
101
  </footer>
102
102
  </body>
103
103
  </html>
package/llms-full.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  # agentcss — full reference (one file)
2
2
 
3
- > Generated from `ai/components.json` + `ai/pitfalls*.json` + `ai/behaviors.json` at version **0.24.2**.
3
+ > Generated from `ai/components.json` + `ai/pitfalls*.json` + `ai/behaviors.json` at version **0.25.0**.
4
4
  > Do not edit by hand: run `python 05-audit/gen-llms.py` (freshness is gated).
5
5
  > Short version: `llms.txt`. Machine contract: `ai/*.json`.
6
6
 
@@ -27,7 +27,7 @@ Every subcommand accepts `--json`; failures print `{"ok":false,...}` and exit no
27
27
 
28
28
  | id | class | tier | maturity | css | js | what it is | pitfalls |
29
29
  |---|---|---|---|---|---|---|---|
30
- | `bar` | `bar` | asset | stable | 5.3 KB | `bar.js` | 柱状图:堆叠/分组两种语义、超量程裁剪、图例 | `chart-multiline-label` |
30
+ | `bar` | `bar` | asset | stable | 6.5 KB | `bar.js` | 柱状图:堆叠/分组两种语义、超量程裁剪、图例 | `chart-multiline-label` |
31
31
  | `model-viewer` | `mv` | asset | stable | 4.0 KB | `model-viewer.js` | 3D 模型查看器:令牌驱动样式,不含渲染库本体 | — |
32
32
  | `scientific-plot` | `splot` | asset | stable | 3.9 KB | `scientific-plot.js` | 二维科学绘图:折线/区间带/对数轴,纯令牌驱动、零依赖 | `chart-multiline-label` |
33
33
  | `sparkline` | `sparkline` | asset | stable | 7.2 KB | `sparkline.js` | 迷你趋势图:无坐标轴、纯形状,适合表格内嵌的一行走势 | `chart-multiline-label` |
@@ -35,20 +35,20 @@ Every subcommand accepts `--json`; failures print `{"ok":false,...}` and exit no
35
35
  | `content` | `prose` | pattern | stable | 11.1 KB | — | 长文排版容器(标题/段落/列表/引用/代码) | `single-scroll-container` `line-height-constant-sync` |
36
36
  | `drawer` | `drawer` | pattern | stable | 4.5 KB | `drawer.js` | 侧边抽屉,含遮罩 | `fixed-element-inventory` |
37
37
  | `dropdown` | `dd` | pattern | stable | 3.9 KB | `dropdown.js` | 下拉菜单 | `popover-measure-after-render` |
38
- | `form-validation` | `form` | pattern | stable | 11.0 KB | — | 表单校验反馈与错误汇总 | — |
38
+ | `form-validation` | `form` | pattern | stable | 11.8 KB | — | 表单校验反馈与错误汇总 | — |
39
39
  | `list` | `list` | pattern | stable | 6.1 KB | `flip.js` | 键值列表/条目列表 | `empty-state-no-decoration` `text-injection-xss` |
40
40
  | `nav` | `nav` | pattern | stable | 12.1 KB | `nav.js` | 顶部导航与目录 | — |
41
- | `overlay` | `toast` | pattern | stable | 12.0 KB | `overlay.js` | 吐司提示与模态遮罩 | `fixed-element-inventory` |
41
+ | `overlay` | `toast` | pattern | stable | 12.8 KB | `overlay.js` | 吐司提示与模态遮罩 | `fixed-element-inventory` |
42
42
  | `pagination` | `pagination` | pattern | stable | 7.7 KB | `pagination.js` | 分页控件 | — |
43
43
  | `reveal` | `reveal` | pattern | stable | 4.0 KB | `reveal.js` | 入场动效:一个 data-reveal 属性六个方向,无 JS 时内容全可见 | — |
44
- | `states` | `state` | pattern | stable | 10.1 KB | — | 空/加载/错误/成功四种整块状态 | `empty-state-no-decoration` `text-injection-xss` |
44
+ | `states` | `state` | pattern | stable | 10.9 KB | — | 空/加载/错误/成功四种整块状态 | `empty-state-no-decoration` `text-injection-xss` |
45
45
  | `tabs` | `tabs` | pattern | stable | 5.9 KB | `tabs.js` | 选项卡切换 | — |
46
46
  | `tooltip` | `tooltip` | pattern | stable | 3.5 KB | `tooltip.js` | 悬停/聚焦提示 | `popover-measure-after-render` `fixed-element-inventory` |
47
47
  | `tree` | `tree` | pattern | stable | 4.0 KB | `tree.js` | 可展开树形结构 | — |
48
48
  | `badge` | `badge` | primitive | stable | 6.1 KB | — | 状态标签:计数、分类、结果标记 | — |
49
49
  | `button` | `btn` | primitive | stable | 15.7 KB | — | 动作触发:主/次/危险/纯文字四档 | — |
50
50
  | `card` | `card` | primitive | stable | 10.4 KB | — | 内容容器:媒体+正文+操作区三段 | — |
51
- | `choice` | `choice` | primitive | stable | 16.8 KB | — | 单选/多选/原生 select 外观的统一控件 | — |
51
+ | `choice` | `choice` | primitive | stable | 16.7 KB | — | 单选/多选/原生 select 外观的统一控件 | — |
52
52
  | `combobox` | `combo` | primitive | stable | 7.0 KB | `combobox.js` | 可搜索 + 可多选标签的输入控件 | — |
53
53
  | `date-range` | `drange` | primitive | stable | 6.0 KB | `date-range.js` | 日期区间选择,含预设快捷范围 | — |
54
54
  | `delta` | `delta` | primitive | stable | 5.5 KB | — | 变化量:涨跌方向 + 符号 + 颜色。只描述往哪边变,不判断好坏(等于好恶是 … | — |
@@ -65,7 +65,7 @@ Every subcommand accepts `--json`; failures print `{"ok":false,...}` and exit no
65
65
  | `analysis-report` | `report` | recipe | stable | 8.4 KB | — | 组合型研究报告页面:正文与辅助栏并排,窄屏自然退回单栏 | `empty-layout-min-height` |
66
66
  | `app-shell` | `shell` | recipe | stable | 24.9 KB | `shell-nav.js` | 应用外壳:侧栏 + 顶栏 + 主区三段式;sticky 侧栏自滚、min-wi… | `empty-layout-min-height` `fixture-demo-split-truth` |
67
67
  | `detail-page` | `detail-page` | recipe | stable | 5.7 KB | — | 实体详情页骨架:字段齐全 / 部分缺失 / 无数据三种状态同构,无数据是一等状态 | `empty-layout-min-height` |
68
- | `report` | `rep` | recipe | stable | 15.7 KB | — | 报告版式系统 v1:共享基础 + 三套版式(杂志/科研技术/金融研究),只换一… | — |
68
+ | `report` | `rep` | recipe | stable | 16.1 KB | — | 报告版式系统 v1:共享基础 + 三套版式(杂志/科研技术/金融研究),只换一… | — |
69
69
  | `table` | `table` | recipe | stable | 18.1 KB | — | 数据表格:排序/加载/空/错误四态;三种用途预设(财务/学术/统计) | `single-scroll-container` `empty-state-no-decoration` `table-overflow-wrapper` `text-injection-xss` |
70
70
 
71
71
  ## 3 · Known failure modes (32)
package/llms.txt CHANGED
@@ -21,8 +21,13 @@ npx agentcss ai tokens --json --set=dark
21
21
  npx agentcss ai pitfalls --json --component=table
22
22
  npx agentcss ai validate ai/components.json --schema=components --json
23
23
  npx agentcss ai check page.json --profile=strict --json
24
+ npx agentcss ai pdf page.html --out page.pdf --max-pages=8 # HTML → PDF (zero deps: uses your Chrome)
24
25
  ```
25
26
 
27
+ Print / PDF: `--medium=paper` is the obligation switch — only then are `printPolicy`
28
+ and `pageBudget` enforced. Per-component paper behaviour lives in
29
+ `ai/components.json` → `printPolicy`. `@page` is owned by the exporter, not the library.
30
+
26
31
  Every subcommand accepts `--json`. On failure it prints
27
32
  `{"ok":false,"command":"…","error":{"kind":"…","message":"…"}}` and exits non-zero,
28
33
  so a pipeline can never mistake an error for data.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentcss",
3
- "version": "0.24.2",
3
+ "version": "0.25.0",
4
4
  "description": "移动 Web 组件库:CSS + 可选行为脚本,零第三方运行时依赖。样式用 bundler 引入,交互行为用 script 标签引入。",
5
5
  "keywords": [
6
6
  "css",
@@ -81,6 +81,11 @@
81
81
  "gate": "bash 05-audit/check-all.sh",
82
82
  "gate:fast": "bash 05-audit/check-all.sh --fast",
83
83
  "gate:timing": "bash 05-audit/check-all.sh --timing",
84
+ "ci:observe": "python3 05-audit/nightly-observe.py",
85
+ "ci:print-cost": "node 05-audit/print-pagination-cost.js",
86
+ "ci:print-audit": "node 05-audit/print-content-audit.js --all",
87
+ "ci:merge-exp": "node 05-audit/render-merge-experiment.js",
88
+ "ci:zoom-merge": "node 05-audit/zoom-merge-experiment.js --all",
84
89
  "size:record": "python3 05-audit/size-baseline.py --record",
85
90
  "dist": "python3 05-audit/build-dist.py",
86
91
  "dist:check": "python3 05-audit/build-dist.py --check && node 05-audit/dist-parity-check.js && python3 05-audit/dist-cost-gate.py",