agentcss 0.26.0 → 0.27.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/page.css +11 -0
- package/01-tokens/responsive-demo.html +1 -1
- package/01-tokens/tokens.core.css +1 -1
- package/01-tokens/tokens.css +2 -2
- package/02-primitives/date-range/date-range.js +1 -1
- package/02-primitives/timeline/demo.html +1 -1
- package/03-patterns/drawer/demo.html +1 -1
- package/03-patterns/overlay/overlay.css +1 -1
- package/03-patterns/states/states.css +1 -1
- package/03-patterns/tabs/tabs.css +9 -0
- package/04-recipes/app-shell/README.md +1 -1
- package/04-recipes/app-shell/demo.html +1 -1
- package/04-recipes/longform/content.html +6 -6
- package/04-recipes/report/demo.html +2 -2
- package/04-recipes/table/README.md +1 -1
- package/04-recipes/table/demo.html +1 -1
- package/09-assets/bar/bar.css +1 -1
- package/09-assets/model-viewer/model-viewer.js +1 -1
- package/AGENTS.md +4 -2
- package/CHANGELOG.md +126 -5
- package/CONTRIBUTING.md +44 -3
- package/README.md +7 -4
- package/README.zh-CN.md +18 -12
- package/START-HERE.md +12 -5
- package/ai/START-HERE.md +41 -7
- package/ai/cdp.js +152 -0
- package/ai/check-html.js +658 -0
- package/ai/cli.js +578 -70
- package/ai/components.json +1 -1
- package/ai/pdf-renderer.js +177 -0
- package/ai/pdf.js +125 -80
- package/ai/recipes.json +86 -0
- package/ai/scaffold.js +195 -0
- package/ai/shot.js +237 -0
- package/ai/validate.js +65 -6
- package/dist/01-tokens/page.css +1 -1
- package/dist/03-patterns/tabs/tabs.css +1 -1
- package/dist/COSTS.md +12 -12
- package/docs/ACCESSIBILITY.md +2 -2
- package/docs/ARCHITECTURE.md +116 -0
- package/docs/LAYER-BASELINE.md +2 -2
- package/docs/PRINT.md +41 -13
- package/docs/RELEASE-PROCESS.md +52 -2
- package/docs/STABILITY.md +1 -1
- package/docs/VERIFY-RELEASE.md +17 -0
- package/index.html +3 -3
- package/llms-full.txt +19 -4
- package/llms.txt +29 -6
- package/package.json +2 -1
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# agentcss 是怎么组成的
|
|
2
|
+
|
|
3
|
+
> 写给第一次接触这个项目的人。不需要先懂前端工程,读完能回答三个问题:
|
|
4
|
+
> 这是什么、东西怎么组织、靠什么保证不出乱子。
|
|
5
|
+
|
|
6
|
+
**一句话**:这是一个给手机网页用的**现成零件库**——按钮、表格、抽屉、整页版式都有,
|
|
7
|
+
拿来就能用。它有三个少见的特点:
|
|
8
|
+
|
|
9
|
+
- **不装任何依赖**。把这个库装进项目,你的 `node_modules` 不会多出任何别的东西。
|
|
10
|
+
- **类名就是说明书**。样式全靠类名控制,不要求写初始化脚本、不绑定任何框架。
|
|
11
|
+
- **专门照顾 AI 编码助手**。每个组件都有一份机器可读的"说明书",AI 先读它再写代码,
|
|
12
|
+
写完还能用配套命令自己检查。
|
|
13
|
+
|
|
14
|
+
规模:40 个组件(全部稳定可用)、约 1 MB 的 npm 包、全库样式总量锁死在 172 KB 以内。
|
|
15
|
+
|
|
16
|
+
## 一张图看懂
|
|
17
|
+
|
|
18
|
+
```mermaid
|
|
19
|
+
flowchart TD
|
|
20
|
+
subgraph lib["组件本体 —— 依赖自上而下"]
|
|
21
|
+
direction TB
|
|
22
|
+
R["整页配方 recipes · 5 个<br/>拿来就是一页完整版式"]
|
|
23
|
+
P["组合模式 patterns · 14 个<br/>抽屉、弹层、时间线…"]
|
|
24
|
+
B["基础件 primitives · 17 个<br/>按钮、表格、下拉框…"]
|
|
25
|
+
T["设计令牌 tokens + 行为核 · 6 个<br/>颜色字号间距 + 少量交互脚本"]
|
|
26
|
+
R --> P --> B --> T
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
subgraph use["两种用法"]
|
|
30
|
+
H["给人:复制 demo 改内容"]
|
|
31
|
+
A["给 AI:先读机器说明书,写完自检"]
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
subgraph out["三个出口"]
|
|
35
|
+
NPM["npm 包"]
|
|
36
|
+
WEB["文档站(40 个组件页)"]
|
|
37
|
+
REPO["GitHub 仓库(检查系统全部公开)"]
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
H --> NPM
|
|
41
|
+
A --> NPM
|
|
42
|
+
NPM -.-> WEB
|
|
43
|
+
NPM -.-> REPO
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
读法:想用一个小按钮,拿 `02-primitives` 里的就行;想要一整页报表,直接拿
|
|
47
|
+
`04-recipes`。上面的层会用到下面的层,反过来不会——所以拆哪儿都拆得动。
|
|
48
|
+
|
|
49
|
+
## 四层组件,像盖房子
|
|
50
|
+
|
|
51
|
+
| 层 | 是什么 | 打个比方 | 数量 |
|
|
52
|
+
|---|---|---|---|
|
|
53
|
+
| `01-tokens` | 颜色、字号、间距这些"数值表",浅色/深色两套主题;附 6 个小交互脚本(弹窗关闭、焦点归位这类) | 调色盘和刻度尺 | 1 套 |
|
|
54
|
+
| `02-primitives` | 最小的独立组件:按钮、卡片、表格、下拉框 | 砖和预制板 | 17 |
|
|
55
|
+
| `03-patterns` | 需要多个组件配合的场景:抽屉、弹层、标签页、时间线 | 预制房间 | 14 |
|
|
56
|
+
| `04-recipes` | 一整页的成品版式:报表页、应用外壳、财务页 | 样板房 | 5 |
|
|
57
|
+
|
|
58
|
+
另有 `09-assets`(4 个独立小资产,比如图表底座),不属于这套分层,按需取用。
|
|
59
|
+
|
|
60
|
+
## 目录地图
|
|
61
|
+
|
|
62
|
+
| 目录 | 放什么 |
|
|
63
|
+
|---|---|
|
|
64
|
+
| `01-tokens/` … `04-recipes/`、`09-assets/` | 上面说的组件本体,每个组件自带可打开的 demo 页和说明 |
|
|
65
|
+
| `ai/` | 给 AI 看的机器说明书(4 份 JSON)和一个命令行工具 |
|
|
66
|
+
| `05-audit/` | 自动检查系统(下节讲),全部公开、任何人可以运行 |
|
|
67
|
+
| `docs/` | 设计与工程文档(本文在这里) |
|
|
68
|
+
| `dist/`、`esm/`、`types/` | 构建产物,由源码自动生成,不许手改 |
|
|
69
|
+
|
|
70
|
+
## 修改一处,处处自动跟上
|
|
71
|
+
|
|
72
|
+
这个项目最讲究的一件事:**同一份数据只存一个地方,别的都由它自动生成。**
|
|
73
|
+
|
|
74
|
+
- 40 个组件的清单(类名、状态、无障碍属性)只写在 `ai/components.json` 一处。
|
|
75
|
+
文档站的 46 个页面、给 AI 的摘要文本,全部由这份清单自动生成——
|
|
76
|
+
有一个自动检查专门盯着"生成物和清单是否一致",改了清单忘了重新生成就会红。
|
|
77
|
+
- 关键数字同理:文档里写的组件数、检查数,都有自动检查对着源头核。
|
|
78
|
+
|
|
79
|
+
好处很直接:文档不会和实现"各说各话",因为大部分文档本来就是实现生成的。
|
|
80
|
+
|
|
81
|
+
## 怎么保证不出乱子:一个自动验收系统
|
|
82
|
+
|
|
83
|
+
仓库里有一套自动检查(这个项目里叫"门禁"),共 **251 项**,像三道验收:
|
|
84
|
+
|
|
85
|
+
| 什么时候跑 | 跑多少 | 多快 | 查什么 |
|
|
86
|
+
|---|---|---|---|
|
|
87
|
+
| 每次提交前 | 5 项 | 约 7 秒 | 说明书、页面结构、文案、类型有没有被改坏 |
|
|
88
|
+
| 每次推送时 | 128 项 | 约 3.5 分钟 | 以上全部,外加所有不需要浏览器的检查 |
|
|
89
|
+
| 发布之前 | 251 项 | 约 10 分钟 | 再加真浏览器实测、逐像素视觉比对、安装包体检 |
|
|
90
|
+
|
|
91
|
+
三条规矩让它长期可信:
|
|
92
|
+
|
|
93
|
+
1. **每个检查先证明自己能抓到问题**——故意弄坏一个组件,检查必须变红;
|
|
94
|
+
把检查关掉后问题必须重新出现。做不到这一点的检查不算数。
|
|
95
|
+
2. **"跳过"不等于"通过"**——环境缺浏览器就明确标"本次没查",绝不悄悄变绿。
|
|
96
|
+
3. **没测过就说没测**——真机只在 5 类环境验证过,其余内核明说"未验证",不写"应该没问题"。
|
|
97
|
+
|
|
98
|
+
## 给 AI 编码助手怎么用
|
|
99
|
+
|
|
100
|
+
机器说明书在 `ai/` 目录,四份 JSON 覆盖:每个组件的类名与状态、已知的坑、
|
|
101
|
+
设计数值、交互脚本的行为。配套命令行工具(装完这个包就能用):
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
npx agentcss ai components --json # 列出全部 40 个组件
|
|
105
|
+
npx agentcss ai check page.html --json # 检查你写出来的页面合不合规范
|
|
106
|
+
npx agentcss ai shot page.html --width=390,1440 # 按真实手机宽度截图
|
|
107
|
+
npx agentcss ai scaffold report/finance # 生成一页报表的最小骨架
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
流程就是:**读说明书 → 出骨架 → 填内容 → 自己检查**。最后一步不是可选项——
|
|
111
|
+
"写完了"和"写对了"是两件事。
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
*本文数字的出处:组件数来自 `ai/components.json`;检查项数以 `05-audit/check-all.sh`
|
|
116
|
+
实际注册为准;样式预算见 `docs/BUDGET.md`。均为 2026-11-05 的实测值。*
|
package/docs/LAYER-BASELINE.md
CHANGED
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
不是手抄的,也不是推测的:探针页把结果 **POST 回采集端**,落成 JSON 后原样贴进表格。
|
|
35
35
|
手机访问 `http://<电脑内网地址>:端口` 属于**非安全上下文**,
|
|
36
36
|
`navigator.clipboard` 在那里根本不存在 —— 所以页面提供的是"发送到电脑"(同源 POST)作为主路径,
|
|
37
|
-
|
|
37
|
+
剪贴板只作备用。
|
|
38
38
|
|
|
39
39
|
---
|
|
40
40
|
|
|
@@ -163,7 +163,7 @@ Android 上 Chrome ≠ 系统 WebView ≠ 各家 App 内置 WebView。**入口
|
|
|
163
163
|
|
|
164
164
|
「iOS 16.4 才支持某个特性」这类说法在本文件里没有位置,原因很直接:
|
|
165
165
|
我没有在真机上验证过它,写下来就会被下一个人当成事实引用
|
|
166
|
-
|
|
166
|
+
(一类同源事故:文档里的结论没人回来复核,最后整份文档都在骗人)。
|
|
167
167
|
|
|
168
168
|
⇒ 需要版本结论时,**跑一次探针页**,用那一次的 UA 与结果说话。
|
|
169
169
|
UA 是证据,版本传闻不是。
|
package/docs/PRINT.md
CHANGED
|
@@ -258,9 +258,9 @@ node 05-audit/print-gate.js --pdf 某文件.pdf
|
|
|
258
258
|
| `print-content-audit.js` | 该印的在不在?(屏幕可见 → 纸上消失?) | 它只在浏览器里量,不读 PDF |
|
|
259
259
|
| `agentcss pdf` + `pdf-export-gate.js` | **导出成文件**这条路能用吗?(§八) | 它不做视觉比对 |
|
|
260
260
|
|
|
261
|
-
前四个判的是"浏览器里按 Ctrl+P",最后一个判的是"导出一份文件"
|
|
262
|
-
|
|
263
|
-
|
|
261
|
+
前四个判的是"浏览器里按 Ctrl+P",最后一个判的是"导出一份文件"。两者都走 CDP,
|
|
262
|
+
但 `@page` 来源、就绪条件、底色参数与输出保护不同;打印策略全绿推不出导出链没有
|
|
263
|
+
旧文件假成功或异步漏内容,所以两边各有各的判据。
|
|
264
264
|
|
|
265
265
|
`printPolicy` 是**有限枚举**,每个值对应一组能在浏览器里量的断言:
|
|
266
266
|
|
|
@@ -291,8 +291,8 @@ L3 声明→生效 在真浏览器的 print 媒体下量标本页的计算值
|
|
|
291
291
|
```
|
|
292
292
|
|
|
293
293
|
反向控制 7 条(覆盖四条腿),其中两条是历史事故的**逐字复刻**:
|
|
294
|
-
|
|
295
|
-
|
|
294
|
+
去掉 `.tabs ` 前缀,让组件 CSS 同特异性盖掉它;以及
|
|
295
|
+
只删 `visibility: visible`,display 与高度全对、一个字不印。
|
|
296
296
|
|
|
297
297
|
### 内容完整性是**硬判据**(2026-11-02 起)
|
|
298
298
|
|
|
@@ -352,20 +352,36 @@ node 05-audit/print-policy-gate.js --selftest # 反向控制
|
|
|
352
352
|
npx agentcss pdf report.html --out report.pdf # 默认 A4 / 18mm 15mm
|
|
353
353
|
npx agentcss pdf report.html --out report.pdf --paper=letter --margin="20mm"
|
|
354
354
|
npx agentcss pdf report.html --out report.pdf --max-pages=8
|
|
355
|
+
npx agentcss pdf report.html --out report.pdf --ready-selector="#report-ready" --wait-ms=0
|
|
355
356
|
```
|
|
356
357
|
|
|
357
358
|
`--paper` 支持 `a4` / `letter` / `a5` / `a3` / `legal`。边距是 CSS 简写
|
|
358
359
|
(`18mm`、`"18mm 15mm"`、四段都认)。这两个参数靠**注入一条 `@page` 规则**实现,
|
|
359
|
-
注入位置在使用者样式之后 ——
|
|
360
|
+
注入位置在使用者样式之后 —— 否则同特异性会被盖掉(同一个病)。
|
|
360
361
|
|
|
361
|
-
零运行时依赖:用使用者机器上**已装好的** Chrome / Chromium / Edge
|
|
362
|
-
|
|
362
|
+
零运行时依赖:用使用者机器上**已装好的** Chrome / Chromium / Edge,经共享 CDP
|
|
363
|
+
管道调用 `Page.printToPDF`,不打包 Puppeteer。找不到浏览器明确报错(退出码 3):
|
|
363
364
|
|
|
364
365
|
```bash
|
|
365
366
|
npx agentcss pdf report.html --out report.pdf --chrome="C:/Program Files/Google/Chrome/Application/chrome.exe"
|
|
366
367
|
# 或环境变量 AGENTCSS_CHROME / CHROME_PATH
|
|
367
368
|
```
|
|
368
369
|
|
|
370
|
+
#### 就绪、失败与旧文件保护
|
|
371
|
+
|
|
372
|
+
导出顺序是:页面 `load` → `document.fonts.ready` → 可选可见元素 → 额外等待 →
|
|
373
|
+
固定动画终态 → PDF。`--wait-ms` 默认 `800`,可设 `0`,上限 `60000`;它只是额外缓冲,
|
|
374
|
+
**不是任意异步数据已经完成的证明**。动态报告应在数据与图表都渲染完后显示一个元素,
|
|
375
|
+
再传 `--ready-selector="#report-ready"`;只存在但 `display:none`、不可见或没有尺寸不算就绪。
|
|
376
|
+
|
|
377
|
+
整个导出默认有 60 秒总预算,超时退出码为 `4`。非法 CSS 选择器、空值与非法等待
|
|
378
|
+
都是用法错误(退出码 `2`)。未捕获的页面 JS 异常会放进 JSON 的 `jsErrors` 供复核,
|
|
379
|
+
普通 `console.error` 不会擅自让导出失败。
|
|
380
|
+
|
|
381
|
+
浏览器只写暂存 PDF;确认本次成功后才原子替换输出文件。浏览器崩溃、就绪超时、
|
|
382
|
+
非法选择器或产物校验失败时,**已有 PDF 保持不变,结论明确为失败**。超页数预算不同:
|
|
383
|
+
完整的新 PDF 会保留,退出码 `5`,由作者决定如何拆改,绝不静默截断。
|
|
384
|
+
|
|
369
385
|
### 8.2 页数预算:超了报错,不替你截断
|
|
370
386
|
|
|
371
387
|
```bash
|
|
@@ -422,8 +438,8 @@ npx agentcss ai check doc.json --medium=paper
|
|
|
422
438
|
### 8.5 这条路谁守着
|
|
423
439
|
|
|
424
440
|
```bash
|
|
425
|
-
node 05-audit/pdf-export-gate.js # E1–
|
|
426
|
-
node 05-audit/pdf-export-gate.js --selftest #
|
|
441
|
+
node 05-audit/pdf-export-gate.js # E1–E20,不需要静态服务,约 40s
|
|
442
|
+
node 05-audit/pdf-export-gate.js --selftest # 旧文件保护 / 超时 / 崩溃结论 / 非法参数
|
|
427
443
|
```
|
|
428
444
|
|
|
429
445
|
| 判据 | 它问什么 | 实测抓到过什么 |
|
|
@@ -436,15 +452,27 @@ node 05-audit/pdf-export-gate.js --selftest # 只跑"必须红"的几条,约 0
|
|
|
436
452
|
| E7 | `--margin` 真的影响页数吗 | 不注入 `@page` 时 60mm 与 10mm 页数相同 |
|
|
437
453
|
| E8/E9″ | 没有浏览器时说人话吗;报错回显原始输入吗 | 退出码不对 / `abc` 被报成 `null` |
|
|
438
454
|
| E11 | 产物本身合格吗(字体链 / 每页有文本) | 交给 `print-gate --pdf` 的分析器判,不重复实现解析 |
|
|
455
|
+
| E13 | 页树 `/Count` 与 `/Type /Page` 数一致吗 | 分段页树按"第一个"取 ⇒ 50 页读成 8 页 |
|
|
456
|
+
| E14 | ready-selector 等到的是内容,不只是耗时吗 | 延迟新增行的文字 runs 必须增加(48 → 143) |
|
|
457
|
+
| E15 | 真实金融长文每页都有内容吗 | 透明面板与全空白尾页;现为 7 页、每页有文字 |
|
|
458
|
+
| E16 | 浏览器失败会冒用旧 PDF 吗 | 旧文件 SHA-256 必须不变,结论必须失败 |
|
|
459
|
+
| E17 | 就绪条件永不出现会无限等吗 | 有界 timeout,且不碰旧文件 |
|
|
460
|
+
| E18 | 新参数写错会静默按默认值导出吗 | 非法 wait / 空值 / 非法 CSS 都是退出码 2 |
|
|
461
|
+
| E19 | 浏览器起不来时给的是结论还是堆栈 | 去掉管道 error 监听 ⇒ 进程以 EPIPE 崩溃 |
|
|
462
|
+
| E20 | 强杀留下的临时 HTML 会一直堆着吗 | 下次导出清掉 6 小时前的残留,刚生成的不碰 |
|
|
439
463
|
|
|
440
464
|
🔴 E3 与 E7 是同一件事的两面:`@page` 注入是这套东西唯一的技术前提。
|
|
441
465
|
把它改坏,门禁必须红 —— 实测过:注释掉注入那行,E3 报
|
|
442
466
|
`a4=612×792pt`(回落成 Letter),E7 报 `10mm=2 页 / 60mm=2 页`。
|
|
443
467
|
|
|
468
|
+
E14–E20 则保证“导出链说成功”与“这份产物真是本次、完整、可用”不会脱节。
|
|
469
|
+
|
|
444
470
|
### 8.6 不覆盖什么
|
|
445
471
|
|
|
446
472
|
- **远程 URL 不注入 `@page`**:拿不到远程页面的字节,硬注入等于假装改了它。
|
|
447
473
|
这类导出会明确打印"(远程页面:未注入 @page)",纸幅由页面自己的 CSS 决定。
|
|
448
|
-
-
|
|
449
|
-
|
|
450
|
-
|
|
474
|
+
- **跨机器像素基线**:库内不把字体光栅化差异当成回归;正式交付仍需对实际 PDF
|
|
475
|
+
逐页栅格化,检查空白、裁切、边框与图表,并做一次实体打印打样。
|
|
476
|
+
- **页眉页脚 / 页码**:导出器显式 `displayHeaderFooter:false`,本工具不生成自己的。
|
|
477
|
+
需要页码时用浏览器打印对话框的页眉页脚选项,或在自有 CDP/Puppeteer 层提供
|
|
478
|
+
`headerTemplate` / `footerTemplate`;不要假设 `@page + counter(page)` 在 Chrome 可用。
|
package/docs/RELEASE-PROCESS.md
CHANGED
|
@@ -132,7 +132,7 @@ pack-smoke.sh # npm pack → 装进空项目 → 解析入口
|
|
|
132
132
|
|
|
133
133
|
工作流按这个顺序落地:
|
|
134
134
|
|
|
135
|
-
1. 校验 tag 名 == `package.json.version
|
|
135
|
+
1. 校验 tag 名 == `package.json.version`,并确认 npm 足够新(OIDC 需 ≥ 11.5.1);
|
|
136
136
|
2. `npm ci`;
|
|
137
137
|
3. **probe**(只读):输出 `npm=… release=… provenance=…`;
|
|
138
138
|
4. `publish:check`;
|
|
@@ -156,7 +156,7 @@ pack-smoke.sh # npm pack → 装进空项目 → 解析入口
|
|
|
156
156
|
|
|
157
157
|
⚠️ 第 8 步的回执必须**等 registry 索引**。`npm publish` 返回 0 之后,版本端点还要几十秒才可见;
|
|
158
158
|
回执在发布后立刻跑,会拿到 `npm=absent` 并把一次成功的发布报成「未完成」。
|
|
159
|
-
`release-run.sh verify` 现在对 `absent` 重试(默认
|
|
159
|
+
`release-run.sh verify` 现在对 `absent` 重试(默认 42 次 × 10 秒 = 420 秒),
|
|
160
160
|
对 `unreadable` **不重试**(那是接口/网络问题,等下去也不会变)。
|
|
161
161
|
|
|
162
162
|
这条不是推演,是 `v0.24.2` 第三次运行的现场:npm 与 Release 都建好了,
|
|
@@ -164,6 +164,56 @@ pack-smoke.sh # npm pack → 装进空项目 → 解析入口
|
|
|
164
164
|
registry `integrity` 与 attestation `subject` 全部一致——产物是对的,
|
|
165
165
|
错的是**回执比索引快**。
|
|
166
166
|
|
|
167
|
+
⚠️ 预算必须**明显大于**实测最大值,不能贴着它设。`v0.26.0`(2026-11-05)是第二次:
|
|
168
|
+
`npm publish` 在 `08:15:34` 返回成功,registry 到 `08:18:40` 才索引到——**186 秒**,
|
|
169
|
+
而当时的上界是 `17 × 10 = 170` 秒,回执在 `08:18:38` 放弃,比真相早 2 秒。
|
|
170
|
+
后果:包已经发出去了,回执却写 `npm=absent`,要再跑一遍 14 分钟的门禁才能拿到绿。
|
|
171
|
+
⇒ 现在的 420 秒是实测量级的 6 倍:慢只是多等,错判是回执说谎。
|
|
172
|
+
|
|
173
|
+
### 5.1.1 事后改包(dist-tag 等):走 trusted publishing,不要走令牌
|
|
174
|
+
|
|
175
|
+
发布完成后要改**包管理类**的状态(例如删一个 dist-tag),**不要**想着用发布令牌去做:
|
|
176
|
+
|
|
177
|
+
- 勾了「绕过两步验证」的细粒度令牌(GAT)自 2026-07 起只能发布写,做包管理删除会被
|
|
178
|
+
`403 Granular access tokens that bypass two-factor authentication may not perform this action` 挡住;
|
|
179
|
+
- npm 网页里**没有** dist-tag 管理入口(`/package/<pkg>/dist-tags` 是 404,
|
|
180
|
+
Versions 的 Current Tags 只有只读表格);
|
|
181
|
+
- 剩下唯一合法的口子是 **trusted publishing**:它的 Allowed actions 里明确有 `npm dist-tag`。
|
|
182
|
+
|
|
183
|
+
本仓的落地方式(一次性运维,不影响发版):
|
|
184
|
+
|
|
185
|
+
1. npm 包设置 → Trusted Publisher → GitHub Actions,
|
|
186
|
+
仓库标识(`owner/repo`,见 `package.json` 的 `repository`)与 `release.yml`,
|
|
187
|
+
勾 `npm publish` 与 `npm dist-tag`;
|
|
188
|
+
2. `release.yml` 里的 `dist-tag-cleanup` job:只在 `workflow_dispatch` 且填了
|
|
189
|
+
`dist_tag_rm` 时跑;`id-token: write` 换 OIDC 凭证;先 `npm i -g npm@latest`
|
|
190
|
+
(OIDC 需 ≥ 11.5.1);**不要**给 `setup-node` 传 `registry-url`
|
|
191
|
+
(它会写一条空的 `_authToken` 行,值指向 `NODE_AUTH_TOKEN`,先撞 ENEEDAUTH,轮不到 OIDC);
|
|
192
|
+
3. 触发:
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
gh workflow run release.yml -f dist_tag_rm=<tag 名>
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
2026-11-05 实测:run 41997717147 success,`probe-2fa` 删除后只剩 `latest`。
|
|
199
|
+
这条作业**不会**被 tag 推送触发(条件是 `github.event_name == 'workflow_dispatch'` 且输入非空)。
|
|
200
|
+
|
|
201
|
+
### 5.1.2 发版本身的凭据:OIDC,没有任何长期令牌
|
|
202
|
+
|
|
203
|
+
发版与上面的包管理动作共用同一套信任关系:npm 侧把 `release.yml` 登记为
|
|
204
|
+
trusted publisher(`Status: Valid`),工作流用 `id-token: write` 现换一次短期凭证。
|
|
205
|
+
**仓库里不再有任何 npm 令牌 secret**,也没有 7 天/90 天到期的东西会悄悄断掉发布。
|
|
206
|
+
|
|
207
|
+
两条硬约束(都实测踩过,`release-gate.py` 的 `workflow_problems` 逐条守着):
|
|
208
|
+
|
|
209
|
+
1. `setup-node` **不传** `registry-url` —— 它会写一行空的 `_authToken`(值指向
|
|
210
|
+
`NODE_AUTH_TOKEN`),npm 先撞 `ENEEDAUTH`,根本轮不到 OIDC;
|
|
211
|
+
2. 必须 `npm install -g npm@latest` —— Node 22 自带 npm 10.x,OIDC 需要 ≥ 11.5.1。
|
|
212
|
+
|
|
213
|
+
`workflow_problems` 同时**反向**断言:谁把 `NPM_TOKEN` / `NODE_AUTH_TOKEN` /
|
|
214
|
+
`registry-url` 加回来,门禁立刻红。这不是风格检查——长期令牌模型在 2027-01
|
|
215
|
+
会连直接发布权一起失效,留着它只是把断点推迟到下一次发版。
|
|
216
|
+
|
|
167
217
|
### 5.2 站点链(主分支触发)
|
|
168
218
|
|
|
169
219
|
| 态 | 含义 | 探测方式 |
|
package/docs/STABILITY.md
CHANGED
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
| JS 成员不消失 | `Select.open()`、`AccordionOptions.duration` 这类名字 | `deprecation-gate.py` ⑦ + `api-contract-gate.py`(d.ts ↔ 运行时**实测**比对) |
|
|
31
31
|
| 声明的名字真的存在 | 不许出现"文档里有、代码里没有"的幻觉 API | `gen-ai-contract.py --check`、`dead-class-gate.py` |
|
|
32
32
|
| 行为事件名不消失 | `fl:select` 这类事件名 | 只记在基线里,**没有运行时探针**(见 §6) |
|
|
33
|
-
| CLI 子命令与 `--json` 形状 | `agentcss ai <cmd> --json` 的
|
|
33
|
+
| CLI 子命令与 `--json` 形状 | `agentcss ai <cmd> --json` 的 14 个子命令、失败也是 JSON | `ai-layer-gate.js` ⑥′⑥″、`facts-gate.py`(计数从 `ai/cli.js` 现算) |
|
|
34
34
|
| 契约文件字段 | `ai/components.json` / `pitfalls*.json` / `behaviors.json` | `gen-ai-contract --check`、`ai-layer-gate` ⑦ |
|
|
35
35
|
| 文件路径 | `02-primitives/button/button.css` 这类 `<link>` 直接指向的路径 | `dist-parity-check`、`pack-smoke.sh`、`assets-catalog-gate.py` |
|
|
36
36
|
| 体积承诺 | 全库生效 CSS ≤ 172 KB,常规增长不涨价 | `perf-gate.py` + `budget-selftest.py`(见 [BUDGET.md](BUDGET.md)) |
|
package/docs/VERIFY-RELEASE.md
CHANGED
|
@@ -170,3 +170,20 @@ a3d36f35ee748632ba05705e669ce950260dd81a3d32b5f3f46fadae0bd084ef # npm 包内
|
|
|
170
170
|
## 6. 更早的版本
|
|
171
171
|
|
|
172
172
|
provenance 不是从第一个版本就有的。实测 `0.10.0` 的 attestation 接口返回 404 —— 这类版本只能核对 `gitHead`(L0),不要把它当作签名证据。
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## 7. 已知偏差:2026-11-05 的历史重写
|
|
177
|
+
|
|
178
|
+
| 项 | 内容 |
|
|
179
|
+
|---|---|
|
|
180
|
+
| 发生了什么 | 仓库提交历史被重写一次,用于移除早期版本里误留的真实项目代号与本机用户名 |
|
|
181
|
+
| 受影响范围 | **`0.26.0` 及更早**的 provenance 里记录的 `gitCommit` |
|
|
182
|
+
| 具体表现 | 那个 SHA 在重写后的仓库里**不再是任何分支的祖先**;`git cat-file -p <sha>` 会报 `Not a valid object` |
|
|
183
|
+
| 仍然成立的部分 | npm 上的 attestation 本身**没有被改动**(sigstore 签名是不可变的)。它仍然能证明:这个 tarball 由本仓库的 `release.yml` 在某个提交上构建 |
|
|
184
|
+
| 从什么时候恢复正常 | `0.27.0` 起,provenance 的 `gitCommit` 与仓库历史一致 |
|
|
185
|
+
| GitHub 侧 | 旧提交会以**不可达对象**状态保留一段时间,知道 SHA 仍能按地址访问;之后由平台 GC。仓库已无任何 ref 指向它们 |
|
|
186
|
+
|
|
187
|
+
核验旧版本时正确的读法:**签名证明"构建来源与工作流",不证明"那个提交现在还在仓库里"**。
|
|
188
|
+
这两件事在重写前是重合的,重写后必须分开看 —— 本文件不打算把这一点藏起来。
|
|
189
|
+
|
package/index.html
CHANGED
|
@@ -39,7 +39,7 @@ li a:active { background: var(--surface-sunken); }
|
|
|
39
39
|
<li><a href="02-primitives/choice/demo.html">checkbox / radio / select</a><span class="r__p">单选/多选/原生 select 外观的统一控件</span></li>
|
|
40
40
|
<li><a href="02-primitives/combobox/demo.html">combobox · 组合框 / 标签输入</a><span class="r__p">可搜索 + 可多选标签的输入控件</span></li>
|
|
41
41
|
<li><a href="02-primitives/date-range/demo.html">date-range · 日期区间</a><span class="r__p">日期区间选择,含预设快捷范围</span></li>
|
|
42
|
-
<li><a href="02-primitives/delta/demo.html">delta · 变化量</a><span class="r__p">变化量:涨跌方向 + 符号 +
|
|
42
|
+
<li><a href="02-primitives/delta/demo.html">delta · 变化量</a><span class="r__p">变化量:涨跌方向 + 符号 + 颜色。</span></li>
|
|
43
43
|
<li><a href="02-primitives/input/demo.html">input / field</a><span class="r__p">文本输入及其标签/帮助/错误三件套</span></li>
|
|
44
44
|
<li><a href="02-primitives/metric/demo.html">metric · 指标块</a><span class="r__p">指标块:一个标签 + 一个值 + 一句上下文。数字等宽、单位分离、缺数是一等状态</span></li>
|
|
45
45
|
<li><a href="02-primitives/popover/demo.html">popover · 气泡卡片</a><span class="r__p">锚定到触发元素的浮层</span></li>
|
|
@@ -48,7 +48,7 @@ li a:active { background: var(--surface-sunken); }
|
|
|
48
48
|
<li><a href="02-primitives/separator/demo.html">separator · 分隔线</a><span class="r__p">分隔线,可带中间文字</span></li>
|
|
49
49
|
<li><a href="02-primitives/skeleton/demo.html">skeleton · 骨架屏</a><span class="r__p">加载占位骨架</span></li>
|
|
50
50
|
<li><a href="02-primitives/switch/demo.html">switch · 开关</a><span class="r__p">开关切换</span></li>
|
|
51
|
-
<li><a href="02-primitives/timeline/demo.html">timeline · 时间轴</a><span class="r__p">时间轴:按时间排的事件序列(公告 / 大事记 /
|
|
51
|
+
<li><a href="02-primitives/timeline/demo.html">timeline · 时间轴</a><span class="r__p">时间轴:按时间排的事件序列(公告 / 大事记 / 版本记录)。</span></li>
|
|
52
52
|
<li><a href="02-primitives/upload/demo.html">upload · 文件上传</a><span class="r__p">文件上传:零 JS 的原生形态 + 拖放/多文件/校验的增强形态</span></li>
|
|
53
53
|
</ul>
|
|
54
54
|
|
|
@@ -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.
|
|
100
|
+
<p class="note">0.27.1 · 零第三方运行时依赖</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.
|
|
3
|
+
> Generated from `ai/components.json` + `ai/pitfalls*.json` + `ai/behaviors.json` at version **0.27.1**.
|
|
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
|
|
|
@@ -16,10 +16,25 @@ npx agentcss ai pitfalls --json --component=table
|
|
|
16
16
|
npx agentcss ai tokens --json --set=dark
|
|
17
17
|
npx agentcss ai tree --json --set=dark --cat=color
|
|
18
18
|
npx agentcss ai validate <file> --schema=components --json
|
|
19
|
-
npx agentcss ai check <doc.json> --profile=strict --json
|
|
19
|
+
npx agentcss ai check <doc.json> --profile=strict --json # the plan
|
|
20
|
+
npx agentcss ai check <page.html> --json # the artifact
|
|
21
|
+
npx agentcss ai scaffold report/finance --out report.html # skeleton only
|
|
22
|
+
npx agentcss ai shot <page.html> --out shot-{width}.png --width=390,1440 --full
|
|
23
|
+
npx agentcss ai pdf <page.html> --out page.pdf --wait-ms=800 # zero deps: your Chrome
|
|
24
|
+
[--ready-selector="#report-ready"] # wait for async content
|
|
20
25
|
```
|
|
21
26
|
|
|
22
|
-
Every subcommand accepts `--json
|
|
27
|
+
Every subcommand accepts `--json`. On failure it prints *one* JSON document —
|
|
28
|
+
`{"ok":false,"command":"…","error":{"kind":"…","message":"…"}}` — so a pipeline can
|
|
29
|
+
never mistake an error for data. Exit codes are one table for the whole CLI:
|
|
30
|
+
`0` pass · `1` the thing you checked is bad (a verdict, not a tool failure) ·
|
|
31
|
+
`2` bad flag or value (unknown flag, unknown enum value, empty value, repeated flag) ·
|
|
32
|
+
`3` environment missing · `4` render failed · `5` over budget · `6` tool bug.
|
|
33
|
+
`check <page.html>` is static (no network, no browser) and reports undefined class names,
|
|
34
|
+
stylesheets that were never linked, missing `img alt` / table name / `th scope`, skipped
|
|
35
|
+
heading levels and the per-layout obligations in `ai/recipes.json`. `shot` drives your
|
|
36
|
+
installed Chrome over a debugging pipe: the viewport is exactly the width you asked for,
|
|
37
|
+
and it reports horizontal overflow plus JS errors.
|
|
23
38
|
|
|
24
39
|
## 2 · Components (40)
|
|
25
40
|
|
|
@@ -42,7 +57,7 @@ Every subcommand accepts `--json`; failures print `{"ok":false,...}` and exit no
|
|
|
42
57
|
| `pagination` | `pagination` | pattern | stable | 7.7 KB | `pagination.js` | 分页控件 | — |
|
|
43
58
|
| `reveal` | `reveal` | pattern | stable | 4.0 KB | `reveal.js` | 入场动效:一个 data-reveal 属性六个方向,无 JS 时内容全可见 | — |
|
|
44
59
|
| `states` | `state` | pattern | stable | 10.9 KB | — | 空/加载/错误/成功四种整块状态 | `empty-state-no-decoration` `text-injection-xss` |
|
|
45
|
-
| `tabs` | `tabs` | pattern | stable |
|
|
60
|
+
| `tabs` | `tabs` | pattern | stable | 6.1 KB | `tabs.js` | 选项卡切换 | — |
|
|
46
61
|
| `tooltip` | `tooltip` | pattern | stable | 3.5 KB | `tooltip.js` | 悬停/聚焦提示 | `popover-measure-after-render` `fixed-element-inventory` |
|
|
47
62
|
| `tree` | `tree` | pattern | stable | 4.0 KB | `tree.js` | 可展开树形结构 | — |
|
|
48
63
|
| `badge` | `badge` | primitive | stable | 6.1 KB | — | 状态标签:计数、分类、结果标记 | — |
|
package/llms.txt
CHANGED
|
@@ -21,22 +21,45 @@ 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
|
|
24
|
+
npx agentcss ai check page.html --json # check the page you actually wrote
|
|
25
|
+
npx agentcss ai scaffold report/finance --out report.html # minimal shell (skeleton, no content)
|
|
26
|
+
npx agentcss ai shot page.html --out shot-{width}.png --width=390,1440 --full
|
|
27
|
+
# PNG at exact viewport widths
|
|
28
|
+
npx agentcss ai pdf page.html --out page.pdf --max-pages=8 --ready-selector="#report-ready"
|
|
29
|
+
# waits for load + fonts + visible async content;
|
|
30
|
+
# zero deps; failed renders preserve an old PDF
|
|
25
31
|
```
|
|
26
32
|
|
|
33
|
+
`check <doc.json>` and `check <page.html>` answer **different** questions: the JSON one
|
|
34
|
+
validates the *plan* (node kinds, component maturity, paper obligations), the HTML one
|
|
35
|
+
validates the *artifact* — class names that the library does not define, stylesheets that
|
|
36
|
+
were never linked, missing `img alt` / table name / `th scope`, skipped heading levels,
|
|
37
|
+
and the per-layout obligations in `ai/recipes.json`. Both are static: no network, no browser.
|
|
38
|
+
|
|
39
|
+
`shot` drives your installed Chrome over a debugging pipe (no port, no bundled browser) so
|
|
40
|
+
the viewport is **exactly** the width you asked for, and reports horizontal overflow plus
|
|
41
|
+
JS errors. Same machine + same flags ⇒ byte-identical PNG (that is what the gate checks).
|
|
42
|
+
|
|
27
43
|
Print / PDF: `--medium=paper` is the obligation switch — only then are `printPolicy`
|
|
28
44
|
and `pageBudget` enforced. Per-component paper behaviour lives in
|
|
29
45
|
`ai/components.json` → `printPolicy`. `@page` is owned by the exporter, not the library.
|
|
30
46
|
|
|
31
|
-
Every subcommand accepts `--json`. On failure it prints
|
|
32
|
-
`{"ok":false,"command":"…","error":{"kind":"…","message":"…"}}` and exits non-zero,
|
|
33
|
-
so a pipeline can never mistake an error for data.
|
|
47
|
+
Every subcommand accepts `--json`. On failure it prints *one* JSON document —
|
|
48
|
+
`{"ok":false,"command":"…","error":{"kind":"…","message":"…"}}` — and exits non-zero,
|
|
49
|
+
so a pipeline can never mistake an error for data. There is exactly one failure shape;
|
|
50
|
+
the `kind` values map to exit codes: `1` verdict-negative (`findings`), `2` bad usage,
|
|
51
|
+
`3` environment missing, `4` render failed, `5` over budget, `6` tool bug.
|
|
52
|
+
|
|
53
|
+
Enum flags (`--set`, `--cat`, `--maturity`, `--profile`, `--medium`, `--recipe`) reject
|
|
54
|
+
an unknown value, an empty value, and a repeated occurrence with exit `2`. Flags a
|
|
55
|
+
subcommand does not understand are rejected too — they are never silently ignored.
|
|
34
56
|
|
|
35
57
|
`pitfalls` needs `agentcss@0.21.0+`: `npx` resolves the *published* version, which can lag
|
|
36
58
|
this repository. If a subcommand is missing, check `npx agentcss --version` first.
|
|
37
59
|
|
|
38
|
-
There is **no MCP server**: the CLI is the whole interface (
|
|
39
|
-
no second copy of the contract to keep in sync).
|
|
60
|
+
There is **no MCP server**: the CLI is the whole interface (no daemon, no network,
|
|
61
|
+
no second copy of the contract to keep in sync). `scaffold` and `shot` write only the file
|
|
62
|
+
you name; every other subcommand is a read-only query. See `ai/START-HERE.md` §7.
|
|
40
63
|
|
|
41
64
|
## Use it in a page
|
|
42
65
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentcss",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.1",
|
|
4
4
|
"description": "移动 Web 组件库:CSS + 可选行为脚本,零第三方运行时依赖。样式用 bundler 引入,交互行为用 script 标签引入。",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"css",
|
|
@@ -94,6 +94,7 @@
|
|
|
94
94
|
"scripts": {
|
|
95
95
|
"test": "node --test 05-audit/unit.test.mjs 05-audit/behavior-cores.test.mjs",
|
|
96
96
|
"gate": "bash 05-audit/check-all.sh",
|
|
97
|
+
"gate:pre-commit": "bash 05-audit/check-all.sh --pre-commit",
|
|
97
98
|
"gate:fast": "bash 05-audit/check-all.sh --fast",
|
|
98
99
|
"gate:timing": "bash 05-audit/check-all.sh --timing",
|
|
99
100
|
"ci:observe": "python3 05-audit/nightly-observe.py",
|