blume 0.6.7 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (211) hide show
  1. package/CHANGELOG.md +618 -0
  2. package/LICENSE +21 -0
  3. package/README.md +107 -0
  4. package/dist/cli/index.js +2609 -1041
  5. package/dist/cli/index.js.map +110 -103
  6. package/dist/types/ai/component-markdown.d.ts +34 -0
  7. package/dist/types/components/content/youtube.d.ts +18 -0
  8. package/dist/types/core/base-path.d.ts +47 -0
  9. package/dist/types/core/config-input.d.ts +110 -12
  10. package/dist/types/core/config.d.ts +6 -4
  11. package/dist/types/core/data.d.ts +4 -0
  12. package/dist/types/core/i18n-ui.d.ts +477 -135
  13. package/dist/types/core/schema.d.ts +309 -195
  14. package/dist/types/core/sources/types.d.ts +2 -0
  15. package/dist/types/core/types.d.ts +6 -1
  16. package/dist/types/index.d.ts +1 -0
  17. package/dist/types/openapi/references.d.ts +60 -0
  18. package/docs/01-quickstart.mdx +5 -2
  19. package/docs/02-deployment.mdx +24 -9
  20. package/docs/03-faq.mdx +46 -16
  21. package/docs/advanced/custom-pages.mdx +1 -1
  22. package/docs/advanced/skills.mdx +1 -1
  23. package/docs/configuration/ai.mdx +49 -10
  24. package/docs/configuration/customization.mdx +11 -0
  25. package/docs/configuration/index.mdx +33 -3
  26. package/docs/configuration/seo.mdx +2 -2
  27. package/docs/content/components.mdx +30 -3
  28. package/docs/content/i18n.mdx +1 -1
  29. package/docs/content/islands.mdx +8 -0
  30. package/docs/content/navigation.mdx +3 -3
  31. package/docs/content/sources.mdx +1 -1
  32. package/docs/content/syntax.mdx +17 -2
  33. package/docs/index.mdx +2 -2
  34. package/docs/reference/cli.mdx +8 -6
  35. package/package.json +15 -4
  36. package/skills/blume/SKILL.md +5 -3
  37. package/skills/blume-update-docs/SKILL.md +3 -2
  38. package/src/ai/agent-readability.ts +11 -5
  39. package/src/ai/ask-context.ts +7 -2
  40. package/src/ai/ask-data.ts +3 -0
  41. package/src/ai/ask.ts +12 -7
  42. package/src/ai/component-markdown.ts +461 -0
  43. package/src/ai/llms.ts +143 -23
  44. package/src/ai/markdown.ts +35 -6
  45. package/src/ai/mcp/data.ts +33 -8
  46. package/src/ai/mcp/discovery.ts +10 -3
  47. package/src/ai/mcp/server.ts +24 -7
  48. package/src/ai/visibility.ts +74 -0
  49. package/src/astro/component-slots.ts +16 -4
  50. package/src/astro/examples.ts +12 -7
  51. package/src/astro/generate.ts +393 -189
  52. package/src/astro/index.ts +5 -1
  53. package/src/astro/integration.ts +9 -5
  54. package/src/astro/islands.ts +11 -5
  55. package/src/astro/markdown-negotiation.ts +2 -2
  56. package/src/astro/pages.ts +89 -22
  57. package/src/astro/templates.ts +259 -25
  58. package/src/blume-modules.d.ts +8 -0
  59. package/src/cli/commands/build.ts +131 -38
  60. package/src/cli/commands/check.ts +1 -1
  61. package/src/cli/commands/dev.ts +71 -17
  62. package/src/cli/commands/doctor.ts +2 -2
  63. package/src/cli/commands/eject.ts +47 -19
  64. package/src/cli/commands/init.ts +120 -180
  65. package/src/cli/commands/preview.ts +4 -1
  66. package/src/cli/commands/validate.ts +44 -2
  67. package/src/cli/dev-lock.ts +34 -19
  68. package/src/cli/eject-scripts.ts +72 -0
  69. package/src/cli/env.ts +15 -5
  70. package/src/cli/init/questions.ts +158 -0
  71. package/src/cli/init/scaffold.ts +380 -0
  72. package/src/cli/required-secrets.ts +2 -1
  73. package/src/components/content/AccordionItem.astro +23 -4
  74. package/src/components/content/Badge.astro +3 -1
  75. package/src/components/content/Card.astro +4 -2
  76. package/src/components/content/CodeBlock.astro +3 -0
  77. package/src/components/content/Component.astro +30 -16
  78. package/src/components/content/Diff.astro +3 -1
  79. package/src/components/content/Step.astro +10 -1
  80. package/src/components/content/Tabs.astro +15 -3
  81. package/src/components/content/Tile.astro +2 -1
  82. package/src/components/content/Tooltip.astro +3 -1
  83. package/src/components/content/Update.astro +9 -2
  84. package/src/components/content/auto-type-table.ts +25 -9
  85. package/src/components/content/base-href.ts +33 -0
  86. package/src/components/content/changelog-element.ts +9 -2
  87. package/src/components/content/diff.ts +12 -6
  88. package/src/components/content/mermaid-element.ts +10 -2
  89. package/src/components/index.ts +23 -1
  90. package/src/components/islands/AskAI.astro +5 -2
  91. package/src/components/islands/ask-ai.tsx +68 -12
  92. package/src/components/islands/base-path.ts +28 -0
  93. package/src/components/islands/hooks.ts +44 -9
  94. package/src/components/layout/Banner.astro +12 -3
  95. package/src/components/layout/Breadcrumbs.astro +2 -1
  96. package/src/components/layout/Favicon.astro +3 -2
  97. package/src/components/layout/Header.astro +15 -5
  98. package/src/components/layout/LanguageSwitcher.astro +2 -1
  99. package/src/components/layout/Logo.astro +13 -4
  100. package/src/components/layout/NavSelector.astro +2 -1
  101. package/src/components/layout/NavTree.astro +22 -7
  102. package/src/components/layout/PageActions.astro +25 -10
  103. package/src/components/layout/PageFeedback.astro +4 -1
  104. package/src/components/layout/PageLayout.astro +51 -9
  105. package/src/components/layout/Pagination.astro +3 -2
  106. package/src/components/layout/ReferenceLayout.astro +8 -1
  107. package/src/components/layout/RootLayout.astro +74 -13
  108. package/src/components/layout/Search.astro +107 -27
  109. package/src/components/layout/nav-utils.ts +18 -10
  110. package/src/components/layout/search/algolia.ts +11 -2
  111. package/src/components/layout/search/endpoint.ts +11 -5
  112. package/src/components/layout/search/orama-cloud.ts +8 -2
  113. package/src/components/layout/search/pagefind.ts +3 -0
  114. package/src/components/layout/search/types.ts +5 -1
  115. package/src/components/layout/search/typesense.ts +4 -1
  116. package/src/components/layout/toc-element.ts +8 -2
  117. package/src/components/openapi/ApiTagOperations.astro +2 -1
  118. package/src/components/openapi/Operation.astro +47 -40
  119. package/src/components/openapi/RequestPanel.astro +8 -2
  120. package/src/components/openapi/helpers.ts +71 -3
  121. package/src/components/openapi/panel.ts +1 -1
  122. package/src/components/openapi/snippets.ts +25 -11
  123. package/src/core/base-path.ts +94 -0
  124. package/src/core/builtin-tags.ts +2 -0
  125. package/src/core/component-overrides.ts +103 -74
  126. package/src/core/config-input.ts +118 -17
  127. package/src/core/config.ts +8 -5
  128. package/src/core/content.ts +2 -0
  129. package/src/core/data.ts +4 -0
  130. package/src/core/diagnostics.ts +54 -34
  131. package/src/core/gitignore.ts +4 -1
  132. package/src/core/graph.ts +166 -88
  133. package/src/core/i18n-ui.ts +63 -3
  134. package/src/core/last-modified.ts +15 -6
  135. package/src/core/links.ts +69 -25
  136. package/src/core/manifest.ts +62 -45
  137. package/src/core/nav-diagnostics.ts +1 -1
  138. package/src/core/navigation.ts +144 -58
  139. package/src/core/package-json.ts +17 -2
  140. package/src/core/project-graph.ts +25 -15
  141. package/src/core/schema.ts +605 -620
  142. package/src/core/sources/assets.ts +6 -1
  143. package/src/core/sources/filesystem.ts +4 -0
  144. package/src/core/sources/github-releases.ts +2 -1
  145. package/src/core/sources/mdx-remote.ts +76 -63
  146. package/src/core/sources/normalize.ts +236 -91
  147. package/src/core/sources/notion.ts +27 -18
  148. package/src/core/sources/types.ts +2 -0
  149. package/src/core/tsconfig-aliases.ts +59 -30
  150. package/src/core/types.ts +6 -1
  151. package/src/core/ui-packs/ar.ts +1 -0
  152. package/src/core/ui-packs/bg.ts +1 -0
  153. package/src/core/ui-packs/bn.ts +1 -0
  154. package/src/core/ui-packs/ca.ts +1 -0
  155. package/src/core/ui-packs/cs.ts +1 -0
  156. package/src/core/ui-packs/da.ts +1 -0
  157. package/src/core/ui-packs/de.ts +1 -0
  158. package/src/core/ui-packs/el.ts +1 -0
  159. package/src/core/ui-packs/es.ts +1 -0
  160. package/src/core/ui-packs/fa.ts +1 -0
  161. package/src/core/ui-packs/fi.ts +1 -0
  162. package/src/core/ui-packs/fr.ts +2 -1
  163. package/src/core/ui-packs/he.ts +1 -0
  164. package/src/core/ui-packs/hi.ts +1 -0
  165. package/src/core/ui-packs/hr.ts +1 -0
  166. package/src/core/ui-packs/hu.ts +1 -0
  167. package/src/core/ui-packs/id.ts +1 -0
  168. package/src/core/ui-packs/it.ts +1 -0
  169. package/src/core/ui-packs/ja.ts +1 -0
  170. package/src/core/ui-packs/ko.ts +1 -0
  171. package/src/core/ui-packs/nl.ts +1 -0
  172. package/src/core/ui-packs/no.ts +1 -0
  173. package/src/core/ui-packs/pl.ts +1 -0
  174. package/src/core/ui-packs/pt-br.ts +1 -0
  175. package/src/core/ui-packs/pt.ts +1 -0
  176. package/src/core/ui-packs/ro.ts +1 -0
  177. package/src/core/ui-packs/ru.ts +1 -0
  178. package/src/core/ui-packs/sk.ts +1 -0
  179. package/src/core/ui-packs/sr.ts +1 -0
  180. package/src/core/ui-packs/sv.ts +1 -0
  181. package/src/core/ui-packs/th.ts +1 -0
  182. package/src/core/ui-packs/tr.ts +1 -0
  183. package/src/core/ui-packs/uk.ts +1 -0
  184. package/src/core/ui-packs/vi.ts +1 -0
  185. package/src/core/ui-packs/zh-tw.ts +1 -0
  186. package/src/core/ui-packs/zh.ts +1 -0
  187. package/src/deploy/adapter-output.ts +18 -8
  188. package/src/deploy/redirects.ts +25 -2
  189. package/src/deploy/robots.ts +6 -1
  190. package/src/deploy/rss.ts +10 -3
  191. package/src/deploy/sitemap.ts +59 -13
  192. package/src/index.ts +5 -0
  193. package/src/markdown/base-links.ts +60 -0
  194. package/src/markdown/code-title.ts +11 -14
  195. package/src/markdown/index.ts +46 -9
  196. package/src/markdown/inline-code.ts +14 -4
  197. package/src/markdown/package-commands.ts +10 -4
  198. package/src/markdown/themes.ts +24 -0
  199. package/src/openapi/model.ts +15 -5
  200. package/src/openapi/parse.ts +21 -0
  201. package/src/openapi/references.ts +75 -21
  202. package/src/openapi/render-mdx.ts +11 -6
  203. package/src/openapi/scalar.ts +32 -16
  204. package/src/openapi/source.ts +59 -10
  205. package/src/registry/eject.ts +247 -19
  206. package/src/registry/registry.ts +0 -3
  207. package/src/search/build.ts +3 -0
  208. package/src/search/documents.ts +36 -4
  209. package/src/search/sync/typesense.ts +6 -4
  210. package/src/seo/jsonld.ts +28 -17
  211. package/src/theme/entry.ts +85 -20
