create-ailk 0.7.0 → 0.8.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 (169) hide show
  1. package/README.md +44 -10
  2. package/component-catalog.json +520 -5
  3. package/component-catalog.md +9 -6
  4. package/dist/cli.js +22 -24
  5. package/dist/lib/extract-module-bundle.js +5 -1
  6. package/dist/lib/module-license-gate.d.ts +79 -0
  7. package/dist/lib/module-license-gate.js +160 -12
  8. package/dist/lib/module-tier.d.ts +45 -16
  9. package/dist/lib/module-tier.js +76 -0
  10. package/dist/lib/pro-callout.js +10 -2
  11. package/dist/parse-args.d.ts +78 -10
  12. package/dist/parse-args.js +204 -14
  13. package/dist/programmatic.d.ts +39 -9
  14. package/dist/programmatic.js +163 -25
  15. package/dist/site-roster.js +11 -6
  16. package/dist/starter-grid.d.ts +216 -0
  17. package/dist/starter-grid.js +449 -0
  18. package/dist/surfaces.d.ts +4 -4
  19. package/dist/surfaces.js +102 -43
  20. package/dist/template-manifest.d.ts +36 -17
  21. package/dist/template-manifest.js +121 -367
  22. package/dist/template-names.d.ts +14 -12
  23. package/dist/template-names.js +13 -17
  24. package/package.json +3 -3
  25. package/site-templates/_base/content/en/BookCall/book-call.mdx +0 -1
  26. package/site-templates/_base/content/en/Feature/feature-1.mdx +69 -0
  27. package/site-templates/_base/content/en/Feature/feature-2.mdx +69 -0
  28. package/site-templates/_base/content/en/Feature/feature-3.mdx +69 -0
  29. package/site-templates/_base/content/en/FeaturesList/features.mdx +91 -0
  30. package/site-templates/_base/content/en/GlossaryList/glossary.mdx +0 -1
  31. package/site-templates/_base/content/en/NewsletterSignup/newsletter.mdx +0 -1
  32. package/site-templates/_base/content/en/PortfolioItem/sample-four.mdx +105 -0
  33. package/site-templates/_base/content/en/PortfolioItem/sample-one.mdx +34 -0
  34. package/site-templates/_base/content/en/PortfolioItem/sample-three.mdx +94 -0
  35. package/site-templates/_base/content/en/PortfolioItem/sample-two.mdx +45 -0
  36. package/site-templates/_base/content/en/PortfolioList/portfolio.mdx +169 -0
  37. package/site-templates/_base/content/en/PrivacyPage/privacy.mdx +15 -0
  38. package/site-templates/_base/content/en/UseCase/persona-1.mdx +69 -0
  39. package/site-templates/_base/content/en/UseCase/persona-2.mdx +69 -0
  40. package/site-templates/_base/content/en/UseCase/persona-3.mdx +69 -0
  41. package/site-templates/designs/standard/DESIGN.md +5 -0
  42. package/site-templates/marketing-site/DESIGN.md +5 -0
  43. package/site-templates/marketing-site/TEMPLATE-MANIFEST.json +89 -25
  44. package/site-templates/marketing-site/TEMPLATE-MANIFEST.md +35 -14
  45. package/site-templates/marketing-site-free/DESIGN.md +5 -0
  46. package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.json +95 -29
  47. package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.md +74 -44
  48. package/site-templates/marketing-site-free/content/en/NewsletterSignup/newsletter.mdx +59 -0
  49. package/site-templates/marketing-site-free/content/en/Pricing/pricing.mdx +199 -0
  50. package/site-templates/minimalism-site/TEMPLATE-MANIFEST.md +17 -29
  51. package/site-templates/minimalism-site/content/en/BookCall/book-call.mdx +0 -1
  52. package/site-templates/minimalism-site/content/en/PurchasePolicyPage/purchase-policy.mdx +0 -1
  53. package/site-templates/saas-product/DESIGN.md +5 -0
  54. package/site-templates/saas-product/TEMPLATE-MANIFEST.md +9 -1
  55. package/site-templates/{simple-service → shapes/local-business-service}/TEMPLATE-MANIFEST.json +96 -76
  56. package/site-templates/shapes/local-business-service/TEMPLATE-MANIFEST.md +302 -0
  57. package/site-templates/shapes/local-business-service/ailk-template.json +10 -0
  58. package/site-templates/{simple-service → shapes/local-business-service}/content/en/AboutPage/about.mdx +4 -4
  59. package/site-templates/shapes/local-business-service/content/en/HomePage/home.mdx +70 -0
  60. package/site-templates/shapes/local-business-service/content/en/NewsletterSignup/newsletter.mdx +59 -0
  61. package/site-templates/shapes/local-business-service/content/en/PortfolioList/portfolio.mdx +171 -0
  62. package/site-templates/{simple-service → shapes/local-business-service}/content/en/PurchasePolicyPage/purchase-policy.mdx +7 -8
  63. package/site-templates/shapes/local-business-service/content/en/Service/first-job.mdx +39 -0
  64. package/site-templates/shapes/local-business-service/content/en/Service/second-job.mdx +39 -0
  65. package/site-templates/shapes/local-business-service/content/en/Service/third-job.mdx +39 -0
  66. package/site-templates/shapes/local-business-service/content/en/ServicesList/services.mdx +61 -0
  67. package/site-templates/shapes/local-business-service/provenance.json +4 -0
  68. package/site-templates/shapes/organization-service/TEMPLATE-MANIFEST.json +362 -0
  69. package/site-templates/shapes/organization-service/TEMPLATE-MANIFEST.md +300 -0
  70. package/site-templates/shapes/organization-service/ailk-template.json +10 -0
  71. package/site-templates/shapes/organization-service/content/en/AboutPage/about.mdx +38 -0
  72. package/site-templates/shapes/organization-service/content/en/HomePage/home.mdx +85 -0
  73. package/site-templates/shapes/organization-service/content/en/NewsletterSignup/newsletter.mdx +59 -0
  74. package/site-templates/shapes/organization-service/content/en/PortfolioList/portfolio.mdx +171 -0
  75. package/site-templates/shapes/organization-service/content/en/PurchasePolicyPage/purchase-policy.mdx +123 -0
  76. package/site-templates/shapes/organization-service/content/en/Service/first-engagement.mdx +38 -0
  77. package/site-templates/shapes/organization-service/content/en/Service/second-engagement.mdx +38 -0
  78. package/site-templates/shapes/organization-service/content/en/Service/third-engagement.mdx +38 -0
  79. package/site-templates/shapes/organization-service/content/en/ServicesList/services.mdx +72 -0
  80. package/site-templates/shapes/organization-service/provenance.json +4 -0
  81. package/site-templates/shapes/person-service/TEMPLATE-MANIFEST.json +369 -0
  82. package/site-templates/shapes/person-service/TEMPLATE-MANIFEST.md +299 -0
  83. package/site-templates/shapes/person-service/ailk-template.json +10 -0
  84. package/site-templates/shapes/person-service/content/_site.mdx +85 -0
  85. package/site-templates/shapes/person-service/content/en/AboutPage/about.mdx +39 -0
  86. package/site-templates/shapes/person-service/content/en/HomePage/home.mdx +97 -0
  87. package/site-templates/shapes/person-service/content/en/NewsletterSignup/newsletter.mdx +59 -0
  88. package/site-templates/shapes/person-service/content/en/PortfolioList/portfolio.mdx +169 -0
  89. package/site-templates/shapes/person-service/content/en/PurchasePolicyPage/purchase-policy.mdx +123 -0
  90. package/site-templates/shapes/person-service/content/en/Service/first-engagement.mdx +38 -0
  91. package/site-templates/shapes/person-service/content/en/Service/second-engagement.mdx +38 -0
  92. package/site-templates/shapes/person-service/content/en/Service/third-engagement.mdx +38 -0
  93. package/site-templates/{simple-service → shapes/person-service}/content/en/ServicesList/services.mdx +16 -16
  94. package/site-templates/shapes/person-service/provenance.json +4 -0
  95. package/templates/.claude/skills/README.md +3 -2
  96. package/templates/.claude/skills/add-page/references/page-types.md +4 -0
  97. package/templates/.claude/skills/setup-database/SKILL.md +156 -0
  98. package/templates/.claude/skills/setup-database/scripts/verify-inbox.ts +154 -0
  99. package/templates/.claude/skills/setup-deploy/SKILL.md +64 -32
  100. package/templates/.claude/skills/setup-deploy/references/env-vars-template.md +19 -28
  101. package/templates/.claude/skills/setup-deploy/references/runbook-template.md +58 -102
  102. package/templates/DESIGN.md +5 -0
  103. package/templates/README.md +46 -38
  104. package/templates/apps/api/CLAUDE.md +3 -2
  105. package/templates/apps/api/src/config/__tests__/index.test.ts +115 -14
  106. package/templates/apps/api/src/config/index.ts +35 -16
  107. package/templates/apps/api/src/lib/__tests__/lead-capture-store.test.ts +30 -0
  108. package/templates/apps/api/src/lib/__tests__/lead-delivery.test.ts +96 -0
  109. package/templates/apps/api/src/lib/lead-capture-store.ts +12 -0
  110. package/templates/apps/api/src/lib/lead-delivery.ts +52 -0
  111. package/templates/apps/api/src/openapi/spec.ts +63 -12
  112. package/templates/apps/api/src/routes/leads/__tests__/capture.test.ts +88 -0
  113. package/templates/apps/api/src/routes/leads/__tests__/index.test.ts +100 -0
  114. package/templates/apps/api/src/routes/leads/index.ts +46 -1
  115. package/templates/apps/api/src/server.ts +7 -0
  116. package/templates/apps/api/src/services/__tests__/lead-routing.test.ts +194 -0
  117. package/templates/apps/api/src/services/__tests__/leads-inbox.test.ts +124 -0
  118. package/templates/apps/api/src/services/lead-routing.ts +140 -30
  119. package/templates/apps/api/src/services/leads-inbox.ts +48 -11
  120. package/templates/apps/mcp/__tests__/parity.test.ts +5 -4
  121. package/templates/apps/mcp/src/tools/create_project.ts +21 -6
  122. package/templates/apps/web/app/[locale]/contact/ConversationalIntakeWrapper.tsx +14 -6
  123. package/templates/apps/web/app/[locale]/contact/__tests__/ConversationalIntakeWrapper.test.tsx +10 -9
  124. package/templates/apps/web/app/[locale]/contact/__tests__/contact-form-text.test.ts +32 -0
  125. package/templates/apps/web/app/[locale]/contact/__tests__/contact.actions.test.ts +129 -0
  126. package/templates/apps/web/app/[locale]/contact/__tests__/page-renderer-migration.test.tsx +227 -84
  127. package/templates/apps/web/app/[locale]/contact/contact-form-text.ts +50 -0
  128. package/templates/apps/web/app/[locale]/contact/contact.actions.ts +73 -20
  129. package/templates/apps/web/app/[locale]/contact/page.tsx +105 -15
  130. package/templates/apps/web/app/[locale]/contact/site-contact-email.ts +54 -0
  131. package/templates/apps/web/app/[locale]/features/[slug]/page.tsx +64 -0
  132. package/templates/apps/web/app/[locale]/features/page.tsx +52 -0
  133. package/templates/apps/web/app/[locale]/layout.tsx +37 -5
  134. package/templates/apps/web/app/[locale]/newsletter/__tests__/newsletter.actions.test.ts +75 -0
  135. package/templates/apps/web/app/[locale]/newsletter/__tests__/page.test.tsx +163 -0
  136. package/templates/apps/web/app/[locale]/newsletter/newsletter.actions.ts +66 -0
  137. package/templates/apps/web/app/[locale]/newsletter/page.tsx +106 -14
  138. package/templates/apps/web/app/[locale]/portfolio/[slug]/page.tsx +59 -0
  139. package/templates/apps/web/app/[locale]/portfolio/page.tsx +49 -0
  140. package/templates/apps/web/app/[locale]/use-cases/[slug]/page.tsx +18 -3
  141. package/templates/apps/web/lib/nav-config.ts +48 -36
  142. package/templates/apps/web/lib/site-identity.ts +14 -0
  143. package/templates/apps/web/messages/en.json +28 -2
  144. package/templates/content/_site.mdx +4 -2
  145. package/templates/content/en/BlogList/blog.mdx +37 -16
  146. package/templates/content/en/ContactPage/contact.mdx +14 -44
  147. package/templates/content/en/HomePage/home.mdx +8 -16
  148. package/templates/content/en/PurchasePolicyPage/purchase-policy.mdx +0 -1
  149. package/templates/content/en/UseCasesList/use-cases.mdx +6 -6
  150. package/templates/database/CHANGELOG.md +7 -0
  151. package/templates/database/package.json +1 -1
  152. package/versions.json +33 -33
  153. package/site-templates/_base/content/en/UseCase/first-use-case.mdx +0 -23
  154. package/site-templates/_base/content/en/UseCase/second-use-case.mdx +0 -23
  155. package/site-templates/_base/content/en/UseCase/third-use-case.mdx +0 -23
  156. package/site-templates/simple-service/DESIGN.md +0 -162
  157. package/site-templates/simple-service/TEMPLATE-MANIFEST.md +0 -333
  158. package/site-templates/simple-service/ailk-template.json +0 -11
  159. package/site-templates/simple-service/content/en/BookCall/book-call.mdx +0 -53
  160. package/site-templates/simple-service/content/en/ContactPage/contact.mdx +0 -32
  161. package/site-templates/simple-service/content/en/FAQPage/faq.mdx +0 -56
  162. package/site-templates/simple-service/content/en/HomePage/home.mdx +0 -85
  163. package/site-templates/simple-service/content/en/Service/landscape-design.mdx +0 -40
  164. package/site-templates/simple-service/content/en/Service/lawn-maintenance.mdx +0 -40
  165. package/site-templates/simple-service/content/en/Service/seasonal-cleanup.mdx +0 -40
  166. package/site-templates/simple-service/provenance.json +0 -4
  167. package/templates/apps/web/app/[locale]/contact/ContactForm.tsx +0 -211
  168. package/templates/apps/web/app/[locale]/contact/__tests__/ContactForm.test.tsx +0 -96
  169. package/templates/content/en/SoftwareProduct/product.mdx +0 -175
