blume 2.0.1 → 2.0.2
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/CHANGELOG.md +82 -0
- package/dist/cli/{chunk-vtk4a6dg.js → chunk-00gs3wqs.js} +1 -1
- package/dist/cli/{chunk-fa25z98p.js → chunk-273ygyr4.js} +4 -3
- package/dist/cli/chunk-273ygyr4.js.map +11 -0
- package/dist/cli/{chunk-yw7dm696.js → chunk-3yce002v.js} +21 -8
- package/dist/cli/{chunk-yw7dm696.js.map → chunk-3yce002v.js.map} +3 -3
- package/dist/cli/{chunk-yt5n7ppj.js → chunk-4e9b9ra6.js} +17 -7
- package/dist/cli/chunk-4e9b9ra6.js.map +10 -0
- package/dist/cli/{chunk-fs23ddbb.js → chunk-5r8g91qn.js} +352 -676
- package/dist/cli/chunk-5r8g91qn.js.map +34 -0
- package/dist/cli/{chunk-6vm74dry.js → chunk-6dtt0zfn.js} +8 -8
- package/dist/cli/{chunk-qwsrynx5.js → chunk-6k4ftwze.js} +38 -19
- package/dist/cli/{chunk-qwsrynx5.js.map → chunk-6k4ftwze.js.map} +4 -4
- package/dist/cli/{chunk-qs4q5p4e.js → chunk-7mbqtmgb.js} +16 -7
- package/dist/cli/chunk-7mbqtmgb.js.map +10 -0
- package/dist/cli/{chunk-q5163e60.js → chunk-7vtckvaw.js} +21 -19
- package/dist/cli/chunk-7vtckvaw.js.map +11 -0
- package/dist/cli/{chunk-kdp5q7ke.js → chunk-8g8ytmgx.js} +17 -18
- package/dist/cli/{chunk-kdp5q7ke.js.map → chunk-8g8ytmgx.js.map} +2 -2
- package/dist/cli/{chunk-epjnccmv.js → chunk-91ws1n6j.js} +18 -15
- package/dist/cli/chunk-91ws1n6j.js.map +10 -0
- package/dist/cli/{chunk-fxypxtvm.js → chunk-bbnwccaz.js} +2 -2
- package/dist/cli/{chunk-m3vmjgmq.js → chunk-bfwp9vp6.js} +16 -8
- package/dist/cli/chunk-bfwp9vp6.js.map +10 -0
- package/dist/cli/{chunk-f2z5v128.js → chunk-d1v5rhy0.js} +14 -15
- package/dist/cli/{chunk-f2z5v128.js.map → chunk-d1v5rhy0.js.map} +2 -2
- package/dist/cli/{chunk-6crbhc3x.js → chunk-ddndchfr.js} +21 -6
- package/dist/cli/chunk-ddndchfr.js.map +14 -0
- package/dist/cli/{chunk-ce574jw2.js → chunk-esh98wmb.js} +1 -1
- package/dist/cli/{chunk-zxcczpyx.js → chunk-fsmrqk8a.js} +1 -1
- package/dist/cli/{chunk-hdpx1tax.js → chunk-g698a744.js} +5 -5
- package/dist/cli/{chunk-jts8mvcz.js → chunk-gs7r695n.js} +9 -3
- package/dist/cli/{chunk-jts8mvcz.js.map → chunk-gs7r695n.js.map} +3 -3
- package/dist/cli/{chunk-zxh4d9vy.js → chunk-h2ez8dzb.js} +4 -4
- package/dist/cli/{chunk-5shv93fd.js → chunk-h7k3nq3v.js} +2 -2
- package/dist/cli/{chunk-79jhk4py.js → chunk-hqp2ajnh.js} +251 -122
- package/dist/cli/chunk-hqp2ajnh.js.map +35 -0
- package/dist/cli/{chunk-2hn4b8z7.js → chunk-hr8ne106.js} +109 -40
- package/dist/cli/chunk-hr8ne106.js.map +13 -0
- package/dist/cli/{chunk-6hsn950k.js → chunk-j85scx15.js} +62 -18
- package/dist/cli/chunk-j85scx15.js.map +10 -0
- package/dist/cli/{chunk-s1p84fyh.js → chunk-k7pj68a8.js} +63 -22
- package/dist/cli/chunk-k7pj68a8.js.map +11 -0
- package/dist/cli/{chunk-ah61y8py.js → chunk-mqc662a6.js} +2 -2
- package/dist/cli/{chunk-ch6g3ar0.js → chunk-n1yg3tj3.js} +4 -4
- package/dist/cli/{chunk-mb2919y2.js → chunk-nfcyttvj.js} +17 -6
- package/dist/cli/chunk-nfcyttvj.js.map +10 -0
- package/dist/cli/{chunk-kpf8rrjc.js → chunk-pbg5a4s3.js} +56 -24
- package/dist/cli/chunk-pbg5a4s3.js.map +19 -0
- package/dist/cli/{chunk-jwyddg7y.js → chunk-ppzjqwx2.js} +21 -14
- package/dist/cli/{chunk-jwyddg7y.js.map → chunk-ppzjqwx2.js.map} +4 -4
- package/dist/cli/{chunk-dh8cwk36.js → chunk-qkb5a8sa.js} +24 -9
- package/dist/cli/chunk-qkb5a8sa.js.map +10 -0
- package/dist/cli/{chunk-wm7js3j9.js → chunk-sqw4ekg1.js} +2 -2
- package/dist/cli/{chunk-qkqwkpte.js → chunk-v6ya5kcb.js} +3083 -953
- package/dist/cli/chunk-v6ya5kcb.js.map +189 -0
- package/dist/cli/{chunk-fz5wtpmh.js → chunk-w4bxdvsa.js} +18 -15
- package/dist/cli/chunk-w4bxdvsa.js.map +10 -0
- package/dist/cli/{chunk-27g6wdth.js → chunk-wdrt2k2v.js} +2 -2
- package/dist/cli/{chunk-wgm7m9qk.js → chunk-xh43dwgw.js} +158 -43
- package/dist/cli/chunk-xh43dwgw.js.map +36 -0
- package/dist/cli/{chunk-s6jhgk0q.js → chunk-zp79m0ts.js} +2 -2
- package/dist/cli/index.js +160 -35
- package/dist/cli/index.js.map +4 -4
- package/dist/types/ai/agent-surface.d.ts +32 -0
- package/dist/types/ai/api-catalog.d.ts +7 -1
- package/dist/types/ai/ask-context.d.ts +7 -0
- package/dist/types/ai/component-markdown.d.ts +4 -4
- package/dist/types/ai/relative-links.d.ts +9 -4
- package/dist/types/ai/static-expression.d.ts +28 -0
- package/dist/types/analytics/databuddy.d.ts +43 -0
- package/dist/types/analytics/index.d.ts +2 -0
- package/dist/types/analytics/schema.d.ts +14 -0
- package/dist/types/cli/env.d.ts +5 -0
- package/dist/types/cli/init/scaffold.d.ts +19 -3
- package/dist/types/cli/init/starter-spec.d.ts +11 -0
- package/dist/types/core/base-path.d.ts +9 -0
- package/dist/types/core/config-input.d.ts +4 -4
- package/dist/types/core/config.d.ts +2 -2
- package/dist/types/core/graph.d.ts +2 -0
- package/dist/types/core/i18n-ui.d.ts +31 -0
- package/dist/types/core/i18n.d.ts +7 -1
- package/dist/types/core/links.d.ts +3 -1
- package/dist/types/core/load-module.d.ts +10 -0
- package/dist/types/core/locale-links.d.ts +12 -2
- package/dist/types/core/meta.d.ts +5 -1
- package/dist/types/core/nav-diagnostics.d.ts +10 -0
- package/dist/types/core/navigation.d.ts +38 -0
- package/dist/types/core/ordering-prefix.d.ts +4 -0
- package/dist/types/core/safe-links.d.ts +3 -1
- package/dist/types/core/schema.d.ts +52 -13
- package/dist/types/core/sources/github-releases.d.ts +5 -0
- package/dist/types/core/sources/lower.d.ts +14 -2
- package/dist/types/core/sources/normalize.d.ts +10 -1
- package/dist/types/core/sources/remote.d.ts +11 -1
- package/dist/types/core/sources/resolve.d.ts +12 -0
- package/dist/types/core/sources/types.d.ts +31 -0
- package/dist/types/core/types.d.ts +9 -0
- package/dist/types/deploy/adapters/node.d.ts +5 -2
- package/dist/types/deploy/adapters/types.d.ts +7 -0
- package/dist/types/deploy/cloudflare-negotiation.d.ts +3 -2
- package/dist/types/deploy/headers.d.ts +31 -7
- package/dist/types/deploy/node-headers.d.ts +43 -8
- package/dist/types/deploy/platforms/netlify.d.ts +27 -2
- package/dist/types/deploy/platforms/node.d.ts +6 -5
- package/dist/types/deploy/platforms/types.d.ts +7 -0
- package/dist/types/deploy/platforms/vercel.d.ts +3 -2
- package/dist/types/deploy/redirects.d.ts +7 -2
- package/dist/types/deploy/vercel-negotiation.d.ts +3 -2
- package/dist/types/openapi/model.d.ts +20 -6
- package/dist/types/search/sync/algolia.d.ts +3 -1
- package/docs/01-quickstart.mdx +3 -2
- package/docs/02-deployment.mdx +17 -8
- package/docs/08-faq.mdx +9 -2
- package/docs/advanced/changelog.mdx +1 -1
- package/docs/advanced/custom-pages.mdx +4 -2
- package/docs/cli/audit.mdx +2 -2
- package/docs/cli/doctor.mdx +2 -2
- package/docs/cli/evals.mdx +2 -2
- package/docs/cli/index.mdx +4 -1
- package/docs/cli/translate.mdx +1 -1
- package/docs/configuration/analytics.mdx +23 -2
- package/docs/configuration/assistant.mdx +1 -1
- package/docs/configuration/customization.mdx +4 -3
- package/docs/configuration/index.mdx +5 -3
- package/docs/configuration/search.mdx +1 -1
- package/docs/content/components.mdx +1 -1
- package/docs/content/frontmatter.mdx +5 -1
- package/docs/content/i18n.mdx +1 -1
- package/docs/content/index.mdx +4 -2
- package/docs/content/meta.mdx +5 -3
- package/docs/content/navigation.mdx +29 -4
- package/docs/content/sources.mdx +18 -12
- package/docs/content/versioning.mdx +1 -0
- package/docs/discoverability/agent-discovery.mdx +21 -7
- package/docs/discoverability/index.mdx +2 -2
- package/docs/discoverability/llms-txt.mdx +2 -5
- package/docs/discoverability/markdown.mdx +5 -3
- package/docs/discoverability/mcp.mdx +4 -0
- package/docs/discoverability/metadata.mdx +3 -2
- package/docs/discoverability/open-graph.mdx +6 -4
- package/docs/discoverability/rss.mdx +3 -1
- package/docs/references/asyncapi.mdx +1 -1
- package/docs/references/graphql.mdx +2 -2
- package/docs/references/openapi.mdx +3 -3
- package/package.json +1 -1
- package/skills/blume-migrate/SKILL.md +6 -6
- package/skills/blume-migrate/references/docusaurus.md +6 -6
- package/skills/blume-migrate/references/mintlify.md +3 -3
- package/skills/blume-migrate/references/monorepo.md +1 -1
- package/skills/blume-migrate/references/nextra.md +1 -1
- package/skills/blume-migrate/references/starlight.md +5 -5
- package/skills/blume-migrate/scripts/mintlify-codemod.mjs +2 -2
- package/skills/blume-update-docs/references/audit-checklist.md +1 -1
- package/src/ai/agent-surface.ts +56 -0
- package/src/ai/api/spec.ts +15 -2
- package/src/ai/api-catalog.ts +7 -1
- package/src/ai/ask-context.ts +14 -2
- package/src/ai/ask-data.ts +26 -12
- package/src/ai/component-markdown.ts +43 -37
- package/src/ai/link-headers.ts +8 -3
- package/src/ai/llms.ts +4 -3
- package/src/ai/markdown.ts +23 -11
- package/src/ai/mcp/server.ts +78 -7
- package/src/ai/relative-links.ts +78 -10
- package/src/ai/static-expression.ts +416 -0
- package/src/ai/visibility.ts +45 -14
- package/src/analytics/databuddy.ts +67 -0
- package/src/analytics/head.ts +4 -0
- package/src/analytics/index.ts +2 -0
- package/src/analytics/posthog.ts +21 -3
- package/src/analytics/schema.ts +2 -0
- package/src/astro/generate.ts +71 -27
- package/src/astro/templates.ts +61 -23
- package/src/audit/catalog.ts +2 -2
- package/src/audit/checks/assets.ts +25 -5
- package/src/audit/checks/content.ts +20 -2
- package/src/audit/checks/i18n.ts +46 -8
- package/src/audit/checks/indexability.ts +39 -19
- package/src/audit/checks/links.ts +14 -0
- package/src/audit/checks/llms.ts +6 -3
- package/src/audit/checks/network.ts +3 -1
- package/src/audit/checks/og-image.ts +10 -0
- package/src/audit/checks/robots.ts +6 -1
- package/src/audit/checks/sitemap.ts +56 -31
- package/src/audit/checks/social.ts +21 -2
- package/src/audit/crawl.ts +88 -15
- package/src/audit/report.ts +54 -17
- package/src/audit/run.ts +1 -0
- package/src/audit/types.ts +18 -0
- package/src/audit/url.ts +37 -6
- package/src/cli/build-failure.ts +50 -0
- package/src/cli/commands/audit.ts +7 -0
- package/src/cli/commands/build.ts +19 -5
- package/src/cli/commands/check.ts +2 -0
- package/src/cli/commands/eval.ts +1 -7
- package/src/cli/commands/init.ts +15 -5
- package/src/cli/commands/preview.ts +15 -0
- package/src/cli/commands/sync.ts +2 -0
- package/src/cli/commands/translate.ts +9 -6
- package/src/cli/commands/upgrade.ts +11 -0
- package/src/cli/eject-scripts.ts +32 -7
- package/src/cli/env.ts +12 -1
- package/src/cli/init/scaffold.ts +117 -11
- package/src/cli/init/starter-spec.ts +235 -0
- package/src/components/content/AccordionItem.astro +26 -22
- package/src/components/content/Badge.astro +2 -9
- package/src/components/content/Card.astro +2 -2
- package/src/components/content/Component.astro +9 -3
- package/src/components/content/Expandable.astro +5 -1
- package/src/components/content/Frame.astro +2 -7
- package/src/components/content/GithubInfo.astro +12 -2
- package/src/components/content/Prompt.astro +2 -7
- package/src/components/content/Tabs.astro +54 -5
- package/src/components/content/Tile.astro +1 -1
- package/src/components/content/Tooltip.astro +69 -7
- package/src/components/content/Tree.astro +7 -2
- package/src/components/content/TypeTable.astro +10 -5
- package/src/components/content/Update.astro +8 -2
- package/src/components/content/auto-type-table.ts +4 -1
- package/src/components/content/badge-color.ts +17 -0
- package/src/components/content/base-href.ts +18 -3
- package/src/components/content/inline-markdown.ts +27 -7
- package/src/components/copy-feedback.ts +35 -8
- package/src/components/islands/assistant.tsx +16 -2
- package/src/components/islands/hooks.ts +7 -2
- package/src/components/islands/webmcp.ts +12 -8
- package/src/components/layout/Banner.astro +23 -4
- package/src/components/layout/Header.astro +22 -9
- package/src/components/layout/Logo.astro +5 -0
- package/src/components/layout/NavSelector.astro +6 -1
- package/src/components/layout/NavTabMenu.astro +133 -0
- package/src/components/layout/NavTree.astro +15 -6
- package/src/components/layout/NavTreeCache.astro +5 -2
- package/src/components/layout/NavTreeScript.astro +45 -5
- package/src/components/layout/PageLayout.astro +22 -8
- package/src/components/layout/ReferenceLayout.astro +4 -1
- package/src/components/layout/RootLayout.astro +21 -8
- package/src/components/layout/Search.astro +5 -1
- package/src/components/layout/analytics-client.ts +2 -0
- package/src/components/openapi/GraphqlType.astro +11 -3
- package/src/components/openapi/MessageComposer.astro +1 -1
- package/src/components/openapi/Operation.astro +21 -5
- package/src/components/openapi/PanelTabs.astro +4 -1
- package/src/components/openapi/Playground.astro +8 -2
- package/src/components/openapi/RequestPanel.astro +9 -5
- package/src/components/openapi/SchemaProperty.astro +11 -33
- package/src/components/openapi/SchemaTable.astro +27 -52
- package/src/components/openapi/helpers.ts +90 -12
- package/src/components/openapi/message-composer.ts +8 -0
- package/src/components/openapi/message-model.ts +12 -2
- package/src/components/openapi/message.ts +4 -1
- package/src/components/openapi/operation-model.ts +40 -8
- package/src/components/openapi/panel.ts +29 -5
- package/src/components/openapi/playground-client.ts +37 -7
- package/src/components/openapi/playground-schema.ts +25 -6
- package/src/components/openapi/request.ts +2 -0
- package/src/components/openapi/schema-tree.ts +203 -0
- package/src/components/openapi/snippets.ts +30 -15
- package/src/components/openapi/validate-json.ts +1 -1
- package/src/core/base-path.ts +15 -0
- package/src/core/config-input.ts +4 -4
- package/src/core/config.ts +18 -4
- package/src/core/diagnostics.ts +217 -30
- package/src/core/graph.ts +120 -11
- package/src/core/i18n-ui.ts +39 -2
- package/src/core/i18n.ts +13 -2
- package/src/core/links.ts +7 -4
- package/src/core/load-module.ts +20 -0
- package/src/core/locale-links.ts +17 -17
- package/src/core/manifest.ts +3 -2
- package/src/core/meta.ts +69 -6
- package/src/core/nav-diagnostics.ts +56 -1
- package/src/core/navigation.ts +245 -76
- package/src/core/ordering-prefix.ts +27 -0
- package/src/core/project-graph.ts +23 -1
- package/src/core/safe-href.ts +53 -1
- package/src/core/safe-links.ts +11 -2
- package/src/core/schema.ts +70 -14
- package/src/core/sources/assets.ts +83 -41
- package/src/core/sources/contentful-rich-text.ts +3 -2
- package/src/core/sources/contentful.ts +25 -12
- package/src/core/sources/filesystem.ts +5 -1
- package/src/core/sources/github-releases.ts +106 -5
- package/src/core/sources/lexical.ts +9 -4
- package/src/core/sources/lower.ts +79 -26
- package/src/core/sources/mdx-remote.ts +1 -0
- package/src/core/sources/normalize.ts +132 -30
- package/src/core/sources/notion.ts +26 -10
- package/src/core/sources/obsidian.ts +17 -3
- package/src/core/sources/payload.ts +1 -0
- package/src/core/sources/portable-text.ts +63 -44
- package/src/core/sources/remote.ts +18 -2
- package/src/core/sources/resolve.ts +52 -33
- package/src/core/sources/sanity.ts +1 -0
- package/src/core/sources/strapi-blocks.ts +9 -4
- package/src/core/sources/strapi.ts +1 -0
- package/src/core/sources/types.ts +31 -0
- package/src/core/types.ts +9 -0
- package/src/core/ui-packs/ar.ts +13 -0
- package/src/core/ui-packs/bg.ts +13 -0
- package/src/core/ui-packs/bn.ts +13 -0
- package/src/core/ui-packs/ca.ts +13 -0
- package/src/core/ui-packs/cs.ts +13 -0
- package/src/core/ui-packs/da.ts +13 -0
- package/src/core/ui-packs/de.ts +13 -0
- package/src/core/ui-packs/el.ts +13 -0
- package/src/core/ui-packs/es.ts +13 -0
- package/src/core/ui-packs/fa.ts +13 -0
- package/src/core/ui-packs/fi.ts +13 -0
- package/src/core/ui-packs/fr.ts +13 -0
- package/src/core/ui-packs/he.ts +13 -0
- package/src/core/ui-packs/hi.ts +13 -0
- package/src/core/ui-packs/hr.ts +13 -0
- package/src/core/ui-packs/hu.ts +13 -0
- package/src/core/ui-packs/id.ts +13 -0
- package/src/core/ui-packs/it.ts +13 -0
- package/src/core/ui-packs/ja.ts +13 -0
- package/src/core/ui-packs/ko.ts +13 -0
- package/src/core/ui-packs/nl.ts +13 -0
- package/src/core/ui-packs/no.ts +13 -0
- package/src/core/ui-packs/pl.ts +13 -0
- package/src/core/ui-packs/pt-br.ts +13 -0
- package/src/core/ui-packs/pt.ts +13 -0
- package/src/core/ui-packs/ro.ts +13 -0
- package/src/core/ui-packs/ru.ts +13 -0
- package/src/core/ui-packs/sk.ts +13 -0
- package/src/core/ui-packs/sr.ts +13 -0
- package/src/core/ui-packs/sv.ts +13 -0
- package/src/core/ui-packs/th.ts +13 -0
- package/src/core/ui-packs/tr.ts +13 -0
- package/src/core/ui-packs/uk.ts +13 -0
- package/src/core/ui-packs/vi.ts +13 -0
- package/src/core/ui-packs/zh-tw.ts +13 -0
- package/src/core/ui-packs/zh.ts +13 -0
- package/src/core/version-cut.ts +17 -2
- package/src/core/versions.ts +4 -1
- package/src/deploy/adapters/node.ts +5 -2
- package/src/deploy/adapters/registry.ts +2 -1
- package/src/deploy/adapters/types.ts +13 -1
- package/src/deploy/artifacts.ts +25 -5
- package/src/deploy/cloudflare-negotiation.ts +23 -4
- package/src/deploy/headers.ts +67 -51
- package/src/deploy/node-headers.ts +148 -27
- package/src/deploy/platforms/cloudflare.ts +1 -0
- package/src/deploy/platforms/netlify.ts +82 -5
- package/src/deploy/platforms/node.ts +7 -5
- package/src/deploy/platforms/static.ts +1 -0
- package/src/deploy/platforms/types.ts +7 -0
- package/src/deploy/platforms/vercel.ts +9 -3
- package/src/deploy/redirects.ts +14 -3
- package/src/deploy/vercel-negotiation.ts +35 -3
- package/src/eval/agents.ts +10 -2
- package/src/eval/run.ts +25 -0
- package/src/markdown/base-links.ts +55 -8
- package/src/markdown/index.ts +6 -3
- package/src/markdown/relative-links.ts +3 -23
- package/src/markdown/route-snapshot.ts +37 -0
- package/src/og/card.ts +20 -4
- package/src/og/derive.ts +145 -4
- package/src/openapi/graphql-build.ts +28 -2
- package/src/openapi/model.ts +77 -13
- package/src/openapi/render-mdx.ts +10 -1
- package/src/registry/eject.ts +119 -22
- package/src/search/documents.ts +22 -1
- package/src/search/sync/algolia.ts +36 -2
- package/src/sources/registry.ts +5 -0
- package/src/theme/entry.ts +11 -4
- package/src/translate/agents.ts +6 -1
- package/src/translate/ledger.ts +26 -3
- package/src/translate/meta.ts +11 -3
- package/src/translate/run.ts +11 -5
- package/src/translate/validate.ts +10 -1
- package/src/translate/work-list.ts +36 -3
- package/src/upgrade/upgrade.ts +36 -4
- package/dist/cli/chunk-2hn4b8z7.js.map +0 -12
- package/dist/cli/chunk-6crbhc3x.js.map +0 -14
- package/dist/cli/chunk-6hsn950k.js.map +0 -10
- package/dist/cli/chunk-79jhk4py.js.map +0 -35
- package/dist/cli/chunk-82bbrxdn.js +0 -51
- package/dist/cli/chunk-82bbrxdn.js.map +0 -10
- package/dist/cli/chunk-abh8yjkn.js +0 -31
- package/dist/cli/chunk-abh8yjkn.js.map +0 -10
- package/dist/cli/chunk-dh8cwk36.js.map +0 -10
- package/dist/cli/chunk-epjnccmv.js.map +0 -10
- package/dist/cli/chunk-fa25z98p.js.map +0 -11
- package/dist/cli/chunk-fs23ddbb.js.map +0 -35
- package/dist/cli/chunk-fz5wtpmh.js.map +0 -10
- package/dist/cli/chunk-kpf8rrjc.js.map +0 -19
- package/dist/cli/chunk-m3vmjgmq.js.map +0 -10
- package/dist/cli/chunk-mb2919y2.js.map +0 -10
- package/dist/cli/chunk-q5163e60.js.map +0 -11
- package/dist/cli/chunk-qkqwkpte.js.map +0 -182
- package/dist/cli/chunk-qs4q5p4e.js.map +0 -10
- package/dist/cli/chunk-s1p84fyh.js.map +0 -10
- package/dist/cli/chunk-wgm7m9qk.js.map +0 -36
- package/dist/cli/chunk-yt5n7ppj.js.map +0 -10
- /package/dist/cli/{chunk-vtk4a6dg.js.map → chunk-00gs3wqs.js.map} +0 -0
- /package/dist/cli/{chunk-6vm74dry.js.map → chunk-6dtt0zfn.js.map} +0 -0
- /package/dist/cli/{chunk-fxypxtvm.js.map → chunk-bbnwccaz.js.map} +0 -0
- /package/dist/cli/{chunk-ce574jw2.js.map → chunk-esh98wmb.js.map} +0 -0
- /package/dist/cli/{chunk-zxcczpyx.js.map → chunk-fsmrqk8a.js.map} +0 -0
- /package/dist/cli/{chunk-hdpx1tax.js.map → chunk-g698a744.js.map} +0 -0
- /package/dist/cli/{chunk-zxh4d9vy.js.map → chunk-h2ez8dzb.js.map} +0 -0
- /package/dist/cli/{chunk-5shv93fd.js.map → chunk-h7k3nq3v.js.map} +0 -0
- /package/dist/cli/{chunk-ah61y8py.js.map → chunk-mqc662a6.js.map} +0 -0
- /package/dist/cli/{chunk-ch6g3ar0.js.map → chunk-n1yg3tj3.js.map} +0 -0
- /package/dist/cli/{chunk-wm7js3j9.js.map → chunk-sqw4ekg1.js.map} +0 -0
- /package/dist/cli/{chunk-27g6wdth.js.map → chunk-wdrt2k2v.js.map} +0 -0
- /package/dist/cli/{chunk-s6jhgk0q.js.map → chunk-zp79m0ts.js.map} +0 -0
|
@@ -23,7 +23,7 @@ Read `themeConfig`, `presets`, and `plugins`:
|
|
|
23
23
|
| `themeConfig.colorMode.defaultMode` | `theme.mode` (`respectPrefersColorScheme: true` → `"system"`) |
|
|
24
24
|
| `themeConfig.prism.theme` / `.darkTheme` | `markdown.code.theme: { light, dark }` (map Prism theme names to Shiki themes, e.g. `github`/`github-dark`) |
|
|
25
25
|
| `themeConfig.metadata` / `themeConfig.image` | per-page `seo` frontmatter / `seo.og`; report what doesn't fit |
|
|
26
|
-
| `url` + `baseUrl` | **`url` →
|
|
26
|
+
| `url` + `baseUrl` | **`url` → `deployment.site`**, unless the target host is Vercel, Netlify, or Cloudflare Pages, which Blume auto-detects (see SKILL.md — GitHub Pages, a common Docusaurus host, is not one of them); `baseUrl` (when not `/`) → `deployment: { base: "/…" }`, or the `base` option of a host adapter (`vercel({ base })`) when the site also needs one |
|
|
27
27
|
| preset `docs.routeBasePath` — **including the default!** | Docusaurus serves docs at **`/docs/…` by default**; the "map only declared fields" rule does **not** apply here because the _URLs_ are load-bearing. Either keep them with top-level **`basePath: "/docs"`** (invisible to the sidebar), or intentionally move to root and emit a `redirects` entry per page. Decide explicitly and say which. (`routeBasePath: '/'` = docs-only mode — nothing to do.) |
|
|
28
28
|
| preset `docs.editUrl` | `github` (owner/repo/branch; a path after the branch → `github.dir`; **an origin other than `https://github.com` → `github.host`** — a GitHub Enterprise repo's edit links and header mark point at the public site without it) |
|
|
29
29
|
| `themeConfig.footer` | drop → Footer override (`defineComponents` layout slot) |
|
|
@@ -50,18 +50,18 @@ Every Docusaurus repo serves **`static/`** at the site root (`static/img/foo.png
|
|
|
50
50
|
|
|
51
51
|
## Versioned docs
|
|
52
52
|
|
|
53
|
-
Docusaurus `versioned_docs/version-X/` + `versions.json` (+ `versioned_sidebars/`) → **recommend migrating the latest released version only**. Mind the URL scheme: by default the **latest release** serves at `/docs/` and the work-in-progress `docs/` folder serves at `/docs/next` (`lastVersion: 'current'` flips this) — pick the folder that matches what users see at `/docs/`. If older versions must stay,
|
|
53
|
+
Docusaurus `versioned_docs/version-X/` + `versions.json` (+ `versioned_sidebars/`) → **recommend migrating the latest released version only**. Mind the URL scheme: by default the **latest release** serves at `/docs/` and the work-in-progress `docs/` folder serves at `/docs/next` (`lastVersion: 'current'` flips this) — pick the folder that matches what users see at `/docs/`. If older versions must stay, use Blume's native versioning rather than a hand-built `navigation.selectors` dropdown: move each `versioned_docs/version-X/` into a top-level folder under `content.root` named for its id, and list that id in `versions.archived` (newest first), with `versions.current` labeling the live tree. Ids must start with a letter, so `version-1.0/` becomes `v1.0/`. Blume then adds the version switcher, the old-version notice, version-scoped search, and canonicals to the latest itself. A version-shaped folder left out of `versions.archived` only warns (`BLUME_VERSIONS_UNCONFIGURED_VERSION`) and publishes as ordinary current content. Snapshot routes become `/<id>/…`, so rewrite root-absolute links inside each snapshot to stay in it (`/guides/x` → `/v1.0/guides/x`) and add `redirects` from the old version URLs. Full reference: `docs/content/versioning.mdx` in the installed package.
|
|
54
54
|
|
|
55
55
|
## Blog
|
|
56
56
|
|
|
57
|
-
A Docusaurus `blog/` → Blume `type: blog` pages. **Dates come from filenames/folders** (`2024-01-31-foo.md`) — extract each into `date` frontmatter and strip the date from the filename (the old dated URLs `/blog/2024/01/31/foo` need `redirects`). Strip `<!-- truncate -->` / `{/* truncate */}` markers. `authors.yml` refs → inline author objects in each post's `authors` frontmatter. RSS stays at `/blog/rss.xml` on both sides.
|
|
57
|
+
A Docusaurus `blog/` → Blume `type: blog` pages. **Dates come from filenames/folders** (`2024-01-31-foo.md`) — extract each into `date` frontmatter and strip the date from the filename (the old dated URLs `/blog/2024/01/31/foo` need `redirects`). Strip `<!-- truncate -->` / `{/* truncate */}` markers. `authors.yml` refs → inline author objects in each post's `authors` frontmatter. RSS stays at `/blog/rss.xml` on both sides. Blume generates **no** blog index, tag, author, or archive pages: write a `blog/index.mdx` whose `CardGroup` links each post (see `docs/advanced/blog.mdx` in the installed package), and report the tag, author, and archive pages as dropped.
|
|
58
58
|
|
|
59
59
|
## Content & components
|
|
60
60
|
|
|
61
61
|
- **`.md` vs `.mdx` — both majors need renames, for opposite reasons.** Blume parses `.md` as plain Markdown: no directives, no JSX, no `$$` math, no mermaid/package-install fences. **v3** treats `.md` as MDX (so a `.md` with imports/JSX/`{}` renders them as literal text in Blume); **v2** content is looser MDX v1. Rule: **rename any `.md` that contains admonitions, JSX, imports, or math to `.mdx`** — for typical Docusaurus repos that is most files.
|
|
62
62
|
- **Admonitions are directives — but check the version.** v3: `:::note`, `:::tip`, `:::info`, `:::warning`, `:::danger` pass through; `:::caution` → `:::warning` (or rely on Blume's alias); titles `:::note[Title]` work. **v2:** titles are space-separated (`:::note Your Title`) — rewrite to brackets or the title is silently lost; and v2's `:::warning` rendered **red/danger** — audit whether it should become `:::danger`.
|
|
63
63
|
- **Tabs:** `<Tabs>`/`<TabItem label="…" value="…">` → `<Tabs>`/`<Tab title="…">`. Drop `groupId`/`queryString`/`value`; strip the `@theme/Tabs` imports.
|
|
64
|
-
- **Theme JSX in content:** `<DocCardList/>` (standard on category index pages) →
|
|
64
|
+
- **Theme JSX in content:** `<DocCardList/>` (standard on category index pages) → a `CardGroup` of `Card` links to the folder's pages, one per child (nothing in Blume lists a folder's children on its index page, so deleting it leaves the page empty); `<TOCInline/>` → drop (report); `<CodeBlock>` JSX → a fenced code block; `<Admonition>` → the matching directive; `<details>`/`<summary>` → `<Accordion>`/`<AccordionItem>` or leave as raw HTML.
|
|
65
65
|
- **`@theme/*` / `@site/*` imports** — strip `@theme/*` (Blume injects components globally); rewrite `@site/` asset/module paths to `/public` URLs or inline. **MDX partials** (`_partial.mdx` imports) → inline the partial's body (Blume's default `**/_*` exclude already hides the partial files themselves).
|
|
66
66
|
- **Code blocks:** `title="file.js"` → works as-is; `showLineNumbers` → `lineNumbers`; **magic comments** (`// highlight-next-line`, `highlight-start`/`end`) → `{ranges}` or `// [!code highlight]` — unconverted they ship as literal comments in every sample; ` ```bash npm2yarn ` → ` ```package-install `.
|
|
67
67
|
- **MDX v1 (v2 sources) pitfalls:** unescaped `<`/`{` in prose, HTML comments `<!-- -->` (→ `{/* */}`), string `style="…"` attributes (→ objects). Fix as build errors surface.
|
|
@@ -72,7 +72,7 @@ A Docusaurus `blog/` → Blume `type: blog` pages. **Dates come from filenames/f
|
|
|
72
72
|
| --- | --- |
|
|
73
73
|
| `title` / `description` | pass through |
|
|
74
74
|
| `id` | usually drop (routing is filesystem-based); use `slug` to pin a route |
|
|
75
|
-
| `slug` | `slug` |
|
|
75
|
+
| `slug` | `slug` as a **full path from the content root**: Blume's `slug` replaces the page's whole route, while Docusaurus resolves a relative slug (no leading `/`) against the doc's folder. So `guides/intro.md` with `slug: start` → `slug: guides/start`; an absolute slug (`/start`) is already a full path |
|
|
76
76
|
| `sidebar_label` | `sidebar.label` |
|
|
77
77
|
| `sidebar_position` | `sidebar.order` |
|
|
78
78
|
| `unlisted` | `hidden: true` + `noindex: true` |
|
|
@@ -95,4 +95,4 @@ Remove `@docusaurus/*` and Algolia deps; delete `docusaurus.config.*`, `sidebars
|
|
|
95
95
|
|
|
96
96
|
## Dropped — report these
|
|
97
97
|
|
|
98
|
-
Custom/swizzled theme components (layout slots or `blume eject`), footer columns, Algolia config, `sidebar_custom_props` and the other dropped frontmatter keys, `createRedirects` functions (→ host rules), React pages under `src/pages/`, `<TOCInline>`, per-category `className`/`customProps`, and any `@theme/*` component with no Blume equivalent.
|
|
98
|
+
Custom/swizzled theme components (layout slots or `blume eject`), footer columns, the blog's generated tag, author, and archive pages, Algolia config, `sidebar_custom_props` and the other dropped frontmatter keys, `createRedirects` functions (→ host rules), React pages under `src/pages/`, `<TOCInline>`, per-category `className`/`customProps`, and any `@theme/*` component with no Blume equivalent.
|
|
@@ -92,7 +92,7 @@ The codemod touches **only frontmatter**. Icons in MDX **body** (`<Icon icon="
|
|
|
92
92
|
| `life-ring` | `life-buoy` | | `shield-halved` | `shield` |
|
|
93
93
|
| `rocket`/`book`/`book-open`/`code`/`terminal`/`key`/`lock`/`user`/`users`/`database`/`server`/`cloud`/`bell`/`calendar`/`star`/`heart`/`tag`/`folder`/`globe`/`link`/`download`/`upload`/`check`/`copy`/`play`/`filter` | _(same name — verify)_ |
|
|
94
94
|
|
|
95
|
-
**Rules:** verify each Lucide name exists at [lucide.dev/icons](https://lucide.dev/icons) before writing it. **Brand icons** (`fa6-brands:*` — github, discord, x, slack, linkedin…) mostly have **no** Lucide equivalent: for GitHub use the `github` config (renders the header repo link); for other socials, drop the icon and report it (or add via a Footer override after `blume eject`). Where no Lucide counterpart exists, **drop the icon and report it
|
|
95
|
+
**Rules:** verify each Lucide name exists at [lucide.dev/icons](https://lucide.dev/icons) before writing it. **Brand icons** (`fa6-brands:*` — github, discord, x, slack, linkedin…) mostly have **no** Lucide equivalent: for GitHub use the `github` config (renders the header repo link); for other socials, drop the icon and report it (or add via a Footer override after `blume eject`). Where no Lucide counterpart exists, **drop the icon and report it**. The build won't catch a wrong name for you: an unknown icon renders nothing, and it's only a warning (`BLUME_UNKNOWN_ICON`) for navigation icons — an icon prop on a component like `<Card>` fails silently — so check every name.
|
|
96
96
|
|
|
97
97
|
## Navigation: `docs.json` `navigation` → filesystem + tabs
|
|
98
98
|
|
|
@@ -143,7 +143,7 @@ Mintlify page frontmatter → Blume's strict schema. **`scripts/mintlify-codemod
|
|
|
143
143
|
| `canonical` | `seo.canonical` | renames |
|
|
144
144
|
| `og:image` | `seo.image` | renames |
|
|
145
145
|
| `hidden: true` | valid top-level in Blume — **kept as-is**; add `noindex: true` yourself if the page must also leave the search index | left (do by hand) |
|
|
146
|
-
| `openapi`/`asyncapi`/`api` | usually an endpoint stub → **delete the page** (Blume generates operation pages); else `
|
|
146
|
+
| `openapi`/`asyncapi`/`api` | usually an endpoint stub → **delete the page** (Blume generates operation pages); else drop the key and keep it as a normal page (there's no built-in `api` page type) | **flags** for review — never auto-deletes a page |
|
|
147
147
|
| `mode`, `public`, `rss`, `groups`, `keywords`, `hideApiMarker`, `hideFooterPagination`, `iconType` | **drop** (report) | drops |
|
|
148
148
|
|
|
149
149
|
The codemod leaves the source key in place and reports a conflict rather than clobbering data when a rename target already exists (e.g. a page already has `sidebar.label`) or the value is too structured to move safely — resolve those by hand. Remove any duplicate H1 in the body — `title` renders the H1. (The codemod only edits frontmatter; it never touches the body.)
|
|
@@ -153,7 +153,7 @@ The codemod leaves the source key in place and reports a conflict rather than cl
|
|
|
153
153
|
Top-level `openapi`, `api.openapi`, or a per-group/per-tab `openapi` → `reference: [openapi({ sources: [{ spec, label?, route? }] })]`, with `openapi` imported from `blume/reference` (`spec` alone is the single-source shorthand; several per-tab specs become several sources, or several `openapi()` entries when they need different routes; a spec the source embedded with Scalar becomes a `scalar({ spec })` entry). A Mintlify `{ source, directory }` object: `directory` → the source's `route`. An `asyncapi` field maps the same way to `asyncapi({ … })` in the list. **Delete every per-endpoint stub page** (frontmatter `openapi: "GET /path"` or a `"GET /path"` nav entry) — Blume's native renderer generates one real page per operation. **Add a `navigation.tabs` entry pointing at the reference `route` yourself** (Mintlify's API tab maps to it); the reference does not create a header tab automatically.
|
|
154
154
|
|
|
155
155
|
- **Vendor the spec.** Mintlify usually points at a spec **URL**. Copying that straight into `spec:` makes every build fetch it at build time — a single point of failure in CI/offline/behind a proxy, and a failed fetch silently drops the reference (leaving the tab pointing at a route that 404s). Prefer downloading it into the repo (`curl … -o openapi/<name>.json`) and pointing `spec` at that local path. If you keep the URL, report the dependency and consider a `prebuild` refresh-with-fallback.
|
|
156
|
-
- **Fix endpoint links.** Blume operation routes are `<route>/<slugified-tag>/<slugified-operationId>` (tag `Models` + id `listModels` → `/api-reference/models/
|
|
156
|
+
- **Fix endpoint links.** Blume operation routes are `<route>/<slugified-tag>/<slugified-operationId>` (tag `Models` + id `listModels` → `/api-reference/models/list-models`: a camelCase id is split into kebab-case, not just lowercased — see SKILL.md "OpenAPI") — this differs from Mintlify's endpoint URLs, so **rewrite every inbound link to an operation**. `blume validate` resolves operation pages like any other route and flags the ones you miss.
|
|
157
157
|
- **Keep the "Introduction" page.** Mintlify commonly has a written intro/auth page in an "Introduction" group beside the "Endpoints" (openapi) group in the same tab. Keep it: a normal content page placed under the `openapi()` adapter's `route` (e.g. `<root>/api-reference/introduction.mdx`) merges into the reference tab's sidebar alongside the generated operations. Delete only the per-endpoint stubs, not the conceptual pages.
|
|
158
158
|
|
|
159
159
|
## Assets
|
|
@@ -56,7 +56,7 @@ Most Nextra pages have **no frontmatter**; the title falls back `_meta` title
|
|
|
56
56
|
|
|
57
57
|
## Code fences
|
|
58
58
|
|
|
59
|
-
Nextra's fence meta differs from Blume's — rewrite it: `filename="app.js"` → a space-separated title (` ```js app.js `); `showLineNumbers` → `lineNumbers`; line highlighting `{1,4-5}` carries over unchanged; **drop** word-highlight `/word
|
|
59
|
+
Nextra's fence meta differs from Blume's — rewrite it: `filename="app.js"` → a space-separated title (` ```js app.js `); `showLineNumbers` → `lineNumbers`; line highlighting `{1,4-5}` carries over unchanged; **drop** word-highlight `/word/` and `copy`/`copy=false`. **Keep** inline-code `{:lang}` suffixes (`` `useState(){:js}` ``) — Blume highlights them natively. ` ```sh npm2yarn ` fences → ` ```package-install `.
|
|
60
60
|
|
|
61
61
|
## Math
|
|
62
62
|
|
|
@@ -12,7 +12,7 @@ Keep content where it is — set `content.root: "src/content/docs"`.
|
|
|
12
12
|
|
|
13
13
|
## Config: `starlight({…})` → `blume.config.ts`
|
|
14
14
|
|
|
15
|
-
**Harvest the surrounding `astro.config.*` too, not just the `starlight()` call:** top-level Astro `redirects` → Blume `redirects`; `site` →
|
|
15
|
+
**Harvest the surrounding `astro.config.*` too, not just the `starlight()` call:** top-level Astro `redirects` → Blume `redirects`; `site` → `deployment.site`, unless the target host is Vercel, Netlify, or Cloudflare Pages, which Blume auto-detects (see SKILL.md); other integrations → report.
|
|
16
16
|
|
|
17
17
|
| Starlight option | Blume |
|
|
18
18
|
| --- | --- |
|
|
@@ -70,7 +70,7 @@ Starlight's primary callout syntax is the `:::note`/`:::tip`/`:::caution`/`:::da
|
|
|
70
70
|
|
|
71
71
|
## Components
|
|
72
72
|
|
|
73
|
-
- **Renames:** `<CardGrid>` → `<CardGroup>`; `<LinkCard>` → `<Card>` (its `description` prop drops — fold into the body); `<TabItem label="…">` → `<Tab title="…">`. `<Tabs>` and `<Card>` stay; a `<Tabs syncKey="…">`
|
|
73
|
+
- **Renames:** `<CardGrid>` → `<CardGroup>`; `<LinkCard>` → `<Card>` (its `description` prop drops — fold into the body); `<TabItem label="…">` → `<Tab title="…">`. `<Tabs>` and `<Card>` stay; **keep** a `<Tabs syncKey="…">` prop as is — Blume's `Tabs` takes `syncKey` with the same scoping (only groups sharing the key switch together). One difference: Blume groups without a key also sync, page-wide, by tab title, where Starlight leaves them independent — add `sync={false}` to a keyless group whose same-titled tabs must stay unlinked.
|
|
74
74
|
- **`<Badge>` needs conversion, not pass-through:** Starlight puts content in a `text` prop and uses variants `note`/`tip`/`caution`/`danger`/`success`/`default` with sizes `small`/`medium`/`large`. Blume's `<Badge>` renders **children** with variants `default`/`accent`/`success`/`warning`/`danger` and sizes `xs`/`sm`/`md`/`lg`. Move `text` into the children; remap variant (`note`→`default`, `tip`→`accent`, `caution`→`warning`, `danger`→`danger`, `success`→`success`) and size (`small`→`sm`, `medium`→`md`, `large`→`lg`).
|
|
75
75
|
- **Convert yourself:** `<Steps>` → Blume `<Steps>`/`<Step>`; `<FileTree>` → Blume `<FileTree>`; `<Code code={…}>` → a fenced code block; `<LinkButton>` → a Markdown link or `<Card>`.
|
|
76
76
|
- Strip `import … from "@astrojs/starlight/*"` and `astro:assets` lines.
|
|
@@ -88,8 +88,8 @@ Starlight content is full of Expressive Code fence meta; Blume understands some
|
|
|
88
88
|
## Plugins — map, don't drop
|
|
89
89
|
|
|
90
90
|
- `starlight-openapi` → an `openapi({ sources })` entry in Blume's `reference` list, imported from `blume/reference` (delete any generated pages; add the `navigation.tabs` entry).
|
|
91
|
-
- `starlight-blog` → `type: blog` pages.
|
|
92
|
-
- `starlight-versions` → `navigation.selectors` with `
|
|
91
|
+
- `starlight-blog` → `type: blog` pages (RSS at `/blog/rss.xml`). Blume generates **no** blog index, tag, or author pages: write a `blog/index.mdx` whose `CardGroup` links each post (see `docs/advanced/blog.mdx` in the installed package), and report the tag and author pages as dropped.
|
|
92
|
+
- `starlight-versions` → Blume's native versioning, not a `navigation.selectors` dropdown: each archived version's content goes in a top-level folder under `content.root` named for its id, listed in `versions.archived` (newest first), and Blume adds the switcher, the old-version notice, and version-scoped search. Ids must start with a letter (`1.0/` → `v1.0/`, with `redirects` from the old URLs), and a version-shaped folder left out of `versions.archived` only warns (`BLUME_VERSIONS_UNCONFIGURED_VERSION`) and publishes as current content. Full reference: `docs/content/versioning.mdx` in the installed package.
|
|
93
93
|
- `starlight-image-zoom` → delete (Blume zooms content images by default).
|
|
94
94
|
- `starlight-links-validator` → delete (`blume validate` covers it).
|
|
95
95
|
- Anything else → report.
|
|
@@ -113,4 +113,4 @@ Remove `@astrojs/starlight` (and plugin deps) from deps, delete the Starlight bi
|
|
|
113
113
|
|
|
114
114
|
## Dropped — report these
|
|
115
115
|
|
|
116
|
-
Non-GitHub socials, badge variants, sidebar/item `attrs` + `translations`, `customCss` beyond `theme.css`, `head` entries, `routeMiddleware`, splash/hero pages (rebuild as custom pages), aside custom icons, EC frames/collapse/text markers, prev/next toggles, unmapped plugins, any `<Icon>` name with no Lucide equivalent.
|
|
116
|
+
Non-GitHub socials, badge variants, sidebar/item `attrs` + `translations`, `customCss` beyond `theme.css`, `head` entries, `routeMiddleware`, splash/hero pages (rebuild as custom pages), starlight-blog's tag and author pages, aside custom icons, EC frames/collapse/text markers, prev/next toggles, unmapped plugins, any `<Icon>` name with no Lucide equivalent.
|
|
@@ -177,8 +177,8 @@ const RENAME = {
|
|
|
177
177
|
};
|
|
178
178
|
|
|
179
179
|
// Keys we deliberately do NOT auto-transform — they usually mean the page is an
|
|
180
|
-
// OpenAPI endpoint stub that should be deleted (Blume generates operation pages)
|
|
181
|
-
// or
|
|
180
|
+
// OpenAPI endpoint stub that should be deleted (Blume generates operation pages),
|
|
181
|
+
// or else a normal page that just loses the key. Flag for the human; never guess.
|
|
182
182
|
const FLAG = new Set(["api", "asyncapi", "openapi"]);
|
|
183
183
|
|
|
184
184
|
// Which change kinds actually edit the file. Report-only kinds (flags,
|
|
@@ -32,7 +32,7 @@ Skip the edit when the only available change is subjective polish, wording prefe
|
|
|
32
32
|
- Preserve existing page order and `defineMeta` style; update `pages` arrays when adding, renaming, or removing pages.
|
|
33
33
|
- Use the Blume components already present in the docs (callout directives, steps, cards) instead of inventing new markup patterns.
|
|
34
34
|
- Match nearby code fences: filenames, language tags, and line numbers where the surrounding docs use them.
|
|
35
|
-
- Keep internal links root-relative (`/
|
|
35
|
+
- Keep internal links root-relative (`/guides/setup`), in the form nearby pages already use.
|
|
36
36
|
- Do not edit generated `.blume/` or `dist/` output.
|
|
37
37
|
|
|
38
38
|
## PR notes
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { routeIsTaken } from "../astro/pages.ts";
|
|
2
|
+
import type { BlumeProject } from "../core/project-graph.ts";
|
|
3
|
+
import type { ResolvedConfig } from "../core/schema.ts";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* What a build actually serves of the agent surfaces whose config flag alone
|
|
7
|
+
* doesn't guarantee them.
|
|
8
|
+
*/
|
|
9
|
+
export interface EmittedAgentSurface {
|
|
10
|
+
/** The MCP server was generated (see {@link servesMcp}). */
|
|
11
|
+
mcp: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* A skills discovery index is served: generated from `agents.skills` (at
|
|
14
|
+
* least one valid skill), or shipped by the user in `public/`.
|
|
15
|
+
*/
|
|
16
|
+
skills: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Whether the build generates the MCP server: it is enabled and no content
|
|
21
|
+
* or custom page owns its route. When one does, the generator skips the
|
|
22
|
+
* server with a warning rather than collide with the page (`planMcp`).
|
|
23
|
+
*/
|
|
24
|
+
export const servesMcp = (
|
|
25
|
+
project: BlumeProject,
|
|
26
|
+
userPages: { pattern: string }[]
|
|
27
|
+
): boolean =>
|
|
28
|
+
project.config.agents.mcp.enabled &&
|
|
29
|
+
!routeIsTaken(
|
|
30
|
+
userPages,
|
|
31
|
+
project.graph.pages,
|
|
32
|
+
project.config.agents.mcp.route
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* The config the discovery documents are built from: `agents.mcp` and
|
|
37
|
+
* `agents.skills` switched off when the build didn't emit them, so llms.txt,
|
|
38
|
+
* agent-readability.json, the catalogs, and the header rules only point at
|
|
39
|
+
* what is there. A config flag says what was asked for; the MCP server is
|
|
40
|
+
* skipped when a page owns its route, and skills publish nothing when their
|
|
41
|
+
* directory is missing or holds no valid skill.
|
|
42
|
+
*/
|
|
43
|
+
export const advertisedConfig = (
|
|
44
|
+
config: ResolvedConfig,
|
|
45
|
+
emitted: EmittedAgentSurface
|
|
46
|
+
): ResolvedConfig => ({
|
|
47
|
+
...config,
|
|
48
|
+
agents: {
|
|
49
|
+
...config.agents,
|
|
50
|
+
mcp: {
|
|
51
|
+
...config.agents.mcp,
|
|
52
|
+
enabled: config.agents.mcp.enabled && emitted.mcp,
|
|
53
|
+
},
|
|
54
|
+
skills: emitted.skills ? config.agents.skills : undefined,
|
|
55
|
+
},
|
|
56
|
+
});
|
package/src/ai/api/spec.ts
CHANGED
|
@@ -113,6 +113,7 @@ export interface ApiSpecDocument {
|
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
const JSON_TYPE = "application/json";
|
|
116
|
+
const EVENT_STREAM_TYPE = "text/event-stream";
|
|
116
117
|
const MARKDOWN_TYPE = "text/markdown";
|
|
117
118
|
const TEXT_TYPE = "text/plain";
|
|
118
119
|
|
|
@@ -623,14 +624,26 @@ export const buildApiSpec = (input: ApiSpecInput): ApiSpecDocument => {
|
|
|
623
624
|
{
|
|
624
625
|
post: {
|
|
625
626
|
description:
|
|
626
|
-
"The Model Context Protocol server (Streamable HTTP, stateless, JSON responses). Tools: `search_docs`, `get_page`, `list_pages`, `get_navigation` — the same operations this API exposes — plus every page as a `text/markdown` resource. Discovery document at `/.well-known/mcp.json`.",
|
|
627
|
+
"The Model Context Protocol server (Streamable HTTP, stateless, JSON responses). Send `Accept: application/json, text/event-stream`: the Streamable HTTP transport requires a client to accept both and answers `406` otherwise, though this server always replies with JSON. Tools: `search_docs`, `get_page`, `list_pages`, `get_navigation` — the same operations this API exposes — plus every page as a `text/markdown` resource. Discovery document at `/.well-known/mcp.json`.",
|
|
627
628
|
operationId: "mcp",
|
|
628
629
|
requestBody: {
|
|
629
630
|
content: { [JSON_TYPE]: { schema: ref("JsonRpcRequest") } },
|
|
630
631
|
required: true,
|
|
631
632
|
},
|
|
632
633
|
responses: {
|
|
633
|
-
|
|
634
|
+
// Both media types, so a generated client sends the Accept header
|
|
635
|
+
// the transport requires; OpenAPI ignores an `Accept` parameter.
|
|
636
|
+
"200": {
|
|
637
|
+
content: {
|
|
638
|
+
[JSON_TYPE]: { schema: ref("JsonRpcResponse") },
|
|
639
|
+
[EVENT_STREAM_TYPE]: { schema: { type: "string" } },
|
|
640
|
+
},
|
|
641
|
+
description: "The JSON-RPC response.",
|
|
642
|
+
},
|
|
643
|
+
"406": jsonResponse(
|
|
644
|
+
"The request's `Accept` header doesn't list both `application/json` and `text/event-stream`.",
|
|
645
|
+
"JsonRpcResponse"
|
|
646
|
+
),
|
|
634
647
|
},
|
|
635
648
|
summary: "Call the MCP server",
|
|
636
649
|
tags: ["MCP"],
|
package/src/ai/api-catalog.ts
CHANGED
|
@@ -17,7 +17,13 @@ import { API_BASE, OPENAPI_PATH } from "./api/paths.ts";
|
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
export const API_CATALOG_PATH = "/.well-known/api-catalog";
|
|
20
|
-
|
|
20
|
+
/** The profile URI RFC 9727 registers for an API catalog linkset. */
|
|
21
|
+
export const API_CATALOG_PROFILE = "https://www.rfc-editor.org/info/rfc9727";
|
|
22
|
+
/**
|
|
23
|
+
* The catalog's media type: a linkset carrying the RFC 9727 profile
|
|
24
|
+
* parameter, which the RFC says an API catalog SHOULD be served with.
|
|
25
|
+
*/
|
|
26
|
+
export const API_CATALOG_TYPE = `application/linkset+json; profile="${API_CATALOG_PROFILE}"`;
|
|
21
27
|
|
|
22
28
|
/** An RFC 9264 linkset entry, restricted to the relations Blume emits. */
|
|
23
29
|
interface LinksetEntry {
|
package/src/ai/ask-context.ts
CHANGED
|
@@ -30,6 +30,13 @@ export interface AskData {
|
|
|
30
30
|
defaultLocale?: string;
|
|
31
31
|
documents: OramaDoc[];
|
|
32
32
|
site: string | null;
|
|
33
|
+
/**
|
|
34
|
+
* Present on a versioned site, whose documents then carry their `version`
|
|
35
|
+
* (`""` for the current docs): retrieval keeps to the version the reader
|
|
36
|
+
* is viewing — the current docs unless they're on an archived page — as
|
|
37
|
+
* the search dialog does.
|
|
38
|
+
*/
|
|
39
|
+
versioned?: boolean;
|
|
33
40
|
}
|
|
34
41
|
|
|
35
42
|
/** Documents retrieved per question and injected into the system prompt. */
|
|
@@ -644,12 +651,17 @@ export const createAskContext = (
|
|
|
644
651
|
// which part of each page is quoted.
|
|
645
652
|
const [query = ""] = queries;
|
|
646
653
|
|
|
647
|
-
// The current page anchors retrieval to its locale and
|
|
654
|
+
// The current page anchors retrieval to its locale and docs version, and
|
|
655
|
+
// is injected first. Without one, a versioned site grounds in the
|
|
656
|
+
// current docs rather than every archived copy of each page.
|
|
648
657
|
const current = page?.path
|
|
649
658
|
? byRoute.get(normalizeRoute(page.path))
|
|
650
659
|
: undefined;
|
|
651
660
|
const db = await index();
|
|
652
|
-
const filters = {
|
|
661
|
+
const filters = {
|
|
662
|
+
locale: current?.locale || undefined,
|
|
663
|
+
version: data.versioned ? (current?.version ?? "") : undefined,
|
|
664
|
+
};
|
|
653
665
|
const hits = interleave(
|
|
654
666
|
await Promise.all(
|
|
655
667
|
queries.map((text) => queryOramaIndex(db, text, maxResults, filters))
|
package/src/ai/ask-data.ts
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import type { BlumeProject } from "../core/project-graph.ts";
|
|
2
2
|
import { buildSearchDocuments } from "../search/documents.ts";
|
|
3
|
+
import type { OramaDoc } from "../search/orama-index.ts";
|
|
3
4
|
import type { AskData } from "./ask-context.ts";
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Build the grounding snapshot the assistant endpoint serves. Like the MCP server,
|
|
7
8
|
* the assistant is independent of on-page search, so documents are indexed even when the
|
|
8
|
-
* search provider is `none` (`includeWhenDisabled`). `locale` is kept
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
9
|
+
* search provider is `none` (`includeWhenDisabled`). `locale` is kept so
|
|
10
|
+
* retrieval can be filtered to the current page's language, and on a
|
|
11
|
+
* versioned site `version` too, so archived snapshots don't crowd the docs
|
|
12
|
+
* being read out of the answer. Content is kept as Markdown so grounding sees
|
|
13
|
+
* fenced code examples — the model answers "what does the config look like?"
|
|
14
|
+
* from the docs instead of declining.
|
|
12
15
|
* The reader is an AI agent, so `<Visibility>` resolves for the agents audience
|
|
13
16
|
* (web-only content removed, agents-only unwrapped) and components downlevel to
|
|
14
17
|
* Markdown, both matching llms-full.txt.
|
|
@@ -19,15 +22,26 @@ export const buildAskData = async (project: BlumeProject): Promise<AskData> => {
|
|
|
19
22
|
content: "markdown",
|
|
20
23
|
includeWhenDisabled: true,
|
|
21
24
|
});
|
|
22
|
-
|
|
25
|
+
const versioned = Boolean(project.config.versions);
|
|
26
|
+
const data: AskData = {
|
|
23
27
|
defaultLocale: project.config.i18n?.defaultLocale,
|
|
24
|
-
documents: documents.map((doc) =>
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
documents: documents.map((doc) => {
|
|
29
|
+
const document: OramaDoc = {
|
|
30
|
+
content: doc.content,
|
|
31
|
+
description: doc.description,
|
|
32
|
+
locale: doc.locale,
|
|
33
|
+
route: doc.route,
|
|
34
|
+
title: doc.title,
|
|
35
|
+
};
|
|
36
|
+
if (versioned) {
|
|
37
|
+
document.version = doc.version;
|
|
38
|
+
}
|
|
39
|
+
return document;
|
|
40
|
+
}),
|
|
31
41
|
site: project.config.deployment.options.site ?? null,
|
|
32
42
|
};
|
|
43
|
+
if (versioned) {
|
|
44
|
+
data.versioned = true;
|
|
45
|
+
}
|
|
46
|
+
return data;
|
|
33
47
|
};
|
|
@@ -4,6 +4,7 @@ import { mdxToMdast } from "satteri";
|
|
|
4
4
|
import { parseYouTubeId } from "../components/content/youtube.ts";
|
|
5
5
|
import type { ExampleLookup } from "../core/types.ts";
|
|
6
6
|
import { MDX_FEATURES } from "../markdown/features.ts";
|
|
7
|
+
import { readStaticExpression } from "./static-expression.ts";
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Downlevel Blume's MDX components to plain Markdown for agent-facing output
|
|
@@ -44,11 +45,19 @@ interface MdxAttribute {
|
|
|
44
45
|
|
|
45
46
|
/** A single source replacement: `[start, end)` byte range → `text`. */
|
|
46
47
|
interface Splice {
|
|
48
|
+
/**
|
|
49
|
+
* The range is a flow (block-level) element, so the line after it must
|
|
50
|
+
* start a block of its own.
|
|
51
|
+
*/
|
|
52
|
+
block: boolean;
|
|
47
53
|
end: number;
|
|
48
54
|
start: number;
|
|
49
55
|
text: string;
|
|
50
56
|
}
|
|
51
57
|
|
|
58
|
+
/** Text that continues on the very next line, with no blank line between. */
|
|
59
|
+
const NEXT_LINE_TEXT = /^[\t ]*\n[\t ]*\S/u;
|
|
60
|
+
|
|
52
61
|
/**
|
|
53
62
|
* A statically-recovered data value. Parsed front matter and evaluated
|
|
54
63
|
* attribute literals are both plain data — scalars, dates, arrays, and
|
|
@@ -135,33 +144,13 @@ export type ComponentMarkdown = (
|
|
|
135
144
|
) => string | null;
|
|
136
145
|
|
|
137
146
|
/**
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
* other scope throw and report as not evaluable.
|
|
147
|
+
* Read an element's attributes into a plain props object. An expression
|
|
148
|
+
* attribute (`prop={...}`) is read as literal data and never executed (see
|
|
149
|
+
* `static-expression.ts`): the downleveler also runs over plain `.md` pages
|
|
150
|
+
* and remote content, which nothing else executes. `prop={frontmatter.status}`
|
|
151
|
+
* resolves against the page's front matter, as it does when Astro renders
|
|
152
|
+
* the page; anything else — a call, an import — marks the props lossy.
|
|
145
153
|
*/
|
|
146
|
-
const evaluateExpression = (
|
|
147
|
-
raw: string,
|
|
148
|
-
frontmatter: Record<string, EvaluatedValue> | undefined
|
|
149
|
-
) => {
|
|
150
|
-
try {
|
|
151
|
-
// Build-time eval of the author's own attribute literals; a throw falls
|
|
152
|
-
// back to leaving the JSX verbatim.
|
|
153
|
-
// oxlint-disable-next-line no-new-func
|
|
154
|
-
const value: EvaluatedValue = new Function(
|
|
155
|
-
"frontmatter",
|
|
156
|
-
`"use strict"; return (${raw});`
|
|
157
|
-
)(frontmatter);
|
|
158
|
-
return { ok: true, value };
|
|
159
|
-
} catch {
|
|
160
|
-
return { ok: false, value: undefined };
|
|
161
|
-
}
|
|
162
|
-
};
|
|
163
|
-
|
|
164
|
-
/** Evaluate an element's attributes into a plain props object. */
|
|
165
154
|
const readProps = (
|
|
166
155
|
node: MdastNode,
|
|
167
156
|
frontmatter: Record<string, EvaluatedValue> | undefined
|
|
@@ -180,7 +169,7 @@ const readProps = (
|
|
|
180
169
|
} else if (isString(attribute.value)) {
|
|
181
170
|
props[attribute.name] = attribute.value;
|
|
182
171
|
} else {
|
|
183
|
-
const result =
|
|
172
|
+
const result = readStaticExpression(attribute.value.value, frontmatter);
|
|
184
173
|
if (result.ok) {
|
|
185
174
|
props[attribute.name] = result.value;
|
|
186
175
|
} else {
|
|
@@ -208,14 +197,24 @@ const applySplices = (text: string, splices: Splice[]): string => {
|
|
|
208
197
|
const lineStart = result.lastIndexOf("\n", splice.start - 1) + 1;
|
|
209
198
|
const prefix = result.slice(lineStart, splice.start);
|
|
210
199
|
const indent = /^[\t ]+$/u.test(prefix) ? prefix : "";
|
|
200
|
+
// The JSX's closing tag ended its block; the Markdown standing in for it
|
|
201
|
+
// doesn't. Text on the very next line would read as a lazy continuation
|
|
202
|
+
// of a blockquote or list item (`> Body` then `Next.` joins the quote),
|
|
203
|
+
// so a blank line keeps it out.
|
|
204
|
+
const spliced =
|
|
205
|
+
splice.block &&
|
|
206
|
+
splice.text !== "" &&
|
|
207
|
+
NEXT_LINE_TEXT.test(result.slice(splice.end))
|
|
208
|
+
? `${splice.text}\n`
|
|
209
|
+
: splice.text;
|
|
211
210
|
const replacement = indent
|
|
212
|
-
?
|
|
211
|
+
? spliced
|
|
213
212
|
.split("\n")
|
|
214
213
|
.map((line, index) =>
|
|
215
214
|
index === 0 || line === "" ? line : `${indent}${line}`
|
|
216
215
|
)
|
|
217
216
|
.join("\n")
|
|
218
|
-
:
|
|
217
|
+
: spliced;
|
|
219
218
|
result =
|
|
220
219
|
result.slice(0, splice.start) + replacement + result.slice(splice.end);
|
|
221
220
|
}
|
|
@@ -888,15 +887,21 @@ const renderSlice = (
|
|
|
888
887
|
const splices: Splice[] = [];
|
|
889
888
|
// oxlint-disable-next-line no-use-before-define
|
|
890
889
|
collectSplices(walk, nodes, splices);
|
|
890
|
+
// Start the slice at its line's indent, so a component that opens the
|
|
891
|
+
// slice is indented like the lines after it once replaced (see
|
|
892
|
+
// `applySplices`) and dedents with them; the final trim drops that indent
|
|
893
|
+
// from the first line again.
|
|
894
|
+
const indent = indentAt(walk.source, start);
|
|
895
|
+
const from = start - (indent ?? 0);
|
|
891
896
|
const spliced = applySplices(
|
|
892
|
-
walk.source.slice(
|
|
897
|
+
walk.source.slice(from, end),
|
|
893
898
|
splices.map((splice) => ({
|
|
894
899
|
...splice,
|
|
895
|
-
end: splice.end -
|
|
896
|
-
start: splice.start -
|
|
900
|
+
end: splice.end - from,
|
|
901
|
+
start: splice.start - from,
|
|
897
902
|
}))
|
|
898
903
|
);
|
|
899
|
-
return dedent(spliced,
|
|
904
|
+
return dedent(spliced, indent).trim();
|
|
900
905
|
};
|
|
901
906
|
|
|
902
907
|
/** The element's body as Markdown: the slice covering all of its children. */
|
|
@@ -996,6 +1001,7 @@ const collectSplices = (
|
|
|
996
1001
|
const text = hasOffsets(node) ? downlevelComponentNode(node, walk) : null;
|
|
997
1002
|
if (text !== null && hasOffsets(node)) {
|
|
998
1003
|
out.push({
|
|
1004
|
+
block: node.type === "mdxJsxFlowElement",
|
|
999
1005
|
end: node.position.end.offset,
|
|
1000
1006
|
start: node.position.start.offset,
|
|
1001
1007
|
text,
|
|
@@ -1015,10 +1021,10 @@ const collectSplices = (
|
|
|
1015
1021
|
* over the built-ins: a same-name entry replaces the built-in serializer, and
|
|
1016
1022
|
* one that always returns `null` effectively opts that component out.
|
|
1017
1023
|
*
|
|
1018
|
-
* `frontmatter` is the page's parsed front-matter data.
|
|
1019
|
-
*
|
|
1020
|
-
*
|
|
1021
|
-
*
|
|
1024
|
+
* `frontmatter` is the page's parsed front-matter data. Attribute
|
|
1025
|
+
* expressions that reference it — `prop={frontmatter.status}` — resolve the
|
|
1026
|
+
* way they do when Astro renders the page, and it is handed to serializers on
|
|
1027
|
+
* their context. Expressions are read as literal data, never executed.
|
|
1022
1028
|
*/
|
|
1023
1029
|
export const downlevelComponents = (
|
|
1024
1030
|
source: string,
|
package/src/ai/link-headers.ts
CHANGED
|
@@ -5,7 +5,11 @@ import {
|
|
|
5
5
|
AI_CATALOG_TYPE,
|
|
6
6
|
hasAiCatalog,
|
|
7
7
|
} from "./ai-catalog.ts";
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
API_CATALOG_PATH,
|
|
10
|
+
API_CATALOG_TYPE,
|
|
11
|
+
hasApiCatalog,
|
|
12
|
+
} from "./api-catalog.ts";
|
|
9
13
|
import { OPENAPI_PATH } from "./api/paths.ts";
|
|
10
14
|
|
|
11
15
|
/**
|
|
@@ -37,10 +41,11 @@ export const buildHomeLinkHeader = (
|
|
|
37
41
|
const deployBase = normalizeBasePath(config.deployment.options.base);
|
|
38
42
|
const links: string[] = [];
|
|
39
43
|
// RFC 9727 §3: the api-catalog relation is how a homepage advertises the
|
|
40
|
-
// well-known catalog.
|
|
44
|
+
// well-known catalog. Its type carries the RFC 9727 profile, whose quotes
|
|
45
|
+
// are escaped inside the quoted `type` value (RFC 8288 quoted-string).
|
|
41
46
|
if (hasApiCatalog(config)) {
|
|
42
47
|
links.push(
|
|
43
|
-
`<${deployBase}${API_CATALOG_PATH}>; rel="api-catalog"; type="
|
|
48
|
+
`<${deployBase}${API_CATALOG_PATH}>; rel="api-catalog"; type="${API_CATALOG_TYPE.replaceAll('"', String.raw`\"`)}"`
|
|
44
49
|
);
|
|
45
50
|
}
|
|
46
51
|
// The ai-catalog spec's own relation for its well-known document, the
|
package/src/ai/llms.ts
CHANGED
|
@@ -312,10 +312,11 @@ const buildFull = async (project: BlumeProject): Promise<string> => {
|
|
|
312
312
|
source: raw,
|
|
313
313
|
sourcePath: page.sourcePath,
|
|
314
314
|
});
|
|
315
|
-
// Relative page links too: a reader of one flat file has no page URL
|
|
316
|
-
// to resolve `./install` against.
|
|
317
|
-
raw = rewriteLinks(raw, page);
|
|
318
315
|
}
|
|
316
|
+
// Page links too: a reader of one flat file has no page URL to resolve
|
|
317
|
+
// `./install` against, and `/install` needs the base the site is
|
|
318
|
+
// served under.
|
|
319
|
+
raw = rewriteLinks(raw, page);
|
|
319
320
|
// Resolve `<Visibility>` audiences (web-only content omitted from the
|
|
320
321
|
// agent-facing output, agents-only unwrapped), then downlevel supported
|
|
321
322
|
// components to plain Markdown.
|
package/src/ai/markdown.ts
CHANGED
|
@@ -8,6 +8,7 @@ import matter from "../core/frontmatter.ts";
|
|
|
8
8
|
import type { BlumeProject } from "../core/project-graph.ts";
|
|
9
9
|
import { readExpandedEntryText } from "../core/sources/read.ts";
|
|
10
10
|
import type { RouteManifestEntry } from "../core/types.ts";
|
|
11
|
+
import { advertisedConfig, servesMcp } from "./agent-surface.ts";
|
|
11
12
|
import { buildChangelogIndexMarkdown } from "./changelog-markdown.ts";
|
|
12
13
|
import { downlevelComponents } from "./component-markdown.ts";
|
|
13
14
|
import { buildLlmsIndex } from "./llms.ts";
|
|
@@ -80,13 +81,14 @@ export const buildRawMarkdown = async (
|
|
|
80
81
|
source: text,
|
|
81
82
|
sourcePath: route.sourcePath,
|
|
82
83
|
});
|
|
83
|
-
// `./install` means the page's sibling, not whatever the `.md` URL
|
|
84
|
-
// an agent fetched resolves it to.
|
|
85
|
-
text = rewriteLinks(text, {
|
|
86
|
-
route: route.path,
|
|
87
|
-
sourcePath: route.sourcePath,
|
|
88
|
-
});
|
|
89
84
|
}
|
|
85
|
+
// `./install` means the page's sibling, not whatever the `.md` URL an
|
|
86
|
+
// agent fetched resolves it to, and `/install` gains the base and the
|
|
87
|
+
// page's locale the rendered link has — remote content included.
|
|
88
|
+
text = rewriteLinks(text, {
|
|
89
|
+
route: route.path,
|
|
90
|
+
sourcePath: route.sourcePath,
|
|
91
|
+
});
|
|
90
92
|
const source = applyAgentVisibility(text);
|
|
91
93
|
// The `.md` variant keeps the front-matter block in the output, but its
|
|
92
94
|
// data must also be in scope for `prop={frontmatter.*}` expressions.
|
|
@@ -97,19 +99,29 @@ export const buildRawMarkdown = async (
|
|
|
97
99
|
})
|
|
98
100
|
);
|
|
99
101
|
const map = Object.fromEntries(entries);
|
|
102
|
+
const userPages = project.context.pagesRoot
|
|
103
|
+
? await discoverPages(project.context.pagesRoot)
|
|
104
|
+
: [];
|
|
100
105
|
// A landing-page homepage (user `.astro` page, or no home route at all) has
|
|
101
106
|
// no Markdown source, but agents negotiating `Accept: text/markdown` on `/`
|
|
102
107
|
// still expect a Markdown answer. The llms.txt index — the machine-readable
|
|
103
108
|
// representation of the site a landing page fronts — becomes its mirror, so
|
|
104
|
-
// `/index.md` always exists (see `markdownRoutePaths`).
|
|
109
|
+
// `/index.md` always exists (see `markdownRoutePaths`). Like llms.txt, it
|
|
110
|
+
// leaves out an MCP server a page's route kept from being generated.
|
|
105
111
|
if (!map["/"]) {
|
|
106
|
-
map["/"] = {
|
|
112
|
+
map["/"] = {
|
|
113
|
+
mdx: buildLlmsIndex({
|
|
114
|
+
...project,
|
|
115
|
+
config: advertisedConfig(project.config, {
|
|
116
|
+
mcp: servesMcp(project, userPages),
|
|
117
|
+
// Skills are collected at the end of the build, after this runs.
|
|
118
|
+
skills: Boolean(project.config.agents.skills),
|
|
119
|
+
}),
|
|
120
|
+
}),
|
|
121
|
+
};
|
|
107
122
|
}
|
|
108
123
|
// The generated changelog index has no source either; its release list is
|
|
109
124
|
// its mirror, so `/changelog.md` and `get_page` answer as the page does.
|
|
110
|
-
const userPages = project.context.pagesRoot
|
|
111
|
-
? await discoverPages(project.context.pagesRoot)
|
|
112
|
-
: [];
|
|
113
125
|
if (hasGeneratedChangelog(project, userPages)) {
|
|
114
126
|
map[CHANGELOG_INDEX_ROUTE] = { mdx: buildChangelogIndexMarkdown(project) };
|
|
115
127
|
}
|