blume 2.2.0 → 2.2.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.
Files changed (125) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/cli/{chunk-xgq4eytj.js → chunk-080mfch6.js} +15 -15
  3. package/dist/cli/{chunk-br0n8n3e.js → chunk-1ch3ct3r.js} +14 -14
  4. package/dist/cli/{chunk-49r370mb.js → chunk-2ssh60qh.js} +6 -6
  5. package/dist/cli/{chunk-1cm0h819.js → chunk-34wap3ed.js} +3 -3
  6. package/dist/cli/{chunk-fqy4n3q2.js → chunk-40vk8kgf.js} +7 -7
  7. package/dist/cli/{chunk-96snx8yy.js → chunk-487b95qy.js} +3 -3
  8. package/dist/cli/{chunk-kkrteb15.js → chunk-4zxh25hc.js} +2 -2
  9. package/dist/cli/{chunk-cn3dy3hz.js → chunk-69rjf786.js} +5 -5
  10. package/dist/cli/{chunk-dmx6cezx.js → chunk-9h8mh2tk.js} +3 -3
  11. package/dist/cli/{chunk-dmx6cezx.js.map → chunk-9h8mh2tk.js.map} +2 -2
  12. package/dist/cli/{chunk-t5xx74rd.js → chunk-9jqmq5hv.js} +6 -6
  13. package/dist/cli/{chunk-8b489v1b.js → chunk-aafhwx74.js} +1 -1
  14. package/dist/cli/{chunk-2nr29y95.js → chunk-b680sv30.js} +3 -3
  15. package/dist/cli/{chunk-rkqae7kh.js → chunk-beb0z983.js} +16 -16
  16. package/dist/cli/{chunk-th0pgaj5.js → chunk-c5bjxq8v.js} +2 -2
  17. package/dist/cli/{chunk-wehv26ry.js → chunk-e1n41w9m.js} +3 -3
  18. package/dist/cli/{chunk-frk2wdq1.js → chunk-etckvbrh.js} +14 -14
  19. package/dist/cli/{chunk-ahc5gc9h.js → chunk-f260jdrn.js} +5 -5
  20. package/dist/cli/{chunk-05f21r8h.js → chunk-fnxgtjeq.js} +1 -1
  21. package/dist/cli/{chunk-4rftmttv.js → chunk-gwy55cx3.js} +2 -2
  22. package/dist/cli/{chunk-4rftmttv.js.map → chunk-gwy55cx3.js.map} +2 -2
  23. package/dist/cli/{chunk-vnbvhgmd.js → chunk-gxhcf2hs.js} +2 -2
  24. package/dist/cli/{chunk-bjk964fp.js → chunk-h0qwdbem.js} +2 -2
  25. package/dist/cli/{chunk-1rkxzg3n.js → chunk-hktq4j5r.js} +15 -12
  26. package/dist/cli/{chunk-1rkxzg3n.js.map → chunk-hktq4j5r.js.map} +3 -3
  27. package/dist/cli/{chunk-enk76qd5.js → chunk-hn3g2b89.js} +9 -9
  28. package/dist/cli/{chunk-w6e455pz.js → chunk-j4nfgn2j.js} +1 -1
  29. package/dist/cli/{chunk-as09pafp.js → chunk-k45sq16q.js} +4 -4
  30. package/dist/cli/{chunk-as09pafp.js.map → chunk-k45sq16q.js.map} +3 -3
  31. package/dist/cli/{chunk-p8zg3a2h.js → chunk-kmswjxj9.js} +3 -3
  32. package/dist/cli/{chunk-xt0qvz1t.js → chunk-nqna8dzp.js} +17 -17
  33. package/dist/cli/{chunk-dyk3r7jw.js → chunk-p834rkcn.js} +5 -5
  34. package/dist/cli/{chunk-dpcahcrb.js → chunk-ppa6mg4d.js} +6 -6
  35. package/dist/cli/{chunk-79bzzkx4.js → chunk-q1wwrxzw.js} +2 -2
  36. package/dist/cli/{chunk-m9bp2hc1.js → chunk-qcyxkj44.js} +1 -1
  37. package/dist/cli/{chunk-dm4mg9bj.js → chunk-r5nm9w0c.js} +740 -685
  38. package/dist/cli/{chunk-dm4mg9bj.js.map → chunk-r5nm9w0c.js.map} +8 -6
  39. package/dist/cli/{chunk-a3ydrqny.js → chunk-rtvgmg2j.js} +2 -2
  40. package/dist/cli/{chunk-c69tw29j.js → chunk-t2h8pwy1.js} +4 -4
  41. package/dist/cli/{chunk-vzy9rh6y.js → chunk-x60e15st.js} +17 -17
  42. package/dist/cli/{chunk-mrvh4c88.js → chunk-x7bh6d9j.js} +4 -4
  43. package/dist/cli/{chunk-7tekknev.js → chunk-ydqzkhjn.js} +6 -6
  44. package/dist/cli/{chunk-gprwej7h.js → chunk-yg8ckc3g.js} +2 -2
  45. package/dist/cli/{chunk-8f8xw4x2.js → chunk-zxd5jrgx.js} +14 -4
  46. package/dist/cli/{chunk-8f8xw4x2.js.map → chunk-zxd5jrgx.js.map} +3 -3
  47. package/dist/cli/index.js +18 -18
  48. package/dist/types/core/config-input.d.ts +37 -5
  49. package/dist/types/core/data.d.ts +6 -2
  50. package/dist/types/core/mcp-clients.d.ts +47 -0
  51. package/dist/types/core/nav-diagnostics.d.ts +7 -0
  52. package/dist/types/core/schema.d.ts +55 -4
  53. package/dist/types/ratelimit/index.d.ts +2 -0
  54. package/dist/types/ratelimit/memory.d.ts +1 -1
  55. package/dist/types/ratelimit/schema.d.ts +40 -0
  56. package/dist/types/ratelimit/unkey.d.ts +48 -0
  57. package/docs/02-deployment.mdx +1 -0
  58. package/docs/configuration/index.mdx +5 -4
  59. package/docs/configuration/rate-limiting.mdx +20 -1
  60. package/docs/content/i18n.mdx +1 -1
  61. package/docs/discoverability/mcp.mdx +40 -8
  62. package/package.json +1 -1
  63. package/skills/blume-migrate/SKILL.md +2 -2
  64. package/skills/blume-migrate/references/docusaurus.md +2 -2
  65. package/skills/blume-migrate/references/gitbook.md +2 -2
  66. package/skills/blume-migrate/references/github-wiki.md +2 -2
  67. package/skills/blume-migrate/references/jekyll.md +2 -2
  68. package/skills/blume-migrate/references/mkdocs.md +2 -2
  69. package/skills/blume-migrate/references/nextra.md +3 -3
  70. package/skills/blume-migrate/references/readme.md +1 -1
  71. package/skills/blume-migrate/references/redocly.md +2 -2
  72. package/skills/blume-migrate/references/vitepress.md +2 -2
  73. package/skills/blume-migrate/references/vuepress.md +1 -1
  74. package/skills/blume-migrate/scripts/github-wiki-codemod.mjs +1 -1
  75. package/src/astro/generate.ts +15 -5
  76. package/src/astro/templates.ts +4 -4
  77. package/src/cli/required-secrets.ts +0 -1
  78. package/src/components/layout/PageActions.astro +119 -34
  79. package/src/components/layout/RootLayout.astro +18 -2
  80. package/src/components/layout/SiteFooter.astro +31 -8
  81. package/src/core/config-input.ts +38 -4
  82. package/src/core/data.ts +10 -3
  83. package/src/core/mcp-clients.ts +87 -0
  84. package/src/core/nav-diagnostics.ts +25 -0
  85. package/src/core/schema.ts +93 -3
  86. package/src/openapi/proxy.ts +5 -1
  87. package/src/ratelimit/index.ts +2 -0
  88. package/src/ratelimit/memory.ts +1 -1
  89. package/src/ratelimit/runtime.ts +81 -0
  90. package/src/ratelimit/schema.ts +2 -0
  91. package/src/ratelimit/unkey.ts +61 -0
  92. package/src/registry/registry.ts +1 -1
  93. /package/dist/cli/{chunk-xgq4eytj.js.map → chunk-080mfch6.js.map} +0 -0
  94. /package/dist/cli/{chunk-br0n8n3e.js.map → chunk-1ch3ct3r.js.map} +0 -0
  95. /package/dist/cli/{chunk-49r370mb.js.map → chunk-2ssh60qh.js.map} +0 -0
  96. /package/dist/cli/{chunk-1cm0h819.js.map → chunk-34wap3ed.js.map} +0 -0
  97. /package/dist/cli/{chunk-fqy4n3q2.js.map → chunk-40vk8kgf.js.map} +0 -0
  98. /package/dist/cli/{chunk-96snx8yy.js.map → chunk-487b95qy.js.map} +0 -0
  99. /package/dist/cli/{chunk-kkrteb15.js.map → chunk-4zxh25hc.js.map} +0 -0
  100. /package/dist/cli/{chunk-cn3dy3hz.js.map → chunk-69rjf786.js.map} +0 -0
  101. /package/dist/cli/{chunk-t5xx74rd.js.map → chunk-9jqmq5hv.js.map} +0 -0
  102. /package/dist/cli/{chunk-8b489v1b.js.map → chunk-aafhwx74.js.map} +0 -0
  103. /package/dist/cli/{chunk-2nr29y95.js.map → chunk-b680sv30.js.map} +0 -0
  104. /package/dist/cli/{chunk-rkqae7kh.js.map → chunk-beb0z983.js.map} +0 -0
  105. /package/dist/cli/{chunk-th0pgaj5.js.map → chunk-c5bjxq8v.js.map} +0 -0
  106. /package/dist/cli/{chunk-wehv26ry.js.map → chunk-e1n41w9m.js.map} +0 -0
  107. /package/dist/cli/{chunk-frk2wdq1.js.map → chunk-etckvbrh.js.map} +0 -0
  108. /package/dist/cli/{chunk-ahc5gc9h.js.map → chunk-f260jdrn.js.map} +0 -0
  109. /package/dist/cli/{chunk-05f21r8h.js.map → chunk-fnxgtjeq.js.map} +0 -0
  110. /package/dist/cli/{chunk-vnbvhgmd.js.map → chunk-gxhcf2hs.js.map} +0 -0
  111. /package/dist/cli/{chunk-bjk964fp.js.map → chunk-h0qwdbem.js.map} +0 -0
  112. /package/dist/cli/{chunk-enk76qd5.js.map → chunk-hn3g2b89.js.map} +0 -0
  113. /package/dist/cli/{chunk-w6e455pz.js.map → chunk-j4nfgn2j.js.map} +0 -0
  114. /package/dist/cli/{chunk-p8zg3a2h.js.map → chunk-kmswjxj9.js.map} +0 -0
  115. /package/dist/cli/{chunk-xt0qvz1t.js.map → chunk-nqna8dzp.js.map} +0 -0
  116. /package/dist/cli/{chunk-dyk3r7jw.js.map → chunk-p834rkcn.js.map} +0 -0
  117. /package/dist/cli/{chunk-dpcahcrb.js.map → chunk-ppa6mg4d.js.map} +0 -0
  118. /package/dist/cli/{chunk-79bzzkx4.js.map → chunk-q1wwrxzw.js.map} +0 -0
  119. /package/dist/cli/{chunk-m9bp2hc1.js.map → chunk-qcyxkj44.js.map} +0 -0
  120. /package/dist/cli/{chunk-a3ydrqny.js.map → chunk-rtvgmg2j.js.map} +0 -0
  121. /package/dist/cli/{chunk-c69tw29j.js.map → chunk-t2h8pwy1.js.map} +0 -0
  122. /package/dist/cli/{chunk-vzy9rh6y.js.map → chunk-x60e15st.js.map} +0 -0
  123. /package/dist/cli/{chunk-mrvh4c88.js.map → chunk-x7bh6d9j.js.map} +0 -0
  124. /package/dist/cli/{chunk-7tekknev.js.map → chunk-ydqzkhjn.js.map} +0 -0
  125. /package/dist/cli/{chunk-gprwej7h.js.map → chunk-yg8ckc3g.js.map} +0 -0
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  title: MCP server
3
- description: Host a Model Context Protocol server so coding agents can search and read your docs directly — tools, resources, discovery documents, content-type and facet filters, and the server output it needs.
3
+ description: Host a Model Context Protocol server so coding agents can search and read your docs directly — tools, resources, discovery documents, content-type and facet filters, the Connect to MCP menu, and the server output it needs.
4
4
  ---
