agentcss 0.16.1 → 0.24.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.
- package/02-primitives/choice/choice.css +31 -2
- package/02-primitives/input/input.css +14 -0
- package/02-primitives/progress/progress.css +56 -0
- package/02-primitives/skeleton/skeleton.css +18 -0
- package/02-primitives/switch/switch.css +61 -2
- package/02-primitives/timeline/README.md +70 -0
- package/02-primitives/timeline/demo.html +161 -0
- package/02-primitives/timeline/timeline.css +152 -0
- package/02-primitives/upload/README.md +142 -0
- package/02-primitives/upload/demo.html +318 -0
- package/02-primitives/upload/upload.css +490 -0
- package/02-primitives/upload/upload.js +676 -0
- package/03-patterns/drawer/drawer.js +30 -5
- package/04-recipes/app-shell/README.md +272 -0
- package/04-recipes/app-shell/app-shell.css +588 -0
- package/04-recipes/app-shell/demo.html +322 -0
- package/04-recipes/app-shell/shell-nav.js +288 -0
- package/04-recipes/table/table.css +22 -0
- package/AGENTS.md +8 -0
- package/API.md +4 -0
- package/CHANGELOG.md +736 -0
- package/CONTRIBUTING.md +22 -1
- package/README.md +17 -5
- package/README.zh-CN.md +16 -6
- package/START-HERE.md +12 -7
- package/ai/START-HERE.md +37 -3
- package/ai/behaviors.json +32 -0
- package/ai/cli.js +183 -25
- package/ai/components.json +185 -7
- package/ai/components.meta.json +13 -0
- package/ai/pitfalls-writing.json +119 -0
- package/ai/pitfalls.json +193 -0
- package/dist/02-primitives/choice/choice.css +1 -1
- package/dist/02-primitives/input/input.css +1 -1
- package/dist/02-primitives/progress/progress.css +1 -1
- package/dist/02-primitives/skeleton/skeleton.css +1 -1
- package/dist/02-primitives/switch/switch.css +1 -1
- package/dist/02-primitives/timeline/timeline.css +1 -0
- package/dist/02-primitives/upload/upload.css +1 -0
- package/dist/02-primitives/upload/upload.js +515 -0
- package/dist/03-patterns/drawer/drawer.js +14 -4
- package/dist/04-recipes/app-shell/app-shell.css +1 -0
- package/dist/04-recipes/app-shell/shell-nav.js +173 -0
- package/dist/04-recipes/table/table.css +1 -1
- package/dist/COSTS.md +12 -10
- package/docs/ACCESSIBILITY.md +20 -7
- package/docs/AI-CONTRACT.md +2 -0
- package/docs/BUDGET.md +179 -0
- package/docs/CONVENTIONS.md +3 -0
- package/docs/STABILITY.md +126 -0
- package/esm/index.mjs +2 -0
- package/esm/upload.mjs +7 -0
- package/index.html +5 -2
- package/llms-full.txt +153 -0
- package/llms.txt +55 -0
- package/package.json +4 -1
package/CONTRIBUTING.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# 参与贡献
|
|
2
2
|
|
|
3
|
+
## 语言
|
|
4
|
+
|
|
5
|
+
**中文优先;英文入口只有 `README.md`。** 这条写在这里,是为了让后来的人不必再反复问一遍:
|
|
6
|
+
|
|
7
|
+
| 文件 | 语言 | 说明 |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| `README.md` | 英文 | 对外主入口;`README.zh-CN.md` 是中文详版 |
|
|
10
|
+
| 组件 `README.md` / `demo.html` / CSS 注释 | 中文 | 使用者读的是取舍理由,不是 API 签名 |
|
|
11
|
+
| `API.md` / `SUPPORT.md` / `docs/` / `CONTRIBUTING.md` | 中文 | 契约、边界与工作方式 |
|
|
12
|
+
| `ai/START-HERE.md` | **中文(有意)** | 见下 |
|
|
13
|
+
|
|
14
|
+
`ai/START-HERE.md` 是给 AI 编码代理看的导航页,它保持中文:
|
|
15
|
+
|
|
16
|
+
它指向的每一份文档都是中文。只把这一页翻成英文,等于把人送到一面中文墙前 ——
|
|
17
|
+
还会多出一份要同步的真值。英文读者走 `README.md`;语言中立的契约在
|
|
18
|
+
`ai/components.json`(机器可读,不含叙述);组件的实际行为看 `demo.html`。
|
|
19
|
+
|
|
20
|
+
⚠️ 这是**记录在案的例外,不是漂移**。若有一天真要面向英文用户,正确做法是
|
|
21
|
+
**整套文档双语**(组件 README + demo 文案 + CSS 注释一起),而不是先翻这一页 ——
|
|
22
|
+
翻一页不会让库变得可用,只会让"其它文档仍是中文"这个事实看不见。
|
|
23
|
+
|
|
3
24
|
## 先跑一遍门禁(这一步别跳)
|
|
4
25
|
|
|
5
26
|
```bash
|
|
@@ -8,7 +29,7 @@ npm run gate # 全量:含浏览器类
|
|
|
8
29
|
npm run gate:fast # 只跑静态层,不用装浏览器
|
|
9
30
|
```
|
|
10
31
|
|
|
11
|
-
全量是 **
|
|
32
|
+
全量是 **220 道门禁**(4 路并发实测约 9 分钟 / 退出码 0;单道耗时累加 1691 秒,
|
|
12
33
|
组件层要起浏览器,还要逐张比 96 张视觉截图。0.11.15 起默认 4 路并发)。
|
|
13
34
|
只想确认没改坏静态契约的话用 `gate:fast`,几秒到几分钟。
|
|
14
35
|
|
package/README.md
CHANGED
|
@@ -46,7 +46,7 @@ This is an optional toolbox, not a spec every page must obey.
|
|
|
46
46
|
- Adding it to an existing site: keep that site's existing framework and styles where they work, and fill only the gap you actually have.
|
|
47
47
|
- When the output is not a web page (slides, documents, email), the layout rules here do not apply.
|
|
48
48
|
|
|
49
|
-
`ai/START-HERE.md` is the
|
|
49
|
+
**Discovery files for agents:** `llms.txt` (short, English, with the CLI commands), `llms-full.txt` (one page: every component plus its known failure modes), `AGENTS.md` (ten lines: contract, query, validate). `ai/START-HERE.md` is the longer navigation for tools (Chinese, like the component docs); `START-HERE.md` at the repository root is the three-step checklist for people.
|
|
50
50
|
|
|
51
51
|
---
|
|
52
52
|
|
|
@@ -171,9 +171,9 @@ Three mistakes the template above already avoids:
|
|
|
171
171
|
|
|
172
172
|
## Components
|
|
173
173
|
|
|
174
|
-
**
|
|
174
|
+
**40** components (stable 40 / beta 0). Each directory holds a `README.md` (why it is built this way) and a `demo.html` (markup you can copy).
|
|
175
175
|
|
|
176
|
-
### primitives (
|
|
176
|
+
### primitives (17)
|
|
177
177
|
|
|
178
178
|
| Component | Root class | Purpose |
|
|
179
179
|
|---|---|---|
|
|
@@ -212,7 +212,7 @@ Three mistakes the template above already avoids:
|
|
|
212
212
|
| `tooltip` | `tooltip` | Hover and focus hints |
|
|
213
213
|
| `tree` | `tree` | Expandable tree |
|
|
214
214
|
|
|
215
|
-
### recipes (
|
|
215
|
+
### recipes (5)
|
|
216
216
|
|
|
217
217
|
| Component | Root class | Purpose |
|
|
218
218
|
|---|---|---|
|
|
@@ -247,6 +247,18 @@ Two builds ship:
|
|
|
247
247
|
|
|
248
248
|
The source tree keeps every comment — that is documentation, not payload.
|
|
249
249
|
|
|
250
|
+
**One frozen ceiling.** The whole library is held to a single budget recorded in
|
|
251
|
+
[`05-audit/budget.json`](05-audit/budget.json): a hard ceiling, a reserve that absorbs
|
|
252
|
+
normal additions *without anyone editing a number*, and a ratchet that tightens the
|
|
253
|
+
budget when the library shrinks. The rules — and what would have to be true to raise
|
|
254
|
+
the ceiling — are in [`docs/BUDGET.md`](docs/BUDGET.md).
|
|
255
|
+
|
|
256
|
+
**Stability.** Since `0.23.0` the public surface is frozen: token names, class names,
|
|
257
|
+
JS members, CLI subcommands and their `--json` shape, contract fields and file paths
|
|
258
|
+
do not disappear or change meaning. Removals go through the deprecation flow, with at
|
|
259
|
+
least one minor version of lead time. What that covers — and what it honestly does
|
|
260
|
+
not — is in [`docs/STABILITY.md`](docs/STABILITY.md).
|
|
261
|
+
|
|
250
262
|
---
|
|
251
263
|
|
|
252
264
|
## Browser support
|
|
@@ -268,7 +280,7 @@ Colour comes from tokens only. Component CSS never writes `@media (prefers-color
|
|
|
268
280
|
|
|
269
281
|
## Machine-readable contract
|
|
270
282
|
|
|
271
|
-
`ai/components.json` describes each component for tools: usable class names, how state is expressed, required behaviours, maturity. `agentcss ai` (the `bin` entry) validates and queries
|
|
283
|
+
`ai/components.json` describes each component for tools: usable class names, how state is expressed, required behaviours, maturity. `ai/pitfalls.json` carries the known failure modes, joined to components by id; `ai/pitfalls-writing.json` holds the ones that happen while writing prose, building demos and publishing pages — those have no component to join to, and keeping them apart is what stops them from showing up as component defects. `agentcss ai` (the `bin` entry) validates and queries both — every subcommand accepts `--json`.
|
|
272
284
|
|
|
273
285
|
## Accessibility
|
|
274
286
|
|
package/README.zh-CN.md
CHANGED
|
@@ -45,8 +45,10 @@
|
|
|
45
45
|
本库只在你确实缺一块时补上去。
|
|
46
46
|
- 输出形态不是网页(PPT / 文档 / 邮件)时,本库的网页布局规则**不适用**。
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
**给 AI 的发现层**:`llms.txt`(短,英文,含命令行用法)、`llms-full.txt`(一页看全 40 个组件
|
|
49
|
+
和各自的已知翻车点)、`AGENTS.md`(十行:契约在哪、怎么查、怎么验)。
|
|
50
|
+
`ai/START-HERE.md` 是更长的中文导航;`START-HERE.md`(根目录)是给人类复用者的三步清单
|
|
51
|
+
(组件表由脚本生成,不会漂移)。
|
|
50
52
|
|
|
51
53
|
## 安装
|
|
52
54
|
|
|
@@ -183,7 +185,7 @@ dist/01-tokens/tokens.css ← 拷这个
|
|
|
183
185
|
01-tokens/tokens.css ← 源码(带 31.6 KB 注释),用于阅读
|
|
184
186
|
```
|
|
185
187
|
|
|
186
|
-
- **别拷源码目录**除非你要读它:全库 CSS 有
|
|
188
|
+
- **别拷源码目录**除非你要读它:全库 CSS 有 68% 是注释(字节口径;字符口径会低报 12 个百分点),`page.css` 一个文件
|
|
187
189
|
17.5 KB 里 15.1 KB 是注释。
|
|
188
190
|
- **JS 也拷 `dist/`**:那一份去了注释但没压缩(理由见「体积」一节)。
|
|
189
191
|
|
|
@@ -250,11 +252,19 @@ dist/01-tokens/tokens.css ← 拷这个
|
|
|
250
252
|
|
|
251
253
|
## 体积:默认给你的已经是干净产物
|
|
252
254
|
|
|
253
|
-
源码目录(`01-tokens/` `02-primitives/` …)里的 CSS **带着全部注释** ——
|
|
254
|
-
|
|
255
|
+
源码目录(`01-tokens/` `02-primitives/` …)里的 CSS **带着全部注释** ——
|
|
256
|
+
实测全库 CSS 有 **约七成是注释**(精确体积由 `dist/COSTS.md` 现算),`page.css` 单个就有 86%。
|
|
255
257
|
|
|
256
258
|
那些注释是写给你看的取舍理由(为什么这么定、踩过什么坑),不是写给你浏览器看的。
|
|
257
|
-
|
|
259
|
+
**注释让你看代码时处处撞墙;从源码目录引入的话,构建工具还会把 68% 的字节原样打进产物。**
|
|
260
|
+
|
|
261
|
+
**一个冻结的上限。** 整套库受一份账本约束([`05-audit/budget.json`](05-audit/budget.json)):
|
|
262
|
+
硬天花板 + 一份「常规新增组件不用改任何数字」的储备 + 一个只在体积下降时收紧的棘轮。
|
|
263
|
+
规则、以及「什么情况才允许抬天花板」,在 [`docs/BUDGET.md`](docs/BUDGET.md)。
|
|
264
|
+
|
|
265
|
+
**稳定性。** 自 `0.23.0` 起公开面冻结:令牌名、类名、JS 成员、CLI 子命令与 `--json`
|
|
266
|
+
形状、契约字段、文件路径 —— 不消失、不改语义;删除走废弃流程,至少留一个次版本的
|
|
267
|
+
迁移窗口。它覆盖什么、又诚实地覆盖不到什么,在 [`docs/STABILITY.md`](docs/STABILITY.md)。
|
|
258
268
|
|
|
259
269
|
⇒ 所以 `import 'agentcss/tokens.css'` **默认给你去注释后的产物**,
|
|
260
270
|
源码版放在 `agentcss/src/*`:
|
package/START-HERE.md
CHANGED
|
@@ -35,16 +35,16 @@
|
|
|
35
35
|
| 组件 | 文件 | 行数 | JS | 什么时候要 |
|
|
36
36
|
|---|---|---|---|---|
|
|
37
37
|
| 按钮 | `02-primitives/button/button.css` | 357 | — | 几乎总要 |
|
|
38
|
-
| 输入框 | `02-primitives/input/input.css` |
|
|
38
|
+
| 输入框 | `02-primitives/input/input.css` | 253 | — | 有表单就要 |
|
|
39
39
|
| 标签 / 徽章 | `02-primitives/badge/badge.css` | 141 | — | 有状态标记就要("已披露""停牌") |
|
|
40
40
|
| 卡片 | `02-primitives/card/card.css` | 283 | — | 有分组内容就要 |
|
|
41
|
-
| 单选 / 多选 | `02-primitives/choice/choice.css` |
|
|
41
|
+
| 单选 / 多选 | `02-primitives/choice/choice.css` | 424 | — | 单选 / 多选就要 |
|
|
42
42
|
| 下拉选择 | `02-primitives/select/select.css` | 151 | **必需 541** (`select.js`) | 原生 select 的外观或交互不够用就要 |
|
|
43
43
|
| 可搜索选择 | `02-primitives/combobox/combobox.css` | 223 | **必需 477** (`combobox.js`) | 选项多到要搜索,或要选多个并留成标签就要 |
|
|
44
|
-
| 开关 | `02-primitives/switch/switch.css` |
|
|
44
|
+
| 开关 | `02-primitives/switch/switch.css` | 429 | — | 有"立即生效的设置"就要 |
|
|
45
45
|
| 分隔线 | `02-primitives/separator/separator.css` | 73 | — | 要分开内容块就要 |
|
|
46
|
-
| 加载骨架 | `02-primitives/skeleton/skeleton.css` |
|
|
47
|
-
| 进度条 / 环 | `02-primitives/progress/progress.css` |
|
|
46
|
+
| 加载骨架 | `02-primitives/skeleton/skeleton.css` | 114 | — | 数据还没到、先把版式占住就要 |
|
|
47
|
+
| 进度条 / 环 | `02-primitives/progress/progress.css` | 228 | — | 有耗时过程要给进度就要 |
|
|
48
48
|
| 浮层气泡 | `02-primitives/popover/popover.css` | 187 | **必需 323** (`popover.js`) | 要一段信息贴着触发元素浮出来就要 |
|
|
49
49
|
| 日期区间 | `02-primitives/date-range/date-range.css` | 206 | **必需 301** (`date-range.js`) | 要选起止日期就要 |
|
|
50
50
|
| 标签页 | `03-patterns/tabs/tabs.css` | 172 | **必需 316** (`tabs.js`) | 同层级内容切换就要 |
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
| 文字提示 | `03-patterns/tooltip/tooltip.css` | 89 | **必需 280** (`tooltip.js`) | 图标按钮或缩写需要一句话解释就要 |
|
|
54
54
|
| 分页 | `03-patterns/pagination/pagination.css` | 195 | **必需 401** (`pagination.js`) | 数据多到要翻页就要 |
|
|
55
55
|
| 树形 | `03-patterns/tree/tree.css` | 122 | **必需 464** (`tree.js`) | 层级数据(文件 / 组织 / 分类)要展开就要 |
|
|
56
|
-
| 侧边抽屉 | `03-patterns/drawer/drawer.css` | 129 | **必需
|
|
56
|
+
| 侧边抽屉 | `03-patterns/drawer/drawer.css` | 129 | **必需 361** (`drawer.js`) | 要从侧边滑出面板就要 |
|
|
57
57
|
| 弹窗 / 吐司 | `03-patterns/overlay/overlay.css` | 319 | **必需 638** (`overlay.js`) | 需要弹层(吐司 / 模态)就要 |
|
|
58
58
|
| 状态(空 / 加载 / 错 / 成功) | `03-patterns/states/states.css` | 252 | — | **凡是会异步取数就要** |
|
|
59
59
|
| 表单校验 | `03-patterns/form-validation/form-validation.css` | 263 | — | 提交前要校验就要 |
|
|
@@ -62,11 +62,14 @@
|
|
|
62
62
|
| 长文排版 | `03-patterns/content/content.css` | 286 | — | 写文档 / 长文就要 |
|
|
63
63
|
| delta | `02-primitives/delta/delta.css` | 113 | — | |
|
|
64
64
|
| metric | `02-primitives/metric/metric.css` | 157 | — | |
|
|
65
|
+
| timeline | `02-primitives/timeline/timeline.css` | 152 | — | 有一串按时间排的事件(公告 / 大事记 / 版本记录)就要 |
|
|
66
|
+
| upload | `02-primitives/upload/upload.css` | 490 | 可选 676 (`upload.js`,拖放 / 文件列表 / 校验;没有它基础形态照常工作) | |
|
|
65
67
|
| reveal | `03-patterns/reveal/reveal.css` | 93 | 可选 175 (`reveal.js`,入场动效,纯增强;没有它内容直接可见) | |
|
|
66
68
|
| analysis-report | `04-recipes/analysis-report/analysis-report.css` | 226 | — | |
|
|
69
|
+
| app-shell | `04-recipes/app-shell/app-shell.css` | 588 | **必需 288** (`shell-nav.js`) | |
|
|
67
70
|
| detail-page | `04-recipes/detail-page/detail-page.css` | 190 | — | |
|
|
68
71
|
| report | `04-recipes/report/report.css` | 364 | — | |
|
|
69
|
-
| table | `04-recipes/table/table.css` |
|
|
72
|
+
| table | `04-recipes/table/table.css` | 409 | — | |
|
|
70
73
|
| bar | `09-assets/bar/bar.css` | 166 | **必需 320** (`bar.js`) | |
|
|
71
74
|
| model-viewer | `09-assets/model-viewer/model-viewer.css` | 143 | **必需 423** (`model-viewer.js`) | |
|
|
72
75
|
| scientific-plot | `09-assets/scientific-plot/scientific-plot.css` | 141 | **必需 610** (`scientific-plot.js`) | |
|
|
@@ -91,6 +94,7 @@
|
|
|
91
94
|
| 侧边抽屉 | `drawer.js` | 键盘 ✓ · ARIA ✓ · 焦点 ✓ |
|
|
92
95
|
| 弹窗 / 吐司 | `overlay.js` | 键盘 ✓ · ARIA ✓ · 焦点 ✓ |
|
|
93
96
|
| 导航 / 目录 | `nav.js` | 键盘 ✓ · ARIA ✓ · 焦点 ✓ |
|
|
97
|
+
| app-shell | `shell-nav.js` | 键盘 — · ARIA ✓ · 焦点 ✓ |
|
|
94
98
|
| bar | `bar.js` | 键盘 — · ARIA ✓ · 焦点 — |
|
|
95
99
|
| model-viewer | `model-viewer.js` | 键盘 — · ARIA — · 焦点 — |
|
|
96
100
|
| scientific-plot | `scientific-plot.js` | 键盘 — · ARIA ✓ · 焦点 — |
|
|
@@ -111,6 +115,7 @@
|
|
|
111
115
|
| 示例 | 目录 | 它示范什么 |
|
|
112
116
|
|---|---|---|
|
|
113
117
|
| `analysis-report/` | `04-recipes/analysis-report/` | 组合型研究报告:正文 + 辅助栏并排,窄屏退回单栏 |
|
|
118
|
+
| `app-shell/` | `04-recipes/app-shell/` | 应用外壳:侧栏 + 顶栏 + 主区;sticky 侧栏自滚、min-width 防撑破、窄屏收走侧栏 |
|
|
114
119
|
| `data-showcase/` | `04-recipes/data-showcase/` | 四种数据表达方式对照:我到底该用哪个 |
|
|
115
120
|
| `detail-page/` | `04-recipes/detail-page/` | 实体详情页骨架:字段齐全 / 部分缺失 / 无数据,三态同构(DOM 不变) |
|
|
116
121
|
| `longform/` | `04-recipes/longform/` | 单栏长文排版与阅读节奏 |
|
package/ai/START-HERE.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# AI 使用入口(frontend-lib)
|
|
2
2
|
|
|
3
|
+
> **English readers:** this index is Chinese, on purpose — the documents it points to
|
|
4
|
+
> (component READMEs, demos, UI copy) are Chinese too, so an English translation of
|
|
5
|
+
> *this page alone* would just walk you into Chinese walls. Start with
|
|
6
|
+
> [`README.md`](../README.md) (English), then use the language-neutral
|
|
7
|
+
> [`ai/components.json`](components.json) for contracts and each component's
|
|
8
|
+
> `demo.html` for behaviour. Language policy: [`CONTRIBUTING.md`](../CONTRIBUTING.md#语言).
|
|
9
|
+
|
|
3
10
|
> **本文件只做导航,不复制契约与组件文档。** 要细节就去它指的地方看。
|
|
4
11
|
|
|
5
12
|
## 0 · 先记住一件事
|
|
@@ -30,8 +37,8 @@
|
|
|
30
37
|
> 它的值直接从 `ai/components.json` 与目录实际内容读出来 —— **不信上面的说法,信这个**。
|
|
31
38
|
|
|
32
39
|
<!-- ==== AI-INVENTORY-BEGIN ==== -->
|
|
33
|
-
- 组件 **
|
|
34
|
-
- `04-recipes/`(页面级示例):`analysis-report`(组合型研究报告:正文 + 辅助栏并排,窄屏退回单栏) · `data-showcase`(四种数据表达方式对照:我到底该用哪个) · `detail-page`(实体详情页骨架:字段齐全 / 部分缺失 / 无数据,三态同构(DOM 不变)) · `longform`(单栏长文排版与阅读节奏) · `report`(报告版式系统 v1:共享基础 + 三种版式取舍(杂志 / 科研技术 / 金融研究)) · `table`(专业数据表格:列级格式与单位,三种用途预设)
|
|
40
|
+
- 组件 **40** 个(`stable` 40)
|
|
41
|
+
- `04-recipes/`(页面级示例):`analysis-report`(组合型研究报告:正文 + 辅助栏并排,窄屏退回单栏) · `app-shell`(应用外壳:侧栏 + 顶栏 + 主区;sticky 侧栏自滚、min-width 防撑破、窄屏收走侧栏) · `data-showcase`(四种数据表达方式对照:我到底该用哪个) · `detail-page`(实体详情页骨架:字段齐全 / 部分缺失 / 无数据,三态同构(DOM 不变)) · `longform`(单栏长文排版与阅读节奏) · `report`(报告版式系统 v1:共享基础 + 三种版式取舍(杂志 / 科研技术 / 金融研究)) · `table`(专业数据表格:列级格式与单位,三种用途预设)
|
|
35
42
|
- `09-assets/`(图表与可视化):`bar`(柱状图,含图表规范的裁剪铁律) · `echarts-adapter`(把令牌喂给 ECharts,按需引入;本库不含 ECharts) · `model-viewer`(惰性加载的 3D 模型查看器) · `scientific-plot`(二维科学绘图:坐标轴 / 误差棒 / 置信区间带 / 对数轴) · `sparkline`(迷你趋势线,没有坐标轴的走势提示)
|
|
36
43
|
<!-- ==== AI-INVENTORY-END ==== -->
|
|
37
44
|
|
|
@@ -49,8 +56,11 @@
|
|
|
49
56
|
|---|---|
|
|
50
57
|
| 有哪些组件、多大、JS 是否必需 | 根目录 `START-HERE.md`(组件表由 `05-audit/fix-start-here.py` 生成,不会漂移) |
|
|
51
58
|
| 组件清单与成熟度 | `node ai/cli.js components --maturity=stable` |
|
|
59
|
+
| 某个组件踩过的坑 | `node ai/cli.js pitfalls --component=<id>`(数据在 `ai/pitfalls.json`) |
|
|
60
|
+
| 写文案 / 做演示 / 发页面时的坑 | `node ai/cli.js pitfalls --scope=writing`(数据在 `ai/pitfalls-writing.json`,不挂组件) |
|
|
52
61
|
| 令牌名与取值 | `node ai/cli.js tokens --mode=dark`、`node ai/cli.js tree`(分层视图) |
|
|
53
62
|
| 组件真实长什么样 | 该组件目录下的 `demo.html` |
|
|
63
|
+
| 英文一页速览 | `llms.txt` / `llms-full.txt`(发现层;本文件是中文详版) |
|
|
54
64
|
| 页面怎么搭 | `04-recipes/` 下的示例 |
|
|
55
65
|
| 令牌怎么改 | README「主题定制」(覆盖 CSS 变量,不需重新编译) |
|
|
56
66
|
|
|
@@ -97,7 +107,31 @@ node ai/cli.js check <doc.json> # 校验契约文档(读 JSON,不解析原
|
|
|
97
107
|
> 本文件(就是那份贴进 system prompt 的极简版)的适用范围是
|
|
98
108
|
> **维护 frontend-lib 自身或严格按本库范式写页面**,不是所有 HTML 任务的通用规则。
|
|
99
109
|
|
|
100
|
-
## 7 ·
|
|
110
|
+
## 7 · 为什么没有 MCP server
|
|
111
|
+
|
|
112
|
+
有人问过要不要把 `ai/*.json` 包成一个 MCP server。结论是**不做**:
|
|
113
|
+
|
|
114
|
+
1. 十一个子命令**全是只读查询** —— MCP 版本只是换一层传输,一个新能力都没有。
|
|
115
|
+
2. 它会是**第二份真值**:命令怎么调、参数叫什么、返回什么形状,都得再写一遍。
|
|
116
|
+
CLI 改了 server 没改,就多一处只有用户能发现的错(`--json` 那次已经踩过同类)。
|
|
117
|
+
3. 用户要多信任一个常驻进程(安装、权限、升级),而 CLI 离线、可审计、跑完即退。
|
|
118
|
+
|
|
119
|
+
**什么情况下该重新考虑**(不是"永远不做"):
|
|
120
|
+
|
|
121
|
+
- 宿主环境**跑不了子进程**(浏览器端、沙箱化的 agent 运行时),CLI 根本调不到;
|
|
122
|
+
- 出现需要**跨调用保持状态**的查询(现在没有:每次查询都无状态)。
|
|
123
|
+
|
|
124
|
+
真要做,形状是给 `cli.js` 套一层 stdio 适配,**不要**重写实现:
|
|
125
|
+
|
|
126
|
+
```js
|
|
127
|
+
// 伪代码:把 tool 参数翻译成 argv,其余全部复用
|
|
128
|
+
server.tool('ai_query', async (a) => runCli([a.cmd].concat(a.args, ['--json'])));
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
⚠️ 别在 server 里重新实现筛选(`--maturity` / `--scope` / `--component`)——
|
|
132
|
+
那些判据在 CLI 里有门禁守,复制一份出去等于把门禁绕开。
|
|
133
|
+
|
|
134
|
+
## 8 · 三句话版本
|
|
101
135
|
|
|
102
136
|
1. 这是**可选**资产;不适用就用别的,别硬套。
|
|
103
137
|
2. 查组件去根目录 `START-HERE.md` 和组件自己的 `demo.html`,别猜。
|
package/ai/behaviors.json
CHANGED
|
@@ -116,6 +116,14 @@
|
|
|
116
116
|
"reveal": [
|
|
117
117
|
"n/a",
|
|
118
118
|
"不是浮层:入场由 IntersectionObserver 触发,没有打开/关闭状态"
|
|
119
|
+
],
|
|
120
|
+
"upload": [
|
|
121
|
+
"n/a",
|
|
122
|
+
"不是浮层:拖放区常驻可见,没有打开/关闭状态,Esc 不参与(Esc 在表单里应当冒泡给外层对话框)"
|
|
123
|
+
],
|
|
124
|
+
"shell-nav": [
|
|
125
|
+
"n/a",
|
|
126
|
+
"本层不接任何键:Esc 与点遮罩由抽屉组件的 dismissable 核处理(那是组件级的模态契约,不是外壳的)"
|
|
119
127
|
]
|
|
120
128
|
},
|
|
121
129
|
"focus-return": {
|
|
@@ -202,6 +210,14 @@
|
|
|
202
210
|
"reveal": [
|
|
203
211
|
"n/a",
|
|
204
212
|
"不改焦点、不接管键盘"
|
|
213
|
+
],
|
|
214
|
+
"upload": [
|
|
215
|
+
"n/a",
|
|
216
|
+
"本组件从不\"打开\"任何东西,也就没有打开前的位置要归还;移除文件后焦点留在原地的下一个移除按钮上(removeAt 里局部删节点、不重建列表,就是为这个)"
|
|
217
|
+
],
|
|
218
|
+
"shell-nav": [
|
|
219
|
+
"n/a",
|
|
220
|
+
"焦点归位同样在抽屉里做:本层只负责\"打开时把焦点交给谁\"(当前页那一项),关闭后的归位由抽屉的 focus-return 核回给菜单按钮"
|
|
205
221
|
]
|
|
206
222
|
},
|
|
207
223
|
"roving": {
|
|
@@ -288,6 +304,14 @@
|
|
|
288
304
|
"reveal": [
|
|
289
305
|
"n/a",
|
|
290
306
|
"不是复合控件:没有一组可聚焦项要在其间移动"
|
|
307
|
+
],
|
|
308
|
+
"upload": [
|
|
309
|
+
"n/a",
|
|
310
|
+
"文件列表不是\"一组选项\":每行的移除按钮都是独立的 Tab 站,方向键不应在行间移动焦点(那是 menu/listbox 的语义,会误导读屏)"
|
|
311
|
+
],
|
|
312
|
+
"shell-nav": [
|
|
313
|
+
"n/a",
|
|
314
|
+
"侧栏是链接列表,不是 menu / listbox:每项都是独立 Tab 站,方向键在条目间移动焦点是错的语义"
|
|
291
315
|
]
|
|
292
316
|
},
|
|
293
317
|
"typeahead": {
|
|
@@ -374,6 +398,14 @@
|
|
|
374
398
|
"reveal": [
|
|
375
399
|
"n/a",
|
|
376
400
|
"不是复合控件:没有可键入定位的集合"
|
|
401
|
+
],
|
|
402
|
+
"upload": [
|
|
403
|
+
"n/a",
|
|
404
|
+
"没有可跳转的选项集合:列表是\"已选中的文件\",用户不会按字母去找其中某一个"
|
|
405
|
+
],
|
|
406
|
+
"shell-nav": [
|
|
407
|
+
"n/a",
|
|
408
|
+
"没有可跳转的选项集合;用户不会按字母去找导航条目"
|
|
377
409
|
]
|
|
378
410
|
}
|
|
379
411
|
}
|
package/ai/cli.js
CHANGED
|
@@ -57,11 +57,31 @@ function out(obj) {
|
|
|
57
57
|
process.stdout.write(JSON.stringify(obj, null, 2) + '\n');
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
var CURRENT_CMD = '';
|
|
61
|
+
|
|
62
|
+
/* 🔴 失败也必须能被机器读。
|
|
63
|
+
以前 die() 只往 stderr 写一行中文,`--json` 的调用方拿到的是
|
|
64
|
+
退出码 1 + 空 stdout —— 它分不清「参数写错了」和「进程崩了」。
|
|
65
|
+
现在:带 --json 时,失败输出一个**单一 JSON 文档**,与成功路径一样可解析。 */
|
|
60
66
|
function die(msg) {
|
|
67
|
+
if (isJson()) {
|
|
68
|
+
out({
|
|
69
|
+
ok: false,
|
|
70
|
+
command: CURRENT_CMD || null,
|
|
71
|
+
error: { kind: 'usage', message: String(msg) }
|
|
72
|
+
});
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
61
75
|
process.stderr.write('[FAIL] ' + msg + '\n');
|
|
62
76
|
process.exit(1);
|
|
63
77
|
}
|
|
64
78
|
|
|
79
|
+
/** 是否要求 JSON 输出。`--json` / `--json=true` 都认,`--json=false` 不认。 */
|
|
80
|
+
function isJson() {
|
|
81
|
+
var v = flag('json', false);
|
|
82
|
+
return v === true || v === 'true';
|
|
83
|
+
}
|
|
84
|
+
|
|
65
85
|
/**
|
|
66
86
|
* 读命令行开关。支持两种写法:
|
|
67
87
|
* --profile strict
|
|
@@ -91,7 +111,7 @@ function cmdCheck(args) {
|
|
|
91
111
|
var doc = readJSON(file);
|
|
92
112
|
var profile = flag('profile', doc.profile || 'standard');
|
|
93
113
|
var r = validate.validateDoc(doc, { profile: profile });
|
|
94
|
-
var json =
|
|
114
|
+
var json = isJson();
|
|
95
115
|
|
|
96
116
|
if (json) {
|
|
97
117
|
out(r);
|
|
@@ -135,6 +155,10 @@ function cmdValidate(args) {
|
|
|
135
155
|
var schema = readJSON(path.join(AI, SCHEMAS[which]));
|
|
136
156
|
var data = readJSON(file);
|
|
137
157
|
var r = validate.validate(schema, data);
|
|
158
|
+
if (isJson()) {
|
|
159
|
+
out({ ok: r.ok, schema: which, file: file, errors: r.errors || [] });
|
|
160
|
+
process.exit(r.ok ? 0 : 1);
|
|
161
|
+
}
|
|
138
162
|
if (r.ok) {
|
|
139
163
|
process.stdout.write(' OK ' + file + ' 符合 ' + which + ' 契约\n');
|
|
140
164
|
process.exit(0);
|
|
@@ -184,7 +208,7 @@ function cmdDiff(args) {
|
|
|
184
208
|
else if (JSON.stringify(cx || []) !== JSON.stringify(cy || [])) moved.push(id);
|
|
185
209
|
});
|
|
186
210
|
|
|
187
|
-
var json =
|
|
211
|
+
var json = isJson();
|
|
188
212
|
var res = { added: added, removed: removed, changed: changed, moved: moved };
|
|
189
213
|
if (json) { out(res); process.exit(0); }
|
|
190
214
|
|
|
@@ -209,24 +233,139 @@ function cmdPatch(args) {
|
|
|
209
233
|
var doc = readJSON(fdoc);
|
|
210
234
|
var p = readJSON(fpatch);
|
|
211
235
|
var r = patch.apply(doc, p);
|
|
236
|
+
|
|
212
237
|
if (!r.ok) {
|
|
238
|
+
if (isJson()) {
|
|
239
|
+
out({ ok: false, applied: 0, errors: r.errors || [] });
|
|
240
|
+
process.exit(1);
|
|
241
|
+
}
|
|
213
242
|
r.errors.forEach(function (e) {
|
|
214
243
|
process.stdout.write(' [FAIL] ' + e.path + ' ' + e.msg + '\n');
|
|
215
244
|
});
|
|
216
245
|
process.stdout.write('\n ⇒ 补丁**未应用**,原文档没有被改动\n');
|
|
217
246
|
process.exit(1);
|
|
218
247
|
}
|
|
248
|
+
|
|
219
249
|
var det = patch.isDeterministic(doc, p);
|
|
250
|
+
var o = flag('o', null);
|
|
251
|
+
if (o) fs.writeFileSync(o, JSON.stringify(r.doc, null, 2) + '\n');
|
|
252
|
+
|
|
253
|
+
/* --json 永远输出**一个** JSON 文档:{ok, applied, deterministic, out, doc}。
|
|
254
|
+
旧版只在"没写 -o"时把 doc 裸打出来 ⇒ 带 -o 时调用方什么也拿不到。 */
|
|
255
|
+
if (isJson()) {
|
|
256
|
+
out({
|
|
257
|
+
ok: true, applied: r.applied, deterministic: det,
|
|
258
|
+
out: o || null, doc: r.doc
|
|
259
|
+
});
|
|
260
|
+
process.exit(det ? 0 : 1);
|
|
261
|
+
}
|
|
262
|
+
|
|
220
263
|
process.stdout.write(' OK 已应用 ' + r.applied + ' 个操作 · 确定性:' +
|
|
221
264
|
(det ? '是(同输入两次结果一致)' : '否(🔴 不可回放)') + '\n');
|
|
222
|
-
if (
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
265
|
+
if (o) process.stdout.write(' 已写出 ' + o + '\n');
|
|
266
|
+
process.exit(det ? 0 : 1);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// ---------------------------------------------------------------- 翻车点
|
|
270
|
+
/* 已知翻车点:`ai/pitfalls.json` 是**人工策展**的事实文件,不是构建产物。
|
|
271
|
+
为什么不塞进 components.json:那份是机器生成的契约,加一条叙述性字段
|
|
272
|
+
会让生成器每次重新生成时都要决定"保留还是覆盖"。两份文件各管一件事。 */
|
|
273
|
+
/* 分两份文件,因为读者不同:
|
|
274
|
+
· `pitfalls.json` —— 组件 / 版式 / 交付过程。能对上组件的写进 `components`,
|
|
275
|
+
`ai components --json` 会把它们挂到组件上。
|
|
276
|
+
· `pitfalls-writing.json` —— 写文案、做演示、发页面时的失效模式,`components` 恒空。
|
|
277
|
+
合成一份的代价:`components` 字段会混进一堆「没有组件可挂」的条目,
|
|
278
|
+
读的人分不清「这个组件没有坑」和「这条本来就不属于组件」。 */
|
|
279
|
+
var PITFALL_FILES = ['pitfalls.json', 'pitfalls-writing.json'];
|
|
280
|
+
var PITFALLS = null;
|
|
281
|
+
|
|
282
|
+
function pitfallsDoc() {
|
|
283
|
+
if (PITFALLS) return PITFALLS;
|
|
284
|
+
var merged = { schemaVersion: '1.0.0', files: [], pitfalls: [] };
|
|
285
|
+
for (var i = 0; i < PITFALL_FILES.length; i++) {
|
|
286
|
+
var f = PITFALL_FILES[i];
|
|
287
|
+
var d = null;
|
|
288
|
+
try {
|
|
289
|
+
d = readJSON(path.join(AI, f));
|
|
290
|
+
} catch (e) {
|
|
291
|
+
/* 🔴 读不到要**吵**。静默跳过会让 `--scope=writing` 返回 0 条,
|
|
292
|
+
而 0 条会被读成「这类没有翻车点」—— 实际是「这份文件不存在」。
|
|
293
|
+
写 stderr 而不是 stdout:stdout 要留给 JSON。 */
|
|
294
|
+
process.stderr.write('[WARN] 读不到 ai/' + f +
|
|
295
|
+
':该文件覆盖的翻车点本次**未提供**\n');
|
|
296
|
+
continue;
|
|
297
|
+
}
|
|
298
|
+
merged.files.push(f);
|
|
299
|
+
if (d.schemaVersion) merged.schemaVersion = d.schemaVersion;
|
|
300
|
+
var list = d.pitfalls || [];
|
|
301
|
+
for (var j = 0; j < list.length; j++) merged.pitfalls.push(list[j]);
|
|
229
302
|
}
|
|
303
|
+
PITFALLS = merged;
|
|
304
|
+
return PITFALLS;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function pitfallsFor(id) {
|
|
308
|
+
var all = pitfallsDoc().pitfalls || [];
|
|
309
|
+
var outList = [];
|
|
310
|
+
for (var i = 0; i < all.length; i++) {
|
|
311
|
+
if ((all[i].components || []).indexOf(id) >= 0) {
|
|
312
|
+
outList.push({ id: all[i].id, title: all[i].title });
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
return outList;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
function cmdPitfalls(args) {
|
|
319
|
+
var doc = pitfallsDoc();
|
|
320
|
+
var list = (doc.pitfalls || []).slice();
|
|
321
|
+
var comp = flag('component', null);
|
|
322
|
+
var scope = flag('scope', null);
|
|
323
|
+
var tag = flag('tag', null);
|
|
324
|
+
|
|
325
|
+
if (comp) {
|
|
326
|
+
// 拼错的组件名要**吵**:静默返回 0 条会被读成"这个组件没坑"。
|
|
327
|
+
var ids = readJSON(path.join(AI, 'components.json')).components.map(function (c) {
|
|
328
|
+
return c.id;
|
|
329
|
+
});
|
|
330
|
+
if (ids.indexOf(comp) < 0) {
|
|
331
|
+
die('未知组件:' + comp + '(可用:' + ids.join(' / ') + ')');
|
|
332
|
+
}
|
|
333
|
+
list = list.filter(function (x) {
|
|
334
|
+
return (x.components || []).indexOf(comp) >= 0;
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
if (scope) {
|
|
338
|
+
list = list.filter(function (x) { return x.scope === scope; });
|
|
339
|
+
}
|
|
340
|
+
if (tag) {
|
|
341
|
+
list = list.filter(function (x) { return (x.tags || []).indexOf(tag) >= 0; });
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
if (isJson()) {
|
|
345
|
+
/* `files` 是**覆盖面**,不是元数据:调用方看到只加载了一份文件时,
|
|
346
|
+
才知道「writing 0 条」是这类没有坑,还是那份文件根本没读到。 */
|
|
347
|
+
out({
|
|
348
|
+
schemaVersion: doc.schemaVersion,
|
|
349
|
+
files: doc.files,
|
|
350
|
+
count: list.length,
|
|
351
|
+
pitfalls: list
|
|
352
|
+
});
|
|
353
|
+
process.exit(0);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
process.stdout.write(' === 已知翻车点(' + list.length + ' 条' +
|
|
357
|
+
(comp ? ' · 组件 ' + comp : '') + (scope ? ' · scope ' + scope : '') + ')===\n\n');
|
|
358
|
+
if (!list.length) {
|
|
359
|
+
process.stdout.write(' (没有匹配项)\n');
|
|
360
|
+
process.exit(0);
|
|
361
|
+
}
|
|
362
|
+
list.forEach(function (x) {
|
|
363
|
+
process.stdout.write(' [' + ((x.components || []).length
|
|
364
|
+
? x.components.join(',') : x.scope) +
|
|
365
|
+
'] ' + x.title + '\n');
|
|
366
|
+
process.stdout.write(' 现象:' + x.symptom + '\n');
|
|
367
|
+
process.stdout.write(' 改法:' + x.fix + '\n');
|
|
368
|
+
});
|
|
230
369
|
process.exit(0);
|
|
231
370
|
}
|
|
232
371
|
|
|
@@ -237,7 +376,16 @@ function cmdComponents(args) {
|
|
|
237
376
|
var list = doc.components.filter(function (c) {
|
|
238
377
|
return !m || c.maturity === m;
|
|
239
378
|
});
|
|
240
|
-
|
|
379
|
+
/* 🔴 每个组件都带上自己的翻车点(id + 标题),字段恒存在(空数组也写)。
|
|
380
|
+
形状恒定比"有值才出现"好:调用方不用写 if,也不会因为某个组件
|
|
381
|
+
恰好没有翻车点而少一个键。 */
|
|
382
|
+
var joined = list.map(function (c) {
|
|
383
|
+
var one = {};
|
|
384
|
+
for (var k in c) if (Object.prototype.hasOwnProperty.call(c, k)) one[k] = c[k];
|
|
385
|
+
one.pitfalls = pitfallsFor(c.id);
|
|
386
|
+
return one;
|
|
387
|
+
});
|
|
388
|
+
if (isJson()) { out(joined); process.exit(0); }
|
|
241
389
|
process.stdout.write(' === 组件契约(' + list.length + ' 个)===\n\n');
|
|
242
390
|
list.forEach(function (c) {
|
|
243
391
|
process.stdout.write(' ' + (c.maturity === 'stable' ? '✅' :
|
|
@@ -251,6 +399,11 @@ function cmdComponents(args) {
|
|
|
251
399
|
process.stdout.write(' ⚠️ 未收敛状态类: .is-' +
|
|
252
400
|
c.states.legacyClass.join(' .is-') + '\n');
|
|
253
401
|
}
|
|
402
|
+
var ps = pitfallsFor(c.id);
|
|
403
|
+
if (ps.length) {
|
|
404
|
+
process.stdout.write(' ⚠️ 翻车点 ' + ps.length + ' 条: ' +
|
|
405
|
+
ps.map(function (x) { return x.title; }).join(' / ') + '\n');
|
|
406
|
+
}
|
|
254
407
|
});
|
|
255
408
|
process.stdout.write('\n ✅ stable 🟡 beta(状态仍在 class 里,I-8 未达标) 🔴 alpha\n');
|
|
256
409
|
process.exit(0);
|
|
@@ -391,7 +544,7 @@ function collectAssets() {
|
|
|
391
544
|
|
|
392
545
|
function cmdAssets(args) {
|
|
393
546
|
var rows = collectAssets();
|
|
394
|
-
if (
|
|
547
|
+
if (isJson()) { out(rows); process.exit(0); }
|
|
395
548
|
var miss = rows.filter(function (r) { return !r.contract; });
|
|
396
549
|
process.stdout.write(' === 全部资产(' + rows.length + ' 项)===\n');
|
|
397
550
|
process.stdout.write(' 契约内 ' + (rows.length - miss.length) + ' 项 · 契约外 ' + miss.length + ' 项\n\n');
|
|
@@ -406,7 +559,7 @@ function cmdAssets(args) {
|
|
|
406
559
|
function cmdTokens(args) {
|
|
407
560
|
var doc = readJSON(path.join(AI, 'tokens.json'));
|
|
408
561
|
var set = flag('set', null);
|
|
409
|
-
if (
|
|
562
|
+
if (isJson()) {
|
|
410
563
|
out(set ? doc.sets[set] : doc);
|
|
411
564
|
process.exit(0);
|
|
412
565
|
}
|
|
@@ -429,7 +582,7 @@ function cmdTree(args) {
|
|
|
429
582
|
var doc = readJSON(path.join(AI, 'tokens.tree.json'));
|
|
430
583
|
var set = flag('set', null);
|
|
431
584
|
var cat = flag('cat', null);
|
|
432
|
-
if (
|
|
585
|
+
if (isJson()) {
|
|
433
586
|
out(cat && set ? doc.sets[set][cat] : (set ? doc.sets[set] : doc));
|
|
434
587
|
process.exit(0);
|
|
435
588
|
}
|
|
@@ -458,7 +611,7 @@ function cmdTree(args) {
|
|
|
458
611
|
|
|
459
612
|
function cmdProfile() {
|
|
460
613
|
var doc = readJSON(path.join(AI, 'profiles.json'));
|
|
461
|
-
if (
|
|
614
|
+
if (isJson()) { out(doc); process.exit(0); }
|
|
462
615
|
process.stdout.write(' === 三档 Profile ===\n\n');
|
|
463
616
|
Object.keys(doc.profiles).forEach(function (k) {
|
|
464
617
|
var p = doc.profiles[k];
|
|
@@ -478,7 +631,7 @@ function cmdProfile() {
|
|
|
478
631
|
|
|
479
632
|
function cmdCapabilities() {
|
|
480
633
|
var doc = readJSON(path.join(AI, 'capabilities.json'));
|
|
481
|
-
if (
|
|
634
|
+
if (isJson()) { out(doc); process.exit(0); }
|
|
482
635
|
process.stdout.write(' === 能力协商 ===\n\n');
|
|
483
636
|
Object.keys(doc.capabilities).forEach(function (k) {
|
|
484
637
|
var c = doc.capabilities[k];
|
|
@@ -502,7 +655,8 @@ var CMDS = {
|
|
|
502
655
|
tokens: cmdTokens,
|
|
503
656
|
tree: cmdTree,
|
|
504
657
|
profile: cmdProfile,
|
|
505
|
-
capabilities: cmdCapabilities
|
|
658
|
+
capabilities: cmdCapabilities,
|
|
659
|
+
pitfalls: cmdPitfalls
|
|
506
660
|
};
|
|
507
661
|
|
|
508
662
|
function main() {
|
|
@@ -510,19 +664,23 @@ function main() {
|
|
|
510
664
|
if (!argv.length || argv[0] === 'help' || argv[0] === '--help') {
|
|
511
665
|
process.stdout.write(
|
|
512
666
|
'agentcss ai —— 独立校验入口(零依赖、不联网、不依赖任何模型)\n\n' +
|
|
513
|
-
' ai check <doc.json> [--profile=creative|standard|strict]\n' +
|
|
514
|
-
' ai validate <file.json> --schema=contract|components|tokens|tokensAudience|tokensTree|deprecations|patch\n' +
|
|
515
|
-
' ai diff <改动前.json> <改动后.json>
|
|
516
|
-
' ai patch <doc.json> <patch.json> [-o out.json]\n' +
|
|
517
|
-
' ai components [--maturity=stable|beta|alpha]\n' +
|
|
667
|
+
' ai check <doc.json> [--profile=creative|standard|strict] [--json]\n' +
|
|
668
|
+
' ai validate <file.json> --schema=contract|components|tokens|tokensAudience|tokensTree|deprecations|patch [--json]\n' +
|
|
669
|
+
' ai diff <改动前.json> <改动后.json> [--json] 按语义 id 比对\n' +
|
|
670
|
+
' ai patch <doc.json> <patch.json> [-o out.json] [--json]\n' +
|
|
671
|
+
' ai components [--maturity=stable|beta|alpha] [--json]\n' +
|
|
518
672
|
' ai assets [--json] 组件之外的资产:布局 / 微行为核 / 示例页 / 适配器\n' +
|
|
519
|
-
' ai tokens [--set=light|dark]\n' +
|
|
520
|
-
' ai tree [--set=light|dark] [--cat=color]\n' +
|
|
521
|
-
' ai
|
|
522
|
-
' ai
|
|
673
|
+
' ai tokens [--set=light|dark] [--json]\n' +
|
|
674
|
+
' ai tree [--set=light|dark] [--cat=color] [--json]\n' +
|
|
675
|
+
' ai pitfalls [--component=<id>] [--scope=component|layout|process|writing] [--tag=<t>] [--json]\n' +
|
|
676
|
+
' ai profile [--json] 列出三档及其差异\n' +
|
|
677
|
+
' ai capabilities [--json] 列出可协商的能力\n' +
|
|
678
|
+
'\n' +
|
|
679
|
+
' 每个子命令都支持 --json;失败时输出 {ok:false, command, error} 并以非 0 退出。\n');
|
|
523
680
|
process.exit(0);
|
|
524
681
|
}
|
|
525
682
|
var name = argv.shift();
|
|
683
|
+
CURRENT_CMD = name;
|
|
526
684
|
var fn = CMDS[name];
|
|
527
685
|
if (!fn) die('未知子命令:' + name + '(可用:' + Object.keys(CMDS).join(' / ') + ')');
|
|
528
686
|
try {
|