create-ailk 0.8.0 → 0.10.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 (238) hide show
  1. package/README.md +71 -3
  2. package/component-catalog.json +279 -45
  3. package/dist/add-module.d.ts +20 -0
  4. package/dist/add-module.js +43 -7
  5. package/dist/add-route.d.ts +56 -0
  6. package/dist/add-route.js +286 -0
  7. package/dist/apply-design-md.d.ts +7 -0
  8. package/dist/apply-design-md.js +50 -0
  9. package/dist/apply-design.d.ts +64 -0
  10. package/dist/apply-design.js +273 -0
  11. package/dist/claude-md.d.ts +111 -0
  12. package/dist/claude-md.js +334 -0
  13. package/dist/cli.js +104 -5
  14. package/dist/derive-architecture.js +41 -36
  15. package/dist/design-compile.d.ts +71 -0
  16. package/dist/design-compile.js +98 -0
  17. package/dist/design-package.d.ts +83 -0
  18. package/dist/design-package.js +468 -0
  19. package/dist/design-presets.d.ts +86 -0
  20. package/dist/design-presets.js +642 -0
  21. package/dist/design-scaffold.d.ts +76 -0
  22. package/dist/design-scaffold.js +220 -0
  23. package/dist/index.d.ts +2 -1
  24. package/dist/index.js +4 -1
  25. package/dist/legacy-nav-renderers.d.ts +45 -0
  26. package/dist/legacy-nav-renderers.js +545 -0
  27. package/dist/lib/auth-secret-file.d.ts +19 -0
  28. package/dist/lib/auth-secret-file.js +112 -0
  29. package/dist/lib/design-checks.d.ts +78 -0
  30. package/dist/lib/design-checks.js +174 -0
  31. package/dist/lib/license-key-files.d.ts +9 -0
  32. package/dist/lib/license-key-files.js +2 -2
  33. package/dist/lib/module-license-gate.d.ts +48 -32
  34. package/dist/lib/module-license-gate.js +117 -8
  35. package/dist/lib/render-verdict.d.ts +52 -0
  36. package/dist/lib/render-verdict.js +77 -0
  37. package/dist/lib/scaffold-render-sweep.d.ts +105 -0
  38. package/dist/lib/scaffold-render-sweep.js +236 -0
  39. package/dist/module-architecture.d.ts +19 -16
  40. package/dist/module-architecture.js +67 -23
  41. package/dist/parse-args.d.ts +12 -2
  42. package/dist/parse-args.js +74 -13
  43. package/dist/programmatic.d.ts +30 -6
  44. package/dist/programmatic.js +216 -19
  45. package/dist/site-chrome.d.ts +19 -9
  46. package/dist/site-chrome.js +23 -13
  47. package/dist/site-manifest.d.ts +25 -0
  48. package/dist/site-manifest.js +254 -0
  49. package/dist/site-roster.d.ts +41 -0
  50. package/dist/site-roster.js +141 -8
  51. package/dist/starter-grid.d.ts +16 -63
  52. package/dist/starter-grid.js +102 -84
  53. package/dist/surfaces.d.ts +41 -9
  54. package/dist/surfaces.js +200 -83
  55. package/dist/template-manifest.d.ts +30 -13
  56. package/dist/template-manifest.js +53 -28
  57. package/package.json +6 -3
  58. package/release-scope.json +25 -0
  59. package/site-templates/_base/content/en/UseCase/persona-1.mdx +7 -6
  60. package/site-templates/_base/content/en/UseCase/persona-2.mdx +7 -6
  61. package/site-templates/_base/content/en/UseCase/persona-3.mdx +7 -6
  62. package/site-templates/designs/minimalism/DESIGN.md +98 -6
  63. package/site-templates/designs/minimalism/sample/README.md +48 -0
  64. package/site-templates/{minimalism-site → designs/minimalism/sample}/content/en/HomePage/home.mdx +1 -1
  65. package/site-templates/designs/standard/DESIGN.md +98 -6
  66. package/site-templates/marketing-site/DESIGN.md +98 -6
  67. package/site-templates/marketing-site/TEMPLATE-MANIFEST.json +60 -27
  68. package/site-templates/marketing-site/TEMPLATE-MANIFEST.md +50 -30
  69. package/site-templates/marketing-site-free/DESIGN.md +98 -6
  70. package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.json +60 -24
  71. package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.md +44 -27
  72. package/site-templates/marketing-site-free/ailk-template.json +1 -1
  73. package/site-templates/saas-product/DESIGN.md +98 -6
  74. package/site-templates/shapes/local-business-service/TEMPLATE-MANIFEST.json +127 -18
  75. package/site-templates/shapes/local-business-service/TEMPLATE-MANIFEST.md +74 -20
  76. package/site-templates/shapes/local-business-service/ailk-template.json +1 -1
  77. package/site-templates/shapes/organization-service/TEMPLATE-MANIFEST.json +127 -18
  78. package/site-templates/shapes/organization-service/TEMPLATE-MANIFEST.md +74 -20
  79. package/site-templates/shapes/organization-service/ailk-template.json +1 -1
  80. package/site-templates/shapes/person-service/TEMPLATE-MANIFEST.json +127 -18
  81. package/site-templates/shapes/person-service/TEMPLATE-MANIFEST.md +75 -21
  82. package/site-templates/shapes/person-service/ailk-template.json +1 -1
  83. package/site-templates/shapes/person-service/content/en/AboutPage/about.mdx +1 -1
  84. package/site-templates/shapes/person-service/content/en/HomePage/home.mdx +2 -2
  85. package/site-templates/shapes/person-service/content/en/PortfolioList/portfolio.mdx +4 -2
  86. package/site-templates/shapes/person-service/content/en/ServicesList/services.mdx +1 -1
  87. package/templates/.claude/agents/web.md +10 -8
  88. package/templates/.claude/rules/architecture.md +17 -7
  89. package/templates/.claude/skills/README.md +3 -2
  90. package/templates/.claude/skills/add-auth/SKILL.md +142 -90
  91. package/templates/.claude/skills/add-auth/references/env-vars.md +32 -17
  92. package/templates/.claude/skills/add-auth/references/oauth-app-setup.md +17 -8
  93. package/templates/.claude/skills/add-page/SKILL.md +241 -238
  94. package/templates/.claude/skills/add-page/references/page-types.md +94 -86
  95. package/templates/.claude/skills/add-page/scripts/site-pages.mjs +87 -0
  96. package/templates/.claude/skills/add-page/templates/comparison-page.mdx.tmpl +99 -0
  97. package/templates/.claude/skills/add-page/templates/content.mdx.tmpl +8 -18
  98. package/templates/.claude/skills/add-page/templates/flow-landing-page.mdx.tmpl +43 -0
  99. package/templates/.claude/skills/add-page/templates/report-page.mdx.tmpl +52 -0
  100. package/templates/.claude/skills/add-page/templates/reports-list.mdx.tmpl +38 -0
  101. package/templates/.claude/skills/check-site/SKILL.md +51 -18
  102. package/templates/.claude/skills/check-site/references/common-errors.md +12 -9
  103. package/templates/.claude/skills/check-site/references/findings-glossary.md +4 -4
  104. package/templates/.claude/skills/check-site/references/severity-levels.md +3 -3
  105. package/templates/.claude/skills/fill-page/SKILL.md +26 -7
  106. package/templates/.claude/skills/fill-page/profiles/plumbing.yaml +1 -1
  107. package/templates/.claude/skills/setup-deploy/SKILL.md +75 -38
  108. package/templates/.claude/skills/update-page/SKILL.md +117 -0
  109. package/templates/.claude/skills/update-page/scripts/update-page.ts +640 -0
  110. package/templates/.claude/skills/update-page/templates/redirects.mjs.tmpl +31 -0
  111. package/templates/.claude/skills/upgrade-plan/SKILL.md +12 -8
  112. package/templates/.env.example +23 -2
  113. package/templates/.github/workflows/ci.yml +4 -0
  114. package/templates/.prettierignore +1 -0
  115. package/templates/CLAUDE.md +146 -103
  116. package/templates/DESIGN.md +98 -6
  117. package/templates/README.md +50 -38
  118. package/templates/apps/api/.env.example +2 -1
  119. package/templates/apps/api/src/__tests__/commerce-claim-registration.test.ts +2 -0
  120. package/templates/apps/api/src/__tests__/server.test.ts +116 -0
  121. package/templates/apps/api/src/lib/stripe.ts +9 -0
  122. package/templates/apps/api/src/middleware/__tests__/auth.optional-cookie.test.ts +140 -0
  123. package/templates/apps/api/src/middleware/auth.ts +54 -0
  124. package/templates/apps/api/src/routes/checkout/__tests__/session.test.ts +5 -2
  125. package/templates/apps/api/src/routes/checkout/__tests__/sessions.test.ts +628 -0
  126. package/templates/apps/api/src/routes/checkout/sessions.ts +222 -24
  127. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-flow-checkout.test.ts +1 -1
  128. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-org-billing.test.ts +5 -1
  129. package/templates/apps/api/src/routes/webhooks/__tests__/stripe.test.ts +521 -20
  130. package/templates/apps/api/src/routes/webhooks/stripe.ts +124 -32
  131. package/templates/apps/api/src/server.ts +28 -0
  132. package/templates/apps/api/src/services/__tests__/revalidation.test.ts +90 -15
  133. package/templates/apps/api/src/services/checkout-buyer.ts +72 -0
  134. package/templates/apps/api/src/services/revalidation.ts +60 -15
  135. package/templates/apps/mcp/__tests__/tools/create_project.test.ts +30 -24
  136. package/templates/apps/mcp/src/tools/purchase.ts +4 -2
  137. package/templates/apps/web/.env.example +13 -0
  138. package/templates/apps/web/CLAUDE.md +22 -28
  139. package/templates/apps/web/app/[locale]/(auth)/layout.tsx +1 -1
  140. package/templates/apps/web/app/[locale]/(authed)/leads/__tests__/page.test.tsx +24 -0
  141. package/templates/apps/web/app/[locale]/(authed)/leads/page.tsx +17 -6
  142. package/templates/apps/web/app/[locale]/[slug]/[detail]/__tests__/page.test.tsx +110 -0
  143. package/templates/apps/web/app/[locale]/[slug]/[detail]/page.tsx +60 -0
  144. package/templates/apps/web/app/[locale]/[slug]/page.tsx +1 -1
  145. package/templates/apps/web/app/[locale]/alternatives/__tests__/page.test.tsx +161 -0
  146. package/templates/apps/web/app/[locale]/alternatives/page.tsx +104 -0
  147. package/templates/apps/web/app/[locale]/{use-cases → for}/[slug]/page.tsx +4 -3
  148. package/templates/apps/web/app/[locale]/for/__tests__/page-renderer-migration.test.tsx +73 -0
  149. package/templates/apps/web/app/[locale]/{use-cases → for}/page.tsx +8 -7
  150. package/templates/apps/web/app/[locale]/glossary/page.tsx +1 -1
  151. package/templates/apps/web/app/[locale]/layout.tsx +35 -19
  152. package/templates/apps/web/app/[locale]/newsletter/page.tsx +1 -1
  153. package/templates/apps/web/app/[locale]/portfolio/[slug]/page.tsx +1 -1
  154. package/templates/apps/web/app/[locale]/portfolio/page.tsx +1 -1
  155. package/templates/apps/web/app/[locale]/vs/[slug]/__tests__/page.test.tsx +112 -0
  156. package/templates/apps/web/app/[locale]/vs/[slug]/page.tsx +70 -0
  157. package/templates/apps/web/app/api/revalidate/__tests__/route.test.ts +236 -44
  158. package/templates/apps/web/app/api/revalidate/route.ts +78 -36
  159. package/templates/apps/web/lib/__tests__/site-brand.test.ts +79 -0
  160. package/templates/apps/web/lib/__tests__/site-theme.test.ts +104 -11
  161. package/templates/apps/web/lib/__tests__/structured-data.test.tsx +21 -4
  162. package/templates/apps/web/lib/locale-guard.ts +18 -0
  163. package/templates/apps/web/lib/meet-placeholder.ts +5 -0
  164. package/templates/apps/web/lib/nav-config.ts +14 -13
  165. package/templates/apps/web/lib/site-brand.tsx +13 -9
  166. package/templates/apps/web/lib/site-logo.tsx +36 -0
  167. package/templates/apps/web/lib/site-theme.ts +46 -26
  168. package/templates/apps/web/messages/en.json +23 -9
  169. package/templates/apps/web/middleware.ts +28 -4
  170. package/templates/content/en/BookCall/book-a-call.mdx +80 -0
  171. package/templates/content/en/BookCall/onsite-estimate.mdx +56 -0
  172. package/templates/content/en/BookCall/onsite-service.mdx +56 -0
  173. package/templates/content/en/BookCall/start-project.mdx +56 -0
  174. package/templates/content/en/ContactPage/contact.mdx +40 -1
  175. package/templates/content/en/HomePage/home.mdx +2 -6
  176. package/templates/content/en/LandingPage/meet.mdx +59 -0
  177. package/templates/content/en/UseCasesList/{use-cases.mdx → for.mdx} +19 -18
  178. package/templates/database/CHANGELOG.md +7 -0
  179. package/templates/database/package.json +1 -1
  180. package/templates/package.json +4 -1
  181. package/templates/tools/check-claude-md.ts +128 -0
  182. package/versions.json +33 -33
  183. package/dist/modules/commerce/0.6.0.tar.gz +0 -0
  184. package/dist/modules/commerce/0.6.1.tar.gz +0 -0
  185. package/dist/modules/docs-blog/0.6.0.tar.gz +0 -0
  186. package/dist/modules/docs-blog/0.6.1.tar.gz +0 -0
  187. package/dist/modules/marketing-site/0.6.1.tar.gz +0 -0
  188. package/dist/modules/minimalism-site/0.6.1.tar.gz +0 -0
  189. package/dist/modules/multi-tenant/0.6.0.tar.gz +0 -0
  190. package/dist/modules/multi-tenant/0.6.1.tar.gz +0 -0
  191. package/dist/modules/saas-product/0.6.1.tar.gz +0 -0
  192. package/dist/modules/scheduling/0.6.0.tar.gz +0 -0
  193. package/dist/modules/scheduling/0.6.1.tar.gz +0 -0
  194. package/dist/modules/signal-collectors/0.6.0.tar.gz +0 -0
  195. package/dist/modules/signal-collectors/0.6.1.tar.gz +0 -0
  196. package/dist/modules/simple-service/0.6.1.tar.gz +0 -0
  197. package/dist/modules/workspace/0.6.0.tar.gz +0 -0
  198. package/dist/modules/workspace/0.6.1.tar.gz +0 -0
  199. package/site-templates/_base/content/en/BookCall/book-call.mdx +0 -52
  200. package/site-templates/minimalism-site/DESIGN.md +0 -162
  201. package/site-templates/minimalism-site/TEMPLATE-MANIFEST.json +0 -506
  202. package/site-templates/minimalism-site/TEMPLATE-MANIFEST.md +0 -458
  203. package/site-templates/minimalism-site/ailk-template.json +0 -23
  204. package/site-templates/minimalism-site/content/en/AboutPage/about.mdx +0 -110
  205. package/site-templates/minimalism-site/content/en/BookCall/book-call.mdx +0 -52
  206. package/site-templates/minimalism-site/content/en/ContactPage/contact.mdx +0 -34
  207. package/site-templates/minimalism-site/content/en/FAQPage/faq.mdx +0 -57
  208. package/site-templates/minimalism-site/content/en/LandingPage/referral.mdx +0 -77
  209. package/site-templates/minimalism-site/content/en/LandingPage/reports.mdx +0 -73
  210. package/site-templates/minimalism-site/content/en/PurchasePolicyPage/purchase-policy.mdx +0 -123
  211. package/site-templates/minimalism-site/content/en/ReportPage/annual-letter-2024.mdx +0 -52
  212. package/site-templates/minimalism-site/content/en/ReportPage/field-notes-2023.mdx +0 -52
  213. package/site-templates/minimalism-site/content/en/ReportPage/platform-shift-2025.mdx +0 -52
  214. package/site-templates/minimalism-site/content/en/ReportPage/state-of-the-market-2026.mdx +0 -52
  215. package/site-templates/minimalism-site/content/en/Service/first-engagement.mdx +0 -38
  216. package/site-templates/minimalism-site/content/en/Service/second-engagement.mdx +0 -38
  217. package/site-templates/minimalism-site/content/en/Service/third-engagement.mdx +0 -38
  218. package/site-templates/minimalism-site/content/en/ServicesList/services.mdx +0 -73
  219. package/site-templates/minimalism-site/flows/referral.flow.json +0 -71
  220. package/site-templates/minimalism-site/provenance.json +0 -4
  221. package/templates/.claude/skills/add-page/templates/route.tsx.tmpl +0 -28
  222. package/templates/.claude/skills/setup-deploy/references/env-vars-template.md +0 -175
  223. package/templates/apps/api/.ailk/inbox/2026-09-20T14-57-31.552Z-fallback-1789916251590-037e9005.json +0 -8
  224. package/templates/apps/api/.ailk/inbox/2026-09-20T14-57-33.840Z-fallback-1789916253842-b52659e9.json +0 -12
  225. package/templates/apps/api/.ailk/inbox/2026-09-20T14-57-33.844Z-fallback-1789916253845-6b266f8c.json +0 -12
  226. package/templates/apps/web/app/[locale]/book-a-call/page.tsx +0 -50
  227. package/templates/apps/web/app/[locale]/use-cases/__tests__/page-renderer-migration.test.tsx +0 -72
  228. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-1.svg +0 -0
  229. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-2.svg +0 -0
  230. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-3.svg +0 -0
  231. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-4.svg +0 -0
  232. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-5.svg +0 -0
  233. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-6.svg +0 -0
  234. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/hero-backdrop.svg +0 -0
  235. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/logo-placeholder-1.svg +0 -0
  236. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/logo-placeholder-2.svg +0 -0
  237. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/logo-placeholder-3.svg +0 -0
  238. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/wordmark-placeholder.svg +0 -0
