create-ailk 0.30.0 → 0.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/README.md +71 -3
  2. package/component-catalog.json +524 -8
  3. package/component-catalog.md +8 -5
  4. package/dist/cli.js +99 -0
  5. package/dist/cutover.d.ts +109 -0
  6. package/dist/cutover.js +494 -0
  7. package/dist/design-presets.js +20 -4
  8. package/dist/export-content.d.ts +55 -0
  9. package/dist/export-content.js +303 -0
  10. package/dist/inventory.d.ts +216 -0
  11. package/dist/inventory.js +833 -0
  12. package/dist/language-import.d.ts +114 -0
  13. package/dist/language-import.js +435 -0
  14. package/dist/lib/env-catalog.js +1 -1
  15. package/dist/lib/import-mdx.d.ts +38 -0
  16. package/dist/lib/import-mdx.js +411 -64
  17. package/dist/lib/render-comparison.d.ts +200 -0
  18. package/dist/lib/render-comparison.js +374 -0
  19. package/dist/migrate-content.d.ts +6 -2
  20. package/dist/migrate-content.js +60 -14
  21. package/dist/seed-workspace.d.ts +3 -1
  22. package/dist/seed-workspace.js +45 -16
  23. package/dist/topology.d.ts +12 -0
  24. package/dist/topology.js +24 -10
  25. package/package.json +3 -3
  26. package/templates/.claude/cloudparity-repo-hooks.json +5 -0
  27. package/templates/.claude/hooks/content-source-guard.sh +75 -0
  28. package/templates/.claude/settings.json +9 -0
  29. package/templates/.github/workflows/ci.yml +2 -0
  30. package/templates/CLAUDE.md +5 -0
  31. package/templates/apps/mcp/CLAUDE.md +8 -4
  32. package/templates/apps/web/.env.example +4 -2
  33. package/templates/apps/web/CLAUDE.md +16 -5
  34. package/templates/apps/web/app/[locale]/[slug]/[detail]/__tests__/page.test.tsx +153 -4
  35. package/templates/apps/web/app/[locale]/[slug]/[detail]/page.tsx +45 -2
  36. package/templates/apps/web/app/[locale]/contact/__tests__/site-contact-lines.test.ts +49 -0
  37. package/templates/apps/web/app/[locale]/contact/site-contact-lines.ts +6 -4
  38. package/templates/apps/web/app/[locale]/events/[slug]/page.tsx +13 -1
  39. package/templates/apps/web/app/[locale]/events/__tests__/program-event.test.tsx +120 -0
  40. package/templates/apps/web/app/[locale]/events/page.tsx +11 -0
  41. package/templates/apps/web/app/[locale]/flows/[slug]/FlowStepperClient.tsx +44 -5
  42. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/FlowStepperClient.thanks-by-tier.test.tsx +306 -0
  43. package/templates/apps/web/app/[locale]/layout.tsx +122 -27
  44. package/templates/apps/web/app/[locale]/thanks/[slug]/__tests__/page.test.tsx +21 -2
  45. package/templates/apps/web/app/[locale]/thanks/[slug]/page.tsx +1 -0
  46. package/templates/apps/web/app/llms.txt/route.ts +16 -9
  47. package/templates/apps/web/app/sitemap.xml/route.ts +3 -0
  48. package/templates/apps/web/jest.config.cjs +46 -1
  49. package/templates/apps/web/lib/__tests__/bot-check.test.ts +247 -4
  50. package/templates/apps/web/lib/__tests__/in-page-magnet-self-request.test.ts +92 -0
  51. package/templates/apps/web/lib/__tests__/page-chrome.test.ts +90 -0
  52. package/templates/apps/web/lib/__tests__/relay.test.ts +33 -8
  53. package/templates/apps/web/lib/__tests__/site-identity-feature-list.test.ts +196 -0
  54. package/templates/apps/web/lib/__tests__/structured-data.test.tsx +11 -1
  55. package/templates/apps/web/lib/bot-check.ts +113 -13
  56. package/templates/apps/web/lib/in-page-magnet.ts +4 -1
  57. package/templates/apps/web/lib/page-chrome.ts +65 -5
  58. package/templates/apps/web/lib/relay.ts +22 -3
  59. package/templates/apps/web/lib/site-identity.ts +75 -24
  60. package/templates/apps/web/messages/en.json +5 -1
  61. package/templates/apps/web/next.config.mjs +15 -1
  62. package/templates/apps/web/package.json +1 -1
  63. package/templates/apps/web/scripts/assert-content-bundled.ts +36 -8
  64. package/templates/apps/web/scripts/content-snapshot.ts +33 -0
  65. package/templates/package.json +2 -1
  66. package/templates/tools/check-content-source.ts +108 -0
  67. package/versions.json +48 -48
