@nurix/etna 0.19.10 → 0.19.12

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 (491) hide show
  1. package/data/harness-index.json +1 -1
  2. package/data/harnesses/code/harness.json +1 -1
  3. package/data/harnesses/code/rules/frontend.md +5 -5
  4. package/data/harnesses/code/skills/design/SKILL.md +70 -50
  5. package/data/harnesses/code/skills/design/components/charts.md +76 -0
  6. package/data/harnesses/code/skills/design/components/collections.md +132 -0
  7. package/data/harnesses/code/skills/design/components/feedback.md +47 -0
  8. package/data/harnesses/code/skills/design/components/hooks.md +35 -0
  9. package/data/harnesses/code/skills/design/components/index.md +143 -0
  10. package/data/harnesses/code/skills/design/components/inputs.md +327 -0
  11. package/data/harnesses/code/skills/design/components/layout.md +52 -0
  12. package/data/harnesses/code/skills/design/components/media.md +66 -0
  13. package/data/harnesses/code/skills/design/components/motion.md +82 -0
  14. package/data/harnesses/code/skills/design/components/navigation.md +29 -0
  15. package/data/harnesses/code/skills/design/components/overlays.md +72 -0
  16. package/data/harnesses/code/skills/design/components/setup.md +40 -0
  17. package/data/harnesses/code/skills/design/components/typography.md +46 -0
  18. package/data/harnesses/code/skills/design/components/utils.md +37 -0
  19. package/data/harnesses/code/skills/design/data/blueprints/browse.md +38 -0
  20. package/data/harnesses/code/skills/design/data/blueprints/creation-flow.md +38 -0
  21. package/data/harnesses/code/skills/design/data/blueprints/dashboard.md +38 -0
  22. package/data/harnesses/code/skills/design/data/blueprints/grid.md +38 -0
  23. package/data/harnesses/code/skills/design/data/blueprints/queue.md +38 -0
  24. package/data/harnesses/code/skills/design/data/blueprints/record-detail.md +38 -0
  25. package/data/harnesses/code/skills/design/data/blueprints/settings.md +38 -0
  26. package/data/harnesses/code/skills/design/data/chart-styling/Readme.md +33 -0
  27. package/data/harnesses/code/skills/design/data/chart-styling/carbon-accessible-alert-semantic.md +19 -0
  28. package/data/harnesses/code/skills/design/data/chart-styling/carbon-monochrome-sequential-trend.md +19 -0
  29. package/data/harnesses/code/skills/design/data/chart-styling/datadog-classic-six-aligned.md +19 -0
  30. package/data/harnesses/code/skills/design/data/chart-styling/datawrapper-tiered-gray-hierarchy.md +19 -0
  31. package/data/harnesses/code/skills/design/data/chart-styling/econ-red-rule-horizontal.md +19 -0
  32. package/data/harnesses/code/skills/design/data/chart-styling/financial-diverging-threshold-overlay.md +19 -0
  33. package/data/harnesses/code/skills/design/data/chart-styling/ft-vocabulary-ranked-muted.md +19 -0
  34. package/data/harnesses/code/skills/design/data/chart-styling/grafana-dark-threshold-bands.md +19 -0
  35. package/data/harnesses/code/skills/design/data/chart-styling/material-rounded-explicit-label.md +19 -0
  36. package/data/harnesses/code/skills/design/data/chart-styling/nyt-ghost-grid-direct-label.md +19 -0
  37. package/data/harnesses/code/skills/design/data/chart-styling/plot-currentcolor-inherit.md +19 -0
  38. package/data/harnesses/code/skills/design/data/chart-styling/saas-gradient-glow-area.md +19 -0
  39. package/data/harnesses/code/skills/design/data/chart-styling/shadcn-composable-css-vars.md +19 -0
  40. package/data/harnesses/code/skills/design/data/charts/census.csv +58 -0
  41. package/data/harnesses/code/skills/design/data/checklists/browse.md +21 -0
  42. package/data/harnesses/code/skills/design/data/checklists/creation-flow.md +20 -0
  43. package/data/harnesses/code/skills/design/data/checklists/dashboard.md +21 -0
  44. package/data/harnesses/code/skills/design/data/checklists/grid.md +21 -0
  45. package/data/harnesses/code/skills/design/data/checklists/queue.md +21 -0
  46. package/data/harnesses/code/skills/design/data/checklists/record-detail.md +21 -0
  47. package/data/harnesses/code/skills/design/data/checklists/settings.md +21 -0
  48. package/data/harnesses/code/skills/design/data/chrome/board-column.md +68 -0
  49. package/data/harnesses/code/skills/design/data/chrome/data-table.md +63 -0
  50. package/data/harnesses/code/skills/design/data/chrome/side-panel.md +60 -0
  51. package/data/harnesses/code/skills/design/data/chrome/sidebar.md +78 -0
  52. package/data/harnesses/code/skills/design/data/chrome/stat-cards.md +62 -0
  53. package/data/harnesses/code/skills/design/data/chrome/topbar.md +65 -0
  54. package/data/harnesses/code/skills/design/data/color/accent-presets.md +90 -0
  55. package/data/harnesses/code/skills/design/data/color/aesop-earth-mute.md +91 -0
  56. package/data/harnesses/code/skills/design/data/color/arc-peach-play.md +90 -0
  57. package/data/harnesses/code/skills/design/data/color/attio-hunter-teal.md +90 -0
  58. package/data/harnesses/code/skills/design/data/color/carbon-cyan-signal.md +90 -0
  59. package/data/harnesses/code/skills/design/data/color/clay-parchment.md +90 -0
  60. package/data/harnesses/code/skills/design/data/color/duolingo-feather.md +90 -0
  61. package/data/harnesses/code/skills/design/data/color/geist-mono-signal.md +90 -0
  62. package/data/harnesses/code/skills/design/data/color/linear-graphite-violet.md +90 -0
  63. package/data/harnesses/code/skills/design/data/color/mercury-onyx-cobalt.md +90 -0
  64. package/data/harnesses/code/skills/design/data/color/notion-paper-ink.md +90 -0
  65. package/data/harnesses/code/skills/design/data/color/radix-slate-iris.md +90 -0
  66. package/data/harnesses/code/skills/design/data/color/raycast-void-spectrum.md +90 -0
  67. package/data/harnesses/code/skills/design/data/color/spectrum-celery-fuchsia.md +90 -0
  68. package/data/harnesses/code/skills/design/data/color/stripe-blurple-ruby.md +90 -0
  69. package/data/harnesses/code/skills/design/data/color/superhuman-cod-picton.md +89 -0
  70. package/data/harnesses/code/skills/design/data/corpora/operations-review/companies.csv +15 -0
  71. package/data/harnesses/code/skills/design/data/corpora/operations-review/corpus.md +87 -0
  72. package/data/harnesses/code/skills/design/data/corpora/operations-review/people.csv +25 -0
  73. package/data/harnesses/code/skills/design/data/corpora/procurement-approvals/companies.csv +15 -0
  74. package/data/harnesses/code/skills/design/data/corpora/procurement-approvals/corpus.md +83 -0
  75. package/data/harnesses/code/skills/design/data/corpora/procurement-approvals/people.csv +25 -0
  76. package/data/harnesses/code/skills/design/data/corpora/revenue-analytics/companies.csv +15 -0
  77. package/data/harnesses/code/skills/design/data/corpora/revenue-analytics/corpus.md +89 -0
  78. package/data/harnesses/code/skills/design/data/corpora/revenue-analytics/people.csv +25 -0
  79. package/data/harnesses/code/skills/design/data/elevation/ant-design-directional-shadow.md +19 -0
  80. package/data/harnesses/code/skills/design/data/elevation/apple-liquid-glass-material.md +18 -0
  81. package/data/harnesses/code/skills/design/data/elevation/atlassian-surface-shadow-pairing.md +20 -0
  82. package/data/harnesses/code/skills/design/data/elevation/fluent-2-key-ambient-ramp.md +20 -0
  83. package/data/harnesses/code/skills/design/data/elevation/github-primer-sparing-shadow.md +19 -0
  84. package/data/harnesses/code/skills/design/data/elevation/ibm-carbon-layer-and-border.md +19 -0
  85. package/data/harnesses/code/skills/design/data/elevation/linear-dark-surface-ladder.md +17 -0
  86. package/data/harnesses/code/skills/design/data/elevation/material-2-key-ambient-dp-ramp.md +19 -0
  87. package/data/harnesses/code/skills/design/data/elevation/material-3-tonal-elevation.md +21 -0
  88. package/data/harnesses/code/skills/design/data/elevation/neobrutalist-hard-offset.md +19 -0
  89. package/data/harnesses/code/skills/design/data/elevation/neumorphic-soft-dual-shadow.md +18 -0
  90. package/data/harnesses/code/skills/design/data/elevation/notion-warm-minimal-hairline.md +17 -0
  91. package/data/harnesses/code/skills/design/data/elevation/polaris-elevation-inset-bevel.md +21 -0
  92. package/data/harnesses/code/skills/design/data/elevation/radix-themes-alpha-ring-scale.md +19 -0
  93. package/data/harnesses/code/skills/design/data/elevation/shadcn-neutral-derived-radius.md +19 -0
  94. package/data/harnesses/code/skills/design/data/elevation/stripe-brand-tinted-dual-shadow.md +18 -0
  95. package/data/harnesses/code/skills/design/data/elevation/tailwind-default-utility-scale.md +19 -0
  96. package/data/harnesses/code/skills/design/data/elevation/vercel-geist-shadow-as-border.md +20 -0
  97. package/data/harnesses/code/skills/design/data/gradients/amber-attention-fill.md +16 -0
  98. package/data/harnesses/code/skills/design/data/gradients/cloud-shadow-wash.md +16 -0
  99. package/data/harnesses/code/skills/design/data/gradients/confident-lavender-wash.md +16 -0
  100. package/data/harnesses/code/skills/design/data/gradients/ember-ship-flare.md +18 -0
  101. package/data/harnesses/code/skills/design/data/gradients/full-metal-wash.md +16 -0
  102. package/data/harnesses/code/skills/design/data/gradients/indigo-ruby-cta-band.md +18 -0
  103. package/data/harnesses/code/skills/design/data/gradients/linear-graphite-wash.md +18 -0
  104. package/data/harnesses/code/skills/design/data/gradients/marble-quartz-wash.md +16 -0
  105. package/data/harnesses/code/skills/design/data/gradients/midnight-aurora-panel.md +16 -0
  106. package/data/harnesses/code/skills/design/data/gradients/neutral-volume-fill.md +16 -0
  107. package/data/harnesses/code/skills/design/data/gradients/revenue-uptrend-fill.md +16 -0
  108. package/data/harnesses/code/skills/design/data/gradients/risk-decline-fill.md +16 -0
  109. package/data/harnesses/code/skills/design/data/gradients/signal-blue-develop.md +18 -0
  110. package/data/harnesses/code/skills/design/data/gradients/slate-mist-wash.md +16 -0
  111. package/data/harnesses/code/skills/design/data/gradients/stripe-atmosphere-mesh.md +18 -0
  112. package/data/harnesses/code/skills/design/data/gradients/teal-signal-accent.md +16 -0
  113. package/data/harnesses/code/skills/design/data/gradients/violet-magenta-promo.md +16 -0
  114. package/data/harnesses/code/skills/design/data/iconography.md +199 -0
  115. package/data/harnesses/code/skills/design/data/motion/accordion-expand.md +18 -0
  116. package/data/harnesses/code/skills/design/data/motion/destructive-hold-confirm.md +18 -0
  117. package/data/harnesses/code/skills/design/data/motion/drag-dismiss-momentum.md +18 -0
  118. package/data/harnesses/code/skills/design/data/motion/empty-state-arrive.md +18 -0
  119. package/data/harnesses/code/skills/design/data/motion/hover-lift.md +18 -0
  120. package/data/harnesses/code/skills/design/data/motion/modal-center-arrive.md +18 -0
  121. package/data/harnesses/code/skills/design/data/motion/number-ticker-roll.md +18 -0
  122. package/data/harnesses/code/skills/design/data/motion/onboarding-bounce.md +18 -0
  123. package/data/harnesses/code/skills/design/data/motion/panel-slide.md +18 -0
  124. package/data/harnesses/code/skills/design/data/motion/press-feedback.md +18 -0
  125. package/data/harnesses/code/skills/design/data/motion/progress-linear-loop.md +18 -0
  126. package/data/harnesses/code/skills/design/data/motion/route-crossfade.md +18 -0
  127. package/data/harnesses/code/skills/design/data/motion/rubber-band-overscroll.md +18 -0
  128. package/data/harnesses/code/skills/design/data/motion/skeleton-shimmer.md +18 -0
  129. package/data/harnesses/code/skills/design/data/motion/stagger-arrive.md +18 -0
  130. package/data/harnesses/code/skills/design/data/motion/toast-enter-stack.md +18 -0
  131. package/data/harnesses/code/skills/design/data/motion/tooltip-chain-instant.md +18 -0
  132. package/data/harnesses/code/skills/design/data/motion/trigger-anchored-reveal.md +18 -0
  133. package/data/harnesses/code/skills/design/data/tells.csv +34 -0
  134. package/data/harnesses/code/skills/design/data/typography/anton-work-sans.md +17 -0
  135. package/data/harnesses/code/skills/design/data/typography/archivo-black-archivo.md +17 -0
  136. package/data/harnesses/code/skills/design/data/typography/bitter-karla.md +17 -0
  137. package/data/harnesses/code/skills/design/data/typography/dm-serif-dm-sans.md +17 -0
  138. package/data/harnesses/code/skills/design/data/typography/fraunces-inter.md +17 -0
  139. package/data/harnesses/code/skills/design/data/typography/geist-geist-mono.md +17 -0
  140. package/data/harnesses/code/skills/design/data/typography/hubot-sans-mona-sans.md +17 -0
  141. package/data/harnesses/code/skills/design/data/typography/ibm-plex-sans-operator-single-family.md +17 -0
  142. package/data/harnesses/code/skills/design/data/typography/instrument-serif-instrument-sans.md +17 -0
  143. package/data/harnesses/code/skills/design/data/typography/inter-operator-single-family.md +17 -0
  144. package/data/harnesses/code/skills/design/data/typography/libre-baskerville-libre-franklin.md +17 -0
  145. package/data/harnesses/code/skills/design/data/typography/newsreader-inter.md +17 -0
  146. package/data/harnesses/code/skills/design/data/typography/playfair-display-source-sans.md +17 -0
  147. package/data/harnesses/code/skills/design/data/typography/public-sans-operator-single-family.md +17 -0
  148. package/data/harnesses/code/skills/design/data/typography/sohne-inter-fintech.md +17 -0
  149. package/data/harnesses/code/skills/design/data/typography/source-serif-source-sans.md +17 -0
  150. package/data/harnesses/code/skills/design/data/typography/space-grotesk-work-sans-space-mono.md +17 -0
  151. package/data/harnesses/code/skills/design/data/typography/spectral-manrope.md +17 -0
  152. package/data/harnesses/code/skills/design/data/voices/bright-collaborator.md +29 -0
  153. package/data/harnesses/code/skills/design/data/voices/direct-operator.md +29 -0
  154. package/data/harnesses/code/skills/design/data/voices/earnest-helper.md +29 -0
  155. package/data/harnesses/code/skills/design/data/voices/editorial-composed.md +29 -0
  156. package/data/harnesses/code/skills/design/data/voices/quiet-concierge.md +29 -0
  157. package/data/harnesses/code/skills/design/data/voices/warm-guide.md +29 -0
  158. package/data/harnesses/code/skills/design/design-md/SCHEMA.md +179 -0
  159. package/data/harnesses/code/skills/design/design-md/index.csv +67 -0
  160. package/data/harnesses/code/skills/design/design-md/library/airbnb.md +207 -0
  161. package/data/harnesses/code/skills/design/design-md/library/airtable.md +205 -0
  162. package/data/harnesses/code/skills/design/design-md/library/anthropic-claude.md +203 -0
  163. package/data/harnesses/code/skills/design/design-md/library/apple.md +206 -0
  164. package/data/harnesses/code/skills/design/design-md/library/binance.md +210 -0
  165. package/data/harnesses/code/skills/design/design-md/library/bmw.md +210 -0
  166. package/data/harnesses/code/skills/design/design-md/library/cal.md +209 -0
  167. package/data/harnesses/code/skills/design/design-md/library/clay.md +204 -0
  168. package/data/harnesses/code/skills/design/design-md/library/clickhouse.md +205 -0
  169. package/data/harnesses/code/skills/design/design-md/library/cohere.md +205 -0
  170. package/data/harnesses/code/skills/design/design-md/library/coinbase.md +198 -0
  171. package/data/harnesses/code/skills/design/design-md/library/composio.md +198 -0
  172. package/data/harnesses/code/skills/design/design-md/library/cursor.md +197 -0
  173. package/data/harnesses/code/skills/design/design-md/library/elevenlabs.md +199 -0
  174. package/data/harnesses/code/skills/design/design-md/library/expo.md +200 -0
  175. package/data/harnesses/code/skills/design/design-md/library/figma.md +199 -0
  176. package/data/harnesses/code/skills/design/design-md/library/framer.md +202 -0
  177. package/data/harnesses/code/skills/design/design-md/library/hashicorp.md +205 -0
  178. package/data/harnesses/code/skills/design/design-md/library/ibm.md +205 -0
  179. package/data/harnesses/code/skills/design/design-md/library/intercom.md +204 -0
  180. package/data/harnesses/code/skills/design/design-md/library/kraken.md +200 -0
  181. package/data/harnesses/code/skills/design/design-md/library/linear-app.md +198 -0
  182. package/data/harnesses/code/skills/design/design-md/library/lovable.md +199 -0
  183. package/data/harnesses/code/skills/design/design-md/library/meta.md +204 -0
  184. package/data/harnesses/code/skills/design/design-md/library/minimax.md +204 -0
  185. package/data/harnesses/code/skills/design/design-md/library/mintlify.md +210 -0
  186. package/data/harnesses/code/skills/design/design-md/library/miro.md +209 -0
  187. package/data/harnesses/code/skills/design/design-md/library/mistral-ai.md +201 -0
  188. package/data/harnesses/code/skills/design/design-md/library/mongodb.md +201 -0
  189. package/data/harnesses/code/skills/design/design-md/library/notion.md +204 -0
  190. package/data/harnesses/code/skills/design/design-md/library/nvidia.md +215 -0
  191. package/data/harnesses/code/skills/design/design-md/library/ollama.md +213 -0
  192. package/data/harnesses/code/skills/design/design-md/library/opencode-ai.md +216 -0
  193. package/data/harnesses/code/skills/design/design-md/library/posthog.md +218 -0
  194. package/data/harnesses/code/skills/design/design-md/library/raycast.md +214 -0
  195. package/data/harnesses/code/skills/design/design-md/library/replicate.md +202 -0
  196. package/data/harnesses/code/skills/design/design-md/library/resend.md +203 -0
  197. package/data/harnesses/code/skills/design/design-md/library/revolut.md +203 -0
  198. package/data/harnesses/code/skills/design/design-md/library/runwayml.md +203 -0
  199. package/data/harnesses/code/skills/design/design-md/library/sanity.md +200 -0
  200. package/data/harnesses/code/skills/design/design-md/library/sentry.md +201 -0
  201. package/data/harnesses/code/skills/design/design-md/library/shopify.md +202 -0
  202. package/data/harnesses/code/skills/design/design-md/library/slack.md +202 -0
  203. package/data/harnesses/code/skills/design/design-md/library/spacex.md +206 -0
  204. package/data/harnesses/code/skills/design/design-md/library/spotify.md +206 -0
  205. package/data/harnesses/code/skills/design/design-md/library/stripe.md +196 -0
  206. package/data/harnesses/code/skills/design/design-md/library/supabase.md +196 -0
  207. package/data/harnesses/code/skills/design/design-md/library/superhuman.md +194 -0
  208. package/data/harnesses/code/skills/design/design-md/library/tesla.md +198 -0
  209. package/data/harnesses/code/skills/design/design-md/library/theverge.md +199 -0
  210. package/data/harnesses/code/skills/design/design-md/library/together-ai.md +193 -0
  211. package/data/harnesses/code/skills/design/design-md/library/uber.md +195 -0
  212. package/data/harnesses/code/skills/design/design-md/library/vercel.md +195 -0
  213. package/data/harnesses/code/skills/design/design-md/library/voltagent.md +197 -0
  214. package/data/harnesses/code/skills/design/design-md/library/warp.md +196 -0
  215. package/data/harnesses/code/skills/design/design-md/library/webflow.md +197 -0
  216. package/data/harnesses/code/skills/design/design-md/library/wired.md +197 -0
  217. package/data/harnesses/code/skills/design/design-md/library/wise.md +198 -0
  218. package/data/harnesses/code/skills/design/design-md/library/x-ai.md +199 -0
  219. package/data/harnesses/code/skills/design/design-md/library/zapier.md +198 -0
  220. package/data/harnesses/code/skills/design/design-md/nurix.md +214 -0
  221. package/data/harnesses/code/skills/design/design-md/variants/editorial-luxury.md +184 -0
  222. package/data/harnesses/code/skills/design/design-md/variants/expressive-saas.md +216 -0
  223. package/data/harnesses/code/skills/design/design-md/variants/quiet-premium.md +211 -0
  224. package/data/harnesses/code/skills/design/design-md/variants/terse-dense-operator.md +212 -0
  225. package/data/harnesses/code/skills/design/design-md/variants/warm-approachable.md +216 -0
  226. package/data/harnesses/code/skills/design/references/compose.md +23 -0
  227. package/data/harnesses/code/skills/design/references/content.md +28 -0
  228. package/data/harnesses/code/skills/design/references/emission.md +21 -0
  229. package/data/harnesses/code/skills/design/references/existing-apps.md +27 -0
  230. package/data/harnesses/code/skills/design/references/intake.md +36 -0
  231. package/data/harnesses/code/skills/design/references/object-pass.md +24 -0
  232. package/data/harnesses/code/skills/design/references/ship-gate.md +29 -0
  233. package/data/harnesses/code/skills/design/references/ux-patterns/Readme.md +195 -0
  234. package/data/harnesses/code/skills/design/references/ux-patterns/ai-layer.md +49 -0
  235. package/data/harnesses/code/skills/design/references/ux-patterns/attributes-lifecycle.md +43 -0
  236. package/data/harnesses/code/skills/design/references/ux-patterns/container-choice.md +44 -0
  237. package/data/harnesses/code/skills/design/references/ux-patterns/creation-paths.md +46 -0
  238. package/data/harnesses/code/skills/design/references/ux-patterns/dashboards.md +42 -0
  239. package/data/harnesses/code/skills/design/references/ux-patterns/modes.md +42 -0
  240. package/data/harnesses/code/skills/design/references/ux-patterns/object-model.md +46 -0
  241. package/data/harnesses/code/skills/design/references/ux-patterns/page-archetype.md +48 -0
  242. package/data/harnesses/code/skills/design/references/ux-patterns/promotion-demotion.md +37 -0
  243. package/data/harnesses/code/skills/design/references/ux-patterns/settings.md +42 -0
  244. package/data/harnesses/code/skills/design/references/ux-patterns/standard-pages.md +46 -0
  245. package/data/harnesses/code/skills/design/references/ux-patterns/state-matrix.md +41 -0
  246. package/data/harnesses/code/skills/design/references/ux-patterns/table-mechanics.md +48 -0
  247. package/data/harnesses/code/skills/design/references/ux-patterns/verbs.md +45 -0
  248. package/data/harnesses/code/skills/design/references/ux-patterns/viewer-context.md +40 -0
  249. package/data/harnesses/code/skills/design/scripts/README-validator.md +27 -0
  250. package/data/harnesses/code/skills/design/scripts/select-chart.mjs +596 -0
  251. package/data/harnesses/code/skills/design/scripts/validate-design-md.mjs +1198 -0
  252. package/data/harnesses/discussion/CLAUDE.md +1 -1
  253. package/data/harnesses/discussion/agents/discussion-baseline.md +27 -2
  254. package/data/harnesses/discussion/harness.json +2 -2
  255. package/data/harnesses/discussion/rules/artifacts.md +2 -0
  256. package/data/harnesses/discussion/rules/method.md +5 -1
  257. package/package.json +1 -1
  258. package/data/harnesses/code/skills/design/data/catalog/rules.csv +0 -137
  259. package/data/harnesses/code/skills/design/data/combinations/Readme.md +0 -33
  260. package/data/harnesses/code/skills/design/data/combinations/accent-presets.md +0 -113
  261. package/data/harnesses/code/skills/design/data/combinations/charts.csv +0 -33
  262. package/data/harnesses/code/skills/design/data/combinations/fonts-known.json +0 -448
  263. package/data/harnesses/code/skills/design/data/combinations/icons.csv +0 -157
  264. package/data/harnesses/code/skills/design/data/combinations/landing.csv +0 -38
  265. package/data/harnesses/code/skills/design/data/combinations/lucide-names.json +0 -2001
  266. package/data/harnesses/code/skills/design/data/combinations/manifest.json +0 -330
  267. package/data/harnesses/code/skills/design/data/combinations/motion.csv +0 -10
  268. package/data/harnesses/code/skills/design/data/combinations/palettes.csv +0 -92
  269. package/data/harnesses/code/skills/design/data/combinations/product-router.csv +0 -80
  270. package/data/harnesses/code/skills/design/data/combinations/styles.csv +0 -67
  271. package/data/harnesses/code/skills/design/data/combinations/typography.csv +0 -64
  272. package/data/harnesses/code/skills/design/data/design-md/SCHEMA.md +0 -106
  273. package/data/harnesses/code/skills/design/data/design-md/library/airbnb.md +0 -154
  274. package/data/harnesses/code/skills/design/data/design-md/library/airtable.md +0 -151
  275. package/data/harnesses/code/skills/design/data/design-md/library/anthropic-claude.md +0 -139
  276. package/data/harnesses/code/skills/design/data/design-md/library/apple.md +0 -139
  277. package/data/harnesses/code/skills/design/data/design-md/library/binance.md +0 -140
  278. package/data/harnesses/code/skills/design/data/design-md/library/bmw.md +0 -140
  279. package/data/harnesses/code/skills/design/data/design-md/library/cal.md +0 -140
  280. package/data/harnesses/code/skills/design/data/design-md/library/clay.md +0 -139
  281. package/data/harnesses/code/skills/design/data/design-md/library/clickhouse.md +0 -139
  282. package/data/harnesses/code/skills/design/data/design-md/library/cohere.md +0 -147
  283. package/data/harnesses/code/skills/design/data/design-md/library/coinbase.md +0 -156
  284. package/data/harnesses/code/skills/design/data/design-md/library/composio.md +0 -138
  285. package/data/harnesses/code/skills/design/data/design-md/library/cursor.md +0 -138
  286. package/data/harnesses/code/skills/design/data/design-md/library/elevenlabs.md +0 -137
  287. package/data/harnesses/code/skills/design/data/design-md/library/expo.md +0 -148
  288. package/data/harnesses/code/skills/design/data/design-md/library/figma.md +0 -141
  289. package/data/harnesses/code/skills/design/data/design-md/library/framer.md +0 -156
  290. package/data/harnesses/code/skills/design/data/design-md/library/hashicorp.md +0 -140
  291. package/data/harnesses/code/skills/design/data/design-md/library/ibm.md +0 -153
  292. package/data/harnesses/code/skills/design/data/design-md/library/intercom.md +0 -158
  293. package/data/harnesses/code/skills/design/data/design-md/library/kraken.md +0 -156
  294. package/data/harnesses/code/skills/design/data/design-md/library/linear-app.md +0 -122
  295. package/data/harnesses/code/skills/design/data/design-md/library/lovable.md +0 -140
  296. package/data/harnesses/code/skills/design/data/design-md/library/meta.md +0 -139
  297. package/data/harnesses/code/skills/design/data/design-md/library/minimax.md +0 -139
  298. package/data/harnesses/code/skills/design/data/design-md/library/mintlify.md +0 -139
  299. package/data/harnesses/code/skills/design/data/design-md/library/miro.md +0 -153
  300. package/data/harnesses/code/skills/design/data/design-md/library/mistral-ai.md +0 -140
  301. package/data/harnesses/code/skills/design/data/design-md/library/mongodb.md +0 -155
  302. package/data/harnesses/code/skills/design/data/design-md/library/notion.md +0 -140
  303. package/data/harnesses/code/skills/design/data/design-md/library/nvidia.md +0 -141
  304. package/data/harnesses/code/skills/design/data/design-md/library/ollama.md +0 -145
  305. package/data/harnesses/code/skills/design/data/design-md/library/opencode-ai.md +0 -142
  306. package/data/harnesses/code/skills/design/data/design-md/library/posthog.md +0 -152
  307. package/data/harnesses/code/skills/design/data/design-md/library/raycast.md +0 -137
  308. package/data/harnesses/code/skills/design/data/design-md/library/replicate.md +0 -140
  309. package/data/harnesses/code/skills/design/data/design-md/library/resend.md +0 -170
  310. package/data/harnesses/code/skills/design/data/design-md/library/revolut.md +0 -145
  311. package/data/harnesses/code/skills/design/data/design-md/library/runwayml.md +0 -137
  312. package/data/harnesses/code/skills/design/data/design-md/library/sanity.md +0 -168
  313. package/data/harnesses/code/skills/design/data/design-md/library/sentry.md +0 -163
  314. package/data/harnesses/code/skills/design/data/design-md/library/shopify.md +0 -147
  315. package/data/harnesses/code/skills/design/data/design-md/library/slack.md +0 -158
  316. package/data/harnesses/code/skills/design/data/design-md/library/spacex.md +0 -171
  317. package/data/harnesses/code/skills/design/data/design-md/library/spotify.md +0 -166
  318. package/data/harnesses/code/skills/design/data/design-md/library/stripe.md +0 -160
  319. package/data/harnesses/code/skills/design/data/design-md/library/supabase.md +0 -173
  320. package/data/harnesses/code/skills/design/data/design-md/library/superhuman.md +0 -145
  321. package/data/harnesses/code/skills/design/data/design-md/library/tesla.md +0 -153
  322. package/data/harnesses/code/skills/design/data/design-md/library/theverge.md +0 -167
  323. package/data/harnesses/code/skills/design/data/design-md/library/together-ai.md +0 -140
  324. package/data/harnesses/code/skills/design/data/design-md/library/uber.md +0 -140
  325. package/data/harnesses/code/skills/design/data/design-md/library/vercel.md +0 -140
  326. package/data/harnesses/code/skills/design/data/design-md/library/voltagent.md +0 -130
  327. package/data/harnesses/code/skills/design/data/design-md/library/warp.md +0 -140
  328. package/data/harnesses/code/skills/design/data/design-md/library/webflow.md +0 -140
  329. package/data/harnesses/code/skills/design/data/design-md/library/wired.md +0 -139
  330. package/data/harnesses/code/skills/design/data/design-md/library/wise.md +0 -137
  331. package/data/harnesses/code/skills/design/data/design-md/library/x-ai.md +0 -138
  332. package/data/harnesses/code/skills/design/data/design-md/library/zapier.md +0 -158
  333. package/data/harnesses/code/skills/design/data/design-md/nurix.md +0 -138
  334. package/data/harnesses/code/skills/design/data/design-tokens/SCHEMA.md +0 -695
  335. package/data/harnesses/code/skills/design/data/design-tokens/airbnb/design.resolver.json +0 -20
  336. package/data/harnesses/code/skills/design/data/design-tokens/airbnb/design.tokens.json +0 -1272
  337. package/data/harnesses/code/skills/design/data/design-tokens/airtable/design.resolver.json +0 -20
  338. package/data/harnesses/code/skills/design/data/design-tokens/airtable/design.tokens.json +0 -1268
  339. package/data/harnesses/code/skills/design/data/design-tokens/anthropic-claude/design.resolver.json +0 -20
  340. package/data/harnesses/code/skills/design/data/design-tokens/anthropic-claude/design.tokens.json +0 -1273
  341. package/data/harnesses/code/skills/design/data/design-tokens/apple/design.resolver.json +0 -20
  342. package/data/harnesses/code/skills/design/data/design-tokens/apple/design.tokens.json +0 -1262
  343. package/data/harnesses/code/skills/design/data/design-tokens/binance/design.resolver.json +0 -20
  344. package/data/harnesses/code/skills/design/data/design-tokens/binance/design.tokens.json +0 -1257
  345. package/data/harnesses/code/skills/design/data/design-tokens/bmw/design.resolver.json +0 -20
  346. package/data/harnesses/code/skills/design/data/design-tokens/bmw/design.tokens.json +0 -1270
  347. package/data/harnesses/code/skills/design/data/design-tokens/cal/design.resolver.json +0 -20
  348. package/data/harnesses/code/skills/design/data/design-tokens/cal/design.tokens.json +0 -1270
  349. package/data/harnesses/code/skills/design/data/design-tokens/clay/design.resolver.json +0 -20
  350. package/data/harnesses/code/skills/design/data/design-tokens/clay/design.tokens.json +0 -1261
  351. package/data/harnesses/code/skills/design/data/design-tokens/clickhouse/design.resolver.json +0 -20
  352. package/data/harnesses/code/skills/design/data/design-tokens/clickhouse/design.tokens.json +0 -1268
  353. package/data/harnesses/code/skills/design/data/design-tokens/cohere/design.resolver.json +0 -20
  354. package/data/harnesses/code/skills/design/data/design-tokens/cohere/design.tokens.json +0 -1281
  355. package/data/harnesses/code/skills/design/data/design-tokens/coinbase/design.resolver.json +0 -20
  356. package/data/harnesses/code/skills/design/data/design-tokens/coinbase/design.tokens.json +0 -1262
  357. package/data/harnesses/code/skills/design/data/design-tokens/composio/design.resolver.json +0 -20
  358. package/data/harnesses/code/skills/design/data/design-tokens/composio/design.tokens.json +0 -1271
  359. package/data/harnesses/code/skills/design/data/design-tokens/cursor/design.resolver.json +0 -20
  360. package/data/harnesses/code/skills/design/data/design-tokens/cursor/design.tokens.json +0 -1276
  361. package/data/harnesses/code/skills/design/data/design-tokens/elevenlabs/design.resolver.json +0 -20
  362. package/data/harnesses/code/skills/design/data/design-tokens/elevenlabs/design.tokens.json +0 -1293
  363. package/data/harnesses/code/skills/design/data/design-tokens/expo/design.resolver.json +0 -20
  364. package/data/harnesses/code/skills/design/data/design-tokens/expo/design.tokens.json +0 -1270
  365. package/data/harnesses/code/skills/design/data/design-tokens/figma/design.resolver.json +0 -20
  366. package/data/harnesses/code/skills/design/data/design-tokens/figma/design.tokens.json +0 -1276
  367. package/data/harnesses/code/skills/design/data/design-tokens/framer/design.resolver.json +0 -20
  368. package/data/harnesses/code/skills/design/data/design-tokens/framer/design.tokens.json +0 -1267
  369. package/data/harnesses/code/skills/design/data/design-tokens/goldens.json +0 -251
  370. package/data/harnesses/code/skills/design/data/design-tokens/hashicorp/design.resolver.json +0 -20
  371. package/data/harnesses/code/skills/design/data/design-tokens/hashicorp/design.tokens.json +0 -1273
  372. package/data/harnesses/code/skills/design/data/design-tokens/ibm/design.resolver.json +0 -20
  373. package/data/harnesses/code/skills/design/data/design-tokens/ibm/design.tokens.json +0 -1286
  374. package/data/harnesses/code/skills/design/data/design-tokens/intercom/design.resolver.json +0 -20
  375. package/data/harnesses/code/skills/design/data/design-tokens/intercom/design.tokens.json +0 -1290
  376. package/data/harnesses/code/skills/design/data/design-tokens/kraken/design.resolver.json +0 -20
  377. package/data/harnesses/code/skills/design/data/design-tokens/kraken/design.tokens.json +0 -1270
  378. package/data/harnesses/code/skills/design/data/design-tokens/linear-app/design.resolver.json +0 -23
  379. package/data/harnesses/code/skills/design/data/design-tokens/linear-app/design.tokens.dark.json +0 -599
  380. package/data/harnesses/code/skills/design/data/design-tokens/linear-app/design.tokens.json +0 -1272
  381. package/data/harnesses/code/skills/design/data/design-tokens/lovable/design.resolver.json +0 -20
  382. package/data/harnesses/code/skills/design/data/design-tokens/lovable/design.tokens.json +0 -1267
  383. package/data/harnesses/code/skills/design/data/design-tokens/meta/design.resolver.json +0 -20
  384. package/data/harnesses/code/skills/design/data/design-tokens/meta/design.tokens.json +0 -1289
  385. package/data/harnesses/code/skills/design/data/design-tokens/minimax/design.resolver.json +0 -20
  386. package/data/harnesses/code/skills/design/data/design-tokens/minimax/design.tokens.json +0 -1258
  387. package/data/harnesses/code/skills/design/data/design-tokens/mintlify/design.resolver.json +0 -20
  388. package/data/harnesses/code/skills/design/data/design-tokens/mintlify/design.tokens.json +0 -1284
  389. package/data/harnesses/code/skills/design/data/design-tokens/miro/design.resolver.json +0 -20
  390. package/data/harnesses/code/skills/design/data/design-tokens/miro/design.tokens.json +0 -1291
  391. package/data/harnesses/code/skills/design/data/design-tokens/mistral-ai/design.resolver.json +0 -20
  392. package/data/harnesses/code/skills/design/data/design-tokens/mistral-ai/design.tokens.json +0 -1263
  393. package/data/harnesses/code/skills/design/data/design-tokens/mongodb/design.resolver.json +0 -20
  394. package/data/harnesses/code/skills/design/data/design-tokens/mongodb/design.tokens.json +0 -1270
  395. package/data/harnesses/code/skills/design/data/design-tokens/notion/design.resolver.json +0 -20
  396. package/data/harnesses/code/skills/design/data/design-tokens/notion/design.tokens.json +0 -1261
  397. package/data/harnesses/code/skills/design/data/design-tokens/nurix/design.resolver.json +0 -20
  398. package/data/harnesses/code/skills/design/data/design-tokens/nurix/design.tokens.json +0 -1209
  399. package/data/harnesses/code/skills/design/data/design-tokens/nvidia/design.resolver.json +0 -20
  400. package/data/harnesses/code/skills/design/data/design-tokens/nvidia/design.tokens.json +0 -1265
  401. package/data/harnesses/code/skills/design/data/design-tokens/ollama/design.resolver.json +0 -20
  402. package/data/harnesses/code/skills/design/data/design-tokens/ollama/design.tokens.json +0 -1253
  403. package/data/harnesses/code/skills/design/data/design-tokens/opencode-ai/design.resolver.json +0 -20
  404. package/data/harnesses/code/skills/design/data/design-tokens/opencode-ai/design.tokens.json +0 -1268
  405. package/data/harnesses/code/skills/design/data/design-tokens/posthog/design.resolver.json +0 -20
  406. package/data/harnesses/code/skills/design/data/design-tokens/posthog/design.tokens.json +0 -1261
  407. package/data/harnesses/code/skills/design/data/design-tokens/raycast/design.resolver.json +0 -20
  408. package/data/harnesses/code/skills/design/data/design-tokens/raycast/design.tokens.json +0 -1263
  409. package/data/harnesses/code/skills/design/data/design-tokens/replicate/design.resolver.json +0 -20
  410. package/data/harnesses/code/skills/design/data/design-tokens/replicate/design.tokens.json +0 -1266
  411. package/data/harnesses/code/skills/design/data/design-tokens/resend/design.resolver.json +0 -23
  412. package/data/harnesses/code/skills/design/data/design-tokens/resend/design.tokens.dark.json +0 -623
  413. package/data/harnesses/code/skills/design/data/design-tokens/resend/design.tokens.json +0 -1276
  414. package/data/harnesses/code/skills/design/data/design-tokens/revolut/design.resolver.json +0 -20
  415. package/data/harnesses/code/skills/design/data/design-tokens/revolut/design.tokens.json +0 -1264
  416. package/data/harnesses/code/skills/design/data/design-tokens/runwayml/design.resolver.json +0 -20
  417. package/data/harnesses/code/skills/design/data/design-tokens/runwayml/design.tokens.json +0 -1268
  418. package/data/harnesses/code/skills/design/data/design-tokens/sanity/design.resolver.json +0 -20
  419. package/data/harnesses/code/skills/design/data/design-tokens/sanity/design.tokens.json +0 -1270
  420. package/data/harnesses/code/skills/design/data/design-tokens/sentry/design.resolver.json +0 -20
  421. package/data/harnesses/code/skills/design/data/design-tokens/sentry/design.tokens.json +0 -1288
  422. package/data/harnesses/code/skills/design/data/design-tokens/shopify/design.resolver.json +0 -20
  423. package/data/harnesses/code/skills/design/data/design-tokens/shopify/design.tokens.json +0 -1272
  424. package/data/harnesses/code/skills/design/data/design-tokens/slack/design.resolver.json +0 -20
  425. package/data/harnesses/code/skills/design/data/design-tokens/slack/design.tokens.json +0 -1265
  426. package/data/harnesses/code/skills/design/data/design-tokens/spacex/design.resolver.json +0 -20
  427. package/data/harnesses/code/skills/design/data/design-tokens/spacex/design.tokens.json +0 -1287
  428. package/data/harnesses/code/skills/design/data/design-tokens/spotify/design.resolver.json +0 -20
  429. package/data/harnesses/code/skills/design/data/design-tokens/spotify/design.tokens.json +0 -1286
  430. package/data/harnesses/code/skills/design/data/design-tokens/stripe/design.resolver.json +0 -20
  431. package/data/harnesses/code/skills/design/data/design-tokens/stripe/design.tokens.json +0 -1285
  432. package/data/harnesses/code/skills/design/data/design-tokens/supabase/design.resolver.json +0 -20
  433. package/data/harnesses/code/skills/design/data/design-tokens/supabase/design.tokens.json +0 -1287
  434. package/data/harnesses/code/skills/design/data/design-tokens/superhuman/design.resolver.json +0 -20
  435. package/data/harnesses/code/skills/design/data/design-tokens/superhuman/design.tokens.json +0 -1278
  436. package/data/harnesses/code/skills/design/data/design-tokens/tesla/design.resolver.json +0 -20
  437. package/data/harnesses/code/skills/design/data/design-tokens/tesla/design.tokens.json +0 -1269
  438. package/data/harnesses/code/skills/design/data/design-tokens/theverge/design.resolver.json +0 -20
  439. package/data/harnesses/code/skills/design/data/design-tokens/theverge/design.tokens.json +0 -1285
  440. package/data/harnesses/code/skills/design/data/design-tokens/together-ai/design.resolver.json +0 -20
  441. package/data/harnesses/code/skills/design/data/design-tokens/together-ai/design.tokens.json +0 -1303
  442. package/data/harnesses/code/skills/design/data/design-tokens/uber/design.resolver.json +0 -20
  443. package/data/harnesses/code/skills/design/data/design-tokens/uber/design.tokens.json +0 -1274
  444. package/data/harnesses/code/skills/design/data/design-tokens/vercel/design.resolver.json +0 -20
  445. package/data/harnesses/code/skills/design/data/design-tokens/vercel/design.tokens.json +0 -1296
  446. package/data/harnesses/code/skills/design/data/design-tokens/voltagent/design.resolver.json +0 -23
  447. package/data/harnesses/code/skills/design/data/design-tokens/voltagent/design.tokens.dark.json +0 -612
  448. package/data/harnesses/code/skills/design/data/design-tokens/voltagent/design.tokens.json +0 -1282
  449. package/data/harnesses/code/skills/design/data/design-tokens/warp/design.resolver.json +0 -20
  450. package/data/harnesses/code/skills/design/data/design-tokens/warp/design.tokens.json +0 -1287
  451. package/data/harnesses/code/skills/design/data/design-tokens/webflow/design.resolver.json +0 -20
  452. package/data/harnesses/code/skills/design/data/design-tokens/webflow/design.tokens.json +0 -1268
  453. package/data/harnesses/code/skills/design/data/design-tokens/wired/design.resolver.json +0 -20
  454. package/data/harnesses/code/skills/design/data/design-tokens/wired/design.tokens.json +0 -1276
  455. package/data/harnesses/code/skills/design/data/design-tokens/wise/design.resolver.json +0 -20
  456. package/data/harnesses/code/skills/design/data/design-tokens/wise/design.tokens.json +0 -1273
  457. package/data/harnesses/code/skills/design/data/design-tokens/x-ai/design.resolver.json +0 -20
  458. package/data/harnesses/code/skills/design/data/design-tokens/x-ai/design.tokens.json +0 -1296
  459. package/data/harnesses/code/skills/design/data/design-tokens/zapier/design.resolver.json +0 -20
  460. package/data/harnesses/code/skills/design/data/design-tokens/zapier/design.tokens.json +0 -1286
  461. package/data/harnesses/code/skills/design/data/operator-pack/exemplars/command-center.tsx +0 -249
  462. package/data/harnesses/code/skills/design/data/operator-pack/exemplars/create-edit.tsx +0 -249
  463. package/data/harnesses/code/skills/design/data/operator-pack/exemplars/dashboard.tsx +0 -225
  464. package/data/harnesses/code/skills/design/data/operator-pack/exemplars/entity-detail.tsx +0 -249
  465. package/data/harnesses/code/skills/design/data/operator-pack/exemplars/list-detail.tsx +0 -224
  466. package/data/harnesses/code/skills/design/data/operator-pack/exemplars/log-stream.tsx +0 -249
  467. package/data/harnesses/code/skills/design/data/operator-pack/fixtures.md +0 -88
  468. package/data/harnesses/code/skills/design/data/operator-pack/surface-catalog.md +0 -132
  469. package/data/harnesses/code/skills/design/data/operator-pack/trust-rubric.md +0 -76
  470. package/data/harnesses/code/skills/design/references/create.md +0 -173
  471. package/data/harnesses/code/skills/design/references/diagnosis.md +0 -108
  472. package/data/harnesses/code/skills/design/references/hard-rules.md +0 -177
  473. package/data/harnesses/code/skills/design/references/improve.md +0 -116
  474. package/data/harnesses/code/skills/design/references/interaction.md +0 -77
  475. package/data/harnesses/code/skills/design/references/introspect.md +0 -100
  476. package/data/harnesses/code/skills/design/references/lifecycle.md +0 -73
  477. package/data/harnesses/code/skills/design/references/personality.md +0 -575
  478. package/data/harnesses/code/skills/design/references/structure.md +0 -159
  479. package/data/harnesses/code/skills/design/scripts/convert-design-md.mjs +0 -1312
  480. package/data/harnesses/code/skills/design/scripts/derive-personality.mjs +0 -1498
  481. package/data/harnesses/code/skills/design/scripts/generate-fixtures.mjs +0 -551
  482. package/data/harnesses/code/skills/design/scripts/lib/checks.mjs +0 -1092
  483. package/data/harnesses/code/skills/design/scripts/lib/golden.mjs +0 -26
  484. package/data/harnesses/code/skills/design/scripts/lib/vocabulary.mjs +0 -65
  485. package/data/harnesses/code/skills/design/scripts/phase-gate.mjs +0 -538
  486. package/data/harnesses/code/skills/design/scripts/preship-sweep.mjs +0 -312
  487. package/data/harnesses/code/skills/design/scripts/render-rung.mjs +0 -890
  488. package/data/harnesses/code/skills/design/scripts/scaffold.mjs +0 -769
  489. package/data/harnesses/code/skills/design/scripts/self-integrity.mjs +0 -675
  490. package/data/harnesses/code/skills/design/scripts/snapshot-goldens.mjs +0 -164
  491. package/data/harnesses/code/skills/design/scripts/validate-combinations.mjs +0 -439
