create-ailk 0.7.0 → 0.9.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 (310) hide show
  1. package/README.md +112 -10
  2. package/component-catalog.json +798 -49
  3. package/component-catalog.md +9 -6
  4. package/dist/add-module.d.ts +20 -0
  5. package/dist/add-module.js +43 -7
  6. package/dist/add-route.d.ts +56 -0
  7. package/dist/add-route.js +286 -0
  8. package/dist/apply-design-md.d.ts +7 -0
  9. package/dist/apply-design-md.js +50 -0
  10. package/dist/apply-design.d.ts +64 -0
  11. package/dist/apply-design.js +273 -0
  12. package/dist/claude-md.d.ts +111 -0
  13. package/dist/claude-md.js +334 -0
  14. package/dist/cli.js +114 -28
  15. package/dist/derive-architecture.js +41 -36
  16. package/dist/design-compile.d.ts +71 -0
  17. package/dist/design-compile.js +98 -0
  18. package/dist/design-package.d.ts +83 -0
  19. package/dist/design-package.js +468 -0
  20. package/dist/design-presets.d.ts +86 -0
  21. package/dist/design-presets.js +642 -0
  22. package/dist/design-scaffold.d.ts +76 -0
  23. package/dist/design-scaffold.js +220 -0
  24. package/dist/index.d.ts +2 -1
  25. package/dist/index.js +4 -1
  26. package/dist/legacy-nav-renderers.d.ts +45 -0
  27. package/dist/legacy-nav-renderers.js +545 -0
  28. package/dist/lib/auth-secret-file.d.ts +19 -0
  29. package/dist/lib/auth-secret-file.js +112 -0
  30. package/dist/lib/design-checks.d.ts +78 -0
  31. package/dist/lib/design-checks.js +174 -0
  32. package/dist/lib/extract-module-bundle.js +5 -1
  33. package/dist/lib/license-key-files.d.ts +9 -0
  34. package/dist/lib/license-key-files.js +2 -2
  35. package/dist/lib/module-license-gate.d.ts +89 -0
  36. package/dist/lib/module-license-gate.js +171 -12
  37. package/dist/lib/module-tier.d.ts +45 -16
  38. package/dist/lib/module-tier.js +76 -0
  39. package/dist/lib/pro-callout.js +10 -2
  40. package/dist/lib/render-verdict.d.ts +52 -0
  41. package/dist/lib/render-verdict.js +77 -0
  42. package/dist/lib/scaffold-render-sweep.d.ts +105 -0
  43. package/dist/lib/scaffold-render-sweep.js +236 -0
  44. package/dist/module-architecture.d.ts +19 -16
  45. package/dist/module-architecture.js +64 -21
  46. package/dist/parse-args.d.ts +88 -10
  47. package/dist/parse-args.js +272 -21
  48. package/dist/programmatic.d.ts +66 -12
  49. package/dist/programmatic.js +361 -34
  50. package/dist/site-chrome.d.ts +19 -9
  51. package/dist/site-chrome.js +23 -13
  52. package/dist/site-manifest.d.ts +25 -0
  53. package/dist/site-manifest.js +254 -0
  54. package/dist/site-roster.d.ts +41 -0
  55. package/dist/site-roster.js +149 -11
  56. package/dist/starter-grid.d.ts +232 -0
  57. package/dist/starter-grid.js +545 -0
  58. package/dist/surfaces.d.ts +41 -9
  59. package/dist/surfaces.js +268 -92
  60. package/dist/template-manifest.d.ts +65 -29
  61. package/dist/template-manifest.js +161 -382
  62. package/dist/template-names.d.ts +14 -12
  63. package/dist/template-names.js +13 -17
  64. package/package.json +5 -4
  65. package/site-templates/_base/content/en/Feature/feature-1.mdx +69 -0
  66. package/site-templates/_base/content/en/Feature/feature-2.mdx +69 -0
  67. package/site-templates/_base/content/en/Feature/feature-3.mdx +69 -0
  68. package/site-templates/_base/content/en/FeaturesList/features.mdx +91 -0
  69. package/site-templates/_base/content/en/GlossaryList/glossary.mdx +0 -1
  70. package/site-templates/_base/content/en/NewsletterSignup/newsletter.mdx +0 -1
  71. package/site-templates/_base/content/en/PortfolioItem/sample-four.mdx +105 -0
  72. package/site-templates/_base/content/en/PortfolioItem/sample-one.mdx +34 -0
  73. package/site-templates/_base/content/en/PortfolioItem/sample-three.mdx +94 -0
  74. package/site-templates/_base/content/en/PortfolioItem/sample-two.mdx +45 -0
  75. package/site-templates/_base/content/en/PortfolioList/portfolio.mdx +169 -0
  76. package/site-templates/_base/content/en/PrivacyPage/privacy.mdx +15 -0
  77. package/site-templates/_base/content/en/UseCase/persona-1.mdx +70 -0
  78. package/site-templates/_base/content/en/UseCase/persona-2.mdx +70 -0
  79. package/site-templates/_base/content/en/UseCase/persona-3.mdx +70 -0
  80. package/site-templates/{minimalism-site/TEMPLATE-MANIFEST.json → aliases/minimalism-site.TEMPLATE-MANIFEST.json} +72 -40
  81. package/site-templates/designs/minimalism/DESIGN.md +98 -6
  82. package/site-templates/designs/minimalism/sample/README.md +48 -0
  83. package/site-templates/designs/standard/DESIGN.md +103 -6
  84. package/site-templates/marketing-site/DESIGN.md +103 -6
  85. package/site-templates/marketing-site/TEMPLATE-MANIFEST.json +144 -47
  86. package/site-templates/marketing-site/TEMPLATE-MANIFEST.md +82 -41
  87. package/site-templates/marketing-site-free/DESIGN.md +103 -6
  88. package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.json +150 -48
  89. package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.md +114 -67
  90. package/site-templates/marketing-site-free/ailk-template.json +1 -1
  91. package/site-templates/marketing-site-free/content/en/NewsletterSignup/newsletter.mdx +59 -0
  92. package/site-templates/marketing-site-free/content/en/Pricing/pricing.mdx +199 -0
  93. package/site-templates/saas-product/DESIGN.md +103 -6
  94. package/site-templates/saas-product/TEMPLATE-MANIFEST.md +9 -1
  95. package/site-templates/{simple-service → shapes/local-business-service}/TEMPLATE-MANIFEST.json +210 -81
  96. package/site-templates/shapes/local-business-service/TEMPLATE-MANIFEST.md +356 -0
  97. package/site-templates/shapes/local-business-service/ailk-template.json +10 -0
  98. package/site-templates/{simple-service → shapes/local-business-service}/content/en/AboutPage/about.mdx +4 -4
  99. package/site-templates/shapes/local-business-service/content/en/HomePage/home.mdx +70 -0
  100. package/site-templates/shapes/local-business-service/content/en/NewsletterSignup/newsletter.mdx +59 -0
  101. package/site-templates/shapes/local-business-service/content/en/PortfolioList/portfolio.mdx +171 -0
  102. package/site-templates/{minimalism-site → shapes/local-business-service}/content/en/PurchasePolicyPage/purchase-policy.mdx +7 -8
  103. package/site-templates/shapes/local-business-service/content/en/Service/first-job.mdx +39 -0
  104. package/site-templates/shapes/local-business-service/content/en/Service/second-job.mdx +39 -0
  105. package/site-templates/shapes/local-business-service/content/en/Service/third-job.mdx +39 -0
  106. package/site-templates/shapes/local-business-service/content/en/ServicesList/services.mdx +61 -0
  107. package/site-templates/shapes/local-business-service/provenance.json +4 -0
  108. package/site-templates/shapes/organization-service/TEMPLATE-MANIFEST.json +471 -0
  109. package/site-templates/shapes/organization-service/TEMPLATE-MANIFEST.md +354 -0
  110. package/site-templates/shapes/organization-service/ailk-template.json +10 -0
  111. package/site-templates/shapes/organization-service/content/en/AboutPage/about.mdx +38 -0
  112. package/site-templates/shapes/organization-service/content/en/HomePage/home.mdx +85 -0
  113. package/site-templates/shapes/organization-service/content/en/NewsletterSignup/newsletter.mdx +59 -0
  114. package/site-templates/shapes/organization-service/content/en/PortfolioList/portfolio.mdx +171 -0
  115. package/site-templates/shapes/organization-service/content/en/PurchasePolicyPage/purchase-policy.mdx +123 -0
  116. package/site-templates/{minimalism-site → shapes/organization-service}/content/en/ServicesList/services.mdx +3 -4
  117. package/site-templates/shapes/organization-service/provenance.json +4 -0
  118. package/site-templates/shapes/person-service/TEMPLATE-MANIFEST.json +478 -0
  119. package/site-templates/shapes/person-service/TEMPLATE-MANIFEST.md +353 -0
  120. package/site-templates/shapes/person-service/ailk-template.json +10 -0
  121. package/site-templates/shapes/person-service/content/_site.mdx +85 -0
  122. package/site-templates/shapes/person-service/content/en/AboutPage/about.mdx +39 -0
  123. package/site-templates/shapes/person-service/content/en/HomePage/home.mdx +97 -0
  124. package/site-templates/shapes/person-service/content/en/NewsletterSignup/newsletter.mdx +59 -0
  125. package/site-templates/shapes/person-service/content/en/PortfolioList/portfolio.mdx +171 -0
  126. package/site-templates/{simple-service → shapes/person-service}/content/en/PurchasePolicyPage/purchase-policy.mdx +10 -11
  127. package/site-templates/shapes/person-service/content/en/Service/first-engagement.mdx +38 -0
  128. package/site-templates/shapes/person-service/content/en/Service/second-engagement.mdx +38 -0
  129. package/site-templates/shapes/person-service/content/en/Service/third-engagement.mdx +38 -0
  130. package/site-templates/{simple-service → shapes/person-service}/content/en/ServicesList/services.mdx +16 -16
  131. package/site-templates/shapes/person-service/provenance.json +4 -0
  132. package/templates/.claude/rules/architecture.md +7 -0
  133. package/templates/.claude/skills/README.md +5 -3
  134. package/templates/.claude/skills/add-auth/references/env-vars.md +22 -15
  135. package/templates/.claude/skills/add-auth/references/oauth-app-setup.md +3 -2
  136. package/templates/.claude/skills/add-page/SKILL.md +241 -238
  137. package/templates/.claude/skills/add-page/references/page-types.md +85 -72
  138. package/templates/.claude/skills/add-page/scripts/site-pages.mjs +87 -0
  139. package/templates/.claude/skills/add-page/templates/comparison-page.mdx.tmpl +99 -0
  140. package/templates/.claude/skills/add-page/templates/content.mdx.tmpl +8 -18
  141. package/templates/.claude/skills/add-page/templates/flow-landing-page.mdx.tmpl +43 -0
  142. package/templates/.claude/skills/add-page/templates/report-page.mdx.tmpl +52 -0
  143. package/templates/.claude/skills/add-page/templates/reports-list.mdx.tmpl +38 -0
  144. package/templates/.claude/skills/check-site/SKILL.md +23 -0
  145. package/templates/.claude/skills/fill-page/SKILL.md +26 -7
  146. package/templates/.claude/skills/fill-page/profiles/plumbing.yaml +1 -1
  147. package/templates/.claude/skills/setup-database/SKILL.md +156 -0
  148. package/templates/.claude/skills/setup-database/scripts/verify-inbox.ts +154 -0
  149. package/templates/.claude/skills/setup-deploy/SKILL.md +64 -32
  150. package/templates/.claude/skills/setup-deploy/references/env-vars-template.md +44 -36
  151. package/templates/.claude/skills/setup-deploy/references/runbook-template.md +58 -102
  152. package/templates/.claude/skills/update-page/SKILL.md +117 -0
  153. package/templates/.claude/skills/update-page/scripts/update-page.ts +640 -0
  154. package/templates/.claude/skills/update-page/templates/redirects.mjs.tmpl +31 -0
  155. package/templates/.claude/skills/upgrade-plan/SKILL.md +12 -8
  156. package/templates/.github/workflows/ci.yml +4 -0
  157. package/templates/.prettierignore +1 -0
  158. package/templates/CLAUDE.md +146 -103
  159. package/templates/DESIGN.md +103 -6
  160. package/templates/README.md +63 -43
  161. package/templates/apps/api/.env.example +2 -1
  162. package/templates/apps/api/CLAUDE.md +3 -2
  163. package/templates/apps/api/src/__tests__/commerce-claim-registration.test.ts +2 -0
  164. package/templates/apps/api/src/__tests__/server.test.ts +116 -0
  165. package/templates/apps/api/src/config/__tests__/index.test.ts +115 -14
  166. package/templates/apps/api/src/config/index.ts +35 -16
  167. package/templates/apps/api/src/lib/__tests__/lead-capture-store.test.ts +30 -0
  168. package/templates/apps/api/src/lib/__tests__/lead-delivery.test.ts +96 -0
  169. package/templates/apps/api/src/lib/lead-capture-store.ts +12 -0
  170. package/templates/apps/api/src/lib/lead-delivery.ts +52 -0
  171. package/templates/apps/api/src/lib/stripe.ts +9 -0
  172. package/templates/apps/api/src/middleware/__tests__/auth.optional-cookie.test.ts +140 -0
  173. package/templates/apps/api/src/middleware/auth.ts +54 -0
  174. package/templates/apps/api/src/openapi/spec.ts +63 -12
  175. package/templates/apps/api/src/routes/checkout/__tests__/session.test.ts +5 -2
  176. package/templates/apps/api/src/routes/checkout/__tests__/sessions.test.ts +628 -0
  177. package/templates/apps/api/src/routes/checkout/sessions.ts +222 -24
  178. package/templates/apps/api/src/routes/leads/__tests__/capture.test.ts +88 -0
  179. package/templates/apps/api/src/routes/leads/__tests__/index.test.ts +100 -0
  180. package/templates/apps/api/src/routes/leads/index.ts +46 -1
  181. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-flow-checkout.test.ts +1 -1
  182. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-org-billing.test.ts +5 -1
  183. package/templates/apps/api/src/routes/webhooks/__tests__/stripe.test.ts +521 -20
  184. package/templates/apps/api/src/routes/webhooks/stripe.ts +124 -32
  185. package/templates/apps/api/src/server.ts +35 -0
  186. package/templates/apps/api/src/services/__tests__/lead-routing.test.ts +194 -0
  187. package/templates/apps/api/src/services/__tests__/leads-inbox.test.ts +124 -0
  188. package/templates/apps/api/src/services/__tests__/revalidation.test.ts +90 -15
  189. package/templates/apps/api/src/services/checkout-buyer.ts +72 -0
  190. package/templates/apps/api/src/services/lead-routing.ts +140 -30
  191. package/templates/apps/api/src/services/leads-inbox.ts +48 -11
  192. package/templates/apps/api/src/services/revalidation.ts +60 -15
  193. package/templates/apps/mcp/__tests__/parity.test.ts +5 -4
  194. package/templates/apps/mcp/__tests__/tools/create_project.test.ts +30 -24
  195. package/templates/apps/mcp/src/tools/create_project.ts +21 -6
  196. package/templates/apps/mcp/src/tools/purchase.ts +4 -2
  197. package/templates/apps/web/.env.example +13 -0
  198. package/templates/apps/web/CLAUDE.md +22 -28
  199. package/templates/apps/web/app/[locale]/(auth)/layout.tsx +1 -1
  200. package/templates/apps/web/app/[locale]/(authed)/leads/__tests__/page.test.tsx +24 -0
  201. package/templates/apps/web/app/[locale]/(authed)/leads/page.tsx +17 -6
  202. package/templates/apps/web/app/[locale]/[slug]/[detail]/__tests__/page.test.tsx +110 -0
  203. package/templates/apps/web/app/[locale]/[slug]/[detail]/page.tsx +60 -0
  204. package/templates/apps/web/app/[locale]/[slug]/page.tsx +1 -1
  205. package/templates/apps/web/app/[locale]/alternatives/__tests__/page.test.tsx +161 -0
  206. package/templates/apps/web/app/[locale]/alternatives/page.tsx +104 -0
  207. package/templates/apps/web/app/[locale]/contact/ConversationalIntakeWrapper.tsx +14 -6
  208. package/templates/apps/web/app/[locale]/contact/__tests__/ConversationalIntakeWrapper.test.tsx +10 -9
  209. package/templates/apps/web/app/[locale]/contact/__tests__/contact-form-text.test.ts +32 -0
  210. package/templates/apps/web/app/[locale]/contact/__tests__/contact.actions.test.ts +129 -0
  211. package/templates/apps/web/app/[locale]/contact/__tests__/page-renderer-migration.test.tsx +227 -84
  212. package/templates/apps/web/app/[locale]/contact/contact-form-text.ts +50 -0
  213. package/templates/apps/web/app/[locale]/contact/contact.actions.ts +73 -20
  214. package/templates/apps/web/app/[locale]/contact/page.tsx +105 -15
  215. package/templates/apps/web/app/[locale]/contact/site-contact-email.ts +54 -0
  216. package/templates/apps/web/app/[locale]/features/[slug]/page.tsx +64 -0
  217. package/templates/apps/web/app/[locale]/features/page.tsx +52 -0
  218. package/templates/apps/web/app/[locale]/{use-cases → for}/[slug]/page.tsx +21 -5
  219. package/templates/apps/web/app/[locale]/for/__tests__/page-renderer-migration.test.tsx +73 -0
  220. package/templates/apps/web/app/[locale]/{use-cases → for}/page.tsx +8 -7
  221. package/templates/apps/web/app/[locale]/glossary/page.tsx +1 -1
  222. package/templates/apps/web/app/[locale]/layout.tsx +65 -17
  223. package/templates/apps/web/app/[locale]/newsletter/__tests__/newsletter.actions.test.ts +75 -0
  224. package/templates/apps/web/app/[locale]/newsletter/__tests__/page.test.tsx +163 -0
  225. package/templates/apps/web/app/[locale]/newsletter/newsletter.actions.ts +66 -0
  226. package/templates/apps/web/app/[locale]/newsletter/page.tsx +106 -14
  227. package/templates/apps/web/app/[locale]/portfolio/[slug]/page.tsx +59 -0
  228. package/templates/apps/web/app/[locale]/{book-a-call → portfolio}/page.tsx +12 -13
  229. package/templates/apps/web/app/[locale]/vs/[slug]/__tests__/page.test.tsx +112 -0
  230. package/templates/apps/web/app/[locale]/vs/[slug]/page.tsx +70 -0
  231. package/templates/apps/web/app/api/revalidate/__tests__/route.test.ts +236 -44
  232. package/templates/apps/web/app/api/revalidate/route.ts +78 -36
  233. package/templates/apps/web/lib/__tests__/site-brand.test.ts +79 -0
  234. package/templates/apps/web/lib/__tests__/site-theme.test.ts +104 -11
  235. package/templates/apps/web/lib/__tests__/structured-data.test.tsx +21 -4
  236. package/templates/apps/web/lib/locale-guard.ts +18 -0
  237. package/templates/apps/web/lib/meet-placeholder.ts +5 -0
  238. package/templates/apps/web/lib/nav-config.ts +50 -37
  239. package/templates/apps/web/lib/site-brand.tsx +13 -9
  240. package/templates/apps/web/lib/site-identity.ts +14 -0
  241. package/templates/apps/web/lib/site-logo.tsx +36 -0
  242. package/templates/apps/web/lib/site-theme.ts +46 -26
  243. package/templates/apps/web/messages/en.json +45 -5
  244. package/templates/apps/web/middleware.ts +28 -4
  245. package/templates/content/_site.mdx +4 -2
  246. package/templates/content/en/BlogList/blog.mdx +37 -16
  247. package/templates/content/en/BookCall/book-a-call.mdx +80 -0
  248. package/templates/content/en/BookCall/onsite-estimate.mdx +56 -0
  249. package/templates/content/en/BookCall/onsite-service.mdx +56 -0
  250. package/templates/content/en/BookCall/start-project.mdx +56 -0
  251. package/templates/content/en/ContactPage/contact.mdx +43 -34
  252. package/templates/content/en/HomePage/home.mdx +10 -22
  253. package/templates/content/en/LandingPage/meet.mdx +59 -0
  254. package/templates/content/en/PurchasePolicyPage/purchase-policy.mdx +0 -1
  255. package/templates/content/en/UseCasesList/{use-cases.mdx → for.mdx} +19 -18
  256. package/templates/database/CHANGELOG.md +14 -0
  257. package/templates/database/package.json +1 -1
  258. package/templates/package.json +2 -1
  259. package/templates/tools/check-claude-md.ts +128 -0
  260. package/versions.json +33 -33
  261. package/site-templates/_base/content/en/BookCall/book-call.mdx +0 -53
  262. package/site-templates/_base/content/en/UseCase/first-use-case.mdx +0 -23
  263. package/site-templates/_base/content/en/UseCase/second-use-case.mdx +0 -23
  264. package/site-templates/_base/content/en/UseCase/third-use-case.mdx +0 -23
  265. package/site-templates/minimalism-site/DESIGN.md +0 -162
  266. package/site-templates/minimalism-site/TEMPLATE-MANIFEST.md +0 -470
  267. package/site-templates/minimalism-site/ailk-template.json +0 -23
  268. package/site-templates/minimalism-site/content/en/AboutPage/about.mdx +0 -110
  269. package/site-templates/minimalism-site/content/en/BookCall/book-call.mdx +0 -53
  270. package/site-templates/minimalism-site/content/en/ContactPage/contact.mdx +0 -34
  271. package/site-templates/minimalism-site/content/en/FAQPage/faq.mdx +0 -57
  272. package/site-templates/minimalism-site/content/en/LandingPage/referral.mdx +0 -77
  273. package/site-templates/minimalism-site/content/en/LandingPage/reports.mdx +0 -73
  274. package/site-templates/minimalism-site/content/en/ReportPage/annual-letter-2024.mdx +0 -52
  275. package/site-templates/minimalism-site/content/en/ReportPage/field-notes-2023.mdx +0 -52
  276. package/site-templates/minimalism-site/content/en/ReportPage/platform-shift-2025.mdx +0 -52
  277. package/site-templates/minimalism-site/content/en/ReportPage/state-of-the-market-2026.mdx +0 -52
  278. package/site-templates/minimalism-site/flows/referral.flow.json +0 -71
  279. package/site-templates/minimalism-site/provenance.json +0 -4
  280. package/site-templates/simple-service/DESIGN.md +0 -162
  281. package/site-templates/simple-service/TEMPLATE-MANIFEST.md +0 -333
  282. package/site-templates/simple-service/ailk-template.json +0 -11
  283. package/site-templates/simple-service/content/en/BookCall/book-call.mdx +0 -53
  284. package/site-templates/simple-service/content/en/ContactPage/contact.mdx +0 -32
  285. package/site-templates/simple-service/content/en/FAQPage/faq.mdx +0 -56
  286. package/site-templates/simple-service/content/en/HomePage/home.mdx +0 -85
  287. package/site-templates/simple-service/content/en/Service/landscape-design.mdx +0 -40
  288. package/site-templates/simple-service/content/en/Service/lawn-maintenance.mdx +0 -40
  289. package/site-templates/simple-service/content/en/Service/seasonal-cleanup.mdx +0 -40
  290. package/site-templates/simple-service/provenance.json +0 -4
  291. package/templates/.claude/skills/add-page/templates/route.tsx.tmpl +0 -28
  292. package/templates/apps/web/app/[locale]/contact/ContactForm.tsx +0 -211
  293. package/templates/apps/web/app/[locale]/contact/__tests__/ContactForm.test.tsx +0 -96
  294. package/templates/apps/web/app/[locale]/use-cases/__tests__/page-renderer-migration.test.tsx +0 -72
  295. package/templates/content/en/SoftwareProduct/product.mdx +0 -175
  296. /package/site-templates/{minimalism-site → designs/minimalism/sample}/content/en/HomePage/home.mdx +0 -0
  297. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-1.svg +0 -0
  298. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-2.svg +0 -0
  299. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-3.svg +0 -0
  300. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-4.svg +0 -0
  301. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-5.svg +0 -0
  302. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-6.svg +0 -0
  303. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/hero-backdrop.svg +0 -0
  304. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/logo-placeholder-1.svg +0 -0
  305. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/logo-placeholder-2.svg +0 -0
  306. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/logo-placeholder-3.svg +0 -0
  307. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/wordmark-placeholder.svg +0 -0
  308. /package/site-templates/{minimalism-site → shapes/organization-service}/content/en/Service/first-engagement.mdx +0 -0
  309. /package/site-templates/{minimalism-site → shapes/organization-service}/content/en/Service/second-engagement.mdx +0 -0
  310. /package/site-templates/{minimalism-site → shapes/organization-service}/content/en/Service/third-engagement.mdx +0 -0
