create-yss-spec 2.2.7 → 2.2.8

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 (130) hide show
  1. package/README.md +1 -1
  2. package/package.json +1 -1
  3. package/template/.agents/skills/maintaining-skills/SKILL.md +1 -1
  4. package/template/.agents/skills/yss-antd-design/references/evidence.md +4 -0
  5. package/template/.agents/skills/yss-design-system/SKILL.md +3 -1
  6. package/template/.agents/skills/yss-page-module-development/SKILL.md +1 -1
  7. package/template/.agents/skills/yss-product-lifecycle/SKILL.md +1 -1
  8. package/template/.agents/skills/yss-product-lifecycle/references/orchestration-contract.yaml +4 -0
  9. package/template/.agents/skills/yss-prototype-stage/SKILL.md +11 -6
  10. package/template/.agents/skills/yss-prototype-stage/references/product-design-adapter.md +54 -0
  11. package/template/.agents/skills/yss-prototype-stage/scripts/prototype-contract.mjs +207 -0
  12. package/template/.agents/skills/yss-prototype-stage/tests/run-scenarios.mjs +154 -0
  13. package/template/.agents/skills/yss-router/references/boundaries.md +1 -1
  14. package/template/.agents/skills/yss-ui/references/antdv-compatibility.md +1 -1
  15. package/template/.claude/skills/maintaining-skills/SKILL.md +1 -1
  16. package/template/.claude/skills/yss-antd-design/references/evidence.md +4 -0
  17. package/template/.claude/skills/yss-design-system/SKILL.md +3 -1
  18. package/template/.claude/skills/yss-page-module-development/SKILL.md +1 -1
  19. package/template/.claude/skills/yss-product-lifecycle/SKILL.md +1 -1
  20. package/template/.claude/skills/yss-product-lifecycle/references/orchestration-contract.yaml +4 -0
  21. package/template/.claude/skills/yss-prototype-stage/SKILL.md +11 -6
  22. package/template/.claude/skills/yss-prototype-stage/references/product-design-adapter.md +54 -0
  23. package/template/.claude/skills/yss-prototype-stage/scripts/prototype-contract.mjs +207 -0
  24. package/template/.claude/skills/yss-prototype-stage/tests/run-scenarios.mjs +154 -0
  25. package/template/.claude/skills/yss-router/references/boundaries.md +1 -1
  26. package/template/.claude/skills/yss-ui/references/antdv-compatibility.md +1 -1
  27. package/template/.codex/skills/maintaining-skills/SKILL.md +1 -1
  28. package/template/.codex/skills/yss-antd-design/references/evidence.md +4 -0
  29. package/template/.codex/skills/yss-design-system/SKILL.md +3 -1
  30. package/template/.codex/skills/yss-page-module-development/SKILL.md +1 -1
  31. package/template/.codex/skills/yss-product-lifecycle/SKILL.md +1 -1
  32. package/template/.codex/skills/yss-product-lifecycle/references/orchestration-contract.yaml +4 -0
  33. package/template/.codex/skills/yss-prototype-stage/SKILL.md +11 -6
  34. package/template/.codex/skills/yss-prototype-stage/references/product-design-adapter.md +54 -0
  35. package/template/.codex/skills/yss-prototype-stage/scripts/prototype-contract.mjs +207 -0
  36. package/template/.codex/skills/yss-prototype-stage/tests/run-scenarios.mjs +154 -0
  37. package/template/.codex/skills/yss-router/references/boundaries.md +1 -1
  38. package/template/.codex/skills/yss-ui/references/antdv-compatibility.md +1 -1
  39. package/template/.cursor/skills/maintaining-skills/SKILL.md +1 -1
  40. package/template/.cursor/skills/yss-antd-design/references/evidence.md +4 -0
  41. package/template/.cursor/skills/yss-design-system/SKILL.md +3 -1
  42. package/template/.cursor/skills/yss-page-module-development/SKILL.md +1 -1
  43. package/template/.cursor/skills/yss-product-lifecycle/SKILL.md +1 -1
  44. package/template/.cursor/skills/yss-product-lifecycle/references/orchestration-contract.yaml +4 -0
  45. package/template/.cursor/skills/yss-prototype-stage/SKILL.md +11 -6
  46. package/template/.cursor/skills/yss-prototype-stage/references/product-design-adapter.md +54 -0
  47. package/template/.cursor/skills/yss-prototype-stage/scripts/prototype-contract.mjs +207 -0
  48. package/template/.cursor/skills/yss-prototype-stage/tests/run-scenarios.mjs +154 -0
  49. package/template/.cursor/skills/yss-router/references/boundaries.md +1 -1
  50. package/template/.cursor/skills/yss-ui/references/antdv-compatibility.md +1 -1
  51. package/template/.hermes/skills/maintaining-skills/SKILL.md +1 -1
  52. package/template/.hermes/skills/yss-antd-design/references/evidence.md +4 -0
  53. package/template/.hermes/skills/yss-design-system/SKILL.md +3 -1
  54. package/template/.hermes/skills/yss-page-module-development/SKILL.md +1 -1
  55. package/template/.hermes/skills/yss-product-lifecycle/SKILL.md +1 -1
  56. package/template/.hermes/skills/yss-product-lifecycle/references/orchestration-contract.yaml +4 -0
  57. package/template/.hermes/skills/yss-prototype-stage/SKILL.md +11 -6
  58. package/template/.hermes/skills/yss-prototype-stage/references/product-design-adapter.md +54 -0
  59. package/template/.hermes/skills/yss-prototype-stage/scripts/prototype-contract.mjs +207 -0
  60. package/template/.hermes/skills/yss-prototype-stage/tests/run-scenarios.mjs +154 -0
  61. package/template/.hermes/skills/yss-router/references/boundaries.md +1 -1
  62. package/template/.hermes/skills/yss-ui/references/antdv-compatibility.md +1 -1
  63. package/template/.pi/skills/maintaining-skills/SKILL.md +1 -1
  64. package/template/.pi/skills/yss-antd-design/references/evidence.md +4 -0
  65. package/template/.pi/skills/yss-design-system/SKILL.md +3 -1
  66. package/template/.pi/skills/yss-page-module-development/SKILL.md +1 -1
  67. package/template/.pi/skills/yss-product-lifecycle/SKILL.md +1 -1
  68. package/template/.pi/skills/yss-product-lifecycle/references/orchestration-contract.yaml +4 -0
  69. package/template/.pi/skills/yss-prototype-stage/SKILL.md +11 -6
  70. package/template/.pi/skills/yss-prototype-stage/references/product-design-adapter.md +54 -0
  71. package/template/.pi/skills/yss-prototype-stage/scripts/prototype-contract.mjs +207 -0
  72. package/template/.pi/skills/yss-prototype-stage/tests/run-scenarios.mjs +154 -0
  73. package/template/.pi/skills/yss-router/references/boundaries.md +1 -1
  74. package/template/.pi/skills/yss-ui/references/antdv-compatibility.md +1 -1
  75. package/template/.qoder/skills/maintaining-skills/SKILL.md +1 -1
  76. package/template/.qoder/skills/yss-antd-design/references/evidence.md +4 -0
  77. package/template/.qoder/skills/yss-design-system/SKILL.md +3 -1
  78. package/template/.qoder/skills/yss-page-module-development/SKILL.md +1 -1
  79. package/template/.qoder/skills/yss-product-lifecycle/SKILL.md +1 -1
  80. package/template/.qoder/skills/yss-product-lifecycle/references/orchestration-contract.yaml +4 -0
  81. package/template/.qoder/skills/yss-prototype-stage/SKILL.md +11 -6
  82. package/template/.qoder/skills/yss-prototype-stage/references/product-design-adapter.md +54 -0
  83. package/template/.qoder/skills/yss-prototype-stage/scripts/prototype-contract.mjs +207 -0
  84. package/template/.qoder/skills/yss-prototype-stage/tests/run-scenarios.mjs +154 -0
  85. package/template/.qoder/skills/yss-router/references/boundaries.md +1 -1
  86. package/template/.qoder/skills/yss-ui/references/antdv-compatibility.md +1 -1
  87. package/template/.trae/skills/maintaining-skills/SKILL.md +1 -1
  88. package/template/.trae/skills/yss-antd-design/references/evidence.md +4 -0
  89. package/template/.trae/skills/yss-design-system/SKILL.md +3 -1
  90. package/template/.trae/skills/yss-page-module-development/SKILL.md +1 -1
  91. package/template/.trae/skills/yss-product-lifecycle/SKILL.md +1 -1
  92. package/template/.trae/skills/yss-product-lifecycle/references/orchestration-contract.yaml +4 -0
  93. package/template/.trae/skills/yss-prototype-stage/SKILL.md +11 -6
  94. package/template/.trae/skills/yss-prototype-stage/references/product-design-adapter.md +54 -0
  95. package/template/.trae/skills/yss-prototype-stage/scripts/prototype-contract.mjs +207 -0
  96. package/template/.trae/skills/yss-prototype-stage/tests/run-scenarios.mjs +154 -0
  97. package/template/.trae/skills/yss-router/references/boundaries.md +1 -1
  98. package/template/.trae/skills/yss-ui/references/antdv-compatibility.md +1 -1
  99. package/template/AGENTS.md +4 -4
  100. package/template/README.md +10 -11
  101. package/template/__yss_dotfile__.gitignore +1 -0
  102. package/template/docs/agents/skills-maintenance.md +2 -2
  103. package/template/docs/api/templates/openapi-draft-review-checklist.md +2 -2
  104. package/template/docs/design/README.md +2 -2
  105. package/template/docs/design/design.md +48 -9
  106. package/template/docs/design/templates/interaction-spec-template.md +2 -2
  107. package/template/docs/design/templates/prototype-confirmation-template.md +1 -1
  108. package/template/docs/design/templates/prototype-evidence-template.yaml +52 -10
  109. package/template/docs/process/harness-process-tailoring.md +5 -5
  110. package/template/docs/process/template-engineering-overview.md +2 -2
  111. package/template/docs/process/template-verification-profiles.yaml +8 -1
  112. package/template/docs/process/templates/maintenance-checkpoint-template.yaml +3 -12
  113. package/template/docs/templates/requirement-freeze-template.md +1 -1
  114. package/template/docs/user-guide//347/224/250/346/210/267/346/211/213/345/206/214.md +961 -0
  115. package/template/scripts/lib/maintenance-intensity.mjs +24 -10
  116. package/template/scripts/lib/skill-governance.mjs +19 -0
  117. package/template/scripts/node-verify-lifecycle-registry.mjs +1 -1
  118. package/template/scripts/verify-template-verification-scenarios +5 -0
  119. package/template/scripts/verify-yss-prototype-contract-scenarios +2 -0
  120. package/template/skills-lock.json +8 -8
  121. package/template.snapshot.json +4 -4
  122. package/template/docs/user-guide/templates//347/224/250/346/210/267/346/211/213/345/206/214/346/250/241/346/235/277.md +0 -53
  123. package/template/docs/user-guide//344/272/247/345/223/201/347/224/237/345/221/275/345/221/250/346/234/237/345/267/245/344/275/234/346/265/201.md +0 -223
  124. package/template/docs/user-guide//344/272/247/345/223/201/347/240/224/345/217/221/345/205/250/347/224/237/345/221/275/345/221/250/346/234/237/346/234/200/344/275/263/345/256/236/350/267/265.md +0 -1115
  125. package/template/docs/user-guide//345/244/226/351/203/250/345/221/275/344/273/244/350/241/214/345/267/245/345/205/267/345/256/236/350/267/265/346/214/207/345/215/227.md +0 -117
  126. package/template/docs/user-guide//347/224/237/345/221/275/345/221/250/346/234/237/346/234/200/344/275/263/345/256/236/350/267/265.md +0 -584
  127. package/template/docs/user-guide//347/224/250/346/210/267/346/211/213/345/206/214/347/264/242/345/274/225.md +0 -31
  128. package/template/docs/user-guide//350/247/204/346/240/274/344/270/216/344/273/273/345/212/241/350/277/201/347/247/273/346/214/207/345/215/227.md +0 -44
  129. package/template/docs/user-guide//351/234/200/346/261/202/346/276/204/346/270/205/346/214/207/345/215/227.md +0 -230
  130. package/template/docs/user-guide//351/234/200/346/261/202/346/276/204/346/270/205/346/234/200/344/275/263/345/256/236/350/267/265.md +0 -275
