create-ailk 0.5.0 → 0.6.1

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 (329) hide show
  1. package/README.md +55 -8
  2. package/component-catalog.json +336 -27
  3. package/component-catalog.md +25 -12
  4. package/dist/cli.js +54 -5
  5. package/dist/copy.d.ts +14 -0
  6. package/dist/copy.js +38 -1
  7. package/dist/lib/api-boot-assertion.d.ts +46 -0
  8. package/dist/lib/api-boot-assertion.js +70 -0
  9. package/dist/lib/extract-module-bundle.d.ts +20 -1
  10. package/dist/lib/extract-module-bundle.js +64 -5
  11. package/dist/lib/import-graph.d.ts +29 -0
  12. package/dist/lib/import-graph.js +140 -0
  13. package/dist/lib/module-license-gate.d.ts +6 -1
  14. package/dist/lib/module-license-gate.js +6 -1
  15. package/dist/lib/pro-callout.js +1 -1
  16. package/dist/module-architecture.d.ts +1 -0
  17. package/dist/module-architecture.js +253 -127
  18. package/dist/modules/commerce/0.6.0.tar.gz +0 -0
  19. package/dist/modules/docs-blog/0.6.0.tar.gz +0 -0
  20. package/dist/modules/multi-tenant/0.6.0.tar.gz +0 -0
  21. package/dist/modules/scheduling/0.6.0.tar.gz +0 -0
  22. package/dist/modules/signal-collectors/0.6.0.tar.gz +0 -0
  23. package/dist/modules/workspace/0.6.0.tar.gz +0 -0
  24. package/dist/programmatic.js +14 -10
  25. package/dist/surfaces.js +105 -7
  26. package/dist/template-manifest.d.ts +33 -0
  27. package/dist/template-manifest.js +99 -16
  28. package/dist/template-names.d.ts +1 -1
  29. package/dist/template-names.js +1 -0
  30. package/package.json +3 -2
  31. package/site-templates/marketing-site/DESIGN.md +148 -0
  32. package/site-templates/marketing-site/TEMPLATE-MANIFEST.json +22 -2
  33. package/site-templates/marketing-site/TEMPLATE-MANIFEST.md +9 -2
  34. package/site-templates/marketing-site/ailk-template.json +1 -1
  35. package/site-templates/marketing-site-free/DESIGN.md +148 -0
  36. package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.json +2 -2
  37. package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.md +1 -0
  38. package/site-templates/minimalism-site/DESIGN.md +148 -0
  39. package/site-templates/minimalism-site/TEMPLATE-MANIFEST.json +10 -2
  40. package/site-templates/minimalism-site/TEMPLATE-MANIFEST.md +47 -35
  41. package/site-templates/minimalism-site/ailk-template.json +2 -1
  42. package/site-templates/minimalism-site/assets/wordmark-placeholder.svg +28 -0
  43. package/site-templates/minimalism-site/content/en/HomePage/home.mdx +49 -19
  44. package/site-templates/saas-product/DESIGN.md +148 -0
  45. package/site-templates/simple-service/DESIGN.md +148 -0
  46. package/site-templates/simple-service/TEMPLATE-MANIFEST.json +240 -0
  47. package/site-templates/simple-service/TEMPLATE-MANIFEST.md +278 -0
  48. package/site-templates/simple-service/ailk-template.json +10 -0
  49. package/site-templates/simple-service/content/en/AboutPage/about.mdx +38 -0
  50. package/site-templates/simple-service/content/en/ContactPage/contact.mdx +67 -0
  51. package/site-templates/simple-service/content/en/FAQPage/faq.mdx +56 -0
  52. package/site-templates/simple-service/content/en/HomePage/home.mdx +85 -0
  53. package/site-templates/simple-service/content/en/Service/landscape-design.mdx +40 -0
  54. package/site-templates/simple-service/content/en/Service/lawn-maintenance.mdx +40 -0
  55. package/site-templates/simple-service/content/en/Service/seasonal-cleanup.mdx +40 -0
  56. package/site-templates/simple-service/content/en/ServicesList/services.mdx +72 -0
  57. package/site-templates/simple-service/provenance.json +4 -0
  58. package/templates/.env.example +72 -7
  59. package/templates/CLAUDE.md +2 -3
  60. package/templates/DESIGN.md +155 -0
  61. package/templates/README.md +42 -8
  62. package/templates/apps/api/.ailk/inbox/2026-09-20T14-57-31.552Z-fallback-1789916251590-037e9005.json +8 -0
  63. package/templates/apps/api/.ailk/inbox/2026-09-20T14-57-33.840Z-fallback-1789916253842-b52659e9.json +12 -0
  64. package/templates/apps/api/.ailk/inbox/2026-09-20T14-57-33.844Z-fallback-1789916253845-6b266f8c.json +12 -0
  65. package/templates/apps/api/.env.example +13 -0
  66. package/templates/apps/api/CLAUDE.md +26 -2
  67. package/templates/apps/api/jest.config.cjs +3 -0
  68. package/templates/apps/api/package.json +1 -0
  69. package/templates/apps/api/src/__tests__/commerce-claim-registration.test.ts +407 -0
  70. package/templates/apps/api/src/__tests__/module-exclusion.test.ts +83 -7
  71. package/templates/apps/api/src/__tests__/server.test.ts +471 -0
  72. package/templates/apps/api/src/__tests__/vercel-handler.test.ts +45 -0
  73. package/templates/apps/api/src/__tests__/workspace-module-registration.test.ts +2 -0
  74. package/templates/apps/api/src/config/index.ts +62 -0
  75. package/templates/apps/api/src/config/modules.ts +7 -3
  76. package/templates/apps/api/src/lib/__mocks__/prisma.ts +238 -2
  77. package/templates/apps/api/src/lib/__tests__/auth-email-budget.test.ts +143 -0
  78. package/templates/apps/api/src/lib/__tests__/content-adapter.test.ts +23 -0
  79. package/templates/apps/api/src/lib/__tests__/deliverable-asset-store.test.ts +125 -0
  80. package/templates/apps/api/src/lib/__tests__/error-serializer.test.ts +20 -0
  81. package/templates/apps/api/src/lib/__tests__/require-commerce-claim.test.ts +317 -0
  82. package/templates/apps/api/src/lib/__tests__/site.test.ts +238 -0
  83. package/templates/apps/api/src/lib/__tests__/stripe.test.ts +75 -0
  84. package/templates/apps/api/src/lib/auth-email-budget.ts +160 -0
  85. package/templates/apps/api/src/lib/content-adapter.ts +57 -31
  86. package/templates/apps/api/src/lib/deliverable-asset-store.ts +76 -0
  87. package/templates/apps/api/src/lib/error-serializer.ts +23 -3
  88. package/templates/apps/api/src/lib/outbound-http.ts +7 -2
  89. package/templates/apps/api/src/lib/require-commerce-claim.ts +250 -0
  90. package/templates/apps/api/src/lib/site.ts +208 -9
  91. package/templates/apps/api/src/lib/stripe.ts +66 -0
  92. package/templates/apps/api/src/middleware/__tests__/default-tenant.test.ts +182 -0
  93. package/templates/apps/api/src/middleware/__tests__/rate-limit.test.ts +42 -0
  94. package/templates/apps/api/src/middleware/rate-limit.ts +7 -1
  95. package/templates/apps/api/src/openapi/spec.ts +543 -2
  96. package/templates/apps/api/src/routes/auth/__tests__/auth-user.functional.test.ts +48 -0
  97. package/templates/apps/api/src/routes/auth/__tests__/transactional-email.test.ts +309 -0
  98. package/templates/apps/api/src/routes/auth/__tests__/user.test.ts +123 -0
  99. package/templates/apps/api/src/routes/auth/transactional-email.ts +273 -0
  100. package/templates/apps/api/src/routes/auth/user.ts +61 -0
  101. package/templates/apps/api/src/routes/checkout/__tests__/session.test.ts +434 -0
  102. package/templates/apps/api/src/routes/checkout/__tests__/sessions.test.ts +888 -0
  103. package/templates/apps/api/src/routes/checkout/index.ts +34 -0
  104. package/templates/apps/api/src/routes/checkout/session.ts +139 -0
  105. package/templates/apps/api/src/routes/checkout/sessions.ts +197 -0
  106. package/templates/apps/api/src/routes/content/__tests__/get-page.test.ts +554 -0
  107. package/templates/apps/api/src/routes/content/__tests__/list-pages.test.ts +108 -0
  108. package/templates/apps/api/src/routes/content/__tests__/search.test.ts +450 -0
  109. package/templates/apps/api/src/routes/content/get-page.ts +94 -12
  110. package/templates/apps/api/src/routes/content/index.ts +13 -73
  111. package/templates/apps/api/src/routes/content/list-pages.ts +15 -3
  112. package/templates/apps/api/src/routes/content/rate-limit.ts +15 -6
  113. package/templates/apps/api/src/routes/content/search.ts +129 -0
  114. package/templates/apps/api/src/routes/leads/__tests__/index.test.ts +447 -31
  115. package/templates/apps/api/src/routes/leads/index.ts +100 -13
  116. package/templates/apps/api/src/routes/project-listings/__tests__/configured-application.test.ts +51 -0
  117. package/templates/apps/api/src/routes/project-listings/__tests__/drafts.test.ts +351 -0
  118. package/templates/apps/api/src/routes/project-listings/__tests__/founder-identity.test.ts +51 -0
  119. package/templates/apps/api/src/routes/project-listings/__tests__/me.test.ts +5 -2
  120. package/templates/apps/api/src/routes/project-listings/__tests__/public.test.ts +4 -1
  121. package/templates/apps/api/src/routes/project-listings/__tests__/resume-email.test.ts +58 -0
  122. package/templates/apps/api/src/routes/project-listings/__tests__/site-answers.test.ts +107 -6
  123. package/templates/apps/api/src/routes/project-listings/__tests__/site-key.test.ts +87 -2
  124. package/templates/apps/api/src/routes/project-listings/__tests__/structured-address.test.ts +51 -0
  125. package/templates/apps/api/src/routes/project-listings/start.ts +5 -1
  126. package/templates/apps/api/src/routes/requests/__tests__/confirm.test.ts +686 -0
  127. package/templates/apps/api/src/routes/requests/confirm.ts +601 -0
  128. package/templates/apps/api/src/routes/requests/index.ts +54 -0
  129. package/templates/apps/api/src/routes/webhooks/README.md +265 -0
  130. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-dunning.test.ts +749 -0
  131. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-flow-checkout.test.ts +330 -0
  132. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-idempotency.test.ts +262 -0
  133. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-org-billing.test.ts +285 -0
  134. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-rate-limit.test.ts +213 -0
  135. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-request-paid.test.ts +301 -0
  136. package/templates/apps/api/src/routes/webhooks/__tests__/stripe.test.ts +648 -0
  137. package/templates/apps/api/src/routes/webhooks/index.ts +89 -0
  138. package/templates/apps/api/src/routes/webhooks/stripe.ts +1399 -0
  139. package/templates/apps/api/src/server.ts +439 -49
  140. package/templates/apps/api/src/services/__tests__/abandon-email.test.ts +39 -0
  141. package/templates/apps/api/src/services/__tests__/aeo-score.test.ts +217 -40
  142. package/templates/apps/api/src/services/__tests__/audit-log.test.ts +620 -0
  143. package/templates/apps/api/src/services/__tests__/consent.test.ts +2 -0
  144. package/templates/apps/api/src/services/__tests__/deliverable-fulfillment.test.ts +300 -5
  145. package/templates/apps/api/src/services/__tests__/deliverable-resend.test.ts +20 -0
  146. package/templates/apps/api/src/services/__tests__/dunning-policy.test.ts +368 -0
  147. package/templates/apps/api/src/services/__tests__/lead-routing.test.ts +160 -0
  148. package/templates/apps/api/src/services/__tests__/listing-config.test.ts +166 -0
  149. package/templates/apps/api/src/services/__tests__/project-listings.fence.test.ts +154 -0
  150. package/templates/apps/api/src/services/__tests__/public-site-resolver.test.ts +137 -0
  151. package/templates/apps/api/src/services/__tests__/request-confirm.test.ts +444 -0
  152. package/templates/apps/api/src/services/__tests__/revalidation.test.ts +238 -0
  153. package/templates/apps/api/src/services/__tests__/verified-email.test.ts +78 -0
  154. package/templates/apps/api/src/services/abandon-email.ts +8 -2
  155. package/templates/apps/api/src/services/aeo-score.ts +49 -12
  156. package/templates/apps/api/src/services/audit-log.ts +668 -0
  157. package/templates/apps/api/src/services/consent.ts +18 -0
  158. package/templates/apps/api/src/services/default-tenant.ts +70 -31
  159. package/templates/apps/api/src/services/deliverable-fulfillment.ts +141 -13
  160. package/templates/apps/api/src/services/dunning-policy.ts +294 -0
  161. package/templates/apps/api/src/services/entitlements.ts +80 -0
  162. package/templates/apps/api/src/services/lead-promotion.ts +13 -14
  163. package/templates/apps/api/src/services/lead-routing.ts +161 -2
  164. package/templates/apps/api/src/services/leads-inbox.ts +23 -2
  165. package/templates/apps/api/src/services/listing-config.ts +27 -9
  166. package/templates/apps/api/src/services/project-listings.ts +201 -6
  167. package/templates/apps/api/src/services/public-site-resolver.ts +106 -0
  168. package/templates/apps/api/src/services/request-confirm.ts +646 -0
  169. package/templates/apps/api/src/services/revalidation.ts +173 -0
  170. package/templates/apps/api/src/services/verified-email.ts +71 -0
  171. package/templates/apps/api/src/vercel-handler.ts +75 -35
  172. package/templates/apps/mcp/.env.example +17 -0
  173. package/templates/apps/mcp/CLAUDE.md +57 -24
  174. package/templates/apps/mcp/__tests__/aeo-cli-parity.test.ts +6 -0
  175. package/templates/apps/mcp/__tests__/audit.test.ts +137 -8
  176. package/templates/apps/mcp/__tests__/catalog-drift.test.ts +79 -36
  177. package/templates/apps/mcp/__tests__/get_offerings.test.ts +111 -2
  178. package/templates/apps/mcp/__tests__/get_pricing.test.ts +82 -2
  179. package/templates/apps/mcp/__tests__/http-transport.test.ts +541 -2
  180. package/templates/apps/mcp/__tests__/index.test.ts +39 -0
  181. package/templates/apps/mcp/__tests__/lib/audit-single-page-readiness-scan.test.ts +143 -0
  182. package/templates/apps/mcp/__tests__/lib/commerce-claim.test.ts +111 -0
  183. package/templates/apps/mcp/__tests__/lib/content-adapter-parity.test.ts +65 -0
  184. package/templates/apps/mcp/__tests__/lib/content-adapter.test.ts +188 -0
  185. package/templates/apps/mcp/__tests__/lib/fail-closed-tools.test.ts +165 -0
  186. package/templates/apps/mcp/__tests__/lib/public-workspace.test.ts +124 -0
  187. package/templates/apps/mcp/__tests__/list_pages.test.ts +116 -0
  188. package/templates/apps/mcp/__tests__/module-exclusion.test.ts +7 -1
  189. package/templates/apps/mcp/__tests__/parity.test.ts +10 -7
  190. package/templates/apps/mcp/__tests__/purchase-disabled.test.ts +89 -22
  191. package/templates/apps/mcp/__tests__/read_content.test.ts +322 -1
  192. package/templates/apps/mcp/__tests__/search_content.test.ts +105 -2
  193. package/templates/apps/mcp/__tests__/server.test.ts +67 -14
  194. package/templates/apps/mcp/__tests__/start_purchase.test.ts +252 -0
  195. package/templates/apps/mcp/__tests__/tools/purchase.test.ts +300 -123
  196. package/templates/apps/mcp/jest.config.cjs +13 -0
  197. package/templates/apps/mcp/package.json +2 -0
  198. package/templates/apps/mcp/src/abuse/index.ts +159 -24
  199. package/templates/apps/mcp/src/config/modules.ts +10 -5
  200. package/templates/apps/mcp/src/http-transport.ts +102 -29
  201. package/templates/apps/mcp/src/index.ts +73 -11
  202. package/templates/apps/mcp/src/lib/audit-single-page.ts +90 -3
  203. package/templates/apps/mcp/src/lib/commerce-claim.ts +94 -0
  204. package/templates/apps/mcp/src/lib/content-adapter.ts +113 -0
  205. package/templates/apps/mcp/src/lib/empty-content-adapter.ts +139 -0
  206. package/templates/apps/mcp/src/lib/prisma.ts +39 -0
  207. package/templates/apps/mcp/src/lib/public-workspace.ts +133 -0
  208. package/templates/apps/mcp/src/lib/stripe-tax-signal.ts +59 -0
  209. package/templates/apps/mcp/src/server.ts +59 -35
  210. package/templates/apps/mcp/src/tools/audit.ts +26 -2
  211. package/templates/apps/mcp/src/tools/get_business_hours.ts +4 -3
  212. package/templates/apps/mcp/src/tools/get_faq.ts +4 -3
  213. package/templates/apps/mcp/src/tools/get_locations.ts +5 -3
  214. package/templates/apps/mcp/src/tools/get_offerings.ts +16 -4
  215. package/templates/apps/mcp/src/tools/get_pricing.ts +25 -6
  216. package/templates/apps/mcp/src/tools/get_site_info.ts +4 -3
  217. package/templates/apps/mcp/src/tools/index.ts +6 -4
  218. package/templates/apps/mcp/src/tools/list_pages.ts +4 -3
  219. package/templates/apps/mcp/src/tools/purchase.ts +128 -45
  220. package/templates/apps/mcp/src/tools/read_content.ts +20 -6
  221. package/templates/apps/mcp/src/tools/search_content.ts +11 -4
  222. package/templates/apps/web/.env.example +71 -5
  223. package/templates/apps/web/CLAUDE.md +44 -0
  224. package/templates/apps/web/PRODUCT.md +86 -0
  225. package/templates/apps/web/app/.well-known/mcp.json/build-manifest.ts +18 -2
  226. package/templates/apps/web/app/.well-known/mcp.json/route.ts +11 -3
  227. package/templates/apps/web/app/[locale]/(auth)/__tests__/auth-pages.test.tsx +282 -0
  228. package/templates/apps/web/app/[locale]/(auth)/__tests__/password-reset.test.tsx +515 -0
  229. package/templates/apps/web/app/[locale]/(auth)/forgot-password/forgot-password-card.tsx +89 -0
  230. package/templates/apps/web/app/[locale]/(auth)/forgot-password/page.tsx +109 -0
  231. package/templates/apps/web/app/[locale]/(auth)/layout.tsx +92 -0
  232. package/templates/apps/web/app/[locale]/(auth)/reset-password/page.tsx +135 -0
  233. package/templates/apps/web/app/[locale]/(auth)/reset-password/reset-password-card.tsx +109 -0
  234. package/templates/apps/web/app/[locale]/{sign-in → (auth)/sign-in}/__tests__/page.test.tsx +48 -2
  235. package/templates/apps/web/app/[locale]/{sign-in → (auth)/sign-in}/page.tsx +20 -6
  236. package/templates/apps/web/app/[locale]/(auth)/sign-in/sign-in-card.tsx +125 -0
  237. package/templates/apps/web/app/[locale]/(auth)/sign-up/page.tsx +96 -0
  238. package/templates/apps/web/app/[locale]/(auth)/sign-up/sign-up-card.tsx +101 -0
  239. package/templates/apps/web/app/[locale]/(auth)/use-auth-card-flow.ts +102 -0
  240. package/templates/apps/web/app/[locale]/(auth)/verify-email/page.tsx +87 -0
  241. package/templates/apps/web/app/[locale]/(authed)/__tests__/gate.test.tsx +20 -10
  242. package/templates/apps/web/app/[locale]/(authed)/account/__tests__/page.test.tsx +84 -0
  243. package/templates/apps/web/app/[locale]/(authed)/account/actions.ts +58 -0
  244. package/templates/apps/web/app/[locale]/(authed)/account/page.tsx +63 -8
  245. package/templates/apps/web/app/[locale]/(authed)/layout.tsx +18 -1
  246. package/templates/apps/web/app/[locale]/cancellation/page.tsx +44 -0
  247. package/templates/apps/web/app/[locale]/layout.tsx +133 -87
  248. package/templates/apps/web/app/[locale]/purchase/__tests__/cancel.test.tsx +162 -0
  249. package/templates/apps/web/app/[locale]/purchase/__tests__/module-scope.test.ts +68 -0
  250. package/templates/apps/web/app/[locale]/purchase/__tests__/success.test.tsx +361 -0
  251. package/templates/apps/web/app/[locale]/purchase/cancel/page.tsx +115 -0
  252. package/templates/apps/web/app/[locale]/purchase/success/page.tsx +307 -0
  253. package/templates/apps/web/app/[locale]/returns/page.tsx +44 -0
  254. package/templates/apps/web/app/[locale]/shipping/page.tsx +44 -0
  255. package/templates/apps/web/app/api/revalidate/__tests__/route.test.ts +670 -0
  256. package/templates/apps/web/app/api/revalidate/route.ts +194 -0
  257. package/templates/apps/web/auth.ts +407 -8
  258. package/templates/apps/web/jest.config.cjs +8 -4
  259. package/templates/apps/web/lib/__tests__/auth-email.test.ts +214 -0
  260. package/templates/apps/web/lib/__tests__/auth-routes.test.ts +74 -0
  261. package/templates/apps/web/lib/__tests__/meeting-slugs.test.ts +72 -0
  262. package/templates/apps/web/lib/__tests__/site-theme.test.ts +135 -20
  263. package/templates/apps/web/lib/__tests__/structured-data.test.tsx +18 -1
  264. package/templates/apps/web/lib/auth-email.ts +318 -0
  265. package/templates/apps/web/lib/auth-env.ts +85 -0
  266. package/templates/apps/web/lib/auth-routes.ts +55 -0
  267. package/templates/apps/web/lib/meeting-slugs.ts +53 -0
  268. package/templates/apps/web/lib/site-brand.tsx +4 -8
  269. package/templates/apps/web/lib/telemetry-scrub.ts +5 -1
  270. package/templates/apps/web/messages/en.json +187 -0
  271. package/templates/apps/web/middleware.ts +1 -1
  272. package/templates/apps/web/package.json +2 -1
  273. package/templates/apps/web/src/lib/commerce-claim.ts +33 -0
  274. package/templates/apps/web/src/lib/commerce-sections.ts +93 -0
  275. package/templates/content/_site.mdx +18 -3
  276. package/templates/content/en/CancellationPolicyPage/cancellation.mdx +108 -0
  277. package/templates/content/en/ReturnsPolicyPage/returns.mdx +108 -0
  278. package/templates/content/en/ShippingPolicyPage/shipping.mdx +108 -0
  279. package/templates/database/CHANGELOG.md +149 -0
  280. package/templates/database/README.md +10 -3
  281. package/templates/database/__tests__/appointment.db.test.ts +106 -0
  282. package/templates/database/__tests__/artifact-content-store.db.test.ts +316 -0
  283. package/templates/database/__tests__/composite-fence.db.test.ts +206 -0
  284. package/templates/database/__tests__/fence-fan-out.db.test.ts +711 -0
  285. package/templates/database/__tests__/fixtures/appointment-create-probe.ts +79 -0
  286. package/templates/database/__tests__/fixtures/project-listing-consent-probe.ts +100 -0
  287. package/templates/database/__tests__/flow-workspace-key.db.test.ts +263 -0
  288. package/templates/database/__tests__/prefixed-ids.db.test.ts +85 -9
  289. package/templates/database/__tests__/project-listing-consent-at.db.test.ts +111 -0
  290. package/templates/database/__tests__/tenancy.test.ts +141 -0
  291. package/templates/database/config/schema.prisma +79 -2
  292. package/templates/database/content/schema.prisma +87 -11
  293. package/templates/database/inbox/schema.prisma +452 -9
  294. package/templates/database/jest.config.cjs +5 -3
  295. package/templates/database/migrations/20260915120000_project_listing_solution/migration.sql +15 -0
  296. package/templates/database/migrations/20260916120000_artifact_content_store/migration.sql +158 -0
  297. package/templates/database/migrations/20260917120000_callback_request_confirm/migration.sql +40 -0
  298. package/templates/database/migrations/20260918120000_add_appointment/migration.sql +67 -0
  299. package/templates/database/migrations/20260918120000_asset_metadata_columns/migration.sql +70 -0
  300. package/templates/database/migrations/20260919120000_flow_workspace_key/migration.sql +181 -0
  301. package/templates/database/migrations/20260919130000_flow_definition_admin_columns/migration.sql +172 -0
  302. package/templates/database/migrations/20260919130000_workspace_meetings/migration.sql +41 -0
  303. package/templates/database/migrations/20260919140000_inbox_workspace_key/migration.sql +185 -0
  304. package/templates/database/migrations/20260920120000_lead_handled_at/migration.sql +70 -0
  305. package/templates/database/migrations/20260920130000_lead_workspace_source_index/migration.sql +57 -0
  306. package/templates/database/migrations/20260921120000_deliverable_grant_workspace_key/migration.sql +68 -0
  307. package/templates/database/migrations/20260922120000_tenancy_fence/migration.sql +1067 -0
  308. package/templates/database/migrations/20260923120000_listing_capturing_magnet/migration.sql +210 -0
  309. package/templates/database/package.json +3 -2
  310. package/templates/database/tenancy.ts +86 -1
  311. package/templates/database/tsconfig.json +1 -0
  312. package/versions.json +34 -34
  313. package/templates/apps/api/src/routes/content/__tests__/create.test.ts +0 -253
  314. package/templates/apps/api/src/routes/content/__tests__/delete.test.ts +0 -215
  315. package/templates/apps/api/src/routes/content/__tests__/update.test.ts +0 -266
  316. package/templates/apps/api/src/routes/content/create.ts +0 -115
  317. package/templates/apps/api/src/routes/content/delete.ts +0 -82
  318. package/templates/apps/api/src/routes/content/update.ts +0 -112
  319. package/templates/apps/mcp/__tests__/create_page.test.ts +0 -202
  320. package/templates/apps/mcp/__tests__/delete_page.test.ts +0 -177
  321. package/templates/apps/mcp/__tests__/update_page.test.ts +0 -196
  322. package/templates/apps/mcp/src/tools/create_page.ts +0 -96
  323. package/templates/apps/mcp/src/tools/delete_page.ts +0 -74
  324. package/templates/apps/mcp/src/tools/update_page.ts +0 -92
  325. package/templates/apps/web/app/[locale]/sign-in/sign-in-card.tsx +0 -123
  326. package/templates/apps/web/public/logo-dark.svg +0 -21
  327. package/templates/apps/web/public/logo-light.svg +0 -21
  328. /package/templates/apps/web/app/[locale]/{sign-in → (auth)/sign-in}/__tests__/next-path.test.ts +0 -0
  329. /package/templates/apps/web/app/[locale]/{sign-in → (auth)/sign-in}/next-path.ts +0 -0
