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,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Programmatic API for create-ailk.
|
|
3
|
+
*
|
|
4
|
+
* Extracts the core scaffolding logic from cli.ts so it can be exercised
|
|
5
|
+
* directly in tests and by other consumers without spawning a subprocess.
|
|
6
|
+
*
|
|
7
|
+
* The CLI entry point (cli.ts) delegates to scaffoldSync() here; no logic is
|
|
8
|
+
* duplicated between the CLI and the programmatic surface.
|
|
9
|
+
*
|
|
10
|
+
* Usage (async, for MCP tool or external tooling):
|
|
11
|
+
* import { scaffold } from './programmatic.js';
|
|
12
|
+
* const result = await scaffold({ targetDir: '/tmp/my-site', projectName: 'my-site' });
|
|
13
|
+
*
|
|
14
|
+
* Usage (sync, for the CLI):
|
|
15
|
+
* import { scaffoldSync } from './programmatic.js';
|
|
16
|
+
* const result = scaffoldSync({ targetDir: '/tmp/my-site', projectName: 'my-site' });
|
|
17
|
+
*/
|
|
18
|
+
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
19
|
+
import { basename, dirname, resolve } from "node:path";
|
|
20
|
+
import { fileURLToPath } from "node:url";
|
|
21
|
+
import { copyTemplate } from "./copy.js";
|
|
22
|
+
import { validateTarget } from "./validate.js";
|
|
23
|
+
const PKG_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
24
|
+
const TEMPLATES_DIR = resolve(PKG_ROOT, "templates");
|
|
25
|
+
const VERSIONS_FILE = resolve(PKG_ROOT, "versions.json");
|
|
26
|
+
function readVersionMap() {
|
|
27
|
+
if (!existsSync(VERSIONS_FILE)) {
|
|
28
|
+
// Empty map is a valid state for tests / dev where build-templates has
|
|
29
|
+
// not been re-run since the last clean.
|
|
30
|
+
return {};
|
|
31
|
+
}
|
|
32
|
+
const raw = readFileSync(VERSIONS_FILE, "utf8");
|
|
33
|
+
return JSON.parse(raw);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Count all files recursively under a directory. Used to report filesCreated.
|
|
37
|
+
*/
|
|
38
|
+
function countFiles(dir) {
|
|
39
|
+
if (!existsSync(dir))
|
|
40
|
+
return 0;
|
|
41
|
+
let count = 0;
|
|
42
|
+
const stack = [dir];
|
|
43
|
+
while (stack.length > 0) {
|
|
44
|
+
const current = stack.pop();
|
|
45
|
+
for (const entry of readdirSync(current, { withFileTypes: true })) {
|
|
46
|
+
if (entry.isDirectory()) {
|
|
47
|
+
stack.push(`${current}/${entry.name}`);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
count++;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return count;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Scaffold an AI Launch Kit starter project into targetDir (synchronous).
|
|
58
|
+
*
|
|
59
|
+
* Throws ValidationError if targetDir already exists and is non-empty.
|
|
60
|
+
* Throws Error if the template copy fails for any other reason.
|
|
61
|
+
*/
|
|
62
|
+
export function scaffoldSync(opts) {
|
|
63
|
+
// Validate target — throws ValidationError on rejection.
|
|
64
|
+
const targetAbs = validateTarget(opts.targetDir);
|
|
65
|
+
const projectName = opts.projectName ?? basename(targetAbs);
|
|
66
|
+
const versions = readVersionMap();
|
|
67
|
+
copyTemplate({
|
|
68
|
+
templatesDir: TEMPLATES_DIR,
|
|
69
|
+
targetDir: targetAbs,
|
|
70
|
+
versions,
|
|
71
|
+
markers: {
|
|
72
|
+
PROJECT_NAME: projectName,
|
|
73
|
+
COMPANY_NAME: "Your Company",
|
|
74
|
+
COMPANY_DOMAIN: "example.com",
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
const filesCreated = countFiles(targetAbs);
|
|
78
|
+
return { targetDir: targetAbs, filesCreated };
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Scaffold an AI Launch Kit starter project into targetDir (async wrapper).
|
|
82
|
+
*
|
|
83
|
+
* Wraps scaffoldSync for callers that prefer Promise-based APIs. The
|
|
84
|
+
* underlying I/O is synchronous; the async signature is provided for
|
|
85
|
+
* compatibility with async callers (e.g. the MCP tool handler via subprocess).
|
|
86
|
+
*/
|
|
87
|
+
export async function scaffold(opts) {
|
|
88
|
+
return scaffoldSync(opts);
|
|
89
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* String-template substitution helpers.
|
|
3
|
+
*
|
|
4
|
+
* Two surfaces:
|
|
5
|
+
* - substituteWorkspaceVersions — `workspace:*` → `^<semver>` for @working-theory/*
|
|
6
|
+
* deps in package.json text. Throws if a `@working-theory/*` entry has no canonical
|
|
7
|
+
* version (escalation per spec §5.3).
|
|
8
|
+
* - substituteMarkers — replaces every `{{KEY}}` with the matching value
|
|
9
|
+
* from the provided map. Markers without a matching entry are left
|
|
10
|
+
* unchanged so the user can author their own.
|
|
11
|
+
*
|
|
12
|
+
* The package.json substitution operates on text (regex), not on parsed JSON,
|
|
13
|
+
* to preserve formatting (whitespace, key order, trailing commas) of the
|
|
14
|
+
* canonical source. Re-serializing JSON would create gratuitous diffs in
|
|
15
|
+
* scaffolder output and obscure intent.
|
|
16
|
+
*/
|
|
17
|
+
export type WorkspaceVersionMap = Record<string, string>;
|
|
18
|
+
/**
|
|
19
|
+
* Replaces every `"@working-theory/<pkg>": "workspace:*"` occurrence with the matching
|
|
20
|
+
* caret-prefixed version from `versions`. Throws when an `@working-theory/*` entry has
|
|
21
|
+
* no version map entry.
|
|
22
|
+
*
|
|
23
|
+
* Non-`@working-theory/*` deps are not touched; non-package.json input is not touched.
|
|
24
|
+
*/
|
|
25
|
+
export declare function substituteWorkspaceVersions(input: string, versions: WorkspaceVersionMap): string;
|
|
26
|
+
export type MarkerMap = Record<string, string>;
|
|
27
|
+
/**
|
|
28
|
+
* Replaces `{{KEY}}` markers with values from the provided map. Markers
|
|
29
|
+
* without a matching entry are left as-is (e.g. user-authored placeholders).
|
|
30
|
+
*/
|
|
31
|
+
export declare function substituteMarkers(input: string, markers: MarkerMap): string;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* String-template substitution helpers.
|
|
3
|
+
*
|
|
4
|
+
* Two surfaces:
|
|
5
|
+
* - substituteWorkspaceVersions — `workspace:*` → `^<semver>` for @working-theory/*
|
|
6
|
+
* deps in package.json text. Throws if a `@working-theory/*` entry has no canonical
|
|
7
|
+
* version (escalation per spec §5.3).
|
|
8
|
+
* - substituteMarkers — replaces every `{{KEY}}` with the matching value
|
|
9
|
+
* from the provided map. Markers without a matching entry are left
|
|
10
|
+
* unchanged so the user can author their own.
|
|
11
|
+
*
|
|
12
|
+
* The package.json substitution operates on text (regex), not on parsed JSON,
|
|
13
|
+
* to preserve formatting (whitespace, key order, trailing commas) of the
|
|
14
|
+
* canonical source. Re-serializing JSON would create gratuitous diffs in
|
|
15
|
+
* scaffolder output and obscure intent.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Replaces every `"@working-theory/<pkg>": "workspace:*"` occurrence with the matching
|
|
19
|
+
* caret-prefixed version from `versions`. Throws when an `@working-theory/*` entry has
|
|
20
|
+
* no version map entry.
|
|
21
|
+
*
|
|
22
|
+
* Non-`@working-theory/*` deps are not touched; non-package.json input is not touched.
|
|
23
|
+
*/
|
|
24
|
+
export function substituteWorkspaceVersions(input, versions) {
|
|
25
|
+
// Match `"@working-theory/<name>": "workspace:*"` with arbitrary whitespace between
|
|
26
|
+
// the colon and the value. The captured group is the package name.
|
|
27
|
+
const re = /"(@working-theory\/[a-z0-9-]+)"(\s*:\s*)"workspace:\*"/g;
|
|
28
|
+
return input.replace(re, (_match, pkg, sep) => {
|
|
29
|
+
const v = versions[pkg];
|
|
30
|
+
if (!v) {
|
|
31
|
+
throw new Error(`no version found for ${pkg} in canonical workspace map. Update scripts/build-templates.mjs or escalate per spec §5.3.`);
|
|
32
|
+
}
|
|
33
|
+
return `"${pkg}"${sep}"^${v}"`;
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Replaces `{{KEY}}` markers with values from the provided map. Markers
|
|
38
|
+
* without a matching entry are left as-is (e.g. user-authored placeholders).
|
|
39
|
+
*/
|
|
40
|
+
export function substituteMarkers(input, markers) {
|
|
41
|
+
return input.replace(/\{\{([A-Z_][A-Z0-9_]*)\}\}/g, (whole, key) => {
|
|
42
|
+
const value = markers[key];
|
|
43
|
+
return value !== undefined ? value : whole;
|
|
44
|
+
});
|
|
45
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare class ValidationError extends Error {
|
|
2
|
+
constructor(message: string);
|
|
3
|
+
}
|
|
4
|
+
/**
|
|
5
|
+
* Validates the user-supplied target dir. Returns the resolved absolute path
|
|
6
|
+
* on success; throws ValidationError on any rejection.
|
|
7
|
+
*/
|
|
8
|
+
export declare function validateTarget(rawTarget: string): string;
|
package/dist/validate.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Target-directory validation for `create-ailk`.
|
|
3
|
+
*
|
|
4
|
+
* Spec §2.2 + §5.1 + §5.2:
|
|
5
|
+
* - Reject if target exists AND is non-empty.
|
|
6
|
+
* - Reject if target arg contains `..` (path traversal guard).
|
|
7
|
+
* - Reject if target arg contains a NUL byte (`\0`) — defense-in-depth
|
|
8
|
+
* against C-string truncation tricks in any downstream syscall path.
|
|
9
|
+
* - Reject filesystem root.
|
|
10
|
+
* - Reject when the parent directory does not exist (surface user error).
|
|
11
|
+
* - Reject when target points at an existing file (not a directory).
|
|
12
|
+
*
|
|
13
|
+
* Note on TOCTOU: validation runs before `copyTemplate` performs writes, so
|
|
14
|
+
* a concurrent process could in principle populate the target between the
|
|
15
|
+
* two. Acceptable for a CLI run interactively by the user themselves; if
|
|
16
|
+
* this scaffolder ever runs in an adversarial multi-tenant context, add a
|
|
17
|
+
* re-check immediately before write.
|
|
18
|
+
*/
|
|
19
|
+
import { existsSync, readdirSync, statSync } from "node:fs";
|
|
20
|
+
import { dirname, isAbsolute, resolve, sep } from "node:path";
|
|
21
|
+
export class ValidationError extends Error {
|
|
22
|
+
constructor(message) {
|
|
23
|
+
super(message);
|
|
24
|
+
this.name = "ValidationError";
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Validates the user-supplied target dir. Returns the resolved absolute path
|
|
29
|
+
* on success; throws ValidationError on any rejection.
|
|
30
|
+
*/
|
|
31
|
+
export function validateTarget(rawTarget) {
|
|
32
|
+
if (typeof rawTarget !== "string" || rawTarget.length === 0) {
|
|
33
|
+
throw new ValidationError("target directory must be a non-empty string");
|
|
34
|
+
}
|
|
35
|
+
// Defense-in-depth: reject NUL bytes — they truncate C strings on some
|
|
36
|
+
// syscalls and have no legitimate use in a directory name.
|
|
37
|
+
if (rawTarget.includes("\0")) {
|
|
38
|
+
throw new ValidationError("target path contains NUL byte (`\\0`); this is never legitimate");
|
|
39
|
+
}
|
|
40
|
+
// Defense-in-depth: reject `..` segments BEFORE resolution. We compare
|
|
41
|
+
// path-separator-bracketed segments so a directory literally named "..foo"
|
|
42
|
+
// is allowed (.. only blocks the parent-traversal segment).
|
|
43
|
+
const segments = rawTarget.split(/[\\/]/);
|
|
44
|
+
if (segments.some((s) => s === "..")) {
|
|
45
|
+
throw new ValidationError(`target path contains \`..\` traversal segment: ${rawTarget}`);
|
|
46
|
+
}
|
|
47
|
+
const resolved = isAbsolute(rawTarget)
|
|
48
|
+
? rawTarget
|
|
49
|
+
: resolve(process.cwd(), rawTarget);
|
|
50
|
+
// Reject filesystem root (e.g. `/`, `C:\`).
|
|
51
|
+
if (resolved === sep || /^[A-Za-z]:[\\/]?$/.test(resolved)) {
|
|
52
|
+
throw new ValidationError(`target directory cannot be the filesystem root: ${resolved}`);
|
|
53
|
+
}
|
|
54
|
+
// Parent must exist.
|
|
55
|
+
const parent = dirname(resolved);
|
|
56
|
+
if (!existsSync(parent)) {
|
|
57
|
+
throw new ValidationError(`parent directory does not exist: ${parent}. Create it first or choose a different path.`);
|
|
58
|
+
}
|
|
59
|
+
if (existsSync(resolved)) {
|
|
60
|
+
const s = statSync(resolved);
|
|
61
|
+
if (!s.isDirectory()) {
|
|
62
|
+
throw new ValidationError(`target exists but is not a directory: ${resolved}`);
|
|
63
|
+
}
|
|
64
|
+
const entries = readdirSync(resolved);
|
|
65
|
+
if (entries.length > 0) {
|
|
66
|
+
throw new ValidationError(`target directory exists and is not empty: ${resolved}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return resolved;
|
|
70
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-ailk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Scaffolder for AI Launch Kit — `pnpm create ailk@latest <dir>` produces a starter repo consuming @working-theory/* from npm (per ADR 0007).",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"create-ailk": "./dist/cli.js"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist",
|
|
13
|
+
"templates",
|
|
14
|
+
"README.md",
|
|
15
|
+
"LICENSE"
|
|
16
|
+
],
|
|
17
|
+
"publishConfig": {
|
|
18
|
+
"access": "public"
|
|
19
|
+
},
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/tailwind-ai/ai-launch-kit.git",
|
|
23
|
+
"directory": "packages/create-ailk"
|
|
24
|
+
},
|
|
25
|
+
"homepage": "https://github.com/tailwind-ai/ai-launch-kit/tree/main/packages/create-ailk#readme",
|
|
26
|
+
"bugs": {
|
|
27
|
+
"url": "https://github.com/tailwind-ai/ai-launch-kit/issues"
|
|
28
|
+
},
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=20.0.0"
|
|
31
|
+
},
|
|
32
|
+
"keywords": [
|
|
33
|
+
"ailk",
|
|
34
|
+
"scaffolder",
|
|
35
|
+
"create-ailk",
|
|
36
|
+
"ai-launch-kit"
|
|
37
|
+
],
|
|
38
|
+
"license": "Apache-2.0",
|
|
39
|
+
"scripts": {
|
|
40
|
+
"build": "tsc -b",
|
|
41
|
+
"type-check": "tsc --noEmit",
|
|
42
|
+
"test": "tsc -b && node scripts/build-templates.mjs && jest",
|
|
43
|
+
"test:watch": "jest --watch",
|
|
44
|
+
"test:coverage": "jest --coverage",
|
|
45
|
+
"build-templates": "node scripts/build-templates.mjs"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: web
|
|
3
|
+
description: Frontend specialist for apps/web and any project-local UI components. Use when work touches React components, pages, styles, or visitor-facing UX. Not for api routes or schema work.
|
|
4
|
+
allowed_tools: [Read, Edit, Write, Glob, Grep, Bash, Agent]
|
|
5
|
+
model: sonnet
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
You are the frontend specialist for this project. You own the
|
|
9
|
+
visitor-facing UX surface — the marketing site, any dashboard pages,
|
|
10
|
+
and any project-local components.
|
|
11
|
+
|
|
12
|
+
## Scope
|
|
13
|
+
|
|
14
|
+
- `apps/web/**` — Next.js 16 + React 19 app, Server Components by
|
|
15
|
+
default.
|
|
16
|
+
- Any project-local component or theme overrides you add alongside
|
|
17
|
+
`apps/web`.
|
|
18
|
+
|
|
19
|
+
You consume `@working-theory/ui` and `@working-theory/theme` from npm — those are
|
|
20
|
+
upstream packages; don't try to edit them locally.
|
|
21
|
+
|
|
22
|
+
## Read before edit
|
|
23
|
+
|
|
24
|
+
1. `.claude/rules/architecture.md` — confirm what `apps/web` may
|
|
25
|
+
import. NextAuth handlers are the only API-shaped code allowed in
|
|
26
|
+
`apps/web`; everything else server-side goes through `apps/api`.
|
|
27
|
+
2. The page or component you're modifying, plus any sibling files in
|
|
28
|
+
the same directory.
|
|
29
|
+
3. Any project-local theme override file before touching styles —
|
|
30
|
+
tokens come from `@working-theory/theme` unless you've extended it.
|
|
31
|
+
|
|
32
|
+
## Verification
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pnpm --filter ./apps/web type-check
|
|
36
|
+
pnpm --filter ./apps/web build
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Run `pnpm preflight` before opening a PR.
|
|
40
|
+
|
|
41
|
+
## Hand-off rules
|
|
42
|
+
|
|
43
|
+
- Need a new HTTP endpoint? Don't invent it in `apps/web`. Add the
|
|
44
|
+
route in `apps/api` (or open an issue if you don't own that surface
|
|
45
|
+
yet) and consume it via `@working-theory/api-client`.
|
|
46
|
+
- Need a new content type? Add it under `content/<TypeName>/` and
|
|
47
|
+
reference the schema from `@working-theory/schema`.
|
|
48
|
+
- Need a database read? Wrong layer — `apps/web` does not read the
|
|
49
|
+
database. Route through `apps/api`.
|
|
50
|
+
|
|
51
|
+
## Domain conventions
|
|
52
|
+
|
|
53
|
+
- **Server Components by default.** `'use client'` only when the
|
|
54
|
+
component needs browser-only APIs (state, refs, browser events).
|
|
55
|
+
Adding `'use client'` to a file that just renders JSX is the
|
|
56
|
+
default failure mode — resist it.
|
|
57
|
+
- **Tailwind tokens only.** No raw hex, rgb, or arbitrary colors.
|
|
58
|
+
Use semantic tokens from `@working-theory/theme` (`bg-canvas`, `text-fg`,
|
|
59
|
+
`border-border`, etc.). If a token doesn't exist, extend the theme;
|
|
60
|
+
don't bypass.
|
|
61
|
+
- **Mobile-first responsive.** Default styles target mobile;
|
|
62
|
+
`md:`/`lg:` modifiers for larger viewports.
|
|
63
|
+
- **MDX rendering** uses `next-mdx-remote/rsc`, never `@next/mdx`
|
|
64
|
+
(the latter requires runtime config that fights Server Components).
|
|
65
|
+
- **NextAuth handlers** are the only API-shaped code in `apps/web`
|
|
66
|
+
— they live at `apps/web/app/api/auth/[...nextauth]/route.ts`.
|
|
67
|
+
Everything else goes to `apps/api`.
|
|
68
|
+
|
|
69
|
+
## Forbidden
|
|
70
|
+
|
|
71
|
+
- Importing from `apps/api` or `apps/mcp` — these are peer apps;
|
|
72
|
+
speak to the API via `@working-theory/api-client`.
|
|
73
|
+
- Importing `@working-theory/database` — `apps/web` does not touch the DB;
|
|
74
|
+
route through `apps/api`.
|
|
75
|
+
- Importing `stripe`, `resend`, `@react-email/*` directly — wrap
|
|
76
|
+
through `@working-theory/stripe-client` or `@working-theory/email`, server-side via
|
|
77
|
+
`apps/api`.
|
|
78
|
+
- Adding a `utils.ts`, `helpers.ts`, `common.ts`, or `misc.ts` file
|
|
79
|
+
— use a descriptive name.
|
|
80
|
+
- Reformatting unrelated lines. Diff is the contract.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Architecture Discipline
|
|
2
|
+
|
|
3
|
+
## The boundary
|
|
4
|
+
|
|
5
|
+
`apps/web`, `apps/api`, and `apps/mcp` are **peer apps**. They share
|
|
6
|
+
code via published `@working-theory/*` packages. They do not import from each
|
|
7
|
+
other.
|
|
8
|
+
|
|
9
|
+
## Why this matters
|
|
10
|
+
|
|
11
|
+
- The agent surface (`apps/api`, `apps/mcp`) is a co-equal product, not
|
|
12
|
+
a bolt-on. Coupling apps means changing the agent surface forces
|
|
13
|
+
changes to the visitor-facing UX.
|
|
14
|
+
- Each app deploys independently. Cross-app imports prevent that.
|
|
15
|
+
- Reading any one app should make sense without reference to the
|
|
16
|
+
others. If it doesn't, you're carrying coupling that will hurt later.
|
|
17
|
+
|
|
18
|
+
## How to apply
|
|
19
|
+
|
|
20
|
+
- Need to share code between apps? Find an existing `@working-theory/*` package
|
|
21
|
+
that fits, or open an issue upstream at
|
|
22
|
+
<https://github.com/tailwind-ai/ai-launch-kit> requesting a new one.
|
|
23
|
+
Do not vendor a copy.
|
|
24
|
+
- Need types shared across apps? Use `@working-theory/validation` (Zod schemas)
|
|
25
|
+
or `@working-theory/schema` (schema.org types).
|
|
26
|
+
- Need an HTTP call from `apps/web` to `apps/api`? Use
|
|
27
|
+
`@working-theory/api-client`. Don't import API route handlers directly.
|
|
28
|
+
- Need database access? Only `apps/api` and `apps/mcp` import
|
|
29
|
+
`@working-theory/database`. `apps/web` never reads the database directly — it
|
|
30
|
+
goes through the HTTP API.
|
|
31
|
+
- Cross-cutting integrations (auth, payments, email, analytics) go
|
|
32
|
+
through their wrapper packages: `@working-theory/auth-client`,
|
|
33
|
+
`@working-theory/stripe-client`, `@working-theory/email`, `@working-theory/analytics`. Never
|
|
34
|
+
import `next-auth`, `stripe`, `resend`, etc. directly.
|
|
35
|
+
|
|
36
|
+
## What you can verify, what you can't
|
|
37
|
+
|
|
38
|
+
- Static imports across boundaries are easy to spot in code review and
|
|
39
|
+
with most TypeScript tooling.
|
|
40
|
+
- Runtime `fetch` calls to internal-only endpoints are NOT enforced by
|
|
41
|
+
any tool. Treat `apps/api` like a third-party HTTP API even when
|
|
42
|
+
you control both ends — version the contract, validate the response.
|
|
43
|
+
- Dynamic `import()` with a runtime-constructed path is also
|
|
44
|
+
unenforced. Don't use it to evade the boundary.
|
|
45
|
+
|
|
46
|
+
## Escalation
|
|
47
|
+
|
|
48
|
+
If a task seems to require crossing a boundary: stop and write a short
|
|
49
|
+
note in `docs/` capturing what you wanted to do and why the boundary
|
|
50
|
+
gets in the way. Don't add the cross-import. Either the boundary moves
|
|
51
|
+
(and you have a record of why) or the task changes shape — both are
|
|
52
|
+
better than a quiet violation.
|
|
53
|
+
|
|
54
|
+
## Forbidden patterns
|
|
55
|
+
|
|
56
|
+
These never appear in source code:
|
|
57
|
+
|
|
58
|
+
- `sk_live_*`, `pk_live_*` — live Stripe keys live in your deployment
|
|
59
|
+
platform's secrets store, never in source files or `.env`.
|
|
60
|
+
- Direct vendor SDK imports outside the wrapper packages
|
|
61
|
+
(`import 'stripe'` outside `@working-theory/stripe-client`, etc.).
|
|
62
|
+
- Hardcoded production database URLs in committed files.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Preserve Existing Style
|
|
2
|
+
|
|
3
|
+
When editing existing files, preserve their existing formatting. Do
|
|
4
|
+
**not** reformat, reflow, reorganize imports, change quote style,
|
|
5
|
+
change indentation, or rearrange whitespace on lines that aren't
|
|
6
|
+
materially changing as part of your task.
|
|
7
|
+
|
|
8
|
+
Your diff should contain only the lines you deliberately touched. A
|
|
9
|
+
20-line functional change should produce a ~20-line diff, not a
|
|
10
|
+
900-line diff with 880 lines of formatting churn.
|
|
11
|
+
|
|
12
|
+
## Why
|
|
13
|
+
|
|
14
|
+
Formatting churn:
|
|
15
|
+
|
|
16
|
+
- Obscures real changes during code review.
|
|
17
|
+
- Creates noise in `git blame` / `git log`.
|
|
18
|
+
- Triggers unnecessary merge conflicts.
|
|
19
|
+
- Violates the spirit of "behavior must not change unless the
|
|
20
|
+
acceptance criteria say so" — even if runtime behavior is identical,
|
|
21
|
+
the meaning to a human reader has changed.
|
|
22
|
+
|
|
23
|
+
## How to apply
|
|
24
|
+
|
|
25
|
+
- **Before committing:** run `git diff --stat`. If the delta is
|
|
26
|
+
wildly larger than the work you did, investigate before pushing.
|
|
27
|
+
- **If your editor runs a formatter on save:** disable it for the
|
|
28
|
+
session, configure it to match the existing style, or revert
|
|
29
|
+
formatting-only lines before committing.
|
|
30
|
+
- **If quotes, semicolons, or import grouping differ from the
|
|
31
|
+
existing file:** match the existing file, not your editor's
|
|
32
|
+
defaults.
|
|
33
|
+
- **The diff is the contract.** A reviewer should see only the lines
|
|
34
|
+
you meant to change.
|
|
35
|
+
|
|
36
|
+
## Not covered by this rule
|
|
37
|
+
|
|
38
|
+
- Deliberate cleanup (removing dead code, inlining single-use
|
|
39
|
+
helpers, collapsing redundant abstraction) is fine when it's the
|
|
40
|
+
point of the task and called out in the PR.
|
|
41
|
+
- Net-new files set their own style, subject to the project's
|
|
42
|
+
existing conventions.
|
|
43
|
+
- A task whose acceptance criteria explicitly say "reformat file X"
|
|
44
|
+
(rare).
|
|
45
|
+
|
|
46
|
+
## Escalation
|
|
47
|
+
|
|
48
|
+
If you believe the existing style is genuinely wrong and want to
|
|
49
|
+
change it: stop. Note it in the PR description and propose the
|
|
50
|
+
reformat as a separate PR. Do not unilaterally reformat the codebase
|
|
51
|
+
as a side effect of an unrelated task.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Skills
|
|
2
|
+
|
|
3
|
+
Skills are reusable Claude Code workflows scoped to this project. Each
|
|
4
|
+
lives in its own subdirectory with a `SKILL.md` describing when to use
|
|
5
|
+
it and how it works.
|
|
6
|
+
|
|
7
|
+
The seven OSS skills below are the canonical AI Launch Kit workflows.
|
|
8
|
+
Their status reflects what's available at the upstream
|
|
9
|
+
<https://github.com/tailwind-ai/ai-launch-kit> repository today. Issue
|
|
10
|
+
numbers in the table refer to that upstream repo (the
|
|
11
|
+
`tailwind-ai/ai-launch-kit#N` form makes the link explicit), not your
|
|
12
|
+
local project's issues.
|
|
13
|
+
|
|
14
|
+
## Status
|
|
15
|
+
|
|
16
|
+
| Skill | Purpose | Status |
|
|
17
|
+
| -------------------- | ------------------------------------------------------ | ---------------------------------------------------- |
|
|
18
|
+
| `suggest-site-pages` | Generic page-type suggestions by category | coming soon — issue #361 (tailwind-ai/ai-launch-kit) |
|
|
19
|
+
| `scaffold-page` | Generate a page with the appropriate schema.org type | coming soon — issue #362 (tailwind-ai/ai-launch-kit) |
|
|
20
|
+
| `scaffold-commerce` | Sell stuff: external store link or direct payments | coming soon — issue #363 (tailwind-ai/ai-launch-kit) |
|
|
21
|
+
| `scaffold-auth` | Wire up an auth flow against `@working-theory/auth-client` | coming soon — issue #364 (tailwind-ai/ai-launch-kit) |
|
|
22
|
+
| `audit-site` | Run `ailk audit` and explain the results | coming soon — issue #365 (tailwind-ai/ai-launch-kit) |
|
|
23
|
+
| `add-schema` | Add Product / Service / FAQ schema to an existing page | coming soon — issue #366 (tailwind-ai/ai-launch-kit) |
|
|
24
|
+
| `provision-config` | Generate `vercel.json` and environment templates | coming soon — issue #367 (tailwind-ai/ai-launch-kit) |
|
|
25
|
+
|
|
26
|
+
## How a skill ships
|
|
27
|
+
|
|
28
|
+
When a skill is built upstream, this directory will contain a
|
|
29
|
+
subdirectory of the same name, each holding:
|
|
30
|
+
|
|
31
|
+
- `SKILL.md` — when to invoke, what it produces, what it requires.
|
|
32
|
+
- Any supporting prompt fragments, code templates, or reference
|
|
33
|
+
files the skill loads at runtime.
|
|
34
|
+
|
|
35
|
+
Until then, the workflows the skills will perform can still be done
|
|
36
|
+
by hand or by asking Claude Code directly.
|
|
37
|
+
|
|
38
|
+
## Adding your own
|
|
39
|
+
|
|
40
|
+
To add a project-specific skill, create a folder here with a
|
|
41
|
+
`SKILL.md` describing it. Claude Code will discover it automatically
|
|
42
|
+
on session start. See the upstream `@working-theory/*` repository for examples
|
|
43
|
+
of the format.
|