5
5
 
6
6
  Host a [Model Context Protocol](https://modelcontextprotocol.io) server so coding agents (Claude Code, Cursor, VS Code, claude.ai connectors) can search and read your docs directly — no scraping. It's opt-in:
@@ -14,12 +14,13 @@ agents: {
14
14
  }
15
15
  ```
16
16
 
17
- | Option | Default | Description |
18
- | -------------- | ------- | ------------------------------------------------- |
19
- | `enabled` | `false` | Generate and host the MCP server. |
20
- | `route` | `/mcp` | Path the Streamable-HTTP endpoint is mounted on. |
21
- | `name` | title | Server name shown to clients (defaults to title). |
22
- | `instructions` | — | Optional system hint passed to connecting agents. |
17
+ | Option | Default | Description |
18
+ | --- | --- | --- |
19
+ | `enabled` | `false` | Generate and host the MCP server. |
20
+ | `route` | `/mcp` | Path the Streamable-HTTP endpoint is mounted on. |
21
+ | `name` | title | Server name shown to clients (defaults to title). |
22
+ | `instructions` | — | Optional system hint passed to connecting agents. |
23
+ | `clients` | `true` | Clients the **Connect to MCP** menu installs into. |
23
24
 
24
25
  If a content or custom page already owns the route, the server isn't generated: the build warns, and `llms.txt` and the other [discovery documents](/docs/discoverability/agent-discovery) leave it out.
25
26
 
@@ -27,7 +28,7 @@ If a content or custom page already owns the route, the server isn't generated:
27
28
 
28
29
  ## Tools and resources
29
30
 
30
- The server exposes read-only tools — `search_docs`, `get_page`, `list_pages`, and `get_navigation` — and every page as an MCP resource (`resources/list` enumerates the pages at their served URLs with a `text/markdown` type, leaving out i18n fallback copies of untranslated pages as `list_pages` does; `resources/read` returns the page's [agent Markdown](/docs/discoverability/markdown), the same output as `get_page`), so clients that attach context by URI can browse the docs without calling a tool. It publishes discovery documents at `/.well-known/mcp.json` and `/.well-known/mcp/server-card.json`. The server card follows the [SEP-2127](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2127) Server Card extension schema (reverse-DNS `name`, `remotes` transport endpoints), with initialize-shaped compat fields (`serverInfo`, `capabilities`, `transports`) for scanners built against the proposal's earlier revision. Each page's **Connect to MCP** menu offers copy-and-go install for Claude Code, Cursor, VS Code, and Codex (shown once [`deployment.site`](/docs/deployment) is set).
31
+ The server exposes read-only tools — `search_docs`, `get_page`, `list_pages`, and `get_navigation` — and every page as an MCP resource (`resources/list` enumerates the pages at their served URLs with a `text/markdown` type, leaving out i18n fallback copies of untranslated pages as `list_pages` does; `resources/read` returns the page's [agent Markdown](/docs/discoverability/markdown), the same output as `get_page`), so clients that attach context by URI can browse the docs without calling a tool. It publishes discovery documents at `/.well-known/mcp.json` and `/.well-known/mcp/server-card.json`. The server card follows the [SEP-2127](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2127) Server Card extension schema (reverse-DNS `name`, `remotes` transport endpoints), with initialize-shaped compat fields (`serverInfo`, `capabilities`, `transports`) for scanners built against the proposal's earlier revision. Each page's **Connect to MCP** menu offers copy-and-go install for Claude Code, Cursor, VS Code, and Codex (shown once [`deployment.site`](/docs/deployment) is set), and you can [choose the clients](#connect-to-mcp-menu) it lists.
31
32
 
32
33
  `search_docs` runs its own full-text index, so it works regardless of your [search](/docs/configuration/search) provider — and even with `search: false`. The MCP server is a separate feature from on-page search.
33
34
 
@@ -55,6 +56,37 @@ Every `filters` entry must match (results carry their facet values, and `list_pa
55
56
 
56
57
  A value matches exactly, case included, as `list_pages` shows it: `"enforced"` doesn't match a page whose `status` is `Enforced`. Facet values are strings, so a number or boolean in `filters` matches its string form (`{"priority": 1}` finds `priority: 1`), and a value of any other shape, such as a list, is ignored rather than filtering.
57
58
 
59
+ ## Connect to MCP menu
60
+
61
+ The **Connect to MCP** page action copies the server's URL, and then lists the clients it installs the server into: commands to copy for Claude Code and Codex, and install links for Cursor and VS Code. `clients` picks them. `true` (the default) lists every built-in client, `false` none, which leaves just **Copy server URL** in the menu, and a list shows the clients you name, in order, with a rule between the commands and the links.
62
+
63
+ A client Blume doesn't ship is an object with a `label` and the `command` to copy. `{name}` in the command becomes the server's name as an id: `name`, or the site title, lowercased, with each run of characters other than `a`–`z` and `0`–`9` turned into a hyphen and the ends trimmed (`docs` if nothing is left). `{url}` becomes the server's URL. On a [multilingual](/docs/content/i18n#per-locale-navigation) site, the `label` can be a map of locale code to text. `icon` takes a [built-in icon](/docs/content/components#icon) name, image path/URL, or inline SVG, and defaults to `terminal`.
64
+
65
+ ```ts blume.config.ts lineNumbers
66
+ agents: {
67
+ mcp: {
68
+ enabled: true,
69
+ clients: [
70
+ "claude-code",
71
+ "codex",
72
+ {
73
+ label: "Copy Copilot CLI command",
74
+ command: "copilot mcp add --transport http {name} {url}",
75
+ },
76
+ "cursor",
77
+ "vscode",
78
+ ],
79
+ },
80
+ }
81
+ ```
82
+
83
+ | Key | Menu row |
84
+ | ------------- | ---------------------------------------------------- |
85
+ | `claude-code` | Copies the `claude mcp add` command for Claude Code. |
86
+ | `codex` | Copies the `codex mcp add` command for Codex. |
87
+ | `cursor` | Opens Cursor's MCP install link. |
88
+ | `vscode` | Opens VS Code's MCP install link. |
89
+
58
90
  ## Server output required
59
91
 
60
92
  The MCP server is a live endpoint (`/mcp`), so it can't run on a static build. Name a host adapter from `blume/deploy` to switch to server output:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blume",
3
- "version": "2.2.0",
3
+ "version": "2.2.2",
4
4
  "description": "The open-source docs framework for humans and agents.",
5
5
  "keywords": [
6
6
  "agents",
@@ -15,7 +15,7 @@ Throughout this skill (including the `references/` files), **`<skill>` means the
15
15
 
16
16
  - **Target idiomatic Blume, not a mechanical port.** Prefer filesystem-derived navigation over an exhaustive explicit `navigation.sidebar`. Prefer `:::` directives over JSX callouts. Prefer Blume defaults over restating them in config.
17
17
  - **Every field has a default; `{}` is a valid config.** Map only what the source _declares_. If the source uses a framework default, don't write it.
18
- - **Drop chrome that has no Blume equivalent — and say so.** Navbar CTAs, footer copyright text, custom theming, conditional redirects, and unmappable icons get reported to the user, not silently discarded or faked.
18
+ - **Drop chrome that has no Blume equivalent — and say so.** Navbar CTAs, custom theming, conditional redirects, and unmappable icons get reported to the user, not silently discarded or faked.
19
19
  - **Convert, don't preserve.** Blume's page frontmatter schema is **strict** — unknown keys are build errors. A source-only frontmatter key must be mapped to a Blume key or removed (and reported), never left to "maybe validate."
20
20
 
21
21
  ## Migration workflow
@@ -190,7 +190,7 @@ A redirect whose `from` equals a page's route (a generated reference overview in
190
190
 
191
191
  1. Run **`blume build`** — it validates the frontmatter schema, duplicate routes, and config, and fails on any error diagnostic by default (**don't pass `--no-strict`**: that builds anyway and silently drops pages with invalid front matter or `.mdx` that doesn't parse). Then run **`blume validate --strict`** — links, heading anchors, assets, and redirect targets live here, not in `build` (add `--external` to also check outbound HTTP links). OpenAPI operation pages are real routes to `validate`, so dead links to them are caught too. Iterate until both are clean. Treat every warning `build` (or `blume check`) prints about another tool's syntax left in a page (`BLUME_TEMPLATE_TAG`, `BLUME_MDC_SYNTAX`, `BLUME_WIKILINK_UNSUPPORTED`, `BLUME_MD_*`, `BLUME_CODE_FENCE_OPTION`, `BLUME_MDX_*`, …) as a conversion you missed: each names the file and line and the Blume spelling, and `validate --strict` fails on them. `validate` reads links as the page renders them: a link definition shadowed by an earlier one with the same label isn't checked (it's dead text; delete it), and neither are links in comments. `validate --strict` also fails on OpenAPI spec warnings (`BLUME_OPENAPI_*`, such as an undeclared path parameter, a `localhost` server, or `nullable` in a 3.1 spec), which no content edit clears: fix them with an OpenAPI Overlay in the source's `overlays` so a generated or third-party spec stays untouched, and report them for a fix at the source; a `codeSamples` id Blume has no generator for (`BLUME_OPENAPI_UNKNOWN_CODE_SAMPLE`) is dropped from the config instead. **If you added redirects, run `blume audit --only redirects` after the build**: `validate` warns about a redirect whose `to` leads nowhere (`BLUME_BROKEN_REDIRECT`, at its line in `blume.config.ts`), but accepts a `to` that is another redirect's `from`, so only `audit` follows each one through the build and reports loops and chains. To check every old URL, request them against `blume dev` or `blume preview` (`curl -sL`; both apply every redirect, patterns included, with its status), or check them against `dist/` plus the redirect rules (`dist/blume-redirects.json` when no host adapter is set, else the host's `_redirects` or `vercel.json`). **Old heading anchors:** every source slugs heading ids differently from Blume. After the first build, run `node <skill>/scripts/pin-heading-ids.mjs --old <old site URL or its built-HTML dir>` (`--map dist/blume-redirects.json` when pages moved, built with no host adapter, `--write` to apply, `--only-linked` to pin only linked ids) and rebuild until it reports 0; on a server build it reads `dist/client` itself (skip it for ReadMe and a GitHub wiki: their heading ids already match Blume's, a ReadMe hub rate-limits a crawl, and the script can't read a wiki's pages); any `BLUME_BROKEN_ANCHOR` left was already dead on the old site, so retarget the obvious ones, drop the fragment from the rest, and report them.
192
192
  2. Run `blume dev` and review the site visually (`blume dev`/`preview --port N` move to the next free port when N is taken, so read the `Local http://…` line they print before requesting URLs) — nav structure, tabs, theme, rendered components.
193
- 3. **Write a migration summary** covering: what was migrated (config, N pages, nav, API references), what was **dropped** (navbar CTAs, footer copyright text, custom theming, conditional redirects, unmappable icons, unsupported components), and suggested follow-ups (`blume eject` for full control, `blume add` to vendor a component for customization).
193
+ 3. **Write a migration summary** covering: what was migrated (config, N pages, nav, API references), what was **dropped** (navbar CTAs, custom theming, conditional redirects, unmappable icons, unsupported components), and suggested follow-ups (`blume eject` for full control, `blume add` to vendor a component for customization).
194
194
 
195
195
  ## Full documentation
196
196
 
@@ -26,7 +26,7 @@ Read `themeConfig`, `presets`, and `plugins`:
26
26
  | `url` + `baseUrl` | **`url` → `deployment.site`**, unless the target host is Vercel or Netlify, which Blume auto-detects (see SKILL.md — GitHub Pages, a common Docusaurus host, is not one of them); `baseUrl` (when not `/`) → `deployment: { base: "/…" }`, or the `base` option of a host adapter (`vercel({ base })`) when the site also needs one |
27
27
  | preset `docs.routeBasePath` — **including the default!** | Docusaurus serves docs at **`/docs/…` by default**; the "map only declared fields" rule does **not** apply here because the _URLs_ are load-bearing. Either keep them with top-level **`basePath: "/docs"`** (invisible to the sidebar), or intentionally move to root and emit a `redirects` entry per page. Decide explicitly and say which. (`routeBasePath: '/'` = docs-only mode — nothing to do.) |
28
28
  | preset `docs.editUrl` | `github` (owner/repo/branch; a path after the branch → `github.dir`; **an origin other than `https://github.com` → `github.host`** — a GitHub Enterprise repo's edit links and header mark point at the public site without it) |
29
- | `themeConfig.footer` | `footer.links`, one row of `{ label, href }`: every column's items flatten into it in order (an item's `to`, a route, is its `href`); column `title`s, `copyright`, `logo`, and `style` drop (report), or keep the whole footer as a Footer override (`defineComponents` layout slot) |
29
+ | `themeConfig.footer` | `footer.links`, one row of `{ label, href }`: every column's items flatten into it in order (an item's `to`, a route, is its `href`); `copyright` (HTML) → `footer.copyright`, plain text: strip the tags, decode entities (`&copy;` → `©`), keep a `${new Date().getFullYear()}` template literal as written, and drop a "Built with Docusaurus." credit; a link inside it loses its URL (report, or add it to `footer.links`); a translated one in `i18n/<locale>/docusaurus-theme-classic/footer.json` → a locale map; column `title`s, `logo`, and `style` drop (report), or keep the whole footer as a Footer override (`defineComponents` layout slot) |
30
30
  | `themeConfig.announcementBar` | `banner` (`{ content, dismissible, id }` — `isCloseable` → `dismissible`; colors drop) |
31
31
  | `i18n.locales` / `defaultLocale` | `i18n` — translated files live at `i18n/<locale>/docusaurus-plugin-content-docs/current/…`; move them to `<locale>/…` under `content.root` |
32
32
  | `themeConfig.algolia` | drop — Blume ships built-in search (Orama); remove the Algolia dep. To keep the index, `search: algolia({ appId, apiKey, indexName })` from `blume/search` (the DocSearch `apiKey` is the search-only key) |
@@ -95,4 +95,4 @@ Remove `@docusaurus/*` and Algolia deps; delete `docusaurus.config.*`, `sidebars
95
95
 
96
96
  ## Dropped — report these
97
97
 
98
- Custom/swizzled theme components (layout slots or `blume eject`), the footer's copyright, logo, and HTML items, the blog's generated tag, author, and archive pages, Algolia config, `sidebar_custom_props` and the other dropped frontmatter keys, `createRedirects` functions (→ host rules), React pages under `src/pages/`, `<TOCInline>`, per-category `className`/`customProps`, and any `@theme/*` component with no Blume equivalent.
98
+ Custom/swizzled theme components (layout slots or `blume eject`), the footer's logo and HTML items (and any link inside its copyright), the blog's generated tag, author, and archive pages, Algolia config, `sidebar_custom_props` and the other dropped frontmatter keys, `createRedirects` functions (→ host rules), React pages under `src/pages/`, `<TOCInline>`, per-category `className`/`customProps`, and any `@theme/*` component with no Blume equivalent.
@@ -35,7 +35,7 @@ Map what step 3 found or the user supplies; leave the rest at Blume's defaults.
35
35
  | Theme style, tint and semantic colors, corner, depth, link, and sidebar styles | drop (report); a root `theme.css` if one matters |
36
36
  | Header links; a button-styled one | `navigation.actions`; `navigation.cta` |
37
37
  | Announcement | `banner` (`{ content, link, dismissible, id }`) |
38
- | Footer | `footer.links`, flattened into one row; group titles, logo, and copyright drop (report) |
38
+ | Footer | `footer.links`, flattened into one row; copyright → `footer.copyright`; group titles and logo drop (report) |
39
39
  | Social accounts | `footer.socials` |
40
40
  | Social preview image | `seo.image` on the landing page (Blume renders a card for every other page) |
41
41
  | Git Sync repository and branch | `github: { owner, repo, branch }`, plus `dir` or `host` when needed; GitLab has no equivalent (report) |
@@ -264,4 +264,4 @@ The old `gitbook-cli` toolchain and its fork HonKit:
264
264
 
265
265
  ## Dropped — report these
266
266
 
267
- Site themes and styles beyond accent, fonts, and mode; footer group titles, logo, and copyright; page covers; page and update tags; adaptive content and visitor authentication; GitBook Assistant unless the user adds `ai.assistant`; hint icons you didn't keep; button styles and search/ask buttons; `<mark>` colors; `fullWidth` and column widths; non-YouTube embeds as players; dark card covers and theme-aware images; inline image sizing; `{% openapi-schemas %}` and GitBook `x-*` spec extensions; automatic redirects you couldn't recover; case-insensitive URLs; page-group icons; sidebar positions Blume can't match (parent pages among loose pages, `***` dividers, external links); section groups flattened into tabs; spaces and translations not in the repo; integrations with no adapter; site redirects nobody could export; anything set only in the app that the user didn't supply.
267
+ Site themes and styles beyond accent, fonts, and mode; footer group titles and logo; page covers; page and update tags; adaptive content and visitor authentication; GitBook Assistant unless the user adds `ai.assistant`; hint icons you didn't keep; button styles and search/ask buttons; `<mark>` colors; `fullWidth` and column widths; non-YouTube embeds as players; dark card covers and theme-aware images; inline image sizing; `{% openapi-schemas %}` and GitBook `x-*` spec extensions; automatic redirects you couldn't recover; case-insensitive URLs; page-group icons; sidebar positions Blume can't match (parent pages among loose pages, `***` dividers, external links); section groups flattened into tabs; spaces and translations not in the repo; integrations with no adapter; site redirects nobody could export; anything set only in the app that the user didn't supply.
@@ -86,7 +86,7 @@ Wikis have no config: map what the repository and the special pages say.
86
86
  | An image at the top of `_Sidebar.md` | `logo`, with the file in `public/` |
87
87
  | External links in `_Sidebar.md` | `navigation.featured`: `convert` prints the array |
88
88
  | `_Footer.md` links | `footer.links` |
89
- | `_Footer.md` text | drop (report), or a `PageFooter` layout slot (`defineComponents`). A "contribute to this wiki" footer drops with its link: edit links replace it |
89
+ | `_Footer.md` text | a copyright or license line → `footer.copyright`, as plain text (Markdown stripped); other text → drop (report), or a `PageFooter` layout slot (`defineComponents`). A "contribute to this wiki" footer drops with its link: edit links replace it |
90
90
  | "edited this page … · N revisions" under each title | drop (report). `lastModified: "git"` would show the migration date on every converted page |
91
91
  | Wiki search, the Pages list, the per-page outline, the clone URL box | built in, or drop |
92
92
  | Site URL | none existed. Ask where the site deploys and set `deployment` (SKILL.md). GitHub Pages: https://useblume.dev/guides/markdown-docs-github-pages, with `deployment: { site: "https://<owner>.github.io", base: "/<repo>" }` for a project site |
@@ -256,4 +256,4 @@ An alert left in a `.md` page warns `BLUME_MD_GITHUB_ALERT`, and an unknown fenc
256
256
 
257
257
  ## Dropped — report these
258
258
 
259
- The Pages list and the clone box; footer text and its link; sidebar prose, images, anchor links, and duplicate entries; external sidebar links moved to `navigation.featured`; the per-page "edited … · N revisions" line; image sizes and wiki image options; images that were broken on GitHub; maps and 3D models; theme-aware image pairs; raw HTML GitHub had stripped; links to missing pages (GitHub's create-page links) and links that were already broken; shadowed link definitions; pages left out (mirror files, tests, fixtures, deprecated stubs) and moved notices mapped to their targets; pages GitHub never served (same-name shadows); non-Markdown pages converted with pandoc; wiki-UI links (history, revisions, `_pages`); and every old URL, which stays on github.com: say what you prepared for it (notice, stubs, or neither), which sync workflows must stop first, and that nothing redirects.
259
+ The Pages list and the clone box; footer text other than a copyright line, and its link; sidebar prose, images, anchor links, and duplicate entries; external sidebar links moved to `navigation.featured`; the per-page "edited … · N revisions" line; image sizes and wiki image options; images that were broken on GitHub; maps and 3D models; theme-aware image pairs; raw HTML GitHub had stripped; links to missing pages (GitHub's create-page links) and links that were already broken; shadowed link definitions; pages left out (mirror files, tests, fixtures, deprecated stubs) and moved notices mapped to their targets; pages GitHub never served (same-name shadows); non-Markdown pages converted with pandoc; wiki-UI links (history, revisions, `_pages`); and every old URL, which stays on github.com: say what you prepared for it (notice, stubs, or neither), which sync workflows must stop first, and that nothing redirects.
@@ -102,7 +102,7 @@ Apply `defaults:` (front matter defaults) to the pages in each `scope.path` that
102
102
  | `ga_tracking` | `googleAnalytics({ id })` from `blume/analytics`, one per `G-` id in the comma list. A `UA-` id no longer collects data: report it |
103
103
  | `gh_edit_link` + `gh_edit_repository` + `gh_edit_branch` | `github: { owner, repo, branch }`. `gh_edit_source: docs` → `github.dir: "docs"` when `blume.config.ts` sits there |
104
104
  | `last_edit_timestamp` | `lastModified: "frontmatter"` when pages set `last_modified_date` (the codemod maps it), else drop: JTD showed no date without it |
105
- | `footer_content` / `_includes/footer_custom.html` | links → `footer.links`, social links → `footer.socials`; copyright text → drop (report) or a `Footer` layout slot (`defineComponents`) |
105
+ | `footer_content` / `_includes/footer_custom.html` | links → `footer.links`, social links → `footer.socials`; copyright text → `footer.copyright`, plain text: strip the tags, decode entities (`&copy;` → `©`), and turn a Liquid year (`{{ "now" \| date: "%Y" }}`) into `${new Date().getFullYear()}` in a template literal; other text → drop (report) or a `Footer` layout slot (`defineComponents`) |
106
106
  | `callouts`, `heading_anchors`, `enable_copy_code_button`, `back_to_top*`, `nav_sort`, `nav_error_report`, `ga_tracking_anonymize_ip`, `gh_edit_link_text`, `gh_edit_view_mode` | drop (the codemod read `callouts`) |
107
107
 
108
108
  ## Navigation: front matter → folders and `meta.ts`
@@ -250,4 +250,4 @@ grep -rnE '\{:[ .#a-z:]|\{%|\{\{|^\*\[|^: |markdown="|<i class="fa|\.html[)#"]|\
250
250
 
251
251
  ## Dropped — report these
252
252
 
253
- Callout title labels that only named the type, unconfigured or malformed callout IALs left plain, the button and label styling the codemod dropped, `nav_external_links` moved above the sidebar, `back_to_top`, `footer_content`/copyright text, theme hooks, custom color schemes beyond the accent, `_sass` rules with no Blume target, content a CSS rule hid, site-wide code line numbers, deeper TOC levels, `UA-` analytics ids, `sitemap: false`, abbreviations, definition-list styling, Liquid logic and `_data` loops now frozen as content, embed widths, page scripts and widgets (sliders, accordions) not rebuilt, icon-font icons with no Lucide match, accidentally published files (`LICENSE`, `.bat`), and every plugin removed without an equivalent.
253
+ Callout title labels that only named the type, unconfigured or malformed callout IALs left plain, the button and label styling the codemod dropped, `nav_external_links` moved above the sidebar, `back_to_top`, other `footer_content` text and links inside the copyright, theme hooks, custom color schemes beyond the accent, `_sass` rules with no Blume target, content a CSS rule hid, site-wide code line numbers, deeper TOC levels, `UA-` analytics ids, `sitemap: false`, abbreviations, definition-list styling, Liquid logic and `_data` loops now frozen as content, embed widths, page scripts and widgets (sliders, accordions) not rebuilt, icon-font icons with no Lucide match, accidentally published files (`LICENSE`, `.bat`), and every plugin removed without an equivalent.
@@ -53,7 +53,7 @@ Map only what's set:
53
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
54
  | `repo_url` elsewhere (GitLab…) | no edit links; a header link → `navigation.actions` (report) |
55
55
  | `repo_name`, `site_author`, `site_dir`, `dev_addr`, `remote_*`, `watch`, `strict`, `validation` | drop |
56
- | `copyright` | drop (report), or a Footer layout slot (`defineComponents`) |
56
+ | `copyright` | `footer.copyright`, plain text: strip any HTML tags, decode entities (`&copy;` → `©`); a link inside it loses its URL (report, or add it to `footer.links`) |
57
57
  | `exclude_docs` | `content.exclude` — the list adds to the default `"**/_*"` and `"**/.*"`; `"!**/_*"` publishes `_` files |
58
58
  | `draft_docs` / `not_in_nav` | `draft: true` / `sidebar.hidden: true` on those pages |
59
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) |
@@ -233,4 +233,4 @@ grep -rnE '^\s*(!!!|\?\?\?\+?|===[+!]*) |^\s*/{3,} ?[a-z]|--8<--|\{ *[.#:][^}]*\
233
233
 
234
234
  ## Dropped — report these
235
235
 
236
- Template overrides and hooks with no slot equivalent, `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.
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.
@@ -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>`. Map them the same way; sidebar/TOC tuning mostly drops (Blume's `toc` config covers min/max heading levels).
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
 
@@ -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.
@@ -66,7 +66,7 @@ There's no config file in Git. Every page of a Refactored hub embeds the project
66
66
  | `integrations.intercom`, `zendesk` (a support widget readers click) | a `PageFooter` component (`defineComponents`, SKILL.md "analytics") that loads it | not `analytics`, which can hold it until consent. Check region settings (an AU Intercom workspace needs `api_base`) |
67
67
  | `integrations.google.site_verification`, `<meta>` tags in head HTML | `seo.metatags` | other head HTML: report |
68
68
  | `stylesheet_hub2` (custom CSS) | a root `theme.css` | rules for ReadMe's classes (`.rm-*`, `.callout_*`, hashed names) match nothing: carry only rules for the site's own markup |
69
- | Footer HTML | `footer: { links }` | report the rest |
69
+ | Footer HTML | `footer: { copyright, links }` | a copyright line → `copyright`, plain text: strip the tags, decode entities (`&copy;` → `©`). Report the rest |
70
70
  | `variables.defaults` | `variables` | Content. **Defaults can be real credentials** (an API key): never copy one into config |
71
71
  | `glossaryTerms` | `--glossary hub.html` | the codemod writes `<Tooltip>`s |
72
72
  | `redirects` | `redirects` | URLs and redirects |
@@ -36,7 +36,7 @@ Resolve `$ref`s first (`redirects: { $ref: ./redirects.yaml }` is common). Produ
36
36
  | `logo.image` / `logo.srcSet` (`"./l.svg light, ./d.svg dark"`), `altText`, `link` | `logo` / `logo: { image: { light, dark, alt }, href }` | move the files into `public/`; a wordmark also gets `text: ""` |
37
37
  | `logo.favicon` | **drop the field**: copy the file to `favicon.<ext>` or `icon.<ext>` in the root or `public/` | detected by filename, for `.svg`, `.png`, and `.ico` only: convert any other format |
38
38
  | `navbar.items` | `navigation.tabs` / `actions` / `cta` | see Navigation |
39
- | `footer.items` (columns, each a `{ group, items }` or a single item) | `footer.links` (one row) + `footer.socials` | flatten every column's items in order (`page` → its route). Links to a platform in Blume's `footer.socials` list (`docs/configuration/index.mdx`) become socials; a podcast (Spotify, Apple Podcasts) is `podcast`; others (TikTok) stay links. Column labels and `copyrightText` drop (report) |
39
+ | `footer.items` (columns, each a `{ group, items }` or a single item) | `footer.links` (one row) + `footer.socials` | flatten every column's items in order (`page` → its route). Links to a platform in Blume's `footer.socials` list (`docs/configuration/index.mdx`) become socials; a podcast (Spotify, Apple Podcasts) is `podcast`; others (TikTok) stay links. `copyrightText` → `footer.copyright`. Column labels drop (report) |
40
40
  | `redirects` (`'/from': { to, type }`) | `redirects: [{ from, to, status: type }]` | write `from` without a trailing slash; a trailing `/*` carries over as written (`{ from: "/a/*", to: "/b/*" }`), and also matches the bare `/a`. Blume takes 301/302/307/308 only |
41
41
  | `markdown.toc` | `toc: { maxHeadingLevel: <depth> }`, or `toc: false` for `hide` | Realm's default depth 3 is Blume's default |
42
42
  | `markdown.lastUpdatedBlock` | `lastModified: "git"`, **only when declared** and not `hide: true` | Realm shows "Last updated" by default; if the source left it at that, offer `lastModified: "git"` in the report. Either way, every page the migration edits (nearly all of them, since each H1 moves) shows the migration commit's date; a rename alone keeps the page's date. Say so |
@@ -195,4 +195,4 @@ Realm icons are Font Awesome names (`book`, `solid check-circle`, `brands github
195
195
 
196
196
  ## Dropped — report these
197
197
 
198
- Login, RBAC, and SSO (every protected path); Reunite's editor, reviews, previews, and feedback dashboard; the API explorer's mock server, environments, saved auth, and default CORS proxy (and which APIs now fail CORS); `x-tagGroups` names and the tags they hid; API tag and `section/` pages (redirected); sidebar separators and `expanded: always`; footer column labels and copyright; the ` - <title>` suffix now on every `<title>`; dropped frontmatter titles; `seo.image`/`jsonLd` and `llms.txt` sections; extra banners; search facets; resolved `if` branches and per-reader content; `code-snippet` ranges; the Markdoc tags with no equivalent; PlantUML/Excalidraw; light/dark image pairs; unmatched icons; ejected components and Realm CSS; a `UA-` analytics id; scripts that now load only in production; trailing-slash URLs; the accidental pages left out; reset "last updated" dates.
198
+ Login, RBAC, and SSO (every protected path); Reunite's editor, reviews, previews, and feedback dashboard; the API explorer's mock server, environments, saved auth, and default CORS proxy (and which APIs now fail CORS); `x-tagGroups` names and the tags they hid; API tag and `section/` pages (redirected); sidebar separators and `expanded: always`; footer column labels; the ` - <title>` suffix now on every `<title>`; dropped frontmatter titles; `seo.image`/`jsonLd` and `llms.txt` sections; extra banners; search facets; resolved `if` branches and per-reader content; `code-snippet` ranges; the Markdoc tags with no equivalent; PlantUML/Excalidraw; light/dark image pairs; unmatched icons; ejected components and Realm CSS; a `UA-` analytics id; scripts that now load only in production; trailing-slash URLs; the accidental pages left out; reset "last updated" dates.
@@ -69,7 +69,7 @@ Read the whole module and the helpers it imports (sidebars, nav, per-locale conf
69
69
  | `siteTitle: false` / a string | `logo: { image: …, text: "" }` / `logo.text` |
70
70
  | `nav`, `sidebar` | see the Navigation sections |
71
71
  | `socialLinks` | GitHub → `github: { owner, repo }` (it renders in the footer); known platforms → `footer.socials` (`twitter` → `x`; list under `footer` in `docs/configuration/index.mdx`); others, including custom `{ svg }` icons → `footer.links`, or drop (report) |
72
- | `footer` (`message`, `copyright`) | drop (report); `footer.links` takes `{ label, href }` |
72
+ | `footer` (`message`, `copyright`) | `copyright` → `footer.copyright`, plain text: strip the tags, decode entities (`&copy;` → `©`); a link inside it loses its URL (report, or add it to `footer.links`); a per-locale `copyright` → a locale map. `message` → drop (report); `footer.links` takes `{ label, href }` |
73
73
  | `editLink.pattern` (`…/edit/<branch>/<path>/:path`) | `github: { owner, repo, branch }`. `<path>` leads to the **srcDir**, but Blume builds edit links from the Blume project dir, so `github.dir` is `<path>` minus `content.root` (omit when empty). A non-`github.com` origin → `github.host` |
74
74
  | `lastUpdated.formatOptions` | its date fields → `dateFormat`; `text` → drop |
75
75
  | `search` | `local` → omit. **Algolia → omit `search`** (Blume's built-in Orama), remove the DocSearch deps, and report the `appId`/`indexName`. That index is almost always DocSearch's, filled by Algolia's crawler, and Blume's sync, given an admin key, replaces the whole index on every build: never point `algolia()` at it. `search: algolia({ appId, apiKey, indexName })` from `blume/search` is for a new index Blume owns, a separate opt-in |
@@ -201,4 +201,4 @@ The old URL list is `<old build>/**/*.html` (or the live `sitemap.xml`). Blume s
201
201
 
202
202
  ## Dropped — report these
203
203
 
204
- `titleTemplate`, footer text, forced `appearance`, per-page `outline`/`aside`, one-sided `prev`/`next`, page-level toggles (`editLink`, `footer`, `navbar`, `pageClass`), `head` entries beyond meta tags and analytics, build hooks, Vite and custom markdown-it plugins, unsupported social links, line-number offsets and the site-wide switch, snippet regions and include ranges (now split files), copied out-of-root snippets, data-driven and unregistered theme components (and any content they hid), `VPTeamMembers`, data loaders and dynamic routes, hero styling, the DocSearch index (with its credentials), old-site anchors that were already broken (and any left unpinned under `--only-linked`), version-dropdown links, and `::: note`/`important`/`caution` text that 1.x showed literally.
204
+ `titleTemplate`, the footer `message` (and any link inside `copyright`), forced `appearance`, per-page `outline`/`aside`, one-sided `prev`/`next`, page-level toggles (`editLink`, `footer`, `navbar`, `pageClass`), `head` entries beyond meta tags and analytics, build hooks, Vite and custom markdown-it plugins, unsupported social links, line-number offsets and the site-wide switch, snippet regions and include ranges (now split files), copied out-of-root snippets, data-driven and unregistered theme components (and any content they hid), `VPTeamMembers`, data loaders and dynamic routes, hero styling, the DocSearch index (with its credentials), old-site anchors that were already broken (and any left unpinned under `--only-linked`), version-dropdown links, and `::: note`/`important`/`caution` text that 1.x showed literally.
@@ -170,7 +170,7 @@ Rebuild it as in vitepress.md § "Home page (`layout: home`)": `index.mdx` with
170
170
  - v1: `heroImage`, `heroAlt`, `heroText` (it defaults to the site title, and `null` hides it), `tagline` (it defaults to the site description, and `null` hides it), `actionText` + `actionLink` (one button), `features: [{ title, details }]`, and `footer`. **v2:** `actions: [{ text, link, type }]` replaces the single action, and adds `heroImageDark`, `heroHeight`, and `footerHtml` (which renders `footer` as HTML).
171
171
  - `mode: custom` is full-bleed with no padding, so a hero image renders huge and flush left. Wrap the hero in a centered block (`<div style={{ maxWidth: "60rem", margin: "0 auto", padding: "3rem 1.5rem 0", textAlign: "center" }}>`, with blank lines inside so the Markdown renders) and cap the image (`style={{ maxHeight: "280px", margin: "0 auto" }}`). Add `sidebar.hidden: true` so the home page isn't a sidebar row.
172
172
  - Features have no icon or link: each becomes a `<Card title>` with `details` as the body, in a `<CardGroup cols={3}>`. Features written as raw HTML in the body (`<div class="features">`) map the same way.
173
- - `footer`, `footerHtml`, or a `::: slot footer` → drop (report), or move its links into `footer.links`. `heroImageDark` → Blume has no light/dark pair for a content image, so keep one (report).
173
+ - `footer` (HTML with **v2** `footerHtml: true`) or a `::: slot footer` is usually a copyright or license line ("MIT Licensed | Copyright © 2018-present …") → `footer.copyright`, plain text: strip the tags, decode entities (`&copy;` → `©`); move its links into `footer.links`, or they lose their URLs (report). A translated home page's `footer` → that locale's entry in a locale map. Other footer content → drop (report). `heroImageDark` → Blume has no light/dark pair for a content image, so keep one (report).
174
174
 
175
175
  ## Frontmatter
176
176
 
@@ -2323,7 +2323,7 @@ const siteNotes = (root, files, sidebarFile, layout) => {
2323
2323
  .split("\n")
2324
2324
  .slice(0, MAX_NOTICE_LINES);
2325
2325
  notes.push(
2326
- `${footer}: ${text.join(" / ")} (links → footer.links; a "contribute to this wiki" footer drops with its link)`
2326
+ `${footer}: ${text.join(" / ")} (links → footer.links; a copyright line → footer.copyright; a "contribute to this wiki" footer drops with its link)`
2327
2327
  );
2328
2328
  }
2329
2329
  return notes;
@@ -73,6 +73,7 @@ import { resolveFallbackLocale } from "../core/i18n.ts";
73
73
  import { buildIncludeGraph } from "../core/includes.ts";
74
74
  import { resolveLocalizable } from "../core/localizable.ts";
75
75
  import {
76
+ validateMcpClientIcons,
76
77
  validateNavTargets,
77
78
  validateSearchPopularIcons,
78
79
  } from "../core/nav-diagnostics.ts";
@@ -1028,7 +1029,9 @@ const resolveFooter = (
1028
1029
  ): ResolvedConfig["footer"] | null => {
1029
1030
  const { footer } = config;
1030
1031
  return footer &&
1031
- (footer.links.length > 0 || Object.keys(footer.socials).length > 0)
1032
+ (footer.copyright !== undefined ||
1033
+ footer.links.length > 0 ||
1034
+ Object.keys(footer.socials).length > 0)
1032
1035
  ? footer
1033
1036
  : null;
1034
1037
  };
@@ -1273,6 +1276,7 @@ export const buildRuntimeData = (project: BlumeProject): string => {
1273
1276
  logo,
1274
1277
  mcp: config.agents.mcp.enabled
1275
1278
  ? {
1279
+ clients: config.agents.mcp.clients,
1276
1280
  name: config.agents.mcp.name ?? config.title,
1277
1281
  route: config.agents.mcp.route,
1278
1282
  }
@@ -2437,10 +2441,10 @@ export const generateRuntime = async (
2437
2441
 
2438
2442
  // Missing-navigation-target check, now that every servable route is known
2439
2443
  // (see `navTargetRoutes`).
2440
- // Curated `search.popular` icons live outside the navigation model, so they
2441
- // miss `validateNavIcons` in the graph build — they're checked here too,
2442
- // where the search config is known. A typo otherwise just renders the
2443
- // default glyph.
2444
+ // Curated `search.popular` icons and custom MCP clients' icons live outside
2445
+ // the navigation model, so they miss `validateNavIcons` in the graph build —
2446
+ // they're checked here too, where their config is known. A typo otherwise
2447
+ // just renders the default glyph, or no icon at all.
2444
2448
  warnings.push(
2445
2449
  ...[
2446
2450
  ...validateNavTargets(
@@ -2449,6 +2453,12 @@ export const generateRuntime = async (
2449
2453
  servedFiles(project)
2450
2454
  ),
2451
2455
  ...validateSearchPopularIcons(config.search.popular),
2456
+ ...(config.agents.mcp.enabled
2457
+ ? validateMcpClientIcons(
2458
+ config.agents.mcp.clients,
2459
+ config.i18n?.defaultLocale
2460
+ )
2461
+ : []),
2452
2462
  ].map(diagnosticWarning)
2453
2463
  );
2454
2464
 
@@ -1244,9 +1244,9 @@ interface RateLimitTemplate {
1244
1244
  * `rateLimit` for one server route: a limiter built at module scope from the
1245
1245
  * configured adapter, checked against every request, keyed by the reader's
1246
1246
  * address and `scope` so each route keeps its own budget (see
1247
- * `ratelimit/runtime.ts`). Upstash reads its secrets through `getSecret`;
1248
- * Cloudflare's binding comes from the Worker's env. Nothing at all when
1249
- * rate limiting is off.
1247
+ * `ratelimit/runtime.ts`). An adapter that names secrets reads them through
1248
+ * `getSecret`; Cloudflare's binding comes from the Worker's env. Nothing at
1249
+ * all when rate limiting is off.
1250
1250
  */
1251
1251
  export const rateLimitTemplate = (
1252
1252
  adapter: RateLimitAdapter | null | undefined,
@@ -1259,7 +1259,7 @@ export const rateLimitTemplate = (
1259
1259
  'import { createLimiter, rateLimited } from "blume/ratelimit/runtime.ts";',
1260
1260
  ];
1261
1261
  let runtime = "";
1262
- if (adapter.kind === "upstash") {
1262
+ if (adapter.requiredSecrets.length > 0) {
1263
1263
  imports.push('import { getSecret } from "astro:env/server";');
1264
1264
  runtime = ", { secret: getSecret }";
1265
1265
  } else if (adapter.kind === "cloudflare") {
@@ -45,7 +45,6 @@ const adapterSecretOwners = (config: ResolvedConfig): SecretOwner[] => {
45
45
  secrets: consent.requiredSecrets,
46
46
  });
47
47
  }
48
- // Upstash's endpoint and token.
49
48
  if (rateLimit) {
50
49
  owners.push({
51
50
  feature: `Rate limiting (${rateLimit.kind})`,