blume 2.1.3 → 2.2.1
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 +134 -0
- package/README.md +4 -4
- package/dist/cli/{chunk-y4msrwm9.js → chunk-080mfch6.js} +15 -15
- package/dist/cli/{chunk-gfc5fqvf.js → chunk-1ch3ct3r.js} +18 -18
- package/dist/cli/{chunk-gfc5fqvf.js.map → chunk-1ch3ct3r.js.map} +1 -1
- package/dist/cli/{chunk-32khwcb6.js → chunk-2ssh60qh.js} +42 -69
- package/dist/cli/{chunk-32khwcb6.js.map → chunk-2ssh60qh.js.map} +9 -10
- package/dist/cli/{chunk-9qzgg6mj.js → chunk-34wap3ed.js} +3 -3
- package/dist/cli/{chunk-k3gr1nm9.js → chunk-40vk8kgf.js} +13 -16
- package/dist/cli/{chunk-k3gr1nm9.js.map → chunk-40vk8kgf.js.map} +3 -3
- package/dist/cli/chunk-487b95qy.js +329 -0
- package/dist/cli/chunk-487b95qy.js.map +13 -0
- package/dist/cli/chunk-4zxh25hc.js +157 -0
- package/dist/cli/chunk-4zxh25hc.js.map +10 -0
- package/dist/cli/chunk-69rjf786.js +146 -0
- package/dist/cli/chunk-69rjf786.js.map +11 -0
- package/dist/cli/{chunk-dqhg54mr.js → chunk-9h8mh2tk.js} +3 -3
- package/dist/cli/{chunk-dqhg54mr.js.map → chunk-9h8mh2tk.js.map} +2 -2
- package/dist/cli/{chunk-bqxaqn5p.js → chunk-9jqmq5hv.js} +8 -8
- package/dist/cli/{chunk-bqxaqn5p.js.map → chunk-9jqmq5hv.js.map} +1 -1
- package/dist/cli/{chunk-dv2z0rzf.js → chunk-aafhwx74.js} +38 -13
- package/dist/cli/{chunk-dv2z0rzf.js.map → chunk-aafhwx74.js.map} +5 -4
- package/dist/cli/{chunk-desvm72z.js → chunk-b680sv30.js} +22 -26
- package/dist/cli/chunk-b680sv30.js.map +13 -0
- package/dist/cli/{chunk-0w6hs479.js → chunk-beb0z983.js} +30 -18
- package/dist/cli/chunk-beb0z983.js.map +10 -0
- package/dist/cli/{chunk-1f882900.js → chunk-c5bjxq8v.js} +2 -2
- package/dist/cli/chunk-e1n41w9m.js +155 -0
- package/dist/cli/chunk-e1n41w9m.js.map +11 -0
- package/dist/cli/{chunk-sc93apfs.js → chunk-etckvbrh.js} +17 -17
- package/dist/cli/{chunk-sc93apfs.js.map → chunk-etckvbrh.js.map} +2 -2
- package/dist/cli/{chunk-bxwhtvw8.js → chunk-f260jdrn.js} +5 -5
- package/dist/cli/{chunk-74wfhv79.js → chunk-fnxgtjeq.js} +1 -1
- package/dist/cli/{chunk-ms9z66nz.js → chunk-gwy55cx3.js} +2 -2
- package/dist/cli/{chunk-ms9z66nz.js.map → chunk-gwy55cx3.js.map} +2 -2
- package/dist/cli/{chunk-dhwtqnnd.js → chunk-gxhcf2hs.js} +2 -2
- package/dist/cli/{chunk-tfycddbt.js → chunk-h0qwdbem.js} +2 -2
- package/dist/cli/{chunk-nbyvgnnm.js → chunk-hktq4j5r.js} +109 -49
- package/dist/cli/chunk-hktq4j5r.js.map +36 -0
- package/dist/cli/{chunk-twy7psdz.js → chunk-hn3g2b89.js} +14 -10
- package/dist/cli/chunk-hn3g2b89.js.map +10 -0
- package/dist/cli/{chunk-j1x92mx9.js → chunk-j4nfgn2j.js} +1 -1
- package/dist/cli/{chunk-dpy8qdjf.js → chunk-k45sq16q.js} +74 -183
- package/dist/cli/chunk-k45sq16q.js.map +18 -0
- package/dist/cli/{chunk-5cmts6dv.js → chunk-kmswjxj9.js} +7 -7
- package/dist/cli/{chunk-5cmts6dv.js.map → chunk-kmswjxj9.js.map} +1 -1
- package/dist/cli/{chunk-36bxs9c7.js → chunk-nqna8dzp.js} +27 -23
- package/dist/cli/chunk-nqna8dzp.js.map +10 -0
- package/dist/cli/{chunk-a57yh0h9.js → chunk-p834rkcn.js} +7 -7
- package/dist/cli/{chunk-a57yh0h9.js.map → chunk-p834rkcn.js.map} +1 -1
- package/dist/cli/{chunk-60hz265r.js → chunk-ppa6mg4d.js} +24 -11
- package/dist/cli/chunk-ppa6mg4d.js.map +10 -0
- package/dist/cli/{chunk-s0bdnc7v.js → chunk-q1wwrxzw.js} +5 -4
- package/dist/cli/chunk-q1wwrxzw.js.map +10 -0
- package/dist/cli/{chunk-ave1wcbr.js → chunk-qcyxkj44.js} +1 -1
- package/dist/cli/{chunk-124fvmzq.js → chunk-r5nm9w0c.js} +11183 -8806
- package/dist/cli/{chunk-124fvmzq.js.map → chunk-r5nm9w0c.js.map} +82 -66
- package/dist/cli/{chunk-ckrcm08h.js → chunk-rtvgmg2j.js} +48 -62
- package/dist/cli/{chunk-ckrcm08h.js.map → chunk-rtvgmg2j.js.map} +4 -5
- package/dist/cli/{chunk-297ajdcv.js → chunk-t2h8pwy1.js} +6 -6
- package/dist/cli/{chunk-297ajdcv.js.map → chunk-t2h8pwy1.js.map} +3 -3
- package/dist/cli/{chunk-gxtg6ed2.js → chunk-x60e15st.js} +21 -21
- package/dist/cli/{chunk-gxtg6ed2.js.map → chunk-x60e15st.js.map} +3 -3
- package/dist/cli/{chunk-58bt3hag.js → chunk-x7bh6d9j.js} +4 -4
- package/dist/cli/{chunk-hvcxng5f.js → chunk-ydqzkhjn.js} +6 -6
- package/dist/cli/{chunk-kdpzw38a.js → chunk-yg8ckc3g.js} +95 -7
- package/dist/cli/chunk-yg8ckc3g.js.map +11 -0
- package/dist/cli/{chunk-0pmb4tr4.js → chunk-zxd5jrgx.js} +1205 -222
- package/dist/cli/chunk-zxd5jrgx.js.map +44 -0
- package/dist/cli/index.js +78 -42
- package/dist/cli/index.js.map +7 -6
- package/dist/types/ai/changelog-components.d.ts +18 -0
- package/dist/types/ai/changelog-markdown.d.ts +12 -0
- package/dist/types/ai/openapi-components.d.ts +7 -7
- package/dist/types/ai/operation-details.d.ts +39 -0
- package/dist/types/ai/relative-links.d.ts +3 -1
- package/dist/types/ai/serializers.d.ts +6 -4
- package/dist/types/analytics/head.d.ts +4 -2
- package/dist/types/analytics/script.d.ts +8 -2
- package/dist/types/components/content/youtube.d.ts +20 -0
- package/dist/types/components/layout/nav-utils.d.ts +8 -0
- package/dist/types/components/openapi/example-panels.d.ts +33 -0
- package/dist/types/components/openapi/helpers.d.ts +53 -11
- package/dist/types/components/openapi/snippets.d.ts +7 -1
- package/dist/types/core/alert-diagnostics.d.ts +10 -0
- package/dist/types/core/builtin-tags.d.ts +16 -0
- package/dist/types/core/changelog-list.d.ts +48 -0
- package/dist/types/core/closest-match.d.ts +6 -0
- package/dist/types/core/code-fence-diagnostics.d.ts +18 -0
- package/dist/types/core/code-fences.d.ts +8 -1
- package/dist/types/core/config-input.d.ts +38 -6
- package/dist/types/core/content-assets.d.ts +16 -18
- package/dist/types/core/data.d.ts +6 -2
- package/dist/types/core/diagnostics.d.ts +14 -0
- package/dist/types/core/directive-diagnostics.d.ts +22 -8
- package/dist/types/core/former-routes.d.ts +14 -0
- package/dist/types/core/github.d.ts +5 -4
- package/dist/types/core/heading-markers.d.ts +65 -2
- package/dist/types/core/hidden-pages.d.ts +3 -0
- package/dist/types/core/includes.d.ts +23 -0
- package/dist/types/core/last-modified.d.ts +18 -6
- package/dist/types/core/links.d.ts +42 -2
- package/dist/types/core/load-module.d.ts +19 -4
- package/dist/types/core/manifest.d.ts +14 -1
- package/dist/types/core/markdown-mirrors.d.ts +22 -0
- package/dist/types/core/mcp-clients.d.ts +47 -0
- package/dist/types/core/mdx-elements.d.ts +32 -0
- package/dist/types/core/mdx-syntax.d.ts +100 -0
- package/dist/types/core/meta-diagnostics.d.ts +7 -0
- package/dist/types/core/meta.d.ts +32 -5
- package/dist/types/core/nav-diagnostics.d.ts +16 -2
- package/dist/types/core/navigation.d.ts +13 -0
- package/dist/types/core/ordering-prefix.d.ts +6 -0
- package/dist/types/core/pinned-ids.d.ts +23 -0
- package/dist/types/core/project-graph.d.ts +9 -1
- package/dist/types/core/redirect-patterns.d.ts +18 -0
- package/dist/types/core/relative-files.d.ts +31 -0
- package/dist/types/core/schema.d.ts +322 -11
- package/dist/types/core/sources/normalize.d.ts +101 -9
- package/dist/types/core/sources/types.d.ts +16 -0
- package/dist/types/core/static-files.d.ts +10 -0
- package/dist/types/core/static-host.d.ts +42 -0
- package/dist/types/core/svg-images.d.ts +26 -0
- package/dist/types/core/syntax-diagnostics.d.ts +14 -0
- package/dist/types/core/types.d.ts +42 -1
- package/dist/types/deploy/generated-files.d.ts +41 -0
- package/dist/types/deploy/redirects.d.ts +21 -7
- package/dist/types/markdown/code-title.d.ts +9 -5
- package/dist/types/markdown/directives.d.ts +8 -0
- package/dist/types/markdown/fence-language.d.ts +51 -0
- package/dist/types/markdown/fence-meta.d.ts +5 -0
- package/dist/types/markdown/github-alerts.d.ts +35 -0
- package/dist/types/openapi/asyncapi.d.ts +6 -5
- package/dist/types/openapi/checks.d.ts +10 -5
- package/dist/types/openapi/model.d.ts +55 -8
- package/dist/types/openapi/parse.d.ts +4 -1
- package/dist/types/ratelimit/index.d.ts +2 -0
- package/dist/types/ratelimit/memory.d.ts +1 -1
- package/dist/types/ratelimit/schema.d.ts +40 -0
- package/dist/types/ratelimit/unkey.d.ts +48 -0
- package/dist/types/sources/filesystem.d.ts +14 -4
- package/dist/types/sources/mdx-remote.d.ts +6 -3
- package/dist/types/sources/registry.d.ts +3 -3
- package/dist/types/theme/color.d.ts +33 -0
- package/dist/types/theme/palette.d.ts +122 -0
- package/docs/01-quickstart.mdx +1 -1
- package/docs/02-deployment.mdx +24 -8
- package/docs/04-migrating.mdx +16 -4
- package/docs/advanced/changelog.mdx +27 -1
- package/docs/advanced/skills.mdx +1 -1
- package/docs/cli/audit.mdx +1 -1
- package/docs/cli/doctor.mdx +2 -2
- package/docs/cli/evals.mdx +1 -1
- package/docs/cli/index.mdx +4 -2
- package/docs/cli/validate.mdx +10 -7
- package/docs/configuration/analytics.mdx +2 -0
- package/docs/configuration/customization.mdx +3 -1
- package/docs/configuration/index.mdx +7 -6
- package/docs/configuration/rate-limiting.mdx +20 -1
- package/docs/configuration/theming.mdx +5 -1
- package/docs/content/components.mdx +26 -6
- package/docs/content/frontmatter.mdx +1 -1
- package/docs/content/i18n.mdx +1 -1
- package/docs/content/includes.mdx +6 -2
- package/docs/content/index.mdx +11 -1
- package/docs/content/islands.mdx +2 -0
- package/docs/content/meta.mdx +9 -3
- package/docs/content/navigation.mdx +14 -6
- package/docs/content/sources/obsidian.mdx +1 -1
- package/docs/content/sources/remote-mdx.mdx +3 -1
- package/docs/content/syntax.mdx +76 -8
- package/docs/content/variables.mdx +3 -1
- package/docs/discoverability/agent-discovery.mdx +1 -1
- package/docs/discoverability/json-api.mdx +1 -1
- package/docs/discoverability/llms-txt.mdx +1 -1
- package/docs/discoverability/markdown.mdx +2 -2
- package/docs/discoverability/mcp.mdx +40 -8
- package/docs/discoverability/open-graph.mdx +1 -1
- package/docs/discoverability/sitemap-and-robots.mdx +1 -1
- package/docs/references/graphql.mdx +2 -0
- package/docs/references/openapi.mdx +45 -7
- package/package.json +4 -4
- package/skills/blume/SKILL.md +2 -2
- package/skills/blume-migrate/SKILL.md +51 -29
- package/skills/blume-migrate/references/docsify.md +262 -0
- package/skills/blume-migrate/references/docus.md +298 -0
- package/skills/blume-migrate/references/docusaurus.md +5 -5
- package/skills/blume-migrate/references/fern.md +327 -0
- package/skills/blume-migrate/references/fumadocs.md +1 -1
- package/skills/blume-migrate/references/gitbook.md +267 -0
- package/skills/blume-migrate/references/github-wiki.md +259 -0
- package/skills/blume-migrate/references/jekyll.md +253 -0
- package/skills/blume-migrate/references/mdbook.md +256 -0
- package/skills/blume-migrate/references/mintlify.md +5 -5
- package/skills/blume-migrate/references/mkdocs.md +236 -0
- package/skills/blume-migrate/references/monorepo.md +20 -8
- package/skills/blume-migrate/references/nextra.md +5 -5
- package/skills/blume-migrate/references/readme.md +257 -0
- package/skills/blume-migrate/references/redocly.md +198 -0
- package/skills/blume-migrate/references/starlight.md +3 -3
- package/skills/blume-migrate/references/vitepress.md +204 -0
- package/skills/blume-migrate/references/vuepress.md +271 -0
- package/skills/blume-migrate/scripts/docsify-codemod.mjs +2387 -0
- package/skills/blume-migrate/scripts/docus-codemod.mjs +2542 -0
- package/skills/blume-migrate/scripts/fern-codemod.mjs +2633 -0
- package/skills/blume-migrate/scripts/github-wiki-codemod.mjs +2808 -0
- package/skills/blume-migrate/scripts/include-excerpts.mjs +649 -0
- package/skills/blume-migrate/scripts/jekyll-codemod.mjs +3649 -0
- package/skills/blume-migrate/scripts/mintlify-codemod.mjs +17 -13
- package/skills/blume-migrate/scripts/mkdocs-codemod.mjs +2526 -0
- package/skills/blume-migrate/scripts/operation-routes.mjs +508 -0
- package/skills/blume-migrate/scripts/pin-heading-ids.mjs +1049 -0
- package/skills/blume-migrate/scripts/readme-codemod.mjs +4139 -0
- package/skills/blume-migrate/scripts/vitepress-codemod.mjs +1511 -0
- package/src/ai/changelog-components.ts +24 -0
- package/src/ai/changelog-markdown.ts +45 -41
- package/src/ai/component-markdown.ts +22 -9
- package/src/ai/llms.ts +36 -5
- package/src/ai/markdown.ts +2 -2
- package/src/ai/openapi-components.ts +25 -9
- package/src/ai/operation-details.ts +208 -0
- package/src/ai/relative-links.ts +48 -8
- package/src/ai/serializers.ts +7 -6
- package/src/ai/site-skill.ts +6 -2
- package/src/analytics/head.ts +11 -5
- package/src/analytics/script.ts +13 -3
- package/src/astro/generate.ts +47 -11
- package/src/astro/index.ts +1 -0
- package/src/astro/integration.ts +27 -1
- package/src/astro/mdx-source-errors.ts +46 -0
- package/src/astro/templates.ts +93 -189
- package/src/audit/checks/redirects.ts +5 -1
- package/src/audit/redirects.ts +36 -19
- package/src/audit/report.ts +22 -9
- package/src/audit/run.ts +12 -28
- package/src/audit/terms.ts +23 -0
- package/src/audit/url.ts +2 -2
- package/src/cli/build-failure.ts +256 -7
- package/src/cli/command-meta.ts +1 -1
- package/src/cli/commands/audit.ts +1 -1
- package/src/cli/commands/build.ts +12 -3
- package/src/cli/commands/check.ts +13 -2
- package/src/cli/commands/dev.ts +1 -1
- package/src/cli/commands/doctor.ts +4 -2
- package/src/cli/commands/init.ts +3 -3
- package/src/cli/commands/preview.ts +17 -1
- package/src/cli/commands/validate.ts +22 -10
- package/src/cli/prepare.ts +1 -1
- package/src/cli/preview-pages.ts +161 -0
- package/src/cli/required-secrets.ts +0 -1
- package/src/cli/unknown-flags.ts +1 -42
- package/src/components/code-copy.ts +51 -0
- package/src/components/code-language.ts +75 -0
- package/src/components/content/AccordionItem.astro +16 -1
- package/src/components/content/Callout.astro +11 -1
- package/src/components/content/Changelog.astro +189 -0
- package/src/components/content/CodeBlock.astro +8 -11
- package/src/components/content/Tabs.astro +16 -2
- package/src/components/content/YouTube.astro +6 -4
- package/src/components/content/code-block.ts +33 -0
- package/src/components/content/content-strings.ts +5 -1
- package/src/components/content/inline-markdown.ts +35 -8
- package/src/components/content/youtube.ts +49 -7
- package/src/components/layout/Analytics.astro +5 -1
- package/src/components/layout/NavTree.astro +8 -3
- package/src/components/layout/PageActions.astro +81 -23
- package/src/components/layout/RootLayout.astro +35 -32
- package/src/components/layout/SiteFooter.astro +31 -8
- package/src/components/layout/nav-utils.ts +14 -0
- package/src/components/layout/search/pagefind.ts +2 -1
- package/src/components/openapi/Operation.astro +4 -0
- package/src/components/openapi/PanelTabs.astro +9 -3
- package/src/components/openapi/RequestBody.astro +42 -8
- package/src/components/openapi/RequestPanel.astro +34 -53
- package/src/components/openapi/example-panels.ts +110 -0
- package/src/components/openapi/helpers.ts +195 -20
- package/src/components/openapi/operation-model.ts +63 -26
- package/src/components/openapi/request.ts +13 -0
- package/src/components/openapi/snippets.ts +14 -2
- package/src/core/alert-diagnostics.ts +89 -0
- package/src/core/builtin-tags.ts +76 -0
- package/src/core/changelog-list.ts +87 -0
- package/src/core/closest-match.ts +41 -0
- package/src/core/code-fence-diagnostics.ts +267 -0
- package/src/core/code-fences.ts +43 -7
- package/src/core/component-diagnostics.ts +65 -12
- package/src/core/config-input.ts +39 -5
- package/src/core/config.ts +46 -1
- package/src/core/content-assets.ts +64 -144
- package/src/core/data.ts +10 -3
- package/src/core/diagnostics.ts +36 -3
- package/src/core/directive-diagnostics.ts +265 -47
- package/src/core/former-routes.ts +46 -0
- package/src/core/git-ignored.ts +53 -0
- package/src/core/github.ts +5 -4
- package/src/core/heading-markers.ts +156 -2
- package/src/core/hidden-pages.ts +64 -0
- package/src/core/includes.ts +181 -41
- package/src/core/last-modified.ts +47 -10
- package/src/core/links.ts +438 -83
- package/src/core/load-module.ts +98 -9
- package/src/core/manifest.ts +12 -9
- package/src/core/markdown-mirrors.ts +52 -0
- package/src/core/mcp-clients.ts +87 -0
- package/src/core/mdx-elements.ts +153 -0
- package/src/core/mdx-syntax.ts +377 -0
- package/src/core/meta-diagnostics.ts +134 -0
- package/src/core/meta.ts +154 -55
- package/src/core/nav-diagnostics.ts +41 -4
- package/src/core/navigation.ts +70 -10
- package/src/core/ordering-prefix.ts +22 -2
- package/src/core/pinned-ids.ts +141 -0
- package/src/core/project-graph.ts +221 -29
- package/src/core/redirect-patterns.ts +41 -0
- package/src/core/relative-files.ts +145 -0
- package/src/core/schema.ts +110 -6
- package/src/core/sources/mdx-remote.ts +75 -14
- package/src/core/sources/normalize.ts +885 -179
- package/src/core/sources/notion.ts +5 -4
- package/src/core/sources/obsidian.ts +2 -5
- package/src/core/sources/types.ts +17 -0
- package/src/core/static-files.ts +40 -0
- package/src/core/static-host.ts +125 -0
- package/src/core/svg-images.ts +98 -0
- package/src/core/syntax-diagnostics.ts +491 -0
- package/src/core/types.ts +43 -1
- package/src/deploy/artifacts.ts +2 -28
- package/src/deploy/generated-files.ts +128 -0
- package/src/deploy/platforms/vercel.ts +25 -1
- package/src/deploy/redirects.ts +43 -16
- package/src/deploy/sitemap.ts +2 -1
- package/src/markdown/base-links.ts +87 -6
- package/src/markdown/code-title.ts +29 -13
- package/src/markdown/content-assets.ts +210 -0
- package/src/markdown/directives.ts +69 -5
- package/src/markdown/fence-language.ts +106 -0
- package/src/markdown/fence-meta.ts +42 -0
- package/src/markdown/github-alerts.ts +172 -0
- package/src/markdown/heading-anchors.ts +265 -56
- package/src/markdown/include.ts +30 -3
- package/src/markdown/index.ts +145 -40
- package/src/markdown/prompt-text.ts +95 -0
- package/src/markdown/relative-links.ts +37 -2
- package/src/markdown/route-snapshot.ts +22 -12
- package/src/markdown/svg-fallback.ts +51 -0
- package/src/markdown/title-heading.ts +134 -0
- package/src/migrate/migrate.ts +127 -2
- package/src/og/card.ts +14 -4
- package/src/openapi/asyncapi.ts +14 -6
- package/src/openapi/checks.ts +160 -15
- package/src/openapi/model.ts +172 -33
- package/src/openapi/parse.ts +13 -4
- package/src/openapi/render-mdx.ts +55 -9
- package/src/openapi/source.ts +87 -6
- package/src/ratelimit/index.ts +2 -0
- package/src/ratelimit/memory.ts +1 -1
- package/src/ratelimit/runtime.ts +81 -0
- package/src/ratelimit/schema.ts +2 -0
- package/src/ratelimit/unkey.ts +61 -0
- package/src/registry/eject.ts +0 -1
- package/src/registry/registry.ts +1 -1
- package/src/search/documents.ts +10 -2
- package/src/sources/filesystem.ts +28 -3
- package/src/sources/mdx-remote.ts +7 -15
- package/src/theme/color.ts +14 -0
- package/src/theme/entry.ts +22 -1
- package/src/theme/palette.ts +74 -1
- package/dist/cli/chunk-0pmb4tr4.js.map +0 -35
- package/dist/cli/chunk-0w6hs479.js.map +0 -10
- package/dist/cli/chunk-150jk7km.js +0 -52
- package/dist/cli/chunk-150jk7km.js.map +0 -10
- package/dist/cli/chunk-36bxs9c7.js.map +0 -10
- package/dist/cli/chunk-53jqw8z0.js +0 -89
- package/dist/cli/chunk-53jqw8z0.js.map +0 -10
- package/dist/cli/chunk-60hz265r.js.map +0 -10
- package/dist/cli/chunk-desvm72z.js.map +0 -14
- package/dist/cli/chunk-dpy8qdjf.js.map +0 -17
- package/dist/cli/chunk-es8h0v3j.js +0 -441
- package/dist/cli/chunk-es8h0v3j.js.map +0 -11
- package/dist/cli/chunk-kdpzw38a.js.map +0 -11
- package/dist/cli/chunk-nbyvgnnm.js.map +0 -36
- package/dist/cli/chunk-s0bdnc7v.js.map +0 -10
- package/dist/cli/chunk-twy7psdz.js.map +0 -10
- package/dist/cli/chunk-ydp3065p.js +0 -64
- package/dist/cli/chunk-ydp3065p.js.map +0 -10
- /package/dist/cli/{chunk-y4msrwm9.js.map → chunk-080mfch6.js.map} +0 -0
- /package/dist/cli/{chunk-9qzgg6mj.js.map → chunk-34wap3ed.js.map} +0 -0
- /package/dist/cli/{chunk-1f882900.js.map → chunk-c5bjxq8v.js.map} +0 -0
- /package/dist/cli/{chunk-bxwhtvw8.js.map → chunk-f260jdrn.js.map} +0 -0
- /package/dist/cli/{chunk-74wfhv79.js.map → chunk-fnxgtjeq.js.map} +0 -0
- /package/dist/cli/{chunk-dhwtqnnd.js.map → chunk-gxhcf2hs.js.map} +0 -0
- /package/dist/cli/{chunk-tfycddbt.js.map → chunk-h0qwdbem.js.map} +0 -0
- /package/dist/cli/{chunk-j1x92mx9.js.map → chunk-j4nfgn2j.js.map} +0 -0
- /package/dist/cli/{chunk-ave1wcbr.js.map → chunk-qcyxkj44.js.map} +0 -0
- /package/dist/cli/{chunk-58bt3hag.js.map → chunk-x7bh6d9j.js.map} +0 -0
- /package/dist/cli/{chunk-hvcxng5f.js.map → chunk-ydqzkhjn.js.map} +0 -0
|
@@ -69,7 +69,7 @@ A minimal result is often just `defineConfig({ title, logo, theme: { accent } })
|
|
|
69
69
|
|
|
70
70
|
Mintlify defaults to **FontAwesome**; Blume is **Lucide-only**. Convert every icon reference — frontmatter `icon`, nav-group `icon`, `<Icon>`, `<Card icon>` — to the closest Lucide name. Discard Mintlify's `iconType` (solid/regular/brands) entirely.
|
|
71
71
|
|
|
72
|
-
**Automate the frontmatter pass — don't hand-edit it.** `scripts/mintlify-codemod.mjs` (in this skill, zero-dependency) remaps every **frontmatter** `icon:` using the table below, drops
|
|
72
|
+
**Automate the frontmatter pass — don't hand-edit it.** `scripts/mintlify-codemod.mjs` (in this skill, zero-dependency) remaps every **frontmatter** `icon:` using the table below, drops icons with no Lucide equivalent, and — in the same pass — drops/renames unsupported frontmatter keys (see [Frontmatter](#frontmatter)). It's deterministic and idempotent, and reports what it changed per file plus what it couldn't (unknown icons, OpenAPI-stub flags):
|
|
73
73
|
|
|
74
74
|
```bash
|
|
75
75
|
# <skill> = this skill's directory (the one containing SKILL.md); dry run first (report only), then apply:
|
|
@@ -99,7 +99,7 @@ The codemod touches **only frontmatter**. Icons in MDX **body** (`<Icon icon="
|
|
|
99
99
|
| `life-ring` | `life-buoy` | | `shield-halved` | `shield` |
|
|
100
100
|
| `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)_ |
|
|
101
101
|
|
|
102
|
-
**Rules:** verify each Lucide name exists at [lucide.dev/icons](https://lucide.dev/icons) before writing it. **Brand icons** (`fa6-brands:*` — github
|
|
102
|
+
**Rules:** verify each Lucide name exists at [lucide.dev/icons](https://lucide.dev/icons) before writing it. **Brand icons** (`fa6-brands:*`): Lucide still ships a few brand marks, and Blume renders them under the same name — `facebook`, `github`, `gitlab`, `instagram`, `linkedin`, `slack`, `twitter`, `youtube`. Keep those. The rest (`discord`, `x-twitter`, `docker`, `npm`, `python`, `react`…) have **no** Lucide equivalent, and FontAwesome's `apple` is the Apple logo while Lucide's `apple` is the fruit. Where no Lucide counterpart exists, **drop the icon and report it**. An icon that only marks a link to the repository or a social profile usually has a better home: the `github` config (renders the footer's repo link) or `footer.socials`. 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.
|
|
103
103
|
|
|
104
104
|
## Navigation: `docs.json` `navigation` → filesystem + tabs
|
|
105
105
|
|
|
@@ -128,11 +128,11 @@ This reshaping **changes URLs** — a page moved from `getting-started/quickstar
|
|
|
128
128
|
|
|
129
129
|
Rewrite each page's MDX:
|
|
130
130
|
|
|
131
|
-
- **Callouts → directives** (directives are **MDX-only** — Mintlify content is already `.mdx`, so this just works; never rename a page to `.md`): `<Note>`→`:::note`, `<Tip>`→`:::tip`, `<Warning>`→`:::warning`, `<Info>`→`:::info`, `<Check>`→`:::success`, `<Danger>`/`<Error>`→`:::danger`. `<Callout type="x">` maps by type (`caution`→warning, `check`→success). A `title` attr → `:::type[Title]`.
|
|
131
|
+
- **Callouts → directives** (directives are **MDX-only** — Mintlify content is already `.mdx`, so this just works; never rename a page to `.md`): `<Note>`→`:::note`, `<Tip>`→`:::tip`, `<Warning>`→`:::warning`, `<Info>`→`:::info`, `<Check>`→`:::success`, `<Danger>`/`<Error>`→`:::danger`. `<Callout type="x">` maps by type (`caution`→warning, `check`→success). A `title` attr → `:::type[Title]`. A callout with an `icon` or `color` (Mintlify's generic `<Callout icon="key" color="#FFC107">`) stays a `<Callout>` instead, since a directive can't set them: Blume's takes `type`, `title`, `icon` (remap it with the table below), and `color` (any CSS color); drop `iconType`.
|
|
132
132
|
- **Accordions — container/item inversion!** Mintlify nests `<Accordion title="…">` inside `<AccordionGroup>`. Blume inverts: `<AccordionGroup>`→`<Accordion>` (container), and each Mintlify `<Accordion title="…">`→`<AccordionItem title="…">` (item).
|
|
133
133
|
- **`<Tabs>` → `<Tabs inline>`.** Mintlify renders tabs **borderless** — a strip on a full-width rule with the content flowing beneath as prose — while Blume's `<Tabs>` defaults to a bordered box. Add `inline` to each `<Tabs>` to preserve Mintlify's appearance; every child `<Tab title="…">` is unchanged. Don't add `param` — Mintlify tabs switch in place and don't deep-link to the URL, so plain `inline` is the faithful mapping.
|
|
134
134
|
- **These pass through — Blume ships them natively:** `<Columns>`/`<Column>`, `<Expandable>`, `<Tooltip>`, `<Frame>`, `<Panel>`, `<Card>`/`<CardGroup>`, `<Tab>`, `<Steps>`/`<Step>`, `<View>` (its `title` becomes an option in the page's view picker, as on Mintlify; remap its `icon` with the table below and drop `iconType`). Keep them as-is.
|
|
135
|
-
- **
|
|
135
|
+
- **Code-block titles carry over.** Both read every bare word after the language as the title (` ```ts Acme SDK `), and `wrap` and `expandable` mean the same in both. Mintlify's other fence options don't: `lines` → `lineNumbers` (left as is, it does nothing and warns `BLUME_CODE_FENCE_OPTION`), `highlight={1-2,5}` → `{1-2,5}`, `focus={2}` → a `// [!code focus]` comment on each line, and drop `icon="…"`.
|
|
136
136
|
- **`<RequestExample>`/`<ResponseExample>` pass through.** Top-level ones pin to a column beside the page on wide screens, request above response, as on Mintlify; `dropdown` works the same.
|
|
137
137
|
- **Hand-written endpoint pages pass through.** `api: "POST /v1/users"` frontmatter, with `authMethod` (`bearer`/`basic`/`key`/`none`) and `playground` (`interactive`/`simple`/`none`), works as on Mintlify: the page's `<ParamField>`s build its Try it panel and request samples. Keep them as written.
|
|
138
138
|
- **API fields pass through.** `<ParamField>` (`path`/`query`/`header`/`body`, `type`, `required`, `deprecated`, `default`, `placeholder`) and `<ResponseField>` (`name`, `type`, `required`, `deprecated`, `default`, `pre`, `post`) render natively, nested `<Expandable>` fields included. Keep them as written. An older `<RequestField>` isn't supported: rewrite it as a `<ParamField>`.
|
|
@@ -168,7 +168,7 @@ The codemod leaves the source key in place and reports a conflict rather than cl
|
|
|
168
168
|
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"`, `openapi: "spec.json webhook name"`, or a `"GET /path"` nav entry) — Blume's native renderer generates one real page per operation and per webhook, and shows callbacks on their operation's page. **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.
|
|
169
169
|
|
|
170
170
|
- **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.
|
|
171
|
-
- **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.
|
|
171
|
+
- **Fix endpoint links.** Blume operation routes are `<route>/<slugified-tag>/<slugified-operationId>` (tag `Models` + id `listModels` → `/api-reference/models/list-models`: a camelCase tag or 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.
|
|
172
172
|
- **Overlays carry over.** An `openapi: { source, overlays: [...] }` object → that source's `overlays` (`openapi({ spec, overlays })`, or `overlays` on each entry in `sources`), in the same order; Blume applies Overlay 1.0 and 1.1 the same way. An overlay Mintlify found only through its `extends` field (auto-discovered, not listed in `docs.json`) must be listed explicitly: Blume doesn't scan for overlays.
|
|
173
173
|
- **Code samples carry over.** `api.examples.languages` → `openapi({ codeSamples: [...] })`; Blume generates the same 18 languages and accepts Mintlify's keys and aliases (`bash`, `javascript`, `node`, `csharp`, `dotnet`, `c++`, …) as written. `api.examples.autogenerate: false` → `codeSamples: false`. `x-codeSamples` in the spec needs nothing: Blume renders them ahead of the generated samples.
|
|
174
174
|
- **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.
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
# MkDocs (Material for MkDocs, Zensical) → Blume
|
|
2
|
+
|
|
3
|
+
MkDocs is a Python generator: one YAML config (`mkdocs.yml`), Markdown in `docs/`, and Python-Markdown extensions for everything beyond CommonMark. Nearly every MkDocs site uses the **Material for MkDocs** theme, so pages are full of extension syntax (`!!!` admonitions, `===` tabs, `--8<--` snippets, `{ #id }` attribute lists), and navigation is an explicit `nav` list in config (or alphabetical). The work is translating `mkdocs.yml`, rebuilding `nav` as folders and `meta.ts`, and converting the syntax — most of which becomes `.mdx`-only Blume features, and **MDX rejects several things Python-Markdown accepts**.
|
|
4
|
+
|
|
5
|
+
Scope: checked against MkDocs 1.6.1, Material for MkDocs 9.7.6–9.7.7, pymdown-extensions 11.0.1–12.1, mkdocs-redirects 1.2.3, awesome-pages 2.10.1, awesome-nav 3.3.0, literate-nav 0.6.3, mkdocs-static-i18n 1.3.1, mkdocs-macros 1.5.0, mike 2.2.0, an end-to-end migration of astral-sh/uv (84 pages), and the codemod on pdm-project/pdm (23 pages). **Zensical** and **ProperDocs** projects are the same migration. MkDocs 2.0 (a pre-release with a TOML config and no plugins) was not checked.
|
|
6
|
+
|
|
7
|
+
## Run the codemod first
|
|
8
|
+
|
|
9
|
+
From the folder that holds `mkdocs.yml` (keep the old Python setup until the end, so `mkdocs build` can still produce the old site for comparison):
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
node <skill>/scripts/mkdocs-codemod.mjs docs # dry run: report only
|
|
13
|
+
node <skill>/scripts/mkdocs-codemod.mjs --write docs # apply
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
It reads `mkdocs.yml` (or `zensical.toml`/`properdocs.yml`, `INHERIT` included) for the enabled extensions, the snippets `base_path`, `extend_pygments_lang`, and `nav` titles, then per page: converts admonitions, details, and tabs (indentation-aware, nested); turns snippets into `<include>` (copying ones from outside the content root into `_snippets/`); rewrites fences, `#!lang` inline code, heading ids, attribute lists, keys, `==mark==`/`^^ins^^`, icon shortcodes, `\(x\)` math, and abbreviation lines; moves the body H1 (ATX or setext) into `title` (inline Markdown stripped — Blume renders backticks in `title` literally), a differing `nav` title into `sidebar.label`, and a differing frontmatter `title` into `seo.title`; maps `hide`/`status`/`tags`/`icon`; renames to `.mdx` **only** the pages that now need MDX and fixes their comments, autolinks, and void tags; renames `README.md` to `index.md`; and rewrites links and `<include>`s to every renamed file. It is idempotent.
|
|
17
|
+
|
|
18
|
+
It **reports**, without changing, what needs judgment: mkdocstrings blocks, macros/Jinja, template overrides, hooks, every plugin (with a hint), mike and `extra.alternate`, snippet line ranges, `///` blocks, grid cards, code annotations, unknown icons, raw `<img>`s with a relative `src`, pages left with no title, snippet files that publish as pages too, `nav` entries with no file, and every MDX hazard left in a renamed page. Work through that report with the sections below. Nav, config, redirects, and repo integration stay yours.
|
|
19
|
+
|
|
20
|
+
After the first `blume build`, pin the old heading ids (MkDocs and Blume slug headings differ — see URLs). Point `--old` at the old site's built HTML (`mkdocs build -d <dir>` before you delete `mkdocs.yml`) or its live URL, and run it from the Blume project:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
node <skill>/scripts/pin-heading-ids.mjs --old <old-build-dir-or-url> # dry run
|
|
24
|
+
node <skill>/scripts/pin-heading-ids.mjs --old <old-build-dir-or-url> --write
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Rebuild and rerun until it reports 0 (add `--map dist/blume-redirects.json` when pages moved).
|
|
28
|
+
|
|
29
|
+
## Detect
|
|
30
|
+
|
|
31
|
+
- **`mkdocs.yml` / `mkdocs.yaml`** — Material when `theme.name: material`; the plain `mkdocs`/`readthedocs` themes migrate the same way with fewer extensions. Sometimes in a subfolder (`docs/mkdocs.yml`), which `blume migrate` doesn't detect from the repo root: name the source, and run the codemod from that folder.
|
|
32
|
+
- **`zensical.toml`** — Zensical's format: MkDocs' keys in TOML, usually under `[project]` (`[project.theme]`, `nav = [ { "Title" = "page.md" } ]`); extensions as `[project.markdown_extensions]` keys (`admonition = {}`, `pymdownx.tabbed.alternate_style = true`) or `[project.markdown_extensions.<name>]` tables. With **no extensions configured**, Zensical enables a default set (admonition, details, tabbed, attr_list, md_in_html, keys, mark, caret, arithmatex, emoji, and more, but not snippets); the codemod applies it to a `zensical.toml`. Zensical also builds a plain `mkdocs.yml` and applies the same defaults when it sets no `markdown_extensions`: the codemod can't tell, so list the extensions the pages use in a copy of the config and pass it with `--config`.
|
|
33
|
+
- **`properdocs.yml` / `.yaml`** — ProperDocs, a continuation of MkDocs 1.x.
|
|
34
|
+
- Python deps, not `package.json`: `mkdocs`, `mkdocs-material`, `zensical`, `properdocs` in `requirements*.txt` or a `pyproject.toml` docs group; `mkdocs build`/`gh-deploy` in CI; `.readthedocs.yaml` with an `mkdocs:` key.
|
|
35
|
+
|
|
36
|
+
Resolve the config first: `INHERIT: base.yml` deep-merges this file over another (a repo may have several configs on one base — migrate the public one, report the rest). `!ENV [VAR, default]` reads an environment variable: use the default and report it. `!relative` and `!!python/name:` tags break JS YAML parsers — read the file as text.
|
|
37
|
+
|
|
38
|
+
**Where the Blume project goes.** `blume build` empties `<project>/dist`, and a Python or Rust repo root often uses `dist/` for wheels or builds. When `mkdocs.yml` sits at the root of a code repo, put `blume.config.ts` and `package.json` **in the docs folder** with `content.root: "."` and `content.include` scoped to the page folders (`["index.mdx", "{guides,concepts,reference}/**/*.{md,mdx}"]`), and say so. That also keeps a `package.json` out of a non-JS repo root.
|
|
39
|
+
|
|
40
|
+
**Generated pages.** A `nav` entry or link whose file isn't in the repo is generated at build time (`gen-files`, a hook, a CI step, a `.gitignore`d output — the codemod lists them). Convert today's output once so the site builds, then report that the **generator must change**: until it writes Blume syntax, CI regenerates the old one and Blume renders it as text with a green build. If conversion renames the output (`settings.md` → `settings.mdx`), update `.gitignore`, `.prettierignore`, and the generator's own check mode too.
|
|
41
|
+
|
|
42
|
+
## Config: `mkdocs.yml` → `blume.config.ts`
|
|
43
|
+
|
|
44
|
+
Map only what's set:
|
|
45
|
+
|
|
46
|
+
| MkDocs | Blume |
|
|
47
|
+
| --- | --- |
|
|
48
|
+
| `site_name` / `site_description` | `title` / `description` |
|
|
49
|
+
| `site_url` | Its origin → `deployment.site` (unless the target is Vercel or Netlify — see SKILL.md); **a path in it** (`https://docs.acme.com/uv/`) → `deployment.base: "/uv"`, on every host. mike adds its version segment after `site_url`, so it isn't part of the base (Versioning) |
|
|
50
|
+
| `docs_dir` | `content.root` (`docs` is the default) |
|
|
51
|
+
| `use_directory_urls` | no setting — see URLs |
|
|
52
|
+
| `repo_url` on GitHub | `github: { owner, repo }` |
|
|
53
|
+
| `edit_uri` / `edit_uri_template` | **`github.branch`** from the segment after `edit/` or `blob/`. Unset with a GitHub `repo_url` means `edit/master/docs/` → `branch: "master"` (Blume defaults to `main`). The path after the branch is `docs_dir`, which Blume adds — **not** `github.dir` (that's only for a project in a repo subfolder). `edit_uri: ""`, or Material without the `content.action.edit` feature, shows no edit button; Blume has no separate switch, so accept edit links or leave `github` unset and set `navigation.repo: "<repo_url>"` (a footer mark) — say which. Leave `github` unset if edit links would point at gitignored generated files |
|
|
54
|
+
| `repo_url` elsewhere (GitLab…) | no edit links; a header link → `navigation.actions` (report) |
|
|
55
|
+
| `repo_name`, `site_author`, `site_dir`, `dev_addr`, `remote_*`, `watch`, `strict`, `validation` | drop |
|
|
56
|
+
| `copyright` | `footer.copyright`, plain text: strip any HTML tags, decode entities (`©` → `©`); a link inside it loses its URL (report, or add it to `footer.links`) |
|
|
57
|
+
| `exclude_docs` | `content.exclude` — the list adds to the default `"**/_*"` and `"**/.*"`; `"!**/_*"` publishes `_` files |
|
|
58
|
+
| `draft_docs` / `not_in_nav` | `draft: true` / `sidebar.hidden: true` on those pages |
|
|
59
|
+
| `extra_css` | a project-root **`theme.css`**: Material's `--md-*` variables and `.md-*` classes don't exist — port only rules that still mean something, and read colors out of it (Theme) |
|
|
60
|
+
| `extra_javascript` | delete MathJax/KaTeX/Mermaid loaders. Anything else → move into `public/` and `script({ src })` in `analytics` (from `blume/analytics`); a root-relative `src` (`"/js/x.js"`) loads under `deployment.base`. Code written against Material's `document$` or `.md-*` DOM won't run — report it |
|
|
61
|
+
| `extra.social` | `footer.socials` (bluesky, discord, facebook, github, hacker-news, instagram, linkedin, medium, podcast, reddit, slack, telegram, threads, website, x, youtube; `twitter`/`x-twitter` → `x`); the site's own repo is covered by `github`; other platforms drop (report) |
|
|
62
|
+
| `extra.analytics` (`provider: google`) | `googleAnalytics({ id: property })`. A `custom_dir` partial `partials/integrations/analytics/<name>.html` is a custom provider: use its adapter (`fathom({ site })` from `data-site`, …) or `script()`. `feedback` → Blume's page feedback is on by default |
|
|
63
|
+
| `extra.consent` | `consent: native()` (from `blume/consent`) |
|
|
64
|
+
| `extra.version` (`provider: mike`) | Versioning |
|
|
65
|
+
| other `extra` keys used as `{{ }}` | `variables` (Manual decisions: macros) |
|
|
66
|
+
| `markdown_extensions` | nothing to configure. `toc.toc_depth: N` → `toc: { maxHeadingLevel: N }` (a `"2-5"` range: its upper bound) |
|
|
67
|
+
| `plugins`, `hooks`, `theme.custom_dir` | Plugins; Manual decisions |
|
|
68
|
+
|
|
69
|
+
### Theme
|
|
70
|
+
|
|
71
|
+
| Material | Blume |
|
|
72
|
+
| --- | --- |
|
|
73
|
+
| `theme.palette` | one palette with `scheme: slate` → `theme.mode: "dark"`; with `default` → `"light"`; a list with toggles → system (the default) |
|
|
74
|
+
| `palette.primary` (link color) | `theme.accent`. Presets `red`, `pink`, `purple`, `blue`, `green`, `orange`, `teal` map by name. Other names aren't usable CSS (`deep purple` warns `BLUME_THEME_COLOR_INVALID`, CSS `indigo` isn't Material's): use Material 9.7's link color (`--md-typeset-a-color`) as `{ light, dark }` — indigo `#4051b5`/`#5488e8`, deep purple `#7e56c2`/`#a47bea`, light blue `#02a6f2`, cyan `#00bdd6`, deep orange `#ff6e42`/`#ff764d`, brown `#795649`/`#c1775c`, amber `#d19d00`/`#ffc105`, lime `#8b990a`/`#cbdc38`, light green `#72ad2e`/`#8bc34b`, yellow `#b8a500`/`#ffec3d`; grey, blue grey, black, and white all link in `#4051b5`/`#5e8bde`. `custom` or a custom `scheme:` is defined in `extra_css`: take `--md-typeset-a-color` per scheme (and `--md-default-bg-color` → `theme.background` when it isn't plain white/black) |
|
|
75
|
+
| `palette.accent` | drop |
|
|
76
|
+
| `theme.font.text` / `.code` | `theme.fonts.body` (and `display`) / `mono` as `{ name: "…" }`; `font: false` → drop |
|
|
77
|
+
| `theme.logo` (a file in `docs_dir`) | move into `public/`, `logo: "/logo.svg"` (SKILL.md on `currentColor` and wordmarks). `theme.icon.logo` → drop and report |
|
|
78
|
+
| `theme.favicon` | move to `public/favicon.<ext>` — no config field |
|
|
79
|
+
| `theme.icon.*`, `theme.language` (English) | drop. A non-English single-language site: the schema accepts a one-locale `i18n` block — check the UI language in `blume dev` |
|
|
80
|
+
|
|
81
|
+
`theme.features`:
|
|
82
|
+
|
|
83
|
+
| Feature | Blume |
|
|
84
|
+
| --- | --- |
|
|
85
|
+
| `navigation.tabs` | **`navigation.tabs`**, one per top-level `nav` section, each in one folder (SKILL.md "Tabs") |
|
|
86
|
+
| `navigation.sections` | top-level sections stay Blume's default `flat` headers; set **`display: "group"` in the `meta.ts` of every second-level section**: Material renders those as collapsible, and a `flat` group lists its pages above its subgroups, reordering a section that interleaves them |
|
|
87
|
+
| neither `sections` nor `tabs` | `navigation.sidebar.display: "group"` (Material's collapsible tree) |
|
|
88
|
+
| `navigation.expand` | `collapsed: false` in those folders' `meta.ts` |
|
|
89
|
+
| `navigation.indexes`, plugin `section-index` | a folder's `index` page links its group header. Blume also lists it as the group's first row, so the label shows twice. To show it once, as Material does, set `sidebar.hidden: true` on the index: that drops only the duplicate row, and the page stays in `sitemap.xml`, search, and `llms.txt`. A hidden index whose `title` differs from its folder's `meta.ts` `title` warns `BLUME_NAV_INDEX_TITLE_MISMATCH`, which fails `validate --strict`: match the two titles, set the index's `sidebar.label` to the folder title to keep its heading, or leave that index's row showing |
|
|
90
|
+
| `content.tabs.link` | same-titled tabs sync within a page, not across pages |
|
|
91
|
+
| `content.action.edit` / `.view` | `github` |
|
|
92
|
+
| `announce.dismiss` | `banner.dismissible`; the text is `main.html`'s `{% block announce %}` → `banner.content` |
|
|
93
|
+
| `content.code.annotate` | no equivalent (the codemod reports annotation markers) |
|
|
94
|
+
| `content.code.copy`/`.select`, `navigation.footer`/`.path`/`.top`/`.instant*`/`.tracking`/`.prune`, `toc.*`, `search.*`, `header.autohide`, `content.tooltips` | drop — built in or no equivalent. Blume's copy button copies only the commands of a `console` or `shellsession` block, without prompts or output, so a custom script that stripped them (`extra_javascript`) can go once those blocks use one of the two |
|
|
95
|
+
|
|
96
|
+
## Navigation
|
|
97
|
+
|
|
98
|
+
Blume builds the sidebar from folders (SKILL.md "Navigation is the file tree"). Translate `nav` into folders and `meta.ts` (the codemod already set each page's `title`/`sidebar.label`):
|
|
99
|
+
|
|
100
|
+
- **`- Section: [ … ]`** → a folder; a label that differs from the humanized folder name ("Getting started" vs "Getting Started") → `meta.ts` `title`. List order → `meta.ts` `pages`, every child. Root order → the content root's `meta.ts`.
|
|
101
|
+
- **A section holding an `index.md`** (with `navigation.indexes`) has that page as its own → nothing to do (see `navigation.indexes` above). Without the feature, Material lists the index as an ordinary row, which is what Blume does anyway.
|
|
102
|
+
- **Nesting that doesn't match folders** is SKILL.md's "Config-declared nesting". Decide per section and report:
|
|
103
|
+
- **One flat folder split into subsections** (`Advanced:` listing `guides/webhooks.md`): a **`(group)/` folder** first, as SKILL.md says — `guides/(advanced)/webhooks.md` keeps `/guides/webhooks` and adds the sidebar group, with no redirects.
|
|
104
|
+
- **A folder shown under another section** (uv's `pip/` under "Concepts"), where a group folder would change the URL segment: **move the files and pin `slug: <old route>` on each moved page**. The sidebar follows the file and the URL follows the slug, with no redirects and no explicit sidebar. Use it when the source kept URLs on purpose.
|
|
105
|
+
- Otherwise, move the files and add `redirects` (the URLs change), or declare the shape in an explicit `navigation.sidebar` (it replaces the whole generated tree).
|
|
106
|
+
- Either move puts a page a folder deeper: re-base its relative links and assets, and rewrite every link to it to name the file as it now is (a link to `page.md` resolves to a slugged page only when it names that exact file).
|
|
107
|
+
- **`- Title: https://…`** → `navigation.featured` (top level) or `navigation.actions`; a `nav` entry to a non-page file (`llms.txt`, a PDF) → a featured link.
|
|
108
|
+
- **Pages left out of `nav`** → `sidebar.hidden: true` (note: this also drops them from `sitemap.xml`).
|
|
109
|
+
- **No `nav`**: MkDocs lists each folder's pages (`index` first, then by filename) before its subfolders, labeled "Getting started"-style; Blume sorts by title. Add `meta.ts` `pages`/`title` where that differs.
|
|
110
|
+
- **`awesome-pages` `.pages` / `awesome-nav` `.nav.yml`** → a `meta.ts` per folder: `title` → `title`; `nav` → `pages` (drop awesome-pages' `...` and awesome-nav's glob entries like `"*"`; an awesome-pages `nav` without `...` hides everything unlisted → `sidebar.hidden: true`; `- Title: page.md` → `sidebar.label`); `hide: true` → hide its pages; sorting, `append_unmatched`, and `collapse*` options drop (report). Delete the files.
|
|
111
|
+
- **`literate-nav`** (`SUMMARY.md`): its nested link list is the nav — convert it like `nav` and delete it (it would publish as a page).
|
|
112
|
+
|
|
113
|
+
## URLs and redirects
|
|
114
|
+
|
|
115
|
+
Save the old URL list first — every `<loc>` in the old `site/sitemap.xml` (or the live one) plus every `redirect_maps` key — and check it at the end.
|
|
116
|
+
|
|
117
|
+
| Source file | MkDocs URL (`use_directory_urls: true`) | (`false`) | Blume route |
|
|
118
|
+
| --- | --- | --- | --- |
|
|
119
|
+
| `docs/a/b.md` | `/a/b/` | `/a/b.html` | `/a/b` |
|
|
120
|
+
| `docs/a/index.md` | `/a/` | `/a/index.html` | `/a` |
|
|
121
|
+
| `docs/a/README.md` | `/a/` | `/a/index.html` | `/a/README` until renamed `index.md` (the codemod does) |
|
|
122
|
+
| `docs/01-setup.md` | `/01-setup/` | `/01-setup.html` | **`/setup`** — Blume strips numeric prefixes; redirect, or pin `slug: 01-setup` |
|
|
123
|
+
|
|
124
|
+
- **Trailing slashes**: a static build writes `<route>/index.html`, so slashed URLs keep working on static hosts; `vercel()` 308s them; Cloudflare Workers needs `html_handling: "drop-trailing-slash"`. `blume dev` and `blume preview` redirect a slashed URL to the slashless page, so old URLs can be checked with or without the slash. **Write targets in any client-side script** (anchor-redirect maps) slashless: Blume's URLs have none.
|
|
125
|
+
- **`use_directory_urls: false`**: one exact redirect per non-index page (`{ from: "/a/b.html", to: "/a/b" }`; a pattern can't strip a suffix). Hosts that read `_redirects`/`vercel.json` answer them; GitHub Pages, which reads neither, is unverified.
|
|
126
|
+
- **`redirects` plugin**: each `redirect_maps` key and value is a Markdown path relative to `docs_dir` → `{ from: <route of key>, to: <route of value> }`, `#anchor` kept; an `http(s)` value stays a URL.
|
|
127
|
+
- **Anchor-level redirects** (a script mapping `/old/#section`): servers never see fragments. Keep the script (`script({ src })`, targets slashless) or drop it; report either way.
|
|
128
|
+
- **Heading ids**: MkDocs' default slugify strips accents, collapses punctuation runs (`A & B` → `a-b`), and numbers duplicates `_1`; Blume keeps accents, writes `a--b`, and numbers `-1`. Run `pin-heading-ids.mjs` (above) — don't compare by hand.
|
|
129
|
+
- **Links**: the codemod rewrites links to renamed files. After you move or rename anything yourself, point links at the real filenames again — a `page.md` link to a file now named `page.mdx` still lands on its page (Blume tries the other extension, `slug` included), but breaks wherever the Markdown is read as files, such as on GitHub. Links inside an included partial resolve from the **including** page, as with MkDocs snippets. A link to a file moved into `public/` becomes root-relative. A link MkDocs couldn't map to a file (`../install/`, written against MkDocs' slashed URLs) lands one level higher in Blume on any page that isn't an `index`, because Blume reads relative links from the page's folder: point it at the `.md` file. `blume validate --strict` catches the rest. The codemod percent-encodes angle-bracket destinations (`[x](<https://…(…)>)` → `…%28…%29`), which only tidies: Blume reads both forms, and rebases a partial's `<…>` image path onto the including page.
|
|
130
|
+
- **llms.txt plugins**: Blume writes `/llms.txt` and `/llms-full.txt`. The plugin's `/<route>/index.md` copies become `/<route>.md`: add one exact redirect each (a pattern can't map them; `blume audit --only redirects` accepts `.md` targets), and reword any URL advice carried into `agents.llmsTxt.details`.
|
|
131
|
+
|
|
132
|
+
## Which pages become `.mdx`
|
|
133
|
+
|
|
134
|
+
Directives, components, math, and Mermaid work only in `.mdx`, and so does an `<include>` indented inside a list item (a `.md` page reads it as indented code and ships the bare tag); the codemod renames exactly the pages that use them (or include a partial that does) and keeps the rest `.md`. MDX **fails the build** on Python-Markdown-valid source, and the codemod reports what's left in renamed pages: `<!-- -->` comments (→ `{/* … */}` on **one line**), `<https://…>` autolinks, unclosed `<br>`/`<img>`, `<placeholder>` text in prose (`uv run <command>` → backticks), and any `{…}` in prose — attribute lists, critic markup, Jinja, `{name}`. Most fail to compile, and `blume check` (and `validate`, `dev`, `build`) names each at its line as `BLUME_MDX_SYNTAX`; it also names an attribute list (`BLUME_MDX_ATTRIBUTE_LIST`: move the attributes onto a JSX element, or drop them) and an unclosed void tag (`BLUME_MDX_UNCLOSED_ELEMENT`: close it, `<br />`). `{ width="300" }`, `{target="_blank"}`, and `{name}` compile and then fail the render, which `blume build` reports as `BLUME_MDX_UNDEFINED_NAME` at the expression's line. In a `.md` page none of these fail and no extension syntax renders: it ships as text (`--8<--` becomes "–8<–", `*[HTML]: …` shows verbatim), and an attribute list warns `BLUME_MD_ATTRIBUTE_LIST`. Smart punctuation turns prose `--flag` outside backticks into an en dash.
|
|
135
|
+
|
|
136
|
+
## Content
|
|
137
|
+
|
|
138
|
+
What the codemod converts, for checking its output, and what it leaves for you:
|
|
139
|
+
|
|
140
|
+
| MkDocs | Blume |
|
|
141
|
+
| --- | --- |
|
|
142
|
+
| `!!! type "Title"` (body indented 4) | `:::type[Title]` … `:::` (longer `::::` outside nested ones). Material styles 12 types; others render like `note`. Mapped: `abstract`/`question` → `info`, `failure`/`bug` → `danger`, `example`/`important`/`todo` → `note`, `caution`/`attention` → `warning`, `hint` → `tip`, `quote` → a blockquote. Untitled callouts lose Material's "Note" title bar; a bracket title keeps its inline Markdown (an unbalanced `]` flattens it) |
|
|
143
|
+
| `??? type "Title"` / `???+` | `<Expandable title="Title">` / `defaultOpen`; the type's color drops, and the title keeps its inline Markdown (the codemod strips raw HTML, which would show as text) |
|
|
144
|
+
| `=== "Tab"` | every tab one code block → `<CodeGroup>` with the label as `title="…"`; otherwise `<Tabs>`/`<Tab title>` (`===+` → `defaultTabIndex`, `===!` → a new group) |
|
|
145
|
+
| `hl_lines="2 4-5"`, `linenums="1"`, `{ .py title="x" }`, options without a language | `{2,4-5}`, `lineNumbers` (a start other than 1 drops), `py title="x"`, `text {…}`. One left over warns `BLUME_CODE_FENCE_OPTION` (with the Blume spelling) or `BLUME_UNKNOWN_CODE_LANGUAGE` |
|
|
146
|
+
| `pycon`, `pwsh-session`, `extend_pygments_lang` names | `python`, `powershell`, the mapped lexer (any other name Shiki lacks warns `BLUME_UNKNOWN_CODE_LANGUAGE`: map it or write `text`) |
|
|
147
|
+
| `` `#!python x()` `` | `` `x(){:python}` `` |
|
|
148
|
+
| `{ #id }`, `{: #id }`, `{#id}` on headings, also beside classes (`{ #id .wide }`) | `[#id]`, classes dropped (a self-link like `### [x](#x) {: #x }` drops). One left over warns `BLUME_MD_CURLY_ANCHOR` in `.md` (only `{#id}` pins there), and `BLUME_MDX_CURLY_ANCHOR` in `.mdx` (`BLUME_MDX_ATTRIBUTE_LIST` beside classes): write `[#id]` |
|
|
149
|
+
| other attribute lists | dropped and reported (one left over warns `BLUME_MD_ATTRIBUTE_LIST` in `.md`): buttons → links or `<Card>`s (a homepage CTA → `navigation.cta`); image sizing → `<img … />` or `<Frame>`; `{target="_blank"}` → `markdown.externalLinks: true` |
|
|
150
|
+
| `++ctrl+c++`, `==x==`, `^^x^^` | `<kbd>Ctrl</kbd>+<kbd>C</kbd>`, `<mark>`, `<ins>` |
|
|
151
|
+
| `:material-check:` (mapped icons) | `<Icon icon="check" />`; `:octicons-link-external-16:` drops (see `externalLinks`) |
|
|
152
|
+
| `\(x\)`, `\[`…`\]` | `$$x$$`, `$$` blocks |
|
|
153
|
+
| `*[HTML]: …`, `[TOC]` | removed |
|
|
154
|
+
| `<div markdown>` | attribute dropped (Markdown inside renders in `.mdx`) |
|
|
155
|
+
| Body `# H1` | frontmatter `title` |
|
|
156
|
+
| **By hand:** single-`$` math | `$$…$$` inside the sentence, where it is math |
|
|
157
|
+
| definition lists | `<dl>` or a list |
|
|
158
|
+
| `///` blocks (pymdownx.blocks) | the same targets as `!!!`/`???`/`===`; `/// caption` → `<Frame caption>` |
|
|
159
|
+
| grid cards (`<div class="grid cards" markdown>`) | `<CardGroup>`/`<Card>` |
|
|
160
|
+
| code annotations (`# (1)!` + a list) | prose after the block |
|
|
161
|
+
| `` / `#only-dark` | a `theme.css` rule: `:root:not([data-theme="dark"]) img[src$="#only-dark"], :root[data-theme="dark"] img[src$="#only-light"] { display: none; }` (checked in a browser) |
|
|
162
|
+
| emoji `:smile:`, magiclink `#123`/`@user` | paste the emoji; write the links |
|
|
163
|
+
| unmapped icons | a Lucide name in `<Icon>` (verify at lucide.dev), or drop; brand icons (Python, Linux, Docker) have none |
|
|
164
|
+
|
|
165
|
+
### Snippets and includes
|
|
166
|
+
|
|
167
|
+
- Snippet paths resolve from the snippets `base_path` (default: where MkDocs runs), never the page; the codemod rewrites them to `/`-rooted `<include>`s.
|
|
168
|
+
- Includes must live in the content root. The codemod copies outside files (`CONTRIBUTING.md`, `examples/`) into `_snippets/`; if the source keeps changing, ship a small `predev`/`prebuild` script that re-copies it, and gitignore the copy. Drop a copied file's H1 (the codemod reports it) — the page's title already renders one.
|
|
169
|
+
- Line ranges (`file.py:3:10`) have no `<include>` equivalent: generate the excerpt with `<skill>/scripts/include-excerpts.mjs` (`lines`, run before every build so it keeps tracking the source). Sections (`file.md:name`, marked `--8<-- [start:name]`) aren't read by that script: split the section into its own file and report it.
|
|
170
|
+
- `auto_append` link-definition files: `<include>` the file at the end of each page that uses them. An included file's definitions resolve references in the including page, as if written inline (and the page's resolve in the partial).
|
|
171
|
+
- A partial is parsed with the page that includes it: its directives render only in an `.mdx` page. An HTML comment in a `.md` partial stays hidden in an `.mdx` page too.
|
|
172
|
+
- A snippet file that isn't under a `_` or `.` folder or name is a page too, and publishes on its own as it did in MkDocs; the codemod reports each one. Move it under `_snippets/` unless it should stay a page.
|
|
173
|
+
- `include-markdown` (`{% include "./x.md" %}`): `./` paths are page-relative like Blume's, bare ones `docs_dir`-relative (→ `/x.md`); `start`/`end` excerpts → their own file.
|
|
174
|
+
|
|
175
|
+
## Frontmatter
|
|
176
|
+
|
|
177
|
+
The codemod maps `hide: [toc]` → `mode: wide`, `hide: [navigation]` → `mode: center`, `hide: [footer]` → `pagination: false`, `status: new` → `sidebar.badge: New` (`deprecated` → `deprecated: true`), `tags` → `search.tags` (a hosted-search facet; tag pages drop), `icon: material/…` → a Lucide name, and drops `subtitle`, `template`, `social`, `comments`, `render_macros`. `search.exclude`/`boost` keep their meaning. It reports every other key Blume's strict schema rejects (`BLUME_FRONTMATTER_INVALID`) — map or remove them; `.meta.yml` defaults (the `meta` plugin) apply to every page in their folder.
|
|
178
|
+
|
|
179
|
+
## Plugins — map, don't drop
|
|
180
|
+
|
|
181
|
+
| Plugin | Blume |
|
|
182
|
+
| --- | --- |
|
|
183
|
+
| `search` | built in — delete |
|
|
184
|
+
| `redirects` | `redirects` (URLs) |
|
|
185
|
+
| `git-revision-date(-localized)` | `lastModified: "git"` (it shows a visible "Last updated" line) |
|
|
186
|
+
| `git-committers`, `git-authors`, `minify`, `privacy`, `offline`, `typeset`, `info` | drop |
|
|
187
|
+
| `social`, `glightbox`, `optimize` | built in: Open Graph images, image zoom, image optimization |
|
|
188
|
+
| `group` | unwrap and map its plugins |
|
|
189
|
+
| `exclude` | `content.exclude` |
|
|
190
|
+
| `meta`, `tags` | Frontmatter |
|
|
191
|
+
| `blog`, `rss` | Blog |
|
|
192
|
+
| `awesome-pages`, `awesome-nav`, `literate-nav`, `section-index` | Navigation |
|
|
193
|
+
| `include-markdown` | Snippets |
|
|
194
|
+
| `llmstxt` | built in: `markdown_description` → `agents.llmsTxt.details` (reword URL advice); `sections` drop |
|
|
195
|
+
| `macros`, `mkdocstrings`, `mkdocs-click`, `gen-files`, `mkdocs-jupyter` | Manual decisions |
|
|
196
|
+
| `i18n`/`static-i18n`, `mike` | i18n; Versioning |
|
|
197
|
+
| anything else | read what it does; report it |
|
|
198
|
+
|
|
199
|
+
## Manual decisions — stop and report
|
|
200
|
+
|
|
201
|
+
- **mkdocstrings** (`::: package.module`): no Python API generator in Blume. Keep that reference published elsewhere and link to it, use `openapi()` for an HTTP API, or hand-write the key pages; redirect the URLs you drop. The same for `mkdocs-click` CLI references and `gen-files` output.
|
|
202
|
+
- **macros**: plain values (`extra`, `include_yaml`, `{% set %}`) → `variables`, same `{{ name }}` syntax — names take letters, digits, `_`, `-` only, and `{{ config.x }}`/`{{ page.x }}` must be inlined. `{% include 'x.md' %}` (from `include_dir`, default `docs_dir`) → `<include>/x.md</include>`. Macro calls and control flow → expand into plain content (a one-off render script is fine); strip `{% raw %}` wrappers.
|
|
203
|
+
- **Template overrides** (`custom_dir`) and **hooks**: read each. Announcement → `banner`; `<head>` meta tags → `seo.metatags` (minus the tags Blume owns); analytics partials → adapters; `<title>`/JSON-LD tweaks → Blume's own; the rest → layout slots (`defineComponents`) or `blume eject`.
|
|
204
|
+
- **Notebooks** (`mkdocs-jupyter`): export to Markdown or link out.
|
|
205
|
+
|
|
206
|
+
## i18n
|
|
207
|
+
|
|
208
|
+
`static-i18n` `languages` → `i18n: { defaultLocale, locales: [{ code, label }] }` (both serve the default at the root, others under `/<locale>/`). `docs_structure: suffix` (`page.fr.md`, the default) → `parser: "dot"`; `folder` → the default `dir` parser with the **default locale's folder moved up to the content root**. `nav_translations` → per-locale `meta.ts` titles; `fallback_to_default` matches `fallbackLocale`. Pin translated headings with `[#id]`.
|
|
209
|
+
|
|
210
|
+
## Versioning (`mike`)
|
|
211
|
+
|
|
212
|
+
mike publishes built HTML per version (`/<version>/…`, aliases like `/latest/`); old versions' sources live only in git tags. Migrate the current version unless asked: serve it at the root and redirect `/<alias>/:path*` and `/<version>/:path*` to `/:path*`. Older versions stay on the old host (a `navigation.featured` link) or are converted from their tags into Blume's `versions.archived` (ids start with a letter). Report which.
|
|
213
|
+
|
|
214
|
+
## Blog (Material `blog` plugin)
|
|
215
|
+
|
|
216
|
+
Posts in `blog/posts/` → `type: blog` pages. `date: { created, updated }` → `date` + `lastModified`; `authors: [id]` → inline objects from `.authors.yml`; `categories` → `search.tags` or drop. Keep the old dated URL with a full-route `slug: blog/2024/01/31/my-post`, or redirect. Delete `<!-- more -->` in `.mdx`. Blume has no blog index, archive, category, or pagination pages: write `blog/index.mdx` (`docs/advanced/blog.mdx`), report the rest. RSS moves to `/blog/rss.xml`; with the `rss` plugin (mkdocs-rss-plugin), redirect its `/feed_rss_created.xml` and `/feed_rss_updated.xml` (and `/feed_json_*.json`) there.
|
|
217
|
+
|
|
218
|
+
## Repo integration and teardown
|
|
219
|
+
|
|
220
|
+
- **Assets**: everything non-Markdown in `docs_dir` that's served by URL — logo, favicon, downloads, `CNAME`, verification files — moves to `public/`. Images and other files that pages link relatively can stay: Blume publishes each with the page, though at a new URL, so a download whose old URL is linked from elsewhere moves to `public/` too.
|
|
221
|
+
- **Renamed files**: after the codemod, **grep the whole repo for the old page paths** — release tooling that bumps versions inside pages (`[tool.rooster] version_files`, `bumpversion`), Renovate/Dependabot file globs, CODEOWNERS, `.prettierignore`, CI path filters, and scripts.
|
|
222
|
+
- **Prettier**: `.prettierrc` and `.editorconfig` overrides keyed on `*.md` stop applying to the new `.mdx` files — extend them to `*.mdx` before reformatting. Prettier turns a multi-line `{/* … */}` into `{/_ … _/}` (keep MDX comments on one line) and rewrites a URL containing parentheses as a `<…>` destination (fine in a page; percent-encode it in a partial, see Links). If the repo uses Ultracite/oxfmt, see `references/monorepo.md` §6.
|
|
223
|
+
- **CI**: replace `mkdocs build`/`gh-deploy` with Node 22, an install, `blume build`, and `blume validate --strict` (GitHub Pages: the "Deploy Markdown docs to GitHub Pages" guide); a `.readthedocs.yaml` build is a hosting change to report. Add `.gitignore` entries for `node_modules/`, `.blume/`, `dist/`, and `.env.local`.
|
|
224
|
+
- **Teardown**: delete `mkdocs.yml` (and `INHERIT`ed bases), `overrides/`, `.pages`/`.nav.yml`/`SUMMARY.md`/`.meta.yml`, hooks, and `extra_css`/`extra_javascript` files once ported. Leave the Python docs dependencies for a follow-up: removing a `pyproject.toml` docs group needs a lock regeneration (`uv lock`), and CI running with `--locked`/`UV_LOCKED=1` fails until it's done — report it.
|
|
225
|
+
|
|
226
|
+
## Leftover check
|
|
227
|
+
|
|
228
|
+
Rerun until it prints only what you mean to keep (code samples, and `{{name}}` variables you defined):
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
grep -rnE '^\s*(!!!|\?\?\?\+?|===[+!]*) |^\s*/{3,} ?[a-z]|--8<--|\{ *[.#:][^}]*\}|\{\{|\{%|<!--|:(material|octicons|fontawesome|simple)-[a-z0-9-]+:|\+\+[a-z]|==[^= ][^=]*==|\{\+\+|\{--|^\*\[|`#![a-z]|hl_lines=|linenums=' docs
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
## Dropped — report these
|
|
235
|
+
|
|
236
|
+
Template overrides and hooks with no slot equivalent, links inside `copyright`, code annotations, admonition title bars and collapsible callout colors, `inline` admonition placement, `palette.accent`, unmapped and brand icons, abbreviation tooltips, definition-list styling, snippet line ranges and sections (split into files), tag index pages, blog archive/category/pagination pages, anchor-level redirects without the script, cross-page tab memory, git committers, mkdocstrings/click/gen-files/notebook output not carried over, macro functions and Jinja logic, social platforms `footer.socials` lacks, a `linenums` start offset, image sizing from attribute lists, and every plugin you removed without an equivalent.
|
|
@@ -35,18 +35,18 @@ export default defineConfig({
|
|
|
35
35
|
"getting-started/**/*.{md,mdx}",
|
|
36
36
|
"guides/**/*.{md,mdx}",
|
|
37
37
|
],
|
|
38
|
-
exclude: ["**/node_modules/**", "**/_*"
|
|
38
|
+
exclude: ["**/node_modules/**"], // added to the default "**/_*" and "**/.*"
|
|
39
39
|
},
|
|
40
40
|
});
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
-
Schema field names, exactly: **`content.root`** (string, relative to the project/cwd), **`content.include`** (array of globs, relative to `content.root`, default `["**/*.{md,mdx}"]`), **`content.exclude`** (array of globs, relative to `content.root`, default `["**/_*", "**/.*"]`). Singular `include`/`exclude`, both arrays.
|
|
43
|
+
Schema field names, exactly: **`content.root`** (string, relative to the project/cwd), **`content.include`** (array of globs, relative to `content.root`, default `["**/*.{md,mdx}"]`), **`content.exclude`** (array of globs, relative to `content.root`, added to the default `["**/_*", "**/.*"]`; a `!`-prefixed default, `"!**/_*"`, takes it back out). Singular `include`/`exclude`, both arrays. A folder `meta.ts` outside every `include` glob is never read (`BLUME_META_OUTSIDE_INCLUDE` names it), so a folder that holds only a `meta.ts`, like an API reference's tag folder, needs a glob of its own (`"api-reference/**/*.{md,mdx}"`).
|
|
44
44
|
|
|
45
45
|
Report to the user: the detected content root, the folders you scoped `include` to, and anything Markdown you deliberately left out (a top-level `README.md`, a `CHANGELOG.md`) so they can confirm it isn't content.
|
|
46
46
|
|
|
47
47
|
---
|
|
48
48
|
|
|
49
|
-
## 2. pnpm `minimumReleaseAge`
|
|
49
|
+
## 2. Release-age guards (pnpm `minimumReleaseAge`, Yarn `npmMinimalAgeGate`) block installing fresh Blume
|
|
50
50
|
|
|
51
51
|
pnpm's supply-chain guard (`minimumReleaseAge`, often set to `1440` = 24h) refuses to install any package version published more recently than the window. Right after Blume publishes, that's **every** Blume release — so `pnpm add blume` / the workspace install fails or silently pins an older version.
|
|
52
52
|
|
|
@@ -75,13 +75,15 @@ minimum-release-age-exclude[]=blume
|
|
|
75
75
|
|
|
76
76
|
Report: "Added `blume` to `minimumReleaseAgeExclude` so the just-published version installs; the release-age guard still applies to everything else."
|
|
77
77
|
|
|
78
|
+
**Yarn ≥4.10** has the same guard: `npmMinimalAgeGate` in `.yarnrc.yml` (e.g. `2w`). Its per-package exemption is `npmPreapprovedPackages`. Yarn reads rc files from parent directories, so a nested `docs/` package inherits the root's gate. Detect with `grep -rn "npmMinimalAgeGate" .yarnrc.yml docs/.yarnrc.yml 2>/dev/null`, then add `npmPreapprovedPackages: ["blume"]` (or append `blume` to the existing list) in the file that sets the gate. Don't remove the gate.
|
|
79
|
+
|
|
78
80
|
---
|
|
79
81
|
|
|
80
|
-
## 3. Frozen lockfile — regenerate and commit
|
|
82
|
+
## 3. Frozen lockfile — regenerate and commit the lockfile in the same change
|
|
81
83
|
|
|
82
84
|
CI and Vercel install with `--frozen-lockfile` (pnpm's default in CI): if `package.json` and `pnpm-lock.yaml` disagree by even one dependency, the install **fails immediately** — before any build step runs. A migration always edits dependencies (add `blume`, drop the old framework), so the lockfile is guaranteed stale.
|
|
83
85
|
|
|
84
|
-
**After every dependency edit, regenerate the lockfile and stage it with the manifest
|
|
86
|
+
**After every dependency edit, regenerate the lockfile with the repo's package manager (`pnpm install` from the workspace root, `yarn install`, `npm install`, `bun install`) and stage it with the manifest.** The pnpm case:
|
|
85
87
|
|
|
86
88
|
```bash
|
|
87
89
|
pnpm install # NOT --frozen-lockfile — this rewrites pnpm-lock.yaml
|
|
@@ -98,7 +100,7 @@ Rules:
|
|
|
98
100
|
|
|
99
101
|
## 4. Vercel monorepo recipe (root-aware install + build)
|
|
100
102
|
|
|
101
|
-
A plain `blume build` works locally, but Vercel in a workspace needs three things aligned: the install must run at the **workspace root** (so pnpm resolves the whole graph under a frozen lockfile), the build must run in the **docs package**, and Vercel must be pointed at the built `dist
|
|
103
|
+
A plain `blume build` works locally, but Vercel in a workspace needs three things aligned: the install must run at the **workspace root** (so pnpm resolves the whole graph under a frozen lockfile), the build must run in the **docs package**, and Vercel must be pointed at the built `dist/` (for a static build; see d) for `vercel()`). `blume build` emits a static site to `dist/` **relative to where it runs** — so building in `apps/docs/` produces `apps/docs/dist/`.
|
|
102
104
|
|
|
103
105
|
This is a **copyable template**, not prose. Three pieces:
|
|
104
106
|
|
|
@@ -132,7 +134,7 @@ This is a **copyable template**, not prose. Three pieces:
|
|
|
132
134
|
**c) The one setting `vercel.json` can't hold — set it in the Vercel project (dashboard → Settings → General, or `vercel` CLI):**
|
|
133
135
|
|
|
134
136
|
- **Root Directory** = `apps/docs`. This makes install/build/output paths resolve from the docs package, which is what the `vercel.json` above assumes.
|
|
135
|
-
- **Node version** = 22 or newer (Blume requires it). Or pin it in the docs package: `"engines": { "node": ">=22" }`.
|
|
137
|
+
- **Node version** = 22.19 or newer (Blume requires it). Or pin it in the docs package: `"engines": { "node": ">=22.19" }`.
|
|
136
138
|
|
|
137
139
|
How the pieces fit, with Root Directory = `apps/docs`:
|
|
138
140
|
|
|
@@ -147,6 +149,14 @@ Report every piece you wrote and the two dashboard settings the user must set by
|
|
|
147
149
|
|
|
148
150
|
**Redirect caveat on this deploy path:** a static build emits `vercel.json` redirect rules into `dist/`, but Vercel's **git-integration** builds read `vercel.json` only from the project's Root Directory — the copy inside `dist/` is honored only when the dist folder is deployed directly via the Vercel CLI. On the §4 setup, `blume.config.ts` redirects still work (Blume also emits per-route meta-refresh pages), but they're soft redirects, not real 3xx. If real 3xx responses matter (SEO for a large moved site), copy the generated redirect rules from `dist/vercel.json` after a build into the committed `apps/docs/vercel.json`'s `redirects` array, and note they must be re-synced when `redirects` change. (Most migrations are fine with the soft fallback — say which you chose.)
|
|
149
151
|
|
|
152
|
+
**d) Server output (`deployment: vercel()`).** A `vercel()` build (needed for the assistant, the MCP server, Mixedbread search, or the playground proxy) doesn't leave a static `dist/` for Vercel to serve. It writes the Build Output API folder `.vercel/output` in the docs package, which Vercel deploys as is. Use the same `vercel.json` without `outputDirectory`: `{ "$schema": …, "framework": null, "installCommand": "cd ../.. && pnpm install --frozen-lockfile", "buildCommand": "pnpm run build" }`.
|
|
153
|
+
|
|
154
|
+
- Keep `framework: null`: it overrides a preset the project already has (Nuxt, Next.js), whose build settings would replace these.
|
|
155
|
+
- Root Directory and Node are the same dashboard settings. Server secrets (`AI_GATEWAY_API_KEY` unless the project relies on Vercel's OIDC token) go in the project's environment variables.
|
|
156
|
+
- With Turborepo, add `".vercel/output/**"` to the docs task's `outputs`.
|
|
157
|
+
- The redirect caveat above doesn't apply: `vercel()` writes redirects into `.vercel/output/config.json`, so they're real 3xx responses.
|
|
158
|
+
- `blume preview` can't serve this build; check it with `blume dev` and a preview deployment.
|
|
159
|
+
|
|
150
160
|
---
|
|
151
161
|
|
|
152
162
|
## 5. Astro/Vite version mismatch → pnpm patch (manual)
|
|
@@ -210,6 +220,7 @@ patchedDependencies:
|
|
|
210
220
|
Commit **both** the patch file and the `patchedDependencies` entry, then re-run `pnpm install`.
|
|
211
221
|
|
|
212
222
|
- **The patch is pinned to `oxfmt@0.71.0`** (the version Blume's own repo pins). pnpm requires an exact version match, and the diff targets a file whose name is hashed per oxfmt release (`dist/markdown-*.js`), so it won't apply to any other version. If `pnpm why oxfmt` reports a different one, pin `oxfmt` to `0.71.0` as a direct dev dependency (Ultracite accepts any `oxfmt` ≥ 0.59 as a peer). If the repo can't take that pin, tell the user and fall back to keeping directive-heavy files out of the formatter's globs.
|
|
223
|
+
- **The risk isn't Ultracite-only.** Any plain `oxfmt` run over Markdown (a lint-staged `oxfmt` on `**/*.md`, say) treats `:::` the same way. Check `lint-staged`/pre-commit config for globs that reach the migrated pages; `.mdx` files outside an `*.md` glob are safe.
|
|
213
224
|
- **Not on pnpm?** The patch mechanism is pnpm-specific. For npm/yarn, either pin oxfmt and apply the diff with `patch-package`, or exclude `.md`/`.mdx` from Ultracite formatting so it never touches the directives — report whichever you chose.
|
|
214
225
|
|
|
215
226
|
---
|
|
@@ -218,8 +229,9 @@ Commit **both** the patch file and the `patchedDependencies` entry, then re-run
|
|
|
218
229
|
|
|
219
230
|
- [ ] Located real content folders (not assumed `docs/`); set `content.root` + scoped `content.include`.
|
|
220
231
|
- [ ] `minimumReleaseAge` present? Added `blume` to `minimumReleaseAgeExclude` only.
|
|
232
|
+
- [ ] `npmMinimalAgeGate` present? Added `blume` to `npmPreapprovedPackages` only.
|
|
221
233
|
- [ ] Ran plain `pnpm install`; committed `pnpm-lock.yaml` with the `package.json` change; verified `pnpm install --frozen-lockfile` is clean.
|
|
222
|
-
- [ ] Wrote `apps/docs/vercel.json` + package scripts; told the user to set Root Directory + Node 22 in the Vercel project.
|
|
234
|
+
- [ ] Wrote `apps/docs/vercel.json` + package scripts; told the user to set Root Directory + Node 22.19+ in the Vercel project.
|
|
223
235
|
- [ ] Checked for a workspace Vite override; if the build crashes inside Astro/Vite, gave the pnpm-patch recipe.
|
|
224
236
|
- [ ] Uses Ultracite/oxfmt? Shipped `patches/oxfmt@0.71.0.patch` + registered it under `patchedDependencies` so formatting doesn't mangle `:::` directives.
|
|
225
237
|
- [ ] Reported every repo-specific edit and every manual step left to the user.
|
|
@@ -15,8 +15,8 @@ Nextra (on Next.js) declares navigation and per-page labels in `_meta` files —
|
|
|
15
15
|
|
|
16
16
|
None of it maps automatically — read the config surface for the generation by hand and reconstruct in `blume.config.ts`:
|
|
17
17
|
|
|
18
|
-
- **v2/v3 — `theme.config.*`:** `logo` (JSX — extract text/image) → `logo`; `project.link` → `github` (renders the footer's repo link); `docsRepositoryBase` → `github` (owner/repo/branch — and any trailing sub-path → `github.dir`; if its origin is not `https://github.com`, set `github.host` to that origin — with `host` omitted, Blume builds the repository and edit links against public GitHub); `banner.text`/`banner.key` → `banner.content`/`banner.id` (`dismissible` maps); `primaryHue`/`primarySaturation` → pick an equivalent `theme.accent` color; `footer` → drop (report); `faviconGlyph` → drop (Blume's favicon is a file convention); `useNextSeoProps`/head → per-page `seo` frontmatter or drop.
|
|
19
|
-
- **v4 — `app/layout.*` props:** the same facts moved: `<Navbar logo projectLink>`, `<Layout docsRepositoryBase editLink sidebar={{…}} toc={{…}}>`, `<Banner>`, `<Footer
|
|
18
|
+
- **v2/v3 — `theme.config.*`:** `logo` (JSX — extract text/image) → `logo`; `project.link` → `github` (renders the footer's repo link); `docsRepositoryBase` → `github` (owner/repo/branch — and any trailing sub-path → `github.dir`; if its origin is not `https://github.com`, set `github.host` to that origin — with `host` omitted, Blume builds the repository and edit links against public GitHub); `banner.text`/`banner.key` → `banner.content`/`banner.id` (`dismissible` maps); `primaryHue`/`primarySaturation` → pick an equivalent `theme.accent` color; `footer.text` (v2) / `footer.content` (v3) → `footer.copyright` when it's a copyright line: reduce the JSX to plain text, and a `{new Date().getFullYear()}` becomes `${new Date().getFullYear()}` in a template literal; anything else in it → drop (report); `faviconGlyph` → drop (Blume's favicon is a file convention); `useNextSeoProps`/head → per-page `seo` frontmatter or drop.
|
|
19
|
+
- **v4 — `app/layout.*` props:** the same facts moved: `<Navbar logo projectLink>`, `<Layout docsRepositoryBase editLink sidebar={{…}} toc={{…}}>`, `<Banner>`, `<Footer>` (its children are v3's `footer.content`). Map them the same way; sidebar/TOC tuning mostly drops (Blume's `toc` config covers min/max heading levels).
|
|
20
20
|
- **`next.config.*`:** harvest **`redirects()`** — static entries and `:param`/`:path*` patterns become Blume `redirects: [{ from, to }]` as written (`permanent: true` → `status: 308`, `false` → `307`); ones with regex params (`:slug(\d+)`) or `has`/`missing` conditions move to host config (report). A `latex: true` flag means math is in play (see Math below). Then delete the file.
|
|
21
21
|
- Root `_meta` entries with **`type: "page"`** → `navigation.tabs` (`{ label, path }`, where `path` is `/` for `index`, else `/<slug>`). `type: "page"` only maps at the **root**.
|
|
22
22
|
|
|
@@ -54,12 +54,12 @@ Most Nextra pages have **no frontmatter**. Nextra keeps two titles apart: the **
|
|
|
54
54
|
- **`<Steps>`:** Nextra's wraps **Markdown headings (h2–h6)**, one step per heading. Convert each heading to a `<Step title="…">` child (Blume `<Steps>`/`<Step>`) and delete the heading — this also keeps step titles out of the TOC, matching Nextra's behavior.
|
|
55
55
|
- **`<FileTree>`/`<FileTree.Folder>`/`<FileTree.File>`** → `<Tree>`/`<Tree.Folder>`/`<Tree.File>` (or a list-driven `<FileTree>`).
|
|
56
56
|
- **`<Bleed>`** (full-bleed) → no equivalent; drop the wrapper and report. **`<Table>`** → a plain Markdown table. **`<Banner>`** (v4, in layout) → the `banner` config.
|
|
57
|
-
- **GitHub alert blockquotes** (v4 renders them): `> [!NOTE]`/`[!TIP]`/`[!WARNING]`/`[!IMPORTANT]`/`[!CAUTION]`
|
|
57
|
+
- **GitHub alert blockquotes** (v4 renders them): `> [!NOTE]`/`[!TIP]`/`[!WARNING]`/`[!IMPORTANT]`/`[!CAUTION]` pass through in `.mdx`, where Blume renders them as note/tip/warning/note/danger callouts. In a `.md` page they stay plain quotes (`BLUME_MD_GITHUB_ALERT`): rename it to `.mdx`.
|
|
58
58
|
- **Strip or convert every import:** `nextra`, `nextra/*`, `nextra-theme-docs`, `nextra-theme-blog`, plus `next/image` (→ Markdown image or `<Frame>`), `next/link` (→ plain link), and local components (port or inline; report).
|
|
59
59
|
|
|
60
60
|
## Code fences
|
|
61
61
|
|
|
62
|
-
Nextra's fence meta differs from Blume's — rewrite it: `filename="app.js"` → a space-separated title (` ```js app.js `); `showLineNumbers` → `lineNumbers
|
|
62
|
+
Nextra's fence meta differs from Blume's — rewrite it: `filename="app.js"` → a space-separated title (` ```js app.js `); `showLineNumbers` → `lineNumbers` (`BLUME_CODE_FENCE_OPTION` flags either one left); 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 `.
|
|
63
63
|
|
|
64
64
|
## Math
|
|
65
65
|
|
|
@@ -76,4 +76,4 @@ Repoint `dev`/`build`/`start` scripts to the Blume CLI; remove `next`/`nextra`/`
|
|
|
76
76
|
|
|
77
77
|
## Dropped — report these
|
|
78
78
|
|
|
79
|
-
Footer content; `primaryHue`-style theming beyond an accent color; `faviconGlyph`; `_meta` separators, menus, `newWindow`; per-page `theme` switches (and `layout: "full"` approximated as `mode: wide`); root-level pages `_meta` ordered after a folder; `<Bleed>`; MathJax macros; word-highlight/copy fence meta; any icon you can't reconstruct as a Lucide name.
|
|
79
|
+
Footer content other than a copyright line; `primaryHue`-style theming beyond an accent color; `faviconGlyph`; `_meta` separators, menus, `newWindow`; per-page `theme` switches (and `layout: "full"` approximated as `mode: wide`); root-level pages `_meta` ordered after a folder; `<Bleed>`; MathJax macros; word-highlight/copy fence meta; any icon you can't reconstruct as a Lucide name.
|