package/README.md CHANGED
@@ -52,7 +52,7 @@ npx create-yss-spec@latest --version
52
52
 
53
53
  ## 当前版本说明
54
54
 
55
- 当前 CLI 版本为 `2.2.7`,模板固定到 `96fb0900f8f49e42fe17d36e4cac4717b341bcf2`,同步 Archify 安全 receipt 写入修复及稳定交付路径示例。
55
+ 当前 CLI 版本为 `2.2.8`,模板固定到 `f9f97eb080519b3388be12fed07b2ce0e026b04b`,同步 L3 模板维护证据策略更新。
56
56
 
57
57
  ## 接管已有项目
58
58
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-yss-spec",
3
- "version": "2.2.7",
3
+ "version": "2.2.8",
4
4
  "description": "Initialize a YSS spec project template repository",
5
5
  "repository": {
6
6
  "type": "git",
@@ -17,7 +17,7 @@ Create skills that add useful, non-obvious guidance without constraining unrelat
17
17
  6. Follow the repository's declared maintenance and review policy. If none exists, run structural validation plus focused checks of the behavior or invariant changed. Use independent forward testing only when complexity or risk makes it meaningful; do not require a failing baseline for every ordinary edit.
18
18
  7. After changes, validate frontmatter, naming, references, scripts, projections, locks, and affected callers. Retire obsolete names and resources unless the repository explicitly requires compatibility.
19
19
  8. When a repository declares staged template verification, default the implementation loop to its fast impact profile and stop at `implementation-ready`. Promote explicitly to `review-ready`; do not create frozen candidates, review packages, or release evidence during ordinary iteration. Unknown paths and changes to the verification framework itself must fail safe to the full profile.
20
- 9. For a formal L3 review, run the repository's full gate before the first frozen candidate and again before release. Between them, use focused/candidate checks. Do not weaken required evidence or independent review to gain speed.
20
+ 9. For L3 template maintenance, record maintainer self-check plus fresh verification and do not create a frozen candidate or formal independent review during ordinary iteration. Before release, run the repository's full `scripts/verify-template` gate once; historical formal-review records remain read-only compatible.
21
21
 
22
22
  ## Boundaries
23
23
 
@@ -11,6 +11,8 @@
11
11
  - `antd.queries.components[]`:每个选用组件的 `info_ref` / `demo_ref` / `token_ref` / `semantic_ref`。
12
12
  - `design_baseline.project_design_ref`:`docs/design/design.md`。
13
13
  - `design_baseline.project_override_reviewed`:上游默认与项目 token 已对照。
14
+ - `prototype_stack.actual_antd_version`:原型 lockfile 中的实际 React `antd@6.x`,必须与 `antd.target_antd_version` 一致。
15
+ - `visual_semantic_mapping.components[]`:记录 v6 semantic role、项目 Token、React 原型组件、生产 YSS/Ant Design Vue 4.x 目标与 React-only API 隔离结论。
14
16
 
15
17
  JSON 输出存为相邻文件,证据清单只引用路径。不要把整份 `llms-full.txt` 或 MCP 对话贴进清单。
16
18
 
@@ -18,6 +20,8 @@ JSON 输出存为相邻文件,证据清单只引用路径。不要把整份 `l
18
20
 
19
21
  `antd lint` 只对可解析的 React/TSX 源码有规则命中。HTML 原型会出现空 issues(假绿)或 `skippedFiles` / `parse-error` / `partial: true`。
20
22
 
23
+ CLI JSON 只能证明查询事实,不能单独证明原型消费了目标版本或完成了 Vue/YSS 映射。`gate.prototype-verified` 还必须通过 `yss-prototype-stage/scripts/prototype-contract.mjs` 的项目与 schema v2 证据校验、Design QA、浏览器和无障碍验证。
24
+
21
25
  | 产物 | `lint_applicable` | 做法 |
22
26
  |---|---|---|
23
27
  | `docs/.scratch/<feature>/design/prototypes/index.html` | `not-applicable` | 写 `lint_reason: html-prototype`;`lint_ref` 可空;`lint_passed` 保持 `false`,不得改成 `true` |
@@ -40,6 +40,7 @@ description: Use when YSS 产品设计系统与 Ant Design 企业级 UI 风格
40
40
  - 组件语言:优先 Ant Design / YSS UI 语义,不自造同类控件。
41
41
  - 状态完整性:loading、empty、error、readonly、disabled、no-permission、conflict、success 必须在设计或实现中可解释。
42
42
  - Ant Design v6 原型基线:先用语义 token 定义角色,再用组件 token 或 CSS variables 落地;不以局部硬编码替代主题层。
43
+ - 双轨版本:主题/视觉标准为 React Ant Design v6;生产 API 为 Vue 3 + YSS UI + 实现仓 lockfile 的 Ant Design Vue 4.x。只迁移语义、Token、状态与验收行为。
43
44
 
44
45
  ## 强制规则
45
46
 
@@ -49,7 +50,7 @@ description: Use when YSS 产品设计系统与 Ant Design 企业级 UI 风格
49
50
  - 每个页面或决策区域只保留一个 single primary action;其余动作降级为默认、链接或危险操作。
50
51
  - 不硬编码表面色、边框色、状态色;优先使用 token 或主题变量。
51
52
  - 交互原型中的每个可点击主动作都必须给出 interaction feedback:状态变化、禁用原因、成功或失败反馈至少覆盖其一。
52
- - accessibility contrast:默认 token 不能满足目标文本对比度时,优先通过 `ConfigProvider` seed / component token 调整,不新增页面级特例色。
53
+ - accessibility:品牌 Seed `#3371ff` 保持不变;实际文字/背景组合不满足 WCAG 2.2 AA 时,优先通过 `ConfigProvider` component token 调整,并验证 default/hover/active/disabled/focus、键盘焦点、200% zoom、reduced motion 与目标尺寸,不新增页面级特例色。
53
54
  - React + Ant Design 的暗色或紧凑密度必须使用 theme algorithm,不手工反转颜色或逐控件压缩尺寸。
54
55
  - 不用 Tag 表达关键错误、阻断或审批状态;关键状态必须有可读文本和语义反馈。
55
56
  - 不让按钮、标签、表头、弹窗、卡片中的文字溢出或遮挡。
@@ -89,6 +90,7 @@ description: Use when YSS 产品设计系统与 Ant Design 企业级 UI 风格
89
90
  | YTable / YTree / 高度自适应 | `yss-components` / `yss-use-table-height` / `yss-use-tree-height` |
90
91
  | 原型阶段的 Ant Design v6 组件 / token / demo 查询 | `yss-antd-design`(只用于原型设计构建;前端落地改用 `yss-ui`) |
91
92
  | Codex 原型交接前的视觉 QA | `design-qa`;token / 字体对照读 `references/design-qa-theme.md`,以项目覆盖为准 |
93
+ | Product Design 通用 starter 接入 YSS | `yss-prototype-stage/references/product-design-adapter.md`;锁定 antd@6、pnpm、主题 adapter、feature 级 QA 与证据 |
92
94
  | API 契约 / 接入 | `yss-openapi-governance` / `yss-api-integration` |
93
95
 
94
96
  ## 更新设计系统
@@ -157,7 +157,7 @@ When implementing a page module, the result should usually include:
157
157
 
158
158
  ## Stage 7 Contract
159
159
 
160
- - Require an approved `Slice Implementation Contract`, requirement freeze, low-fidelity review, Ant Design v6 high-fidelity HTML prototype, AntD CLI evidence, user confirmation, and state matrix for UI-impact work.
160
+ - Require an approved `Slice Implementation Contract`, requirement freeze, low-fidelity review, Ant Design v6 theme/visual-standard high-fidelity HTML prototype, schema v2 semantic mapping/browser/accessibility evidence, user confirmation, and state matrix for UI-impact work; production APIs still come from YSS UI + the actual Ant Design Vue 4.x lockfile.
161
161
  - Bind page, hooks, schema, blocks, generated API client, component tests, and E2E paths to contract fields and `allowed_write_paths`.
162
162
  - User-visible loading, empty, error, permission, selection, pagination, and action behavior use `behavior-tdd`; purely mechanical page scaffolding may use documented `controlled-generation`.
163
163
  - Return the shared `YSS Skill Execution Result`. A prototype mismatch, new API, new permission state, path overrun, or missing evidence must produce `drift`, `violation`, or `new_impacts`, not `implemented`.
@@ -31,7 +31,7 @@ Matt 的 `grill-with-docs`、`to-spec`、`to-tickets`、`implement` 等保留为
31
31
  | 入口分诊 `stage.entry-triage` | 身份、影响面、最近可信阶段 | `work-unit.entry-triage`;`yss-product-lifecycle` | `yss-project.yaml` 合法且影响面可解释 |
32
32
  | Discovery `stage.discovery` | Discovery、用户/MVP/非目标/成功标准、测试 seam;命中 DDD 影响时补充领域战略设计与阶段决策包 | `work-unit.discovery-opportunity` + `work-unit.discovery-requirements` + `work-unit.domain-strategy-design` + `work-unit.stage-decision`;市场/竞品事实用 `competitive-intelligence`,技术/标准事实用 `research`;需求澄清用 `grilling`,领域建模用 `domain-modeling` / `yss-stage-decision`;`grill-with-docs` 为兼容入口 | 未决事实已 research 或 handoff,领域边界和统一语言可审查,阶段决策包完成必要批准;`gate.domain-strategy-approved`、`gate.stage-decision-package-approved` |
33
33
  | Spec / 功能架构 `stage.spec-architecture` | Spec、产品总体设计、功能架构;必要时 Spec Delta | 原生 `work-unit.spec-synthesis`;`to-spec` 为兼容入口 | 初稿先为 `ready-for-human`;只有 Spec baseline 会签批准后资产才为 `approved` 并进入下游 |
34
- | 产品设计 `stage.product-design` | 交互说明、低保真、状态矩阵、高保真 HTML、评审记录 | `work-unit.prototype-design`;`yss-design-system` → `prototype-review` → `yss-prototype-stage` → `yss-antd-design`(仅原型事实)→ Codex `product-design:index`(非 Codex 交付等价合同)。前端落地改用 `yss-ui` | `gate.prototype-reviewed`、`gate.prototype-verified`、`gate.user-confirmation` 均有证据 |
34
+ | 产品设计 `stage.product-design` | 交互说明、低保真、状态矩阵、高保真 HTML、评审记录 | `work-unit.prototype-design`;`yss-prototype-stage` 为主合同,依次消费 `yss-design-system`、独立 `prototype-review`、`yss-antd-design` pre-build facts、Codex `product-design:index` focused workflow、post-build/浏览器/无障碍验证(非 Codex 交付等价合同)。前端落地改用 `yss-ui` | `gate.prototype-reviewed`、`gate.prototype-verified`、`gate.user-confirmation` 均有 schema v2 证据 |
35
35
  | 系统 / 数据架构与工程契约 `stage.system-data-engineering` | OpenAPI Draft/Freeze、数据架构、工程基线、架构审查;按领域影响执行 Tactical DDD Check | `work-unit.technical-analysis`;`yss-router` + `yss-openapi-governance` / `yss-openapi-draft-review`、`codebase-design`、`implementation-repo-onboarding`、`yss-tactical-design`;用户或合同明确要求架构可视化时条件追加 `archify` | API/架构契约冻结;无 API 影响有明确记录;战术模型无未解释冲突;脚手架策略满足;Archify 图只作派生审查证据;`gate.openapi-draft-reviewed`、`gate.design-reviewed`、`gate.openapi-frozen`、`gate.engineering-baseline-accepted`、`gate.architecture-reviewed` |
36
36
  | Ticket 正式化 `stage.ticket-formalization` | 功能父 Ticket、垂直切片、Slice Implementation Contract | 原生 `work-unit.ticket-decomposition`;`yss-router`;`to-tickets` 为兼容入口;生命周期复算 | 依赖、验收、测试 seam 可执行;合同已批准、持久化且为当前版本;`gate.slice-contract-approved`、`gate.slice-ready-for-agent` |
37
37
  | 垂直切片实现 `stage.vertical-slice-implementation` | 前端/后端代码、TDD 证据、YSS Skill Execution Result | 原生 `work-unit.slice-implementation`;`yss-router` + `tdd`;前端按 `yss-ui` + `yss-page-module-development`,后端按 Router 最小闭包;`implement` 为兼容入口 | 仅接收已完成 Ticket 正式化、已绑定垂直切片且 `ready-for-agent` 公式通过的输入;只写允许路径;业务行为用 `tdd` 的 `behavior-tdd` 模式;UI 影响必须有还原计划 |
@@ -241,6 +241,10 @@ work_unit_routes:
241
241
  primary_skill: yss-prototype-stage
242
242
  supporting_skills: [prototype-review, yss-design-system, yss-antd-design, product-design:index]
243
243
  skills: [prototype-review, yss-design-system, yss-prototype-stage, yss-antd-design, product-design:index]
244
+ execution_order: [yss-design-system, low-fidelity-assets, prototype-review, yss-antd-design-pre-build, product-design-focused-workflow, yss-antd-design-post-build, browser-design-qa-accessibility, user-confirmation]
245
+ prototype_adapter_ref: .agents/skills/yss-prototype-stage/references/product-design-adapter.md
246
+ evidence_schema_version: 2
247
+ version_boundary: {design_standard: ant-design-v6, prototype_components: react-antd-6.x, production_components: yss-ui-ant-design-vue-4.x, production_version_source: implementation-lockfile}
244
248
  human_gate: prototype-confirmation
245
249
  applies_when: product_design_impact
246
250
  not_applicable_reason: no_ui_or_product_design_impact
@@ -15,11 +15,12 @@ description: Use when a YSS feature has product-design impact on a primary flow,
15
15
 
16
16
  ## 资产与门禁顺序
17
17
 
18
- 1. 以 Spec、产品总体设计和 `docs/design/design.md` 形成交互说明、低保真页面/流程与状态矩阵。
18
+ 1. 以 Spec、产品总体设计、`yss-design-system` 和 `docs/design/design.md` 形成交互说明、低保真页面/流程与状态矩阵。
19
19
  2. 用 `prototype-review` 形成独立评审结论;未通过不得生成高保真或进入需求冻结。
20
- 3. 通过 `product-design:index` 产出 `docs/.scratch/<feature>/design/prototypes/index.html`。
21
- 4. 写入 `docs/.scratch/<feature>/verification/prototype-evidence.yaml`,完成 AntD CLI 与浏览器验证。
22
- 5. 用户确认后,才可校准 Spec、分析 API 影响或进入 Router readiness。
20
+ 3. 用 `yss-antd-design` 固定目标 React `antd@6.x`,先查询 `design.md` 与本功能组件事实。
21
+ 4. 通过 `product-design:index` 的 `get-context → ideate → 用户选择 → image-to-code → design-qa` 产出 feature 级 React/Vite 原型;必须套用 `references/product-design-adapter.md`,不能把通用 starter 视为已符合 YSS。
22
+ 5. 完成 AntD post-build manifest/lint(按产物类型)、同视口 Design QA、浏览器与无障碍验证,写入 schema v2 `docs/.scratch/<feature>/verification/prototype-evidence.yaml`。
23
+ 6. 用户确认后,才可校准 Spec、分析 API 影响或进入 Router readiness。
23
24
 
24
25
  ## 设计与 AntD 依据
25
26
 
@@ -27,11 +28,13 @@ description: Use when a YSS feature has product-design impact on a primary flow,
27
28
 
28
29
  Codex `$design-qa` 仍走官方对比流程;Colors/tokens 与 Fonts/typography 必须以项目覆盖为 source visual truth。对照清单见 `yss-design-system/references/design-qa-theme.md`。仍用官方 `#1677ff`、强制 `Inter` 或历史 8px 品牌圆角当默认主题,视为项目覆盖漂移。
29
30
 
30
- Ant Design v6 事实由 `yss-antd-design` 查询并回写证据,不要并列调用官方 `antd` skill,也不要在前端代码落地时继续使用它。进入实现后改走 `yss-ui`。
31
+ 主题与视觉标准固定为 `ant-design-v6`;生产运行时固定为 Vue 3 + YSS UI + `ant-design-vue-4.x`,精确生产版本来自实现仓 lockfile。版本号不同本身不是冲突。Ant Design v6 事实由 `yss-antd-design` 查询并回写证据,不要并列调用官方 `antd` skill,也不要在前端代码落地时继续使用它。进入实现后改走 `yss-ui`。
32
+
33
+ 标准原型组件存在 Ant Design 实现时必须精确锁定与 CLI 目标一致的 `antd@6.x`,并通过 `ConfigProvider` 消费项目主题 adapter。执行与验证命令见 `references/product-design-adapter.md` 和 `scripts/prototype-contract.mjs`。
31
34
 
32
35
  ## 验证与回流
33
36
 
34
- `browser_verification` 至少覆盖非空渲染、主流程、一个失败/权限/冲突状态、桌面与窄屏视口和控制台错误;优先使用 Browser 或可执行浏览器自动化,Computer Use 只作人工交互补充。把路径、命令、版本、视口、结果和阻塞项写入证据清单。
37
+ `browser_verification` 至少覆盖非空渲染、主流程、一个失败/权限/冲突状态、桌面与窄屏视口和控制台错误;`accessibility_verification` 至少覆盖对比度、键盘/焦点、语义标签与 Dialog、200% zoom、reduced motion、目标尺寸和自动化扫描。优先使用 Browser 或可执行浏览器自动化,Computer Use 只作人工交互补充。把路径、命令、版本、视口、结果和阻塞项写入证据清单。
35
38
 
36
39
  `gate.prototype-reviewed` 的证据是评审记录;`gate.prototype-verified` 的证据是 AntD CLI 与浏览器验证;`gate.user-confirmation` 的证据是确认记录。三者均不是实现授权。
37
40
 
@@ -40,3 +43,5 @@ Ant Design v6 事实由 `yss-antd-design` 查询并回写证据,不要并列
40
43
  - 仅有截图或 HTML,却没有可复现的 CLI、浏览器和确认记录。
41
44
  - 把 `product-design:index` 或某个旧技能当作生命周期批准者。
42
45
  - 直接复制官方默认颜色、圆角或间距,忽略项目覆盖。
46
+ - 只证明查询过 AntD v6,却没有 v6 semantic role → 项目 Token → YSS/AntDV4 的映射证据。
47
+ - 沿用 Product Design starter 的 npm、根目录 `design-qa.md` 或未安装 `antd` 的通用配置。
@@ -0,0 +1,54 @@
1
+ # YSS Product Design Adapter
2
+
3
+ 本合同把 Codex Product Design 的通用 React/Vite 产出接入 YSS 原型阶段。它不修改上游 Product Design skill,也不把 React API 带入 Vue 生产实现。
4
+
5
+ ## 双轨版本
6
+
7
+ - `design_standard: ant-design-v6`:高保真原型的主题、视觉语义、标准组件和 CLI 事实。
8
+ - `runtime_component_library: ant-design-vue-4.x`:生产 Vue/YSS 组件 API;精确版本只从实现仓 lockfile 读取。
9
+ - 标准原型组件存在 Ant Design 实现时,React 原型必须精确锁定与 CLI 查询一致的 `antd@6.x`。YSS 专有布局可用适配 CSS,但仍消费项目 Token。
10
+ - 禁止把 React hook、props、JSX、静态 API 或事件模型作为 Vue/YSS 实现合同。
11
+
12
+ ## 产出前适配
13
+
14
+ 1. 目标目录固定为 `docs/.scratch/<feature>/design/prototypes/`。
15
+ 2. Product Design 完成 `get-context`、三方案 `ideate` 和用户视觉选择后,进入 `image-to-code` 的 local preflight,只执行官方 bootstrap 创建空 starter;在安装依赖或编写 UI 前立即运行 adapter:
16
+
17
+ ```bash
18
+ node .agents/skills/yss-prototype-stage/scripts/prototype-contract.mjs prepare \
19
+ --project-root <project-root> \
20
+ --root <project-root>/docs/.scratch/<feature>/design/prototypes \
21
+ --feature <feature> \
22
+ --target-antd-version <exact-6.x-version> \
23
+ --pnpm-version <actual-pnpm-version>
24
+ ```
25
+
26
+ 3. adapter 只做机械动作:精确写入 `antd` 版本、登记 pnpm、生成 `src/yss-theme.js` 和 `yss-prototype-adapter.json`。随后由 Product Design 将入口包在 `ConfigProvider theme={yssTheme}` 中,并优先使用标准 `antd` 组件。
27
+ 4. 执行 `pnpm install`、`pnpm build`,保留 `pnpm-lock.yaml`、源码入口、构建入口、实际命令与退出码。禁止用 npm lockfile 代替受控例外记录。
28
+ 5. 校验项目:
29
+
30
+ ```bash
31
+ node .agents/skills/yss-prototype-stage/scripts/prototype-contract.mjs validate-project \
32
+ --root <project-root>/docs/.scratch/<feature>/design/prototypes \
33
+ --target-antd-version <exact-6.x-version>
34
+ ```
35
+
36
+ ## 视觉与实现映射
37
+
38
+ 每个关键组件在 `visual_semantic_mapping` 中记录四层映射:Ant Design v6 semantic role、项目 Token、React 原型组件、生产 YSS/Ant Design Vue 目标。映射的是视觉角色、状态和验收行为,不是 React API 表面形状。
39
+
40
+ 至少覆盖主操作、表单输入、表格/列表、反馈、弹层和导航中本功能实际出现的类型。每项记录 `default/hover/active/disabled/loading/error` 等适用状态,并把 `react_only_api_not_copied` 设为 `true` 后才能通过。
41
+
42
+ ## 视口、QA 与无障碍
43
+
44
+ - 默认视觉目标和同状态 QA 使用 desktop `1440x900`、mobile `390x844`;按影响追加 tablet/laptop/wide,不机械要求九个视口。
45
+ - Design QA 报告固定到 `docs/.scratch/<feature>/verification/design-qa.md`,不得写仓库根共享文件。
46
+ - 项目品牌 Seed `#3371ff` 保持不变;普通文本、按钮及状态组合不满足 WCAG 2.2 AA 时,通过组件 Token 调整实际填充或文字色,并保存对比度证据。
47
+ - 验证至少包含键盘、焦点、语义标签/Dialog、200% zoom、reduced motion、目标尺寸和自动化扫描;工具不可用时记录人工替代与未覆盖缺口,不得空填 passed。
48
+
49
+ ## 交互档位
50
+
51
+ - `reviewable-flow`(默认):合同内主路径和关键状态可操作;非范围控件禁用或明确标注,不伪装完整功能。
52
+ - `full-prototype`:brief 明确要求的全部可见范围控件可操作。
53
+
54
+ 不得使用含义冲突的 `static` / `mostly-static` 作为 YSS 交付状态。
@@ -0,0 +1,207 @@
1
+ #!/usr/bin/env node
2
+ import { existsSync } from "node:fs";
3
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
4
+ import path from "node:path";
5
+ import process from "node:process";
6
+ import { fileURLToPath, pathToFileURL } from "node:url";
7
+ import { parseDocument } from "../../../../scripts/vendor/yaml.mjs";
8
+
9
+ const nonEmpty = (value) => typeof value === "string" && value.trim().length > 0;
10
+ const object = (value) => value && typeof value === "object" && !Array.isArray(value);
11
+ const semver = /^6\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z.-]+)?$/;
12
+ const pnpmSemver = /^[0-9]+\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z.-]+)?$/;
13
+
14
+ function required(data, field, parent, errors) {
15
+ if (!object(data) || data[field] === undefined || data[field] === null) errors.push(`${parent}.${field} 缺失`);
16
+ }
17
+
18
+ function requiredString(data, field, parent, errors) {
19
+ required(data, field, parent, errors);
20
+ if (object(data) && data[field] !== undefined && !nonEmpty(data[field])) errors.push(`${parent}.${field} 必须是非空字符串`);
21
+ }
22
+
23
+ function requiredPassed(data, field, parent, errors) {
24
+ requiredString(data, field, parent, errors);
25
+ if (object(data) && nonEmpty(data[field]) && !["passed", "approved"].includes(data[field])) errors.push(`${parent}.${field} 必须为 passed/approved`);
26
+ }
27
+
28
+ export function validatePrototypeEvidence(data, { allowTemplate = false, allowLegacy = false } = {}) {
29
+ const errors = [];
30
+ const warnings = [];
31
+ if (!object(data)) return { errors: ["原型证据必须是对象"], warnings };
32
+ if (data.schema_version === 1) {
33
+ if (!allowLegacy) errors.push("schema_version 1 是旧证据;完成 gate.prototype-verified 前必须迁移到 2,或只读时显式 --allow-legacy");
34
+ else warnings.push("legacy prototype evidence schema v1");
35
+ return { errors, warnings };
36
+ }
37
+ if (data.schema_version !== 2) errors.push("schema_version 必须为 2");
38
+ for (const field of ["feature", "prototype_ref", "prototype_stack", "design_baseline", "visual_semantic_mapping", "antd", "browser_verification", "design_qa", "accessibility_verification", "review", "user_confirmation", "blockers"]) required(data, field, "root", errors);
39
+
40
+ const templateValue = (value) => allowTemplate && nonEmpty(value) && /<[^>]+>/.test(value);
41
+ const stack = data.prototype_stack;
42
+ if (object(stack)) {
43
+ for (const field of ["framework", "package_manager", "package_manifest_ref", "lockfile_ref", "source_entry_ref", "build_entry_ref", "build_command", "build_result", "actual_antd_version"]) requiredString(stack, field, "prototype_stack", errors);
44
+ if (stack.framework !== "react") errors.push("prototype_stack.framework 必须为 react");
45
+ if (stack.package_manager !== "pnpm") errors.push("prototype_stack.package_manager 必须为 pnpm");
46
+ if (nonEmpty(stack.lockfile_ref) && !stack.lockfile_ref.endsWith("pnpm-lock.yaml")) errors.push("prototype_stack.lockfile_ref 必须指向 pnpm-lock.yaml");
47
+ if (!templateValue(stack.actual_antd_version) && nonEmpty(stack.actual_antd_version) && !semver.test(stack.actual_antd_version)) errors.push("prototype_stack.actual_antd_version 必须是明确的 antd 6.x semver");
48
+ if (!allowTemplate) requiredPassed(stack, "build_result", "prototype_stack", errors);
49
+ }
50
+
51
+ const baseline = data.design_baseline;
52
+ if (object(baseline)) {
53
+ for (const field of ["design_standard", "project_design_ref", "project_token_refs", "theme_adapter_ref", "project_override_reviewed"]) required(baseline, field, "design_baseline", errors);
54
+ if (baseline.design_standard !== "ant-design-v6") errors.push("design_baseline.design_standard 必须为 ant-design-v6");
55
+ if (!Array.isArray(baseline.project_token_refs) || baseline.project_token_refs.length === 0) errors.push("design_baseline.project_token_refs 必须是非空数组");
56
+ if (!allowTemplate && baseline.project_override_reviewed !== true) errors.push("design_baseline.project_override_reviewed 必须为 true");
57
+ }
58
+
59
+ const mapping = data.visual_semantic_mapping;
60
+ if (object(mapping)) {
61
+ if (mapping.runtime_component_library !== "ant-design-vue-4.x") errors.push("visual_semantic_mapping.runtime_component_library 必须为 ant-design-vue-4.x");
62
+ if (mapping.runtime_version_source !== "implementation-lockfile") errors.push("visual_semantic_mapping.runtime_version_source 必须为 implementation-lockfile");
63
+ if (!Array.isArray(mapping.components) || mapping.components.length === 0) errors.push("visual_semantic_mapping.components 必须是非空数组");
64
+ for (const [index, component] of (mapping.components ?? []).entries()) {
65
+ const parent = `visual_semantic_mapping.components[${index}]`;
66
+ for (const field of ["semantic_role", "antd_v6_component", "project_token_refs", "yss_or_antdv_target", "state_mapping", "react_only_api_not_copied", "verification_ref"]) required(component, field, parent, errors);
67
+ if (!Array.isArray(component?.project_token_refs) || component.project_token_refs.length === 0) errors.push(`${parent}.project_token_refs 必须是非空数组`);
68
+ if (!Array.isArray(component?.state_mapping) || component.state_mapping.length === 0) errors.push(`${parent}.state_mapping 必须是非空数组`);
69
+ if (!allowTemplate && component?.react_only_api_not_copied !== true) errors.push(`${parent}.React-only API 未确认隔离`);
70
+ }
71
+ }
72
+
73
+ if (object(data.antd)) {
74
+ requiredString(data.antd, "target_antd_version", "antd", errors);
75
+ if (object(stack) && nonEmpty(data.antd.target_antd_version) && nonEmpty(stack.actual_antd_version) && !templateValue(data.antd.target_antd_version) && data.antd.target_antd_version !== stack.actual_antd_version) errors.push("antd.target_antd_version 必须与 prototype_stack.actual_antd_version 一致");
76
+ }
77
+ if (object(data.design_qa)) {
78
+ requiredString(data.design_qa, "report_ref", "design_qa", errors);
79
+ requiredString(data.design_qa, "result", "design_qa", errors);
80
+ if (nonEmpty(data.design_qa.report_ref) && !/^docs\/\.scratch\/[^/]+\/verification\/design-qa\.md$/.test(data.design_qa.report_ref) && !templateValue(data.design_qa.report_ref)) errors.push("design_qa.report_ref 必须是 feature 级 verification/design-qa.md");
81
+ if (!allowTemplate) requiredPassed(data.design_qa, "result", "design_qa", errors);
82
+ }
83
+ const accessibility = data.accessibility_verification;
84
+ if (object(accessibility)) {
85
+ for (const field of ["contrast_results_ref", "keyboard_navigation_result", "focus_visible_and_order_result", "semantic_label_dialog_result", "zoom_200_result", "reduced_motion_result", "target_size_result", "automated_scan"]) required(accessibility, field, "accessibility_verification", errors);
86
+ requiredString(accessibility, "contrast_results_ref", "accessibility_verification", errors);
87
+ if (!allowTemplate) for (const field of ["keyboard_navigation_result", "focus_visible_and_order_result", "semantic_label_dialog_result", "zoom_200_result", "reduced_motion_result", "target_size_result"]) requiredPassed(accessibility, field, "accessibility_verification", errors);
88
+ if (object(accessibility.automated_scan)) for (const field of ["tool", "version", "result", "ref"]) requiredString(accessibility.automated_scan, field, "accessibility_verification.automated_scan", errors);
89
+ }
90
+ if (!Array.isArray(data.blockers)) errors.push("root.blockers 必须是数组");
91
+ if (!allowTemplate && Array.isArray(data.blockers) && data.blockers.length > 0) errors.push("存在 blockers,不能通过原型验证");
92
+ return { errors, warnings };
93
+ }
94
+
95
+ function safePrototypeRoot(projectRoot, root, feature) {
96
+ const resolvedProject = path.resolve(projectRoot);
97
+ const resolvedRoot = path.resolve(root);
98
+ const expected = path.resolve(resolvedProject, "docs/.scratch", feature, "design/prototypes");
99
+ if (resolvedRoot !== expected) throw new TypeError(`原型目录必须精确匹配 ${expected}`);
100
+ if (!resolvedRoot.startsWith(`${resolvedProject}${path.sep}`)) throw new TypeError("原型目录越出项目根");
101
+ return { resolvedProject, resolvedRoot };
102
+ }
103
+
104
+ export async function preparePrototype({ projectRoot, root, feature, targetAntdVersion, pnpmVersion }) {
105
+ if (!/^[a-z0-9][a-z0-9-]*$/.test(feature ?? "")) throw new TypeError("feature 必须是小写 kebab-case");
106
+ if (!semver.test(targetAntdVersion ?? "")) throw new TypeError("targetAntdVersion 必须是明确的 antd 6.x semver");
107
+ if (!pnpmSemver.test(pnpmVersion ?? "")) throw new TypeError("pnpmVersion 必须是明确 semver");
108
+ const { resolvedProject, resolvedRoot } = safePrototypeRoot(projectRoot, root, feature);
109
+ const packagePath = path.join(resolvedRoot, "package.json");
110
+ if (!existsSync(packagePath)) throw new TypeError(`缺少 Product Design starter package.json: ${packagePath}`);
111
+ const pkg = JSON.parse(await readFile(packagePath, "utf8"));
112
+ pkg.packageManager = `pnpm@${pnpmVersion}`;
113
+ pkg.dependencies = { ...(pkg.dependencies ?? {}), "@ant-design/icons": "^6.0.0", antd: targetAntdVersion };
114
+ await writeFile(packagePath, `${JSON.stringify(pkg, null, 2)}\n`);
115
+
116
+ const themeSourcePath = path.join(resolvedProject, "docs/design/tokens/theme.json");
117
+ if (!existsSync(themeSourcePath)) throw new TypeError(`缺少项目主题: ${themeSourcePath}`);
118
+ const themeSource = JSON.parse(await readFile(themeSourcePath, "utf8"));
119
+ const generated = [
120
+ 'import { theme } from "antd";',
121
+ "",
122
+ `const source = ${JSON.stringify(themeSource, null, 2)};`,
123
+ 'const layoutKeys = new Set(["layoutHeaderHeight", "layoutSiderBackground", "layoutBodyBackground"]);',
124
+ "export const yssLayoutTokens = Object.fromEntries(Object.entries(source.token ?? {}).filter(([key]) => layoutKeys.has(key)));",
125
+ "export const yssTheme = {",
126
+ " algorithm: [theme.defaultAlgorithm, theme.compactAlgorithm],",
127
+ " token: Object.fromEntries(Object.entries(source.token ?? {}).filter(([key]) => !layoutKeys.has(key)))",
128
+ "};",
129
+ ""
130
+ ].join("\n");
131
+ await mkdir(path.join(resolvedRoot, "src"), { recursive: true });
132
+ await writeFile(path.join(resolvedRoot, "src/yss-theme.js"), generated);
133
+ const manifest = {
134
+ schema_version: 1,
135
+ feature,
136
+ design_standard: "ant-design-v6",
137
+ target_antd_version: targetAntdVersion,
138
+ prototype_framework: "react",
139
+ package_manager: `pnpm@${pnpmVersion}`,
140
+ theme_source: "docs/design/tokens/theme.json",
141
+ theme_adapter: `docs/.scratch/${feature}/design/prototypes/src/yss-theme.js`,
142
+ production_runtime: { framework: "vue-3", component_library: "ant-design-vue-4.x", version_source: "implementation-lockfile" },
143
+ next_commands: ["pnpm install", "pnpm build"]
144
+ };
145
+ await writeFile(path.join(resolvedRoot, "yss-prototype-adapter.json"), `${JSON.stringify(manifest, null, 2)}\n`);
146
+ return manifest;
147
+ }
148
+
149
+ export async function validatePrototypeProject({ root, targetAntdVersion }) {
150
+ const errors = [];
151
+ const packagePath = path.join(root, "package.json");
152
+ if (!existsSync(packagePath)) return { errors: ["缺少 package.json"] };
153
+ const pkg = JSON.parse(await readFile(packagePath, "utf8"));
154
+ if (pkg.dependencies?.antd !== targetAntdVersion) errors.push(`package.json 必须精确锁定 antd ${targetAntdVersion}`);
155
+ if (!String(pkg.packageManager ?? "").startsWith("pnpm@")) errors.push("package.json 必须记录实际 pnpm packageManager");
156
+ if (!existsSync(path.join(root, "pnpm-lock.yaml"))) errors.push("缺少 pnpm-lock.yaml");
157
+ if (!existsSync(path.join(root, "src/yss-theme.js"))) errors.push("缺少 src/yss-theme.js");
158
+ const sourceFiles = ["src/App.jsx", "src/App.tsx", "src/main.jsx", "src/main.tsx"].filter((file) => existsSync(path.join(root, file)));
159
+ const source = (await Promise.all(sourceFiles.map((file) => readFile(path.join(root, file), "utf8")))).join("\n");
160
+ if (!/ConfigProvider/.test(source) || !/yssTheme/.test(source)) errors.push("原型入口必须通过 ConfigProvider 消费 yssTheme");
161
+ if (!existsSync(path.join(root, "yss-prototype-adapter.json"))) errors.push("缺少 yss-prototype-adapter.json");
162
+ return { errors };
163
+ }
164
+
165
+ function args(argv) {
166
+ const result = { _: [] };
167
+ for (let index = 0; index < argv.length; index += 1) {
168
+ const item = argv[index];
169
+ if (!item.startsWith("--")) { result._.push(item); continue; }
170
+ const key = item.slice(2);
171
+ const value = argv[index + 1];
172
+ if (!value || value.startsWith("--")) result[key] = true;
173
+ else { result[key] = value; index += 1; }
174
+ }
175
+ return result;
176
+ }
177
+
178
+ async function loadYaml(file) {
179
+ const document = parseDocument(await readFile(file, "utf8"), { uniqueKeys: true });
180
+ if (document.errors.length > 0) throw new TypeError(document.errors[0].message);
181
+ return document.toJS({ maxAliasCount: 0 });
182
+ }
183
+
184
+ async function main(argv) {
185
+ const parsed = args(argv);
186
+ const command = parsed._[0];
187
+ if (command === "prepare") {
188
+ const result = await preparePrototype({ projectRoot: parsed["project-root"], root: parsed.root, feature: parsed.feature, targetAntdVersion: parsed["target-antd-version"], pnpmVersion: parsed["pnpm-version"] });
189
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
190
+ return;
191
+ }
192
+ if (command === "validate-project") {
193
+ const result = await validatePrototypeProject({ root: parsed.root, targetAntdVersion: parsed["target-antd-version"] });
194
+ if (result.errors.length > 0) throw new TypeError(result.errors.join("\n"));
195
+ process.stdout.write("prototype project contract passed\n");
196
+ return;
197
+ }
198
+ if (command === "validate-evidence") {
199
+ const result = validatePrototypeEvidence(await loadYaml(parsed._[1]), { allowTemplate: Boolean(parsed["allow-template"]), allowLegacy: Boolean(parsed["allow-legacy"]) });
200
+ if (result.errors.length > 0) throw new TypeError(result.errors.join("\n"));
201
+ process.stdout.write(`prototype evidence passed${result.warnings.length ? ` with warnings: ${result.warnings.join(", ")}` : ""}\n`);
202
+ return;
203
+ }
204
+ throw new TypeError("usage: prototype-contract.mjs prepare|validate-project|validate-evidence ...");
205
+ }
206
+
207
+ if (import.meta.url === pathToFileURL(process.argv[1]).href) main(process.argv.slice(2)).catch((error) => { process.stderr.write(`${error.message}\n`); process.exitCode = 1; });
@@ -0,0 +1,154 @@
1
+ #!/usr/bin/env node
2
+ import assert from "node:assert/strict";
3
+ import { mkdtemp, mkdir, readFile, writeFile } from "node:fs/promises";
4
+ import os from "node:os";
5
+ import path from "node:path";
6
+ import {
7
+ preparePrototype,
8
+ validatePrototypeEvidence,
9
+ validatePrototypeProject
10
+ } from "../scripts/prototype-contract.mjs";
11
+
12
+ const tempRoot = await mkdtemp(path.join(os.tmpdir(), "yss-prototype-contract-"));
13
+ const projectRoot = path.join(tempRoot, "project");
14
+ const feature = "order-review";
15
+ const prototypeRoot = path.join(projectRoot, "docs/.scratch", feature, "design/prototypes");
16
+ await mkdir(path.join(prototypeRoot, "src"), { recursive: true });
17
+ await mkdir(path.join(projectRoot, "docs/design/tokens"), { recursive: true });
18
+ await writeFile(path.join(prototypeRoot, "package.json"), JSON.stringify({
19
+ name: "order-review-prototype",
20
+ private: true,
21
+ type: "module",
22
+ scripts: { build: "vite build" },
23
+ dependencies: { react: "19.2.0", "react-dom": "19.2.0", vite: "6.4.2" }
24
+ }, null, 2));
25
+ await writeFile(path.join(projectRoot, "docs/design/tokens/theme.json"), JSON.stringify({
26
+ algorithm: "default",
27
+ token: {
28
+ colorPrimary: "#3371ff",
29
+ borderRadius: 6,
30
+ controlHeight: 32,
31
+ layoutHeaderHeight: 64
32
+ }
33
+ }, null, 2));
34
+
35
+ const before = await validatePrototypeProject({ root: prototypeRoot, targetAntdVersion: "6.6.2" });
36
+ assert(before.errors.some((message) => message.includes("antd")), "RED: starter without antd must fail");
37
+ assert(before.errors.some((message) => message.includes("pnpm-lock.yaml")), "RED: missing pnpm lockfile must fail");
38
+
39
+ await preparePrototype({ projectRoot, root: prototypeRoot, feature, targetAntdVersion: "6.6.2", pnpmVersion: "10.15.0" });
40
+ const pkg = JSON.parse(await readFile(path.join(prototypeRoot, "package.json"), "utf8"));
41
+ assert.equal(pkg.dependencies.antd, "6.6.2");
42
+ assert.equal(pkg.packageManager, "pnpm@10.15.0");
43
+ assert.match(await readFile(path.join(prototypeRoot, "src/yss-theme.js"), "utf8"), /compactAlgorithm/);
44
+
45
+ await writeFile(path.join(prototypeRoot, "pnpm-lock.yaml"), "lockfileVersion: '9.0'\n");
46
+ await writeFile(path.join(prototypeRoot, "src/App.jsx"), [
47
+ 'import { ConfigProvider, Button } from "antd";',
48
+ 'import { yssTheme } from "./yss-theme.js";',
49
+ 'export function App() { return <ConfigProvider theme={yssTheme}><Button type="primary">提交</Button></ConfigProvider>; }'
50
+ ].join("\n"));
51
+ const after = await validatePrototypeProject({ root: prototypeRoot, targetAntdVersion: "6.6.2" });
52
+ assert.deepEqual(after.errors, []);
53
+
54
+ const wrongTarget = await validatePrototypeProject({ root: prototypeRoot, targetAntdVersion: "6.6.1" });
55
+ assert(wrongTarget.errors.some((message) => message.includes("精确锁定 antd 6.6.1")), "target 与实际 antd 版本不一致必须失败");
56
+
57
+ const npmPackage = structuredClone(pkg);
58
+ npmPackage.packageManager = "npm@11.0.0";
59
+ await writeFile(path.join(prototypeRoot, "package.json"), JSON.stringify(npmPackage, null, 2));
60
+ const npmProject = await validatePrototypeProject({ root: prototypeRoot, targetAntdVersion: "6.6.2" });
61
+ assert(npmProject.errors.some((message) => message.includes("packageManager")), "原型包管理器漂移到 npm 必须失败");
62
+ await writeFile(path.join(prototypeRoot, "package.json"), JSON.stringify(pkg, null, 2));
63
+
64
+ await assert.rejects(
65
+ preparePrototype({
66
+ projectRoot,
67
+ root: path.join(projectRoot, "prototypes", feature),
68
+ feature,
69
+ targetAntdVersion: "6.6.2",
70
+ pnpmVersion: "10.15.0"
71
+ }),
72
+ /docs\/.scratch/,
73
+ "非标准原型目录必须被拒绝"
74
+ );
75
+
76
+ const validEvidence = {
77
+ schema_version: 2,
78
+ feature,
79
+ prototype_ref: `docs/.scratch/${feature}/design/prototypes/index.html`,
80
+ prototype_stack: {
81
+ framework: "react",
82
+ package_manager: "pnpm",
83
+ package_manifest_ref: `docs/.scratch/${feature}/design/prototypes/package.json`,
84
+ lockfile_ref: `docs/.scratch/${feature}/design/prototypes/pnpm-lock.yaml`,
85
+ source_entry_ref: `docs/.scratch/${feature}/design/prototypes/src/App.jsx`,
86
+ build_entry_ref: `docs/.scratch/${feature}/design/prototypes/dist/index.html`,
87
+ build_command: "pnpm build",
88
+ build_result: "passed",
89
+ actual_antd_version: "6.6.2"
90
+ },
91
+ design_baseline: {
92
+ design_standard: "ant-design-v6",
93
+ project_design_ref: "docs/design/design.md",
94
+ project_token_refs: ["docs/design/tokens/theme.json"],
95
+ theme_adapter_ref: `docs/.scratch/${feature}/design/prototypes/src/yss-theme.js`,
96
+ project_override_reviewed: true
97
+ },
98
+ visual_semantic_mapping: {
99
+ runtime_component_library: "ant-design-vue-4.x",
100
+ runtime_version_source: "implementation-lockfile",
101
+ components: [{
102
+ semantic_role: "primary-action",
103
+ antd_v6_component: "Button",
104
+ project_token_refs: ["colorPrimary"],
105
+ yss_or_antdv_target: "YButton",
106
+ state_mapping: ["default", "hover", "active", "disabled", "loading"],
107
+ react_only_api_not_copied: true,
108
+ verification_ref: "verification/button-states.png"
109
+ }]
110
+ },
111
+ antd: { target_antd_version: "6.6.2", queries: { design_md: "verification/antd-design.json", components: [] } },
112
+ browser_verification: { rendered_nonblank: true, viewports: [], main_flow_result: "passed", failure_permission_or_conflict_result: "passed", console_error_ref: "verification/console.txt" },
113
+ design_qa: { report_ref: `docs/.scratch/${feature}/verification/design-qa.md`, result: "passed" },
114
+ accessibility_verification: {
115
+ contrast_results_ref: "verification/contrast.json",
116
+ keyboard_navigation_result: "passed",
117
+ focus_visible_and_order_result: "passed",
118
+ semantic_label_dialog_result: "passed",
119
+ zoom_200_result: "passed",
120
+ reduced_motion_result: "passed",
121
+ target_size_result: "passed",
122
+ automated_scan: { tool: "axe", version: "4", result: "passed", ref: "verification/axe.json" }
123
+ },
124
+ review: { prototype_review_ref: "design/review.md", result: "approved" },
125
+ user_confirmation: { confirmation_ref: "design/confirmation.md", result: "approved" },
126
+ blockers: []
127
+ };
128
+ assert.deepEqual(validatePrototypeEvidence(validEvidence).errors, []);
129
+
130
+ const missingMapping = structuredClone(validEvidence);
131
+ delete missingMapping.visual_semantic_mapping;
132
+ assert(validatePrototypeEvidence(missingMapping).errors.some((message) => message.includes("visual_semantic_mapping")));
133
+
134
+ const copiedReactApi = structuredClone(validEvidence);
135
+ copiedReactApi.visual_semantic_mapping.components[0].react_only_api_not_copied = false;
136
+ assert(validatePrototypeEvidence(copiedReactApi).errors.some((message) => message.includes("React-only")));
137
+
138
+ const inaccessible = structuredClone(validEvidence);
139
+ inaccessible.accessibility_verification.contrast_results_ref = "";
140
+ assert(validatePrototypeEvidence(inaccessible).errors.some((message) => message.includes("contrast_results_ref")));
141
+
142
+ const wrongQaRoot = structuredClone(validEvidence);
143
+ wrongQaRoot.design_qa.report_ref = "docs/design/design-qa.md";
144
+ assert(validatePrototypeEvidence(wrongQaRoot).errors.some((message) => message.includes("design_qa.report_ref")));
145
+
146
+ const versionMismatch = structuredClone(validEvidence);
147
+ versionMismatch.antd.target_antd_version = "6.6.1";
148
+ assert(validatePrototypeEvidence(versionMismatch).errors.some((message) => message.includes("target_antd_version")));
149
+
150
+ const unresolvedBlocker = structuredClone(validEvidence);
151
+ unresolvedBlocker.blockers = ["缺少权限失败态"];
152
+ assert(validatePrototypeEvidence(unresolvedBlocker).errors.some((message) => message.includes("blockers")));
153
+
154
+ process.stdout.write("YSS prototype contract scenarios passed\n");
@@ -15,7 +15,7 @@ Use this reference when multiple YSS skills seem applicable.
15
15
  - `yss-use-table-height`: Only table available-height calculation and required container/pagination/toolbar wiring.
