create-ailk 0.6.1 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (324) hide show
  1. package/README.md +87 -14
  2. package/component-catalog.json +735 -95
  3. package/component-catalog.md +13 -7
  4. package/dist/add-module-core.d.ts +22 -0
  5. package/dist/add-module-core.js +50 -0
  6. package/dist/add-module.d.ts +89 -0
  7. package/dist/add-module.js +334 -0
  8. package/dist/category-profile.d.ts +126 -0
  9. package/dist/category-profile.js +262 -0
  10. package/dist/cli.js +89 -29
  11. package/dist/index.d.ts +4 -2
  12. package/dist/index.js +6 -1
  13. package/dist/lib/extract-module-bundle.d.ts +56 -1
  14. package/dist/lib/extract-module-bundle.js +170 -14
  15. package/dist/lib/license-key-files.d.ts +15 -0
  16. package/dist/lib/license-key-files.js +102 -0
  17. package/dist/lib/module-license-gate.d.ts +79 -0
  18. package/dist/lib/module-license-gate.js +160 -12
  19. package/dist/lib/module-tier.d.ts +45 -16
  20. package/dist/lib/module-tier.js +76 -0
  21. package/dist/lib/pro-callout.d.ts +16 -10
  22. package/dist/lib/pro-callout.js +34 -3
  23. package/dist/license-set.d.ts +34 -0
  24. package/dist/license-set.js +194 -0
  25. package/dist/module-architecture.d.ts +20 -0
  26. package/dist/module-architecture.js +77 -19
  27. package/dist/modules/commerce/0.6.1.tar.gz +0 -0
  28. package/dist/modules/docs-blog/0.6.1.tar.gz +0 -0
  29. package/dist/modules/marketing-site/0.6.1.tar.gz +0 -0
  30. package/dist/modules/minimalism-site/0.6.1.tar.gz +0 -0
  31. package/dist/modules/multi-tenant/0.6.1.tar.gz +0 -0
  32. package/dist/modules/saas-product/0.6.1.tar.gz +0 -0
  33. package/dist/modules/scheduling/0.6.1.tar.gz +0 -0
  34. package/dist/modules/signal-collectors/0.6.1.tar.gz +0 -0
  35. package/dist/modules/simple-service/0.6.1.tar.gz +0 -0
  36. package/dist/modules/workspace/0.6.1.tar.gz +0 -0
  37. package/dist/parse-args.d.ts +85 -10
  38. package/dist/parse-args.js +227 -15
  39. package/dist/programmatic.d.ts +81 -5
  40. package/dist/programmatic.js +291 -32
  41. package/dist/site-chrome.d.ts +18 -7
  42. package/dist/site-chrome.js +32 -14
  43. package/dist/site-roster.d.ts +127 -0
  44. package/dist/site-roster.js +499 -0
  45. package/dist/starter-grid.d.ts +216 -0
  46. package/dist/starter-grid.js +449 -0
  47. package/dist/surfaces.d.ts +20 -7
  48. package/dist/surfaces.js +204 -24
  49. package/dist/sync-routes.d.ts +9 -0
  50. package/dist/sync-routes.js +2 -2
  51. package/dist/template-manifest.d.ts +94 -19
  52. package/dist/template-manifest.js +170 -289
  53. package/dist/template-names.d.ts +14 -12
  54. package/dist/template-names.js +13 -17
  55. package/package.json +6 -4
  56. package/site-templates/_base/content/en/BookCall/book-call.mdx +52 -0
  57. package/site-templates/_base/content/en/Feature/feature-1.mdx +69 -0
  58. package/site-templates/_base/content/en/Feature/feature-2.mdx +69 -0
  59. package/site-templates/_base/content/en/Feature/feature-3.mdx +69 -0
  60. package/site-templates/_base/content/en/FeaturesList/features.mdx +91 -0
  61. package/site-templates/_base/content/en/GlossaryList/glossary.mdx +65 -0
  62. package/site-templates/_base/content/en/NewsletterSignup/newsletter.mdx +67 -0
  63. package/site-templates/_base/content/en/PortfolioItem/sample-four.mdx +105 -0
  64. package/site-templates/_base/content/en/PortfolioItem/sample-one.mdx +34 -0
  65. package/site-templates/_base/content/en/PortfolioItem/sample-three.mdx +94 -0
  66. package/site-templates/_base/content/en/PortfolioItem/sample-two.mdx +45 -0
  67. package/site-templates/_base/content/en/PortfolioList/portfolio.mdx +169 -0
  68. package/site-templates/_base/content/en/Pricing/pricing.mdx +71 -62
  69. package/site-templates/_base/content/en/PrivacyPage/privacy.mdx +17 -3
  70. package/site-templates/_base/content/en/TermsPage/terms.mdx +2 -3
  71. package/site-templates/_base/content/en/UseCase/persona-1.mdx +69 -0
  72. package/site-templates/_base/content/en/UseCase/persona-2.mdx +69 -0
  73. package/site-templates/_base/content/en/UseCase/persona-3.mdx +69 -0
  74. package/site-templates/designs/minimalism/DESIGN.md +162 -0
  75. package/site-templates/designs/standard/DESIGN.md +167 -0
  76. package/site-templates/marketing-site/DESIGN.md +59 -40
  77. package/site-templates/marketing-site/TEMPLATE-MANIFEST.json +376 -57
  78. package/site-templates/marketing-site/TEMPLATE-MANIFEST.md +230 -90
  79. package/site-templates/marketing-site/ailk-template.json +1 -0
  80. package/site-templates/marketing-site-free/DESIGN.md +59 -40
  81. package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.json +323 -63
  82. package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.md +323 -113
  83. package/site-templates/marketing-site-free/ailk-template.json +3 -2
  84. package/site-templates/marketing-site-free/content/en/NewsletterSignup/newsletter.mdx +59 -0
  85. package/site-templates/marketing-site-free/content/en/Pricing/pricing.mdx +199 -0
  86. package/site-templates/minimalism-site/DESIGN.md +54 -40
  87. package/site-templates/minimalism-site/TEMPLATE-MANIFEST.json +246 -19
  88. package/site-templates/minimalism-site/TEMPLATE-MANIFEST.md +173 -51
  89. package/site-templates/minimalism-site/ailk-template.json +3 -2
  90. package/site-templates/minimalism-site/content/en/BookCall/book-call.mdx +52 -0
  91. package/site-templates/minimalism-site/content/en/ContactPage/contact.mdx +3 -37
  92. package/site-templates/minimalism-site/content/en/PurchasePolicyPage/purchase-policy.mdx +123 -0
  93. package/site-templates/saas-product/DESIGN.md +59 -40
  94. package/site-templates/saas-product/TEMPLATE-MANIFEST.md +9 -1
  95. package/site-templates/shapes/local-business-service/TEMPLATE-MANIFEST.json +369 -0
  96. package/site-templates/shapes/local-business-service/TEMPLATE-MANIFEST.md +302 -0
  97. package/site-templates/shapes/local-business-service/ailk-template.json +10 -0
  98. package/site-templates/{simple-service → shapes/local-business-service}/content/en/AboutPage/about.mdx +4 -4
  99. package/site-templates/shapes/local-business-service/content/en/HomePage/home.mdx +70 -0
  100. package/site-templates/shapes/local-business-service/content/en/NewsletterSignup/newsletter.mdx +59 -0
  101. package/site-templates/shapes/local-business-service/content/en/PortfolioList/portfolio.mdx +171 -0
  102. package/site-templates/shapes/local-business-service/content/en/PurchasePolicyPage/purchase-policy.mdx +123 -0
  103. package/site-templates/shapes/local-business-service/content/en/Service/first-job.mdx +39 -0
  104. package/site-templates/shapes/local-business-service/content/en/Service/second-job.mdx +39 -0
  105. package/site-templates/shapes/local-business-service/content/en/Service/third-job.mdx +39 -0
  106. package/site-templates/shapes/local-business-service/content/en/ServicesList/services.mdx +61 -0
  107. package/site-templates/shapes/local-business-service/provenance.json +4 -0
  108. package/site-templates/shapes/organization-service/TEMPLATE-MANIFEST.json +362 -0
  109. package/site-templates/shapes/organization-service/TEMPLATE-MANIFEST.md +300 -0
  110. package/site-templates/shapes/organization-service/ailk-template.json +10 -0
  111. package/site-templates/shapes/organization-service/content/en/AboutPage/about.mdx +38 -0
  112. package/site-templates/shapes/organization-service/content/en/HomePage/home.mdx +85 -0
  113. package/site-templates/shapes/organization-service/content/en/NewsletterSignup/newsletter.mdx +59 -0
  114. package/site-templates/shapes/organization-service/content/en/PortfolioList/portfolio.mdx +171 -0
  115. package/site-templates/shapes/organization-service/content/en/PurchasePolicyPage/purchase-policy.mdx +123 -0
  116. package/site-templates/shapes/organization-service/content/en/Service/first-engagement.mdx +38 -0
  117. package/site-templates/shapes/organization-service/content/en/Service/second-engagement.mdx +38 -0
  118. package/site-templates/shapes/organization-service/content/en/Service/third-engagement.mdx +38 -0
  119. package/site-templates/shapes/organization-service/content/en/ServicesList/services.mdx +72 -0
  120. package/site-templates/shapes/organization-service/provenance.json +4 -0
  121. package/site-templates/shapes/person-service/TEMPLATE-MANIFEST.json +369 -0
  122. package/site-templates/shapes/person-service/TEMPLATE-MANIFEST.md +299 -0
  123. package/site-templates/shapes/person-service/ailk-template.json +10 -0
  124. package/site-templates/shapes/person-service/content/_site.mdx +85 -0
  125. package/site-templates/shapes/person-service/content/en/AboutPage/about.mdx +39 -0
  126. package/site-templates/shapes/person-service/content/en/HomePage/home.mdx +97 -0
  127. package/site-templates/shapes/person-service/content/en/NewsletterSignup/newsletter.mdx +59 -0
  128. package/site-templates/shapes/person-service/content/en/PortfolioList/portfolio.mdx +169 -0
  129. package/site-templates/shapes/person-service/content/en/PurchasePolicyPage/purchase-policy.mdx +123 -0
  130. package/site-templates/shapes/person-service/content/en/Service/first-engagement.mdx +38 -0
  131. package/site-templates/shapes/person-service/content/en/Service/second-engagement.mdx +38 -0
  132. package/site-templates/shapes/person-service/content/en/Service/third-engagement.mdx +38 -0
  133. package/site-templates/{simple-service → shapes/person-service}/content/en/ServicesList/services.mdx +16 -16
  134. package/site-templates/shapes/person-service/provenance.json +4 -0
  135. package/templates/.claude/settings.json +15 -0
  136. package/templates/.claude/skills/README.md +10 -9
  137. package/templates/.claude/skills/{scaffold-auth → add-auth}/SKILL.md +7 -7
  138. package/templates/.claude/skills/{scaffold-auth → add-auth}/references/env-vars.md +2 -2
  139. package/templates/.claude/skills/{scaffold-auth → add-auth}/references/oauth-app-setup.md +3 -3
  140. package/templates/.claude/skills/{scaffold-page → add-page}/SKILL.md +76 -62
  141. package/templates/.claude/skills/add-page/references/page-types.md +115 -0
  142. package/templates/.claude/skills/{scaffold-page → add-page}/templates/content.mdx.tmpl +4 -4
  143. package/templates/.claude/skills/{scaffold-page → add-page}/templates/route.tsx.tmpl +1 -1
  144. package/templates/.claude/skills/{audit-site → check-site}/SKILL.md +16 -17
  145. package/templates/.claude/skills/{audit-site → check-site}/references/common-errors.md +3 -3
  146. package/templates/.claude/skills/{audit-site → check-site}/references/findings-glossary.md +16 -14
  147. package/templates/.claude/skills/{audit-site → check-site}/references/severity-levels.md +1 -1
  148. package/templates/.claude/skills/fill-page/SKILL.md +180 -0
  149. package/templates/.claude/skills/fill-page/profiles/plumbing.yaml +80 -0
  150. package/templates/.claude/skills/fill-page/references/section-sources.md +41 -0
  151. package/templates/.claude/skills/setup-database/SKILL.md +156 -0
  152. package/templates/.claude/skills/setup-database/scripts/verify-inbox.ts +154 -0
  153. package/templates/.claude/skills/{provision-config → setup-deploy}/SKILL.md +73 -41
  154. package/templates/.claude/skills/{provision-config → setup-deploy}/references/env-vars-template.md +21 -30
  155. package/templates/.claude/skills/setup-deploy/references/runbook-template.md +204 -0
  156. package/templates/.claude/skills/{provision-config → setup-deploy}/references/vercel-json-template.md +1 -1
  157. package/templates/.claude/skills/upgrade-plan/SKILL.md +117 -0
  158. package/templates/.claude/skills/upgrade-plan/references/options.md +24 -0
  159. package/templates/.claude/skills/upgrade-plan/scripts/upgrade-plan.ts +527 -0
  160. package/templates/.github/workflows/ci.yml +5 -0
  161. package/templates/CLAUDE.md +8 -2
  162. package/templates/DESIGN.md +56 -44
  163. package/templates/README.md +116 -46
  164. package/templates/apps/api/.env.example +2 -1
  165. package/templates/apps/api/CLAUDE.md +3 -2
  166. package/templates/apps/api/package.json +1 -1
  167. package/templates/apps/api/src/config/__tests__/index.test.ts +146 -10
  168. package/templates/apps/api/src/config/index.ts +46 -14
  169. package/templates/apps/api/src/lib/__tests__/lead-capture-store.test.ts +30 -0
  170. package/templates/apps/api/src/lib/__tests__/lead-delivery.test.ts +96 -0
  171. package/templates/apps/api/src/lib/lead-capture-store.ts +12 -0
  172. package/templates/apps/api/src/lib/lead-delivery.ts +52 -0
  173. package/templates/apps/api/src/lib/license-key-store.ts +45 -0
  174. package/templates/apps/api/src/lib/site.ts +5 -3
  175. package/templates/apps/api/src/middleware/__tests__/auth.database-not-configured.test.ts +97 -0
  176. package/templates/apps/api/src/middleware/auth.ts +9 -0
  177. package/templates/apps/api/src/openapi/spec.ts +63 -12
  178. package/templates/apps/api/src/routes/content/__tests__/get-page.test.ts +127 -5
  179. package/templates/apps/api/src/routes/content/get-page.ts +86 -2
  180. package/templates/apps/api/src/routes/leads/__tests__/capture.test.ts +88 -0
  181. package/templates/apps/api/src/routes/leads/__tests__/index.test.ts +100 -0
  182. package/templates/apps/api/src/routes/leads/index.ts +46 -1
  183. package/templates/apps/api/src/server.ts +13 -0
  184. package/templates/apps/api/src/services/__tests__/lead-routing.test.ts +194 -0
  185. package/templates/apps/api/src/services/__tests__/leads-inbox.test.ts +124 -0
  186. package/templates/apps/api/src/services/lead-routing.ts +140 -30
  187. package/templates/apps/api/src/services/leads-inbox.ts +48 -11
  188. package/templates/apps/mcp/__tests__/audit-single-page.test.ts +75 -1
  189. package/templates/apps/mcp/__tests__/lib/audit-single-page-readiness-scan.test.ts +57 -9
  190. package/templates/apps/mcp/__tests__/parity.test.ts +5 -4
  191. package/templates/apps/mcp/package.json +2 -1
  192. package/templates/apps/mcp/src/index.ts +7 -0
  193. package/templates/apps/mcp/src/lib/audit-single-page.ts +36 -10
  194. package/templates/apps/mcp/src/lib/license-key-store.ts +45 -0
  195. package/templates/apps/mcp/src/tools/create_project.ts +21 -6
  196. package/templates/apps/web/__tests__/setup.ts +18 -0
  197. package/templates/apps/web/app/[locale]/(auth)/forgot-password/forgot-password-card.tsx +10 -2
  198. package/templates/apps/web/app/[locale]/(auth)/layout.tsx +2 -2
  199. package/templates/apps/web/app/[locale]/(auth)/reset-password/reset-password-card.tsx +10 -4
  200. package/templates/apps/web/app/[locale]/(auth)/sign-in/sign-in-card.tsx +22 -14
  201. package/templates/apps/web/app/[locale]/(auth)/sign-up/sign-up-card.tsx +26 -18
  202. package/templates/apps/web/app/[locale]/(authed)/account/page.tsx +12 -4
  203. package/templates/apps/web/app/[locale]/[slug]/__tests__/page.test.tsx +35 -4
  204. package/templates/apps/web/app/[locale]/[slug]/page.tsx +49 -9
  205. package/templates/apps/web/app/[locale]/book-a-call/page.tsx +50 -0
  206. package/templates/apps/web/app/[locale]/careers/__tests__/page-renderer-migration.test.tsx +3 -3
  207. package/templates/apps/web/app/[locale]/case-studies/__tests__/page-renderer-migration.test.tsx +3 -3
  208. package/templates/apps/web/app/[locale]/clients/__tests__/page-renderer-migration.test.tsx +3 -4
  209. package/templates/apps/web/app/[locale]/contact/ConversationalIntakeWrapper.tsx +67 -29
  210. package/templates/apps/web/app/[locale]/contact/__tests__/ConversationalIntakeWrapper.test.tsx +94 -11
  211. package/templates/apps/web/app/[locale]/contact/__tests__/contact-form-text.test.ts +32 -0
  212. package/templates/apps/web/app/[locale]/contact/__tests__/contact.actions.test.ts +129 -0
  213. package/templates/apps/web/app/[locale]/contact/__tests__/page-renderer-migration.test.tsx +228 -86
  214. package/templates/apps/web/app/[locale]/contact/contact-form-text.ts +50 -0
  215. package/templates/apps/web/app/[locale]/contact/contact.actions.ts +73 -20
  216. package/templates/apps/web/app/[locale]/contact/page.tsx +115 -7
  217. package/templates/apps/web/app/[locale]/contact/site-contact-email.ts +54 -0
  218. package/templates/apps/web/app/[locale]/courses/__tests__/page-renderer-migration.test.tsx +3 -3
  219. package/templates/apps/web/app/[locale]/downloads/__tests__/page-renderer-migration.test.tsx +3 -4
  220. package/templates/apps/web/app/[locale]/events/__tests__/page-renderer-migration.test.tsx +4 -5
  221. package/templates/apps/web/app/[locale]/features/[slug]/page.tsx +64 -0
  222. package/templates/apps/web/app/[locale]/features/page.tsx +52 -0
  223. package/templates/apps/web/app/[locale]/glossary/page.tsx +50 -0
  224. package/templates/apps/web/app/[locale]/how-to/__tests__/page-renderer-migration.test.tsx +1 -1
  225. package/templates/apps/web/app/[locale]/how-to/page.tsx +25 -15
  226. package/templates/apps/web/app/[locale]/integrations/__tests__/page-renderer-migration.test.tsx +3 -3
  227. package/templates/apps/web/app/[locale]/layout.tsx +146 -52
  228. package/templates/apps/web/app/[locale]/newsletter/__tests__/newsletter.actions.test.ts +75 -0
  229. package/templates/apps/web/app/[locale]/newsletter/__tests__/page.test.tsx +163 -0
  230. package/templates/apps/web/app/[locale]/newsletter/newsletter.actions.ts +66 -0
  231. package/templates/apps/web/app/[locale]/newsletter/page.tsx +142 -0
  232. package/templates/apps/web/app/[locale]/partners/__tests__/page-renderer-migration.test.tsx +3 -3
  233. package/templates/apps/web/app/[locale]/portfolio/[slug]/page.tsx +59 -0
  234. package/templates/apps/web/app/[locale]/portfolio/page.tsx +49 -0
  235. package/templates/apps/web/app/[locale]/products/__tests__/page-renderer-migration.test.tsx +3 -3
  236. package/templates/apps/web/app/[locale]/projects/__tests__/page-renderer-migration.test.tsx +4 -5
  237. package/templates/apps/web/app/[locale]/{cancellation → purchase-policy}/page.tsx +15 -10
  238. package/templates/apps/web/app/[locale]/resources/__tests__/page-renderer-migration.test.tsx +4 -5
  239. package/templates/apps/web/app/[locale]/services/__tests__/page-renderer-migration.test.tsx +3 -3
  240. package/templates/apps/web/app/[locale]/software/[slug]/page.tsx +14 -1
  241. package/templates/apps/web/app/[locale]/software/__tests__/page-renderer-migration.test.tsx +1 -1
  242. package/templates/apps/web/app/[locale]/software/page.tsx +25 -15
  243. package/templates/apps/web/app/[locale]/tech-articles/__tests__/page-renderer-migration.test.tsx +1 -1
  244. package/templates/apps/web/app/[locale]/tech-articles/page.tsx +25 -15
  245. package/templates/apps/web/app/[locale]/testimonials/__tests__/page-renderer-migration.test.tsx +3 -4
  246. package/templates/apps/web/app/[locale]/use-cases/[slug]/page.tsx +63 -0
  247. package/templates/apps/web/app/[locale]/use-cases/__tests__/page-renderer-migration.test.tsx +3 -4
  248. package/templates/apps/web/app/[locale]/use-cases/page.tsx +15 -2
  249. package/templates/apps/web/app/[locale]/whitepapers/__tests__/page-renderer-migration.test.tsx +1 -1
  250. package/templates/apps/web/app/[locale]/whitepapers/page.tsx +25 -15
  251. package/templates/apps/web/app/error-fallback.tsx +17 -45
  252. package/templates/apps/web/app/not-found.tsx +14 -38
  253. package/templates/apps/web/app/og/route.tsx +6 -0
  254. package/templates/apps/web/eslint.config.mjs +3 -0
  255. package/templates/apps/web/instrumentation.ts +14 -0
  256. package/templates/apps/web/lib/__tests__/structured-data.test.tsx +38 -0
  257. package/templates/apps/web/lib/license-key-store.ts +52 -0
  258. package/templates/apps/web/lib/nav-config.ts +82 -18
  259. package/templates/apps/web/lib/prisma-for-auth.ts +9 -6
  260. package/templates/apps/web/lib/site-brand.tsx +1 -1
  261. package/templates/apps/web/lib/site-chrome.ts +3 -3
  262. package/templates/apps/web/lib/site-identity.ts +148 -0
  263. package/templates/apps/web/lib/site-theme.ts +11 -0
  264. package/templates/apps/web/messages/en.json +78 -37
  265. package/templates/apps/web/public/android-chrome-192x192.png +0 -0
  266. package/templates/apps/web/public/android-chrome-512x512.png +0 -0
  267. package/templates/apps/web/public/apple-touch-icon.png +0 -0
  268. package/templates/apps/web/public/favicon-16x16.png +0 -0
  269. package/templates/apps/web/public/favicon-32x32.png +0 -0
  270. package/templates/apps/web/public/favicon.ico +0 -0
  271. package/templates/apps/web/public/favicon.svg +3 -3
  272. package/templates/apps/web/public/logomark.svg +6 -3
  273. package/templates/apps/web/public/logos/ai-launch-kit-light.svg +4 -0
  274. package/templates/apps/web/public/logos/ai-launch-kit.svg +4 -0
  275. package/templates/apps/web/public/logos/atomic-agent-light.svg +4 -0
  276. package/templates/apps/web/public/logos/atomic-agent.svg +4 -0
  277. package/templates/apps/web/public/logos/salessmyth-light.svg +4 -0
  278. package/templates/apps/web/public/logos/salessmyth.svg +4 -0
  279. package/templates/apps/web/public/site.webmanifest +4 -4
  280. package/templates/apps/web/public/wordmark-light.svg +4 -0
  281. package/templates/apps/web/public/wordmark.svg +3 -3
  282. package/templates/apps/web/security-headers.config.ts +5 -1
  283. package/templates/content/_site.mdx +25 -0
  284. package/templates/content/en/AboutPage/about.mdx +150 -144
  285. package/templates/content/en/BlogList/blog.mdx +126 -0
  286. package/templates/content/en/ContactPage/contact.mdx +21 -92
  287. package/templates/content/en/FAQPage/faq.mdx +86 -57
  288. package/templates/content/en/HomePage/home.mdx +268 -217
  289. package/templates/content/en/PurchasePolicyPage/purchase-policy.mdx +181 -0
  290. package/templates/content/en/UseCasesList/use-cases.mdx +170 -0
  291. package/templates/database/CHANGELOG.md +14 -0
  292. package/templates/database/package.json +1 -1
  293. package/templates/package.json +3 -1
  294. package/templates/tools/lint-architecture.ts +315 -0
  295. package/templates/tools/tsconfig.json +14 -0
  296. package/versions.json +33 -33
  297. package/site-templates/simple-service/DESIGN.md +0 -148
  298. package/site-templates/simple-service/TEMPLATE-MANIFEST.json +0 -240
  299. package/site-templates/simple-service/TEMPLATE-MANIFEST.md +0 -278
  300. package/site-templates/simple-service/ailk-template.json +0 -10
  301. package/site-templates/simple-service/content/en/ContactPage/contact.mdx +0 -67
  302. package/site-templates/simple-service/content/en/FAQPage/faq.mdx +0 -56
  303. package/site-templates/simple-service/content/en/HomePage/home.mdx +0 -85
  304. package/site-templates/simple-service/content/en/Service/landscape-design.mdx +0 -40
  305. package/site-templates/simple-service/content/en/Service/lawn-maintenance.mdx +0 -40
  306. package/site-templates/simple-service/content/en/Service/seasonal-cleanup.mdx +0 -40
  307. package/site-templates/simple-service/provenance.json +0 -4
  308. package/templates/.claude/skills/add-schema/SKILL.md +0 -277
  309. package/templates/.claude/skills/add-schema/references/conflict-handling.md +0 -200
  310. package/templates/.claude/skills/add-schema/references/file-finding.md +0 -123
  311. package/templates/.claude/skills/add-schema/references/schema-types.md +0 -234
  312. package/templates/.claude/skills/provision-config/references/runbook-template.md +0 -248
  313. package/templates/.claude/skills/scaffold-page/references/page-types.md +0 -169
  314. package/templates/.claude/skills/suggest-site-pages/SKILL.md +0 -242
  315. package/templates/.claude/skills/suggest-site-pages/references/categories.md +0 -287
  316. package/templates/apps/web/app/[locale]/contact/ContactForm.tsx +0 -150
  317. package/templates/apps/web/app/[locale]/returns/page.tsx +0 -44
  318. package/templates/apps/web/app/[locale]/shipping/page.tsx +0 -44
  319. package/templates/content/en/CancellationPolicyPage/cancellation.mdx +0 -108
  320. package/templates/content/en/LandingPage/blog.mdx +0 -83
  321. package/templates/content/en/LandingPage/features.mdx +0 -103
  322. package/templates/content/en/LandingPage/how-it-works.mdx +0 -143
  323. package/templates/content/en/ReturnsPolicyPage/returns.mdx +0 -108
  324. package/templates/content/en/ShippingPolicyPage/shipping.mdx +0 -108
