create-ailk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (533) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +39 -0
  3. package/dist/cli.d.ts +2 -0
  4. package/dist/cli.js +80 -0
  5. package/dist/copy.d.ts +8 -0
  6. package/dist/copy.js +109 -0
  7. package/dist/index.d.ts +10 -0
  8. package/dist/index.js +10 -0
  9. package/dist/lib/pro-callout.d.ts +12 -0
  10. package/dist/lib/pro-callout.js +20 -0
  11. package/dist/parse-args.d.ts +13 -0
  12. package/dist/parse-args.js +81 -0
  13. package/dist/programmatic.d.ts +49 -0
  14. package/dist/programmatic.js +89 -0
  15. package/dist/substitute.d.ts +31 -0
  16. package/dist/substitute.js +45 -0
  17. package/dist/validate.d.ts +8 -0
  18. package/dist/validate.js +70 -0
  19. package/package.json +47 -0
  20. package/templates/.claude/.gitkeep +0 -0
  21. package/templates/.claude/agents/web.md +80 -0
  22. package/templates/.claude/rules/architecture.md +62 -0
  23. package/templates/.claude/rules/preserve-existing-style.md +51 -0
  24. package/templates/.claude/skills/README.md +43 -0
  25. package/templates/.claude/skills/add-schema/SKILL.md +270 -0
  26. package/templates/.claude/skills/add-schema/references/conflict-handling.md +200 -0
  27. package/templates/.claude/skills/add-schema/references/file-finding.md +123 -0
  28. package/templates/.claude/skills/add-schema/references/schema-types.md +131 -0
  29. package/templates/.claude/skills/audit-site/SKILL.md +213 -0
  30. package/templates/.claude/skills/audit-site/references/common-errors.md +113 -0
  31. package/templates/.claude/skills/audit-site/references/findings-glossary.md +138 -0
  32. package/templates/.claude/skills/audit-site/references/severity-levels.md +114 -0
  33. package/templates/.claude/skills/provision-config/SKILL.md +243 -0
  34. package/templates/.claude/skills/provision-config/references/env-vars-template.md +184 -0
  35. package/templates/.claude/skills/provision-config/references/runbook-template.md +248 -0
  36. package/templates/.claude/skills/provision-config/references/vercel-json-template.md +98 -0
  37. package/templates/.claude/skills/scaffold-auth/SKILL.md +261 -0
  38. package/templates/.claude/skills/scaffold-auth/references/env-vars.md +91 -0
  39. package/templates/.claude/skills/scaffold-auth/references/oauth-app-setup.md +171 -0
  40. package/templates/.claude/skills/scaffold-commerce/SKILL.md +310 -0
  41. package/templates/.claude/skills/scaffold-commerce/references/lookup-keys-template.md +71 -0
  42. package/templates/.claude/skills/scaffold-commerce/references/marketplace-brand-pages.md +83 -0
  43. package/templates/.claude/skills/scaffold-commerce/templates/marketplace-cta-route.tsx.tmpl +72 -0
  44. package/templates/.claude/skills/scaffold-page/SKILL.md +243 -0
  45. package/templates/.claude/skills/scaffold-page/references/page-types.md +169 -0
  46. package/templates/.claude/skills/scaffold-page/templates/content.mdx.tmpl +28 -0
  47. package/templates/.claude/skills/scaffold-page/templates/route.tsx.tmpl +28 -0
  48. package/templates/.claude/skills/suggest-site-pages/SKILL.md +242 -0
  49. package/templates/.claude/skills/suggest-site-pages/references/categories.md +287 -0
  50. package/templates/.env.example +205 -0
  51. package/templates/.gitkeep +2 -0
  52. package/templates/CLAUDE.md +142 -0
  53. package/templates/CONVENTIONS.md +222 -0
  54. package/templates/README.md +110 -0
  55. package/templates/apps/api/.env.example +40 -0
  56. package/templates/apps/api/CLAUDE.md +63 -0
  57. package/templates/apps/api/api/index.ts +144 -0
  58. package/templates/apps/api/jest.config.cjs +74 -0
  59. package/templates/apps/api/package.json +54 -0
  60. package/templates/apps/api/src/__tests__/factories/content-fixture.ts +138 -0
  61. package/templates/apps/api/src/__tests__/factories/index.ts +70 -0
  62. package/templates/apps/api/src/__tests__/factories/lead-fixture.ts +82 -0
  63. package/templates/apps/api/src/__tests__/index.test.ts +118 -0
  64. package/templates/apps/api/src/__tests__/server.test.ts +207 -0
  65. package/templates/apps/api/src/__tests__/services/enrichment-shim.test.ts +126 -0
  66. package/templates/apps/api/src/__tests__/setup.ts +24 -0
  67. package/templates/apps/api/src/cli.ts +30 -0
  68. package/templates/apps/api/src/config/__tests__/index.test.ts +97 -0
  69. package/templates/apps/api/src/config/index.ts +56 -0
  70. package/templates/apps/api/src/index.ts +32 -0
  71. package/templates/apps/api/src/lib/__mocks__/prisma-client.js +15 -0
  72. package/templates/apps/api/src/lib/__mocks__/prisma.ts +45 -0
  73. package/templates/apps/api/src/lib/__tests__/content-adapter.test.ts +178 -0
  74. package/templates/apps/api/src/lib/__tests__/error-serializer.test.ts +100 -0
  75. package/templates/apps/api/src/lib/__tests__/errors.test.ts +94 -0
  76. package/templates/apps/api/src/lib/__tests__/file-fallback.test.ts +144 -0
  77. package/templates/apps/api/src/lib/__tests__/fixtures/HomePage/home.mdx +8 -0
  78. package/templates/apps/api/src/lib/__tests__/lead-capture-store.test.ts +227 -0
  79. package/templates/apps/api/src/lib/__tests__/outbound-http.test.ts +125 -0
  80. package/templates/apps/api/src/lib/__tests__/prisma.test.ts +165 -0
  81. package/templates/apps/api/src/lib/__tests__/require-paid-tier.test.ts +129 -0
  82. package/templates/apps/api/src/lib/__tests__/stripe.test.ts +74 -0
  83. package/templates/apps/api/src/lib/content-adapter.ts +86 -0
  84. package/templates/apps/api/src/lib/error-serializer.ts +77 -0
  85. package/templates/apps/api/src/lib/errors.ts +95 -0
  86. package/templates/apps/api/src/lib/file-fallback.ts +87 -0
  87. package/templates/apps/api/src/lib/lead-capture-store.ts +110 -0
  88. package/templates/apps/api/src/lib/locales.ts +201 -0
  89. package/templates/apps/api/src/lib/outbound-http.ts +122 -0
  90. package/templates/apps/api/src/lib/prisma.ts +21 -0
  91. package/templates/apps/api/src/lib/require-paid-tier.ts +53 -0
  92. package/templates/apps/api/src/lib/stripe.ts +30 -0
  93. package/templates/apps/api/src/lib/webhook-idempotency.ts +92 -0
  94. package/templates/apps/api/src/middleware/__tests__/adversarial/bearer-token-format.test.ts +111 -0
  95. package/templates/apps/api/src/middleware/__tests__/adversarial/cookie-or-bearer-precedence.test.ts +172 -0
  96. package/templates/apps/api/src/middleware/__tests__/adversarial/csrf-bearer-skip.test.ts +119 -0
  97. package/templates/apps/api/src/middleware/__tests__/adversarial/csrf-cookie-path.test.ts +138 -0
  98. package/templates/apps/api/src/middleware/__tests__/adversarial/session-fixation.test.ts +149 -0
  99. package/templates/apps/api/src/middleware/__tests__/adversarial/session-timeout.test.ts +139 -0
  100. package/templates/apps/api/src/middleware/__tests__/auth.bearer-path.test.ts +175 -0
  101. package/templates/apps/api/src/middleware/__tests__/auth.both-present-precedence.test.ts +76 -0
  102. package/templates/apps/api/src/middleware/__tests__/auth.cookie-path.test.ts +153 -0
  103. package/templates/apps/api/src/middleware/__tests__/auth.neither-present.test.ts +72 -0
  104. package/templates/apps/api/src/middleware/__tests__/rate-limit.test.ts +292 -0
  105. package/templates/apps/api/src/middleware/auth.ts +246 -0
  106. package/templates/apps/api/src/middleware/rate-limit.ts +132 -0
  107. package/templates/apps/api/src/openapi/__tests__/openapi.test.ts +129 -0
  108. package/templates/apps/api/src/openapi/index.ts +12 -0
  109. package/templates/apps/api/src/openapi/spec.ts +408 -0
  110. package/templates/apps/api/src/routes/auth/__tests__/auth-tokens.functional.test.ts +193 -0
  111. package/templates/apps/api/src/routes/auth/__tests__/auth-user.functional.test.ts +201 -0
  112. package/templates/apps/api/src/routes/auth/__tests__/tokens.test.ts +294 -0
  113. package/templates/apps/api/src/routes/auth/__tests__/user.test.ts +486 -0
  114. package/templates/apps/api/src/routes/auth/tokens.ts +199 -0
  115. package/templates/apps/api/src/routes/auth/user.ts +244 -0
  116. package/templates/apps/api/src/routes/checkout/__tests__/sessions.test.ts +588 -0
  117. package/templates/apps/api/src/routes/checkout/index.ts +13 -0
  118. package/templates/apps/api/src/routes/checkout/sessions.ts +185 -0
  119. package/templates/apps/api/src/routes/content/__tests__/create.test.ts +239 -0
  120. package/templates/apps/api/src/routes/content/__tests__/delete.test.ts +201 -0
  121. package/templates/apps/api/src/routes/content/__tests__/get-page.test.ts +141 -0
  122. package/templates/apps/api/src/routes/content/__tests__/list-pages.test.ts +122 -0
  123. package/templates/apps/api/src/routes/content/__tests__/list-types.test.ts +44 -0
  124. package/templates/apps/api/src/routes/content/__tests__/locale.test.ts +118 -0
  125. package/templates/apps/api/src/routes/content/__tests__/rate-limit.test.ts +51 -0
  126. package/templates/apps/api/src/routes/content/__tests__/update.test.ts +252 -0
  127. package/templates/apps/api/src/routes/content/create.ts +114 -0
  128. package/templates/apps/api/src/routes/content/delete.ts +81 -0
  129. package/templates/apps/api/src/routes/content/get-page.ts +98 -0
  130. package/templates/apps/api/src/routes/content/index.ts +32 -0
  131. package/templates/apps/api/src/routes/content/list-pages.ts +83 -0
  132. package/templates/apps/api/src/routes/content/list-types.ts +19 -0
  133. package/templates/apps/api/src/routes/content/rate-limit.ts +13 -0
  134. package/templates/apps/api/src/routes/content/slug.ts +9 -0
  135. package/templates/apps/api/src/routes/content/update.ts +111 -0
  136. package/templates/apps/api/src/routes/leads/__tests__/index.test.ts +415 -0
  137. package/templates/apps/api/src/routes/leads/__tests__/track.test.ts +165 -0
  138. package/templates/apps/api/src/routes/leads/index.ts +130 -0
  139. package/templates/apps/api/src/routes/test/auth/__tests__/session.test.ts +296 -0
  140. package/templates/apps/api/src/routes/test/auth/session.ts +141 -0
  141. package/templates/apps/api/src/routes/webhooks/README.md +57 -0
  142. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-idempotency.test.ts +247 -0
  143. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-rate-limit.test.ts +198 -0
  144. package/templates/apps/api/src/routes/webhooks/__tests__/stripe.test.ts +633 -0
  145. package/templates/apps/api/src/routes/webhooks/index.ts +41 -0
  146. package/templates/apps/api/src/routes/webhooks/stripe.ts +253 -0
  147. package/templates/apps/api/src/server.ts +157 -0
  148. package/templates/apps/api/src/services/__tests__/lead-routing.test.ts +395 -0
  149. package/templates/apps/api/src/services/enrichment-shim.ts +53 -0
  150. package/templates/apps/api/src/services/lead-routing.ts +338 -0
  151. package/templates/apps/api/tsconfig.json +34 -0
  152. package/templates/apps/api/vercel.json +17 -0
  153. package/templates/apps/mcp/.env.example +52 -0
  154. package/templates/apps/mcp/CLAUDE.md +84 -0
  155. package/templates/apps/mcp/__tests__/abuse/daily-cap.test.ts +52 -0
  156. package/templates/apps/mcp/__tests__/abuse/email-validator.test.ts +46 -0
  157. package/templates/apps/mcp/__tests__/abuse/honeypot.test.ts +36 -0
  158. package/templates/apps/mcp/__tests__/abuse/user-agent-deny.test.ts +54 -0
  159. package/templates/apps/mcp/__tests__/aeo-cli-parity.test.ts +110 -0
  160. package/templates/apps/mcp/__tests__/audit-single-page.test.ts +213 -0
  161. package/templates/apps/mcp/__tests__/audit.test.ts +217 -0
  162. package/templates/apps/mcp/__tests__/catalog-drift.test.ts +52 -0
  163. package/templates/apps/mcp/__tests__/create_page.test.ts +201 -0
  164. package/templates/apps/mcp/__tests__/delete_page.test.ts +176 -0
  165. package/templates/apps/mcp/__tests__/get_business_hours.test.ts +82 -0
  166. package/templates/apps/mcp/__tests__/get_faq.test.ts +80 -0
  167. package/templates/apps/mcp/__tests__/get_locations.test.ts +65 -0
  168. package/templates/apps/mcp/__tests__/get_offerings.test.ts +90 -0
  169. package/templates/apps/mcp/__tests__/get_pricing.test.ts +80 -0
  170. package/templates/apps/mcp/__tests__/get_site_info.test.ts +81 -0
  171. package/templates/apps/mcp/__tests__/http-transport.test.ts +323 -0
  172. package/templates/apps/mcp/__tests__/lib/errors.test.ts +75 -0
  173. package/templates/apps/mcp/__tests__/lib/require-paid-tier.test.ts +75 -0
  174. package/templates/apps/mcp/__tests__/list_pages.test.ts +112 -0
  175. package/templates/apps/mcp/__tests__/locale.test.ts +135 -0
  176. package/templates/apps/mcp/__tests__/parity.test.ts +205 -0
  177. package/templates/apps/mcp/__tests__/purchase-disabled.test.ts +34 -0
  178. package/templates/apps/mcp/__tests__/read_content.test.ts +153 -0
  179. package/templates/apps/mcp/__tests__/request_callback.test.ts +163 -0
  180. package/templates/apps/mcp/__tests__/search_content.test.ts +153 -0
  181. package/templates/apps/mcp/__tests__/server.test.ts +115 -0
  182. package/templates/apps/mcp/__tests__/submit_lead.test.ts +165 -0
  183. package/templates/apps/mcp/__tests__/subscribe_newsletter.test.ts +161 -0
  184. package/templates/apps/mcp/__tests__/tools/purchase.test.ts +227 -0
  185. package/templates/apps/mcp/__tests__/tools/scaffold.test.ts +237 -0
  186. package/templates/apps/mcp/__tests__/update_page.test.ts +195 -0
  187. package/templates/apps/mcp/jest.config.cjs +82 -0
  188. package/templates/apps/mcp/package.json +37 -0
  189. package/templates/apps/mcp/src/abuse/daily-cap.ts +47 -0
  190. package/templates/apps/mcp/src/abuse/email-validator.ts +25 -0
  191. package/templates/apps/mcp/src/abuse/honeypot.ts +21 -0
  192. package/templates/apps/mcp/src/abuse/index.ts +111 -0
  193. package/templates/apps/mcp/src/abuse/user-agent-deny.ts +58 -0
  194. package/templates/apps/mcp/src/http-transport.ts +303 -0
  195. package/templates/apps/mcp/src/index.ts +67 -0
  196. package/templates/apps/mcp/src/lib/audit-single-page.ts +194 -0
  197. package/templates/apps/mcp/src/lib/errors.ts +61 -0
  198. package/templates/apps/mcp/src/lib/locales.ts +171 -0
  199. package/templates/apps/mcp/src/lib/require-paid-tier.ts +44 -0
  200. package/templates/apps/mcp/src/lib/resolve-locale.ts +30 -0
  201. package/templates/apps/mcp/src/server.ts +139 -0
  202. package/templates/apps/mcp/src/tools/audit.ts +103 -0
  203. package/templates/apps/mcp/src/tools/capture_lead.ts +52 -0
  204. package/templates/apps/mcp/src/tools/create_page.ts +95 -0
  205. package/templates/apps/mcp/src/tools/delete_page.ts +73 -0
  206. package/templates/apps/mcp/src/tools/get_business_hours.ts +66 -0
  207. package/templates/apps/mcp/src/tools/get_faq.ts +69 -0
  208. package/templates/apps/mcp/src/tools/get_locations.ts +85 -0
  209. package/templates/apps/mcp/src/tools/get_offerings.ts +66 -0
  210. package/templates/apps/mcp/src/tools/get_pricing.ts +74 -0
  211. package/templates/apps/mcp/src/tools/get_site_info.ts +84 -0
  212. package/templates/apps/mcp/src/tools/index.ts +125 -0
  213. package/templates/apps/mcp/src/tools/list_pages.ts +72 -0
  214. package/templates/apps/mcp/src/tools/purchase.ts +89 -0
  215. package/templates/apps/mcp/src/tools/read_content.ts +61 -0
  216. package/templates/apps/mcp/src/tools/request_callback.ts +51 -0
  217. package/templates/apps/mcp/src/tools/scaffold.ts +119 -0
  218. package/templates/apps/mcp/src/tools/search_content.ts +59 -0
  219. package/templates/apps/mcp/src/tools/subscribe_newsletter.ts +47 -0
  220. package/templates/apps/mcp/src/tools/update_page.ts +91 -0
  221. package/templates/apps/mcp/tsconfig.json +19 -0
  222. package/templates/apps/web/.env.example +47 -0
  223. package/templates/apps/web/CLAUDE.md +81 -0
  224. package/templates/apps/web/__tests__/auth/adversarial/cookie-attributes.test.ts +94 -0
  225. package/templates/apps/web/__tests__/auth/adversarial/oauth-state-parameter.test.ts +75 -0
  226. package/templates/apps/web/__tests__/auth/adversarial/redirect-uri-allowlist.test.ts +82 -0
  227. package/templates/apps/web/__tests__/auth/env-helpers.test.ts +168 -0
  228. package/templates/apps/web/__tests__/authority-list-routes.test.tsx +208 -0
  229. package/templates/apps/web/__tests__/better-stack.test.ts +66 -0
  230. package/templates/apps/web/__tests__/blog-dir-resolution.test.ts +87 -0
  231. package/templates/apps/web/__tests__/blog-source-populated.test.ts +130 -0
  232. package/templates/apps/web/__tests__/data-testid-coverage.test.tsx +60 -0
  233. package/templates/apps/web/__tests__/google-analytics.test.tsx +104 -0
  234. package/templates/apps/web/__tests__/i18n/middleware.test.ts +119 -0
  235. package/templates/apps/web/__tests__/i18n/routing.test.ts +114 -0
  236. package/templates/apps/web/__tests__/i18n/translations.test.ts +191 -0
  237. package/templates/apps/web/__tests__/json-ld.test.ts +98 -0
  238. package/templates/apps/web/__tests__/knowledge-events-routes.test.tsx +580 -0
  239. package/templates/apps/web/__tests__/layout-stealth.test.ts +39 -0
  240. package/templates/apps/web/__tests__/lighthouse-fixtures/improvement-image-shrink.tsx +103 -0
  241. package/templates/apps/web/__tests__/lighthouse-fixtures/override-fixture.md +114 -0
  242. package/templates/apps/web/__tests__/lighthouse-fixtures/regression-bloat.tsx +94 -0
  243. package/templates/apps/web/__tests__/page.test.tsx +230 -0
  244. package/templates/apps/web/__tests__/products-services-phase1.test.tsx +321 -0
  245. package/templates/apps/web/__tests__/projects-routes.test.tsx +392 -0
  246. package/templates/apps/web/__tests__/resources-downloads-integrations-phase2.test.tsx +475 -0
  247. package/templates/apps/web/__tests__/routes/ai-plugin-json.test.ts +53 -0
  248. package/templates/apps/web/__tests__/routes/blog-route.test.tsx +191 -0
  249. package/templates/apps/web/__tests__/routes/llms-txt.test.ts +123 -0
  250. package/templates/apps/web/__tests__/routes/robots-txt.test.ts +52 -0
  251. package/templates/apps/web/__tests__/routes/sitemap-xml.test.ts +78 -0
  252. package/templates/apps/web/__tests__/routes/well-known-mcp.test.ts +203 -0
  253. package/templates/apps/web/__tests__/section-routes.test.tsx +693 -0
  254. package/templates/apps/web/__tests__/security-headers.test.ts +201 -0
  255. package/templates/apps/web/__tests__/sentry-config.test.ts +116 -0
  256. package/templates/apps/web/__tests__/setup.ts +82 -0
  257. package/templates/apps/web/__tests__/sitemap-locales.test.ts +415 -0
  258. package/templates/apps/web/__tests__/standalone-informational-routes.test.tsx +844 -0
  259. package/templates/apps/web/app/.well-known/ai-plugin.json/route.ts +81 -0
  260. package/templates/apps/web/app/.well-known/mcp.json/build-manifest.ts +110 -0
  261. package/templates/apps/web/app/.well-known/mcp.json/route.ts +58 -0
  262. package/templates/apps/web/app/[locale]/__tests__/layout.test.tsx +120 -0
  263. package/templates/apps/web/app/[locale]/__tests__/page-renderer-migration.test.tsx +202 -0
  264. package/templates/apps/web/app/[locale]/about/page.tsx +31 -0
  265. package/templates/apps/web/app/[locale]/blog/[[...slug]]/page.tsx +173 -0
  266. package/templates/apps/web/app/[locale]/careers/[slug]/page.tsx +45 -0
  267. package/templates/apps/web/app/[locale]/careers/__tests__/page-renderer-migration.test.tsx +117 -0
  268. package/templates/apps/web/app/[locale]/careers/page.tsx +25 -0
  269. package/templates/apps/web/app/[locale]/case-studies/[slug]/page.tsx +44 -0
  270. package/templates/apps/web/app/[locale]/case-studies/__tests__/page-renderer-migration.test.tsx +113 -0
  271. package/templates/apps/web/app/[locale]/case-studies/page.tsx +25 -0
  272. package/templates/apps/web/app/[locale]/clients/__tests__/page-renderer-migration.test.tsx +63 -0
  273. package/templates/apps/web/app/[locale]/clients/page.tsx +27 -0
  274. package/templates/apps/web/app/[locale]/contact/ContactForm.tsx +130 -0
  275. package/templates/apps/web/app/[locale]/contact/__tests__/contact.actions.test.ts +152 -0
  276. package/templates/apps/web/app/[locale]/contact/__tests__/page-renderer-migration.test.tsx +92 -0
  277. package/templates/apps/web/app/[locale]/contact/contact.actions.ts +79 -0
  278. package/templates/apps/web/app/[locale]/contact/error.tsx +24 -0
  279. package/templates/apps/web/app/[locale]/contact/page.tsx +38 -0
  280. package/templates/apps/web/app/[locale]/courses/[slug]/page.tsx +34 -0
  281. package/templates/apps/web/app/[locale]/courses/__tests__/page-renderer-migration.test.tsx +119 -0
  282. package/templates/apps/web/app/[locale]/courses/page.tsx +25 -0
  283. package/templates/apps/web/app/[locale]/dev/purchase/__tests__/actions.test.ts +160 -0
  284. package/templates/apps/web/app/[locale]/dev/purchase/error.tsx +25 -0
  285. package/templates/apps/web/app/[locale]/dev/purchase/page.tsx +117 -0
  286. package/templates/apps/web/app/[locale]/dev/purchase/purchase.actions.ts +58 -0
  287. package/templates/apps/web/app/[locale]/docs/[[...slug]]/page.tsx +118 -0
  288. package/templates/apps/web/app/[locale]/downloads/__tests__/page-renderer-migration.test.tsx +72 -0
  289. package/templates/apps/web/app/[locale]/downloads/page.tsx +25 -0
  290. package/templates/apps/web/app/[locale]/events/[slug]/page.tsx +47 -0
  291. package/templates/apps/web/app/[locale]/events/__tests__/page-renderer-migration.test.tsx +130 -0
  292. package/templates/apps/web/app/[locale]/events/page.tsx +25 -0
  293. package/templates/apps/web/app/[locale]/faq/page.tsx +36 -0
  294. package/templates/apps/web/app/[locale]/how-to/[slug]/page.tsx +34 -0
  295. package/templates/apps/web/app/[locale]/how-to/__tests__/page-renderer-migration.test.tsx +78 -0
  296. package/templates/apps/web/app/[locale]/how-to/page.tsx +40 -0
  297. package/templates/apps/web/app/[locale]/integrations/[slug]/page.tsx +43 -0
  298. package/templates/apps/web/app/[locale]/integrations/__tests__/page-renderer-migration.test.tsx +129 -0
  299. package/templates/apps/web/app/[locale]/integrations/page.tsx +25 -0
  300. package/templates/apps/web/app/[locale]/launch-service/page.tsx +31 -0
  301. package/templates/apps/web/app/[locale]/layout.tsx +241 -0
  302. package/templates/apps/web/app/[locale]/page.tsx +41 -0
  303. package/templates/apps/web/app/[locale]/partners/[slug]/page.tsx +44 -0
  304. package/templates/apps/web/app/[locale]/partners/__tests__/page-renderer-migration.test.tsx +113 -0
  305. package/templates/apps/web/app/[locale]/partners/page.tsx +25 -0
  306. package/templates/apps/web/app/[locale]/products/[slug]/page.tsx +43 -0
  307. package/templates/apps/web/app/[locale]/products/__tests__/page-renderer-migration.test.tsx +129 -0
  308. package/templates/apps/web/app/[locale]/products/page.tsx +25 -0
  309. package/templates/apps/web/app/[locale]/projects/[slug]/page.tsx +39 -0
  310. package/templates/apps/web/app/[locale]/projects/__tests__/page-renderer-migration.test.tsx +138 -0
  311. package/templates/apps/web/app/[locale]/projects/page.tsx +30 -0
  312. package/templates/apps/web/app/[locale]/resources/[slug]/page.tsx +51 -0
  313. package/templates/apps/web/app/[locale]/resources/__tests__/page-renderer-migration.test.tsx +117 -0
  314. package/templates/apps/web/app/[locale]/resources/page.tsx +27 -0
  315. package/templates/apps/web/app/[locale]/services/[slug]/page.tsx +43 -0
  316. package/templates/apps/web/app/[locale]/services/__tests__/page-renderer-migration.test.tsx +129 -0
  317. package/templates/apps/web/app/[locale]/services/page.tsx +25 -0
  318. package/templates/apps/web/app/[locale]/software/[slug]/page.tsx +34 -0
  319. package/templates/apps/web/app/[locale]/software/__tests__/page-renderer-migration.test.tsx +81 -0
  320. package/templates/apps/web/app/[locale]/software/page.tsx +39 -0
  321. package/templates/apps/web/app/[locale]/tech-articles/[slug]/page.tsx +34 -0
  322. package/templates/apps/web/app/[locale]/tech-articles/__tests__/page-renderer-migration.test.tsx +82 -0
  323. package/templates/apps/web/app/[locale]/tech-articles/page.tsx +39 -0
  324. package/templates/apps/web/app/[locale]/testimonials/__tests__/page-renderer-migration.test.tsx +63 -0
  325. package/templates/apps/web/app/[locale]/testimonials/page.tsx +27 -0
  326. package/templates/apps/web/app/[locale]/use-cases/__tests__/page-renderer-migration.test.tsx +63 -0
  327. package/templates/apps/web/app/[locale]/use-cases/page.tsx +27 -0
  328. package/templates/apps/web/app/[locale]/whitepapers/[slug]/page.tsx +34 -0
  329. package/templates/apps/web/app/[locale]/whitepapers/__tests__/page-renderer-migration.test.tsx +82 -0
  330. package/templates/apps/web/app/[locale]/whitepapers/page.tsx +39 -0
  331. package/templates/apps/web/app/__tests__/error-boundaries.test.tsx +152 -0
  332. package/templates/apps/web/app/api/auth/[...all]/route.ts +16 -0
  333. package/templates/apps/web/app/error-fallback.tsx +75 -0
  334. package/templates/apps/web/app/error.tsx +23 -0
  335. package/templates/apps/web/app/layout.tsx +18 -0
  336. package/templates/apps/web/app/llms.txt/route.ts +101 -0
  337. package/templates/apps/web/app/not-found.tsx +48 -0
  338. package/templates/apps/web/app/og/__tests__/route.test.ts +164 -0
  339. package/templates/apps/web/app/og/route.tsx +135 -0
  340. package/templates/apps/web/app/robots.txt/route.ts +36 -0
  341. package/templates/apps/web/app/sitemap.xml/route.ts +146 -0
  342. package/templates/apps/web/auth.ts +141 -0
  343. package/templates/apps/web/components/ThemeToggle.tsx +60 -0
  344. package/templates/apps/web/components/google-analytics.tsx +34 -0
  345. package/templates/apps/web/content/en/blog/index.mdx +15 -0
  346. package/templates/apps/web/content/en/blog/launching-ailk.mdx +20 -0
  347. package/templates/apps/web/content/en/docs/getting-started.mdx +30 -0
  348. package/templates/apps/web/i18n/request.ts +36 -0
  349. package/templates/apps/web/jest.config.cjs +100 -0
  350. package/templates/apps/web/lib/__mocks__/next-mdx-remote-rsc.js +12 -0
  351. package/templates/apps/web/lib/__mocks__/source-server.js +31 -0
  352. package/templates/apps/web/lib/__tests__/og.test.ts +65 -0
  353. package/templates/apps/web/lib/auth-env.ts +66 -0
  354. package/templates/apps/web/lib/blog-list-data.ts +95 -0
  355. package/templates/apps/web/lib/blog-post-data.ts +79 -0
  356. package/templates/apps/web/lib/nav-config.ts +13 -0
  357. package/templates/apps/web/lib/observability/better-stack.ts +27 -0
  358. package/templates/apps/web/lib/og.ts +23 -0
  359. package/templates/apps/web/lib/prisma-for-auth.ts +34 -0
  360. package/templates/apps/web/lib/source.ts +34 -0
  361. package/templates/apps/web/messages/en.json +131 -0
  362. package/templates/apps/web/middleware.ts +80 -0
  363. package/templates/apps/web/next.config.mjs +167 -0
  364. package/templates/apps/web/package.json +62 -0
  365. package/templates/apps/web/public/.well-known/security.txt +17 -0
  366. package/templates/apps/web/public/android-chrome-192x192.png +0 -0
  367. package/templates/apps/web/public/android-chrome-512x512.png +0 -0
  368. package/templates/apps/web/public/apple-touch-icon.png +0 -0
  369. package/templates/apps/web/public/favicon-16x16.png +0 -0
  370. package/templates/apps/web/public/favicon-32x32.png +0 -0
  371. package/templates/apps/web/public/favicon.ico +0 -0
  372. package/templates/apps/web/public/favicon.svg +4 -0
  373. package/templates/apps/web/public/logo-dark.svg +21 -0
  374. package/templates/apps/web/public/logo-light.svg +21 -0
  375. package/templates/apps/web/public/logomark-dark.svg +4 -0
  376. package/templates/apps/web/public/logomark-light.svg +4 -0
  377. package/templates/apps/web/public/og-default.png +0 -0
  378. package/templates/apps/web/public/site.webmanifest +19 -0
  379. package/templates/apps/web/scripts/assert-content-bundled.ts +55 -0
  380. package/templates/apps/web/security-headers.config.ts +132 -0
  381. package/templates/apps/web/sentry.client.config.ts +27 -0
  382. package/templates/apps/web/sentry.edge.config.ts +15 -0
  383. package/templates/apps/web/sentry.server.config.ts +20 -0
  384. package/templates/apps/web/source.config.ts +78 -0
  385. package/templates/apps/web/src/components/SiteNav.tsx +21 -0
  386. package/templates/apps/web/src/lib/routes.ts +37 -0
  387. package/templates/apps/web/tsconfig.json +35 -0
  388. package/templates/apps/web/types/messages.d.ts +19 -0
  389. package/templates/content/.gitkeep +0 -0
  390. package/templates/content/CLAUDE.md +85 -0
  391. package/templates/content/_site.mdx +38 -0
  392. package/templates/content/ar/HomePage/home.mdx +123 -0
  393. package/templates/content/ar/_site.mdx +35 -0
  394. package/templates/content/de/_site.mdx +29 -0
  395. package/templates/content/en/.gitkeep +0 -0
  396. package/templates/content/en/AboutPage/about.mdx +19 -0
  397. package/templates/content/en/AboutPage/about.schema.json +82 -0
  398. package/templates/content/en/BookCall/book-call.mdx +19 -0
  399. package/templates/content/en/BookCall/book-call.schema.json +121 -0
  400. package/templates/content/en/BreadcrumbList/site-breadcrumbs.mdx +20 -0
  401. package/templates/content/en/CareersList/careers.mdx +24 -0
  402. package/templates/content/en/CaseStudiesList/case-studies.mdx +22 -0
  403. package/templates/content/en/CaseStudiesList/showcase.mdx +8 -0
  404. package/templates/content/en/CaseStudy/ailk-aeo-rollout.mdx +32 -0
  405. package/templates/content/en/CaseStudy/schema-builder-migration.mdx +41 -0
  406. package/templates/content/en/ClientsList/clients.mdx +38 -0
  407. package/templates/content/en/ContactPage/contact.mdx +19 -0
  408. package/templates/content/en/ContactPage/contact.schema.json +100 -0
  409. package/templates/content/en/ContactPoint/primary.mdx +14 -0
  410. package/templates/content/en/Course/aeo-fundamentals.mdx +37 -0
  411. package/templates/content/en/Course/schema-builder-workshop.mdx +62 -0
  412. package/templates/content/en/CoursesList/courses.mdx +22 -0
  413. package/templates/content/en/DownloadsList/downloads.mdx +22 -0
  414. package/templates/content/en/Event/aeo-office-hours-may-2026.mdx +39 -0
  415. package/templates/content/en/Event/ailk-launch-day-2026.mdx +35 -0
  416. package/templates/content/en/EventsList/events.mdx +26 -0
  417. package/templates/content/en/FAQPage/faq.mdx +420 -0
  418. package/templates/content/en/FAQPage/faq.schema.json +231 -0
  419. package/templates/content/en/GlossaryList/glossary.mdx +19 -0
  420. package/templates/content/en/GlossaryList/glossary.schema.json +300 -0
  421. package/templates/content/en/HomePage/home.mdx +312 -0
  422. package/templates/content/en/HomePage/home.schema.json +88 -0
  423. package/templates/content/en/HomePage/launch-service.mdx +475 -0
  424. package/templates/content/en/HomePage/launch-service.schema.json +138 -0
  425. package/templates/content/en/HowTo/add-mdx-content.mdx +38 -0
  426. package/templates/content/en/HowTo/configure-aeo-scoring.mdx +35 -0
  427. package/templates/content/en/HowTo/set-up-json-ld.mdx +36 -0
  428. package/templates/content/en/Integration/github-actions.mdx +31 -0
  429. package/templates/content/en/Integration/openai-api.mdx +26 -0
  430. package/templates/content/en/Integration/vercel.mdx +32 -0
  431. package/templates/content/en/IntegrationsList/integrations.mdx +22 -0
  432. package/templates/content/en/JobPosting/content-strategist.mdx +46 -0
  433. package/templates/content/en/JobPosting/developer-advocate.mdx +47 -0
  434. package/templates/content/en/JobPosting/senior-fullstack-engineer.mdx +57 -0
  435. package/templates/content/en/LandingPage/aeo-audit.mdx +19 -0
  436. package/templates/content/en/LandingPage/aeo-audit.schema.json +92 -0
  437. package/templates/content/en/LandingPage/agency-waitlist.mdx +340 -0
  438. package/templates/content/en/LandingPage/agency-waitlist.schema.json +152 -0
  439. package/templates/content/en/LandingPage/developers.mdx +19 -0
  440. package/templates/content/en/LandingPage/developers.schema.json +109 -0
  441. package/templates/content/en/LandingPage/for-agencies.mdx +390 -0
  442. package/templates/content/en/LandingPage/for-agencies.schema.json +107 -0
  443. package/templates/content/en/LandingPage/for-ai-search-agencies.mdx +417 -0
  444. package/templates/content/en/LandingPage/for-ai-search-agencies.schema.json +105 -0
  445. package/templates/content/en/LandingPage/for-businesses.mdx +19 -0
  446. package/templates/content/en/LandingPage/for-businesses.schema.json +96 -0
  447. package/templates/content/en/LandingPage/platform.mdx +369 -0
  448. package/templates/content/en/LandingPage/platform.schema.json +166 -0
  449. package/templates/content/en/LandingPage/vs-ai-website-builders.mdx +19 -0
  450. package/templates/content/en/LandingPage/vs-ai-website-builders.schema.json +102 -0
  451. package/templates/content/en/LandingPage/vs-wordpress.mdx +19 -0
  452. package/templates/content/en/LandingPage/vs-wordpress.schema.json +53 -0
  453. package/templates/content/en/NewsletterSignup/newsletter.mdx +236 -0
  454. package/templates/content/en/NewsletterSignup/newsletter.schema.json +91 -0
  455. package/templates/content/en/Organization/site-owner.mdx +16 -0
  456. package/templates/content/en/Partner/prisma.mdx +31 -0
  457. package/templates/content/en/Partner/supabase.mdx +30 -0
  458. package/templates/content/en/Partner/vercel.mdx +28 -0
  459. package/templates/content/en/PartnersList/partners.mdx +22 -0
  460. package/templates/content/en/Person/founder.mdx +18 -0
  461. package/templates/content/en/Pricing/pricing.mdx +538 -0
  462. package/templates/content/en/Pricing/pricing.schema.json +209 -0
  463. package/templates/content/en/PrivacyPage/privacy.mdx +165 -0
  464. package/templates/content/en/PrivacyPage/privacy.schema.json +64 -0
  465. package/templates/content/en/Product/ailk.mdx +19 -0
  466. package/templates/content/en/Product/ailk.schema.json +94 -0
  467. package/templates/content/en/Product/api-launch-kit.mdx +26 -0
  468. package/templates/content/en/Product/launch-kit.mdx +28 -0
  469. package/templates/content/en/ProductsList/products.mdx +26 -0
  470. package/templates/content/en/Project/ailk-phase-2.mdx +54 -0
  471. package/templates/content/en/ProjectsList/projects.mdx +25 -0
  472. package/templates/content/en/ResourceDetail/aeo-scoring-guide.mdx +27 -0
  473. package/templates/content/en/ResourceDetail/content-model-whitepaper.mdx +28 -0
  474. package/templates/content/en/ResourceDetail/schema-org-quick-reference.mdx +39 -0
  475. package/templates/content/en/ResourcesHub/resources.mdx +22 -0
  476. package/templates/content/en/Service/consulting.mdx +22 -0
  477. package/templates/content/en/Service/implementation.mdx +30 -0
  478. package/templates/content/en/Service/launch-service.mdx +232 -0
  479. package/templates/content/en/Service/launch.mdx +228 -0
  480. package/templates/content/en/ServicesList/services.mdx +84 -0
  481. package/templates/content/en/SoftwareProduct/ailk-aeo.mdx +44 -0
  482. package/templates/content/en/SoftwareProduct/ailk-content-adapters.mdx +47 -0
  483. package/templates/content/en/SoftwareProduct/ailk-schema.mdx +49 -0
  484. package/templates/content/en/TeamList/team.mdx +63 -0
  485. package/templates/content/en/TeamMember/founder.mdx +72 -0
  486. package/templates/content/en/TermsPage/terms.mdx +19 -0
  487. package/templates/content/en/TermsPage/terms.schema.json +99 -0
  488. package/templates/content/en/TestimonialsList/testimonials.mdx +44 -0
  489. package/templates/content/en/UseCasesList/use-cases.mdx +30 -0
  490. package/templates/content/en/Whitepaper/ax-first-product-development.mdx +27 -0
  491. package/templates/content/en/Whitepaper/open-core-commercial-strategy.mdx +27 -0
  492. package/templates/content/en/Whitepaper/structured-data-for-answer-engines.mdx +31 -0
  493. package/templates/content/en-XA/AboutPage/about.mdx +8 -0
  494. package/templates/content/en-XA/FAQPage/faq.mdx +8 -0
  495. package/templates/content/en-XA/HomePage/home.mdx +8 -0
  496. package/templates/content/es/_site.mdx +30 -0
  497. package/templates/content/fr/_site.mdx +30 -0
  498. package/templates/content/ja/_site.mdx +30 -0
  499. package/templates/content/pt-BR/AboutPage/about.mdx +8 -0
  500. package/templates/content/pt-BR/FAQPage/faq.mdx +8 -0
  501. package/templates/content/pt-BR/HomePage/home.mdx +23 -0
  502. package/templates/database/CHANGELOG.md +5 -0
  503. package/templates/database/README.md +234 -0
  504. package/templates/database/__tests__/user-cascade.test.ts +125 -0
  505. package/templates/database/auth/.gitkeep +0 -0
  506. package/templates/database/config/.gitkeep +0 -0
  507. package/templates/database/content/.gitkeep +0 -0
  508. package/templates/database/inbox/.gitkeep +0 -0
  509. package/templates/database/inbox/README.md +3 -0
  510. package/templates/database/inbox/__tests__/schema.test.ts +40 -0
  511. package/templates/database/inbox/schema.prisma +52 -0
  512. package/templates/database/jest.config.cjs +29 -0
  513. package/templates/database/migrations/20260508000000_add_inbox_namespace/migration.sql +328 -0
  514. package/templates/database/migrations/20260513000000_better_auth_migration/migration.sql +100 -0
  515. package/templates/database/migrations/20260515000000_add_user_billing_fields/migration.sql +28 -0
  516. package/templates/database/migrations/20260516000000_add_user_tier_care_plan_seat/migration.sql +25 -0
  517. package/templates/database/migrations/20260518000000_add_telemetry_records/migration.sql +42 -0
  518. package/templates/database/migrations/20260525000000_theme_wiring/migration.sql +67 -0
  519. package/templates/database/migrations/20260710000000_retire_commercial_tier/migration.sql +21 -0
  520. package/templates/database/migrations/migration_lock.toml +3 -0
  521. package/templates/database/ops/.gitkeep +0 -0
  522. package/templates/database/package.json +45 -0
  523. package/templates/database/prisma.config.ts +20 -0
  524. package/templates/database/schema.prisma +487 -0
  525. package/templates/database/scripts/db-generate-locked.sh +80 -0
  526. package/templates/database/seed-test.ts +85 -0
  527. package/templates/database/tsconfig.build.json +16 -0
  528. package/templates/database/tsconfig.json +9 -0
  529. package/templates/package.json +125 -0
  530. package/templates/pnpm-workspace.yaml +6 -0
  531. package/templates/project.yaml +59 -0
  532. package/templates/tsconfig.base.json +18 -0
  533. package/templates/tsconfig.json +45 -0