@@ -159,7 +159,7 @@ Two flags control how remote content is fetched and what's included:
159
159
  blume dev --preview # author workflow: see drafts live
160
160
  blume build --preview # render a full preview build
161
161
  blume sync # refresh remote content now
162
- blume sync --force # ...ignoring any cached snapshot
162
+ blume sync --force # ...ignoring any cached snapshot
163
163
  ```
164
164
 
165
165
  ## Custom sources
@@ -33,6 +33,7 @@ For footnote markers, ordinals, and scientific or chemical notation inline.
33
33
 
34
34
  E = mc^2^ and H~2~O.
35
35
 
36
+ {/* prettier-ignore */}
36
37
  ```md
37
38
  E = mc^2^ and H~2~O.
38
39
  ```
@@ -141,6 +142,18 @@ export default defineConfig({
141
142
 
142
143
  Inline code can be highlighted too: add a `{:lang}` marker inside a backtick span and it's colored like a tiny code block — `useState(){:js}` or `T extends object{:ts}`. It only kicks in when you add the marker, so plain inline code stays untouched — nothing to switch on.
143
144
 
145
+ Highlighting uses the `github-light`/`github-dark` themes by default. Swap in any [bundled Shiki theme](https://shiki.style/themes) per color mode with `markdown.codeBlocks.theme` — it colors every code surface at once (fences, inline snippets, `<CodeBlock>`, and `<Diff>`):
146
+
147
+ ```ts blume.config.ts
148
+ export default defineConfig({
149
+ markdown: {
150
+ codeBlocks: {
151
+ theme: { light: "github-light", dark: "vesper" },
152
+ },
153
+ },
154
+ });
155
+ ```
156
+
144
157
  ### Line numbers
145
158
 
146
159
  Append `lineNumbers` to render a line-number gutter — on its own or alongside a title:
@@ -332,11 +345,13 @@ Your docs built successfully and are ready to deploy.
332
345
 
333
346
  Flag something that needs care to avoid a mistake or surprising behavior.
334
347
 
335
- :::warning[Heads up] Switching to `output: "server"` requires an adapter before you can deploy.
348
+ :::warning[Heads up]
349
+ Switching to `output: "server"` requires an adapter before you can deploy.
336
350
  :::
337
351
 
338
352
  ```md
