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
@@ -0,0 +1,194 @@
1
+ /**
2
+ * `create-ailk license set <key|-> [dir]` — put a licence key into an existing
3
+ * scaffold and, when it is Vercel-linked, into production (#6683 § 3 D9).
4
+ *
5
+ * The one-liner a buyer runs is `pnpm create ailk@latest license set <key>`:
6
+ * `create-ailk` is the public CLI they already have (§ 1.8).
7
+ *
8
+ * 1. The target (default: cwd) must contain `architecture.yaml` — the
9
+ * `sync-routes` precondition — else exit 1 with nothing written.
10
+ * 2. `writeLicenseKeyFiles` — `ailk.key` + `apps/api/.env`, both 0600 and
11
+ * gitignored; the same writer `--license` uses.
12
+ * 3. For each of `<dir>`, `<dir>/apps/api`, `<dir>/apps/web` holding
13
+ * `.vercel/project.json`, with that directory as `cwd`:
14
+ * a. print the linked `projectId` about to change (SEC-13);
15
+ * b. list `ailk.key` and `.env` in its `.vercelignore` — a CLI deploy
16
+ * uploads the local tree, which `.gitignore` does not govern (SEC-10);
17
+ * c. `vercel env rm AILK_LICENSE_KEY production --yes` (failure
18
+ * tolerated: the variable may not exist yet);
19
+ * d. `vercel env add AILK_LICENSE_KEY production`, the key on STDIN;
20
+ * e. `vercel deploy --prod --yes`.
21
+ *
22
+ * The key is never an argv element of a spawned process and never appears in
23
+ * an error (SEC-11). `vercel` missing → exit 1 naming what was written and the
24
+ * exact manual commands; a failed `env add` after `env rm` → exit 1 saying the
25
+ * production variable is now UNSET, with the command that finishes the job.
26
+ * No Vercel link → exit 0 after the local write.
27
+ *
28
+ * Pure module (no `import.meta.url`): every effect on the outside world —
29
+ * output, stdin, the process runner — is injected, so jest drives it directly.
30
+ */
31
+ import { spawnSync } from "node:child_process";
32
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
33
+ import { join, relative, resolve } from "node:path";
34
+ import { LICENSE_ENV_FILE, LICENSE_ENV_VAR, LICENSE_KEY_FILE, assertLicenseKeyShape, writeLicenseKeyFiles, } from "./lib/license-key-files.js";
35
+ export const LICENSE_SET_HELP = `create-ailk license set — put your licence key into an existing site.
36
+
37
+ Usage:
38
+ pnpm create ailk@latest license set <key> [<target-dir>]
39
+ pnpm create ailk@latest license set - [<target-dir>] < key.txt
40
+
41
+ Arguments:
42
+ <key> Your licence key, or \`-\` to read it from stdin
43
+ (keeps it out of your shell history).
44
+ <target-dir> An already-scaffolded repo (contains
45
+ architecture.yaml). Defaults to the current dir.
46
+
47
+ Writes the key to ailk.key and apps/api/.env (owner-only, gitignored). When the
48
+ site (or apps/api, or apps/web) is linked to Vercel, it also replaces the
49
+ production AILK_LICENSE_KEY variable and redeploys.
50
+ `;
51
+ const LINK_DIRS = [".", join("apps", "api"), join("apps", "web")];
52
+ const VERCELIGNORE_LINES = [LICENSE_KEY_FILE, ".env"];
53
+ const ENV_RM = ["env", "rm", LICENSE_ENV_VAR, "production", "--yes"];
54
+ const ENV_ADD = ["env", "add", LICENSE_ENV_VAR, "production"];
55
+ const DEPLOY = ["deploy", "--prod", "--yes"];
56
+ /** `spawnSync`, never through a shell; stdin piped only when there is input. */
57
+ export const defaultRunner = (args, options) => {
58
+ const res = spawnSync("vercel", [...args], {
59
+ cwd: options.cwd,
60
+ shell: false,
61
+ stdio: [options.input !== undefined ? "pipe" : "inherit", "inherit", "inherit"],
62
+ ...(options.input !== undefined ? { input: options.input } : {}),
63
+ });
64
+ return {
65
+ status: res.status,
66
+ ...(res.error !== undefined
67
+ ? { error: res.error }
68
+ : {}),
69
+ };
70
+ };
71
+ class LicenseSetError extends Error {
72
+ }
73
+ /**
74
+ * Hand-parsed rather than through `node:util` `parseArgs`: its errors quote
75
+ * the offending token, and the token here may be the key.
76
+ */
77
+ function parseLicenseSetArgs(argv) {
78
+ if (argv.includes("--help") || argv.includes("-h")) {
79
+ return { help: true, key: undefined, target: undefined };
80
+ }
81
+ if (argv.length > 2) {
82
+ throw new LicenseSetError(`expected <key|-> and at most one target directory, got ${argv.length} arguments`);
83
+ }
84
+ return { help: false, key: argv[0], target: argv[1] };
85
+ }
86
+ /** Append whichever of `lines` the file does not already list. */
87
+ function ensureVercelIgnore(dir) {
88
+ const path = join(dir, ".vercelignore");
89
+ const text = existsSync(path) ? readFileSync(path, "utf8") : "";
90
+ const present = new Set(text.split("\n").map((l) => l.trim()));
91
+ const missing = VERCELIGNORE_LINES.filter((l) => !present.has(l) && !present.has(`/${l}`));
92
+ if (missing.length === 0)
93
+ return;
94
+ const sep = text.length === 0 || text.endsWith("\n") ? "" : "\n";
95
+ writeFileSync(path, `${text}${sep}${missing.join("\n")}\n`);
96
+ }
97
+ function readProjectId(dir) {
98
+ try {
99
+ const raw = JSON.parse(readFileSync(join(dir, ".vercel", "project.json"), "utf8"));
100
+ if (typeof raw.projectId === "string" && raw.projectId.length > 0) {
101
+ return raw.projectId;
102
+ }
103
+ }
104
+ catch {
105
+ // fall through
106
+ }
107
+ throw new LicenseSetError(`${join(dir, ".vercel", "project.json")} has no readable projectId; run \`vercel link\` there, then re-run.`);
108
+ }
109
+ /** The exact commands that finish the push by hand, from `dir`. */
110
+ function manualCommands(dir, keyFile, from) {
111
+ const keyRel = relative(dir, keyFile) || LICENSE_KEY_FILE;
112
+ const lines = [` cd ${dir}`];
113
+ if (from === "rm")
114
+ lines.push(` vercel ${ENV_RM.join(" ")}`);
115
+ lines.push(` tr -d '\\n' < ${keyRel} | vercel ${ENV_ADD.join(" ")}`);
116
+ lines.push(` vercel ${DEPLOY.join(" ")}`);
117
+ return lines.join("\n");
118
+ }
119
+ /**
120
+ * Run `license set` with `argv` = everything after the `license set` words.
121
+ * Returns the process exit code; never throws for an expected failure.
122
+ */
123
+ export function runLicenseSet(argv, io) {
124
+ const runner = io.runner ?? defaultRunner;
125
+ const fail = (message) => {
126
+ io.stderr(`[create-ailk] license set: ${message}\n`);
127
+ return 1;
128
+ };
129
+ let args;
130
+ try {
131
+ args = parseLicenseSetArgs(argv);
132
+ }
133
+ catch (err) {
134
+ return fail(`${err.message}\n\n${LICENSE_SET_HELP}`);
135
+ }
136
+ if (args.help) {
137
+ io.stdout(LICENSE_SET_HELP);
138
+ return 0;
139
+ }
140
+ if (args.key === undefined) {
141
+ return fail(`missing <key>.\n\n${LICENSE_SET_HELP}`);
142
+ }
143
+ const key = args.key === "-" ? io.readStdin().trim() : args.key;
144
+ try {
145
+ assertLicenseKeyShape(key);
146
+ }
147
+ catch (err) {
148
+ return fail(err.message);
149
+ }
150
+ const target = resolve(io.cwd, args.target ?? ".");
151
+ if (!existsSync(join(target, "architecture.yaml"))) {
152
+ return fail(`not a scaffolded repo: no architecture.yaml at ${target}. Run it from your site's root, or pass the site's directory.`);
153
+ }
154
+ writeLicenseKeyFiles(target, key);
155
+ const keyFile = join(target, LICENSE_KEY_FILE);
156
+ const written = `Wrote ${LICENSE_KEY_FILE} and ${LICENSE_ENV_FILE.split("\\").join("/")} in ${target}`;
157
+ io.stdout(`[create-ailk] ${written} (owner-only, gitignored).\n`);
158
+ const linked = LINK_DIRS.map((d) => join(target, d)).filter((d) => existsSync(join(d, ".vercel", "project.json")));
159
+ if (linked.length === 0) {
160
+ io.stdout("[create-ailk] No Vercel link found (.vercel/project.json); nothing pushed. Set AILK_LICENSE_KEY on your host yourself if you deploy elsewhere.\n");
161
+ return 0;
162
+ }
163
+ for (const dir of linked) {
164
+ let projectId;
165
+ try {
166
+ projectId = readProjectId(dir);
167
+ }
168
+ catch (err) {
169
+ return fail(err.message);
170
+ }
171
+ io.stdout(`[create-ailk] Updating ${LICENSE_ENV_VAR} (production) on Vercel project ${projectId}, linked at ${dir}\n`);
172
+ ensureVercelIgnore(dir);
173
+ const rm = runner(ENV_RM, { cwd: dir });
174
+ if (rm.error?.code === "ENOENT") {
175
+ return fail(`the vercel CLI was not found. ${written}; nothing was pushed. Install it (npm i -g vercel), or finish by hand:\n${manualCommands(dir, keyFile, "rm")}`);
176
+ }
177
+ // `rm` may fail because the variable never existed — tolerated — but then
178
+ // it removed nothing, and the message below must not say it did.
179
+ const removed = rm.error === undefined && rm.status === 0;
180
+ const add = runner(ENV_ADD, { cwd: dir, input: key });
181
+ if (add.error !== undefined || add.status !== 0) {
182
+ const state = removed
183
+ ? `The production variable ${LICENSE_ENV_VAR} is now UNSET there (the old value was removed).`
184
+ : `The production variable ${LICENSE_ENV_VAR} was not changed (removing the old value also failed).`;
185
+ return fail(`\`vercel ${ENV_ADD.join(" ")}\` failed on project ${projectId}. ${state} Finish with:\n${manualCommands(dir, keyFile, removed ? "add" : "rm")}`);
186
+ }
187
+ const deploy = runner(DEPLOY, { cwd: dir });
188
+ if (deploy.error !== undefined || deploy.status !== 0) {
189
+ return fail(`\`vercel ${DEPLOY.join(" ")}\` failed on project ${projectId}. ${LICENSE_ENV_VAR} is set in production; redeploy with:\n cd ${dir}\n vercel ${DEPLOY.join(" ")}`);
190
+ }
191
+ }
192
+ io.stdout("[create-ailk] Licence key set and production redeployed.\n");
193
+ return 0;
194
+ }
@@ -61,6 +61,14 @@ export interface PageRosterRow {
61
61
  * (`/meet` renders from the scheduling API, not from an MDX file).
62
62
  */
63
63
  content?: readonly string[];
64
+ /**
65
+ * Scaffold-relative seed DIRECTORY a dynamic detail row serves, e.g.
66
+ * `content/en/Service` under `/services/[slug]` (#6646 disposition (a)).
67
+ * `content` names files; a detail route whose seeds are a whole directory
68
+ * declares the directory instead. Every `.mdx` under it is a declared page,
69
+ * so it installs; a seed no row names does not.
70
+ */
71
+ contentDir?: string;
64
72
  }
