create-ailk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (533) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +39 -0
  3. package/dist/cli.d.ts +2 -0
  4. package/dist/cli.js +80 -0
  5. package/dist/copy.d.ts +8 -0
  6. package/dist/copy.js +109 -0
  7. package/dist/index.d.ts +10 -0
  8. package/dist/index.js +10 -0
  9. package/dist/lib/pro-callout.d.ts +12 -0
  10. package/dist/lib/pro-callout.js +20 -0
  11. package/dist/parse-args.d.ts +13 -0
  12. package/dist/parse-args.js +81 -0
  13. package/dist/programmatic.d.ts +49 -0
  14. package/dist/programmatic.js +89 -0
  15. package/dist/substitute.d.ts +31 -0
  16. package/dist/substitute.js +45 -0
  17. package/dist/validate.d.ts +8 -0
  18. package/dist/validate.js +70 -0
  19. package/package.json +47 -0
  20. package/templates/.claude/.gitkeep +0 -0
  21. package/templates/.claude/agents/web.md +80 -0
  22. package/templates/.claude/rules/architecture.md +62 -0
  23. package/templates/.claude/rules/preserve-existing-style.md +51 -0
  24. package/templates/.claude/skills/README.md +43 -0
  25. package/templates/.claude/skills/add-schema/SKILL.md +270 -0
  26. package/templates/.claude/skills/add-schema/references/conflict-handling.md +200 -0
  27. package/templates/.claude/skills/add-schema/references/file-finding.md +123 -0
  28. package/templates/.claude/skills/add-schema/references/schema-types.md +131 -0
  29. package/templates/.claude/skills/audit-site/SKILL.md +213 -0
  30. package/templates/.claude/skills/audit-site/references/common-errors.md +113 -0
  31. package/templates/.claude/skills/audit-site/references/findings-glossary.md +138 -0
  32. package/templates/.claude/skills/audit-site/references/severity-levels.md +114 -0
  33. package/templates/.claude/skills/provision-config/SKILL.md +243 -0
  34. package/templates/.claude/skills/provision-config/references/env-vars-template.md +184 -0
  35. package/templates/.claude/skills/provision-config/references/runbook-template.md +248 -0
  36. package/templates/.claude/skills/provision-config/references/vercel-json-template.md +98 -0
  37. package/templates/.claude/skills/scaffold-auth/SKILL.md +261 -0
  38. package/templates/.claude/skills/scaffold-auth/references/env-vars.md +91 -0
  39. package/templates/.claude/skills/scaffold-auth/references/oauth-app-setup.md +171 -0
  40. package/templates/.claude/skills/scaffold-commerce/SKILL.md +310 -0
  41. package/templates/.claude/skills/scaffold-commerce/references/lookup-keys-template.md +71 -0
  42. package/templates/.claude/skills/scaffold-commerce/references/marketplace-brand-pages.md +83 -0
  43. package/templates/.claude/skills/scaffold-commerce/templates/marketplace-cta-route.tsx.tmpl +72 -0
  44. package/templates/.claude/skills/scaffold-page/SKILL.md +243 -0
  45. package/templates/.claude/skills/scaffold-page/references/page-types.md +169 -0
  46. package/templates/.claude/skills/scaffold-page/templates/content.mdx.tmpl +28 -0
  47. package/templates/.claude/skills/scaffold-page/templates/route.tsx.tmpl +28 -0
  48. package/templates/.claude/skills/suggest-site-pages/SKILL.md +242 -0
  49. package/templates/.claude/skills/suggest-site-pages/references/categories.md +287 -0
  50. package/templates/.env.example +205 -0
  51. package/templates/.gitkeep +2 -0
  52. package/templates/CLAUDE.md +142 -0
  53. package/templates/CONVENTIONS.md +222 -0
  54. package/templates/README.md +110 -0
  55. package/templates/apps/api/.env.example +40 -0
  56. package/templates/apps/api/CLAUDE.md +63 -0
  57. package/templates/apps/api/api/index.ts +144 -0
  58. package/templates/apps/api/jest.config.cjs +74 -0
  59. package/templates/apps/api/package.json +54 -0
  60. package/templates/apps/api/src/__tests__/factories/content-fixture.ts +138 -0
  61. package/templates/apps/api/src/__tests__/factories/index.ts +70 -0
  62. package/templates/apps/api/src/__tests__/factories/lead-fixture.ts +82 -0
  63. package/templates/apps/api/src/__tests__/index.test.ts +118 -0
  64. package/templates/apps/api/src/__tests__/server.test.ts +207 -0
  65. package/templates/apps/api/src/__tests__/services/enrichment-shim.test.ts +126 -0
  66. package/templates/apps/api/src/__tests__/setup.ts +24 -0
  67. package/templates/apps/api/src/cli.ts +30 -0
  68. package/templates/apps/api/src/config/__tests__/index.test.ts +97 -0
  69. package/templates/apps/api/src/config/index.ts +56 -0
  70. package/templates/apps/api/src/index.ts +32 -0
  71. package/templates/apps/api/src/lib/__mocks__/prisma-client.js +15 -0
  72. package/templates/apps/api/src/lib/__mocks__/prisma.ts +45 -0
  73. package/templates/apps/api/src/lib/__tests__/content-adapter.test.ts +178 -0
  74. package/templates/apps/api/src/lib/__tests__/error-serializer.test.ts +100 -0
  75. package/templates/apps/api/src/lib/__tests__/errors.test.ts +94 -0
  76. package/templates/apps/api/src/lib/__tests__/file-fallback.test.ts +144 -0
  77. package/templates/apps/api/src/lib/__tests__/fixtures/HomePage/home.mdx +8 -0
  78. package/templates/apps/api/src/lib/__tests__/lead-capture-store.test.ts +227 -0
  79. package/templates/apps/api/src/lib/__tests__/outbound-http.test.ts +125 -0
  80. package/templates/apps/api/src/lib/__tests__/prisma.test.ts +165 -0
  81. package/templates/apps/api/src/lib/__tests__/require-paid-tier.test.ts +129 -0
  82. package/templates/apps/api/src/lib/__tests__/stripe.test.ts +74 -0
  83. package/templates/apps/api/src/lib/content-adapter.ts +86 -0
  84. package/templates/apps/api/src/lib/error-serializer.ts +77 -0
  85. package/templates/apps/api/src/lib/errors.ts +95 -0
  86. package/templates/apps/api/src/lib/file-fallback.ts +87 -0
  87. package/templates/apps/api/src/lib/lead-capture-store.ts +110 -0
  88. package/templates/apps/api/src/lib/locales.ts +201 -0
  89. package/templates/apps/api/src/lib/outbound-http.ts +122 -0
  90. package/templates/apps/api/src/lib/prisma.ts +21 -0
  91. package/templates/apps/api/src/lib/require-paid-tier.ts +53 -0
  92. package/templates/apps/api/src/lib/stripe.ts +30 -0
  93. package/templates/apps/api/src/lib/webhook-idempotency.ts +92 -0
  94. package/templates/apps/api/src/middleware/__tests__/adversarial/bearer-token-format.test.ts +111 -0
  95. package/templates/apps/api/src/middleware/__tests__/adversarial/cookie-or-bearer-precedence.test.ts +172 -0
  96. package/templates/apps/api/src/middleware/__tests__/adversarial/csrf-bearer-skip.test.ts +119 -0
  97. package/templates/apps/api/src/middleware/__tests__/adversarial/csrf-cookie-path.test.ts +138 -0
  98. package/templates/apps/api/src/middleware/__tests__/adversarial/session-fixation.test.ts +149 -0
  99. package/templates/apps/api/src/middleware/__tests__/adversarial/session-timeout.test.ts +139 -0
  100. package/templates/apps/api/src/middleware/__tests__/auth.bearer-path.test.ts +175 -0
  101. package/templates/apps/api/src/middleware/__tests__/auth.both-present-precedence.test.ts +76 -0
  102. package/templates/apps/api/src/middleware/__tests__/auth.cookie-path.test.ts +153 -0
  103. package/templates/apps/api/src/middleware/__tests__/auth.neither-present.test.ts +72 -0
  104. package/templates/apps/api/src/middleware/__tests__/rate-limit.test.ts +292 -0
  105. package/templates/apps/api/src/middleware/auth.ts +246 -0
  106. package/templates/apps/api/src/middleware/rate-limit.ts +132 -0
  107. package/templates/apps/api/src/openapi/__tests__/openapi.test.ts +129 -0
  108. package/templates/apps/api/src/openapi/index.ts +12 -0
  109. package/templates/apps/api/src/openapi/spec.ts +408 -0
  110. package/templates/apps/api/src/routes/auth/__tests__/auth-tokens.functional.test.ts +193 -0
  111. package/templates/apps/api/src/routes/auth/__tests__/auth-user.functional.test.ts +201 -0
  112. package/templates/apps/api/src/routes/auth/__tests__/tokens.test.ts +294 -0
  113. package/templates/apps/api/src/routes/auth/__tests__/user.test.ts +486 -0
  114. package/templates/apps/api/src/routes/auth/tokens.ts +199 -0
  115. package/templates/apps/api/src/routes/auth/user.ts +244 -0
  116. package/templates/apps/api/src/routes/checkout/__tests__/sessions.test.ts +588 -0
  117. package/templates/apps/api/src/routes/checkout/index.ts +13 -0
  118. package/templates/apps/api/src/routes/checkout/sessions.ts +185 -0
  119. package/templates/apps/api/src/routes/content/__tests__/create.test.ts +239 -0
  120. package/templates/apps/api/src/routes/content/__tests__/delete.test.ts +201 -0
  121. package/templates/apps/api/src/routes/content/__tests__/get-page.test.ts +141 -0
  122. package/templates/apps/api/src/routes/content/__tests__/list-pages.test.ts +122 -0
  123. package/templates/apps/api/src/routes/content/__tests__/list-types.test.ts +44 -0
  124. package/templates/apps/api/src/routes/content/__tests__/locale.test.ts +118 -0
  125. package/templates/apps/api/src/routes/content/__tests__/rate-limit.test.ts +51 -0
  126. package/templates/apps/api/src/routes/content/__tests__/update.test.ts +252 -0
  127. package/templates/apps/api/src/routes/content/create.ts +114 -0
  128. package/templates/apps/api/src/routes/content/delete.ts +81 -0
  129. package/templates/apps/api/src/routes/content/get-page.ts +98 -0
  130. package/templates/apps/api/src/routes/content/index.ts +32 -0
  131. package/templates/apps/api/src/routes/content/list-pages.ts +83 -0
  132. package/templates/apps/api/src/routes/content/list-types.ts +19 -0
  133. package/templates/apps/api/src/routes/content/rate-limit.ts +13 -0
  134. package/templates/apps/api/src/routes/content/slug.ts +9 -0
  135. package/templates/apps/api/src/routes/content/update.ts +111 -0
  136. package/templates/apps/api/src/routes/leads/__tests__/index.test.ts +415 -0
  137. package/templates/apps/api/src/routes/leads/__tests__/track.test.ts +165 -0
  138. package/templates/apps/api/src/routes/leads/index.ts +130 -0
  139. package/templates/apps/api/src/routes/test/auth/__tests__/session.test.ts +296 -0
  140. package/templates/apps/api/src/routes/test/auth/session.ts +141 -0
  141. package/templates/apps/api/src/routes/webhooks/README.md +57 -0
  142. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-idempotency.test.ts +247 -0
  143. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-rate-limit.test.ts +198 -0
  144. package/templates/apps/api/src/routes/webhooks/__tests__/stripe.test.ts +633 -0
  145. package/templates/apps/api/src/routes/webhooks/index.ts +41 -0
  146. package/templates/apps/api/src/routes/webhooks/stripe.ts +253 -0
  147. package/templates/apps/api/src/server.ts +157 -0
  148. package/templates/apps/api/src/services/__tests__/lead-routing.test.ts +395 -0
  149. package/templates/apps/api/src/services/enrichment-shim.ts +53 -0
  150. package/templates/apps/api/src/services/lead-routing.ts +338 -0
  151. package/templates/apps/api/tsconfig.json +34 -0
  152. package/templates/apps/api/vercel.json +17 -0
  153. package/templates/apps/mcp/.env.example +52 -0
  154. package/templates/apps/mcp/CLAUDE.md +84 -0
  155. package/templates/apps/mcp/__tests__/abuse/daily-cap.test.ts +52 -0
  156. package/templates/apps/mcp/__tests__/abuse/email-validator.test.ts +46 -0
  157. package/templates/apps/mcp/__tests__/abuse/honeypot.test.ts +36 -0
  158. package/templates/apps/mcp/__tests__/abuse/user-agent-deny.test.ts +54 -0
  159. package/templates/apps/mcp/__tests__/aeo-cli-parity.test.ts +110 -0
  160. package/templates/apps/mcp/__tests__/audit-single-page.test.ts +213 -0
  161. package/templates/apps/mcp/__tests__/audit.test.ts +217 -0
  162. package/templates/apps/mcp/__tests__/catalog-drift.test.ts +52 -0
  163. package/templates/apps/mcp/__tests__/create_page.test.ts +201 -0
  164. package/templates/apps/mcp/__tests__/delete_page.test.ts +176 -0
  165. package/templates/apps/mcp/__tests__/get_business_hours.test.ts +82 -0
  166. package/templates/apps/mcp/__tests__/get_faq.test.ts +80 -0
  167. package/templates/apps/mcp/__tests__/get_locations.test.ts +65 -0
  168. package/templates/apps/mcp/__tests__/get_offerings.test.ts +90 -0
  169. package/templates/apps/mcp/__tests__/get_pricing.test.ts +80 -0
  170. package/templates/apps/mcp/__tests__/get_site_info.test.ts +81 -0
  171. package/templates/apps/mcp/__tests__/http-transport.test.ts +323 -0
  172. package/templates/apps/mcp/__tests__/lib/errors.test.ts +75 -0
  173. package/templates/apps/mcp/__tests__/lib/require-paid-tier.test.ts +75 -0
  174. package/templates/apps/mcp/__tests__/list_pages.test.ts +112 -0
  175. package/templates/apps/mcp/__tests__/locale.test.ts +135 -0
  176. package/templates/apps/mcp/__tests__/parity.test.ts +205 -0
  177. package/templates/apps/mcp/__tests__/purchase-disabled.test.ts +34 -0
  178. package/templates/apps/mcp/__tests__/read_content.test.ts +153 -0
  179. package/templates/apps/mcp/__tests__/request_callback.test.ts +163 -0
  180. package/templates/apps/mcp/__tests__/search_content.test.ts +153 -0
  181. package/templates/apps/mcp/__tests__/server.test.ts +115 -0
  182. package/templates/apps/mcp/__tests__/submit_lead.test.ts +165 -0
  183. package/templates/apps/mcp/__tests__/subscribe_newsletter.test.ts +161 -0
  184. package/templates/apps/mcp/__tests__/tools/purchase.test.ts +227 -0
  185. package/templates/apps/mcp/__tests__/tools/scaffold.test.ts +237 -0
  186. package/templates/apps/mcp/__tests__/update_page.test.ts +195 -0
  187. package/templates/apps/mcp/jest.config.cjs +82 -0
  188. package/templates/apps/mcp/package.json +37 -0
  189. package/templates/apps/mcp/src/abuse/daily-cap.ts +47 -0
  190. package/templates/apps/mcp/src/abuse/email-validator.ts +25 -0
  191. package/templates/apps/mcp/src/abuse/honeypot.ts +21 -0
  192. package/templates/apps/mcp/src/abuse/index.ts +111 -0
  193. package/templates/apps/mcp/src/abuse/user-agent-deny.ts +58 -0
  194. package/templates/apps/mcp/src/http-transport.ts +303 -0
  195. package/templates/apps/mcp/src/index.ts +67 -0
  196. package/templates/apps/mcp/src/lib/audit-single-page.ts +194 -0
  197. package/templates/apps/mcp/src/lib/errors.ts +61 -0
  198. package/templates/apps/mcp/src/lib/locales.ts +171 -0
  199. package/templates/apps/mcp/src/lib/require-paid-tier.ts +44 -0
  200. package/templates/apps/mcp/src/lib/resolve-locale.ts +30 -0
  201. package/templates/apps/mcp/src/server.ts +139 -0
  202. package/templates/apps/mcp/src/tools/audit.ts +103 -0
  203. package/templates/apps/mcp/src/tools/capture_lead.ts +52 -0
  204. package/templates/apps/mcp/src/tools/create_page.ts +95 -0
  205. package/templates/apps/mcp/src/tools/delete_page.ts +73 -0
  206. package/templates/apps/mcp/src/tools/get_business_hours.ts +66 -0
  207. package/templates/apps/mcp/src/tools/get_faq.ts +69 -0
  208. package/templates/apps/mcp/src/tools/get_locations.ts +85 -0
  209. package/templates/apps/mcp/src/tools/get_offerings.ts +66 -0
  210. package/templates/apps/mcp/src/tools/get_pricing.ts +74 -0
  211. package/templates/apps/mcp/src/tools/get_site_info.ts +84 -0
  212. package/templates/apps/mcp/src/tools/index.ts +125 -0
  213. package/templates/apps/mcp/src/tools/list_pages.ts +72 -0
  214. package/templates/apps/mcp/src/tools/purchase.ts +89 -0
  215. package/templates/apps/mcp/src/tools/read_content.ts +61 -0
  216. package/templates/apps/mcp/src/tools/request_callback.ts +51 -0
  217. package/templates/apps/mcp/src/tools/scaffold.ts +119 -0
  218. package/templates/apps/mcp/src/tools/search_content.ts +59 -0
  219. package/templates/apps/mcp/src/tools/subscribe_newsletter.ts +47 -0
  220. package/templates/apps/mcp/src/tools/update_page.ts +91 -0
  221. package/templates/apps/mcp/tsconfig.json +19 -0
  222. package/templates/apps/web/.env.example +47 -0
  223. package/templates/apps/web/CLAUDE.md +81 -0
  224. package/templates/apps/web/__tests__/auth/adversarial/cookie-attributes.test.ts +94 -0
  225. package/templates/apps/web/__tests__/auth/adversarial/oauth-state-parameter.test.ts +75 -0
  226. package/templates/apps/web/__tests__/auth/adversarial/redirect-uri-allowlist.test.ts +82 -0
  227. package/templates/apps/web/__tests__/auth/env-helpers.test.ts +168 -0
  228. package/templates/apps/web/__tests__/authority-list-routes.test.tsx +208 -0
  229. package/templates/apps/web/__tests__/better-stack.test.ts +66 -0
  230. package/templates/apps/web/__tests__/blog-dir-resolution.test.ts +87 -0
  231. package/templates/apps/web/__tests__/blog-source-populated.test.ts +130 -0
  232. package/templates/apps/web/__tests__/data-testid-coverage.test.tsx +60 -0
  233. package/templates/apps/web/__tests__/google-analytics.test.tsx +104 -0
  234. package/templates/apps/web/__tests__/i18n/middleware.test.ts +119 -0
  235. package/templates/apps/web/__tests__/i18n/routing.test.ts +114 -0
  236. package/templates/apps/web/__tests__/i18n/translations.test.ts +191 -0
  237. package/templates/apps/web/__tests__/json-ld.test.ts +98 -0
  238. package/templates/apps/web/__tests__/knowledge-events-routes.test.tsx +580 -0
  239. package/templates/apps/web/__tests__/layout-stealth.test.ts +39 -0
  240. package/templates/apps/web/__tests__/lighthouse-fixtures/improvement-image-shrink.tsx +103 -0
  241. package/templates/apps/web/__tests__/lighthouse-fixtures/override-fixture.md +114 -0
  242. package/templates/apps/web/__tests__/lighthouse-fixtures/regression-bloat.tsx +94 -0
  243. package/templates/apps/web/__tests__/page.test.tsx +230 -0
  244. package/templates/apps/web/__tests__/products-services-phase1.test.tsx +321 -0
  245. package/templates/apps/web/__tests__/projects-routes.test.tsx +392 -0
  246. package/templates/apps/web/__tests__/resources-downloads-integrations-phase2.test.tsx +475 -0
  247. package/templates/apps/web/__tests__/routes/ai-plugin-json.test.ts +53 -0
  248. package/templates/apps/web/__tests__/routes/blog-route.test.tsx +191 -0
  249. package/templates/apps/web/__tests__/routes/llms-txt.test.ts +123 -0
  250. package/templates/apps/web/__tests__/routes/robots-txt.test.ts +52 -0
  251. package/templates/apps/web/__tests__/routes/sitemap-xml.test.ts +78 -0
  252. package/templates/apps/web/__tests__/routes/well-known-mcp.test.ts +203 -0
  253. package/templates/apps/web/__tests__/section-routes.test.tsx +693 -0
  254. package/templates/apps/web/__tests__/security-headers.test.ts +201 -0
  255. package/templates/apps/web/__tests__/sentry-config.test.ts +116 -0
  256. package/templates/apps/web/__tests__/setup.ts +82 -0
  257. package/templates/apps/web/__tests__/sitemap-locales.test.ts +415 -0
  258. package/templates/apps/web/__tests__/standalone-informational-routes.test.tsx +844 -0
  259. package/templates/apps/web/app/.well-known/ai-plugin.json/route.ts +81 -0
  260. package/templates/apps/web/app/.well-known/mcp.json/build-manifest.ts +110 -0
  261. package/templates/apps/web/app/.well-known/mcp.json/route.ts +58 -0
  262. package/templates/apps/web/app/[locale]/__tests__/layout.test.tsx +120 -0
  263. package/templates/apps/web/app/[locale]/__tests__/page-renderer-migration.test.tsx +202 -0
  264. package/templates/apps/web/app/[locale]/about/page.tsx +31 -0
  265. package/templates/apps/web/app/[locale]/blog/[[...slug]]/page.tsx +173 -0
  266. package/templates/apps/web/app/[locale]/careers/[slug]/page.tsx +45 -0
  267. package/templates/apps/web/app/[locale]/careers/__tests__/page-renderer-migration.test.tsx +117 -0
  268. package/templates/apps/web/app/[locale]/careers/page.tsx +25 -0
  269. package/templates/apps/web/app/[locale]/case-studies/[slug]/page.tsx +44 -0
  270. package/templates/apps/web/app/[locale]/case-studies/__tests__/page-renderer-migration.test.tsx +113 -0
  271. package/templates/apps/web/app/[locale]/case-studies/page.tsx +25 -0
  272. package/templates/apps/web/app/[locale]/clients/__tests__/page-renderer-migration.test.tsx +63 -0
  273. package/templates/apps/web/app/[locale]/clients/page.tsx +27 -0
  274. package/templates/apps/web/app/[locale]/contact/ContactForm.tsx +130 -0
  275. package/templates/apps/web/app/[locale]/contact/__tests__/contact.actions.test.ts +152 -0
  276. package/templates/apps/web/app/[locale]/contact/__tests__/page-renderer-migration.test.tsx +92 -0
  277. package/templates/apps/web/app/[locale]/contact/contact.actions.ts +79 -0
  278. package/templates/apps/web/app/[locale]/contact/error.tsx +24 -0
  279. package/templates/apps/web/app/[locale]/contact/page.tsx +38 -0
  280. package/templates/apps/web/app/[locale]/courses/[slug]/page.tsx +34 -0
  281. package/templates/apps/web/app/[locale]/courses/__tests__/page-renderer-migration.test.tsx +119 -0
  282. package/templates/apps/web/app/[locale]/courses/page.tsx +25 -0
  283. package/templates/apps/web/app/[locale]/dev/purchase/__tests__/actions.test.ts +160 -0
  284. package/templates/apps/web/app/[locale]/dev/purchase/error.tsx +25 -0
  285. package/templates/apps/web/app/[locale]/dev/purchase/page.tsx +117 -0
  286. package/templates/apps/web/app/[locale]/dev/purchase/purchase.actions.ts +58 -0
  287. package/templates/apps/web/app/[locale]/docs/[[...slug]]/page.tsx +118 -0
  288. package/templates/apps/web/app/[locale]/downloads/__tests__/page-renderer-migration.test.tsx +72 -0
  289. package/templates/apps/web/app/[locale]/downloads/page.tsx +25 -0
  290. package/templates/apps/web/app/[locale]/events/[slug]/page.tsx +47 -0
  291. package/templates/apps/web/app/[locale]/events/__tests__/page-renderer-migration.test.tsx +130 -0
  292. package/templates/apps/web/app/[locale]/events/page.tsx +25 -0
  293. package/templates/apps/web/app/[locale]/faq/page.tsx +36 -0
  294. package/templates/apps/web/app/[locale]/how-to/[slug]/page.tsx +34 -0
  295. package/templates/apps/web/app/[locale]/how-to/__tests__/page-renderer-migration.test.tsx +78 -0
  296. package/templates/apps/web/app/[locale]/how-to/page.tsx +40 -0
  297. package/templates/apps/web/app/[locale]/integrations/[slug]/page.tsx +43 -0
  298. package/templates/apps/web/app/[locale]/integrations/__tests__/page-renderer-migration.test.tsx +129 -0
  299. package/templates/apps/web/app/[locale]/integrations/page.tsx +25 -0
  300. package/templates/apps/web/app/[locale]/launch-service/page.tsx +31 -0
  301. package/templates/apps/web/app/[locale]/layout.tsx +241 -0
  302. package/templates/apps/web/app/[locale]/page.tsx +41 -0
  303. package/templates/apps/web/app/[locale]/partners/[slug]/page.tsx +44 -0
  304. package/templates/apps/web/app/[locale]/partners/__tests__/page-renderer-migration.test.tsx +113 -0
  305. package/templates/apps/web/app/[locale]/partners/page.tsx +25 -0
  306. package/templates/apps/web/app/[locale]/products/[slug]/page.tsx +43 -0
  307. package/templates/apps/web/app/[locale]/products/__tests__/page-renderer-migration.test.tsx +129 -0
  308. package/templates/apps/web/app/[locale]/products/page.tsx +25 -0
  309. package/templates/apps/web/app/[locale]/projects/[slug]/page.tsx +39 -0
  310. package/templates/apps/web/app/[locale]/projects/__tests__/page-renderer-migration.test.tsx +138 -0
  311. package/templates/apps/web/app/[locale]/projects/page.tsx +30 -0
  312. package/templates/apps/web/app/[locale]/resources/[slug]/page.tsx +51 -0
  313. package/templates/apps/web/app/[locale]/resources/__tests__/page-renderer-migration.test.tsx +117 -0
  314. package/templates/apps/web/app/[locale]/resources/page.tsx +27 -0
  315. package/templates/apps/web/app/[locale]/services/[slug]/page.tsx +43 -0
  316. package/templates/apps/web/app/[locale]/services/__tests__/page-renderer-migration.test.tsx +129 -0
  317. package/templates/apps/web/app/[locale]/services/page.tsx +25 -0
  318. package/templates/apps/web/app/[locale]/software/[slug]/page.tsx +34 -0
  319. package/templates/apps/web/app/[locale]/software/__tests__/page-renderer-migration.test.tsx +81 -0
  320. package/templates/apps/web/app/[locale]/software/page.tsx +39 -0
  321. package/templates/apps/web/app/[locale]/tech-articles/[slug]/page.tsx +34 -0
  322. package/templates/apps/web/app/[locale]/tech-articles/__tests__/page-renderer-migration.test.tsx +82 -0
  323. package/templates/apps/web/app/[locale]/tech-articles/page.tsx +39 -0
  324. package/templates/apps/web/app/[locale]/testimonials/__tests__/page-renderer-migration.test.tsx +63 -0
  325. package/templates/apps/web/app/[locale]/testimonials/page.tsx +27 -0
  326. package/templates/apps/web/app/[locale]/use-cases/__tests__/page-renderer-migration.test.tsx +63 -0
  327. package/templates/apps/web/app/[locale]/use-cases/page.tsx +27 -0
  328. package/templates/apps/web/app/[locale]/whitepapers/[slug]/page.tsx +34 -0
  329. package/templates/apps/web/app/[locale]/whitepapers/__tests__/page-renderer-migration.test.tsx +82 -0
  330. package/templates/apps/web/app/[locale]/whitepapers/page.tsx +39 -0
  331. package/templates/apps/web/app/__tests__/error-boundaries.test.tsx +152 -0
  332. package/templates/apps/web/app/api/auth/[...all]/route.ts +16 -0
  333. package/templates/apps/web/app/error-fallback.tsx +75 -0
  334. package/templates/apps/web/app/error.tsx +23 -0
  335. package/templates/apps/web/app/layout.tsx +18 -0
  336. package/templates/apps/web/app/llms.txt/route.ts +101 -0
  337. package/templates/apps/web/app/not-found.tsx +48 -0
  338. package/templates/apps/web/app/og/__tests__/route.test.ts +164 -0
  339. package/templates/apps/web/app/og/route.tsx +135 -0
  340. package/templates/apps/web/app/robots.txt/route.ts +36 -0
  341. package/templates/apps/web/app/sitemap.xml/route.ts +146 -0
  342. package/templates/apps/web/auth.ts +141 -0
  343. package/templates/apps/web/components/ThemeToggle.tsx +60 -0
  344. package/templates/apps/web/components/google-analytics.tsx +34 -0
  345. package/templates/apps/web/content/en/blog/index.mdx +15 -0
  346. package/templates/apps/web/content/en/blog/launching-ailk.mdx +20 -0
  347. package/templates/apps/web/content/en/docs/getting-started.mdx +30 -0
  348. package/templates/apps/web/i18n/request.ts +36 -0
  349. package/templates/apps/web/jest.config.cjs +100 -0
  350. package/templates/apps/web/lib/__mocks__/next-mdx-remote-rsc.js +12 -0
  351. package/templates/apps/web/lib/__mocks__/source-server.js +31 -0
  352. package/templates/apps/web/lib/__tests__/og.test.ts +65 -0
  353. package/templates/apps/web/lib/auth-env.ts +66 -0
  354. package/templates/apps/web/lib/blog-list-data.ts +95 -0
  355. package/templates/apps/web/lib/blog-post-data.ts +79 -0
  356. package/templates/apps/web/lib/nav-config.ts +13 -0
  357. package/templates/apps/web/lib/observability/better-stack.ts +27 -0
  358. package/templates/apps/web/lib/og.ts +23 -0
  359. package/templates/apps/web/lib/prisma-for-auth.ts +34 -0
  360. package/templates/apps/web/lib/source.ts +34 -0
  361. package/templates/apps/web/messages/en.json +131 -0
  362. package/templates/apps/web/middleware.ts +80 -0
  363. package/templates/apps/web/next.config.mjs +167 -0
  364. package/templates/apps/web/package.json +62 -0
  365. package/templates/apps/web/public/.well-known/security.txt +17 -0
  366. package/templates/apps/web/public/android-chrome-192x192.png +0 -0
  367. package/templates/apps/web/public/android-chrome-512x512.png +0 -0
  368. package/templates/apps/web/public/apple-touch-icon.png +0 -0
  369. package/templates/apps/web/public/favicon-16x16.png +0 -0
  370. package/templates/apps/web/public/favicon-32x32.png +0 -0
  371. package/templates/apps/web/public/favicon.ico +0 -0
  372. package/templates/apps/web/public/favicon.svg +4 -0
  373. package/templates/apps/web/public/logo-dark.svg +21 -0
  374. package/templates/apps/web/public/logo-light.svg +21 -0
  375. package/templates/apps/web/public/logomark-dark.svg +4 -0
  376. package/templates/apps/web/public/logomark-light.svg +4 -0
  377. package/templates/apps/web/public/og-default.png +0 -0
  378. package/templates/apps/web/public/site.webmanifest +19 -0
  379. package/templates/apps/web/scripts/assert-content-bundled.ts +55 -0
  380. package/templates/apps/web/security-headers.config.ts +132 -0
  381. package/templates/apps/web/sentry.client.config.ts +27 -0
  382. package/templates/apps/web/sentry.edge.config.ts +15 -0
  383. package/templates/apps/web/sentry.server.config.ts +20 -0
  384. package/templates/apps/web/source.config.ts +78 -0
  385. package/templates/apps/web/src/components/SiteNav.tsx +21 -0
  386. package/templates/apps/web/src/lib/routes.ts +37 -0
  387. package/templates/apps/web/tsconfig.json +35 -0
  388. package/templates/apps/web/types/messages.d.ts +19 -0
  389. package/templates/content/.gitkeep +0 -0
  390. package/templates/content/CLAUDE.md +85 -0
  391. package/templates/content/_site.mdx +38 -0
  392. package/templates/content/ar/HomePage/home.mdx +123 -0
  393. package/templates/content/ar/_site.mdx +35 -0
  394. package/templates/content/de/_site.mdx +29 -0
  395. package/templates/content/en/.gitkeep +0 -0
  396. package/templates/content/en/AboutPage/about.mdx +19 -0
  397. package/templates/content/en/AboutPage/about.schema.json +82 -0
  398. package/templates/content/en/BookCall/book-call.mdx +19 -0
  399. package/templates/content/en/BookCall/book-call.schema.json +121 -0
  400. package/templates/content/en/BreadcrumbList/site-breadcrumbs.mdx +20 -0
  401. package/templates/content/en/CareersList/careers.mdx +24 -0
  402. package/templates/content/en/CaseStudiesList/case-studies.mdx +22 -0
  403. package/templates/content/en/CaseStudiesList/showcase.mdx +8 -0
  404. package/templates/content/en/CaseStudy/ailk-aeo-rollout.mdx +32 -0
  405. package/templates/content/en/CaseStudy/schema-builder-migration.mdx +41 -0
  406. package/templates/content/en/ClientsList/clients.mdx +38 -0
  407. package/templates/content/en/ContactPage/contact.mdx +19 -0
  408. package/templates/content/en/ContactPage/contact.schema.json +100 -0
  409. package/templates/content/en/ContactPoint/primary.mdx +14 -0
  410. package/templates/content/en/Course/aeo-fundamentals.mdx +37 -0
  411. package/templates/content/en/Course/schema-builder-workshop.mdx +62 -0
  412. package/templates/content/en/CoursesList/courses.mdx +22 -0
  413. package/templates/content/en/DownloadsList/downloads.mdx +22 -0
  414. package/templates/content/en/Event/aeo-office-hours-may-2026.mdx +39 -0
  415. package/templates/content/en/Event/ailk-launch-day-2026.mdx +35 -0
  416. package/templates/content/en/EventsList/events.mdx +26 -0
  417. package/templates/content/en/FAQPage/faq.mdx +420 -0
  418. package/templates/content/en/FAQPage/faq.schema.json +231 -0
  419. package/templates/content/en/GlossaryList/glossary.mdx +19 -0
  420. package/templates/content/en/GlossaryList/glossary.schema.json +300 -0
  421. package/templates/content/en/HomePage/home.mdx +312 -0
  422. package/templates/content/en/HomePage/home.schema.json +88 -0
  423. package/templates/content/en/HomePage/launch-service.mdx +475 -0
  424. package/templates/content/en/HomePage/launch-service.schema.json +138 -0
  425. package/templates/content/en/HowTo/add-mdx-content.mdx +38 -0
  426. package/templates/content/en/HowTo/configure-aeo-scoring.mdx +35 -0
  427. package/templates/content/en/HowTo/set-up-json-ld.mdx +36 -0
  428. package/templates/content/en/Integration/github-actions.mdx +31 -0
  429. package/templates/content/en/Integration/openai-api.mdx +26 -0
  430. package/templates/content/en/Integration/vercel.mdx +32 -0
  431. package/templates/content/en/IntegrationsList/integrations.mdx +22 -0
  432. package/templates/content/en/JobPosting/content-strategist.mdx +46 -0
  433. package/templates/content/en/JobPosting/developer-advocate.mdx +47 -0
  434. package/templates/content/en/JobPosting/senior-fullstack-engineer.mdx +57 -0
  435. package/templates/content/en/LandingPage/aeo-audit.mdx +19 -0
  436. package/templates/content/en/LandingPage/aeo-audit.schema.json +92 -0
  437. package/templates/content/en/LandingPage/agency-waitlist.mdx +340 -0
  438. package/templates/content/en/LandingPage/agency-waitlist.schema.json +152 -0
  439. package/templates/content/en/LandingPage/developers.mdx +19 -0
  440. package/templates/content/en/LandingPage/developers.schema.json +109 -0
  441. package/templates/content/en/LandingPage/for-agencies.mdx +390 -0
  442. package/templates/content/en/LandingPage/for-agencies.schema.json +107 -0
  443. package/templates/content/en/LandingPage/for-ai-search-agencies.mdx +417 -0
  444. package/templates/content/en/LandingPage/for-ai-search-agencies.schema.json +105 -0
  445. package/templates/content/en/LandingPage/for-businesses.mdx +19 -0
  446. package/templates/content/en/LandingPage/for-businesses.schema.json +96 -0
  447. package/templates/content/en/LandingPage/platform.mdx +369 -0
  448. package/templates/content/en/LandingPage/platform.schema.json +166 -0
  449. package/templates/content/en/LandingPage/vs-ai-website-builders.mdx +19 -0
  450. package/templates/content/en/LandingPage/vs-ai-website-builders.schema.json +102 -0
  451. package/templates/content/en/LandingPage/vs-wordpress.mdx +19 -0
  452. package/templates/content/en/LandingPage/vs-wordpress.schema.json +53 -0
  453. package/templates/content/en/NewsletterSignup/newsletter.mdx +236 -0
  454. package/templates/content/en/NewsletterSignup/newsletter.schema.json +91 -0
  455. package/templates/content/en/Organization/site-owner.mdx +16 -0
  456. package/templates/content/en/Partner/prisma.mdx +31 -0
  457. package/templates/content/en/Partner/supabase.mdx +30 -0
  458. package/templates/content/en/Partner/vercel.mdx +28 -0
  459. package/templates/content/en/PartnersList/partners.mdx +22 -0
  460. package/templates/content/en/Person/founder.mdx +18 -0
  461. package/templates/content/en/Pricing/pricing.mdx +538 -0
  462. package/templates/content/en/Pricing/pricing.schema.json +209 -0
  463. package/templates/content/en/PrivacyPage/privacy.mdx +165 -0
  464. package/templates/content/en/PrivacyPage/privacy.schema.json +64 -0
  465. package/templates/content/en/Product/ailk.mdx +19 -0
  466. package/templates/content/en/Product/ailk.schema.json +94 -0
  467. package/templates/content/en/Product/api-launch-kit.mdx +26 -0
  468. package/templates/content/en/Product/launch-kit.mdx +28 -0
  469. package/templates/content/en/ProductsList/products.mdx +26 -0
  470. package/templates/content/en/Project/ailk-phase-2.mdx +54 -0
  471. package/templates/content/en/ProjectsList/projects.mdx +25 -0
  472. package/templates/content/en/ResourceDetail/aeo-scoring-guide.mdx +27 -0
  473. package/templates/content/en/ResourceDetail/content-model-whitepaper.mdx +28 -0
  474. package/templates/content/en/ResourceDetail/schema-org-quick-reference.mdx +39 -0
  475. package/templates/content/en/ResourcesHub/resources.mdx +22 -0
  476. package/templates/content/en/Service/consulting.mdx +22 -0
  477. package/templates/content/en/Service/implementation.mdx +30 -0
  478. package/templates/content/en/Service/launch-service.mdx +232 -0
  479. package/templates/content/en/Service/launch.mdx +228 -0
  480. package/templates/content/en/ServicesList/services.mdx +84 -0
  481. package/templates/content/en/SoftwareProduct/ailk-aeo.mdx +44 -0
  482. package/templates/content/en/SoftwareProduct/ailk-content-adapters.mdx +47 -0
  483. package/templates/content/en/SoftwareProduct/ailk-schema.mdx +49 -0
  484. package/templates/content/en/TeamList/team.mdx +63 -0
  485. package/templates/content/en/TeamMember/founder.mdx +72 -0
  486. package/templates/content/en/TermsPage/terms.mdx +19 -0
  487. package/templates/content/en/TermsPage/terms.schema.json +99 -0
  488. package/templates/content/en/TestimonialsList/testimonials.mdx +44 -0
  489. package/templates/content/en/UseCasesList/use-cases.mdx +30 -0
  490. package/templates/content/en/Whitepaper/ax-first-product-development.mdx +27 -0
  491. package/templates/content/en/Whitepaper/open-core-commercial-strategy.mdx +27 -0
  492. package/templates/content/en/Whitepaper/structured-data-for-answer-engines.mdx +31 -0
  493. package/templates/content/en-XA/AboutPage/about.mdx +8 -0
  494. package/templates/content/en-XA/FAQPage/faq.mdx +8 -0
  495. package/templates/content/en-XA/HomePage/home.mdx +8 -0
  496. package/templates/content/es/_site.mdx +30 -0
  497. package/templates/content/fr/_site.mdx +30 -0
  498. package/templates/content/ja/_site.mdx +30 -0
  499. package/templates/content/pt-BR/AboutPage/about.mdx +8 -0
  500. package/templates/content/pt-BR/FAQPage/faq.mdx +8 -0
  501. package/templates/content/pt-BR/HomePage/home.mdx +23 -0
  502. package/templates/database/CHANGELOG.md +5 -0
  503. package/templates/database/README.md +234 -0
  504. package/templates/database/__tests__/user-cascade.test.ts +125 -0
  505. package/templates/database/auth/.gitkeep +0 -0
  506. package/templates/database/config/.gitkeep +0 -0
  507. package/templates/database/content/.gitkeep +0 -0
  508. package/templates/database/inbox/.gitkeep +0 -0
  509. package/templates/database/inbox/README.md +3 -0
  510. package/templates/database/inbox/__tests__/schema.test.ts +40 -0
  511. package/templates/database/inbox/schema.prisma +52 -0
  512. package/templates/database/jest.config.cjs +29 -0
  513. package/templates/database/migrations/20260508000000_add_inbox_namespace/migration.sql +328 -0
  514. package/templates/database/migrations/20260513000000_better_auth_migration/migration.sql +100 -0
  515. package/templates/database/migrations/20260515000000_add_user_billing_fields/migration.sql +28 -0
  516. package/templates/database/migrations/20260516000000_add_user_tier_care_plan_seat/migration.sql +25 -0
  517. package/templates/database/migrations/20260518000000_add_telemetry_records/migration.sql +42 -0
  518. package/templates/database/migrations/20260525000000_theme_wiring/migration.sql +67 -0
  519. package/templates/database/migrations/20260710000000_retire_commercial_tier/migration.sql +21 -0
  520. package/templates/database/migrations/migration_lock.toml +3 -0
  521. package/templates/database/ops/.gitkeep +0 -0
  522. package/templates/database/package.json +45 -0
  523. package/templates/database/prisma.config.ts +20 -0
  524. package/templates/database/schema.prisma +487 -0
  525. package/templates/database/scripts/db-generate-locked.sh +80 -0
  526. package/templates/database/seed-test.ts +85 -0
  527. package/templates/database/tsconfig.build.json +16 -0
  528. package/templates/database/tsconfig.json +9 -0
  529. package/templates/package.json +125 -0
  530. package/templates/pnpm-workspace.yaml +6 -0
  531. package/templates/project.yaml +59 -0
  532. package/templates/tsconfig.base.json +18 -0
  533. package/templates/tsconfig.json +45 -0
