openyida 2026.9.21 → 2026.9.22-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (334) hide show
  1. package/README.md +14 -20
  2. package/bin/yida.js +6 -11
  3. package/lib/app/app-list.js +3 -7
  4. package/lib/app/canvas-compile.js +12 -22
  5. package/lib/app/check-prd-completeness.js +0 -7
  6. package/lib/app/create-app.js +1 -4
  7. package/lib/app/create-form/args.js +12 -37
  8. package/lib/app/create-form/batch.js +11 -86
  9. package/lib/app/create-form.js +86 -193
  10. package/lib/app/create-page.js +17 -84
  11. package/lib/app/custom-theme.js +0 -11
  12. package/lib/app/form-field-validator.js +41 -26
  13. package/lib/app/form-open-guard.js +10 -97
  14. package/lib/app/get-form-config.js +0 -1
  15. package/lib/app/inline-css-guard.js +31 -1
  16. package/lib/app/services/form-compiler.js +4 -2
  17. package/lib/app/theme-from-design.js +41 -144
  18. package/lib/app/theme-presets.js +1 -1
  19. package/lib/app/update-app.js +13 -63
  20. package/lib/asset/ai-image.js +9 -59
  21. package/lib/asset/asset-cmd.js +7 -18
  22. package/lib/asset/asset-plan.js +9 -102
  23. package/lib/asset/asset-resolve.js +10 -55
  24. package/lib/asset/asset-status.js +4 -5
  25. package/lib/asset/host-capabilities.js +2 -11
  26. package/lib/asset/url-verify.js +4 -19
  27. package/lib/auth/dws-sync.js +145 -0
  28. package/lib/auth/token-auth.js +73 -9
  29. package/lib/auth/token-store.js +50 -0
  30. package/lib/connector/connector-test.js +5 -19
  31. package/lib/connector/contract.js +1 -3
  32. package/lib/core/agent-capabilities.js +16 -19
  33. package/lib/core/command-manifest.js +40 -329
  34. package/lib/core/locales/en.js +17 -74
  35. package/lib/core/locales/zh.js +16 -73
  36. package/lib/core/redact.js +10 -15
  37. package/lib/core/sample.js +30 -72
  38. package/lib/core/utils.js +4 -0
  39. package/lib/design-plan/design-plan.js +4 -51
  40. package/lib/design-plan/init.js +26 -121
  41. package/lib/design-plan/materialize.js +348 -451
  42. package/lib/design-plan/normalize.js +29 -74
  43. package/lib/design-plan/parallel.js +16 -71
  44. package/lib/design-plan/patch.js +16 -63
  45. package/lib/design-plan/preview.js +8 -6
  46. package/lib/design-plan/validate.js +11 -71
  47. package/lib/process/create-process.js +50 -84
  48. package/lib/samples/openyida-scaffold/canvas-form-drawer.canvas.jsx +90 -20
  49. package/lib/samples/openyida-scaffold/canvas-nav/content.jsx +13 -93
  50. package/lib/samples/openyida-scaffold/canvas-nav/data.jsx +18 -100
  51. package/lib/samples/openyida-scaffold/canvas-nav/mixed.jsx +4 -6
  52. package/lib/samples/openyida-scaffold/canvas-nav/shared.jsx +5 -5
  53. package/lib/samples/openyida-scaffold/canvas-nav/side.jsx +2 -1
  54. package/lib/samples/openyida-scaffold/canvas-nav/sidebar.jsx +1 -1
  55. package/lib/samples/openyida-scaffold/canvas-nav/top.jsx +9 -15
  56. package/lib/samples/yida-canvas-table-form/table-form-batch-submit.canvas.jsx +83 -9
  57. package/lib/samples/yida-rechart/trend-combo.canvas.jsx +87 -14
  58. package/package.json +1 -3
  59. package/scripts/postinstall.js +3 -3
  60. package/yida-skills/SKILL.md +16 -19
  61. package/yida-skills/references/official-example-schema-patterns.md +1 -1
  62. package/yida-skills/references/yida-api.md +0 -4
  63. package/yida-skills/skills/yida-app/SKILL.md +23 -46
  64. package/yida-skills/skills/yida-app/workflow/parallel-work.md +6 -15
  65. package/yida-skills/skills/yida-app/workflow/plan/step-1-understand.md +1 -1
  66. package/yida-skills/skills/yida-app/workflow/plan/step-2-confirm.md +1 -1
  67. package/yida-skills/skills/yida-app/workflow/plan/step-4-deliver.md +15 -29
  68. package/yida-skills/skills/yida-app/workflow/plan/workflow.md +11 -29
  69. package/yida-skills/skills/yida-app/workflow/step-1-resource-context.md +2 -4
  70. package/yida-skills/skills/yida-app/workflow/step-2-design.md +9 -23
  71. package/yida-skills/skills/yida-app/workflow/step-3-create-or-reuse-app.md +4 -6
  72. package/yida-skills/skills/yida-app/workflow/step-4-forms-processes.md +4 -15
  73. package/yida-skills/skills/yida-app/workflow/step-6-main-page.md +4 -6
  74. package/yida-skills/skills/yida-app/workflow/step-7-page-code.md +9 -15
  75. package/yida-skills/skills/yida-app/workflow/step-8-publish-navigation.md +11 -25
  76. package/yida-skills/skills/yida-app/workflow/step-9-output-finish.md +28 -68
  77. package/yida-skills/skills/yida-canvas-custom-page/SKILL.md +43 -42
  78. package/yida-skills/skills/yida-canvas-custom-page/references/canvas-style-implementation-guide.md +44 -60
  79. package/yida-skills/skills/yida-canvas-custom-page/references/canvas-theme-provider.md +50 -72
  80. package/yida-skills/skills/yida-canvas-custom-page/references/component-library-guide.md +1 -13
  81. package/yida-skills/skills/yida-canvas-custom-page/references/data-bridge-guide.md +1 -140
  82. package/yida-skills/skills/yida-canvas-custom-page/references/navigation-and-entry-guide.md +72 -101
  83. package/yida-skills/skills/yida-canvas-custom-page/references/page-generation-guide.md +32 -35
  84. package/yida-skills/skills/yida-canvas-custom-page/scripts/build-canvas-theme.js +3 -29
  85. package/yida-skills/skills/yida-canvas-custom-page/scripts/canvas-theme-provider.template.jsx +6 -69
  86. package/yida-skills/skills/yida-canvas-data-binding/SKILL.md +0 -26
  87. package/yida-skills/skills/yida-create-app/SKILL.md +0 -2
  88. package/yida-skills/skills/yida-create-form-page/SKILL.md +58 -72
  89. package/yida-skills/skills/yida-create-form-page/references/advanced-form-modes.md +5 -5
  90. package/yida-skills/skills/yida-create-form-page/references/association-form-field.md +4 -4
  91. package/yida-skills/skills/yida-create-form-page/references/batch-forms.md +5 -6
  92. package/yida-skills/skills/yida-create-form-page/references/field-definition-guide.md +19 -7
  93. package/yida-skills/skills/yida-create-form-page/references/form-field-properties.md +44 -62
  94. package/yida-skills/skills/yida-create-page/SKILL.md +6 -14
  95. package/yida-skills/skills/yida-create-process/SKILL.md +2 -13
  96. package/yida-skills/skills/yida-custom-page/SKILL.md +0 -2
  97. package/yida-skills/skills/yida-custom-page/references/design-system.md +1 -1
  98. package/yida-skills/skills/yida-dashboard/SKILL.md +4 -5
  99. package/yida-skills/skills/yida-data-management/SKILL.md +2 -4
  100. package/yida-skills/skills/yida-data-management/references/data-format-guide.md +4 -4
  101. package/yida-skills/skills/yida-design/SKILL.md +14 -29
  102. package/yida-skills/skills/yida-design/references/app/blueprint.md +70 -0
  103. package/yida-skills/skills/yida-design/references/app/navigation-patterns.md +43 -0
  104. package/yida-skills/skills/yida-design/references/app/role-journey.md +30 -0
  105. package/yida-skills/skills/yida-design/references/ask-human-interaction-contract.md +42 -67
  106. package/yida-skills/skills/yida-design/references/asset-workflow.md +2 -6
  107. package/yida-skills/skills/yida-design/references/design-mode.md +4 -4
  108. package/yida-skills/skills/yida-design/references/page-quality-gates.md +38 -26
  109. package/yida-skills/skills/yida-design/references/style-design-selection.md +137 -0
  110. package/yida-skills/skills/yida-design/references/style-designs/_design-md-template.md +185 -0
  111. package/yida-skills/skills/yida-design/references/style-designs/aqua-service-progress-dashboard.md +242 -0
  112. package/yida-skills/skills/yida-design/references/style-designs/blue-insight-operations-dashboard.md +243 -0
  113. package/yida-skills/skills/yida-design/references/style-designs/blue-productivity-insight-workbench.md +242 -0
  114. package/yida-skills/skills/yida-design/references/style-designs/command-filter-card-console.md +304 -0
  115. package/yida-skills/skills/yida-design/references/style-designs/contrast-command-analytics-workbench.md +261 -0
  116. package/yida-skills/skills/yida-design/references/style-designs/dark-stage-analytic-dashboard.md +369 -0
  117. package/yida-skills/skills/yida-design/references/style-designs/filterable-card-catalog.md +354 -0
  118. package/yida-skills/skills/yida-design/references/style-designs/green-timeline-progress-workbench.md +250 -0
  119. package/yida-skills/skills/yida-design/references/style-designs/registry.md +117 -0
  120. package/yida-skills/skills/yida-design/references/style-designs/soft-analytic-workbench.md +348 -0
  121. package/yida-skills/skills/yida-design/references/style-designs/soft-blue-grid-analytic-dashboard.md +658 -0
  122. package/yida-skills/skills/yida-design/references/style-designs/soft-bordered-analytic-workbench.md +385 -0
  123. package/yida-skills/skills/yida-design/references/style-designs/soft-curated-filter-gallery.md +300 -0
  124. package/yida-skills/skills/yida-design/references/style-designs/soft-modular-analytic-workbench.md +404 -0
  125. package/yida-skills/skills/yida-design/references/style-designs/soft-progress-analytics-workbench.md +382 -0
  126. package/yida-skills/skills/yida-design/references/style-designs/soft-timeline-analytics-workbench.md +367 -0
  127. package/yida-skills/skills/yida-design/references/style-designs/teal-rail-analytics-workbench.md +341 -0
  128. package/yida-skills/skills/yida-design/references/theme/app-custom-theme-template.css +432 -350
  129. package/yida-skills/skills/yida-design/references/visual-decision-engine.md +143 -19
  130. package/yida-skills/skills/yida-design/references/visual-scaffold-recipes.md +27 -15
  131. package/yida-skills/skills/yida-design/sub_skill/page-design/SKILL.md +0 -4
  132. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/SKILL.md +8 -22
  133. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/assets/README.md +10 -14
  134. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/assets/build-plan-template.html +4 -9
  135. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/references/build-plan-compact-schema.md +27 -49
  136. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/references/build-plan-schema.md +154 -33
  137. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/references/visual-design.md +127 -48
  138. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/references/visual-theme-selection.md +51 -37
  139. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/scripts/render_build_plan.py +48 -43
  140. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/scripts/validate_design_themes.py +190 -0
  141. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/README.md +98 -0
  142. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/airy-media-grid.md +339 -0
  143. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/airy-modular-clarity.md +348 -0
  144. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/airy-structured-clarity.md +344 -0
  145. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/ambient-halo-layered.md +345 -0
  146. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/dark-focus-layered.md +355 -0
  147. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/dark-luminous-modular.md +377 -0
  148. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/deep-stage-duotone.md +352 -0
  149. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/hairline-runway-clarity.md +389 -0
  150. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/high-contrast-modular.md +364 -0
  151. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/index.json +329 -0
  152. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/interlocked-vivid-modules.md +348 -0
  153. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/matrix-grid-focus.md +345 -0
  154. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/media-rail-inspector.md +379 -0
  155. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/mist-layered-signal.md +347 -0
  156. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/modular-rail-signal.md +352 -0
  157. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/mono-grid-signal.md +386 -0
  158. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/ribbon-ledger-lift.md +384 -0
  159. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/segmented-meter-clarity.md +388 -0
  160. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/split-rail-precision.md +341 -0
  161. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/status-framed-media-grid.md +361 -0
  162. package/yida-skills/skills/yida-design/workflow/output-design.md +375 -117
  163. package/yida-skills/skills/yida-design/workflow/output-prd.md +185 -0
  164. package/yida-skills/skills/yida-design/workflow/step-1-read-brief.md +1 -1
  165. package/yida-skills/skills/yida-design/workflow/step-2-theme-system.md +29 -33
  166. package/yida-skills/skills/yida-design/workflow/step-4-wireframe-interaction.md +1 -3
  167. package/yida-skills/skills/yida-design/workflow/step-5-visual-states.md +106 -22
  168. package/yida-skills/skills/yida-design/workflow/step-6-handoff.md +22 -15
  169. package/yida-skills/skills/yida-form-permission/SKILL.md +0 -6
  170. package/yida-skills/skills/yida-image-assets/SKILL.md +50 -73
  171. package/yida-skills/skills/yida-image-assets/references/manifest-contract.md +52 -82
  172. package/yida-skills/skills/yida-image-assets/references/source-policy.md +15 -14
  173. package/yida-skills/skills/yida-integration/SKILL.md +0 -1
  174. package/yida-skills/skills/yida-login/SKILL.md +0 -2
  175. package/yida-skills/skills/yida-nav-group/SKILL.md +2 -4
  176. package/yida-skills/skills/yida-nav-shell/SKILL.md +12 -36
  177. package/yida-skills/skills/yida-nav-shell/references/nav-shell-patterns.md +136 -79
  178. package/yida-skills/skills/yida-page-config/SKILL.md +4 -13
  179. package/yida-skills/skills/yida-prd/SKILL.md +3 -5
  180. package/yida-skills/skills/yida-prd/references/app/blueprint.md +4 -4
  181. package/yida-skills/skills/yida-prd/references/app/navigation-patterns.md +3 -6
  182. package/yida-skills/skills/yida-prd/references/app/role-journey.md +3 -5
  183. package/yida-skills/skills/yida-prd/references/plan-content.md +0 -4
  184. package/yida-skills/skills/yida-prd/workflow/output-prd.md +11 -18
  185. package/yida-skills/skills/yida-prd/workflow/plan-business.md +4 -4
  186. package/yida-skills/skills/yida-prd/workflow/step-2-information-architecture.md +8 -11
  187. package/yida-skills/skills/yida-publish-page/SKILL.md +1 -9
  188. package/yida-skills/skills/yida-requirement-analysis/SKILL.md +39 -10
  189. package/yida-skills/skills/yida-requirement-analysis/workflow/prepare-brief.md +71 -40
  190. package/yida-skills/skills-index.json +16 -36
  191. package/lib/app/application-entry-urls.js +0 -31
  192. package/lib/app/application-style.js +0 -69
  193. package/lib/app/canvas-icon-exports.json +0 -6160
  194. package/lib/app/canvas-icon-guard.js +0 -87
  195. package/lib/app/canvas-navigation-guard.js +0 -84
  196. package/lib/app/canvas-path-guard.js +0 -78
  197. package/lib/app/canvas-theme-guard.js +0 -184
  198. package/lib/app/form-data-response-guard.js +0 -57
  199. package/lib/asset/asset-execution.js +0 -79
  200. package/lib/core/css-structure.js +0 -37
  201. package/lib/design/check-design.js +0 -51
  202. package/lib/design/document.js +0 -458
  203. package/lib/design/icon-contrast.js +0 -85
  204. package/lib/design/page-content.js +0 -11
  205. package/lib/design-plan/artifact-updates.js +0 -117
  206. package/lib/design-plan/confirmation.js +0 -13
  207. package/lib/design-plan/entry-navigation.js +0 -97
  208. package/lib/design-plan/navigation-policy.js +0 -38
  209. package/lib/design-plan/rebase.js +0 -60
  210. package/lib/design-plan/themes.js +0 -101
  211. package/lib/design-plan/visual-policy.js +0 -42
  212. package/lib/samples/openyida-scaffold/canvas-admin-entry.jsx +0 -62
  213. package/lib/samples/openyida-scaffold/canvas-navigation.jsx +0 -56
  214. package/lib/samples/openyida-scaffold/canvas-view-state.jsx +0 -74
  215. package/yida-skills/skills/yida-app/references/entry-navigation.md +0 -193
  216. package/yida-skills/skills/yida-canvas-custom-page/references/view-state-recovery.md +0 -52
  217. package/yida-skills/skills/yida-canvas-data-binding/references/business-action-permissions.md +0 -31
  218. package/yida-skills/skills/yida-design/references/application-style-library.md +0 -93
  219. package/yida-skills/skills/yida-design/references/application-theme-consistency.md +0 -150
  220. package/yida-skills/skills/yida-design/references/native-form-styles.md +0 -208
  221. package/yida-skills/skills/yida-design/references/navigation-decision.md +0 -53
  222. package/yida-skills/skills/yida-design/references/page-continuity.md +0 -42
  223. package/yida-skills/skills/yida-design/references/theme/application-style-recipes.css +0 -58
  224. package/yida-skills/skills/yida-design/references/theme-selection.md +0 -67
  225. package/yida-skills/skills/yida-design/scripts/validate_design_themes.py +0 -302
  226. package/yida-skills/skills/yida-design/templates/application-styles.json +0 -398
  227. package/yida-skills/skills/yida-design/templates/design-themes/README.md +0 -73
  228. package/yida-skills/skills/yida-design/templates/design-themes/app-amber/app_theme.css +0 -748
  229. package/yida-skills/skills/yida-design/templates/design-themes/app-amber/design.md +0 -274
  230. package/yida-skills/skills/yida-design/templates/design-themes/app-amber/form-layout.json +0 -15
  231. package/yida-skills/skills/yida-design/templates/design-themes/app-editorial/app_theme.css +0 -748
  232. package/yida-skills/skills/yida-design/templates/design-themes/app-editorial/design.md +0 -274
  233. package/yida-skills/skills/yida-design/templates/design-themes/app-editorial/form-layout.json +0 -14
  234. package/yida-skills/skills/yida-design/templates/design-themes/app-executive/app_theme.css +0 -748
  235. package/yida-skills/skills/yida-design/templates/design-themes/app-executive/design.md +0 -274
  236. package/yida-skills/skills/yida-design/templates/design-themes/app-executive/form-layout.json +0 -13
  237. package/yida-skills/skills/yida-design/templates/design-themes/app-finance/app_theme.css +0 -748
  238. package/yida-skills/skills/yida-design/templates/design-themes/app-finance/design.md +0 -274
  239. package/yida-skills/skills/yida-design/templates/design-themes/app-finance/form-layout.json +0 -14
  240. package/yida-skills/skills/yida-design/templates/design-themes/app-glass/app_theme.css +0 -748
  241. package/yida-skills/skills/yida-design/templates/design-themes/app-glass/design.md +0 -274
  242. package/yida-skills/skills/yida-design/templates/design-themes/app-glass/form-layout.json +0 -14
  243. package/yida-skills/skills/yida-design/templates/design-themes/app-graphite/app_theme.css +0 -748
  244. package/yida-skills/skills/yida-design/templates/design-themes/app-graphite/design.md +0 -274
  245. package/yida-skills/skills/yida-design/templates/design-themes/app-graphite/form-layout.json +0 -14
  246. package/yida-skills/skills/yida-design/templates/design-themes/app-line/app_theme.css +0 -748
  247. package/yida-skills/skills/yida-design/templates/design-themes/app-line/design.md +0 -274
  248. package/yida-skills/skills/yida-design/templates/design-themes/app-line/form-layout.json +0 -13
  249. package/yida-skills/skills/yida-design/templates/design-themes/app-neon/app_theme.css +0 -748
  250. package/yida-skills/skills/yida-design/templates/design-themes/app-neon/design.md +0 -274
  251. package/yida-skills/skills/yida-design/templates/design-themes/app-neon/form-layout.json +0 -14
  252. package/yida-skills/skills/yida-design/templates/design-themes/app-nordic/app_theme.css +0 -754
  253. package/yida-skills/skills/yida-design/templates/design-themes/app-nordic/design.md +0 -279
  254. package/yida-skills/skills/yida-design/templates/design-themes/app-nordic/form-layout.json +0 -13
  255. package/yida-skills/skills/yida-design/templates/design-themes/app-paper/app_theme.css +0 -748
  256. package/yida-skills/skills/yida-design/templates/design-themes/app-paper/design.md +0 -274
  257. package/yida-skills/skills/yida-design/templates/design-themes/app-paper/form-layout.json +0 -13
  258. package/yida-skills/skills/yida-design/templates/design-themes/app-platinum/app_theme.css +0 -748
  259. package/yida-skills/skills/yida-design/templates/design-themes/app-platinum/design.md +0 -274
  260. package/yida-skills/skills/yida-design/templates/design-themes/app-platinum/form-layout.json +0 -14
  261. package/yida-skills/skills/yida-design/templates/design-themes/app-plum/app_theme.css +0 -748
  262. package/yida-skills/skills/yida-design/templates/design-themes/app-plum/design.md +0 -274
  263. package/yida-skills/skills/yida-design/templates/design-themes/app-plum/form-layout.json +0 -14
  264. package/yida-skills/skills/yida-design/templates/design-themes/app-pop/app_theme.css +0 -758
  265. package/yida-skills/skills/yida-design/templates/design-themes/app-pop/design.md +0 -281
  266. package/yida-skills/skills/yida-design/templates/design-themes/app-pop/form-layout.json +0 -14
  267. package/yida-skills/skills/yida-design/templates/design-themes/app-sage/app_theme.css +0 -748
  268. package/yida-skills/skills/yida-design/templates/design-themes/app-sage/design.md +0 -274
  269. package/yida-skills/skills/yida-design/templates/design-themes/app-sage/form-layout.json +0 -14
  270. package/yida-skills/skills/yida-design/templates/design-themes/app-teal/app_theme.css +0 -748
  271. package/yida-skills/skills/yida-design/templates/design-themes/app-teal/design.md +0 -274
  272. package/yida-skills/skills/yida-design/templates/design-themes/app-teal/form-layout.json +0 -14
  273. package/yida-skills/skills/yida-design/templates/design-themes/app-terminal/app_theme.css +0 -754
  274. package/yida-skills/skills/yida-design/templates/design-themes/app-terminal/design.md +0 -279
  275. package/yida-skills/skills/yida-design/templates/design-themes/app-terminal/form-layout.json +0 -14
  276. package/yida-skills/skills/yida-design/templates/design-themes/app-ticket/app_theme.css +0 -752
  277. package/yida-skills/skills/yida-design/templates/design-themes/app-ticket/design.md +0 -278
  278. package/yida-skills/skills/yida-design/templates/design-themes/app-ticket/form-layout.json +0 -13
  279. package/yida-skills/skills/yida-design/templates/design-themes/app-wire/app_theme.css +0 -748
  280. package/yida-skills/skills/yida-design/templates/design-themes/app-wire/design.md +0 -274
  281. package/yida-skills/skills/yida-design/templates/design-themes/app-wire/form-layout.json +0 -14
  282. package/yida-skills/skills/yida-design/templates/design-themes/basic-tokens.json +0 -118
  283. package/yida-skills/skills/yida-design/templates/design-themes/dark-inset-hairline/app_theme.css +0 -690
  284. package/yida-skills/skills/yida-design/templates/design-themes/dark-inset-hairline/design.md +0 -382
  285. package/yida-skills/skills/yida-design/templates/design-themes/dark-inset-hairline/form-layout.json +0 -13
  286. package/yida-skills/skills/yida-design/templates/design-themes/dark-rail-fine-lines/app_theme.css +0 -691
  287. package/yida-skills/skills/yida-design/templates/design-themes/dark-rail-fine-lines/design.md +0 -380
  288. package/yida-skills/skills/yida-design/templates/design-themes/dark-rail-fine-lines/form-layout.json +0 -13
  289. package/yida-skills/skills/yida-design/templates/design-themes/dark-rail-signal-panels/app_theme.css +0 -696
  290. package/yida-skills/skills/yida-design/templates/design-themes/dark-rail-signal-panels/design.md +0 -378
  291. package/yida-skills/skills/yida-design/templates/design-themes/dark-rail-signal-panels/form-layout.json +0 -13
  292. package/yida-skills/skills/yida-design/templates/design-themes/free-creative/app_theme.css +0 -689
  293. package/yida-skills/skills/yida-design/templates/design-themes/free-creative/design.md +0 -238
  294. package/yida-skills/skills/yida-design/templates/design-themes/free-creative/form-layout.json +0 -13
  295. package/yida-skills/skills/yida-design/templates/design-themes/graphite-bevel-grid/app_theme.css +0 -692
  296. package/yida-skills/skills/yida-design/templates/design-themes/graphite-bevel-grid/design.md +0 -375
  297. package/yida-skills/skills/yida-design/templates/design-themes/graphite-bevel-grid/form-layout.json +0 -13
  298. package/yida-skills/skills/yida-design/templates/design-themes/hairline-shared-bands/app_theme.css +0 -691
  299. package/yida-skills/skills/yida-design/templates/design-themes/hairline-shared-bands/design.md +0 -362
  300. package/yida-skills/skills/yida-design/templates/design-themes/hairline-shared-bands/form-layout.json +0 -13
  301. package/yida-skills/skills/yida-design/templates/design-themes/hairline-soft-blocks/app_theme.css +0 -691
  302. package/yida-skills/skills/yida-design/templates/design-themes/hairline-soft-blocks/design.md +0 -409
  303. package/yida-skills/skills/yida-design/templates/design-themes/hairline-soft-blocks/form-layout.json +0 -13
  304. package/yida-skills/skills/yida-design/templates/design-themes/index.json +0 -464
  305. package/yida-skills/skills/yida-design/templates/design-themes/ink-glow-soft-panels/app_theme.css +0 -701
  306. package/yida-skills/skills/yida-design/templates/design-themes/ink-glow-soft-panels/design.md +0 -379
  307. package/yida-skills/skills/yida-design/templates/design-themes/ink-glow-soft-panels/form-layout.json +0 -13
  308. package/yida-skills/skills/yida-design/templates/design-themes/inset-frame-pixel-rhythm/app_theme.css +0 -691
  309. package/yida-skills/skills/yida-design/templates/design-themes/inset-frame-pixel-rhythm/design.md +0 -404
  310. package/yida-skills/skills/yida-design/templates/design-themes/inset-frame-pixel-rhythm/form-layout.json +0 -13
  311. package/yida-skills/skills/yida-design/templates/design-themes/outlined-texture-duotone/app_theme.css +0 -698
  312. package/yida-skills/skills/yida-design/templates/design-themes/outlined-texture-duotone/design.md +0 -389
  313. package/yida-skills/skills/yida-design/templates/design-themes/outlined-texture-duotone/form-layout.json +0 -13
  314. package/yida-skills/skills/yida-design/templates/design-themes/soft-inset-surfaces/app_theme.css +0 -691
  315. package/yida-skills/skills/yida-design/templates/design-themes/soft-inset-surfaces/design.md +0 -372
  316. package/yida-skills/skills/yida-design/templates/design-themes/soft-inset-surfaces/form-layout.json +0 -13
  317. package/yida-skills/skills/yida-design/templates/design-themes/soft-outline-rhythm/app_theme.css +0 -690
  318. package/yida-skills/skills/yida-design/templates/design-themes/soft-outline-rhythm/design.md +0 -455
  319. package/yida-skills/skills/yida-design/templates/design-themes/soft-outline-rhythm/form-layout.json +0 -13
  320. package/yida-skills/skills/yida-design/templates/design-themes/soft-rail-bold-band/app_theme.css +0 -698
  321. package/yida-skills/skills/yida-design/templates/design-themes/soft-rail-bold-band/design.md +0 -394
  322. package/yida-skills/skills/yida-design/templates/design-themes/soft-rail-bold-band/form-layout.json +0 -13
  323. package/yida-skills/skills/yida-design/templates/design-themes/soft-spectral-panels/app_theme.css +0 -692
  324. package/yida-skills/skills/yida-design/templates/design-themes/soft-spectral-panels/design.md +0 -391
  325. package/yida-skills/skills/yida-design/templates/design-themes/soft-spectral-panels/form-layout.json +0 -13
  326. package/yida-skills/skills/yida-design/templates/design-themes/warm-canvas-contrast-panels/app_theme.css +0 -711
  327. package/yida-skills/skills/yida-design/templates/design-themes/warm-canvas-contrast-panels/design.md +0 -408
  328. package/yida-skills/skills/yida-design/templates/design-themes/warm-canvas-contrast-panels/form-layout.json +0 -13
  329. package/yida-skills/skills/yida-design/templates/design-themes/warm-rail-muted-panels/app_theme.css +0 -692
  330. package/yida-skills/skills/yida-design/templates/design-themes/warm-rail-muted-panels/design.md +0 -383
  331. package/yida-skills/skills/yida-design/templates/design-themes/warm-rail-muted-panels/form-layout.json +0 -13
  332. package/yida-skills/skills/yida-design/templates/navigation-styles.json +0 -769
  333. package/yida-skills/skills/yida-requirement-analysis/references/experience-groups.md +0 -79
  334. package/yida-skills/skills/yida-requirement-analysis/references/handoff.md +0 -68
