create-ailk 0.6.1 → 0.8.0
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 +87 -14
- package/component-catalog.json +735 -95
- package/component-catalog.md +13 -7
- package/dist/add-module-core.d.ts +22 -0
- package/dist/add-module-core.js +50 -0
- package/dist/add-module.d.ts +89 -0
- package/dist/add-module.js +334 -0
- package/dist/category-profile.d.ts +126 -0
- package/dist/category-profile.js +262 -0
- package/dist/cli.js +89 -29
- package/dist/index.d.ts +4 -2
- package/dist/index.js +6 -1
- package/dist/lib/extract-module-bundle.d.ts +56 -1
- package/dist/lib/extract-module-bundle.js +170 -14
- package/dist/lib/license-key-files.d.ts +15 -0
- package/dist/lib/license-key-files.js +102 -0
- package/dist/lib/module-license-gate.d.ts +79 -0
- package/dist/lib/module-license-gate.js +160 -12
- package/dist/lib/module-tier.d.ts +45 -16
- package/dist/lib/module-tier.js +76 -0
- package/dist/lib/pro-callout.d.ts +16 -10
- package/dist/lib/pro-callout.js +34 -3
- package/dist/license-set.d.ts +34 -0
- package/dist/license-set.js +194 -0
- package/dist/module-architecture.d.ts +20 -0
- package/dist/module-architecture.js +77 -19
- package/dist/modules/commerce/0.6.1.tar.gz +0 -0
- package/dist/modules/docs-blog/0.6.1.tar.gz +0 -0
- package/dist/modules/marketing-site/0.6.1.tar.gz +0 -0
- package/dist/modules/minimalism-site/0.6.1.tar.gz +0 -0
- package/dist/modules/multi-tenant/0.6.1.tar.gz +0 -0
- package/dist/modules/saas-product/0.6.1.tar.gz +0 -0
- package/dist/modules/scheduling/0.6.1.tar.gz +0 -0
- package/dist/modules/signal-collectors/0.6.1.tar.gz +0 -0
- package/dist/modules/simple-service/0.6.1.tar.gz +0 -0
- package/dist/modules/workspace/0.6.1.tar.gz +0 -0
- package/dist/parse-args.d.ts +85 -10
- package/dist/parse-args.js +227 -15
- package/dist/programmatic.d.ts +81 -5
- package/dist/programmatic.js +291 -32
- package/dist/site-chrome.d.ts +18 -7
- package/dist/site-chrome.js +32 -14
- package/dist/site-roster.d.ts +127 -0
- package/dist/site-roster.js +499 -0
- package/dist/starter-grid.d.ts +216 -0
- package/dist/starter-grid.js +449 -0
- package/dist/surfaces.d.ts +20 -7
- package/dist/surfaces.js +204 -24
- package/dist/sync-routes.d.ts +9 -0
- package/dist/sync-routes.js +2 -2
- package/dist/template-manifest.d.ts +94 -19
- package/dist/template-manifest.js +170 -289
- package/dist/template-names.d.ts +14 -12
- package/dist/template-names.js +13 -17
- package/package.json +6 -4
- package/site-templates/_base/content/en/BookCall/book-call.mdx +52 -0
- package/site-templates/_base/content/en/Feature/feature-1.mdx +69 -0
- package/site-templates/_base/content/en/Feature/feature-2.mdx +69 -0
- package/site-templates/_base/content/en/Feature/feature-3.mdx +69 -0
- package/site-templates/_base/content/en/FeaturesList/features.mdx +91 -0
- package/site-templates/_base/content/en/GlossaryList/glossary.mdx +65 -0
- package/site-templates/_base/content/en/NewsletterSignup/newsletter.mdx +67 -0
- package/site-templates/_base/content/en/PortfolioItem/sample-four.mdx +105 -0
- package/site-templates/_base/content/en/PortfolioItem/sample-one.mdx +34 -0
- package/site-templates/_base/content/en/PortfolioItem/sample-three.mdx +94 -0
- package/site-templates/_base/content/en/PortfolioItem/sample-two.mdx +45 -0
- package/site-templates/_base/content/en/PortfolioList/portfolio.mdx +169 -0
- package/site-templates/_base/content/en/Pricing/pricing.mdx +71 -62
- package/site-templates/_base/content/en/PrivacyPage/privacy.mdx +17 -3
- package/site-templates/_base/content/en/TermsPage/terms.mdx +2 -3
- package/site-templates/_base/content/en/UseCase/persona-1.mdx +69 -0
- package/site-templates/_base/content/en/UseCase/persona-2.mdx +69 -0
- package/site-templates/_base/content/en/UseCase/persona-3.mdx +69 -0
- package/site-templates/designs/minimalism/DESIGN.md +162 -0
- package/site-templates/designs/standard/DESIGN.md +167 -0
- package/site-templates/marketing-site/DESIGN.md +59 -40
- package/site-templates/marketing-site/TEMPLATE-MANIFEST.json +376 -57
- package/site-templates/marketing-site/TEMPLATE-MANIFEST.md +230 -90
- package/site-templates/marketing-site/ailk-template.json +1 -0
- package/site-templates/marketing-site-free/DESIGN.md +59 -40
- package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.json +323 -63
- package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.md +323 -113
- package/site-templates/marketing-site-free/ailk-template.json +3 -2
- package/site-templates/marketing-site-free/content/en/NewsletterSignup/newsletter.mdx +59 -0
- package/site-templates/marketing-site-free/content/en/Pricing/pricing.mdx +199 -0
- package/site-templates/minimalism-site/DESIGN.md +54 -40
- package/site-templates/minimalism-site/TEMPLATE-MANIFEST.json +246 -19
- package/site-templates/minimalism-site/TEMPLATE-MANIFEST.md +173 -51
- package/site-templates/minimalism-site/ailk-template.json +3 -2
- package/site-templates/minimalism-site/content/en/BookCall/book-call.mdx +52 -0
- package/site-templates/minimalism-site/content/en/ContactPage/contact.mdx +3 -37
- package/site-templates/minimalism-site/content/en/PurchasePolicyPage/purchase-policy.mdx +123 -0
- package/site-templates/saas-product/DESIGN.md +59 -40
- package/site-templates/saas-product/TEMPLATE-MANIFEST.md +9 -1
- package/site-templates/shapes/local-business-service/TEMPLATE-MANIFEST.json +369 -0
- package/site-templates/shapes/local-business-service/TEMPLATE-MANIFEST.md +302 -0
- package/site-templates/shapes/local-business-service/ailk-template.json +10 -0
- package/site-templates/{simple-service → shapes/local-business-service}/content/en/AboutPage/about.mdx +4 -4
- package/site-templates/shapes/local-business-service/content/en/HomePage/home.mdx +70 -0
- package/site-templates/shapes/local-business-service/content/en/NewsletterSignup/newsletter.mdx +59 -0
- package/site-templates/shapes/local-business-service/content/en/PortfolioList/portfolio.mdx +171 -0
- package/site-templates/shapes/local-business-service/content/en/PurchasePolicyPage/purchase-policy.mdx +123 -0
- package/site-templates/shapes/local-business-service/content/en/Service/first-job.mdx +39 -0
- package/site-templates/shapes/local-business-service/content/en/Service/second-job.mdx +39 -0
- package/site-templates/shapes/local-business-service/content/en/Service/third-job.mdx +39 -0
- package/site-templates/shapes/local-business-service/content/en/ServicesList/services.mdx +61 -0
- package/site-templates/shapes/local-business-service/provenance.json +4 -0
- package/site-templates/shapes/organization-service/TEMPLATE-MANIFEST.json +362 -0
- package/site-templates/shapes/organization-service/TEMPLATE-MANIFEST.md +300 -0
- package/site-templates/shapes/organization-service/ailk-template.json +10 -0
- package/site-templates/shapes/organization-service/content/en/AboutPage/about.mdx +38 -0
- package/site-templates/shapes/organization-service/content/en/HomePage/home.mdx +85 -0
- package/site-templates/shapes/organization-service/content/en/NewsletterSignup/newsletter.mdx +59 -0
- package/site-templates/shapes/organization-service/content/en/PortfolioList/portfolio.mdx +171 -0
- package/site-templates/shapes/organization-service/content/en/PurchasePolicyPage/purchase-policy.mdx +123 -0
- package/site-templates/shapes/organization-service/content/en/Service/first-engagement.mdx +38 -0
- package/site-templates/shapes/organization-service/content/en/Service/second-engagement.mdx +38 -0
- package/site-templates/shapes/organization-service/content/en/Service/third-engagement.mdx +38 -0
- package/site-templates/shapes/organization-service/content/en/ServicesList/services.mdx +72 -0
- package/site-templates/shapes/organization-service/provenance.json +4 -0
- package/site-templates/shapes/person-service/TEMPLATE-MANIFEST.json +369 -0
- package/site-templates/shapes/person-service/TEMPLATE-MANIFEST.md +299 -0
- package/site-templates/shapes/person-service/ailk-template.json +10 -0
- package/site-templates/shapes/person-service/content/_site.mdx +85 -0
- package/site-templates/shapes/person-service/content/en/AboutPage/about.mdx +39 -0
- package/site-templates/shapes/person-service/content/en/HomePage/home.mdx +97 -0
- package/site-templates/shapes/person-service/content/en/NewsletterSignup/newsletter.mdx +59 -0
- package/site-templates/shapes/person-service/content/en/PortfolioList/portfolio.mdx +169 -0
- package/site-templates/shapes/person-service/content/en/PurchasePolicyPage/purchase-policy.mdx +123 -0
- package/site-templates/shapes/person-service/content/en/Service/first-engagement.mdx +38 -0
- package/site-templates/shapes/person-service/content/en/Service/second-engagement.mdx +38 -0
- package/site-templates/shapes/person-service/content/en/Service/third-engagement.mdx +38 -0
- package/site-templates/{simple-service → shapes/person-service}/content/en/ServicesList/services.mdx +16 -16
- package/site-templates/shapes/person-service/provenance.json +4 -0
- package/templates/.claude/settings.json +15 -0
- package/templates/.claude/skills/README.md +10 -9
- package/templates/.claude/skills/{scaffold-auth → add-auth}/SKILL.md +7 -7
- package/templates/.claude/skills/{scaffold-auth → add-auth}/references/env-vars.md +2 -2
- package/templates/.claude/skills/{scaffold-auth → add-auth}/references/oauth-app-setup.md +3 -3
- package/templates/.claude/skills/{scaffold-page → add-page}/SKILL.md +76 -62
- package/templates/.claude/skills/add-page/references/page-types.md +115 -0
- package/templates/.claude/skills/{scaffold-page → add-page}/templates/content.mdx.tmpl +4 -4
- package/templates/.claude/skills/{scaffold-page → add-page}/templates/route.tsx.tmpl +1 -1
- package/templates/.claude/skills/{audit-site → check-site}/SKILL.md +16 -17
- package/templates/.claude/skills/{audit-site → check-site}/references/common-errors.md +3 -3
- package/templates/.claude/skills/{audit-site → check-site}/references/findings-glossary.md +16 -14
- package/templates/.claude/skills/{audit-site → check-site}/references/severity-levels.md +1 -1
- package/templates/.claude/skills/fill-page/SKILL.md +180 -0
- package/templates/.claude/skills/fill-page/profiles/plumbing.yaml +80 -0
- package/templates/.claude/skills/fill-page/references/section-sources.md +41 -0
- package/templates/.claude/skills/setup-database/SKILL.md +156 -0
- package/templates/.claude/skills/setup-database/scripts/verify-inbox.ts +154 -0
- package/templates/.claude/skills/{provision-config → setup-deploy}/SKILL.md +73 -41
- package/templates/.claude/skills/{provision-config → setup-deploy}/references/env-vars-template.md +21 -30
- package/templates/.claude/skills/setup-deploy/references/runbook-template.md +204 -0
- package/templates/.claude/skills/{provision-config → setup-deploy}/references/vercel-json-template.md +1 -1
- package/templates/.claude/skills/upgrade-plan/SKILL.md +117 -0
- package/templates/.claude/skills/upgrade-plan/references/options.md +24 -0
- package/templates/.claude/skills/upgrade-plan/scripts/upgrade-plan.ts +527 -0
- package/templates/.github/workflows/ci.yml +5 -0
- package/templates/CLAUDE.md +8 -2
- package/templates/DESIGN.md +56 -44
- package/templates/README.md +116 -46
- package/templates/apps/api/.env.example +2 -1
- package/templates/apps/api/CLAUDE.md +3 -2
- package/templates/apps/api/package.json +1 -1
- package/templates/apps/api/src/config/__tests__/index.test.ts +146 -10
- package/templates/apps/api/src/config/index.ts +46 -14
- package/templates/apps/api/src/lib/__tests__/lead-capture-store.test.ts +30 -0
- package/templates/apps/api/src/lib/__tests__/lead-delivery.test.ts +96 -0
- package/templates/apps/api/src/lib/lead-capture-store.ts +12 -0
- package/templates/apps/api/src/lib/lead-delivery.ts +52 -0
- package/templates/apps/api/src/lib/license-key-store.ts +45 -0
- package/templates/apps/api/src/lib/site.ts +5 -3
- package/templates/apps/api/src/middleware/__tests__/auth.database-not-configured.test.ts +97 -0
- package/templates/apps/api/src/middleware/auth.ts +9 -0
- package/templates/apps/api/src/openapi/spec.ts +63 -12
- package/templates/apps/api/src/routes/content/__tests__/get-page.test.ts +127 -5
- package/templates/apps/api/src/routes/content/get-page.ts +86 -2
- package/templates/apps/api/src/routes/leads/__tests__/capture.test.ts +88 -0
- package/templates/apps/api/src/routes/leads/__tests__/index.test.ts +100 -0
- package/templates/apps/api/src/routes/leads/index.ts +46 -1
- package/templates/apps/api/src/server.ts +13 -0
- package/templates/apps/api/src/services/__tests__/lead-routing.test.ts +194 -0
- package/templates/apps/api/src/services/__tests__/leads-inbox.test.ts +124 -0
- package/templates/apps/api/src/services/lead-routing.ts +140 -30
- package/templates/apps/api/src/services/leads-inbox.ts +48 -11
- package/templates/apps/mcp/__tests__/audit-single-page.test.ts +75 -1
- package/templates/apps/mcp/__tests__/lib/audit-single-page-readiness-scan.test.ts +57 -9
- package/templates/apps/mcp/__tests__/parity.test.ts +5 -4
- package/templates/apps/mcp/package.json +2 -1
- package/templates/apps/mcp/src/index.ts +7 -0
- package/templates/apps/mcp/src/lib/audit-single-page.ts +36 -10
- package/templates/apps/mcp/src/lib/license-key-store.ts +45 -0
- package/templates/apps/mcp/src/tools/create_project.ts +21 -6
- package/templates/apps/web/__tests__/setup.ts +18 -0
- package/templates/apps/web/app/[locale]/(auth)/forgot-password/forgot-password-card.tsx +10 -2
- package/templates/apps/web/app/[locale]/(auth)/layout.tsx +2 -2
- package/templates/apps/web/app/[locale]/(auth)/reset-password/reset-password-card.tsx +10 -4
- package/templates/apps/web/app/[locale]/(auth)/sign-in/sign-in-card.tsx +22 -14
- package/templates/apps/web/app/[locale]/(auth)/sign-up/sign-up-card.tsx +26 -18
- package/templates/apps/web/app/[locale]/(authed)/account/page.tsx +12 -4
- package/templates/apps/web/app/[locale]/[slug]/__tests__/page.test.tsx +35 -4
- package/templates/apps/web/app/[locale]/[slug]/page.tsx +49 -9
- package/templates/apps/web/app/[locale]/book-a-call/page.tsx +50 -0
- package/templates/apps/web/app/[locale]/careers/__tests__/page-renderer-migration.test.tsx +3 -3
- package/templates/apps/web/app/[locale]/case-studies/__tests__/page-renderer-migration.test.tsx +3 -3
- package/templates/apps/web/app/[locale]/clients/__tests__/page-renderer-migration.test.tsx +3 -4
- package/templates/apps/web/app/[locale]/contact/ConversationalIntakeWrapper.tsx +67 -29
- package/templates/apps/web/app/[locale]/contact/__tests__/ConversationalIntakeWrapper.test.tsx +94 -11
- package/templates/apps/web/app/[locale]/contact/__tests__/contact-form-text.test.ts +32 -0
- package/templates/apps/web/app/[locale]/contact/__tests__/contact.actions.test.ts +129 -0
- package/templates/apps/web/app/[locale]/contact/__tests__/page-renderer-migration.test.tsx +228 -86
- package/templates/apps/web/app/[locale]/contact/contact-form-text.ts +50 -0
- package/templates/apps/web/app/[locale]/contact/contact.actions.ts +73 -20
- package/templates/apps/web/app/[locale]/contact/page.tsx +115 -7
- package/templates/apps/web/app/[locale]/contact/site-contact-email.ts +54 -0
- package/templates/apps/web/app/[locale]/courses/__tests__/page-renderer-migration.test.tsx +3 -3
- package/templates/apps/web/app/[locale]/downloads/__tests__/page-renderer-migration.test.tsx +3 -4
- package/templates/apps/web/app/[locale]/events/__tests__/page-renderer-migration.test.tsx +4 -5
- package/templates/apps/web/app/[locale]/features/[slug]/page.tsx +64 -0
- package/templates/apps/web/app/[locale]/features/page.tsx +52 -0
- package/templates/apps/web/app/[locale]/glossary/page.tsx +50 -0
- package/templates/apps/web/app/[locale]/how-to/__tests__/page-renderer-migration.test.tsx +1 -1
- package/templates/apps/web/app/[locale]/how-to/page.tsx +25 -15
- package/templates/apps/web/app/[locale]/integrations/__tests__/page-renderer-migration.test.tsx +3 -3
- package/templates/apps/web/app/[locale]/layout.tsx +146 -52
- package/templates/apps/web/app/[locale]/newsletter/__tests__/newsletter.actions.test.ts +75 -0
- package/templates/apps/web/app/[locale]/newsletter/__tests__/page.test.tsx +163 -0
- package/templates/apps/web/app/[locale]/newsletter/newsletter.actions.ts +66 -0
- package/templates/apps/web/app/[locale]/newsletter/page.tsx +142 -0
- package/templates/apps/web/app/[locale]/partners/__tests__/page-renderer-migration.test.tsx +3 -3
- package/templates/apps/web/app/[locale]/portfolio/[slug]/page.tsx +59 -0
- package/templates/apps/web/app/[locale]/portfolio/page.tsx +49 -0
- package/templates/apps/web/app/[locale]/products/__tests__/page-renderer-migration.test.tsx +3 -3
- package/templates/apps/web/app/[locale]/projects/__tests__/page-renderer-migration.test.tsx +4 -5
- package/templates/apps/web/app/[locale]/{cancellation → purchase-policy}/page.tsx +15 -10
- package/templates/apps/web/app/[locale]/resources/__tests__/page-renderer-migration.test.tsx +4 -5
- package/templates/apps/web/app/[locale]/services/__tests__/page-renderer-migration.test.tsx +3 -3
- package/templates/apps/web/app/[locale]/software/[slug]/page.tsx +14 -1
- package/templates/apps/web/app/[locale]/software/__tests__/page-renderer-migration.test.tsx +1 -1
- package/templates/apps/web/app/[locale]/software/page.tsx +25 -15
- package/templates/apps/web/app/[locale]/tech-articles/__tests__/page-renderer-migration.test.tsx +1 -1
- package/templates/apps/web/app/[locale]/tech-articles/page.tsx +25 -15
- package/templates/apps/web/app/[locale]/testimonials/__tests__/page-renderer-migration.test.tsx +3 -4
- package/templates/apps/web/app/[locale]/use-cases/[slug]/page.tsx +63 -0
- package/templates/apps/web/app/[locale]/use-cases/__tests__/page-renderer-migration.test.tsx +3 -4
- package/templates/apps/web/app/[locale]/use-cases/page.tsx +15 -2
- package/templates/apps/web/app/[locale]/whitepapers/__tests__/page-renderer-migration.test.tsx +1 -1
- package/templates/apps/web/app/[locale]/whitepapers/page.tsx +25 -15
- package/templates/apps/web/app/error-fallback.tsx +17 -45
- package/templates/apps/web/app/not-found.tsx +14 -38
- package/templates/apps/web/app/og/route.tsx +6 -0
- package/templates/apps/web/eslint.config.mjs +3 -0
- package/templates/apps/web/instrumentation.ts +14 -0
- package/templates/apps/web/lib/__tests__/structured-data.test.tsx +38 -0
- package/templates/apps/web/lib/license-key-store.ts +52 -0
- package/templates/apps/web/lib/nav-config.ts +82 -18
- package/templates/apps/web/lib/prisma-for-auth.ts +9 -6
- package/templates/apps/web/lib/site-brand.tsx +1 -1
- package/templates/apps/web/lib/site-chrome.ts +3 -3
- package/templates/apps/web/lib/site-identity.ts +148 -0
- package/templates/apps/web/lib/site-theme.ts +11 -0
- package/templates/apps/web/messages/en.json +78 -37
- package/templates/apps/web/public/android-chrome-192x192.png +0 -0
- package/templates/apps/web/public/android-chrome-512x512.png +0 -0
- package/templates/apps/web/public/apple-touch-icon.png +0 -0
- package/templates/apps/web/public/favicon-16x16.png +0 -0
- package/templates/apps/web/public/favicon-32x32.png +0 -0
- package/templates/apps/web/public/favicon.ico +0 -0
- package/templates/apps/web/public/favicon.svg +3 -3
- package/templates/apps/web/public/logomark.svg +6 -3
- package/templates/apps/web/public/logos/ai-launch-kit-light.svg +4 -0
- package/templates/apps/web/public/logos/ai-launch-kit.svg +4 -0
- package/templates/apps/web/public/logos/atomic-agent-light.svg +4 -0
- package/templates/apps/web/public/logos/atomic-agent.svg +4 -0
- package/templates/apps/web/public/logos/salessmyth-light.svg +4 -0
- package/templates/apps/web/public/logos/salessmyth.svg +4 -0
- package/templates/apps/web/public/site.webmanifest +4 -4
- package/templates/apps/web/public/wordmark-light.svg +4 -0
- package/templates/apps/web/public/wordmark.svg +3 -3
- package/templates/apps/web/security-headers.config.ts +5 -1
- package/templates/content/_site.mdx +25 -0
- package/templates/content/en/AboutPage/about.mdx +150 -144
- package/templates/content/en/BlogList/blog.mdx +126 -0
- package/templates/content/en/ContactPage/contact.mdx +21 -92
- package/templates/content/en/FAQPage/faq.mdx +86 -57
- package/templates/content/en/HomePage/home.mdx +268 -217
- package/templates/content/en/PurchasePolicyPage/purchase-policy.mdx +181 -0
- package/templates/content/en/UseCasesList/use-cases.mdx +170 -0
- package/templates/database/CHANGELOG.md +14 -0
- package/templates/database/package.json +1 -1
- package/templates/package.json +3 -1
- package/templates/tools/lint-architecture.ts +315 -0
- package/templates/tools/tsconfig.json +14 -0
- package/versions.json +33 -33
- package/site-templates/simple-service/DESIGN.md +0 -148
- package/site-templates/simple-service/TEMPLATE-MANIFEST.json +0 -240
- package/site-templates/simple-service/TEMPLATE-MANIFEST.md +0 -278
- package/site-templates/simple-service/ailk-template.json +0 -10
- package/site-templates/simple-service/content/en/ContactPage/contact.mdx +0 -67
- package/site-templates/simple-service/content/en/FAQPage/faq.mdx +0 -56
- package/site-templates/simple-service/content/en/HomePage/home.mdx +0 -85
- package/site-templates/simple-service/content/en/Service/landscape-design.mdx +0 -40
- package/site-templates/simple-service/content/en/Service/lawn-maintenance.mdx +0 -40
- package/site-templates/simple-service/content/en/Service/seasonal-cleanup.mdx +0 -40
- package/site-templates/simple-service/provenance.json +0 -4
- package/templates/.claude/skills/add-schema/SKILL.md +0 -277
- package/templates/.claude/skills/add-schema/references/conflict-handling.md +0 -200
- package/templates/.claude/skills/add-schema/references/file-finding.md +0 -123
- package/templates/.claude/skills/add-schema/references/schema-types.md +0 -234
- package/templates/.claude/skills/provision-config/references/runbook-template.md +0 -248
- package/templates/.claude/skills/scaffold-page/references/page-types.md +0 -169
- package/templates/.claude/skills/suggest-site-pages/SKILL.md +0 -242
- package/templates/.claude/skills/suggest-site-pages/references/categories.md +0 -287
- package/templates/apps/web/app/[locale]/contact/ContactForm.tsx +0 -150
- package/templates/apps/web/app/[locale]/returns/page.tsx +0 -44
- package/templates/apps/web/app/[locale]/shipping/page.tsx +0 -44
- package/templates/content/en/CancellationPolicyPage/cancellation.mdx +0 -108
- package/templates/content/en/LandingPage/blog.mdx +0 -83
- package/templates/content/en/LandingPage/features.mdx +0 -103
- package/templates/content/en/LandingPage/how-it-works.mdx +0 -143
- package/templates/content/en/ReturnsPolicyPage/returns.mdx +0 -108
- package/templates/content/en/ShippingPolicyPage/shipping.mdx +0 -108
package/dist/surfaces.d.ts
CHANGED
|
@@ -57,6 +57,14 @@ export declare const RECOGNIZED_SURFACES: readonly string[];
|
|
|
57
57
|
* comment on that row. Resolving through an alias prints a deprecation notice.
|
|
58
58
|
*/
|
|
59
59
|
export declare const SURFACE_ALIASES: Readonly<Record<string, string>>;
|
|
60
|
+
/**
|
|
61
|
+
* Surface ids that became core routes (#6658 D3: `software` — the product's
|
|
62
|
+
* own page is in every scaffold). Accepted and dropped wherever a surface list
|
|
63
|
+
* is read — a `--surfaces` value or an existing site's `# Surfaces:` header —
|
|
64
|
+
* so a site scaffolded with `--surfaces software` keeps working: its route
|
|
65
|
+
* is copied regardless.
|
|
66
|
+
*/
|
|
67
|
+
export declare const CORE_PROMOTED_SURFACES: ReadonlySet<string>;
|
|
60
68
|
/**
|
|
61
69
|
* Surfaces each recognized module contributes.
|
|
62
70
|
*
|
|
@@ -183,19 +191,24 @@ export declare const NAV_CONFIG_PATH = "apps/web/lib/nav-config.ts";
|
|
|
183
191
|
* surface set for the same reason the route tree does.
|
|
184
192
|
*
|
|
185
193
|
* The base items are the Free marketing-site chrome (#5469 D5, the approved
|
|
186
|
-
* chrome diff recorded on that card):
|
|
187
|
-
* a Product flyout
|
|
188
|
-
* and About.
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
*
|
|
192
|
-
* the nav still never links a page the
|
|
194
|
+
* chrome diff recorded on that card, re-pointed by #6658 D8):
|
|
195
|
+
* a Product flyout in two columns (Features · Use Cases, #6721), then Blog,
|
|
196
|
+
* Pricing and About. The feature and use-case links ride the `features` and
|
|
197
|
+
* `use-cases` surfaces; `/blog` is always linked (the teaser or the docs-blog
|
|
198
|
+
* module serves it). Pricing is gateable
|
|
199
|
+
* surfaces: each item is emitted only when its surface is enabled (a template
|
|
200
|
+
* roster enables it, #5469 D10), so the nav still never links a page the
|
|
201
|
+
* scaffold does not carry.
|
|
193
202
|
*
|
|
194
203
|
* Only gateable surfaces carrying a `navLabelKey` are linked after the base
|
|
195
204
|
* items, because a nav entry needs a translated label. Emitting an entry whose
|
|
196
205
|
* `labelKey` has no translation would trade a dead link for a missing-message
|
|
197
206
|
* error.
|
|
198
207
|
*
|
|
208
|
+
* The same file carries `footerColumns`, the footer's column groups (#6468):
|
|
209
|
+
* label keys and paths only, under the same gates, so the footer links every
|
|
210
|
+
* seed page the header does not.
|
|
211
|
+
*
|
|
199
212
|
* Deterministic: gateable entries follow GATEABLE_SURFACES order (alphabetical
|
|
200
213
|
* by id), after the fixed base items.
|
|
201
214
|
*/
|
package/dist/surfaces.js
CHANGED
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
*
|
|
21
21
|
* The default (`--modules marketing`) enables NO gateable surface: every one of
|
|
22
22
|
* them is a claim about the business that the scaffolder cannot make. The path
|
|
23
|
-
* from there is the `
|
|
24
|
-
*
|
|
23
|
+
* from there is the `add-page` skill that already ships in
|
|
24
|
+
* `templates/.claude/skills/`.
|
|
25
25
|
*
|
|
26
26
|
* Zero runtime dependencies — create-ailk is a published, standalone CLI.
|
|
27
27
|
*
|
|
@@ -75,9 +75,11 @@ export const CORE_ROUTE_DIRS = [
|
|
|
75
75
|
// registering the group keeps `sign-in`'s existing `core` identity exactly.
|
|
76
76
|
`${ROUTE_ROOT}/(auth)`,
|
|
77
77
|
// #5469 D2 — always copied: it is what serves the Free template's
|
|
78
|
-
// /how-it-works
|
|
79
|
-
//
|
|
80
|
-
//
|
|
78
|
+
// /blog teaser page (its former /how-it-works and /features siblings
|
|
79
|
+
// moved to the /use-cases list and the product's own page), and it is
|
|
80
|
+
// inert for every slug that has no LandingPage MDX (notFound), so a
|
|
81
|
+
// scaffold carrying it and no content is byte-for-byte a scaffold with one
|
|
82
|
+
// more 404, nothing else.
|
|
81
83
|
`${ROUTE_ROOT}/[slug]`,
|
|
82
84
|
// #6084 D12 (the operator's shape-2 disposition) — the checkout return
|
|
83
85
|
// pair. The launchers pointing at them (`apps/mcp/src/tools/purchase.ts`,
|
|
@@ -118,6 +120,13 @@ export const GATEABLE_SURFACES = [
|
|
|
118
120
|
content: ["apps/web/content/<locale>/blog"],
|
|
119
121
|
navLabelKey: "blog",
|
|
120
122
|
},
|
|
123
|
+
{
|
|
124
|
+
// Module-less (#6658 D5), like `pricing`: every starter's roster names
|
|
125
|
+
// it. No `navLabelKey` — the footer links it, gated on this surface.
|
|
126
|
+
id: "book-a-call",
|
|
127
|
+
routes: [`${ROUTE_ROOT}/book-a-call`],
|
|
128
|
+
content: ["content/<locale>/BookCall"],
|
|
129
|
+
},
|
|
121
130
|
{
|
|
122
131
|
id: "careers",
|
|
123
132
|
routes: [`${ROUTE_ROOT}/careers`],
|
|
@@ -164,12 +173,25 @@ export const GATEABLE_SURFACES = [
|
|
|
164
173
|
routes: [`${ROUTE_ROOT}/events`],
|
|
165
174
|
content: ["content/<locale>/EventsList", "content/<locale>/Event"],
|
|
166
175
|
},
|
|
176
|
+
{
|
|
177
|
+
// #6721 — the product's feature pages: a FeaturesList hub over one
|
|
178
|
+
// Feature page per feature. The Free roster enables it by its rows.
|
|
179
|
+
id: "features",
|
|
180
|
+
routes: [`${ROUTE_ROOT}/features`],
|
|
181
|
+
content: ["content/<locale>/FeaturesList", "content/<locale>/Feature"],
|
|
182
|
+
},
|
|
167
183
|
{
|
|
168
184
|
// API-backed (the flow engine); no MDX of its own.
|
|
169
185
|
id: "flows",
|
|
170
186
|
routes: [`${ROUTE_ROOT}/flows`],
|
|
171
187
|
content: [],
|
|
172
188
|
},
|
|
189
|
+
{
|
|
190
|
+
// Module-less (#6658 D5) — see `book-a-call`.
|
|
191
|
+
id: "glossary",
|
|
192
|
+
routes: [`${ROUTE_ROOT}/glossary`],
|
|
193
|
+
content: ["content/<locale>/GlossaryList"],
|
|
194
|
+
},
|
|
173
195
|
{
|
|
174
196
|
id: "how-to",
|
|
175
197
|
routes: [`${ROUTE_ROOT}/how-to`],
|
|
@@ -206,11 +228,23 @@ export const GATEABLE_SURFACES = [
|
|
|
206
228
|
// functional gain, since no route derives from a message key.
|
|
207
229
|
navLabelKey: "schedule",
|
|
208
230
|
},
|
|
231
|
+
{
|
|
232
|
+
// Module-less (#6658 D5) — see `book-a-call`. The page's form posts to
|
|
233
|
+
// lead capture and sends no verification email.
|
|
234
|
+
id: "newsletter",
|
|
235
|
+
routes: [`${ROUTE_ROOT}/newsletter`],
|
|
236
|
+
content: ["content/<locale>/NewsletterSignup"],
|
|
237
|
+
},
|
|
209
238
|
{
|
|
210
239
|
id: "partners",
|
|
211
240
|
routes: [`${ROUTE_ROOT}/partners`],
|
|
212
241
|
content: ["content/<locale>/PartnersList", "content/<locale>/Partner"],
|
|
213
242
|
},
|
|
243
|
+
{
|
|
244
|
+
id: "portfolio",
|
|
245
|
+
routes: [`${ROUTE_ROOT}/portfolio`],
|
|
246
|
+
content: ["content/<locale>/PortfolioList", "content/<locale>/PortfolioItem"],
|
|
247
|
+
},
|
|
214
248
|
{
|
|
215
249
|
// Module-LESS by construction (#5479 D16): no MODULE_SURFACES value names
|
|
216
250
|
// it, so a site template may enable it by roster alone. Same for
|
|
@@ -248,6 +282,8 @@ export const GATEABLE_SURFACES = [
|
|
|
248
282
|
content: ["content/<locale>/ServicesList", "content/<locale>/Service"],
|
|
249
283
|
},
|
|
250
284
|
{
|
|
285
|
+
// #6721 — the product's own page (#6658 D3), a gateable surface again now
|
|
286
|
+
// that the Free roster links /features instead of /software/product.
|
|
251
287
|
id: "software",
|
|
252
288
|
routes: [`${ROUTE_ROOT}/software`],
|
|
253
289
|
content: ["content/<locale>/SoftwareProduct"],
|
|
@@ -270,7 +306,7 @@ export const GATEABLE_SURFACES = [
|
|
|
270
306
|
{
|
|
271
307
|
id: "use-cases",
|
|
272
308
|
routes: [`${ROUTE_ROOT}/use-cases`],
|
|
273
|
-
content: ["content/<locale>/UseCasesList"],
|
|
309
|
+
content: ["content/<locale>/UseCasesList", "content/<locale>/UseCase"],
|
|
274
310
|
},
|
|
275
311
|
{
|
|
276
312
|
id: "whitepapers",
|
|
@@ -288,6 +324,17 @@ export const RECOGNIZED_SURFACES = GATEABLE_SURFACES.map((s) => s.id);
|
|
|
288
324
|
export const SURFACE_ALIASES = {
|
|
289
325
|
schedule: "meet",
|
|
290
326
|
};
|
|
327
|
+
/**
|
|
328
|
+
* Surface ids that became core routes (#6658 D3: `software` — the product's
|
|
329
|
+
* own page is in every scaffold). Accepted and dropped wherever a surface list
|
|
330
|
+
* is read — a `--surfaces` value or an existing site's `# Surfaces:` header —
|
|
331
|
+
* so a site scaffolded with `--surfaces software` keeps working: its route
|
|
332
|
+
* is copied regardless.
|
|
333
|
+
*/
|
|
334
|
+
// #6721 — `software` is a gateable surface again (the Free roster now carries
|
|
335
|
+
// /features + /features/[slug] instead); the set is kept, empty, so the
|
|
336
|
+
// accept-and-drop read sites stay in place for the next promotion.
|
|
337
|
+
export const CORE_PROMOTED_SURFACES = new Set([]);
|
|
291
338
|
/** Canonical id for a `--surfaces` value, resolving a retired alias. */
|
|
292
339
|
function canonicalizeSurface(s) {
|
|
293
340
|
return SURFACE_ALIASES[s] ?? s;
|
|
@@ -346,7 +393,7 @@ export function parseSurfaces(raw) {
|
|
|
346
393
|
const requested = raw
|
|
347
394
|
.split(",")
|
|
348
395
|
.map((s) => canonicalizeSurface(s.trim().toLowerCase()))
|
|
349
|
-
.filter(
|
|
396
|
+
.filter((s) => s !== "" && !CORE_PROMOTED_SURFACES.has(s));
|
|
350
397
|
for (const s of requested) {
|
|
351
398
|
if (!RECOGNIZED_SURFACES.includes(s)) {
|
|
352
399
|
throw new SurfaceError(`unknown surface "${s}". Recognized: ${RECOGNIZED_SURFACES.join(", ")}`);
|
|
@@ -376,6 +423,8 @@ export function resolveSurfaces(modules = ["marketing"], explicit = []) {
|
|
|
376
423
|
const selected = new Set(modules.map((m) => m.trim().toLowerCase()));
|
|
377
424
|
for (const raw of explicit) {
|
|
378
425
|
const s = canonicalizeSurface(raw);
|
|
426
|
+
if (CORE_PROMOTED_SURFACES.has(s))
|
|
427
|
+
continue;
|
|
379
428
|
if (!RECOGNIZED_SURFACES.includes(s)) {
|
|
380
429
|
throw new SurfaceError(`unknown surface "${s}". Recognized: ${RECOGNIZED_SURFACES.join(", ")}`);
|
|
381
430
|
}
|
|
@@ -458,6 +507,10 @@ export function excludedContentPaths(enabled) {
|
|
|
458
507
|
export const ROUTE_SINCE = {
|
|
459
508
|
about: "0.0.0",
|
|
460
509
|
"blog/[[...slug]]": "0.0.0",
|
|
510
|
+
// #6658 — four genuinely new route directories (D4, D5), attaching at
|
|
511
|
+
// today's fixed-group version, the same "attach at today's version" rule
|
|
512
|
+
// #6084, #5977, #5678, #5479, #5371 and #5048 applied.
|
|
513
|
+
"book-a-call": "0.26.0",
|
|
461
514
|
careers: "0.0.0",
|
|
462
515
|
"careers/[slug]": "0.0.0",
|
|
463
516
|
"case-studies": "0.0.0",
|
|
@@ -471,10 +524,14 @@ export const ROUTE_SINCE = {
|
|
|
471
524
|
downloads: "0.0.0",
|
|
472
525
|
events: "0.0.0",
|
|
473
526
|
"events/[slug]": "0.0.0",
|
|
527
|
+
// #6721 — the feature pages, a new route pair at today's line.
|
|
528
|
+
features: "0.27.0",
|
|
529
|
+
"features/[slug]": "0.27.0",
|
|
474
530
|
faq: "0.0.0",
|
|
475
531
|
"flows/[slug]": "0.0.0",
|
|
476
532
|
"flows/[slug]/results/[payload]": "0.14.0",
|
|
477
533
|
"flows/[slug]/start": "0.18.0",
|
|
534
|
+
glossary: "0.26.0",
|
|
478
535
|
"how-to": "0.0.0",
|
|
479
536
|
"how-to/[slug]": "0.0.0",
|
|
480
537
|
integrations: "0.0.0",
|
|
@@ -486,11 +543,15 @@ export const ROUTE_SINCE = {
|
|
|
486
543
|
// in rather than the "predates the manifest" 0.0.0 above.
|
|
487
544
|
"meet/[slug]": "0.5.0",
|
|
488
545
|
"meet/confirmed": "0.0.0",
|
|
546
|
+
newsletter: "0.26.0",
|
|
489
547
|
partners: "0.0.0",
|
|
490
548
|
"partners/[slug]": "0.0.0",
|
|
491
549
|
// #5479 — three genuinely new route directories, so they attach at today's
|
|
492
550
|
// fixed-group version rather than the "predates the manifest" 0.0.0 above,
|
|
493
551
|
// the same rule #5048 ("projects/apply") and #5014 ("(authed)") applied.
|
|
552
|
+
// #6687 — the before/after portfolio, a new route pair at today's line.
|
|
553
|
+
portfolio: "0.27.0",
|
|
554
|
+
"portfolio/[slug]": "0.27.0",
|
|
494
555
|
pricing: "0.22.0",
|
|
495
556
|
privacy: "0.22.0",
|
|
496
557
|
products: "0.0.0",
|
|
@@ -519,6 +580,7 @@ export const ROUTE_SINCE = {
|
|
|
519
580
|
testimonials: "0.0.0",
|
|
520
581
|
"thanks/[slug]": "0.14.0",
|
|
521
582
|
"use-cases": "0.0.0",
|
|
583
|
+
"use-cases/[slug]": "0.26.0",
|
|
522
584
|
whitepapers: "0.0.0",
|
|
523
585
|
"whitepapers/[slug]": "0.0.0",
|
|
524
586
|
// #5014 — the (authed) route GROUP: layout.tsx + sign-in-gate.tsx sit
|
|
@@ -708,44 +770,152 @@ export const NAV_CONFIG_PATH = "apps/web/lib/nav-config.ts";
|
|
|
708
770
|
* surface set for the same reason the route tree does.
|
|
709
771
|
*
|
|
710
772
|
* The base items are the Free marketing-site chrome (#5469 D5, the approved
|
|
711
|
-
* chrome diff recorded on that card):
|
|
712
|
-
* a Product flyout
|
|
713
|
-
* and About.
|
|
714
|
-
*
|
|
715
|
-
*
|
|
716
|
-
*
|
|
717
|
-
* the nav still never links a page the
|
|
773
|
+
* chrome diff recorded on that card, re-pointed by #6658 D8):
|
|
774
|
+
* a Product flyout in two columns (Features · Use Cases, #6721), then Blog,
|
|
775
|
+
* Pricing and About. The feature and use-case links ride the `features` and
|
|
776
|
+
* `use-cases` surfaces; `/blog` is always linked (the teaser or the docs-blog
|
|
777
|
+
* module serves it). Pricing is gateable
|
|
778
|
+
* surfaces: each item is emitted only when its surface is enabled (a template
|
|
779
|
+
* roster enables it, #5469 D10), so the nav still never links a page the
|
|
780
|
+
* scaffold does not carry.
|
|
718
781
|
*
|
|
719
782
|
* Only gateable surfaces carrying a `navLabelKey` are linked after the base
|
|
720
783
|
* items, because a nav entry needs a translated label. Emitting an entry whose
|
|
721
784
|
* `labelKey` has no translation would trade a dead link for a missing-message
|
|
722
785
|
* error.
|
|
723
786
|
*
|
|
787
|
+
* The same file carries `footerColumns`, the footer's column groups (#6468):
|
|
788
|
+
* label keys and paths only, under the same gates, so the footer links every
|
|
789
|
+
* seed page the header does not.
|
|
790
|
+
*
|
|
724
791
|
* Deterministic: gateable entries follow GATEABLE_SURFACES order (alphabetical
|
|
725
792
|
* by id), after the fixed base items.
|
|
726
793
|
*/
|
|
727
794
|
export function renderNavConfig(enabled) {
|
|
728
795
|
const on = new Set(enabled);
|
|
729
|
-
|
|
796
|
+
// `blog` is linked unconditionally below (operator ruling 2026-09-23), so
|
|
797
|
+
// it is excluded here; `use-cases` is the Free roster's own page (a
|
|
798
|
+
// module-less surface the roster enables, like `pricing`), linked in its
|
|
799
|
+
// fixed positions below rather than appended.
|
|
800
|
+
const linked = GATEABLE_SURFACES.filter((s) => s.navLabelKey !== undefined &&
|
|
801
|
+
on.has(s.id) &&
|
|
802
|
+
s.id !== "blog" &&
|
|
803
|
+
s.id !== "use-cases");
|
|
804
|
+
const useCases = on.has("use-cases");
|
|
805
|
+
const features = on.has("features");
|
|
806
|
+
// #6721 (operator ruling 2026-09-25): the Product flyout is two columns —
|
|
807
|
+
// Features and Use Cases — each a heading over three label-only links. The
|
|
808
|
+
// `groups` render the desktop panel; `features` carries the same links for
|
|
809
|
+
// the mobile disclosure and the active-path match. "Use cases" left the top
|
|
810
|
+
// nav (it lives in the flyout and its own footer column).
|
|
811
|
+
const featureLinks = features
|
|
812
|
+
? [
|
|
813
|
+
' { labelKey: "feature1", path: "/features/feature-1" },',
|
|
814
|
+
' { labelKey: "feature2", path: "/features/feature-2" },',
|
|
815
|
+
' { labelKey: "feature3", path: "/features/feature-3" },',
|
|
816
|
+
]
|
|
817
|
+
: [];
|
|
818
|
+
const useCaseLinks = useCases
|
|
819
|
+
? [
|
|
820
|
+
' { labelKey: "useCase1", path: "/use-cases/persona-1" },',
|
|
821
|
+
' { labelKey: "useCase2", path: "/use-cases/persona-2" },',
|
|
822
|
+
' { labelKey: "useCase3", path: "/use-cases/persona-3" },',
|
|
823
|
+
]
|
|
824
|
+
: [];
|
|
825
|
+
const indent = (line) => ` ${line}`;
|
|
826
|
+
const group = (headingKey, links) => links.length === 0
|
|
827
|
+
? []
|
|
828
|
+
: [
|
|
829
|
+
" {",
|
|
830
|
+
` headingKey: "${headingKey}",`,
|
|
831
|
+
" items: [",
|
|
832
|
+
...links.map(indent),
|
|
833
|
+
" ],",
|
|
834
|
+
" },",
|
|
835
|
+
];
|
|
730
836
|
const entries = [
|
|
731
837
|
" {",
|
|
732
838
|
' labelKey: "product",',
|
|
733
839
|
" flyout: {",
|
|
734
|
-
|
|
735
|
-
' width: "
|
|
840
|
+
// SOFT_LOCK_OK: #6508 — width "panel" (D4/D5): a fixed 640px panel.
|
|
841
|
+
' width: "panel",',
|
|
736
842
|
" features: [",
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
843
|
+
...featureLinks,
|
|
844
|
+
...useCaseLinks,
|
|
845
|
+
" ],",
|
|
846
|
+
" groups: [",
|
|
847
|
+
...group("flyoutFeaturesHeading", featureLinks),
|
|
848
|
+
...group("flyoutUseCasesHeading", useCaseLinks),
|
|
740
849
|
" ],",
|
|
741
|
-
|
|
850
|
+
" actions: [],",
|
|
742
851
|
" },",
|
|
743
852
|
" },",
|
|
744
|
-
|
|
853
|
+
// Operator ruling 2026-09-25: Product · Blog · Pricing · About.
|
|
854
|
+
// `/blog` is always linked — the `blog` surface serves the real route, and
|
|
855
|
+
// with it off the `[slug]` route serves the overlay's module page.
|
|
856
|
+
' { labelKey: "blog", path: "/blog" },',
|
|
745
857
|
...(on.has("pricing") ? [' { labelKey: "pricing", path: "/pricing" },'] : []),
|
|
746
858
|
' { labelKey: "about", path: "/about" },',
|
|
747
859
|
...linked.map((s) => ` { labelKey: "${s.navLabelKey}", path: "/${s.id}" },`),
|
|
748
860
|
];
|
|
861
|
+
// The footer's column groups (operator rulings 2026-09-23 + 2026-09-25):
|
|
862
|
+
// Site pages, Features, Use Cases, Resources. Pricing rides the same
|
|
863
|
+
// `pricing` gate as the header item; `/blog` is always linked (above). The
|
|
864
|
+
// Features column links the three feature pages and the /features hub; the
|
|
865
|
+
// Use Cases column the three use cases and the /use-cases hub — each rides
|
|
866
|
+
// its surface's gate. Book a call, Glossary and Newsletter (#6658 D8) each
|
|
867
|
+
// ride their own surface's gate.
|
|
868
|
+
const footerEntries = [
|
|
869
|
+
" {",
|
|
870
|
+
' headingKey: "footerSitePagesHeading",',
|
|
871
|
+
" items: [",
|
|
872
|
+
...(features ? [' { labelKey: "features", path: "/features" },'] : []),
|
|
873
|
+
...(on.has("pricing")
|
|
874
|
+
? [' { labelKey: "pricing", path: "/pricing" },']
|
|
875
|
+
: []),
|
|
876
|
+
' { labelKey: "about", path: "/about" },',
|
|
877
|
+
' { labelKey: "contact", path: "/contact" },',
|
|
878
|
+
...(on.has("book-a-call")
|
|
879
|
+
? [' { labelKey: "bookACall", path: "/book-a-call" },']
|
|
880
|
+
: []),
|
|
881
|
+
" ],",
|
|
882
|
+
" },",
|
|
883
|
+
...(features
|
|
884
|
+
? [
|
|
885
|
+
" {",
|
|
886
|
+
' headingKey: "footerFeaturesHeading",',
|
|
887
|
+
" items: [",
|
|
888
|
+
...featureLinks.map((l) => l.slice(2)),
|
|
889
|
+
' { labelKey: "allFeatures", path: "/features" },',
|
|
890
|
+
" ],",
|
|
891
|
+
" },",
|
|
892
|
+
]
|
|
893
|
+
: []),
|
|
894
|
+
...(useCases
|
|
895
|
+
? [
|
|
896
|
+
" {",
|
|
897
|
+
' headingKey: "footerUseCasesHeading",',
|
|
898
|
+
" items: [",
|
|
899
|
+
...useCaseLinks.map((l) => l.slice(2)),
|
|
900
|
+
' { labelKey: "allUseCases", path: "/use-cases" },',
|
|
901
|
+
" ],",
|
|
902
|
+
" },",
|
|
903
|
+
]
|
|
904
|
+
: []),
|
|
905
|
+
" {",
|
|
906
|
+
' headingKey: "footerResourcesHeading",',
|
|
907
|
+
" items: [",
|
|
908
|
+
' { labelKey: "blog", path: "/blog" },',
|
|
909
|
+
...(on.has("glossary")
|
|
910
|
+
? [' { labelKey: "glossary", path: "/glossary" },']
|
|
911
|
+
: []),
|
|
912
|
+
...(on.has("newsletter")
|
|
913
|
+
? [' { labelKey: "newsletter", path: "/newsletter" },']
|
|
914
|
+
: []),
|
|
915
|
+
' { labelKey: "faq", path: "/faq" },',
|
|
916
|
+
" ],",
|
|
917
|
+
" },",
|
|
918
|
+
];
|
|
749
919
|
// The emitted file imports the consumer's `NavItem` type from the UI package.
|
|
750
920
|
// Assembled from fragments so THIS source file never contains the literal
|
|
751
921
|
// import string: `tools/lint-architecture.ts` matches on source text, so a
|
|
@@ -763,15 +933,25 @@ export function renderNavConfig(enabled) {
|
|
|
763
933
|
// points at a route this site actually carries — the nav is regenerated with
|
|
764
934
|
// the surface set so it can never link a page that was not scaffolded.
|
|
765
935
|
//
|
|
766
|
-
// Adding a link: scaffold the page (the \`
|
|
936
|
+
// Adding a link: scaffold the page (the \`add-page\` skill), then add an
|
|
767
937
|
// entry below with a \`labelKey\` that exists in the \`nav\` namespace of
|
|
768
938
|
// \`apps/web/messages/<locale>.json\`. Paths are locale-agnostic — Nav prefixes
|
|
769
939
|
// them with the active locale at render.
|
|
770
940
|
${navItemImport}
|
|
771
|
-
import { BookOpen, HelpCircle, Layers, Sparkles } from "lucide-react";
|
|
772
941
|
|
|
773
942
|
export const navItems: NavItem[] = [
|
|
774
943
|
${entries.join("\n")}
|
|
775
944
|
];
|
|
945
|
+
|
|
946
|
+
// Footer column groups. Keys only — the layout resolves each \`headingKey\`
|
|
947
|
+
// and \`labelKey\` through the same \`nav\` labels as the header.
|
|
948
|
+
export interface FooterColumnConfig {
|
|
949
|
+
headingKey: string;
|
|
950
|
+
items: { labelKey: string; path: string }[];
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
export const footerColumns: FooterColumnConfig[] = [
|
|
954
|
+
${footerEntries.join("\n")}
|
|
955
|
+
];
|
|
776
956
|
`;
|
|
777
957
|
}
|
package/dist/sync-routes.d.ts
CHANGED
|
@@ -15,6 +15,15 @@ export interface SyncRoutesOptions {
|
|
|
15
15
|
versions: WorkspaceVersionMap;
|
|
16
16
|
/** Copy the missing routes into the target. Default false = check only. */
|
|
17
17
|
apply?: boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Surface ids to treat as carried whether or not any of their route dirs
|
|
20
|
+
* exists yet (#6653 D8) — `add-module` passes the added module's
|
|
21
|
+
* `MODULE_SURFACES`, since a surface whose routes ship from `templates/`
|
|
22
|
+
* would otherwise read as not-carried on first add and never be copied.
|
|
23
|
+
* Undefined for every other caller: the carried set is then exactly the
|
|
24
|
+
* presence-derived one.
|
|
25
|
+
*/
|
|
26
|
+
forceSurfaces?: readonly string[];
|
|
18
27
|
}
|
|
19
28
|
/** One route directory the report names. */
|
|
20
29
|
export interface RouteReport {
|
package/dist/sync-routes.js
CHANGED
|
@@ -141,10 +141,10 @@ export function syncRoutes(opts) {
|
|
|
141
141
|
// unrelated "projects" CONTENT surface is separately requested. Without
|
|
142
142
|
// this exclusion, a signal-collectors-only scaffold would falsely read as
|
|
143
143
|
// "carries projects" the moment its bundle lands that one file.
|
|
144
|
-
const carried = new Set();
|
|
144
|
+
const carried = new Set(opts.forceSurfaces ?? []);
|
|
145
145
|
const skippedSurfaces = [];
|
|
146
146
|
for (const surface of GATEABLE_SURFACES) {
|
|
147
|
-
const present = surface.routes.some((r) => {
|
|
147
|
+
const present = carried.has(surface.id) || surface.routes.some((r) => {
|
|
148
148
|
const p = join(targetAbs, r);
|
|
149
149
|
if (!existsSync(p) || !statSync(p).isDirectory())
|
|
150
150
|
return false;
|
|
@@ -18,6 +18,34 @@ import type { CategorySlug } from "@working-theory/schema/categories";
|
|
|
18
18
|
import { type PageRosterRow } from "./module-architecture.js";
|
|
19
19
|
import type { ModuleName } from "./parse-args.js";
|
|
20
20
|
import type { TemplateLayout } from "./site-chrome.js";
|
|
21
|
+
import { type BuildableShape, type TemplateAlias } from "./starter-grid.js";
|
|
22
|
+
/**
|
|
23
|
+
* The closed **shape** enum (starter-template contract § The three axes,
|
|
24
|
+
* operator-disposed 2026-09-24) — `<primary node>-<offering node>` in
|
|
25
|
+
* schema.org terms, kebab-cased. Declared beside `TemplateManifest`, the same
|
|
26
|
+
* pattern `ModuleName` uses in `parse-args.ts`: a `readonly [...] as const`
|
|
27
|
+
* array plus its derived literal-union type, so an unrecognized value fails
|
|
28
|
+
* type-check rather than a runtime validation.
|
|
29
|
+
*/
|
|
30
|
+
export declare const STARTER_SHAPES: readonly ["organization-product", "organization-service", "local-business-service", "local-business-product", "person-service"];
|
|
31
|
+
export type StarterShape = (typeof STARTER_SHAPES)[number];
|
|
32
|
+
/**
|
|
33
|
+
* The closed **design** enum (same contract section) — the look applied to
|
|
34
|
+
* any shape; orthogonal to it by construction.
|
|
35
|
+
*/
|
|
36
|
+
export declare const STARTER_DESIGNS: readonly ["standard", "minimalism"];
|
|
37
|
+
export type StarterDesign = (typeof STARTER_DESIGNS)[number];
|
|
38
|
+
/**
|
|
39
|
+
* Each design's layout knobs (#6638) — the part of a design that is chrome,
|
|
40
|
+
* so a template names `design:` instead of re-typing a `layout` block, and any
|
|
41
|
+
* shape can wear any design. `resolveSiteChrome(layout, design)` reads it:
|
|
42
|
+
* an explicit `TemplateManifest.layout` wins field by field, then this, then
|
|
43
|
+
* `DEFAULT_SITE_CHROME`. `standard` declares nothing — it IS the defaults, so
|
|
44
|
+
* spelling them out here would be a second copy of them to drift. A plain
|
|
45
|
+
* object, not a file: this module touches no disk. The design's documented
|
|
46
|
+
* look lives in `site-templates/designs/<design>/DESIGN.md`.
|
|
47
|
+
*/
|
|
48
|
+
export declare const DESIGN_LAYOUTS: Readonly<Record<StarterDesign, TemplateLayout>>;
|
|
21
49
|
/**
|
|
22
50
|
* One site template: its fixed module list and the page rows it brings itself.
|
|
23
51
|
*
|
|
@@ -57,6 +85,20 @@ export interface TemplateManifest {
|
|
|
57
85
|
* registry — never a group here.
|
|
58
86
|
*/
|
|
59
87
|
categories: readonly CategorySlug[];
|
|
88
|
+
/**
|
|
89
|
+
* The shape this template's roster renders (starter-template contract § The
|
|
90
|
+
* three axes) — `<primary node>-<offering node>`, from the closed
|
|
91
|
+
* {@link STARTER_SHAPES} enum. Owns the entity preset, the roster and each
|
|
92
|
+
* page's section stack; the machine truth the showcase, the build-starter
|
|
93
|
+
* skill and the render gate read — never the directory name.
|
|
94
|
+
*/
|
|
95
|
+
shape: StarterShape;
|
|
96
|
+
/**
|
|
97
|
+
* The design this template renders (same contract section) — the look,
|
|
98
|
+
* orthogonal to `shape` by construction: any design applies to any shape.
|
|
99
|
+
* From the closed {@link STARTER_DESIGNS} enum.
|
|
100
|
+
*/
|
|
101
|
+
design: StarterDesign;
|
|
60
102
|
/**
|
|
61
103
|
* The template this one EXTENDS — its lineage, never its level (#5618 D2).
|
|
62
104
|
* A single parent, not a list: "later layers win file by file" needs a
|
|
@@ -70,7 +112,7 @@ export interface TemplateManifest {
|
|
|
70
112
|
*/
|
|
71
113
|
extends: string;
|
|
72
114
|
/** Base rows, before any module's contribution is merged. */
|
|
73
|
-
roster: readonly
|
|
115
|
+
roster: readonly TemplateRosterRow[];
|
|
74
116
|
/** Bundle-relative source → scaffold-relative destination. */
|
|
75
117
|
installMap?: Record<string, string>;
|
|
76
118
|
/**
|
|
@@ -94,26 +136,30 @@ export interface TemplateManifest {
|
|
|
94
136
|
* the directory-scanning tests key their skip on.
|
|
95
137
|
*/
|
|
96
138
|
export declare const BASE_LAYER_DIR = "_base";
|
|
139
|
+
/**
|
|
140
|
+
* One row of a template's own roster — the same shape as a module's
|
|
141
|
+
* `PageRosterRow`, `contentDir` included (#6646 disposition (a)): a module's
|
|
142
|
+
* contributed detail row (`/reports/[slug]`) serves a seed directory exactly
|
|
143
|
+
* as a template's own does. Where `routes-map.ts` records the route's
|
|
144
|
+
* `contentPath`, the generator refuses a `contentDir` that disagrees.
|
|
145
|
+
*/
|
|
146
|
+
export type TemplateRosterRow = PageRosterRow;
|
|
147
|
+
/**
|
|
148
|
+
* Whether a merged roster declares one scaffold-relative content file
|
|
149
|
+
* (#6646 D1): named by a row's `content`, or under a row's `contentDir`.
|
|
150
|
+
* The one predicate the scaffold's per-row install and the manifest
|
|
151
|
+
* generator's install-diff both read, so the two cannot disagree.
|
|
152
|
+
*/
|
|
153
|
+
export declare function rosterDeclares(roster: readonly TemplateRosterRow[], path: string): boolean;
|
|
97
154
|
/** Thrown on an undeclared template name or a route claimed twice. Mirrors `SurfaceError`'s shape. */
|
|
98
155
|
export declare class TemplateError extends Error {
|
|
99
156
|
constructor(message: string);
|
|
100
157
|
}
|
|
101
158
|
/**
|
|
102
|
-
* The
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
* `workspace` appears in none of them. It is a Pro module, but an authed app
|
|
107
|
-
* surface contributing no PUBLIC page to a marketing site, and `requires`
|
|
108
|
-
* names what the roster uses (parent § D15). A Pro key unlocks it regardless
|
|
109
|
-
* of any template. `ModuleName` could express it either way — `workspace` is
|
|
110
|
-
* one of the seven `RECOGNIZED_MODULES` names; it is simply not one any
|
|
111
|
-
* template's fixed `requires` list names.
|
|
112
|
-
*
|
|
113
|
-
* `commerce` is likewise in none of them: it is a per-site add-on available at
|
|
114
|
-
* any level, so a template for it would contradict the offering model and
|
|
115
|
-
* multiply the set combinatorially (parent § D13). It still contributes rows
|
|
116
|
-
* to whichever template takes it, through `mergeRoster` below.
|
|
159
|
+
* The declared templates, each composed once at load from its `ALIASES` row
|
|
160
|
+
* (#6753) — no manifest here is hand-typed, so a template's shape, design,
|
|
161
|
+
* modules and roster have one authority: `starter-grid.ts`. Declaration order
|
|
162
|
+
* is `ALIASES`'s, which is `RECOGNIZED_TEMPLATES`'s.
|
|
117
163
|
*
|
|
118
164
|
* Frozen (#5507): this registry is also the issuer's authorization allowlist
|
|
119
165
|
* (spec 5480 § C7) — a mutable global there could be monkey-patched at
|
|
@@ -121,8 +167,37 @@ export declare class TemplateError extends Error {
|
|
|
121
167
|
* fixture rather than mutating this one.
|
|
122
168
|
*/
|
|
123
169
|
export declare const TEMPLATE_MANIFESTS: Readonly<Record<string, TemplateManifest>>;
|
|
124
|
-
/**
|
|
125
|
-
|
|
170
|
+
/**
|
|
171
|
+
* The composed FREE manifest per shape with no `--template` alias of its own
|
|
172
|
+
* (#6757 D5) — the coordinates a keyless `--shape S` builds. `Object.freeze`d,
|
|
173
|
+
* composed once at load by the same module-private `composeManifest` over
|
|
174
|
+
* `SHAPE_STARTER_ALIASES`, each manifest's `name` the shape. Data holding
|
|
175
|
+
* composed manifests, the status D5 gives `TEMPLATE_MANIFESTS`;
|
|
176
|
+
* `resolveTemplate` stays the only exported function that yields a
|
|
177
|
+
* template's roster, and its behavior is unchanged — it does NOT resolve a
|
|
178
|
+
* shape name (NFR-3, the issuer allowlist stays `TEMPLATE_MANIFESTS`-only).
|
|
179
|
+
*/
|
|
180
|
+
export declare const SHAPE_STARTERS: Readonly<Partial<Record<BuildableShape, TemplateManifest>>>;
|
|
181
|
+
/**
|
|
182
|
+
* Where a starter's files live under `site-templates/` (#6757 D5) — the one
|
|
183
|
+
* place that says so. A `SHAPE_STARTERS` key (a bare-shape starter with no
|
|
184
|
+
* `--template` alias) lives at `shapes/<name>`, out of the template showcase
|
|
185
|
+
* (§ 1.6); every other name (a declared `--template` alias) is unchanged.
|
|
186
|
+
*/
|
|
187
|
+
export declare function templateTreeDir(name: string): string;
|
|
188
|
+
/**
|
|
189
|
+
* Look up a declared template — the one exported function that yields a
|
|
190
|
+
* template's roster (#6753 AC-1); `TEMPLATE_MANIFESTS`, the frozen record it
|
|
191
|
+
* reads, holds only manifests composed from `ALIASES`.
|
|
192
|
+
*
|
|
193
|
+
* With no `aliases`, returns the frozen `TEMPLATE_MANIFESTS` entry itself.
|
|
194
|
+
* With an injected alias table — the `resolveTemplateLineage` precedent
|
|
195
|
+
* (#5507) — composes `aliases[name]` against the shipped shape rosters, so a
|
|
196
|
+
* test exercises the composer's refusals without touching the shipped table.
|
|
197
|
+
*
|
|
198
|
+
* @throws TemplateError on an undeclared name, or a malformed injected alias.
|
|
199
|
+
*/
|
|
200
|
+
export declare function resolveTemplate(name: string, aliases?: Readonly<Record<string, TemplateAlias>>): TemplateManifest;
|
|
126
201
|
/**
|
|
127
202
|
* Resolve a template's `extends` chain — `[name, …ancestors, "_base"]` — in
|
|
128
203
|
* the client registry, before any fetch (#5618 D2). `_base` is the only
|
|
@@ -161,7 +236,7 @@ export declare function resolveTemplateLineage(name: string, registry?: Readonly
|
|
|
161
236
|
* runtime by a base-wins or module-wins precedence rule, either of which
|
|
162
237
|
* silently produces a site missing a page someone declared.
|
|
163
238
|
*/
|
|
164
|
-
export declare function mergeRoster(manifest: TemplateManifest, modules: readonly string[]):
|
|
239
|
+
export declare function mergeRoster(manifest: TemplateManifest, modules: readonly string[]): TemplateRosterRow[];
|
|
165
240
|
/**
|
|
166
241
|
* Whether a template installs on the keyless path or needs a verified
|
|
167
242
|
* `AILK_LICENSE_KEY` — derived from `requires`, never declared (parent § D3).
|