@@ -21,8 +21,8 @@
21
21
  * `architecture.yaml` template files — a fixed template IS the drift this
22
22
  * removes.
23
23
  */
24
- import { readFileSync, readdirSync } from "node:fs";
25
- import { dirname, join, sep } from "node:path";
24
+ import { sep } from "node:path";
25
+ import { importClosure } from "./lib/import-graph.js";
26
26
  import { PAID_MODULES } from "./lib/module-tier.js";
27
27
  import { RECOGNIZED_MODULES } from "./parse-args.js";
28
28
  /**
@@ -124,6 +124,31 @@ export const ARCHITECTURE_BASE = {
124
124
  },
125
125
  ],
126
126
  };
127
+ /**
128
+ * The workspace asset store (#5854), CO-OWNED by the `workspace` and
129
+ * `multi-tenant` slices.
130
+ *
131
+ * `server.ts` registers both of its routes under
132
+ * `isModuleEnabled("workspace") || isModuleEnabled("multi-tenant")`, and a file
133
+ * behind a two-module disjunction must be deliverable by BOTH bundles — or
134
+ * whichever module lacks it throws ERR_MODULE_NOT_FOUND during `build()`. One
135
+ * array spread into both `ownedFiles` lists makes the two copies incapable of
136
+ * drifting, which matters because a drift only surfaces in a scaffolded
137
+ * customer repo rather than here.
138
+ *
139
+ * `routes/assets/index.ts` is listed although it registers nothing: the
140
+ * template-exclusion closure runs over IMPORTERS, so a shared-constants module
141
+ * that is imported BY the routes and imports neither of them is never reached
142
+ * from them, and an unlisted one would ship into the keyless Free starter.
143
+ */
144
+ const ASSET_STORE_FILES = [
145
+ "apps/api/src/routes/assets/index.ts",
146
+ "apps/api/src/routes/assets/upload.ts",
147
+ "apps/api/src/routes/assets/read.ts",
148
+ // The manage routes — list, PATCH, DELETE (#6093 D16).
149
+ "apps/api/src/routes/assets/manage.ts",
150
+ "apps/api/src/lib/asset-store.ts",
151
+ ];
127
152
  /**
128
153
  * The per-module slices. Authored for every `RECOGNIZED_MODULES` value; only
129
154
  * `marketing` (the default) is validated end-to-end against a golden.
@@ -246,6 +271,11 @@ export const MODULE_SLICES = {
246
271
  // The Fumadocs source pair — both whole, both loaders (D3).
247
272
  "apps/web/source.config.ts",
248
273
  "apps/web/lib/source.ts",
274
+ // The runtime source `lib/source.ts` resolves to under
275
+ // CONTENT_ADAPTER=database (#5878). Listed explicitly: the exclusion
276
+ // closure grows over DEPENDENTS, not dependencies, so being imported by
277
+ // `lib/source.ts` does not pull this file into the bundle by itself.
278
+ "apps/web/lib/runtime-source.ts",
249
279
  // The route adapters and the jest stub for the codegen output.
250
280
  "apps/web/lib/blog-list-data.ts",
251
281
  "apps/web/lib/blog-post-data.ts",
@@ -656,6 +686,11 @@ export const MODULE_SLICES = {
656
686
  "apps/api/src/routes/workspaces/index.ts",
657
687
  "apps/api/src/routes/workspaces/sessions.ts",
658
688
  "apps/api/src/routes/workspaces/config.ts",
689
+ // Co-owned with `workspace` (#5853): the content-write scope is gated on
690
+ // content-write AND (workspace || multi-tenant) and this file imports
691
+ // lib/tenant-db.ts, so each tenancy slice must deliver it.
692
+ "apps/api/src/routes/workspaces/content.ts",
693
+ ...ASSET_STORE_FILES,
659
694
  "apps/api/src/routes/billing/index.ts",
660
695
  "apps/api/src/routes/billing/portal.ts",
661
696
  "apps/api/src/routes/billing/read.ts",
@@ -672,8 +707,42 @@ export const MODULE_SLICES = {
672
707
  "apps/api/src/middleware/tenant.ts",
673
708
  "apps/api/src/services/tenant-context.ts",
674
709
  "apps/api/src/services/waitlist-dashboard.ts",
710
+ // #6258 — the file waitlist-dashboard.ts imports for the pinned
711
+ // platform-operator read scope. It rides BOTH slices for the same
712
+ // reason its importer does: an unlisted import target breaks a
713
+ // signal-collectors-without-multi-tenant scaffold at build() time.
714
+ "apps/api/src/services/waitlist-operator-reads.ts",
715
+ // #6204/#6280 CI fix — `listUnhandledMessages`/`markMessageHandled`
716
+ // (the "Needs-you" message read/write over `tenantDb(tenant).leads`)
717
+ // moved here off `services/leads-inbox.ts`, a BASE-tier file every
718
+ // scaffold ships. Importing `lib/tenant-db.ts` from that base file
719
+ // walked `paidModuleTemplateExclusions()`'s companion closure
720
+ // (`lib/import-graph.ts`) BACKWARD into `leads-inbox.ts` itself and
721
+ // then into every one of `apps/api/src/{server,cli,index,
722
+ // vercel-handler}.ts` — all of which reach it through
723
+ // `routes/leads/list.ts` — dropping them from a keyless scaffold
724
+ // (`__tests__/paid-module-exclusions.test.ts`'s `MUST_SHIP` guard,
725
+ // #5678's cascade shape recurring a third time).
726
+ //
727
+ // #6216 — now reached: `routes/workspaces/messages.ts` (below)
728
+ // consumes `getMessage` alongside the two functions above. That route
729
+ // registers under `isModuleEnabled("workspace") ||
730
+ // isModuleEnabled("multi-tenant")` — the SAME gate
731
+ // `workspaces/general.ts`/`members.ts` register under, NOT the
732
+ // multi-tenant-only family `workspaces/meetings.ts`/`config.ts` sit
733
+ // in — so this file and `routes/workspaces/messages.ts` are now
734
+ // CO-OWNED with `workspace` too (see that slice's entry below), the
735
+ // asset-store precedent: a file behind an OR gate must be
736
+ // deliverable by BOTH bundles.
737
+ "apps/api/src/services/inbox-messages.ts",
738
+ "apps/api/src/routes/workspaces/messages.ts",
675
739
  "apps/api/src/lib/tenant-db.ts",
676
740
  "apps/api/src/lib/ws-token.ts",
741
+ // #6157 D16 — the magnet Admin authoring surface, co-owned with
742
+ // `signal-collectors` below for the SAME reason #5677 co-owns the
743
+ // review surface under both: its scope is registered under the
744
+ // widened `multi-tenant || signal-collectors` gate.
745
+ "apps/api/src/routes/magnets/index.ts",
677
746
  "apps/web/app/[locale]/(authed)/waitlist/page.tsx",
678
747
  "apps/web/app/[locale]/(authed)/waitlist/[experimentId]/page.tsx",
679
748
  "apps/web/app/[locale]/(authed)/waitlist/[experimentId]/signups/[leadId]/page.tsx",
@@ -769,6 +838,16 @@ export const MODULE_SLICES = {
769
838
  "apps/web/app/[locale]/(authed)/admin/team/page.tsx",
770
839
  "apps/api/src/routes/workspaces/general.ts",
771
840
  "apps/api/src/routes/workspaces/members.ts",
841
+ // Co-owned with `multi-tenant` (#6216) — see that slice's entry: the
842
+ // route registers under the SAME workspace||multi-tenant gate as the
843
+ // two lines above, and its service function imports `lib/tenant-db.ts`
844
+ // (a multi-tenant-owned file), so both must be deliverable by either
845
+ // bundle alone.
846
+ "apps/api/src/routes/workspaces/messages.ts",
847
+ "apps/api/src/services/inbox-messages.ts",
848
+ // Co-owned with `multi-tenant` (#5853) — see that slice's entry.
849
+ "apps/api/src/routes/workspaces/content.ts",
850
+ ...ASSET_STORE_FILES,
772
851
  ],
773
852
  // patches — the dependency add that delivers the shared package to the
774
853
  // buyer's apps/web, mirroring docs-blog's own fumadocs-schema merge-keys
@@ -951,12 +1030,67 @@ export const MODULE_SLICES = {
951
1030
  "apps/api/src/services/scheduling/index.ts",
952
1031
  "apps/api/src/services/scheduling/cal-provider.ts",
953
1032
  "apps/api/src/services/scheduling/types.ts",
1033
+ // #6182 (S9a) — the Cal adapter's own suite. Individually, never as a
1034
+ // glob (§ D12 above, property 1: a glob entry is a silent no-op, so
1035
+ // `__tests__/**` would ship no test at all to a keyed scaffold).
1036
+ "apps/api/src/services/scheduling/__tests__/cal-provider.test.ts",
954
1037
  "apps/mcp/src/tools/list_availability.ts",
955
1038
  "apps/mcp/src/tools/get_event_meta.ts",
956
1039
  "apps/mcp/src/tools/create_booking.ts",
957
1040
  "apps/web/app/[locale]/meet/page.tsx",
958
1041
  "apps/web/app/[locale]/meet/[slug]/page.tsx",
959
1042
  "apps/web/app/[locale]/meet/confirmed/page.tsx",
1043
+ // #6085 (brief H7) — the six files the webhook receiver + the
1044
+ // tenant-guarded appointments read add. Individually, never as a
1045
+ // glob (§ D12 / this card's own comment above, property 1: a glob
1046
+ // entry is a silent no-op, so __tests__/** would ship no test at all
1047
+ // to a keyed scaffold). `apps/api/src/routes/webhooks/index.ts` is
1048
+ // NOT added — it is the mixed barrel that also registers the Stripe
1049
+ // receiver, the same "mixed barrel is never listed" precedent this
1050
+ // slice already records for `routes/project-listings/index.ts`.
1051
+ // `apps/api/src/routes/schedule/index.ts` is already listed above and
1052
+ // stays (it re-exports `listAppointmentsRoute` alongside the three
1053
+ // anonymous routes it already re-exports).
1054
+ "apps/api/src/routes/webhooks/calcom.ts",
1055
+ "apps/api/src/routes/webhooks/__tests__/calcom.test.ts",
1056
+ "apps/api/src/services/scheduling/appointments.ts",
1057
+ "apps/api/src/services/scheduling/__tests__/appointments.test.ts",
1058
+ "apps/api/src/routes/schedule/appointments.ts",
1059
+ "apps/api/src/routes/schedule/__tests__/appointments.test.ts",
1060
+ // #6086 (brief H7) — the SITE's appointments page, the visible half of
1061
+ // the read above. The co-located suite is listed EXPLICITLY alongside
1062
+ // its page: `EXCLUDE_TEMPLATE_DIRS` below drops only the three
1063
+ // top-level `apps/web/**/__tests__` directories, and the import-graph
1064
+ // closure walks FORWARD from an owned file — a test that imports
1065
+ // `../page` is a dependent, not a companion, so it is never swept
1066
+ // along. Without the second entry a keyless scaffold would carry a
1067
+ // test for a page it does not have.
1068
+ "apps/web/app/[locale]/(authed)/appointments/page.tsx",
1069
+ "apps/web/app/[locale]/(authed)/appointments/__tests__/page.test.tsx",
1070
+ // #6183 S9b — the enabled-meeting-slugs gate. `meetings.ts` is its own
1071
+ // file (not folded into `routes/workspaces/config.ts`, which is
1072
+ // `workspace`/`multi-tenant`-owned) precisely because its GET reaches
1073
+ // `services/scheduling/` — the SAME reason `routes/schedule/
1074
+ // appointments.ts` above is its own file rather than a row on an
1075
+ // existing route. `lib/public-meetings-config.ts` is the public-read
1076
+ // boundary `routes/schedule/meeting-types.ts` (the anonymous read,
1077
+ // already reached via the already-listed `routes/schedule/index.ts`)
1078
+ // calls into.
1079
+ "apps/api/src/routes/workspaces/meetings.ts",
1080
+ "apps/api/src/routes/workspaces/__tests__/meetings.test.ts",
1081
+ "apps/api/src/lib/public-meetings-config.ts",
1082
+ "apps/api/src/routes/schedule/meeting-types.ts",
1083
+ "apps/api/src/routes/schedule/__tests__/meeting-types.test.ts",
1084
+ // meetings.ts is the FIRST scheduling-gated route to use the generic
1085
+ // tenantDb() scope layer directly (its sibling, appointments.ts, does
1086
+ // its own scoped read in services/scheduling/appointments.ts instead)
1087
+ // — and `workspaceMeetings` is now in architecture.yaml's tenant-scope
1088
+ // forbidden_pattern (#6183), so meetings.ts cannot bypass tenantDb()
1089
+ // with a raw prisma call. Co-owned with `multi-tenant` below (the
1090
+ // SAME two files, same reason `content.ts`'s own comment there
1091
+ // records: "each tenancy slice must deliver it").
1092
+ "apps/api/src/lib/tenant-db.ts",
1093
+ "apps/api/src/services/tenant-context.ts",
960
1094
  ],