339
- :::warning[Heads up] Switching to `output: "server"` requires an adapter before you can deploy.
353
+ :::warning[Heads up]
354
+ Switching to `output: "server"` requires an adapter before you can deploy.
340
355
  :::
341
356
  ```
342
357
 
package/docs/index.mdx CHANGED
@@ -19,9 +19,9 @@ Drop Markdown or MDX into a folder, run `blume dev`, and get a production-grade
19
19
 
20
20
  ## Why Blume exists
21
21
 
22
- Docs should be fast, AI-ready and require zero configuration — down to not needing a starter template at all. Some docs tools hand you an entire codebase to maintain before you've written a word. Others build the template around your content, but lock you in to their managed service.
22
+ Docs should be fast, AI-ready, and zero-config — down to not needing a starter template at all. Some docs tools hand you an entire codebase to maintain before you've written a word. Others build the template around your content, but lock you in to their managed service.
23
23
 
24
- Blume takes the best of both worlds. The framework is the template, so the only thing you ever touch is your content. When you want to customize, you can start replacing the built-in components, modifying the single configuration file or even ejecting if you want the Astro site directly.
24
+ Blume takes the best of both worlds. The framework is the template, so the only thing you ever touch is your content. When you want to customize, you can start by replacing the built-in components, modifying the single configuration file, or even ejecting if you want the Astro site directly.
25
25
 
26
26
  ## What makes Blume different
27
27
 
@@ -11,7 +11,7 @@ blume <command> [options]
11
11
 
12
12
  | Command | Description |
13
13
  | ------------------ | ------------------------------------------------ |
14
- | `blume init` | Scaffold a minimal project. |
14
+ | `blume init [dir]` | Scaffold a project (interactive by default). |
15
15
  | `blume dev` | Start the dev server with hot reload. |
16
16
  | `blume build` | Build the static (or server) site. |
17
17
  | `blume preview` | Preview the last build. |
@@ -24,7 +24,9 @@ blume <command> [options]
24
24
 
25
25
  ## Common flags
26
26
 
27
- - `blume init --content-dir <dir> --yes` set the content folder (default `docs`) and skip prompts.
27
+ - `blume init` in a terminal, walks you through a few questions (where to create the project, site name, template, content sources); each flag below pre-answers its question.
28
+ - `blume init --yes` — skip the prompts and scaffold with defaults (also the behavior in CI or when stdin isn't a terminal).
29
+ - `blume init --content-dir <dir>` — set the content folder (default `docs`).
28
30
  - `blume init --template docs|api|sdk|changelog` — scaffold from a starter (API reference, SDK, or changelog instead of the plain docs seed).
29
31
  - `blume init --package-manager npm|pnpm|yarn|bun` — tailor the printed next-steps to your package manager.
30
32
  - `blume init --eject` — scaffold, then eject to a standalone Astro project (falls back to guiding you through `blume eject` when dependencies aren't installed yet).
@@ -53,9 +55,9 @@ blume <command> [options]
53
55
  `blume dev` serves a live Astro server rooted at the generated `.blume/` runtime and regenerates it on every change. `blume build` and `blume check` regenerate the _same_ `.blume/`, so running either while the dev server is live would corrupt it — both refuse with an error and exit non-zero:
54
56
 
55
57
  ```
