agentcss 0.0.0-stage → 0.11.3

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 (274) hide show
  1. package/01-tokens/README.md +236 -0
  2. package/01-tokens/behavior/dismissable.js +132 -0
  3. package/01-tokens/behavior/emit.js +76 -0
  4. package/01-tokens/behavior/focus-return.js +81 -0
  5. package/01-tokens/behavior/roving.js +152 -0
  6. package/01-tokens/behavior/typeahead.js +124 -0
  7. package/01-tokens/focus-ring-demo.html +133 -0
  8. package/01-tokens/focus-ring.css +102 -0
  9. package/01-tokens/page.css +244 -0
  10. package/01-tokens/polyfill.js +116 -0
  11. package/01-tokens/responsive-demo.html +171 -0
  12. package/01-tokens/scrollbar-demo.html +194 -0
  13. package/01-tokens/scrollbar.css +179 -0
  14. package/01-tokens/theme-toggle.js +103 -0
  15. package/01-tokens/tokens.css +972 -0
  16. package/01-tokens/typography.css +156 -0
  17. package/02-primitives/badge/README.md +71 -0
  18. package/02-primitives/badge/badge.css +141 -0
  19. package/02-primitives/badge/demo.html +101 -0
  20. package/02-primitives/button/README.md +99 -0
  21. package/02-primitives/button/button.css +353 -0
  22. package/02-primitives/button/demo.html +200 -0
  23. package/02-primitives/card/README.md +145 -0
  24. package/02-primitives/card/card.css +246 -0
  25. package/02-primitives/card/demo.html +170 -0
  26. package/02-primitives/choice/README.md +161 -0
  27. package/02-primitives/choice/choice.css +395 -0
  28. package/02-primitives/choice/demo.html +277 -0
  29. package/02-primitives/combobox/README.md +79 -0
  30. package/02-primitives/combobox/combobox.css +223 -0
  31. package/02-primitives/combobox/combobox.js +485 -0
  32. package/02-primitives/combobox/demo.html +109 -0
  33. package/02-primitives/date-range/README.md +100 -0
  34. package/02-primitives/date-range/date-range.css +206 -0
  35. package/02-primitives/date-range/date-range.js +301 -0
  36. package/02-primitives/date-range/demo.html +104 -0
  37. package/02-primitives/input/README.md +170 -0
  38. package/02-primitives/input/demo.html +246 -0
  39. package/02-primitives/input/input.css +239 -0
  40. package/02-primitives/popover/README.md +80 -0
  41. package/02-primitives/popover/demo.html +150 -0
  42. package/02-primitives/popover/popover.css +187 -0
  43. package/02-primitives/popover/popover.js +331 -0
  44. package/02-primitives/progress/README.md +82 -0
  45. package/02-primitives/progress/demo.html +154 -0
  46. package/02-primitives/progress/progress.css +172 -0
  47. package/02-primitives/select/README.md +95 -0
  48. package/02-primitives/select/demo.html +121 -0
  49. package/02-primitives/select/select.css +151 -0
  50. package/02-primitives/select/select.js +549 -0
  51. package/02-primitives/separator/README.md +63 -0
  52. package/02-primitives/separator/demo.html +84 -0
  53. package/02-primitives/separator/separator.css +73 -0
  54. package/02-primitives/skeleton/README.md +69 -0
  55. package/02-primitives/skeleton/demo.html +110 -0
  56. package/02-primitives/skeleton/skeleton.css +96 -0
  57. package/02-primitives/switch/README.md +65 -0
  58. package/02-primitives/switch/demo.html +115 -0
  59. package/02-primitives/switch/switch.css +370 -0
  60. package/03-patterns/accordion/README.md +121 -0
  61. package/03-patterns/accordion/accordion.css +453 -0
  62. package/03-patterns/accordion/accordion.js +369 -0
  63. package/03-patterns/accordion/demo.html +223 -0
  64. package/03-patterns/content/README.md +103 -0
  65. package/03-patterns/content/content.css +286 -0
  66. package/03-patterns/content/demo.html +88 -0
  67. package/03-patterns/drawer/README.md +79 -0
  68. package/03-patterns/drawer/demo.html +101 -0
  69. package/03-patterns/drawer/drawer.css +129 -0
  70. package/03-patterns/drawer/drawer.js +258 -0
  71. package/03-patterns/dropdown/README.md +78 -0
  72. package/03-patterns/dropdown/demo.html +101 -0
  73. package/03-patterns/dropdown/dropdown.css +135 -0
  74. package/03-patterns/dropdown/dropdown.js +451 -0
  75. package/03-patterns/form-validation/README.md +147 -0
  76. package/03-patterns/form-validation/demo.html +280 -0
  77. package/03-patterns/form-validation/form-validation.css +263 -0
  78. package/03-patterns/list/README.md +150 -0
  79. package/03-patterns/list/demo.html +225 -0
  80. package/03-patterns/list/flip.js +201 -0
  81. package/03-patterns/list/list.css +162 -0
  82. package/03-patterns/nav/README.md +225 -0
  83. package/03-patterns/nav/demo.html +131 -0
  84. package/03-patterns/nav/nav.css +314 -0
  85. package/03-patterns/nav/nav.js +430 -0
  86. package/03-patterns/nav/toc.js +111 -0
  87. package/03-patterns/overlay/README.md +196 -0
  88. package/03-patterns/overlay/demo.html +241 -0
  89. package/03-patterns/overlay/overlay.css +319 -0
  90. package/03-patterns/overlay/overlay.js +563 -0
  91. package/03-patterns/pagination/README.md +114 -0
  92. package/03-patterns/pagination/demo.html +165 -0
  93. package/03-patterns/pagination/pagination.css +195 -0
  94. package/03-patterns/pagination/pagination.js +395 -0
  95. package/03-patterns/reveal/README.md +91 -0
  96. package/03-patterns/reveal/demo.html +106 -0
  97. package/03-patterns/reveal/reveal.css +93 -0
  98. package/03-patterns/reveal/reveal.js +172 -0
  99. package/03-patterns/states/README.md +141 -0
  100. package/03-patterns/states/demo.html +240 -0
  101. package/03-patterns/states/states.css +252 -0
  102. package/03-patterns/tabs/README.md +84 -0
  103. package/03-patterns/tabs/demo.html +139 -0
  104. package/03-patterns/tabs/tabs.css +172 -0
  105. package/03-patterns/tabs/tabs.js +307 -0
  106. package/03-patterns/tooltip/README.md +96 -0
  107. package/03-patterns/tooltip/demo.html +78 -0
  108. package/03-patterns/tooltip/tooltip.css +89 -0
  109. package/03-patterns/tooltip/tooltip.js +288 -0
  110. package/03-patterns/tree/README.md +94 -0
  111. package/03-patterns/tree/demo.html +138 -0
  112. package/03-patterns/tree/tree.css +113 -0
  113. package/03-patterns/tree/tree.js +456 -0
  114. package/04-recipes/analysis-report/README.md +80 -0
  115. package/04-recipes/analysis-report/analysis-report.css +187 -0
  116. package/04-recipes/analysis-report/demo.html +274 -0
  117. package/04-recipes/data-showcase/README.md +45 -0
  118. package/04-recipes/data-showcase/demo.html +247 -0
  119. package/04-recipes/detail-page/README.md +93 -0
  120. package/04-recipes/detail-page/demo.html +55 -0
  121. package/04-recipes/detail-page/detail-page.css +190 -0
  122. package/04-recipes/detail-page/full.html +60 -0
  123. package/04-recipes/detail-page/null.html +60 -0
  124. package/04-recipes/detail-page/partial.html +60 -0
  125. package/04-recipes/detail-page/verify-skeleton.py +19 -0
  126. package/04-recipes/longform/README.md +93 -0
  127. package/04-recipes/longform/agc-memory.svg +4 -0
  128. package/04-recipes/longform/content.html +610 -0
  129. package/04-recipes/longform/content.md +51 -0
  130. package/04-recipes/longform/longform.html +627 -0
  131. package/04-recipes/report/README.md +176 -0
  132. package/04-recipes/report/demo.html +355 -0
  133. package/04-recipes/report/report.css +364 -0
  134. package/04-recipes/table/README.md +103 -0
  135. package/04-recipes/table/demo.html +455 -0
  136. package/04-recipes/table/table.css +372 -0
  137. package/04-recipes/tierA-tokens.css +189 -0
  138. package/09-assets/README.md +74 -0
  139. package/09-assets/bar/README.md +94 -0
  140. package/09-assets/bar/bar.css +166 -0
  141. package/09-assets/bar/bar.js +320 -0
  142. package/09-assets/bar/demo.html +176 -0
  143. package/09-assets/echarts-adapter/demo.html +192 -0
  144. package/09-assets/echarts-adapter/echarts-adapter.js +277 -0
  145. package/09-assets/model-viewer/README.md +155 -0
  146. package/09-assets/model-viewer/demo.html +105 -0
  147. package/09-assets/model-viewer/model-viewer.css +143 -0
  148. package/09-assets/model-viewer/model-viewer.js +423 -0
  149. package/09-assets/scientific-plot/README.md +94 -0
  150. package/09-assets/scientific-plot/demo.html +252 -0
  151. package/09-assets/scientific-plot/scientific-plot.css +141 -0
  152. package/09-assets/scientific-plot/scientific-plot.js +610 -0
  153. package/09-assets/sparkline/README.md +153 -0
  154. package/09-assets/sparkline/demo.html +163 -0
  155. package/09-assets/sparkline/sparkline.css +158 -0
  156. package/09-assets/sparkline/sparkline.js +508 -0
  157. package/API.md +332 -0
  158. package/CHANGELOG.md +3138 -0
  159. package/CODE_OF_CONDUCT.md +64 -0
  160. package/CONTRIBUTING.md +89 -0
  161. package/ERRORS.md +1658 -0
  162. package/LICENSE +21 -0
  163. package/README.md +497 -2
  164. package/SECURITY.md +72 -0
  165. package/START-HERE.md +164 -0
  166. package/SUPPORT.md +109 -0
  167. package/adapters/presentation/README.md +113 -0
  168. package/adapters/presentation/check.js +101 -0
  169. package/adapters/presentation/deck.schema.json +74 -0
  170. package/adapters/presentation/to-doc.js +138 -0
  171. package/ai/START-HERE.md +104 -0
  172. package/ai/behaviors.json +380 -0
  173. package/ai/behaviors.schema.json +61 -0
  174. package/ai/capabilities.json +56 -0
  175. package/ai/cli.js +387 -0
  176. package/ai/components.json +1944 -0
  177. package/ai/components.meta.json +168 -0
  178. package/ai/components.schema.json +220 -0
  179. package/ai/contract.schema.json +147 -0
  180. package/ai/deprecations.json +55 -0
  181. package/ai/deprecations.schema.json +85 -0
  182. package/ai/motion-policy.json +22 -0
  183. package/ai/patch.js +323 -0
  184. package/ai/patch.schema.json +63 -0
  185. package/ai/profiles.json +92 -0
  186. package/ai/tokens.audience.json +55 -0
  187. package/ai/tokens.audience.schema.json +73 -0
  188. package/ai/tokens.json +762 -0
  189. package/ai/tokens.schema.json +58 -0
  190. package/ai/tokens.tree.json +752 -0
  191. package/ai/tokens.tree.schema.json +56 -0
  192. package/ai/validate.js +383 -0
  193. package/dist/01-tokens/behavior/dismissable.js +60 -0
  194. package/dist/01-tokens/behavior/emit.js +21 -0
  195. package/dist/01-tokens/behavior/focus-return.js +31 -0
  196. package/dist/01-tokens/behavior/roving.js +77 -0
  197. package/dist/01-tokens/behavior/typeahead.js +61 -0
  198. package/dist/01-tokens/focus-ring.css +1 -0
  199. package/dist/01-tokens/page.css +1 -0
  200. package/dist/01-tokens/polyfill.js +78 -0
  201. package/dist/01-tokens/scrollbar.css +1 -0
  202. package/dist/01-tokens/theme-toggle.js +61 -0
  203. package/dist/01-tokens/tokens.css +1 -0
  204. package/dist/01-tokens/typography.css +1 -0
  205. package/dist/02-primitives/badge/badge.css +1 -0
  206. package/dist/02-primitives/button/button.css +1 -0
  207. package/dist/02-primitives/card/card.css +1 -0
  208. package/dist/02-primitives/choice/choice.css +1 -0
  209. package/dist/02-primitives/combobox/combobox.css +1 -0
  210. package/dist/02-primitives/combobox/combobox.js +439 -0
  211. package/dist/02-primitives/date-range/date-range.css +1 -0
  212. package/dist/02-primitives/date-range/date-range.js +267 -0
  213. package/dist/02-primitives/input/input.css +1 -0
  214. package/dist/02-primitives/popover/popover.css +1 -0
  215. package/dist/02-primitives/popover/popover.js +257 -0
  216. package/dist/02-primitives/progress/progress.css +1 -0
  217. package/dist/02-primitives/select/select.css +1 -0
  218. package/dist/02-primitives/select/select.js +449 -0
  219. package/dist/02-primitives/separator/separator.css +1 -0
  220. package/dist/02-primitives/skeleton/skeleton.css +1 -0
  221. package/dist/02-primitives/switch/switch.css +1 -0
  222. package/dist/03-patterns/accordion/accordion.css +1 -0
  223. package/dist/03-patterns/accordion/accordion.js +219 -0
  224. package/dist/03-patterns/content/content.css +1 -0
  225. package/dist/03-patterns/drawer/drawer.css +1 -0
  226. package/dist/03-patterns/drawer/drawer.js +229 -0
  227. package/dist/03-patterns/dropdown/dropdown.css +1 -0
  228. package/dist/03-patterns/dropdown/dropdown.js +365 -0
  229. package/dist/03-patterns/form-validation/form-validation.css +1 -0
  230. package/dist/03-patterns/list/flip.js +117 -0
  231. package/dist/03-patterns/list/list.css +1 -0
  232. package/dist/03-patterns/nav/nav.css +1 -0
  233. package/dist/03-patterns/nav/nav.js +322 -0
  234. package/dist/03-patterns/nav/toc.js +76 -0
  235. package/dist/03-patterns/overlay/overlay.css +1 -0
  236. package/dist/03-patterns/overlay/overlay.js +398 -0
  237. package/dist/03-patterns/pagination/pagination.css +1 -0
  238. package/dist/03-patterns/pagination/pagination.js +273 -0
  239. package/dist/03-patterns/reveal/reveal.css +1 -0
  240. package/dist/03-patterns/reveal/reveal.js +138 -0
  241. package/dist/03-patterns/states/states.css +1 -0
  242. package/dist/03-patterns/tabs/tabs.css +1 -0
  243. package/dist/03-patterns/tabs/tabs.js +242 -0
  244. package/dist/03-patterns/tooltip/tooltip.css +1 -0
  245. package/dist/03-patterns/tooltip/tooltip.js +213 -0
  246. package/dist/03-patterns/tree/tree.css +1 -0
  247. package/dist/03-patterns/tree/tree.js +383 -0
  248. package/dist/04-recipes/analysis-report/analysis-report.css +1 -0
  249. package/dist/04-recipes/detail-page/detail-page.css +1 -0
  250. package/dist/04-recipes/report/report.css +1 -0
  251. package/dist/04-recipes/table/table.css +1 -0
  252. package/dist/04-recipes/tierA-tokens.css +1 -0
  253. package/dist/09-assets/bar/bar.css +1 -0
  254. package/dist/09-assets/bar/bar.js +222 -0
  255. package/dist/09-assets/echarts-adapter/echarts-adapter.js +185 -0
  256. package/dist/09-assets/model-viewer/model-viewer.css +1 -0
  257. package/dist/09-assets/model-viewer/model-viewer.js +320 -0
  258. package/dist/09-assets/scientific-plot/scientific-plot.css +1 -0
  259. package/dist/09-assets/scientific-plot/scientific-plot.js +568 -0
  260. package/dist/09-assets/sparkline/sparkline.css +1 -0
  261. package/dist/09-assets/sparkline/sparkline.js +265 -0
  262. package/dist/COSTS.md +56 -0
  263. package/docs/AI-CONTRACT.md +197 -0
  264. package/docs/BACKLOG.md +127 -0
  265. package/docs/BENCHMARK.md +252 -0
  266. package/docs/GUIDANCE.md +154 -0
  267. package/docs/INVARIANT.md +372 -0
  268. package/docs/LAYER-BASELINE.md +158 -0
  269. package/docs/RELEASING.md +311 -0
  270. package/docs/RFC-THEME-SCOPE.md +141 -0
  271. package/docs/ROADMAP.md +182 -0
  272. package/index.html +82 -0
  273. package/package.json +107 -4
  274. package/types/index.d.ts +310 -0
