create-ailk 0.7.0 → 0.9.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 +112 -10
- package/component-catalog.json +798 -49
- package/component-catalog.md +9 -6
- package/dist/add-module.d.ts +20 -0
- package/dist/add-module.js +43 -7
- package/dist/add-route.d.ts +56 -0
- package/dist/add-route.js +286 -0
- package/dist/apply-design-md.d.ts +7 -0
- package/dist/apply-design-md.js +50 -0
- package/dist/apply-design.d.ts +64 -0
- package/dist/apply-design.js +273 -0
- package/dist/claude-md.d.ts +111 -0
- package/dist/claude-md.js +334 -0
- package/dist/cli.js +114 -28
- package/dist/derive-architecture.js +41 -36
- package/dist/design-compile.d.ts +71 -0
- package/dist/design-compile.js +98 -0
- package/dist/design-package.d.ts +83 -0
- package/dist/design-package.js +468 -0
- package/dist/design-presets.d.ts +86 -0
- package/dist/design-presets.js +642 -0
- package/dist/design-scaffold.d.ts +76 -0
- package/dist/design-scaffold.js +220 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +4 -1
- package/dist/legacy-nav-renderers.d.ts +45 -0
- package/dist/legacy-nav-renderers.js +545 -0
- package/dist/lib/auth-secret-file.d.ts +19 -0
- package/dist/lib/auth-secret-file.js +112 -0
- package/dist/lib/design-checks.d.ts +78 -0
- package/dist/lib/design-checks.js +174 -0
- package/dist/lib/extract-module-bundle.js +5 -1
- package/dist/lib/license-key-files.d.ts +9 -0
- package/dist/lib/license-key-files.js +2 -2
- package/dist/lib/module-license-gate.d.ts +89 -0
- package/dist/lib/module-license-gate.js +171 -12
- package/dist/lib/module-tier.d.ts +45 -16
- package/dist/lib/module-tier.js +76 -0
- package/dist/lib/pro-callout.js +10 -2
- package/dist/lib/render-verdict.d.ts +52 -0
- package/dist/lib/render-verdict.js +77 -0
- package/dist/lib/scaffold-render-sweep.d.ts +105 -0
- package/dist/lib/scaffold-render-sweep.js +236 -0
- package/dist/module-architecture.d.ts +19 -16
- package/dist/module-architecture.js +64 -21
- package/dist/parse-args.d.ts +88 -10
- package/dist/parse-args.js +272 -21
- package/dist/programmatic.d.ts +66 -12
- package/dist/programmatic.js +361 -34
- package/dist/site-chrome.d.ts +19 -9
- package/dist/site-chrome.js +23 -13
- package/dist/site-manifest.d.ts +25 -0
- package/dist/site-manifest.js +254 -0
- package/dist/site-roster.d.ts +41 -0
- package/dist/site-roster.js +149 -11
- package/dist/starter-grid.d.ts +232 -0
- package/dist/starter-grid.js +545 -0
- package/dist/surfaces.d.ts +41 -9
- package/dist/surfaces.js +268 -92
- package/dist/template-manifest.d.ts +65 -29
- package/dist/template-manifest.js +161 -382
- package/dist/template-names.d.ts +14 -12
- package/dist/template-names.js +13 -17
- package/package.json +5 -4
- 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 +0 -1
- package/site-templates/_base/content/en/NewsletterSignup/newsletter.mdx +0 -1
- 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/PrivacyPage/privacy.mdx +15 -0
- package/site-templates/_base/content/en/UseCase/persona-1.mdx +70 -0
- package/site-templates/_base/content/en/UseCase/persona-2.mdx +70 -0
- package/site-templates/_base/content/en/UseCase/persona-3.mdx +70 -0
- package/site-templates/{minimalism-site/TEMPLATE-MANIFEST.json → aliases/minimalism-site.TEMPLATE-MANIFEST.json} +72 -40
- package/site-templates/designs/minimalism/DESIGN.md +98 -6
- package/site-templates/designs/minimalism/sample/README.md +48 -0
- package/site-templates/designs/standard/DESIGN.md +103 -6
- package/site-templates/marketing-site/DESIGN.md +103 -6
- package/site-templates/marketing-site/TEMPLATE-MANIFEST.json +144 -47
- package/site-templates/marketing-site/TEMPLATE-MANIFEST.md +82 -41
- package/site-templates/marketing-site-free/DESIGN.md +103 -6
- package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.json +150 -48
- package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.md +114 -67
- package/site-templates/marketing-site-free/ailk-template.json +1 -1
- 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/saas-product/DESIGN.md +103 -6
- package/site-templates/saas-product/TEMPLATE-MANIFEST.md +9 -1
- package/site-templates/{simple-service → shapes/local-business-service}/TEMPLATE-MANIFEST.json +210 -81
- package/site-templates/shapes/local-business-service/TEMPLATE-MANIFEST.md +356 -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/{minimalism-site → shapes/local-business-service}/content/en/PurchasePolicyPage/purchase-policy.mdx +7 -8
- 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 +471 -0
- package/site-templates/shapes/organization-service/TEMPLATE-MANIFEST.md +354 -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/{minimalism-site → shapes/organization-service}/content/en/ServicesList/services.mdx +3 -4
- package/site-templates/shapes/organization-service/provenance.json +4 -0
- package/site-templates/shapes/person-service/TEMPLATE-MANIFEST.json +478 -0
- package/site-templates/shapes/person-service/TEMPLATE-MANIFEST.md +353 -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 +171 -0
- package/site-templates/{simple-service → shapes/person-service}/content/en/PurchasePolicyPage/purchase-policy.mdx +10 -11
- 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/rules/architecture.md +7 -0
- package/templates/.claude/skills/README.md +5 -3
- package/templates/.claude/skills/add-auth/references/env-vars.md +22 -15
- package/templates/.claude/skills/add-auth/references/oauth-app-setup.md +3 -2
- package/templates/.claude/skills/add-page/SKILL.md +241 -238
- package/templates/.claude/skills/add-page/references/page-types.md +85 -72
- package/templates/.claude/skills/add-page/scripts/site-pages.mjs +87 -0
- package/templates/.claude/skills/add-page/templates/comparison-page.mdx.tmpl +99 -0
- package/templates/.claude/skills/add-page/templates/content.mdx.tmpl +8 -18
- package/templates/.claude/skills/add-page/templates/flow-landing-page.mdx.tmpl +43 -0
- package/templates/.claude/skills/add-page/templates/report-page.mdx.tmpl +52 -0
- package/templates/.claude/skills/add-page/templates/reports-list.mdx.tmpl +38 -0
- package/templates/.claude/skills/check-site/SKILL.md +23 -0
- package/templates/.claude/skills/fill-page/SKILL.md +26 -7
- package/templates/.claude/skills/fill-page/profiles/plumbing.yaml +1 -1
- 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/setup-deploy/SKILL.md +64 -32
- package/templates/.claude/skills/setup-deploy/references/env-vars-template.md +44 -36
- package/templates/.claude/skills/setup-deploy/references/runbook-template.md +58 -102
- package/templates/.claude/skills/update-page/SKILL.md +117 -0
- package/templates/.claude/skills/update-page/scripts/update-page.ts +640 -0
- package/templates/.claude/skills/update-page/templates/redirects.mjs.tmpl +31 -0
- package/templates/.claude/skills/upgrade-plan/SKILL.md +12 -8
- package/templates/.github/workflows/ci.yml +4 -0
- package/templates/.prettierignore +1 -0
- package/templates/CLAUDE.md +146 -103
- package/templates/DESIGN.md +103 -6
- package/templates/README.md +63 -43
- package/templates/apps/api/.env.example +2 -1
- package/templates/apps/api/CLAUDE.md +3 -2
- package/templates/apps/api/src/__tests__/commerce-claim-registration.test.ts +2 -0
- package/templates/apps/api/src/__tests__/server.test.ts +116 -0
- package/templates/apps/api/src/config/__tests__/index.test.ts +115 -14
- package/templates/apps/api/src/config/index.ts +35 -16
- 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/stripe.ts +9 -0
- package/templates/apps/api/src/middleware/__tests__/auth.optional-cookie.test.ts +140 -0
- package/templates/apps/api/src/middleware/auth.ts +54 -0
- package/templates/apps/api/src/openapi/spec.ts +63 -12
- package/templates/apps/api/src/routes/checkout/__tests__/session.test.ts +5 -2
- package/templates/apps/api/src/routes/checkout/__tests__/sessions.test.ts +628 -0
- package/templates/apps/api/src/routes/checkout/sessions.ts +222 -24
- 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/routes/webhooks/__tests__/stripe-flow-checkout.test.ts +1 -1
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-org-billing.test.ts +5 -1
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe.test.ts +521 -20
- package/templates/apps/api/src/routes/webhooks/stripe.ts +124 -32
- package/templates/apps/api/src/server.ts +35 -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/__tests__/revalidation.test.ts +90 -15
- package/templates/apps/api/src/services/checkout-buyer.ts +72 -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/api/src/services/revalidation.ts +60 -15
- package/templates/apps/mcp/__tests__/parity.test.ts +5 -4
- package/templates/apps/mcp/__tests__/tools/create_project.test.ts +30 -24
- package/templates/apps/mcp/src/tools/create_project.ts +21 -6
- package/templates/apps/mcp/src/tools/purchase.ts +4 -2
- package/templates/apps/web/.env.example +13 -0
- package/templates/apps/web/CLAUDE.md +22 -28
- package/templates/apps/web/app/[locale]/(auth)/layout.tsx +1 -1
- package/templates/apps/web/app/[locale]/(authed)/leads/__tests__/page.test.tsx +24 -0
- package/templates/apps/web/app/[locale]/(authed)/leads/page.tsx +17 -6
- package/templates/apps/web/app/[locale]/[slug]/[detail]/__tests__/page.test.tsx +110 -0
- package/templates/apps/web/app/[locale]/[slug]/[detail]/page.tsx +60 -0
- package/templates/apps/web/app/[locale]/[slug]/page.tsx +1 -1
- package/templates/apps/web/app/[locale]/alternatives/__tests__/page.test.tsx +161 -0
- package/templates/apps/web/app/[locale]/alternatives/page.tsx +104 -0
- package/templates/apps/web/app/[locale]/contact/ConversationalIntakeWrapper.tsx +14 -6
- package/templates/apps/web/app/[locale]/contact/__tests__/ConversationalIntakeWrapper.test.tsx +10 -9
- 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 +227 -84
- 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 +105 -15
- package/templates/apps/web/app/[locale]/contact/site-contact-email.ts +54 -0
- 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]/{use-cases → for}/[slug]/page.tsx +21 -5
- package/templates/apps/web/app/[locale]/for/__tests__/page-renderer-migration.test.tsx +73 -0
- package/templates/apps/web/app/[locale]/{use-cases → for}/page.tsx +8 -7
- package/templates/apps/web/app/[locale]/glossary/page.tsx +1 -1
- package/templates/apps/web/app/[locale]/layout.tsx +65 -17
- 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 +106 -14
- package/templates/apps/web/app/[locale]/portfolio/[slug]/page.tsx +59 -0
- package/templates/apps/web/app/[locale]/{book-a-call → portfolio}/page.tsx +12 -13
- package/templates/apps/web/app/[locale]/vs/[slug]/__tests__/page.test.tsx +112 -0
- package/templates/apps/web/app/[locale]/vs/[slug]/page.tsx +70 -0
- package/templates/apps/web/app/api/revalidate/__tests__/route.test.ts +236 -44
- package/templates/apps/web/app/api/revalidate/route.ts +78 -36
- package/templates/apps/web/lib/__tests__/site-brand.test.ts +79 -0
- package/templates/apps/web/lib/__tests__/site-theme.test.ts +104 -11
- package/templates/apps/web/lib/__tests__/structured-data.test.tsx +21 -4
- package/templates/apps/web/lib/locale-guard.ts +18 -0
- package/templates/apps/web/lib/meet-placeholder.ts +5 -0
- package/templates/apps/web/lib/nav-config.ts +50 -37
- package/templates/apps/web/lib/site-brand.tsx +13 -9
- package/templates/apps/web/lib/site-identity.ts +14 -0
- package/templates/apps/web/lib/site-logo.tsx +36 -0
- package/templates/apps/web/lib/site-theme.ts +46 -26
- package/templates/apps/web/messages/en.json +45 -5
- package/templates/apps/web/middleware.ts +28 -4
- package/templates/content/_site.mdx +4 -2
- package/templates/content/en/BlogList/blog.mdx +37 -16
- package/templates/content/en/BookCall/book-a-call.mdx +80 -0
- package/templates/content/en/BookCall/onsite-estimate.mdx +56 -0
- package/templates/content/en/BookCall/onsite-service.mdx +56 -0
- package/templates/content/en/BookCall/start-project.mdx +56 -0
- package/templates/content/en/ContactPage/contact.mdx +43 -34
- package/templates/content/en/HomePage/home.mdx +10 -22
- package/templates/content/en/LandingPage/meet.mdx +59 -0
- package/templates/content/en/PurchasePolicyPage/purchase-policy.mdx +0 -1
- package/templates/content/en/UseCasesList/{use-cases.mdx → for.mdx} +19 -18
- package/templates/database/CHANGELOG.md +14 -0
- package/templates/database/package.json +1 -1
- package/templates/package.json +2 -1
- package/templates/tools/check-claude-md.ts +128 -0
- package/versions.json +33 -33
- package/site-templates/_base/content/en/BookCall/book-call.mdx +0 -53
- package/site-templates/_base/content/en/UseCase/first-use-case.mdx +0 -23
- package/site-templates/_base/content/en/UseCase/second-use-case.mdx +0 -23
- package/site-templates/_base/content/en/UseCase/third-use-case.mdx +0 -23
- package/site-templates/minimalism-site/DESIGN.md +0 -162
- package/site-templates/minimalism-site/TEMPLATE-MANIFEST.md +0 -470
- package/site-templates/minimalism-site/ailk-template.json +0 -23
- package/site-templates/minimalism-site/content/en/AboutPage/about.mdx +0 -110
- package/site-templates/minimalism-site/content/en/BookCall/book-call.mdx +0 -53
- package/site-templates/minimalism-site/content/en/ContactPage/contact.mdx +0 -34
- package/site-templates/minimalism-site/content/en/FAQPage/faq.mdx +0 -57
- package/site-templates/minimalism-site/content/en/LandingPage/referral.mdx +0 -77
- package/site-templates/minimalism-site/content/en/LandingPage/reports.mdx +0 -73
- package/site-templates/minimalism-site/content/en/ReportPage/annual-letter-2024.mdx +0 -52
- package/site-templates/minimalism-site/content/en/ReportPage/field-notes-2023.mdx +0 -52
- package/site-templates/minimalism-site/content/en/ReportPage/platform-shift-2025.mdx +0 -52
- package/site-templates/minimalism-site/content/en/ReportPage/state-of-the-market-2026.mdx +0 -52
- package/site-templates/minimalism-site/flows/referral.flow.json +0 -71
- package/site-templates/minimalism-site/provenance.json +0 -4
- package/site-templates/simple-service/DESIGN.md +0 -162
- package/site-templates/simple-service/TEMPLATE-MANIFEST.md +0 -333
- package/site-templates/simple-service/ailk-template.json +0 -11
- package/site-templates/simple-service/content/en/BookCall/book-call.mdx +0 -53
- package/site-templates/simple-service/content/en/ContactPage/contact.mdx +0 -32
- 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-page/templates/route.tsx.tmpl +0 -28
- package/templates/apps/web/app/[locale]/contact/ContactForm.tsx +0 -211
- package/templates/apps/web/app/[locale]/contact/__tests__/ContactForm.test.tsx +0 -96
- package/templates/apps/web/app/[locale]/use-cases/__tests__/page-renderer-migration.test.tsx +0 -72
- package/templates/content/en/SoftwareProduct/product.mdx +0 -175
- /package/site-templates/{minimalism-site → designs/minimalism/sample}/content/en/HomePage/home.mdx +0 -0
- /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-1.svg +0 -0
- /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-2.svg +0 -0
- /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-3.svg +0 -0
- /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-4.svg +0 -0
- /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-5.svg +0 -0
- /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-6.svg +0 -0
- /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/hero-backdrop.svg +0 -0
- /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/logo-placeholder-1.svg +0 -0
- /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/logo-placeholder-2.svg +0 -0
- /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/logo-placeholder-3.svg +0 -0
- /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/wordmark-placeholder.svg +0 -0
- /package/site-templates/{minimalism-site → shapes/organization-service}/content/en/Service/first-engagement.mdx +0 -0
- /package/site-templates/{minimalism-site → shapes/organization-service}/content/en/Service/second-engagement.mdx +0 -0
- /package/site-templates/{minimalism-site → shapes/organization-service}/content/en/Service/third-engagement.mdx +0 -0
package/dist/parse-args.js
CHANGED
|
@@ -7,6 +7,9 @@
|
|
|
7
7
|
* On any parse / validation failure: throws ParseError. The orchestrator's
|
|
8
8
|
* top-level catch turns this into a stderr write + non-zero exit.
|
|
9
9
|
*/
|
|
10
|
+
import { existsSync, statSync } from "node:fs";
|
|
11
|
+
import { join, resolve } from "node:path";
|
|
12
|
+
import { createInterface } from "node:readline/promises";
|
|
10
13
|
import { parseArgs } from "node:util";
|
|
11
14
|
import { assertLicenseKeyShape } from "./lib/license-key-files.js";
|
|
12
15
|
import { RECOGNIZED_SURFACES, parseSurfaces } from "./surfaces.js";
|
|
@@ -29,8 +32,33 @@ export const RECOGNIZED_MODULES = [
|
|
|
29
32
|
"signal-collectors",
|
|
30
33
|
"commerce",
|
|
31
34
|
];
|
|
32
|
-
/**
|
|
33
|
-
|
|
35
|
+
/**
|
|
36
|
+
* Shapes a starter can be built from today (`--shape`, #6754 D1).
|
|
37
|
+
*
|
|
38
|
+
* Declared HERE rather than imported from `template-manifest.ts` for the
|
|
39
|
+
* reason `RECOGNIZED_MODULES` is: importing the registry closes the runtime
|
|
40
|
+
* cycle `template-names.ts`'s header records. `parse-args.test.ts` pins this
|
|
41
|
+
* list, `RESERVED_SHAPES` and `RECOGNIZED_DESIGNS` to their authorities
|
|
42
|
+
* (`STARTER_SHAPES`, `STARTER_DESIGNS`, `SHAPE_ROSTERS`).
|
|
43
|
+
*/
|
|
44
|
+
export const RECOGNIZED_SHAPES = [
|
|
45
|
+
"organization-product",
|
|
46
|
+
"organization-service",
|
|
47
|
+
"local-business-service",
|
|
48
|
+
"person-service",
|
|
49
|
+
];
|
|
50
|
+
/** Shapes the contract names but no release builds yet. */
|
|
51
|
+
export const RESERVED_SHAPES = ["local-business-product"];
|
|
52
|
+
/** The `--design` vocabulary (#6754 D1) — `STARTER_DESIGNS`, pinned by test. */
|
|
53
|
+
export const RECOGNIZED_DESIGNS = ["standard", "minimalism"];
|
|
54
|
+
/** What each shape is, for the prompt (D3). A shape without one is a type error. */
|
|
55
|
+
const SHAPE_DESCRIPTIONS = {
|
|
56
|
+
"organization-product": "a company selling a product",
|
|
57
|
+
"organization-service": "a company selling a service",
|
|
58
|
+
"local-business-service": "a local business selling a service",
|
|
59
|
+
"person-service": "a person selling their own service",
|
|
60
|
+
};
|
|
61
|
+
const SHAPE_LIST = RECOGNIZED_SHAPES.join(", ");
|
|
34
62
|
export class ParseError extends Error {
|
|
35
63
|
constructor(message) {
|
|
36
64
|
super(message);
|
|
@@ -51,11 +79,32 @@ Arguments:
|
|
|
51
79
|
Options:
|
|
52
80
|
--modules <csv> Comma-separated list of modules to compose the site
|
|
53
81
|
from (recognized: ${RECOGNIZED_MODULES.join(", ")}).
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
82
|
+
Trims or ADDS relative to the level your licence
|
|
83
|
+
key unlocks (#6759) — it never replaces it. With no
|
|
84
|
+
key, the level is Free (\`marketing\`). A Pro key
|
|
85
|
+
switches on docs-blog, scheduling and
|
|
86
|
+
signal-collectors too; Pro Plus adds multi-tenant.
|
|
87
|
+
Naming modules here keeps EXACTLY those, trimming
|
|
88
|
+
the level's default. Naming only \`commerce\` (a
|
|
89
|
+
per-site add-on) or \`workspace\` (included at Pro,
|
|
90
|
+
opt-in) ADDS it on top of the level's default
|
|
91
|
+
without trimming. A module your licence does not
|
|
92
|
+
include is refused, naming the level that does. A
|
|
93
|
+
module is a composable unit across the three tiers
|
|
94
|
+
(data · API · presentation).
|
|
95
|
+
--shape <shape> The kind of site to build (recognized:
|
|
96
|
+
${SHAPE_LIST}).
|
|
97
|
+
Installs that shape's Free starter. A run naming
|
|
98
|
+
neither --shape nor --template asks for a shape on
|
|
99
|
+
a terminal, and refuses without one.
|
|
100
|
+
--design <design> The look to render the starter in: a design name
|
|
101
|
+
(recognized: ${RECOGNIZED_DESIGNS.join(", ")}) or a
|
|
102
|
+
directory holding a DESIGN.md. Defaults to the
|
|
103
|
+
starter's own.
|
|
57
104
|
--template <name> The site template to install (recognized:
|
|
58
105
|
${RECOGNIZED_TEMPLATES.join(", ")}).
|
|
106
|
+
A template already fixes its shape and design, so
|
|
107
|
+
it cannot be combined with --shape or --design.
|
|
59
108
|
A template is a page roster plus seed content and
|
|
60
109
|
config — never code. Its required modules are ADDED
|
|
61
110
|
to whatever \`--modules\` names, so the two compose.
|
|
@@ -74,8 +123,9 @@ Options:
|
|
|
74
123
|
Surfaces the declared architecture does not carry are
|
|
75
124
|
NOT scaffolded — their routes are absent, so a fresh
|
|
76
125
|
site never serves a stock page with placeholder
|
|
77
|
-
content. Add one later with
|
|
78
|
-
|
|
126
|
+
content. Add one later with
|
|
127
|
+
\`create-ailk add-route <surface>\`, or re-run with
|
|
128
|
+
the surface named here.
|
|
79
129
|
--sync-architecture <csv> Regenerate architecture.yaml in place in an
|
|
80
130
|
already-scaffolded repo from the given module set
|
|
81
131
|
(recognized: ${RECOGNIZED_MODULES.join(", ")}), then
|
|
@@ -94,6 +144,12 @@ Options:
|
|
|
94
144
|
file, at the target dir (positional arg, else cwd).
|
|
95
145
|
Bypasses the scaffold path — copies no template, runs
|
|
96
146
|
no install. Re-run after upgrading create-ailk.
|
|
147
|
+
--sync-claude-md Rewrite the AI Launch Kit sections of CLAUDE.md in
|
|
148
|
+
an already-scaffolded repo to the template this
|
|
149
|
+
create-ailk ships, then exit. Only CLAUDE.md
|
|
150
|
+
changes; your Site notes and anything between the
|
|
151
|
+
sections are kept byte for byte. Target dir is the
|
|
152
|
+
positional arg, else cwd.
|
|
97
153
|
--license <key> Your licence key: fetch paid modules with it and
|
|
98
154
|
write it into the scaffold (apps/api/.env and a
|
|
99
155
|
gitignored ailk.key, both owner-only).
|
|
@@ -103,8 +159,8 @@ Options:
|
|
|
103
159
|
--version Print the scaffolder version.
|
|
104
160
|
|
|
105
161
|
Examples:
|
|
106
|
-
pnpm create ailk@latest my-site
|
|
107
|
-
pnpm create ailk@latest /tmp/test-site --install
|
|
162
|
+
pnpm create ailk@latest my-site --shape organization-product
|
|
163
|
+
pnpm create ailk@latest /tmp/test-site --template marketing-site-free --install
|
|
108
164
|
|
|
109
165
|
Next steps after a successful scaffold:
|
|
110
166
|
cd <target-dir>
|
|
@@ -113,7 +169,12 @@ Next steps after a successful scaffold:
|
|
|
113
169
|
|
|
114
170
|
Reference: ADR 0007 — \`pnpm create ailk@latest\` is the canonical install path.
|
|
115
171
|
`;
|
|
116
|
-
|
|
172
|
+
/**
|
|
173
|
+
* Parse `create-ailk` argv. `env.interactive` defaults to false —
|
|
174
|
+
* fail-closed: a caller that does not assert a human is present gets refusal
|
|
175
|
+
* R1, never a prompt it cannot answer (#6754 D2).
|
|
176
|
+
*/
|
|
177
|
+
export function parseCliArgs(argv, env = { interactive: false }) {
|
|
117
178
|
let parsed;
|
|
118
179
|
try {
|
|
119
180
|
parsed = parseArgs({
|
|
@@ -123,10 +184,13 @@ export function parseCliArgs(argv) {
|
|
|
123
184
|
options: {
|
|
124
185
|
modules: { type: "string" },
|
|
125
186
|
template: { type: "string" },
|
|
187
|
+
shape: { type: "string" },
|
|
188
|
+
design: { type: "string" },
|
|
126
189
|
license: { type: "string" },
|
|
127
190
|
surfaces: { type: "string" },
|
|
128
191
|
"sync-architecture": { type: "string" },
|
|
129
192
|
"sync-catalog": { type: "boolean", default: false },
|
|
193
|
+
"sync-claude-md": { type: "boolean", default: false },
|
|
130
194
|
"with-catalog": { type: "boolean", default: false },
|
|
131
195
|
install: { type: "boolean", default: false },
|
|
132
196
|
help: { type: "boolean", default: false, short: "h" },
|
|
@@ -140,17 +204,28 @@ export function parseCliArgs(argv) {
|
|
|
140
204
|
const help = parsed.values.help === true;
|
|
141
205
|
const version = parsed.values.version === true;
|
|
142
206
|
const install = parsed.values.install === true;
|
|
143
|
-
|
|
207
|
+
// #6759 D3 — an absent flag stays `undefined` (the key's level decides);
|
|
208
|
+
// only a PRESENT value goes through `parseModules`.
|
|
209
|
+
const rawModules = parsed.values.modules;
|
|
210
|
+
const modules = rawModules === undefined ? undefined : parseModules(rawModules);
|
|
144
211
|
const template = parseTemplate(parsed.values.template);
|
|
212
|
+
const shape = parseShape(parsed.values.shape);
|
|
213
|
+
const design = parseDesign(parsed.values.design);
|
|
145
214
|
const surfaces = parseSurfaceList(parsed.values.surfaces);
|
|
146
215
|
const syncArchitecture = parsed.values["sync-architecture"];
|
|
147
216
|
const syncCatalog = parsed.values["sync-catalog"] === true;
|
|
217
|
+
const syncClaudeMd = parsed.values["sync-claude-md"] === true;
|
|
148
218
|
const withCatalog = parsed.values["with-catalog"] === true;
|
|
149
219
|
const license = parseLicense(parsed.values.license);
|
|
150
|
-
// The
|
|
151
|
-
//
|
|
152
|
-
|
|
153
|
-
|
|
220
|
+
// The sync modes each exit after rewriting their one file, so asking for
|
|
221
|
+
// more than one in one invocation has no coherent meaning.
|
|
222
|
+
const syncFlags = [
|
|
223
|
+
syncCatalog ? "--sync-catalog" : undefined,
|
|
224
|
+
syncArchitecture !== undefined ? "--sync-architecture" : undefined,
|
|
225
|
+
syncClaudeMd ? "--sync-claude-md" : undefined,
|
|
226
|
+
].filter((f) => f !== undefined);
|
|
227
|
+
if (syncFlags.length > 1) {
|
|
228
|
+
throw new ParseError(`${syncFlags.join(" and ")} cannot be combined; run them one at a time`);
|
|
154
229
|
}
|
|
155
230
|
// Validate the sync-architecture value now, through the SAME parseModules
|
|
156
231
|
// path `--modules` uses, so an unknown module throws ParseError at parse time
|
|
@@ -163,30 +238,34 @@ export function parseCliArgs(argv) {
|
|
|
163
238
|
return {
|
|
164
239
|
target: undefined,
|
|
165
240
|
template: undefined,
|
|
241
|
+
needsShapePrompt: false,
|
|
166
242
|
install,
|
|
167
243
|
help,
|
|
168
244
|
version,
|
|
169
245
|
modules,
|
|
170
246
|
surfaces,
|
|
171
247
|
syncCatalog: false,
|
|
248
|
+
syncClaudeMd: false,
|
|
172
249
|
withCatalog: false,
|
|
173
250
|
syncArchitecture: undefined,
|
|
174
251
|
};
|
|
175
252
|
}
|
|
176
253
|
// Sync modes: the target dir is optional (positional if given, else cwd).
|
|
177
|
-
if (syncArchitecture !== undefined || syncCatalog) {
|
|
254
|
+
if (syncArchitecture !== undefined || syncCatalog || syncClaudeMd) {
|
|
178
255
|
if (parsed.positionals.length > 1) {
|
|
179
256
|
throw new ParseError(`expected at most one target directory, got ${parsed.positionals.length}`);
|
|
180
257
|
}
|
|
181
258
|
return {
|
|
182
259
|
target: parsed.positionals[0],
|
|
183
260
|
template,
|
|
261
|
+
needsShapePrompt: false,
|
|
184
262
|
install,
|
|
185
263
|
help,
|
|
186
264
|
version,
|
|
187
265
|
modules,
|
|
188
266
|
surfaces,
|
|
189
267
|
syncCatalog,
|
|
268
|
+
syncClaudeMd,
|
|
190
269
|
withCatalog,
|
|
191
270
|
syncArchitecture,
|
|
192
271
|
};
|
|
@@ -197,20 +276,192 @@ export function parseCliArgs(argv) {
|
|
|
197
276
|
if (parsed.positionals.length > 1) {
|
|
198
277
|
throw new ParseError(`expected exactly one target directory, got ${parsed.positionals.length}`);
|
|
199
278
|
}
|
|
279
|
+
// R3 — a template already fixes its shape and design.
|
|
280
|
+
if (template !== undefined && (shape !== undefined || design !== undefined)) {
|
|
281
|
+
const flags = shape !== undefined && design !== undefined
|
|
282
|
+
? "--shape and --design"
|
|
283
|
+
: shape !== undefined
|
|
284
|
+
? "--shape"
|
|
285
|
+
: "--design";
|
|
286
|
+
throw new ParseError(`--template cannot be combined with ${flags}: a template already fixes its shape and design. Pass --template alone, or --shape with an optional --design.`);
|
|
287
|
+
}
|
|
288
|
+
// R1 — no silent default: with neither a template nor a shape, ask on a
|
|
289
|
+
// terminal and refuse without one.
|
|
290
|
+
const needsShapePrompt = template === undefined && shape === undefined;
|
|
291
|
+
if (needsShapePrompt && !env.interactive) {
|
|
292
|
+
throw new ParseError(`no shape given, and there is no terminal to ask on. Pass --shape <shape> (one of: ${SHAPE_LIST}), or --template <name>.`);
|
|
293
|
+
}
|
|
200
294
|
return {
|
|
201
295
|
target: parsed.positionals[0],
|
|
202
296
|
template,
|
|
297
|
+
...(shape !== undefined ? { shape } : {}),
|
|
298
|
+
...(design !== undefined ? { design } : {}),
|
|
299
|
+
needsShapePrompt,
|
|
203
300
|
install,
|
|
204
301
|
help,
|
|
205
302
|
version,
|
|
206
303
|
modules,
|
|
207
304
|
surfaces,
|
|
208
305
|
syncCatalog,
|
|
306
|
+
syncClaudeMd,
|
|
209
307
|
withCatalog,
|
|
210
308
|
syncArchitecture: undefined,
|
|
211
309
|
...(license !== undefined ? { license } : {}),
|
|
212
310
|
};
|
|
213
311
|
}
|
|
312
|
+
/**
|
|
313
|
+
* Validate `--shape` (#6754 D2 step 2): trimmed and lowercased. A reserved
|
|
314
|
+
* shape is refusal R2; any other unrecognized value names the recognized set.
|
|
315
|
+
*/
|
|
316
|
+
function parseShape(raw) {
|
|
317
|
+
if (raw === undefined)
|
|
318
|
+
return undefined;
|
|
319
|
+
const name = raw.trim().toLowerCase();
|
|
320
|
+
if (RESERVED_SHAPES.includes(name)) {
|
|
321
|
+
throw new ParseError(`shape "${name}" is not available yet. Choose one of: ${SHAPE_LIST}.`);
|
|
322
|
+
}
|
|
323
|
+
if (!RECOGNIZED_SHAPES.includes(name)) {
|
|
324
|
+
throw new ParseError(`unknown shape "${raw}". Recognized: ${SHAPE_LIST}`);
|
|
325
|
+
}
|
|
326
|
+
return name;
|
|
327
|
+
}
|
|
328
|
+
/** `path` is an existing directory. */
|
|
329
|
+
function isExistingDir(path) {
|
|
330
|
+
try {
|
|
331
|
+
return statSync(path).isDirectory();
|
|
332
|
+
}
|
|
333
|
+
catch {
|
|
334
|
+
return false;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* `dir` (resolved from `raw`) as a design path: an existing directory
|
|
339
|
+
* holding a `DESIGN.md`, else `ParseError` naming `raw` (#6813 D1 rule 2).
|
|
340
|
+
*/
|
|
341
|
+
function validateDesignDir(dir, raw) {
|
|
342
|
+
if (!isExistingDir(dir)) {
|
|
343
|
+
throw new ParseError(`design directory "${raw}" does not exist`);
|
|
344
|
+
}
|
|
345
|
+
if (!existsSync(join(dir, "DESIGN.md"))) {
|
|
346
|
+
throw new ParseError(`design directory "${raw}" holds no DESIGN.md`);
|
|
347
|
+
}
|
|
348
|
+
return dir;
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Validate `--design` (#6754 D2 step 2, widened #6813 D1): a recognized
|
|
352
|
+
* name, or a directory holding a `DESIGN.md`. A value with no `/` or `\` is
|
|
353
|
+
* classified as a name first (trimmed and lowercased, filesystem never
|
|
354
|
+
* consulted) — falling back to a path only when it names an existing
|
|
355
|
+
* directory in `process.cwd()`, so `--design mydesign` and `--design
|
|
356
|
+
* ./mydesign` can differ. A value with a separator is always a path,
|
|
357
|
+
* resolved against `process.cwd()`, case preserved. The package's CONTENT is
|
|
358
|
+
* validated later, in `scaffold()` (`resolveDesign`) — this parser checks
|
|
359
|
+
* presence only.
|
|
360
|
+
*/
|
|
361
|
+
function parseDesign(raw) {
|
|
362
|
+
if (raw === undefined)
|
|
363
|
+
return undefined;
|
|
364
|
+
const trimmed = raw.trim();
|
|
365
|
+
const hasSeparator = trimmed.includes("/") || trimmed.includes("\\");
|
|
366
|
+
if (!hasSeparator) {
|
|
367
|
+
const name = trimmed.toLowerCase();
|
|
368
|
+
if (RECOGNIZED_DESIGNS.includes(name)) {
|
|
369
|
+
return name;
|
|
370
|
+
}
|
|
371
|
+
const dir = resolve(process.cwd(), trimmed);
|
|
372
|
+
if (isExistingDir(dir)) {
|
|
373
|
+
return validateDesignDir(dir, raw);
|
|
374
|
+
}
|
|
375
|
+
throw new ParseError(`unknown design "${raw}". Recognized: ${RECOGNIZED_DESIGNS.join(", ")}`);
|
|
376
|
+
}
|
|
377
|
+
return validateDesignDir(resolve(process.cwd(), trimmed), raw);
|
|
378
|
+
}
|
|
379
|
+
/** How many answers the prompt takes before it gives up. */
|
|
380
|
+
const PROMPT_ATTEMPTS = 3;
|
|
381
|
+
/**
|
|
382
|
+
* Ask once for a shape (#6754 D3): a number 1–4 or a shape name. A bad answer
|
|
383
|
+
* re-asks, naming what was wrong; the third bad answer, or a closed input,
|
|
384
|
+
* throws. There is no default — an empty line is a bad answer.
|
|
385
|
+
*/
|
|
386
|
+
export async function promptForShape(io) {
|
|
387
|
+
const width = Math.max(...RECOGNIZED_SHAPES.map((s) => s.length));
|
|
388
|
+
io.output.write([
|
|
389
|
+
"Which kind of site is this?",
|
|
390
|
+
...RECOGNIZED_SHAPES.map((s, i) => ` ${i + 1}) ${s.padEnd(width)} ${SHAPE_DESCRIPTIONS[s]}`),
|
|
391
|
+
"",
|
|
392
|
+
].join("\n"));
|
|
393
|
+
const noShape = new ParseError(`no shape chosen. Re-run with --shape <shape> (one of: ${SHAPE_LIST}).`);
|
|
394
|
+
const rl = createInterface({ input: io.input, terminal: false });
|
|
395
|
+
// The async iterator buffers every line, so an answer typed (or piped)
|
|
396
|
+
// ahead of its question is never dropped, and a closed input ends it.
|
|
397
|
+
const lines = rl[Symbol.asyncIterator]();
|
|
398
|
+
try {
|
|
399
|
+
for (let attempt = 0; attempt < PROMPT_ATTEMPTS; attempt++) {
|
|
400
|
+
io.output.write(`Shape [1-${RECOGNIZED_SHAPES.length} or name]: `);
|
|
401
|
+
const next = await lines.next();
|
|
402
|
+
if (next.done === true)
|
|
403
|
+
throw noShape;
|
|
404
|
+
const answer = next.value;
|
|
405
|
+
const picked = pickShape(answer);
|
|
406
|
+
if (picked !== undefined)
|
|
407
|
+
return picked;
|
|
408
|
+
const shown = answer.trim();
|
|
409
|
+
io.output.write(shown === ""
|
|
410
|
+
? "No answer given.\n"
|
|
411
|
+
: `"${shown}" is not a shape. Answer 1-${RECOGNIZED_SHAPES.length} or a shape name.\n`);
|
|
412
|
+
}
|
|
413
|
+
throw noShape;
|
|
414
|
+
}
|
|
415
|
+
finally {
|
|
416
|
+
rl.close();
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
/** A prompt answer as a shape, or undefined when it names none. */
|
|
420
|
+
function pickShape(answer) {
|
|
421
|
+
const value = answer.trim().toLowerCase();
|
|
422
|
+
if (/^[0-9]+$/.test(value))
|
|
423
|
+
return RECOGNIZED_SHAPES[Number(value) - 1];
|
|
424
|
+
return RECOGNIZED_SHAPES.includes(value)
|
|
425
|
+
? value
|
|
426
|
+
: undefined;
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* Fill `opts.shape` by prompting when, and only when, `needsShapePrompt` is
|
|
430
|
+
* set (#6754 D3). Help, version, sync and every run naming a shape or a
|
|
431
|
+
* template come back unchanged, with nothing written to `io.output`.
|
|
432
|
+
*/
|
|
433
|
+
export async function resolveCliShape(opts, io) {
|
|
434
|
+
if (!opts.needsShapePrompt)
|
|
435
|
+
return opts;
|
|
436
|
+
const shape = await promptForShape(io);
|
|
437
|
+
return { ...opts, shape, needsShapePrompt: false };
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
* The one mapping from parsed flags to `scaffold()` options (#6754 D4).
|
|
441
|
+
* `template`, `shape`, `design` and `license` are each spread only when set,
|
|
442
|
+
* so a `--template` run hands `scaffold()` the object it did before #6754.
|
|
443
|
+
*
|
|
444
|
+
* @throws ParseError when the shape prompt is unresolved or the target is
|
|
445
|
+
* unset — an unresolved prompt must never fall through to the bare overlay.
|
|
446
|
+
*/
|
|
447
|
+
export function toScaffoldOptions(opts) {
|
|
448
|
+
if (opts.needsShapePrompt) {
|
|
449
|
+
throw new ParseError(`no shape given. Pass --shape <shape> (one of: ${SHAPE_LIST}), or --template <name>.`);
|
|
450
|
+
}
|
|
451
|
+
if (opts.target === undefined) {
|
|
452
|
+
throw new ParseError("missing target directory. Usage: pnpm create ailk@latest <target-dir>");
|
|
453
|
+
}
|
|
454
|
+
return {
|
|
455
|
+
targetDir: opts.target,
|
|
456
|
+
surfaces: opts.surfaces,
|
|
457
|
+
withCatalog: opts.withCatalog,
|
|
458
|
+
...(opts.modules !== undefined ? { modules: opts.modules } : {}),
|
|
459
|
+
...(opts.template !== undefined ? { template: opts.template } : {}),
|
|
460
|
+
...(opts.shape !== undefined ? { shape: opts.shape } : {}),
|
|
461
|
+
...(opts.design !== undefined ? { design: opts.design } : {}),
|
|
462
|
+
...(opts.license !== undefined ? { license: opts.license } : {}),
|
|
463
|
+
};
|
|
464
|
+
}
|
|
214
465
|
/**
|
|
215
466
|
* Shape-check the `--license` value through the one validator `license set`
|
|
216
467
|
* also uses, re-thrown as a ParseError. The message never repeats the value.
|
|
@@ -270,20 +521,20 @@ function parseSurfaceList(raw) {
|
|
|
270
521
|
* validated, normalized string[].
|
|
271
522
|
*
|
|
272
523
|
* Splits on `,`, trims and lowercases each entry, drops empties, and validates
|
|
273
|
-
* each against RECOGNIZED_MODULES.
|
|
274
|
-
*
|
|
524
|
+
* each against RECOGNIZED_MODULES. Takes a PRESENT value only — an ABSENT
|
|
525
|
+
* `--modules` flag is `undefined` (#6759 D3: the key's level decides) and
|
|
526
|
+
* never reaches this function; an all-empty value (`--modules ""`,
|
|
527
|
+
* `--modules ,`) still names the Free set, spelled inline here.
|
|
275
528
|
*
|
|
276
529
|
* @throws ParseError on an unrecognized module value, naming the recognized set.
|
|
277
530
|
*/
|
|
278
531
|
export function parseModules(raw) {
|
|
279
|
-
if (raw === undefined)
|
|
280
|
-
return [...DEFAULT_MODULES];
|
|
281
532
|
const requested = raw
|
|
282
533
|
.split(",")
|
|
283
534
|
.map((m) => m.trim().toLowerCase())
|
|
284
535
|
.filter(Boolean);
|
|
285
536
|
if (requested.length === 0)
|
|
286
|
-
return [
|
|
537
|
+
return ["marketing"];
|
|
287
538
|
for (const m of requested) {
|
|
288
539
|
if (!RECOGNIZED_MODULES.includes(m)) {
|
|
289
540
|
throw new ParseError(`unknown module "${m}". Recognized: ${RECOGNIZED_MODULES.join(", ")}`);
|
package/dist/programmatic.d.ts
CHANGED
|
@@ -16,11 +16,12 @@
|
|
|
16
16
|
* const result = scaffoldSync({ targetDir: '/tmp/my-site', projectName: 'my-site' });
|
|
17
17
|
*/
|
|
18
18
|
import { type AddModuleResult } from "./add-module.js";
|
|
19
|
+
import { type SyncClaudeMdResult } from "./claude-md.js";
|
|
19
20
|
import { CATALOG_TARGET_PATH } from "./component-catalog.js";
|
|
20
21
|
import { type ModuleName } from "./parse-args.js";
|
|
21
22
|
import { type TemplateLayout } from "./site-chrome.js";
|
|
22
23
|
import { type SyncRoutesResult } from "./sync-routes.js";
|
|
23
|
-
import { type
|
|
24
|
+
import { type StarterShape } from "./template-manifest.js";
|
|
24
25
|
export interface ScaffoldOptions {
|
|
25
26
|
/** Absolute or relative path to the target directory. Must not exist or be empty. */
|
|
26
27
|
targetDir: string;
|
|
@@ -36,9 +37,10 @@ export interface ScaffoldOptions {
|
|
|
36
37
|
*
|
|
37
38
|
* Consumed ONLY by the async `scaffold()` below. `scaffoldSync` stays
|
|
38
39
|
* template-oblivious for exactly the reason it stays licensing-oblivious
|
|
39
|
-
* (spec 5481 § 3 DD3): a call naming
|
|
40
|
-
* new statement in it
|
|
41
|
-
*
|
|
40
|
+
* (spec 5481 § 3 DD3): a call naming neither a template nor a `shape`
|
|
41
|
+
* takes a code path with no new statement in it — the bare overlay, the
|
|
42
|
+
* library's default. The CLI never takes that path (#6754 D2: it refuses a
|
|
43
|
+
* run naming neither, or asks for a shape on a terminal).
|
|
42
44
|
*
|
|
43
45
|
* What a template DOES change is `modules` — `scaffold()` unions the
|
|
44
46
|
* template's `requires` with whatever `--modules` named and passes THAT
|
|
@@ -46,6 +48,13 @@ export interface ScaffoldOptions {
|
|
|
46
48
|
* `architecture.yaml` and the generated nav are all functions of the union.
|
|
47
49
|
*/
|
|
48
50
|
template?: string;
|
|
51
|
+
/**
|
|
52
|
+
* The starter shape to install (`--shape`, #6754 D5): `scaffold()` resolves
|
|
53
|
+
* it to the one template of that shape whose delivery is `free`, then runs
|
|
54
|
+
* exactly as a `template` naming it would. Mutually exclusive with
|
|
55
|
+
* `template`. A shape with no Free starter yet is refused (D6).
|
|
56
|
+
*/
|
|
57
|
+
shape?: StarterShape;
|
|
49
58
|
/**
|
|
50
59
|
* Selected modules (recognized: marketing, docs-blog, multi-tenant,
|
|
51
60
|
* scheduling). Defaults to
|
|
@@ -110,14 +119,23 @@ export interface ScaffoldOptions {
|
|
|
110
119
|
*/
|
|
111
120
|
layout?: TemplateLayout;
|
|
112
121
|
/**
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
* `design`; a caller may name one to OVERRIDE the template's — the
|
|
122
|
+
* A design name or a directory holding a DESIGN.md (#6638; widened to a
|
|
123
|
+
* path #6813 D1/D3). `scaffold()` sets it from the resolved template's
|
|
124
|
+
* `design`; a caller may name one to OVERRIDE the template's — the
|
|
116
125
|
* shape × design pairing `verify-scaffold.mjs --design` renders (#6638
|
|
117
|
-
* DD-4)
|
|
118
|
-
* resolves exactly as before.
|
|
126
|
+
* DD-4), and the CLI's `--design` beside `--shape` (#6754). Unset (every
|
|
127
|
+
* existing `scaffoldSync` caller) resolves exactly as before. Gated
|
|
128
|
+
* (#6760): a non-Free design needs a Pro or Pro Plus level.
|
|
129
|
+
*/
|
|
130
|
+
design?: string;
|
|
131
|
+
/**
|
|
132
|
+
* INTERNAL — the resolved design's own layout knobs (#6813 D2/D4/D8),
|
|
133
|
+
* populated by `scaffold()` from `resolveDesign(...).pkg.layout` before
|
|
134
|
+
* calling `scaffoldSync`. Never set by a CLI/MCP caller. Replaces the
|
|
135
|
+
* design-NAME lookup `scaffoldSync` used to do internally through the
|
|
136
|
+
* code registry that has since been deleted (#6638's per-name table).
|
|
119
137
|
*/
|
|
120
|
-
|
|
138
|
+
designLayout?: TemplateLayout;
|
|
121
139
|
}
|
|
122
140
|
export interface ScaffoldResult {
|
|
123
141
|
/** Resolved absolute path to the scaffolded directory. */
|
|
@@ -126,6 +144,23 @@ export interface ScaffoldResult {
|
|
|
126
144
|
filesCreated: number;
|
|
127
145
|
/** The gateable route surfaces this scaffold declares (sorted). */
|
|
128
146
|
surfaces: string[];
|
|
147
|
+
/**
|
|
148
|
+
* The starter this scaffold resolved (#6754 D5) — set whenever a template
|
|
149
|
+
* was resolved, from `template` or from `shape`; absent for the bare overlay.
|
|
150
|
+
* `design` is the applied design's recorded name (#6813 D6): the shipped
|
|
151
|
+
* registry name, or the package's own `name` for an unrecognized one.
|
|
152
|
+
*/
|
|
153
|
+
starter?: {
|
|
154
|
+
template: string;
|
|
155
|
+
shape: StarterShape;
|
|
156
|
+
design: string;
|
|
157
|
+
};
|
|
158
|
+
/**
|
|
159
|
+
* The effective module set this scaffold installed (#6759 D6) — what
|
|
160
|
+
* `scaffoldSync` actually received, never the requested `--modules` alone:
|
|
161
|
+
* a keyed run with no `--modules` carries the key's derived level here.
|
|
162
|
+
*/
|
|
163
|
+
modules: ModuleName[];
|
|
129
164
|
}
|
|
130
165
|
/**
|
|
131
166
|
* Scaffold an AI Launch Kit starter project into targetDir (synchronous).
|
|
@@ -152,8 +187,14 @@ export declare function scaffoldSync(opts: ScaffoldOptions): ScaffoldResult;
|
|
|
152
187
|
* its fetched bundle or — when it requires only free modules — from the
|
|
153
188
|
* `site-templates/` tree this package ships.
|
|
154
189
|
*
|
|
155
|
-
*
|
|
156
|
-
*
|
|
190
|
+
* Between 2 and 3, `assertDesignAllowed` (#6760) refuses a design the caller
|
|
191
|
+
* CHOSE (`opts.design`) for a level below Pro, HERE, also before anything is
|
|
192
|
+
* written to disk. A template's own declared design is never gated (#6778
|
|
193
|
+
* option (c)): the template's `requires` already decide its level.
|
|
194
|
+
*
|
|
195
|
+
* And, ahead of all five when `opts.template` (or `opts.shape`, #6754 D5) is
|
|
196
|
+
* set (0): resolve the template and union its `requires` with `opts.modules`,
|
|
197
|
+
* so every step above
|
|
157
198
|
* runs over the EFFECTIVE module set rather than the requested one.
|
|
158
199
|
*
|
|
159
200
|
* `scaffoldSync` itself stays licensing-oblivious on purpose: every existing
|
|
@@ -228,6 +269,19 @@ export interface SyncCatalogResult {
|
|
|
228
269
|
export declare function syncCatalogSync(opts: {
|
|
229
270
|
targetDir: string;
|
|
230
271
|
}): SyncCatalogResult;
|
|
272
|
+
/**
|
|
273
|
+
* Rewrite the template-owned sections of an already-scaffolded repo's root
|
|
274
|
+
* `CLAUDE.md` to the template this create-ailk ships (#6904 D3). The logic
|
|
275
|
+
* lives in `claude-md.ts` (a module jest imports directly); this wrapper
|
|
276
|
+
* only supplies the package's `templates/CLAUDE.md` — the `syncRoutesSync`
|
|
277
|
+
* split. `templateText` stands in for the shipped template in tests.
|
|
278
|
+
*/
|
|
279
|
+
export declare function syncClaudeMdSync(opts: {
|
|
280
|
+
targetDir: string;
|
|
281
|
+
templateText?: string;
|
|
282
|
+
}): SyncClaudeMdResult;
|
|
283
|
+
/** Re-exported beside the other sync results so consumers see one surface. */
|
|
284
|
+
export type { SyncClaudeMdResult } from "./claude-md.js";
|
|
231
285
|
export interface SyncRoutesSyncOptions {
|
|
232
286
|
/** The already-scaffolded repo to sync (absolute or relative). */
|
|
233
287
|
targetDir: string;
|