56
- A `blume dev` server is running against .blume; building would corrupt it.
57
- Stop the dev server, or re-run with --isolated to build/verify against
58
- .blume-verify without touching it.
58
+ A `blume dev` server is running at http://localhost:3000; building would
59
+ corrupt its .blume runtime. Reuse that server, stop it first, or re-run with
60
+ --isolated to build/verify against .blume-verify without touching it.
59
61
  ```
60
62
 
61
63
  The `--isolated` flag is the escape hatch. It relocates the entire generated runtime (and, for `build`, its output `dist/`) to a sibling `.blume-verify/` directory, so the verification never writes anything the dev server — or your real `dist/` — depends on:
@@ -66,7 +68,7 @@ blume check --isolated # fast: type-check the .astro/config changes
66
68
  blume build --isolated # thorough: full production render into .blume-verify/dist
67
69
  ```
68
70
 
69
- `check --isolated` is the quick path (Astro type + template diagnostics, no `dist/`); `build --isolated` is the heavier one that also catches runtime render errors. Isolated builds skip the deploy post-steps (search index, hosted-provider sync, `llms.txt`, sitemap/robots, redirects) — a verify only needs to confirm the site compiles and renders, not publish it. Blume adds `.blume-verify/` to your `.gitignore` automatically.
71
+ `check --isolated` is the quick path (Astro type + template diagnostics, no `dist/`); `build --isolated` is the heavier one that also catches runtime render errors. Isolated builds skip the deploy post-steps (search index, hosted-provider sync, `llms.txt`, sitemap/robots, redirects) — a verify only needs to confirm the site compiles and renders, not publish it. `--analyze` and the `--budget-js`/`--budget-css` gates still run, measured against the isolated output. Blume adds `.blume-verify/` to your `.gitignore` automatically.
70
72
 
