@tryvitris/website-harness 0.1.0-beta.6 → 0.1.0-beta.7
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/README.md +4 -4
- package/agent/graph.yaml +0 -2
- package/agent/refs/components.md +5 -41
- package/agent/refs/compose.md +1 -1
- package/agent/refs/implement.md +2 -2
- package/agent/refs/jev.md +1 -1
- package/agent/refs/layout.md +1 -1
- package/agent/refs/storyboard.md +1 -1
- package/agent/refs/template-adaptation.md +1 -1
- package/bin/api/agent/evaluate.js +10 -15
- package/bin/api/agent/grade.js +10 -15
- package/bin/api/cli/api.js +18 -23
- package/bin/api/cli.js +20 -25
- package/bin/api/engine.js +11 -16
- package/bin/api/hosting.js +12 -17
- package/bin/api/index.js +2 -3
- package/bin/api/references.js +1 -2
- package/bin/api/render.js +2 -4
- package/bin/chunks/{chunk-4GZCAWWK.js → chunk-4MFPATAB.js} +2 -4
- package/bin/chunks/{chunk-5OOPJNGN.js → chunk-5JTBC6UK.js} +1 -4
- package/bin/chunks/{chunk-Z2UNY47A.js → chunk-5YSPWKFF.js} +1 -1
- package/bin/chunks/{chunk-FYN4T4SV.js → chunk-7V3OKLKH.js} +15 -26
- package/bin/chunks/{chunk-3CTBXY5K.js → chunk-FRABKM65.js} +1936 -1899
- package/bin/chunks/{chunk-4DM5TTLG.js → chunk-H7Y72HXC.js} +5 -5
- package/bin/chunks/{chunk-R7YELY3C.js → chunk-HL6JVA4A.js} +100 -81
- package/bin/chunks/{chunk-54JC5L35.js → chunk-O55LAQ2C.js} +3 -5
- package/bin/chunks/{chunk-VH7PM7KJ.js → chunk-P56ZDMX7.js} +4 -6
- package/bin/chunks/{chunk-7VLBEAFW.js → chunk-PGFFKPK6.js} +2 -2
- package/bin/chunks/{chunk-YQYHROLZ.js → chunk-QRWGFLUU.js} +2 -2
- package/bin/chunks/{chunk-CBEJZO4L.js → chunk-TTAUU3AZ.js} +2 -2
- package/bin/chunks/{chunk-E5Y46VBX.js → chunk-VTI32UGJ.js} +200 -103
- package/bin/chunks/{chunk-DRJQ4OOU.js → chunk-WOORR67N.js} +0 -45
- package/bin/chunks/{chunk-B5I45LFD.js → chunk-YZWEXHT4.js} +11 -13
- package/bin/chunks/{chunk-YCVGD2CG.js → chunk-ZIROO2U4.js} +1204 -1176
- package/bin/chunks/{chunk-42IXFXUD.js → chunk-ZWFG4GPG.js} +11 -15
- package/bin/chunks/{design-context-store-IAT2P2OC.js → design-context-store-DCZOAK56.js} +10 -15
- package/bin/chunks/{packets-VBMY4SQJ.js → packets-QOLWPRNV.js} +10 -15
- package/bin/chunks/{policy-2I37JUU3.js → policy-MP2JZXI3.js} +1 -1
- package/bin/chunks/{preparation-S4MG3RPL.js → preparation-T2IOD5SJ.js} +10 -15
- package/bin/chunks/{questions-HKELBDFL.js → questions-XK545GCX.js} +1 -11
- package/bin/types/src/agent/composition-authoring.d.ts +2 -2
- package/bin/types/src/agent/jev/calibration.d.ts +2 -2
- package/bin/types/src/agent/jev/config.d.ts +1 -1
- package/bin/types/src/agent/jev/questions.d.ts +0 -10
- package/bin/types/src/agent/jev/types.d.ts +0 -2
- package/bin/types/src/agent/site-inputs.d.ts +9 -1
- package/bin/types/src/agent/template-catalog.d.ts +20 -0
- package/bin/types/src/agent/theme-selection.d.ts +4 -2
- package/bin/types/src/build/archives.d.ts +2 -0
- package/bin/vitris-art.js +10 -15
- package/bin/vitris-build.js +3 -5
- package/bin/vitris-create-site.js +12 -17
- package/bin/vitris-cursor-hook.js +10 -15
- package/bin/vitris-eval.js +12 -17
- package/bin/vitris-go.js +14 -19
- package/bin/vitris-harvest.js +11 -16
- package/bin/vitris-knowledge.js +11 -16
- package/bin/vitris-launch-preflight.js +11 -17
- package/bin/vitris-motion-view.js +13 -19
- package/bin/vitris-references.js +4 -7
- package/bin/vitris-refresh.js +11 -16
- package/bin/vitris-stock.js +1 -1
- package/bin/vitris-themes.js +10 -15
- package/bin/vitris-upgrade.js +11 -16
- package/bin/vitris-verify-browser.js +43 -8
- package/bin/vitris-verify-performance.js +3 -5
- package/bin/vitris.js +20 -25
- package/design-system/MASTER.md +2 -2
- package/docs/CLI.md +2 -1
- package/docs/DISTRIBUTION.md +1 -1
- package/package.json +2 -7
- package/templates/site/README.md +2 -0
- package/templates/site/gitignore +1 -0
- package/bin/chunks/chunk-6H3T46F5.js +0 -25
- package/bin/chunks/chunk-ANMJRJQ5.js +0 -31
- package/bin/chunks/chunk-FOXUQXTV.js +0 -278
- package/bin/chunks/chunk-HNORQ74T.js +0 -40
- package/bin/chunks/chunk-T7DGRVTP.js +0 -458
- package/bin/types/src/agent/jev/block-catalog.d.ts +0 -95
- package/bin/types/src/agent/jev/component-select.d.ts +0 -102
- package/bin/types/src/blocks/library-profile.d.ts +0 -9
- package/bin/types/src/blocks/metadata.d.ts +0 -65
- package/bin/vitris-blocks.js +0 -238
- package/blocks/CONVENTIONS.md +0 -121
- package/blocks/INDEX.md +0 -130
- package/blocks/about/about-awards/README.md +0 -36
- package/blocks/about/about-awards/styles.css +0 -13
- package/blocks/about/about-awards/template.html +0 -1
- package/blocks/about/about-credentials/README.md +0 -33
- package/blocks/about/about-credentials/block.meta.json +0 -85
- package/blocks/about/about-credentials/styles.css +0 -4
- package/blocks/about/about-credentials/template.html +0 -1
- package/blocks/about/about-founder/README.md +0 -35
- package/blocks/about/about-founder/styles.css +0 -9
- package/blocks/about/about-founder/template.html +0 -1
- package/blocks/about/about-mission/README.md +0 -31
- package/blocks/about/about-mission/styles.css +0 -5
- package/blocks/about/about-mission/template.html +0 -1
- package/blocks/about/about-statement/README.md +0 -28
- package/blocks/about/about-statement/styles.css +0 -7
- package/blocks/about/about-statement/template.html +0 -1
- package/blocks/about/about-story/README.md +0 -35
- package/blocks/about/about-story/styles.css +0 -5
- package/blocks/about/about-story/template.html +0 -1
- package/blocks/about/about-timeline/README.md +0 -33
- package/blocks/about/about-timeline/styles.css +0 -8
- package/blocks/about/about-timeline/template.html +0 -1
- package/blocks/about/about-values/README.md +0 -31
- package/blocks/about/about-values/styles.css +0 -3
- package/blocks/about/about-values/template.html +0 -1
- package/blocks/blog/blog-featured/README.md +0 -39
- package/blocks/blog/blog-featured/styles.css +0 -12
- package/blocks/blog/blog-featured/template.html +0 -1
- package/blocks/blog/blog-index/README.md +0 -34
- package/blocks/blog/blog-index/styles.css +0 -6
- package/blocks/blog/blog-index/template.html +0 -1
- package/blocks/blog/blog-post-header/README.md +0 -31
- package/blocks/blog/blog-post-header/styles.css +0 -8
- package/blocks/blog/blog-post-header/template.html +0 -1
- package/blocks/contact/contact-cards/README.md +0 -32
- package/blocks/contact/contact-cards/styles.css +0 -7
- package/blocks/contact/contact-cards/template.html +0 -1
- package/blocks/contact/contact-chips/README.md +0 -41
- package/blocks/contact/contact-chips/styles.css +0 -13
- package/blocks/contact/contact-chips/template.html +0 -1
- package/blocks/contact/contact-hours/README.md +0 -41
- package/blocks/contact/contact-hours/block.meta.json +0 -87
- package/blocks/contact/contact-hours/styles.css +0 -8
- package/blocks/contact/contact-hours/template.html +0 -1
- package/blocks/contact/contact-map/README.md +0 -39
- package/blocks/contact/contact-map/styles.css +0 -10
- package/blocks/contact/contact-map/template.html +0 -1
- package/blocks/contact/contact-offices/README.md +0 -32
- package/blocks/contact/contact-offices/styles.css +0 -8
- package/blocks/contact/contact-offices/template.html +0 -1
- package/blocks/contact/contact-phone-first/README.md +0 -33
- package/blocks/contact/contact-phone-first/block.meta.json +0 -86
- package/blocks/contact/contact-phone-first/styles.css +0 -11
- package/blocks/contact/contact-phone-first/template.html +0 -1
- package/blocks/contact/contact-split/README.md +0 -43
- package/blocks/contact/contact-split/styles.css +0 -12
- package/blocks/contact/contact-split/template.html +0 -1
- package/blocks/contact/contact-visit/README.md +0 -36
- package/blocks/contact/contact-visit/block.meta.json +0 -88
- package/blocks/contact/contact-visit/styles.css +0 -13
- package/blocks/contact/contact-visit/template.html +0 -1
- package/blocks/contact/service-areas/README.md +0 -32
- package/blocks/contact/service-areas/styles.css +0 -9
- package/blocks/contact/service-areas/template.html +0 -1
- package/blocks/content/glossary/README.md +0 -35
- package/blocks/content/glossary/styles.css +0 -6
- package/blocks/content/glossary/template.html +0 -1
- package/blocks/content/list-split/README.md +0 -33
- package/blocks/content/list-split/styles.css +0 -13
- package/blocks/content/list-split/template.html +0 -1
- package/blocks/content/prose-split/README.md +0 -32
- package/blocks/content/prose-split/styles.css +0 -12
- package/blocks/content/prose-split/template.html +0 -1
- package/blocks/content/specification-ledger/README.md +0 -32
- package/blocks/content/specification-ledger/block.meta.json +0 -85
- package/blocks/content/specification-ledger/styles.css +0 -10
- package/blocks/content/specification-ledger/template.html +0 -1
- package/blocks/cta/cta-band/README.md +0 -33
- package/blocks/cta/cta-band/styles.css +0 -11
- package/blocks/cta/cta-band/template.html +0 -1
- package/blocks/cta/cta-card/README.md +0 -35
- package/blocks/cta/cta-card/styles.css +0 -8
- package/blocks/cta/cta-card/template.html +0 -1
- package/blocks/cta/cta-floating-bar/README.md +0 -28
- package/blocks/cta/cta-floating-bar/styles.css +0 -8
- package/blocks/cta/cta-floating-bar/template.html +0 -1
- package/blocks/cta/cta-inline/README.md +0 -30
- package/blocks/cta/cta-inline/styles.css +0 -9
- package/blocks/cta/cta-inline/template.html +0 -1
- package/blocks/cta/cta-newsletter/README.md +0 -34
- package/blocks/cta/cta-newsletter/styles.css +0 -8
- package/blocks/cta/cta-newsletter/template.html +0 -1
- package/blocks/cta/cta-photo-fan/README.md +0 -36
- package/blocks/cta/cta-photo-fan/styles.css +0 -14
- package/blocks/cta/cta-photo-fan/template.html +0 -1
- package/blocks/cta/cta-split/README.md +0 -38
- package/blocks/cta/cta-split/styles.css +0 -10
- package/blocks/cta/cta-split/template.html +0 -1
- package/blocks/faq/faq-accordion/README.md +0 -36
- package/blocks/faq/faq-accordion/styles.css +0 -6
- package/blocks/faq/faq-accordion/template.html +0 -1
- package/blocks/faq/faq-grouped/README.md +0 -40
- package/blocks/faq/faq-grouped/styles.css +0 -20
- package/blocks/faq/faq-grouped/template.html +0 -1
- package/blocks/faq/faq-split/README.md +0 -37
- package/blocks/faq/faq-split/styles.css +0 -5
- package/blocks/faq/faq-split/template.html +0 -1
- package/blocks/faq/faq-tabs/README.md +0 -36
- package/blocks/faq/faq-tabs/styles.css +0 -3
- package/blocks/faq/faq-tabs/template.html +0 -1
- package/blocks/feature/feature-bento/README.md +0 -33
- package/blocks/feature/feature-bento/styles.css +0 -7
- package/blocks/feature/feature-bento/template.html +0 -1
- package/blocks/feature/feature-compare-table/README.md +0 -44
- package/blocks/feature/feature-compare-table/styles.css +0 -15
- package/blocks/feature/feature-compare-table/template.html +0 -1
- package/blocks/feature/feature-comparison/README.md +0 -34
- package/blocks/feature/feature-comparison/styles.css +0 -6
- package/blocks/feature/feature-comparison/template.html +0 -1
- package/blocks/feature/feature-grid-3/README.md +0 -34
- package/blocks/feature/feature-grid-3/styles.css +0 -8
- package/blocks/feature/feature-grid-3/template.html +0 -1
- package/blocks/feature/feature-icon-list/README.md +0 -39
- package/blocks/feature/feature-icon-list/styles.css +0 -9
- package/blocks/feature/feature-icon-list/template.html +0 -1
- package/blocks/feature/feature-spotlight/README.md +0 -39
- package/blocks/feature/feature-spotlight/styles.css +0 -5
- package/blocks/feature/feature-spotlight/template.html +0 -1
- package/blocks/feature/feature-stats-band/README.md +0 -33
- package/blocks/feature/feature-stats-band/styles.css +0 -8
- package/blocks/feature/feature-stats-band/template.html +0 -1
- package/blocks/feature/feature-tabs/README.md +0 -38
- package/blocks/feature/feature-tabs/styles.css +0 -7
- package/blocks/feature/feature-tabs/template.html +0 -1
- package/blocks/feature/feature-thumb-list/README.md +0 -38
- package/blocks/feature/feature-thumb-list/styles.css +0 -13
- package/blocks/feature/feature-thumb-list/template.html +0 -1
- package/blocks/feature/feature-zigzag/README.md +0 -31
- package/blocks/feature/feature-zigzag/styles.css +0 -6
- package/blocks/feature/feature-zigzag/template.html +0 -1
- package/blocks/footer/footer-columns/README.md +0 -39
- package/blocks/footer/footer-columns/styles.css +0 -16
- package/blocks/footer/footer-columns/template.html +0 -1
- package/blocks/footer/footer-compact/README.md +0 -33
- package/blocks/footer/footer-compact/styles.css +0 -12
- package/blocks/footer/footer-compact/template.html +0 -1
- package/blocks/footer/footer-cta/README.md +0 -37
- package/blocks/footer/footer-cta/styles.css +0 -18
- package/blocks/footer/footer-cta/template.html +0 -1
- package/blocks/footer/footer-social/README.md +0 -37
- package/blocks/footer/footer-social/styles.css +0 -17
- package/blocks/footer/footer-social/template.html +0 -1
- package/blocks/footer/footer-wordmark/README.md +0 -40
- package/blocks/footer/footer-wordmark/styles.css +0 -19
- package/blocks/footer/footer-wordmark/template.html +0 -1
- package/blocks/gallery/gallery-before-after/README.md +0 -31
- package/blocks/gallery/gallery-before-after/styles.css +0 -6
- package/blocks/gallery/gallery-before-after/template.html +0 -1
- package/blocks/gallery/gallery-carousel/README.md +0 -32
- package/blocks/gallery/gallery-carousel/styles.css +0 -7
- package/blocks/gallery/gallery-carousel/template.html +0 -1
- package/blocks/gallery/gallery-grid/README.md +0 -39
- package/blocks/gallery/gallery-grid/styles.css +0 -13
- package/blocks/gallery/gallery-grid/template.html +0 -1
- package/blocks/gallery/gallery-masonry/README.md +0 -33
- package/blocks/gallery/gallery-masonry/styles.css +0 -4
- package/blocks/gallery/gallery-masonry/template.html +0 -1
- package/blocks/gallery/gallery-mosaic-split/README.md +0 -40
- package/blocks/gallery/gallery-mosaic-split/styles.css +0 -15
- package/blocks/gallery/gallery-mosaic-split/template.html +0 -1
- package/blocks/hero/hero-asymmetric/README.md +0 -34
- package/blocks/hero/hero-asymmetric/styles.css +0 -13
- package/blocks/hero/hero-asymmetric/template.html +0 -10
- package/blocks/hero/hero-before-after/README.md +0 -38
- package/blocks/hero/hero-before-after/styles.css +0 -8
- package/blocks/hero/hero-before-after/template.html +0 -19
- package/blocks/hero/hero-editorial/README.md +0 -34
- package/blocks/hero/hero-editorial/block.meta.json +0 -85
- package/blocks/hero/hero-editorial/styles.css +0 -6
- package/blocks/hero/hero-editorial/template.html +0 -10
- package/blocks/hero/hero-evidence/README.md +0 -32
- package/blocks/hero/hero-evidence/block.meta.json +0 -85
- package/blocks/hero/hero-evidence/styles.css +0 -13
- package/blocks/hero/hero-evidence/template.html +0 -1
- package/blocks/hero/hero-form/README.md +0 -46
- package/blocks/hero/hero-form/styles.css +0 -11
- package/blocks/hero/hero-form/template.html +0 -15
- package/blocks/hero/hero-menu/README.md +0 -36
- package/blocks/hero/hero-menu/styles.css +0 -7
- package/blocks/hero/hero-menu/template.html +0 -10
- package/blocks/hero/hero-overlay/README.md +0 -35
- package/blocks/hero/hero-overlay/styles.css +0 -14
- package/blocks/hero/hero-overlay/template.html +0 -10
- package/blocks/hero/hero-page/README.md +0 -35
- package/blocks/hero/hero-page/styles.css +0 -19
- package/blocks/hero/hero-page/template.html +0 -1
- package/blocks/hero/hero-product/README.md +0 -41
- package/blocks/hero/hero-product/styles.css +0 -11
- package/blocks/hero/hero-product/template.html +0 -14
- package/blocks/hero/hero-service/README.md +0 -37
- package/blocks/hero/hero-service/block.meta.json +0 -85
- package/blocks/hero/hero-service/styles.css +0 -17
- package/blocks/hero/hero-service/template.html +0 -1
- package/blocks/hero/hero-split/README.md +0 -36
- package/blocks/hero/hero-split/styles.css +0 -7
- package/blocks/hero/hero-split/template.html +0 -11
- package/blocks/hero/hero-statement/README.md +0 -33
- package/blocks/hero/hero-statement/styles.css +0 -8
- package/blocks/hero/hero-statement/template.html +0 -1
- package/blocks/hero/hero-stats/README.md +0 -37
- package/blocks/hero/hero-stats/styles.css +0 -10
- package/blocks/hero/hero-stats/template.html +0 -10
- package/blocks/hero/hero-video-still/README.md +0 -36
- package/blocks/hero/hero-video-still/styles.css +0 -9
- package/blocks/hero/hero-video-still/template.html +0 -13
- package/blocks/icons.md +0 -44
- package/blocks/incentives/incentive-banner/README.md +0 -28
- package/blocks/incentives/incentive-banner/styles.css +0 -7
- package/blocks/incentives/incentive-banner/template.html +0 -1
- package/blocks/incentives/incentive-cards/README.md +0 -31
- package/blocks/incentives/incentive-cards/styles.css +0 -4
- package/blocks/incentives/incentive-cards/template.html +0 -1
- package/blocks/navbar/nav-announcement/README.md +0 -35
- package/blocks/navbar/nav-announcement/styles.css +0 -10
- package/blocks/navbar/nav-announcement/template.html +0 -14
- package/blocks/navbar/nav-centered/README.md +0 -35
- package/blocks/navbar/nav-centered/styles.css +0 -11
- package/blocks/navbar/nav-centered/template.html +0 -12
- package/blocks/navbar/nav-minimal/README.md +0 -29
- package/blocks/navbar/nav-minimal/styles.css +0 -5
- package/blocks/navbar/nav-minimal/template.html +0 -6
- package/blocks/navbar/nav-split/README.md +0 -34
- package/blocks/navbar/nav-split/styles.css +0 -11
- package/blocks/navbar/nav-split/template.html +0 -11
- package/blocks/navbar/nav-utility/README.md +0 -37
- package/blocks/navbar/nav-utility/styles.css +0 -17
- package/blocks/navbar/nav-utility/template.html +0 -12
- package/blocks/pricing/menu-featured/README.md +0 -34
- package/blocks/pricing/menu-featured/styles.css +0 -4
- package/blocks/pricing/menu-featured/template.html +0 -1
- package/blocks/pricing/menu-sections/README.md +0 -33
- package/blocks/pricing/menu-sections/styles.css +0 -9
- package/blocks/pricing/menu-sections/template.html +0 -1
- package/blocks/pricing/pricing-table/README.md +0 -40
- package/blocks/pricing/pricing-table/styles.css +0 -9
- package/blocks/pricing/pricing-table/template.html +0 -1
- package/blocks/pricing/pricing-tiers/README.md +0 -34
- package/blocks/pricing/pricing-tiers/styles.css +0 -7
- package/blocks/pricing/pricing-tiers/template.html +0 -1
- package/blocks/pricing/pricing-toggle/README.md +0 -34
- package/blocks/pricing/pricing-toggle/styles.css +0 -10
- package/blocks/pricing/pricing-toggle/template.html +0 -1
- package/blocks/process/process-carousel/README.md +0 -33
- package/blocks/process/process-carousel/styles.css +0 -5
- package/blocks/process/process-carousel/template.html +0 -1
- package/blocks/process/process-split/README.md +0 -35
- package/blocks/process/process-split/styles.css +0 -6
- package/blocks/process/process-split/template.html +0 -1
- package/blocks/process/process-stepper/README.md +0 -40
- package/blocks/process/process-stepper/styles.css +0 -11
- package/blocks/process/process-stepper/template.html +0 -1
- package/blocks/process/process-steps/README.md +0 -35
- package/blocks/process/process-steps/styles.css +0 -6
- package/blocks/process/process-steps/template.html +0 -1
- package/blocks/process/process-sticky/README.md +0 -38
- package/blocks/process/process-sticky/styles.css +0 -12
- package/blocks/process/process-sticky/template.html +0 -1
- package/blocks/process/process-timeline/README.md +0 -35
- package/blocks/process/process-timeline/styles.css +0 -10
- package/blocks/process/process-timeline/template.html +0 -1
- package/blocks/services/services-cards/README.md +0 -34
- package/blocks/services/services-cards/styles.css +0 -3
- package/blocks/services/services-cards/template.html +0 -1
- package/blocks/services/services-carousel/README.md +0 -34
- package/blocks/services/services-carousel/styles.css +0 -6
- package/blocks/services/services-carousel/template.html +0 -1
- package/blocks/services/services-list/README.md +0 -32
- package/blocks/services/services-list/block.meta.json +0 -85
- package/blocks/services/services-list/styles.css +0 -10
- package/blocks/services/services-list/template.html +0 -1
- package/blocks/services/services-menu/README.md +0 -39
- package/blocks/services/services-menu/styles.css +0 -6
- package/blocks/services/services-menu/template.html +0 -1
- package/blocks/services/services-packages/README.md +0 -34
- package/blocks/services/services-packages/styles.css +0 -6
- package/blocks/services/services-packages/template.html +0 -1
- package/blocks/services/services-panels/README.md +0 -36
- package/blocks/services/services-panels/styles.css +0 -15
- package/blocks/services/services-panels/template.html +0 -1
- package/blocks/services/services-photo-grid/README.md +0 -39
- package/blocks/services/services-photo-grid/styles.css +0 -10
- package/blocks/services/services-photo-grid/template.html +0 -1
- package/blocks/services/services-priority/README.md +0 -33
- package/blocks/services/services-priority/block.meta.json +0 -86
- package/blocks/services/services-priority/styles.css +0 -16
- package/blocks/services/services-priority/template.html +0 -1
- package/blocks/stats/stats-cards/README.md +0 -31
- package/blocks/stats/stats-cards/styles.css +0 -4
- package/blocks/stats/stats-cards/template.html +0 -1
- package/blocks/stats/stats-mosaic/README.md +0 -27
- package/blocks/stats/stats-mosaic/styles.css +0 -9
- package/blocks/stats/stats-mosaic/template.html +0 -1
- package/blocks/stats/stats-row/README.md +0 -29
- package/blocks/stats/stats-row/styles.css +0 -8
- package/blocks/stats/stats-row/template.html +0 -1
- package/blocks/stats/stats-split/README.md +0 -35
- package/blocks/stats/stats-split/styles.css +0 -3
- package/blocks/stats/stats-split/template.html +0 -1
- package/blocks/team/team-featured/README.md +0 -42
- package/blocks/team/team-featured/styles.css +0 -9
- package/blocks/team/team-featured/template.html +0 -1
- package/blocks/team/team-grid/README.md +0 -35
- package/blocks/team/team-grid/styles.css +0 -8
- package/blocks/team/team-grid/template.html +0 -1
- package/blocks/team/team-list/README.md +0 -32
- package/blocks/team/team-list/styles.css +0 -7
- package/blocks/team/team-list/template.html +0 -1
- package/blocks/testimonial/testimonial-carousel/README.md +0 -32
- package/blocks/testimonial/testimonial-carousel/styles.css +0 -7
- package/blocks/testimonial/testimonial-carousel/template.html +0 -1
- package/blocks/testimonial/testimonial-grid/README.md +0 -32
- package/blocks/testimonial/testimonial-grid/styles.css +0 -5
- package/blocks/testimonial/testimonial-grid/template.html +0 -1
- package/blocks/testimonial/testimonial-mosaic/README.md +0 -38
- package/blocks/testimonial/testimonial-mosaic/styles.css +0 -14
- package/blocks/testimonial/testimonial-mosaic/template.html +0 -1
- package/blocks/testimonial/testimonial-platform/README.md +0 -34
- package/blocks/testimonial/testimonial-platform/styles.css +0 -17
- package/blocks/testimonial/testimonial-platform/template.html +0 -1
- package/blocks/testimonial/testimonial-rating/README.md +0 -28
- package/blocks/testimonial/testimonial-rating/styles.css +0 -6
- package/blocks/testimonial/testimonial-rating/template.html +0 -1
- package/blocks/testimonial/testimonial-spotlight/README.md +0 -31
- package/blocks/testimonial/testimonial-spotlight/styles.css +0 -9
- package/blocks/testimonial/testimonial-spotlight/template.html +0 -1
- package/blocks/testimonial/testimonial-switcher/README.md +0 -39
- package/blocks/testimonial/testimonial-switcher/styles.css +0 -23
- package/blocks/testimonial/testimonial-switcher/template.html +0 -1
- package/blocks/testimonial/testimonial-wall/README.md +0 -34
- package/blocks/testimonial/testimonial-wall/styles.css +0 -7
- package/blocks/testimonial/testimonial-wall/template.html +0 -1
- package/blocks/trust-strip/trust-badges/README.md +0 -30
- package/blocks/trust-strip/trust-badges/styles.css +0 -5
- package/blocks/trust-strip/trust-badges/template.html +0 -1
- package/blocks/trust-strip/trust-certs/README.md +0 -31
- package/blocks/trust-strip/trust-certs/styles.css +0 -12
- package/blocks/trust-strip/trust-certs/template.html +0 -1
- package/blocks/trust-strip/trust-logos/README.md +0 -32
- package/blocks/trust-strip/trust-logos/styles.css +0 -5
- package/blocks/trust-strip/trust-logos/template.html +0 -1
- package/blocks/trust-strip/trust-quote/README.md +0 -29
- package/blocks/trust-strip/trust-quote/styles.css +0 -5
- package/blocks/trust-strip/trust-quote/template.html +0 -1
- package/blocks/trust-strip/trust-reviews/README.md +0 -35
- package/blocks/trust-strip/trust-reviews/styles.css +0 -9
- package/blocks/trust-strip/trust-reviews/template.html +0 -1
- package/blocks/work/case-alternating/README.md +0 -34
- package/blocks/work/case-alternating/block.meta.json +0 -86
- package/blocks/work/case-alternating/styles.css +0 -7
- package/blocks/work/case-alternating/template.html +0 -1
- package/blocks/work/case-carousel/README.md +0 -26
- package/blocks/work/case-carousel/styles.css +0 -7
- package/blocks/work/case-carousel/template.html +0 -1
- package/blocks/work/case-header/README.md +0 -38
- package/blocks/work/case-header/styles.css +0 -18
- package/blocks/work/case-header/template.html +0 -1
- package/blocks/work/project-evidence/README.md +0 -35
- package/blocks/work/project-evidence/block.meta.json +0 -87
- package/blocks/work/project-evidence/styles.css +0 -12
- package/blocks/work/project-evidence/template.html +0 -1
- package/blocks/work/project-grid/README.md +0 -38
- package/blocks/work/project-grid/styles.css +0 -9
- package/blocks/work/project-grid/template.html +0 -1
|
@@ -2,14 +2,12 @@ import {
|
|
|
2
2
|
buildSite,
|
|
3
3
|
connectForms,
|
|
4
4
|
loadSiteDir
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import {
|
|
7
|
-
findHarnessRoot
|
|
8
|
-
} from "./chunk-HNORQ74T.js";
|
|
5
|
+
} from "./chunk-4MFPATAB.js";
|
|
9
6
|
import {
|
|
10
7
|
leadsJs
|
|
11
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-ZIROO2U4.js";
|
|
12
9
|
import {
|
|
10
|
+
acquirePathLock,
|
|
13
11
|
files,
|
|
14
12
|
fingerprint,
|
|
15
13
|
json,
|
|
@@ -147,15 +145,51 @@ function pageFile(path) {
|
|
|
147
145
|
return decoded === "/" ? "index.html" : `${decoded.replace(/^\/|\/$/g, "")}/index.html`;
|
|
148
146
|
}
|
|
149
147
|
|
|
148
|
+
// src/cli/root.ts
|
|
149
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
|
|
150
|
+
import { dirname, join as join2, resolve } from "node:path";
|
|
151
|
+
import { fileURLToPath } from "node:url";
|
|
152
|
+
function findHarnessRoot(startDir) {
|
|
153
|
+
if ((process.env.VITRIS_HARNESS || process.env.VITRIS_KERNEL) && existsSync2(process.env.VITRIS_HARNESS || process.env.VITRIS_KERNEL)) {
|
|
154
|
+
return resolve(process.env.VITRIS_HARNESS || process.env.VITRIS_KERNEL);
|
|
155
|
+
}
|
|
156
|
+
let curr = resolve(startDir || dirname(fileURLToPath(import.meta.url)));
|
|
157
|
+
for (let i = 0; i < 6; i++) {
|
|
158
|
+
const candidateTmpl = join2(curr, "templates/site");
|
|
159
|
+
const candidatePkg = join2(curr, "package.json");
|
|
160
|
+
if (existsSync2(candidateTmpl) && existsSync2(candidatePkg)) {
|
|
161
|
+
try {
|
|
162
|
+
const pkg = JSON.parse(readFileSync2(candidatePkg, "utf8"));
|
|
163
|
+
if (["@tryvitris/website-harness", "@tryvitris/harness", "@vitris/harness", "@vitris/kernel"].includes(pkg.name)) {
|
|
164
|
+
return curr;
|
|
165
|
+
}
|
|
166
|
+
} catch {
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
const parent = dirname(curr);
|
|
170
|
+
if (parent === curr) break;
|
|
171
|
+
curr = parent;
|
|
172
|
+
}
|
|
173
|
+
const moduleDir = dirname(fileURLToPath(import.meta.url));
|
|
174
|
+
for (const rel of [".", "..", "../.."]) {
|
|
175
|
+
const target = resolve(moduleDir, rel);
|
|
176
|
+
if (existsSync2(join2(target, "templates/site"))) {
|
|
177
|
+
return target;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
throw new Error("Could not locate @tryvitris/website-harness root directory containing templates/site");
|
|
181
|
+
}
|
|
182
|
+
var findKernelRoot = findHarnessRoot;
|
|
183
|
+
|
|
150
184
|
// src/build/verified.ts
|
|
151
|
-
import { cpSync as cpSync2, existsSync as
|
|
152
|
-
import { dirname as
|
|
153
|
-
import { writeFileSync as
|
|
185
|
+
import { cpSync as cpSync2, existsSync as existsSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync8 } from "node:fs";
|
|
186
|
+
import { dirname as dirname5, join as join8, resolve as resolve3, sep as sep2 } from "node:path";
|
|
187
|
+
import { writeFileSync as writeFileSync5 } from "node:fs";
|
|
154
188
|
|
|
155
189
|
// src/preserve/build.ts
|
|
156
|
-
import { cpSync, existsSync as
|
|
157
|
-
import { dirname, join as
|
|
158
|
-
import { randomUUID } from "node:crypto";
|
|
190
|
+
import { cpSync, existsSync as existsSync5, mkdirSync as mkdirSync2, readFileSync as readFileSync5, writeFileSync as writeFileSync2 } from "node:fs";
|
|
191
|
+
import { dirname as dirname2, join as join5, resolve as resolve2, sep } from "node:path";
|
|
192
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
159
193
|
|
|
160
194
|
// src/preserve/runtime.ts
|
|
161
195
|
var preserveRuntime = `(() => {
|
|
@@ -304,18 +338,18 @@ var preserveRuntime = `(() => {
|
|
|
304
338
|
})();`;
|
|
305
339
|
|
|
306
340
|
// src/preserve/supplement.ts
|
|
307
|
-
import { existsSync as
|
|
308
|
-
import { join as
|
|
341
|
+
import { existsSync as existsSync3, readFileSync as readFileSync3 } from "node:fs";
|
|
342
|
+
import { join as join3 } from "node:path";
|
|
309
343
|
function preserveManifest(root) {
|
|
310
|
-
const manifest = JSON.parse(
|
|
311
|
-
const index =
|
|
312
|
-
if (
|
|
313
|
-
const supplement = JSON.parse(
|
|
344
|
+
const manifest = JSON.parse(readFileSync3(join3(root, "onboarding/preserve.json"), "utf8"));
|
|
345
|
+
const index = join3(root, "onboarding/preserve-supplements.json");
|
|
346
|
+
if (existsSync3(index)) for (const file of JSON.parse(readFileSync3(index, "utf8")).files) {
|
|
347
|
+
const supplement = JSON.parse(readFileSync3(within(root, file), "utf8"));
|
|
314
348
|
if (supplement.sourceUrl !== manifest.sourceUrl || supplement.capturedAt !== manifest.capturedAt) throw Error("Asset supplement does not match the original capture");
|
|
315
349
|
manifest.warnings = [.../* @__PURE__ */ new Set([...manifest.warnings, ...supplement.warnings || []])];
|
|
316
350
|
if (supplement.blockers?.length) manifest.blockers = [.../* @__PURE__ */ new Set([...manifest.blockers || [], ...supplement.blockers])];
|
|
317
351
|
for (const page of supplement.pages || []) {
|
|
318
|
-
within(
|
|
352
|
+
within(join3(root, "preserved"), page.file);
|
|
319
353
|
page.references.forEach((r) => within(root, r.file));
|
|
320
354
|
if (page.sourceFailure) within(root, page.sourceFailure.responseFile);
|
|
321
355
|
if (new URL(page.url).origin !== new URL(manifest.sourceUrl).origin || new URL(page.url).pathname !== page.path || manifest.pages.some((p) => p.path === page.path || p.file.toLowerCase() === page.file.toLowerCase())) throw Error("Page supplement would replace a captured route or leave its source");
|
|
@@ -323,7 +357,7 @@ function preserveManifest(root) {
|
|
|
323
357
|
}
|
|
324
358
|
for (const asset of supplement.assets || []) {
|
|
325
359
|
within(root, asset.referenceFile);
|
|
326
|
-
within(
|
|
360
|
+
within(join3(root, "preserved"), asset.file);
|
|
327
361
|
if (manifest.assets.some((a) => a.file === asset.file || a.url === asset.url)) throw Error("Asset supplement would replace a captured asset");
|
|
328
362
|
manifest.assets.push(asset);
|
|
329
363
|
if (asset.captureError) manifest.blockers = [.../* @__PURE__ */ new Set([...manifest.blockers || [], asset.captureError + "; missing authored asset retained as an empty placeholder, not claimed as preserved bytes"])];
|
|
@@ -332,17 +366,64 @@ function preserveManifest(root) {
|
|
|
332
366
|
return manifest;
|
|
333
367
|
}
|
|
334
368
|
|
|
369
|
+
// src/build/archives.ts
|
|
370
|
+
import { randomUUID } from "node:crypto";
|
|
371
|
+
import { lstatSync, mkdirSync, readdirSync, readFileSync as readFileSync4, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
372
|
+
import { join as join4 } from "node:path";
|
|
373
|
+
function archivePreviousBuild(root, previous) {
|
|
374
|
+
const archiveRoot = within(root, ".vitris/build-archives");
|
|
375
|
+
mkdirSync(archiveRoot, { recursive: true });
|
|
376
|
+
const unlock = acquirePathLock(join4(archiveRoot, "retention"));
|
|
377
|
+
try {
|
|
378
|
+
const id = randomUUID(), now = Date.now();
|
|
379
|
+
const priorTimes = readdirSync(archiveRoot).flatMap((name) => {
|
|
380
|
+
if (!/^[0-9a-f-]{36}$/.test(name)) return [];
|
|
381
|
+
try {
|
|
382
|
+
const manifest = JSON.parse(readFileSync4(within(root, `.vitris/build-archives/${name}/archive.json`), "utf8"));
|
|
383
|
+
return manifest.version === 1 && manifest.id === name && Number.isSafeInteger(manifest.createdAt) && manifest.createdAt <= now + 6e4 ? [manifest.createdAt] : [];
|
|
384
|
+
} catch {
|
|
385
|
+
return [];
|
|
386
|
+
}
|
|
387
|
+
});
|
|
388
|
+
const createdAt = Math.max(now, ...priorTimes.map((time) => time + 1));
|
|
389
|
+
const folder = within(root, `.vitris/build-archives/${id}`);
|
|
390
|
+
const hash2 = fingerprint(previous, ["."]);
|
|
391
|
+
mkdirSync(folder);
|
|
392
|
+
renameSync(previous, join4(folder, "dist"));
|
|
393
|
+
writeFileSync(join4(folder, "archive.json"), JSON.stringify({ version: 1, id, createdAt, hash: hash2 }) + "\n", { flag: "wx" });
|
|
394
|
+
const candidates = readdirSync(archiveRoot).flatMap((name) => {
|
|
395
|
+
if (!/^[0-9a-f-]{36}$/.test(name)) return [];
|
|
396
|
+
const candidate = within(root, `.vitris/build-archives/${name}`);
|
|
397
|
+
try {
|
|
398
|
+
if (!lstatSync(candidate).isDirectory() || lstatSync(candidate).isSymbolicLink()) return [];
|
|
399
|
+
const entries = readdirSync(candidate).sort();
|
|
400
|
+
if (entries.join(",") !== "archive.json,dist") return [];
|
|
401
|
+
const manifestPath = within(root, `.vitris/build-archives/${name}/archive.json`);
|
|
402
|
+
const dist = within(root, `.vitris/build-archives/${name}/dist`);
|
|
403
|
+
const manifest = JSON.parse(readFileSync4(manifestPath, "utf8"));
|
|
404
|
+
if (manifest.version !== 1 || manifest.id !== name || !Number.isSafeInteger(manifest.createdAt) || manifest.hash !== fingerprint(dist, ["."])) return [];
|
|
405
|
+
return [{ candidate, createdAt: manifest.createdAt, name }];
|
|
406
|
+
} catch {
|
|
407
|
+
return [];
|
|
408
|
+
}
|
|
409
|
+
}).sort((a, b) => b.createdAt - a.createdAt || b.name.localeCompare(a.name));
|
|
410
|
+
for (const stale of candidates.slice(3)) rmSync(stale.candidate, { recursive: true });
|
|
411
|
+
} finally {
|
|
412
|
+
unlock();
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
335
416
|
// src/preserve/build.ts
|
|
336
|
-
async function buildPreservedSite(siteRoot, output =
|
|
337
|
-
const root =
|
|
338
|
-
if (out === root || root.startsWith(out + sep) || ["preserved", "agent", "onboarding", "public", "pages", "components", "media", "theme", "artifacts"].some((p) => out ===
|
|
417
|
+
async function buildPreservedSite(siteRoot, output = join5(siteRoot, "dist")) {
|
|
418
|
+
const root = resolve2(siteRoot), out = resolve2(output), source = join5(root, "preserved");
|
|
419
|
+
if (out === root || root.startsWith(out + sep) || ["preserved", "agent", "onboarding", "public", "pages", "components", "media", "theme", "artifacts"].some((p) => out === join5(root, p) || out.startsWith(join5(root, p) + sep))) throw new Error("Preserve build output cannot overwrite site source");
|
|
339
420
|
const config = preserveConfig(root);
|
|
340
421
|
const manifest = preserveManifest(root);
|
|
341
422
|
if (config.mode !== "preserve" || !["vitris-v1", "vitris-v2"].includes(manifest.adapter) || !manifest.pages.length) throw new Error("Missing preserve capture; run vitris run first");
|
|
342
423
|
if (new URL(config.sourceUrl).href !== manifest.sourceUrl) throw new Error("Source URL differs from the captured site; create a new preservation directory");
|
|
343
424
|
files(source);
|
|
344
|
-
const stage = `${out}.stage-${
|
|
345
|
-
|
|
425
|
+
const stage = `${out}.stage-${randomUUID2()}`;
|
|
426
|
+
mkdirSync2(dirname2(stage), { recursive: true });
|
|
346
427
|
cpSync(source, stage, { recursive: true });
|
|
347
428
|
let backend = "";
|
|
348
429
|
if (config.backendOrigin) {
|
|
@@ -351,43 +432,50 @@ async function buildPreservedSite(siteRoot, output = join3(siteRoot, "dist")) {
|
|
|
351
432
|
backend = url.origin;
|
|
352
433
|
}
|
|
353
434
|
for (const file of files(stage).filter((f) => f.endsWith(".html"))) {
|
|
354
|
-
let html =
|
|
435
|
+
let html = readFileSync5(file, "utf8");
|
|
355
436
|
if (backend && config.forms?.length) {
|
|
356
|
-
const path = manifest.pages.find((p) =>
|
|
437
|
+
const path = manifest.pages.find((p) => join5(stage, p.file) === file)?.path || "/";
|
|
357
438
|
html = connectForms(html, backend, path, config.forms);
|
|
358
439
|
html = html.replace(/<\/head>/i, "<style>.c-lead-status:empty{display:none}</style></head>");
|
|
359
440
|
html = html.replace(/<\/body>/i, '<script src="/_preserve/leads.js" defer></script></body>');
|
|
360
441
|
}
|
|
361
|
-
|
|
442
|
+
writeFileSync2(file, html);
|
|
362
443
|
}
|
|
363
|
-
if (backend && config.forms?.length)
|
|
364
|
-
|
|
365
|
-
|
|
444
|
+
if (backend && config.forms?.length) writeFileSync2(join5(stage, "_preserve/leads.js"), leadsJs);
|
|
445
|
+
writeFileSync2(join5(stage, "_preserve/runtime.js"), preserveRuntime);
|
|
446
|
+
writeFileSync2(join5(stage, "robots.txt"), "User-agent: *\nDisallow: /\n");
|
|
366
447
|
const rewrites = manifest.pages.filter((p) => p.file.startsWith("_preserve/routes/")).map((p) => `${p.path} /${p.file} 200`);
|
|
367
|
-
if (rewrites.length)
|
|
448
|
+
if (rewrites.length) writeFileSync2(join5(stage, "_redirects"), rewrites.join("\n") + "\n");
|
|
368
449
|
const connected = backend && config.forms?.length;
|
|
369
|
-
const frameOrigins = [...new Set(files(stage).filter((f) => f.endsWith(".html")).flatMap((f) => iframeSources(
|
|
450
|
+
const frameOrigins = [...new Set(files(stage).filter((f) => f.endsWith(".html")).flatMap((f) => iframeSources(readFileSync5(f, "utf8")).filter((src) => readOnlyEmbedProvider(src)).map((src) => new URL(approvedEmbedUrl(src)).origin)))];
|
|
370
451
|
if (connected) frameOrigins.push("https://challenges.cloudflare.com");
|
|
371
|
-
|
|
452
|
+
writeFileSync2(join5(stage, "_headers"), `/*
|
|
372
453
|
X-Robots-Tag: noindex, nofollow
|
|
373
454
|
Content-Security-Policy: default-src 'self'; img-src 'self' data: blob:; font-src 'self' data:; style-src 'self' 'unsafe-inline'; script-src 'self'${connected ? " https://challenges.cloudflare.com" : ""}; connect-src 'self'${connected ? " " + backend + " https://challenges.cloudflare.com" : ""}; frame-src ${frameOrigins.length ? frameOrigins.join(" ") : "'none'"}; object-src 'none'; base-uri 'self'; form-action 'self'${connected ? " " + backend : ""}
|
|
374
455
|
`);
|
|
375
|
-
|
|
376
|
-
save(
|
|
377
|
-
const previous = `${out}.previous-${
|
|
378
|
-
if (
|
|
456
|
+
writeFileSync2(join5(stage, "404.html"), '<!doctype html><html><head><meta name="robots" content="noindex"></head><body><h1>Page not found</h1></body></html>');
|
|
457
|
+
save(join5(stage, "build-evidence.json"), { version: 1, mode: "preserve", compilerHash: fingerprint(findHarnessRoot(), ["src/preserve", "src/forms", "src/runtime/leads.ts", "src/compile/flatten.ts"]) });
|
|
458
|
+
const previous = `${out}.previous-${randomUUID2()}`;
|
|
459
|
+
if (existsSync5(out)) replacePath(out, previous);
|
|
379
460
|
try {
|
|
380
461
|
replacePath(stage, out);
|
|
381
462
|
} catch (error) {
|
|
382
|
-
if (
|
|
463
|
+
if (existsSync5(previous)) replacePath(previous, out);
|
|
383
464
|
throw error;
|
|
384
465
|
}
|
|
466
|
+
if (out === join5(root, "dist") && existsSync5(previous)) {
|
|
467
|
+
try {
|
|
468
|
+
archivePreviousBuild(root, previous);
|
|
469
|
+
} catch (error) {
|
|
470
|
+
console.warn(`Could not finish archiving previous build; inspect the previous-build and archive folders: ${String(error)}`);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
385
473
|
}
|
|
386
474
|
|
|
387
475
|
// src/build/responsive-media.ts
|
|
388
476
|
import { createHash } from "node:crypto";
|
|
389
|
-
import { existsSync as
|
|
390
|
-
import { dirname as
|
|
477
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync6, writeFileSync as writeFileSync3 } from "node:fs";
|
|
478
|
+
import { dirname as dirname3, join as join6, relative } from "node:path";
|
|
391
479
|
import { parse as parse2 } from "parse5";
|
|
392
480
|
import sharp from "sharp";
|
|
393
481
|
var hash = (bytes) => createHash("sha256").update(bytes).digest("hex");
|
|
@@ -404,7 +492,7 @@ async function responsiveMedia(dist, cacheDir) {
|
|
|
404
492
|
const report = { version: 1, images: [], warnings: [] };
|
|
405
493
|
const generated = /* @__PURE__ */ new Map();
|
|
406
494
|
for (const file of files(dist).filter((p) => p.endsWith(".html"))) {
|
|
407
|
-
let html =
|
|
495
|
+
let html = readFileSync6(file, "utf8");
|
|
408
496
|
const edits = [];
|
|
409
497
|
const images = elements(parse2(html, { sourceCodeLocationInfo: true })).filter((el) => el.tagName === "img");
|
|
410
498
|
if (images.filter((el) => attr(el, "data-media-priority") === "critical").length > 1) report.warnings.push(`${relative(dist, file)}: more than one critical image; check mobile/desktop visibility`);
|
|
@@ -426,10 +514,10 @@ async function responsiveMedia(dist, cacheDir) {
|
|
|
426
514
|
const picture = el.parentNode && "tagName" in el.parentNode && el.parentNode.tagName === "picture";
|
|
427
515
|
if (src && !/^(?:[a-z]+:|\/\/|#)/i.test(src) && /\.(?:jpe?g|png|webp|avif)$/i.test(src) && !attr(el, "srcset") && !picture && attr(el, "data-media-optimize") !== "off") {
|
|
428
516
|
const decoded = decodeURIComponent(src);
|
|
429
|
-
const source = within(dist, decoded.startsWith("/") ? decoded.slice(1) :
|
|
430
|
-
if (!
|
|
517
|
+
const source = within(dist, decoded.startsWith("/") ? decoded.slice(1) : join6(relative(dist, dirname3(file)), decoded));
|
|
518
|
+
if (!existsSync6(source)) throw new Error(`Missing asset (image): ${src} in ${relative(dist, file)}`);
|
|
431
519
|
const format = attr(el, "data-media-format") === "avif" ? "avif" : "webp";
|
|
432
|
-
const bytes =
|
|
520
|
+
const bytes = readFileSync6(source), digest2 = hash(bytes), key = digest2 + "-" + format;
|
|
433
521
|
if (!generated.has(key)) {
|
|
434
522
|
const meta = await sharp(bytes, { limitInputPixels: 8e7 }).metadata();
|
|
435
523
|
if ((meta.pages || 1) > 1 || !meta.width || !meta.height) generated.set(key, null);
|
|
@@ -439,19 +527,19 @@ async function responsiveMedia(dist, cacheDir) {
|
|
|
439
527
|
const variants2 = [];
|
|
440
528
|
const widths = [...new Set([480, 768, 1280, 1920].filter((w) => w < width).concat(Math.min(width, 1920)))];
|
|
441
529
|
for (const w of widths) {
|
|
442
|
-
const cache =
|
|
530
|
+
const cache = join6(cacheDir, `v1-sharp-${sharp.versions.sharp}-${key}-${w}`);
|
|
443
531
|
let output;
|
|
444
|
-
if (
|
|
532
|
+
if (existsSync6(cache)) output = readFileSync6(cache);
|
|
445
533
|
else {
|
|
446
534
|
const pipeline = sharp(bytes).rotate().resize({ width: w, withoutEnlargement: true });
|
|
447
535
|
output = await (format === "avif" ? pipeline.avif({ quality: 52, effort: 4 }) : pipeline.webp({ quality: 78, effort: 4 })).toBuffer();
|
|
448
|
-
|
|
449
|
-
|
|
536
|
+
mkdirSync3(cacheDir, { recursive: true });
|
|
537
|
+
writeFileSync3(cache, output);
|
|
450
538
|
}
|
|
451
539
|
const sha256 = hash(output), url = `/media/optimized/${sha256}.${format}`;
|
|
452
540
|
const dimensions = await sharp(output).metadata();
|
|
453
|
-
|
|
454
|
-
|
|
541
|
+
mkdirSync3(join6(dist, "media/optimized"), { recursive: true });
|
|
542
|
+
writeFileSync3(join6(dist, url.slice(1)), output);
|
|
455
543
|
variants2.push({ url, width: dimensions.width, height: dimensions.height, bytes: output.length, sha256 });
|
|
456
544
|
}
|
|
457
545
|
generated.set(key, variants2);
|
|
@@ -480,58 +568,58 @@ async function responsiveMedia(dist, cacheDir) {
|
|
|
480
568
|
edits.push({ start: loc.startOffset, end: loc.endOffset, value: "<img" + el.attrs.map((a) => ` ${a.name}="${escapeHtml(a.value)}"`).join("") + ">" });
|
|
481
569
|
}
|
|
482
570
|
for (const edit of edits.sort((a, b) => b.start - a.start)) html = html.slice(0, edit.start) + edit.value + html.slice(edit.end);
|
|
483
|
-
|
|
571
|
+
writeFileSync3(file, html);
|
|
484
572
|
}
|
|
485
|
-
|
|
573
|
+
writeFileSync3(join6(dist, "media-manifest.json"), JSON.stringify(report, null, 2) + "\n");
|
|
486
574
|
return report;
|
|
487
575
|
}
|
|
488
576
|
|
|
489
577
|
// src/build/static-output.ts
|
|
490
578
|
import { createHash as createHash2 } from "node:crypto";
|
|
491
|
-
import { existsSync as
|
|
492
|
-
import { dirname as
|
|
579
|
+
import { existsSync as existsSync7, readFileSync as readFileSync7, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, unlinkSync } from "node:fs";
|
|
580
|
+
import { dirname as dirname4, join as join7, relative as relative2 } from "node:path";
|
|
493
581
|
import { parse as parse3 } from "parse5";
|
|
494
582
|
var digest = (bytes) => createHash2("sha256").update(bytes).digest("hex");
|
|
495
583
|
function finalizeStaticOutput(dist, publicOrigin) {
|
|
496
|
-
|
|
497
|
-
if (!
|
|
584
|
+
mkdirSync4(join7(dist, "assets/immutable"), { recursive: true });
|
|
585
|
+
if (!existsSync7(join7(dist, "404.html"))) writeFileSync4(join7(dist, "404.html"), existsSync7(join7(dist, "404/index.html")) ? readFileSync7(join7(dist, "404/index.html")) : '<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width"><meta name="robots" content="noindex"><title>Page not found</title></head><body><main><h1>Page not found</h1><p>This address is unavailable.</p><a href="/">Return home</a></main></body></html>');
|
|
498
586
|
const mapped = /* @__PURE__ */ new Map();
|
|
499
587
|
const immutable = /* @__PURE__ */ new Set();
|
|
500
588
|
for (const file of files(dist).filter((f) => f.endsWith(".css"))) {
|
|
501
|
-
let css =
|
|
589
|
+
let css = readFileSync7(file, "utf8");
|
|
502
590
|
css = css.replace(/url\(\s*(["']?)data:(?:font\/woff2?|application\/(?:font-woff|x-font-woff));base64,([a-z0-9+/=\s]+)\1\s*\)/gi, (match, _quote, encoded) => {
|
|
503
591
|
const bytes = Buffer.from(encoded.replace(/\s/g, ""), "base64");
|
|
504
592
|
const signature = bytes.subarray(0, 4).toString();
|
|
505
593
|
if (!["wOF2", "wOFF"].includes(signature)) return match;
|
|
506
594
|
const url = `/assets/immutable/${digest(bytes)}.${signature === "wOF2" ? "woff2" : "woff"}`;
|
|
507
|
-
|
|
508
|
-
|
|
595
|
+
mkdirSync4(join7(dist, "assets/immutable"), { recursive: true });
|
|
596
|
+
writeFileSync4(join7(dist, url.slice(1)), bytes);
|
|
509
597
|
immutable.add(url);
|
|
510
598
|
return `url("${url}")`;
|
|
511
599
|
});
|
|
512
|
-
if (
|
|
600
|
+
if (dirname4(file) === join7(dist, "assets/immutable")) css = css.replace(/url\(\s*(["']?)(?![a-z]+:|\/|#)([^)'"\s]+)\1\s*\)/gi, (_m, _q, url) => `url("/${url}")`);
|
|
513
601
|
css = css.replace(/url\(\s*(["']?)([^)'"\s]+\.woff2?)\1\s*\)/gi, (match, _q, url) => {
|
|
514
602
|
if (/^(?:[a-z]+:|\/\/)/i.test(url)) return match;
|
|
515
|
-
const path = within(dist, url.startsWith("/") ? url.slice(1) :
|
|
516
|
-
if (!
|
|
517
|
-
const bytes =
|
|
518
|
-
|
|
603
|
+
const path = within(dist, url.startsWith("/") ? url.slice(1) : join7(relative2(dist, dirname4(file)), url));
|
|
604
|
+
if (!existsSync7(path)) return match;
|
|
605
|
+
const bytes = readFileSync7(path), next2 = `/assets/immutable/${digest(bytes)}.${url.split(".").at(-1)}`;
|
|
606
|
+
writeFileSync4(join7(dist, next2.slice(1)), bytes);
|
|
519
607
|
immutable.add(next2);
|
|
520
608
|
return `url("${next2}")`;
|
|
521
609
|
});
|
|
522
610
|
css = css.replace(/@font-face\s*\{[^}]*\}/gi, (rule) => /font-display\s*:/.test(rule) ? rule : rule.slice(0, -1) + ";font-display:swap}");
|
|
523
|
-
|
|
611
|
+
writeFileSync4(file, css);
|
|
524
612
|
const rel = "/" + relative2(dist, file).replaceAll("\\", "/");
|
|
525
613
|
const next = `/assets/immutable/${digest(css)}.css`;
|
|
526
|
-
|
|
614
|
+
writeFileSync4(join7(dist, next.slice(1)), css);
|
|
527
615
|
mapped.set(rel, next);
|
|
528
616
|
immutable.add(next);
|
|
529
617
|
if (rel !== next && /^\/assets\/immutable\/[a-f0-9]{64}\.css$/.test(rel)) unlinkSync(file);
|
|
530
618
|
}
|
|
531
619
|
for (const name of ["islands.js", "beacon.js"]) {
|
|
532
|
-
if (!
|
|
533
|
-
const bytes =
|
|
534
|
-
|
|
620
|
+
if (!existsSync7(join7(dist, name))) continue;
|
|
621
|
+
const bytes = readFileSync7(join7(dist, name)), url = `/assets/immutable/${digest(bytes)}.js`;
|
|
622
|
+
writeFileSync4(join7(dist, url.slice(1)), bytes);
|
|
535
623
|
mapped.set("/" + name, url);
|
|
536
624
|
immutable.add(url);
|
|
537
625
|
}
|
|
@@ -541,7 +629,7 @@ function finalizeStaticOutput(dist, publicOrigin) {
|
|
|
541
629
|
}
|
|
542
630
|
const routes = new Set(files(dist).filter((f) => f.endsWith("index.html")).map((f) => "/" + relative2(dist, f).replaceAll("\\", "/").replace(/index\.html$/, "")));
|
|
543
631
|
for (const file of files(dist).filter((f) => f.endsWith(".html"))) {
|
|
544
|
-
let html =
|
|
632
|
+
let html = readFileSync7(file, "utf8");
|
|
545
633
|
for (const [old, next] of mapped) html = html.replaceAll(`"${old}"`, `"${next}"`).replaceAll(`'${old}'`, `'${next}'`);
|
|
546
634
|
const edits = [];
|
|
547
635
|
let hasIcon = false;
|
|
@@ -568,57 +656,57 @@ function finalizeStaticOutput(dist, publicOrigin) {
|
|
|
568
656
|
walk(parse3(html, { sourceCodeLocationInfo: true }));
|
|
569
657
|
for (const edit of edits.sort((a, b) => b.start - a.start)) html = html.slice(0, edit.start) + edit.value + html.slice(edit.end);
|
|
570
658
|
if (!hasIcon) {
|
|
571
|
-
const icon =
|
|
572
|
-
if (!
|
|
659
|
+
const icon = existsSync7(join7(dist, "favicon.ico")) ? "/favicon.ico" : "/favicon.svg";
|
|
660
|
+
if (!existsSync7(join7(dist, icon.slice(1)))) writeFileSync4(join7(dist, "favicon.svg"), '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><rect width="64" height="64" rx="14" fill="#20252c"/><g fill="none" stroke="#fff" stroke-width="3"><circle cx="32" cy="32" r="20"/><ellipse cx="32" cy="32" rx="9" ry="20"/><path d="M12 32h40M16 21h32M16 43h32"/></g></svg>');
|
|
573
661
|
html = html.replace(/<\/head\s*>/i, `<link rel="icon" href="${icon}" type="${icon.endsWith(".ico") ? "image/x-icon" : "image/svg+xml"}"></head>`);
|
|
574
662
|
}
|
|
575
|
-
|
|
663
|
+
writeFileSync4(file, html);
|
|
576
664
|
}
|
|
577
|
-
const sitemap =
|
|
578
|
-
if (
|
|
665
|
+
const sitemap = join7(dist, "sitemap.xml");
|
|
666
|
+
if (existsSync7(sitemap)) writeFileSync4(sitemap, readFileSync7(sitemap, "utf8").replace(/<loc>([^<]+)<\/loc>/g, (_m, loc) => {
|
|
579
667
|
const path = publicOrigin && loc.startsWith(publicOrigin.replace(/\/$/, "")) ? loc.slice(publicOrigin.replace(/\/$/, "").length) : loc;
|
|
580
668
|
return `<loc>${loc}${path !== "/" && routes.has(path.replace(/\/$/, "") + "/") && !loc.endsWith("/") ? "/" : ""}</loc>`;
|
|
581
669
|
}));
|
|
582
|
-
const headersPath =
|
|
583
|
-
const headers =
|
|
584
|
-
|
|
670
|
+
const headersPath = join7(dist, "_headers");
|
|
671
|
+
const headers = existsSync7(headersPath) ? readFileSync7(headersPath, "utf8") : "";
|
|
672
|
+
writeFileSync4(headersPath, headers + "\n# Vitris content-addressed build assets\n/assets/immutable/*\n Cache-Control: public, max-age=31536000, immutable\n/media/optimized/*\n Cache-Control: public, max-age=31536000, immutable\n");
|
|
585
673
|
}
|
|
586
674
|
|
|
587
675
|
// src/build/verified.ts
|
|
588
|
-
async function buildVerified(siteRoot, output =
|
|
676
|
+
async function buildVerified(siteRoot, output = join8(siteRoot, "dist"), origin, slug) {
|
|
589
677
|
if (isPreserveSite(siteRoot)) return buildPreservedSite(siteRoot, output);
|
|
590
|
-
const root =
|
|
678
|
+
const root = resolve3(siteRoot), out = resolve3(output);
|
|
591
679
|
if (out === root || root.startsWith(out + sep2)) throw new Error("Build output cannot contain site source");
|
|
592
680
|
for (const path of ["pages", "components", "theme", "media", "public", "agent", "onboarding"]) {
|
|
593
|
-
const source =
|
|
681
|
+
const source = join8(root, path);
|
|
594
682
|
if (out === source || out.startsWith(source + sep2)) throw new Error("Build output cannot overwrite source directories");
|
|
595
683
|
}
|
|
596
684
|
const stage = out + `.stage-${Date.now()}-${process.pid}`;
|
|
597
|
-
|
|
685
|
+
mkdirSync5(dirname5(stage), { recursive: true });
|
|
598
686
|
const local = await loadSiteDir(root);
|
|
599
687
|
if (slug) local.site = { ...local.site, slug };
|
|
600
|
-
const launch =
|
|
688
|
+
const launch = existsSync8(join8(root, "launch.json")) ? json(join8(root, "launch.json")) : {};
|
|
601
689
|
await buildSite({ ...local, webAnalyticsToken: launch.webAnalyticsToken, forms: launch.forms, kernelOrigin: origin || process.env.VITRIS_BACKEND_ORIGIN || process.env.KERNEL_ORIGIN || launch.backendOrigin || launch.kernelOrigin || "", publicOrigin: process.env.VITRIS_PUBLIC_ORIGIN || launch.publicOrigin, outDir: stage });
|
|
602
690
|
for (const path of ["media", "public"]) {
|
|
603
691
|
const source = within(root, path);
|
|
604
|
-
if (!
|
|
692
|
+
if (!existsSync8(source)) continue;
|
|
605
693
|
files(source);
|
|
606
|
-
if (path === "media") cpSync2(source,
|
|
694
|
+
if (path === "media") cpSync2(source, join8(stage, path), { recursive: true });
|
|
607
695
|
else for (const file of files(source)) {
|
|
608
696
|
const rel = file.slice(source.length + 1);
|
|
609
|
-
if (
|
|
610
|
-
|
|
611
|
-
cpSync2(file,
|
|
697
|
+
if (existsSync8(join8(stage, rel))) throw new Error(`Public asset conflicts with compiled output: ${rel}`);
|
|
698
|
+
mkdirSync5(dirname5(join8(stage, rel)), { recursive: true });
|
|
699
|
+
cpSync2(file, join8(stage, rel));
|
|
612
700
|
}
|
|
613
701
|
}
|
|
614
|
-
await responsiveMedia(stage,
|
|
702
|
+
await responsiveMedia(stage, join8(root, ".vitris/cache/media"));
|
|
615
703
|
finalizeStaticOutput(stage, process.env.VITRIS_PUBLIC_ORIGIN || launch.publicOrigin);
|
|
616
704
|
const errors = [];
|
|
617
|
-
const storyboardPath =
|
|
618
|
-
if (
|
|
705
|
+
const storyboardPath = join8(root, "onboarding/storyboard.json");
|
|
706
|
+
if (existsSync8(storyboardPath)) {
|
|
619
707
|
const plan = json(storyboardPath);
|
|
620
|
-
const redirectPath =
|
|
621
|
-
let redirects =
|
|
708
|
+
const redirectPath = join8(stage, "_redirects");
|
|
709
|
+
let redirects = existsSync8(redirectPath) ? readFileSync8(redirectPath, "utf8") : "";
|
|
622
710
|
for (const route of plan.routes || []) {
|
|
623
711
|
if (!["redirect", "consolidate"].includes(route.disposition) || !route.target) continue;
|
|
624
712
|
const from = new URL(route.source).pathname.replace(/\/$/, "") || "/";
|
|
@@ -629,32 +717,39 @@ async function buildVerified(siteRoot, output = join6(siteRoot, "dist"), origin,
|
|
|
629
717
|
if (!existing) redirects += `
|
|
630
718
|
${from} ${route.target} 301`;
|
|
631
719
|
}
|
|
632
|
-
if (redirects.trim())
|
|
720
|
+
if (redirects.trim()) writeFileSync5(redirectPath, redirects.trim() + "\n");
|
|
633
721
|
}
|
|
634
722
|
for (const file of files(stage).filter((p) => /\.(html|css)$/.test(p))) {
|
|
635
|
-
const content =
|
|
723
|
+
const content = readFileSync8(file, "utf8");
|
|
636
724
|
const refs = file.endsWith(".html") ? [...content.matchAll(/(?:src|poster)=["']([^"']+)["']/g)].map((m) => m[1]) : [...content.matchAll(/url\(["']?([^)'"\s]+)["']?\)/g)].map((m) => m[1]);
|
|
637
725
|
for (const ref of refs) {
|
|
638
726
|
if (/^(https?:|data:|blob:|#|\/\/)/.test(ref)) continue;
|
|
639
727
|
const path = ref.split(/[?#]/)[0];
|
|
640
|
-
const target = within(stage, path.startsWith("/") ? path.slice(1) :
|
|
641
|
-
if (!
|
|
728
|
+
const target = within(stage, path.startsWith("/") ? path.slice(1) : join8(dirname5(file).slice(stage.length + 1), path));
|
|
729
|
+
if (!existsSync8(target)) errors.push(`Missing asset ${ref} in ${file}`);
|
|
642
730
|
}
|
|
643
731
|
if (file.endsWith(".html") && /<slot\b/.test(content)) errors.push(`Unresolved slots: ${file}`);
|
|
644
732
|
}
|
|
645
733
|
if (errors.length) throw new Error(errors.join("\n"));
|
|
646
|
-
save(
|
|
647
|
-
const kernelParent =
|
|
648
|
-
const kernelSource =
|
|
649
|
-
save(
|
|
734
|
+
save(join8(stage, "package-manifest.json"), { slug: local.site.slug || "", site: local.site });
|
|
735
|
+
const kernelParent = resolve3(import.meta.dirname, "..");
|
|
736
|
+
const kernelSource = existsSync8(join8(kernelParent, "compile")) ? kernelParent : join8(kernelParent, "src");
|
|
737
|
+
save(join8(stage, "build-evidence.json"), { version: 2, sourceHash: sourceHash(root), compilerHash: fingerprint(kernelSource, ["compile", "build", "runtime", "forms", "theme.ts"]) });
|
|
650
738
|
const previous = out + `.previous-${Date.now()}-${process.pid}`;
|
|
651
|
-
if (
|
|
739
|
+
if (existsSync8(out)) replacePath(out, previous);
|
|
652
740
|
try {
|
|
653
741
|
replacePath(stage, out);
|
|
654
742
|
} catch (error) {
|
|
655
|
-
if (
|
|
743
|
+
if (existsSync8(previous)) replacePath(previous, out);
|
|
656
744
|
throw error;
|
|
657
745
|
}
|
|
746
|
+
if (out === join8(root, "dist") && existsSync8(previous)) {
|
|
747
|
+
try {
|
|
748
|
+
archivePreviousBuild(root, previous);
|
|
749
|
+
} catch (error) {
|
|
750
|
+
console.warn(`Could not finish archiving previous build; inspect the previous-build and archive folders: ${String(error)}`);
|
|
751
|
+
}
|
|
752
|
+
}
|
|
658
753
|
}
|
|
659
754
|
|
|
660
755
|
export {
|
|
@@ -671,6 +766,8 @@ export {
|
|
|
671
766
|
SUPPORTED_REACT_BLOCKS,
|
|
672
767
|
unresolvedCaptureBlockers,
|
|
673
768
|
pageFile,
|
|
769
|
+
findHarnessRoot,
|
|
770
|
+
findKernelRoot,
|
|
674
771
|
preserveRuntime,
|
|
675
772
|
preserveManifest,
|
|
676
773
|
buildPreservedSite,
|
|
@@ -376,46 +376,6 @@ ${proposal}`,
|
|
|
376
376
|
CREATIVE_SCORE_RUBRICS
|
|
377
377
|
);
|
|
378
378
|
}
|
|
379
|
-
var COMPONENT_FIT_RUBRICS = [
|
|
380
|
-
{ score: 0, description: "Fail: incompatible with this dimension." },
|
|
381
|
-
{ score: 1, description: "Weak fit; would need heavy adaptation." },
|
|
382
|
-
{ score: 2, description: "Usable starting point with documented adaptations." },
|
|
383
|
-
{ score: 3, description: "Strong fit on this dimension from metadata alone." },
|
|
384
|
-
{ score: 4, description: "Excellent fit; little adaptation required." }
|
|
385
|
-
];
|
|
386
|
-
function makeComponentFitQuestion(dimension, candidate, state) {
|
|
387
|
-
return score(
|
|
388
|
-
`Score "${dimension}" for this block using only the supplied textual metadata. Jev has not seen pixels or screenshots.
|
|
389
|
-
|
|
390
|
-
Section state:
|
|
391
|
-
${state}
|
|
392
|
-
|
|
393
|
-
Candidate:
|
|
394
|
-
${candidate}`,
|
|
395
|
-
COMPONENT_FIT_RUBRICS
|
|
396
|
-
);
|
|
397
|
-
}
|
|
398
|
-
function makeRhythmRepetitionQuestion(pageRhythm, candidate) {
|
|
399
|
-
return noul(
|
|
400
|
-
`Would reusing this block create repetitive page rhythm relative to adjacent sections?
|
|
401
|
-
|
|
402
|
-
Adjacent / page rhythm:
|
|
403
|
-
${pageRhythm}
|
|
404
|
-
|
|
405
|
-
Candidate:
|
|
406
|
-
${candidate}`,
|
|
407
|
-
{
|
|
408
|
-
true: "Reuse would create repetitive page rhythm.",
|
|
409
|
-
false: "Reuse would not create repetitive page rhythm."
|
|
410
|
-
}
|
|
411
|
-
);
|
|
412
|
-
}
|
|
413
|
-
var COMPONENT_FIT_TASK_SEMANTICS = {
|
|
414
|
-
version: QUESTION_VERSION,
|
|
415
|
-
primitive: "score+noul",
|
|
416
|
-
rubrics: COMPONENT_FIT_RUBRICS
|
|
417
|
-
};
|
|
418
|
-
var COMPONENT_FIT_SEMANTICS_HASH = questionSemanticsHash(COMPONENT_FIT_TASK_SEMANTICS);
|
|
419
379
|
var DIRECTION_DECISION_CRITERIA = {
|
|
420
380
|
supports: "The textual proposal supports this check.",
|
|
421
381
|
contradicts: "The textual proposal conflicts with this check.",
|
|
@@ -501,11 +461,6 @@ export {
|
|
|
501
461
|
makeRedundancyNoulQuestion,
|
|
502
462
|
CREATIVE_SCORE_RUBRICS,
|
|
503
463
|
makeCreativeDimensionQuestion,
|
|
504
|
-
COMPONENT_FIT_RUBRICS,
|
|
505
|
-
makeComponentFitQuestion,
|
|
506
|
-
makeRhythmRepetitionQuestion,
|
|
507
|
-
COMPONENT_FIT_TASK_SEMANTICS,
|
|
508
|
-
COMPONENT_FIT_SEMANTICS_HASH,
|
|
509
464
|
DIRECTION_DECISION_CRITERIA,
|
|
510
465
|
DIRECTION_DECISION_CHECKS,
|
|
511
466
|
makeDirectionDecisionQuestion,
|