961
1095
  // pageContributions (spec 5478; parent § D6 shape 1) — the booker, the
962
1096
  // per-booking-type page and the confirmation page, whose route files
@@ -966,6 +1100,10 @@ export const MODULE_SLICES = {
966
1100
  { route: "/meet" },
967
1101
  { route: "/meet/[slug]" },
968
1102
  { route: "/meet/confirmed" },
1103
+ // #6086 — the authed appointments page. Bracket (roster) grammar and no
1104
+ // `content` key, for the same reason the three /meet rows carry none:
1105
+ // it renders from `/v1/schedule/appointments`, not from an MDX file.
1106
+ { route: "/appointments" },
969
1107
  ],
970
1108
  // patches (#5581 U3, D5) — delivers the extracted component package to a
971
1109
  // keyed scaffold's apps/web, mirroring the signal-collectors slice's
@@ -1183,6 +1321,28 @@ export const MODULE_SLICES = {
1183
1321
  "apps/api/src/routes/waitlist-experiments/signups.ts",
1184
1322
  "apps/api/src/routes/waitlist-experiments/respond.ts",
1185
1323
  "apps/api/src/services/waitlist-dashboard.ts",
1324
+ // #6258 — the file waitlist-dashboard.ts imports for the pinned
1325
+ // platform-operator read scope. It rides BOTH slices for the same
1326
+ // reason its importer does: an unlisted import target breaks a
1327
+ // signal-collectors-without-multi-tenant scaffold at build() time.
1328
+ "apps/api/src/services/waitlist-operator-reads.ts",
1329
+ // #6157 D14/D16 — the magnet Admin authoring surface's own sibling
1330
+ // tenant scope is gated `multi-tenant || signal-collectors` (D4,
1331
+ // the SAME expression this review-surface block co-owns files
1332
+ // under), so both its route file AND `lib/tenant-db.ts` (the ONE
1333
+ // data path it reads/writes through, FR3) must be delivered here
1334
+ // too. `lib/tenant-db.ts` is ALSO listed under `multi-tenant` above
1335
+ // — additive, not a transfer (the same reasoning this array's own
1336
+ // header comment already states for every other file in it).
1337
+ //
1338
+ // The closure stays tight WITHOUT dragging in `tenant-context.ts` or
1339
+ // the multi-tenant guard assembly behind it, because `tenant-db.ts`'s
1340
+ // own type import was retargeted from `tenant-context.js` to the
1341
+ // BASE-tree `services/default-tenant.js` in this same unit (D15) —
1342
+ // the identical one-line class of move #5677 made for
1343
+ // `waitlist-dashboard.ts` two paragraphs above this one.
1344
+ "apps/api/src/routes/magnets/index.ts",
1345
+ "apps/api/src/lib/tenant-db.ts",
1186
1346
  "apps/api/src/routes/project-listings/get.ts",
1187
1347
  "apps/api/src/routes/project-listings/list.ts",
1188
1348
  "apps/api/src/routes/project-listings/patch.ts",
@@ -1370,18 +1530,14 @@ export const MODULE_SLICES = {
1370
1530
  },
1371
1531
  },