@@ -0,0 +1,270 @@
1
+ ---
2
+ name: add-schema
3
+ description: Add or replace schema.org JSON-LD on an existing page in an AILK consumer site. Use when the user says "add Product schema to /pricing", "add FAQ to /contact", "put Service schema on this page", or otherwise wants schema attached to a page that already exists. Does NOT scaffold new pages — that's `scaffold-page` (#362). Type-aware conflict handling: replaces existing schema of the same `@type`, appends supplementary schema, asks on ambiguity.
4
+ ---
5
+
6
+ # add-schema
7
+
8
+ Inject schema.org JSON-LD into an existing page without re-scaffolding
9
+ the route. Pairs with `scaffold-page` (#362) — that skill creates new
10
+ pages, this one modifies existing ones. Both share the same `<JsonLd>`
11
+ attachment pattern from `@working-theory/jsonld`.
12
+
13
+ ## When to use
14
+
15
+ The consumer wants to add or update structured data on an existing
16
+ page. Triggers:
17
+
18
+ - "add Product schema to /pricing"
19
+ - "add FAQ to /contact" / "add an FAQ section schema to about"
20
+ - "put Service schema on this page"
21
+ - "swap out the Product schema on /pricing for a new one"
22
+
23
+ Skip this skill when:
24
+
25
+ - The consumer wants a **new page** — that's `scaffold-page` (#362).
26
+ This skill refuses on no-match and points at #362 explicitly.
27
+ - The consumer wants to **audit** schema coverage / validity —
28
+ that's `audit-site` (#365). Never invoked from here.
29
+ - The schema type isn't in `references/schema-types.md`. Ask the
30
+ consumer rather than guessing.
31
+
32
+ ## What this skill does
33
+
34
+ 1. Parse the consumer's input: extract the **schema type** (Product,
35
+ FAQ, Service, etc.) and the **target slug** (`/pricing`,
36
+ `/contact`).
37
+ 2. **Resolve the file.** Slug-pattern lookup against:
38
+ - App Router: `apps/web/app/<slug>/page.tsx` (or
39
+ `app/<slug>/page.tsx` depending on consumer layout).
40
+ - MDX content: `content/<Type>/<slug>.mdx` for any of the page
41
+ types in `@working-theory/schema`.
42
+ 3. **Refuse on zero matches.** Point at `scaffold-page` (#362).
43
+ 4. **Ask on multiple matches.** List route vs MDX (or multiple
44
+ MDX matches) and ask which to modify.
45
+ 5. **Detect existing `<JsonLd>` attachments** in the resolved file.
46
+ Use `references/conflict-handling.md` to decide:
47
+ - Same `@type` already present → **replace** (after confirming).
48
+ - Different `@type` (supplementary) already present → **append**.
49
+ - Existing JSON-LD is malformed / unparseable → **ask** for
50
+ clarification before writing.
51
+ 6. **Show the diff** in a single confirmation step. After approval,
52
+ write.
53
+ 7. **Validate** the modified file still parses cleanly (TS or MDX
54
+ syntax check). Surface failures with the literal parse error.
55
+
56
+ ## What this skill does NOT do
57
+
58
+ - Create new pages. Refuses + points at `scaffold-page` (#362).
59
+ - Validate schema.org rich-results against Google's Rich Results
60
+ Test or schema.org's own validator. The typed builder from
61
+ `@working-theory/schema` is the type-correctness contract; rich-results
62
+ validation is `audit-site` (#365)'s lane.
63
+ - Modify `packages/schema/` (read-only at v1). If a builder is
64
+ missing, surface and stop.
65
+ - Use a `<script>` tag, `metadata.other`, or hand-coded JSON
66
+ literals. The canonical attachment is always
67
+ `<JsonLd schema={builder(...)} />` from `@working-theory/jsonld` +
68
+ `@working-theory/schema`. This matches `scaffold-page` (#362) — the two
69
+ skills share one attachment pattern.
70
+ - Auto-invoke other skills.
71
+
72
+ ## The mechanic
73
+
74
+ ### Step 1 — Parse the input
75
+
76
+ Extract two things:
77
+
78
+ - **Schema type.** Match the consumer's words to a `@type` from
79
+ `references/schema-types.md`. "Product" → `Product`, "FAQ" →
80
+ `FAQPage`, "how-to" → `HowTo`, "Service" → `Service`. If
81
+ ambiguous (e.g., "review" could be `Review` or
82
+ `AggregateRating`), ask.
83
+ - **Target slug.** From phrases like "/pricing", "to /contact", "on
84
+ the about page". Drop the leading `/`. If the consumer says
85
+ "this page" without specifying, ask which page.
86
+
87
+ ### Step 2 — File resolution
88
+
89
+ Look in two places:
90
+
91
+ 1. **App Router route:** `apps/web/app/<slug>/page.tsx` (also try
92
+ `app/<slug>/page.tsx` for non-monorepo layouts).
93
+ 2. **MDX content:** scan `content/**/<slug>.mdx`. The frontmatter
94
+ `slug:` field is authoritative; filename is a fallback.
95
+
96
+ **Zero matches** — refuse:
97
+
98
+ > "I don't see a page at `/<slug>`. To **create** the page first,
99
+ > run `scaffold-page` (#362). Once it exists, come back here to add
100
+ > additional schema."
101
+
102
+ Stop. No writes.
103
+
104
+ **One match** — proceed to Step 3.
105
+
106
+ **Multiple matches** — list and ask:
107
+
108
+ > "Found multiple files for `/<slug>`:
109
+ >
110
+ > - `apps/web/app/<slug>/page.tsx` (App Router route)
111
+ > - `content/Product/<slug>.mdx` (MDX content)
112
+ >
113
+ > Which one should I modify?"
114
+
115
+ Wait for the consumer's choice.
116
+
117
+ ### Step 3 — Detect existing attachments
118
+
119
+ In the resolved file, look for `<JsonLd schema={...} />` JSX
120
+ elements. The canonical pattern emits one of these per attached
121
+ schema. Two states matter:
122
+
123
+ - **Same `@type` already present.** Example: consumer wants to add
124
+ `Product` schema to `/pricing`, and the file already has
125
+ `<JsonLd schema={buildProduct(...)} />`. This is a **replace**
126
+ case (Step 4).
127
+ - **Different `@type` already present.** Example: file has
128
+ `<JsonLd schema={buildOrganization(...)} />` and consumer wants
129
+ to add `FAQPage`. This is an **append** case (Step 5).
130
+
131
+ If existing JSON-LD is **malformed or unrecognized** (raw `<script
132
+ type="application/ld+json">` block, hand-coded literal not
133
+ matching a builder, malformed JSX), do not silently rewrite. Ask:
134
+
135
+ > "I see existing structured data on this page that wasn't created
136
+ > by the canonical `<JsonLd schema={builder(...)} />` pattern. I
137
+ > can:
138
+ >
139
+ > - Add my new schema alongside (no conflict — different
140
+ > attachment style).
141
+ > - Replace what's there with the canonical pattern + my new
142
+ > schema (clean migration).
143
+ > - Cancel — leave the file alone.
144
+ >
145
+ > Which?"
146
+
147
+ ### Step 4 — Conflict handling: replace (same `@type`)
148
+
149
+ When the same `@type` is already attached, the default is
150
+ **replace**. Confirm:
151
+
152
+ > "`<Type>` schema is already attached to `/<slug>`. I'll replace
153
+ > it with the new one — confirm or cancel."
154
+
155
+ After approval, locate the existing `<JsonLd>` JSX, swap the
156
+ `schema={...}` expression. Keep surrounding code (imports, other
157
+ JSX, exports) untouched.
158
+
159
+ ### Step 5 — Conflict handling: append (different `@type`)
160
+
161
+ When the new schema is a different `@type` from existing
162
+ attachments, the default is **append**. Show the diff:
163
+
164
+ > "Your page already has `<Organization>` schema. I'll add an
165
+ > `<FAQPage>` block next to it — confirm or cancel."
166
+
167
+ After approval, add a new `<JsonLd schema={buildFAQPage(...)} />`
168
+ JSX element next to the existing one(s). Add the import for the
169
+ new builder if not already imported.
170
+
171
+ ### Step 6 — Type-aware classification
172
+
173
+ `references/schema-types.md` tags each of the 45 schema.org types
174
+ in `@working-theory/schema` as **primary** or **supplementary**:
175
+
176
+ - **Primary** types are typically one-per-page: `HomePage`,
177
+ `AboutPage`, `BlogPosting`, `Product`, `Service`. A page rarely
178
+ has two `Product` schemas.
179
+ - **Supplementary** types stack naturally: `FAQPage`, `HowTo`,
180
+ `BreadcrumbList`, `Review`, `AggregateRating`. A single product
181
+ page might have `Product` + `FAQPage` + `Review` + `BreadcrumbList`.
182
+
183
+ Default behavior:
184
+
185
+ - Adding a **primary** type → if same type already present, replace.
186
+ - Adding a **supplementary** type → always append; never replace
187
+ (you'd lose information).
188
+
189
+ The classification is read-only at v1 — the skill knows the table,
190
+ but does not write to `packages/schema/`. Future PR may move
191
+ classification into the package.
192
+
193
+ ### Step 7 — Show the diff + confirm
194
+
195
+ Single confirmation message:
196
+
197
+ > "Adding `<Type>` schema to `<filepath>`:
198
+ >
199
+ > ```diff
200
+ > + import { buildType } from "@working-theory/schema";
201
+ > ...
202
+ > + <JsonLd schema={buildType({ ... })} />
203
+ > ```
204
+ >
205
+ > Confirm to write, or tell me what to adjust."
206
+
207
+ Wait for approval. Do not write per-step.
208
+
209
+ ### Step 8 — Write + validate
210
+
211
+ Write the modified file atomically. After write, validate the file
212
+ still parses:
213
+
214
+ - For `.tsx` routes: run a TS parse check on the modified file
215
+ (parse only — full type-check is the consumer's `pnpm
216
+ type-check` job).
217
+ - For `.mdx` content: run an MDX parse check.
218
+
219
+ If parse fails, surface the literal error and revert the write:
220
+
221
+ > "After writing, the file no longer parses cleanly:
222
+ >
223
+ > ```
224
+ > <verbatim parse error>
225
+ > ```
226
+ >
227
+ > I've reverted the change. Try a different approach, or hand-edit
228
+ > the file."
229
+
230
+ If parse succeeds, print a closing summary:
231
+
232
+ > "Added `<Type>` schema to `<filepath>`. Run `pnpm dev` to verify
233
+ > the page renders, or `audit-site` (#365) to check
234
+ > citation-readiness."
235
+
236
+ ## Type-by-name recognition
237
+
238
+ The skill recognizes all 45 schema types in `@working-theory/schema` by name.
239
+ Common aliases (e.g., "FAQ" → `FAQPage`, "how-to" → `HowTo`,
240
+ "review" → `Review`) are handled in `references/schema-types.md`.
241
+ If the consumer asks for a type not in the catalog, surface and
242
+ ask:
243
+
244
+ > "I don't see `<requested type>` in the v1 schema catalog. The 45
245
+ > recognized types are listed in `references/schema-types.md` —
246
+ > closest matches are `<X>` and `<Y>`. Use one of those, or hand-
247
+ > author the JSON-LD inline if you need a less-common type."
248
+
249
+ ## References
250
+
251
+ - `references/schema-types.md` — the 45 schema.org types from
252
+ `@working-theory/schema`, each tagged primary or supplementary, with
253
+ human-friendly aliases.
254
+ - `references/file-finding.md` — slug-to-file resolution rules
255
+ (App Router + MDX).
256
+ - `references/conflict-handling.md` — full decision tree for
257
+ replace / append / ask.
258
+
259
+ ## Coordination
260
+
261
+ - **`scaffold-page` (#362)** — creates new pages. This skill
262
+ modifies existing ones. Same `<JsonLd>` attachment pattern.
263
+ - **`audit-site` (#365)** — citation-readiness check. Never
264
+ invoked from inside this skill; the audit reports, this fix
265
+ tool fixes.
266
+ - **`@working-theory/jsonld` (#389)** — the React component for JSON-LD
267
+ rendering. Single source of truth for the attachment pattern.
268
+ - **`@working-theory/schema`** — typed builders + `JsonLdObject` output.
269
+ Read-only at v1; `references/schema-types.md` is the skill's
270
+ copy of the catalog.
@@ -0,0 +1,200 @@
1
+ # Conflict Handling — Replace / Append / Ask
2
+
3
+ When `add-schema` is asked to attach a schema to a page that
4
+ already has JSON-LD, the resolution depends on (a) whether the
5
+ incoming type is **primary** or **supplementary** per
6
+ `references/schema-types.md`, and (b) what's already there.
7
+
8
+ This file is the decision tree the skill applies in Steps 4–5 of
9
+ the SKILL.md mechanic.
10
+
11
+ ## The decision tree
12
+
13
+ ```
14
+ ┌─────────────────────────────────┐
15
+ │ New schema — type T, page P │
16
+ └─────────────────┬───────────────┘
17
+
18
+ ┌────────────────────────────────────┐
19
+ │ Existing JSON-LD on page P? │
20
+ └─┬─────────────────┬────────────────┘
21
+ │ │
22
+ No│ Yes│
23
+ ▼ ▼
24
+ ┌──────────┐ ┌─────────────────────────────┐
25
+ │ APPEND │ │ Existing schema parseable? │
26
+ │ (first │ │ (canonical <JsonLd> │
27
+ │ attach) │ │ pattern only) │
28
+ └──────────┘ └──┬──────────────┬───────────┘
29
+ │ │
30
+ No│ Yes│
31
+ ▼ ▼
32
+ ┌────────────┐ ┌──────────────────────┐
33
+ │ ASK │ │ Same @type as T? │
34
+ │ (consumer │ └──┬────────────────┬──┘
35
+ │ decides: │ │ │
36
+ │ alongside │ Yes│ No│
37
+ │ / │ ▼ ▼
38
+ │ migrate / │ ┌─────────────┐ ┌──────────────────┐
39
+ │ cancel) │ │ T is │ │ APPEND │
40
+ └────────────┘ │ primary? │ │ (different types │
41
+ └─┬───────┬───┘ │ always stack) │
42
+ │ │ └──────────────────┘
43
+ Yes│ No│
44
+ ▼ ▼
45
+ ┌──────────┐ ┌──────────┐
46
+ │ REPLACE │ │ APPEND │
47
+ │ (after │ │ (supp. │
48
+ │ confirm) │ │ stacks) │
49
+ └──────────┘ └──────────┘
50
+ ```
51
+
52
+ ## Case-by-case
53
+
54
+ ### Case 1 — No existing JSON-LD
55
+
56
+ **Action:** APPEND (first attachment).
57
+
58
+ Add the import line + `<JsonLd>` JSX element. Confirm via Step 7
59
+ diff before write. This is the simplest path.
60
+
61
+ ### Case 2 — Existing JSON-LD, same `@type`, primary type
62
+
63
+ **Action:** REPLACE (after confirming).
64
+
65
+ Example: page has `<JsonLd schema={buildProduct(oldProduct)}/>`,
66
+ consumer asks to add `Product` schema. The new `Product` replaces
67
+ the old one — locating the existing JSX, swapping the
68
+ `schema={…}` expression.
69
+
70
+ Confirmation message:
71
+
72
+ > "`Product` schema is already attached to `/<slug>`. I'll replace
73
+ > it with the new one. The old expression
74
+ > `buildProduct(oldProduct)` becomes
75
+ > `buildProduct(newProduct)` — confirm or cancel."
76
+
77
+ ### Case 3 — Existing JSON-LD, same `@type`, supplementary type
78
+
79
+ **Action:** APPEND (supplementary stacks).
80
+
81
+ This is rare but valid. Example: page has `<JsonLd
82
+ schema={buildReview(review1)}/>`, consumer asks to add another
83
+ `Review`. Reviews can stack — append a second `<JsonLd>` element
84
+ rather than replacing.
85
+
86
+ If unsure whether the consumer meant replace or append, ask:
87
+
88
+ > "There's already a `Review` schema on this page. I can:
89
+ >
90
+ > - Add a second `Review` (stack — both visible in
91
+ > structured data).
92
+ > - Replace the existing one (only the new review is visible).
93
+ >
94
+ > Which?"
95
+
96
+ ### Case 4 — Existing JSON-LD, different `@type`
97
+
98
+ **Action:** APPEND.
99
+
100
+ Example: page has `<JsonLd schema={buildOrganization(...)}/>`,
101
+ consumer asks to add `FAQPage`. Different types always stack — add
102
+ a new `<JsonLd>` element next to the existing one.
103
+
104
+ This is the most common case for supplementary types
105
+ (`FAQPage`, `HowTo`, `BreadcrumbList`, `Review`,
106
+ `AggregateRating`).
107
+
108
+ ### Case 5 — Existing JSON-LD is non-canonical
109
+
110
+ **Action:** ASK.
111
+
112
+ Triggers when the existing structured data:
113
+
114
+ - Uses a raw `<script type="application/ld+json">` block.
115
+ - Uses a hand-coded JSON literal (no builder import).
116
+ - Uses `metadata.other` in `generateMetadata`.
117
+ - Has `<JsonLd>` JSX with a `schema` prop that doesn't match a
118
+ recognized builder call.
119
+
120
+ The skill must not silently rewrite. Ask:
121
+
122
+ > "I see existing structured data on this page that wasn't
123
+ > created by the canonical `<JsonLd schema={builder(...)}/>`
124
+ > pattern. I can:
125
+ >
126
+ > - **Add alongside** — leave the existing data, add my new
127
+ > schema as a separate `<JsonLd>` element.
128
+ > - **Migrate to canonical** — replace the existing structured
129
+ > data with the canonical pattern, then add my new schema.
130
+ > - **Cancel** — leave the file alone.
131
+ >
132
+ > Which?"
133
+
134
+ Wait for choice. The "migrate to canonical" path is the deepest —
135
+ it requires parsing the existing JSON-LD object literal,
136
+ inferring the builder, and rewriting. Don't attempt unless the
137
+ consumer explicitly chooses migrate.
138
+
139
+ ### Case 6 — Existing JSON-LD is malformed / unparseable
140
+
141
+ **Action:** ASK with a stronger refuse-default.
142
+
143
+ Triggers when the file's JSON-LD block can't be parsed at all (broken
144
+ JSX, malformed JSON literal, syntax error). The default is **don't
145
+ touch the existing data**:
146
+
147
+ > "There's existing JSON-LD on this page that doesn't parse
148
+ > cleanly. I shouldn't rewrite it without you seeing what's
149
+ > there. I can:
150
+ >
151
+ > - **Add alongside** — append my new schema as a separate
152
+ > `<JsonLd>` element. Existing broken data stays as-is (you
153
+ > fix it later).
154
+ > - **Cancel** — open the file yourself, fix the existing
155
+ > block, then re-run this skill.
156
+ >
157
+ > Recommended: cancel and fix the existing data first."
158
+
159
+ ## Identity-on-non-home-page edge case
160
+
161
+ If the consumer asks to attach `Organization`, `Person`, or
162
+ another identity type (per `references/schema-types.md`) to a
163
+ **non-home** page, surface a flag:
164
+
165
+ > "`Organization` is typically a site-wide identity emitted in
166
+ > the layout (so it appears on every page). Adding it to one
167
+ > page means only that page surfaces the entity. Continue, or
168
+ > add it to your layout instead?"
169
+
170
+ Wait for the consumer's choice. If they continue, proceed
171
+ through the normal decision tree. If they want to add to the
172
+ layout, point at `apps/web/app/layout.tsx` and stop —
173
+ modifying the layout is outside this skill's lane.
174
+
175
+ ## Validation after write
176
+
177
+ Regardless of replace / append, after the write the file must
178
+ still parse:
179
+
180
+ - For `.tsx`: TS parse check (parse only, not full type-check).
181
+ - For `.mdx`: MDX parse check.
182
+
183
+ If parse fails, revert the write and surface the literal parse
184
+ error per SKILL.md Step 8.
185
+
186
+ ## Why this complexity exists
187
+
188
+ Type-aware conflict handling is what separates `add-schema` from
189
+ "just append every time." The two cases that drive the
190
+ complexity:
191
+
192
+ - A consumer iterating on `Product` schema (Case 2) expects
193
+ replacement, not stacking — duplicate `Product` schemas hurt
194
+ citation more than help.
195
+ - A consumer adding `FAQPage` to a `Product` page (Case 4) wants
196
+ both — `Product` is the page's identity, `FAQPage` adds
197
+ question/answer dimensions. Stacking is correct.
198
+
199
+ The decision tree above codifies the difference once so the
200
+ skill applies it consistently.
@@ -0,0 +1,123 @@
1
+ # File-Finding — Slug → File Resolution
2
+
3
+ The `add-schema` skill resolves a slug like `/pricing` to one or
4
+ more files in the consumer's repo. This file is the source of
5
+ truth for the resolution logic the skill applies in Step 2.
6
+
7
+ ## The two locations to scan
8
+
9
+ A slug can map to either (or both) of:
10
+
11
+ 1. **App Router route file.**
12
+ - Primary: `apps/web/app/<slug>/page.tsx` (monorepo layout, the
13
+ AILK default).
14
+ - Fallback: `app/<slug>/page.tsx` (standalone Next.js app at
15
+ repo root).
16
+ - Slug supports nested paths: `/products/widget` →
17
+ `app/products/widget/page.tsx`.
18
+ - The `[slug]` dynamic-route convention is also valid: `/blog/foo`
19
+ can map to `app/blog/[slug]/page.tsx`. The skill recognizes
20
+ both static and dynamic route files; for dynamic routes, it
21
+ modifies the route handler itself (not the dynamic instance).
22
+
23
+ 2. **MDX content file.**
24
+ - Scan: `content/**/<slug>.mdx`.
25
+ - The frontmatter `slug:` field is **authoritative** when
26
+ present. Filename match is a fallback.
27
+ - Multi-type content folders: a slug can live in
28
+ `content/Product/widget.mdx` or
29
+ `content/BlogPosting/widget.mdx`. The frontmatter `type:`
30
+ field disambiguates.
31
+
32
+ ## Match outcomes
33
+
34
+ ### Zero matches
35
+
36
+ Refuse with a clear pointer:
37
+
38
+ > "No page exists at `/<slug>`. Use `scaffold-page` (#362) to
39
+ > create one first; come back here once it exists to add
40
+ > additional schema."
41
+
42
+ Do not write anything.
43
+
44
+ ### One match
45
+
46
+ Proceed. Show the consumer which file you'll modify in Step 7's
47
+ diff so they can confirm the path before any write.
48
+
49
+ ### Multiple matches
50
+
51
+ List and ask. Common multi-match shapes:
52
+
53
+ - **Route + MDX coexistence.** Many AILK pages have both a
54
+ `apps/web/app/<slug>/page.tsx` (renderer) and a
55
+ `content/<Type>/<slug>.mdx` (data). The route renders the MDX —
56
+ schema can attach in either:
57
+ - Attaching in the route puts JSON-LD in JSX.
58
+ - Attaching in the MDX puts JSON-LD inline in content.
59
+ - The canonical AILK pattern emits via the route (the route
60
+ imports `<JsonLd schema={builder(page)}/>` and reads frontmatter
61
+ via the content adapter). When in doubt, modify the route.
62
+
63
+ - **Multiple MDX files for the same slug.** Rare; usually means
64
+ the consumer has organized content by `type/` and the same slug
65
+ appears in different type folders. List all matches with their
66
+ `type:` frontmatter and ask which one the consumer means.
67
+
68
+ - **Static + dynamic route ambiguity.** If both `app/<slug>/page.tsx`
69
+ and `app/<slug>/[child]/page.tsx` exist, only the static
70
+ `<slug>/page.tsx` is the target — the dynamic file handles
71
+ child routes, not the index.
72
+
73
+ Ask the consumer plainly:
74
+
75
+ > "Found multiple files for `/<slug>`:
76
+ >
77
+ > - `apps/web/app/<slug>/page.tsx` — App Router route
78
+ > - `content/Product/<slug>.mdx` — MDX content
79
+ >
80
+ > Where should I attach the schema? (Recommended: route, since
81
+ > JSON-LD belongs in the rendered output.)"
82
+
83
+ Wait for the consumer's choice.
84
+
85
+ ## What the skill does NOT touch
86
+
87
+ - **Layout files.** `apps/web/app/layout.tsx` is the right place
88
+ for site-wide identity schema (`Organization` / `Person`). If
89
+ the consumer asks to add identity schema to a leaf page, the
90
+ skill flags this and asks (per `references/schema-types.md`).
91
+ - **`globals.css`, `metadata.ts`, `route.ts`** — these aren't
92
+ where JSON-LD lives. The skill scans only `page.tsx` and
93
+ `*.mdx` for slug-pattern matches.
94
+ - **`packages/schema/`** — read-only at v1 (per the issue scope).
95
+ The skill imports from `@working-theory/schema` but never modifies it.
96
+
97
+ ## Edge case — non-MDX content backend
98
+
99
+ If the consumer's project uses a non-MDX adapter (Sanity, Payload,
100
+ or any other), the MDX scan returns nothing. The skill still tries
101
+ the App Router route file. If the route exists, attaching schema
102
+ there works regardless of where the page's content data lives.
103
+
104
+ If the consumer wants schema attached **to content** (not the
105
+ route) and they're on a non-MDX backend, this skill at v1 says:
106
+
107
+ > "Your content backend isn't MDX. JSON-LD attachment in
108
+ > non-MDX backends ships in a future PR. For now, attach the
109
+ > schema to the route file (`app/<slug>/page.tsx`) — that's
110
+ > rendered server-side and works regardless of content adapter."
111
+
112
+ ## Validation after resolution
113
+
114
+ Before any write, the skill confirms the resolved file is one of:
115
+
116
+ - `.tsx` (App Router page) — must contain `export default
117
+ function … Page()`.
118
+ - `.mdx` (content file) — must have frontmatter delimiters
119
+ (`---`).
120
+
121
+ If the file at the resolved path doesn't match one of those
122
+ shapes, the skill surfaces the mismatch and stops. Don't write to
123
+ a file you can't recognize.