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.
- package/LICENSE +201 -0
- package/README.md +39 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +80 -0
- package/dist/copy.d.ts +8 -0
- package/dist/copy.js +109 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +10 -0
- package/dist/lib/pro-callout.d.ts +12 -0
- package/dist/lib/pro-callout.js +20 -0
- package/dist/parse-args.d.ts +13 -0
- package/dist/parse-args.js +81 -0
- package/dist/programmatic.d.ts +49 -0
- package/dist/programmatic.js +89 -0
- package/dist/substitute.d.ts +31 -0
- package/dist/substitute.js +45 -0
- package/dist/validate.d.ts +8 -0
- package/dist/validate.js +70 -0
- package/package.json +47 -0
- package/templates/.claude/.gitkeep +0 -0
- package/templates/.claude/agents/web.md +80 -0
- package/templates/.claude/rules/architecture.md +62 -0
- package/templates/.claude/rules/preserve-existing-style.md +51 -0
- package/templates/.claude/skills/README.md +43 -0
- package/templates/.claude/skills/add-schema/SKILL.md +270 -0
- package/templates/.claude/skills/add-schema/references/conflict-handling.md +200 -0
- package/templates/.claude/skills/add-schema/references/file-finding.md +123 -0
- package/templates/.claude/skills/add-schema/references/schema-types.md +131 -0
- package/templates/.claude/skills/audit-site/SKILL.md +213 -0
- package/templates/.claude/skills/audit-site/references/common-errors.md +113 -0
- package/templates/.claude/skills/audit-site/references/findings-glossary.md +138 -0
- package/templates/.claude/skills/audit-site/references/severity-levels.md +114 -0
- package/templates/.claude/skills/provision-config/SKILL.md +243 -0
- package/templates/.claude/skills/provision-config/references/env-vars-template.md +184 -0
- package/templates/.claude/skills/provision-config/references/runbook-template.md +248 -0
- package/templates/.claude/skills/provision-config/references/vercel-json-template.md +98 -0
- package/templates/.claude/skills/scaffold-auth/SKILL.md +261 -0
- package/templates/.claude/skills/scaffold-auth/references/env-vars.md +91 -0
- package/templates/.claude/skills/scaffold-auth/references/oauth-app-setup.md +171 -0
- package/templates/.claude/skills/scaffold-commerce/SKILL.md +310 -0
- package/templates/.claude/skills/scaffold-commerce/references/lookup-keys-template.md +71 -0
- package/templates/.claude/skills/scaffold-commerce/references/marketplace-brand-pages.md +83 -0
- package/templates/.claude/skills/scaffold-commerce/templates/marketplace-cta-route.tsx.tmpl +72 -0
- package/templates/.claude/skills/scaffold-page/SKILL.md +243 -0
- package/templates/.claude/skills/scaffold-page/references/page-types.md +169 -0
- package/templates/.claude/skills/scaffold-page/templates/content.mdx.tmpl +28 -0
- package/templates/.claude/skills/scaffold-page/templates/route.tsx.tmpl +28 -0
- package/templates/.claude/skills/suggest-site-pages/SKILL.md +242 -0
- package/templates/.claude/skills/suggest-site-pages/references/categories.md +287 -0
- package/templates/.env.example +205 -0
- package/templates/.gitkeep +2 -0
- package/templates/CLAUDE.md +142 -0
- package/templates/CONVENTIONS.md +222 -0
- package/templates/README.md +110 -0
- package/templates/apps/api/.env.example +40 -0
- package/templates/apps/api/CLAUDE.md +63 -0
- package/templates/apps/api/api/index.ts +144 -0
- package/templates/apps/api/jest.config.cjs +74 -0
- package/templates/apps/api/package.json +54 -0
- package/templates/apps/api/src/__tests__/factories/content-fixture.ts +138 -0
- package/templates/apps/api/src/__tests__/factories/index.ts +70 -0
- package/templates/apps/api/src/__tests__/factories/lead-fixture.ts +82 -0
- package/templates/apps/api/src/__tests__/index.test.ts +118 -0
- package/templates/apps/api/src/__tests__/server.test.ts +207 -0
- package/templates/apps/api/src/__tests__/services/enrichment-shim.test.ts +126 -0
- package/templates/apps/api/src/__tests__/setup.ts +24 -0
- package/templates/apps/api/src/cli.ts +30 -0
- package/templates/apps/api/src/config/__tests__/index.test.ts +97 -0
- package/templates/apps/api/src/config/index.ts +56 -0
- package/templates/apps/api/src/index.ts +32 -0
- package/templates/apps/api/src/lib/__mocks__/prisma-client.js +15 -0
- package/templates/apps/api/src/lib/__mocks__/prisma.ts +45 -0
- package/templates/apps/api/src/lib/__tests__/content-adapter.test.ts +178 -0
- package/templates/apps/api/src/lib/__tests__/error-serializer.test.ts +100 -0
- package/templates/apps/api/src/lib/__tests__/errors.test.ts +94 -0
- package/templates/apps/api/src/lib/__tests__/file-fallback.test.ts +144 -0
- package/templates/apps/api/src/lib/__tests__/fixtures/HomePage/home.mdx +8 -0
- package/templates/apps/api/src/lib/__tests__/lead-capture-store.test.ts +227 -0
- package/templates/apps/api/src/lib/__tests__/outbound-http.test.ts +125 -0
- package/templates/apps/api/src/lib/__tests__/prisma.test.ts +165 -0
- package/templates/apps/api/src/lib/__tests__/require-paid-tier.test.ts +129 -0
- package/templates/apps/api/src/lib/__tests__/stripe.test.ts +74 -0
- package/templates/apps/api/src/lib/content-adapter.ts +86 -0
- package/templates/apps/api/src/lib/error-serializer.ts +77 -0
- package/templates/apps/api/src/lib/errors.ts +95 -0
- package/templates/apps/api/src/lib/file-fallback.ts +87 -0
- package/templates/apps/api/src/lib/lead-capture-store.ts +110 -0
- package/templates/apps/api/src/lib/locales.ts +201 -0
- package/templates/apps/api/src/lib/outbound-http.ts +122 -0
- package/templates/apps/api/src/lib/prisma.ts +21 -0
- package/templates/apps/api/src/lib/require-paid-tier.ts +53 -0
- package/templates/apps/api/src/lib/stripe.ts +30 -0
- package/templates/apps/api/src/lib/webhook-idempotency.ts +92 -0
- package/templates/apps/api/src/middleware/__tests__/adversarial/bearer-token-format.test.ts +111 -0
- package/templates/apps/api/src/middleware/__tests__/adversarial/cookie-or-bearer-precedence.test.ts +172 -0
- package/templates/apps/api/src/middleware/__tests__/adversarial/csrf-bearer-skip.test.ts +119 -0
- package/templates/apps/api/src/middleware/__tests__/adversarial/csrf-cookie-path.test.ts +138 -0
- package/templates/apps/api/src/middleware/__tests__/adversarial/session-fixation.test.ts +149 -0
- package/templates/apps/api/src/middleware/__tests__/adversarial/session-timeout.test.ts +139 -0
- package/templates/apps/api/src/middleware/__tests__/auth.bearer-path.test.ts +175 -0
- package/templates/apps/api/src/middleware/__tests__/auth.both-present-precedence.test.ts +76 -0
- package/templates/apps/api/src/middleware/__tests__/auth.cookie-path.test.ts +153 -0
- package/templates/apps/api/src/middleware/__tests__/auth.neither-present.test.ts +72 -0
- package/templates/apps/api/src/middleware/__tests__/rate-limit.test.ts +292 -0
- package/templates/apps/api/src/middleware/auth.ts +246 -0
- package/templates/apps/api/src/middleware/rate-limit.ts +132 -0
- package/templates/apps/api/src/openapi/__tests__/openapi.test.ts +129 -0
- package/templates/apps/api/src/openapi/index.ts +12 -0
- package/templates/apps/api/src/openapi/spec.ts +408 -0
- package/templates/apps/api/src/routes/auth/__tests__/auth-tokens.functional.test.ts +193 -0
- package/templates/apps/api/src/routes/auth/__tests__/auth-user.functional.test.ts +201 -0
- package/templates/apps/api/src/routes/auth/__tests__/tokens.test.ts +294 -0
- package/templates/apps/api/src/routes/auth/__tests__/user.test.ts +486 -0
- package/templates/apps/api/src/routes/auth/tokens.ts +199 -0
- package/templates/apps/api/src/routes/auth/user.ts +244 -0
- package/templates/apps/api/src/routes/checkout/__tests__/sessions.test.ts +588 -0
- package/templates/apps/api/src/routes/checkout/index.ts +13 -0
- package/templates/apps/api/src/routes/checkout/sessions.ts +185 -0
- package/templates/apps/api/src/routes/content/__tests__/create.test.ts +239 -0
- package/templates/apps/api/src/routes/content/__tests__/delete.test.ts +201 -0
- package/templates/apps/api/src/routes/content/__tests__/get-page.test.ts +141 -0
- package/templates/apps/api/src/routes/content/__tests__/list-pages.test.ts +122 -0
- package/templates/apps/api/src/routes/content/__tests__/list-types.test.ts +44 -0
- package/templates/apps/api/src/routes/content/__tests__/locale.test.ts +118 -0
- package/templates/apps/api/src/routes/content/__tests__/rate-limit.test.ts +51 -0
- package/templates/apps/api/src/routes/content/__tests__/update.test.ts +252 -0
- package/templates/apps/api/src/routes/content/create.ts +114 -0
- package/templates/apps/api/src/routes/content/delete.ts +81 -0
- package/templates/apps/api/src/routes/content/get-page.ts +98 -0
- package/templates/apps/api/src/routes/content/index.ts +32 -0
- package/templates/apps/api/src/routes/content/list-pages.ts +83 -0
- package/templates/apps/api/src/routes/content/list-types.ts +19 -0
- package/templates/apps/api/src/routes/content/rate-limit.ts +13 -0
- package/templates/apps/api/src/routes/content/slug.ts +9 -0
- package/templates/apps/api/src/routes/content/update.ts +111 -0
- package/templates/apps/api/src/routes/leads/__tests__/index.test.ts +415 -0
- package/templates/apps/api/src/routes/leads/__tests__/track.test.ts +165 -0
- package/templates/apps/api/src/routes/leads/index.ts +130 -0
- package/templates/apps/api/src/routes/test/auth/__tests__/session.test.ts +296 -0
- package/templates/apps/api/src/routes/test/auth/session.ts +141 -0
- package/templates/apps/api/src/routes/webhooks/README.md +57 -0
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-idempotency.test.ts +247 -0
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-rate-limit.test.ts +198 -0
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe.test.ts +633 -0
- package/templates/apps/api/src/routes/webhooks/index.ts +41 -0
- package/templates/apps/api/src/routes/webhooks/stripe.ts +253 -0
- package/templates/apps/api/src/server.ts +157 -0
- package/templates/apps/api/src/services/__tests__/lead-routing.test.ts +395 -0
- package/templates/apps/api/src/services/enrichment-shim.ts +53 -0
- package/templates/apps/api/src/services/lead-routing.ts +338 -0
- package/templates/apps/api/tsconfig.json +34 -0
- package/templates/apps/api/vercel.json +17 -0
- package/templates/apps/mcp/.env.example +52 -0
- package/templates/apps/mcp/CLAUDE.md +84 -0
- package/templates/apps/mcp/__tests__/abuse/daily-cap.test.ts +52 -0
- package/templates/apps/mcp/__tests__/abuse/email-validator.test.ts +46 -0
- package/templates/apps/mcp/__tests__/abuse/honeypot.test.ts +36 -0
- package/templates/apps/mcp/__tests__/abuse/user-agent-deny.test.ts +54 -0
- package/templates/apps/mcp/__tests__/aeo-cli-parity.test.ts +110 -0
- package/templates/apps/mcp/__tests__/audit-single-page.test.ts +213 -0
- package/templates/apps/mcp/__tests__/audit.test.ts +217 -0
- package/templates/apps/mcp/__tests__/catalog-drift.test.ts +52 -0
- package/templates/apps/mcp/__tests__/create_page.test.ts +201 -0
- package/templates/apps/mcp/__tests__/delete_page.test.ts +176 -0
- package/templates/apps/mcp/__tests__/get_business_hours.test.ts +82 -0
- package/templates/apps/mcp/__tests__/get_faq.test.ts +80 -0
- package/templates/apps/mcp/__tests__/get_locations.test.ts +65 -0
- package/templates/apps/mcp/__tests__/get_offerings.test.ts +90 -0
- package/templates/apps/mcp/__tests__/get_pricing.test.ts +80 -0
- package/templates/apps/mcp/__tests__/get_site_info.test.ts +81 -0
- package/templates/apps/mcp/__tests__/http-transport.test.ts +323 -0
- package/templates/apps/mcp/__tests__/lib/errors.test.ts +75 -0
- package/templates/apps/mcp/__tests__/lib/require-paid-tier.test.ts +75 -0
- package/templates/apps/mcp/__tests__/list_pages.test.ts +112 -0
- package/templates/apps/mcp/__tests__/locale.test.ts +135 -0
- package/templates/apps/mcp/__tests__/parity.test.ts +205 -0
- package/templates/apps/mcp/__tests__/purchase-disabled.test.ts +34 -0
- package/templates/apps/mcp/__tests__/read_content.test.ts +153 -0
- package/templates/apps/mcp/__tests__/request_callback.test.ts +163 -0
- package/templates/apps/mcp/__tests__/search_content.test.ts +153 -0
- package/templates/apps/mcp/__tests__/server.test.ts +115 -0
- package/templates/apps/mcp/__tests__/submit_lead.test.ts +165 -0
- package/templates/apps/mcp/__tests__/subscribe_newsletter.test.ts +161 -0
- package/templates/apps/mcp/__tests__/tools/purchase.test.ts +227 -0
- package/templates/apps/mcp/__tests__/tools/scaffold.test.ts +237 -0
- package/templates/apps/mcp/__tests__/update_page.test.ts +195 -0
- package/templates/apps/mcp/jest.config.cjs +82 -0
- package/templates/apps/mcp/package.json +37 -0
- package/templates/apps/mcp/src/abuse/daily-cap.ts +47 -0
- package/templates/apps/mcp/src/abuse/email-validator.ts +25 -0
- package/templates/apps/mcp/src/abuse/honeypot.ts +21 -0
- package/templates/apps/mcp/src/abuse/index.ts +111 -0
- package/templates/apps/mcp/src/abuse/user-agent-deny.ts +58 -0
- package/templates/apps/mcp/src/http-transport.ts +303 -0
- package/templates/apps/mcp/src/index.ts +67 -0
- package/templates/apps/mcp/src/lib/audit-single-page.ts +194 -0
- package/templates/apps/mcp/src/lib/errors.ts +61 -0
- package/templates/apps/mcp/src/lib/locales.ts +171 -0
- package/templates/apps/mcp/src/lib/require-paid-tier.ts +44 -0
- package/templates/apps/mcp/src/lib/resolve-locale.ts +30 -0
- package/templates/apps/mcp/src/server.ts +139 -0
- package/templates/apps/mcp/src/tools/audit.ts +103 -0
- package/templates/apps/mcp/src/tools/capture_lead.ts +52 -0
- package/templates/apps/mcp/src/tools/create_page.ts +95 -0
- package/templates/apps/mcp/src/tools/delete_page.ts +73 -0
- package/templates/apps/mcp/src/tools/get_business_hours.ts +66 -0
- package/templates/apps/mcp/src/tools/get_faq.ts +69 -0
- package/templates/apps/mcp/src/tools/get_locations.ts +85 -0
- package/templates/apps/mcp/src/tools/get_offerings.ts +66 -0
- package/templates/apps/mcp/src/tools/get_pricing.ts +74 -0
- package/templates/apps/mcp/src/tools/get_site_info.ts +84 -0
- package/templates/apps/mcp/src/tools/index.ts +125 -0
- package/templates/apps/mcp/src/tools/list_pages.ts +72 -0
- package/templates/apps/mcp/src/tools/purchase.ts +89 -0
- package/templates/apps/mcp/src/tools/read_content.ts +61 -0
- package/templates/apps/mcp/src/tools/request_callback.ts +51 -0
- package/templates/apps/mcp/src/tools/scaffold.ts +119 -0
- package/templates/apps/mcp/src/tools/search_content.ts +59 -0
- package/templates/apps/mcp/src/tools/subscribe_newsletter.ts +47 -0
- package/templates/apps/mcp/src/tools/update_page.ts +91 -0
- package/templates/apps/mcp/tsconfig.json +19 -0
- package/templates/apps/web/.env.example +47 -0
- package/templates/apps/web/CLAUDE.md +81 -0
- package/templates/apps/web/__tests__/auth/adversarial/cookie-attributes.test.ts +94 -0
- package/templates/apps/web/__tests__/auth/adversarial/oauth-state-parameter.test.ts +75 -0
- package/templates/apps/web/__tests__/auth/adversarial/redirect-uri-allowlist.test.ts +82 -0
- package/templates/apps/web/__tests__/auth/env-helpers.test.ts +168 -0
- package/templates/apps/web/__tests__/authority-list-routes.test.tsx +208 -0
- package/templates/apps/web/__tests__/better-stack.test.ts +66 -0
- package/templates/apps/web/__tests__/blog-dir-resolution.test.ts +87 -0
- package/templates/apps/web/__tests__/blog-source-populated.test.ts +130 -0
- package/templates/apps/web/__tests__/data-testid-coverage.test.tsx +60 -0
- package/templates/apps/web/__tests__/google-analytics.test.tsx +104 -0
- package/templates/apps/web/__tests__/i18n/middleware.test.ts +119 -0
- package/templates/apps/web/__tests__/i18n/routing.test.ts +114 -0
- package/templates/apps/web/__tests__/i18n/translations.test.ts +191 -0
- package/templates/apps/web/__tests__/json-ld.test.ts +98 -0
- package/templates/apps/web/__tests__/knowledge-events-routes.test.tsx +580 -0
- package/templates/apps/web/__tests__/layout-stealth.test.ts +39 -0
- package/templates/apps/web/__tests__/lighthouse-fixtures/improvement-image-shrink.tsx +103 -0
- package/templates/apps/web/__tests__/lighthouse-fixtures/override-fixture.md +114 -0
- package/templates/apps/web/__tests__/lighthouse-fixtures/regression-bloat.tsx +94 -0
- package/templates/apps/web/__tests__/page.test.tsx +230 -0
- package/templates/apps/web/__tests__/products-services-phase1.test.tsx +321 -0
- package/templates/apps/web/__tests__/projects-routes.test.tsx +392 -0
- package/templates/apps/web/__tests__/resources-downloads-integrations-phase2.test.tsx +475 -0
- package/templates/apps/web/__tests__/routes/ai-plugin-json.test.ts +53 -0
- package/templates/apps/web/__tests__/routes/blog-route.test.tsx +191 -0
- package/templates/apps/web/__tests__/routes/llms-txt.test.ts +123 -0
- package/templates/apps/web/__tests__/routes/robots-txt.test.ts +52 -0
- package/templates/apps/web/__tests__/routes/sitemap-xml.test.ts +78 -0
- package/templates/apps/web/__tests__/routes/well-known-mcp.test.ts +203 -0
- package/templates/apps/web/__tests__/section-routes.test.tsx +693 -0
- package/templates/apps/web/__tests__/security-headers.test.ts +201 -0
- package/templates/apps/web/__tests__/sentry-config.test.ts +116 -0
- package/templates/apps/web/__tests__/setup.ts +82 -0
- package/templates/apps/web/__tests__/sitemap-locales.test.ts +415 -0
- package/templates/apps/web/__tests__/standalone-informational-routes.test.tsx +844 -0
- package/templates/apps/web/app/.well-known/ai-plugin.json/route.ts +81 -0
- package/templates/apps/web/app/.well-known/mcp.json/build-manifest.ts +110 -0
- package/templates/apps/web/app/.well-known/mcp.json/route.ts +58 -0
- package/templates/apps/web/app/[locale]/__tests__/layout.test.tsx +120 -0
- package/templates/apps/web/app/[locale]/__tests__/page-renderer-migration.test.tsx +202 -0
- package/templates/apps/web/app/[locale]/about/page.tsx +31 -0
- package/templates/apps/web/app/[locale]/blog/[[...slug]]/page.tsx +173 -0
- package/templates/apps/web/app/[locale]/careers/[slug]/page.tsx +45 -0
- package/templates/apps/web/app/[locale]/careers/__tests__/page-renderer-migration.test.tsx +117 -0
- package/templates/apps/web/app/[locale]/careers/page.tsx +25 -0
- package/templates/apps/web/app/[locale]/case-studies/[slug]/page.tsx +44 -0
- package/templates/apps/web/app/[locale]/case-studies/__tests__/page-renderer-migration.test.tsx +113 -0
- package/templates/apps/web/app/[locale]/case-studies/page.tsx +25 -0
- package/templates/apps/web/app/[locale]/clients/__tests__/page-renderer-migration.test.tsx +63 -0
- package/templates/apps/web/app/[locale]/clients/page.tsx +27 -0
- package/templates/apps/web/app/[locale]/contact/ContactForm.tsx +130 -0
- package/templates/apps/web/app/[locale]/contact/__tests__/contact.actions.test.ts +152 -0
- package/templates/apps/web/app/[locale]/contact/__tests__/page-renderer-migration.test.tsx +92 -0
- package/templates/apps/web/app/[locale]/contact/contact.actions.ts +79 -0
- package/templates/apps/web/app/[locale]/contact/error.tsx +24 -0
- package/templates/apps/web/app/[locale]/contact/page.tsx +38 -0
- package/templates/apps/web/app/[locale]/courses/[slug]/page.tsx +34 -0
- package/templates/apps/web/app/[locale]/courses/__tests__/page-renderer-migration.test.tsx +119 -0
- package/templates/apps/web/app/[locale]/courses/page.tsx +25 -0
- package/templates/apps/web/app/[locale]/dev/purchase/__tests__/actions.test.ts +160 -0
- package/templates/apps/web/app/[locale]/dev/purchase/error.tsx +25 -0
- package/templates/apps/web/app/[locale]/dev/purchase/page.tsx +117 -0
- package/templates/apps/web/app/[locale]/dev/purchase/purchase.actions.ts +58 -0
- package/templates/apps/web/app/[locale]/docs/[[...slug]]/page.tsx +118 -0
- package/templates/apps/web/app/[locale]/downloads/__tests__/page-renderer-migration.test.tsx +72 -0
- package/templates/apps/web/app/[locale]/downloads/page.tsx +25 -0
- package/templates/apps/web/app/[locale]/events/[slug]/page.tsx +47 -0
- package/templates/apps/web/app/[locale]/events/__tests__/page-renderer-migration.test.tsx +130 -0
- package/templates/apps/web/app/[locale]/events/page.tsx +25 -0
- package/templates/apps/web/app/[locale]/faq/page.tsx +36 -0
- package/templates/apps/web/app/[locale]/how-to/[slug]/page.tsx +34 -0
- package/templates/apps/web/app/[locale]/how-to/__tests__/page-renderer-migration.test.tsx +78 -0
- package/templates/apps/web/app/[locale]/how-to/page.tsx +40 -0
- package/templates/apps/web/app/[locale]/integrations/[slug]/page.tsx +43 -0
- package/templates/apps/web/app/[locale]/integrations/__tests__/page-renderer-migration.test.tsx +129 -0
- package/templates/apps/web/app/[locale]/integrations/page.tsx +25 -0
- package/templates/apps/web/app/[locale]/launch-service/page.tsx +31 -0
- package/templates/apps/web/app/[locale]/layout.tsx +241 -0
- package/templates/apps/web/app/[locale]/page.tsx +41 -0
- package/templates/apps/web/app/[locale]/partners/[slug]/page.tsx +44 -0
- package/templates/apps/web/app/[locale]/partners/__tests__/page-renderer-migration.test.tsx +113 -0
- package/templates/apps/web/app/[locale]/partners/page.tsx +25 -0
- package/templates/apps/web/app/[locale]/products/[slug]/page.tsx +43 -0
- package/templates/apps/web/app/[locale]/products/__tests__/page-renderer-migration.test.tsx +129 -0
- package/templates/apps/web/app/[locale]/products/page.tsx +25 -0
- package/templates/apps/web/app/[locale]/projects/[slug]/page.tsx +39 -0
- package/templates/apps/web/app/[locale]/projects/__tests__/page-renderer-migration.test.tsx +138 -0
- package/templates/apps/web/app/[locale]/projects/page.tsx +30 -0
- package/templates/apps/web/app/[locale]/resources/[slug]/page.tsx +51 -0
- package/templates/apps/web/app/[locale]/resources/__tests__/page-renderer-migration.test.tsx +117 -0
- package/templates/apps/web/app/[locale]/resources/page.tsx +27 -0
- package/templates/apps/web/app/[locale]/services/[slug]/page.tsx +43 -0
- package/templates/apps/web/app/[locale]/services/__tests__/page-renderer-migration.test.tsx +129 -0
- package/templates/apps/web/app/[locale]/services/page.tsx +25 -0
- package/templates/apps/web/app/[locale]/software/[slug]/page.tsx +34 -0
- package/templates/apps/web/app/[locale]/software/__tests__/page-renderer-migration.test.tsx +81 -0
- package/templates/apps/web/app/[locale]/software/page.tsx +39 -0
- package/templates/apps/web/app/[locale]/tech-articles/[slug]/page.tsx +34 -0
- package/templates/apps/web/app/[locale]/tech-articles/__tests__/page-renderer-migration.test.tsx +82 -0
- package/templates/apps/web/app/[locale]/tech-articles/page.tsx +39 -0
- package/templates/apps/web/app/[locale]/testimonials/__tests__/page-renderer-migration.test.tsx +63 -0
- package/templates/apps/web/app/[locale]/testimonials/page.tsx +27 -0
- package/templates/apps/web/app/[locale]/use-cases/__tests__/page-renderer-migration.test.tsx +63 -0
- package/templates/apps/web/app/[locale]/use-cases/page.tsx +27 -0
- package/templates/apps/web/app/[locale]/whitepapers/[slug]/page.tsx +34 -0
- package/templates/apps/web/app/[locale]/whitepapers/__tests__/page-renderer-migration.test.tsx +82 -0
- package/templates/apps/web/app/[locale]/whitepapers/page.tsx +39 -0
- package/templates/apps/web/app/__tests__/error-boundaries.test.tsx +152 -0
- package/templates/apps/web/app/api/auth/[...all]/route.ts +16 -0
- package/templates/apps/web/app/error-fallback.tsx +75 -0
- package/templates/apps/web/app/error.tsx +23 -0
- package/templates/apps/web/app/layout.tsx +18 -0
- package/templates/apps/web/app/llms.txt/route.ts +101 -0
- package/templates/apps/web/app/not-found.tsx +48 -0
- package/templates/apps/web/app/og/__tests__/route.test.ts +164 -0
- package/templates/apps/web/app/og/route.tsx +135 -0
- package/templates/apps/web/app/robots.txt/route.ts +36 -0
- package/templates/apps/web/app/sitemap.xml/route.ts +146 -0
- package/templates/apps/web/auth.ts +141 -0
- package/templates/apps/web/components/ThemeToggle.tsx +60 -0
- package/templates/apps/web/components/google-analytics.tsx +34 -0
- package/templates/apps/web/content/en/blog/index.mdx +15 -0
- package/templates/apps/web/content/en/blog/launching-ailk.mdx +20 -0
- package/templates/apps/web/content/en/docs/getting-started.mdx +30 -0
- package/templates/apps/web/i18n/request.ts +36 -0
- package/templates/apps/web/jest.config.cjs +100 -0
- package/templates/apps/web/lib/__mocks__/next-mdx-remote-rsc.js +12 -0
- package/templates/apps/web/lib/__mocks__/source-server.js +31 -0
- package/templates/apps/web/lib/__tests__/og.test.ts +65 -0
- package/templates/apps/web/lib/auth-env.ts +66 -0
- package/templates/apps/web/lib/blog-list-data.ts +95 -0
- package/templates/apps/web/lib/blog-post-data.ts +79 -0
- package/templates/apps/web/lib/nav-config.ts +13 -0
- package/templates/apps/web/lib/observability/better-stack.ts +27 -0
- package/templates/apps/web/lib/og.ts +23 -0
- package/templates/apps/web/lib/prisma-for-auth.ts +34 -0
- package/templates/apps/web/lib/source.ts +34 -0
- package/templates/apps/web/messages/en.json +131 -0
- package/templates/apps/web/middleware.ts +80 -0
- package/templates/apps/web/next.config.mjs +167 -0
- package/templates/apps/web/package.json +62 -0
- package/templates/apps/web/public/.well-known/security.txt +17 -0
- package/templates/apps/web/public/android-chrome-192x192.png +0 -0
- package/templates/apps/web/public/android-chrome-512x512.png +0 -0
- package/templates/apps/web/public/apple-touch-icon.png +0 -0
- package/templates/apps/web/public/favicon-16x16.png +0 -0
- package/templates/apps/web/public/favicon-32x32.png +0 -0
- package/templates/apps/web/public/favicon.ico +0 -0
- package/templates/apps/web/public/favicon.svg +4 -0
- package/templates/apps/web/public/logo-dark.svg +21 -0
- package/templates/apps/web/public/logo-light.svg +21 -0
- package/templates/apps/web/public/logomark-dark.svg +4 -0
- package/templates/apps/web/public/logomark-light.svg +4 -0
- package/templates/apps/web/public/og-default.png +0 -0
- package/templates/apps/web/public/site.webmanifest +19 -0
- package/templates/apps/web/scripts/assert-content-bundled.ts +55 -0
- package/templates/apps/web/security-headers.config.ts +132 -0
- package/templates/apps/web/sentry.client.config.ts +27 -0
- package/templates/apps/web/sentry.edge.config.ts +15 -0
- package/templates/apps/web/sentry.server.config.ts +20 -0
- package/templates/apps/web/source.config.ts +78 -0
- package/templates/apps/web/src/components/SiteNav.tsx +21 -0
- package/templates/apps/web/src/lib/routes.ts +37 -0
- package/templates/apps/web/tsconfig.json +35 -0
- package/templates/apps/web/types/messages.d.ts +19 -0
- package/templates/content/.gitkeep +0 -0
- package/templates/content/CLAUDE.md +85 -0
- package/templates/content/_site.mdx +38 -0
- package/templates/content/ar/HomePage/home.mdx +123 -0
- package/templates/content/ar/_site.mdx +35 -0
- package/templates/content/de/_site.mdx +29 -0
- package/templates/content/en/.gitkeep +0 -0
- package/templates/content/en/AboutPage/about.mdx +19 -0
- package/templates/content/en/AboutPage/about.schema.json +82 -0
- package/templates/content/en/BookCall/book-call.mdx +19 -0
- package/templates/content/en/BookCall/book-call.schema.json +121 -0
- package/templates/content/en/BreadcrumbList/site-breadcrumbs.mdx +20 -0
- package/templates/content/en/CareersList/careers.mdx +24 -0
- package/templates/content/en/CaseStudiesList/case-studies.mdx +22 -0
- package/templates/content/en/CaseStudiesList/showcase.mdx +8 -0
- package/templates/content/en/CaseStudy/ailk-aeo-rollout.mdx +32 -0
- package/templates/content/en/CaseStudy/schema-builder-migration.mdx +41 -0
- package/templates/content/en/ClientsList/clients.mdx +38 -0
- package/templates/content/en/ContactPage/contact.mdx +19 -0
- package/templates/content/en/ContactPage/contact.schema.json +100 -0
- package/templates/content/en/ContactPoint/primary.mdx +14 -0
- package/templates/content/en/Course/aeo-fundamentals.mdx +37 -0
- package/templates/content/en/Course/schema-builder-workshop.mdx +62 -0
- package/templates/content/en/CoursesList/courses.mdx +22 -0
- package/templates/content/en/DownloadsList/downloads.mdx +22 -0
- package/templates/content/en/Event/aeo-office-hours-may-2026.mdx +39 -0
- package/templates/content/en/Event/ailk-launch-day-2026.mdx +35 -0
- package/templates/content/en/EventsList/events.mdx +26 -0
- package/templates/content/en/FAQPage/faq.mdx +420 -0
- package/templates/content/en/FAQPage/faq.schema.json +231 -0
- package/templates/content/en/GlossaryList/glossary.mdx +19 -0
- package/templates/content/en/GlossaryList/glossary.schema.json +300 -0
- package/templates/content/en/HomePage/home.mdx +312 -0
- package/templates/content/en/HomePage/home.schema.json +88 -0
- package/templates/content/en/HomePage/launch-service.mdx +475 -0
- package/templates/content/en/HomePage/launch-service.schema.json +138 -0
- package/templates/content/en/HowTo/add-mdx-content.mdx +38 -0
- package/templates/content/en/HowTo/configure-aeo-scoring.mdx +35 -0
- package/templates/content/en/HowTo/set-up-json-ld.mdx +36 -0
- package/templates/content/en/Integration/github-actions.mdx +31 -0
- package/templates/content/en/Integration/openai-api.mdx +26 -0
- package/templates/content/en/Integration/vercel.mdx +32 -0
- package/templates/content/en/IntegrationsList/integrations.mdx +22 -0
- package/templates/content/en/JobPosting/content-strategist.mdx +46 -0
- package/templates/content/en/JobPosting/developer-advocate.mdx +47 -0
- package/templates/content/en/JobPosting/senior-fullstack-engineer.mdx +57 -0
- package/templates/content/en/LandingPage/aeo-audit.mdx +19 -0
- package/templates/content/en/LandingPage/aeo-audit.schema.json +92 -0
- package/templates/content/en/LandingPage/agency-waitlist.mdx +340 -0
- package/templates/content/en/LandingPage/agency-waitlist.schema.json +152 -0
- package/templates/content/en/LandingPage/developers.mdx +19 -0
- package/templates/content/en/LandingPage/developers.schema.json +109 -0
- package/templates/content/en/LandingPage/for-agencies.mdx +390 -0
- package/templates/content/en/LandingPage/for-agencies.schema.json +107 -0
- package/templates/content/en/LandingPage/for-ai-search-agencies.mdx +417 -0
- package/templates/content/en/LandingPage/for-ai-search-agencies.schema.json +105 -0
- package/templates/content/en/LandingPage/for-businesses.mdx +19 -0
- package/templates/content/en/LandingPage/for-businesses.schema.json +96 -0
- package/templates/content/en/LandingPage/platform.mdx +369 -0
- package/templates/content/en/LandingPage/platform.schema.json +166 -0
- package/templates/content/en/LandingPage/vs-ai-website-builders.mdx +19 -0
- package/templates/content/en/LandingPage/vs-ai-website-builders.schema.json +102 -0
- package/templates/content/en/LandingPage/vs-wordpress.mdx +19 -0
- package/templates/content/en/LandingPage/vs-wordpress.schema.json +53 -0
- package/templates/content/en/NewsletterSignup/newsletter.mdx +236 -0
- package/templates/content/en/NewsletterSignup/newsletter.schema.json +91 -0
- package/templates/content/en/Organization/site-owner.mdx +16 -0
- package/templates/content/en/Partner/prisma.mdx +31 -0
- package/templates/content/en/Partner/supabase.mdx +30 -0
- package/templates/content/en/Partner/vercel.mdx +28 -0
- package/templates/content/en/PartnersList/partners.mdx +22 -0
- package/templates/content/en/Person/founder.mdx +18 -0
- package/templates/content/en/Pricing/pricing.mdx +538 -0
- package/templates/content/en/Pricing/pricing.schema.json +209 -0
- package/templates/content/en/PrivacyPage/privacy.mdx +165 -0
- package/templates/content/en/PrivacyPage/privacy.schema.json +64 -0
- package/templates/content/en/Product/ailk.mdx +19 -0
- package/templates/content/en/Product/ailk.schema.json +94 -0
- package/templates/content/en/Product/api-launch-kit.mdx +26 -0
- package/templates/content/en/Product/launch-kit.mdx +28 -0
- package/templates/content/en/ProductsList/products.mdx +26 -0
- package/templates/content/en/Project/ailk-phase-2.mdx +54 -0
- package/templates/content/en/ProjectsList/projects.mdx +25 -0
- package/templates/content/en/ResourceDetail/aeo-scoring-guide.mdx +27 -0
- package/templates/content/en/ResourceDetail/content-model-whitepaper.mdx +28 -0
- package/templates/content/en/ResourceDetail/schema-org-quick-reference.mdx +39 -0
- package/templates/content/en/ResourcesHub/resources.mdx +22 -0
- package/templates/content/en/Service/consulting.mdx +22 -0
- package/templates/content/en/Service/implementation.mdx +30 -0
- package/templates/content/en/Service/launch-service.mdx +232 -0
- package/templates/content/en/Service/launch.mdx +228 -0
- package/templates/content/en/ServicesList/services.mdx +84 -0
- package/templates/content/en/SoftwareProduct/ailk-aeo.mdx +44 -0
- package/templates/content/en/SoftwareProduct/ailk-content-adapters.mdx +47 -0
- package/templates/content/en/SoftwareProduct/ailk-schema.mdx +49 -0
- package/templates/content/en/TeamList/team.mdx +63 -0
- package/templates/content/en/TeamMember/founder.mdx +72 -0
- package/templates/content/en/TermsPage/terms.mdx +19 -0
- package/templates/content/en/TermsPage/terms.schema.json +99 -0
- package/templates/content/en/TestimonialsList/testimonials.mdx +44 -0
- package/templates/content/en/UseCasesList/use-cases.mdx +30 -0
- package/templates/content/en/Whitepaper/ax-first-product-development.mdx +27 -0
- package/templates/content/en/Whitepaper/open-core-commercial-strategy.mdx +27 -0
- package/templates/content/en/Whitepaper/structured-data-for-answer-engines.mdx +31 -0
- package/templates/content/en-XA/AboutPage/about.mdx +8 -0
- package/templates/content/en-XA/FAQPage/faq.mdx +8 -0
- package/templates/content/en-XA/HomePage/home.mdx +8 -0
- package/templates/content/es/_site.mdx +30 -0
- package/templates/content/fr/_site.mdx +30 -0
- package/templates/content/ja/_site.mdx +30 -0
- package/templates/content/pt-BR/AboutPage/about.mdx +8 -0
- package/templates/content/pt-BR/FAQPage/faq.mdx +8 -0
- package/templates/content/pt-BR/HomePage/home.mdx +23 -0
- package/templates/database/CHANGELOG.md +5 -0
- package/templates/database/README.md +234 -0
- package/templates/database/__tests__/user-cascade.test.ts +125 -0
- package/templates/database/auth/.gitkeep +0 -0
- package/templates/database/config/.gitkeep +0 -0
- package/templates/database/content/.gitkeep +0 -0
- package/templates/database/inbox/.gitkeep +0 -0
- package/templates/database/inbox/README.md +3 -0
- package/templates/database/inbox/__tests__/schema.test.ts +40 -0
- package/templates/database/inbox/schema.prisma +52 -0
- package/templates/database/jest.config.cjs +29 -0
- package/templates/database/migrations/20260508000000_add_inbox_namespace/migration.sql +328 -0
- package/templates/database/migrations/20260513000000_better_auth_migration/migration.sql +100 -0
- package/templates/database/migrations/20260515000000_add_user_billing_fields/migration.sql +28 -0
- package/templates/database/migrations/20260516000000_add_user_tier_care_plan_seat/migration.sql +25 -0
- package/templates/database/migrations/20260518000000_add_telemetry_records/migration.sql +42 -0
- package/templates/database/migrations/20260525000000_theme_wiring/migration.sql +67 -0
- package/templates/database/migrations/20260710000000_retire_commercial_tier/migration.sql +21 -0
- package/templates/database/migrations/migration_lock.toml +3 -0
- package/templates/database/ops/.gitkeep +0 -0
- package/templates/database/package.json +45 -0
- package/templates/database/prisma.config.ts +20 -0
- package/templates/database/schema.prisma +487 -0
- package/templates/database/scripts/db-generate-locked.sh +80 -0
- package/templates/database/seed-test.ts +85 -0
- package/templates/database/tsconfig.build.json +16 -0
- package/templates/database/tsconfig.json +9 -0
- package/templates/package.json +125 -0
- package/templates/pnpm-workspace.yaml +6 -0
- package/templates/project.yaml +59 -0
- package/templates/tsconfig.base.json +18 -0
- 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.
|