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
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `create-ailk apply-design <name|path> [--target <site-dir>]` — make an
|
|
3
|
+
* existing site wear a design, changing only how it LOOKS (#6819, spec
|
|
4
|
+
* docs/specs/6819-apply-design-name-path-one-spec.md).
|
|
5
|
+
*
|
|
6
|
+
* Composes four already-shipped units and edits none of them: #6813's
|
|
7
|
+
* resolver and theme splicer, #6816's preset validator and applier, #6760's
|
|
8
|
+
* design gate and #6813's manifest writer. Every refusal happens before the
|
|
9
|
+
* first write (D3); every new text is planned in memory, then written in one
|
|
10
|
+
* pass (D4). Routes, content fields, `brand:` and structured data never move.
|
|
11
|
+
*
|
|
12
|
+
* Reads no module URL of its own — every package directory it reads is passed in
|
|
13
|
+
* — so Jest's CJS transform can import it, unlike `programmatic.ts`.
|
|
14
|
+
*/
|
|
15
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync, } from "node:fs";
|
|
16
|
+
import { dirname, join, relative, resolve, sep } from "node:path";
|
|
17
|
+
import { parseArgs } from "node:util";
|
|
18
|
+
import { planDesignMd } from "./apply-design-md.js";
|
|
19
|
+
import { compileDesignTheme } from "./design-compile.js";
|
|
20
|
+
import { applyDesignPresets, readSectionLookCatalog, shippedPageTypes, validateDesignPresets, } from "./design-presets.js";
|
|
21
|
+
import { resolveDesign, spliceThemeBlock } from "./design-scaffold.js";
|
|
22
|
+
import { LICENSE_KEY_FILE } from "./lib/license-key-files.js";
|
|
23
|
+
import { CONVERSION_HINT_URL, LicenseRequiredError, assertDesignAllowed, deriveLevel, } from "./lib/module-license-gate.js";
|
|
24
|
+
import { LEVEL_LABEL } from "./lib/module-tier.js";
|
|
25
|
+
import { ParseError } from "./parse-args.js";
|
|
26
|
+
import { SITE_CHROME_PATH, renderSiteChrome, resolveSiteChrome, } from "./site-chrome.js";
|
|
27
|
+
import { SITE_ROSTER_PATH, planSiteManifestDesign, readSiteRoster, } from "./site-roster.js";
|
|
28
|
+
export const APPLY_DESIGN_HELP = `create-ailk apply-design — make an existing site wear a design.
|
|
29
|
+
|
|
30
|
+
Usage:
|
|
31
|
+
create-ailk apply-design <name> [--target <site-dir>]
|
|
32
|
+
create-ailk apply-design <path> [--target <site-dir>]
|
|
33
|
+
|
|
34
|
+
Arguments:
|
|
35
|
+
<name|path> A shipped design (standard, minimalism), or a
|
|
36
|
+
directory holding a DESIGN.md. A relative path
|
|
37
|
+
resolves from the current directory.
|
|
38
|
+
|
|
39
|
+
Options:
|
|
40
|
+
--target <site-dir> An already-scaffolded repo (contains
|
|
41
|
+
architecture.yaml). Defaults to the current dir.
|
|
42
|
+
--help, -h Print this message.
|
|
43
|
+
|
|
44
|
+
Writes only the look: DESIGN.md (replaced whole by the design's, keeping the
|
|
45
|
+
site's Source template and Version lines), the theme: block of
|
|
46
|
+
content/_site.mdx, the generated apps/web/lib/site-chrome.ts, the look fields
|
|
47
|
+
of sections the site's pages already place, and the design/layout/theme record
|
|
48
|
+
in .ailk-site-manifest.json.
|
|
49
|
+
Never adds, removes or renames a route or page, never touches a content field
|
|
50
|
+
or the brand: block, and leaves every page's structured data unchanged.
|
|
51
|
+
|
|
52
|
+
A design other than standard needs a Pro or Pro Plus key: the site's own
|
|
53
|
+
ailk.key (put one there with create-ailk license set <key>), else
|
|
54
|
+
AILK_LICENSE_KEY. A malformed package, a preset the validator refuses or a
|
|
55
|
+
missing key is refused before any file is written.
|
|
56
|
+
|
|
57
|
+
A preset sets the look fields it names and never unsets one: a field it does
|
|
58
|
+
not name keeps whatever value the page has. Running it again changes nothing.
|
|
59
|
+
`;
|
|
60
|
+
/**
|
|
61
|
+
* Parse the argv AFTER the `apply-design` word (D1). Strict `node:util`
|
|
62
|
+
* parseArgs, like `parseSyncRoutesArgs`: exactly one positional, the design
|
|
63
|
+
* reference, and an optional `--target`.
|
|
64
|
+
*/
|
|
65
|
+
export function parseApplyDesignArgs(argv) {
|
|
66
|
+
const parsed = parseArgs({
|
|
67
|
+
args: argv,
|
|
68
|
+
strict: true,
|
|
69
|
+
allowPositionals: true,
|
|
70
|
+
options: {
|
|
71
|
+
target: { type: "string" },
|
|
72
|
+
help: { type: "boolean", default: false, short: "h" },
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
const help = parsed.values.help === true;
|
|
76
|
+
if (parsed.positionals.length > 1) {
|
|
77
|
+
throw new ParseError(`expected one design (a name or a directory), got ${parsed.positionals.length} arguments`);
|
|
78
|
+
}
|
|
79
|
+
const design = parsed.positionals[0];
|
|
80
|
+
if (design === undefined && !help) {
|
|
81
|
+
throw new ParseError("apply-design needs a design. Usage: create-ailk apply-design <name|path> [--target <site-dir>]");
|
|
82
|
+
}
|
|
83
|
+
return { design, target: parsed.values.target, help };
|
|
84
|
+
}
|
|
85
|
+
/** `abs` relative to `root`, with `/` separators. */
|
|
86
|
+
function siteRelative(root, abs) {
|
|
87
|
+
return relative(root, abs).split(sep).join("/");
|
|
88
|
+
}
|
|
89
|
+
/** Every `.mdx` under `dir`, sorted by path (D4 step 3). */
|
|
90
|
+
function listMdxFiles(dir) {
|
|
91
|
+
if (!existsSync(dir))
|
|
92
|
+
return [];
|
|
93
|
+
const out = [];
|
|
94
|
+
const stack = [dir];
|
|
95
|
+
while (stack.length > 0) {
|
|
96
|
+
const current = stack.pop();
|
|
97
|
+
for (const entry of readdirSync(current, { withFileTypes: true })) {
|
|
98
|
+
const abs = join(current, entry.name);
|
|
99
|
+
if (entry.isDirectory())
|
|
100
|
+
stack.push(abs);
|
|
101
|
+
else if (entry.name.endsWith(".mdx"))
|
|
102
|
+
out.push(abs);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return out.sort();
|
|
106
|
+
}
|
|
107
|
+
/** The site's own key (D6): `<target>/ailk.key`, else `AILK_LICENSE_KEY`, else none. */
|
|
108
|
+
function readSiteKey(targetAbs, env) {
|
|
109
|
+
const keyPath = join(targetAbs, LICENSE_KEY_FILE);
|
|
110
|
+
if (existsSync(keyPath)) {
|
|
111
|
+
const key = readFileSync(keyPath, "utf8").trim();
|
|
112
|
+
if (key.length > 0)
|
|
113
|
+
return key;
|
|
114
|
+
}
|
|
115
|
+
const fromEnv = env["AILK_LICENSE_KEY"];
|
|
116
|
+
return fromEnv !== undefined && fromEnv.length > 0 ? fromEnv : undefined;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Apply a design to an existing site (D2–D7). Refuses before any write
|
|
120
|
+
* (C1–C6); otherwise writes only the files whose text changes — page files,
|
|
121
|
+
* `site-chrome.ts`, `DESIGN.md`, `_site.mdx`, then the manifest last.
|
|
122
|
+
*/
|
|
123
|
+
export async function applyDesign(opts) {
|
|
124
|
+
const targetAbs = resolve(opts.targetDir);
|
|
125
|
+
const env = opts.env ?? process.env;
|
|
126
|
+
// C1 — a scaffolded repo (the `addModule` wording).
|
|
127
|
+
if (!existsSync(targetAbs)) {
|
|
128
|
+
throw new Error(`apply-design target does not exist: ${targetAbs}. Point apply-design at an already-scaffolded repo.`);
|
|
129
|
+
}
|
|
130
|
+
if (!statSync(targetAbs).isDirectory()) {
|
|
131
|
+
throw new Error(`apply-design target is not a directory: ${targetAbs}`);
|
|
132
|
+
}
|
|
133
|
+
if (!existsSync(join(targetAbs, "architecture.yaml"))) {
|
|
134
|
+
throw new Error(`not a scaffolded repo: no architecture.yaml at ${targetAbs}. Run \`create-ailk <target-dir>\` to scaffold first.`);
|
|
135
|
+
}
|
|
136
|
+
// C2 — the site config the theme lives in.
|
|
137
|
+
const siteMdxPath = join(targetAbs, "content", "_site.mdx");
|
|
138
|
+
if (!existsSync(siteMdxPath)) {
|
|
139
|
+
throw new Error(`no content/_site.mdx at ${targetAbs}: there is no theme to replace`);
|
|
140
|
+
}
|
|
141
|
+
// C3 — resolve (a malformed package throws DesignPackageError, naming the field).
|
|
142
|
+
const resolved = resolveDesign(opts.design, {
|
|
143
|
+
designsDir: opts.designsDir,
|
|
144
|
+
cwd: opts.cwd ?? process.cwd(),
|
|
145
|
+
});
|
|
146
|
+
const { pkg } = resolved;
|
|
147
|
+
const hasPresets = Object.keys(pkg.sections).length > 0;
|
|
148
|
+
// C4 — the presets, validated exactly as scaffold() validates them.
|
|
149
|
+
if (hasPresets) {
|
|
150
|
+
validateDesignPresets(pkg.sections, {
|
|
151
|
+
catalog: readSectionLookCatalog(opts.catalogPath),
|
|
152
|
+
pageTypes: shippedPageTypes(opts.siteTemplatesDir),
|
|
153
|
+
file: join(resolved.dir, "DESIGN.md"),
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
// C5 — the design gate, fed the site's own key (D6). A Free design reads no key.
|
|
157
|
+
if (!resolved.free) {
|
|
158
|
+
const key = readSiteKey(targetAbs, env);
|
|
159
|
+
const { level } = await deriveLevel({
|
|
160
|
+
licenseKey: key ?? "",
|
|
161
|
+
...(opts.registryUrl !== undefined ? { registryUrl: opts.registryUrl } : {}),
|
|
162
|
+
...(opts.fetchImpl !== undefined ? { fetchImpl: opts.fetchImpl } : {}),
|
|
163
|
+
});
|
|
164
|
+
try {
|
|
165
|
+
assertDesignAllowed(resolved.display, level, false);
|
|
166
|
+
}
|
|
167
|
+
catch (err) {
|
|
168
|
+
if (!(err instanceof LicenseRequiredError))
|
|
169
|
+
throw err;
|
|
170
|
+
throw new LicenseRequiredError(`design "${resolved.display}" is a Pro feature — this site's licence level is ${LEVEL_LABEL[level]}; put a Pro or Pro Plus key in the site with create-ailk license set <key>, or set AILK_LICENSE_KEY → ${CONVERSION_HINT_URL}`);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
// C6 / D4 — plan every write in memory.
|
|
174
|
+
const theme = compileDesignTheme(pkg);
|
|
175
|
+
const siteMdxCurrent = readFileSync(siteMdxPath, "utf8");
|
|
176
|
+
const siteMdxNext = spliceThemeBlock(siteMdxCurrent, theme, siteMdxPath);
|
|
177
|
+
const roster = readSiteRoster(targetAbs);
|
|
178
|
+
const chrome = resolveSiteChrome(roster?.template.layout, pkg.layout);
|
|
179
|
+
const chromePath = join(targetAbs, SITE_CHROME_PATH);
|
|
180
|
+
const chromeCurrent = existsSync(chromePath) ? readFileSync(chromePath, "utf8") : undefined;
|
|
181
|
+
const chromeNext = renderSiteChrome(chrome);
|
|
182
|
+
const designMdPath = join(targetAbs, "DESIGN.md");
|
|
183
|
+
const designMdCurrent = existsSync(designMdPath) ? readFileSync(designMdPath, "utf8") : undefined;
|
|
184
|
+
const designMdNext = planDesignMd(resolved.dir, targetAbs);
|
|
185
|
+
const pageWrites = [];
|
|
186
|
+
if (hasPresets && roster !== undefined) {
|
|
187
|
+
const pageTypes = new Set();
|
|
188
|
+
for (const row of roster.rows) {
|
|
189
|
+
const pageType = row.value["pageType"];
|
|
190
|
+
if (typeof pageType === "string")
|
|
191
|
+
pageTypes.add(pageType);
|
|
192
|
+
}
|
|
193
|
+
const contentDir = join(targetAbs, "content");
|
|
194
|
+
const pages = listMdxFiles(contentDir)
|
|
195
|
+
.filter((path) => path !== siteMdxPath)
|
|
196
|
+
.map((path) => ({ path, text: readFileSync(path, "utf8") }));
|
|
197
|
+
const presetResult = applyDesignPresets(pages, pkg.sections, { pageTypes });
|
|
198
|
+
for (const page of presetResult.pages) {
|
|
199
|
+
const fields = [
|
|
200
|
+
...new Set(presetResult.applied
|
|
201
|
+
.filter((a) => a.path === page.path)
|
|
202
|
+
.map((a) => `${a.sectionType}.${a.field}`)),
|
|
203
|
+
].sort();
|
|
204
|
+
pageWrites.push({ path: page.path, text: page.text, fields });
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
let manifest = "no-roster";
|
|
208
|
+
let manifestNext;
|
|
209
|
+
const rosterAbs = roster !== undefined ? join(targetAbs, roster.path) : undefined;
|
|
210
|
+
if (roster !== undefined && rosterAbs !== undefined) {
|
|
211
|
+
if (roster.path === SITE_ROSTER_PATH) {
|
|
212
|
+
manifestNext = planSiteManifestDesign(readFileSync(rosterAbs, "utf8"), { design: resolved.recorded, layout: chrome, theme }, rosterAbs);
|
|
213
|
+
manifest = manifestNext === undefined ? "unchanged" : "recorded";
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
manifest = "legacy-roster";
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
// Write — page files, site-chrome.ts, DESIGN.md, _site.mdx, the manifest last (D4).
|
|
220
|
+
const changes = [];
|
|
221
|
+
for (const page of pageWrites) {
|
|
222
|
+
writeFileSync(page.path, page.text);
|
|
223
|
+
changes.push({ path: siteRelative(targetAbs, page.path), kind: "preset", fields: page.fields });
|
|
224
|
+
}
|
|
225
|
+
if (chromeNext !== chromeCurrent) {
|
|
226
|
+
mkdirSync(dirname(chromePath), { recursive: true });
|
|
227
|
+
writeFileSync(chromePath, chromeNext);
|
|
228
|
+
changes.push({ path: SITE_CHROME_PATH, kind: "layout" });
|
|
229
|
+
}
|
|
230
|
+
if (designMdNext !== designMdCurrent) {
|
|
231
|
+
writeFileSync(designMdPath, designMdNext);
|
|
232
|
+
changes.push({ path: "DESIGN.md", kind: "design" });
|
|
233
|
+
}
|
|
234
|
+
if (siteMdxNext !== siteMdxCurrent) {
|
|
235
|
+
writeFileSync(siteMdxPath, siteMdxNext);
|
|
236
|
+
changes.push({ path: "content/_site.mdx", kind: "theme" });
|
|
237
|
+
}
|
|
238
|
+
if (manifestNext !== undefined && rosterAbs !== undefined) {
|
|
239
|
+
writeFileSync(rosterAbs, manifestNext);
|
|
240
|
+
changes.push({ path: SITE_ROSTER_PATH, kind: "manifest" });
|
|
241
|
+
}
|
|
242
|
+
return {
|
|
243
|
+
targetDir: targetAbs,
|
|
244
|
+
design: resolved.recorded,
|
|
245
|
+
display: resolved.display,
|
|
246
|
+
changes,
|
|
247
|
+
manifest,
|
|
248
|
+
...(roster !== undefined ? { rosterPath: roster.path } : {}),
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
/** The changed-file report (D9). */
|
|
252
|
+
export function formatApplyDesignReport(result) {
|
|
253
|
+
const lines = [];
|
|
254
|
+
if (result.changes.length === 0) {
|
|
255
|
+
lines.push(`[create-ailk] The site already wears design "${result.design}" — no file changed.`);
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
lines.push(`[create-ailk] Applied design "${result.design}" to ${result.targetDir}`);
|
|
259
|
+
for (const change of result.changes) {
|
|
260
|
+
const suffix = change.kind === "preset" ? ` (${change.fields.join(", ")})` : "";
|
|
261
|
+
lines.push(` ${change.kind.padEnd(8)} ${change.path}${suffix}`);
|
|
262
|
+
}
|
|
263
|
+
const n = result.changes.length;
|
|
264
|
+
lines.push(`${n} file${n === 1 ? "" : "s"} changed. Routes, page content and structured data are unchanged.`);
|
|
265
|
+
}
|
|
266
|
+
if (result.manifest === "legacy-roster") {
|
|
267
|
+
lines.push(`manifest not recorded: ${result.rosterPath} predates the design record`);
|
|
268
|
+
}
|
|
269
|
+
else if (result.manifest === "no-roster") {
|
|
270
|
+
lines.push(`manifest not recorded: the site has no ${SITE_ROSTER_PATH}`);
|
|
271
|
+
}
|
|
272
|
+
return `${lines.join("\n")}\n`;
|
|
273
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/** The drift check a scaffold ships (`template-overlay/tools/`). */
|
|
2
|
+
export declare const CLAUDE_MD_CHECK_PATH = "tools/check-claude-md.ts";
|
|
3
|
+
/**
|
|
4
|
+
* SHA-256 of every `templates/CLAUDE.md` a published create-ailk shipped
|
|
5
|
+
* before markers existed, with `{{PROJECT_NAME}}` unsubstituted (spec § 1.7,
|
|
6
|
+
* D4). An unmarked scaffold `CLAUDE.md` that hashes to one of these after
|
|
7
|
+
* undoing the name substitution was never edited by its owner.
|
|
8
|
+
*/
|
|
9
|
+
export declare const LEGACY_TEMPLATE_SHA256: readonly string[];
|
|
10
|
+
export interface ClaudeMdRegion {
|
|
11
|
+
id: string;
|
|
12
|
+
/** The recorded hash, or undefined when the begin marker carries none. */
|
|
13
|
+
sha256: string | undefined;
|
|
14
|
+
/** Index of the begin line's first character. */
|
|
15
|
+
start: number;
|
|
16
|
+
/** Index just past the end line's newline (or end of text). */
|
|
17
|
+
end: number;
|
|
18
|
+
/** Every character between the begin line's newline and the end line. */
|
|
19
|
+
body: string;
|
|
20
|
+
}
|
|
21
|
+
export interface ParsedClaudeMd {
|
|
22
|
+
regions: ClaudeMdRegion[];
|
|
23
|
+
/** Index of the first `<!-- ailk:site -->` line, when there is one. */
|
|
24
|
+
siteStart: number | undefined;
|
|
25
|
+
/** Structural faults, in file order. Empty for a well-formed file. */
|
|
26
|
+
faults: string[];
|
|
27
|
+
/** True when the file carries any region or site marker at all. */
|
|
28
|
+
marked: boolean;
|
|
29
|
+
}
|
|
30
|
+
/** SHA-256, lowercase hex, of a region body with every CRLF folded to LF (D2). */
|
|
31
|
+
export declare function hashBody(body: string): string;
|
|
32
|
+
/** Parse a `CLAUDE.md` against the D1 grammar. Never throws. */
|
|
33
|
+
export declare function parseClaudeMd(text: string): ParsedClaudeMd;
|
|
34
|
+
/**
|
|
35
|
+
* Render the committed template for a project (D2): substitute the scaffold
|
|
36
|
+
* markers, then stamp each begin marker with its body's hash. LF output.
|
|
37
|
+
*
|
|
38
|
+
* @throws Error when the template is malformed or a begin marker already
|
|
39
|
+
* carries a hash — a hash is never committed by hand.
|
|
40
|
+
*/
|
|
41
|
+
export declare function renderClaudeMd(templateText: string, projectName: string): string;
|
|
42
|
+
export interface ClaudeMdDrift {
|
|
43
|
+
/** No file, a file with no markers at all, or a marked one. */
|
|
44
|
+
state: "missing" | "unmarked" | "marked";
|
|
45
|
+
/** Ids of regions whose body no longer matches the recorded hash. */
|
|
46
|
+
edited: string[];
|
|
47
|
+
/** Structural faults, including a begin marker with no sha256. */
|
|
48
|
+
faults: string[];
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The drift verdict for a rendered file (D6). `undefined` = no file. The
|
|
52
|
+
* reference implementation `tools/check-claude-md.ts` is held to.
|
|
53
|
+
*/
|
|
54
|
+
export declare function findDrift(text: string | undefined): ClaudeMdDrift;
|
|
55
|
+
/** The drift check's output lines; empty means the file passes. */
|
|
56
|
+
export declare function formatDrift(drift: ClaudeMdDrift): string[];
|
|
57
|
+
export interface ClaudeMdMerge {
|
|
58
|
+
text: string;
|
|
59
|
+
/** Regions whose bytes the sync changed. */
|
|
60
|
+
updated: string[];
|
|
61
|
+
/** Regions the current template has and the file lacked. */
|
|
62
|
+
added: string[];
|
|
63
|
+
/** Regions the file had and the current template retired. */
|
|
64
|
+
removed: string[];
|
|
65
|
+
/** Regions whose hand-edited body the sync replaced. */
|
|
66
|
+
overwritten: string[];
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Rewrite a marked file's template-owned regions to a rendered template (D3).
|
|
70
|
+
* Every character outside a region — the gaps and the whole site section —
|
|
71
|
+
* is copied through unchanged, except the one blank line a retired region
|
|
72
|
+
* takes with it. Regions and inserted separators are written in the file's
|
|
73
|
+
* own line ending, so a CRLF checkout stays CRLF and syncs idempotently.
|
|
74
|
+
*
|
|
75
|
+
* @throws Error naming the fault when the file is structurally malformed.
|
|
76
|
+
*/
|
|
77
|
+
export declare function mergeClaudeMd(fileText: string, renderedText: string): ClaudeMdMerge;
|
|
78
|
+
/**
|
|
79
|
+
* True when an unmarked `CLAUDE.md` is a published template the owner never
|
|
80
|
+
* changed (D4): with some candidate project name un-substituted, it hashes to
|
|
81
|
+
* a `LEGACY_TEMPLATE_SHA256` entry. A miss is always safe — it refuses.
|
|
82
|
+
*/
|
|
83
|
+
export declare function isUneditedLegacy(text: string, names: string[]): boolean;
|
|
84
|
+
export interface SyncClaudeMdResult {
|
|
85
|
+
/** Resolved absolute path to the synced directory. */
|
|
86
|
+
targetDir: string;
|
|
87
|
+
/** Absolute path of the `CLAUDE.md` read and (maybe) written. */
|
|
88
|
+
claudeMdPath: string;
|
|
89
|
+
/**
|
|
90
|
+
* `created` — there was no file; `replaced-legacy` — an unedited pre-marker
|
|
91
|
+
* template was replaced; `updated` / `unchanged` — a marked file was synced.
|
|
92
|
+
*/
|
|
93
|
+
action: "created" | "replaced-legacy" | "updated" | "unchanged";
|
|
94
|
+
updated: string[];
|
|
95
|
+
added: string[];
|
|
96
|
+
removed: string[];
|
|
97
|
+
overwritten: string[];
|
|
98
|
+
/** True when the site lacks `tools/check-claude-md.ts` or its script. */
|
|
99
|
+
missingDriftCheck: boolean;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* `--sync-claude-md` (D3): the `syncCatalogSync` shape — validate the target
|
|
103
|
+
* is an existing scaffold, write at most its `CLAUDE.md`, spawn nothing. An
|
|
104
|
+
* unmarked file is replaced only when it is an unedited published template
|
|
105
|
+
* (D4); anything else unmarked, or a structural fault, is refused with
|
|
106
|
+
* nothing written.
|
|
107
|
+
*/
|
|
108
|
+
export declare function syncClaudeMd(opts: {
|
|
109
|
+
targetDir: string;
|
|
110
|
+
templateText: string;
|
|
111
|
+
}): SyncClaudeMdResult;
|