agentcss 0.25.6 → 0.27.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 (81) hide show
  1. package/01-tokens/README.md +1 -1
  2. package/01-tokens/behavior/labels.js +44 -0
  3. package/01-tokens/responsive-demo.html +1 -1
  4. package/01-tokens/tokens.core.css +1 -1
  5. package/01-tokens/tokens.css +2 -2
  6. package/02-primitives/combobox/combobox.js +26 -3
  7. package/02-primitives/date-range/date-range.js +28 -6
  8. package/02-primitives/popover/popover.js +22 -2
  9. package/02-primitives/select/select.js +23 -2
  10. package/02-primitives/timeline/demo.html +1 -1
  11. package/02-primitives/upload/upload.js +50 -17
  12. package/03-patterns/content/content.css +13 -1
  13. package/03-patterns/content/demo.html +1 -1
  14. package/03-patterns/drawer/demo.html +1 -1
  15. package/03-patterns/drawer/drawer.js +44 -6
  16. package/03-patterns/dropdown/dropdown.js +21 -1
  17. package/03-patterns/overlay/overlay.css +1 -1
  18. package/03-patterns/overlay/overlay.js +39 -2
  19. package/03-patterns/pagination/pagination.js +37 -10
  20. package/03-patterns/states/states.css +1 -1
  21. package/03-patterns/tooltip/tooltip.js +17 -2
  22. package/03-patterns/tree/tree.js +21 -1
  23. package/04-recipes/analysis-report/demo.html +1 -1
  24. package/04-recipes/app-shell/README.md +1 -1
  25. package/04-recipes/app-shell/demo.html +1 -1
  26. package/04-recipes/data-showcase/demo.html +2 -2
  27. package/04-recipes/longform/content.html +993 -78
  28. package/04-recipes/longform/longform.html +3 -3
  29. package/04-recipes/report/demo.html +3 -3
  30. package/04-recipes/table/README.md +23 -1
  31. package/04-recipes/table/demo.html +7 -7
  32. package/09-assets/bar/bar.css +1 -1
  33. package/09-assets/bar/bar.js +28 -4
  34. package/09-assets/model-viewer/model-viewer.js +45 -13
  35. package/09-assets/scientific-plot/demo.html +6 -6
  36. package/AGENTS.md +3 -1
  37. package/API.md +32 -0
  38. package/CHANGELOG.md +174 -5
  39. package/CONTRIBUTING.md +44 -3
  40. package/README.md +19 -0
  41. package/README.zh-CN.md +18 -0
  42. package/SECURITY.md +16 -4
  43. package/START-HERE.md +25 -18
  44. package/ai/START-HERE.md +40 -6
  45. package/ai/check-html.js +658 -0
  46. package/ai/cli.js +557 -67
  47. package/ai/components.json +9 -4
  48. package/ai/pdf.js +52 -10
  49. package/ai/recipes.json +86 -0
  50. package/ai/scaffold.js +195 -0
  51. package/ai/shot.js +345 -0
  52. package/ai/validate.js +65 -6
  53. package/dist/01-tokens/behavior/labels.js +11 -0
  54. package/dist/02-primitives/combobox/combobox.js +25 -3
  55. package/dist/02-primitives/date-range/date-range.js +26 -5
  56. package/dist/02-primitives/popover/popover.js +14 -1
  57. package/dist/02-primitives/select/select.js +22 -2
  58. package/dist/02-primitives/upload/upload.js +47 -17
  59. package/dist/03-patterns/content/content.css +1 -1
  60. package/dist/03-patterns/drawer/drawer.js +32 -4
  61. package/dist/03-patterns/dropdown/dropdown.js +20 -1
  62. package/dist/03-patterns/overlay/overlay.js +25 -1
  63. package/dist/03-patterns/pagination/pagination.js +34 -10
  64. package/dist/03-patterns/tooltip/tooltip.js +14 -2
  65. package/dist/03-patterns/tree/tree.js +20 -1
  66. package/dist/09-assets/bar/bar.js +23 -4
  67. package/dist/09-assets/model-viewer/model-viewer.js +38 -12
  68. package/dist/COSTS.md +20 -20
  69. package/docs/ACCESSIBILITY.md +3 -3
  70. package/docs/ARCHITECTURE.md +116 -0
  71. package/docs/L10N.md +92 -0
  72. package/docs/LAYER-BASELINE.md +2 -2
  73. package/docs/PRINT.md +3 -3
  74. package/docs/RELEASE-PROCESS.md +59 -3
  75. package/docs/STABILITY.md +1 -1
  76. package/docs/VERIFY-RELEASE.md +24 -2
  77. package/index.html +3 -3
  78. package/llms-full.txt +18 -4
  79. package/llms.txt +26 -5
  80. package/package.json +4 -2
  81. package/types/index.d.ts +218 -13