@@ -1,38 +0,0 @@
1
- ---
2
- type: "Service"
3
- slug: "second-engagement"
4
- title: "{Second engagement}"
5
- description: "{One line on what this engagement is and who it suits. Replace before you launch.}"
6
- schema:
7
- serviceType: "{Second engagement}"
8
- provider:
9
- "@type": Organization
10
- name: "Your Company"
11
- ---
12
-
13
- # {Second engagement}
14
-
15
- {Open with the situation a reader is in when they come looking for this. Two or
16
- three sentences, no more — the detail belongs under the headings below.}
17
-
18
- ## What it covers
19
-
20
- - {The first thing you actually do}
21
- - {The second thing you actually do}
22
- - {The third thing you actually do}
23
-
24
- ## How it runs
25
-
26
- {One paragraph on the shape of the engagement: how it starts, how long it runs,
27
- who is involved on both sides, and what a week looks like.}
28
-
29
- ## What you end up with
30
-
31
- {One paragraph on the deliverable. Be concrete — name the artefact, not the
32
- feeling.}
33
-
34
- ## What it costs
35
-
36
- {One line on the pricing shape — fixed fee, retainer, day rate — and what it
37
- excludes. Replace with your real numbers, or delete this section and let the
38
- call do it.}
@@ -1,38 +0,0 @@
1
- ---
2
- type: "Service"
3
- slug: "third-engagement"
4
- title: "{Third engagement}"
5
- description: "{One line on what this engagement is and who it suits. Replace before you launch.}"
6
- schema:
7
- serviceType: "{Third engagement}"
8
- provider:
9
- "@type": Organization
10
- name: "Your Company"
11
- ---
12
-
13
- # {Third engagement}
14
-
15
- {Open with the situation a reader is in when they come looking for this. Two or
16
- three sentences, no more — the detail belongs under the headings below.}
17
-
18
- ## What it covers
19
-
20
- - {The first thing you actually do}
21
- - {The second thing you actually do}
22
- - {The third thing you actually do}
23
-
24
- ## How it runs
25
-
26
- {One paragraph on the shape of the engagement: how it starts, how long it runs,
27
- who is involved on both sides, and what a week looks like.}
28
-
29
- ## What you end up with
30
-
31
- {One paragraph on the deliverable. Be concrete — name the artefact, not the
32
- feeling.}
33
-
34
- ## What it costs
35
-
36
- {One line on the pricing shape — fixed fee, retainer, day rate — and what it
37
- excludes. Replace with your real numbers, or delete this section and let the
38
- call do it.}
@@ -1,73 +0,0 @@
1
- ---
2
- type: "ServicesList"
3
- slug: "services"
4
- title: "Services"
5
- description: "The three engagements {your company} offers. Placeholder copy — replace before you launch."
6
- sections:
7
- [
8
- {
9
- "id": "hero",
10
- "type": "hero",
11
- "data":
12
- {
13
- "variant": "centered",
14
- "eyebrow": "Services",
15
- "headline": "Three ways to work together",
16
- "subheadline": "{One line on how to choose between them. Name the question a reader is actually asking.}",
17
- },
18
- },
19
- {
20
- "id": "engagements",
21
- "type": "items",
22
- "data":
23
- {
24
- "headline": "Engagements",
25
- "columns": 3,
26
- "items":
27
- [
28
- {
29
- "title": "{First engagement}",
30
- "description": "{One line on what it is and who it suits.}",
31
- "link":
32
- {
33
- "label": "Read more",
34
- "href": "/services/first-engagement",
35
- },
36
- },
37
- {
38
- "title": "{Second engagement}",
39
- "description": "{One line on what it is and who it suits.}",
40
- "link":
41
- {
42
- "label": "Read more",
43
- "href": "/services/second-engagement",
44
- },
45
- },
46
- {
47
- "title": "{Third engagement}",
48
- "description": "{One line on what it is and who it suits.}",
49
- "link":
50
- {
51
- "label": "Read more",
52
- "href": "/services/third-engagement",
53
- },
54
- },
55
- ],
56
- },
57
- },
58
- {
59
- "id": "closing",
60
- "type": "cta",
61
- "data":
62
- {
63
- "variant": "minimal",
64
- "headline": "Not sure which one?",
65
- "description": "{One line inviting the reader to book the call instead of guessing.}",
66
- "primaryCta": { "label": "Hire me →", "href": "/meet" },
67
- },
68
- },
69
- ]
70
- ---
71
-
72
- {/_ Placeholder copy. The three detail pages under `content/en/Service/` carry
73
- the long form; this page is the chooser. _/}
@@ -1,71 +0,0 @@
1
- {
2
- "slug": "referral",
3
- "defaultLocale": "en",
4
- "steps": [
5
- {
6
- "key": "introduction",
7
- "type": "field",
8
- "copy": {
9
- "title": {
10
- "en": "Who should we meet?"
11
- }
12
- },
13
- "fields": [
14
- {
15
- "name": "referrer_name",
16
- "inputType": "text",
17
- "required": true,
18
- "mapsTo": "name",
19
- "copy": {
20
- "label": {
21
- "en": "Your name"
22
- },
23
- "help": {
24
- "en": "So we can tell them who sent us."
25
- }
26
- }
27
- },
28
- {
29
- "name": "referrer_email",
30
- "inputType": "email",
31
- "required": true,
32
- "mapsTo": "email",
33
- "copy": {
34
- "label": {
35
- "en": "Your email"
36
- },
37
- "help": {
38
- "en": "Where we tell you how it went."
39
- }
40
- }
41
- },
42
- {
43
- "name": "referral_details",
44
- "inputType": "textarea",
45
- "required": true,
46
- "minLength": 20,
47
- "copy": {
48
- "label": {
49
- "en": "Who are they, and why them?"
50
- },
51
- "placeholder": {
52
- "en": "Their name, a way to reach them, and one line on why you thought of them."
53
- }
54
- }
55
- }
56
- ]
57
- },
58
- {
59
- "key": "sent",
60
- "type": "message",
61
- "copy": {
62
- "title": {
63
- "en": "Thank you — the introduction is in"
64
- },
65
- "body": {
66
- "en": "We will reach out within a few days and let you know either way. Placeholder copy: replace it with what you actually do."
67
- }
68
- }
69
- }
70
- ]
71
- }
@@ -1,4 +0,0 @@
1
- {
2
- "template": "minimalism-site",
3
- "requires": ["marketing", "scheduling", "signal-collectors"]
4
- }
@@ -1,28 +0,0 @@
1
- // Emitted by `add-page` at `app/{{SLUG}}/page.tsx`. Substitutions:
2
- // {{SLUG}} — page slug (e.g., "pricing")
3
- // {{TYPE}} — schema.org @type (e.g., "Service")
4
- // {{BUILDER}} — typed builder name (e.g., "buildService")
5
- // {{TITLE}} — page title (e.g., "Pricing")
6
- import { notFound } from "next/navigation";
7
-
8
- import { JsonLd } from "@working-theory/jsonld";
9
- import { {{BUILDER}} } from "@working-theory/schema";
10
- import { mdxAdapter } from "@/lib/content";
11
-
12
- export default async function {{TYPE}}Page() {
13
- const page = await mdxAdapter.getPage("{{SLUG}}");
14
- if (!page) return notFound();
15
-
16
- const schema = {{BUILDER}}(page);
17
-
18
- return (
19
- <main className="mx-auto max-w-3xl px-6 py-12">
20
- <JsonLd schema={schema} />
21
- <article className="prose dark:prose-invert">
22
- <h1>{page.title}</h1>
23
- {page.description ? <p className="lead">{page.description}</p> : null}
24
- {/* Render MDX body via your project's MDX renderer of choice. */}
25
- </article>
26
- </main>
27
- );
28
- }
@@ -1,175 +0,0 @@
1
- # `.env.example` Template
2
-
3
- The structure the `setup-deploy` skill emits at the consumer's
4
- project root. Placeholder values only — the skill never echoes a
5
- real secret.
6
-
7
- When `@working-theory/env` ships a Zod schema (currently a placeholder
8
- package), this template should be revised to derive from that
9
- schema instead. Until then, this file is the source of truth for
10
- what env vars an AILK consumer site reads.
11
-
12
- ## Template
13
-
14
- ```bash
15
- # AI Launch Kit — environment template
16
- # Copy this file to `.env.local` (gitignored) and fill in values.
17
- # Production values live in your deploy platform's dashboard
18
- # (Vercel project settings → Environment Variables).
19
-
20
- # ── Marketing / canonical domain ─────────────────────────────────
21
- # Your site's canonical public domain (no protocol).
22
- AILK_PUBLIC_DOMAIN=your-domain.com
23
-
24
- # ── Content backend ──────────────────────────────────────────────
25
- # AILK's MDX adapter is the default. Other adapters ship as
26
- # additive PRs later.
27
- CONTENT_BACKEND=mdx
28
- # Override the content directory. Default is <repo-root>/content.
29
- # AILK_CONTENT_ROOT=
30
-
31
- # ── Lead delivery ────────────────────────────────────────────────
32
- # Where contact-form messages go (RUNBOOK.md § "Leads — where
33
- # messages go"). Set these on the API project.
34
- #
35
- # Lead inbox — set by the `setup-database` skill. With it, messages
36
- # land in /leads and newsletter signups are collected.
37
- # DATABASE_URL=postgres://user:pass@host:5432/db
38
- # DATABASE_URL_NON_POOLED=postgres://user:pass@host:5432/db
39
- #
40
- # Email (default) — with no database, each message is emailed to you.
41
- # All three are required; a key alone sends nothing.
42
- # RESEND_API_KEY=
43
- # AILK_LEAD_NOTIFICATION_TO=you@your-domain.com
44
- # AILK_LEAD_NOTIFICATION_FROM=leads@your-domain.com
45
- #
46
- # With neither, /contact shows your contact email (content/_site.mdx
47
- # `contactEmail`) instead of the form in production.
48
-
49
- # ── Auth — required env vars ─────────────────────────────────────
50
- # Set to "1" to require sign-in for protected routes; default is
51
- # auth-disabled / public.
52
- # AILK_AUTH_REQUIRED=1
53
- #
54
- # NextAuth secret — production must be set; generate with:
55
- # openssl rand -base64 32
56
- # Local dev (next dev) auto-generates a session-only secret.
57
- # NEXTAUTH_SECRET=
58
- #
59
- # Production base URL for callback construction. Local dev defaults
60
- # to http://localhost:3000 if unset.
61
- # NEXTAUTH_URL=https://your-domain.com
62
-
63
- # ── Auth — magic-link (Resend) ───────────────────────────────────
64
- # Activated when both AUTH_EMAIL_SERVER and AUTH_EMAIL_FROM are set.
65
- # Get a Resend API key at https://resend.com/api-keys.
66
- # AUTH_EMAIL_SERVER=smtp://resend:re_yourkeyhere@smtp.resend.com:465
67
- # AUTH_EMAIL_FROM=onboarding@resend.dev
68
-
69
- # ── Auth — Google OAuth ──────────────────────────────────────────
70
- # Activated when both GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET set.
71
- # Set up at https://console.cloud.google.com/apis/credentials.
72
- # Production callback: https://your-domain.com/api/auth/callback/google
73
- # GOOGLE_CLIENT_ID=
74
- # GOOGLE_CLIENT_SECRET=
75
-
76
- # ── Auth — GitHub OAuth ──────────────────────────────────────────
77
- # Activated when both GITHUB_CLIENT_ID and GITHUB_CLIENT_SECRET set.
78
- # Set up at https://github.com/settings/developers.
79
- # Production callback: https://your-domain.com/api/auth/callback/github
80
- # GITHUB_CLIENT_ID=
81
- # GITHUB_CLIENT_SECRET=
82
-
83
- # ── Stripe (sandbox keys only — sk_test_* / pk_test_*) ───────────
84
- # AILK is sandbox-only at v1. Live keys (sk_live_*, pk_live_*) are
85
- # hook-blocked from appearing in source.
86
- # Get test keys at https://dashboard.stripe.com/test/apikeys.
87
- # STRIPE_SECRET_KEY=sk_test_...
88
- # NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_...
89
- # Webhook signing secret — see Stripe Dashboard → Developers →
90
- # Webhooks → <endpoint> → Signing secret. Format: whsec_*.
91
- # STRIPE_WEBHOOK_SECRET=
92
-
93
- # ── Analytics — all off by default ───────────────────────────────
94
- # Each provider is independent. Set the env var(s) to enable.
95
- #
96
- # Vercel Analytics — built-in dashboard for Vercel deploys.
97
- # Requires Vercel hosting. Set to "true" to enable. Requires redeploy
98
- # after change (NEXT_PUBLIC_* values bake at build time).
99
- # NEXT_PUBLIC_VERCEL_ANALYTICS_ENABLED=
100
- #
101
- # Google Analytics 4 — gtag.js measurement. Requires consent in EU/UK/CA.
102
- # Get the measurement ID from analytics.google.com → Admin → Data Streams.
103
- # Format: G-XXXXXXXXXX. Requires redeploy after change.
104
- # NEXT_PUBLIC_GA_MEASUREMENT_ID=
105
- #
106
- # GA4 Measurement Protocol — server-side analytics secret.
107
- # Required alongside NEXT_PUBLIC_GA_MEASUREMENT_ID for server-side
108
- # lead/purchase events.
109
- # GA_API_SECRET=
110
- #
111
- # Google Search Console — verification meta tag. No script, no consent.
112
- # Get the token from search.google.com/search-console → Settings →
113
- # Ownership verification → HTML tag. Paste only the content="..." value.
114
- # GOOGLE_SITE_VERIFICATION=
115
- ```
116
-
117
- ## Categories the skill emits
118
-
119
- The template above groups vars into six categories. Every emitted
120
- `.env.example` should hit each category at least with its header
121
- comment, even if the consumer hasn't activated any vars in that
122
- category — the comment block tells future-them what's available.
123
-
124
- Categories:
125
-
126
- 1. Marketing / canonical domain
127
- 2. Content backend
128
- 3. Lead delivery (database or email)
129
- 4. Auth — required + per-provider
130
- 5. Stripe (sandbox-only)
131
- 6. Analytics
132
-
133
- ## What the skill never includes
134
-
135
- - Real secret values. All values are placeholders or commented
136
- examples.
137
- - Live Stripe keys. Sandbox-only at AILK v1.
138
- - Live Vercel deploy tokens. The Vercel CLI handles deploy auth via
139
- `vercel login`.
140
- - Database connection strings with embedded passwords. Comments
141
- show shape only.
142
-
143
- ## Counting vars for validation
144
-
145
- The skill's Step 5 validation counts the declared (uncommented) vars
146
- the template emits and confirms the count is non-zero. Empty
147
- `.env.example` is a bug. Currently declared vars in the template:
148
-
149
- - `AILK_PUBLIC_DOMAIN`
150
- - `CONTENT_BACKEND`
151
-
152
- (All other entries are commented optional vars.) The skill should
153
- not require the consumer to set every commented var — they're
154
- opt-in. The two declared entries are the minimum the AILK scaffold
155
- needs to boot, even on a static-content-only site.
156
-
157
- ## Merge logic
158
-
159
- If the consumer already has `.env.example`, the skill (per SKILL.md
160
- Step 3) offers merge / overwrite / skip. Merge logic:
161
-
162
- 1. Read the existing file.
163
- 2. For each line in this template that's not a comment-only line,
164
- check whether the var name already appears anywhere in the
165
- existing file (commented or uncommented).
166
- 3. Vars **already present** are not modified — the consumer's
167
- existing comments and value choices win.
168
- 4. Vars **missing** are appended at the end of the existing file
169
- under a new section:
170
- ```
171
- # ── Added by setup-deploy ────────────────────────────────
172
- ```
173
-
174
- This avoids duplicating vars while still surfacing additions the
175
- template gained since the consumer's last run.
@@ -1,8 +0,0 @@
1
- {
2
- "id": "fallback-1789916251590-037e9005",
3
- "siteId": "site_1",
4
- "source": "callback",
5
- "email": "",
6
- "payload": {},
7
- "createdAt": "2026-09-20T14:57:31.552Z"
8
- }
@@ -1,12 +0,0 @@
1
- {
2
- "id": "fallback-1789916253842-b52659e9",
3
- "siteId": "wksp_00000000-0000-7000-8000-000000000001",
4
- "source": "flow:get-a-quote",
5
- "email": "abandoner@example.com",
6
- "payload": {
7
- "email": "abandoner@example.com",
8
- "flowSlug": "get-a-quote",
9
- "locale": "en"
10
- },
11
- "createdAt": "2026-09-20T14:57:33.840Z"
12
- }
@@ -1,12 +0,0 @@
1
- {
2
- "id": "fallback-1789916253845-6b266f8c",
3
- "siteId": "default",
4
- "source": "flow:get-a-quote",
5
- "email": "abandoner@example.com",
6
- "payload": {
7
- "email": "abandoner@example.com",
8
- "flowSlug": "get-a-quote",
9
- "locale": "en"
10
- },
11
- "createdAt": "2026-09-20T14:57:33.844Z"
12
- }
@@ -1,50 +0,0 @@
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.
7
- import type { getMdxSource as defaultGetMdxSource } from "@working-theory/page-renderer";
8
- import {
9
- getMdxSource as loadMdxSource,
10
- renderPage,
11
- renderPageMetadata,
12
- } from "@working-theory/page-renderer";
13
- import type { Metadata } from "next";
14
- import type { ReactElement } from "react";
15
-
16
- interface Props {
17
- params: Promise<{ locale: string }>;
18
- getMdxSource?: typeof defaultGetMdxSource;
19
- }
20
-
21
- export async function generateMetadata({
22
- params,
23
- }: Pick<Props, "params">): Promise<Metadata> {
24
- const { locale } = await params;
25
- return renderPageMetadata({
26
- type: "BookCall",
27
- slug: "book-call",
28
- locale,
29
- });
30
- }
31
-
32
- export default async function Page({
33
- params,
34
- getMdxSource,
35
- }: Props): Promise<ReactElement> {
36
- const { locale } = await params;
37
- const source = await (getMdxSource ?? loadMdxSource)("BookCall", "book-call", locale);
38
- const composed =
39
- source !== null &&
40
- Array.isArray((source.frontmatter as { sections?: unknown[] }).sections) &&
41
- ((source.frontmatter as { sections?: unknown[] }).sections?.length ?? 0) >
42
- 0;
43
- return renderPage({
44
- type: "BookCall",
45
- slug: "book-call",
46
- locale,
47
- ...(composed ? {} : { bodyMode: "mdx-body" as const }),
48
- ...(getMdxSource !== undefined && { getMdxSource }),
49
- });
50
- }
@@ -1,72 +0,0 @@
1
- /**
2
- * HTML snapshot regression tests for use-cases/page.tsx → @working-theory/page-renderer migration.
3
- *
4
- * Two-commit strategy:
5
- * Commit 1: this file added; snapshots captured against pre-migration route (RED-passing).
6
- * Commit 2: route migrated; same snapshots verify diff=0 (GREEN).
7
- *
8
- * Two states tested:
9
- * - empty: getMdxSource returns null → empty-state branch
10
- * - populated: getMdxSource returns a minimal MdxPageSource → full render
11
- *
12
- * Failure = snapshot diff > 0 bytes. DO NOT regenerate snapshots to pass.
13
- */
14
- import React from "react";
15
- import { render } from "@testing-library/react";
16
-
17
- // ── @working-theory/ui mock ─────────────────────────────────────────────────────────────
18
- jest.mock("@working-theory/ui", () => ({
19
- // #4446/#4447: renderPage's own fallback/empty-state title now composes
20
- // Heading (mobile type-budget classes, #4417) instead of a bare <h1>.
21
- Heading: ({
22
- children,
23
- level,
24
- }: {
25
- children: React.ReactNode;
26
- level: number;
27
- }): React.ReactElement => React.createElement(`h${level}`, null, children),
28
- SectionRenderer: ({ sections }: { sections: unknown[] }) =>
29
- React.createElement("div", {
30
- "data-testid": "section-renderer",
31
- "data-section-count": String(sections.length),
32
- }),
33
- }));
34
-
35
- import UseCasesPage from "../page";
36
-
37
- const getMdxSourceEmpty = jest.fn().mockResolvedValue(null);
38
-
39
- describe("UseCasesPage — snapshot regression", () => {
40
- it("empty state renders deterministic HTML", async () => {
41
- const element = await UseCasesPage({
42
- params: Promise.resolve({ locale: "en" }),
43
- getMdxSource: getMdxSourceEmpty,
44
- });
45
- const { container } = render(element);
46
- expect(container.innerHTML).toMatchInlineSnapshot(
47
- `"<main id="main"><h1>Use Cases</h1><p data-testid="section-empty-state">Use cases listing coming soon.</p></main>"`,
48
- );
49
- });
50
-
51
- it("populated state renders deterministic HTML", async () => {
52
- const source = {
53
- frontmatter: {
54
- type: "UseCasesList" as const,
55
- slug: "use-cases",
56
- title: "Use Cases",
57
- description: "How teams use our platform.",
58
- },
59
- body: "",
60
- };
61
- const getMdxSourcePopulated = jest.fn().mockResolvedValue(source);
62
-
63
- const element = await UseCasesPage({
64
- params: Promise.resolve({ locale: "en" }),
65
- getMdxSource: getMdxSourcePopulated,
66
- });
67
- const { container } = render(element);
68
- expect(container.innerHTML).toMatchInlineSnapshot(
69
- `"<script type="application/ld+json" data-testid="json-ld">{"@context":"https://schema.org","@type":"CollectionPage","inLanguage":"en","name":"Use Cases","description":"How teams use our platform.","mainEntity":{"@type":"ItemList","itemListElement":[{"@type":"Article"}]}}</script><main id="main"><h1>Use Cases</h1><p data-testid="use-cases-description">How teams use our platform.</p><div data-testid="markdown-view-toggle" class="ailk-markdown-view-toggle"><div class="flex justify-end mb-3"><div role="radiogroup" aria-label="Page view" data-testid="markdown-view-toggle" class="inline-flex items-center gap-0.5 rounded-lg p-1 bg-(--color-surface-secondary)"><button class="inline-flex items-center justify-center gap-2 font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50 [&amp;>svg]:shrink-0 text-(--color-fg) hover:bg-(--color-surface-secondary) active:bg-gray-200 rounded-control px-control-x h-(--control-height-thin) text-caption leading-none rounded-md px-3 text-body-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 min-w-(--control-height-thin) min-h-(--control-height-big) bg-(--color-bg) text-(--color-fg) shadow-sm" type="button" role="radio" aria-checked="true" aria-label="Rendered" tabindex="0" data-testid="markdown-view-toggle-rendered">Rendered</button><button class="inline-flex items-center justify-center gap-2 font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50 [&amp;>svg]:shrink-0 text-(--color-fg) hover:bg-(--color-surface-secondary) active:bg-gray-200 rounded-control px-control-x h-(--control-height-thin) text-caption leading-none rounded-md px-3 text-body-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 min-w-(--control-height-thin) min-h-(--control-height-big) text-(--color-text-muted) hover:text-(--color-fg)" type="button" role="radio" aria-checked="false" aria-label="Markdown" tabindex="-1" data-testid="markdown-view-toggle-markdown">Markdown</button></div></div><div role="status" aria-live="polite" aria-atomic="true" class="sr-only" data-testid="markdown-view-toggle-status">Showing Rendered view</div><div data-testid="markdown-view-rendered"><article data-testid="mdx-body"><div data-testid="mdx-remote" data-source=""></div></article></div></div></main>"`,
70
- );
71
- });
72
- });