@@ -0,0 +1,449 @@
1
+ /**
2
+ * The three pages every starter carries whatever its shape (#6658 D5,
3
+ * `docs/decisions/starter-roster-page-set.md` D4/D7): a glossary, a newsletter
4
+ * signup and a book-a-call page. Each is a module-less `GATEABLE_SURFACES`
5
+ * entry the roster enables, with its seed in `_base`. A template carrying the
6
+ * scheduling module overrides `BookCall/book-call.mdx` in its own tree, so the
7
+ * call to action opens `/meet` rather than `/contact`.
8
+ */
9
+ const SHAPE_INDEPENDENT_ROWS = [
10
+ { route: "/glossary", content: ["content/en/GlossaryList/glossary.mdx"] },
11
+ {
12
+ route: "/newsletter",
13
+ content: ["content/en/NewsletterSignup/newsletter.mdx"],
14
+ },
15
+ { route: "/book-a-call", content: ["content/en/BookCall/book-call.mdx"] },
16
+ ];
17
+ /**
18
+ * The rows every `organization-product` template brings itself — one declared
19
+ * page set, whichever layer carries each seed. Re-derived by #6658 from the
20
+ * standard (`derive-roster.py --entity-type software --offering-type software
21
+ * --primary-goal convert --scale global`, the `--shape organization-product`
22
+ * equivalent), edited only by the deviations the Free manifest's § 3a records
23
+ * with their reasons. With a template named, `scaffold()` keeps a `_base` or
24
+ * overlay seed only when a merged roster row names it (#6646 D1): the roster
25
+ * decides what installs, and the manifest generator's `--check` proves it.
26
+ *
27
+ * Two layers, one roster:
28
+ *
29
+ * - `/`, `/software/[slug]`, `/use-cases`, `/about`, `/faq`, `/contact` and
30
+ * `/purchase-policy` take their content from the overlay
31
+ * (`template-overlay/content/en/**`, copied whole into `templates/` by
32
+ * `build-templates.mjs`). `/features` is the FeaturesList hub over one
33
+ * Feature page per feature at `/features/[slug]` (#6721, reversing the
34
+ * single `/software/product` page of #6658 D3); both ride the `features`
35
+ * surface the roster enables.
36
+ * `/use-cases` lists the three UseCase pages at `/use-cases/[slug]`
37
+ * (#6658 D4).
38
+ * - `/pricing`, `/privacy`, `/terms`, `/glossary`, `/newsletter`,
39
+ * `/book-a-call` and the three UseCase pages take their content from the
40
+ * base layer (`site-templates/_base/content/**`, #5618 D1), which every
41
+ * template reaches by declaring `extends` — installed before the module
42
+ * bundles and the template's own tree, so a template may override a base
43
+ * page by shipping the same path. Their surfaces are module-less by
44
+ * construction (parent § D16, #6658 D5): a template enables them by
45
+ * NAMING them in its roster — `scaffold()` selects their
46
+ * `GATEABLE_SURFACES` entries from the merged roster's routes (#5469 D10).
47
+ *
48
+ * `/software`, `/sign-in` and `/sign-up` carry no `content`: they are code
49
+ * routes (the SoftwareProduct listing, the SignInCard island, the sign-up
50
+ * form), like the API-backed rows the scheduling module contributes — listed
51
+ * so the manifest is a complete install record, where the generator marks
52
+ * them `kind: route` (#6646 D2).
53
+ *
54
+ * `/purchase-policy` is the product-shape purchase policy (#6646 D3): its
55
+ * overlay seed carries returns, shipping and refunds sections — the overlay,
56
+ * not `_base`, because the route is core and a scaffold naming no template
57
+ * serves it too. A service-shape template overrides that seed with its own
58
+ * cancellation and refunds file.
59
+ *
60
+ * `/blog` is deliberately NOT here (#5469 D3): the docs-blog module
61
+ * contributes its own `/blog` row, so a base row would make `mergeRoster`
62
+ * refuse every template that takes that module. The teaser row is an
63
+ * `organization-product` shape row instead (#6753 D3), which the two aliases
64
+ * taking docs-blog drop.
65
+ */
66
+ const TEMPLATE_BASE_ROSTER = [
67
+ { route: "/", content: ["content/en/HomePage/home.mdx"] },
68
+ // #6721 — the product's features: a FeaturesList hub over one Feature page
69
+ // per feature (replaces the single /software/product page, #6658 D3).
70
+ { route: "/features", content: ["content/en/FeaturesList/features.mdx"] },
71
+ { route: "/features/[slug]", contentDir: "content/en/Feature" },
72
+ {
73
+ route: "/use-cases",
74
+ content: ["content/en/UseCasesList/use-cases.mdx"],
75
+ },
76
+ { route: "/use-cases/[slug]", contentDir: "content/en/UseCase" },
77
+ { route: "/pricing", content: ["content/en/Pricing/pricing.mdx"] },
78
+ { route: "/about", content: ["content/en/AboutPage/about.mdx"] },
79
+ { route: "/faq", content: ["content/en/FAQPage/faq.mdx"] },
80
+ { route: "/contact", content: ["content/en/ContactPage/contact.mdx"] },
81
+ ...SHAPE_INDEPENDENT_ROWS,
82
+ { route: "/sign-in" },
83
+ { route: "/sign-up" },
84
+ { route: "/privacy", content: ["content/en/PrivacyPage/privacy.mdx"] },
85
+ { route: "/terms", content: ["content/en/TermsPage/terms.mdx"] },
86
+ {
87
+ route: "/purchase-policy",
88
+ content: ["content/en/PurchasePolicyPage/purchase-policy.mdx"],
89
+ },
90
+ ];
91
+ /**
92
+ * The Free `/blog` teaser (#5469 D3) — one static BlogList page (schema `Blog`
93
+ * with an empty `ItemList`; the correct page type, not a LandingPage) that
94
+ * says what the Pro docs-blog module gives you. It is served by the generic
95
+ * `[slug]` route — which probes `LandingPage` first, then `BlogList` — over
96
+ * `content/en/BlogList/blog.mdx`, which ships in the always-copied overlay. `/blog` degrades by DIRECTORY PRECEDENCE, not
97
+ * by a module gate: in a keyed docs-blog scaffold the module's own
98
+ * `blog/[[...slug]]/page.tsx` directory exists and Next.js resolves the static
99
+ * segment first, so the teaser file is inert; keyless, no `blog/` directory
100
+ * exists and the teaser renders. An `organization-product` shape row
101
+ * (#6753 D3): the aliases taking docs-blog drop it, so on `marketing-site`
102
+ * the docs-blog contribution claims the route.
103
+ */
104
+ const FREE_BLOG_TEASER_ROW = {
105
+ route: "/blog",
106
+ content: ["content/en/BlogList/blog.mdx"],
107
+ };
108
+ /**
109
+ * The rows for the `signal-collectors` bundle's six sample pages (#6646
110
+ * disposition (a)) — the project listing, its two project pages and the
111
+ * three thank-you pages its `installMap` lands. The module contributes no
112
+ * row for any of these routes (`module-architecture.ts`'s installMap
113
+ * comment), so a template that takes the module declares them, and the
114
+ * roster names every page the scaffold installs. `/projects` is a
115
+ * module-less `GATEABLE_SURFACES` entry, so naming it here also copies the
116
+ * route directory the samples render through (`rosterSurfaces`).
117
+ */
118
+ const SIGNAL_COLLECTORS_SAMPLE_ROWS = [
119
+ { route: "/projects", content: ["content/en/ProjectsList/projects.mdx"] },
120
+ { route: "/projects/[slug]", contentDir: "content/en/Project" },
121
+ { route: "/thanks/[slug]", contentDir: "content/en/ThankYouPage" },
122
+ ];
123
+ /**
124
+ * The portfolio pages (#6687) — before/after project comparisons: a
125
+ * PortfolioList hub on the /alternatives stack and one PortfolioItem page per
126
+ * comparison, each one `before-after` section carrying its header band and
127
+ * pager. They belong to the SHAPE, Free included (roadmap § 4, operator
128
+ * 2026-09-25, reversing #6687's "Pro and up"): every shape roster below
129
+ * carries them, and an alias sheds them only by an explicit `drop`. The seeds
130
+ * live in the `_base` layer under `content/en/PortfolioItem/`; the detail
131
+ * row's `contentDir` installs them (#6646 D1), exactly as `/use-cases/[slug]`
132
+ * serves `content/en/UseCase`.
133
+ */
134
+ // NO_HAND_IMPLEMENT_OK: /build-starter operator-directed live pass (#6687).
135
+ const PORTFOLIO_ROWS = [
136
+ { route: "/portfolio", content: ["content/en/PortfolioList/portfolio.mdx"] },
137
+ { route: "/portfolio/[slug]", contentDir: "content/en/PortfolioItem" },
138
+ ];
139
+ /**
140
+ * `minimalism-site`'s two OWN rows (#5589, shrunk from its own 17-row roster
141
+ * by #6757 once the `organization-service` shape carried a standard roster of
142
+ * its own): the deck's two `LandingPage` slugs, positioned by `insert` (D7)
143
+ * at the two points this alias interleaves them into the shape's row order
144
+ * (§ 1.2) — `/reports` before `/about`, `/referral` before `/faq`. Neither
145
+ * carries a `GATEABLE_SURFACES` entry: both are single-segment slugs served
146
+ * by the generic `[slug]` route (#5469 D2), the same mechanism Free's
147
+ * `/how-it-works` used.
148
+ */
149
+ const REPORTS_ROW = {
150
+ route: "/reports",
151
+ content: ["content/en/LandingPage/reports.mdx"],
152
+ };
153
+ const REFERRAL_ROW = {
154
+ route: "/referral",
155
+ content: ["content/en/LandingPage/referral.mdx"],
156
+ };
157
+ /**
158
+ * `organization-service`'s own rows (#6757 D1), derived from
159
+ * `derive-roster.py --shape organization-service --primary-goal generate-leads
160
+ * --registry packages/schema/src/registry/entries.ts` at harness commit
161
+ * `7bdaf148e1b0e639cd90a80008955e55cc4aa2b5`, edited only by the deviations
162
+ * `site-templates/shapes/organization-service/TEMPLATE-MANIFEST.md` § 3a
163
+ * records with their reasons. Row order matches `minimalism-site`'s (D3), so
164
+ * that alias's `differences` are additions and drops only.
165
+ */
166
+ const ORGANIZATION_SERVICE_ROWS = [
167
+ { route: "/", content: ["content/en/HomePage/home.mdx"] },
168
+ { route: "/about", content: ["content/en/AboutPage/about.mdx"] },
169
+ { route: "/services", content: ["content/en/ServicesList/services.mdx"] },
170
+ { route: "/services/[slug]", contentDir: "content/en/Service" },
171
+ { route: "/contact", content: ["content/en/ContactPage/contact.mdx"] },
172
+ { route: "/faq", content: ["content/en/FAQPage/faq.mdx"] },
173
+ ...SHAPE_INDEPENDENT_ROWS,
174
+ { route: "/privacy", content: ["content/en/PrivacyPage/privacy.mdx"] },
175
+ { route: "/terms", content: ["content/en/TermsPage/terms.mdx"] },
176
+ {
177
+ route: "/purchase-policy",
178
+ content: ["content/en/PurchasePolicyPage/purchase-policy.mdx"],
179
+ },
180
+ ];
181
+ /**
182
+ * `local-business-service`'s own rows (#6757 D1), derived the same way with
183
+ * `--shape local-business-service`. It has no `--template` alias of its own
184
+ * since #6789 retired the one alias that composed it; `--shape` is its only entry.
185
+ */
186
+ const LOCAL_BUSINESS_SERVICE_ROWS = [
187
+ { route: "/", content: ["content/en/HomePage/home.mdx"] },
188
+ { route: "/services", content: ["content/en/ServicesList/services.mdx"] },
189
+ { route: "/services/[slug]", contentDir: "content/en/Service" },
190
+ { route: "/about", content: ["content/en/AboutPage/about.mdx"] },
191
+ { route: "/contact", content: ["content/en/ContactPage/contact.mdx"] },
192
+ { route: "/faq", content: ["content/en/FAQPage/faq.mdx"] },
193
+ ...SHAPE_INDEPENDENT_ROWS,
194
+ {
195
+ route: "/purchase-policy",
196
+ content: ["content/en/PurchasePolicyPage/purchase-policy.mdx"],
197
+ },
198
+ { route: "/privacy", content: ["content/en/PrivacyPage/privacy.mdx"] },
199
+ { route: "/terms", content: ["content/en/TermsPage/terms.mdx"] },
200
+ ];
201
+ /**
202
+ * `person-service`'s own rows (#6758 D1, D3), derived from
203
+ * `derive-roster.py --shape person-service --primary-goal generate-leads
204
+ * --registry packages/schema/src/registry/entries.ts` at harness commit
205
+ * `7bdaf148e1b0e639cd90a80008955e55cc4aa2b5` (the vendored equivalent:
206
+ * `--entity-type person --offering-type services --primary-goal
207
+ * generate-leads --scale global`), edited only by the deviations
208
+ * `site-templates/shapes/person-service/TEMPLATE-MANIFEST.md` § 3a records
209
+ * with their reasons. Row order matches `local-business-service`'s (D3):
210
+ * services before about, because a consultant is hired for an engagement
211
+ * first.
212
+ */
213
+ const PERSON_SERVICE_ROWS = [
214
+ { route: "/", content: ["content/en/HomePage/home.mdx"] },
215
+ { route: "/services", content: ["content/en/ServicesList/services.mdx"] },
216
+ { route: "/services/[slug]", contentDir: "content/en/Service" },
217
+ { route: "/about", content: ["content/en/AboutPage/about.mdx"] },
218
+ { route: "/contact", content: ["content/en/ContactPage/contact.mdx"] },
219
+ { route: "/faq", content: ["content/en/FAQPage/faq.mdx"] },
220
+ ...SHAPE_INDEPENDENT_ROWS,
221
+ {
222
+ route: "/purchase-policy",
223
+ content: ["content/en/PurchasePolicyPage/purchase-policy.mdx"],
224
+ },
225
+ { route: "/privacy", content: ["content/en/PrivacyPage/privacy.mdx"] },
226
+ { route: "/terms", content: ["content/en/TermsPage/terms.mdx"] },
227
+ ];
228
+ /**
229
+ * Each buildable shape's standard roster (#6753 D3) — the rows an alias starts
230
+ * from before its `differences` apply.
231
+ *
232
+ * `organization-product` is today's base roster, the `/blog` teaser and the
233
+ * portfolio pair. `organization-service`, `local-business-service` (#6757)
234
+ * and `person-service` (#6758, roadmap § 6 Phase 2) are each their own rows,
235
+ * the `/blog` teaser and the portfolio pair.
236
+ */
237
+ export const SHAPE_ROSTERS = Object.freeze({
238
+ "organization-product": [
239
+ ...TEMPLATE_BASE_ROSTER,
240
+ FREE_BLOG_TEASER_ROW,
241
+ ...PORTFOLIO_ROWS,
242
+ ],
243
+ "organization-service": [
244
+ ...ORGANIZATION_SERVICE_ROWS,
245
+ FREE_BLOG_TEASER_ROW,
246
+ ...PORTFOLIO_ROWS,
247
+ ],
248
+ "local-business-service": [
249
+ ...LOCAL_BUSINESS_SERVICE_ROWS,
250
+ FREE_BLOG_TEASER_ROW,
251
+ ...PORTFOLIO_ROWS,
252
+ ],
253
+ "person-service": [
254
+ ...PERSON_SERVICE_ROWS,
255
+ FREE_BLOG_TEASER_ROW,
256
+ ...PORTFOLIO_ROWS,
257
+ ],
258
+ });
259
+ /**
260
+ * The `--template` names and the grid coordinates each stands for (#6753) —
261
+ * the one table `TEMPLATE_MANIFESTS` and `RECOGNIZED_TEMPLATES` derive from,
262
+ * in the declaration order both keep. The plain name is the Pro one: it is
263
+ * the flagship and the demo (Sam, 2026-09-14, parent § D12).
264
+ *
265
+ * `workspace` appears in no module list. It is a Pro module, but an authed app
266
+ * surface contributing no PUBLIC page to a marketing site, and `modules` names
267
+ * what the roster uses (parent § D15). A Pro key unlocks it regardless of any
268
+ * template.
269
+ *
270
+ * `commerce` is a per-site add-on available at any level, so no alias exists
271
+ * FOR it (parent § D13); it still contributes rows to whichever alias takes
272
+ * it, through `mergeRoster`.
273
+ *
274
+ * Frozen (#5507): the registry composed from this table is also the issuer's
275
+ * authorization allowlist (spec 5480 § C7). A test needing a different table
276
+ * passes its own to `resolveTemplate(name, aliases)` rather than mutating
277
+ * this one.
278
+ */
279
+ export const ALIASES = Object.freeze({
280
+ /**
281
+ * The Free template, and the mechanism's own proof (parent § D11): it
282
+ * requires only `marketing`, so the keyless merge path is exercised by a
283
+ * template we ship anyway rather than by a throwaway fixture. The bare
284
+ * `organization-product` shape — no differences at all.
285
+ */
286
+ "marketing-site-free": {
287
+ shape: "organization-product",
288
+ design: "standard",
289
+ modules: ["marketing"],
290
+ categories: ["accounting", "legal", "technology"],
291
+ // The demo site carries the "Get started with this template" banner
292
+ // (operator ruling 2026-09-23); every other layout knob keeps its default.
293
+ layout: { announcementBanner: true },
294
+ },
295
+ /**
296
+ * The Pro flagship. Its module list is OFFERINGS § 4 offering 3's tiers line
297
+ * — "docs, scheduling and flows modules" — where "flows" is
298
+ * `signal-collectors` (`MODULE_SURFACES` maps it to `["flows"]`). It drops
299
+ * the shape's `/blog` teaser because docs-blog contributes the real `/blog`,
300
+ * and adds the signal-collectors sample rows ahead of the portfolio pair.
301
+ */
302
+ "marketing-site": {
303
+ shape: "organization-product",
304
+ design: "standard",
305
+ modules: ["marketing", "docs-blog", "scheduling", "signal-collectors"],
306
+ // The flagship is the general-purpose template: it carries the whole
307
+ // registry, so every group tile on the hub has at least one template.
308
+ categories: [
309
+ "accounting",
310
+ "legal",
311
+ "consulting",
312
+ "hvac",
313
+ "roofing",
314
+ "plumbing",
315
+ "electrical",
316
+ "landscaping",
317
+ "auto-repair",
318
+ "real-estate",
319
+ "technology",
320
+ "medical-specialty",
321
+ ],
322
+ differences: {
323
+ drop: ["/blog"],
324
+ add: SIGNAL_COLLECTORS_SAMPLE_ROWS,
325
+ before: "/portfolio",
326
+ },
327
+ },
328
+ /**
329
+ * Pro Plus — the Pro list plus `multi-tenant`, which is correctly in the
330
+ * list because it DOES contribute pages (the org and workspace surfaces).
331
+ * Its `pageContributions` is nonetheless unset today, deferred to its own
332
+ * instance, so this template's merged roster carries the same contributed
333
+ * rows as `marketing-site`'s and no more. That is a module which has
334
+ * declared no rows yet — visible in the diff — not a merge that dropped
335
+ * declared rows.
336
+ */
337
+ "saas-product": {
338
+ shape: "organization-product",
339
+ design: "standard",
340
+ modules: [
341
+ "marketing",
342
+ "docs-blog",
343
+ "scheduling",
344
+ "signal-collectors",
345
+ "multi-tenant",
346
+ ],
347
+ categories: ["technology", "medical-specialty"],
348
+ differences: {
349
+ drop: ["/blog"],
350
+ add: SIGNAL_COLLECTORS_SAMPLE_ROWS,
351
+ before: "/portfolio",
352
+ },
353
+ },
354
+ /**
355
+ * The second Pro template (#5589) — the reports-first, scroll-snap deck
356
+ * site. NOT `marketing-site` plus a module: its `modules` omit `docs-blog`,
357
+ * so the two Pro templates are siblings under `_base` (#5618 D2), never a
358
+ * lineage. Level still derives from `modules`: `scheduling` and
359
+ * `signal-collectors` are paid, so `templateDelivery` returns `"paid"`
360
+ * exactly as it does for `marketing-site`.
361
+ *
362
+ * It composes the `organization-service` shape roster (#6757) rather than
363
+ * the organization-product one: the deck home replaces the document-scroll
364
+ * home, and `/how-it-works`, the product page, `/pricing` and `/sign-in`
365
+ * are not pages this site has. The roster is what the
366
+ * template IS, so an unrostered page has neither a route directory
367
+ * (`rosterSurfaces`) nor its `_base`/overlay seed (#6646 D1).
368
+ *
369
+ * It declares NO `layout` block (#6638): the deck home, mark-only nav and
370
+ * centered footer are the `minimalism` design's, supplied by
371
+ * `DESIGN_LAYOUTS` from `design:` — the look any shape can wear. The
372
+ * roster rows the `organization-service` shape does not derive
373
+ * (`/reports`, `/referral`) are recorded with their reasons in this
374
+ * template's TEMPLATE-MANIFEST.md § 3a.
375
+ *
376
+ * `/reports` and `/referral` carry no `GATEABLE_SURFACES` entry and need
377
+ * none: both are single-segment `LandingPage` slugs served by the generic
378
+ * `[slug]` route (#5469 D2), the same mechanism Free's `/how-it-works`
379
+ * uses. `/reports/[slug]` (the reader) is the signal-collectors module's
380
+ * own contributed row.
381
+ *
382
+ * `/services/[slug]` declares its seed DIRECTORY as `contentDir`
383
+ * (`content/en/Service`, as `routes-map.ts` records it). The three
384
+ * samples ride the template tree unmapped, landing at that directory.
385
+ *
386
+ * Since #6757, `organization-service` carries a real standard roster
387
+ * (D1), so this alias's `differences` is additions and drops only: it
388
+ * drops the `/blog` teaser (a Pro alias does not upsell its own level,
389
+ * D8) and the portfolio pair (the reports are the proof, not a
390
+ * portfolio), adds the signal-collectors samples, and INSERTS its two own
391
+ * rows — `/reports` before `/about`, `/referral` before `/faq` (D7) — to
392
+ * reproduce its pre-#6757 row order (§ 1.2) exactly.
393
+ */
394
+ "minimalism-site": {
395
+ shape: "organization-service",
396
+ design: "minimalism",
397
+ modules: ["marketing", "scheduling", "signal-collectors"],
398
+ categories: ["real-estate", "technology", "legal"],
399
+ differences: {
400
+ drop: ["/blog", "/portfolio", "/portfolio/[slug]"],
401
+ add: SIGNAL_COLLECTORS_SAMPLE_ROWS,
402
+ insert: [
403
+ { before: "/about", rows: [REPORTS_ROW] },
404
+ { before: "/faq", rows: [REFERRAL_ROW] },
405
+ ],
406
+ },
407
+ },
408
+ });
409
+ /**
410
+ * The coordinates a keyless `--shape S` builds (#6757 D5) — the composed
411
+ * FREE manifest per shape, for a shape with no `--template` alias of its
412
+ * own. Frozen and `Partial`; `organization-product` needs none — its
413
+ * keyless tree is `marketing-site-free`'s (#6754 AC-2).
414
+ *
415
+ * No `differences` (a bare shape is its standard roster, D1) and no
416
+ * `layout`. Every category is a leaf of `packages/schema/src/categories.ts`,
417
+ * as `TemplateManifest.categories` requires. `person-service`'s single
418
+ * `consulting` category is the operator's disposition (2026-09-26,
419
+ * ai-launch-kit-internal#6758): the leaf did not exist when #6758's spec was
420
+ * written, and adding it replaced that spec's `["accounting", "legal",
421
+ * "technology"]` author-pick stand-in.
422
+ */
423
+ export const SHAPE_STARTER_ALIASES = Object.freeze({
424
+ "organization-service": {
425
+ shape: "organization-service",
426
+ design: "standard",
427
+ modules: ["marketing"],
428
+ categories: ["accounting", "legal", "real-estate"],
429
+ },
430
+ "local-business-service": {
431
+ shape: "local-business-service",
432
+ design: "standard",
433
+ modules: ["marketing"],
434
+ categories: [
435
+ "hvac",
436
+ "roofing",
437
+ "plumbing",
438
+ "electrical",
439
+ "landscaping",
440
+ "auto-repair",
441
+ ],
442
+ },
443
+ "person-service": {
444
+ shape: "person-service",
445
+ design: "standard",
446
+ modules: ["marketing"],
447
+ categories: ["consulting"],
448
+ },
449
+ });
@@ -192,10 +192,10 @@ export declare const NAV_CONFIG_PATH = "apps/web/lib/nav-config.ts";
192
192
  *
193
193
  * The base items are the Free marketing-site chrome (#5469 D5, the approved
194
194
  * chrome diff recorded on that card, re-pointed by #6658 D8):
195
- * a Product flyout (Use cases · Features · FAQ), then Use cases, Blog, Pricing
196
- * and About. Features links the product's own page (`/software/product`), a
197
- * core route like `/faq` and `/about`; `/blog` is always linked (the teaser or
198
- * the docs-blog module serves it). Use cases and Pricing are gateable
195
+ * a Product flyout in two columns (Features · Use Cases, #6721), then Blog,
196
+ * Pricing and About. The feature and use-case links ride the `features` and
197
+ * `use-cases` surfaces; `/blog` is always linked (the teaser or the docs-blog
198
+ * module serves it). Pricing is gateable
199
199
  * surfaces: each item is emitted only when its surface is enabled (a template
200
200
  * roster enables it, #5469 D10), so the nav still never links a page the
201
201
  * scaffold does not carry.