16
16
  - `yss-use-tree-height`: Only tree available-height calculation, search offset, and virtual scrolling wiring.
17
17
 
18
- Default for a new page: first verify the approved product design, state matrix, Ant Design v6 high-fidelity HTML prototype, AntD CLI evidence, and user confirmation; then start with `yss-page-module-development` and add the narrow skills that match the page controls.
18
+ Default for a new page: first verify the approved product design, state matrix, Ant Design v6 theme/visual-standard high-fidelity HTML prototype, schema v2 semantic mapping/browser/accessibility evidence, and user confirmation; then use the implementation lockfile to map into YSS UI + Ant Design Vue 4.x, start with `yss-page-module-development`, and add the narrow skills that match the page controls.
19
19
 
20
20
  中文说明:新建页面默认从页面模块技能开始,只有遇到具体组件、Hook、API、Formily 细节时再加载专项技能。
21
21
 
@@ -32,7 +32,7 @@ pnpm why vue @yss-ui/components @yss-ui/hooks ant-design-vue vxe-table
32
32
 
33
33
  ## Ant Design v6 边界
34
34
 
35
- Ant Design v6 可以作为产品原型的视觉和 token 语义参考;Vue 生产实现使用 Ant Design Vue 4.x。禁止复制 React hooks、JSX、组件 props、theme algorithm API 或事件模型到 Vue 代码。
35
+ Ant Design v6 是产品原型默认的主题样式、视觉和 token 语义标准;Vue 生产实现使用 Ant Design Vue 4.x。版本号不同本身不是冲突。生产映射必须消费原型证据中的 `visual_semantic_mapping`,并用实现仓 lockfile/类型验证 YSS 或 AntDV 目标;禁止复制 React hooks、JSX、组件 props、theme algorithm API 或事件模型到 Vue 代码。
36
36
 
