create-ailk 0.24.0 → 0.25.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 (599) hide show
  1. package/README.md +42 -20
  2. package/component-catalog.json +3 -3
  3. package/component-catalog.md +3 -3
  4. package/dist/add-module.js +4 -2
  5. package/dist/add-route.d.ts +12 -1
  6. package/dist/add-route.js +31 -3
  7. package/dist/cli.js +12 -7
  8. package/dist/derive-architecture.d.ts +3 -4
  9. package/dist/derive-architecture.js +65 -29
  10. package/dist/lib/design-checks.d.ts +9 -4
  11. package/dist/lib/design-checks.js +13 -7
  12. package/dist/lib/extract-module-bundle.js +29 -2
  13. package/dist/lib/fetch-template-snapshot.d.ts +1 -1
  14. package/dist/lib/fetch-template-snapshot.js +7 -3
  15. package/dist/lib/import-graph.d.ts +1 -1
  16. package/dist/lib/import-graph.js +4 -4
  17. package/dist/lib/module-license-gate.d.ts +12 -1
  18. package/dist/lib/module-license-gate.js +34 -12
  19. package/dist/module-architecture.d.ts +20 -3
  20. package/dist/module-architecture.js +117 -550
  21. package/dist/paid-sections.d.ts +25 -1
  22. package/dist/paid-sections.js +88 -3
  23. package/dist/surfaces.js +10 -2
  24. package/dist/template-record.d.ts +14 -4
  25. package/dist/template-record.js +23 -5
  26. package/dist/topology.d.ts +16 -3
  27. package/dist/topology.js +31 -19
  28. package/dist/update.d.ts +10 -1
  29. package/dist/update.js +540 -16
  30. package/package.json +3 -3
  31. package/release-scope.json +1 -1
  32. package/templates/.claude/cloudparity-repo-hooks.json +5 -0
  33. package/templates/.claude/hooks/template-guard.sh +137 -0
  34. package/templates/.claude/rules/extending.md +106 -0
  35. package/templates/.claude/rules/loop-contract.md +2 -2
  36. package/templates/.claude/settings.json +11 -0
  37. package/templates/.env.example +5 -5
  38. package/templates/.github/workflows/ci.yml +7 -4
  39. package/templates/CLAUDE.md +11 -1
  40. package/templates/CONVENTIONS.md +8 -10
  41. package/templates/README.md +14 -13
  42. package/templates/apps/api/.env.example +2 -2
  43. package/templates/apps/api/CLAUDE.md +102 -76
  44. package/templates/apps/api/jest.config.cjs +15 -5
  45. package/templates/apps/api/package.json +16 -20
  46. package/templates/apps/api/src/__tests__/trusted-origins.server.test.ts +2 -2
  47. package/templates/apps/api/src/__tests__/vercel-handler.test.ts +4 -4
  48. package/templates/apps/api/src/index.ts +1 -1
  49. package/templates/apps/api/src/lib/__mocks__/prisma.ts +3 -3
  50. package/templates/apps/api/src/modules/commerce.ts +10 -0
  51. package/templates/apps/api/src/modules/content-write.ts +10 -0
  52. package/templates/apps/api/src/modules/multi-tenant.ts +10 -0
  53. package/templates/apps/api/src/modules/scheduling.ts +10 -0
  54. package/templates/apps/api/src/modules/signal-collectors.ts +10 -0
  55. package/templates/apps/api/src/modules/workspace.ts +10 -0
  56. package/templates/apps/api/src/server.ts +117 -1882
  57. package/templates/apps/api/vercel.json +2 -2
  58. package/templates/apps/mcp/CLAUDE.md +67 -20
  59. package/templates/apps/mcp/__tests__/app-entry.test.ts +4 -254
  60. package/templates/apps/mcp/__tests__/boot-file.test.ts +92 -0
  61. package/templates/apps/mcp/jest.config.cjs +6 -1
  62. package/templates/apps/mcp/package.json +5 -13
  63. package/templates/apps/mcp/src/app.ts +8 -7
  64. package/templates/apps/mcp/src/index.ts +6 -34
  65. package/templates/apps/mcp/src/lib/paid-tools.generated.ts +10 -0
  66. package/templates/apps/mcp/src/lib/topology.generated.ts +2 -2
  67. package/templates/apps/mcp/src/site.ts +12 -0
  68. package/templates/apps/web/.env.example +1 -1
  69. package/templates/apps/web/CLAUDE.md +10 -3
  70. package/templates/apps/web/app/.well-known/mcp.json/route.ts +9 -3
  71. package/templates/apps/web/app/[locale]/contact/intake-analytics.ts +1 -1
  72. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/magnet-page.test.tsx +22 -1
  73. package/templates/apps/web/app/[locale]/flows/[slug]/magnet-page.tsx +7 -3
  74. package/templates/apps/web/app/[locale]/pricing/__tests__/unconnected.test.tsx +43 -0
  75. package/templates/apps/web/app/[locale]/pricing/page.tsx +7 -3
  76. package/templates/apps/web/app/api/offerings/checkout/[lookupKey]/__tests__/route.test.ts +222 -0
  77. package/templates/apps/web/app/api/offerings/checkout/[lookupKey]/route.ts +10 -3
  78. package/templates/apps/web/app/api/revalidate/route.ts +3 -3
  79. package/templates/apps/web/auth.ts +2 -2
  80. package/templates/apps/web/jest.config.cjs +1 -0
  81. package/templates/apps/web/lib/auth-email.ts +1 -1
  82. package/templates/apps/web/lib/relay.ts +2 -2
  83. package/templates/apps/web/lib/release-scope.ts +47 -0
  84. package/templates/apps/web/lib/server-api.ts +1 -1
  85. package/templates/apps/web/src/lib/commerce-claim.ts +1 -1
  86. package/templates/customizations.yaml +37 -0
  87. package/templates/database/prisma.config.ts +10 -14
  88. package/templates/database/seed-test.ts +2 -2
  89. package/templates/database/seed.ts +5 -5
  90. package/templates/package.json +12 -6
  91. package/templates/pnpm-workspace.yaml +0 -1
  92. package/templates/project.yaml +16 -8
  93. package/templates/tools/jest/reporters.cjs +65 -0
  94. package/templates/tools/lint-architecture.ts +553 -7
  95. package/templates/tsconfig.json +1 -2
  96. package/versions.json +48 -35
  97. package/templates/apps/api/src/__tests__/commerce-claim-registration.test.ts +0 -409
  98. package/templates/apps/api/src/__tests__/factories/agent-caller.ts +0 -102
  99. package/templates/apps/api/src/__tests__/factories/content-fixture.ts +0 -138
  100. package/templates/apps/api/src/__tests__/factories/in-memory-prisma.ts +0 -441
  101. package/templates/apps/api/src/__tests__/factories/index.ts +0 -70
  102. package/templates/apps/api/src/__tests__/factories/lead-fixture.ts +0 -82
  103. package/templates/apps/api/src/__tests__/leads-forwarded-rate-limit.test.ts +0 -135
  104. package/templates/apps/api/src/__tests__/services/enrichment-shim.test.ts +0 -126
  105. package/templates/apps/api/src/__tests__/stripe-boot.test.ts +0 -132
  106. package/templates/apps/api/src/__tests__/support/hub-sign-in-fake-db.ts +0 -362
  107. package/templates/apps/api/src/bin/__tests__/rate-limit-probe.test.ts +0 -184
  108. package/templates/apps/api/src/bin/abandon-sweep.ts +0 -42
  109. package/templates/apps/api/src/bin/rate-limit-probe.ts +0 -53
  110. package/templates/apps/api/src/bin/spokes.ts +0 -198
  111. package/templates/apps/api/src/bin/stripe-connections-rekey.ts +0 -45
  112. package/templates/apps/api/src/config/__tests__/hub-require-spoke-key.test.ts +0 -196
  113. package/templates/apps/api/src/config/__tests__/index.test.ts +0 -233
  114. package/templates/apps/api/src/config/__tests__/modules.test.ts +0 -76
  115. package/templates/apps/api/src/config/__tests__/stripe-connection-key.test.ts +0 -185
  116. package/templates/apps/api/src/config/__tests__/trusted-origins.test.ts +0 -238
  117. package/templates/apps/api/src/config/index.ts +0 -596
  118. package/templates/apps/api/src/config/modules.ts +0 -83
  119. package/templates/apps/api/src/lib/__tests__/agent-store.test.ts +0 -581
  120. package/templates/apps/api/src/lib/__tests__/auth-email-budget.test.ts +0 -143
  121. package/templates/apps/api/src/lib/__tests__/consent-ledger-double.ts +0 -237
  122. package/templates/apps/api/src/lib/__tests__/consent-store.test.ts +0 -353
  123. package/templates/apps/api/src/lib/__tests__/content-adapter.test.ts +0 -201
  124. package/templates/apps/api/src/lib/__tests__/deliverable-asset-store.test.ts +0 -224
  125. package/templates/apps/api/src/lib/__tests__/error-serializer.test.ts +0 -120
  126. package/templates/apps/api/src/lib/__tests__/errors.test.ts +0 -94
  127. package/templates/apps/api/src/lib/__tests__/file-fallback.test.ts +0 -144
  128. package/templates/apps/api/src/lib/__tests__/fixtures/HomePage/home.mdx +0 -8
  129. package/templates/apps/api/src/lib/__tests__/flow-completion-store.test.ts +0 -149
  130. package/templates/apps/api/src/lib/__tests__/flow-rename-race.db.test.ts +0 -116
  131. package/templates/apps/api/src/lib/__tests__/hub-sign-in-store.test.ts +0 -209
  132. package/templates/apps/api/src/lib/__tests__/lead-capture-store.test.ts +0 -257
  133. package/templates/apps/api/src/lib/__tests__/lead-delivery.test.ts +0 -96
  134. package/templates/apps/api/src/lib/__tests__/outbound-http.test.ts +0 -125
  135. package/templates/apps/api/src/lib/__tests__/prisma.test.ts +0 -165
  136. package/templates/apps/api/src/lib/__tests__/require-commerce-claim.test.ts +0 -317
  137. package/templates/apps/api/src/lib/__tests__/require-paid-tier.test.ts +0 -129
  138. package/templates/apps/api/src/lib/__tests__/site.test.ts +0 -308
  139. package/templates/apps/api/src/lib/__tests__/slice-load.test.ts +0 -89
  140. package/templates/apps/api/src/lib/__tests__/spoke-store.test.ts +0 -202
  141. package/templates/apps/api/src/lib/__tests__/stripe-admission.test.ts +0 -217
  142. package/templates/apps/api/src/lib/__tests__/stripe.test.ts +0 -82
  143. package/templates/apps/api/src/lib/agent-store.ts +0 -613
  144. package/templates/apps/api/src/lib/auth-email-budget.ts +0 -161
  145. package/templates/apps/api/src/lib/consent-store.ts +0 -363
  146. package/templates/apps/api/src/lib/content-adapter.ts +0 -112
  147. package/templates/apps/api/src/lib/deliverable-asset-store.ts +0 -96
  148. package/templates/apps/api/src/lib/error-serializer.ts +0 -164
  149. package/templates/apps/api/src/lib/errors.ts +0 -95
  150. package/templates/apps/api/src/lib/file-fallback.ts +0 -87
  151. package/templates/apps/api/src/lib/flow-completion-store.ts +0 -136
  152. package/templates/apps/api/src/lib/hub-sign-in-store.ts +0 -455
  153. package/templates/apps/api/src/lib/lead-capture-store.ts +0 -122
  154. package/templates/apps/api/src/lib/lead-delivery.ts +0 -52
  155. package/templates/apps/api/src/lib/license-key-store.ts +0 -45
  156. package/templates/apps/api/src/lib/locales.ts +0 -201
  157. package/templates/apps/api/src/lib/outbound-http.ts +0 -127
  158. package/templates/apps/api/src/lib/prisma.ts +0 -21
  159. package/templates/apps/api/src/lib/proposal-paid-store.ts +0 -66
  160. package/templates/apps/api/src/lib/rate-limit-probe.ts +0 -165
  161. package/templates/apps/api/src/lib/rate-limit-store.ts +0 -142
  162. package/templates/apps/api/src/lib/require-commerce-claim.ts +0 -250
  163. package/templates/apps/api/src/lib/require-paid-tier.ts +0 -53
  164. package/templates/apps/api/src/lib/site.ts +0 -257
  165. package/templates/apps/api/src/lib/slice-load.ts +0 -90
  166. package/templates/apps/api/src/lib/spoke-store.ts +0 -180
  167. package/templates/apps/api/src/lib/stripe.ts +0 -321
  168. package/templates/apps/api/src/lib/webhook-idempotency.ts +0 -156
  169. package/templates/apps/api/src/middleware/__tests__/adversarial/bearer-token-format.test.ts +0 -111
  170. package/templates/apps/api/src/middleware/__tests__/adversarial/cookie-or-bearer-precedence.test.ts +0 -172
  171. package/templates/apps/api/src/middleware/__tests__/adversarial/csrf-bearer-skip.test.ts +0 -119
  172. package/templates/apps/api/src/middleware/__tests__/adversarial/csrf-cookie-path.test.ts +0 -138
  173. package/templates/apps/api/src/middleware/__tests__/adversarial/csrf-trusted-origins.test.ts +0 -142
  174. package/templates/apps/api/src/middleware/__tests__/adversarial/session-fixation.test.ts +0 -155
  175. package/templates/apps/api/src/middleware/__tests__/adversarial/session-timeout.test.ts +0 -139
  176. package/templates/apps/api/src/middleware/__tests__/auth.bearer-path.test.ts +0 -562
  177. package/templates/apps/api/src/middleware/__tests__/auth.both-present-precedence.test.ts +0 -76
  178. package/templates/apps/api/src/middleware/__tests__/auth.cookie-path.test.ts +0 -220
  179. package/templates/apps/api/src/middleware/__tests__/auth.database-not-configured.test.ts +0 -97
  180. package/templates/apps/api/src/middleware/__tests__/auth.hub-session-path.test.ts +0 -557
  181. package/templates/apps/api/src/middleware/__tests__/auth.neither-present.test.ts +0 -72
  182. package/templates/apps/api/src/middleware/__tests__/auth.optional-cookie.test.ts +0 -140
  183. package/templates/apps/api/src/middleware/__tests__/default-tenant.test.ts +0 -721
  184. package/templates/apps/api/src/middleware/__tests__/rate-limit-cross-isolate.db.test.ts +0 -220
  185. package/templates/apps/api/src/middleware/__tests__/rate-limit-store.test.ts +0 -430
  186. package/templates/apps/api/src/middleware/__tests__/rate-limit.test.ts +0 -1409
  187. package/templates/apps/api/src/middleware/__tests__/write-budget.test.ts +0 -174
  188. package/templates/apps/api/src/middleware/auth.ts +0 -864
  189. package/templates/apps/api/src/middleware/default-tenant.ts +0 -166
  190. package/templates/apps/api/src/middleware/rate-limit.ts +0 -983
  191. package/templates/apps/api/src/openapi/__tests__/openapi.test.ts +0 -391
  192. package/templates/apps/api/src/openapi/__tests__/spec-identity.test.ts +0 -182
  193. package/templates/apps/api/src/openapi/index.ts +0 -18
  194. package/templates/apps/api/src/openapi/spec.ts +0 -2148
  195. package/templates/apps/api/src/openapi/surface-drift.ts +0 -195
  196. package/templates/apps/api/src/routes/aeo/__tests__/index.test.ts +0 -175
  197. package/templates/apps/api/src/routes/aeo/index.ts +0 -107
  198. package/templates/apps/api/src/routes/auth/__tests__/auth-tokens.functional.test.ts +0 -196
  199. package/templates/apps/api/src/routes/auth/__tests__/auth-user.functional.test.ts +0 -249
  200. package/templates/apps/api/src/routes/auth/__tests__/hub-sign-in.test.ts +0 -532
  201. package/templates/apps/api/src/routes/auth/__tests__/tokens.test.ts +0 -313
  202. package/templates/apps/api/src/routes/auth/__tests__/transactional-email.test.ts +0 -413
  203. package/templates/apps/api/src/routes/auth/__tests__/user.test.ts +0 -609
  204. package/templates/apps/api/src/routes/auth/hub-sign-in.ts +0 -242
  205. package/templates/apps/api/src/routes/auth/tokens.ts +0 -211
  206. package/templates/apps/api/src/routes/auth/transactional-email.ts +0 -301
  207. package/templates/apps/api/src/routes/auth/user.ts +0 -305
  208. package/templates/apps/api/src/routes/billing/plan-checkout.ts +0 -332
  209. package/templates/apps/api/src/routes/checkout/__tests__/live-key.test.ts +0 -178
  210. package/templates/apps/api/src/routes/checkout/__tests__/offerings-authorization.test.ts +0 -1426
  211. package/templates/apps/api/src/routes/checkout/__tests__/session.test.ts +0 -448
  212. package/templates/apps/api/src/routes/checkout/__tests__/sessions.test.ts +0 -1742
  213. package/templates/apps/api/src/routes/checkout/index.ts +0 -34
  214. package/templates/apps/api/src/routes/checkout/session.ts +0 -171
  215. package/templates/apps/api/src/routes/checkout/sessions.ts +0 -540
  216. package/templates/apps/api/src/routes/consent/__tests__/account.test.ts +0 -386
  217. package/templates/apps/api/src/routes/consent/__tests__/sign-up-rate-limit.test.ts +0 -160
  218. package/templates/apps/api/src/routes/consent/account.ts +0 -268
  219. package/templates/apps/api/src/routes/consent/cookie.ts +0 -90
  220. package/templates/apps/api/src/routes/consent/index.ts +0 -26
  221. package/templates/apps/api/src/routes/consent/unsubscribe.ts +0 -127
  222. package/templates/apps/api/src/routes/content/__tests__/get-page.test.ts +0 -853
  223. package/templates/apps/api/src/routes/content/__tests__/list-pages.test.ts +0 -230
  224. package/templates/apps/api/src/routes/content/__tests__/list-types.test.ts +0 -44
  225. package/templates/apps/api/src/routes/content/__tests__/locale.test.ts +0 -118
  226. package/templates/apps/api/src/routes/content/__tests__/offerings.test.ts +0 -731
  227. package/templates/apps/api/src/routes/content/__tests__/pricing.test.ts +0 -753
  228. package/templates/apps/api/src/routes/content/__tests__/rate-limit.test.ts +0 -51
  229. package/templates/apps/api/src/routes/content/__tests__/search.test.ts +0 -450
  230. package/templates/apps/api/src/routes/content/__tests__/shown-offerings.test.ts +0 -762
  231. package/templates/apps/api/src/routes/content/get-page.ts +0 -183
  232. package/templates/apps/api/src/routes/content/index.ts +0 -49
  233. package/templates/apps/api/src/routes/content/list-pages.ts +0 -74
  234. package/templates/apps/api/src/routes/content/list-types.ts +0 -19
  235. package/templates/apps/api/src/routes/content/offerings.ts +0 -184
  236. package/templates/apps/api/src/routes/content/pricing.ts +0 -176
  237. package/templates/apps/api/src/routes/content/rate-limit.ts +0 -22
  238. package/templates/apps/api/src/routes/content/search.ts +0 -100
  239. package/templates/apps/api/src/routes/content/shown-offerings.ts +0 -229
  240. package/templates/apps/api/src/routes/leads/__tests__/capture.test.ts +0 -88
  241. package/templates/apps/api/src/routes/leads/__tests__/list.test.ts +0 -171
  242. package/templates/apps/api/src/routes/leads/__tests__/magnet-completion.test.ts +0 -515
  243. package/templates/apps/api/src/routes/leads/__tests__/spoke.test.ts +0 -392
  244. package/templates/apps/api/src/routes/leads/__tests__/track.test.ts +0 -165
  245. package/templates/apps/api/src/routes/leads/index.ts +0 -639
  246. package/templates/apps/api/src/routes/leads/list.ts +0 -104
  247. package/templates/apps/api/src/routes/project-listings/__tests__/configured-application.test.ts +0 -626
  248. package/templates/apps/api/src/routes/project-listings/__tests__/drafts.test.ts +0 -1268
  249. package/templates/apps/api/src/routes/project-listings/__tests__/founder-identity.test.ts +0 -847
  250. package/templates/apps/api/src/routes/project-listings/__tests__/me.test.ts +0 -491
  251. package/templates/apps/api/src/routes/project-listings/__tests__/public.test.ts +0 -476
  252. package/templates/apps/api/src/routes/project-listings/__tests__/resume-email.test.ts +0 -872
  253. package/templates/apps/api/src/routes/project-listings/__tests__/site-answers.test.ts +0 -1022
  254. package/templates/apps/api/src/routes/project-listings/__tests__/site-key.test.ts +0 -484
  255. package/templates/apps/api/src/routes/project-listings/__tests__/structured-address.test.ts +0 -535
  256. package/templates/apps/api/src/routes/project-listings/index.ts +0 -164
  257. package/templates/apps/api/src/routes/project-listings/me.ts +0 -87
  258. package/templates/apps/api/src/routes/project-listings/patch-copy.ts +0 -224
  259. package/templates/apps/api/src/routes/project-listings/patch-draft.ts +0 -102
  260. package/templates/apps/api/src/routes/project-listings/public.ts +0 -98
  261. package/templates/apps/api/src/routes/project-listings/respond.ts +0 -48
  262. package/templates/apps/api/src/routes/project-listings/resume-token.ts +0 -27
  263. package/templates/apps/api/src/routes/project-listings/start.ts +0 -140
  264. package/templates/apps/api/src/routes/project-listings/submit.ts +0 -130
  265. package/templates/apps/api/src/routes/project-listings/verify-email.ts +0 -150
  266. package/templates/apps/api/src/routes/requests/__tests__/confirm.test.ts +0 -686
  267. package/templates/apps/api/src/routes/requests/confirm.ts +0 -601
  268. package/templates/apps/api/src/routes/requests/index.ts +0 -54
  269. package/templates/apps/api/src/routes/test/auth/__tests__/session.test.ts +0 -306
  270. package/templates/apps/api/src/routes/test/auth/session.ts +0 -143
  271. package/templates/apps/api/src/routes/webhooks/README.md +0 -398
  272. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-checkout-consent.test.ts +0 -649
  273. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-dunning.test.ts +0 -749
  274. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-flow-checkout.test.ts +0 -449
  275. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-idempotency.test.ts +0 -264
  276. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-livemode-live.test.ts +0 -159
  277. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-livemode.test.ts +0 -158
  278. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-offerings.test.ts +0 -814
  279. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-org-billing.test.ts +0 -301
  280. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-proposal-paid.test.ts +0 -369
  281. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-rate-limit.test.ts +0 -215
  282. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-request-paid.test.ts +0 -301
  283. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-site-filter.test.ts +0 -809
  284. package/templates/apps/api/src/routes/webhooks/__tests__/stripe.test.ts +0 -1155
  285. package/templates/apps/api/src/routes/webhooks/index.ts +0 -141
  286. package/templates/apps/api/src/routes/webhooks/stripe-offerings.ts +0 -384
  287. package/templates/apps/api/src/routes/webhooks/stripe.ts +0 -2028
  288. package/templates/apps/api/src/services/__tests__/abandon-email.test.ts +0 -645
  289. package/templates/apps/api/src/services/__tests__/answer-distributions.test.ts +0 -132
  290. package/templates/apps/api/src/services/__tests__/audit-log.test.ts +0 -1028
  291. package/templates/apps/api/src/services/__tests__/checkout-plan.test.ts +0 -313
  292. package/templates/apps/api/src/services/__tests__/consent-ledger.test.ts +0 -503
  293. package/templates/apps/api/src/services/__tests__/consent-migration.test.ts +0 -65
  294. package/templates/apps/api/src/services/__tests__/consent.test.ts +0 -299
  295. package/templates/apps/api/src/services/__tests__/default-tenant.test.ts +0 -147
  296. package/templates/apps/api/src/services/__tests__/deliverable-fulfillment.test.ts +0 -877
  297. package/templates/apps/api/src/services/__tests__/deliverable-resend.test.ts +0 -379
  298. package/templates/apps/api/src/services/__tests__/dunning-policy.test.ts +0 -368
  299. package/templates/apps/api/src/services/__tests__/entitlements.test.ts +0 -142
  300. package/templates/apps/api/src/services/__tests__/hub-sign-in.test.ts +0 -854
  301. package/templates/apps/api/src/services/__tests__/keyless-workspace-predicate.test.ts +0 -234
  302. package/templates/apps/api/src/services/__tests__/lead-accept-user.test.ts +0 -251
  303. package/templates/apps/api/src/services/__tests__/lead-routing.test.ts +0 -2660
  304. package/templates/apps/api/src/services/__tests__/listing-config.test.ts +0 -166
  305. package/templates/apps/api/src/services/__tests__/magnet-completion.test.ts +0 -389
  306. package/templates/apps/api/src/services/__tests__/person.test.ts +0 -1204
  307. package/templates/apps/api/src/services/__tests__/plan-offerings.test.ts +0 -450
  308. package/templates/apps/api/src/services/__tests__/project-listings.counts.test.ts +0 -202
  309. package/templates/apps/api/src/services/__tests__/project-listings.fence.test.ts +0 -151
  310. package/templates/apps/api/src/services/__tests__/public-site-resolver.test.ts +0 -137
  311. package/templates/apps/api/src/services/__tests__/request-confirm.test.ts +0 -531
  312. package/templates/apps/api/src/services/__tests__/revalidation.test.ts +0 -372
  313. package/templates/apps/api/src/services/__tests__/slack-notify.test.ts +0 -348
  314. package/templates/apps/api/src/services/__tests__/spoke-resolution.test.ts +0 -660
  315. package/templates/apps/api/src/services/__tests__/usage-aggregation.test.ts +0 -941
  316. package/templates/apps/api/src/services/__tests__/usage-credits.test.ts +0 -588
  317. package/templates/apps/api/src/services/__tests__/verified-email.test.ts +0 -78
  318. package/templates/apps/api/src/services/abandon-email.ts +0 -336
  319. package/templates/apps/api/src/services/aeo-score.ts +0 -325
  320. package/templates/apps/api/src/services/answer-distributions.ts +0 -138
  321. package/templates/apps/api/src/services/audit-log.ts +0 -961
  322. package/templates/apps/api/src/services/checkout-buyer.ts +0 -168
  323. package/templates/apps/api/src/services/consent.ts +0 -834
  324. package/templates/apps/api/src/services/default-tenant.ts +0 -416
  325. package/templates/apps/api/src/services/deliverable-fulfillment.ts +0 -750
  326. package/templates/apps/api/src/services/dunning-policy.ts +0 -294
  327. package/templates/apps/api/src/services/enrichment-shim.ts +0 -53
  328. package/templates/apps/api/src/services/entitlements.ts +0 -338
  329. package/templates/apps/api/src/services/hub-sign-in.ts +0 -472
  330. package/templates/apps/api/src/services/lead-accept-user.ts +0 -126
  331. package/templates/apps/api/src/services/lead-promotion.ts +0 -160
  332. package/templates/apps/api/src/services/lead-routing.ts +0 -1372
  333. package/templates/apps/api/src/services/leads-inbox.ts +0 -312
  334. package/templates/apps/api/src/services/listing-config.ts +0 -178
  335. package/templates/apps/api/src/services/magnet-completion.ts +0 -242
  336. package/templates/apps/api/src/services/offerings/__tests__/catalog.test.ts +0 -348
  337. package/templates/apps/api/src/services/offerings/__tests__/checkout-session-record.test.ts +0 -268
  338. package/templates/apps/api/src/services/offerings/__tests__/connection.test.ts +0 -975
  339. package/templates/apps/api/src/services/offerings/__tests__/fixtures.ts +0 -416
  340. package/templates/apps/api/src/services/offerings/__tests__/org-products.test.ts +0 -400
  341. package/templates/apps/api/src/services/offerings/__tests__/readers.test.ts +0 -685
  342. package/templates/apps/api/src/services/offerings/__tests__/source.test.ts +0 -231
  343. package/templates/apps/api/src/services/offerings/catalog.ts +0 -318
  344. package/templates/apps/api/src/services/offerings/checkout-authorization.ts +0 -403
  345. package/templates/apps/api/src/services/offerings/checkout-session-record.ts +0 -192
  346. package/templates/apps/api/src/services/offerings/connection.ts +0 -1083
  347. package/templates/apps/api/src/services/offerings/index.ts +0 -614
  348. package/templates/apps/api/src/services/offerings/source.ts +0 -140
  349. package/templates/apps/api/src/services/offerings/store.ts +0 -150
  350. package/templates/apps/api/src/services/owner-workspaces.ts +0 -132
  351. package/templates/apps/api/src/services/person.ts +0 -1211
  352. package/templates/apps/api/src/services/plan-offerings.ts +0 -125
  353. package/templates/apps/api/src/services/project-listing-resume-email.ts +0 -326
  354. package/templates/apps/api/src/services/project-listings.ts +0 -2085
  355. package/templates/apps/api/src/services/public-site-resolver.ts +0 -396
  356. package/templates/apps/api/src/services/request-confirm.ts +0 -698
  357. package/templates/apps/api/src/services/revalidation.ts +0 -235
  358. package/templates/apps/api/src/services/slack-notify.ts +0 -291
  359. package/templates/apps/api/src/services/usage-aggregation.ts +0 -516
  360. package/templates/apps/api/src/services/usage-credits.ts +0 -340
  361. package/templates/apps/api/src/services/verified-email.ts +0 -71
  362. package/templates/apps/mcp/__tests__/abuse/daily-cap.test.ts +0 -52
  363. package/templates/apps/mcp/__tests__/abuse/email-validator.test.ts +0 -46
  364. package/templates/apps/mcp/__tests__/abuse/guard.test.ts +0 -198
  365. package/templates/apps/mcp/__tests__/abuse/honeypot.test.ts +0 -36
  366. package/templates/apps/mcp/__tests__/abuse/user-agent-deny.test.ts +0 -54
  367. package/templates/apps/mcp/__tests__/aeo-cli-parity.test.ts +0 -116
  368. package/templates/apps/mcp/__tests__/audit-single-page.test.ts +0 -299
  369. package/templates/apps/mcp/__tests__/boot.test.ts +0 -280
  370. package/templates/apps/mcp/__tests__/catalog-drift.test.ts +0 -359
  371. package/templates/apps/mcp/__tests__/config/modules.test.ts +0 -78
  372. package/templates/apps/mcp/__tests__/get_business_hours.test.ts +0 -82
  373. package/templates/apps/mcp/__tests__/get_faq.test.ts +0 -80
  374. package/templates/apps/mcp/__tests__/get_locations.test.ts +0 -65
  375. package/templates/apps/mcp/__tests__/get_offerings.test.ts +0 -557
  376. package/templates/apps/mcp/__tests__/get_pricing.test.ts +0 -524
  377. package/templates/apps/mcp/__tests__/get_site_info.test.ts +0 -81
  378. package/templates/apps/mcp/__tests__/http-transport.test.ts +0 -1232
  379. package/templates/apps/mcp/__tests__/index.test.ts +0 -195
  380. package/templates/apps/mcp/__tests__/lib/audit-single-page-readiness-scan.test.ts +0 -191
  381. package/templates/apps/mcp/__tests__/lib/commerce-claim.test.ts +0 -531
  382. package/templates/apps/mcp/__tests__/lib/content-adapter-parity.test.ts +0 -70
  383. package/templates/apps/mcp/__tests__/lib/content-adapter.test.ts +0 -162
  384. package/templates/apps/mcp/__tests__/lib/content-root.test.ts +0 -93
  385. package/templates/apps/mcp/__tests__/lib/errors.test.ts +0 -75
  386. package/templates/apps/mcp/__tests__/lib/fail-closed-tools.test.ts +0 -180
  387. package/templates/apps/mcp/__tests__/lib/public-workspace.test.ts +0 -124
  388. package/templates/apps/mcp/__tests__/list_pages.test.ts +0 -268
  389. package/templates/apps/mcp/__tests__/locale.test.ts +0 -120
  390. package/templates/apps/mcp/__tests__/module-exclusion.test.ts +0 -175
  391. package/templates/apps/mcp/__tests__/purchase-disabled.test.ts +0 -101
  392. package/templates/apps/mcp/__tests__/rate-limit-write.test.ts +0 -189
  393. package/templates/apps/mcp/__tests__/read_content.test.ts +0 -511
  394. package/templates/apps/mcp/__tests__/request_callback.test.ts +0 -160
  395. package/templates/apps/mcp/__tests__/search_content.test.ts +0 -271
  396. package/templates/apps/mcp/__tests__/server.test.ts +0 -388
  397. package/templates/apps/mcp/__tests__/start_purchase.test.ts +0 -448
  398. package/templates/apps/mcp/__tests__/submit_lead.test.ts +0 -222
  399. package/templates/apps/mcp/__tests__/subscribe_newsletter.test.ts +0 -152
  400. package/templates/apps/mcp/__tests__/tools/create_project.test.ts +0 -243
  401. package/templates/apps/mcp/__tests__/tools/purchase.test.ts +0 -451
  402. package/templates/apps/mcp/src/abuse/daily-cap.ts +0 -47
  403. package/templates/apps/mcp/src/abuse/email-validator.ts +0 -25
  404. package/templates/apps/mcp/src/abuse/honeypot.ts +0 -21
  405. package/templates/apps/mcp/src/abuse/index.ts +0 -349
  406. package/templates/apps/mcp/src/abuse/user-agent-deny.ts +0 -58
  407. package/templates/apps/mcp/src/boot.ts +0 -167
  408. package/templates/apps/mcp/src/config/modules.ts +0 -43
  409. package/templates/apps/mcp/src/http-transport.ts +0 -564
  410. package/templates/apps/mcp/src/lib/audit-single-page.ts +0 -308
  411. package/templates/apps/mcp/src/lib/commerce-claim.ts +0 -263
  412. package/templates/apps/mcp/src/lib/content-adapter.ts +0 -116
  413. package/templates/apps/mcp/src/lib/empty-content-adapter.ts +0 -140
  414. package/templates/apps/mcp/src/lib/errors.ts +0 -61
  415. package/templates/apps/mcp/src/lib/license-key-store.ts +0 -45
  416. package/templates/apps/mcp/src/lib/locales.ts +0 -171
  417. package/templates/apps/mcp/src/lib/prisma.ts +0 -39
  418. package/templates/apps/mcp/src/lib/public-workspace.ts +0 -133
  419. package/templates/apps/mcp/src/lib/resolve-locale.ts +0 -30
  420. package/templates/apps/mcp/src/lib/shown-offerings.ts +0 -105
  421. package/templates/apps/mcp/src/lib/site-config.ts +0 -53
  422. package/templates/apps/mcp/src/lib/stripe-tax-signal.ts +0 -59
  423. package/templates/apps/mcp/src/request-context.ts +0 -52
  424. package/templates/apps/mcp/src/server.ts +0 -343
  425. package/templates/apps/mcp/src/serverless-app.ts +0 -88
  426. package/templates/apps/mcp/src/tools/audit.ts +0 -127
  427. package/templates/apps/mcp/src/tools/capture_lead.ts +0 -66
  428. package/templates/apps/mcp/src/tools/create_project.ts +0 -134
  429. package/templates/apps/mcp/src/tools/get_business_hours.ts +0 -68
  430. package/templates/apps/mcp/src/tools/get_faq.ts +0 -71
  431. package/templates/apps/mcp/src/tools/get_locations.ts +0 -88
  432. package/templates/apps/mcp/src/tools/get_offerings.ts +0 -96
  433. package/templates/apps/mcp/src/tools/get_pricing.ts +0 -94
  434. package/templates/apps/mcp/src/tools/get_site_info.ts +0 -86
  435. package/templates/apps/mcp/src/tools/index.ts +0 -138
  436. package/templates/apps/mcp/src/tools/list_pages.ts +0 -68
  437. package/templates/apps/mcp/src/tools/person_notes.ts +0 -25
  438. package/templates/apps/mcp/src/tools/proposals.ts +0 -27
  439. package/templates/apps/mcp/src/tools/purchase.ts +0 -205
  440. package/templates/apps/mcp/src/tools/read_content.ts +0 -81
  441. package/templates/apps/mcp/src/tools/request_callback.ts +0 -52
  442. package/templates/apps/mcp/src/tools/search_content.ts +0 -63
  443. package/templates/apps/mcp/src/tools/subscribe_newsletter.ts +0 -54
  444. package/templates/apps/mcp/src/workspace-server.ts +0 -224
  445. package/templates/database/CHANGELOG.md +0 -981
  446. package/templates/database/LICENSE +0 -202
  447. package/templates/database/NOTICE +0 -2
  448. package/templates/database/README.md +0 -243
  449. package/templates/database/__tests__/agents.db.test.ts +0 -320
  450. package/templates/database/__tests__/appointment.db.test.ts +0 -106
  451. package/templates/database/__tests__/artifact-content-store.db.test.ts +0 -316
  452. package/templates/database/__tests__/composite-fence.db.test.ts +0 -206
  453. package/templates/database/__tests__/consent-ledger.db.test.ts +0 -345
  454. package/templates/database/__tests__/consent-source-checkout-migration.test.ts +0 -79
  455. package/templates/database/__tests__/fence-fan-out.db.test.ts +0 -715
  456. package/templates/database/__tests__/fixtures/appointment-create-probe.ts +0 -79
  457. package/templates/database/__tests__/fixtures/person-backfill.json +0 -264
  458. package/templates/database/__tests__/fixtures/person-contact-backfill.json +0 -182
  459. package/templates/database/__tests__/fixtures/project-listing-consent-probe.ts +0 -100
  460. package/templates/database/__tests__/flow-completion-migration.test.ts +0 -115
  461. package/templates/database/__tests__/flow-completion.db.test.ts +0 -136
  462. package/templates/database/__tests__/flow-workspace-key.db.test.ts +0 -263
  463. package/templates/database/__tests__/flows-listing-diagnostic.test.ts +0 -392
  464. package/templates/database/__tests__/flows-presets.test.ts +0 -173
  465. package/templates/database/__tests__/in-page-magnets-migration.test.ts +0 -161
  466. package/templates/database/__tests__/lead-idempotency-key.db.test.ts +0 -92
  467. package/templates/database/__tests__/member-area.db.test.ts +0 -257
  468. package/templates/database/__tests__/member-contract-migration.test.ts +0 -85
  469. package/templates/database/__tests__/member-contract.db.test.ts +0 -413
  470. package/templates/database/__tests__/offerings-checkout-session.db.test.ts +0 -270
  471. package/templates/database/__tests__/offerings-migration.test.ts +0 -197
  472. package/templates/database/__tests__/offerings-shown-price-ids-migration.test.ts +0 -86
  473. package/templates/database/__tests__/offerings.db.test.ts +0 -303
  474. package/templates/database/__tests__/outbound-message-action.db.test.ts +0 -80
  475. package/templates/database/__tests__/person-contact.db.test.ts +0 -563
  476. package/templates/database/__tests__/person-notes.db.test.ts +0 -249
  477. package/templates/database/__tests__/person.db.test.ts +0 -586
  478. package/templates/database/__tests__/piece-kind-migration.test.ts +0 -67
  479. package/templates/database/__tests__/piece-kind.db.test.ts +0 -208
  480. package/templates/database/__tests__/prefixed-ids.db.test.ts +0 -222
  481. package/templates/database/__tests__/project-listing-consent-at.db.test.ts +0 -111
  482. package/templates/database/__tests__/seed.test.ts +0 -272
  483. package/templates/database/__tests__/spoke-registry.db.test.ts +0 -191
  484. package/templates/database/__tests__/tenancy.test.ts +0 -141
  485. package/templates/database/__tests__/trial-magnet-migration.test.ts +0 -186
  486. package/templates/database/__tests__/user-cascade.test.ts +0 -140
  487. package/templates/database/_gitignore +0 -8
  488. package/templates/database/auth/.gitkeep +0 -0
  489. package/templates/database/auth/schema.prisma +0 -641
  490. package/templates/database/config/.gitkeep +0 -0
  491. package/templates/database/config/schema.prisma +0 -441
  492. package/templates/database/content/.gitkeep +0 -0
  493. package/templates/database/content/schema.prisma +0 -339
  494. package/templates/database/eslint.config.mjs +0 -69
  495. package/templates/database/flows/listing-diagnostic.ts +0 -182
  496. package/templates/database/flows/presets.ts +0 -315
  497. package/templates/database/inbox/.gitkeep +0 -0
  498. package/templates/database/inbox/README.md +0 -3
  499. package/templates/database/inbox/__tests__/schema.test.ts +0 -44
  500. package/templates/database/inbox/schema.prisma +0 -1447
  501. package/templates/database/jest.config.cjs +0 -36
  502. package/templates/database/migrations/20260508000000_add_inbox_namespace/migration.sql +0 -328
  503. package/templates/database/migrations/20260513000000_better_auth_migration/migration.sql +0 -100
  504. package/templates/database/migrations/20260515000000_add_user_billing_fields/migration.sql +0 -28
  505. package/templates/database/migrations/20260516000000_add_user_tier_care_plan_seat/migration.sql +0 -25
  506. package/templates/database/migrations/20260518000000_add_telemetry_records/migration.sql +0 -42
  507. package/templates/database/migrations/20260525000000_theme_wiring/migration.sql +0 -67
  508. package/templates/database/migrations/20260710000000_retire_commercial_tier/migration.sql +0 -21
  509. package/templates/database/migrations/20260712215647_add_multi_tenant_tenancy/migration.sql +0 -201
  510. package/templates/database/migrations/20260713143320_reanchor_site_config_to_workspace/migration.sql +0 -67
  511. package/templates/database/migrations/20260713174000_add_audit_logs/migration.sql +0 -46
  512. package/templates/database/migrations/20260713190000_drop_telemetry_records/migration.sql +0 -25
  513. package/templates/database/migrations/20260713192000_add_uuidv7_function/migration.sql +0 -49
  514. package/templates/database/migrations/20260713192429_prefixed_uuid_entity_ids/migration.sql +0 -197
  515. package/templates/database/migrations/20260713200000_add_org_billing/migration.sql +0 -32
  516. package/templates/database/migrations/20260714000000_add_lead_promotion_fields/migration.sql +0 -22
  517. package/templates/database/migrations/20260714010000_add_usage_billing_content_models/migration.sql +0 -151
  518. package/templates/database/migrations/20260714020000_add_usage_billing_auth_config_models/migration.sql +0 -223
  519. package/templates/database/migrations/20260714030000_credit_balance_non_negative/migration.sql +0 -22
  520. package/templates/database/migrations/20260714030000_widen_usage_billing_report_aggregates/migration.sql +0 -32
  521. package/templates/database/migrations/20260810233516_add_flow_engine_models/migration.sql +0 -40
  522. package/templates/database/migrations/20260811020000_add_flow_session_abandon_email_columns/migration.sql +0 -4
  523. package/templates/database/migrations/20260811030000_add_flow_session_abandon_email_index/migration.sql +0 -2
  524. package/templates/database/migrations/20260811040000_add_flow_session_segment/migration.sql +0 -2
  525. package/templates/database/migrations/20260811050000_add_deliverable_models/migration.sql +0 -29
  526. package/templates/database/migrations/20260812000000_add_deliverable_grant_send_columns/migration.sql +0 -6
  527. package/templates/database/migrations/20260902222948_add_waitlist_experiment_models/migration.sql +0 -39
  528. package/templates/database/migrations/20260902224500_add_waitlist_id_format_checks/migration.sql +0 -24
  529. package/templates/database/migrations/20260903004112_add_flow_session_flags_aeo_score/migration.sql +0 -3
  530. package/templates/database/migrations/20260903010000_add_playbook_instance/migration.sql +0 -33
  531. package/templates/database/migrations/20260904000000_add_waitlist_followup_send/migration.sql +0 -30
  532. package/templates/database/migrations/20260905230000_add_flow_checkout/migration.sql +0 -47
  533. package/templates/database/migrations/20260906000000_add_flow_checkout_idempotency/migration.sql +0 -16
  534. package/templates/database/migrations/20260907120000_add_project_listing/migration.sql +0 -47
  535. package/templates/database/migrations/20260907130000_add_project_listing_slack_columns/migration.sql +0 -10
  536. package/templates/database/migrations/20260907180000_add_listing_csv_send/migration.sql +0 -26
  537. package/templates/database/migrations/20260909120000_project_listings_platform/migration.sql +0 -90
  538. package/templates/database/migrations/20260909180000_listing_draft_and_fields/migration.sql +0 -174
  539. package/templates/database/migrations/20260910120000_listing_public_site_key/migration.sql +0 -14
  540. package/templates/database/migrations/20260911120000_listing_copy_edit_audit/migration.sql +0 -25
  541. package/templates/database/migrations/20260911140000_listing_structured_address/migration.sql +0 -32
  542. package/templates/database/migrations/20260911180000_consent_grants/migration.sql +0 -71
  543. package/templates/database/migrations/20260911200000_listing_site_answers/migration.sql +0 -30
  544. package/templates/database/migrations/20260912120000_listing_owner_link/migration.sql +0 -49
  545. package/templates/database/migrations/20260914120000_listing_founder_identity/migration.sql +0 -123
  546. package/templates/database/migrations/20260915120000_project_listing_solution/migration.sql +0 -15
  547. package/templates/database/migrations/20260916120000_artifact_content_store/migration.sql +0 -158
  548. package/templates/database/migrations/20260917120000_callback_request_confirm/migration.sql +0 -40
  549. package/templates/database/migrations/20260918120000_add_appointment/migration.sql +0 -67
  550. package/templates/database/migrations/20260918120000_asset_metadata_columns/migration.sql +0 -70
  551. package/templates/database/migrations/20260919120000_flow_workspace_key/migration.sql +0 -181
  552. package/templates/database/migrations/20260919130000_flow_definition_admin_columns/migration.sql +0 -172
  553. package/templates/database/migrations/20260919130000_workspace_meetings/migration.sql +0 -41
  554. package/templates/database/migrations/20260919140000_inbox_workspace_key/migration.sql +0 -185
  555. package/templates/database/migrations/20260920120000_lead_handled_at/migration.sql +0 -70
  556. package/templates/database/migrations/20260920130000_lead_workspace_source_index/migration.sql +0 -57
  557. package/templates/database/migrations/20260921120000_deliverable_grant_workspace_key/migration.sql +0 -68
  558. package/templates/database/migrations/20260922120000_tenancy_fence/migration.sql +0 -1067
  559. package/templates/database/migrations/20260923120000_listing_capturing_magnet/migration.sql +0 -210
  560. package/templates/database/migrations/20261003120000_spoke_registry/migration.sql +0 -80
  561. package/templates/database/migrations/20261003130000_scheduling_connection/migration.sql +0 -49
  562. package/templates/database/migrations/20261005120000_agents/migration.sql +0 -84
  563. package/templates/database/migrations/20261008120000_user_last_workspace/migration.sql +0 -35
  564. package/templates/database/migrations/20261008130000_lead_idempotency_key/migration.sql +0 -20
  565. package/templates/database/migrations/20261009120000_agent_grants/migration.sql +0 -33
  566. package/templates/database/migrations/20261010120000_person/migration.sql +0 -106
  567. package/templates/database/migrations/20261010121000_person_backfill/migration.sql +0 -132
  568. package/templates/database/migrations/20261010130000_agent_grants_people_read/migration.sql +0 -20
  569. package/templates/database/migrations/20261011120000_member_area/migration.sql +0 -158
  570. package/templates/database/migrations/20261011130000_agent_grants_member_pieces_manage/migration.sql +0 -21
  571. package/templates/database/migrations/20261012120000_member_contract/migration.sql +0 -192
  572. package/templates/database/migrations/20261013120000_lead_spoke_checkout/migration.sql +0 -20
  573. package/templates/database/migrations/20261014120000_consent_ledger/migration.sql +0 -122
  574. package/templates/database/migrations/20261014120000_person_contact/migration.sql +0 -231
  575. package/templates/database/migrations/20261015120000_person_notes/migration.sql +0 -77
  576. package/templates/database/migrations/20261015120000_rate_limit_counters/migration.sql +0 -43
  577. package/templates/database/migrations/20261016120000_piece_kind/migration.sql +0 -95
  578. package/templates/database/migrations/20261017120000_outbound_message_action/migration.sql +0 -30
  579. package/templates/database/migrations/20261018120000_flow_completion/migration.sql +0 -52
  580. package/templates/database/migrations/20261019120000_consent_source_checkout/migration.sql +0 -27
  581. package/templates/database/migrations/20261020120000_offerings_data_model/migration.sql +0 -146
  582. package/templates/database/migrations/20261021120000_offerings_checkout_session/migration.sql +0 -77
  583. package/templates/database/migrations/20261022120000_in_page_magnets/migration.sql +0 -45
  584. package/templates/database/migrations/20261023120000_offerings_shown_price_ids/migration.sql +0 -47
  585. package/templates/database/migrations/20261024120000_organization_plan_checkout_session/migration.sql +0 -16
  586. package/templates/database/migrations/20261025120000_trial_magnet/migration.sql +0 -28
  587. package/templates/database/migrations/20261026120000_trial_magnet_proof_line/migration.sql +0 -23
  588. package/templates/database/migrations/migration_lock.toml +0 -3
  589. package/templates/database/ops/.gitkeep +0 -0
  590. package/templates/database/ops/schema.prisma +0 -43
  591. package/templates/database/package.json +0 -89
  592. package/templates/database/schema.prisma +0 -71
  593. package/templates/database/scripts/db-generate-locked.sh +0 -80
  594. package/templates/database/scripts/person-backfill.sql +0 -132
  595. package/templates/database/tenancy.ts +0 -183
  596. package/templates/database/tsconfig.build.json +0 -16
  597. package/templates/database/tsconfig.flows.json +0 -15
  598. package/templates/database/tsconfig.json +0 -16
  599. package/templates/database/tsconfig.tenancy.json +0 -14
