blume 2.0.0 → 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/AGENTS.md +1 -1
- package/CHANGELOG.md +110 -0
- package/README.md +2 -2
- package/dist/cli/{chunk-f2972sbt.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-pat2zzwc.js → chunk-3yce002v.js} +21 -8
- package/dist/cli/{chunk-pat2zzwc.js.map → chunk-3yce002v.js.map} +4 -4
- package/dist/cli/{chunk-d1tadaw7.js → chunk-4e9b9ra6.js} +17 -7
- package/dist/cli/chunk-4e9b9ra6.js.map +10 -0
- package/dist/cli/{chunk-zg2gtj10.js → chunk-5r8g91qn.js} +352 -676
- package/dist/cli/chunk-5r8g91qn.js.map +34 -0
- package/dist/cli/{chunk-11j0384y.js → chunk-6dtt0zfn.js} +14 -14
- package/dist/cli/{chunk-11j0384y.js.map → chunk-6dtt0zfn.js.map} +3 -3
- package/dist/cli/{chunk-bw22s759.js → chunk-6k4ftwze.js} +38 -19
- package/dist/cli/{chunk-bw22s759.js.map → chunk-6k4ftwze.js.map} +4 -4
- package/dist/cli/{chunk-sqn5t4q0.js → chunk-7mbqtmgb.js} +16 -7
- package/dist/cli/chunk-7mbqtmgb.js.map +10 -0
- package/dist/cli/{chunk-79njf86q.js → chunk-7vtckvaw.js} +21 -19
- package/dist/cli/chunk-7vtckvaw.js.map +11 -0
- package/dist/cli/{chunk-fh5hj5jt.js → chunk-8g8ytmgx.js} +17 -18
- package/dist/cli/{chunk-fh5hj5jt.js.map → chunk-8g8ytmgx.js.map} +2 -2
- package/dist/cli/{chunk-1w8dp3qb.js → chunk-91ws1n6j.js} +18 -15
- package/dist/cli/chunk-91ws1n6j.js.map +10 -0
- package/dist/cli/{chunk-7ez8ny0t.js → chunk-bbnwccaz.js} +2 -2
- package/dist/cli/{chunk-5a2z0198.js → chunk-bfwp9vp6.js} +18 -10
- package/dist/cli/chunk-bfwp9vp6.js.map +10 -0
- package/dist/cli/{chunk-ernrthtr.js → chunk-d1v5rhy0.js} +14 -15
- package/dist/cli/{chunk-ernrthtr.js.map → chunk-d1v5rhy0.js.map} +2 -2
- package/dist/cli/{chunk-a9kptbw5.js → chunk-ddndchfr.js} +21 -6
- package/dist/cli/chunk-ddndchfr.js.map +14 -0
- package/dist/cli/{chunk-zxccj738.js → chunk-esh98wmb.js} +1 -1
- package/dist/cli/{chunk-88cpgt6h.js → chunk-fsmrqk8a.js} +1 -1
- package/dist/cli/{chunk-b5aj94ah.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-41za066z.js → chunk-h2ez8dzb.js} +4 -4
- package/dist/cli/{chunk-by2290sx.js → chunk-h7k3nq3v.js} +2 -2
- package/dist/cli/{chunk-j8mw0za6.js → chunk-hqp2ajnh.js} +252 -123
- package/dist/cli/chunk-hqp2ajnh.js.map +35 -0
- package/dist/cli/{chunk-mnqj32sj.js → chunk-hr8ne106.js} +119 -50
- package/dist/cli/chunk-hr8ne106.js.map +13 -0
- package/dist/cli/{chunk-mwt1k8n7.js → chunk-j85scx15.js} +74 -30
- package/dist/cli/chunk-j85scx15.js.map +10 -0
- package/dist/cli/{chunk-z01ze5c1.js → chunk-k7pj68a8.js} +63 -22
- package/dist/cli/chunk-k7pj68a8.js.map +11 -0
- package/dist/cli/{chunk-2q1dwty4.js → chunk-mqc662a6.js} +8 -8
- package/dist/cli/{chunk-2q1dwty4.js.map → chunk-mqc662a6.js.map} +4 -4
- package/dist/cli/{chunk-y3e45rc8.js → chunk-n1yg3tj3.js} +4 -4
- package/dist/cli/{chunk-bctazmbk.js → chunk-nfcyttvj.js} +17 -6
- package/dist/cli/chunk-nfcyttvj.js.map +10 -0
- package/dist/cli/{chunk-6k8vp3ta.js → chunk-pbg5a4s3.js} +60 -28
- package/dist/cli/chunk-pbg5a4s3.js.map +19 -0
- package/dist/cli/{chunk-d80hr03s.js → chunk-ppzjqwx2.js} +24 -17
- package/dist/cli/{chunk-d80hr03s.js.map → chunk-ppzjqwx2.js.map} +4 -4
- package/dist/cli/{chunk-beat36xx.js → chunk-qkb5a8sa.js} +25 -10
- package/dist/cli/chunk-qkb5a8sa.js.map +10 -0
- package/dist/cli/{chunk-bnbmcwfb.js → chunk-sqw4ekg1.js} +5 -5
- package/dist/cli/{chunk-bnbmcwfb.js.map → chunk-sqw4ekg1.js.map} +3 -3
- package/dist/cli/{chunk-xaz13gwg.js → chunk-v6ya5kcb.js} +3268 -1150
- package/dist/cli/chunk-v6ya5kcb.js.map +189 -0
- package/dist/cli/{chunk-tzne8qfq.js → chunk-w4bxdvsa.js} +18 -15
- package/dist/cli/chunk-w4bxdvsa.js.map +10 -0
- package/dist/cli/{chunk-f7t03s3g.js → chunk-wdrt2k2v.js} +2 -2
- package/dist/cli/{chunk-z1f5arsg.js → chunk-xh43dwgw.js} +170 -55
- package/dist/cli/chunk-xh43dwgw.js.map +36 -0
- package/dist/cli/{chunk-pnnvybbk.js → chunk-zp79m0ts.js} +5 -5
- package/dist/cli/{chunk-pnnvybbk.js.map → chunk-zp79m0ts.js.map} +2 -2
- package/dist/cli/index.js +160 -35
- package/dist/cli/index.js.map +4 -4
- package/dist/types/ai/agent-readability.d.ts +1 -1
- package/dist/types/ai/agent-surface.d.ts +32 -0
- package/dist/types/ai/api/paths.d.ts +1 -1
- package/dist/types/ai/api-catalog.d.ts +7 -1
- package/dist/types/ai/ask-context.d.ts +14 -7
- package/dist/types/ai/ask.d.ts +43 -43
- package/dist/types/ai/component-markdown.d.ts +4 -4
- package/dist/types/ai/index.d.ts +3 -3
- package/dist/types/ai/openapi-components.d.ts +1 -1
- package/dist/types/ai/relative-links.d.ts +9 -4
- package/dist/types/ai/serializers.d.ts +1 -1
- package/dist/types/ai/static-expression.d.ts +28 -0
- package/dist/types/ai/visibility.d.ts +1 -1
- 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 +21 -21
- package/dist/types/core/config.d.ts +5 -5
- package/dist/types/core/data.d.ts +3 -3
- package/dist/types/core/graph.d.ts +2 -0
- package/dist/types/core/i18n-ui.d.ts +37 -8
- 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 +57 -18
- 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/core/unrecognized-keys.d.ts +1 -1
- 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/documents.d.ts +1 -1
- package/dist/types/search/orama-index.d.ts +1 -1
- package/dist/types/search/sync/algolia.d.ts +3 -1
- package/docs/01-quickstart.mdx +3 -2
- package/docs/02-deployment.mdx +21 -12
- package/docs/03-upgrading.mdx +22 -9
- package/docs/04-migrating.mdx +4 -4
- package/docs/08-faq.mdx +12 -5
- package/docs/advanced/changelog.mdx +1 -1
- package/docs/advanced/custom-pages.mdx +5 -3
- package/docs/advanced/skills.mdx +1 -1
- package/docs/cli/audit.mdx +5 -5
- package/docs/cli/doctor.mdx +4 -4
- package/docs/cli/evals.mdx +9 -9
- package/docs/cli/index.mdx +6 -3
- package/docs/cli/translate.mdx +8 -8
- package/docs/configuration/analytics.mdx +23 -2
- package/docs/configuration/{ask-ai.mdx → assistant.mdx} +20 -20
- package/docs/configuration/customization.mdx +5 -4
- package/docs/configuration/index.mdx +7 -5
- package/docs/configuration/meta.ts +1 -1
- package/docs/configuration/search.mdx +2 -2
- package/docs/content/components.mdx +1 -1
- package/docs/content/frontmatter.mdx +5 -1
- package/docs/content/i18n.mdx +3 -3
- package/docs/content/index.mdx +4 -2
- package/docs/content/islands.mdx +1 -1
- 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 +22 -8
- package/docs/discoverability/index.mdx +3 -3
- 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/index.mdx +2 -2
- 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/SKILL.md +5 -5
- 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-readability.ts +4 -4
- package/src/ai/agent-surface.ts +56 -0
- package/src/ai/api/paths.ts +1 -1
- package/src/ai/api/spec.ts +15 -2
- package/src/ai/api-catalog.ts +7 -1
- package/src/ai/ask-context.ts +21 -9
- package/src/ai/ask-data.ts +28 -14
- package/src/ai/ask.ts +84 -71
- package/src/ai/component-markdown.ts +43 -37
- package/src/ai/cors.ts +3 -3
- package/src/ai/index.ts +16 -16
- 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/openapi-components.ts +1 -1
- package/src/ai/relative-links.ts +78 -10
- package/src/ai/serializers.ts +1 -1
- package/src/ai/static-expression.ts +416 -0
- package/src/ai/visibility.ts +46 -15
- 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 +90 -45
- package/src/astro/module-types.ts +1 -1
- package/src/astro/runtime-deps.ts +6 -6
- package/src/astro/templates.ts +87 -49
- 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/blume-modules.d.ts +2 -2
- package/src/cli/build-failure.ts +50 -0
- package/src/cli/commands/audit.ts +8 -1
- package/src/cli/commands/build.ts +19 -5
- package/src/cli/commands/check.ts +2 -0
- package/src/cli/commands/doctor.ts +7 -5
- package/src/cli/commands/eval.ts +4 -10
- package/src/cli/commands/init.ts +15 -5
- package/src/cli/commands/migrate.ts +2 -2
- package/src/cli/commands/preview.ts +15 -0
- package/src/cli/commands/sync.ts +2 -0
- package/src/cli/commands/translate.ts +12 -9
- package/src/cli/commands/upgrade.ts +13 -2
- 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/cli/required-secrets.ts +3 -3
- 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 +36 -9
- package/src/components/islands/{AskAI.astro → Assistant.astro} +10 -10
- package/src/components/islands/{ask-ai.tsx → assistant.tsx} +39 -25
- package/src/components/islands/hooks.ts +21 -14
- package/src/components/islands/webmcp.ts +12 -8
- package/src/components/layout/Banner.astro +23 -4
- package/src/components/layout/Header.astro +32 -19
- 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 +28 -14
- package/src/components/layout/Pagination.astro +7 -7
- package/src/components/layout/ReferenceLayout.astro +5 -2
- package/src/components/layout/RootLayout.astro +27 -14
- package/src/components/layout/Search.astro +18 -14
- package/src/components/layout/analytics-client.ts +3 -1
- package/src/components/layout/drawer-inert.ts +1 -1
- 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/description.ts +2 -2
- 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/code-fences.ts +1 -1
- package/src/core/config-input.ts +23 -23
- package/src/core/config.ts +21 -7
- package/src/core/data.ts +3 -3
- package/src/core/diagnostics.ts +217 -30
- package/src/core/graph.ts +120 -11
- package/src/core/i18n-ui.ts +74 -11
- 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/request-body.ts +1 -1
- package/src/core/safe-href.ts +53 -1
- package/src/core/safe-links.ts +11 -2
- package/src/core/schema.ts +95 -34
- package/src/core/server-features.ts +2 -2
- 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 +17 -5
- package/src/core/ui-packs/bg.ts +17 -5
- package/src/core/ui-packs/bn.ts +17 -5
- package/src/core/ui-packs/ca.ts +17 -5
- package/src/core/ui-packs/cs.ts +17 -5
- package/src/core/ui-packs/da.ts +17 -5
- package/src/core/ui-packs/de.ts +17 -5
- package/src/core/ui-packs/el.ts +17 -5
- package/src/core/ui-packs/es.ts +17 -5
- package/src/core/ui-packs/fa.ts +17 -5
- package/src/core/ui-packs/fi.ts +17 -5
- package/src/core/ui-packs/fr.ts +17 -5
- package/src/core/ui-packs/he.ts +17 -5
- package/src/core/ui-packs/hi.ts +17 -5
- package/src/core/ui-packs/hr.ts +17 -5
- package/src/core/ui-packs/hu.ts +17 -5
- package/src/core/ui-packs/id.ts +17 -5
- package/src/core/ui-packs/it.ts +17 -5
- package/src/core/ui-packs/ja.ts +17 -5
- package/src/core/ui-packs/ko.ts +17 -5
- package/src/core/ui-packs/nl.ts +17 -5
- package/src/core/ui-packs/no.ts +17 -5
- package/src/core/ui-packs/pl.ts +17 -5
- package/src/core/ui-packs/pt-br.ts +17 -5
- package/src/core/ui-packs/pt.ts +17 -5
- package/src/core/ui-packs/ro.ts +17 -5
- package/src/core/ui-packs/ru.ts +17 -5
- package/src/core/ui-packs/sk.ts +17 -5
- package/src/core/ui-packs/sr.ts +17 -5
- package/src/core/ui-packs/sv.ts +17 -5
- package/src/core/ui-packs/th.ts +17 -5
- package/src/core/ui-packs/tr.ts +17 -5
- package/src/core/ui-packs/uk.ts +17 -5
- package/src/core/ui-packs/vi.ts +17 -5
- package/src/core/ui-packs/zh-tw.ts +17 -5
- package/src/core/ui-packs/zh.ts +17 -5
- package/src/core/unrecognized-keys.ts +1 -1
- 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 +135 -37
- package/src/search/documents.ts +24 -3
- package/src/search/orama-index.ts +1 -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/report.ts +1 -1
- 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 +37 -5
- package/dist/cli/chunk-1w8dp3qb.js.map +0 -10
- package/dist/cli/chunk-5a2z0198.js.map +0 -10
- package/dist/cli/chunk-6k8vp3ta.js.map +0 -19
- package/dist/cli/chunk-79njf86q.js.map +0 -11
- package/dist/cli/chunk-a9kptbw5.js.map +0 -14
- package/dist/cli/chunk-abh8yjkn.js +0 -31
- package/dist/cli/chunk-abh8yjkn.js.map +0 -10
- package/dist/cli/chunk-bctazmbk.js.map +0 -10
- package/dist/cli/chunk-beat36xx.js.map +0 -10
- package/dist/cli/chunk-d1tadaw7.js.map +0 -10
- package/dist/cli/chunk-fa25z98p.js.map +0 -11
- package/dist/cli/chunk-j8mw0za6.js.map +0 -35
- package/dist/cli/chunk-mnqj32sj.js.map +0 -12
- package/dist/cli/chunk-mwt1k8n7.js.map +0 -10
- package/dist/cli/chunk-nk3ts2xk.js +0 -51
- package/dist/cli/chunk-nk3ts2xk.js.map +0 -10
- package/dist/cli/chunk-sqn5t4q0.js.map +0 -10
- package/dist/cli/chunk-tzne8qfq.js.map +0 -10
- package/dist/cli/chunk-xaz13gwg.js.map +0 -182
- package/dist/cli/chunk-z01ze5c1.js.map +0 -10
- package/dist/cli/chunk-z1f5arsg.js.map +0 -36
- package/dist/cli/chunk-zg2gtj10.js.map +0 -35
- /package/dist/cli/{chunk-f2972sbt.js.map → chunk-00gs3wqs.js.map} +0 -0
- /package/dist/cli/{chunk-7ez8ny0t.js.map → chunk-bbnwccaz.js.map} +0 -0
- /package/dist/cli/{chunk-zxccj738.js.map → chunk-esh98wmb.js.map} +0 -0
- /package/dist/cli/{chunk-88cpgt6h.js.map → chunk-fsmrqk8a.js.map} +0 -0
- /package/dist/cli/{chunk-b5aj94ah.js.map → chunk-g698a744.js.map} +0 -0
- /package/dist/cli/{chunk-41za066z.js.map → chunk-h2ez8dzb.js.map} +0 -0
- /package/dist/cli/{chunk-by2290sx.js.map → chunk-h7k3nq3v.js.map} +0 -0
- /package/dist/cli/{chunk-y3e45rc8.js.map → chunk-n1yg3tj3.js.map} +0 -0
- /package/dist/cli/{chunk-f7t03s3g.js.map → chunk-wdrt2k2v.js.map} +0 -0
package/src/ai/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Assistant provider adapters for `blume.config.ts`:
|
|
3
3
|
*
|
|
4
4
|
* ```ts
|
|
5
5
|
* import { defineConfig } from "blume";
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*
|
|
8
8
|
* export default defineConfig({
|
|
9
9
|
* ai: {
|
|
10
|
-
*
|
|
10
|
+
* assistant: {
|
|
11
11
|
* enabled: true,
|
|
12
12
|
* provider: openrouter({ model: "anthropic/claude-sonnet-4-5" }),
|
|
13
13
|
* },
|
|
@@ -27,19 +27,19 @@ export {
|
|
|
27
27
|
openrouter,
|
|
28
28
|
} from "./ask.ts";
|
|
29
29
|
export type {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
30
|
+
AssistantAdapter,
|
|
31
|
+
AssistantAdapterOptions,
|
|
32
|
+
AssistantGatewayAdapter,
|
|
33
|
+
AssistantGatewayOptions,
|
|
34
|
+
AssistantInkeepAdapter,
|
|
35
|
+
AssistantInkeepOptions,
|
|
36
|
+
AssistantLlmGatewayAdapter,
|
|
37
|
+
AssistantLlmGatewayOptions,
|
|
38
|
+
AssistantOpenAICompatibleAdapter,
|
|
39
|
+
AssistantOpenAICompatibleOptions,
|
|
40
|
+
AssistantOpenRouterAdapter,
|
|
41
|
+
AssistantOpenRouterOptions,
|
|
42
|
+
AssistantProviderOptions,
|
|
43
|
+
AssistantReasoning,
|
|
44
44
|
} from "./ask.ts";
|
|
45
45
|
export type { AdapterDescriptor } from "../core/adapter.ts";
|
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
|
}
|
package/src/ai/mcp/server.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
|
2
2
|
import type { ServerOptions } from "@modelcontextprotocol/sdk/server/index.js";
|
|
3
3
|
import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
|
|
4
4
|
import {
|
|
5
|
-
|
|
5
|
+
ErrorCode,
|
|
6
6
|
ListResourcesRequestSchema,
|
|
7
7
|
ListToolsRequestSchema,
|
|
8
8
|
McpError,
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
import { z } from "zod";
|
|
12
12
|
|
|
13
13
|
import { withBasePath } from "../../core/base-path.ts";
|
|
14
|
+
import { readCappedText } from "../../core/request-body.ts";
|
|
14
15
|
import type { McpData } from "./data.ts";
|
|
15
16
|
import {
|
|
16
17
|
createIndexProvider,
|
|
@@ -42,6 +43,12 @@ const RESOURCE_MIME_TYPE = "text/markdown";
|
|
|
42
43
|
const RESOURCE_NOT_FOUND = -32_002;
|
|
43
44
|
/** URI scheme for page resources when no `deployment.site` is configured. */
|
|
44
45
|
const LOCAL_RESOURCE_SCHEME = "blume:";
|
|
46
|
+
/**
|
|
47
|
+
* The largest request body the HTTP endpoint reads. A JSON-RPC call to these
|
|
48
|
+
* tools is a few hundred bytes; the cap keeps one oversized POST from being
|
|
49
|
+
* buffered whole, as the assistant route's does.
|
|
50
|
+
*/
|
|
51
|
+
const MCP_BODY_LIMIT_BYTES = 65_536;
|
|
45
52
|
|
|
46
53
|
const CORS_HEADERS = {
|
|
47
54
|
"Access-Control-Allow-Headers":
|
|
@@ -108,6 +115,20 @@ const resourceRoute = (uri: string, data: McpData): string =>
|
|
|
108
115
|
data
|
|
109
116
|
);
|
|
110
117
|
|
|
118
|
+
/**
|
|
119
|
+
* The `tools/call` params, as far as the server reads them before dispatch:
|
|
120
|
+
* each tool validates its own `arguments` against `TOOL_INPUTS`.
|
|
121
|
+
*/
|
|
122
|
+
const TOOL_CALL_PARAMS = z.object({
|
|
123
|
+
arguments: z.record(z.string(), z.unknown()).optional(),
|
|
124
|
+
name: z.string(),
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
/** A tool call's `arguments` object, before the tool's own validation. */
|
|
128
|
+
type ToolArguments = NonNullable<
|
|
129
|
+
z.output<typeof TOOL_CALL_PARAMS>["arguments"]
|
|
130
|
+
>;
|
|
131
|
+
|
|
111
132
|
/** A tool call's text result, marked as an error when `isError` is set. */
|
|
112
133
|
const text = (value: string, isError = false) => {
|
|
113
134
|
const content = [{ text: value, type: "text" as const }];
|
|
@@ -165,9 +186,7 @@ export const buildServer = (
|
|
|
165
186
|
};
|
|
166
187
|
});
|
|
167
188
|
|
|
168
|
-
|
|
169
|
-
const { arguments: args = {}, name } = request.params;
|
|
170
|
-
|
|
189
|
+
const callTool = async (name: string, args: ToolArguments) => {
|
|
171
190
|
if (name === "search_docs") {
|
|
172
191
|
const results = await searchDocs(
|
|
173
192
|
data,
|
|
@@ -206,12 +225,44 @@ export const buildServer = (
|
|
|
206
225
|
return text(JSON.stringify(result.navigation, null, 2));
|
|
207
226
|
}
|
|
208
227
|
|
|
209
|
-
|
|
210
|
-
|
|
228
|
+
// The MCP spec answers an unknown tool with a protocol error, not a
|
|
229
|
+
// failed tool result.
|
|
230
|
+
throw new McpError(ErrorCode.InvalidParams, `Unknown tool: ${name}`);
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
// `tools/call` goes through the fallback handler rather than a registered
|
|
234
|
+
// one: the SDK parses a registered handler's request against its own
|
|
235
|
+
// schema first and reports a malformed call (`arguments` that aren't an
|
|
236
|
+
// object) as -32603 Internal error carrying a raw Zod dump. Reading the
|
|
237
|
+
// params here answers it as -32602 Invalid params with a short message.
|
|
238
|
+
server.fallbackRequestHandler = async (request) => {
|
|
239
|
+
if (request.method !== "tools/call") {
|
|
240
|
+
throw new McpError(ErrorCode.MethodNotFound, "Method not found");
|
|
241
|
+
}
|
|
242
|
+
const params = TOOL_CALL_PARAMS.safeParse(request.params);
|
|
243
|
+
if (!params.success) {
|
|
244
|
+
throw new McpError(
|
|
245
|
+
ErrorCode.InvalidParams,
|
|
246
|
+
"Invalid tools/call params: `name` must be a string and `arguments`, when given, an object."
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
return await callTool(params.data.name, params.data.arguments ?? {});
|
|
250
|
+
};
|
|
211
251
|
|
|
212
252
|
return server;
|
|
213
253
|
};
|
|
214
254
|
|
|
255
|
+
/** A JSON-RPC error response the transport would send, for errors raised before it runs. */
|
|
256
|
+
const jsonRpcError = (
|
|
257
|
+
status: number,
|
|
258
|
+
code: number,
|
|
259
|
+
message: string
|
|
260
|
+
): Response =>
|
|
261
|
+
Response.json(
|
|
262
|
+
{ error: { code, message }, id: null, jsonrpc: "2.0" },
|
|
263
|
+
{ headers: CORS_HEADERS, status }
|
|
264
|
+
);
|
|
265
|
+
|
|
215
266
|
/**
|
|
216
267
|
* Build a stateless Streamable-HTTP MCP request handler from a data snapshot.
|
|
217
268
|
*
|
|
@@ -239,6 +290,26 @@ export const createMcpFetchHandler = (
|
|
|
239
290
|
});
|
|
240
291
|
}
|
|
241
292
|
|
|
293
|
+
// The transport would read the body with `request.json()`, buffering
|
|
294
|
+
// whatever a client sends; read it under the cap first and hand the
|
|
295
|
+
// transport a copy.
|
|
296
|
+
let forwarded = request;
|
|
297
|
+
if (request.method === "POST") {
|
|
298
|
+
const body = await readCappedText(request, MCP_BODY_LIMIT_BYTES);
|
|
299
|
+
if (body === undefined) {
|
|
300
|
+
return jsonRpcError(
|
|
301
|
+
413,
|
|
302
|
+
ErrorCode.InvalidRequest,
|
|
303
|
+
"Request too large: the body must be at most 64 KB."
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
forwarded = new Request(request.url, {
|
|
307
|
+
body,
|
|
308
|
+
headers: request.headers,
|
|
309
|
+
method: "POST",
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
|
|
242
313
|
const server = buildServer(data, index);
|
|
243
314
|
const transport = new WebStandardStreamableHTTPServerTransport({
|
|
244
315
|
enableJsonResponse: true,
|
|
@@ -248,7 +319,7 @@ export const createMcpFetchHandler = (
|
|
|
248
319
|
sessionIdGenerator: undefined,
|
|
249
320
|
});
|
|
250
321
|
await server.connect(transport);
|
|
251
|
-
const response = await transport.handleRequest(
|
|
322
|
+
const response = await transport.handleRequest(forwarded);
|
|
252
323
|
|
|
253
324
|
const headers = new Headers(response.headers);
|
|
254
325
|
for (const [key, value] of Object.entries(CORS_HEADERS)) {
|
|
@@ -44,7 +44,7 @@ const listItem = (
|
|
|
44
44
|
* the body plus one of these components, deliberately: the structured UI is the
|
|
45
45
|
* component's job, and the prose stays Markdown so it indexes. That split is
|
|
46
46
|
* right for the rendered page and lossy everywhere else — `<route>.md`,
|
|
47
|
-
* llms-full.txt, MCP `get_page` and the
|
|
47
|
+
* llms-full.txt, MCP `get_page` and the assistant corpus all downlevel components
|
|
48
48
|
* to Markdown, and these three had no serializer, so an operation page reached
|
|
49
49
|
* an agent as its description followed by a bare tag. On a site whose reference
|
|
50
50
|
* is most of the corpus, that is most of the corpus: measured on one 449-page
|
package/src/ai/relative-links.ts
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import { basename } from "pathe";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
isInternalPath,
|
|
5
|
+
normalizeBasePath,
|
|
6
|
+
withBasePath,
|
|
7
|
+
withComposedBasePath,
|
|
8
|
+
} from "../core/base-path.ts";
|
|
4
9
|
import { nextFenceState } from "../core/code-fences.ts";
|
|
5
10
|
import type { FenceState } from "../core/code-fences.ts";
|
|
11
|
+
import { localePrefix } from "../core/i18n.ts";
|
|
6
12
|
import {
|
|
7
13
|
buildFileRouteIndex,
|
|
8
14
|
isIndexFileName,
|
|
@@ -10,19 +16,25 @@ import {
|
|
|
10
16
|
routeOfLinkedFile,
|
|
11
17
|
} from "../core/links.ts";
|
|
12
18
|
import type { RelativeLinkBase } from "../core/links.ts";
|
|
19
|
+
import { localizeHref } from "../core/locale-links.ts";
|
|
13
20
|
import type { BlumeProject } from "../core/project-graph.ts";
|
|
14
21
|
import { extractLinks } from "../core/sources/normalize.ts";
|
|
15
22
|
|
|
16
23
|
/**
|
|
17
|
-
*
|
|
24
|
+
* Page links on the agent surfaces — the `.md`/`.mdx` mirrors,
|
|
18
25
|
* llms-full.txt, MCP `get_page` and `resources/read`. An agent resolves
|
|
19
26
|
* `[Install](./install)` against the URL it fetched (`/guides.md`), so the
|
|
20
27
|
* link lands on `/install`; the rendered page rewrites it to the route it
|
|
21
28
|
* means (`markdown/relative-links.ts`), and the Markdown an agent reads gets
|
|
22
29
|
* the same rewrite from the same resolver (`resolveRelativeHref`), so both
|
|
23
|
-
* point at one page.
|
|
24
|
-
*
|
|
25
|
-
*
|
|
30
|
+
* point at one page. Root-relative page links (`[x](/guide)`,
|
|
31
|
+
* `<Card href="/guide">`) get what the rendered page gives them too: the
|
|
32
|
+
* `deployment.base` + `basePath` prefix (`markdown/base-links.ts`,
|
|
33
|
+
* `components/content/base-href.ts`) and, on a page in a prefixed locale,
|
|
34
|
+
* that locale's copy of the route when it is served
|
|
35
|
+
* (`components/layout/LocaleLinks.astro`). Inline links, component `href`s,
|
|
36
|
+
* and reference definitions are rewritten; fenced and inline code, images,
|
|
37
|
+
* asset links, and external URLs are left as written.
|
|
26
38
|
*/
|
|
27
39
|
|
|
28
40
|
/** The page a Markdown text was written for. */
|
|
@@ -47,6 +59,21 @@ const DEFINITION =
|
|
|
47
59
|
const MAYBE_RELATIVE =
|
|
48
60
|
/\]\([\t ]*<?(?![a-z][\d+.a-z-]*:|\/|#)|^ {0,3}\[[^\]\n]+\]:[\t ]*<?(?![a-z][\d+.a-z-]*:|\/|#)|\shref=["'](?![a-z][\d+.a-z-]*:|\/|#)/imu;
|
|
49
61
|
|
|
62
|
+
/**
|
|
63
|
+
* {@link MAYBE_RELATIVE}, or a root-relative target (`/x`, never `//host`):
|
|
64
|
+
* the gate when root-relative links are rewritten too — a base or basePath is
|
|
65
|
+
* set, or the page sits under a locale prefix.
|
|
66
|
+
*/
|
|
67
|
+
const MAYBE_PAGE_LINK =
|
|
68
|
+
/\]\([\t ]*<?(?![a-z][\d+.a-z-]*:|\/\/|#)|^ {0,3}\[[^\]\n]+\]:[\t ]*<?(?![a-z][\d+.a-z-]*:|\/\/|#)|\shref=["'](?![a-z][\d+.a-z-]*:|\/\/|#)/imu;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* A path whose final segment carries a file extension — a `public/` asset or
|
|
72
|
+
* a raw `.md` twin, which the rendered page neither bases nor localizes (see
|
|
73
|
+
* `markdown/base-links.ts`).
|
|
74
|
+
*/
|
|
75
|
+
const ASSET_PATH = /\.[\da-z]+$/iu;
|
|
76
|
+
|
|
50
77
|
interface Splice {
|
|
51
78
|
column: number;
|
|
52
79
|
length: number;
|
|
@@ -124,7 +151,7 @@ const collectSplices = (
|
|
|
124
151
|
export const relativeLinkRewriter = (
|
|
125
152
|
project: BlumeProject
|
|
126
153
|
): RelativeLinkRewriter => {
|
|
127
|
-
const { deployment, i18n } = project.config;
|
|
154
|
+
const { basePath, deployment, i18n } = project.config;
|
|
128
155
|
const deployBase = normalizeBasePath(deployment.options.base);
|
|
129
156
|
const localeTokens = i18n
|
|
130
157
|
? ["$", ...i18n.locales.map((locale) => locale.code)]
|
|
@@ -137,11 +164,20 @@ export const relativeLinkRewriter = (
|
|
|
137
164
|
])
|
|
138
165
|
);
|
|
139
166
|
const routes = new Set(project.manifest.routes.map((route) => route.path));
|
|
167
|
+
const localeByRoute = new Map(
|
|
168
|
+
project.manifest.routes.map((route) => [route.path, route.locale])
|
|
169
|
+
);
|
|
140
170
|
|
|
141
|
-
|
|
171
|
+
/**
|
|
172
|
+
* A page's relative-link resolver; `undefined` when the page has no file
|
|
173
|
+
* to resolve its links from.
|
|
174
|
+
*/
|
|
175
|
+
const relativeRoute = (
|
|
176
|
+
page: LinkedPage
|
|
177
|
+
): ((target: string) => string | undefined) | undefined => {
|
|
142
178
|
const { sourcePath } = page;
|
|
143
|
-
if (!sourcePath
|
|
144
|
-
return
|
|
179
|
+
if (!sourcePath) {
|
|
180
|
+
return;
|
|
145
181
|
}
|
|
146
182
|
const from: RelativeLinkBase = {
|
|
147
183
|
isIndex: isIndexFileName(basename(sourcePath), localeTokens),
|
|
@@ -150,12 +186,44 @@ export const relativeLinkRewriter = (
|
|
|
150
186
|
const navPath = navPathBySource.get(sourcePath) ?? basename(sourcePath);
|
|
151
187
|
const resolveFile = (path: string): string | undefined =>
|
|
152
188
|
routeOfLinkedFile(fileRoutes, { navPath, sourcePath }, path);
|
|
153
|
-
|
|
189
|
+
return (target) => {
|
|
154
190
|
const route = resolveRelativeHref(target, from, resolveFile, (path) =>
|
|
155
191
|
routes.has(path)
|
|
156
192
|
);
|
|
157
193
|
return route === undefined ? undefined : withBasePath(deployBase, route);
|
|
158
194
|
};
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
return (text, page) => {
|
|
198
|
+
const locale = localeByRoute.get(page.route);
|
|
199
|
+
// The page's locale moves root links only when it has a URL prefix.
|
|
200
|
+
const localize =
|
|
201
|
+
i18n && locale !== undefined && localePrefix(locale, i18n) !== ""
|
|
202
|
+
? { basePath, deployBase, i18n, locale, routes }
|
|
203
|
+
: undefined;
|
|
204
|
+
// A root-relative link only changes when the site is mounted under a
|
|
205
|
+
// prefix or the page reads in a prefixed locale.
|
|
206
|
+
const rootLinks =
|
|
207
|
+
deployBase !== "" || basePath !== "" || localize !== undefined;
|
|
208
|
+
if (
|
|
209
|
+
!(page.sourcePath || rootLinks) ||
|
|
210
|
+
!(rootLinks ? MAYBE_PAGE_LINK : MAYBE_RELATIVE).test(text)
|
|
211
|
+
) {
|
|
212
|
+
return text;
|
|
213
|
+
}
|
|
214
|
+
const relative = relativeRoute(page);
|
|
215
|
+
// What the rendered page makes of `/guide`: based, then moved into the
|
|
216
|
+
// page's locale when that route is served.
|
|
217
|
+
const rooted = (target: string): string | undefined => {
|
|
218
|
+
if (ASSET_PATH.test(target.replace(/[#?].*$/u, ""))) {
|
|
219
|
+
return undefined;
|
|
220
|
+
}
|
|
221
|
+
const based = withComposedBasePath(deployBase, basePath, target);
|
|
222
|
+
const href = localize ? localizeHref(based, localize) : based;
|
|
223
|
+
return href === target ? undefined : href;
|
|
224
|
+
};
|
|
225
|
+
const routed = (target: string): string | undefined =>
|
|
226
|
+
isInternalPath(target) ? rooted(target) : relative?.(target);
|
|
159
227
|
|
|
160
228
|
const lines = text.split("\n");
|
|
161
229
|
const splices = collectSplices(text, lines, routed);
|
package/src/ai/serializers.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { openapiComponentSerializers } from "./openapi-components.ts";
|
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Every serializer a project brings to a downlevel pass, layered once for all
|
|
9
|
-
* the agent surfaces (`<route>.md`, llms-full.txt, the search and
|
|
9
|
+
* the agent surfaces (`<route>.md`, llms-full.txt, the search and assistant
|
|
10
10
|
* corpora): the built-in families that read project data — examples, then the
|
|
11
11
|
* API reference — under the user's `agents.markdownComponents`, which is spread
|
|
12
12
|
* last so an entry of the same name still wins. One layering, so a new family
|