@@ -7,7 +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 { createInterface } from "node:readline/promises";
10
11
  import { parseArgs } from "node:util";
12
+ import { assertLicenseKeyShape } from "./lib/license-key-files.js";
11
13
  import { RECOGNIZED_SURFACES, parseSurfaces } from "./surfaces.js";
12
14
  import { RECOGNIZED_TEMPLATES } from "./template-names.js";
13
15
  /**
@@ -28,8 +30,33 @@ export const RECOGNIZED_MODULES = [
28
30
  "signal-collectors",
29
31
  "commerce",
30
32
  ];
31
- /** The default module selection when `--modules` is absent (reproduces today's scaffold). */
32
- const DEFAULT_MODULES = ["marketing"];
33
+ /**
34
+ * Shapes a starter can be built from today (`--shape`, #6754 D1).
35
+ *
36
+ * Declared HERE rather than imported from `template-manifest.ts` for the
37
+ * reason `RECOGNIZED_MODULES` is: importing the registry closes the runtime
38
+ * cycle `template-names.ts`'s header records. `parse-args.test.ts` pins this
39
+ * list, `RESERVED_SHAPES` and `RECOGNIZED_DESIGNS` to their authorities
40
+ * (`STARTER_SHAPES`, `STARTER_DESIGNS`, `SHAPE_ROSTERS`).
41
+ */
42
+ export const RECOGNIZED_SHAPES = [
43
+ "organization-product",
44
+ "organization-service",
45
+ "local-business-service",
46
+ "person-service",
47
+ ];
48
+ /** Shapes the contract names but no release builds yet. */
49
+ export const RESERVED_SHAPES = ["local-business-product"];
50
+ /** The `--design` vocabulary (#6754 D1) — `STARTER_DESIGNS`, pinned by test. */
51
+ export const RECOGNIZED_DESIGNS = ["standard", "minimalism"];
52
+ /** What each shape is, for the prompt (D3). A shape without one is a type error. */
53
+ const SHAPE_DESCRIPTIONS = {
54
+ "organization-product": "a company selling a product",
55
+ "organization-service": "a company selling a service",
56
+ "local-business-service": "a local business selling a service",
57
+ "person-service": "a person selling their own service",
58
+ };
59
+ const SHAPE_LIST = RECOGNIZED_SHAPES.join(", ");
33
60
  export class ParseError extends Error {
34
61
  constructor(message) {
35
62
  super(message);
@@ -50,11 +77,31 @@ Arguments:
50
77
  Options:
51
78
  --modules <csv> Comma-separated list of modules to compose the site
52
79
  from (recognized: ${RECOGNIZED_MODULES.join(", ")}).
53
- Defaults to \`marketing\`, which reproduces today's
54
- scaffold. A module is a composable unit across the
55
- three tiers (data · API · presentation).
80
+ Trims or ADDS relative to the level your licence
81
+ key unlocks (#6759) — it never replaces it. With no
82
+ key, the level is Free (\`marketing\`). A Pro key
83
+ switches on docs-blog, scheduling and
84
+ signal-collectors too; Pro Plus adds multi-tenant.
85
+ Naming modules here keeps EXACTLY those, trimming
86
+ the level's default. Naming only \`commerce\` (a
87
+ per-site add-on) or \`workspace\` (included at Pro,
88
+ opt-in) ADDS it on top of the level's default
89
+ without trimming. A module your licence does not
90
+ include is refused, naming the level that does. A
91
+ module is a composable unit across the three tiers
92
+ (data · API · presentation).
93
+ --shape <shape> The kind of site to build (recognized:
94
+ ${SHAPE_LIST}).
95
+ Installs that shape's Free starter. A run naming
96
+ neither --shape nor --template asks for a shape on
97
+ a terminal, and refuses without one.
98
+ --design <design> The look to render the starter in (recognized:
99
+ ${RECOGNIZED_DESIGNS.join(", ")}). Defaults to the
100
+ starter's own.
56
101
  --template <name> The site template to install (recognized:
57
102
  ${RECOGNIZED_TEMPLATES.join(", ")}).
103
+ A template already fixes its shape and design, so
104
+ it cannot be combined with --shape or --design.
58
105
  A template is a page roster plus seed content and
59
106
  config — never code. Its required modules are ADDED
60
107
  to whatever \`--modules\` names, so the two compose.
@@ -73,7 +120,7 @@ Options:
73
120
  Surfaces the declared architecture does not carry are
74
121
  NOT scaffolded — their routes are absent, so a fresh
75
122
  site never serves a stock page with placeholder
76
- content. Add one later with the \`scaffold-page\`
123
+ content. Add one later with the \`add-page\`
77
124
  skill, or re-run with the surface named here.
78
125
  --sync-architecture <csv> Regenerate architecture.yaml in place in an
79
126
  already-scaffolded repo from the given module set
@@ -93,14 +140,17 @@ Options:
93
140
  file, at the target dir (positional arg, else cwd).
94
141
  Bypasses the scaffold path — copies no template, runs
95
142
  no install. Re-run after upgrading create-ailk.
143
+ --license <key> Your licence key: fetch paid modules with it and
144
+ write it into the scaffold (apps/api/.env and a
145
+ gitignored ailk.key, both owner-only).
96
146
  --install After scaffolding, run \`pnpm install\` in the
97
147
  target directory. Off by default.
98
148
  --help, -h Print this message.
99
149
  --version Print the scaffolder version.
100
150
 
101
151
  Examples:
102
- pnpm create ailk@latest my-site
103
- pnpm create ailk@latest /tmp/test-site --install
152
+ pnpm create ailk@latest my-site --shape organization-product
153
+ pnpm create ailk@latest /tmp/test-site --template marketing-site-free --install
104
154
 
105
155
  Next steps after a successful scaffold:
106
156
  cd <target-dir>
@@ -109,7 +159,12 @@ Next steps after a successful scaffold:
109
159
 
110
160
  Reference: ADR 0007 — \`pnpm create ailk@latest\` is the canonical install path.
111
161
  `;
112
- export function parseCliArgs(argv) {
162
+ /**
163
+ * Parse `create-ailk` argv. `env.interactive` defaults to false —
164
+ * fail-closed: a caller that does not assert a human is present gets refusal
165
+ * R1, never a prompt it cannot answer (#6754 D2).
166
+ */
167
+ export function parseCliArgs(argv, env = { interactive: false }) {
113
168
  let parsed;
114
169
  try {
115
170
  parsed = parseArgs({
@@ -119,6 +174,9 @@ export function parseCliArgs(argv) {
119
174
  options: {
120
175
  modules: { type: "string" },
121
176
  template: { type: "string" },
177
+ shape: { type: "string" },
178
+ design: { type: "string" },
179
+ license: { type: "string" },
122
180
  surfaces: { type: "string" },
123
181
  "sync-architecture": { type: "string" },
124
182
  "sync-catalog": { type: "boolean", default: false },
@@ -135,12 +193,18 @@ export function parseCliArgs(argv) {
135
193
  const help = parsed.values.help === true;
136
194
  const version = parsed.values.version === true;
137
195
  const install = parsed.values.install === true;
138
- const modules = parseModules(parsed.values.modules);
196
+ // #6759 D3 — an absent flag stays `undefined` (the key's level decides);
197
+ // only a PRESENT value goes through `parseModules`.
198
+ const rawModules = parsed.values.modules;
199
+ const modules = rawModules === undefined ? undefined : parseModules(rawModules);
139
200
  const template = parseTemplate(parsed.values.template);
201
+ const shape = parseShape(parsed.values.shape);
202
+ const design = parseDesign(parsed.values.design);
140
203
  const surfaces = parseSurfaceList(parsed.values.surfaces);
141
204
  const syncArchitecture = parsed.values["sync-architecture"];
142
205
  const syncCatalog = parsed.values["sync-catalog"] === true;
143
206
  const withCatalog = parsed.values["with-catalog"] === true;
207
+ const license = parseLicense(parsed.values.license);
144
208
  // The two sync modes each exit after rewriting their one file, so asking for
145
209
  // both in one invocation has no coherent meaning.
146
210
  if (syncCatalog && syncArchitecture !== undefined) {
@@ -157,6 +221,7 @@ export function parseCliArgs(argv) {
157
221
  return {
158
222
  target: undefined,
159
223
  template: undefined,
224
+ needsShapePrompt: false,
160
225
  install,
161
226
  help,
162
227
  version,
@@ -175,6 +240,7 @@ export function parseCliArgs(argv) {
175
240
  return {
176
241
  target: parsed.positionals[0],
177
242
  template,
243
+ needsShapePrompt: false,
178
244
  install,
179
245
  help,
180
246
  version,
@@ -191,9 +257,27 @@ export function parseCliArgs(argv) {
191
257
  if (parsed.positionals.length > 1) {
192
258
  throw new ParseError(`expected exactly one target directory, got ${parsed.positionals.length}`);
193
259
  }
260
+ // R3 — a template already fixes its shape and design.
261
+ if (template !== undefined && (shape !== undefined || design !== undefined)) {
262
+ const flags = shape !== undefined && design !== undefined
263
+ ? "--shape and --design"
264
+ : shape !== undefined
265
+ ? "--shape"
266
+ : "--design";
267
+ 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.`);
268
+ }
269
+ // R1 — no silent default: with neither a template nor a shape, ask on a
270
+ // terminal and refuse without one.
271
+ const needsShapePrompt = template === undefined && shape === undefined;
272
+ if (needsShapePrompt && !env.interactive) {
273
+ throw new ParseError(`no shape given, and there is no terminal to ask on. Pass --shape <shape> (one of: ${SHAPE_LIST}), or --template <name>.`);
274
+ }
194
275
  return {
195
276
  target: parsed.positionals[0],
196
277
  template,
278
+ ...(shape !== undefined ? { shape } : {}),
279
+ ...(design !== undefined ? { design } : {}),
280
+ needsShapePrompt,
197
281
  install,
198
282
  help,
199
283
  version,
@@ -202,8 +286,136 @@ export function parseCliArgs(argv) {
202
286
  syncCatalog,
203
287
  withCatalog,
204
288
  syncArchitecture: undefined,
289
+ ...(license !== undefined ? { license } : {}),
205
290
  };
206
291
  }
292
+ /**
293
+ * Validate `--shape` (#6754 D2 step 2): trimmed and lowercased. A reserved
294
+ * shape is refusal R2; any other unrecognized value names the recognized set.
295
+ */
296
+ function parseShape(raw) {
297
+ if (raw === undefined)
298
+ return undefined;
299
+ const name = raw.trim().toLowerCase();
300
+ if (RESERVED_SHAPES.includes(name)) {
301
+ throw new ParseError(`shape "${name}" is not available yet. Choose one of: ${SHAPE_LIST}.`);
302
+ }
303
+ if (!RECOGNIZED_SHAPES.includes(name)) {
304
+ throw new ParseError(`unknown shape "${raw}". Recognized: ${SHAPE_LIST}`);
305
+ }
306
+ return name;
307
+ }
308
+ /** Validate `--design` (#6754 D2 step 2): trimmed and lowercased. */
309
+ function parseDesign(raw) {
310
+ if (raw === undefined)
311
+ return undefined;
312
+ const name = raw.trim().toLowerCase();
313
+ if (!RECOGNIZED_DESIGNS.includes(name)) {
314
+ throw new ParseError(`unknown design "${raw}". Recognized: ${RECOGNIZED_DESIGNS.join(", ")}`);
315
+ }
316
+ return name;
317
+ }
318
+ /** How many answers the prompt takes before it gives up. */
319
+ const PROMPT_ATTEMPTS = 3;
320
+ /**
321
+ * Ask once for a shape (#6754 D3): a number 1–4 or a shape name. A bad answer
322
+ * re-asks, naming what was wrong; the third bad answer, or a closed input,
323
+ * throws. There is no default — an empty line is a bad answer.
324
+ */
325
+ export async function promptForShape(io) {
326
+ const width = Math.max(...RECOGNIZED_SHAPES.map((s) => s.length));
327
+ io.output.write([
328
+ "Which kind of site is this?",
329
+ ...RECOGNIZED_SHAPES.map((s, i) => ` ${i + 1}) ${s.padEnd(width)} ${SHAPE_DESCRIPTIONS[s]}`),
330
+ "",
331
+ ].join("\n"));
332
+ const noShape = new ParseError(`no shape chosen. Re-run with --shape <shape> (one of: ${SHAPE_LIST}).`);
333
+ const rl = createInterface({ input: io.input, terminal: false });
334
+ // The async iterator buffers every line, so an answer typed (or piped)
335
+ // ahead of its question is never dropped, and a closed input ends it.
336
+ const lines = rl[Symbol.asyncIterator]();
337
+ try {
338
+ for (let attempt = 0; attempt < PROMPT_ATTEMPTS; attempt++) {
339
+ io.output.write(`Shape [1-${RECOGNIZED_SHAPES.length} or name]: `);
340
+ const next = await lines.next();
341
+ if (next.done === true)
342
+ throw noShape;
343
+ const answer = next.value;
344
+ const picked = pickShape(answer);
345
+ if (picked !== undefined)
346
+ return picked;
347
+ const shown = answer.trim();
348
+ io.output.write(shown === ""
349
+ ? "No answer given.\n"
350
+ : `"${shown}" is not a shape. Answer 1-${RECOGNIZED_SHAPES.length} or a shape name.\n`);
351
+ }
352
+ throw noShape;
353
+ }
354
+ finally {
355
+ rl.close();
356
+ }
357
+ }
358
+ /** A prompt answer as a shape, or undefined when it names none. */
359
+ function pickShape(answer) {
360
+ const value = answer.trim().toLowerCase();
361
+ if (/^[0-9]+$/.test(value))
362
+ return RECOGNIZED_SHAPES[Number(value) - 1];
363
+ return RECOGNIZED_SHAPES.includes(value)
364
+ ? value
365
+ : undefined;
366
+ }
367
+ /**
368
+ * Fill `opts.shape` by prompting when, and only when, `needsShapePrompt` is
369
+ * set (#6754 D3). Help, version, sync and every run naming a shape or a
370
+ * template come back unchanged, with nothing written to `io.output`.
371
+ */
372
+ export async function resolveCliShape(opts, io) {
373
+ if (!opts.needsShapePrompt)
374
+ return opts;
375
+ const shape = await promptForShape(io);
376
+ return { ...opts, shape, needsShapePrompt: false };
377
+ }
378
+ /**
379
+ * The one mapping from parsed flags to `scaffold()` options (#6754 D4).
380
+ * `template`, `shape`, `design` and `license` are each spread only when set,
381
+ * so a `--template` run hands `scaffold()` the object it did before #6754.
382
+ *
383
+ * @throws ParseError when the shape prompt is unresolved or the target is
384
+ * unset — an unresolved prompt must never fall through to the bare overlay.
385
+ */
386
+ export function toScaffoldOptions(opts) {
387
+ if (opts.needsShapePrompt) {
388
+ throw new ParseError(`no shape given. Pass --shape <shape> (one of: ${SHAPE_LIST}), or --template <name>.`);
389
+ }
390
+ if (opts.target === undefined) {
391
+ throw new ParseError("missing target directory. Usage: pnpm create ailk@latest <target-dir>");
392
+ }
393
+ return {
394
+ targetDir: opts.target,
395
+ surfaces: opts.surfaces,
396
+ withCatalog: opts.withCatalog,
397
+ ...(opts.modules !== undefined ? { modules: opts.modules } : {}),
398
+ ...(opts.template !== undefined ? { template: opts.template } : {}),
399
+ ...(opts.shape !== undefined ? { shape: opts.shape } : {}),
400
+ ...(opts.design !== undefined ? { design: opts.design } : {}),
401
+ ...(opts.license !== undefined ? { license: opts.license } : {}),
402
+ };
403
+ }
404
+ /**
405
+ * Shape-check the `--license` value through the one validator `license set`
406
+ * also uses, re-thrown as a ParseError. The message never repeats the value.
407
+ */
408
+ function parseLicense(raw) {
409
+ if (raw === undefined)
410
+ return undefined;
411
+ try {
412
+ assertLicenseKeyShape(raw);
413
+ }
414
+ catch (err) {
415
+ throw new ParseError(`--license: ${err.message}`);
416
+ }
417
+ return raw;
418
+ }
207
419
  /**
208
420
  * Validate the `--template` value against the declared template set
209
421
  * (spec 5481 § 3 DD1).
@@ -248,20 +460,20 @@ function parseSurfaceList(raw) {
248
460
  * validated, normalized string[].
249
461
  *
250
462
  * Splits on `,`, trims and lowercases each entry, drops empties, and validates
251
- * each against RECOGNIZED_MODULES. An absent flag (or an all-empty value)
252
- * defaults to DEFAULT_MODULES (`['marketing']`) — reproducing today's scaffold.
463
+ * each against RECOGNIZED_MODULES. Takes a PRESENT value only — an ABSENT
464
+ * `--modules` flag is `undefined` (#6759 D3: the key's level decides) and
465
+ * never reaches this function; an all-empty value (`--modules ""`,
466
+ * `--modules ,`) still names the Free set, spelled inline here.
253
467
  *
254
468
  * @throws ParseError on an unrecognized module value, naming the recognized set.
255
469
  */
256
470
  export function parseModules(raw) {
257
- if (raw === undefined)
258
- return [...DEFAULT_MODULES];
259
471
  const requested = raw
260
472
  .split(",")
261
473
  .map((m) => m.trim().toLowerCase())
262
474
  .filter(Boolean);
263
475
  if (requested.length === 0)
264
- return [...DEFAULT_MODULES];
476
+ return ["marketing"];
265
477
  for (const m of requested) {
266
478
  if (!RECOGNIZED_MODULES.includes(m)) {
267
479
  throw new ParseError(`unknown module "${m}". Recognized: ${RECOGNIZED_MODULES.join(", ")}`);
@@ -15,10 +15,12 @@
15
15
  * import { scaffoldSync } from './programmatic.js';
16
16
  * const result = scaffoldSync({ targetDir: '/tmp/my-site', projectName: 'my-site' });
17
17
  */
18
+ import { type AddModuleResult } from "./add-module.js";
18
19
  import { CATALOG_TARGET_PATH } from "./component-catalog.js";
19
20
  import { type ModuleName } from "./parse-args.js";
20
21
  import { type TemplateLayout } from "./site-chrome.js";
21
22
  import { type SyncRoutesResult } from "./sync-routes.js";
23
+ import { type StarterDesign, type StarterShape } from "./template-manifest.js";
22
24
  export interface ScaffoldOptions {
23
25
  /** Absolute or relative path to the target directory. Must not exist or be empty. */
24
26
  targetDir: string;
@@ -34,9 +36,10 @@ export interface ScaffoldOptions {
34
36
  *
35
37
  * Consumed ONLY by the async `scaffold()` below. `scaffoldSync` stays
36
38
  * template-oblivious for exactly the reason it stays licensing-oblivious
37
- * (spec 5481 § 3 DD3): a call naming no template takes a code path with no
38
- * new statement in it, which is a stronger byte-identity guarantee than a
39
- * test asserting the output happens to match.
39
+ * (spec 5481 § 3 DD3): a call naming neither a template nor a `shape`
40
+ * takes a code path with no new statement in it — the bare overlay, the
41
+ * library's default. The CLI never takes that path (#6754 D2: it refuses a
42
+ * run naming neither, or asks for a shape on a terminal).
40
43
  *
41
44
  * What a template DOES change is `modules` — `scaffold()` unions the
42
45
  * template's `requires` with whatever `--modules` named and passes THAT
@@ -44,6 +47,13 @@ export interface ScaffoldOptions {
44
47
  * `architecture.yaml` and the generated nav are all functions of the union.
45
48
  */
46
49
  template?: string;
50
+ /**
51
+ * The starter shape to install (`--shape`, #6754 D5): `scaffold()` resolves
52
+ * it to the one template of that shape whose delivery is `free`, then runs
53
+ * exactly as a `template` naming it would. Mutually exclusive with
54
+ * `template`. A shape with no Free starter yet is refused (D6).
55
+ */
56
+ shape?: StarterShape;
47
57
  /**
48
58
  * Selected modules (recognized: marketing, docs-blog, multi-tenant,
49
59
  * scheduling). Defaults to
@@ -84,6 +94,14 @@ export interface ScaffoldOptions {
84
94
  * bare/all-Free scaffold reads neither).
85
95
  */
86
96
  licenseKey?: string;
97
+ /**
98
+ * The buyer's licence key (`--license`, #6683 D9). Takes precedence over
99
+ * `licenseKey` and `AILK_LICENSE_KEY` for bundle fetches, and — unlike
100
+ * them — is PERSISTED: after a successful scaffold it is written to the
101
+ * target's `ailk.key` and `apps/api/.env` (`writeLicenseKeyFiles`). Unset,
102
+ * the scaffold is byte-identical to one made before the option existed.
103
+ */
104
+ license?: string;
87
105
  /** Overrides `AILK_MODULE_REGISTRY_URL` / the built-in module-distribution default. */
88
106
  moduleRegistryUrl?: string;
89
107
  /** Overrides `AILK_TEMPLATE_REGISTRY_URL` / the built-in template-distribution default. */
@@ -99,6 +117,16 @@ export interface ScaffoldOptions {
99
117
  * caller) writes the same defaults `site-chrome.ts` always has.
100
118
  */
101
119
  layout?: TemplateLayout;
120
+ /**
121
+ * The design whose layout knobs fill what `layout` leaves unset (#6638,
122
+ * `DESIGN_LAYOUTS`). `scaffold()` sets it from the resolved template's
123
+ * `design`; a caller may name one to OVERRIDE the template's — the
124
+ * shape × design pairing `verify-scaffold.mjs --design` renders (#6638
125
+ * DD-4), and the CLI's `--design` beside `--shape` (#6754). Unset (every
126
+ * existing `scaffoldSync` caller) resolves exactly as before. Gated
127
+ * (#6760): a design outside `FREE_DESIGNS` needs a Pro or Pro Plus level.
128
+ */
129
+ design?: StarterDesign;
102
130
  }
103
131
  export interface ScaffoldResult {
104
132
  /** Resolved absolute path to the scaffolded directory. */
@@ -107,6 +135,21 @@ export interface ScaffoldResult {
107
135
  filesCreated: number;
108
136
  /** The gateable route surfaces this scaffold declares (sorted). */
109
137
  surfaces: string[];
138
+ /**
139
+ * The starter this scaffold resolved (#6754 D5) — set whenever a template
140
+ * was resolved, from `template` or from `shape`; absent for the bare overlay.
141
+ */
142
+ starter?: {
143
+ template: string;
144
+ shape: StarterShape;
145
+ design: StarterDesign;
146
+ };
147
+ /**
148
+ * The effective module set this scaffold installed (#6759 D6) — what
149
+ * `scaffoldSync` actually received, never the requested `--modules` alone:
150
+ * a keyed run with no `--modules` carries the key's derived level here.
151
+ */
152
+ modules: ModuleName[];
110
153
  }
111
154
  /**
112
155
  * Scaffold an AI Launch Kit starter project into targetDir (synchronous).
@@ -133,8 +176,14 @@ export declare function scaffoldSync(opts: ScaffoldOptions): ScaffoldResult;
133
176
  * its fetched bundle or — when it requires only free modules — from the
134
177
  * `site-templates/` tree this package ships.
135
178
  *
136
- * And, ahead of all five when `opts.template` is set (0): resolve the
137
- * template and union its `requires` with `opts.modules`, so every step above
179
+ * Between 2 and 3, `assertDesignAllowed` (#6760) refuses a design the caller
180
+ * CHOSE (`opts.design`) for a level below Pro, HERE, also before anything is
181
+ * written to disk. A template's own declared design is never gated (#6778
182
+ * option (c)): the template's `requires` already decide its level.
183
+ *
184
+ * And, ahead of all five when `opts.template` (or `opts.shape`, #6754 D5) is
185
+ * set (0): resolve the template and union its `requires` with `opts.modules`,
186
+ * so every step above
138
187
  * runs over the EFFECTIVE module set rather than the requested one.
139
188
  *
140
189
  * `scaffoldSync` itself stays licensing-oblivious on purpose: every existing
@@ -233,6 +282,33 @@ export interface SyncRoutesSyncOptions {
233
282
  export declare function syncRoutesSync(opts: SyncRoutesSyncOptions): SyncRoutesResult;
234
283
  /** Re-exported beside the other sync results so consumers see one surface. */
235
284
  export type { RouteReport, SyncRoutesResult } from "./sync-routes.js";
285
+ export interface AddModuleOptions {
286
+ /** The already-scaffolded site (absolute or relative). */
287
+ targetDir: string;
288
+ /** The module to add (validated upstream by `parseAddModuleArgs`). */
289
+ moduleName: ModuleName;
290
+ /** Defaults to `process.env["AILK_LICENSE_KEY"]`, as for `scaffold()`. */
291
+ licenseKey?: string;
292
+ /** Defaults to `AILK_MODULE_REGISTRY_URL` / the built-in default. */
293
+ moduleRegistryUrl?: string;
294
+ /** Defaults to `globalThis.fetch`. Never a live call in tests. */
295
+ fetchImpl?: typeof fetch;
296
+ }
297
+ /**
298
+ * Apply a purchased module to an already-scaffolded site in place
299
+ * (`create-ailk add-module`, #6653). The thin package-rooted wrapper around
300
+ * `add-module.ts`'s `applyModuleToScaffold`, the `syncRoutesSync` split:
301
+ *
302
+ * 1. the target must be an existing scaffold — the same check as the sync
303
+ * subcommands above;
304
+ * 2. a free module is refused before any key read or network call — it
305
+ * ships with every scaffold, there is no bundle to add;
306
+ * 3. `resolvePaidModules` — the SAME gate `scaffold()` runs, so a missing
307
+ * key or a key that does not cover the module is refused with the
308
+ * scaffold-time message, before anything is written;
309
+ * 4. the fetched bundle is merged under the plus-config policy.
310
+ */
311
+ export declare function addModule(opts: AddModuleOptions): Promise<AddModuleResult>;
236
312
  /** Re-exported so the CLI can name the file it wrote without duplicating it. */
237
313
  export { CATALOG_TARGET_PATH };
238
314
  /**