@@ -0,0 +1,56 @@
1
+ {
2
+ "$comment": [
3
+ "能力协商:编辑方【声明自己能做什么】,前端库据此开放不同的操作集。",
4
+ "",
5
+ "🔴 为什么要协商,而不是判断模型名",
6
+ " if (model === 'xxx') { ... } 这种写法有三个致命问题:",
7
+ " ① 立刻过期 —— 新模型出来就失效",
8
+ " ② 同一模型不同接入方式(带工具 / 不带工具)能力完全不同",
9
+ " ③ 我们把别人的产品路线图写进了自己的代码,改不了也跟不上",
10
+ " ⇒ 正解:**问能力,不问名字。**",
11
+ " 这是 HTTP 内容协商、CSS @supports 同一个思路 —— 探测能力本身。",
12
+ "",
13
+ "🔴 协商的方向是单向的:",
14
+ " 编辑方声明 → 本库决定开放哪些操作。",
15
+ " 本库**不**声明自己的版本去让对方适配 —— 那样就变成双向耦合了。"
16
+ ],
17
+ "schemaVersion": "1.0.0",
18
+ "capabilities": {
19
+ "structuredOutput": {
20
+ "label": "能稳定输出符合契约的 JSON",
21
+ "unlocks": ["patch.apply", "patch.batch"],
22
+ "without": ["只能整篇重写(风险高,需人工 diff)"]
23
+ },
24
+ "toolCalling": {
25
+ "label": "能调用外部工具",
26
+ "unlocks": ["validate.cli", "impact.report", "gate.run"],
27
+ "without": ["改完无法自证,必须交给人工验证"]
28
+ },
29
+ "visualInspection": {
30
+ "label": "能看到渲染结果",
31
+ "unlocks": ["visual.baseline", "visual.diff"],
32
+ "without": ["样式类错误只能靠门禁兜住,不能靠眼睛"]
33
+ },
34
+ "patchEditing": {
35
+ "label": "能按语义 id 增量修改",
36
+ "unlocks": ["patch.create", "patch.update", "patch.move",
37
+ "patch.delete", "patch.replace"],
38
+ "without": ["只能 regenerate —— 每次都可能重写未改动的部分,",
39
+ "这正是'改 A 坏 B'的来源"]
40
+ }
41
+ },
42
+ "defaults": {
43
+ "$comment": "未声明的能力一律视为 false —— 保守默认值。宁可少给,不可错给。",
44
+ "structuredOutput": false,
45
+ "toolCalling": false,
46
+ "visualInspection": false,
47
+ "patchEditing": false
48
+ },
49
+ "minimumForSafeEditing": {
50
+ "$comment": [
51
+ "要做**无人值守**的自动编辑,至少需要下面两项。",
52
+ "达不到 ⇒ 只应做『生成草稿 + 人工确认』,不应声称自动化。"
53
+ ],
54
+ "requires": ["structuredOutput", "patchEditing"]
55
+ }
56
+ }
package/ai/cli.js ADDED
@@ -0,0 +1,387 @@
1
+ #!/usr/bin/env node
2
+ /*
3
+ * cli.js — 本库(包名 `agentcss`)的**独立校验入口**
4
+ *
5
+ * ============================================================================
6
+ * 🔴 为什么必须是独立 CLI,而不是"写在提示词里让 AI 自己注意"
7
+ * ----------------------------------------------------------------------------
8
+ * 提示词里的规则是靠模型自觉执行的 —— 它会累、会忘、会在长上下文里丢掉。
9
+ * 而 CLI 是**机器判定**:跑出来是几就是几,跟谁在调用无关。
10
+ *
11
+ * ⇒ 校验必须是**独立可执行的东西**,不能是给 AI 的一段说明。
12
+ * 这也是为什么它不依赖任何模型、不联网、不读取任何环境变量:
13
+ * **它能被任何人在任何地方跑出同样的结果。**
14
+ *
15
+ * ============================================================================
16
+ * 用法
17
+ * ----------------------------------------------------------------------------
18
+ * agentcss ai check <doc.json> [--profile=strict]
19
+ * agentcss ai validate <file.json> --schema=contract|components|tokens|tokensAudience|tokensTree|deprecations|patch
20
+ * agentcss ai diff <a.json> <b.json>
21
+ * agentcss ai patch <doc.json> <patch.json> [-o out.json]
22
+ * agentcss ai components [--maturity=stable] [--json]
23
+ * agentcss ai tokens [--set=light|dark] [--json]
24
+ * agentcss ai profile 列出三档及其差异
25
+ * agentcss ai capabilities
26
+ * ============================================================================
27
+ */
28
+ 'use strict';
29
+
30
+ var fs = require('fs');
31
+ var path = require('path');
32
+ var validate = require('./validate.js');
33
+ var patch = require('./patch.js');
34
+
35
+ var AI = __dirname;
36
+
37
+ /* ⚠️ 不能用 `String#padEnd`:它是 ES2017,
38
+ 在老 WebView 上会**直接抛异常**(静默失效,只在真机炸)。
39
+ 本文件虽跑在 Node 里,但同一份代码被复制进页面用是完全可能的
40
+ ⇒ `legacy-api` 门禁就是这么抓到它的。 */
41
+ function pad(s, n) {
42
+ var out = String(s);
43
+ while (out.length < n) out += ' ';
44
+ return out;
45
+ }
46
+
47
+ function readJSON(file) {
48
+ var txt = fs.readFileSync(file, 'utf8');
49
+ try {
50
+ return JSON.parse(txt);
51
+ } catch (e) {
52
+ throw new Error(file + ' 不是合法 JSON:' + e.message);
53
+ }
54
+ }
55
+
56
+ function out(obj) {
57
+ process.stdout.write(JSON.stringify(obj, null, 2) + '\n');
58
+ }
59
+
60
+ function die(msg) {
61
+ process.stderr.write('[FAIL] ' + msg + '\n');
62
+ process.exit(1);
63
+ }
64
+
65
+ /**
66
+ * 读命令行开关。支持两种写法:
67
+ * --profile strict
68
+ * --profile=strict
69
+ * ⚠️ 第一版只支持空格写法 ⇒ `--maturity=beta` 被静默忽略,
70
+ * 过滤器没生效却输出了全部 27 个组件(实测)。
71
+ * **参数解析失败时不报错、只是少做一件事**,是最难发现的一类假绿。
72
+ */
73
+ function flag(name, def) {
74
+ var eq = '--' + name + '=';
75
+ for (var i = 0; i < process.argv.length; i++) {
76
+ if (process.argv[i].indexOf(eq) === 0) {
77
+ return process.argv[i].slice(eq.length);
78
+ }
79
+ }
80
+ var i2 = process.argv.indexOf('--' + name);
81
+ if (i2 < 0) return def;
82
+ var v = process.argv[i2 + 1];
83
+ if (v === undefined || v.charAt(0) === '-') return true;
84
+ return v;
85
+ }
86
+
87
+ // ---------------------------------------------------------------- check
88
+ function cmdCheck(args) {
89
+ var file = args[0];
90
+ if (!file) die('用法:ai check <doc.json> [--profile=creative|standard|strict]');
91
+ var doc = readJSON(file);
92
+ var profile = flag('profile', doc.profile || 'standard');
93
+ var r = validate.validateDoc(doc, { profile: profile });
94
+ var json = flag('json', false) === true || flag('json', false) === 'true';
95
+
96
+ if (json) {
97
+ out(r);
98
+ process.exit(r.ok ? 0 : 1);
99
+ }
100
+ process.stdout.write(' === 契约校验(档位:' + r.profile + ')===\n\n');
101
+ if (r.errors.length === 0) {
102
+ process.stdout.write(' OK ' + Object.keys(doc.nodes || {}).length +
103
+ ' 个节点,无违规\n');
104
+ } else {
105
+ r.errors.forEach(function (e) {
106
+ process.stdout.write(' [FAIL] ' + e.path + '\n ' + e.msg + '\n');
107
+ });
108
+ }
109
+ if (r.warnings.length) {
110
+ process.stdout.write('\n ⚠️ 提示(不阻断):\n');
111
+ r.warnings.forEach(function (w) {
112
+ process.stdout.write(' ' + w.path + ' ' + w.msg + '\n');
113
+ });
114
+ }
115
+ process.exit(r.ok ? 0 : 1);
116
+ }
117
+
118
+ // ---------------------------------------------------------------- validate
119
+ var SCHEMAS = {
120
+ contract: 'contract.schema.json',
121
+ components: 'components.schema.json',
122
+ tokens: 'tokens.schema.json',
123
+ tokensAudience: 'tokens.audience.schema.json',
124
+ tokensTree: 'tokens.tree.schema.json',
125
+ deprecations: 'deprecations.schema.json',
126
+ patch: 'patch.schema.json'
127
+ };
128
+
129
+ function cmdValidate(args) {
130
+ var file = args[0];
131
+ var which = flag('schema', 'contract');
132
+ if (!file) die('用法:ai validate <file.json> --schema=' + Object.keys(SCHEMAS).join('|'));
133
+ if (!SCHEMAS[which]) die('未知 schema:' + which);
134
+ validate.assertSchemasUseOnlySupported();
135
+ var schema = readJSON(path.join(AI, SCHEMAS[which]));
136
+ var data = readJSON(file);
137
+ var r = validate.validate(schema, data);
138
+ if (r.ok) {
139
+ process.stdout.write(' OK ' + file + ' 符合 ' + which + ' 契约\n');
140
+ process.exit(0);
141
+ }
142
+ r.errors.forEach(function (e) {
143
+ process.stdout.write(' [FAIL] ' + e.path + ' ' + e.msg + '\n');
144
+ });
145
+ process.exit(1);
146
+ }
147
+
148
+ // ---------------------------------------------------------------- diff
149
+ /**
150
+ * 语义 diff:按 id 比对,输出 added / removed / changed / **moved**。
151
+ * 🔴 moved 单独一类是关键:
152
+ * "内容没变,只是挪了位置" 和 "内容被改了" 是两种完全不同的风险,
153
+ * 混在一起报告,人就没法判断要不要紧。
154
+ */
155
+ function cmdDiff(args) {
156
+ var fa = args[0], fb = args[1];
157
+ if (!fa || !fb) die('用法:ai diff <改动前.json> <改动后.json>');
158
+ var a = readJSON(fa), b = readJSON(fb);
159
+ var na = a.nodes || {}, nb = b.nodes || {};
160
+ var added = [], removed = [], changed = [], moved = [];
161
+
162
+ function parentOf(nodes, id) {
163
+ var found = null;
164
+ Object.keys(nodes).forEach(function (pid) {
165
+ var at = (nodes[pid].children || []).indexOf(id);
166
+ if (at >= 0) found = { parent: pid, index: at };
167
+ });
168
+ if (!found) {
169
+ var at2 = (nodes.__root || []).indexOf(id);
170
+ if (at2 >= 0) found = { parent: null, index: at2 };
171
+ }
172
+ return found;
173
+ }
174
+
175
+ Object.keys(nb).forEach(function (id) { if (!(id in na)) added.push(id); });
176
+ Object.keys(na).forEach(function (id) { if (!(id in nb)) removed.push(id); });
177
+ Object.keys(na).forEach(function (id) {
178
+ if (!(id in nb)) return;
179
+ var x = JSON.parse(JSON.stringify(na[id]));
180
+ var y = JSON.parse(JSON.stringify(nb[id]));
181
+ var cx = x.children, cy = y.children;
182
+ delete x.children; delete y.children;
183
+ if (JSON.stringify(x) !== JSON.stringify(y)) changed.push(id);
184
+ else if (JSON.stringify(cx || []) !== JSON.stringify(cy || [])) moved.push(id);
185
+ });
186
+
187
+ var json = flag('json', false) === true || flag('json', false) === 'true';
188
+ var res = { added: added, removed: removed, changed: changed, moved: moved };
189
+ if (json) { out(res); process.exit(0); }
190
+
191
+ process.stdout.write(' === 语义 diff ===\n\n');
192
+ process.stdout.write(' 新增 ' + added.length + '\n');
193
+ process.stdout.write(' 删除 ' + removed.length + '\n');
194
+ process.stdout.write(' 内容变更 ' + changed.length +
195
+ ' ⇒ 需要复查渲染结果\n');
196
+ process.stdout.write(' 仅移动 ' + moved.length +
197
+ ' ⇒ 内容未变,风险低\n');
198
+ if (added.length) process.stdout.write('\n 新增:' + added.join(', ') + '\n');
199
+ if (removed.length) process.stdout.write(' 删除:' + removed.join(', ') + '\n');
200
+ if (changed.length) process.stdout.write(' 变更:' + changed.join(', ') + '\n');
201
+ if (moved.length) process.stdout.write(' 移动:' + moved.join(', ') + '\n');
202
+ process.exit(0);
203
+ }
204
+
205
+ // ---------------------------------------------------------------- patch
206
+ function cmdPatch(args) {
207
+ var fdoc = args[0], fpatch = args[1];
208
+ if (!fdoc || !fpatch) die('用法:ai patch <doc.json> <patch.json> [-o out.json]');
209
+ var doc = readJSON(fdoc);
210
+ var p = readJSON(fpatch);
211
+ var r = patch.apply(doc, p);
212
+ if (!r.ok) {
213
+ r.errors.forEach(function (e) {
214
+ process.stdout.write(' [FAIL] ' + e.path + ' ' + e.msg + '\n');
215
+ });
216
+ process.stdout.write('\n ⇒ 补丁**未应用**,原文档没有被改动\n');
217
+ process.exit(1);
218
+ }
219
+ var det = patch.isDeterministic(doc, p);
220
+ process.stdout.write(' OK 已应用 ' + r.applied + ' 个操作 · 确定性:' +
221
+ (det ? '是(同输入两次结果一致)' : '否(🔴 不可回放)') + '\n');
222
+ if (!det) process.exit(1);
223
+ var o = flag('o', null);
224
+ if (o) {
225
+ fs.writeFileSync(o, JSON.stringify(r.doc, null, 2) + '\n');
226
+ process.stdout.write(' 已写出 ' + o + '\n');
227
+ } else if (flag('json', false)) {
228
+ out(r.doc);
229
+ }
230
+ process.exit(0);
231
+ }
232
+
233
+ // ---------------------------------------------------------------- 列表类
234
+ function cmdComponents(args) {
235
+ var doc = readJSON(path.join(AI, 'components.json'));
236
+ var m = flag('maturity', null);
237
+ var list = doc.components.filter(function (c) {
238
+ return !m || c.maturity === m;
239
+ });
240
+ if (flag('json', false)) { out(list); process.exit(0); }
241
+ process.stdout.write(' === 组件契约(' + list.length + ' 个)===\n\n');
242
+ list.forEach(function (c) {
243
+ process.stdout.write(' ' + (c.maturity === 'stable' ? '✅' :
244
+ c.maturity === 'beta' ? '🟡' : '🔴') + ' ' + c.id +
245
+ ' [' + c.tier + '/' + c.maturity + ']\n');
246
+ process.stdout.write(' ' + (c.purpose || '') + '\n');
247
+ if (c.slots.length) {
248
+ process.stdout.write(' 插槽: ' + c.slots.join(' ') + '\n');
249
+ }
250
+ if (c.states.legacyClass.length) {
251
+ process.stdout.write(' ⚠️ 未收敛状态类: .is-' +
252
+ c.states.legacyClass.join(' .is-') + '\n');
253
+ }
254
+ });
255
+ process.stdout.write('\n ✅ stable 🟡 beta(状态仍在 class 里,I-8 未达标) 🔴 alpha\n');
256
+ process.exit(0);
257
+ }
258
+
259
+ function cmdTokens(args) {
260
+ var doc = readJSON(path.join(AI, 'tokens.json'));
261
+ var set = flag('set', null);
262
+ if (flag('json', false)) {
263
+ out(set ? doc.sets[set] : doc);
264
+ process.exit(0);
265
+ }
266
+ process.stdout.write(' === 令牌(浅色 ' + doc.coverage.lightCount +
267
+ ' / 暗色 ' + doc.coverage.darkCount + ')===\n\n');
268
+ ['light', 'dark'].forEach(function (k) {
269
+ if (set && set !== k) return;
270
+ process.stdout.write(' -- ' + k + ' --\n');
271
+ Object.keys(doc.sets[k]).sort().forEach(function (n) {
272
+ var t = doc.sets[k][n];
273
+ process.stdout.write(' ' + pad(n, 24) + t.$value.slice(0, 34) +
274
+ ' [' + t.$type + ']\n');
275
+ });
276
+ process.stdout.write('\n');
277
+ });
278
+ process.exit(0);
279
+ }
280
+
281
+ function cmdTree(args) {
282
+ var doc = readJSON(path.join(AI, 'tokens.tree.json'));
283
+ var set = flag('set', null);
284
+ var cat = flag('cat', null);
285
+ if (flag('json', false)) {
286
+ out(cat && set ? doc.sets[set][cat] : (set ? doc.sets[set] : doc));
287
+ process.exit(0);
288
+ }
289
+ /* 第二种导出是给**工具链**(Style Dictionary / Figma Tokens)的:
290
+ 分层、键名不带 --、字段用 value/type(不带 $)。
291
+ `ai tokens` 那份是 DTCG 形状,喂不进这两套工具 ⇒ 两种各出一份。 */
292
+ process.stdout.write(' === 令牌(第二种导出 · 分层 / 无 -- 前缀 / value 不带 $)===\n');
293
+ process.stdout.write(' 浅色 ' + doc.meta.lightCount + ' / 暗色 ' +
294
+ doc.meta.darkCount + ' · 类别 ' + doc.meta.categories.length + '\n\n');
295
+ ['light', 'dark'].forEach(function (k) {
296
+ if (set && set !== k) return;
297
+ process.stdout.write(' -- ' + k + ' --\n');
298
+ Object.keys(doc.sets[k]).sort().forEach(function (c) {
299
+ if (cat && cat !== c) return;
300
+ process.stdout.write(' ' + c + '\n');
301
+ Object.keys(doc.sets[k][c]).sort().forEach(function (leaf) {
302
+ var t = doc.sets[k][c][leaf];
303
+ process.stdout.write(' ' + pad(leaf, 22) + t.value.slice(0, 30) +
304
+ ' [' + t.type + ']\n');
305
+ });
306
+ });
307
+ process.stdout.write('\n');
308
+ });
309
+ process.exit(0);
310
+ }
311
+
312
+ function cmdProfile() {
313
+ var doc = readJSON(path.join(AI, 'profiles.json'));
314
+ if (flag('json', false)) { out(doc); process.exit(0); }
315
+ process.stdout.write(' === 三档 Profile ===\n\n');
316
+ Object.keys(doc.profiles).forEach(function (k) {
317
+ var p = doc.profiles[k];
318
+ process.stdout.write(' ' + k + '(' + p.label + ')\n');
319
+ process.stdout.write(' 允许成熟度 ' + p.allowedMaturity.join(' / ') + '\n');
320
+ process.stdout.write(' 未知组件 ' + (p.allowedUnknownComponent ? '放行' : '拒绝') + '\n');
321
+ process.stdout.write(' 未知状态取值 ' + (p.allowedUnknownState ? '放行' : '拒绝') + '\n');
322
+ process.stdout.write(' extensions ' + (p.allowedExtensions ? '允许' : '拒绝') + '\n');
323
+ process.stdout.write('\n');
324
+ });
325
+ process.stdout.write(' 🔴 任何档位下都必须成立:\n');
326
+ doc.alwaysEnforced.rules.forEach(function (r) {
327
+ process.stdout.write(' · ' + r + '\n');
328
+ });
329
+ process.exit(0);
330
+ }
331
+
332
+ function cmdCapabilities() {
333
+ var doc = readJSON(path.join(AI, 'capabilities.json'));
334
+ if (flag('json', false)) { out(doc); process.exit(0); }
335
+ process.stdout.write(' === 能力协商 ===\n\n');
336
+ Object.keys(doc.capabilities).forEach(function (k) {
337
+ var c = doc.capabilities[k];
338
+ process.stdout.write(' ' + k + ' —— ' + c.label + '\n');
339
+ process.stdout.write(' 有 → 开放 ' + c.unlocks.join(', ') + '\n');
340
+ process.stdout.write(' 无 → ' + c.without.join(';') + '\n\n');
341
+ });
342
+ process.stdout.write(' 无人值守自动编辑的最低要求:' +
343
+ doc.minimumForSafeEditing.requires.join(' + ') + '\n');
344
+ process.exit(0);
345
+ }
346
+
347
+ // ---------------------------------------------------------------- 分发
348
+ var CMDS = {
349
+ check: cmdCheck,
350
+ validate: cmdValidate,
351
+ diff: cmdDiff,
352
+ patch: cmdPatch,
353
+ components: cmdComponents,
354
+ tokens: cmdTokens,
355
+ tree: cmdTree,
356
+ profile: cmdProfile,
357
+ capabilities: cmdCapabilities
358
+ };
359
+
360
+ function main() {
361
+ var argv = process.argv.slice(2);
362
+ if (!argv.length || argv[0] === 'help' || argv[0] === '--help') {
363
+ process.stdout.write(
364
+ 'agentcss ai —— 独立校验入口(零依赖、不联网、不依赖任何模型)\n\n' +
365
+ ' ai check <doc.json> [--profile=creative|standard|strict]\n' +
366
+ ' ai validate <file.json> --schema=contract|components|tokens|tokensAudience|tokensTree|deprecations|patch\n' +
367
+ ' ai diff <改动前.json> <改动后.json> 按语义 id 比对\n' +
368
+ ' ai patch <doc.json> <patch.json> [-o out.json]\n' +
369
+ ' ai components [--maturity=stable|beta|alpha]\n' +
370
+ ' ai tokens [--set=light|dark]\n' +
371
+ ' ai tree [--set=light|dark] [--cat=color]\n' +
372
+ ' ai profile 列出三档及其差异\n' +
373
+ ' ai capabilities 列出可协商的能力\n');
374
+ process.exit(0);
375
+ }
376
+ var name = argv.shift();
377
+ var fn = CMDS[name];
378
+ if (!fn) die('未知子命令:' + name + '(可用:' + Object.keys(CMDS).join(' / ') + ')');
379
+ try {
380
+ fn(argv);
381
+ } catch (e) {
382
+ die(e.message);
383
+ }
384
+ }
385
+
386
+ if (require.main === module) main();
387
+ module.exports = { CMDS: CMDS };