@@ -1,26 +0,0 @@
1
- // skills/design/scripts/lib/golden.mjs — golden-CSS comparison primitives: comment stripping + sha256 hashing for the byte-match regression oracle.
2
-
3
- import { createHash } from "node:crypto";
4
-
5
- // Remove every /* ... */ comment block (CSS has no other comment syntax; an unterminated comment strips to EOF) — no whitespace normalization, byte-exact otherwise.
6
- export function stripCssComments(css) {
7
- let out = "";
8
- let i = 0;
9
- while (i < css.length) {
10
- const open = css.indexOf("/*", i);
11
- if (open === -1) {
12
- out += css.slice(i);
13
- break;
14
- }
15
- out += css.slice(i, open);
16
- const close = css.indexOf("*/", open + 2);
17
- if (close === -1) break; // unterminated comment: strip to EOF
18
- i = close + 2;
19
- }
20
- return out;
21
- }
22
-
23
- // sha256 hex digest of stripCssComments(css) — the golden fingerprint of one emitted CSS file.
24
- export function goldenHash(css) {
25
- return createHash("sha256").update(stripCssComments(css), "utf8").digest("hex");
26
- }
@@ -1,65 +0,0 @@
1
- // skills/design/scripts/lib/vocabulary.mjs — single-source shared runtime vocabulary for the design skill's scripts: the delight-budget enum + file-header stamps, the surface-archetype budget defaults, the motion-moment class names, and the theme attribute convention. scaffold.mjs writes these strings; phase-gate.mjs reads them at the surfaces gate; the preship sweep and emission read them in later steps. One module so the stamp text, the enum, and the theme names never drift between the writer and its readers.
2
-
3
- // The two delight-budget values a surface can carry (references/structure.md, the delight budget).
4
- export const BUDGETS = ['baseline', 'brand-forward'];
5
-
6
- // The verbatim file-header comment scaffold.mjs writes at the top of each surface route file, keyed by budget.
7
- export const BUDGET_STAMPS = {
8
- baseline: '// Surface: baseline',
9
- 'brand-forward': '// Surface: brand-forward (delight-allowing)',
10
- };
11
-
12
- // The stamp comment for a budget, or null when it is not one of BUDGETS.
13
- export function stampFor(budget) {
14
- return Object.prototype.hasOwnProperty.call(BUDGET_STAMPS, budget) ? BUDGET_STAMPS[budget] : null;
15
- }
16
-
17
- // Matches any `// Surface:` header line, well-formed or not — gates count these to catch a malformed
18
- // or duplicated stamp against the well-formed matches below.
19
- export const BUDGET_STAMP_LOOSE_RE = /\/\/ Surface:.*/g;
20
-
21
- // Every well-formed budget stamp in a source blob, in order, as budget values ('baseline' | 'brand-forward').
22
- // Gates count occurrences (exactly one per route file) and read the stamped budget from this.
23
- export function findBudgetStamps(source) {
24
- const re = /\/\/ Surface: (brand-forward \(delight-allowing\)|baseline)(?=\s|$)/g;
25
- const found = [];
26
- let m;
27
- while ((m = re.exec(String(source))) !== null) {
28
- found.push(m[1].startsWith('brand-forward') ? 'brand-forward' : 'baseline');
29
- }
30
- return found;
31
- }
32
-
33
- // Surface archetypes whose delight budget defaults to `baseline` — a `brand-forward` stamp on one of
34
- // these needs a recorded reason in the surface map (references/structure.md, the delight budget).
35
- export const BASELINE_DEFAULT_ARCHETYPES = ['list-detail', 'log-stream', 'command-center'];
36
-
37
- // Surface archetypes that are `brand-forward` *candidates* — granted when the look's delight is
38
- // expressive or the brief asks for presence, else baseline; no recorded reason needed either way.
39
- export const BRAND_FORWARD_CANDIDATE_ARCHETYPES = ['dashboard', 'entity-detail', 'create-edit'];
40
-
41
- // True when a `brand-forward` stamp on this archetype requires a recorded reason in the surface map.
42
- export function requiresBudgetReason(archetype, budget) {
43
- return budget === 'brand-forward' && BASELINE_DEFAULT_ARCHETYPES.includes(String(archetype));
44
- }
45
-
46
- // Motion-moment CSS classes (references/structure.md the delight budget; data/combinations/motion.csv).
47
- // scaffold consumes them where the archetype calls: table rows ride motion-lift (hover feedback,
48
- // budget-free); card grids ride motion-stagger on brand-forward surfaces only — baseline-stamped
49
- // surfaces skip arrival cascades (mot-08). The render rung audits rendered stagger containers.
50
- export const MOTION_LIFT_CLASS = 'motion-lift';
51
- export const MOTION_STAGGER_CLASS = 'motion-stagger';
52
- // The derived custom property the stagger cascade reads; cap the staggered children at STAGGER_CHILD_CAP.
53
- export const STAGGER_DELAY_VAR = '--stagger-delay';
54
- export const STAGGER_CHILD_CAP = 8;
55
-
56
- // The theme runtime attribute: its name and the two legal rendered values. look.theme `both` boots
57
- // light with a working toggle, so the emitted default is always one of these two.
58
- export const THEME_ATTR = 'data-theme';
59
- export const THEME_VALUES = ['light', 'dark'];
60
-
61
- // Resolve a look.theme (light | dark | both) to the emitted default data-theme value (both → light);
62
- // anything unrecognized falls back to light.
63
- export function resolveThemeDefault(theme) {
64
- return theme === 'dark' ? 'dark' : 'light';
65
- }
@@ -1,538 +0,0 @@
1
- // skills/design/scripts/phase-gate.mjs — create-phase precondition gates (D21/D23): validate the named phase's exit preconditions, printing the exact fix on failure; every gate also fires the machine-check engine (lib/checks.mjs — per-file catalog + manifest drift) over the project's whole UI tree and exits non-zero on either failure.
2
- import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
3
- import { join, dirname, resolve, relative } from 'node:path';
4
- import { fileURLToPath } from 'node:url';
5
- import { spawnSync } from 'node:child_process';
6
- import { runChecks, formatFindings, walkUiFiles } from './lib/checks.mjs';
7
- import { findBudgetStamps, BUDGET_STAMP_LOOSE_RE, requiresBudgetReason } from './lib/vocabulary.mjs';
8
-
9
- const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url));
10
- const PHASES = ['intake', 'structure', 'scaffold', 'tokens', 'fixtures', 'surfaces'];
11
- const ARCHETYPES = new Set(['list-detail', 'dashboard', 'entity-detail', 'create-edit', 'log-stream', 'command-center']);
12
- const PROVENANCE = new Set(['project', 'extracted', 'library', 'default']);
13
- const STATE_SYNONYMS = { loading: ['loading', 'skeleton'], empty: ['empty'], error: ['error'], partial: ['partial', 'degraded', 'stale'] };
14
- // The intake look block's enums (references/create.md, the look block). theme carries `both`; the emitted
15
- // data-theme value the attribute cascade uses is light|dark (both boots light) — that pair lives in vocabulary.mjs.
16
- const LOOK_THEMES = new Set(['light', 'dark', 'both']);
17
- const DELIGHT_LEVELS = new Set(['baseline', 'expressive']);
18
- const RESOLUTION_MODES = new Set(['confirmed', 'recorded']);
19
- // The resolution spine's legal shapes: project | library:<slug> | seed:<style-row>+<palette-row> | default.
20
- const RESOLUTION_RE = /^(project|default|library:.+|seed:.+\+.+)$/i;
21
-
22
- const useColor = process.stdout.isTTY;
23
- // Wrap a string in green/red when writing to a TTY, plain otherwise.
24
- const green = (s) => (useColor ? `\x1b[32m${s}\x1b[0m` : s);
25
- const red = (s) => (useColor ? `\x1b[31m${s}\x1b[0m` : s);
26
-
27
- // Read a UTF-8 file, returning '' when it is absent.
28
- function readText(path) {
29
- try { return readFileSync(path, 'utf8'); } catch { return ''; }
30
- }
31
-
32
- // Sentinel a gate throws (via fail) to abort its remaining precondition checks without exiting the process.
33
- class GateFailure extends Error {}
34
-
35
- // Report a passing gate as one green line (the process exit code is decided in main, after the source sweep).
36
- function pass(phase, msg) {
37
- console.log(`${green(`PASS phase-gate[${phase}]`)} ${msg}`);
38
- }
39
-
40
- // Report a failing gate with the problem and the exact fix, then abort the gate.
41
- function fail(phase, problem, fixLines) {
42
- console.error(`${red(`FAIL phase-gate[${phase}]`)} ${problem}`);
43
- console.error('');
44
- console.error(' Fix:');
45
- for (const line of fixLines) {
46
- if (line == null || line === '') continue;
47
- for (const sub of String(line).split('\n')) console.error(` ${sub}`);
48
- }
49
- throw new GateFailure(problem);
50
- }
51
-
52
- // Lowercase-kebab a display name for route-dir / fixture-module matching.
53
- function kebab(s) {
54
- return String(s).trim().toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');
55
- }
56
-
57
- // Return the first non-parameter path segment of a route (/tickets/:id -> tickets).
58
- function firstStaticSegment(route) {
59
- for (const p of String(route).split('/').filter(Boolean)) {
60
- if (!p.startsWith(':')) return kebab(p);
61
- }
62
- return null;
63
- }
64
-
65
- // Return the last non-parameter path segment of a route (/tickets/new -> new).
66
- function lastStaticSegment(route) {
67
- const parts = String(route).split('/').filter(Boolean).filter((p) => !p.startsWith(':'));
68
- return parts.length ? kebab(parts[parts.length - 1]) : null;
69
- }
70
-
71
- // Parse a JSON file into an object, or null when it is absent or malformed.
72
- function readJson(path) {
73
- try {
74
- const parsed = JSON.parse(readFileSync(path, 'utf8'));
75
- return parsed && typeof parsed === 'object' ? parsed : null;
76
- } catch { return null; }
77
- }
78
-
79
- // Collect every token file the resolver references (set values plus all modifier-context overlays).
80
- function resolverNamedFiles(resolver) {
81
- const named = [];
82
- for (const set of Array.isArray(resolver.sets) ? resolver.sets : []) {
83
- if (set && Array.isArray(set.values)) named.push(...set.values.filter((f) => typeof f === 'string'));
84
- }
85
- for (const mod of Array.isArray(resolver.modifiers) ? resolver.modifiers : []) {
86
- const contexts = mod && mod.contexts && typeof mod.contexts === 'object' ? mod.contexts : {};
87
- for (const files of Object.values(contexts)) {
88
- if (Array.isArray(files)) named.push(...files.filter((f) => typeof f === 'string'));
89
- }
90
- }
91
- return named;
92
- }
93
-
94
- // Split a `[a, b, c]` inline list into trimmed members.
95
- function parseBracketList(s) {
96
- const m = String(s).match(/\[([^\]]*)\]/);
97
- if (!m) return [];
98
- return m[1].split(',').map((x) => x.trim()).filter(Boolean);
99
- }
100
-
101
- // Store one `key: value` pair onto a list-item object, parsing `states` into an array.
102
- function applyKV(obj, s) {
103
- const idx = s.indexOf(':');
104
- if (idx < 0) return;
105
- const key = s.slice(0, idx).trim();
106
- const value = s.slice(idx + 1).trim();
107
- if (key === 'states') obj.states = parseBracketList(value);
108
- else obj[key] = value;
109
- }
110
-
111
- // Parse the fenced ```yaml structure block into entities, surfaces, and temporal facts.
112
- function parseStructureBlock(md) {
113
- const m = md.match(/```yaml structure\r?\n([\s\S]*?)```/);
114
- if (!m) return null;
115
- const result = { unitOfWork: null, coreLoop: null, entities: [], temporal: null, surfaces: [] };
116
- let section = null;
117
- let itemIndent = -1;
118
- let current = null;
119
- for (const raw of m[1].split(/\r?\n/)) {
120
- if (!raw.trim() || raw.trim().startsWith('#')) continue;
121
- const indent = raw.length - raw.trimStart().length;
122
- const line = raw.trim();
123
- if (indent === 0) {
124
- current = null;
125
- itemIndent = -1;
126
- if (line.startsWith('unit-of-work:')) { result.unitOfWork = line.slice(line.indexOf(':') + 1).trim(); section = null; }
127
- else if (line.startsWith('core-loop:')) { result.coreLoop = line.slice(line.indexOf(':') + 1).trim(); section = null; }
128
- else if (line === 'entities:') section = 'entities';
129
- else if (line === 'surfaces:') section = 'surfaces';
130
- else if (line === 'temporal:') { section = 'temporal'; result.temporal = {}; }
131
- else section = null;
132
- continue;
133
- }
134
- if (section === 'entities' || section === 'surfaces') {
135
- const list = section === 'entities' ? result.entities : result.surfaces;
136
- if (line.startsWith('- ')) {
137
- if (itemIndent === -1) itemIndent = indent;
138
- if (indent === itemIndent) {
139
- current = {};
140
- list.push(current);
141
- const rest = line.slice(2).trim();
142
- if (rest && rest.includes(':')) applyKV(current, rest);
143
- }
144
- } else if (current && itemIndent !== -1 && indent > itemIndent) {
145
- applyKV(current, line);
146
- }
147
- } else if (section === 'temporal') {
148
- const idx = line.indexOf(':');
149
- if (idx > 0) result.temporal[line.slice(0, idx).trim()] = line.slice(idx + 1).trim();
150
- }
151
- }
152
- return result;
153
- }
154
-
155
- // Read and parse the structure map, or fail the gate with the structure-phase fix.
156
- function requireMap(phase, project) {
157
- const p = join(project, 'docs/design/structure.md');
158
- if (!existsSync(p)) {
159
- fail(phase, `No entity/surface map at ${p} — this phase reads it.`, [
160
- 'Complete the structure phase first: derive docs/design/structure.md with a fenced ```yaml structure block (references/structure.md).',
161
- ]);
162
- }
163
- const blk = parseStructureBlock(readText(p));
164
- if (!blk) {
165
- fail(phase, `${p} has no parseable "yaml structure" fenced block.`, [
166
- 'The block must open exactly with the fence info-string `yaml structure` and carry entities[], temporal, and surfaces[].',
167
- ]);
168
- }
169
- return blk;
170
- }
171
-
172
- // Collect all .ts/.tsx source under a route directory into one lowercased blob.
173
- function routeSource(dir) {
174
- return routeSourceRaw(dir).toLowerCase();
175
- }
176
-
177
- // Collect all .ts/.tsx source under a route directory, case preserved (the budget stamp is case-sensitive).
178
- function routeSourceRaw(dir) {
179
- let out = '';
180
- const stack = [dir];
181
- while (stack.length) {
182
- const cur = stack.pop();
183
- let entries;
184
- try { entries = readdirSync(cur, { withFileTypes: true }); } catch { continue; }
185
- for (const ent of entries) {
186
- const full = join(cur, ent.name);
187
- if (ent.isDirectory()) stack.push(full);
188
- else if (/\.(tsx|ts)$/.test(ent.name)) out += `\n${readText(full)}`;
189
- }
190
- }
191
- return out;
192
- }
193
-
194
- // Return the candidate route-dir slugs for a surface (name-kebab, route segments, archetype).
195
- function routeDirCandidates(s) {
196
- const out = [];
197
- if (s.name) out.push(kebab(s.name));
198
- if (s.route) { const f = firstStaticSegment(s.route); if (f) out.push(f); const l = lastStaticSegment(s.route); if (l) out.push(l); }
199
- if (s.archetype) out.push(s.archetype);
200
- return [...new Set(out.filter(Boolean))];
201
- }
202
-
203
- // Resolve a surface's route directory to the first existing candidate, or null.
204
- function resolveRouteDir(s, routesDir) {
205
- for (const c of routeDirCandidates(s)) {
206
- const d = join(routesDir, c);
207
- if (existsSync(d) && statSync(d).isDirectory()) return d;
208
- }
209
- return null;
210
- }
211
-
212
- // List the declared states whose branch is absent from a route's shell source.
213
- function missingStates(dir, states) {
214
- const text = routeSource(dir);
215
- return states.filter((st) => {
216
- const words = STATE_SYNONYMS[st] || [st.toLowerCase()];
217
- return !words.some((w) => text.includes(w));
218
- });
219
- }
220
-
221
- // Validate the load-bearing five-step globals.css import order (Cascade Contract 2).
222
- function checkImportOrder(rawCss) {
223
- const css = rawCss.replace(/\/\*[\s\S]*?\*\//g, '').replace(/^[ \t]*\/\/.*$/gm, '');
224
- const marks = [
225
- ['@import "./personality.css"', css.indexOf('@import "./personality.css"')],
226
- ['@import "tailwindcss"', css.indexOf('@import "tailwindcss"')],
227
- ['@import "@nurix/components/styles.css"', css.indexOf('@import "@nurix/components/styles.css"')],
228
- ['@theme inline', css.search(/^\s*@theme\s+inline\b/m)],
229
- ];
230
- const absent = marks.filter(([, i]) => i < 0).map(([n]) => n);
231
- if (absent.length) {
232
- return { problem: `globals.css is missing: ${absent.join(', ')}.`, fix: [
233
- 'Emit the five-step cascade order (references/personality.md §4, Cascade Contract 2):',
234
- '@import "./personality.css"; -> @import "tailwindcss"; -> @import "@nurix/components/styles.css"; -> @theme inline { ... }',
235
- ] };
236
- }
237
- const [p, t, l, th] = marks.map(([, i]) => i);
238
- if (!(p < t && t < l && l < th)) {
239
- return { problem: 'globals.css import order is wrong — personality -> tailwindcss -> library -> @theme is load-bearing.', fix: [
240
- 'Reorder so the consumer @theme inline comes AFTER the @nurix/components/styles.css import, or the library radius scale and token defaults win.',
241
- ] };
242
- }
243
- return null;
244
- }
245
-
246
- // Validate the payload's mandatory look block (references/create.md, the look block): presence, the theme /
247
- // delight / resolution-mode enums, 2–3 named anchor strings, the resolution shape, and — when the
248
- // resolution was authorized autonomously (resolution-mode: recorded) — that the artifact root
249
- // $description carries a resolution record naming the runner-up. Fails the gate with the exact fix.
250
- function validateLookBlock(payload, tokens) {
251
- const look = payload.look;
252
- if (!look || typeof look !== 'object' || Array.isArray(look)) {
253
- fail('intake', 'payload carries no look block (payload.look).', [
254
- 'Add the mandatory look block to the artifact payload (references/create.md, the look block):',
255
- 'look: { theme: light|dark|both, anchors: ["Product A", "Product B"], delight: baseline|expressive,',
256
- ' resolution: project | library:<slug> | seed:<style>+<palette> | default, resolution-mode: confirmed|recorded }.',
257
- ]);
258
- }
259
- if (!LOOK_THEMES.has(look.theme)) {
260
- fail('intake', `look.theme is "${look.theme ?? '(missing)'}"; must be light | dark | both.`, [
261
- 'Set look.theme from the brief; it is binding when stated, default light (references/create.md, the look block).',
262
- ]);
263
- }
264
- if (!DELIGHT_LEVELS.has(look.delight)) {
265
- fail('intake', `look.delight is "${look.delight ?? '(missing)'}"; must be baseline | expressive.`, [
266
- 'Set look.delight — the global delight ceiling per-surface budgets refine (references/create.md the look block, references/structure.md the delight budget).',
267
- ]);
268
- }
269
- const mode = look['resolution-mode'];
270
- if (!RESOLUTION_MODES.has(mode)) {
271
- fail('intake', `look.resolution-mode is "${mode ?? '(missing)'}"; must be confirmed | recorded.`, [
272
- 'Set look.resolution-mode: confirmed when a confirmer authorized the pick, recorded when it was resolved autonomously (references/create.md, Resolution).',
273
- ]);
274
- }
275
- const anchors = look.anchors;
276
- if (!Array.isArray(anchors) || anchors.length < 2 || anchors.length > 3 || !anchors.every((a) => typeof a === 'string' && a.trim())) {
277
- fail('intake', `look.anchors must be 2–3 non-empty named strings; got ${JSON.stringify(anchors ?? null)}.`, [
278
- 'Name two or three real products (["Linear", "Stripe Dashboard"]); adjectives are not anchors —',
279
- 'convert an adjective to a named product by asking (interactive) or inferring-and-recording (autonomous) via the design-md resemblance lookup (references/create.md, the look block).',
280
- ]);
281
- }
282
- if (typeof look.resolution !== 'string' || !RESOLUTION_RE.test(look.resolution.trim())) {
283
- fail('intake', `look.resolution is "${look.resolution ?? '(missing)'}"; must match project | library:<slug> | seed:<style>+<palette> | default.`, [
284
- 'Set look.resolution to the resolved source from the precedence spine (references/create.md, Resolution).',
285
- ]);
286
- }
287
- if (mode === 'recorded') {
288
- const desc = tokens.$description;
289
- if (typeof desc !== 'string' || !desc.trim() || !/runner-up/i.test(desc)) {
290
- fail('intake', 'resolution-mode is recorded but the artifact root $description carries no resolution record naming the runner-up.', [
291
- 'Write the resolution record into the artifact root $description — winner, runner-up, and the deciding evidence, e.g.:',
292
- 'resolution: library:stripe (recorded; runner-up palettes.csv#3; brief phrase "Stripe-dashboard territory" matched product + fintech traits).',
293
- 'A recorded (autonomous) resolution is legitimate only once it is auditable (references/create.md, Resolution).',
294
- ]);
295
- }
296
- }
297
- }
298
-
299
- // intake gate: a structurally sound design-tokens artifact sits at project root — both files parse, the dark
300
- // file agrees with the resolver, the payload carries a legal schema/provenance/product, and the mandatory
301
- // look block is present and well-formed. Light checks only; deep validation (coverage, aliases, parse-back)
302
- // is derive-personality.mjs --check at the tokens gate.
303
- function gateIntake(project) {
304
- const tokensPath = join(project, 'design.tokens.json');
305
- const resolverPath = join(project, 'design.resolver.json');
306
- const absent = [tokensPath, resolverPath].filter((p) => !existsSync(p)).map((p) => relative(project, p));
307
- if (absent.length) {
308
- fail('intake', `Missing token-artifact file(s) at project root: ${absent.join(', ')}.`, [
309
- 'Write the design-tokens artifact against skills/design/data/design-tokens/SCHEMA.md:',
310
- 'design.tokens.json (base/light set + the $extensions["com.nurix.design"] payload) and design.resolver.json,',
311
- 'plus design.tokens.dark.json only when the look has dark values.',
312
- 'Resolve the look artifact-first: the project artifact wins, else a confirmed library entry, else the Nurix default.',
313
- ]);
314
- }
315
- const tokens = readJson(tokensPath);
316
- if (!tokens) fail('intake', 'design.tokens.json does not parse as JSON.', ['Fix the JSON before anything deeper runs (data/design-tokens/SCHEMA.md).']);
317
- const resolver = readJson(resolverPath);
318
- if (!resolver) fail('intake', 'design.resolver.json does not parse as JSON.', ['Fix the JSON (data/design-tokens/SCHEMA.md — the resolver section).']);
319
- const namesDark = resolverNamedFiles(resolver).includes('design.tokens.dark.json');
320
- const hasDark = existsSync(join(project, 'design.tokens.dark.json'));
321
- if (namesDark && !hasDark) {
322
- fail('intake', 'design.resolver.json names design.tokens.dark.json but the file is absent.', [
323
- 'Ship the dark modifier set beside the base file, or drop the dark context from the resolver —',
324
- 'the dark file exists exactly when the resolver names it (data/design-tokens/SCHEMA.md).',
325
- ]);
326
- }
327
- if (!namesDark && hasDark) {
328
- fail('intake', 'design.tokens.dark.json is present but the resolver names no dark context.', [
329
- 'Add "dark": ["design.tokens.dark.json"] to the theme modifier contexts, or remove the dark file —',
330
- 'the dark file exists exactly when the resolver names it (data/design-tokens/SCHEMA.md).',
331
- ]);
332
- }
333
- const payload = tokens.$extensions && tokens.$extensions['com.nurix.design'];
334
- if (!payload || typeof payload !== 'object') {
335
- fail('intake', 'design.tokens.json carries no root $extensions["com.nurix.design"] payload.', [
336
- 'Add the file-level payload (schema, dtcg, product, provenance, sourced, lever-manifest, …) per data/design-tokens/SCHEMA.md.',
337
- ]);
338
- }
339
- if (payload.schema !== 'design-tokens/v2') fail('intake', `payload schema is "${payload.schema || '(missing)'}", expected design-tokens/v2.`, ['Set schema: "design-tokens/v2" in the payload (data/design-tokens/SCHEMA.md).']);
340
- if (!PROVENANCE.has(payload.provenance)) fail('intake', `payload provenance is "${payload.provenance || '(missing)'}"; must be one of project|extracted|library|default.`, ['Set provenance to one of: project | extracted | library | default (data/design-tokens/SCHEMA.md).']);
341
- if (typeof payload.product !== 'string' || !payload.product.trim()) fail('intake', 'payload product is missing or empty.', ['Set product to the product name; slugified it becomes the data-style value (data/design-tokens/SCHEMA.md).']);
342
- validateLookBlock(payload, tokens);
343
- pass('intake', `design.tokens.json + design.resolver.json present and parsing; payload schema design-tokens/v2, provenance "${payload.provenance}"${namesDark ? ', dark set named and present' : ', light-only'}; look block valid (theme ${payload.look.theme}, delight ${payload.look.delight}, ${Array.isArray(payload.look.anchors) ? payload.look.anchors.length : 0} anchors, resolution-mode ${payload.look['resolution-mode']}).`);
344
- }
345
-
346
- // structure gate: the map parses, is populated, has a temporal block, and every surface archetype is one of the six.
347
- function gateStructure(project) {
348
- const blk = requireMap('structure', project);
349
- if (!blk.entities.length) fail('structure', 'The structure map has no entities — the object pass was skipped.', ['Populate entities[] from the domain nouns (references/structure.md -> object pass); a small brief earns a small pass, never a skipped one.']);
350
- if (!blk.surfaces.length) fail('structure', 'The structure map has no surfaces.', ['Assign each surface an archetype from the closed six under surfaces[].']);
351
- if (!blk.temporal || !Object.keys(blk.temporal).length) fail('structure', 'The structure map has no temporal block.', ['Add the temporal probe (intermediate-states, read-model-lag, deletion, failure-paths) — model facts, not later polish.']);
352
- const bad = blk.surfaces.filter((s) => !ARCHETYPES.has(s.archetype));
353
- if (bad.length) {
354
- fail('structure', `${bad.length} surface(s) carry an archetype outside the closed six: ${bad.map((s) => `${s.name || '(unnamed)'}="${s.archetype || '(none)'}"`).join(', ')}.`, [
355
- `Every surface's archetype must be one of: ${[...ARCHETYPES].join(', ')}.`,
356
- ]);
357
- }
358
- pass('structure', `${blk.surfaces.length} surface(s), all archetypes valid; ${blk.entities.length} entit(ies) and a temporal block present.`);
359
- }
360
-
361
- // scaffold gate: the shell, per-surface route dirs + state-shells, router wiring, and globals.css import order are in place.
362
- function gateScaffold(project) {
363
- const blk = requireMap('scaffold', project);
364
- const shellFiles = ['index.html', 'src/main.tsx', 'src/App.tsx'];
365
- const missing = shellFiles.filter((f) => !existsSync(join(project, f)));
366
- if (missing.length) {
367
- fail('scaffold', `Missing shell file(s): ${missing.join(', ')}.`, [
368
- `Run scaffold.mjs docs/design/structure.md --out ${project} to emit index.html, src/main.tsx, src/App.tsx, route wiring, and state-shells.`,
369
- ]);
370
- }
371
- const indexHtml = readText(join(project, 'index.html'));
372
- if (!/<html[^>]*\bdata-style=/.test(indexHtml)) {
373
- fail('scaffold', 'index.html <html> is missing the data-style attribute.', [
374
- 'Emit <html data-style="..." data-density="..." data-verbosity="..." data-feedback="..." data-theme="light"> (references/personality.md §5).',
375
- ]);
376
- }
377
- const routesDir = join(project, 'src/routes');
378
- const app = readText(join(project, 'src/App.tsx'));
379
- const noRoute = [];
380
- const noWire = [];
381
- const noShell = [];
382
- for (const s of blk.surfaces) {
383
- const dir = resolveRouteDir(s, routesDir);
384
- const name = s.name || s.route || '(unnamed)';
385
- if (!dir) { noRoute.push(`${name} (expected src/routes/${routeDirCandidates(s).join(' or /')})`); continue; }
386
- const seg = s.route ? firstStaticSegment(s.route) : null;
387
- if (seg && !app.toLowerCase().includes(seg)) noWire.push(`${name} (route "${s.route}" not referenced in src/App.tsx)`);
388
- const states = (s.states && s.states.length) ? s.states : ['loading', 'empty', 'error', 'partial'];
389
- const miss = missingStates(dir, states);
390
- if (miss.length) noShell.push(`${name} (no ${miss.join(', ')} shell)`);
391
- }
392
- if (noRoute.length) fail('scaffold', `No route directory for surface(s): ${noRoute.join('; ')}.`, ['scaffold.mjs owns route/nav wiring — emit src/routes/<surface>/ per surface from the map.']);
393
- if (noWire.length) fail('scaffold', `Route(s) not wired into the router: ${noWire.join('; ')}.`, ['Every surface route must be registered in src/App.tsx (react-router-dom) — routes and nav derive from the map, never decorated on.']);
394
- if (noShell.length) fail('scaffold', `Missing state-shell stubs: ${noShell.join('; ')}.`, ['Each surface needs its loading / empty / error / degraded shells wired (references/create.md -> scaffold).']);
395
- const globals = join(project, 'src/styles/globals.css');
396
- if (!existsSync(globals)) fail('scaffold', 'Missing src/styles/globals.css (Tailwind glue with the five-step import order).', ['Emit src/styles/globals.css with the Cascade Contract 2 import order (references/personality.md §4).']);
397
- const orderErr = checkImportOrder(readText(globals));
398
- if (orderErr) fail('scaffold', orderErr.problem, orderErr.fix);
399
- pass('scaffold', `Shell, ${blk.surfaces.length} wired route dir(s) with state-shells, and globals.css import order all in place.`);
400
- }
401
-
402
- // tokens gate: the design-tokens artifact clears the coverage gate (derive-personality.mjs <project> --check) and both CSS files are emitted with the cascade order intact.
403
- function gateTokens(project) {
404
- const tokensPath = join(project, 'design.tokens.json');
405
- if (!existsSync(tokensPath)) fail('tokens', `No design.tokens.json at ${tokensPath}.`, ['Resolve and materialize the design-tokens artifact first (intake phase; data/design-tokens/SCHEMA.md).']);
406
- const derive = join(SCRIPT_DIR, 'derive-personality.mjs');
407
- if (!existsSync(derive)) fail('tokens', `Coverage-gate sibling not found: ${derive}.`, ['derive-personality.mjs must sit beside phase-gate.mjs in the scripts/ directory.']);
408
- const res = spawnSync(process.execPath, [derive, project, '--check'], { encoding: 'utf8' });
409
- if (res.status !== 0) {
410
- const detail = `${res.stdout || ''}${res.stderr || ''}`.trim();
411
- fail('tokens', `The token-artifact coverage gate failed (derive-personality.mjs --check exited ${res.status == null ? '(spawn error)' : res.status}).`, [
412
- 'Assign or hint every named token path below, then re-run this gate:',
413
- detail,
414
- ]);
415
- }
416
- const files = ['src/styles/personality.css', 'src/styles/globals.css'];
417
- const miss = files.filter((f) => !existsSync(join(project, f)));
418
- if (miss.length) {
419
- fail('tokens', `Coverage gate passed but emitted CSS is missing: ${miss.join(', ')}.`, [
420
- `Run derive-personality.mjs ${project} --emit ${project} to write src/styles/personality.css and src/styles/globals.css.`,
421
- ]);
422
- }
423
- const orderErr = checkImportOrder(readText(join(project, 'src/styles/globals.css')));
424
- if (orderErr) fail('tokens', orderErr.problem, orderErr.fix);
425
- pass('tokens', 'Coverage gate green; personality.css + globals.css emitted with the cascade order intact.');
426
- }
427
-
428
- // fixtures gate: src/fixtures/ carries one seeded module per map entity.
429
- function gateFixtures(project) {
430
- const blk = requireMap('fixtures', project);
431
- const fdir = join(project, 'src/fixtures');
432
- if (!existsSync(fdir)) {
433
- fail('fixtures', 'No src/fixtures/ directory.', [
434
- `Run generate-fixtures.mjs docs/design/structure.md --seed <n> --out ${join(project, 'src/fixtures/')} to write one seeded module per entity.`,
435
- ]);
436
- }
437
- const bases = readdirSync(fdir).filter((f) => /\.(ts|tsx)$/.test(f)).map((f) => f.replace(/\.(ts|tsx)$/, '').toLowerCase());
438
- const missing = [];
439
- for (const e of blk.entities) {
440
- if (!e.name) continue;
441
- const base = e.name.toLowerCase();
442
- const k = kebab(e.name);
443
- const cands = new Set([base, k, `${base}s`, `${k}s`]);
444
- if (/y$/.test(base)) { cands.add(`${base.slice(0, -1)}ies`); cands.add(`${k.slice(0, -1)}ies`); }
445
- if (!bases.some((n) => cands.has(n))) missing.push(e.name);
446
- }
447
- if (missing.length) {
448
- fail('fixtures', `No seeded fixture module for entity/ies: ${missing.join(', ')}.`, [
449
- 'Each map entity needs a seeded module in src/fixtures/ (fixture-before-surface). Re-run generate-fixtures.mjs.',
450
- ]);
451
- }
452
- pass('fixtures', `Seeded fixture module present for all ${blk.entities.length} entit(ies).`);
453
- }
454
-
455
- // surfaces gate: every surface's route dir exists, its shell contains every declared state branch, and
456
- // it carries exactly one well-formed budget stamp — with a recorded budget-reason in the map when a
457
- // brand-forward stamp overrides a baseline-default archetype (references/structure.md, the delight budget). The
458
- // budget-gated vocabulary sweeps (display step typ-20, wash col-16) land with the rule catalog in a
459
- // later step; the stamp is parsed here via lib/vocabulary.mjs so those sweeps reuse the same reader.
460
- function gateSurfaces(project) {
461
- const blk = requireMap('surfaces', project);
462
- const routesDir = join(project, 'src/routes');
463
- const problems = [];
464
- for (const s of blk.surfaces) {
465
- const name = s.name || s.route || '(unnamed)';
466
- const dir = resolveRouteDir(s, routesDir);
467
- if (!dir) { problems.push(`${name}: no route dir under src/routes/ (expected ${routeDirCandidates(s).join(' or ')})`); continue; }
468
- const states = (s.states && s.states.length) ? s.states : ['loading', 'empty', 'error'];
469
- const miss = missingStates(dir, states);
470
- if (miss.length) problems.push(`${name}: shell missing state branch(es) ${miss.join(', ')}`);
471
- const src = routeSourceRaw(dir);
472
- const looseCount = (src.match(BUDGET_STAMP_LOOSE_RE) || []).length;
473
- const stamps = findBudgetStamps(src);
474
- if (looseCount === 0) {
475
- problems.push(`${name}: no budget stamp at the top of the route file`);
476
- } else if (stamps.length !== 1 || looseCount !== 1) {
477
- problems.push(`${name}: expected exactly one well-formed budget stamp, found ${looseCount} "// Surface:" line(s) (${stamps.length} well-formed)`);
478
- } else if (requiresBudgetReason(s.archetype, stamps[0]) && !(typeof s['budget-reason'] === 'string' && s['budget-reason'].trim())) {
479
- problems.push(`${name}: brand-forward stamp on a ${s.archetype} surface (archetype defaults baseline) with no budget-reason in the surface map`);
480
- }
481
- }
482
- if (problems.length) {
483
- fail('surfaces', `${problems.length} surface(s) not fully composed. Handle these before finalizing:`, [
484
- ...problems.map((p) => `- ${p}`),
485
- 'Fill every declared lifecycle state into its pre-created shell (references/create.md -> surfaces); states are composed with the surface, not bolted on.',
486
- 'Every surface route file carries exactly one stamp — "// Surface: baseline" or "// Surface: brand-forward (delight-allowing)"; scaffold.mjs writes it from the map budget, so re-classify by editing the surface budget in docs/design/structure.md and re-running scaffold.mjs.',
487
- 'A brand-forward stamp on a baseline-default archetype (list-detail / log-stream / command-center) needs a recorded budget-reason on that surface entry (references/structure.md, the delight budget).',
488
- ]);
489
- }
490
- pass('surfaces', `All ${blk.surfaces.length} surface(s) have a route dir, every declared state branch, and exactly one legal budget stamp.`);
491
- }
492
-
493
- const GATES = { intake: gateIntake, structure: gateStructure, scaffold: gateScaffold, tokens: gateTokens, fixtures: gateFixtures, surfaces: gateSurfaces };
494
-
495
- // Fire the check engine over the project's whole UI tree (plus design.tokens.json manifest drift); print findings fix-or-classify style, return the violation count.
496
- function sourceSweep(project) {
497
- const files = walkUiFiles(join(project, 'src'));
498
- console.log('');
499
- if (!files.length) {
500
- console.log('source sweep: no src/**/*.{tsx,ts,css,html} files to scan.');
501
- return 0;
502
- }
503
- const manifest = join(project, 'design.tokens.json');
504
- const findings = runChecks(files, { manifestPath: existsSync(manifest) ? manifest : null })
505
- .map((f) => ({ ...f, file: relative(project, f.file) || f.file }));
506
- if (!findings.length) {
507
- console.log(green(`source sweep: clean — ${files.length} file(s), no catalog or manifest-drift violations.`));
508
- return 0;
509
- }
510
- console.log(formatFindings(findings, { color: useColor, label: 'source sweep' }));
511
- return findings.length;
512
- }
513
-
514
- // Parse argv, resolve the project dir, dispatch to the named phase gate, then fire the whole-tree source sweep.
515
- function main() {
516
- const args = process.argv.slice(2);
517
- const phase = args[0];
518
- let project = process.cwd();
519
- for (let i = 1; i < args.length; i++) {
520
- if (args[i] === '--project') project = resolve(args[++i] || '.');
521
- else if (args[i].startsWith('--project=')) project = resolve(args[i].slice('--project='.length));
522
- }
523
- if (!phase || !PHASES.includes(phase)) {
524
- console.error(`usage: phase-gate.mjs <${PHASES.join('|')}> [--project <dir>]`);
525
- process.exit(2);
526
- }
527
- let gateFailed = false;
528
- try {
529
- GATES[phase](project);
530
- } catch (e) {
531
- if (!(e instanceof GateFailure)) throw e;
532
- gateFailed = true;
533
- }
534
- const sweepCount = sourceSweep(project);
535
- process.exit(gateFailed || sweepCount > 0 ? 1 : 0);
536
- }
537
-
538
- main();