1372
1532
  packages: {
1373
- // Duplicated VERBATIM from the multi-tenant slice's own "stripe-client"
1374
- // entry (§7 Q1 — a multi-tenant deployment using the Stripe billing
1375
- // portal or org-billing webhook routing also installs commerce, so
1376
- // both slices can be selected together) — the same order-independence
1377
- // reason the multi-tenant/scheduling slices state for `validation`
1378
- // below: `deriveArchitecture` merges `packages` blocks with
1379
- // `Object.assign`, so two slices declaring this key differently would
1380
- // make the derivation depend on module order.
1381
- "stripe-client": {
1382
- description: "Stripe SDK wrapper + webhook signature verification",
1383
- may_import_from: ["packages/validation"],
1384
- },
1533
+ // `stripe-client` is deliberately NOT declared here (#5823). It was,
1534
+ // duplicated verbatim from the multi-tenant slice, while the package was
1535
+ // paid and commerce-owned. Since #5810 it is `commercial_tier: oss`,
1536
+ // published public, and since #5812 its sole `apps/api` importer
1537
+ // (`lib/stripe.ts`) is a base file — so the package is base, not a
1538
+ // commerce slice member. The `packages/stripe-client` entries in the
1539
+ // `may_import_from` lists above and in the base/multi-tenant slices are
1540
+ // unaffected: those declare who may reach the package, not who owns it.
1385
1541
  // Duplicated VERBATIM from the marketing slice for the same
1386
1542
  // order-independence reason the multi-tenant/scheduling slices state.
1387
1543
  validation: {
@@ -1402,28 +1558,36 @@ export const MODULE_SLICES = {
1402
1558
  // ownedFiles (S1, #5088). SOURCE files only (#5182 D6) — no __tests__/,
1403
1559
  // no .stories.tsx, no .text.ts... except .text.ts siblings ARE source
1404
1560
  // (they ship as runtime copy modules, not test fixtures), so the ten
1405
- // annotated below are listed. 42 in all: 9 apps/api + 26 packages/ui
1561
+ // annotated below are listed. 36 in all: 4 apps/api + 26 packages/ui
1406
1562
  // (15 components + 10 .text.ts siblings + this slice's own
1407
1563
  // sections/slices/commerce.ts) + 7 apps/web.
1564
+ //
1565
+ // THE PRIMITIVES LEFT THIS SLICE (D-64, epic #5770, #5796). The checkout
1566
+ // launcher, the Stripe webhook receiver, customer mapping and the
1567
+ // `lib/stripe.ts` shim are BASE TREE now: `apps/api/src/server.ts`
1568
+ // registers them unconditionally and gates them at CALL time on the JWT
1569
+ // `commerce` claim (`apps/api/src/lib/require-commerce-claim.ts`), so a
1570
+ // keyless scaffold must CARRY them. Claiming them here is what deleted
1571
+ // them from that scaffold while the server still loaded them —
1572
+ // ERR_MODULE_NOT_FOUND inside build(), every route 500ing, which is the
1573
+ // exact defect `tools/lint-slice-registration.ts` (#5701) exists to
1574
+ // catch. The six that left: lib/stripe.ts,
1575
+ // routes/checkout/{index,sessions}.ts, routes/webhooks/{index,stripe}.ts
1576
+ // and routes/webhooks/README.md. The four below STAY — they are commerce
1577
+ // OVERLAY, still registered behind `isModuleEnabled("commerce")` and
1578
+ // still carrying their `// oss: false` markers.
1408
1579
  ownedFiles: [
1409
- "apps/api/src/lib/stripe.ts",
1410
- "apps/api/src/routes/checkout/index.ts",
1411
- "apps/api/src/routes/checkout/sessions.ts",
1412
- "apps/api/src/routes/webhooks/index.ts",
1413
- "apps/api/src/routes/webhooks/stripe.ts",
1414
- // README.md documents the Stripe webhook receiver — not a test/
1415
- // generated file, and its absence is exactly what left a stray
1416
- // apps/api/src/routes/webhooks/ directory in a keyless templates/
1417
- // snapshot (empirically found, #5364 build pass): the import-graph
1418
- // closure only scans source extensions, never markdown, so once
1419
- // index.ts and stripe.ts are excluded this is the one file left
1420
- // behind. Same defect class #5366 found and fixed the same way for
1421
- // routes/flows/README.md — see that entry above.
1422
- "apps/api/src/routes/webhooks/README.md",
1423
1580
  "apps/api/src/routes/flow-checkouts/index.ts",
1424
1581
  "apps/api/src/routes/flows/recommender.ts",
1425
1582
  "apps/api/src/services/recommender-capture.ts",
1426
1583
  "apps/api/src/services/flow-checkouts.ts",
1584
+ // #6038 — the buyer-scoped subscription-status route pair (the
1585
+ // update-your-card banner's read + portal handoff). Commerce OVERLAY,
1586
+ // same posture as the four flow-checkouts/recommender entries above.
1587
+ "apps/api/src/routes/subscription/index.ts",
1588
+ "apps/api/src/routes/subscription/me.ts",
1589
+ "apps/api/src/routes/subscription/portal.ts",
1590
+ "apps/api/src/services/subscription.ts",
1427
1591
  // #5581 U5 — the fifteen commerce components (+ ten .text.ts extractors
1428
1592
  // + the slice's own re-export entry point) moved to
1429
1593
  // packages-paid/ui-commerce; the package is delivered to a keyed
@@ -1457,6 +1621,13 @@ export const MODULE_SLICES = {
1457
1621
  "packages/create-ailk/module-templates/commerce/.claude/skills/scaffold-commerce/templates/portal-route.template.ts": ".claude/skills/scaffold-commerce/templates/portal-route.template.ts",
1458
1622
  "packages/create-ailk/module-templates/commerce/.claude/skills/scaffold-commerce/templates/stripe-config.template.ts": ".claude/skills/scaffold-commerce/templates/stripe-config.template.ts",
1459
1623
  "packages/create-ailk/module-templates/commerce/.claude/skills/scaffold-commerce/templates/subscription-route.template.ts": ".claude/skills/scaffold-commerce/templates/subscription-route.template.ts",
1624
+ // The commerce-boundary rule (#6039/#6070, this entry #6041): ships to
1625
+ // a commerce-keyed scaffold's project root so an agent working there
1626
+ // reads the money/live-mode/personal-data classification before it
1627
+ // acts. One more literal entry alongside the ten scaffold-commerce
1628
+ // skill entries above, for the same reason — a directory source is
1629
+ // rejected by `validateInstallMap`.
1630
+ "packages/create-ailk/module-templates/commerce/.claude/rules/commerce-boundary.md": ".claude/rules/commerce-boundary.md",
1460
1631
  },
1461
1632
  // patches (#5581 U5, D5) — delivers the extracted component package to a
1462
1633
  // keyed scaffold's apps/web, mirroring the workspace slice's identical
@@ -1565,9 +1736,56 @@ export function coOwnedModuleDestinations() {
1565
1736
  }
1566
1737
  return coOwned;
1567
1738
  }
1739
+ // Template-relative directories excluded from the snapshot outright (#4154).
1740
+ // - apps/web/__tests__ — this repo's own harness tests. Several import route
1741
+ // modules across multiple surfaces (resources-downloads-integrations-phase2,
1742
+ // standalone-informational-routes, routes/blog-route, blog-dir-resolution),
1743
+ // so they fail outright in a scaffold whose surfaces are gated off. The
1744
+ // co-located app/[locale]/<surface>/__tests__ suites travel with their
1745
+ // surface and are unaffected.
1746
+ // - apps/web/app/[locale]/__tests__ — same class: page-renderer-migration
1747
+ // reaches across surfaces (`../launch-service/page`), so it breaks in a
1748
+ // scaffold that gated launch-service off. The PER-SURFACE co-located
1749
+ // suites (app/[locale]/<surface>/__tests__) import only their own route and
1750
+ // travel with their surface, so they are kept.
1751
+ // - apps/web/content — the blog/docs sample posts (the launching-ailk class).
1752
+ // Replaced by neutral stubs from template-overlay/.
1753
+ // - apps/web/app/[locale]/(authed)/edit — the Pro content host's editor
1754
+ // routes (#5977; added to apps/web by #5957, spec 5872 FR1/FR2). Both
1755
+ // pages are `// oss: false` and the [type]/[slug] page imports
1756
+ // `@working-theory/admin-ui`, which a keyless (Free) scaffold does not
1757
+ // carry — so shipping them puts two files importing an absent package
1758
+ // into the scaffold and fails both co-located `__tests__` suites under
1759
+ // verify-scaffold's `apps/web` jest run. The directory is taken whole,
1760
+ // `__tests__` with it, since a test of an excluded route has nothing to
1761
+ // test.
1762
+ //
1763
+ // WHY AN EXCLUSION AND NOT A MODULE SLICE. Spec 5872 D11 settled the two
1764
+ // constraints that rule out the alternatives, quoted rather than
1765
+ // re-derived:
1766
+ // 1. "content-write cannot be a MODULE_SLICES key"
1767
+ // (`module-architecture.ts:214-222` — a key would make
1768
+ // `--modules content-write` a valid selection).
1769
+ // 2. "the workspace slice is the wrong owner" (#5853 §4.2/D14 — it
1770
+ // would bind the Pro editor to a Pro Plus bundle).
1771
+ // So there is no correct `ownedFiles` owner for these files today. This
1772
+ // entry is the INTERIM: a flat exclusion that keeps the keyless scaffold
1773
+ // honest until a content-write delivery path exists, at which point the
1774
+ // routes move to that path's owner and this entry comes back out. The
1775
+ // routes stay registered in `ROUTE_SINCE` (src/surfaces.ts) meanwhile —
1776
+ // see that entry, and sync-routes' AC-5 coverage test, which reads this
1777
+ // list so the resulting ROUTE_SINCE-vs-template absence is justified
1778
+ // rather than reported stale.
1779
+ export const EXCLUDE_TEMPLATE_DIRS = [
1780
+ "apps/web/__tests__",
1781
+ "apps/web/app/__tests__",
1782
+ "apps/web/app/[locale]/__tests__",
1783
+ "apps/web/app/[locale]/(authed)/edit",
1784
+ "apps/web/content",
1785
+ ];
1568
1786
  export function paidModuleTemplateExclusions(snapshotRoots, repoRoot) {
1569
1787
  const roots = new Set(snapshotRoots);
1570
- const excluded = new Set();
1788
+ const seeds = new Set();
1571
1789
  for (const moduleName of PAID_MODULES) {
1572
1790
  for (const owned of MODULE_SLICES[moduleName]?.ownedFiles ?? []) {
1573
1791
  const rel = owned.split(sep).join("/");
@@ -1575,103 +1793,11 @@ export function paidModuleTemplateExclusions(snapshotRoots, repoRoot) {
1575
1793
  continue;
1576
1794
  if (rel.includes("*"))
1577
1795
  continue;
1578
- excluded.add(rel);
1796
+ seeds.add(rel);
1579
1797
  }
1580
1798
  }
1581
- // Companion closure by import graph, to a fixed point — never a filename
1582
- // stem rule (#5182 D7), which misses eleven files and over-marks three.
1583
- const candidates = listFilesUnder(repoRoot, [...roots]);
1584
- for (;;) {
1585
- let grew = false;
1586
- for (const file of candidates) {
1587
- if (excluded.has(file))
1588
- continue;
1589
- const imports = relativeImportsOf(join(repoRoot, file));
1590
- for (const spec of imports) {
1591
- const target = resolveRelativeImport(file, spec, candidates);
1592
- if (target !== undefined && excluded.has(target)) {
1593
- excluded.add(file);
1594
- grew = true;
1595
- break;
1596
- }
1597
- }
1598
- }
1599
- if (!grew)
1600
- break;
1601
- }
1602
- return [...excluded].sort();
1603
- }
1604
- const SOURCE_EXTS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
1605
- /** Every source file under the given repo-relative roots, as "/"-joined paths. */
1606
- function listFilesUnder(repoRoot, roots) {
1607
- const out = new Set();
1608
- const skip = new Set(["node_modules", ".next", "dist", ".turbo", ".source"]);
1609
- const stack = roots.map((r) => r);
1610
- while (stack.length > 0) {
1611
- const rel = stack.pop();
1612
- const abs = join(repoRoot, rel);
1613
- let entries;
1614
- try {
1615
- entries = readdirSync(abs, { withFileTypes: true });
1616
- }
1617
- catch {
1618
- continue;
1619
- }
1620
- for (const entry of entries) {
1621
- if (skip.has(entry.name))
1622
- continue;
1623
- const childRel = `${rel}/${entry.name}`;
1624
- if (entry.isDirectory())
1625
- stack.push(childRel);
1626
- else if (SOURCE_EXTS.some((e) => entry.name.endsWith(e)))
1627
- out.add(childRel);
1628
- }
1629
- }
1630
- return out;
1631
- }
1632
- /** The relative import specifiers a source file names (static imports + re-exports). */
1633
- function relativeImportsOf(absPath) {
1634
- let src;
1635
- try {
1636
- src = readFileSync(absPath, "utf8");
1637
- }
1638
- catch {
1639
- return [];
1640
- }
1641
- const out = [];
1642
- for (const m of src.matchAll(/(?:^|\n)\s*(?:import|export)[\s\S]{0,400}?from\s*["'](\.[^"']*)["']/g))
1643
- out.push(m[1]);
1644
- for (const m of src.matchAll(/\bimport\s*\(\s*["'](\.[^"']*)["']\s*\)/g))
1645
- out.push(m[1]);
1646
- return out;
1647
- }
1648
- /**
1649
- * Resolve a relative specifier against the candidate set. TypeScript ESM writes
1650
- * `./x.js` for `./x.ts`, so the `.js` → `.ts`/`.tsx` rewrite is the common case.
1651
- */
1652
- function resolveRelativeImport(fromFile, spec, candidates) {
1653
- const base = posixJoin(dirname(fromFile.split("/").join(sep)), spec);
1654
- const stem = base.replace(/\.(js|jsx|mjs|cjs)$/, "");
1655
- for (const cand of [
1656
- base,
1657
- ...SOURCE_EXTS.map((e) => stem + e),
1658
- ...SOURCE_EXTS.map((e) => `${stem}/index${e}`),
1659
- ])
1660
- if (candidates.has(cand))
1661
- return cand;
1662
- return undefined;
1663
- }
1664
- /** Join and normalize a "/"-separated path, resolving `.` and `..` segments. */
1665
- function posixJoin(dir, spec) {
1666
- const parts = `${dir.split(sep).join("/")}/${spec}`.split("/");
1667
- const out = [];
1668
- for (const part of parts) {
1669
- if (part === "" || part === ".")
1670
- continue;
1671
- if (part === "..")
1672
- out.pop();
1673
- else
1674
- out.push(part);
1675
- }
1676
- return out.join("/");
1799
+ // Companion closure by import graph, to a fixed point — the shared walker
1800
+ // (`lib/import-graph.ts`), so `tools/lint-slice-registration.ts` asks the
1801
+ // question with the same resolution this answer was computed with (#5701).
1802
+ return [...importClosure(repoRoot, [...roots], seeds)].sort();
1677
1803
  }
@@ -19,7 +19,7 @@ import { existsSync, readdirSync, readFileSync, statSync, writeFileSync, } from
19
19
  import { basename, dirname, join, resolve } from "node:path";
20
20
  import { fileURLToPath } from "node:url";
21
21
  import { CATALOG_TARGET_PATH, writeComponentCatalog, } from "./component-catalog.js";
22
- import { copyTemplate } from "./copy.js";
22
+ import { buildScaffoldMarkers, copyTemplate } from "./copy.js";
23
23
  import { deriveArchitecture } from "./derive-architecture.js";
24
24
  import { extractModuleBundle, installBundleTree, } from "./lib/extract-module-bundle.js";
25
25
  import { fetchTemplate } from "./lib/fetch-template.js";
@@ -92,15 +92,7 @@ export function scaffoldSync(opts) {
92
92
  targetDir: targetAbs,
93
93
  versions,
94
94
  excludePaths: excludedRoutePaths(enabledSurfaces),
95
- markers: {
96
- PROJECT_NAME: projectName,
97
- COMPANY_NAME: "Your Company",
98
- COMPANY_DOMAIN: "example.com",
99
- // The social-profile handle the Free chrome's footer links carry
100
- // (`https://x.com/{{COMPANY_HANDLE}}`, #5469 D5) — a placeholder the
101
- // site owner replaces, never the kit vendor's own handle.
102
- COMPANY_HANDLE: "yourcompany",
103
- },
95
+ markers: buildScaffoldMarkers(projectName),
104
96
  });
105
97
  // Derive + write the module-set-driven architecture.yaml (spec #3787). This
106
98
  // is the single source of the scaffolded site's code-boundary config and
@@ -241,6 +233,14 @@ export async function scaffold(opts) {
241
233
  // `scaffoldSync` already reads for `copyTemplate`, re-read here since
242
234
  // `scaffold()` doesn't share `scaffoldSync`'s call frame.
243
235
  const versions = readVersionMap();
236
+ // #6460 — the SAME marker map `scaffoldSync` just substituted the base
237
+ // `templates/` copy with, rebuilt here from the same inputs (`scaffold()`
238
+ // does not share `scaffoldSync`'s call frame, exactly as `versions` above
239
+ // does not) and threaded into every layer that lands on top of it. Without
240
+ // it a `{{MARKER}}` authored in a base-layer or site-template file would
241
+ // survive into the scaffold verbatim — the state before this card, and the
242
+ // reason a template file could not carry the version stamp.
243
+ const markers = buildScaffoldMarkers(opts.projectName ?? basename(result.targetDir));
244
244
  // #5618 D4 — the file-grain ownership registry for THIS scaffold: which
245
245
  // layer wrote which destination. Call-scoped (a fresh Map per scaffold(),
246
246
  // never module-level), threaded through every layer install below in the
@@ -267,6 +267,7 @@ export async function scaffold(opts) {
267
267
  name: BASE_LAYER_DIR,
268
268
  templateRequires: [],
269
269
  versions,
270
+ markers,
270
271
  ownership,
271
272
  });
272
273
  }
@@ -276,6 +277,7 @@ export async function scaffold(opts) {
276
277
  targetDir: result.targetDir,
277
278
  moduleName,
278
279
  versions,
280
+ markers,
279
281
  ownership,
280
282
  });
281
283
  }
@@ -305,6 +307,7 @@ export async function scaffold(opts) {
305
307
  templateRequires: template.requires,
306
308
  templateExtends: template.extends,
307
309
  versions,
310
+ markers,
308
311
  ownership,
309
312
  })
310
313
  : (() => {
@@ -319,6 +322,7 @@ export async function scaffold(opts) {
319
322
  templateRequires: template.requires,
320
323
  templateExtends: template.extends,
321
324
  versions,
325
+ markers,
322
326
  ownership,
323
327
  });
324
328
  })();