@@ -0,0 +1,72 @@
1
+ /**
2
+ * list_pages — returns published content pages, optionally filtered by type.
3
+ *
4
+ * Pure read: imports the MDX adapter from @working-theory/content-adapters (ADR 0011).
5
+ * No auth, no side effects, no network. The adapter reads from the filesystem.
6
+ *
7
+ * Phase 3 S3: optional `locale` parameter. Validated against `readLocales()`
8
+ * allowlist; invalid or unknown values silently fall back to the project's
9
+ * default locale (AC-i18n-07). Lists are locale-scoped — pages must exist in
10
+ * the requested locale's directory to be enumerated.
11
+ *
12
+ * Input: { type?: SchemaOrgType, locale?: string }
13
+ * Output: { pages: Array<{ slug, type, title, description? }> }
14
+ * Session/scope: none — read-only public content.
15
+ */
16
+
17
+ import { join } from "node:path";
18
+
19
+ import {
20
+ createMdxAdapter,
21
+ SCHEMA_ORG_TYPES,
22
+ type SchemaOrgType,
23
+ } from "@working-theory/content-adapters";
24
+ import {
25
+ listPagesInputSchema,
26
+ listPagesOutputSchema,
27
+ type ListPagesInput,
28
+ type ListPagesOutput,
29
+ } from "@working-theory/validation";
30
+
31
+ import { resolveLocale } from "../lib/resolve-locale.js";
32
+
33
+ export { listPagesInputSchema, listPagesOutputSchema };
34
+ export type { ListPagesInput, ListPagesOutput };
35
+
36
+ /**
37
+ * list_pages handler.
38
+ *
39
+ * Accepts an optional `contentRoot` override for testing (avoids coupling
40
+ * unit tests to the deployed filesystem layout). When omitted, resolves the
41
+ * content root relative to this file at call time (supports ESM runtime).
42
+ */
43
+ export async function ailkListPages(
44
+ input: ListPagesInput,
45
+ contentRoot?: string,
46
+ ): Promise<ListPagesOutput> {
47
+ listPagesInputSchema.parse(input);
48
+
49
+ // Default: resolve content/ relative to cwd (works in ESM and jest/commonjs).
50
+ const root = contentRoot ?? join(process.cwd(), "content");
51
+ const locale = resolveLocale(input.locale);
52
+ const adapter = createMdxAdapter({ contentRoot: root, defaultLocale: locale });
53
+
54
+ const types: readonly SchemaOrgType[] = input.type
55
+ ? [input.type]
56
+ : SCHEMA_ORG_TYPES;
57
+
58
+ const perType = await Promise.all(
59
+ types.map((type) => adapter.listPages(type, locale)),
60
+ );
61
+
62
+ const pages: ListPagesOutput["pages"] = perType.flatMap((results) =>
63
+ results.map((page) => ({
64
+ slug: page.slug,
65
+ type: page.type,
66
+ title: page.title,
67
+ ...(page.description !== undefined && { description: page.description }),
68
+ })),
69
+ );
70
+
71
+ return listPagesOutputSchema.parse({ pages });
72
+ }
@@ -0,0 +1,89 @@
1
+ /**
2
+ * AGENT TOOL — purchase (`start_purchase`)
3
+ *
4
+ * DISABLED AT OSS CATALOG (S15a, 2026-05-12, issue #610).
5
+ *
6
+ * The implementation below is preserved for the eventual Phase 3 re-enable.
7
+ * The MCP catalog at `packages/metadata/src/mcp-tool-catalog.ts` filters this
8
+ * tool out via `OSS_DISABLED_TOOLS`, and `apps/mcp/src/server.ts` applies the
9
+ * same filter defensively so neither the discovery manifest nor the running
10
+ * server advertises it.
11
+ *
12
+ * Re-enablement requires the Phase 3 criteria documented at
13
+ * `docs/internal/roadmaps/phase-3-readiness.md`:
14
+ *
15
+ * 1. Identity verification confirmed at session level
16
+ * 2. Payment-authorization handshake with Stripe Connect (or equivalent)
17
+ * 3. Threat-model entry M_purchase reclassified from "Disabled" to
18
+ * "Remediated"
19
+ * 4. Commercial-tier flag gating registered to allow re-enable only on
20
+ * Pro / Agencies
21
+ *
22
+ * To re-enable: remove `"start_purchase"` from `OSS_DISABLED_TOOLS` in
23
+ * `packages/metadata/src/mcp-tool-catalog.ts`. The regression tests at
24
+ * `apps/mcp/__tests__/purchase-disabled.test.ts` and
25
+ * `packages/metadata/__tests__/purchase-not-in-catalog.test.ts` will fail
26
+ * loudly, forcing a deliberate review against the criteria above.
27
+ *
28
+ * --- Original Phase 3 U2 implementation notes ---
29
+ *
30
+ * Proxies POST /api/checkout/sessions and returns the Stripe hosted-checkout
31
+ * URL. Paired with the `purchaseAction` Server Action in apps/web per ADR 0013.
32
+ *
33
+ * Schemas live in `@working-theory/validation` per ADR 0013.
34
+ * Network calls go through `@working-theory/api-client` per architecture invariants
35
+ * (apps may not import from each other; shared HTTP surface lives in packages/).
36
+ */
37
+
38
+ import { checkout } from "@working-theory/api-client";
39
+ import {
40
+ purchaseInputSchema,
41
+ type PurchaseInput,
42
+ type PurchaseOutput,
43
+ } from "@working-theory/validation";
44
+
45
+ /**
46
+ * Export name `ailkPurchase` satisfies the parity-test naming convention
47
+ * (ailk<PascalVerb>) so the harness can discover it.
48
+ *
49
+ * Paired with `purchaseAction` Server Action in apps/web/app/dev/purchase/.
50
+ */
51
+ export async function ailkPurchase(
52
+ input: PurchaseInput,
53
+ ): Promise<PurchaseOutput> {
54
+ // Validate input before any side effect (security requirement).
55
+ purchaseInputSchema.parse(input);
56
+
57
+ const baseUrl =
58
+ process.env.AILK_BASE_URL ||
59
+ process.env.NEXT_PUBLIC_BASE_URL ||
60
+ "http://localhost:3000";
61
+
62
+ const successUrl =
63
+ input.successUrl ?? `${baseUrl}/purchase/success`;
64
+ const cancelUrl =
65
+ input.cancelUrl ?? `${baseUrl}/purchase/cancel`;
66
+
67
+ const result = await checkout.createSession({
68
+ productCode: input.priceId,
69
+ ...(input.quantity !== undefined && { quantity: input.quantity }),
70
+ successUrl,
71
+ cancelUrl,
72
+ });
73
+
74
+ if (!result.ok) {
75
+ throw new Error(
76
+ `checkout-unavailable: POST /api/checkout/sessions returned ${result.status}`,
77
+ );
78
+ }
79
+
80
+ return { url: result.body.url };
81
+ }
82
+
83
+ // Re-export schemas/types from @working-theory/validation for barrel consumers.
84
+ export {
85
+ purchaseInputSchema,
86
+ purchaseOutputSchema,
87
+ type PurchaseInput,
88
+ type PurchaseOutput,
89
+ } from "@working-theory/validation";
@@ -0,0 +1,61 @@
1
+ /**
2
+ * read_content — returns a single page's frontmatter + raw MDX body.
3
+ *
4
+ * Pure read: imports the MDX adapter from @working-theory/content-adapters (ADR 0011).
5
+ * Composes getPageBySlug (frontmatter) + getPageSource (body) into a single
6
+ * output shape. Returns null when the slug is not found — never throws for
7
+ * a missing page.
8
+ *
9
+ * Phase 3 S3: optional `locale` parameter. Validated against `readLocales()`
10
+ * allowlist; invalid or unknown values silently fall back to the project's
11
+ * default locale (AC-i18n-07). The adapter applies its own fallback chain.
12
+ *
13
+ * Input: { type: SchemaOrgType, slug: string, locale?: string }
14
+ * Output: { slug, type, frontmatter, body } | null
15
+ * Session/scope: none — read-only public content.
16
+ */
17
+
18
+ import { join } from "node:path";
19
+
20
+ import { createMdxAdapter } from "@working-theory/content-adapters";
21
+ import {
22
+ readContentInputSchema,
23
+ readContentOutputSchema,
24
+ type ReadContentInput,
25
+ type ReadContentOutput,
26
+ } from "@working-theory/validation";
27
+
28
+ import { resolveLocale } from "../lib/resolve-locale.js";
29
+
30
+ export { readContentInputSchema, readContentOutputSchema };
31
+ export type { ReadContentInput, ReadContentOutput };
32
+
33
+ /**
34
+ * read_content handler.
35
+ *
36
+ * Accepts an optional `contentRoot` override for testing. When omitted,
37
+ * resolves the content root relative to this file at call time (supports
38
+ * ESM runtime).
39
+ */
40
+ export async function ailkReadContent(
41
+ input: ReadContentInput,
42
+ contentRoot?: string,
43
+ ): Promise<ReadContentOutput> {
44
+ readContentInputSchema.parse(input);
45
+
46
+ // Default: resolve content/ relative to cwd (works in ESM and jest/commonjs).
47
+ const root = contentRoot ?? join(process.cwd(), "content");
48
+ const locale = resolveLocale(input.locale);
49
+
50
+ const adapter = createMdxAdapter({ contentRoot: root, defaultLocale: locale });
51
+
52
+ const source = await adapter.getPageSource(input.type, input.slug, locale);
53
+ if (source === null) return null;
54
+
55
+ return readContentOutputSchema.parse({
56
+ slug: source.frontmatter.slug,
57
+ type: source.frontmatter.type,
58
+ frontmatter: source.frontmatter as Record<string, unknown>,
59
+ body: source.body,
60
+ });
61
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * request_callback — schedule a callback request.
3
+ *
4
+ * Validates input via Zod, forwards to POST /api/leads/callback via
5
+ * @working-theory/api-client, and shapes the response into the MCP output schema.
6
+ * No business logic — orchestration lives in apps/api B6.
7
+ *
8
+ * Input: { name, phone, preferredTime? }
9
+ * Output: { ok: true, id, persisted } | { ok: false, error: { kind, ... } }
10
+ * Session/scope: none — anonymous write, no auth required.
11
+ */
12
+
13
+ import { apiClient } from "@working-theory/api-client";
14
+ import {
15
+ requestCallbackInputSchema,
16
+ requestCallbackOutputSchema,
17
+ type RequestCallbackInput,
18
+ type RequestCallbackOutput,
19
+ } from "@working-theory/validation";
20
+
21
+ export { requestCallbackInputSchema, requestCallbackOutputSchema };
22
+ export type { RequestCallbackInput, RequestCallbackOutput };
23
+
24
+ export async function ailkRequestCallback(
25
+ input: RequestCallbackInput,
26
+ ): Promise<RequestCallbackOutput> {
27
+ const parsed = requestCallbackInputSchema.safeParse(input);
28
+ if (!parsed.success) {
29
+ return {
30
+ ok: false,
31
+ error: { kind: "invalid_input", issues: parsed.error.issues },
32
+ };
33
+ }
34
+
35
+ const { name, phone, preferredTime } = parsed.data;
36
+ const siteId = process.env.AILK_SITE_ID ?? "default";
37
+ const body = {
38
+ siteId,
39
+ name,
40
+ phone,
41
+ ...(preferredTime !== undefined && { preferredTime }),
42
+ payload: {},
43
+ };
44
+
45
+ const res = await apiClient.leads.callback(body);
46
+ if (!res.ok) {
47
+ return { ok: false, error: { kind: "api_error", status: res.status } };
48
+ }
49
+
50
+ return { ok: true, id: res.body.id, persisted: res.body.persisted };
51
+ }
@@ -0,0 +1,119 @@
1
+ /**
2
+ * scaffold — creates an AI Launch Kit starter project via create-ailk.
3
+ *
4
+ * Agent-only: no web Server Action equivalent. Scaffolding is an
5
+ * orchestration-layer action that only makes sense for an agent driving a
6
+ * project setup flow.
7
+ *
8
+ * Implementation: spawns the `create-ailk` CLI binary via Node's spawnSync.
9
+ * `apps/mcp` does NOT import `create-ailk` directly — the package is not on
10
+ * the apps/mcp allow-list in architecture.yaml (it is a standalone CLI, not a
11
+ * side-effect-free read library per ADR 0011). Spawning the built CLI binary
12
+ * is the architecturally correct delegation pattern.
13
+ *
14
+ * The CLI binary path defaults to `<cwd>/packages/create-ailk/dist/cli.js`.
15
+ * The MCP server runs from the repo root (cwd = repo root), so this resolves
16
+ * correctly in production and in integration tests.
17
+ *
18
+ * Input: { targetDir, projectName, preset? }
19
+ * targetDir — absolute or relative path to scaffold into; must not exist
20
+ * or must be empty (enforced by create-ailk ValidationError)
21
+ * projectName — project name used in README and package.json
22
+ * preset — permissive string; reserved for Phase 3 U6 named starters
23
+ * // TODO(U6): narrow to z.enum([...]) once named presets land
24
+ *
25
+ * Output: { targetDir, filesCreated }
26
+ * targetDir — resolved absolute path that was scaffolded
27
+ * filesCreated — number of files written
28
+ *
29
+ * Session/scope: none — scaffolding is a write to the local filesystem
30
+ * initiated by the agent; no auth required for the tool itself.
31
+ */
32
+
33
+ import { spawnSync } from "node:child_process";
34
+ import { existsSync, readdirSync } from "node:fs";
35
+ import { join, resolve } from "node:path";
36
+
37
+ import {
38
+ scaffoldInputSchema,
39
+ scaffoldOutputSchema,
40
+ type ScaffoldInput,
41
+ type ScaffoldOutput,
42
+ } from "@working-theory/validation";
43
+
44
+ export { scaffoldInputSchema, scaffoldOutputSchema };
45
+ export type { ScaffoldInput, ScaffoldOutput };
46
+
47
+ /**
48
+ * Resolve the path to the create-ailk CLI binary.
49
+ *
50
+ * Uses process.cwd() — the MCP server always starts from the repo root.
51
+ * Accepts an override for tests.
52
+ */
53
+ function resolveCliBin(override?: string): string {
54
+ if (override) return override;
55
+ return join(process.cwd(), "packages/create-ailk/dist/cli.js");
56
+ }
57
+
58
+ /**
59
+ * Count all files recursively under a directory.
60
+ */
61
+ function countFiles(dir: string): number {
62
+ if (!existsSync(dir)) return 0;
63
+ let count = 0;
64
+ const stack: string[] = [dir];
65
+ while (stack.length > 0) {
66
+ const current = stack.pop()!;
67
+ for (const entry of readdirSync(current, { withFileTypes: true })) {
68
+ if (entry.isDirectory()) {
69
+ stack.push(`${current}/${entry.name}`);
70
+ } else {
71
+ count++;
72
+ }
73
+ }
74
+ }
75
+ return count;
76
+ }
77
+
78
+ /**
79
+ * ailkScaffold handler.
80
+ *
81
+ * Spawns the create-ailk CLI binary to scaffold a starter project into
82
+ * targetDir. The binary must be pre-built (`pnpm --filter create-ailk build`).
83
+ *
84
+ * Accepts an optional `cliBin` override for testing (mirrors the contentRoot
85
+ * override pattern in ailkAudit).
86
+ */
87
+ export async function ailkScaffold(
88
+ input: ScaffoldInput,
89
+ cliBin?: string,
90
+ ): Promise<ScaffoldOutput> {
91
+ scaffoldInputSchema.parse(input);
92
+
93
+ const bin = resolveCliBin(cliBin);
94
+ const targetAbs = resolve(input.targetDir);
95
+
96
+ // Spawn the CLI synchronously — no network, no async I/O needed.
97
+ // Hard-coded node invocation; only targetDir flows through user input.
98
+ const result = spawnSync("node", [bin, targetAbs], {
99
+ stdio: ["ignore", "pipe", "pipe"],
100
+ shell: false,
101
+ encoding: "utf8",
102
+ });
103
+
104
+ if (result.status !== 0) {
105
+ // Extract the error message from stderr (CLI writes "[create-ailk] <msg>").
106
+ const stderr = (result.stderr ?? "").trim();
107
+ const msg = stderr.replace(/^\[create-ailk\]\s*/, "") || "scaffold failed";
108
+ throw new Error(msg);
109
+ }
110
+
111
+ const filesCreated = countFiles(targetAbs);
112
+
113
+ const output: ScaffoldOutput = {
114
+ targetDir: targetAbs,
115
+ filesCreated,
116
+ };
117
+
118
+ return scaffoldOutputSchema.parse(output);
119
+ }
@@ -0,0 +1,59 @@
1
+ /**
2
+ * search_content — full-text search across published content pages.
3
+ *
4
+ * Pure read: imports the MDX adapter from @working-theory/content-adapters (ADR 0011).
5
+ * Delegates to adapter.searchPages which scores by title/description/body match.
6
+ * Limit defaults to 10; max 50. Query capped at 200 chars (enforced by Zod).
7
+ *
8
+ * Phase 3 S3: optional `locale` parameter. Search is locale-scoped — only the
9
+ * requested locale's content directory is searched. Invalid or unknown values
10
+ * silently fall back to the project's default locale (AC-i18n-07).
11
+ *
12
+ * Input: { query: string, type?: SchemaOrgType, limit?: number, locale?: string }
13
+ * Output: { results: Array<{ slug, type, title, snippet, score }> }
14
+ * Session/scope: none — read-only public content.
15
+ */
16
+
17
+ import { join } from "node:path";
18
+
19
+ import { createMdxAdapter } from "@working-theory/content-adapters";
20
+ import {
21
+ searchContentInputSchema,
22
+ searchContentOutputSchema,
23
+ type SearchContentInput,
24
+ type SearchContentOutput,
25
+ } from "@working-theory/validation";
26
+
27
+ import { resolveLocale } from "../lib/resolve-locale.js";
28
+
29
+ export { searchContentInputSchema, searchContentOutputSchema };
30
+ export type { SearchContentInput, SearchContentOutput };
31
+
32
+ const DEFAULT_LIMIT = 10;
33
+
34
+ /**
35
+ * search_content handler.
36
+ *
37
+ * Accepts an optional `contentRoot` override for testing. When omitted,
38
+ * resolves the content root relative to cwd (supports ESM runtime).
39
+ */
40
+ export async function ailkSearchContent(
41
+ input: SearchContentInput,
42
+ contentRoot?: string,
43
+ ): Promise<SearchContentOutput> {
44
+ searchContentInputSchema.parse(input);
45
+
46
+ const root = contentRoot ?? join(process.cwd(), "content");
47
+ const locale = resolveLocale(input.locale);
48
+ const adapter = createMdxAdapter({ contentRoot: root, defaultLocale: locale });
49
+
50
+ const options = {
51
+ limit: input.limit ?? DEFAULT_LIMIT,
52
+ ...(input.type !== undefined && { type: input.type }),
53
+ locale,
54
+ };
55
+
56
+ const rawResults = await adapter.searchPages(input.query, options);
57
+
58
+ return searchContentOutputSchema.parse({ results: rawResults });
59
+ }
@@ -0,0 +1,47 @@
1
+ /**
2
+ * subscribe_newsletter — add an email to the newsletter list.
3
+ *
4
+ * Validates input via Zod, forwards to POST /api/leads/subscribe via
5
+ * @working-theory/api-client, and shapes the response into the MCP output schema.
6
+ * No business logic — orchestration lives in apps/api B6.
7
+ *
8
+ * Input: { email, firstName? }
9
+ * Output: { ok: true, id, persisted } | { ok: false, error: { kind, ... } }
10
+ * Session/scope: none — anonymous write, no auth required.
11
+ */
12
+
13
+ import { apiClient } from "@working-theory/api-client";
14
+ import {
15
+ subscribeNewsletterInputSchema,
16
+ subscribeNewsletterOutputSchema,
17
+ type SubscribeNewsletterInput,
18
+ type SubscribeNewsletterOutput,
19
+ } from "@working-theory/validation";
20
+
21
+ export { subscribeNewsletterInputSchema, subscribeNewsletterOutputSchema };
22
+ export type { SubscribeNewsletterInput, SubscribeNewsletterOutput };
23
+
24
+ export async function ailkSubscribeNewsletter(
25
+ input: SubscribeNewsletterInput,
26
+ ): Promise<SubscribeNewsletterOutput> {
27
+ const parsed = subscribeNewsletterInputSchema.safeParse(input);
28
+ if (!parsed.success) {
29
+ return {
30
+ ok: false,
31
+ error: { kind: "invalid_input", issues: parsed.error.issues },
32
+ };
33
+ }
34
+
35
+ const { email } = parsed.data;
36
+ // firstName is not part of the canonical subscribeSchema (no payload field);
37
+ // it is accepted by the MCP input but dropped here for now.
38
+ const siteId = process.env.AILK_SITE_ID ?? "default";
39
+ const body = { siteId, email, source: "mcp" };
40
+
41
+ const res = await apiClient.leads.subscribe(body);
42
+ if (!res.ok) {
43
+ return { ok: false, error: { kind: "api_error", status: res.status } };
44
+ }
45
+
46
+ return { ok: true, id: res.body.id, persisted: res.body.persisted };
47
+ }
@@ -0,0 +1,91 @@
1
+ /**
2
+ * update_page — Paid-tier MCP tool for revising an existing content page.
3
+ *
4
+ * D14a Stage 1 Unit C — wires McpServer update_page to ContentAdapter.updatePage.
5
+ * Mandatory optimistic locking: caller supplies `ifMatch` (version token from a
6
+ * prior read or write); stale or missing tokens yield canonical conflict bodies.
7
+ *
8
+ * Validation strategy mirrors create_page — strict parse via
9
+ * FrontmatterSchema.extend({ body, ifMatch }) inside the handler so bad
10
+ * frontmatter surfaces as validation_failed (the Stage 0 catalog uses a
11
+ * permissive outer shape because @working-theory/metadata cannot import
12
+ * @working-theory/content-adapters).
13
+ */
14
+
15
+ import { join } from "node:path";
16
+
17
+ import {
18
+ FrontmatterSchema,
19
+ createMdxAdapter,
20
+ mapAdapterError,
21
+ type ContentAdapter,
22
+ } from "@working-theory/content-adapters";
23
+ import { z } from "zod";
24
+
25
+ import { validationError, type ErrorBody } from "../lib/errors.js";
26
+ import { requirePaidTier } from "../lib/require-paid-tier.js";
27
+
28
+ const UpdatePageInputSchema = FrontmatterSchema.extend({
29
+ body: z.string().min(1),
30
+ ifMatch: z.string().min(1),
31
+ });
32
+
33
+ interface UpdatePageSuccess {
34
+ page: Record<string, unknown>;
35
+ version: string;
36
+ }
37
+
38
+ export type UpdatePageResult = UpdatePageSuccess | ErrorBody;
39
+
40
+ export interface UpdatePageInput {
41
+ type: string;
42
+ slug: string;
43
+ page: Record<string, unknown>;
44
+ body: string;
45
+ ifMatch: string;
46
+ }
47
+
48
+ export async function ailkUpdatePage(
49
+ input: UpdatePageInput,
50
+ adapter?: ContentAdapter,
51
+ ): Promise<UpdatePageResult> {
52
+ const guard = await requirePaidTier();
53
+ if (guard) return guard;
54
+
55
+ const parsed = UpdatePageInputSchema.safeParse({
56
+ ...input.page,
57
+ type: input.type,
58
+ slug: input.slug,
59
+ body: input.body,
60
+ ifMatch: input.ifMatch,
61
+ });
62
+
63
+ if (!parsed.success) {
64
+ return validationError(
65
+ "Invalid frontmatter, body, or ifMatch for update_page.",
66
+ { issues: parsed.error.issues },
67
+ );
68
+ }
69
+
70
+ const { ifMatch, ...pageWithBody } = parsed.data;
71
+ const resolved =
72
+ adapter ??
73
+ createMdxAdapter({ contentRoot: join(process.cwd(), "content") });
74
+
75
+ try {
76
+ const result = await resolved.updatePage(
77
+ pageWithBody.type,
78
+ pageWithBody.slug,
79
+ pageWithBody,
80
+ { ifMatch },
81
+ );
82
+ return { page: result.page, version: result.version };
83
+ } catch (err) {
84
+ const mapped = mapAdapterError(err, {
85
+ type: pageWithBody.type,
86
+ slug: pageWithBody.slug,
87
+ });
88
+ if (mapped) return mapped;
89
+ throw err;
90
+ }
91
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "outDir": "./dist",
5
+ "rootDir": "./src",
6
+ "composite": true,
7
+ "types": ["node"]
8
+ },
9
+ "include": ["src"],
10
+ "exclude": ["node_modules", "dist"],
11
+ "references": [
12
+ { "path": "../../packages/aeo" },
13
+ { "path": "../../packages/api-client" },
14
+ { "path": "../../packages/content-adapters" },
15
+ { "path": "../../packages/metadata" },
16
+ { "path": "../../packages/schema" },
17
+ { "path": "../../packages/validation" }
18
+ ]
19
+ }
@@ -0,0 +1,47 @@
1
+ # =============================================================================
2
+ # AI Launch Kit Web Configuration
3
+ # =============================================================================
4
+ # Defaults are set inside the app where reasonable; this file documents the
5
+ # overrides apps/web reads at runtime.
6
+
7
+ # =============================================================================
8
+ # Content backend
9
+ # =============================================================================
10
+ # Which content adapter apps/web uses.
11
+ # mdx — reads /content/<Type>/<slug>.mdx (default)
12
+ # pro-cms — separate adapter, not bundled with the OSS template
13
+ CONTENT_BACKEND=mdx
14
+
15
+ # Override the on-disk content root. Defaults to <repo-root>/content.
16
+ # AILK_CONTENT_ROOT=
17
+
18
+ # =============================================================================
19
+ # Better Auth (apps/web)
20
+ # =============================================================================
21
+ # Base URL Better Auth uses for OAuth callback construction.
22
+ # BETTER_AUTH_URL=http://localhost:3000
23
+ # Secret used to sign session cookies. REQUIRED in production.
24
+ # BETTER_AUTH_SECRET=
25
+ #
26
+ # OAuth provider env vars — set both id + secret to activate a provider.
27
+ # Provider activation is checked at boot via apps/web/lib/auth-env.ts.
28
+ # GOOGLE_CLIENT_ID=
29
+ # GOOGLE_CLIENT_SECRET=
30
+ # GITHUB_CLIENT_ID=
31
+ # GITHUB_CLIENT_SECRET=
32
+
33
+ # =============================================================================
34
+ # Observability
35
+ # =============================================================================
36
+ # Sentry DSN for server-side error capture (apps/web/sentry.server.config.ts).
37
+ # Gates enabled: !!process.env.SENTRY_DSN — unset means SDK is a no-op.
38
+ # SENTRY_DSN=
39
+ # Sentry DSN for browser-side error capture (apps/web/sentry.client.config.ts).
40
+ # Gates enabled: !!process.env.NEXT_PUBLIC_SENTRY_DSN — unset means SDK is a no-op.
41
+ # NEXT_PUBLIC_SENTRY_DSN=
42
+ # Sentry auth token used by the Sentry webpack plugin to upload source maps.
43
+ # Required for production source map uploads; unset disables source map upload.
44
+ # SENTRY_AUTH_TOKEN=
45
+ # Better Stack heartbeat URL — when set, pingHeartbeat() POSTs on cron/startup.
46
+ # Unset means the heartbeat util is a no-op (apps/web/lib/observability/better-stack.ts).
47
+ # BETTER_STACK_HEARTBEAT_URL=