65
73
  /**
66
74
  * The architecture fragment one module contributes.
@@ -144,6 +152,8 @@ export interface ModuleSlice {
144
152
  * `ownedFiles` names which files in THIS monorepo physically belong to the
145
153
  * module; `pageContributions` names which PAGES the module brings to a
146
154
  * template's roster. `template-manifest.ts`'s `mergeRoster` reads it.
155
+ * A row's `contentDir` names seeds a TEMPLATE supplies, not the module:
156
+ * the module's bundle stages only `content` files (#6646).
147
157
  *
148
158
  * A contribution never carries route CODE. How the route code reaches a
149
159
  * scaffold is a property of the module, not of the contribution (parent
@@ -399,3 +409,13 @@ export declare function normalizeModules(modules: string[]): ModuleName[];
399
409
  export declare function coOwnedModuleDestinations(): ReadonlySet<string>;
400
410
  export declare const EXCLUDE_TEMPLATE_DIRS: readonly string[];
401
411
  export declare function paidModuleTemplateExclusions(snapshotRoots: readonly string[], repoRoot: string): string[];
412
+ /** The scaffold's architecture linter, relative to the site root (#6649). */
413
+ export declare const ARCHITECTURE_LINT_PATH = "tools/lint-architecture.ts";
414
+ /**
415
+ * What a scaffold needs so its `architecture.yaml` is enforced rather than
416
+ * declared (#6649): the linter, the `architecture` + `preflight` root scripts
417
+ * that run it, and a `.claude/settings.json` PostToolUse hook on Edit|Write
418
+ * that runs it in-session. Returns one line per missing piece — empty means
419
+ * all present. `verify-scaffold.mjs` fails on a non-empty result.
420
+ */
421
+ export declare function missingArchitectureEnforcement(siteDir: string): string[];
@@ -21,7 +21,8 @@
21
21
  * `architecture.yaml` template files — a fixed template IS the drift this