package/CONTRIBUTING.md CHANGED
@@ -27,23 +27,45 @@
27
27
  npm ci # 按锁文件装(验证 lockfile 真能装)
28
28
  npm run gate # 全量:含浏览器类
29
29
  npm run gate:fast # 只跑静态层,不用装浏览器
30
+ npm run gate:pre-commit # 提交前:五道秒级判据(实测约 7s)
30
31
  ```
31
32
 
33
+ 三档不是"快慢"的区别,是**判断边界**的区别:
34
+
35
+ | 档 | 什么时候跑 | 能证明什么 |
36
+ |---|---|---|
37
+ | `gate:pre-commit` | 每次 `git commit` 前 | 契约 / 页面结构 / 文案 / 行为核心 / 类型没被改坏 |
38
+ | `gate:fast` | push 前 | 加上静态层的全部判据(不含浏览器) |
39
+ | `gate` | 收尾、发版前 | 全部,含浏览器、视觉基线、打包闭包 |
40
+
41
+ `gate:pre-commit` 走绿只说明"可以提交",**不说明可以发版**。想让它自动跑,
42
+ 把 `bash 05-audit/check-all.sh --pre-commit` 写进 `.git/hooks/pre-commit` 即可;
43
+ 本仓不替使用者装 hook —— 提交节奏是个人选择。
44
+
32
45
  全量的门禁条数由 `05-audit/check-all.sh` 实算,**不在文档里写死** —— 新增一道门禁
33
46
  就会变,写下来的第二天就是第二个会漂的真值(I-7)。默认 `min(核数, 6)` 路并发;
34
47
  组件层要起浏览器,还要逐张比浅色 / 暗色 / RTL 三套视觉基线(按平台分集,
35
48
  只比本平台那套)。条数、耗时、并发效率一律以**本轮门禁打印的结果**为准。
36
49
  只想确认没改坏静态契约的话用 `gate:fast`,几秒到几分钟。
37
50
 
38
- ### 全量为什么**不**在 CI 上跑(这不是缺口,是结论)
51
+ ### CI 跑什么、不跑什么(边界,不是缺口)
39
52
 
40
53
  `.github/workflows/gate.yml` 分三层:`quick`(`MODE=fast`,静态 + 视觉)、
41
- `contract`(API 契约,需 Chromium)、`browsers`(nightly,三引擎矩阵)。
54
+ `contract`(API 契约,需 Chromium)、`browsers`(三引擎矩阵)。
42
55
  **没有任何一处是 `MODE=full`**,而且不该有 —— 实测在 Linux runner 上跑全量会
43
56
  FAIL 10+ 道(字体渲染不同 ⇒ 视觉 diff 必然不一致;路径/编码不同 ⇒ 体积类误报;
44
57
  shallow clone ⇒ 依赖 git 状态的判据语义不同;浏览器版本不同 ⇒ 截图基线不匹配)。
45
58
 
46
59
  **一个长期红的 CI 比没有 CI 更糟**:大家会习惯性忽略它,真正的新问题也一起被忽略。
60
+
61
+ 触发面(2026-11-05 调整):
62
+
63
+ | 事件 | 跑哪些 | 为什么 |
64
+ |---|---|---|
65
+ | 直推 `master` | 只 `quick` | 这个仓库一直是直推,之前**完全没有 CI 保护**;quick 约 3–4 分钟,能挡住"本地没跑就推" |
66
+ | PR | `quick` + `contract` | 合并前要契约 |
67
+ | nightly / 手动 | 全部三个 job | 三引擎矩阵成本高,不该每次 push 都烧 |
68
+
47
69
  所以边界是:
48
70
 
49
71
  - **CI 负责**:跨平台可靠的那部分(静态契约、类型、API 形态、单引擎行为)
@@ -52,10 +74,29 @@ shallow clone ⇒ 依赖 git 状态的判据语义不同;浏览器版本不同
52
74
  `browsers` job 已覆盖三引擎的组件行为契约,但它**不替代**本机全量:
53
75
  它不跑视觉基线(基线按平台分集)、不跑 RTL/响应式/无障碍全量。
54
76
 
77
+ ### 私有词表(维护者;缺失时 leak 判据会变弱)
78
+
79
+ `leak-scan` 的「真实代号 / 用户名」两类要靠一份**不随包分发**的词表才能生效。
80
+ 它放在 `internal/private-terms.txt`(已被 `.gitignore` 挡住,也不在 `package.json`
81
+ 的 `files` 里)。文件不在时,脚本会打印:
82
+
83
+ ```
84
+ ⚠️ 私有词表未加载(0 条)⇒ 真实代号 / 用户名判据**本次未覆盖**
85
+ ```
86
+
87
+ **这不是通过**。本地开发把它放回去即可;CI 上因为拿不到这个文件,需要:
88
+
89
+ 1. GitHub 仓库 → Settings → Secrets and variables → Actions → 新建
90
+ `FL_PRIVATE_TERMS`,值就是词表全文(多行);
91
+ 2. `gate.yml` 的 `quick` job 会把它写进 `internal/private-terms.txt` 再跑门禁;
92
+ 3. 没配时日志里会有一条 `::notice`,明确写着"这一类在 CI 上不覆盖"。
93
+
94
+ ⚠️ 不要把词表直接提交进仓库 —— 那等于把要防的东西本身公开了。
95
+
55
96
  ### 失败时先读哪里
56
97
 
57
98
  `selftest-all` 报红时,除屏幕上那 4 行摘要,**完整子输出会落盘**到
58
- `internal/tmp/selftest-fail-<脚本名>.log`(`internal/` 已被忽略,不进仓库)。
99
+ `internal/tmp/selftest-fail-<脚本名>.log`(`internal/` 是本地忽略目录,不进仓库)。
59
100
  不可复现的红最需要这个 —— 摘要往往不够定位。
60
101
 
61
102
  只想验一条反向控制时,用 `SKIP_SELFTESTS="a.py,b.py" python3 05-audit/selftest-all.py`
package/README.md CHANGED
@@ -10,10 +10,29 @@ npm install agentcss
10
10
 
11
11
  The npm package is `agentcss`; the repository is `frontend-lib`. They are different things: the package name is what you install, the repository name is where the source lives.
12
12
 
13
+ ### Module format: ESM-only
14
+
15
+ The JS entry points (`esm/*.mjs`) are **ESM only** — `exports` has no `require` condition.
16
+
17
+ | You write | Node **≥ 20.19 / ≥ 22.12** | Node 18 – 20.18 |
18
+ |---|---|---|
19
+ | `import 'agentcss'` | ✅ | ✅ |
20
+ | `require('agentcss')` | ✅ (Node's built-in require(ESM)) | ❌ `ERR_REQUIRE_ESM` |
21
+
22
+ - On older runtimes use `await import('agentcss')`, or consume the CSS entry points only
23
+ (`agentcss/tokens.css` etc. are not JS and work on any Node version).
24
+ - The shipped `*.js` files under `02-primitives/**` and `03-patterns/**` are **classic
25
+ scripts** for `<script>` tags, not CommonJS modules — they attach to `window.*`.
26
+ - `"type": "commonjs"` is deliberate: it describes how those classic scripts are
27
+ *parsed*. Flipping it to `module` would make bundlers re-interpret them as ESM,
28
+ which is a breaking change.
29
+
13
30
  ## Docs and live demos
14
31
 
15
32
  - **Every demo page, one index** — https://owain323.github.io/frontend-lib/
16
33
  - **Component documentation with search** — https://owain323.github.io/frontend-lib/guide/
34
+ - **How this project is organized** — [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)
35
+ (what each layer is, how the automated checks work — in plain language)
17
36
 
18
37
  Both are generated from `ai/components.json` and the per-component `README.md`
19
38
  files, so a page cannot quietly go missing from the index when a component is
package/README.zh-CN.md CHANGED
@@ -15,6 +15,8 @@
15
15
 
16
16
  - **全部示例页,一个索引** —— https://owain323.github.io/frontend-lib/
17
17
  - **带搜索的组件文档** —— https://owain323.github.io/frontend-lib/guide/
18
+ - **这个项目是怎么组成的** —— [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)
19
+ (四层组件、自动检查系统,用平话讲)
18
20
 
19
21
  两者都由 `ai/components.json` 与各组件的 `README.md` **生成**:
20
22
  新增组件时索引不会悄悄漏掉它,文档页里的每条链接都指向真实存在的文件。
@@ -60,6 +62,22 @@ npm install agentcss
60
62
 
61
63
  装出来的目录名就是 `agentcss`,`dist-tags.latest` 指向当前版本。
62
64
 
65
+ ### 模块格式:ESM-only(请先读这一条)
66
+
67
+ `agentcss` 的 JS 入口(`esm/*.mjs`)**只有 ESM**,`exports` 里没有 `require` 条件。
68
+
69
+ | 你的写法 | Node **≥ 20.19 / ≥ 22.12** | Node 18 ~ 20.18 |
70
+ |---|---|---|
71
+ | `import 'agentcss'` | ✅ | ✅ |
72
+ | `require('agentcss')` | ✅(Node 自带的 require(ESM)) | ❌ `ERR_REQUIRE_ESM` |
73
+
74
+ - 走 `require` 的旧环境请改用 `await import('agentcss')`,或只用 CSS 入口
75
+ (`agentcss/tokens.css` 这类**不是 JS**,任何 Node 版本都能直接引用)。
76
+ - 包里的 `*.js`(`02-primitives/**`、`03-patterns/**`)是给 `<script>` 用的**经典脚本**,
77
+ 不是 CommonJS 模块 —— 它们挂 `window.*`,不需要 bundler。
78
+ - `type` 字段保持 `commonjs` 是**有意**的:它描述的是那批经典脚本的解析方式。
79
+ 把它改成 `module` 会让 bundler 用 ESM 语义重新解析它们,属于破坏性变更。
80
+
63
81
  另外两条**同样真实可用**的路(内容与 registry 上那一份同源):
64
82
 
65
83
  ```bash
package/SECURITY.md CHANGED
@@ -44,10 +44,22 @@
44
44
  下面两处会把字符串**当 HTML 解析**。它们是**有意的 API**,不是疏漏 ——
45
45
  `popover` 要能放任意块级内容,`drawer` 要能放整页内容,只收文本就废了。
46
46
 
47
- | 文件 | 入口 | 谁负责净化 |
48
- |---|---|---|
49
- | `02-primitives/popover/popover.js` | `opts.html` | 调用方 |
50
- | `03-patterns/drawer/drawer.js` | `opt.content` | 调用方 |
47
+ | 文件 | 入口 | 净化钩子 | 谁负责净化 |
48
+ |---|---|---|---|
49
+ | `02-primitives/popover/popover.js` | `opts.html` | `opts.sanitize` / `Popover.setSanitizer(fn)` | 调用方(或接钩子) |
50
+ | `03-patterns/drawer/drawer.js` | `opt.content`(字符串) | `opt.sanitize` / `Drawer.setSanitizer(fn)` | 调用方(或接钩子) |
51
+
52
+ **0.26.0 起有钩子,但默认不改变行为**:不传 `sanitize`、也不调 `setSanitizer()`
53
+ 时,两处仍然直接把字符串当 HTML 解析 —— 与 0.25.x 完全一致(静默"自动净化"
54
+ 会让既有页面里的 `<b>` / `<svg>` 突然消失,那也是一种破坏)。
55
+ 接 DOMPurify 只需一行:
56
+
57
+ ```js
58
+ Popover.setSanitizer(function (html) { return DOMPurify.sanitize(html); });
59
+ Drawer.setSanitizer(function (html) { return DOMPurify.sanitize(html); });
60
+ ```
61
+
62
+ 逐次覆盖优先于模块级:`Popover.attach(el, { html: s, sanitize: fn })`。
51
63
 
52
64
  **为什么本库不做净化**:净化需要一个 HTML 解析器或一份允许列表实现,而本库的目标是
53
65
  零运行时依赖 + Chromium 97 可用。给一个"看起来安全"的半吊子净化,比明确说
package/START-HERE.md CHANGED
@@ -39,39 +39,39 @@
39
39
  | 标签 / 徽章 | `02-primitives/badge/badge.css` | 141 | — | 有状态标记就要("已披露""停牌") |
40
40
  | 卡片 | `02-primitives/card/card.css` | 283 | — | 有分组内容就要 |
41
41
  | 单选 / 多选 | `02-primitives/choice/choice.css` | 434 | — | 单选 / 多选就要 |
42
- | 下拉选择 | `02-primitives/select/select.css` | 151 | **必需 631** (`select.js`) | 原生 select 的外观或交互不够用就要 |
43
- | 可搜索选择 | `02-primitives/combobox/combobox.css` | 223 | **必需 480** (`combobox.js`) | 选项多到要搜索,或要选多个并留成标签就要 |
42
+ | 下拉选择 | `02-primitives/select/select.css` | 151 | **必需 652** (`select.js`) | 原生 select 的外观或交互不够用就要 |
43
+ | 可搜索选择 | `02-primitives/combobox/combobox.css` | 223 | **必需 503** (`combobox.js`) | 选项多到要搜索,或要选多个并留成标签就要 |
44
44
  | 开关 | `02-primitives/switch/switch.css` | 429 | — | 有"立即生效的设置"就要 |
45
45
  | 分隔线 | `02-primitives/separator/separator.css` | 73 | — | 要分开内容块就要 |
46
46
  | 加载骨架 | `02-primitives/skeleton/skeleton.css` | 114 | — | 数据还没到、先把版式占住就要 |
47
47
  | 进度条 / 环 | `02-primitives/progress/progress.css` | 228 | — | 有耗时过程要给进度就要 |
48
- | 浮层气泡 | `02-primitives/popover/popover.css` | 187 | **必需 325** (`popover.js`) | 要一段信息贴着触发元素浮出来就要 |
49
- | 日期区间 | `02-primitives/date-range/date-range.css` | 206 | **必需 310** (`date-range.js`) | 要选起止日期就要 |
48
+ | 浮层气泡 | `02-primitives/popover/popover.css` | 187 | **必需 345** (`popover.js`) | 要一段信息贴着触发元素浮出来就要 |
49
+ | 日期区间 | `02-primitives/date-range/date-range.css` | 206 | **必需 332** (`date-range.js`) | 要选起止日期就要 |
50
50
  | 标签页 | `03-patterns/tabs/tabs.css` | 172 | **必需 316** (`tabs.js`) | 同层级内容切换就要 |
51
51
  | 折叠面板 | `03-patterns/accordion/accordion.css` | 453 | **必需 389** (`accordion.js`) | 长表单分段就要 |
52
- | 动作菜单 | `03-patterns/dropdown/dropdown.css` | 135 | **必需 555** (`dropdown.js`) | 要一组动作(新建 / 导出 / 删除)就要 |
53
- | 文字提示 | `03-patterns/tooltip/tooltip.css` | 89 | **必需 284** (`tooltip.js`) | 图标按钮或缩写需要一句话解释就要 |
54
- | 分页 | `03-patterns/pagination/pagination.css` | 195 | **必需 401** (`pagination.js`) | 数据多到要翻页就要 |
55
- | 树形 | `03-patterns/tree/tree.css` | 122 | **必需 464** (`tree.js`) | 层级数据(文件 / 组织 / 分类)要展开就要 |
56
- | 侧边抽屉 | `03-patterns/drawer/drawer.css` | 145 | **必需 378** (`drawer.js`) | 要从侧边滑出面板就要 |
57
- | 弹窗 / 吐司 | `03-patterns/overlay/overlay.css` | 338 | **必需 697** (`overlay.js`) | 需要弹层(吐司 / 模态)就要 |
52
+ | 动作菜单 | `03-patterns/dropdown/dropdown.css` | 135 | **必需 575** (`dropdown.js`) | 要一组动作(新建 / 导出 / 删除)就要 |
53
+ | 文字提示 | `03-patterns/tooltip/tooltip.css` | 89 | **必需 299** (`tooltip.js`) | 图标按钮或缩写需要一句话解释就要 |
54
+ | 分页 | `03-patterns/pagination/pagination.css` | 195 | **必需 428** (`pagination.js`) | 数据多到要翻页就要 |
55
+ | 树形 | `03-patterns/tree/tree.css` | 122 | **必需 484** (`tree.js`) | 层级数据(文件 / 组织 / 分类)要展开就要 |
56
+ | 侧边抽屉 | `03-patterns/drawer/drawer.css` | 145 | **必需 416** (`drawer.js`) | 要从侧边滑出面板就要 |
57
+ | 弹窗 / 吐司 | `03-patterns/overlay/overlay.css` | 338 | **必需 734** (`overlay.js`) | 需要弹层(吐司 / 模态)就要 |
58
58
  | 状态(空 / 加载 / 错 / 成功) | `03-patterns/states/states.css` | 269 | — | **凡是会异步取数就要** |
59
59
  | 表单校验 | `03-patterns/form-validation/form-validation.css` | 274 | — | 提交前要校验就要 |
60
60
  | 列表增删 | `03-patterns/list/list.css` | 162 | 可选 201 (`flip.js`,FLIP 增删动画,纯增强) | 列表会动态增删就要 |
61
61
  | 导航 / 目录 | `03-patterns/nav/nav.css` | 314 | **必需 425** (`nav.js`) · 可选 111 (`toc.js`,自动生成目录,纯增强) | 顶部要导航,或长文要目录就要 |
62
- | 长文排版 | `03-patterns/content/content.css` | 286 | — | 写文档 / 长文就要 |
62
+ | 长文排版 | `03-patterns/content/content.css` | 298 | — | 写文档 / 长文就要 |
63
63
  | delta | `02-primitives/delta/delta.css` | 113 | — | |
64
64
  | metric | `02-primitives/metric/metric.css` | 157 | — | |
65
65
  | timeline | `02-primitives/timeline/timeline.css` | 152 | — | 有一串按时间排的事件(公告 / 大事记 / 版本记录)就要 |
66
- | upload | `02-primitives/upload/upload.css` | 490 | 可选 676 (`upload.js`,拖放 / 文件列表 / 校验;没有它基础形态照常工作) | |
66
+ | upload | `02-primitives/upload/upload.css` | 490 | 可选 709 (`upload.js`,拖放 / 文件列表 / 校验;没有它基础形态照常工作) | |
67
67
  | reveal | `03-patterns/reveal/reveal.css` | 93 | 可选 175 (`reveal.js`,入场动效,纯增强;没有它内容直接可见) | |
68
68
  | analysis-report | `04-recipes/analysis-report/analysis-report.css` | 226 | — | |
69
69
  | app-shell | `04-recipes/app-shell/app-shell.css` | 588 | **必需 289** (`shell-nav.js`) | |
70
70
  | detail-page | `04-recipes/detail-page/detail-page.css` | 190 | — | |
71
71
  | report | `04-recipes/report/report.css` | 369 | — | |
72
72
  | table | `04-recipes/table/table.css` | 409 | — | |
73
- | bar | `09-assets/bar/bar.css` | 181 | **必需 324** (`bar.js`) | |
74
- | model-viewer | `09-assets/model-viewer/model-viewer.css` | 143 | **必需 432** (`model-viewer.js`) | |
73
+ | bar | `09-assets/bar/bar.css` | 181 | **必需 348** (`bar.js`) | |
74
+ | model-viewer | `09-assets/model-viewer/model-viewer.css` | 143 | **必需 464** (`model-viewer.js`) | |
75
75
  | scientific-plot | `09-assets/scientific-plot/scientific-plot.css` | 141 | **必需 604** (`scientific-plot.js`) | |
76
76
  | sparkline | `09-assets/sparkline/sparkline.css` | 158 | **必需 508** (`sparkline.js`) | |
77
77
 
@@ -122,11 +122,15 @@
122
122
  | `report/` | `04-recipes/report/` | 报告版式系统 v1:共享基础 + 三种版式取舍(杂志 / 科研技术 / 金融研究) |
123
123
  | `table/` | `04-recipes/table/` | 专业数据表格:列级格式与单位,三种用途预设 |
124
124
 
125
- ## 抄完先做这三件事
125
+ ## 抄完先做这几件事
126
126
 
127
- 1. **看效果** —— 每个组件目录下有 `demo.html`,抄完对照着比
128
- 2. **跑一遍无障碍** —— 浏览器控制台里(或用 axe)确认对比度达标
129
- 3. **别改类名** —— 类名是 API(`.btn` `.btn--primary` `.field__input`),
127
+ 1. **查一遍结构** —— `node ai/cli.js check 你的页面.html`
128
+ 查的是产物:类名在库里存不存在、引没引到定义它的样式表、图有没有 alt、
129
+ 表有没有名字、标题有没有跳级。**它不联网、不开浏览器,一秒出结果。**
130
+ 2. **看一眼** —— `node ai/cli.js shot 你的页面.html --out shot-{width}.png --width=390,1440 --full`
131
+ 390 那张是按真 390 宽度排的(不是把宽图裁一刀),顺手报横向溢出与 JS 报错。
132
+ 3. **跑一遍无障碍** —— 浏览器控制台里(或用 axe)确认对比度达标
133
+ 4. **别改类名** —— 类名是 API(`.btn` `.btn--primary` `.field__input`),
130
134
  改名等于换组件。**要改样式就改令牌**,全库会一起变
131
135
 
132
136
  ---
@@ -146,6 +150,9 @@ CSS 类跨框架通用,React 组件会绑死框架。
146
150
 
147
151
  > **抄 `tierA-tokens.css`(A 档)或 `tokens.css`(B/C 档)→ 再抄你要的那几个 CSS → 保留类名。**
148
152
 
153
+ **让模型来写页面时**,另有一份按「它需要知道什么」组织的清单:`ai/START-HERE.md`
154
+ (`ai components` / `ai pitfalls` / `ai check` / `ai shot` / `ai scaffold` 都在那里)。
155
+
149
156
  ---
150
157
 
151
158
  ## 你可能还想找的(有 / 没有,一次说清)
package/ai/START-HERE.md CHANGED
@@ -61,7 +61,9 @@
61
61
  | 令牌名与取值 | `node ai/cli.js tokens --mode=dark`、`node ai/cli.js tree`(分层视图) |
62
62
  | 组件真实长什么样 | 该组件目录下的 `demo.html` |
63
63
  | 英文一页速览 | `llms.txt` / `llms-full.txt`(发现层;本文件是中文详版) |
64
- | 页面怎么搭 | `04-recipes/` 下的示例 |
64
+ | 页面怎么搭 | `04-recipes/` 下的示例;要写报告/长文就先 `node ai/cli.js scaffold list` |
65
+ | 写完了对不对 | `node ai/cli.js check <页面.html>`(类名/结构/版式必有件) |
66
+ | 写完好不看 | `node ai/cli.js shot <页面.html> --out shot-{width}.png --width=390,1440 --full` |
65
67
  | 令牌怎么改 | README「主题定制」(覆盖 CSS 变量,不需重新编译) |
66
68
 
67
69
  **类名即 API**(`.btn`、`.btn--primary`)。改样式改**令牌**,不要改类名,
@@ -71,7 +73,7 @@
71
73
 
72
74
  | 信号 | 怎么看 |
73
75
  |---|---|
74
- | 成熟度 | `ai/components.json` 的 `maturity` 是**算出来的**(判据在 `ai/components.meta.json`),不是人写的 |
76
+ | 成熟度 | `ai/components.json` 的 `maturity` 是**算出来的**(判据在 `ai/components.meta.json`),不是人写的。它判的是**机制完整**:有 demo、有专属门禁、没有旧 `.is-*` 状态类、没有行为债。**它不判**视觉质量、真实模型生成效果、真机表现 —— `40/40 stable` 不等于 `40/40 好看`,更不等于有人在生产里用过 |
75
77
  | 有没有 demo | 组件目录下有 `demo.html` 就能直接跑起来对照 |
76
78
  | 有没有门禁守 | `05-audit/check-all.sh`(`npm run gate`)一次跑全,逐项打印 `PASS`/`FAIL`/`SKIP` |
77
79
  | 浏览器支持 | README「浏览器支持」表:桌面 Chrome/Edge/Firefox 已验证(自动化);iOS Safari / 微信 / 企微 / QQ 等 7 个入口**人工实测过能力探针**(`🔍`,无回归保护);**Android 系统 WebView 无数据** |
@@ -92,11 +94,42 @@
92
94
  npm ci # 按锁文件安装(首次)
93
95
  npm test # 单元测试
94
96
  npm run test:types # 类型契约:正例必过 + 反例必挂
95
- npm run gate:fast # 静态检查(约 45 秒,改代码时跑)
96
- npm run gate # 全量检查(含浏览器,提交前跑)
97
- node ai/cli.js check <doc.json> # 校验契约文档(读 JSON,不解析原始 HTML)
97
+ npm run gate:pre-commit # 提交前档(约 7 秒:契约 / 页面 / 文案 / 行为核心 / 类型)
98
+ npm run gate:fast # 静态层全部(约 4 分钟,不含浏览器类判据)
99
+ npm run gate # 全量(含浏览器与视觉基线;**发版前**跑,不是提交前)
100
+ node ai/cli.js check <doc.json> # 校验契约文档(计划:节点类型 / 组件档位)
101
+ node ai/cli.js check <页面.html> # 校验产物(类名 / 结构 / 版式必有件)
102
+ node ai/cli.js shot <页面.html> --out shot-{width}.png --width=390,1440 --full
103
+ # 截图(真实视口),顺带报横向溢出与 JS 报错
104
+ node ai/cli.js scaffold report/finance --out report.html
105
+ # 生成最小壳(正确骨架 + 必有件位置),不含内容
98
106
  ```
99
107
 
108
+ **退出码可以直接分支**(全部子命令同一套):
109
+
110
+ | 码 | 含义 | 你该做什么 |
111
+ |---|---|---|
112
+ | 0 | 通过 | — |
113
+ | 1 | **判定不通过**(页面/文档确实有错) | 读 `findings` / `errors`,改产物 |
114
+ | 2 | 用法错误(开关名、取值、重复、空值) | 改调用 |
115
+ | 3 | 环境不具备(没有浏览器 / 没有 node) | 换机器或跳过,别改代码 |
116
+ | 4 | 渲染失败 | 看 message |
117
+ | 5 | 超出预算(产物是完整的) | 拆文档或放宽预算 |
118
+ | 6 | 工具内部错误 | 报 bug,别改自己的参数 |
119
+
120
+ > `1` 和 `2` 分开是有原因的:把「页面有 3 个错」和「`--profile` 拼错了」都返回 1,
121
+ > 自动修复循环会去改**错的那一边**。
122
+
123
+ **计划与产物是两件事,判据不重叠**:
124
+
125
+ | 查什么 | 命令 | 能发现 | 发现不了 |
126
+ |---|---|---|---|
127
+ | 计划(doc.json) | `check <doc.json>` | 节点类型、组件是否在档位内、介质义务 | 写出来的 HTML 对不对 |
128
+ | 产物(.html) | `check <页面.html>` | 类名未定义 / 引错样式表 / 缺 alt、caption、scope / 标题跳级 / 版式缺件 | 页面**好看不好看**(那要 `shot` 看一眼) |
129
+
130
+ > 两个命令都**不联网、不启动浏览器**;`shot` 用你机器上已装的 Chrome/Edge,
131
+ > 不打包浏览器(理由同 `ai pdf`)。
132
+
100
133
  改动本库**自身**时的分层(决定该动哪一层):
101
134
 
102
135
  | 层 | 文件 | 性质 |
@@ -112,7 +145,8 @@ node ai/cli.js check <doc.json> # 校验契约文档(读 JSON,不解析原
112
145
 
113
146
  有人问过要不要把 `ai/*.json` 包成一个 MCP server。结论是**不做**:
114
147
 
115
- 1. 十一个子命令**全是只读查询** —— MCP 版本只是换一层传输,一个新能力都没有。
148
+ 1. 十四个子命令**全是本机命令**(读契约 / 校验文件 / 调本机浏览器)——
149
+ MCP 版本只是换一层传输,一个新能力都没有。
116
150
  2. 它会是**第二份真值**:命令怎么调、参数叫什么、返回什么形状,都得再写一遍。
117
151
  CLI 改了 server 没改,就多一处只有用户能发现的错(`--json` 那次已经踩过同类)。
118
152
  3. 用户要多信任一个常驻进程(安装、权限、升级),而 CLI 离线、可审计、跑完即退。