package/README.md CHANGED
@@ -558,7 +558,9 @@ On a site with an Admin (the `workspace` or `multi-tenant` module), the
558
558
  starter's pages are also rows in the site's workspace, so the Admin's Docs
559
559
  lists Home, About, Contact and every other roster page on first open.
560
560
  `seed-workspace` writes them there: each `content/en/<Type>/<slug>.mdx` page
561
- becomes one draft `text/page` Artifact.
561
+ becomes one `text/page` Artifact, set Live when it has no Live version. A page
562
+ already Live is never published over: a newer draft stays a draft for the
563
+ owner to set Live in the Admin.
562
564
 
563
565
  ```bash
564
566
  AILK_AGENT_KEY=<agent key> create-ailk seed-workspace ./my-site --api-url <api origin> --workspace <wksp_id>
@@ -570,7 +572,9 @@ AILK_AGENT_KEY=<agent key> create-ailk seed-workspace ./my-site --api-url <api o
570
572
  and the origin's source, before any request.
571
573
  - The agent key is read from `AILK_AGENT_KEY` only — never a flag or a file —
572
574
  and never printed. An owner issues it in the Admin with the `content-edit`
573
- grant.
575
+ and `content-publish` grants. After the first refused publish, the rest of
576
+ the pages are saved as drafts and fail `not published`; a re-run with a
577
+ granted key publishes them.
574
578
  - Each page prints `created`, `updated`, `unchanged`, `skipped` or `failed`,
575
579
  then a count line. A re-run creates nothing and reports every page
576
580
  `unchanged`. An agent writes ten times a minute, so a first seed of about
@@ -580,6 +584,15 @@ AILK_AGENT_KEY=<agent key> create-ailk seed-workspace ./my-site --api-url <api o
580
584
  - The API must run with `content-write` and a tenancy module (`workspace` or
581
585
  `multi-tenant`) in `AILK_ENABLED_MODULES`. Without them the content routes
582
586
  are not served and every page fails `404`.
587
+ - When every page is in the workspace and Live, the site switches to the
588
+ database: `CONTENT_ADAPTER=database` is written to `apps/web/.env.local`
589
+ (which the web app reads) and to `apps/api/.env` (which the API that serves
590
+ the pages reads). Each app keeps a `CONTENT_ADAPTER` it already sets. A
591
+ skipped, refused or partial seed writes neither, and the site stays on
592
+ `content/` until a re-run succeeds.
593
+ - The API then serves the pages only when it runs on the database it was
594
+ seeded through (its `DATABASE_URL`) and its site resolves to the seeded
595
+ workspace.
583
596
  - Exit 0 when every page was seeded, 1 when any failed, 2 on a refusal (no
584
597
  `.ailk-site-manifest.json`, a spoke, a missing key, workspace id or origin,
585
598
  the adapter not installed), which sends nothing.
@@ -610,6 +623,17 @@ scaffold time — a site with no `.ailk-site-manifest.json`, or a spoke — into
610
623
  a workspace: each `content/en/<Type>/<slug>.mdx` page, and each legacy
611
624
  `content/<Type>/<slug>.mdx` page, becomes one draft `text/page` Artifact.
612
625
 
626
+ When the site has the docs-blog tree `apps/web/content`, its posts and docs
627
+ are imported too (#10701): `apps/web/content/en/blog/<slug>.mdx` and
628
+ `blog/<slug>/index.mdx` become `BlogPosting/<slug>`, the same under `docs`
629
+ become `DocsDetail/<slug>`, and each directory's own `index.mdx` becomes its
630
+ `BlogList/index` or `DocsList/index` — replacing a `content/` teaser of that
631
+ type. Their fumadocs frontmatter is mapped to the stored fields (`date` →
632
+ `publishedAt`, `updated` → `updatedAt`); keys the store does not keep from a
633
+ caller (`featured`, `sidebar`, `tags`) are not sent, and `--apply` names them
634
+ in one line per file. Each outcome carries `root: "content"` or
635
+ `root: "editorial"`, and an editorial line is printed prefixed `editorial: `.
636
+
613
637
  ```bash
614
638
  AILK_AGENT_KEY=<agent key> create-ailk migrate-content ./my-site --api-url <api origin> --workspace <wksp_id>
615
639
  AILK_AGENT_KEY=<agent key> create-ailk migrate-content ./my-site --apply --api-url <api origin> --workspace <wksp_id>
