@nurix/etna 0.19.11 → 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.
- package/data/harness-index.json +1 -1
- package/data/harnesses/code/harness.json +1 -1
- package/data/harnesses/code/rules/frontend.md +5 -5
- package/data/harnesses/code/skills/design/SKILL.md +70 -50
- package/data/harnesses/code/skills/design/components/charts.md +76 -0
- package/data/harnesses/code/skills/design/components/collections.md +132 -0
- package/data/harnesses/code/skills/design/components/feedback.md +47 -0
- package/data/harnesses/code/skills/design/components/hooks.md +35 -0
- package/data/harnesses/code/skills/design/components/index.md +143 -0
- package/data/harnesses/code/skills/design/components/inputs.md +327 -0
- package/data/harnesses/code/skills/design/components/layout.md +52 -0
- package/data/harnesses/code/skills/design/components/media.md +66 -0
- package/data/harnesses/code/skills/design/components/motion.md +82 -0
- package/data/harnesses/code/skills/design/components/navigation.md +29 -0
- package/data/harnesses/code/skills/design/components/overlays.md +72 -0
- package/data/harnesses/code/skills/design/components/setup.md +40 -0
- package/data/harnesses/code/skills/design/components/typography.md +46 -0
- package/data/harnesses/code/skills/design/components/utils.md +37 -0
- package/data/harnesses/code/skills/design/data/blueprints/browse.md +38 -0
- package/data/harnesses/code/skills/design/data/blueprints/creation-flow.md +38 -0
- package/data/harnesses/code/skills/design/data/blueprints/dashboard.md +38 -0
- package/data/harnesses/code/skills/design/data/blueprints/grid.md +38 -0
- package/data/harnesses/code/skills/design/data/blueprints/queue.md +38 -0
- package/data/harnesses/code/skills/design/data/blueprints/record-detail.md +38 -0
- package/data/harnesses/code/skills/design/data/blueprints/settings.md +38 -0
- package/data/harnesses/code/skills/design/data/chart-styling/Readme.md +33 -0
- package/data/harnesses/code/skills/design/data/chart-styling/carbon-accessible-alert-semantic.md +19 -0
- package/data/harnesses/code/skills/design/data/chart-styling/carbon-monochrome-sequential-trend.md +19 -0
- package/data/harnesses/code/skills/design/data/chart-styling/datadog-classic-six-aligned.md +19 -0
- package/data/harnesses/code/skills/design/data/chart-styling/datawrapper-tiered-gray-hierarchy.md +19 -0
- package/data/harnesses/code/skills/design/data/chart-styling/econ-red-rule-horizontal.md +19 -0
- package/data/harnesses/code/skills/design/data/chart-styling/financial-diverging-threshold-overlay.md +19 -0
- package/data/harnesses/code/skills/design/data/chart-styling/ft-vocabulary-ranked-muted.md +19 -0
- package/data/harnesses/code/skills/design/data/chart-styling/grafana-dark-threshold-bands.md +19 -0
- package/data/harnesses/code/skills/design/data/chart-styling/material-rounded-explicit-label.md +19 -0
- package/data/harnesses/code/skills/design/data/chart-styling/nyt-ghost-grid-direct-label.md +19 -0
- package/data/harnesses/code/skills/design/data/chart-styling/plot-currentcolor-inherit.md +19 -0
- package/data/harnesses/code/skills/design/data/chart-styling/saas-gradient-glow-area.md +19 -0
- package/data/harnesses/code/skills/design/data/chart-styling/shadcn-composable-css-vars.md +19 -0
- package/data/harnesses/code/skills/design/data/charts/census.csv +58 -0
- package/data/harnesses/code/skills/design/data/checklists/browse.md +21 -0
- package/data/harnesses/code/skills/design/data/checklists/creation-flow.md +20 -0
- package/data/harnesses/code/skills/design/data/checklists/dashboard.md +21 -0
- package/data/harnesses/code/skills/design/data/checklists/grid.md +21 -0
- package/data/harnesses/code/skills/design/data/checklists/queue.md +21 -0
- package/data/harnesses/code/skills/design/data/checklists/record-detail.md +21 -0
- package/data/harnesses/code/skills/design/data/checklists/settings.md +21 -0
- package/data/harnesses/code/skills/design/data/chrome/board-column.md +68 -0
- package/data/harnesses/code/skills/design/data/chrome/data-table.md +63 -0
- package/data/harnesses/code/skills/design/data/chrome/side-panel.md +60 -0
- package/data/harnesses/code/skills/design/data/chrome/sidebar.md +78 -0
- package/data/harnesses/code/skills/design/data/chrome/stat-cards.md +62 -0
- package/data/harnesses/code/skills/design/data/chrome/topbar.md +65 -0
- package/data/harnesses/code/skills/design/data/color/accent-presets.md +90 -0
- package/data/harnesses/code/skills/design/data/color/aesop-earth-mute.md +91 -0
- package/data/harnesses/code/skills/design/data/color/arc-peach-play.md +90 -0
- package/data/harnesses/code/skills/design/data/color/attio-hunter-teal.md +90 -0
- package/data/harnesses/code/skills/design/data/color/carbon-cyan-signal.md +90 -0
- package/data/harnesses/code/skills/design/data/color/clay-parchment.md +90 -0
- package/data/harnesses/code/skills/design/data/color/duolingo-feather.md +90 -0
- package/data/harnesses/code/skills/design/data/color/geist-mono-signal.md +90 -0
- package/data/harnesses/code/skills/design/data/color/linear-graphite-violet.md +90 -0
- package/data/harnesses/code/skills/design/data/color/mercury-onyx-cobalt.md +90 -0
- package/data/harnesses/code/skills/design/data/color/notion-paper-ink.md +90 -0
- package/data/harnesses/code/skills/design/data/color/radix-slate-iris.md +90 -0
- package/data/harnesses/code/skills/design/data/color/raycast-void-spectrum.md +90 -0
- package/data/harnesses/code/skills/design/data/color/spectrum-celery-fuchsia.md +90 -0
- package/data/harnesses/code/skills/design/data/color/stripe-blurple-ruby.md +90 -0
- package/data/harnesses/code/skills/design/data/color/superhuman-cod-picton.md +89 -0
- package/data/harnesses/code/skills/design/data/corpora/operations-review/companies.csv +15 -0
- package/data/harnesses/code/skills/design/data/corpora/operations-review/corpus.md +87 -0
- package/data/harnesses/code/skills/design/data/corpora/operations-review/people.csv +25 -0
- package/data/harnesses/code/skills/design/data/corpora/procurement-approvals/companies.csv +15 -0
- package/data/harnesses/code/skills/design/data/corpora/procurement-approvals/corpus.md +83 -0
- package/data/harnesses/code/skills/design/data/corpora/procurement-approvals/people.csv +25 -0
- package/data/harnesses/code/skills/design/data/corpora/revenue-analytics/companies.csv +15 -0
- package/data/harnesses/code/skills/design/data/corpora/revenue-analytics/corpus.md +89 -0
- package/data/harnesses/code/skills/design/data/corpora/revenue-analytics/people.csv +25 -0
- package/data/harnesses/code/skills/design/data/elevation/ant-design-directional-shadow.md +19 -0
- package/data/harnesses/code/skills/design/data/elevation/apple-liquid-glass-material.md +18 -0
- package/data/harnesses/code/skills/design/data/elevation/atlassian-surface-shadow-pairing.md +20 -0
- package/data/harnesses/code/skills/design/data/elevation/fluent-2-key-ambient-ramp.md +20 -0
- package/data/harnesses/code/skills/design/data/elevation/github-primer-sparing-shadow.md +19 -0
- package/data/harnesses/code/skills/design/data/elevation/ibm-carbon-layer-and-border.md +19 -0
- package/data/harnesses/code/skills/design/data/elevation/linear-dark-surface-ladder.md +17 -0
- package/data/harnesses/code/skills/design/data/elevation/material-2-key-ambient-dp-ramp.md +19 -0
- package/data/harnesses/code/skills/design/data/elevation/material-3-tonal-elevation.md +21 -0
- package/data/harnesses/code/skills/design/data/elevation/neobrutalist-hard-offset.md +19 -0
- package/data/harnesses/code/skills/design/data/elevation/neumorphic-soft-dual-shadow.md +18 -0
- package/data/harnesses/code/skills/design/data/elevation/notion-warm-minimal-hairline.md +17 -0
- package/data/harnesses/code/skills/design/data/elevation/polaris-elevation-inset-bevel.md +21 -0
- package/data/harnesses/code/skills/design/data/elevation/radix-themes-alpha-ring-scale.md +19 -0
- package/data/harnesses/code/skills/design/data/elevation/shadcn-neutral-derived-radius.md +19 -0
- package/data/harnesses/code/skills/design/data/elevation/stripe-brand-tinted-dual-shadow.md +18 -0
- package/data/harnesses/code/skills/design/data/elevation/tailwind-default-utility-scale.md +19 -0
- package/data/harnesses/code/skills/design/data/elevation/vercel-geist-shadow-as-border.md +20 -0
- package/data/harnesses/code/skills/design/data/gradients/amber-attention-fill.md +16 -0
- package/data/harnesses/code/skills/design/data/gradients/cloud-shadow-wash.md +16 -0
- package/data/harnesses/code/skills/design/data/gradients/confident-lavender-wash.md +16 -0
- package/data/harnesses/code/skills/design/data/gradients/ember-ship-flare.md +18 -0
- package/data/harnesses/code/skills/design/data/gradients/full-metal-wash.md +16 -0
- package/data/harnesses/code/skills/design/data/gradients/indigo-ruby-cta-band.md +18 -0
- package/data/harnesses/code/skills/design/data/gradients/linear-graphite-wash.md +18 -0
- package/data/harnesses/code/skills/design/data/gradients/marble-quartz-wash.md +16 -0
- package/data/harnesses/code/skills/design/data/gradients/midnight-aurora-panel.md +16 -0
- package/data/harnesses/code/skills/design/data/gradients/neutral-volume-fill.md +16 -0
- package/data/harnesses/code/skills/design/data/gradients/revenue-uptrend-fill.md +16 -0
- package/data/harnesses/code/skills/design/data/gradients/risk-decline-fill.md +16 -0
- package/data/harnesses/code/skills/design/data/gradients/signal-blue-develop.md +18 -0
- package/data/harnesses/code/skills/design/data/gradients/slate-mist-wash.md +16 -0
- package/data/harnesses/code/skills/design/data/gradients/stripe-atmosphere-mesh.md +18 -0
- package/data/harnesses/code/skills/design/data/gradients/teal-signal-accent.md +16 -0
- package/data/harnesses/code/skills/design/data/gradients/violet-magenta-promo.md +16 -0
- package/data/harnesses/code/skills/design/data/iconography.md +199 -0
- package/data/harnesses/code/skills/design/data/motion/accordion-expand.md +18 -0
- package/data/harnesses/code/skills/design/data/motion/destructive-hold-confirm.md +18 -0
- package/data/harnesses/code/skills/design/data/motion/drag-dismiss-momentum.md +18 -0
- package/data/harnesses/code/skills/design/data/motion/empty-state-arrive.md +18 -0
- package/data/harnesses/code/skills/design/data/motion/hover-lift.md +18 -0
- package/data/harnesses/code/skills/design/data/motion/modal-center-arrive.md +18 -0
- package/data/harnesses/code/skills/design/data/motion/number-ticker-roll.md +18 -0
- package/data/harnesses/code/skills/design/data/motion/onboarding-bounce.md +18 -0
- package/data/harnesses/code/skills/design/data/motion/panel-slide.md +18 -0
- package/data/harnesses/code/skills/design/data/motion/press-feedback.md +18 -0
- package/data/harnesses/code/skills/design/data/motion/progress-linear-loop.md +18 -0
- package/data/harnesses/code/skills/design/data/motion/route-crossfade.md +18 -0
- package/data/harnesses/code/skills/design/data/motion/rubber-band-overscroll.md +18 -0
- package/data/harnesses/code/skills/design/data/motion/skeleton-shimmer.md +18 -0
- package/data/harnesses/code/skills/design/data/motion/stagger-arrive.md +18 -0
- package/data/harnesses/code/skills/design/data/motion/toast-enter-stack.md +18 -0
- package/data/harnesses/code/skills/design/data/motion/tooltip-chain-instant.md +18 -0
- package/data/harnesses/code/skills/design/data/motion/trigger-anchored-reveal.md +18 -0
- package/data/harnesses/code/skills/design/data/tells.csv +34 -0
- package/data/harnesses/code/skills/design/data/typography/anton-work-sans.md +17 -0
- package/data/harnesses/code/skills/design/data/typography/archivo-black-archivo.md +17 -0
- package/data/harnesses/code/skills/design/data/typography/bitter-karla.md +17 -0
- package/data/harnesses/code/skills/design/data/typography/dm-serif-dm-sans.md +17 -0
- package/data/harnesses/code/skills/design/data/typography/fraunces-inter.md +17 -0
- package/data/harnesses/code/skills/design/data/typography/geist-geist-mono.md +17 -0
- package/data/harnesses/code/skills/design/data/typography/hubot-sans-mona-sans.md +17 -0
- package/data/harnesses/code/skills/design/data/typography/ibm-plex-sans-operator-single-family.md +17 -0
- package/data/harnesses/code/skills/design/data/typography/instrument-serif-instrument-sans.md +17 -0
- package/data/harnesses/code/skills/design/data/typography/inter-operator-single-family.md +17 -0
- package/data/harnesses/code/skills/design/data/typography/libre-baskerville-libre-franklin.md +17 -0
- package/data/harnesses/code/skills/design/data/typography/newsreader-inter.md +17 -0
- package/data/harnesses/code/skills/design/data/typography/playfair-display-source-sans.md +17 -0
- package/data/harnesses/code/skills/design/data/typography/public-sans-operator-single-family.md +17 -0
- package/data/harnesses/code/skills/design/data/typography/sohne-inter-fintech.md +17 -0
- package/data/harnesses/code/skills/design/data/typography/source-serif-source-sans.md +17 -0
- package/data/harnesses/code/skills/design/data/typography/space-grotesk-work-sans-space-mono.md +17 -0
- package/data/harnesses/code/skills/design/data/typography/spectral-manrope.md +17 -0
- package/data/harnesses/code/skills/design/data/voices/bright-collaborator.md +29 -0
- package/data/harnesses/code/skills/design/data/voices/direct-operator.md +29 -0
- package/data/harnesses/code/skills/design/data/voices/earnest-helper.md +29 -0
- package/data/harnesses/code/skills/design/data/voices/editorial-composed.md +29 -0
- package/data/harnesses/code/skills/design/data/voices/quiet-concierge.md +29 -0
- package/data/harnesses/code/skills/design/data/voices/warm-guide.md +29 -0
- package/data/harnesses/code/skills/design/design-md/SCHEMA.md +179 -0
- package/data/harnesses/code/skills/design/design-md/index.csv +67 -0
- package/data/harnesses/code/skills/design/design-md/library/airbnb.md +207 -0
- package/data/harnesses/code/skills/design/design-md/library/airtable.md +205 -0
- package/data/harnesses/code/skills/design/design-md/library/anthropic-claude.md +203 -0
- package/data/harnesses/code/skills/design/design-md/library/apple.md +206 -0
- package/data/harnesses/code/skills/design/design-md/library/binance.md +210 -0
- package/data/harnesses/code/skills/design/design-md/library/bmw.md +210 -0
- package/data/harnesses/code/skills/design/design-md/library/cal.md +209 -0
- package/data/harnesses/code/skills/design/design-md/library/clay.md +204 -0
- package/data/harnesses/code/skills/design/design-md/library/clickhouse.md +205 -0
- package/data/harnesses/code/skills/design/design-md/library/cohere.md +205 -0
- package/data/harnesses/code/skills/design/design-md/library/coinbase.md +198 -0
- package/data/harnesses/code/skills/design/design-md/library/composio.md +198 -0
- package/data/harnesses/code/skills/design/design-md/library/cursor.md +197 -0
- package/data/harnesses/code/skills/design/design-md/library/elevenlabs.md +199 -0
- package/data/harnesses/code/skills/design/design-md/library/expo.md +200 -0
- package/data/harnesses/code/skills/design/design-md/library/figma.md +199 -0
- package/data/harnesses/code/skills/design/design-md/library/framer.md +202 -0
- package/data/harnesses/code/skills/design/design-md/library/hashicorp.md +205 -0
- package/data/harnesses/code/skills/design/design-md/library/ibm.md +205 -0
- package/data/harnesses/code/skills/design/design-md/library/intercom.md +204 -0
- package/data/harnesses/code/skills/design/design-md/library/kraken.md +200 -0
- package/data/harnesses/code/skills/design/design-md/library/linear-app.md +198 -0
- package/data/harnesses/code/skills/design/design-md/library/lovable.md +199 -0
- package/data/harnesses/code/skills/design/design-md/library/meta.md +204 -0
- package/data/harnesses/code/skills/design/design-md/library/minimax.md +204 -0
- package/data/harnesses/code/skills/design/design-md/library/mintlify.md +210 -0
- package/data/harnesses/code/skills/design/design-md/library/miro.md +209 -0
- package/data/harnesses/code/skills/design/design-md/library/mistral-ai.md +201 -0
- package/data/harnesses/code/skills/design/design-md/library/mongodb.md +201 -0
- package/data/harnesses/code/skills/design/design-md/library/notion.md +204 -0
- package/data/harnesses/code/skills/design/design-md/library/nvidia.md +215 -0
- package/data/harnesses/code/skills/design/design-md/library/ollama.md +213 -0
- package/data/harnesses/code/skills/design/design-md/library/opencode-ai.md +216 -0
- package/data/harnesses/code/skills/design/design-md/library/posthog.md +218 -0
- package/data/harnesses/code/skills/design/design-md/library/raycast.md +214 -0
- package/data/harnesses/code/skills/design/design-md/library/replicate.md +202 -0
- package/data/harnesses/code/skills/design/design-md/library/resend.md +203 -0
- package/data/harnesses/code/skills/design/design-md/library/revolut.md +203 -0
- package/data/harnesses/code/skills/design/design-md/library/runwayml.md +203 -0
- package/data/harnesses/code/skills/design/design-md/library/sanity.md +200 -0
- package/data/harnesses/code/skills/design/design-md/library/sentry.md +201 -0
- package/data/harnesses/code/skills/design/design-md/library/shopify.md +202 -0
- package/data/harnesses/code/skills/design/design-md/library/slack.md +202 -0
- package/data/harnesses/code/skills/design/design-md/library/spacex.md +206 -0
- package/data/harnesses/code/skills/design/design-md/library/spotify.md +206 -0
- package/data/harnesses/code/skills/design/design-md/library/stripe.md +196 -0
- package/data/harnesses/code/skills/design/design-md/library/supabase.md +196 -0
- package/data/harnesses/code/skills/design/design-md/library/superhuman.md +194 -0
- package/data/harnesses/code/skills/design/design-md/library/tesla.md +198 -0
- package/data/harnesses/code/skills/design/design-md/library/theverge.md +199 -0
- package/data/harnesses/code/skills/design/design-md/library/together-ai.md +193 -0
- package/data/harnesses/code/skills/design/design-md/library/uber.md +195 -0
- package/data/harnesses/code/skills/design/design-md/library/vercel.md +195 -0
- package/data/harnesses/code/skills/design/design-md/library/voltagent.md +197 -0
- package/data/harnesses/code/skills/design/design-md/library/warp.md +196 -0
- package/data/harnesses/code/skills/design/design-md/library/webflow.md +197 -0
- package/data/harnesses/code/skills/design/design-md/library/wired.md +197 -0
- package/data/harnesses/code/skills/design/design-md/library/wise.md +198 -0
- package/data/harnesses/code/skills/design/design-md/library/x-ai.md +199 -0
- package/data/harnesses/code/skills/design/design-md/library/zapier.md +198 -0
- package/data/harnesses/code/skills/design/design-md/nurix.md +214 -0
- package/data/harnesses/code/skills/design/design-md/variants/editorial-luxury.md +184 -0
- package/data/harnesses/code/skills/design/design-md/variants/expressive-saas.md +216 -0
- package/data/harnesses/code/skills/design/design-md/variants/quiet-premium.md +211 -0
- package/data/harnesses/code/skills/design/design-md/variants/terse-dense-operator.md +212 -0
- package/data/harnesses/code/skills/design/design-md/variants/warm-approachable.md +216 -0
- package/data/harnesses/code/skills/design/references/compose.md +23 -0
- package/data/harnesses/code/skills/design/references/content.md +28 -0
- package/data/harnesses/code/skills/design/references/emission.md +21 -0
- package/data/harnesses/code/skills/design/references/existing-apps.md +27 -0
- package/data/harnesses/code/skills/design/references/intake.md +36 -0
- package/data/harnesses/code/skills/design/references/object-pass.md +24 -0
- package/data/harnesses/code/skills/design/references/ship-gate.md +29 -0
- package/data/harnesses/code/skills/design/references/ux-patterns/Readme.md +195 -0
- package/data/harnesses/code/skills/design/references/ux-patterns/ai-layer.md +49 -0
- package/data/harnesses/code/skills/design/references/ux-patterns/attributes-lifecycle.md +43 -0
- package/data/harnesses/code/skills/design/references/ux-patterns/container-choice.md +44 -0
- package/data/harnesses/code/skills/design/references/ux-patterns/creation-paths.md +46 -0
- package/data/harnesses/code/skills/design/references/ux-patterns/dashboards.md +42 -0
- package/data/harnesses/code/skills/design/references/ux-patterns/modes.md +42 -0
- package/data/harnesses/code/skills/design/references/ux-patterns/object-model.md +46 -0
- package/data/harnesses/code/skills/design/references/ux-patterns/page-archetype.md +48 -0
- package/data/harnesses/code/skills/design/references/ux-patterns/promotion-demotion.md +37 -0
- package/data/harnesses/code/skills/design/references/ux-patterns/settings.md +42 -0
- package/data/harnesses/code/skills/design/references/ux-patterns/standard-pages.md +46 -0
- package/data/harnesses/code/skills/design/references/ux-patterns/state-matrix.md +41 -0
- package/data/harnesses/code/skills/design/references/ux-patterns/table-mechanics.md +48 -0
- package/data/harnesses/code/skills/design/references/ux-patterns/verbs.md +45 -0
- package/data/harnesses/code/skills/design/references/ux-patterns/viewer-context.md +40 -0
- package/data/harnesses/code/skills/design/scripts/README-validator.md +27 -0
- package/data/harnesses/code/skills/design/scripts/select-chart.mjs +596 -0
- package/data/harnesses/code/skills/design/scripts/validate-design-md.mjs +1198 -0
- package/package.json +1 -1
- package/data/harnesses/code/skills/design/data/catalog/rules.csv +0 -137
- package/data/harnesses/code/skills/design/data/combinations/Readme.md +0 -33
- package/data/harnesses/code/skills/design/data/combinations/accent-presets.md +0 -113
- package/data/harnesses/code/skills/design/data/combinations/charts.csv +0 -33
- package/data/harnesses/code/skills/design/data/combinations/fonts-known.json +0 -448
- package/data/harnesses/code/skills/design/data/combinations/icons.csv +0 -157
- package/data/harnesses/code/skills/design/data/combinations/landing.csv +0 -38
- package/data/harnesses/code/skills/design/data/combinations/lucide-names.json +0 -2001
- package/data/harnesses/code/skills/design/data/combinations/manifest.json +0 -330
- package/data/harnesses/code/skills/design/data/combinations/motion.csv +0 -10
- package/data/harnesses/code/skills/design/data/combinations/palettes.csv +0 -92
- package/data/harnesses/code/skills/design/data/combinations/product-router.csv +0 -80
- package/data/harnesses/code/skills/design/data/combinations/styles.csv +0 -67
- package/data/harnesses/code/skills/design/data/combinations/typography.csv +0 -64
- package/data/harnesses/code/skills/design/data/design-md/SCHEMA.md +0 -106
- package/data/harnesses/code/skills/design/data/design-md/library/airbnb.md +0 -154
- package/data/harnesses/code/skills/design/data/design-md/library/airtable.md +0 -151
- package/data/harnesses/code/skills/design/data/design-md/library/anthropic-claude.md +0 -139
- package/data/harnesses/code/skills/design/data/design-md/library/apple.md +0 -139
- package/data/harnesses/code/skills/design/data/design-md/library/binance.md +0 -140
- package/data/harnesses/code/skills/design/data/design-md/library/bmw.md +0 -140
- package/data/harnesses/code/skills/design/data/design-md/library/cal.md +0 -140
- package/data/harnesses/code/skills/design/data/design-md/library/clay.md +0 -139
- package/data/harnesses/code/skills/design/data/design-md/library/clickhouse.md +0 -139
- package/data/harnesses/code/skills/design/data/design-md/library/cohere.md +0 -147
- package/data/harnesses/code/skills/design/data/design-md/library/coinbase.md +0 -156
- package/data/harnesses/code/skills/design/data/design-md/library/composio.md +0 -138
- package/data/harnesses/code/skills/design/data/design-md/library/cursor.md +0 -138
- package/data/harnesses/code/skills/design/data/design-md/library/elevenlabs.md +0 -137
- package/data/harnesses/code/skills/design/data/design-md/library/expo.md +0 -148
- package/data/harnesses/code/skills/design/data/design-md/library/figma.md +0 -141
- package/data/harnesses/code/skills/design/data/design-md/library/framer.md +0 -156
- package/data/harnesses/code/skills/design/data/design-md/library/hashicorp.md +0 -140
- package/data/harnesses/code/skills/design/data/design-md/library/ibm.md +0 -153
- package/data/harnesses/code/skills/design/data/design-md/library/intercom.md +0 -158
- package/data/harnesses/code/skills/design/data/design-md/library/kraken.md +0 -156
- package/data/harnesses/code/skills/design/data/design-md/library/linear-app.md +0 -122
- package/data/harnesses/code/skills/design/data/design-md/library/lovable.md +0 -140
- package/data/harnesses/code/skills/design/data/design-md/library/meta.md +0 -139
- package/data/harnesses/code/skills/design/data/design-md/library/minimax.md +0 -139
- package/data/harnesses/code/skills/design/data/design-md/library/mintlify.md +0 -139
- package/data/harnesses/code/skills/design/data/design-md/library/miro.md +0 -153
- package/data/harnesses/code/skills/design/data/design-md/library/mistral-ai.md +0 -140
- package/data/harnesses/code/skills/design/data/design-md/library/mongodb.md +0 -155
- package/data/harnesses/code/skills/design/data/design-md/library/notion.md +0 -140
- package/data/harnesses/code/skills/design/data/design-md/library/nvidia.md +0 -141
- package/data/harnesses/code/skills/design/data/design-md/library/ollama.md +0 -145
- package/data/harnesses/code/skills/design/data/design-md/library/opencode-ai.md +0 -142
- package/data/harnesses/code/skills/design/data/design-md/library/posthog.md +0 -152
- package/data/harnesses/code/skills/design/data/design-md/library/raycast.md +0 -137
- package/data/harnesses/code/skills/design/data/design-md/library/replicate.md +0 -140
- package/data/harnesses/code/skills/design/data/design-md/library/resend.md +0 -170
- package/data/harnesses/code/skills/design/data/design-md/library/revolut.md +0 -145
- package/data/harnesses/code/skills/design/data/design-md/library/runwayml.md +0 -137
- package/data/harnesses/code/skills/design/data/design-md/library/sanity.md +0 -168
- package/data/harnesses/code/skills/design/data/design-md/library/sentry.md +0 -163
- package/data/harnesses/code/skills/design/data/design-md/library/shopify.md +0 -147
- package/data/harnesses/code/skills/design/data/design-md/library/slack.md +0 -158
- package/data/harnesses/code/skills/design/data/design-md/library/spacex.md +0 -171
- package/data/harnesses/code/skills/design/data/design-md/library/spotify.md +0 -166
- package/data/harnesses/code/skills/design/data/design-md/library/stripe.md +0 -160
- package/data/harnesses/code/skills/design/data/design-md/library/supabase.md +0 -173
- package/data/harnesses/code/skills/design/data/design-md/library/superhuman.md +0 -145
- package/data/harnesses/code/skills/design/data/design-md/library/tesla.md +0 -153
- package/data/harnesses/code/skills/design/data/design-md/library/theverge.md +0 -167
- package/data/harnesses/code/skills/design/data/design-md/library/together-ai.md +0 -140
- package/data/harnesses/code/skills/design/data/design-md/library/uber.md +0 -140
- package/data/harnesses/code/skills/design/data/design-md/library/vercel.md +0 -140
- package/data/harnesses/code/skills/design/data/design-md/library/voltagent.md +0 -130
- package/data/harnesses/code/skills/design/data/design-md/library/warp.md +0 -140
- package/data/harnesses/code/skills/design/data/design-md/library/webflow.md +0 -140
- package/data/harnesses/code/skills/design/data/design-md/library/wired.md +0 -139
- package/data/harnesses/code/skills/design/data/design-md/library/wise.md +0 -137
- package/data/harnesses/code/skills/design/data/design-md/library/x-ai.md +0 -138
- package/data/harnesses/code/skills/design/data/design-md/library/zapier.md +0 -158
- package/data/harnesses/code/skills/design/data/design-md/nurix.md +0 -138
- package/data/harnesses/code/skills/design/data/design-tokens/SCHEMA.md +0 -695
- package/data/harnesses/code/skills/design/data/design-tokens/airbnb/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/airbnb/design.tokens.json +0 -1272
- package/data/harnesses/code/skills/design/data/design-tokens/airtable/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/airtable/design.tokens.json +0 -1268
- package/data/harnesses/code/skills/design/data/design-tokens/anthropic-claude/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/anthropic-claude/design.tokens.json +0 -1273
- package/data/harnesses/code/skills/design/data/design-tokens/apple/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/apple/design.tokens.json +0 -1262
- package/data/harnesses/code/skills/design/data/design-tokens/binance/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/binance/design.tokens.json +0 -1257
- package/data/harnesses/code/skills/design/data/design-tokens/bmw/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/bmw/design.tokens.json +0 -1270
- package/data/harnesses/code/skills/design/data/design-tokens/cal/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/cal/design.tokens.json +0 -1270
- package/data/harnesses/code/skills/design/data/design-tokens/clay/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/clay/design.tokens.json +0 -1261
- package/data/harnesses/code/skills/design/data/design-tokens/clickhouse/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/clickhouse/design.tokens.json +0 -1268
- package/data/harnesses/code/skills/design/data/design-tokens/cohere/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/cohere/design.tokens.json +0 -1281
- package/data/harnesses/code/skills/design/data/design-tokens/coinbase/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/coinbase/design.tokens.json +0 -1262
- package/data/harnesses/code/skills/design/data/design-tokens/composio/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/composio/design.tokens.json +0 -1271
- package/data/harnesses/code/skills/design/data/design-tokens/cursor/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/cursor/design.tokens.json +0 -1276
- package/data/harnesses/code/skills/design/data/design-tokens/elevenlabs/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/elevenlabs/design.tokens.json +0 -1293
- package/data/harnesses/code/skills/design/data/design-tokens/expo/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/expo/design.tokens.json +0 -1270
- package/data/harnesses/code/skills/design/data/design-tokens/figma/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/figma/design.tokens.json +0 -1276
- package/data/harnesses/code/skills/design/data/design-tokens/framer/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/framer/design.tokens.json +0 -1267
- package/data/harnesses/code/skills/design/data/design-tokens/goldens.json +0 -251
- package/data/harnesses/code/skills/design/data/design-tokens/hashicorp/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/hashicorp/design.tokens.json +0 -1273
- package/data/harnesses/code/skills/design/data/design-tokens/ibm/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/ibm/design.tokens.json +0 -1286
- package/data/harnesses/code/skills/design/data/design-tokens/intercom/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/intercom/design.tokens.json +0 -1290
- package/data/harnesses/code/skills/design/data/design-tokens/kraken/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/kraken/design.tokens.json +0 -1270
- package/data/harnesses/code/skills/design/data/design-tokens/linear-app/design.resolver.json +0 -23
- package/data/harnesses/code/skills/design/data/design-tokens/linear-app/design.tokens.dark.json +0 -599
- package/data/harnesses/code/skills/design/data/design-tokens/linear-app/design.tokens.json +0 -1272
- package/data/harnesses/code/skills/design/data/design-tokens/lovable/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/lovable/design.tokens.json +0 -1267
- package/data/harnesses/code/skills/design/data/design-tokens/meta/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/meta/design.tokens.json +0 -1289
- package/data/harnesses/code/skills/design/data/design-tokens/minimax/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/minimax/design.tokens.json +0 -1258
- package/data/harnesses/code/skills/design/data/design-tokens/mintlify/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/mintlify/design.tokens.json +0 -1284
- package/data/harnesses/code/skills/design/data/design-tokens/miro/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/miro/design.tokens.json +0 -1291
- package/data/harnesses/code/skills/design/data/design-tokens/mistral-ai/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/mistral-ai/design.tokens.json +0 -1263
- package/data/harnesses/code/skills/design/data/design-tokens/mongodb/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/mongodb/design.tokens.json +0 -1270
- package/data/harnesses/code/skills/design/data/design-tokens/notion/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/notion/design.tokens.json +0 -1261
- package/data/harnesses/code/skills/design/data/design-tokens/nurix/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/nurix/design.tokens.json +0 -1209
- package/data/harnesses/code/skills/design/data/design-tokens/nvidia/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/nvidia/design.tokens.json +0 -1265
- package/data/harnesses/code/skills/design/data/design-tokens/ollama/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/ollama/design.tokens.json +0 -1253
- package/data/harnesses/code/skills/design/data/design-tokens/opencode-ai/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/opencode-ai/design.tokens.json +0 -1268
- package/data/harnesses/code/skills/design/data/design-tokens/posthog/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/posthog/design.tokens.json +0 -1261
- package/data/harnesses/code/skills/design/data/design-tokens/raycast/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/raycast/design.tokens.json +0 -1263
- package/data/harnesses/code/skills/design/data/design-tokens/replicate/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/replicate/design.tokens.json +0 -1266
- package/data/harnesses/code/skills/design/data/design-tokens/resend/design.resolver.json +0 -23
- package/data/harnesses/code/skills/design/data/design-tokens/resend/design.tokens.dark.json +0 -623
- package/data/harnesses/code/skills/design/data/design-tokens/resend/design.tokens.json +0 -1276
- package/data/harnesses/code/skills/design/data/design-tokens/revolut/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/revolut/design.tokens.json +0 -1264
- package/data/harnesses/code/skills/design/data/design-tokens/runwayml/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/runwayml/design.tokens.json +0 -1268
- package/data/harnesses/code/skills/design/data/design-tokens/sanity/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/sanity/design.tokens.json +0 -1270
- package/data/harnesses/code/skills/design/data/design-tokens/sentry/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/sentry/design.tokens.json +0 -1288
- package/data/harnesses/code/skills/design/data/design-tokens/shopify/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/shopify/design.tokens.json +0 -1272
- package/data/harnesses/code/skills/design/data/design-tokens/slack/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/slack/design.tokens.json +0 -1265
- package/data/harnesses/code/skills/design/data/design-tokens/spacex/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/spacex/design.tokens.json +0 -1287
- package/data/harnesses/code/skills/design/data/design-tokens/spotify/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/spotify/design.tokens.json +0 -1286
- package/data/harnesses/code/skills/design/data/design-tokens/stripe/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/stripe/design.tokens.json +0 -1285
- package/data/harnesses/code/skills/design/data/design-tokens/supabase/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/supabase/design.tokens.json +0 -1287
- package/data/harnesses/code/skills/design/data/design-tokens/superhuman/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/superhuman/design.tokens.json +0 -1278
- package/data/harnesses/code/skills/design/data/design-tokens/tesla/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/tesla/design.tokens.json +0 -1269
- package/data/harnesses/code/skills/design/data/design-tokens/theverge/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/theverge/design.tokens.json +0 -1285
- package/data/harnesses/code/skills/design/data/design-tokens/together-ai/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/together-ai/design.tokens.json +0 -1303
- package/data/harnesses/code/skills/design/data/design-tokens/uber/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/uber/design.tokens.json +0 -1274
- package/data/harnesses/code/skills/design/data/design-tokens/vercel/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/vercel/design.tokens.json +0 -1296
- package/data/harnesses/code/skills/design/data/design-tokens/voltagent/design.resolver.json +0 -23
- package/data/harnesses/code/skills/design/data/design-tokens/voltagent/design.tokens.dark.json +0 -612
- package/data/harnesses/code/skills/design/data/design-tokens/voltagent/design.tokens.json +0 -1282
- package/data/harnesses/code/skills/design/data/design-tokens/warp/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/warp/design.tokens.json +0 -1287
- package/data/harnesses/code/skills/design/data/design-tokens/webflow/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/webflow/design.tokens.json +0 -1268
- package/data/harnesses/code/skills/design/data/design-tokens/wired/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/wired/design.tokens.json +0 -1276
- package/data/harnesses/code/skills/design/data/design-tokens/wise/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/wise/design.tokens.json +0 -1273
- package/data/harnesses/code/skills/design/data/design-tokens/x-ai/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/x-ai/design.tokens.json +0 -1296
- package/data/harnesses/code/skills/design/data/design-tokens/zapier/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/zapier/design.tokens.json +0 -1286
- package/data/harnesses/code/skills/design/data/operator-pack/exemplars/command-center.tsx +0 -249
- package/data/harnesses/code/skills/design/data/operator-pack/exemplars/create-edit.tsx +0 -249
- package/data/harnesses/code/skills/design/data/operator-pack/exemplars/dashboard.tsx +0 -225
- package/data/harnesses/code/skills/design/data/operator-pack/exemplars/entity-detail.tsx +0 -249
- package/data/harnesses/code/skills/design/data/operator-pack/exemplars/list-detail.tsx +0 -224
- package/data/harnesses/code/skills/design/data/operator-pack/exemplars/log-stream.tsx +0 -249
- package/data/harnesses/code/skills/design/data/operator-pack/fixtures.md +0 -88
- package/data/harnesses/code/skills/design/data/operator-pack/surface-catalog.md +0 -132
- package/data/harnesses/code/skills/design/data/operator-pack/trust-rubric.md +0 -76
- package/data/harnesses/code/skills/design/references/create.md +0 -173
- package/data/harnesses/code/skills/design/references/diagnosis.md +0 -108
- package/data/harnesses/code/skills/design/references/hard-rules.md +0 -177
- package/data/harnesses/code/skills/design/references/improve.md +0 -116
- package/data/harnesses/code/skills/design/references/interaction.md +0 -77
- package/data/harnesses/code/skills/design/references/introspect.md +0 -100
- package/data/harnesses/code/skills/design/references/lifecycle.md +0 -73
- package/data/harnesses/code/skills/design/references/personality.md +0 -575
- package/data/harnesses/code/skills/design/references/structure.md +0 -159
- package/data/harnesses/code/skills/design/scripts/convert-design-md.mjs +0 -1312
- package/data/harnesses/code/skills/design/scripts/derive-personality.mjs +0 -1498
- package/data/harnesses/code/skills/design/scripts/generate-fixtures.mjs +0 -551
- package/data/harnesses/code/skills/design/scripts/lib/checks.mjs +0 -1092
- package/data/harnesses/code/skills/design/scripts/lib/golden.mjs +0 -26
- package/data/harnesses/code/skills/design/scripts/lib/vocabulary.mjs +0 -65
- package/data/harnesses/code/skills/design/scripts/phase-gate.mjs +0 -538
- package/data/harnesses/code/skills/design/scripts/preship-sweep.mjs +0 -312
- package/data/harnesses/code/skills/design/scripts/render-rung.mjs +0 -890
- package/data/harnesses/code/skills/design/scripts/scaffold.mjs +0 -769
- package/data/harnesses/code/skills/design/scripts/self-integrity.mjs +0 -675
- package/data/harnesses/code/skills/design/scripts/snapshot-goldens.mjs +0 -164
- 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();
|