22
22
  * removes.
23
23
  */
24
- import { sep } from "node:path";
24
+ import { existsSync, readFileSync } from "node:fs";
25
+ import { join, sep } from "node:path";
25
26
  import { importClosure } from "./lib/import-graph.js";
26
27
  import { PAID_MODULES } from "./lib/module-tier.js";
27
28
  import { RECOGNIZED_MODULES } from "./parse-args.js";
@@ -149,6 +150,15 @@ const ASSET_STORE_FILES = [
149
150
  "apps/api/src/routes/assets/manage.ts",
150
151
  "apps/api/src/lib/asset-store.ts",
151
152
  ];
153
+ /**
154
+ * The auth-adapter exception (#587 in the AILK repo's own architecture.yaml):
155
+ * the base apps/web hands Better Auth its Prisma client from
156
+ * `lib/prisma-for-auth.ts`, whatever modules are selected. Every slice that
157
+ * contributes `webImports` — and so makes apps/web's allowlist non-empty —
158
+ * names it, so no module set yields an allowlist the scaffold's own
159
+ * tools/lint-architecture.ts fails on (#6649).
160
+ */
161
+ const WEB_AUTH_ADAPTER_IMPORT = "database";
152
162
  /**
153
163
  * The per-module slices. Authored for every `RECOGNIZED_MODULES` value; only
154
164
  * `marketing` (the default) is validated end-to-end against a golden.
@@ -157,6 +167,7 @@ export const MODULE_SLICES = {
157
167
  // ── marketing — thin presentation module (the default) ───────────────────
158
168
  marketing: {
159
169
  webImports: [
170
+ WEB_AUTH_ADAPTER_IMPORT,
160
171
  "packages/content-adapters",
161
172
  "packages/jsonld",
162
173
  "packages/metadata",
@@ -236,7 +247,7 @@ export const MODULE_SLICES = {
236
247
  },
237
248
  // ── docs-blog — Pro module: both fumadocs surfaces (D-46) ────────────────
238
249
  "docs-blog": {
239
- webImports: ["packages/fumadocs-schema"],
250
+ webImports: [WEB_AUTH_ADAPTER_IMPORT, "packages/fumadocs-schema"],
240
251
  packages: {
241
252
  "fumadocs-schema": {
242
253
  description: "Fumadocs ↔ schema.org bridge — BlogList / DocsPage JSON-LD from Fumadocs MDX",
@@ -376,7 +387,10 @@ export const MODULE_SLICES = {
376
387
  path: ["scripts"],
377
388
  entries: {
378
389
  prebuild: "fumadocs-mdx",
379
- pretypecheck: "fumadocs-mdx",
390
+ // `pretype-check`, not `pretypecheck`: pnpm runs `pre<name>`
391
+ // only before a script named `<name>`, and the scaffold's is
392
+ // `type-check` (#6680).
393
+ "pretype-check": "fumadocs-mdx",
380
394
  pretest: "fumadocs-mdx",
381
395
  },
382
396
  },
@@ -795,7 +809,7 @@ export const MODULE_SLICES = {
795
809
  // dependency under `node_modules/`, never as a `packages/admin-ui`
796
810
  // source sibling; the `patches` entry below is what puts it in the
797
811
  // buyer's apps/web/package.json.
798
- webImports: ["packages/admin-ui"],
812
+ webImports: [WEB_AUTH_ADAPTER_IMPORT, "packages/admin-ui"],
799
813
  packages: {
800
814
  "admin-ui": {
801
815
  description: "Shared Admin-settings components — the settings shell plus the General / Site / Team panels, presentational only (data + save callbacks as props)",
@@ -892,12 +906,9 @@ export const MODULE_SLICES = {
892
906
  // all, and no scheduling value is ever published to the browser as a
893
907
  // `NEXT_PUBLIC_` variable.
894
908
  //
895
- // NOTE — a scaffolded site cannot run these yet. It receives
896
- // `architecture.yaml` and a `package.json` whose `architecture` script names
897
- // `tools/lint-architecture.ts`, but `build-templates.mjs` snapshots only
898
- // `apps/` and `database/`, so `tools/` is absent. The rules are declarative
899
- // there until the scaffold ships its linter; they ARE enforced in the AILK
900
- // repo, whose own architecture.yaml carries the same four.
909
+ // A scaffolded site enforces these with its own `tools/lint-architecture.ts`
910
+ // (template-overlay/, #6649) via `pnpm architecture`; the AILK repo's own
911
+ // architecture.yaml carries the same four.
901
912
  //
902
913
  // The `api` block is a VERBATIM copy of multi-tenant's, deliberately. Two
903
914
  // reasons: `deriveArchitecture` merges app blocks with `Object.assign`, so
@@ -1434,8 +1445,10 @@ export const MODULE_SLICES = {
1434
1445
  { route: "/flows/[slug]/results/[payload]" },
1435
1446
  // #5562 — the report reader. Unlike the three rows above, this row's
1436
1447
  // code IS this module's own `ownedFiles` (see the note beside it), so
1437
- // the contribution and the delivery shape carrying it agree here.
1438
- { route: "/reports/[slug]" },
1448
+ // the contribution and the delivery shape carrying it agree here. Its
1449
+ // seeds are a directory a template supplies (minimalism-site's four
1450
+ // reports), so the row declares that directory (#6646).
1451
+ { route: "/reports/[slug]", contentDir: "content/en/ReportPage" },
1439
1452
  ],
1440
1453
  // installMap (#5618 D6.3) — the module's ten sample files, moved here out
1441
1454
  // of `site-templates/marketing-site/` so the module OWNS its samples
@@ -1451,13 +1464,13 @@ export const MODULE_SLICES = {
1451
1464
  //
1452
1465
  // Four entries are real renames (the flow and waitlist seeds the API
1453
1466
  // reads, and the report PDF under apps/web/public/); the six MDX entries
1454
- // are self-addressed because no `pageContributions` row declares
1455
- // `/projects`, `/projects/[slug]` or `/thanks/[slug]` yet (spec § 7
1456
- // finding 7 — declaring them changes the enabled-surface set and so the
1457
- // Pro scaffold's file set, a separate decision). Once those rows exist
1458
- // the six move to `pageContributions[].content` with no further
1459
- // migration. `generate-sample-report.py` keeps its root-level
1460
- // destination (finding 1 — AC7 forbids changing the Pro file set).
1467
+ // are self-addressed. Their `/projects`, `/projects/[slug]` and
1468
+ // `/thanks/[slug]` rows are declared by the templates that install them
1469
+ // (`template-manifest.ts`'s signal-collectors sample rows, #6646), not
1470
+ // here — a module contribution would change the enabled-surface set and
1471
+ // so the Pro scaffold's file set (spec 5618 § 7 finding 7).
1472
+ // `generate-sample-report.py` keeps its root-level destination
1473
+ // (finding 1 — AC7 forbids changing the Pro file set).
1461
1474
  installMap: {
1462
1475
  "packages/create-ailk/module-templates/signal-collectors/content/en/ProjectsList/projects.mdx": "content/en/ProjectsList/projects.mdx",
1463
1476
  "packages/create-ailk/module-templates/signal-collectors/content/en/Project/fit-check-funnel.mdx": "content/en/Project/fit-check-funnel.mdx",
@@ -1801,3 +1814,48 @@ export function paidModuleTemplateExclusions(snapshotRoots, repoRoot) {
1801
1814
  // question with the same resolution this answer was computed with (#5701).
1802
1815
  return [...importClosure(repoRoot, [...roots], seeds)].sort();
1803
1816
  }
1817
+ /** The scaffold's architecture linter, relative to the site root (#6649). */
1818
+ export const ARCHITECTURE_LINT_PATH = "tools/lint-architecture.ts";
1819
+ /**
1820
+ * What a scaffold needs so its `architecture.yaml` is enforced rather than
1821
+ * declared (#6649): the linter, the `architecture` + `preflight` root scripts
1822
+ * that run it, and a `.claude/settings.json` PostToolUse hook on Edit|Write
1823
+ * that runs it in-session. Returns one line per missing piece — empty means
1824
+ * all present. `verify-scaffold.mjs` fails on a non-empty result.
1825
+ */
1826
+ export function missingArchitectureEnforcement(siteDir) {
1827
+ const missing = [];
1828
+ if (!existsSync(join(siteDir, ARCHITECTURE_LINT_PATH))) {
1829
+ missing.push(ARCHITECTURE_LINT_PATH);
1830
+ }
1831
+ const readJson = (rel) => {
1832
+ const p = join(siteDir, rel);
1833
+ if (!existsSync(p))
1834
+ return undefined;
1835
+ try {
1836
+ return JSON.parse(readFileSync(p, "utf8"));
1837
+ }
1838
+ catch {
1839
+ return undefined;
1840
+ }
1841
+ };
1842
+ const scripts = readJson("package.json")
1843
+ ?.scripts ?? {};
1844
+ if (!scripts.architecture?.includes(ARCHITECTURE_LINT_PATH)) {
1845
+ missing.push(`package.json scripts.architecture (runs ${ARCHITECTURE_LINT_PATH})`);
1846
+ }
1847
+ if (!scripts.preflight?.includes("pnpm architecture")) {
1848
+ missing.push("package.json scripts.preflight (runs pnpm architecture)");
1849
+ }
1850
+ const postToolUse = readJson(".claude/settings.json")?.hooks?.PostToolUse ?? [];
1851
+ const hooked = postToolUse.some((entry) => {
1852
+ const tools = (entry.matcher ?? "").split("|");
1853
+ return (tools.includes("Edit") &&
1854
+ tools.includes("Write") &&
1855
+ (entry.hooks ?? []).some((h) => /\bpnpm\b.*\barchitecture\b/.test(h.command ?? "")));
1856
+ });
1857
+ if (!hooked) {
1858
+ missing.push(".claude/settings.json PostToolUse hook on Edit|Write (runs pnpm architecture)");
1859
+ }
1860
+ return missing;
1861
+ }
@@ -1,3 +1,4 @@
1
+ import type { ScaffoldOptions } from "./programmatic.js";
1
2
  /**
2
3
  * The recognized module vocabulary for the `--modules` selector.
3
4
  *
@@ -9,23 +10,52 @@
9
10
  */