package/README.md CHANGED
@@ -17,9 +17,13 @@ Compose the site from modules with `--modules`. The recognized vocabulary is
17
17
  `RECOGNIZED_MODULES` in `src/parse-args.ts` — `marketing`, `docs-blog`,
18
18
  `multi-tenant`, `workspace`, `scheduling`, `signal-collectors`, `commerce` —
19
19
  and `--modules` TRIMS or ADDS relative to the level your licence key unlocks
20
- (#6759), never replaces it: with no key the level is Free (`marketing`
21
- alone); a Pro key switches on `docs-blog`, `scheduling` and
22
- `signal-collectors` too; Pro Plus adds `multi-tenant`. Naming modules here
20
+ (#6759), never replaces it: Free is `marketing` alone; a Pro key switches
21
+ on `docs-blog`, `scheduling` and `signal-collectors` too; Pro Plus adds
22
+ `multi-tenant`. A run with no key is a Free run, and Free is held for now
23
+ (`release-scope.json` marks `levels.free` `deferred`, #6484): the CLI refuses
24
+ it before its first write, naming `https://ailaunchkit.ai/pricing` and the
25
+ two ways to pass a key (`--license <key>` or `AILK_LICENSE_KEY`). The Free
26
+ template and level stay defined; only the keyless path is held. Naming modules here
23
27
  keeps exactly those, trimming the level's default; naming only `commerce`
24
28
  (a per-site add-on) or `workspace` (included at Pro, opt-in) adds it on top
25
29
  of the level's default without trimming. The level is always DERIVED from
@@ -42,24 +46,27 @@ vocabulary is `RECOGNIZED_SHAPES` in `src/parse-args.ts` — `organization-produ
42
46
  `organization-service`, `local-business-service`, `person-service` (the README
43
47
  already lists `RECOGNIZED_MODULES` the same way); `local-business-product` is
44
48
  refused as not available yet. A terminal run with no `--shape` asks; a
45
- non-interactive one stops. The level comes only from your license key: no key
46
- is Free, and a key switches on its level's modules (`LEVEL_MODULES`) —
47
- `--modules` trims or adds relative to that set, as above. A keyed example:
49
+ non-interactive one stops. The level comes only from your license key: a key
50
+ switches on its level's modules (`LEVEL_MODULES`) — `--modules` trims or adds
51
+ relative to that set, as above — and no key is the Free level, which is held
52
+ (above), so the run is refused before the shape prompt. A keyed example:
48
53
 
49
54
  ```bash
50
55
  pnpm create ailk@latest my-site --shape organization-service --license <key>
51
56
  ```
52
57
 
53
58
  `--design minimalism` picks the other look and needs a Pro or Pro Plus key;
54
- `standard` (the default) needs none. `--template <alias>` scaffolds one of the
59
+ `standard` (the default) needs none of its own (the run itself still needs a
60
+ key while Free is held, above). `--template <alias>` scaffolds one of the
55
61
  three named aliases (`marketing-site-free`, `marketing-site`, `saas-product`) —
56
62
  each fixes a shape, a design and its own module list — and cannot be combined
57
- with `--shape` or `--design`.
63
+ with `--shape` or `--design`; `marketing-site-free` with no key is refused the
64
+ same way while Free is held.
58
65
 
59
66
  ### Add a purchased module to an existing site
60
67
 
61
- A site scaffolded without a paid module (a Free site whose owner then buys
62
- Pro, say) gets it with `add-module` — alias `upgrade` — run against the site
68
+ A site scaffolded without a paid module (a site scaffolded with `--modules
69
+ marketing` whose owner then adds `docs-blog`, say) gets it with `add-module` — alias `upgrade` — run against the site
63
70
  itself, with `AILK_LICENSE_KEY` covering the module:
64
71
 
65
72
  ```bash
@@ -245,7 +252,7 @@ of three outcomes:
245
252
 
246
253
  - **Copied** — the site lacks it and the template has it: `--apply` copies it
247
254
  (never overwriting) and check mode lists it under `copies:` and `Also
248
- required`.
255
+ required`.
249
256
  - **Left as-is** — the site has it and its copy differs from the template's:
250
257
  it is named under `left as-is (differs from the template)` and never
251
258
  written. The route is still copied; run your type-check afterwards.
@@ -496,6 +503,17 @@ from the module distribution's own 401/403 (`src/lib/fetch-module.ts`). The
496
503
  gate runs before anything is copied (`scaffold()` in `src/programmatic.ts`), so
497
504
  a refused run leaves no partial scaffold behind.
498
505
 
506
+ While the Free level is held (`release-scope.json` `levels.free: "deferred"`,
507
+ #6484), a request that names no paid module needs a key as well: with none,
508
+ `resolvePaidModules` and `cli.ts` call `assertKeyedOrFreeReleased`, which
509
+ refuses the run with `level "free" is not available yet. No licence key, so
510
+ this would be a Free scaffold — pass --license <key> or set AILK_LICENSE_KEY
511
+ with a Pro key → https://ailaunchkit.ai/pricing`, before any prompt, fetch or
512
+ write. The key is read on that path but never validated or sent — an all-Free
513
+ request still makes no request — and a keyed run proceeds exactly as before.
514
+ `AILK_RELEASE_SCOPE=ignore` is the test-only bypass (this package's jest
515
+ setup); a published CLI never sets it.
516
+
499
517
  `AILK_MODULE_REGISTRY_URL` is optional: `fetchModule` uses an explicitly passed
500
518
  `registryUrl`, then that variable, then `https://api.ailaunchkit.ai/v1/modules`
501
519
  (`DEFAULT_AILK_MODULE_REGISTRY_URL`, `src/lib/fetch-module.ts`).
@@ -506,7 +524,10 @@ explicitly passed `registryUrl`, then that variable, then
506
524
  either registry fails the fetch before any second request is sent.
507
525
 
508
526
  ```bash
509
- # free-only — no key read, no network call
527
+ # all-Free — the key is read (Free is held), never validated or sent; no network call
528
+ AILK_LICENSE_KEY=... pnpm create ailk@latest my-site --shape organization-product --modules marketing
529
+
530
+ # the same run with no key is refused before its first write (exit 1)
510
531
  pnpm create ailk@latest my-site --shape organization-product --modules marketing
511
532
 
512
533
  # paid — the key is read from the environment
@@ -515,9 +536,10 @@ AILK_LICENSE_KEY=... pnpm create ailk@latest my-site --shape organization-produc
515
536
 
516
537
  The network invariant (#6759 D6), in full:
517
538
 
518
- - **No key** → no request at all. A request that names no paid module never
519
- reaches the key check either: `resolvePaidModules` returns an empty map on
520
- its first branch, before touching `process.env` or the network.
539
+ - **No key** → no request at all. A request that names no paid module reads
540
+ the key (#6484) but never validates or sends it: `resolvePaidModules` runs
541
+ `assertKeyedOrFreeReleased` — refusing a keyless run while Free is held —
542
+ and returns an empty map on its first branch, before the network.
521
543
  - **A key with no `--modules`** → the level probe (`deriveLevel`): 3-4
522
544
  requests, to find out what the key unlocks.
523
545
  - **An explicit `--modules` list** → requests only for the paid modules it
@@ -526,7 +548,7 @@ The network invariant (#6759 D6), in full:
526
548
  ## What it does
527
549
 
528
550
  1. Validates the target directory does not exist OR is empty.
529
- 2. Copies the curated template tree (`apps/{web,api,mcp}` + `database/` + `content/` + root config files) from the package's `templates/` directory.
551
+ 2. Copies the curated template tree (`apps/{web,api,mcp}` + the thin `database/` — `prisma.config.ts` over the installed `@working-theory/database`, plus the two seeds — + `content/` + root config files) from the package's `templates/` directory.
530
552
  3. Substitutes `workspace:*` references in every `package.json` with the matching `@working-theory/*` semver from npm — versions are pinned at npm-publish time.
531
553
  4. Substitutes `{{PROJECT_NAME}}`, `{{COMPANY_NAME}}`, `{{COMPANY_DOMAIN}}` markers in `templates/README.md` from the target directory name (and CLI flags / interactive prompts in future versions).
532
554
  5. Derives and writes `architecture.yaml` (the site's code-boundary config) from the selected module set — see below.
@@ -557,10 +579,10 @@ declares a slice for every recognized module.
557
579
  ## Templates are snapshotted at build time
558
580
 
559
581
  The `prepublishOnly` script (`scripts/build-templates.mjs`) reads the canonical
560
- sources from this monorepo (`apps/`, `database/`, `content/`, root config) and
561
- populates `templates/`. The npm tarball ships the populated templates via the
562
- `files` field. A free-only scaffold performs no network access at scaffold
563
- time; only `pnpm install` (run by the user after scaffolding) hits the npm
582
+ sources from this monorepo (`apps/`, the two `database/` seeds, `content/`, root
583
+ config) and populates `templates/`. The npm tarball ships the populated templates via the
584
+ `files` field. An all-Free scaffold (a key plus `--modules marketing`)
585
+ performs no network access at scaffold time; only `pnpm install` (run by the user after scaffolding) hits the npm
564
586
  registry. A run naming a paid module fetches that module's bundle — see
565
587
  [Paid modules require `AILK_LICENSE_KEY`](#paid-modules-require-ailk_license_key).
566
588
 
@@ -1283,7 +1283,7 @@
1283
1283
  "sourcePath": "packages/ui/src/blocks/ListRow.tsx",
1284
1284
  "importPath": "@working-theory/ui/blocks",
1285
1285
  "exported": true,
1286
- "description": "The PHONE form of one admin list item. The reference is `apps-paid/admin/design/demos/first-steps/demo.html:475` (`rowDoc`), which lays the row out as: a leading type glyph, a two-line text column with the MUTED META LINE FIRST and the item's name second (every phone screen in the demo agrees), an optional trailing control, and a chevron.",
1286
+ "description": "The PHONE form of one admin list item. The reference is `packages-paid/admin/design/demos/first-steps/demo.html:475` (`rowDoc`), which lays the row out as: a leading type glyph, a two-line text column with the MUTED META LINE FIRST and the item's name second (every phone screen in the demo agrees), an optional trailing control, and a chevron.",
1287
1287
  "descriptionSource": "doc-comment",
1288
1288
  "descriptionGrade": "strong",
1289
1289
  "sectionType": null
@@ -1294,7 +1294,7 @@
1294
1294
  "sourcePath": "packages/ui/src/blocks/ListTable.tsx",
1295
1295
  "importPath": "@working-theory/ui/blocks",
1296
1296
  "exported": true,
1297
- "description": "The desktop form: a fixed-layout list table that never wraps, with the shared Tags and Live cells. The reference is `apps-paid/admin/design/demos/first-steps/demo.html`'s `.tbl`: `table-layout:fixed` on the table and `white-space:nowrap;overflow:hidden;text-overflow:ellipsis` on every cell. BOTH are load-bearing — `table-fixed` alone lets the cell wrap, `truncate` alone lets the browser widen the column to fit.",
1297
+ "description": "The desktop form: a fixed-layout list table that never wraps, with the shared Tags and Live cells. The reference is `packages-paid/admin/design/demos/first-steps/demo.html`'s `.tbl`: `table-layout:fixed` on the table and `white-space:nowrap;overflow:hidden;text-overflow:ellipsis` on every cell. BOTH are load-bearing — `table-fixed` alone lets the cell wrap, `truncate` alone lets the browser widen the column to fit.",
1298
1298
  "descriptionSource": "barrel",
1299
1299
  "descriptionGrade": "strong",
1300
1300
  "sectionType": null
@@ -1646,7 +1646,7 @@
1646
1646
  "sourcePath": "packages/ui/src/blocks/RowGroup.tsx",
1647
1647
  "importPath": "@working-theory/ui/blocks",
1648
1648
  "exported": true,
1649
- "description": "The bordered box that groups ListRows with hairline dividers. The reference is `apps-paid/admin/design/demos/first-steps/demo.html`'s `.box` (`background:var(--bg);border:1px solid var(--border); border-radius:6px;overflow:hidden`) with `.row{border-top:…}` and `.row:first-child{border-top:0}` — i.e. hairlines BETWEEN rows, none above the first.",
1649
+ "description": "The bordered box that groups ListRows with hairline dividers. The reference is `packages-paid/admin/design/demos/first-steps/demo.html`'s `.box` (`background:var(--bg);border:1px solid var(--border); border-radius:6px;overflow:hidden`) with `.row{border-top:…}` and `.row:first-child{border-top:0}` — i.e. hairlines BETWEEN rows, none above the first.",
1650
1650
  "descriptionSource": "barrel",
1651
1651
  "descriptionGrade": "strong",
1652
1652
  "sectionType": null
@@ -177,8 +177,8 @@ Import: `import { X } from "@working-theory/ui/blocks";` (or from the `@working-
177
177
  | `LeadCaptureForm` | The one contact form every template renders. Submits ONLY through the `action` prop — a Server Action the page binds — so there is no fetch, no URL and no browser-side JSON here. | `import { LeadCaptureForm } from "@working-theory/ui/blocks"` |
178
178
  | `LinkCard` | A whole-tile link card: the entire tile IS the anchor (Claude-docs link-card anatomy). Optional leading icon, a title heading, and an optional description paragraph. Hover fill + chrome are intrinsic to the block — never props. | `import { LinkCard } from "@working-theory/ui/blocks"` |
179
179
  | `LinkListItem` | Hub-page spoke list row: prose Link + optional description, enlarged to the 44px touch-target floor. Fix: the enlarged-hit-area pattern (same idiom as ShortcutTrigger, SegmentedControl's touchTargetFloor) — `min-h-(control-height-big)` clamps the anchor's clickable box to 44px while `inline-flex items-center` keeps the visible text at its normal prose size. | `import { LinkListItem } from "@working-theory/ui/blocks"` |
180
- | `ListRow` | The PHONE form of one admin list item. The reference is `apps-paid/admin/design/demos/first-steps/demo.html:475` (`rowDoc`), which lays the row out as: a leading type glyph, a two-line text column with the MUTED META LINE FIRST and the item's name second (every phone screen in the demo agrees), an optional trailing control, and a chevron. | `import { ListRow } from "@working-theory/ui/blocks"` |
181
- | `ListTable` | The desktop form: a fixed-layout list table that never wraps, with the shared Tags and Live cells. The reference is `apps-paid/admin/design/demos/first-steps/demo.html`'s `.tbl`: `table-layout:fixed` on the table and `white-space:nowrap;overflow:hidden;text-overflow:ellipsis` on every cell. BOTH are load-bearing — `table-fixed` alone lets the cell wrap, `truncate` alone lets the browser widen the column to fit. | `import { ListTable } from "@working-theory/ui/blocks"` |
180
+ | `ListRow` | The PHONE form of one admin list item. The reference is `packages-paid/admin/design/demos/first-steps/demo.html:475` (`rowDoc`), which lays the row out as: a leading type glyph, a two-line text column with the MUTED META LINE FIRST and the item's name second (every phone screen in the demo agrees), an optional trailing control, and a chevron. | `import { ListRow } from "@working-theory/ui/blocks"` |
181
+ | `ListTable` | The desktop form: a fixed-layout list table that never wraps, with the shared Tags and Live cells. The reference is `packages-paid/admin/design/demos/first-steps/demo.html`'s `.tbl`: `table-layout:fixed` on the table and `white-space:nowrap;overflow:hidden;text-overflow:ellipsis` on every cell. BOTH are load-bearing — `table-fixed` alone lets the cell wrap, `truncate` alone lets the browser widen the column to fit. | `import { ListTable } from "@working-theory/ui/blocks"` |
182
182
  | `LocaleSwitcher` | Compact globe + locale dropdown. Extracts the "🌐 English ▾" affordance that lived as an inline node in the chrome Footer story into a reusable block. Composes the `Select` primitive (NOT a raw &lt;select>): a leading globe icon, the current locale label (via SelectValue), and the trigger's built-in chevron. | `import { LocaleSwitcher } from "@working-theory/ui/blocks"` |
183
183
  | `LocaleSwitcherNav` | Composes the controlled `LocaleSwitcher` block and owns the navigation side-effect that block deliberately leaves to its consumer: on a locale change it writes the `NEXT_LOCALE` cookie and navigates to the as-needed prefixed path (default locale unprefixed, every other locale `/&lt;code>` + path — mirroring `apps/web/middleware.ts`'s `localePrefix: "as-needed"`). | `import { LocaleSwitcherNav } from "@working-theory/ui/blocks"` |
184
184
  | `LogoRow` | The ONE logo-strip implementation; bounded layout/treatment/logoSize plus an opt-in motion-safe marquee; composed by the LogoCloud section and the Hero logoStrip opt-in. | `import { LogoRow } from "@working-theory/ui/blocks"` |
@@ -210,7 +210,7 @@ Import: `import { X } from "@working-theory/ui/blocks";` (or from the `@working-
210
210
  | `Prose` | The single typography wrapper both the docs route and blog render their compiled-MDX body inside. It styles every RAW markdown element a compiled document emits — h2–h6, p, ul/ol/li, blockquote, table parts, hr, a, inline code, pre, img, kbd, strong/em — via `@working-theory/theme` semantic tokens and type roles. No raw color or spacing literals; dark mode rides the semantic tokens (no `dark:` variants needed). | `import { Prose } from "@working-theory/ui/blocks"` |
211
211
  | `RecommendationCard` | "For you" proactive-recommendation tile: status + title + description + "Why this?" disclosure + context chip + action + dismiss (ploy-capture recomposition). The "For you" proactive-recommendation card captured off ploy.ai's Overview page (behavior spec: -2, — `overview-page` "For you" feed / rebuild-triage row "For you" recommendation card"). | `import { RecommendationCard } from "@working-theory/ui/blocks"` |
212
212
  | `ResponsiveSheet` | ONE component, TWO forms, ONE open pair. Renders its `children` as a Radix Dialog at `md` (768px, --breakpoint-md) and up, and as a full-screen Radix Sheet below it — never both at once. | `import { ResponsiveSheet } from "@working-theory/ui/blocks"` |
213
- | `RowGroup` | The bordered box that groups ListRows with hairline dividers. The reference is `apps-paid/admin/design/demos/first-steps/demo.html`'s `.box` (`background:var(--bg);border:1px solid var(--border); border-radius:6px;overflow:hidden`) with `.row{border-top:…}` and `.row:first-child{border-top:0}` — i.e. hairlines BETWEEN rows, none above the first. | `import { RowGroup } from "@working-theory/ui/blocks"` |
213
+ | `RowGroup` | The bordered box that groups ListRows with hairline dividers. The reference is `packages-paid/admin/design/demos/first-steps/demo.html`'s `.box` (`background:var(--bg);border:1px solid var(--border); border-radius:6px;overflow:hidden`) with `.row{border-top:…}` and `.row:first-child{border-top:0}` — i.e. hairlines BETWEEN rows, none above the first. | `import { RowGroup } from "@working-theory/ui/blocks"` |
214
214
  | `SchedulerEmbed` | A declarative third-party booking iframe. Renders a full-width, border-0, lazy-loaded &lt;iframe> at `src` with a graceful loading skeleton (shown until the iframe's own `load` event fires) and a timeout-gated plain-link fallback beneath it — for environments that block third-party frames (ad blockers, a strict CSP `frame-src`) where the iframe may load blank or never load at all. | `import { SchedulerEmbed } from "@working-theory/ui/blocks"` · `packages/ui/src/blocks/SchedulerEmbed.tsx` |
215
215
  | `SectionActionRow` | The bottom-anchored, centered action row a section places BENEATH its own content, at the 44×44px target-size floor. It is the block form of the placement established for `stair-steps`: a bounded 1-2 action list rendered after the section body rather than inside the section header. | `import { SectionActionRow } from "@working-theory/ui/blocks"` |
216
216
  | `SectionHeader` | Alignment-parameterized section header (eyebrow/subtitle/description/supportLink). The same component serves two ranks (headingLevel="section" \| "subsection") and three alignments (align="start" \| "center" \| "end"). It knows nothing about columns/splits/carousels — it is width-flexible and fills whatever container the section places it in. | `import { SectionHeader } from "@working-theory/ui/blocks"` |
@@ -35,7 +35,7 @@ import { writeAuthSecretFile } from "./lib/auth-secret-file.js";
35
35
  import { appendEnvRows } from "./lib/declared-env.js";
36
36
  import { diffTwoStrings, extractModuleBundle, } from "./lib/extract-module-bundle.js";
37
37
  import { normalizeModules } from "./module-architecture.js";
38
- import { MODULE_FLAGS_PATH, PAID_SECTIONS_PATH, writePaidSections } from "./paid-sections.js";
38
+ import { MODULE_FLAGS_PATH, PAID_MCP_TOOLS_PATH, PAID_SECTIONS_PATH, writePaidSections, } from "./paid-sections.js";
39
39
  import { ParseError, parseModules } from "./parse-args.js";
40
40
  import { writeSpokeFlowsReadme } from "./seed-flows.js";
41
41
  import { SITE_ROSTER_PATH, moduleRosterRows, planRosterAppend, readSiteRoster, siteRosterProblems, } from "./site-roster.js";
@@ -211,7 +211,9 @@ export async function applyModuleToScaffold(opts) {
211
211
  // overwritten, like `architecture.yaml` above.
212
212
  // #8843 D10 — its module-presence flags follow the same file, and are
213
213
  // reported the same way when a module turns one on.
214
- const generated = [PAID_SECTIONS_PATH, MODULE_FLAGS_PATH].map((path) => {
214
+ // #9460 DD6 — the paid MCP tool registry follows `apps/mcp/package.json`
215
+ // the same way.
216
+ const generated = [PAID_SECTIONS_PATH, MODULE_FLAGS_PATH, PAID_MCP_TOOLS_PATH].map((path) => {
215
217
  const abs = join(targetAbs, path);
216
218
  return { path, abs, before: existsSync(abs) ? readFileSync(abs, "utf8") : undefined };
217
219
  });
@@ -72,6 +72,11 @@ export interface AddMagnetResult {
72
72
  flow: string;
73
73
  /** The landing's row, then the walk's. */
74
74
  report: MagnetReportRow[];
75
+ /**
76
+ * The `customizations.yaml` entry mapping both pages, indented to append
77
+ * under `customizations:` as `--seed-customizations` prints entries.
78
+ */
79
+ entry: string;
75
80
  }
76
81
  /**
77
82
  * Write a magnet page pair — `apps/web/app/[locale]/<path>/page.tsx` (the
@@ -83,6 +88,12 @@ export interface AddMagnetResult {
83
88
  * that already exists is never overwritten: a second run reports both
84
89
  * `skipped`. No `architecture.yaml`, nav or seed changes — the pair is the
85
90
  * site's own, with no `ROUTE_SINCE` key or routes-map row (D13).
91
+ *
92
+ * Being the site's own, the pair is no template-record row either: `update`
93
+ * deletes an untouched recorded file the template does not carry. So the
94
+ * site lint's R5a reads both pages as site-authored, and the result carries
95
+ * the `customizations.yaml` entry that maps them, a site-kept decision the
96
+ * report prints ready to paste (#9553).
86
97
  */
87
98
  export declare function addMagnetToScaffold(opts: AddMagnetOptions): AddMagnetResult;
88
99
  /** The report `add-route magnet` prints. */
@@ -98,7 +109,7 @@ export interface AddRouteArgs {
98
109
  /** `--flow`, the magnet mode's flow slug — set only with `magnet`. */
99
110
  flow?: string;
100
111
  }
101
- export declare const ADD_ROUTE_HELP = "create-ailk add-route \u2014 add a route family to an existing site.\n\nUsage:\n create-ailk add-route <route> [<target-dir>]\n create-ailk add-route magnet --path <path> --flow <slug> [<target-dir>]\n\nArguments:\n <route> One route family, named as --surfaces names it,\n e.g. pricing.\n <target-dir> An already-scaffolded repo (contains\n architecture.yaml). Defaults to the current dir.\n\nOptions:\n --path <path> magnet only: the site path the landing serves,\n one to three kebab-case segments, e.g. /diagnostic.\n --flow <slug> magnet only: the flow slug the pages are bound to.\n --help, -h Print this message.\n\nCopies the route's pages, writes its seed content, declares it in\narchitecture.yaml and adds its link to the generated nav \u2014 the site a fresh\nscaffold with --surfaces <route> would have been. A file the site already has\nis never overwritten: one whose content differs, a hand-edited nav included,\nis left as-is and listed for manual review with the change the route wanted.\nLike add-module, it also restores any other page route the site carries but\nlacks. A route a module delivers (blog and docs come with docs-blog) is\nrefused; add that module with create-ailk add-module. Running it again changes\nnothing.\n\nadd-route magnet writes a magnet page pair bound to one flow: a landing at\napps/web/app/[locale]/<path>/page.tsx and a full-screen walk at\n<path>/start/page.tsx, each a few lines over the standard magnet pages, so the\ncopy, consent and ending come from the flow's record. It needs the\nsignal-collectors module, and refuses (nothing written) a path the site already\nserves, a one-segment path a LandingPage seed of the same slug owns, a path\nending in start or apply, a reserved first segment (api, v1, flows, account,\nadmin, the sign-in routes, a locale) and a slug the flow API would refuse. A\npage that exists is never overwritten: running it again skips both. It changes\nno architecture.yaml, nav or seed.\n";
112
+ export declare const ADD_ROUTE_HELP = "create-ailk add-route \u2014 add a route family to an existing site.\n\nUsage:\n create-ailk add-route <route> [<target-dir>]\n create-ailk add-route magnet --path <path> --flow <slug> [<target-dir>]\n\nArguments:\n <route> One route family, named as --surfaces names it,\n e.g. pricing.\n <target-dir> An already-scaffolded repo (contains\n architecture.yaml). Defaults to the current dir.\n\nOptions:\n --path <path> magnet only: the site path the landing serves,\n one to three kebab-case segments, e.g. /diagnostic.\n --flow <slug> magnet only: the flow slug the pages are bound to.\n --help, -h Print this message.\n\nCopies the route's pages, writes its seed content, declares it in\narchitecture.yaml and adds its link to the generated nav \u2014 the site a fresh\nscaffold with --surfaces <route> would have been. A file the site already has\nis never overwritten: one whose content differs, a hand-edited nav included,\nis left as-is and listed for manual review with the change the route wanted.\nLike add-module, it also restores any other page route the site carries but\nlacks. A route a module delivers (blog and docs come with docs-blog) is\nrefused; add that module with create-ailk add-module. Running it again changes\nnothing.\n\nadd-route magnet writes a magnet page pair bound to one flow: a landing at\napps/web/app/[locale]/<path>/page.tsx and a full-screen walk at\n<path>/start/page.tsx, each a few lines over the standard magnet pages, so the\ncopy, consent and ending come from the flow's record. It needs the\nsignal-collectors module, and refuses (nothing written) a path the site already\nserves, a one-segment path a LandingPage seed of the same slug owns, a path\nending in start or apply, a reserved first segment (api, v1, flows, account,\nadmin, the sign-in routes, a locale) and a slug the flow API would refuse. A\npage that exists is never overwritten: running it again skips both. It changes\nno architecture.yaml, nav or seed; it prints the customizations.yaml entry\nthat maps the two pages, for pnpm architecture.\n";
102
113
  /**
103
114
  * Parse the argv AFTER the `add-route` word. Strict `node:util` parseArgs,
104
115
  * like `parseAddModuleArgs`; the route itself is validated by
package/dist/add-route.js CHANGED
@@ -314,6 +314,11 @@ const RESERVED_FIRST_SEGMENTS = new Set([
314
314
  const LOCALE_SHAPED_RE = /^[a-z]{2}(-[a-z]{2})?$/;
315
315
  /** Template-relative root every page directory sits under. */
316
316
  const WEB_ROUTE_ROOT = "apps/web/app/[locale]";
317
+ /**
318
+ * The `request` a pair's `customizations.yaml` entry names (#9553): the AILK
319
+ * issue that made the pair the site's own page (#8840 C1).
320
+ */
321
+ const MAGNET_REQUEST = "working-theory-labs/ai-launch-kit-internal#8840";
317
322
  /** Whether `slug` passes `flowSlugSchema`'s rule. */
318
323
  export function isMagnetFlowSlug(slug) {
319
324
  return slug.length <= FLOW_SLUG_MAX && FLOW_SLUG_RE.test(slug);
@@ -328,6 +333,12 @@ export function isMagnetFlowSlug(slug) {
328
333
  * that already exists is never overwritten: a second run reports both
329
334
  * `skipped`. No `architecture.yaml`, nav or seed changes — the pair is the
330
335
  * site's own, with no `ROUTE_SINCE` key or routes-map row (D13).
336
+ *
337
+ * Being the site's own, the pair is no template-record row either: `update`
338
+ * deletes an untouched recorded file the template does not carry. So the
339
+ * site lint's R5a reads both pages as site-authored, and the result carries
340
+ * the `customizations.yaml` entry that maps them, a site-kept decision the
341
+ * report prints ready to paste (#9553).
331
342
  */
332
343
  export function addMagnetToScaffold(opts) {
333
344
  const targetAbs = resolve(opts.targetDir);
@@ -382,7 +393,23 @@ export function addMagnetToScaffold(opts) {
382
393
  writeFileSync(dest, text);
383
394
  report.push({ path, action: "written" });
384
395
  }
385
- return { targetDir: targetAbs, path: opts.path, flow: opts.flow, report };
396
+ // Segments join on `--`, which no kebab segment carries, so `/a-b` and
397
+ // `/a/b` never share an id.
398
+ const today = new Date().toISOString().slice(0, 10);
399
+ const entry = [
400
+ ` - id: ${JSON.stringify(`magnet-${segments.join("--")}`)}`,
401
+ " paths:",
402
+ ...pages.map(([path]) => ` - ${JSON.stringify(path)}`),
403
+ ` request: ${JSON.stringify(MAGNET_REQUEST)}`,
404
+ ` decision: ${JSON.stringify(`build-in: site — ailk#8840, ${today}, a magnet pair is the site's own page over AILK's standard renderers`)}`,
405
+ ].join("\n");
406
+ return {
407
+ targetDir: targetAbs,
408
+ path: opts.path,
409
+ flow: opts.flow,
410
+ report,
411
+ entry,
412
+ };
386
413
  }
387
414
  /** `--path`'s segments, refusing a path a pair may not take (SEC-8840-J). */
388
415
  function magnetPathSegments(path) {
@@ -507,7 +534,7 @@ export function formatAddMagnetReport(result) {
507
534
  lines.push(...skipped.map((row) => ` ${row.path}`));
508
535
  }
509
536
  if (written.length > 0) {
510
- lines.push(`Next: pnpm build, then open ${result.path}. The page's copy comes from the ${result.flow} flow's record.`);
537
+ lines.push(`Next: append this entry to customizations.yaml unless it is there already (an empty \`customizations: []\` becomes \`customizations:\` first), then pnpm build and open ${result.path}. The page's copy comes from the ${result.flow} flow's record.`, result.entry);
511
538
  }
512
539
  return lines.join("\n") + "\n";
513
540
  }
@@ -548,7 +575,8 @@ serves, a one-segment path a LandingPage seed of the same slug owns, a path
548
575
  ending in start or apply, a reserved first segment (api, v1, flows, account,
549
576
  admin, the sign-in routes, a locale) and a slug the flow API would refuse. A
550
577
  page that exists is never overwritten: running it again skips both. It changes
551
- no architecture.yaml, nav or seed.
578
+ no architecture.yaml, nav or seed; it prints the customizations.yaml entry
579
+ that maps the two pages, for pnpm architecture.
552
580
  `;
553
581
  /**
554
582
  * Parse the argv AFTER the `add-route` word. Strict `node:util` parseArgs,
package/dist/cli.js CHANGED
@@ -55,7 +55,7 @@ import { ADOPT_HELP, AdoptRefusedError, adoptSite, formatAdoptReport, parseAdopt
55
55
  import { APPLY_DESIGN_HELP, applyDesign, formatApplyDesignReport, parseApplyDesignArgs, } from "./apply-design.js";
56
56
  import { CLAUDE_MD_CHECK_PATH } from "./claude-md.js";
57
57
  import { buildScaffoldMarkers } from "./copy.js";
58
- import { assertReleased } from "./lib/module-license-gate.js";
58
+ import { assertKeyedOrFreeReleased, assertReleased } from "./lib/module-license-gate.js";
59
59
  import { withNpmTokenUserConfig } from "./lib/npm-auth.js";
60
60
  import { FREE_PREREQUISITES_NOTE, LICENSED_PREREQUISITES_NOTE, isLicensedInstall, proCallout, } from "./lib/pro-callout.js";
61
61
  import { LICENSE_SET_HELP, runLicenseSet } from "./license-set.js";
@@ -309,6 +309,7 @@ async function main() {
309
309
  targetDir: args.target ?? process.cwd(),
310
310
  templatesDir: resolve(PKG_ROOT, "templates"),
311
311
  version: readPackageVersion(),
312
+ versions: readVersionMap(),
312
313
  });
313
314
  process.stdout.write(formatUpdateReport(result));
314
315
  }
@@ -328,6 +329,8 @@ async function main() {
328
329
  if (parsed.needsShapePrompt && !parsed.help && !parsed.version) {
329
330
  assertReleased("designs", [parsed.design]);
330
331
  assertReleased("modules", parsed.modules ?? []);
332
+ // #6484 — and a keyless run, which is the Free level the scope defers.
333
+ assertKeyedOrFreeReleased(parsed.license);
331
334
  }
332
335
  const opts = await resolveCliShape(parsed, {
333
336
  input: process.stdin,
@@ -433,10 +436,12 @@ async function main() {
433
436
  // rejection (caught at top level below). The network invariant (#6759 D6):
434
437
  // no key → no request at all; a key with no --modules → the D4 level probe
435
438
  // (3-4 requests); an explicit --modules list → requests only for the paid
436
- // modules it names, exactly as before this card. `--template
437
- // marketing-site-free` still rides the no-key case (record D11): its
438
- // `requires` is all-free, so it installs from the shipped
439
- // `site-templates/` tree with no key and no request.
439
+ // modules it names, exactly as before this card. A keyless run — `--template
440
+ // marketing-site-free` included, whose all-free `requires` once rode the
441
+ // no-key case (record D11) — is refused by the licence gate inside
442
+ // scaffold() (#6484, REL-034.1: Free is a deferred level,
443
+ // `release-scope.json`), after its scope-name refusals and before its first
444
+ // write, naming the pricing page. With a key, every branch is as before.
440
445
  const { targetDir: targetAbs, surfaces, starter, modules: effectiveModules, droppedModules, hubOrigin, hubSignInOrigin, } = await scaffold(toScaffoldOptions(opts));
441
446
  const isSpoke = opts.topology === "spoke";
442
447
  // The starter scaffold() resolved — from --template, or from --shape (#6754 D4).
@@ -491,7 +496,7 @@ async function main() {
491
496
  " AILK_HUB_CLIENT_SECRET # issued by the hub; never written here",
492
497
  "",
493
498
  "On the hub, issue the client id and secret with:",
494
- " pnpm --filter @working-theory/api spokes sign-in-client --id <spoke_id> --redirect-uri <this site's origin>/api/hub-session/callback",
499
+ " pnpm --filter @working-theory/app-api spokes sign-in-client --id <spoke_id> --redirect-uri <this site's origin>/api/hub-session/callback",
495
500
  ]
496
501
  : []),
497
502
  ]
@@ -500,7 +505,7 @@ async function main() {
500
505
  ];
501
506
  // Prerequisites (#6440 AC4) — every one the scaffold enforces, and nothing
502
507
  // it does not. A starter reaches `pnpm dev` AND `pnpm build` on a toolchain
503
- // alone: the Prisma client is generated by `database`'s own `postinstall`,
508
+ // alone: the Prisma client ships prebuilt in `@working-theory/database`,
504
509
  // so there is no generator step to remember, and no database or vendor API
505
510
  // key gates either command (a free install also says no licence key does;
506
511
  // a licensed one, #6480, does not). Saying so is the point — the previous
@@ -14,7 +14,7 @@
14
14
  * fixed document shape this module produces — no `yaml`/`js-yaml` dependency.
15
15
  */
16
16
  import { type ForbiddenPattern } from "./module-architecture.js";
17
- import type { Topology } from "./topology.js";
17
+ import { type Topology } from "./topology.js";
18
18
  /** The topology a document is derived for (#7426 D8). */
19
19
  export interface DeriveArchitectureOptions {
20
20
  /** `"hub"` (the default) or `"spoke"`. */
@@ -51,9 +51,8 @@ export declare const SPOKE_MCP_FORBIDDEN_PATTERNS: readonly ForbiddenPattern[];
51
51
  * modules gets exactly what the modules imply.
52
52
  * @param options the topology (#7426 D8). Absent or `"hub"` ⟹ the output is
53
53
  * byte-identical to the two-argument form. `"spoke"` ⟹ only the spoke's own
54
- * apps (`web`, and `mcp` unless `mcp: false`), no `namespaces`, no
55
- * `database` root, a top-level `topology: spoke` and the hub-facing
56
- * composition tiers.
54
+ * apps (`web`, and `mcp` unless `mcp: false`), no `database` root, a
55
+ * top-level `topology: spoke` and the hub-facing composition tiers.
57
56
  * @returns the complete `architecture.yaml` file content (a deterministic
58
57
  * function of the module SET, the surface SET and the topology).
59
58
  * @throws Error on an unrecognized module (defensive; parse-args rejects first).
@@ -14,9 +14,19 @@
14
14
  * fixed document shape this module produces — no `yaml`/`js-yaml` dependency.
15
15
  */
16
16
  import { ARCHITECTURE_BASE, MODULE_SLICES, normalizeModules, } from "./module-architecture.js";
17
- import { CORE_SURFACE_PATHS, RECOGNIZED_SURFACES, resolveSurfaces, } from "./surfaces.js";
17
+ import { MODULE_FLAGS_PATH, PAID_MCP_TOOLS_PATH, PAID_SECTIONS_PATH } from "./paid-sections.js";
18
+ import { SITE_CHROME_PATH } from "./site-chrome.js";
19
+ import { SITE_FONTS_PATH } from "./site-fonts.js";
20
+ import { SPOKE_CHECKOUT_CONFIG_PATH, SPOKE_CHECKOUT_TEMPLATE_PATHS, } from "./spoke-checkout.js";
21
+ import { CORE_SURFACE_PATHS, NAV_CONFIG_PATH, RECOGNIZED_SURFACES, resolveSurfaces, } from "./surfaces.js";
22
+ import { SPOKE_SEAM_FILES } from "./topology.js";
18
23
  /** The npm scope a site consumes and never forks (#9191). */
19
24
  const PACKAGE_SCOPE = "@working-theory/";
25
+ /** Apps whose `package.json` name is not `@working-theory/<dir>`, because the published package took it (#9564, #9570). */
26
+ const SHELL_PACKAGE_NAME = {
27
+ api: "app-api",
28
+ admin: "admin-shell",
29
+ };
20
30
  /** A spoke's composition tiers (#7426 D8): its data and API are the hub's. */
21
31
  const SPOKE_TIERS = {
22
32
  data: "none — the hub's database",
@@ -209,18 +219,6 @@ function appToYaml(app) {
209
219
  }
210
220
  return m;
211
221
  }
212
- function namespacesToYaml(ns) {
213
- const members = {};
214
- const sortedMembers = Object.entries(ns.members).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
215
- for (const [key, mem] of sortedMembers) {
216
- members[key] = { path: mem.path, description: mem.description };
217
- }
218
- return {
219
- description: ns.description,
220
- members,
221
- rules: [...ns.rules],
222
- };
223
- }
224
222
  /**
225
223
  * Derive the `architecture.yaml` document for a module set.
226
224
  *
@@ -231,9 +229,8 @@ function namespacesToYaml(ns) {
231
229
  * modules gets exactly what the modules imply.
232
230
  * @param options the topology (#7426 D8). Absent or `"hub"` ⟹ the output is
233
231
  * byte-identical to the two-argument form. `"spoke"` ⟹ only the spoke's own
234
- * apps (`web`, and `mcp` unless `mcp: false`), no `namespaces`, no
235
- * `database` root, a top-level `topology: spoke` and the hub-facing
236
- * composition tiers.
232
+ * apps (`web`, and `mcp` unless `mcp: false`), no `database` root, a
233
+ * top-level `topology: spoke` and the hub-facing composition tiers.
237
234
  * @returns the complete `architecture.yaml` file content (a deterministic
238
235
  * function of the module SET, the surface SET and the topology).
239
236
  * @throws Error on an unrecognized module (defensive; parse-args rejects first).
@@ -306,11 +303,10 @@ export function deriveArchitecture(modules = ["marketing"], surfaces, options =
306
303
  forbidden_patterns: mergeForbidden([...ARCHITECTURE_BASE.appForbiddenPatterns], [...(a.forbidden_patterns ?? []), ...extra]).map(scoped),
307
304
  });
308
305
  }
309
- // namespaces — present only if a data-tier module contributes one, and
310
- // never on a spoke, which has no database/ of its own.
311
- const nsSlice = spoke
312
- ? undefined
313
- : slices.find((s) => s.namespaces)?.namespaces;
306
+ // No `namespaces` block (#9569): a site's `database/` holds no schema — the
307
+ // namespace boundaries belong to `@working-theory/database`'s own source and
308
+ // this monorepo's lint, and a rule naming `database/<ns>` paths a scaffold
309
+ // lacks is what #6940 refuses.
314
310
  // forbidden_patterns — base floor first, then the selected modules' patterns.
315
311
  const extraForbidden = [];
316
312
  for (const s of slices)
@@ -319,17 +315,57 @@ export function deriveArchitecture(modules = ["marketing"], surfaces, options =
319
315
  // The upgradeable-consumer rules (#9191): the workspaces this scaffold
320
316
  // creates and the in-scope package names it gives them. The site lint
321
317
  // reads this block to refuse a forked, patched or pinned-off package.
322
- // Every app the scaffold ships is named `@working-theory/<dir>`.
318
+ // A hub's `database/` is a plain folder, not a workspace (#9569): the
319
+ // package is an npm dependency the same-caret rule covers like any other.
323
320
  const upgradeableConsumer = {
324
321
  package_scope: PACKAGE_SCOPE,
325
- workspaces: spoke ? ["apps/*"] : ["apps/*", "database"],
326
- scaffold_packages: [
327
- ...(spoke ? [] : ["database"]),
328
- ...Object.keys(apps),
329
- ]
330
- .map((dir) => `${PACKAGE_SCOPE}${dir}`)
322
+ workspaces: ["apps/*"],
323
+ // Every app the scaffold ships is named `@working-theory/<dir>`, except
324
+ // the two whose published package took the name: `@working-theory/api` is
325
+ // what the API app boots from (#9564), so the app is
326
+ // `@working-theory/app-api`; `@working-theory/admin` is what the Admin
327
+ // shell boots from (#9570), so the app is `@working-theory/admin-shell`.
328
+ scaffold_packages: Object.keys(apps)
329
+ .map((dir) => `${PACKAGE_SCOPE}${SHELL_PACKAGE_NAME[dir] ?? dir}`)
331
330
  .sort(),
332
331
  };
332
+ // The customizations manifest (#9223): the files under `apps/` the template
333
+ // record (`.ailk-template-files.json`) cannot see, so the site lint can tell
334
+ // a site-authored file from a scaffolded one by membership alone. (a) The
335
+ // generator outputs, on a hub and a spoke alike — an exempted path that is
336
+ // absent exempts nothing, and only a create-ailk generator writes each. The
337
+ // constants are composed here, never at module top level: `spoke-checkout`
338
+ // imports this module back, and `template-record`'s own list is deliberately
339
+ // not imported (it reads `spoke-checkout` at top level). (b) Each selected
340
+ // module's bundle-delivered and patched app files, scoped to the apps this
341
+ // derivation declares. (c) A commerce spoke's checkout slice, which
342
+ // `add-module` writes with no record row.
343
+ const generatorPaths = [
344
+ NAV_CONFIG_PATH,
345
+ SITE_CHROME_PATH,
346
+ SITE_FONTS_PATH,
347
+ PAID_SECTIONS_PATH,
348
+ MODULE_FLAGS_PATH,
349
+ PAID_MCP_TOOLS_PATH,
350
+ ...SPOKE_SEAM_FILES,
351
+ SPOKE_CHECKOUT_CONFIG_PATH,
352
+ SPOKE_BILLING_ACTION_PATH,
353
+ ];
354
+ const modulePaths = [];
355
+ for (const s of slices) {
356
+ modulePaths.push(...(s.ownedFiles ?? []));
357
+ modulePaths.push(...Object.values(s.installMap ?? {}));
358
+ if (s.installRoot)
359
+ modulePaths.push(`${s.installRoot.replace(/\/$/, "")}/**`);
360
+ modulePaths.push(...(s.patches ?? []).map((p) => p.target));
361
+ }
362
+ const checkoutPaths = spoke && selected.includes("commerce")
363
+ ? SPOKE_CHECKOUT_TEMPLATE_PATHS.map((p) => (/\.[^/]+$/.test(p) ? p : `${p}/**`))
364
+ : [];
365
+ const customizations = {
366
+ manifest: "customizations.yaml",
367
+ scaffold_paths: sortedUnion(generatorPaths, [...modulePaths, ...checkoutPaths].filter((p) => p.startsWith("apps/") && inScaffold(p))),
368
+ };
333
369
  const doc = {
334
370
  version: ARCHITECTURE_BASE.version,
335
371
  ...(spoke ? { topology: "spoke" } : {}),
@@ -344,9 +380,9 @@ export function deriveArchitecture(modules = ["marketing"], surfaces, options =
344
380
  available: [...RECOGNIZED_SURFACES],
345
381
  },
346
382
  apps,
347
- ...(nsSlice ? { namespaces: namespacesToYaml(nsSlice) } : {}),
348
383
  forbidden_patterns: forbidden.map(forbiddenToYaml),
349
384
  upgradeable_consumer: upgradeableConsumer,
385
+ customizations,
350
386
  };
351
387
  const header = [
352
388
  "# Architecture Boundaries — AI Launch Kit site",
@@ -79,13 +79,18 @@ export interface MeasureApplyDesignDriftOptions {
79
79
  workDir: string;
80
80
  /** The loopback registry the CLI resolves modules and templates from. */
81
81
  registryUrl?: string;
82
- /** Written to the site's own `ailk.key`, which `apply-design` gates a non-Free design on. */
82
+ /**
83
+ * Scaffolds with `--license <key>` (#9650: a keyless run refuses while Free
84
+ * is held), which writes the site's own `ailk.key` — what `apply-design`
85
+ * gates a non-Free design on.
86
+ */
83
87
  licenseKey?: string;
84
88
  }
85
89
  /**
86
- * Scaffold a keyless `organization-product` site on `standard`, compose its
87
- * JSON-LD, run `apply-design <design>` on it, and compose again. A non-zero
88
- * exit at any step throws naming the step and the child's stderr.
90
+ * Scaffold an `organization-product` site on `standard` — keyed when
91
+ * `licenseKey` is given — compose its JSON-LD, run `apply-design <design>` on
92
+ * it, and compose again. A non-zero exit at any step throws naming the step
93
+ * and the child's stderr.
89
94
  */
90
95
  export declare function measureApplyDesignDrift(opts: MeasureApplyDesignDriftOptions): {
91
96
  before: ComposedPages;
@@ -25,7 +25,6 @@
25
25
  * (#8661 D11); `admitSeededContactPage` admits only those two fields.
26
26
  */
27
27
  import { execFileSync } from "node:child_process";
28
- import { writeFileSync } from "node:fs";
29
28
  import { join } from "node:path";
30
29
  import { isDeepStrictEqual } from "node:util";
31
30
  import { CONTACT_PAGE_PATH } from "../design-home.js";
@@ -189,9 +188,10 @@ export function assessJsonLdDrift(design, before, after) {
189
188
  };
190
189
  }
191
190
  /**
192
- * Scaffold a keyless `organization-product` site on `standard`, compose its
193
- * JSON-LD, run `apply-design <design>` on it, and compose again. A non-zero
194
- * exit at any step throws naming the step and the child's stderr.
191
+ * Scaffold an `organization-product` site on `standard` — keyed when
192
+ * `licenseKey` is given — compose its JSON-LD, run `apply-design <design>` on
193
+ * it, and compose again. A non-zero exit at any step throws naming the step
194
+ * and the child's stderr.
195
195
  */
196
196
  export function measureApplyDesignDrift(opts) {
197
197
  const baseEnv = { ...process.env };
@@ -223,9 +223,15 @@ export function measureApplyDesignDrift(opts) {
223
223
  throw new Error(`drift: ${label} printed no JSON: ${err.message}`, { cause: err });
224
224
  }
225
225
  };
226
- exec("scaffold organization-product on standard", process.execPath, [opts.cliPath, site, "--shape", "organization-product", "--design", "standard"], registryEnv);
227
- if (opts.licenseKey !== undefined)
228
- writeFileSync(join(site, "ailk.key"), `${opts.licenseKey}\n`);
226
+ exec("scaffold organization-product on standard", process.execPath, [
227
+ opts.cliPath,
228
+ site,
229
+ "--shape",
230
+ "organization-product",
231
+ "--design",
232
+ "standard",
233
+ ...(opts.licenseKey === undefined ? [] : ["--license", opts.licenseKey]),
234
+ ], registryEnv);
229
235
  const before = compose("compose JSON-LD before apply-design");
230
236
  const applyStdout = exec(`apply-design ${opts.design}`, process.execPath, [opts.cliPath, "apply-design", opts.design, "--target", site], opts.registryUrl === undefined ? {} : { AILK_MODULE_REGISTRY_URL: opts.registryUrl });
231
237
  const after = compose("compose JSON-LD after apply-design");