71
73
  This is especially useful when a coding agent needs to verify changes while you keep the dev server open. To make plain `blume build`/`blume check` isolate without the flag — for example in an agent's shell — set `BLUME_RUNTIME_DIR` to the runtime directory to use:
72
74
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blume",
3
- "version": "0.6.7",
3
+ "version": "0.8.0",
4
4
  "description": "Documentation that's fast, AI-ready, and zero-config.",
5
5
  "keywords": [
6
6
  "astro",
@@ -29,7 +29,8 @@
29
29
  "src",
30
30
  "bin",
31
31
  "docs",
32
- "skills"
32
+ "skills",
33
+ "CHANGELOG.md"
33
34
  ],
34
35
  "type": "module",
35
36
  "types": "./dist/types/index.d.ts",
@@ -71,6 +72,7 @@
71
72
  "@astrojs/node": "^11.0.0",
72
73
  "@astrojs/react": "^6.0.0",
73
74
  "@astrojs/vercel": "^11.0.0",
75
+ "@clack/prompts": "^1.7.0",
74
76
  "@iconify-json/lucide": "^1.2.115",
75
77
  "@iconify/types": "^2.0.0",
76
78
  "@iconify/utils": "^3.1.3",
@@ -89,9 +91,9 @@
89
91
  "@vercel/analytics": "^2.0.1",
90
92
  "ai": "^5.0.0",