10
11
  export declare const RECOGNIZED_MODULES: readonly ["marketing", "docs-blog", "multi-tenant", "workspace", "scheduling", "signal-collectors", "commerce"];
11
12
  export type ModuleName = (typeof RECOGNIZED_MODULES)[number];
13
+ /**
14
+ * Shapes a starter can be built from today (`--shape`, #6754 D1).
15
+ *
16
+ * Declared HERE rather than imported from `template-manifest.ts` for the
17
+ * reason `RECOGNIZED_MODULES` is: importing the registry closes the runtime
18
+ * cycle `template-names.ts`'s header records. `parse-args.test.ts` pins this
19
+ * list, `RESERVED_SHAPES` and `RECOGNIZED_DESIGNS` to their authorities
20
+ * (`STARTER_SHAPES`, `STARTER_DESIGNS`, `SHAPE_ROSTERS`).
21
+ */
22
+ export declare const RECOGNIZED_SHAPES: readonly ["organization-product", "organization-service", "local-business-service", "person-service"];
23
+ export type ShapeName = (typeof RECOGNIZED_SHAPES)[number];
24
+ /** Shapes the contract names but no release builds yet. */
25
+ export declare const RESERVED_SHAPES: readonly ["local-business-product"];
26
+ /** The `--design` vocabulary (#6754 D1) — `STARTER_DESIGNS`, pinned by test. */
27
+ export declare const RECOGNIZED_DESIGNS: readonly ["standard", "minimalism"];
28
+ export type DesignName = (typeof RECOGNIZED_DESIGNS)[number];
12
29
  export interface CliOptions {
13
30
  /** Positional target directory (the dir to scaffold into). Optional only
14
31
  * when `help` or `version` is set. */
15
32
  target: string | undefined;
16
33
  /**
17
34
  * The site template to install (`--template`), validated against
18
- * `RECOGNIZED_TEMPLATES` at parse time. Undefined when the flag is absent —
19
- * and a run naming no template scaffolds exactly what it did before the
20
- * flag existed (spec 5481 § 3 DD3).
35
+ * `RECOGNIZED_TEMPLATES` at parse time. Undefined when the flag is absent.
36
+ * The CLI never scaffolds a run naming neither a template nor a shape
37
+ * (#6754 D2 — refusal R1, or the shape prompt on a terminal).
21
38
  */
22
39
  template: string | undefined;
40
+ /** The starter's shape (`--shape`, #6754), normalized. Never set with `template`. */
41
+ shape?: ShapeName;
42
+ /** The starter's design (`--design`, #6754). Never set with `template`. */
43
+ design?: DesignName;
44
+ /**
45
+ * True when a scaffold run named neither `--shape` nor `--template` on a
46
+ * terminal: `resolveCliShape` must ask before anything is scaffolded.
47
+ */
48
+ needsShapePrompt: boolean;
23
49
  install: boolean;
24
50
  help: boolean;
25
51
  version: boolean;
26
- /** Selected modules (recognized: marketing, docs-blog, multi-tenant, scheduling).
27
- * Defaults to ['marketing'] when the flag is absent. */
28
- modules: string[];
52
+ /**
53
+ * Selected modules (recognized: marketing, docs-blog, multi-tenant,
54
+ * scheduling). `undefined` when `--modules` is absent — the key's level
55
+ * decides (#6759 D3); never read as `['marketing']` here. An empty or
56
+ * all-empty `--modules` value still names the Free set (`parseModules`).
57
+ */
58
+ modules: string[] | undefined;
29
59
  /** Explicitly requested route surfaces (`--surfaces`). Empty when the flag is
30
60
  * absent — the module set alone then decides (see surfaces.ts
31
61
  * `resolveSurfaces`). Validated, lowercased, deduped and sorted. */
@@ -47,20 +77,65 @@ export interface CliOptions {
47
77
  * value is validated through `parseModules` at parse time; cli.ts re-parses
48
78
  * it to the module list. Undefined when the flag is absent (scaffold mode). */
49
79
  syncArchitecture: string | undefined;
80
+ /**
81
+ * The licence key (`--license <key>`, #6683 D9), shape-checked at parse
82
+ * time. When set, `scaffold()` fetches paid bundles with it and writes it
83
+ * into the new scaffold (`ailk.key` + `apps/api/.env`). Absent when the
84
+ * flag is.
85
+ */
86
+ license?: string;
50
87
  }
51
88
  export declare class ParseError extends Error {
52
89
  constructor(message: string);
53
90
  }
91
+ /** The caller's terminal state (#6754 D2). */
92
+ export interface ParseEnv {
93
+ /** A human can answer a prompt: `process.stdin.isTTY === true` in cli.ts. */
94
+ interactive: boolean;
95
+ }
54
96
  export declare const helpText: string;
55
- export declare function parseCliArgs(argv: string[]): CliOptions;
97
+ /**
98
+ * Parse `create-ailk` argv. `env.interactive` defaults to false —
99
+ * fail-closed: a caller that does not assert a human is present gets refusal
100
+ * R1, never a prompt it cannot answer (#6754 D2).
101
+ */
102
+ export declare function parseCliArgs(argv: string[], env?: ParseEnv): CliOptions;
103
+ /** The streams the shape prompt reads and writes (a `PassThrough` pair in tests). */
104
+ export interface PromptIo {
105
+ input: NodeJS.ReadableStream;
106
+ output: NodeJS.WritableStream;
107
+ }
108
+ /**
109
+ * Ask once for a shape (#6754 D3): a number 1–4 or a shape name. A bad answer
110
+ * re-asks, naming what was wrong; the third bad answer, or a closed input,
111
+ * throws. There is no default — an empty line is a bad answer.
112
+ */
113
+ export declare function promptForShape(io: PromptIo): Promise<ShapeName>;
114
+ /**
115
+ * Fill `opts.shape` by prompting when, and only when, `needsShapePrompt` is
116
+ * set (#6754 D3). Help, version, sync and every run naming a shape or a
117
+ * template come back unchanged, with nothing written to `io.output`.
118
+ */
119
+ export declare function resolveCliShape(opts: CliOptions, io: PromptIo): Promise<CliOptions>;
120
+ /**
121
+ * The one mapping from parsed flags to `scaffold()` options (#6754 D4).
122
+ * `template`, `shape`, `design` and `license` are each spread only when set,
123
+ * so a `--template` run hands `scaffold()` the object it did before #6754.
124
+ *
125
+ * @throws ParseError when the shape prompt is unresolved or the target is
126
+ * unset — an unresolved prompt must never fall through to the bare overlay.
127
+ */
128
+ export declare function toScaffoldOptions(opts: CliOptions): ScaffoldOptions;
56
129
  /**
57
130
  * Parse a module CSV (the `--modules` or `--sync-architecture` value) into a
58
131
  * validated, normalized string[].
59
132
  *
60
133
  * Splits on `,`, trims and lowercases each entry, drops empties, and validates
61
- * each against RECOGNIZED_MODULES. An absent flag (or an all-empty value)
62
- * defaults to DEFAULT_MODULES (`['marketing']`) — reproducing today's scaffold.
134
+ * each against RECOGNIZED_MODULES. Takes a PRESENT value only — an ABSENT
135
+ * `--modules` flag is `undefined` (#6759 D3: the key's level decides) and
136
+ * never reaches this function; an all-empty value (`--modules ""`,
137
+ * `--modules ,`) still names the Free set, spelled inline here.
63
138
  *
64
139
  * @throws ParseError on an unrecognized module value, naming the recognized set.
65
140
  */
66
- export declare function parseModules(raw: string | undefined): string[];
141
+ export declare function parseModules(raw: string): string[];