create-ailk 0.22.0 → 0.24.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/README.md +27 -14
- package/component-catalog.json +149 -5
- package/component-catalog.md +7 -6
- package/dist/add-module.js +17 -10
- package/dist/add-route.d.ts +55 -1
- package/dist/add-route.js +301 -13
- package/dist/cli.js +27 -10
- package/dist/derive-architecture.d.ts +7 -5
- package/dist/derive-architecture.js +26 -32
- package/dist/lib/design-checks.js +4 -2
- package/dist/lib/env-catalog.js +0 -4
- package/dist/lib/npm-auth.d.ts +9 -0
- package/dist/lib/npm-auth.js +48 -0
- package/dist/lib/scaffold-render-sweep.d.ts +36 -2
- package/dist/lib/scaffold-render-sweep.js +50 -8
- package/dist/module-architecture.js +115 -10
- package/dist/paid-sections.d.ts +21 -2
- package/dist/paid-sections.js +69 -7
- package/dist/seed-flows.d.ts +4 -1
- package/dist/seed-flows.js +50 -4
- package/dist/spoke-checkout.d.ts +38 -35
- package/dist/spoke-checkout.js +66 -229
- package/dist/starter-grid.d.ts +0 -3
- package/dist/starter-grid.js +24 -14
- package/dist/surfaces.js +33 -12
- package/dist/sync-routes.d.ts +68 -5
- package/dist/sync-routes.js +455 -29
- package/dist/template-record.d.ts +1 -1
- package/dist/template-record.js +3 -2
- package/dist/update.js +10 -0
- package/package.json +3 -3
- package/site-templates/_base/content/en/NewsletterSignup/newsletter.mdx +4 -49
- package/site-templates/_base/content/en/Pricing/pricing.mdx +3 -21
- package/site-templates/marketing-site/TEMPLATE-MANIFEST.json +23 -20
- package/site-templates/marketing-site/TEMPLATE-MANIFEST.md +28 -14
- package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.json +15 -39
- package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.md +38 -34
- package/site-templates/marketing-site-free/content/en/NewsletterSignup/newsletter.mdx +6 -43
- package/site-templates/shapes/local-business-service/TEMPLATE-MANIFEST.json +14 -31
- package/site-templates/shapes/local-business-service/TEMPLATE-MANIFEST.md +26 -25
- package/site-templates/shapes/local-business-service/content/en/NewsletterSignup/newsletter.mdx +6 -43
- package/site-templates/shapes/organization-service/TEMPLATE-MANIFEST.json +14 -31
- package/site-templates/shapes/organization-service/TEMPLATE-MANIFEST.md +26 -25
- package/site-templates/shapes/organization-service/content/en/NewsletterSignup/newsletter.mdx +6 -43
- package/site-templates/shapes/person-service/TEMPLATE-MANIFEST.json +14 -31
- package/site-templates/shapes/person-service/TEMPLATE-MANIFEST.md +26 -25
- package/site-templates/shapes/person-service/content/en/NewsletterSignup/newsletter.mdx +6 -43
- package/templates/.env.example +13 -7
- package/templates/.github/workflows/ci.yml +13 -0
- package/templates/CLAUDE.md +4 -2
- package/templates/README.md +1 -0
- package/templates/_gitignore +4 -0
- package/templates/apps/api/.env.example +34 -0
- package/templates/apps/api/CLAUDE.md +94 -19
- package/templates/apps/api/package.json +1 -0
- package/templates/apps/api/src/__tests__/factories/in-memory-prisma.ts +2 -0
- package/templates/apps/api/src/bin/stripe-connections-rekey.ts +45 -0
- package/templates/apps/api/src/config/__tests__/stripe-connection-key.test.ts +185 -0
- package/templates/apps/api/src/config/index.ts +109 -0
- package/templates/apps/api/src/lib/__mocks__/prisma.ts +7 -1
- package/templates/apps/api/src/lib/__tests__/flow-rename-race.db.test.ts +116 -0
- package/templates/apps/api/src/lib/__tests__/site.test.ts +16 -0
- package/templates/apps/api/src/lib/error-serializer.ts +74 -7
- package/templates/apps/api/src/lib/site.ts +4 -1
- package/templates/apps/api/src/lib/stripe.ts +77 -4
- package/templates/apps/api/src/lib/webhook-idempotency.ts +66 -2
- package/templates/apps/api/src/middleware/__tests__/rate-limit.test.ts +218 -0
- package/templates/apps/api/src/middleware/__tests__/write-budget.test.ts +174 -0
- package/templates/apps/api/src/middleware/rate-limit.ts +226 -4
- package/templates/apps/api/src/openapi/__tests__/openapi.test.ts +127 -0
- package/templates/apps/api/src/openapi/spec.ts +343 -7
- package/templates/apps/api/src/routes/billing/plan-checkout.ts +332 -0
- package/templates/apps/api/src/routes/checkout/__tests__/live-key.test.ts +11 -0
- package/templates/apps/api/src/routes/checkout/__tests__/offerings-authorization.test.ts +1426 -0
- package/templates/apps/api/src/routes/checkout/__tests__/session.test.ts +11 -0
- package/templates/apps/api/src/routes/checkout/__tests__/sessions.test.ts +49 -0
- package/templates/apps/api/src/routes/checkout/session.ts +57 -25
- package/templates/apps/api/src/routes/checkout/sessions.ts +232 -82
- package/templates/apps/api/src/routes/consent/__tests__/account.test.ts +5 -5
- package/templates/apps/api/src/routes/consent/__tests__/sign-up-rate-limit.test.ts +160 -0
- package/templates/apps/api/src/routes/consent/account.ts +4 -2
- package/templates/apps/api/src/routes/content/__tests__/get-page.test.ts +2 -2
- package/templates/apps/api/src/routes/content/__tests__/offerings.test.ts +731 -0
- package/templates/apps/api/src/routes/content/__tests__/pricing.test.ts +753 -0
- package/templates/apps/api/src/routes/content/__tests__/shown-offerings.test.ts +762 -0
- package/templates/apps/api/src/routes/content/get-page.ts +34 -119
- package/templates/apps/api/src/routes/content/index.ts +16 -2
- package/templates/apps/api/src/routes/content/list-pages.ts +15 -36
- package/templates/apps/api/src/routes/content/offerings.ts +184 -0
- package/templates/apps/api/src/routes/content/pricing.ts +176 -0
- package/templates/apps/api/src/routes/content/search.ts +16 -45
- package/templates/apps/api/src/routes/content/shown-offerings.ts +229 -0
- package/templates/apps/api/src/routes/leads/index.ts +377 -308
- package/templates/apps/api/src/routes/project-listings/__tests__/me.test.ts +20 -9
- package/templates/apps/api/src/routes/project-listings/__tests__/public.test.ts +17 -6
- package/templates/apps/api/src/routes/project-listings/__tests__/site-answers.test.ts +1 -1
- package/templates/apps/api/src/routes/webhooks/README.md +66 -0
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-flow-checkout.test.ts +1 -0
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-offerings.test.ts +814 -0
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-org-billing.test.ts +80 -68
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-site-filter.test.ts +6 -5
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe.test.ts +8 -2
- package/templates/apps/api/src/routes/webhooks/index.ts +23 -0
- package/templates/apps/api/src/routes/webhooks/stripe-offerings.ts +384 -0
- package/templates/apps/api/src/routes/webhooks/stripe.ts +93 -17
- package/templates/apps/api/src/server.ts +165 -51
- package/templates/apps/api/src/services/__tests__/abandon-email.test.ts +121 -4
- package/templates/apps/api/src/services/__tests__/checkout-plan.test.ts +313 -0
- package/templates/apps/api/src/services/__tests__/deliverable-fulfillment.test.ts +61 -2
- package/templates/apps/api/src/services/__tests__/keyless-workspace-predicate.test.ts +234 -0
- package/templates/apps/api/src/services/__tests__/lead-routing.test.ts +374 -44
- package/templates/apps/api/src/services/__tests__/person.test.ts +260 -1
- package/templates/apps/api/src/services/__tests__/plan-offerings.test.ts +450 -0
- package/templates/apps/api/src/services/__tests__/project-listings.counts.test.ts +202 -0
- package/templates/apps/api/src/services/__tests__/project-listings.fence.test.ts +15 -18
- package/templates/apps/api/src/services/abandon-email.ts +28 -5
- package/templates/apps/api/src/services/deliverable-fulfillment.ts +15 -12
- package/templates/apps/api/src/services/entitlements.ts +157 -1
- package/templates/apps/api/src/services/lead-routing.ts +113 -58
- package/templates/apps/api/src/services/offerings/__tests__/catalog.test.ts +348 -0
- package/templates/apps/api/src/services/offerings/__tests__/checkout-session-record.test.ts +268 -0
- package/templates/apps/api/src/services/offerings/__tests__/connection.test.ts +975 -0
- package/templates/apps/api/src/services/offerings/__tests__/fixtures.ts +416 -0
- package/templates/apps/api/src/services/offerings/__tests__/org-products.test.ts +400 -0
- package/templates/apps/api/src/services/offerings/__tests__/readers.test.ts +685 -0
- package/templates/apps/api/src/services/offerings/__tests__/source.test.ts +231 -0
- package/templates/apps/api/src/services/offerings/catalog.ts +318 -0
- package/templates/apps/api/src/services/offerings/checkout-authorization.ts +403 -0
- package/templates/apps/api/src/services/offerings/checkout-session-record.ts +192 -0
- package/templates/apps/api/src/services/offerings/connection.ts +1083 -0
- package/templates/apps/api/src/services/offerings/index.ts +614 -0
- package/templates/apps/api/src/services/offerings/source.ts +140 -0
- package/templates/apps/api/src/services/offerings/store.ts +150 -0
- package/templates/apps/api/src/services/person.ts +147 -9
- package/templates/apps/api/src/services/plan-offerings.ts +96 -30
- package/templates/apps/api/src/services/project-listings.ts +43 -31
- package/templates/apps/api/src/services/public-site-resolver.ts +19 -14
- package/templates/apps/mcp/CLAUDE.md +32 -18
- package/templates/apps/mcp/__tests__/app-entry.test.ts +2 -2
- package/templates/apps/mcp/__tests__/catalog-drift.test.ts +9 -4
- package/templates/apps/mcp/__tests__/get_offerings.test.ts +358 -0
- package/templates/apps/mcp/__tests__/get_pricing.test.ts +364 -0
- package/templates/apps/mcp/__tests__/http-transport.test.ts +95 -14
- package/templates/apps/mcp/__tests__/lib/content-adapter-parity.test.ts +8 -3
- package/templates/apps/mcp/__tests__/lib/content-adapter.test.ts +0 -25
- package/templates/apps/mcp/__tests__/lib/fail-closed-tools.test.ts +22 -7
- package/templates/apps/mcp/__tests__/list_pages.test.ts +84 -44
- package/templates/apps/mcp/__tests__/locale.test.ts +41 -56
- package/templates/apps/mcp/__tests__/module-exclusion.test.ts +2 -2
- package/templates/apps/mcp/__tests__/rate-limit-write.test.ts +189 -0
- package/templates/apps/mcp/__tests__/read_content.test.ts +115 -78
- package/templates/apps/mcp/__tests__/request_callback.test.ts +63 -128
- package/templates/apps/mcp/__tests__/search_content.test.ts +76 -61
- package/templates/apps/mcp/__tests__/server.test.ts +13 -11
- package/templates/apps/mcp/__tests__/start_purchase.test.ts +208 -12
- package/templates/apps/mcp/__tests__/submit_lead.test.ts +82 -167
- package/templates/apps/mcp/__tests__/subscribe_newsletter.test.ts +59 -130
- package/templates/apps/mcp/__tests__/tools/purchase.test.ts +11 -11
- package/templates/apps/mcp/package.json +1 -0
- package/templates/apps/mcp/src/abuse/index.ts +18 -11
- package/templates/apps/mcp/src/http-transport.ts +47 -9
- package/templates/apps/mcp/src/lib/content-adapter.ts +0 -26
- package/templates/apps/mcp/src/lib/empty-content-adapter.ts +5 -4
- package/templates/apps/mcp/src/lib/shown-offerings.ts +105 -0
- package/templates/apps/mcp/src/lib/site-config.ts +53 -0
- package/templates/apps/mcp/src/server.ts +5 -0
- package/templates/apps/mcp/src/tools/capture_lead.ts +30 -28
- package/templates/apps/mcp/src/tools/get_offerings.ts +47 -30
- package/templates/apps/mcp/src/tools/get_pricing.ts +40 -40
- package/templates/apps/mcp/src/tools/index.ts +22 -21
- package/templates/apps/mcp/src/tools/list_pages.ts +27 -33
- package/templates/apps/mcp/src/tools/purchase.ts +30 -2
- package/templates/apps/mcp/src/tools/read_content.ts +46 -40
- package/templates/apps/mcp/src/tools/request_callback.ts +21 -28
- package/templates/apps/mcp/src/tools/search_content.ts +20 -24
- package/templates/apps/mcp/src/tools/subscribe_newsletter.ts +23 -26
- package/templates/apps/mcp/src/workspace-server.ts +15 -0
- package/templates/apps/web/.env.example +10 -31
- package/templates/apps/web/CLAUDE.md +324 -42
- package/templates/apps/web/app/[locale]/(authed)/account/__tests__/agreements-prompt.test.tsx +3 -3
- package/templates/apps/web/app/[locale]/(authed)/account/__tests__/layout.test.tsx +3 -3
- package/templates/apps/web/app/[locale]/(authed)/account/__tests__/privacy.test.tsx +3 -3
- package/templates/apps/web/app/[locale]/careers/[slug]/[action]/page.tsx +189 -0
- package/templates/apps/web/app/[locale]/careers/[slug]/apply.actions.ts +4 -2
- package/templates/apps/web/app/[locale]/careers/[slug]/job-application-form.ts +8 -3
- package/templates/apps/web/app/[locale]/careers/[slug]/page.tsx +22 -144
- package/templates/apps/web/app/[locale]/careers/__tests__/apply.actions.test.ts +9 -0
- package/templates/apps/web/app/[locale]/careers/__tests__/careers-hub.test.tsx +172 -0
- package/templates/apps/web/app/[locale]/careers/__tests__/careers-set.test.tsx +149 -0
- package/templates/apps/web/app/[locale]/careers/__tests__/job-application-form.test.ts +22 -24
- package/templates/apps/web/app/[locale]/careers/__tests__/job-apply-page.test.tsx +140 -66
- package/templates/apps/web/app/[locale]/careers/__tests__/page-renderer-migration.test.tsx +57 -22
- package/templates/apps/web/app/[locale]/careers/page.tsx +129 -5
- package/templates/apps/web/app/[locale]/contact/__tests__/ConversationalIntakeWrapper.test.tsx +1 -1
- package/templates/apps/web/app/[locale]/contact/__tests__/contact-magnet-page.test.tsx +119 -11
- package/templates/apps/web/app/[locale]/contact/__tests__/contact.actions.test.ts +28 -5
- package/templates/apps/web/app/[locale]/contact/contact.actions.ts +20 -6
- package/templates/apps/web/app/[locale]/contact/intake-script.ts +1 -1
- package/templates/apps/web/app/[locale]/contact/page.tsx +99 -92
- package/templates/apps/web/app/[locale]/flows/[slug]/FlowStepperClient.tsx +237 -5
- package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/FlowStepperClient.count.test.tsx +43 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/FlowStepperClient.deliverable.test.tsx +200 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/FlowStepperClient.ending.test.tsx +197 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/magnet-page.test.tsx +430 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/two-route-tool.test.tsx +21 -9
- package/templates/apps/web/app/[locale]/flows/[slug]/magnet-page.tsx +369 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/page.tsx +12 -73
- package/templates/apps/web/app/[locale]/flows/[slug]/start/page.tsx +10 -31
- package/templates/apps/web/app/[locale]/layout.tsx +55 -4
- package/templates/apps/web/app/[locale]/newsletter/__tests__/page.test.tsx +174 -104
- package/templates/apps/web/app/[locale]/newsletter/page.tsx +95 -58
- package/templates/apps/web/app/[locale]/pricing/__tests__/__snapshots__/unconnected.test.tsx.snap +7 -0
- package/templates/apps/web/app/[locale]/pricing/__tests__/offerings.test.tsx +599 -0
- package/templates/apps/web/app/[locale]/pricing/__tests__/page.test.tsx +216 -0
- package/templates/apps/web/app/[locale]/pricing/__tests__/unconnected.test.tsx +236 -0
- package/templates/apps/web/app/[locale]/pricing/page.tsx +367 -6
- package/templates/apps/web/app/[locale]/team/__tests__/team-routes.test.tsx +4 -1
- package/templates/apps/web/app/[locale]/unsubscribe/__tests__/unsubscribe-rsc-boundary.test.tsx +17 -0
- package/templates/apps/web/app/[locale]/unsubscribe/__tests__/unsubscribe.test.tsx +62 -3
- package/templates/apps/web/app/[locale]/unsubscribe/page.tsx +70 -18
- package/templates/apps/web/app/[locale]/unsubscribe/unsubscribe-button.tsx +30 -9
- package/templates/apps/web/app/api/offerings/checkout/[lookupKey]/route.ts +316 -0
- package/templates/apps/web/app/api/offerings/checkout/__tests__/route.test.ts +810 -0
- package/templates/apps/web/lib/__tests__/auth-routes.test.ts +27 -1
- package/templates/apps/web/lib/__tests__/deck-page.test.ts +2 -1
- package/templates/apps/web/lib/__tests__/in-page-magnet.test.ts +265 -0
- package/templates/apps/web/lib/__tests__/magnet-routes.test.ts +64 -0
- package/templates/apps/web/lib/__tests__/newsletter.actions.test.ts +293 -0
- package/templates/apps/web/lib/__tests__/offerings-pricing.test.ts +601 -0
- package/templates/apps/web/lib/__tests__/structured-data.test.tsx +67 -8
- package/templates/apps/web/lib/auth-routes.ts +36 -2
- package/templates/apps/web/lib/checkout-config.ts +9 -20
- package/templates/apps/web/lib/deck-page.ts +1 -0
- package/templates/apps/web/lib/deliverable-grant.ts +18 -0
- package/templates/apps/web/lib/in-page-magnet.ts +416 -0
- package/templates/apps/web/lib/magnet-routes.ts +44 -0
- package/templates/apps/web/lib/modules.generated.ts +9 -0
- package/templates/apps/web/lib/newsletter.actions.ts +205 -0
- package/templates/apps/web/lib/offerings-pricing.ts +326 -0
- package/templates/apps/web/lib/posting-title.ts +17 -0
- package/templates/apps/web/lib/sign-up-agreements.ts +4 -2
- package/templates/apps/web/messages/en.json +49 -15
- package/templates/apps/web/middleware.ts +12 -2
- package/templates/apps/web/security-headers.config.ts +17 -0
- package/templates/content/en/BlogList/blog.mdx +4 -71
- package/templates/content/en/BookCall/book-a-call.mdx +1 -41
- package/templates/content/en/BookCall/onsite-estimate.mdx +1 -17
- package/templates/content/en/BookCall/onsite-service.mdx +1 -17
- package/templates/content/en/BookCall/start-project.mdx +1 -17
- package/templates/content/en/ContactPage/contact.mdx +6 -63
- package/templates/content/en/HomePage/home.mdx +3 -21
- package/templates/database/CHANGELOG.md +51 -0
- package/templates/database/__tests__/in-page-magnets-migration.test.ts +161 -0
- package/templates/database/__tests__/offerings-checkout-session.db.test.ts +270 -0
- package/templates/database/__tests__/offerings-migration.test.ts +197 -0
- package/templates/database/__tests__/offerings-shown-price-ids-migration.test.ts +86 -0
- package/templates/database/__tests__/offerings.db.test.ts +303 -0
- package/templates/database/__tests__/seed.test.ts +63 -1
- package/templates/database/__tests__/trial-magnet-migration.test.ts +186 -0
- package/templates/database/auth/schema.prisma +4 -0
- package/templates/database/config/schema.prisma +91 -0
- package/templates/database/migrations/20261020120000_offerings_data_model/migration.sql +146 -0
- package/templates/database/migrations/20261021120000_offerings_checkout_session/migration.sql +77 -0
- package/templates/database/migrations/20261022120000_in_page_magnets/migration.sql +45 -0
- package/templates/database/migrations/20261023120000_offerings_shown_price_ids/migration.sql +47 -0
- package/templates/database/migrations/20261024120000_organization_plan_checkout_session/migration.sql +16 -0
- package/templates/database/migrations/20261025120000_trial_magnet/migration.sql +28 -0
- package/templates/database/migrations/20261026120000_trial_magnet_proof_line/migration.sql +23 -0
- package/templates/database/package.json +1 -1
- package/templates/database/seed.ts +57 -2
- package/templates/tools/lint-architecture.ts +205 -1
- package/versions.json +35 -35
- package/site-templates/marketing-site-free/content/en/Pricing/pricing.mdx +0 -199
- package/templates/apps/api/src/routes/content/slug.ts +0 -9
- package/templates/apps/web/app/[locale]/downloads/__tests__/page-renderer-migration.test.tsx +0 -93
- package/templates/apps/web/app/[locale]/downloads/page.tsx +0 -37
- package/templates/apps/web/app/[locale]/newsletter/__tests__/newsletter.actions.test.ts +0 -139
- package/templates/apps/web/app/[locale]/newsletter/newsletter.actions.ts +0 -93
- package/templates/apps/web/app/api/checkout/[offering]/route.ts +0 -48
- package/templates/apps/web/app/api/checkout/__tests__/route.test.ts +0 -120
- package/templates/apps/web/app/api/checkout/__tests__/success-path.test.ts +0 -86
- package/templates/apps/web/app/api/webhooks/stripe/__tests__/route.test.ts +0 -92
- package/templates/apps/web/app/api/webhooks/stripe/route.ts +0 -31
- package/templates/apps/web/lib/__tests__/checkout.test.ts +0 -243
- package/templates/apps/web/lib/__tests__/meeting-slugs.test.ts +0 -120
- package/templates/apps/web/lib/checkout.ts +0 -93
- package/templates/apps/web/lib/meeting-slugs.ts +0 -63
package/README.md
CHANGED
|
@@ -214,9 +214,9 @@ as-is, they never fail the check, and `--apply` never overwrites them.
|
|
|
214
214
|
|
|
215
215
|
`--apply` only creates route directories that are absent, through the same
|
|
216
216
|
copier a fresh scaffold uses (so the copied files are byte-identical to a fresh
|
|
217
|
-
scaffold's). It never rewrites or deletes an existing file,
|
|
218
|
-
outside `apps/web/app/[locale]
|
|
219
|
-
no-op. `--apply` exits 0 on success.
|
|
217
|
+
scaffold's). It never rewrites or deletes an existing file, writes nothing
|
|
218
|
+
outside `apps/web/app/[locale]/` except the local modules those routes import
|
|
219
|
+
(below), runs no install, and a second run is a no-op. `--apply` exits 0 on success.
|
|
220
220
|
|
|
221
221
|
**Scope.** Every core route (`about`, `contact`, `faq`, `thanks/[slug]`,
|
|
222
222
|
`sign-in`) is always checked, and so is the `(authed)` route GROUP —
|
|
@@ -232,17 +232,30 @@ gated off at scaffold time is listed as skipped, not missing — its absence is
|
|
|
232
232
|
deliberate, not drift. Add a surface with `--sync-architecture` and the
|
|
233
233
|
`add-page` skill, not with `sync-routes`.
|
|
234
234
|
|
|
235
|
-
**The
|
|
236
|
-
files OUTSIDE their own route directory — `
|
|
237
|
-
`apps/web/lib/
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
235
|
+
**The local-module dependency contract (#5014, #9406).** Some routes import
|
|
236
|
+
files OUTSIDE their own route directory — `purchase/success/page.tsx` imports
|
|
237
|
+
`apps/web/src/lib/commerce-claim.ts`; the `(authed)` group's `layout.tsx`
|
|
238
|
+
imports `apps/web/auth.ts`. Copying a route's directory alone would leave those
|
|
239
|
+
imports dangling in an older consumer that never had them. So `sync-routes`
|
|
240
|
+
resolves every relative import (`./`, `../`) of every file the route would
|
|
241
|
+
copy, and of every helper that brings in turn, against the site first and then
|
|
242
|
+
the template. `ROUTE_DEPENDENCIES` in `src/surfaces.ts` is a declared
|
|
243
|
+
supplement, unioned with what the resolver finds. Each imported module has one
|
|
244
|
+
of three outcomes:
|
|
245
|
+
|
|
246
|
+
- **Copied** — the site lacks it and the template has it: `--apply` copies it
|
|
247
|
+
(never overwriting) and check mode lists it under `copies:` and `Also
|
|
248
|
+
required`.
|
|
249
|
+
- **Left as-is** — the site has it and its copy differs from the template's:
|
|
250
|
+
it is named under `left as-is (differs from the template)` and never
|
|
251
|
+
written. The route is still copied; run your type-check afterwards.
|
|
252
|
+
- **Refused** — the import resolves to no file in the site or the template,
|
|
253
|
+
only to a spoke-excluded file, or to a surface the site does not carry: the
|
|
254
|
+
route is listed under `cannot resolve:` and `--apply` does not write it, nor
|
|
255
|
+
its sub-routes, nor a route that imports from it. Its ancestor route is still
|
|
256
|
+
copied without the refused sub-tree.
|
|
257
|
+
|
|
258
|
+
`ROUTE_MESSAGE_NAMESPACES`
|
|
246
259
|
does the same for the i18n namespaces a route's copy needs
|
|
247
260
|
(`signIn`, `account`, `waitlistDashboard.gate`) — but CHECK-ONLY: a
|
|
248
261
|
consumer's `apps/web/messages/<locale>.json` already exists and may carry
|
package/component-catalog.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"importPath": "@working-theory/ui/sections",
|
|
10
10
|
"rootBarrel": "@working-theory/ui",
|
|
11
11
|
"sourceRoot": "packages/ui/src/sections",
|
|
12
|
-
"count":
|
|
12
|
+
"count": 57
|
|
13
13
|
},
|
|
14
14
|
{
|
|
15
15
|
"name": "blocks",
|
|
@@ -485,6 +485,17 @@
|
|
|
485
485
|
"descriptionGrade": "strong",
|
|
486
486
|
"sectionType": "items"
|
|
487
487
|
},
|
|
488
|
+
{
|
|
489
|
+
"name": "ItemsFilterIsland",
|
|
490
|
+
"tier": "sections",
|
|
491
|
+
"sourcePath": "packages/ui/src/sections/ItemsFilterIsland.tsx",
|
|
492
|
+
"importPath": "@working-theory/ui/sections",
|
|
493
|
+
"exported": false,
|
|
494
|
+
"description": "A search box and facet selects over an items section's cards. Items (a Server Component) renders every card on the server and wraps each in an `ItemsFilterSlot`; the island only decides which slots show. So every card is in the server HTML, and before hydration (or with no JavaScript) every slot is visible.",
|
|
495
|
+
"descriptionSource": "doc-comment",
|
|
496
|
+
"descriptionGrade": "strong",
|
|
497
|
+
"sectionType": null
|
|
498
|
+
},
|
|
488
499
|
{
|
|
489
500
|
"name": "ItemsTileLinkIsland",
|
|
490
501
|
"tier": "sections",
|
|
@@ -1426,7 +1437,7 @@
|
|
|
1426
1437
|
"sourcePath": "packages/ui/src/blocks/NewsletterFormInline.tsx",
|
|
1427
1438
|
"importPath": "@working-theory/ui/blocks",
|
|
1428
1439
|
"exported": true,
|
|
1429
|
-
"description": "Inline email signup form: email Input + submit Button side-by-side at
|
|
1440
|
+
"description": "Inline email signup form: email Input + submit Button side-by-side at md+, stacked on mobile (input full-width on its own row, Subscribe below). Manages its own submit state so the parent Newsletter section can remain RSC-oriented (only this block needs the client boundary).",
|
|
1430
1441
|
"descriptionSource": "doc-comment",
|
|
1431
1442
|
"descriptionGrade": "strong",
|
|
1432
1443
|
"sectionType": null
|
|
@@ -4795,6 +4806,30 @@
|
|
|
4795
4806
|
"alt"
|
|
4796
4807
|
]
|
|
4797
4808
|
},
|
|
4809
|
+
"avatar": {
|
|
4810
|
+
"type": "object",
|
|
4811
|
+
"properties": {
|
|
4812
|
+
"src": {
|
|
4813
|
+
"type": "string"
|
|
4814
|
+
},
|
|
4815
|
+
"alt": {
|
|
4816
|
+
"type": "string"
|
|
4817
|
+
},
|
|
4818
|
+
"width": {
|
|
4819
|
+
"type": "number"
|
|
4820
|
+
},
|
|
4821
|
+
"height": {
|
|
4822
|
+
"type": "number"
|
|
4823
|
+
},
|
|
4824
|
+
"blurDataURL": {
|
|
4825
|
+
"type": "string"
|
|
4826
|
+
}
|
|
4827
|
+
},
|
|
4828
|
+
"required": [
|
|
4829
|
+
"src",
|
|
4830
|
+
"alt"
|
|
4831
|
+
]
|
|
4832
|
+
},
|
|
4798
4833
|
"logoStrip": {
|
|
4799
4834
|
"type": "object",
|
|
4800
4835
|
"properties": {
|
|
@@ -5335,6 +5370,17 @@
|
|
|
5335
5370
|
"body"
|
|
5336
5371
|
]
|
|
5337
5372
|
}
|
|
5373
|
+
},
|
|
5374
|
+
"facets": {
|
|
5375
|
+
"type": "object",
|
|
5376
|
+
"propertyNames": {
|
|
5377
|
+
"type": "string"
|
|
5378
|
+
},
|
|
5379
|
+
"additionalProperties": {
|
|
5380
|
+
"type": "string",
|
|
5381
|
+
"minLength": 1,
|
|
5382
|
+
"maxLength": 80
|
|
5383
|
+
}
|
|
5338
5384
|
}
|
|
5339
5385
|
},
|
|
5340
5386
|
"required": [
|
|
@@ -5342,6 +5388,13 @@
|
|
|
5342
5388
|
]
|
|
5343
5389
|
}
|
|
5344
5390
|
},
|
|
5391
|
+
"gapAbove": {
|
|
5392
|
+
"type": "string",
|
|
5393
|
+
"enum": [
|
|
5394
|
+
"default",
|
|
5395
|
+
"tight"
|
|
5396
|
+
]
|
|
5397
|
+
},
|
|
5345
5398
|
"surface": {
|
|
5346
5399
|
"type": "string",
|
|
5347
5400
|
"enum": [
|
|
@@ -5360,6 +5413,76 @@
|
|
|
5360
5413
|
"card",
|
|
5361
5414
|
"plain"
|
|
5362
5415
|
]
|
|
5416
|
+
},
|
|
5417
|
+
"filter": {
|
|
5418
|
+
"type": "object",
|
|
5419
|
+
"properties": {
|
|
5420
|
+
"searchLabel": {
|
|
5421
|
+
"type": "string",
|
|
5422
|
+
"minLength": 1,
|
|
5423
|
+
"maxLength": 80
|
|
5424
|
+
},
|
|
5425
|
+
"facets": {
|
|
5426
|
+
"maxItems": 4,
|
|
5427
|
+
"type": "array",
|
|
5428
|
+
"items": {
|
|
5429
|
+
"type": "object",
|
|
5430
|
+
"properties": {
|
|
5431
|
+
"key": {
|
|
5432
|
+
"type": "string",
|
|
5433
|
+
"pattern": "^[a-z][a-z0-9-]{0,31}$"
|
|
5434
|
+
},
|
|
5435
|
+
"label": {
|
|
5436
|
+
"type": "string",
|
|
5437
|
+
"minLength": 1,
|
|
5438
|
+
"maxLength": 80
|
|
5439
|
+
},
|
|
5440
|
+
"allLabel": {
|
|
5441
|
+
"type": "string",
|
|
5442
|
+
"minLength": 1,
|
|
5443
|
+
"maxLength": 80
|
|
5444
|
+
}
|
|
5445
|
+
},
|
|
5446
|
+
"required": [
|
|
5447
|
+
"key",
|
|
5448
|
+
"label",
|
|
5449
|
+
"allLabel"
|
|
5450
|
+
],
|
|
5451
|
+
"additionalProperties": false
|
|
5452
|
+
}
|
|
5453
|
+
},
|
|
5454
|
+
"emptyText": {
|
|
5455
|
+
"type": "string",
|
|
5456
|
+
"minLength": 1,
|
|
5457
|
+
"maxLength": 200
|
|
5458
|
+
},
|
|
5459
|
+
"countText": {
|
|
5460
|
+
"type": "object",
|
|
5461
|
+
"properties": {
|
|
5462
|
+
"one": {
|
|
5463
|
+
"type": "string",
|
|
5464
|
+
"minLength": 1,
|
|
5465
|
+
"maxLength": 80
|
|
5466
|
+
},
|
|
5467
|
+
"other": {
|
|
5468
|
+
"type": "string",
|
|
5469
|
+
"minLength": 1,
|
|
5470
|
+
"maxLength": 80
|
|
5471
|
+
}
|
|
5472
|
+
},
|
|
5473
|
+
"required": [
|
|
5474
|
+
"one",
|
|
5475
|
+
"other"
|
|
5476
|
+
],
|
|
5477
|
+
"additionalProperties": false
|
|
5478
|
+
}
|
|
5479
|
+
},
|
|
5480
|
+
"required": [
|
|
5481
|
+
"searchLabel",
|
|
5482
|
+
"emptyText",
|
|
5483
|
+
"countText"
|
|
5484
|
+
],
|
|
5485
|
+
"additionalProperties": false
|
|
5363
5486
|
}
|
|
5364
5487
|
},
|
|
5365
5488
|
"required": [
|
|
@@ -5375,7 +5498,8 @@
|
|
|
5375
5498
|
"separation",
|
|
5376
5499
|
"gap",
|
|
5377
5500
|
"surface",
|
|
5378
|
-
"itemStyle"
|
|
5501
|
+
"itemStyle",
|
|
5502
|
+
"gapAbove"
|
|
5379
5503
|
]
|
|
5380
5504
|
},
|
|
5381
5505
|
{
|
|
@@ -6767,6 +6891,9 @@
|
|
|
6767
6891
|
"annualBadge": {
|
|
6768
6892
|
"type": "string"
|
|
6769
6893
|
},
|
|
6894
|
+
"annualCtaHref": {
|
|
6895
|
+
"type": "string"
|
|
6896
|
+
},
|
|
6770
6897
|
"priceSubheadAccent": {
|
|
6771
6898
|
"type": "string"
|
|
6772
6899
|
},
|
|
@@ -6999,6 +7126,9 @@
|
|
|
6999
7126
|
"annualBadge": {
|
|
7000
7127
|
"type": "string"
|
|
7001
7128
|
},
|
|
7129
|
+
"annualCtaHref": {
|
|
7130
|
+
"type": "string"
|
|
7131
|
+
},
|
|
7002
7132
|
"priceSubheadAccent": {
|
|
7003
7133
|
"type": "string"
|
|
7004
7134
|
},
|
|
@@ -10727,6 +10857,13 @@
|
|
|
10727
10857
|
"hideEventTypeDetails": {
|
|
10728
10858
|
"type": "boolean"
|
|
10729
10859
|
},
|
|
10860
|
+
"gapAbove": {
|
|
10861
|
+
"type": "string",
|
|
10862
|
+
"enum": [
|
|
10863
|
+
"default",
|
|
10864
|
+
"tight"
|
|
10865
|
+
]
|
|
10866
|
+
},
|
|
10730
10867
|
"fallback": {
|
|
10731
10868
|
"default": "auto",
|
|
10732
10869
|
"type": "string",
|
|
@@ -10748,7 +10885,8 @@
|
|
|
10748
10885
|
"look": [
|
|
10749
10886
|
"surface",
|
|
10750
10887
|
"height",
|
|
10751
|
-
"layout"
|
|
10888
|
+
"layout",
|
|
10889
|
+
"gapAbove"
|
|
10752
10890
|
]
|
|
10753
10891
|
},
|
|
10754
10892
|
{
|
|
@@ -11536,13 +11674,19 @@
|
|
|
11536
11674
|
"no-outline",
|
|
11537
11675
|
"no-download",
|
|
11538
11676
|
"no-print",
|
|
11539
|
-
"no-share"
|
|
11677
|
+
"no-share",
|
|
11678
|
+
"no-zoom",
|
|
11679
|
+
"no-fullscreen"
|
|
11540
11680
|
]
|
|
11541
11681
|
}
|
|
11542
11682
|
},
|
|
11543
11683
|
"downloadFilename": {
|
|
11544
11684
|
"type": "string"
|
|
11545
11685
|
},
|
|
11686
|
+
"shareUrl": {
|
|
11687
|
+
"type": "string",
|
|
11688
|
+
"format": "uri"
|
|
11689
|
+
},
|
|
11546
11690
|
"surface": {
|
|
11547
11691
|
"type": "string",
|
|
11548
11692
|
"enum": [
|
package/component-catalog.md
CHANGED
|
@@ -15,13 +15,13 @@ The component inventory of `@working-theory/ui` and the shells of `@working-theo
|
|
|
15
15
|
3. Check the Primitives, Panels and Shells tables too — a low-level control, a collapsible layout container, or a route-level frame lives there, not under Sections or Blocks.
|
|
16
16
|
4. Only then build. If you do build, you are declaring the capability is genuinely absent.
|
|
17
17
|
|
|
18
|
-
Inventory: **
|
|
18
|
+
Inventory: **321 component files** across 16 tiers — 57 sections, 107 blocks, 19 chrome, 79 primitives, 6 panels, 8 shells, 5 docs-blog-blocks, 1 docs-blog-chrome, 2 docs-blog-shells, 2 scheduling-sections, 6 scheduling-blocks, 5 signal-collectors-sections, 9 signal-collectors-blocks, 2 commerce-sections, 12 commerce-blocks, 1 commerce-panels. 318 distinct names: `SchedulerEmbed`, `Separator`, `Tabs` exist in more than one tier as genuinely different components, listed once per tier with its own source path.
|
|
19
19
|
|
|
20
|
-
Description coverage: **
|
|
20
|
+
Description coverage: **317/321** components carry a capability description derived from source — 44 from the section registry's hand-authored when-to-use text, 238 from the component's own doc-comment header, 35 from its tier barrel's roster line. **4** have none; they are listed under [Undescribed components](#undescribed-components) rather than given a sentence invented from their name.
|
|
21
21
|
|
|
22
|
-
Of those, **
|
|
22
|
+
Of those, **283** are *strong* — a capability sentence you could match a requirement against — and **34** are *weak*: either one short clause, or a long one that spends itself on wiring (client boundaries, class names, which primitives it composes) instead of on what the thing is for. Weak rows are marked `(weak)` and listed in full under [Weak descriptions](#weak-descriptions). Coverage is 99%, but **findable-without-luck coverage is 88%**.
|
|
23
23
|
|
|
24
|
-
Per tier, strong out of total: **Sections**
|
|
24
|
+
Per tier, strong out of total: **Sections** 56/57 · **Blocks** 99/107 · **Chrome** 10/19 · **Primitives** 64/79 (4 undescribed) · **Panels** 5/6 · **Shells** 7/8 · **Docs + Blog Blocks** 5/5 · **Docs + Blog Chrome** 1/1 · **Docs + Blog Shells** 0/2 · **Scheduling Sections** 2/2 · **Scheduling Blocks** 6/6 · **Signal-Collectors Sections** 5/5 · **Signal-Collectors Blocks** 8/9 · **Commerce Sections** 2/2 · **Commerce Blocks** 12/12 · **Commerce Panels** 1/1. A tier low on this line is a tier where a capability search is most likely to come up empty on something that exists.
|
|
25
25
|
|
|
26
26
|
That grade is **mechanical**. It counts what it can measure — how much a description adds beyond the component's own name, how much of it is spent on wiring, whether the extraction came out damaged — and it cannot tell a fluent paragraph about the wrong subject from a useful one. A person reading these tables will find more rows unusable than the weak count admits. Treat it as a floor on the problem, not a measurement of it, and read the source before concluding a capability is absent.
|
|
27
27
|
|
|
@@ -53,7 +53,7 @@ The left column is search vocabulary — how a person phrases the need. It is ha
|
|
|
53
53
|
|
|
54
54
|
---
|
|
55
55
|
|
|
56
|
-
## Sections (
|
|
56
|
+
## Sections (57)
|
|
57
57
|
|
|
58
58
|
Page-level content bands. Most are MDX-driven (authored by `type` in page frontmatter and dispatched by `SectionRenderer`); a few are composed directly in a route.
|
|
59
59
|
|
|
@@ -93,6 +93,7 @@ Import: `import { X } from "@working-theory/ui/sections";` (or from the `@workin
|
|
|
93
93
|
| `HeroPromptCapture` | The Hero `promptCapture` opt-in's wiring. Composes the two new blocks — `PromptCaptureCard` (the chat-style card) and `SuggestionChipCarousel` (the one-expanded-slot chip row) — and owns the ONE piece of state they share: the typed text. A chip click writes into it; the card renders and edits it; submit carries it onward. | `import { HeroPromptCapture } from "@working-theory/ui/sections"` |
|
|
94
94
|
| `HeroQuickSearch` | Surfaces the existing ⌘K quick-search as an inline trigger inside the hero CTA cluster (Chassis 2). It does NOT re-roll a search input: it composes the SearchInputTrigger primitive (an input-style control at CTA height) plus the Command palette primitive, so there is ONE search mechanism. The nav's compact 24px ⌘K pill stays as-is — the hero reads as a search INPUT, matching the 44px "Get Started" CTA. | internal — compose from `packages/ui/src/sections/HeroQuickSearch.tsx` |
|
|
95
95
|
| `Items` | A general-purpose card/items grid — use for services, use cases, or any homogeneous list of cards. | MDX `type: items` · `import { Items } from "@working-theory/ui/sections"` |
|
|
96
|
+
| `ItemsFilterIsland` | A search box and facet selects over an items section's cards. Items (a Server Component) renders every card on the server and wraps each in an `ItemsFilterSlot`; the island only decides which slots show. So every card is in the server HTML, and before hydration (or with no JavaScript) every slot is visible. | internal — compose from `packages/ui/src/sections/ItemsFilterIsland.tsx` |
|
|
96
97
|
| `ItemsTileLinkIsland` | Makes a whole linked tile card its link's click target. | internal — compose from `packages/ui/src/sections/ItemsTileLinkIsland.tsx` |
|
|
97
98
|
| `LogoCloud` | A customer/partner logo wall — use for trust-by-association social proof. | MDX `type: logoCloud` · `import { LogoCloud } from "@working-theory/ui/sections"` |
|
|
98
99
|
| `MDXContent` | The keystone the docs route and blog both render their compiled MDX through. | `import { MDXContent } from "@working-theory/ui/sections"` |
|
|
@@ -190,7 +191,7 @@ Import: `import { X } from "@working-theory/ui/blocks";` (or from the `@working-
|
|
|
190
191
|
| `NavFlyoutPanel` | Mega-menu body block (feature grid + action bar) for Nav flyouts. Renders the content of a flyout (mega-menu) panel opened by a NavigationMenu trigger in the Nav chrome component. | `import { NavFlyoutPanel } from "@working-theory/ui/blocks"` |
|
|
191
192
|
| `NavSearchTrigger` | ⌘K search trigger control for Nav desktop pill + mobile icon-only surfaces. ⌘K search trigger button for Nav, desktop + mobile. Thin domain wrapper over the ShortcutTrigger primitive: it resolves the i18n "Open search" label and passes the search specifics (Search icon, the ⌘/K shortcut, the onSearchOpen handler) to ShortcutTrigger. | `import { NavSearchTrigger } from "@working-theory/ui/blocks"` |
|
|
192
193
|
| `NewsletterDetail` | One "why subscribe" detail item: colored icon square + headline + description. Vertically arranged (icon top, heading + description below). Used in the right-column 2-up grid of the 'side-by-side-with-details' variant. | `import { NewsletterDetail } from "@working-theory/ui/blocks"` |
|
|
193
|
-
| `NewsletterFormInline` | Inline email signup form: email Input + submit Button side-by-side at
|
|
194
|
+
| `NewsletterFormInline` | Inline email signup form: email Input + submit Button side-by-side at md+, stacked on mobile (input full-width on its own row, Subscribe below). Manages its own submit state so the parent Newsletter section can remain RSC-oriented (only this block needs the client boundary). | `import { NewsletterFormInline } from "@working-theory/ui/blocks"` |
|
|
194
195
|
| `OnboardingChecklist` | Global onboarding launcher: floating "N/5" bubble expanding into a Popover (lg+) / bottom Sheet (<lg) checklist with SegmentedProgress + item rows (ploy-capture recomposition). The global onboarding launcher captured off ploy.ai's app frame (behavior spec: `post-ftu-checklist` — "global onboarding launcher (floating, all pages)"). | `import { OnboardingChecklist } from "@working-theory/ui/blocks"` |
|
|
195
196
|
| `PageHeader` | RSC. Page-level header composing the Breadcrumb primitive for the left-side wayfinding trail, a generic right-side `actions` slot, and an optional `switcher` slot for header-owned segment switching. Fills AppShell's `header` slot (AdminShell and similar). No accent bar. No tab API. No named action props — the caller assembles whatever button/menu nodes it needs and passes them as `actions`. *(weak)* | `import { PageHeader } from "@working-theory/ui/blocks"` |
|
|
196
197
|
| `PageHeaderSwitcher` | Header-owned context-switcher island (DropdownMenu-backed). Header-owned segment switcher rendered inside PageHeader's `switcher` slot. Composes DropdownMenu (Radix-backed — positioning, click-outside, Escape, focus management, and roving keyboard nav all come for free). | `import { PageHeaderSwitcher } from "@working-theory/ui/blocks"` |
|
package/dist/add-module.js
CHANGED
|
@@ -35,7 +35,7 @@ import { writeAuthSecretFile } from "./lib/auth-secret-file.js";
|
|
|
35
35
|
import { appendEnvRows } from "./lib/declared-env.js";
|
|
36
36
|
import { diffTwoStrings, extractModuleBundle, } from "./lib/extract-module-bundle.js";
|
|
37
37
|
import { normalizeModules } from "./module-architecture.js";
|
|
38
|
-
import { PAID_SECTIONS_PATH, writePaidSections } from "./paid-sections.js";
|
|
38
|
+
import { MODULE_FLAGS_PATH, PAID_SECTIONS_PATH, writePaidSections } from "./paid-sections.js";
|
|
39
39
|
import { ParseError, parseModules } from "./parse-args.js";
|
|
40
40
|
import { writeSpokeFlowsReadme } from "./seed-flows.js";
|
|
41
41
|
import { SITE_ROSTER_PATH, moduleRosterRows, planRosterAppend, readSiteRoster, siteRosterProblems, } from "./site-roster.js";
|
|
@@ -209,16 +209,18 @@ export async function applyModuleToScaffold(opts) {
|
|
|
209
209
|
// #7536 D3 — the paid-sections registry follows `apps/web/package.json`,
|
|
210
210
|
// which the bundle's `patches` just edited. Generated and always
|
|
211
211
|
// overwritten, like `architecture.yaml` above.
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
212
|
+
// #8843 D10 — its module-presence flags follow the same file, and are
|
|
213
|
+
// reported the same way when a module turns one on.
|
|
214
|
+
const generated = [PAID_SECTIONS_PATH, MODULE_FLAGS_PATH].map((path) => {
|
|
215
|
+
const abs = join(targetAbs, path);
|
|
216
|
+
return { path, abs, before: existsSync(abs) ? readFileSync(abs, "utf8") : undefined };
|
|
217
|
+
});
|
|
216
218
|
writePaidSections(targetAbs);
|
|
217
|
-
const registryChanged = existsSync(registryPath) &&
|
|
218
|
-
readFileSync(registryPath, "utf8") !== registryBefore;
|
|
219
219
|
const rows = [...report, ...checkoutRows];
|
|
220
|
-
|
|
221
|
-
|
|
220
|
+
for (const { path, abs, before } of generated) {
|
|
221
|
+
if (existsSync(abs) && readFileSync(abs, "utf8") !== before)
|
|
222
|
+
rows.push({ path, action: "written" });
|
|
223
|
+
}
|
|
222
224
|
const navRow = syncNavConfig(targetAbs, current.surfaces, surfaces);
|
|
223
225
|
if (navRow !== undefined)
|
|
224
226
|
rows.push(navRow);
|
|
@@ -349,7 +351,9 @@ export function formatAddModuleReport(result, moduleName) {
|
|
|
349
351
|
const lines = [
|
|
350
352
|
`[create-ailk] add-module ${moduleName} → ${result.targetDir}`,
|
|
351
353
|
];
|
|
352
|
-
if (result.report.length === 0 &&
|
|
354
|
+
if (result.report.length === 0 &&
|
|
355
|
+
result.routes.applied.length === 0 &&
|
|
356
|
+
result.routes.refused.length === 0) {
|
|
353
357
|
lines.push(`Nothing to add — the site already carries everything ${moduleName} brings.`);
|
|
354
358
|
}
|
|
355
359
|
if (written.length > 0) {
|
|
@@ -385,6 +389,9 @@ export function formatAddModuleReport(result, moduleName) {
|
|
|
385
389
|
lines.push(`Also copied ${routes.appliedDependencies.length} file(s) those routes import:`);
|
|
386
390
|
lines.push(...routes.appliedDependencies.map((dep) => ` ${dep}`));
|
|
387
391
|
}
|
|
392
|
+
if (routes.refused.length > 0) {
|
|
393
|
+
lines.push(`Routes not copied (${routes.refused.length}) — an import does not resolve (run create-ailk sync-routes for the paths): ${routes.refused.join(", ")}`);
|
|
394
|
+
}
|
|
388
395
|
if (routes.missingMessageNamespaces.length > 0) {
|
|
389
396
|
lines.push("Also required — message namespace(s) not found in apps/web/messages/en.json (add manually, not auto-merged):");
|
|
390
397
|
lines.push(...routes.missingMessageNamespaces.map((ns) => ` ${ns}`));
|
package/dist/add-route.d.ts
CHANGED
|
@@ -40,17 +40,71 @@ export interface AddRouteResult {
|
|
|
40
40
|
export declare function addRouteToScaffold(opts: AddRouteOptions): AddRouteResult;
|
|
41
41
|
/** The report `add-route` prints. */
|
|
42
42
|
export declare function formatAddRouteReport(result: AddRouteResult): string;
|
|
43
|
+
/** The route word that selects the magnet mode. */
|
|
44
|
+
export declare const MAGNET_ROUTE = "magnet";
|
|
45
|
+
/**
|
|
46
|
+
* The header-comment marker every standard magnet page carries — the same
|
|
47
|
+
* string `flows/[slug]/magnet-page.tsx` exports, which the site's
|
|
48
|
+
* `structured-data.test.tsx` reads to exempt the pair (#8840 D13).
|
|
49
|
+
*/
|
|
50
|
+
export declare const MAGNET_PAGE_MARKER = "Standard magnet page (#8840)";
|
|
51
|
+
/** Whether `slug` passes `flowSlugSchema`'s rule. */
|
|
52
|
+
export declare function isMagnetFlowSlug(slug: string): boolean;
|
|
53
|
+
export interface AddMagnetOptions {
|
|
54
|
+
/** The already-scaffolded site. */
|
|
55
|
+
targetDir: string;
|
|
56
|
+
/** The site path the landing serves, e.g. `/diagnostic`. */
|
|
57
|
+
path: string;
|
|
58
|
+
/** The flow slug the pair is bound to. */
|
|
59
|
+
flow: string;
|
|
60
|
+
}
|
|
61
|
+
/** One page of the pair: written, or left as the site has it. */
|
|
62
|
+
export interface MagnetReportRow {
|
|
63
|
+
path: string;
|
|
64
|
+
action: "written" | "skipped";
|
|
65
|
+
}
|
|
66
|
+
export interface AddMagnetResult {
|
|
67
|
+
/** Resolved absolute path to the site. */
|
|
68
|
+
targetDir: string;
|
|
69
|
+
/** The landing's site path. */
|
|
70
|
+
path: string;
|
|
71
|
+
/** The bound flow slug. */
|
|
72
|
+
flow: string;
|
|
73
|
+
/** The landing's row, then the walk's. */
|
|
74
|
+
report: MagnetReportRow[];
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Write a magnet page pair — `apps/web/app/[locale]/<path>/page.tsx` (the
|
|
78
|
+
* landing) and `<path>/start/page.tsx` (the walk) — bound to one flow slug.
|
|
79
|
+
* Each page is a few lines over the factories in `flows/[slug]/magnet-page`;
|
|
80
|
+
* the copy, consent and ending come from the flow's record.
|
|
81
|
+
*
|
|
82
|
+
* Every refusal throws `AddRouteRefusedError` before the first write. A page
|
|
83
|
+
* that already exists is never overwritten: a second run reports both
|
|
84
|
+
* `skipped`. No `architecture.yaml`, nav or seed changes — the pair is the
|
|
85
|
+
* site's own, with no `ROUTE_SINCE` key or routes-map row (D13).
|
|
86
|
+
*/
|
|
87
|
+
export declare function addMagnetToScaffold(opts: AddMagnetOptions): AddMagnetResult;
|
|
88
|
+
/** The report `add-route magnet` prints. */
|
|
89
|
+
export declare function formatAddMagnetReport(result: AddMagnetResult): string;
|
|
43
90
|
export interface AddRouteArgs {
|
|
44
91
|
/** The route to add; undefined only with `help`. */
|
|
45
92
|
route: string | undefined;
|
|
46
93
|
/** Positional target directory; undefined = the caller's cwd. */
|
|
47
94
|
target: string | undefined;
|
|
48
95
|
help: boolean;
|
|
96
|
+
/** `--path`, the magnet mode's site path — set only with `magnet`. */
|
|
97
|
+
path?: string;
|
|
98
|
+
/** `--flow`, the magnet mode's flow slug — set only with `magnet`. */
|
|
99
|
+
flow?: string;
|
|
49
100
|
}
|
|
50
|
-
export declare const ADD_ROUTE_HELP = "create-ailk add-route \u2014 add a route family to an existing site.\n\nUsage:\n create-ailk add-route <route> [<target-dir>]\n\nArguments:\n <route> One route family, named as --surfaces names it,\n e.g. pricing.\n <target-dir> An already-scaffolded repo (contains\n architecture.yaml). Defaults to the current dir.\n\nOptions:\n --help, -h Print this message.\n\nCopies the route's pages, writes its seed content, declares it in\narchitecture.yaml and adds its link to the generated nav \u2014 the site a fresh\nscaffold with --surfaces <route> would have been. A file the site already has\nis never overwritten: one whose content differs, a hand-edited nav included,\nis left as-is and listed for manual review with the change the route wanted.\nLike add-module, it also restores any other page route the site carries but\nlacks. A route a module delivers (blog and docs come with docs-blog) is\nrefused; add that module with create-ailk add-module. Running it again changes\nnothing.\n";
|
|
101
|
+
export declare const ADD_ROUTE_HELP = "create-ailk add-route \u2014 add a route family to an existing site.\n\nUsage:\n create-ailk add-route <route> [<target-dir>]\n create-ailk add-route magnet --path <path> --flow <slug> [<target-dir>]\n\nArguments:\n <route> One route family, named as --surfaces names it,\n e.g. pricing.\n <target-dir> An already-scaffolded repo (contains\n architecture.yaml). Defaults to the current dir.\n\nOptions:\n --path <path> magnet only: the site path the landing serves,\n one to three kebab-case segments, e.g. /diagnostic.\n --flow <slug> magnet only: the flow slug the pages are bound to.\n --help, -h Print this message.\n\nCopies the route's pages, writes its seed content, declares it in\narchitecture.yaml and adds its link to the generated nav \u2014 the site a fresh\nscaffold with --surfaces <route> would have been. A file the site already has\nis never overwritten: one whose content differs, a hand-edited nav included,\nis left as-is and listed for manual review with the change the route wanted.\nLike add-module, it also restores any other page route the site carries but\nlacks. A route a module delivers (blog and docs come with docs-blog) is\nrefused; add that module with create-ailk add-module. Running it again changes\nnothing.\n\nadd-route magnet writes a magnet page pair bound to one flow: a landing at\napps/web/app/[locale]/<path>/page.tsx and a full-screen walk at\n<path>/start/page.tsx, each a few lines over the standard magnet pages, so the\ncopy, consent and ending come from the flow's record. It needs the\nsignal-collectors module, and refuses (nothing written) a path the site already\nserves, a one-segment path a LandingPage seed of the same slug owns, a path\nending in start or apply, a reserved first segment (api, v1, flows, account,\nadmin, the sign-in routes, a locale) and a slug the flow API would refuse. A\npage that exists is never overwritten: running it again skips both. It changes\nno architecture.yaml, nav or seed.\n";
|
|
51
102
|
/**
|
|
52
103
|
* Parse the argv AFTER the `add-route` word. Strict `node:util` parseArgs,
|
|
53
104
|
* like `parseAddModuleArgs`; the route itself is validated by
|
|
54
105
|
* `addRouteToScaffold`, which refuses an unknown one naming the recognized.
|
|
106
|
+
* `--path` and `--flow` belong to the `magnet` route word alone (#8840 D12):
|
|
107
|
+
* with any other route they are refused (`AddRouteRefusedError`, exit 2),
|
|
108
|
+
* and `magnet` needs both. Their values are checked by `addMagnetToScaffold`.
|
|
55
109
|
*/
|
|
56
110
|
export declare function parseAddRouteArgs(argv: string[]): AddRouteArgs;
|