91
93
  "astro": "^7.0.2",
94
+ "babel-plugin-react-compiler": "^1.0.0",
92
95
  "citty": "^0.1.6",
93
96
  "consola": "^3.4.0",
94
- "deepmerge": "^4.3.1",
95
97
  "dompurify": "^3.4.11",
96
98
  "epub-gen-memory": "^1.1.2",
97
99
  "github-slugger": "^2.0.0",
@@ -105,11 +107,12 @@
105
107
  "pathe": "^2.0.0",
106
108
  "react": "^19.0.0",
107
109
  "react-dom": "^19.0.0",
110
+ "satteri": "^0.9.5",
108
111
  "shiki": "^4.2.0",
109
112
  "simple-icons": "^13.0.0",
110
113
  "tailwindcss": "^4",
111
114
  "tinyglobby": "^0.2.10",
112
- "typescript": "^5.7.0",
115
+ "typescript": "^6.0.3",
113
116
  "undici": "^8.6.0",
114
117
  "zod": "^3.24.0"
115
118
  },
@@ -123,6 +126,8 @@
123
126
  },
124
127
  "peerDependencies": {
125
128
  "@ai-sdk/openai-compatible": "^1.0.41",
129
+ "@astrojs/cloudflare": "^14.0.0",
130
+ "@astrojs/netlify": "^8.0.0",
126
131
  "@mixedbread/sdk": "^0.76.0",
127
132
  "@notionhq/client": "^2.2.15",
128
133
  "@openrouter/ai-sdk-provider": "^1.5.4",
@@ -136,6 +141,12 @@
136
141
  "@ai-sdk/openai-compatible": {
137
142
  "optional": true
138
143
  },
144
+ "@astrojs/cloudflare": {
145
+ "optional": true
146
+ },
147
+ "@astrojs/netlify": {
148
+ "optional": true
149
+ },
139
150
  "@mixedbread/sdk": {
140
151
  "optional": true
141
152
  },
@@ -18,7 +18,7 @@ The core idea: **the framework _is_ the template.** There's no starter to clone
18
18
 
19
19
  ## Quickstart
20
20
 
21
- Blume needs **Node.js 22 or newer**. From an empty or existing project:
21
+ Blume needs **Node.js 22.12 or newer**. From an empty or existing project:
22
22
 
23
23
  ```bash
24
24
  npm i blume # install the package
@@ -41,7 +41,9 @@ description: Welcome to my docs.
41
41
 
42
42
  Welcome! Use **Markdown** and built-in components — no imports required:
43
43
 
44
- :::note Blume ships callouts, cards, tabs, steps, and more. :::
44
+ :::note
45
+ Blume ships callouts, cards, tabs, steps, and more.
46
+ :::
45
47
  ```
46
48
 
47
49
  Navigation, search, and page metadata are inferred from your files as you add them.
@@ -50,7 +52,7 @@ Navigation, search, and page metadata are inferred from your files as you add th
50
52
 
51
53
  - **Components** — callouts, cards, steps, tabs, accordions, badges, file trees, and parameter tables, usable in MDX with no imports.
52
54
  - **Local search** — Orama in dev and production; Pagefind is one flag away for large sites. No hosted index.
53
- - **AI** — `llms.txt`, raw Markdown URLs, Copy as Markdown, Open in chat, an Ask AI assistant, and a hosted MCP server.
55
+ - **AI** — `llms.txt`, raw Markdown URLs, Copy as Markdown, Open in chat, an Ask AI assistant, and an MCP server endpoint served by the docs site itself.
54
56
  - **Navigation** — inferred from files, refined with `meta.ts` or config.
55
57
  - **SEO** — metadata, Open Graph images, RSS feeds, and JSON-LD.
56
58
  - **Customization** — component overrides, React islands, custom pages, theme tokens, and a source-component registry via `blume add`.
@@ -5,7 +5,7 @@ description: Keep a Blume docs site in sync with the product it documents. Audit
5
5
 
6
6
  # Update Blume Docs
7
7
 
8
- Blume is a **markdown-first** documentation framework on Astro/Vite: content lives as Markdown/MDX under a content root (default `docs/`), navigation derives from the file tree plus optional `meta.ts` files, and `blume build` validates links, anchors, frontmatter, and routes.
8
+ Blume is a **markdown-first** documentation framework on Astro/Vite: content lives as Markdown/MDX under a content root (default `docs/`), navigation derives from the file tree plus optional `meta.ts` files, `blume build` validates frontmatter and duplicate routes, and `blume validate` checks links and anchors.
9
9
 
10
10
  Your job is **docs maintenance, not docs authorship**: find where shipped, user-facing behavior has drifted from what the docs claim, fix exactly that, prove the site still builds, and deliver the result as a pull request. A run that finds nothing actionable ends with a short report and **no branch, no commit, no PR** — prefer a no-op over a noisy PR.
11
11
 
@@ -39,7 +39,8 @@ Your job is **docs maintenance, not docs authorship**: find where shipped, user-
39
39
  - Match the surrounding pages: frontmatter shape, Blume components already in use, code-fence style, root-relative internal links.
40
40
 
41
41
  5. **Verify.**
42
- - Run the docs build (`blume build` or the repo's documented docs QA) — it validates links, anchors, frontmatter, and duplicate routes.
42
+ - Run the docs build (`blume build` or the repo's documented docs QA) — it validates frontmatter and duplicate routes.
43
+ - Run `blume validate` to check internal links and anchors.
43
44
  - Run lint/format/typecheck when the repo's conventions call for them on docs changes.
44
45
  - Fix failures your edits caused; report pre-existing failures separately instead of fixing them in this PR.
45
46
 
@@ -1,3 +1,4 @@
1
+ import { normalizeBasePath, withBasePath } from "../core/base-path.ts";
1
2
  import type { BlumeProject } from "../core/project-graph.ts";
2
3
  import type { ContentSignalPolicy, ContentSignals } from "../core/schema.ts";
3
4
  import { buildRssFeeds } from "../deploy/rss.ts";
@@ -31,7 +32,8 @@ const usagePolicy = (
31
32
  * agent-facing surface — llms.txt, the raw-Markdown mirrors, the MCP server,
32
33
  * Ask AI, sitemap, and feeds — so agents can discover and cite the docs without
33
34
  * scraping HTML. URLs are absolute when a `site` is configured and root-relative
34
- * otherwise. Returns null when the manifest is disabled.
35
+ * (still under `deployment.base`) otherwise. Returns null when the manifest is
36
+ * disabled.
35
37
  */
36
38
  export const buildAgentReadability = (
37
39
  project: BlumeProject
@@ -42,9 +44,13 @@ export const buildAgentReadability = (
42
44
  }
43
45
 
44
46
  const site = config.deployment.site ?? null;
45
- // Concatenate rather than `new URL()` so a subpath deployment's base is kept.
46
- const abs = (path: string): string =>
47
- site ? `${site.replace(/\/+$/u, "")}${path}` : path;
47
+ // Every artifact is served under `deployment.base` with or without a
48
+ // `site`; concatenate rather than `new URL()` so the subpath is preserved.
49
+ const deployBase = normalizeBasePath(config.deployment.base);
50
+ const abs = (path: string): string => {
51
+ const based = withBasePath(deployBase, path);
52
+ return site ? `${site.replace(/\/+$/u, "")}${based}` : based;
53
+ };
48
54
 
49
55
  const artifacts: Record<string, unknown> = {
50
56
  markdown: {
@@ -52,7 +58,7 @@ export const buildAgentReadability = (
52
58
  pattern: abs("/{route}.md"),
53
59
  },
54
60
  };
55
- if (config.ai.llmsTxt) {
61
+ if (config.ai.llmsTxt.enabled) {
56
62
  artifacts.llmsFullTxt = abs("/llms-full.txt");
57
63
  artifacts.llmsTxt = abs("/llms.txt");
58
64
  }
@@ -124,8 +124,9 @@ const lastUserMessage = (messages: AskMessage[]): string => {
124
124
  * where "How does Ask AI work?" retrieves the right page but only sees its
125
125
  * opening paragraph. This centers the window on the densest cluster of query
126
126
  * terms so the injected text is the part that actually answers the question.
127
+ * Exported for testing; {@link createAskContext} is the runtime entry point.
127
128
  */
128
- const relevantExcerpt = (
129
+ export const relevantExcerpt = (
129
130
  content: string,
130
131
  query: string,
131
132
  max: number
@@ -177,7 +178,11 @@ const relevantExcerpt = (
177
178
  best = start;
178
179
  }
179
180
  }
180
- return withEllipsis(Math.max(0, best - EXCERPT_LEAD));
181
+ // Cap the lead-in at half the window: under a tight remaining budget `max`
182
+ // can be smaller than EXCERPT_LEAD, and an uncapped `best - EXCERPT_LEAD`
183
+ // start would end the slice before the very match it centered on.
184
+ const lead = Math.min(EXCERPT_LEAD, Math.floor(max / 2));
185
+ return withEllipsis(Math.max(0, best - lead));
181
186
  };
182
187
 
183
188
  /**
@@ -9,9 +9,12 @@ import type { AskData } from "./ask-context.ts";
9
9
  * MCP snapshot) so retrieval can be filtered to the current page's language, and
10
10
  * content is kept as Markdown so grounding sees fenced code examples — the model
11
11
  * answers "what does the config look like?" from the docs instead of declining.
12
+ * The reader is an AI agent, so `<Visibility>` resolves for the agents audience
13
+ * (web-only content removed, agents-only unwrapped), matching llms-full.txt.
12
14
  */
13
15
  export const buildAskData = async (project: BlumeProject): Promise<AskData> => {
14
16
  const documents = await buildSearchDocuments(project, {
17
+ audience: "agents",
15
18
  content: "markdown",
16
19
  includeWhenDisabled: true,
17
20
  });
package/src/ai/ask.ts CHANGED
@@ -30,20 +30,25 @@ interface AskPreset {
30
30
  * dedicated AI SDK provider; LLMGateway and Inkeep are OpenAI-compatible
31
31
  * endpoints with no dedicated provider, so they reuse `@ai-sdk/openai-compatible`.
32
32
  */
33
+ /** The discriminant/name shared by the OpenAI-compatible providers. */
34
+ const OPENAI_COMPATIBLE = "openai-compatible";
35
+ /** The AI SDK provider package the OpenAI-compatible providers install. */
36
+ const OPENAI_COMPATIBLE_DEP = "@ai-sdk/openai-compatible";
37
+
33
38
  const ASK_PRESETS: Record<string, AskPreset> = {
34
39
  inkeep: {
35
40
  apiKeyEnv: "INKEEP_API_KEY",
36
41
  baseUrl: "https://api.inkeep.com/v1",
37
- kind: "openai-compatible",
42
+ kind: OPENAI_COMPATIBLE,
38
43
  name: "inkeep",
39
- runtimeDep: "@ai-sdk/openai-compatible",
44
+ runtimeDep: OPENAI_COMPATIBLE_DEP,
40
45
  },
41
46
  llmgateway: {
42
47
  apiKeyEnv: "LLMGATEWAY_API_KEY",
43
48
  baseUrl: "https://api.llmgateway.io/v1",
44
- kind: "openai-compatible",
49
+ kind: OPENAI_COMPATIBLE,
45
50
  name: "llmgateway",
46
- runtimeDep: "@ai-sdk/openai-compatible",
51
+ runtimeDep: OPENAI_COMPATIBLE_DEP,
47
52
  },
48
53
  openrouter: {
49
54
  apiKeyEnv: "OPENROUTER_API_KEY",
@@ -73,9 +78,9 @@ export const resolveAskBackend = (ask?: AskAiConfig): AskBackend => {
73
78
  return {
74
79
  apiKeyEnv,
75
80
  baseUrl: ask?.baseUrl ?? preset?.baseUrl ?? "",
76
- kind: "openai-compatible",
81
+ kind: OPENAI_COMPATIBLE,
77
82
  model,
78
- name: preset?.name ?? "openai-compatible",
83
+ name: preset?.name ?? OPENAI_COMPATIBLE,
79
84
  };
80
85
  };
81
86
 
@@ -89,5 +94,5 @@ export const askBackendRuntimeDep = (ask?: AskAiConfig): string | undefined => {
89
94
  if (provider === "gateway") {
90
95
  return undefined;
91
96
  }
92
- return ASK_PRESETS[provider]?.runtimeDep ?? "@ai-sdk/openai-compatible";
97
+ return ASK_PRESETS[provider]?.runtimeDep ?? OPENAI_COMPATIBLE_DEP;
93
98
  };