@@ -669,6 +693,50 @@ diff -r before after && echo "live site unchanged"
669
693
  A non-empty diff is a finding: stop and report it before migrating another
670
694
  site.
671
695
 
696
+ ### Cutting a site over to the database
697
+
698
+ Once a site's pages are in its workspace, three commands move it from its
699
+ page files to the database and back (#10648). Each reads the workspace with
700
+ `AILK_AGENT_KEY` (the `content-edit` grant), `--api-url`/`AILK_API_URL` and
701
+ `--workspace`/`AILK_WORKSPACE_ID`, as `migrate-content` does; a spoke also
702
+ needs `AILK_SPOKE_KEY`.
703
+
704
+ ```bash
705
+ # 1. Freeze what the site serves today, and audit it. Commit both files.
706
+ create-ailk inventory . --origin https://example.com
707
+ # → .ailk-cutover/inventory.json (written once; --refreeze crawls again)
708
+ # → .ailk-cutover/audit.json (every run: per page, words in Markdown? published?)
709
+
710
+ # 2. Plan the cutover, then run it against a preview reading the database.
711
+ create-ailk cutover . --before https://example.com --after https://preview.example.com
712
+ create-ailk cutover . --before https://example.com --after https://preview.example.com --apply
713
+
714
+ # Rollback: every published page back to its file, published edits kept.
715
+ create-ailk export-content .
716
+ ```
717
+
718
+ `inventory` freezes every URL the sitemap, a crawl and the route roster name,
719
+ with each page's prose status and images, and joins each page to its
720
+ workspace page — by the inventory's operator-written `joins`, the roster,
721
+ then `/blog` and the docs path. It exits 1 when any prose page is not
722
+ published or its words are not in its Markdown.
723
+
724
+ `cutover` runs import → publish → inventory → comparison → set env → deploy →
725
+ verify → remove files, in that order, and stops at the first step that fails.
726
+ The comparison renders every frozen page on both origins at 1440 and 390 wide
727
+ and records a text, JSON-LD and screenshot verdict for each, then sweeps every
728
+ frozen URL for a direct 200; it needs Playwright's Chromium in the site
729
+ (`pnpm add -D @playwright/test && pnpm exec playwright install chromium`).
730
+ Without `--apply` it sends only reads and writes and spawns nothing. The kit
731
+ never publishes: the publish step names the pages to publish in Admin. Step 8
732
+ stages the imported files' removal with `git rm`; you commit it. Each run's
733
+ record and screenshots go to `.ailk-cutover/runs/` (gitignored).
734
+
735
+ `export-content` writes each published page to the file `migrate-content`
736
+ reads it from, with its words moved back into its sections, so a re-run of
737
+ `migrate-content` reports every page `unchanged`. The full sequence, the
738
+ evidence each step leaves and each step's rollback are in the cutover runbook.
739
+
672
740
  ### A spoke's declared environment
673
741
 
674
742
  A spoke scaffold's `pnpm preflight` and CI run `pnpm env:declared`: every
@@ -755,7 +823,7 @@ The network invariant (#6759 D6), in full:
755
823
  3. Substitutes `workspace:*` references in every `package.json` with the matching `@working-theory/*` semver from npm — versions are pinned at npm-publish time.
756
824
  4. Substitutes `{{PROJECT_NAME}}`, `{{COMPANY_NAME}}`, `{{COMPANY_DOMAIN}}` markers in `templates/README.md` from the target directory name (and CLI flags / interactive prompts in future versions).
757
825
  5. Derives and writes `architecture.yaml` (the site's code-boundary config) from the selected module set — see below.
758
- 6. On a site with an Admin, seeds the starter's pages into its workspace when `--install` ran and `AILK_API_URL`, `AILK_WORKSPACE_ID` and `AILK_AGENT_KEY` are set, else prints why not and the `seed-workspace` command — see [Seeding the workspace](#seeding-the-workspace).
826
+ 6. On a site with an Admin, seeds the starter's pages into its workspace when `--install` ran and `AILK_API_URL`, `AILK_WORKSPACE_ID` and `AILK_AGENT_KEY` are set, sets each page Live and, when every page is Live, switches `apps/web` and `apps/api` to `CONTENT_ADAPTER=database`; else prints why not and the `seed-workspace` command that seeds and switches later — see [Seeding the workspace](#seeding-the-workspace).
759
827
  7. Prints next steps: `cd <dir> && pnpm install && pnpm dev`.
760
828
 
761
829
  ## `architecture.yaml` is derived from the module set