@@ -0,0 +1,59 @@
1
+ // Portfolio item page (#6687). Reads the PortfolioItem MDX for the given slug and emits a
2
+ // JSON-LD <script>. Unknown slugs trigger 404. Renders `sections[]` when the
3
+ // frontmatter carries them (the /for composed pattern), MDX prose otherwise.
4
+ // NO_HAND_IMPLEMENT_OK: /build-starter operator-directed live pass (#6687).
5
+ import {
6
+ getMdxSource as defaultGetMdxSource,
7
+ getMdxSlugs,
8
+ renderPage,
9
+ renderPageMetadata,
10
+ } from "@working-theory/page-renderer";
11
+ import type { Metadata } from "next";
12
+ import { notFound } from "next/navigation";
13
+ import type { ReactElement } from "react";
14
+
15
+ interface Props {
16
+ params: Promise<{ locale: string; slug: string }>;
17
+ getMdxSource?: typeof defaultGetMdxSource;
18
+ }
19
+
20
+ export async function generateMetadata({
21
+ params,
22
+ }: Pick<Props, "params">): Promise<Metadata> {
23
+ const { locale, slug } = await params;
24
+ return renderPageMetadata({ type: "PortfolioItem", slug, locale });
25
+ }
26
+
27
+ export async function generateStaticParams({
28
+ params,
29
+ }: {
30
+ params: { locale: string };
31
+ }): Promise<{ slug: string }[]> {
32
+ const slugs = await getMdxSlugs("PortfolioItem", params.locale);
33
+ return slugs.map((slug: string) => ({ slug }));
34
+ }
35
+
36
+ export default async function Page({
37
+ params,
38
+ getMdxSource = defaultGetMdxSource,
39
+ }: Props): Promise<ReactElement> {
40
+ const { locale, slug } = await params;
41
+ const source = await getMdxSource("PortfolioItem", slug, locale);
42
+
43
+ if (!source) {
44
+ notFound();
45
+ }
46
+
47
+ const composed =
48
+ Array.isArray((source.frontmatter as { sections?: unknown[] }).sections) &&
49
+ ((source.frontmatter as { sections?: unknown[] }).sections?.length ?? 0) > 0;
50
+
51
+ return renderPage({
52
+ type: "PortfolioItem",
53
+ slug,
54
+ locale,
55
+ translationsNamespace: "portfolio",
56
+ ...(composed ? {} : { bodyMode: "mdx-body" as const }),
57
+ getMdxSource: async () => source,
58
+ });
59
+ }
@@ -1,9 +1,8 @@
1
- // Book-a-call page (#6658 D5) — a BookCall at /book-a-call, reading the
2
- // fixed slug `book-call` (the monorepo's own content already uses it). Its
3
- // CTA points at /contact, or at /meet where a template carries scheduling. A
4
- // module-less surface a template enables by naming it in its roster; with no
5
- // content the route 404s. Mirrors use-cases/page.tsx: a sections-composed page
6
- // renders its sections, a prose-only page its MDX body.
1
+ // Portfolio list page (#6687). Reads PortfolioList MDX via the content adapter and emits
2
+ // a JSON-LD CollectionPage via the dispatcher.
3
+ // NO_HAND_IMPLEMENT_OK: /build-starter operator-directed live pass (#6687) — the
4
+ // /for composed pattern mirrored onto the portfolio hub: sections when the
5
+ // frontmatter carries `sections[]`, MDX prose otherwise (existing prose pages unchanged).
7
6
  import type { getMdxSource as defaultGetMdxSource } from "@working-theory/page-renderer";