@@ -1,458 +0,0 @@
1
- 'use strict';
2
-
3
- const yaml = require('js-yaml');
4
- const path = require('path');
5
- const fs = require('fs');
6
- const { CliError } = require('../core/cli-error');
7
- const { t } = require('../core/i18n');
8
- const { concretePageText } = require('./page-content');
9
- const { validateIconContrast } = require('./icon-contrast');
10
- const CONTRACT = require('../../yida-skills/skills/yida-design/templates/design-themes/basic-tokens.json');
11
-
12
- const HEADINGS = ['1. 风格摘要', '2. 页面视觉系统', '3. 基础组件表达', '4. 特色表达配方', '5. 项目应用与调整规则'];
13
- const PAGE_LABELS = ['页面任务', '首屏焦点', '布局', '表面与组件', '主操作', '状态', '响应式', '验收'];
14
- const BRAND_TOKENS = [1, 2, 3, 5, 6, 9, 10].map(n => `--color-brand1-${n}`);
15
- const TOKEN_NAME = /^--[a-zA-Z_][\w-]*$/;
16
- const ANCHOR = /^#[a-zA-Z][\w.:-]*$/;
17
- const REFERENCE_KEY = /^[\p{L}\p{N}_-]+$/u;
18
- const object = value => value !== null && typeof value === 'object' && !Array.isArray(value);
19
- const nonempty = value => typeof value === 'string' && value.trim().length > 0;
20
-
21
- function invalid(field, code, details = {}) {
22
- throw new CliError(t('design_document.invalid', field, code), {
23
- code: 'DESIGN_DOCUMENT_INVALID', details: { field, issue: code, ...details },
24
- });
25
- }
26
-
27
- function jsonValue(value, field = 'metadata', active = new Set(), visited = new Set(), depth = 0) {
28
- if (depth > 128) {invalid(field, 'MAX_DEPTH');}
29
- if (value === null || ['string', 'boolean'].includes(typeof value)) {return;}
30
- if (typeof value === 'number' && Number.isFinite(value)) {return;}
31
- if (!object(value) && !Array.isArray(value)) {invalid(field, 'JSON_VALUE_REQUIRED');}
32
- if (active.has(value)) {invalid(field, 'CYCLIC_ALIAS');}
33
- if (visited.has(value)) {return;}
34
- if (!Array.isArray(value) && ![Object.prototype, null].includes(Object.getPrototypeOf(value))) {
35
- invalid(field, 'PLAIN_MAPPING_REQUIRED');
36
- }
37
- active.add(value);
38
- for (const [key, child] of Object.entries(value)) {
39
- if (['__proto__', 'constructor', 'prototype'].includes(key)) {invalid(`${field}.${key}`, 'UNSAFE_KEY');}
40
- jsonValue(child, `${field}.${key}`, active, visited, depth + 1);
41
- }
42
- active.delete(value);
43
- visited.add(value);
44
- }
45
-
46
- function parseDesignDocument(markdown, options = {}) {
47
- if (typeof markdown !== 'string') {invalid('document', 'STRING_REQUIRED');}
48
- const match = /^\uFEFF?---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/.exec(markdown);
49
- if (!match) {invalid('frontmatter', 'FRONTMATTER_REQUIRED');}
50
- let metadata;
51
- try {
52
- const load = source => yaml.load(source, { schema: yaml.JSON_SCHEMA, json: false });
53
- metadata = load(match[1]);
54
- // Historical Fast files allowed bare HEX tokens. Opt in only for consumers
55
- // reading unversioned files; final document validation always uses real YAML.
56
- if (options.legacyTokenValues === true && object(metadata)
57
- && !Object.prototype.hasOwnProperty.call(metadata, 'schemaVersion')) {
58
- const compatible = match[1].replace(/^(\s*["']?--[\w-]+["']?\s*:\s*)(#[\da-f]{3,8})([ \t]*(?:#.*)?)$/gmi,
59
- (line, prefix, color, comment) => `${prefix}${JSON.stringify(color)}${comment}`);
60
- if (compatible !== match[1]) {metadata = load(compatible);}
61
- }
62
- } catch (error) {
63
- throw new CliError(t('design_document.yaml'), {
64
- code: 'DESIGN_DOCUMENT_INVALID', details: { field: 'frontmatter', issue: 'INVALID_YAML', reason: error.reason || error.message },
65
- });
66
- }
67
- if (!object(metadata)) {invalid('frontmatter', 'MAPPING_REQUIRED');}
68
- jsonValue(metadata);
69
- return { metadata, body: markdown.slice(match[0].length).replace(/\r\n/g, '\n') };
70
- }
71
-
72
- function serializeDesignDocument(metadata, body) {
73
- if (body === undefined && object(metadata) && object(metadata.metadata) && typeof metadata.body === 'string') {
74
- ({ metadata, body } = metadata);
75
- }
76
- if (!object(metadata) || typeof body !== 'string') {invalid('document', 'METADATA_AND_BODY_REQUIRED');}
77
- jsonValue(metadata);
78
- const lines = ['---'];
79
- const keyText = key => /^[a-zA-Z_][\w-]*$/.test(key) ? key : JSON.stringify(key);
80
- function tokenLines(node, indent) {
81
- return Object.entries(node).map(([key, value]) => {
82
- const prefix = `${' '.repeat(indent)}${keyText(key)}:`;
83
- return object(value) && Object.keys(value).length
84
- ? `${prefix}\n${tokenLines(value, indent + 2).join('\n')}`
85
- : `${prefix} ${JSON.stringify(value)}`;
86
- });
87
- }
88
- for (const [key, value] of Object.entries(metadata)) {
89
- if (key === 'tokens' && object(value) && Object.keys(value).length) {
90
- lines.push('tokens:', ...tokenLines(value, 2));
91
- } else {
92
- // JSON is a YAML subset and keeps names and arbitrary user text safely quoted.
93
- // assetStrategy deliberately remains one line for existing stored documents.
94
- lines.push(`${keyText(key)}: ${JSON.stringify(value)}`);
95
- }
96
- }
97
- lines.push('---', '', body.trim(), '');
98
- return lines.join('\n');
99
- }
100
-
101
- function cssValue(name, raw) {
102
- const value = typeof raw === 'number' && Number.isFinite(raw) ? String(raw) : raw;
103
- if (!TOKEN_NAME.test(name) || typeof value !== 'string' || !value.trim()
104
- || /[;{}\r\n<>]|\/\*|\*\//.test(value) || /^[|>]/.test(value)
105
- || /(?:javascript|data|vbscript|file|blob)\s*:/i.test(value)) {
106
- throw new CliError(t('design_document.token_value', name), { code: 'DESIGN_THEME_TOKEN_INVALID', details: { token: name } });
107
- }
108
- if (['--pod-app-root-bg-color', '--pod-page-bg-color', '--pod-card-bg-color'].includes(name)
109
- && /(?:gradient|url)\s*\(/i.test(value)) {
110
- invalid(name, 'COLOR_CANNOT_BE_IMAGE');
111
- }
112
- let quote = '';
113
- let depth = 0;
114
- for (let index = 0; index < value.length; index++) {
115
- const char = value[index];
116
- if (char === '\\') {index++; continue;}
117
- if (quote) {if (char === quote) {quote = '';} continue;}
118
- if (char === '"' || char === "'") {quote = char;}
119
- else if (char === '(') {depth++;}
120
- else if (char === ')' && --depth < 0) {invalid(name, 'UNBALANCED_CSS_VALUE');}
121
- }
122
- if (quote || depth) {invalid(name, 'UNBALANCED_CSS_VALUE');}
123
- return value;
124
- }
125
-
126
- function flattenTokens(node, target, field, strict) {
127
- if (!object(node)) {invalid(field, 'TOKEN_MAPPING_REQUIRED');}
128
- for (const [key, value] of Object.entries(node)) {
129
- if (key.startsWith('--')) {
130
- const scalar = cssValue(key, value);
131
- if (Object.prototype.hasOwnProperty.call(target, key) && (strict || target[key] !== scalar)) {
132
- throw new CliError(t('design_document.token_conflict', key), { code: 'DESIGN_THEME_TOKEN_CONFLICT', details: { token: key } });
133
- }
134
- if (/^--color-brand1-(4|7|8)$/.test(key)) {invalid(key, 'UNSUPPORTED_BRAND_TOKEN');}
135
- target[key] = scalar;
136
- } else {
137
- flattenTokens(value, target, `${field}.${key}`, strict);
138
- }
139
- }
140
- }
141
-
142
- function validateTokenReferences(tokens) {
143
- const dependencies = new Map(Object.entries(tokens).map(([name, value]) => [name, [...value.matchAll(/var\(\s*(--[\w-]+)/g)].map(match => match[1])]));
144
- for (const [name, refs] of dependencies) {
145
- for (const ref of refs) {
146
- if (!(ref in tokens)) {invalid(name, 'UNDECLARED_TOKEN_REFERENCE', { reference: ref });}
147
- }
148
- }
149
- const active = new Set();
150
- const visited = new Set();
151
- function visit(name) {
152
- if (active.has(name)) {invalid(name, 'TOKEN_REFERENCE_CYCLE');}
153
- if (visited.has(name)) {return;}
154
- active.add(name);
155
- for (const ref of dependencies.get(name)) {visit(ref);}
156
- active.delete(name);
157
- visited.add(name);
158
- }
159
- for (const name of dependencies.keys()) {visit(name);}
160
- }
161
-
162
- function extractDesignTokens(metadata, options = {}) {
163
- const strict = options.strict === true;
164
- if (!object(metadata) || !object(metadata.tokens)) {
165
- throw new CliError(t('design_document.tokens_required'), { code: 'DESIGN_THEME_TOKENS_REQUIRED' });
166
- }
167
- jsonValue(metadata.tokens, 'tokens');
168
- const tokens = {};
169
- if (strict) {
170
- if (Object.keys(metadata.tokens).length !== 2 || !object(metadata.tokens['application-global']) || !object(metadata.tokens['custom-page'])) {
171
- invalid('tokens', 'GLOBAL_AND_CUSTOM_SCOPES_REQUIRED');
172
- }
173
- const globals = metadata.tokens['application-global'];
174
- if (Object.keys(globals).sort().join('|') !== Object.keys(CONTRACT.groups).sort().join('|')) {
175
- invalid('tokens.application-global', 'SIX_GLOBAL_GROUPS_REQUIRED');
176
- }
177
- for (const [group, expected] of Object.entries(CONTRACT.groups)) {
178
- const values = {};
179
- flattenTokens(globals[group], values, `tokens.application-global.${group}`, true);
180
- const otherGroups = Object.entries(CONTRACT.groups).filter(([name]) => name !== group).flatMap(([, names]) => names);
181
- if (expected.some(name => !(name in values)) || otherGroups.some(name => name in values)) {
182
- invalid(`tokens.application-global.${group}`, 'GLOBAL_TOKEN_SET_MISMATCH', { expected });
183
- }
184
- }
185
- for (const scope of ['application-global', 'custom-page']) {
186
- flattenTokens(metadata.tokens[scope], tokens, `tokens.${scope}`, true);
187
- }
188
- for (const name of ['--color-white', '--pod-table-cell-color', '--color-fill1-10', '--color-text1-5']) {
189
- if (tokens[name] !== CONTRACT.fixedValues[name]) {invalid(name, 'FIXED_PLATFORM_VALUE', { expected: CONTRACT.fixedValues[name] });}
190
- }
191
- // Both metadata groups are emitted into the application's :root. Shared
192
- // project tokens can back platform roles; only missing/cyclic refs are invalid.
193
- validateTokenReferences(tokens);
194
- } else {
195
- flattenTokens(metadata.tokens, tokens, 'tokens', false);
196
- }
197
- const missing = BRAND_TOKENS.filter(name => !tokens[name]);
198
- if (missing.length) {
199
- throw new CliError(t('design_document.brand_required', missing.join(', ')), {
200
- code: 'DESIGN_THEME_TOKENS_REQUIRED', details: { missing },
201
- });
202
- }
203
- validateIconContrast(metadata.iconSystem, tokens);
204
- return tokens;
205
- }
206
-
207
- // Strip fenced examples before interpreting document headings, anchors or labels.
208
- function structuralLines(body) {
209
- const lines = body.split('\n');
210
- let fence = null;
211
- return lines.map(line => {
212
- const open = /^ {0,3}(`{3,}|~{3,})(.*)$/.exec(line);
213
- if (!fence && open) {fence = open[1]; return '';}
214
- if (fence) {
215
- if (new RegExp(`^ {0,3}${fence[0]}{${fence.length},}\\s*$`).test(line)) {fence = null;}
216
- return '';
217
- }
218
- return line;
219
- });
220
- }
221
-
222
- function documentAnchors(body) {
223
- const text = structuralLines(body).join('\n');
224
- const anchors = new Map();
225
- for (const match of text.matchAll(/<a\s+id=(?:"([^"]+)"|'([^']+)')\s*>\s*<\/a>/g)) {
226
- const id = '#' + (match[1] || match[2]);
227
- if (!ANCHOR.test(id)) {invalid('body', 'INVALID_ANCHOR', { anchor: id });}
228
- if (anchors.has(id)) {invalid('body', 'DUPLICATE_ANCHOR', { anchor: id });}
229
- anchors.set(id, match.index);
230
- }
231
- return { text, anchors };
232
- }
233
-
234
- function inlineValue(value) {
235
- const text = value.trim();
236
- const code = /^(`+)([^`]*)\1$/.exec(text);
237
- return code ? code[2].trim() : text;
238
- }
239
-
240
- function fastPrdPages(prdMarkdown) {
241
- const lines = structuralLines(prdMarkdown);
242
- const starts = lines.map((line, index) => /^## 4\. 页面与功能设计\s*$/.test(line) ? index : -1).filter(index => index >= 0);
243
- if (starts.length !== 1) {invalid('prd', 'ONE_STRUCTURED_HANDOFF_REQUIRED', { count: 0 });}
244
- const end = lines.findIndex((line, index) => index > starts[0] && /^## /.test(line));
245
- const section = lines.slice(starts[0] + 1, end < 0 ? undefined : end);
246
- const headings = section.map((line, index) => /^### /.test(line) ? index : -1).filter(index => index >= 0);
247
- const pages = [];
248
- for (let index = 0; index < headings.length; index++) {
249
- const entries = section.slice(headings[index] + 1, headings[index + 1]).flatMap(line => {
250
- const match = /^([ \t]*)[-*+]\s+(.+?)[::][ \t]*(.*?)\s*$/.exec(line);
251
- return match ? [{ indent: match[1].replace(/\t/g, ' ').length, key: inlineValue(match[2]).replace(/^\*\*|\*\*$/g, ''), value: match[3] }] : [];
252
- });
253
- if (!entries.length) {continue;}
254
- const topIndent = Math.min(...entries.map(entry => entry.indent));
255
- const top = entries.filter(entry => entry.indent === topIndent);
256
- const field = (records, key) => {
257
- const matches = records.filter(entry => entry.key === key);
258
- if (matches.length > 1) {invalid(`prd.${key}`, 'DUPLICATE_PRD_FIELD');}
259
- return matches[0];
260
- };
261
- if (inlineValue(field(top, '页面类型')?.value || '') !== 'display-page') {continue;}
262
- const pageId = inlineValue(field(top, 'pageId')?.value || '');
263
- const parent = field(top, 'pageSpecHandoff');
264
- if (!parent) {invalid(`prd.pages.${pageId}.pageSpecHandoff`, 'PAGE_HANDOFF_REQUIRED');}
265
- const following = entries.slice(entries.indexOf(parent) + 1);
266
- const nextTop = following.findIndex(entry => entry.indent <= topIndent);
267
- const children = following.slice(0, nextTop < 0 ? undefined : nextTop);
268
- const childIndent = Math.min(...children.map(entry => entry.indent));
269
- const direct = children.filter(entry => entry.indent === childIndent);
270
- const designFile = inlineValue(field(direct, 'designFile')?.value || '');
271
- const rawRefs = inlineValue(field(direct, 'designRefs')?.value || '');
272
- let designRefs;
273
- if (rawRefs.startsWith('[')) {
274
- try {designRefs = JSON.parse(rawRefs);} catch {invalid('prd.designRefs', 'INVALID_DESIGN_REFERENCE');}
275
- } else {
276
- designRefs = rawRefs ? rawRefs.split(/[/、,,]/).map(inlineValue) : [];
277
- }
278
- pages.push({ pageId, pageSpecHandoff: { designFile, designRefs } });
279
- }
280
- return pages;
281
- }
282
-
283
- function prdHandoffPages(prdMarkdown) {
284
- const candidates = [];
285
- const lines = prdMarkdown.replace(/\r\n/g, '\n').split('\n');
286
- const declared = structuralLines(prdMarkdown).some(line => /^#{2,6} (?:\d+\.\s*)?结构化交接\s*$/.test(line));
287
- let fence;
288
- let content = [];
289
- for (const line of lines) {
290
- const start = /^ {0,3}(`{3,}|~{3,})(.*)$/.exec(line);
291
- if (!fence && start) {fence = { marker: start[1], info: start[2].trim() }; content = []; continue;}
292
- if (!fence) {continue;}
293
- if (!new RegExp(`^ {0,3}${fence.marker[0]}{${fence.marker.length},}\\s*$`).test(line)) {content.push(line); continue;}
294
- if (fence.info === 'json') {
295
- const source = content.join('\n');
296
- let value;
297
- try {value = JSON.parse(source);} catch {
298
- if (declared || /"pages"\s*:/.test(source) && /"(?:appConfig|resourceBlueprint)"\s*:/.test(source)) {
299
- invalid('prd', 'INVALID_STRUCTURED_HANDOFF');
300
- }
301
- }
302
- if (object(value) && 'pages' in value && ('appConfig' in value || 'resourceBlueprint' in value)) {
303
- if (!Array.isArray(value.pages) || !(object(value.appConfig) || Array.isArray(value.resourceBlueprint))) {
304
- invalid('prd', 'INVALID_STRUCTURED_HANDOFF');
305
- }
306
- candidates.push(value);
307
- }
308
- }
309
- fence = null;
310
- }
311
- if (fence?.info === 'json' && /"pages"\s*:/.test(content.join('\n'))
312
- && /"(?:appConfig|resourceBlueprint)"\s*:/.test(content.join('\n'))) {invalid('prd', 'INVALID_STRUCTURED_HANDOFF');}
313
- if (candidates.length > 1) {invalid('prd', 'ONE_STRUCTURED_HANDOFF_REQUIRED', { count: candidates.length });}
314
- if (candidates.length === 1) {return candidates[0].pages;}
315
- if (declared) {invalid('prd', 'INVALID_STRUCTURED_HANDOFF');}
316
- return fastPrdPages(prdMarkdown);
317
- }
318
-
319
- /** Compare existing document locations through symlinks; retain logical paths before files are written. */
320
- function documentLocation(file) {
321
- const resolved = path.resolve(file);
322
- try {return fs.realpathSync(resolved);} catch (error) {
323
- if (!['ENOENT', 'ENOTDIR'].includes(error.code)) {throw error;}
324
- return resolved;
325
- }
326
- }
327
-
328
- function validatePrd(prdMarkdown, metadata, pageIds, options) {
329
- const prdPages = new Set();
330
- for (const page of prdHandoffPages(prdMarkdown)) {
331
- if (!object(page)) {invalid('prd.pages', 'PAGE_MAPPING_REQUIRED');}
332
- if (!object(page.pageSpecHandoff)) {continue;}
333
- const handoff = page.pageSpecHandoff;
334
- if (!nonempty(page.pageId) || prdPages.has(page.pageId)) {invalid('prd.pages', 'UNIQUE_PAGE_ID_REQUIRED');}
335
- prdPages.add(page.pageId);
336
- if (!nonempty(handoff.designFile)) {invalid(`prd.pages.${page.pageId}.designFile`, 'DESIGN_FILE_REQUIRED');}
337
- // A supplied document location is always checked. Relocated bundles must
338
- // explicitly provide their project root instead of skipping relative paths.
339
- if (options.designFile) {
340
- const expected = documentLocation(options.designFile);
341
- const resolved = documentLocation(path.resolve(options.baseDir || process.cwd(), handoff.designFile));
342
- if (resolved !== expected) {
343
- invalid(`prd.pages.${page.pageId}.designFile`, 'DESIGN_FILE_MISMATCH', { actual: handoff.designFile, resolved, expected });
344
- }
345
- }
346
- if (!Array.isArray(handoff.designRefs) || !handoff.designRefs.length) {invalid('prd.designRefs', 'NONEMPTY_ARRAY_REQUIRED');}
347
- for (const ref of handoff.designRefs) {
348
- if (typeof ref !== 'string' || !/^(themeProfile|(?:sceneRecipes|components|states)\.[\p{L}\p{N}_-]+)$/u.test(ref)) {
349
- invalid('prd.designRefs', 'INVALID_DESIGN_REFERENCE', { reference: ref });
350
- }
351
- const [root, key] = ref.split('.');
352
- const target = key === undefined ? metadata[root] : metadata[root]?.[key];
353
- if (!target) {invalid('prd.designRefs', 'MISSING_DESIGN_REFERENCE', { reference: ref });}
354
- if (root === 'sceneRecipes' && !target.pages.some(item => item.pageId === page.pageId)) {
355
- invalid('prd.designRefs', 'SCENE_PAGE_MISMATCH', { reference: ref, pageId: page.pageId });
356
- }
357
- }
358
- }
359
- if ([...pageIds].sort().join('|') !== [...prdPages].sort().join('|')) {invalid('prd.pages', 'DESIGN_PAGE_COVERAGE_MISMATCH');}
360
- }
361
-
362
- function validateDesignDocument(markdown, options = {}) {
363
- const { metadata, body } = parseDesignDocument(markdown);
364
- if (metadata.schemaVersion !== '1.0') {invalid('schemaVersion', 'EXPECTED_1_0');}
365
- for (const key of ['name', 'description']) {if (!nonempty(metadata[key])) {invalid(key, 'NONEMPTY_STRING_REQUIRED');}}
366
- if (metadata.buildPlanRevision !== undefined && !nonempty(metadata.buildPlanRevision)) {
367
- invalid('buildPlanRevision', 'NONEMPTY_STRING_REQUIRED');
368
- }
369
- for (const key of ['themeId', 'templatePath']) {
370
- if (Object.prototype.hasOwnProperty.call(metadata, key)) {invalid(key, 'TEMPLATE_IDENTITY_NOT_ALLOWED');}
371
- }
372
- const tokens = extractDesignTokens(metadata, { strict: true });
373
- const profile = metadata.themeProfile;
374
- if (!object(profile)) {invalid('themeProfile', 'MAPPING_REQUIRED');}
375
- for (const key of ['name', 'themeColor', 'themeColorSource']) {if (!nonempty(profile[key])) {invalid(`themeProfile.${key}`, 'NONEMPTY_STRING_REQUIRED');}}
376
- if (!/^#[\da-f]{6}$/i.test(profile.themeColor) || profile.themeColor.toUpperCase() !== tokens['--color-brand1-6'].toUpperCase()) {
377
- invalid('themeProfile.themeColor', 'PRIMARY_COLOR_MISMATCH');
378
- }
379
- if (!['light', 'dark'].includes(profile.contentTone)) {invalid('themeProfile.contentTone', 'LIGHT_OR_DARK_REQUIRED');}
380
- if (!['light', 'dark'].includes(profile.navTheme)) {invalid('themeProfile.navTheme', 'LIGHT_OR_DARK_REQUIRED');}
381
- if (!['app-custom-theme-file', 'current-app-theme'].includes(profile.themeDelivery)) {invalid('themeProfile.themeDelivery', 'INVALID_THEME_DELIVERY');}
382
- if (typeof profile.themeFile !== 'string') {invalid('themeProfile.themeFile', 'STRING_REQUIRED');}
383
- if (profile.themeDelivery === 'app-custom-theme-file' && !nonempty(profile.themeFile)) {invalid('themeProfile.themeFile', 'THEME_FILE_REQUIRED');}
384
- for (const [key, values] of Object.entries({
385
- navigationType: ['platform-l-shape', 'platform-top', 'platform-side', 'custom'],
386
- layoutDirection: ['l_shape', 'top', 'side'], hideAppNav: ['y', 'n'],
387
- })) {
388
- if (profile[key] !== undefined && !values.includes(profile[key])) {invalid(`themeProfile.${key}`, 'INVALID_NAVIGATION_VALUE');}
389
- }
390
- if (!object(metadata.iconSystem) || !['lucide-react', '@ant-design/icons'].includes(metadata.iconSystem.library) || !object(metadata.iconSystem.mappings)) {
391
- invalid('iconSystem', 'ICON_LIBRARY_AND_MAPPINGS_REQUIRED');
392
- }
393
- for (const [key, value] of Object.entries(metadata.iconSystem.mappings)) {
394
- if (!nonempty(key) || !nonempty(value)) {invalid(`iconSystem.mappings.${key}`, 'ICON_COMPONENT_NAME_REQUIRED');}
395
- }
396
- if (!object(metadata.assetStrategy) || !Array.isArray(metadata.assetStrategy.pages)) {invalid('assetStrategy.pages', 'ARRAY_REQUIRED');}
397
- // Lazy require: the asset reader imports this document parser too.
398
- require('../asset/asset-plan').prepareAssetPlan([], metadata.assetStrategy);
399
- const lines = structuralLines(body);
400
- if (!/^# [^#\s]/.test(lines.find(line => line.trim()) || '') || lines.filter(line => /^# /.test(line)).length !== 1) {
401
- invalid('body', 'ONE_LEADING_H1_REQUIRED');
402
- }
403
- const headings = lines.filter(line => /^## /.test(line)).map(line => line.slice(3).trim());
404
- if (headings.join('|') !== HEADINGS.join('|')) {invalid('body', 'FIVE_ORDERED_CHAPTERS_REQUIRED', { expected: HEADINGS });}
405
- if (/\{\{[^}]+\}\}|<[^>]*(?:实际色值|生成期标记)[^>]*>/.test(markdown)) {invalid('document', 'UNRESOLVED_PLACEHOLDER');}
406
- const { text, anchors } = documentAnchors(body);
407
- const chapterThree = text.indexOf('## 3. 基础组件表达');
408
- const chapterFour = text.indexOf('## 4. 特色表达配方');
409
- function reference(value, field) {
410
- if (!object(value) || !ANCHOR.test(value.anchor || '') || !anchors.has(value.anchor)) {
411
- invalid(field, 'EXISTING_ANCHOR_REQUIRED', { anchor: value?.anchor });
412
- }
413
- }
414
- for (const root of ['components', 'states']) {
415
- if (!object(metadata[root])) {invalid(root, 'MAPPING_REQUIRED');}
416
- for (const [key, value] of Object.entries(metadata[root])) {
417
- if (!REFERENCE_KEY.test(key)) {invalid(`${root}.${key}`, 'INVALID_REFERENCE_KEY');}
418
- reference(value, `${root}.${key}`);
419
- if (Object.keys(value).join('|') !== 'anchor') {invalid(`${root}.${key}`, 'ANCHOR_ONLY_REQUIRED');}
420
- const position = anchors.get(value.anchor);
421
- if (position < chapterThree || position >= chapterFour) {invalid(`${root}.${key}`, 'ANCHOR_MUST_BE_IN_CHAPTER_THREE');}
422
- }
423
- }
424
- if (!object(metadata.sceneRecipes)) {invalid('sceneRecipes', 'MAPPING_REQUIRED');}
425
- const pageIds = new Set();
426
- const pageAnchors = new Set();
427
- for (const [key, scene] of Object.entries(metadata.sceneRecipes)) {
428
- if (!REFERENCE_KEY.test(key)) {invalid(`sceneRecipes.${key}`, 'INVALID_REFERENCE_KEY');}
429
- if (!object(scene) || !Array.isArray(scene.pages) || !scene.pages.length) {invalid(`sceneRecipes.${key}.pages`, 'NONEMPTY_ARRAY_REQUIRED');}
430
- for (const page of scene.pages) {
431
- if (!object(page) || !nonempty(page.pageId) || pageIds.has(page.pageId)) {invalid(`sceneRecipes.${key}.pages`, 'UNIQUE_PAGE_ID_REQUIRED');}
432
- reference(page, `sceneRecipes.${key}.${page.pageId}`);
433
- if (Object.keys(page).sort().join('|') !== 'anchor|pageId') {invalid(`sceneRecipes.${key}.${page.pageId}`, 'PAGE_ID_AND_ANCHOR_ONLY_REQUIRED');}
434
- if (!page.anchor.startsWith('#page-') || pageAnchors.has(page.anchor)) {invalid(page.pageId, 'UNIQUE_PAGE_ANCHOR_REQUIRED');}
435
- pageIds.add(page.pageId);
436
- pageAnchors.add(page.anchor);
437
- }
438
- }
439
- const positions = [...pageAnchors].map(anchor => [anchor, anchors.get(anchor)]).sort((a, b) => a[1] - b[1]);
440
- const chapterFive = text.indexOf('## 5. 项目应用与调整规则');
441
- for (let index = 0; index < positions.length; index++) {
442
- const [anchor, start] = positions[index];
443
- if (start < chapterFive) {invalid(anchor, 'PAGE_MUST_BE_IN_CHAPTER_FIVE');}
444
- const section = text.slice(start, positions[index + 1]?.[1] || text.length);
445
- for (const label of PAGE_LABELS) {
446
- const pattern = new RegExp(`^(?:[ \\t]*[-*][ \\t]+)?(?:\\*\\*)?${label}[::](?:\\*\\*)?[ \\t]*(\\S[^\\n]*)$`, 'm');
447
- const match = pattern.exec(section);
448
- if (!match || !concretePageText(match[1])) {invalid(anchor, 'PAGE_LABEL_REQUIRED', { label });}
449
- }
450
- }
451
- for (const page of metadata.assetStrategy.pages) {if (!pageIds.has(page.pageId)) {invalid('assetStrategy.pages', 'UNKNOWN_DESIGN_PAGE', { pageId: page.pageId });}}
452
- for (const match of text.matchAll(/var\(\s*(--[\w-]+)/g)) {if (!(match[1] in tokens)) {invalid('body', 'UNDECLARED_TOKEN_REFERENCE', { reference: match[1] });}}
453
- if (options.prdMarkdown !== undefined) {validatePrd(options.prdMarkdown, metadata, pageIds, options);}
454
- return { success: true, schemaVersion: metadata.schemaVersion, name: metadata.name, pages: [...pageIds], tokenCount: Object.keys(tokens).length, anchorCount: anchors.size, prdChecked: options.prdMarkdown !== undefined,
455
- iconContrast: validateIconContrast(metadata.iconSystem, tokens) };
456
- }
457
-
458
- module.exports = { parseDesignDocument, serializeDesignDocument, extractDesignTokens, validateDesignDocument, HEADINGS, PAGE_LABELS };
@@ -1,85 +0,0 @@
1
- 'use strict';
2
-
3
- const { CliError } = require('../core/cli-error');
4
- const { t } = require('../core/i18n');
5
-
6
- function invalid(field, issue, details = {}) {
7
- throw new CliError(t('design_document.invalid', field, issue), {
8
- code: 'DESIGN_DOCUMENT_INVALID', details: { field, issue, ...details },
9
- });
10
- }
11
-
12
- function color(value, tokens = {}, seen = new Set()) {
13
- if (typeof value !== 'string') {return null;}
14
- const text = value.trim().toLowerCase();
15
- const variable = /^var\(\s*(--[\w-]+)\s*(?:,\s*(.+))?\)$/.exec(value.trim());
16
- if (variable) {
17
- if (seen.has(variable[1]) || seen.size > 32) {return null;}
18
- return color(tokens[variable[1]] ?? variable[2], tokens, new Set([...seen, variable[1]]));
19
- }
20
- if (text === 'white') {return [255, 255, 255, 1];}
21
- if (text === 'black') {return [0, 0, 0, 1];}
22
- if (text === 'transparent') {return [0, 0, 0, 0];}
23
- if (/^#(?:[\da-f]{3,4}|[\da-f]{6}|[\da-f]{8})$/.test(text)) {
24
- let hex = text.slice(1);
25
- if (hex.length < 5) {hex = [...hex].map(c => c + c).join('');}
26
- return [0, 2, 4].map(i => parseInt(hex.slice(i, i + 2), 16)).concat(hex.length === 8 ? parseInt(hex.slice(6), 16) / 255 : 1);
27
- }
28
- const rgb = /^rgba?\(([^()]+)\)$/.exec(text);
29
- if (!rgb) {return null;}
30
- let components;
31
- if (rgb[1].includes(',')) {
32
- components = rgb[1].split(',').map(part => part.trim());
33
- } else {
34
- const parts = rgb[1].trim().split('/');
35
- if (parts.length > 2) {return null;}
36
- components = parts[0].trim().split(/\s+/);
37
- if (components.length !== 3) {return null;}
38
- if (parts.length === 2) {components.push(parts[1].trim());}
39
- }
40
- if (![3, 4].includes(components.length) || components.some(c => !/^(?:\d*\.)?\d+%?$/.test(c))) {return null;}
41
- const values = components.map((c, i) => parseFloat(c) * (c.endsWith('%') ? (i < 3 ? 255 / 100 : 1 / 100) : 1));
42
- if (values.some((v, i) => v < 0 || v > (i < 3 ? 255 : 1))) {return null;}
43
- return values.length === 3 ? [...values, 1] : values;
44
- }
45
-
46
- function composite(front, back) {
47
- return front.slice(0, 3).map((value, i) => value * front[3] + back[i] * (1 - front[3])).concat(1);
48
- }
49
-
50
- function contrast(foreground, background) {
51
- const luminance = rgb => rgb.slice(0, 3).reduce((sum, value, index) => {
52
- const channel = value / 255;
53
- return sum + [0.2126, 0.7152, 0.0722][index] * (channel <= 0.04045 ? channel / 12.92 : ((channel + 0.055) / 1.055) ** 2.4);
54
- }, 0);
55
- const a = luminance(foreground), b = luminance(background);
56
- return (Math.max(a, b) + 0.05) / (Math.min(a, b) + 0.05);
57
- }
58
-
59
- function validateIconContrast(iconSystem, tokens) {
60
- const pairs = iconSystem?.colorPairs;
61
- if (pairs === undefined) {return [];}
62
- if (!Array.isArray(pairs)) {invalid('iconSystem.colorPairs', 'ARRAY_REQUIRED');}
63
- const names = new Set();
64
- return pairs.map((pair, index) => {
65
- const field = `iconSystem.colorPairs[${index}]`;
66
- if (!pair || typeof pair !== 'object' || Array.isArray(pair) || typeof pair.name !== 'string' || !pair.name.trim()
67
- || names.has(pair.name) || Object.keys(pair).some(key => !['name', 'foreground', 'background', 'surface'].includes(key))) {
68
- invalid(field, 'ICON_COLOR_PAIR_INVALID');
69
- }
70
- names.add(pair.name);
71
- const foreground = color(pair.foreground, tokens);
72
- let background = color(pair.background, tokens);
73
- if (!foreground || !background) {invalid(field, 'ICON_COLOR_UNRESOLVED', { name: pair.name });}
74
- if (pair.surface !== undefined || background[3] < 1) {
75
- const surface = color(pair.surface, tokens);
76
- if (!surface || surface[3] !== 1) {invalid(field, 'ICON_OPAQUE_SURFACE_REQUIRED', { name: pair.name });}
77
- background = composite(background, surface);
78
- }
79
- const ratio = contrast(composite(foreground, background), background);
80
- if (ratio < 3) {invalid(field, 'ICON_CONTRAST_LOW', { name: pair.name, ratio, minimum: 3 });}
81
- return { name: pair.name, ratio: Math.round(ratio * 100) / 100, minimum: 3 };
82
- });
83
- }
84
-
85
- module.exports = { color, contrast, validateIconContrast };
@@ -1,11 +0,0 @@
1
- 'use strict';
2
-
3
- // Shared by Plan authoring and the final Fast/Plan document check.
4
- function concretePageText(value) {
5
- if (typeof value !== 'string' || !value.trim()) {return false;}
6
- const text = value.trim().replace(/^(?:\*\*|`)|(?:\*\*|`)$/g, '').trim();
7
- return !/草稿待补充/.test(text)
8
- && !/^(?:继承主题|继承全局|遵循主题|遵循全局|同全局|同上|按主题执行|按全局执行|待補充|待补充|待定|TBD|TODO|[-—])[。.!!]*$/i.test(text);
9
- }
10
-
11
- module.exports = { concretePageText };