37
37
  ## 兼容性证据
38
38
 
@@ -17,7 +17,7 @@ Create skills that add useful, non-obvious guidance without constraining unrelat
17
17
  6. Follow the repository's declared maintenance and review policy. If none exists, run structural validation plus focused checks of the behavior or invariant changed. Use independent forward testing only when complexity or risk makes it meaningful; do not require a failing baseline for every ordinary edit.
18
18
  7. After changes, validate frontmatter, naming, references, scripts, projections, locks, and affected callers. Retire obsolete names and resources unless the repository explicitly requires compatibility.
19
19
  8. When a repository declares staged template verification, default the implementation loop to its fast impact profile and stop at `implementation-ready`. Promote explicitly to `review-ready`; do not create frozen candidates, review packages, or release evidence during ordinary iteration. Unknown paths and changes to the verification framework itself must fail safe to the full profile.
20
- 9. For a formal L3 review, run the repository's full gate before the first frozen candidate and again before release. Between them, use focused/candidate checks. Do not weaken required evidence or independent review to gain speed.
20
+ 9. For L3 template maintenance, record maintainer self-check plus fresh verification and do not create a frozen candidate or formal independent review during ordinary iteration. Before release, run the repository's full `scripts/verify-template` gate once; historical formal-review records remain read-only compatible.
21
21
 
22
22
  ## Boundaries
23
23