8
7
  import {
9
8
  getMdxSource as loadMdxSource,
@@ -23,8 +22,8 @@ export async function generateMetadata({
23
22
  }: Pick<Props, "params">): Promise<Metadata> {
24
23
  const { locale } = await params;
25
24
  return renderPageMetadata({
26
- type: "BookCall",
27
- slug: "book-call",
25
+ type: "PortfolioList",
26
+ slug: "portfolio",
28
27
  locale,
29
28
  });
30
29
  }
@@ -34,16 +33,16 @@ export default async function Page({
34
33
  getMdxSource,
35
34
  }: Props): Promise<ReactElement> {
36
35
  const { locale } = await params;
37
- const source = await (getMdxSource ?? loadMdxSource)("BookCall", "book-call", locale);
36
+ const source = await (getMdxSource ?? loadMdxSource)("PortfolioList", "portfolio", locale);
38
37
  const composed =
39
38
  source !== null &&
40
39
  Array.isArray((source.frontmatter as { sections?: unknown[] }).sections) &&
41
- ((source.frontmatter as { sections?: unknown[] }).sections?.length ?? 0) >
42
- 0;
40
+ ((source.frontmatter as { sections?: unknown[] }).sections?.length ?? 0) > 0;
43
41
  return renderPage({
44
- type: "BookCall",
45
- slug: "book-call",
42
+ type: "PortfolioList",
43
+ slug: "portfolio",
46
44
  locale,
45
+ translationsNamespace: "portfolio",
47
46
  ...(composed ? {} : { bodyMode: "mdx-body" as const }),
48
47
  ...(getMdxSource !== undefined && { getMdxSource }),
49
48
  });
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Tests for /vs/[slug] (#6878 D9) — the ComparisonPage detail route.
3
+ * `renderPage`/`renderPageMetadata`/`getMdxSlugs` are mocked at the
4
+ * `@working-theory/page-renderer` boundary; `getMdxSource` is supplied
5
+ * per-call through the route's DI prop.
6
+ */
7
+ // The mock return value is never rendered — every assertion below inspects
8
+ // `mockRenderPage.mock.calls` directly — so it carries no `ReactElement`
9
+ // cast; `renderPage`'s real return type is `Promise<ReactElement>` in
10
+ // production, unaffected by this mock's loose type here.
11
+ const mockRenderPage = jest.fn(async (..._args: unknown[]) => "<rendered/>");
12
+ const mockRenderPageMetadata = jest.fn((..._args: unknown[]) => undefined);
13
+ const mockGetMdxSlugs = jest.fn((..._args: unknown[]) => Promise.resolve<string[]>([]));
14
+
15
+ jest.mock("@working-theory/page-renderer", () => ({
16
+ __esModule: true,
17
+ getMdxSlugs: (...args: unknown[]) => mockGetMdxSlugs(...args),
18
+ renderPage: (...args: unknown[]) => mockRenderPage(...args),
19
+ renderPageMetadata: (...args: unknown[]) => mockRenderPageMetadata(...args),
20
+ getMdxSource: jest.fn(),
21
+ }));
22
+
23
+ import ComparisonPage, {
24
+ generateMetadata,
25
+ generateStaticParams,
26
+ } from "../page";
27
+
28
+ beforeEach(() => jest.clearAllMocks());
29
+
30
+ describe("ComparisonPage detail — metadata + static params", () => {
31
+ it("resolves metadata for the given slug", async () => {
32
+ await generateMetadata({
33
+ params: Promise.resolve({ locale: "en", slug: "acme" }),
34
+ });
35
+ expect(mockRenderPageMetadata).toHaveBeenCalledWith({
36
+ type: "ComparisonPage",
37
+ slug: "acme",
38
+ locale: "en",
39
+ });
40
+ });
41
+
42
+ it("enumerates every ComparisonPage slug for static generation", async () => {
43
+ mockGetMdxSlugs.mockResolvedValue(["acme", "globex"]);
44
+ const params = await generateStaticParams({ params: { locale: "en" } });
45
+ expect(mockGetMdxSlugs).toHaveBeenCalledWith("ComparisonPage", "en");
46
+ expect(params).toEqual([{ slug: "acme" }, { slug: "globex" }]);
47
+ });
48
+ });
49
+
50
+ describe("ComparisonPage detail — sections vs mdx-body", () => {
51
+ it("renders in sections mode (D10: hero, decision-split, comparison-table, cta) when frontmatter carries sections", async () => {
52
+ const getMdxSource = jest.fn().mockResolvedValue({
53
+ frontmatter: {
54
+ type: "ComparisonPage",
55
+ slug: "acme",
56
+ title: "vs. Acme",
57
+ description: "How we compare to Acme.",
58
+ sections: [
59
+ { id: "hero", type: "hero", data: {} },
60
+ { id: "compare", type: "decision-split", data: {} },
61
+ { id: "table", type: "comparison-table", data: {} },
62
+ {
63
+ id: "cta",
64
+ type: "cta",
65
+ data: { primaryCta: { label: "See all alternatives", href: "/alternatives" } },
66
+ },
67
+ ],
68
+ },
69
+ body: "",
70
+ });
71
+
72
+ await ComparisonPage({
73
+ params: Promise.resolve({ locale: "en", slug: "acme" }),
74
+ getMdxSource,
75
+ });
76
+
77
+ const passedInput = mockRenderPage.mock.calls[0]?.[0] as {
78
+ type: string;
79
+ slug: string;
80
+ bodyMode?: string;
81
+ };
82
+ expect(passedInput.type).toBe("ComparisonPage");
83
+ expect(passedInput.slug).toBe("acme");
84
+ expect(passedInput.bodyMode).toBeUndefined();
85
+ });
86
+
87
+ it("falls back to mdx-body mode for a prose-only comparison page", async () => {
88
+ const getMdxSource = jest.fn().mockResolvedValue({
89
+ frontmatter: {
90
+ type: "ComparisonPage",
91
+ slug: "acme",
92
+ title: "vs. Acme",
93
+ description: "How we compare to Acme.",
94
+ },
95
+ body: "Prose comparison.",
96
+ });
97
+
98
+ await ComparisonPage({
99
+ params: Promise.resolve({ locale: "en", slug: "acme" }),
100
+ getMdxSource,
101
+ });
102
+
103
+ const passedInput = mockRenderPage.mock.calls[0]?.[0] as {
104
+ bodyMode?: string;
105
+ populatedDescriptionTestId?: string;
106
+ };
107
+ expect(passedInput.bodyMode).toBe("mdx-body");
108
+ expect(passedInput.populatedDescriptionTestId).toBe(
109
+ "comparison-description",
110
+ );
111
+ });
112
+ });
@@ -0,0 +1,70 @@
1
+ // ComparisonPage detail (#6878 D9) — one head-to-head comparison at
2
+ // /vs/<slug>, listed by the /alternatives hub. Reads the ComparisonPage MDX
3
+ // for the given slug, renders via @working-theory/page-renderer, and emits a
4
+ // JSON-LD WebPage. Unknown slugs 404. Composed `sections[]` (D10 — the
5
+ // generic detail chassis, no dedicated comparison section: hero,
6
+ // decision-split, comparison-table, cta) render as sections; a prose page
7
+ // renders its MDX body — the same rule the /for detail page applies.
8
+ //
9
+ // Gated off by default (surfaces.ts `alternatives` surface): no roster names
10
+ // this route, so a fresh scaffold excludes it. `add-page` installs it (D11)
11
+ // the first time a site adds a comparison.
12
+ import type { getMdxSource as defaultGetMdxSource } from "@working-theory/page-renderer";
13
+ import {
14
+ getMdxSource as loadMdxSource,
15
+ getMdxSlugs,
16
+ renderPage,
17
+ renderPageMetadata,
18
+ } from "@working-theory/page-renderer";
19
+ import type { Metadata } from "next";
20
+ import type { ReactElement } from "react";
21
+
22
+ interface Props {
23
+ params: Promise<{ locale: string; slug: string }>;
24
+ getMdxSource?: typeof defaultGetMdxSource;
25
+ }
26
+
27
+ export async function generateMetadata({
28
+ params,
29
+ }: Pick<Props, "params">): Promise<Metadata> {
30
+ const { locale, slug } = await params;
31
+ return renderPageMetadata({ type: "ComparisonPage", slug, locale });
32
+ }
33
+
34
+ export async function generateStaticParams({
35
+ params,
36
+ }: {
37
+ params: { locale: string };
38
+ }): Promise<{ slug: string }[]> {
39
+ const slugs = await getMdxSlugs("ComparisonPage", params.locale);
40
+ return slugs.map((slug) => ({ slug }));
41
+ }
42
+
43
+ export default async function Page({
44
+ params,
45
+ getMdxSource,
46
+ }: Props): Promise<ReactElement> {
47
+ const { locale, slug } = await params;
48
+ const source = await (getMdxSource ?? loadMdxSource)(
49
+ "ComparisonPage",
50
+ slug,
51
+ locale,
52
+ );
53
+ const composed =
54
+ source !== null &&
55
+ Array.isArray((source.frontmatter as { sections?: unknown[] }).sections) &&
56
+ ((source.frontmatter as { sections?: unknown[] }).sections?.length ?? 0) >
57
+ 0;
58
+ return renderPage({
59
+ type: "ComparisonPage",
60
+ slug,
61
+ locale,
62
+ ...(composed
63
+ ? {}
64
+ : {
65
+ bodyMode: "mdx-body" as const,
66
+ populatedDescriptionTestId: "comparison-description",
67
+ }),
68
+ ...(getMdxSource !== undefined && { getMdxSource }),
69
+ });
70
+ }