blume 2.0.0 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (454) hide show
  1. package/AGENTS.md +1 -1
  2. package/CHANGELOG.md +110 -0
  3. package/README.md +2 -2
  4. package/dist/cli/{chunk-f2972sbt.js → chunk-00gs3wqs.js} +1 -1
  5. package/dist/cli/{chunk-fa25z98p.js → chunk-273ygyr4.js} +4 -3
  6. package/dist/cli/chunk-273ygyr4.js.map +11 -0
  7. package/dist/cli/{chunk-pat2zzwc.js → chunk-3yce002v.js} +21 -8
  8. package/dist/cli/{chunk-pat2zzwc.js.map → chunk-3yce002v.js.map} +4 -4
  9. package/dist/cli/{chunk-d1tadaw7.js → chunk-4e9b9ra6.js} +17 -7
  10. package/dist/cli/chunk-4e9b9ra6.js.map +10 -0
  11. package/dist/cli/{chunk-zg2gtj10.js → chunk-5r8g91qn.js} +352 -676
  12. package/dist/cli/chunk-5r8g91qn.js.map +34 -0
  13. package/dist/cli/{chunk-11j0384y.js → chunk-6dtt0zfn.js} +14 -14
  14. package/dist/cli/{chunk-11j0384y.js.map → chunk-6dtt0zfn.js.map} +3 -3
  15. package/dist/cli/{chunk-bw22s759.js → chunk-6k4ftwze.js} +38 -19
  16. package/dist/cli/{chunk-bw22s759.js.map → chunk-6k4ftwze.js.map} +4 -4
  17. package/dist/cli/{chunk-sqn5t4q0.js → chunk-7mbqtmgb.js} +16 -7
  18. package/dist/cli/chunk-7mbqtmgb.js.map +10 -0
  19. package/dist/cli/{chunk-79njf86q.js → chunk-7vtckvaw.js} +21 -19
  20. package/dist/cli/chunk-7vtckvaw.js.map +11 -0
  21. package/dist/cli/{chunk-fh5hj5jt.js → chunk-8g8ytmgx.js} +17 -18
  22. package/dist/cli/{chunk-fh5hj5jt.js.map → chunk-8g8ytmgx.js.map} +2 -2
  23. package/dist/cli/{chunk-1w8dp3qb.js → chunk-91ws1n6j.js} +18 -15
  24. package/dist/cli/chunk-91ws1n6j.js.map +10 -0
  25. package/dist/cli/{chunk-7ez8ny0t.js → chunk-bbnwccaz.js} +2 -2
  26. package/dist/cli/{chunk-5a2z0198.js → chunk-bfwp9vp6.js} +18 -10
  27. package/dist/cli/chunk-bfwp9vp6.js.map +10 -0
  28. package/dist/cli/{chunk-ernrthtr.js → chunk-d1v5rhy0.js} +14 -15
  29. package/dist/cli/{chunk-ernrthtr.js.map → chunk-d1v5rhy0.js.map} +2 -2
  30. package/dist/cli/{chunk-a9kptbw5.js → chunk-ddndchfr.js} +21 -6
  31. package/dist/cli/chunk-ddndchfr.js.map +14 -0
  32. package/dist/cli/{chunk-zxccj738.js → chunk-esh98wmb.js} +1 -1
  33. package/dist/cli/{chunk-88cpgt6h.js → chunk-fsmrqk8a.js} +1 -1
  34. package/dist/cli/{chunk-b5aj94ah.js → chunk-g698a744.js} +5 -5
  35. package/dist/cli/{chunk-jts8mvcz.js → chunk-gs7r695n.js} +9 -3
  36. package/dist/cli/{chunk-jts8mvcz.js.map → chunk-gs7r695n.js.map} +3 -3
  37. package/dist/cli/{chunk-41za066z.js → chunk-h2ez8dzb.js} +4 -4
  38. package/dist/cli/{chunk-by2290sx.js → chunk-h7k3nq3v.js} +2 -2
  39. package/dist/cli/{chunk-j8mw0za6.js → chunk-hqp2ajnh.js} +252 -123
  40. package/dist/cli/chunk-hqp2ajnh.js.map +35 -0
  41. package/dist/cli/{chunk-mnqj32sj.js → chunk-hr8ne106.js} +119 -50
  42. package/dist/cli/chunk-hr8ne106.js.map +13 -0
  43. package/dist/cli/{chunk-mwt1k8n7.js → chunk-j85scx15.js} +74 -30
  44. package/dist/cli/chunk-j85scx15.js.map +10 -0
  45. package/dist/cli/{chunk-z01ze5c1.js → chunk-k7pj68a8.js} +63 -22
  46. package/dist/cli/chunk-k7pj68a8.js.map +11 -0
  47. package/dist/cli/{chunk-2q1dwty4.js → chunk-mqc662a6.js} +8 -8
  48. package/dist/cli/{chunk-2q1dwty4.js.map → chunk-mqc662a6.js.map} +4 -4
  49. package/dist/cli/{chunk-y3e45rc8.js → chunk-n1yg3tj3.js} +4 -4
  50. package/dist/cli/{chunk-bctazmbk.js → chunk-nfcyttvj.js} +17 -6
  51. package/dist/cli/chunk-nfcyttvj.js.map +10 -0
  52. package/dist/cli/{chunk-6k8vp3ta.js → chunk-pbg5a4s3.js} +60 -28
  53. package/dist/cli/chunk-pbg5a4s3.js.map +19 -0
  54. package/dist/cli/{chunk-d80hr03s.js → chunk-ppzjqwx2.js} +24 -17
  55. package/dist/cli/{chunk-d80hr03s.js.map → chunk-ppzjqwx2.js.map} +4 -4
  56. package/dist/cli/{chunk-beat36xx.js → chunk-qkb5a8sa.js} +25 -10
  57. package/dist/cli/chunk-qkb5a8sa.js.map +10 -0
  58. package/dist/cli/{chunk-bnbmcwfb.js → chunk-sqw4ekg1.js} +5 -5
  59. package/dist/cli/{chunk-bnbmcwfb.js.map → chunk-sqw4ekg1.js.map} +3 -3
  60. package/dist/cli/{chunk-xaz13gwg.js → chunk-v6ya5kcb.js} +3268 -1150
  61. package/dist/cli/chunk-v6ya5kcb.js.map +189 -0
  62. package/dist/cli/{chunk-tzne8qfq.js → chunk-w4bxdvsa.js} +18 -15
  63. package/dist/cli/chunk-w4bxdvsa.js.map +10 -0
  64. package/dist/cli/{chunk-f7t03s3g.js → chunk-wdrt2k2v.js} +2 -2
  65. package/dist/cli/{chunk-z1f5arsg.js → chunk-xh43dwgw.js} +170 -55
  66. package/dist/cli/chunk-xh43dwgw.js.map +36 -0
  67. package/dist/cli/{chunk-pnnvybbk.js → chunk-zp79m0ts.js} +5 -5
  68. package/dist/cli/{chunk-pnnvybbk.js.map → chunk-zp79m0ts.js.map} +2 -2
  69. package/dist/cli/index.js +160 -35
  70. package/dist/cli/index.js.map +4 -4
  71. package/dist/types/ai/agent-readability.d.ts +1 -1
  72. package/dist/types/ai/agent-surface.d.ts +32 -0
  73. package/dist/types/ai/api/paths.d.ts +1 -1
  74. package/dist/types/ai/api-catalog.d.ts +7 -1
  75. package/dist/types/ai/ask-context.d.ts +14 -7
  76. package/dist/types/ai/ask.d.ts +43 -43
  77. package/dist/types/ai/component-markdown.d.ts +4 -4
  78. package/dist/types/ai/index.d.ts +3 -3
  79. package/dist/types/ai/openapi-components.d.ts +1 -1
  80. package/dist/types/ai/relative-links.d.ts +9 -4
  81. package/dist/types/ai/serializers.d.ts +1 -1
  82. package/dist/types/ai/static-expression.d.ts +28 -0
  83. package/dist/types/ai/visibility.d.ts +1 -1
  84. package/dist/types/analytics/databuddy.d.ts +43 -0
  85. package/dist/types/analytics/index.d.ts +2 -0
  86. package/dist/types/analytics/schema.d.ts +14 -0
  87. package/dist/types/cli/env.d.ts +5 -0
  88. package/dist/types/cli/init/scaffold.d.ts +19 -3
  89. package/dist/types/cli/init/starter-spec.d.ts +11 -0
  90. package/dist/types/core/base-path.d.ts +9 -0
  91. package/dist/types/core/config-input.d.ts +21 -21
  92. package/dist/types/core/config.d.ts +5 -5
  93. package/dist/types/core/data.d.ts +3 -3
  94. package/dist/types/core/graph.d.ts +2 -0
  95. package/dist/types/core/i18n-ui.d.ts +37 -8
  96. package/dist/types/core/i18n.d.ts +7 -1
  97. package/dist/types/core/links.d.ts +3 -1
  98. package/dist/types/core/load-module.d.ts +10 -0
  99. package/dist/types/core/locale-links.d.ts +12 -2
  100. package/dist/types/core/meta.d.ts +5 -1
  101. package/dist/types/core/nav-diagnostics.d.ts +10 -0
  102. package/dist/types/core/navigation.d.ts +38 -0
  103. package/dist/types/core/ordering-prefix.d.ts +4 -0
  104. package/dist/types/core/safe-links.d.ts +3 -1
  105. package/dist/types/core/schema.d.ts +57 -18
  106. package/dist/types/core/sources/github-releases.d.ts +5 -0
  107. package/dist/types/core/sources/lower.d.ts +14 -2
  108. package/dist/types/core/sources/normalize.d.ts +10 -1
  109. package/dist/types/core/sources/remote.d.ts +11 -1
  110. package/dist/types/core/sources/resolve.d.ts +12 -0
  111. package/dist/types/core/sources/types.d.ts +31 -0
  112. package/dist/types/core/types.d.ts +9 -0
  113. package/dist/types/core/unrecognized-keys.d.ts +1 -1
  114. package/dist/types/deploy/adapters/node.d.ts +5 -2
  115. package/dist/types/deploy/adapters/types.d.ts +7 -0
  116. package/dist/types/deploy/cloudflare-negotiation.d.ts +3 -2
  117. package/dist/types/deploy/headers.d.ts +31 -7
  118. package/dist/types/deploy/node-headers.d.ts +43 -8
  119. package/dist/types/deploy/platforms/netlify.d.ts +27 -2
  120. package/dist/types/deploy/platforms/node.d.ts +6 -5
  121. package/dist/types/deploy/platforms/types.d.ts +7 -0
  122. package/dist/types/deploy/platforms/vercel.d.ts +3 -2
  123. package/dist/types/deploy/redirects.d.ts +7 -2
  124. package/dist/types/deploy/vercel-negotiation.d.ts +3 -2
  125. package/dist/types/openapi/model.d.ts +20 -6
  126. package/dist/types/search/documents.d.ts +1 -1
  127. package/dist/types/search/orama-index.d.ts +1 -1
  128. package/dist/types/search/sync/algolia.d.ts +3 -1
  129. package/docs/01-quickstart.mdx +3 -2
  130. package/docs/02-deployment.mdx +21 -12
  131. package/docs/03-upgrading.mdx +22 -9
  132. package/docs/04-migrating.mdx +4 -4
  133. package/docs/08-faq.mdx +12 -5
  134. package/docs/advanced/changelog.mdx +1 -1
  135. package/docs/advanced/custom-pages.mdx +5 -3
  136. package/docs/advanced/skills.mdx +1 -1
  137. package/docs/cli/audit.mdx +5 -5
  138. package/docs/cli/doctor.mdx +4 -4
  139. package/docs/cli/evals.mdx +9 -9
  140. package/docs/cli/index.mdx +6 -3
  141. package/docs/cli/translate.mdx +8 -8
  142. package/docs/configuration/analytics.mdx +23 -2
  143. package/docs/configuration/{ask-ai.mdx → assistant.mdx} +20 -20
  144. package/docs/configuration/customization.mdx +5 -4
  145. package/docs/configuration/index.mdx +7 -5
  146. package/docs/configuration/meta.ts +1 -1
  147. package/docs/configuration/search.mdx +2 -2
  148. package/docs/content/components.mdx +1 -1
  149. package/docs/content/frontmatter.mdx +5 -1
  150. package/docs/content/i18n.mdx +3 -3
  151. package/docs/content/index.mdx +4 -2
  152. package/docs/content/islands.mdx +1 -1
  153. package/docs/content/meta.mdx +5 -3
  154. package/docs/content/navigation.mdx +29 -4
  155. package/docs/content/sources.mdx +18 -12
  156. package/docs/content/versioning.mdx +1 -0
  157. package/docs/discoverability/agent-discovery.mdx +22 -8
  158. package/docs/discoverability/index.mdx +3 -3
  159. package/docs/discoverability/llms-txt.mdx +2 -5
  160. package/docs/discoverability/markdown.mdx +5 -3
  161. package/docs/discoverability/mcp.mdx +4 -0
  162. package/docs/discoverability/metadata.mdx +3 -2
  163. package/docs/discoverability/open-graph.mdx +6 -4
  164. package/docs/discoverability/rss.mdx +3 -1
  165. package/docs/index.mdx +2 -2
  166. package/docs/references/asyncapi.mdx +1 -1
  167. package/docs/references/graphql.mdx +2 -2
  168. package/docs/references/openapi.mdx +3 -3
  169. package/package.json +1 -1
  170. package/skills/blume/SKILL.md +5 -5
  171. package/skills/blume-migrate/SKILL.md +6 -6
  172. package/skills/blume-migrate/references/docusaurus.md +6 -6
  173. package/skills/blume-migrate/references/mintlify.md +3 -3
  174. package/skills/blume-migrate/references/monorepo.md +1 -1
  175. package/skills/blume-migrate/references/nextra.md +1 -1
  176. package/skills/blume-migrate/references/starlight.md +5 -5
  177. package/skills/blume-migrate/scripts/mintlify-codemod.mjs +2 -2
  178. package/skills/blume-update-docs/references/audit-checklist.md +1 -1
  179. package/src/ai/agent-readability.ts +4 -4
  180. package/src/ai/agent-surface.ts +56 -0
  181. package/src/ai/api/paths.ts +1 -1
  182. package/src/ai/api/spec.ts +15 -2
  183. package/src/ai/api-catalog.ts +7 -1
  184. package/src/ai/ask-context.ts +21 -9
  185. package/src/ai/ask-data.ts +28 -14
  186. package/src/ai/ask.ts +84 -71
  187. package/src/ai/component-markdown.ts +43 -37
  188. package/src/ai/cors.ts +3 -3
  189. package/src/ai/index.ts +16 -16
  190. package/src/ai/link-headers.ts +8 -3
  191. package/src/ai/llms.ts +4 -3
  192. package/src/ai/markdown.ts +23 -11
  193. package/src/ai/mcp/server.ts +78 -7
  194. package/src/ai/openapi-components.ts +1 -1
  195. package/src/ai/relative-links.ts +78 -10
  196. package/src/ai/serializers.ts +1 -1
  197. package/src/ai/static-expression.ts +416 -0
  198. package/src/ai/visibility.ts +46 -15
  199. package/src/analytics/databuddy.ts +67 -0
  200. package/src/analytics/head.ts +4 -0
  201. package/src/analytics/index.ts +2 -0
  202. package/src/analytics/posthog.ts +21 -3
  203. package/src/analytics/schema.ts +2 -0
  204. package/src/astro/generate.ts +90 -45
  205. package/src/astro/module-types.ts +1 -1
  206. package/src/astro/runtime-deps.ts +6 -6
  207. package/src/astro/templates.ts +87 -49
  208. package/src/audit/catalog.ts +2 -2
  209. package/src/audit/checks/assets.ts +25 -5
  210. package/src/audit/checks/content.ts +20 -2
  211. package/src/audit/checks/i18n.ts +46 -8
  212. package/src/audit/checks/indexability.ts +39 -19
  213. package/src/audit/checks/links.ts +14 -0
  214. package/src/audit/checks/llms.ts +6 -3
  215. package/src/audit/checks/network.ts +3 -1
  216. package/src/audit/checks/og-image.ts +10 -0
  217. package/src/audit/checks/robots.ts +6 -1
  218. package/src/audit/checks/sitemap.ts +56 -31
  219. package/src/audit/checks/social.ts +21 -2
  220. package/src/audit/crawl.ts +88 -15
  221. package/src/audit/report.ts +54 -17
  222. package/src/audit/run.ts +1 -0
  223. package/src/audit/types.ts +18 -0
  224. package/src/audit/url.ts +37 -6
  225. package/src/blume-modules.d.ts +2 -2
  226. package/src/cli/build-failure.ts +50 -0
  227. package/src/cli/commands/audit.ts +8 -1
  228. package/src/cli/commands/build.ts +19 -5
  229. package/src/cli/commands/check.ts +2 -0
  230. package/src/cli/commands/doctor.ts +7 -5
  231. package/src/cli/commands/eval.ts +4 -10
  232. package/src/cli/commands/init.ts +15 -5
  233. package/src/cli/commands/migrate.ts +2 -2
  234. package/src/cli/commands/preview.ts +15 -0
  235. package/src/cli/commands/sync.ts +2 -0
  236. package/src/cli/commands/translate.ts +12 -9
  237. package/src/cli/commands/upgrade.ts +13 -2
  238. package/src/cli/eject-scripts.ts +32 -7
  239. package/src/cli/env.ts +12 -1
  240. package/src/cli/init/scaffold.ts +117 -11
  241. package/src/cli/init/starter-spec.ts +235 -0
  242. package/src/cli/required-secrets.ts +3 -3
  243. package/src/components/content/AccordionItem.astro +26 -22
  244. package/src/components/content/Badge.astro +2 -9
  245. package/src/components/content/Card.astro +2 -2
  246. package/src/components/content/Component.astro +9 -3
  247. package/src/components/content/Expandable.astro +5 -1
  248. package/src/components/content/Frame.astro +2 -7
  249. package/src/components/content/GithubInfo.astro +12 -2
  250. package/src/components/content/Prompt.astro +2 -7
  251. package/src/components/content/Tabs.astro +54 -5
  252. package/src/components/content/Tile.astro +1 -1
  253. package/src/components/content/Tooltip.astro +69 -7
  254. package/src/components/content/Tree.astro +7 -2
  255. package/src/components/content/TypeTable.astro +10 -5
  256. package/src/components/content/Update.astro +8 -2
  257. package/src/components/content/auto-type-table.ts +4 -1
  258. package/src/components/content/badge-color.ts +17 -0
  259. package/src/components/content/base-href.ts +18 -3
  260. package/src/components/content/inline-markdown.ts +27 -7
  261. package/src/components/copy-feedback.ts +36 -9
  262. package/src/components/islands/{AskAI.astro → Assistant.astro} +10 -10
  263. package/src/components/islands/{ask-ai.tsx → assistant.tsx} +39 -25
  264. package/src/components/islands/hooks.ts +21 -14
  265. package/src/components/islands/webmcp.ts +12 -8
  266. package/src/components/layout/Banner.astro +23 -4
  267. package/src/components/layout/Header.astro +32 -19
  268. package/src/components/layout/Logo.astro +5 -0
  269. package/src/components/layout/NavSelector.astro +6 -1
  270. package/src/components/layout/NavTabMenu.astro +133 -0
  271. package/src/components/layout/NavTree.astro +15 -6
  272. package/src/components/layout/NavTreeCache.astro +5 -2
  273. package/src/components/layout/NavTreeScript.astro +45 -5
  274. package/src/components/layout/PageLayout.astro +28 -14
  275. package/src/components/layout/Pagination.astro +7 -7
  276. package/src/components/layout/ReferenceLayout.astro +5 -2
  277. package/src/components/layout/RootLayout.astro +27 -14
  278. package/src/components/layout/Search.astro +18 -14
  279. package/src/components/layout/analytics-client.ts +3 -1
  280. package/src/components/layout/drawer-inert.ts +1 -1
  281. package/src/components/openapi/GraphqlType.astro +11 -3
  282. package/src/components/openapi/MessageComposer.astro +1 -1
  283. package/src/components/openapi/Operation.astro +21 -5
  284. package/src/components/openapi/PanelTabs.astro +4 -1
  285. package/src/components/openapi/Playground.astro +8 -2
  286. package/src/components/openapi/RequestPanel.astro +9 -5
  287. package/src/components/openapi/SchemaProperty.astro +11 -33
  288. package/src/components/openapi/SchemaTable.astro +27 -52
  289. package/src/components/openapi/description.ts +2 -2
  290. package/src/components/openapi/helpers.ts +90 -12
  291. package/src/components/openapi/message-composer.ts +8 -0
  292. package/src/components/openapi/message-model.ts +12 -2
  293. package/src/components/openapi/message.ts +4 -1
  294. package/src/components/openapi/operation-model.ts +40 -8
  295. package/src/components/openapi/panel.ts +29 -5
  296. package/src/components/openapi/playground-client.ts +37 -7
  297. package/src/components/openapi/playground-schema.ts +25 -6
  298. package/src/components/openapi/request.ts +2 -0
  299. package/src/components/openapi/schema-tree.ts +203 -0
  300. package/src/components/openapi/snippets.ts +30 -15
  301. package/src/components/openapi/validate-json.ts +1 -1
  302. package/src/core/base-path.ts +15 -0
  303. package/src/core/code-fences.ts +1 -1
  304. package/src/core/config-input.ts +23 -23
  305. package/src/core/config.ts +21 -7
  306. package/src/core/data.ts +3 -3
  307. package/src/core/diagnostics.ts +217 -30
  308. package/src/core/graph.ts +120 -11
  309. package/src/core/i18n-ui.ts +74 -11
  310. package/src/core/i18n.ts +13 -2
  311. package/src/core/links.ts +7 -4
  312. package/src/core/load-module.ts +20 -0
  313. package/src/core/locale-links.ts +17 -17
  314. package/src/core/manifest.ts +3 -2
  315. package/src/core/meta.ts +69 -6
  316. package/src/core/nav-diagnostics.ts +56 -1
  317. package/src/core/navigation.ts +245 -76
  318. package/src/core/ordering-prefix.ts +27 -0
  319. package/src/core/project-graph.ts +23 -1
  320. package/src/core/request-body.ts +1 -1
  321. package/src/core/safe-href.ts +53 -1
  322. package/src/core/safe-links.ts +11 -2
  323. package/src/core/schema.ts +95 -34
  324. package/src/core/server-features.ts +2 -2
  325. package/src/core/sources/assets.ts +83 -41
  326. package/src/core/sources/contentful-rich-text.ts +3 -2
  327. package/src/core/sources/contentful.ts +25 -12
  328. package/src/core/sources/filesystem.ts +5 -1
  329. package/src/core/sources/github-releases.ts +106 -5
  330. package/src/core/sources/lexical.ts +9 -4
  331. package/src/core/sources/lower.ts +79 -26
  332. package/src/core/sources/mdx-remote.ts +1 -0
  333. package/src/core/sources/normalize.ts +132 -30
  334. package/src/core/sources/notion.ts +26 -10
  335. package/src/core/sources/obsidian.ts +17 -3
  336. package/src/core/sources/payload.ts +1 -0
  337. package/src/core/sources/portable-text.ts +63 -44
  338. package/src/core/sources/remote.ts +18 -2
  339. package/src/core/sources/resolve.ts +52 -33
  340. package/src/core/sources/sanity.ts +1 -0
  341. package/src/core/sources/strapi-blocks.ts +9 -4
  342. package/src/core/sources/strapi.ts +1 -0
  343. package/src/core/sources/types.ts +31 -0
  344. package/src/core/types.ts +9 -0
  345. package/src/core/ui-packs/ar.ts +17 -5
  346. package/src/core/ui-packs/bg.ts +17 -5
  347. package/src/core/ui-packs/bn.ts +17 -5
  348. package/src/core/ui-packs/ca.ts +17 -5
  349. package/src/core/ui-packs/cs.ts +17 -5
  350. package/src/core/ui-packs/da.ts +17 -5
  351. package/src/core/ui-packs/de.ts +17 -5
  352. package/src/core/ui-packs/el.ts +17 -5
  353. package/src/core/ui-packs/es.ts +17 -5
  354. package/src/core/ui-packs/fa.ts +17 -5
  355. package/src/core/ui-packs/fi.ts +17 -5
  356. package/src/core/ui-packs/fr.ts +17 -5
  357. package/src/core/ui-packs/he.ts +17 -5
  358. package/src/core/ui-packs/hi.ts +17 -5
  359. package/src/core/ui-packs/hr.ts +17 -5
  360. package/src/core/ui-packs/hu.ts +17 -5
  361. package/src/core/ui-packs/id.ts +17 -5
  362. package/src/core/ui-packs/it.ts +17 -5
  363. package/src/core/ui-packs/ja.ts +17 -5
  364. package/src/core/ui-packs/ko.ts +17 -5
  365. package/src/core/ui-packs/nl.ts +17 -5
  366. package/src/core/ui-packs/no.ts +17 -5
  367. package/src/core/ui-packs/pl.ts +17 -5
  368. package/src/core/ui-packs/pt-br.ts +17 -5
  369. package/src/core/ui-packs/pt.ts +17 -5
  370. package/src/core/ui-packs/ro.ts +17 -5
  371. package/src/core/ui-packs/ru.ts +17 -5
  372. package/src/core/ui-packs/sk.ts +17 -5
  373. package/src/core/ui-packs/sr.ts +17 -5
  374. package/src/core/ui-packs/sv.ts +17 -5
  375. package/src/core/ui-packs/th.ts +17 -5
  376. package/src/core/ui-packs/tr.ts +17 -5
  377. package/src/core/ui-packs/uk.ts +17 -5
  378. package/src/core/ui-packs/vi.ts +17 -5
  379. package/src/core/ui-packs/zh-tw.ts +17 -5
  380. package/src/core/ui-packs/zh.ts +17 -5
  381. package/src/core/unrecognized-keys.ts +1 -1
  382. package/src/core/version-cut.ts +17 -2
  383. package/src/core/versions.ts +4 -1
  384. package/src/deploy/adapters/node.ts +5 -2
  385. package/src/deploy/adapters/registry.ts +2 -1
  386. package/src/deploy/adapters/types.ts +13 -1
  387. package/src/deploy/artifacts.ts +25 -5
  388. package/src/deploy/cloudflare-negotiation.ts +23 -4
  389. package/src/deploy/headers.ts +67 -51
  390. package/src/deploy/node-headers.ts +148 -27
  391. package/src/deploy/platforms/cloudflare.ts +1 -0
  392. package/src/deploy/platforms/netlify.ts +82 -5
  393. package/src/deploy/platforms/node.ts +7 -5
  394. package/src/deploy/platforms/static.ts +1 -0
  395. package/src/deploy/platforms/types.ts +7 -0
  396. package/src/deploy/platforms/vercel.ts +9 -3
  397. package/src/deploy/redirects.ts +14 -3
  398. package/src/deploy/vercel-negotiation.ts +35 -3
  399. package/src/eval/agents.ts +10 -2
  400. package/src/eval/run.ts +25 -0
  401. package/src/markdown/base-links.ts +55 -8
  402. package/src/markdown/index.ts +6 -3
  403. package/src/markdown/relative-links.ts +3 -23
  404. package/src/markdown/route-snapshot.ts +37 -0
  405. package/src/og/card.ts +20 -4
  406. package/src/og/derive.ts +145 -4
  407. package/src/openapi/graphql-build.ts +28 -2
  408. package/src/openapi/model.ts +77 -13
  409. package/src/openapi/render-mdx.ts +10 -1
  410. package/src/registry/eject.ts +135 -37
  411. package/src/search/documents.ts +24 -3
  412. package/src/search/orama-index.ts +1 -1
  413. package/src/search/sync/algolia.ts +36 -2
  414. package/src/sources/registry.ts +5 -0
  415. package/src/theme/entry.ts +11 -4
  416. package/src/translate/agents.ts +6 -1
  417. package/src/translate/ledger.ts +26 -3
  418. package/src/translate/meta.ts +11 -3
  419. package/src/translate/report.ts +1 -1
  420. package/src/translate/run.ts +11 -5
  421. package/src/translate/validate.ts +10 -1
  422. package/src/translate/work-list.ts +36 -3
  423. package/src/upgrade/upgrade.ts +37 -5
  424. package/dist/cli/chunk-1w8dp3qb.js.map +0 -10
  425. package/dist/cli/chunk-5a2z0198.js.map +0 -10
  426. package/dist/cli/chunk-6k8vp3ta.js.map +0 -19
  427. package/dist/cli/chunk-79njf86q.js.map +0 -11
  428. package/dist/cli/chunk-a9kptbw5.js.map +0 -14
  429. package/dist/cli/chunk-abh8yjkn.js +0 -31
  430. package/dist/cli/chunk-abh8yjkn.js.map +0 -10
  431. package/dist/cli/chunk-bctazmbk.js.map +0 -10
  432. package/dist/cli/chunk-beat36xx.js.map +0 -10
  433. package/dist/cli/chunk-d1tadaw7.js.map +0 -10
  434. package/dist/cli/chunk-fa25z98p.js.map +0 -11
  435. package/dist/cli/chunk-j8mw0za6.js.map +0 -35
  436. package/dist/cli/chunk-mnqj32sj.js.map +0 -12
  437. package/dist/cli/chunk-mwt1k8n7.js.map +0 -10
  438. package/dist/cli/chunk-nk3ts2xk.js +0 -51
  439. package/dist/cli/chunk-nk3ts2xk.js.map +0 -10
  440. package/dist/cli/chunk-sqn5t4q0.js.map +0 -10
  441. package/dist/cli/chunk-tzne8qfq.js.map +0 -10
  442. package/dist/cli/chunk-xaz13gwg.js.map +0 -182
  443. package/dist/cli/chunk-z01ze5c1.js.map +0 -10
  444. package/dist/cli/chunk-z1f5arsg.js.map +0 -36
  445. package/dist/cli/chunk-zg2gtj10.js.map +0 -35
  446. /package/dist/cli/{chunk-f2972sbt.js.map → chunk-00gs3wqs.js.map} +0 -0
  447. /package/dist/cli/{chunk-7ez8ny0t.js.map → chunk-bbnwccaz.js.map} +0 -0
  448. /package/dist/cli/{chunk-zxccj738.js.map → chunk-esh98wmb.js.map} +0 -0
  449. /package/dist/cli/{chunk-88cpgt6h.js.map → chunk-fsmrqk8a.js.map} +0 -0
  450. /package/dist/cli/{chunk-b5aj94ah.js.map → chunk-g698a744.js.map} +0 -0
  451. /package/dist/cli/{chunk-41za066z.js.map → chunk-h2ez8dzb.js.map} +0 -0
  452. /package/dist/cli/{chunk-by2290sx.js.map → chunk-h7k3nq3v.js.map} +0 -0
  453. /package/dist/cli/{chunk-y3e45rc8.js.map → chunk-n1yg3tj3.js.map} +0 -0
  454. /package/dist/cli/{chunk-f7t03s3g.js.map → chunk-wdrt2k2v.js.map} +0 -0
@@ -92,7 +92,7 @@ The codemod touches **only frontmatter**. Icons in MDX **body** (`<Icon icon="
92
92
  | `life-ring` | `life-buoy` | | `shield-halved` | `shield` |
93
93
  | `rocket`/`book`/`book-open`/`code`/`terminal`/`key`/`lock`/`user`/`users`/`database`/`server`/`cloud`/`bell`/`calendar`/`star`/`heart`/`tag`/`folder`/`globe`/`link`/`download`/`upload`/`check`/`copy`/`play`/`filter` | _(same name — verify)_ |
94
94
 
95
- **Rules:** verify each Lucide name exists at [lucide.dev/icons](https://lucide.dev/icons) before writing it. **Brand icons** (`fa6-brands:*` — github, discord, x, slack, linkedin…) mostly have **no** Lucide equivalent: for GitHub use the `github` config (renders the header repo link); for other socials, drop the icon and report it (or add via a Footer override after `blume eject`). Where no Lucide counterpart exists, **drop the icon and report it** — an unknown icon name is a build error.
95
+ **Rules:** verify each Lucide name exists at [lucide.dev/icons](https://lucide.dev/icons) before writing it. **Brand icons** (`fa6-brands:*` — github, discord, x, slack, linkedin…) mostly have **no** Lucide equivalent: for GitHub use the `github` config (renders the header repo link); for other socials, drop the icon and report it (or add via a Footer override after `blume eject`). Where no Lucide counterpart exists, **drop the icon and report it**. The build won't catch a wrong name for you: an unknown icon renders nothing, and it's only a warning (`BLUME_UNKNOWN_ICON`) for navigation icons — an icon prop on a component like `<Card>` fails silently — so check every name.
96
96
 
97
97
  ## Navigation: `docs.json` `navigation` → filesystem + tabs
98
98
 
@@ -143,7 +143,7 @@ Mintlify page frontmatter → Blume's strict schema. **`scripts/mintlify-codemod
143
143
  | `canonical` | `seo.canonical` | renames |
144
144
  | `og:image` | `seo.image` | renames |
145
145
  | `hidden: true` | valid top-level in Blume — **kept as-is**; add `noindex: true` yourself if the page must also leave the search index | left (do by hand) |
146
- | `openapi`/`asyncapi`/`api` | usually an endpoint stub → **delete the page** (Blume generates operation pages); else `type: api` | **flags** for review — never auto-deletes a page |
146
+ | `openapi`/`asyncapi`/`api` | usually an endpoint stub → **delete the page** (Blume generates operation pages); else drop the key and keep it as a normal page (there's no built-in `api` page type) | **flags** for review — never auto-deletes a page |
147
147
  | `mode`, `public`, `rss`, `groups`, `keywords`, `hideApiMarker`, `hideFooterPagination`, `iconType` | **drop** (report) | drops |
148
148
 
149
149
  The codemod leaves the source key in place and reports a conflict rather than clobbering data when a rename target already exists (e.g. a page already has `sidebar.label`) or the value is too structured to move safely — resolve those by hand. Remove any duplicate H1 in the body — `title` renders the H1. (The codemod only edits frontmatter; it never touches the body.)
@@ -153,7 +153,7 @@ The codemod leaves the source key in place and reports a conflict rather than cl
153
153
  Top-level `openapi`, `api.openapi`, or a per-group/per-tab `openapi` → `reference: [openapi({ sources: [{ spec, label?, route? }] })]`, with `openapi` imported from `blume/reference` (`spec` alone is the single-source shorthand; several per-tab specs become several sources, or several `openapi()` entries when they need different routes; a spec the source embedded with Scalar becomes a `scalar({ spec })` entry). A Mintlify `{ source, directory }` object: `directory` → the source's `route`. An `asyncapi` field maps the same way to `asyncapi({ … })` in the list. **Delete every per-endpoint stub page** (frontmatter `openapi: "GET /path"` or a `"GET /path"` nav entry) — Blume's native renderer generates one real page per operation. **Add a `navigation.tabs` entry pointing at the reference `route` yourself** (Mintlify's API tab maps to it); the reference does not create a header tab automatically.
154
154
 
155
155
  - **Vendor the spec.** Mintlify usually points at a spec **URL**. Copying that straight into `spec:` makes every build fetch it at build time — a single point of failure in CI/offline/behind a proxy, and a failed fetch silently drops the reference (leaving the tab pointing at a route that 404s). Prefer downloading it into the repo (`curl … -o openapi/<name>.json`) and pointing `spec` at that local path. If you keep the URL, report the dependency and consider a `prebuild` refresh-with-fallback.
156
- - **Fix endpoint links.** Blume operation routes are `<route>/<slugified-tag>/<slugified-operationId>` (tag `Models` + id `listModels` → `/api-reference/models/listmodels`) — 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.
156
+ - **Fix endpoint links.** Blume operation routes are `<route>/<slugified-tag>/<slugified-operationId>` (tag `Models` + id `listModels` → `/api-reference/models/list-models`: a camelCase id is split into kebab-case, not just lowercased — see SKILL.md "OpenAPI") — this differs from Mintlify's endpoint URLs, so **rewrite every inbound link to an operation**. `blume validate` resolves operation pages like any other route and flags the ones you miss.
157
157
  - **Keep the "Introduction" page.** Mintlify commonly has a written intro/auth page in an "Introduction" group beside the "Endpoints" (openapi) group in the same tab. Keep it: a normal content page placed under the `openapi()` adapter's `route` (e.g. `<root>/api-reference/introduction.mdx`) merges into the reference tab's sidebar alongside the generated operations. Delete only the per-endpoint stubs, not the conceptual pages.
158
158
 
159
159
  ## Assets
@@ -112,7 +112,7 @@ This is a **copyable template**, not prose. Three pieces:
112
112
  "preview": "blume preview"
113
113
  },
114
114
  "dependencies": {
115
- "blume": "^1"
115
+ "blume": "^2"
116
116
  }
117
117
  }
118
118
  ```
@@ -56,7 +56,7 @@ Most Nextra pages have **no frontmatter**; the title falls back `_meta` title
56
56
 
57
57
  ## Code fences
58
58
 
59
- Nextra's fence meta differs from Blume's — rewrite it: `filename="app.js"` → a space-separated title (` ```js app.js `); `showLineNumbers` → `lineNumbers`; line highlighting `{1,4-5}` carries over unchanged; **drop** word-highlight `/word/`, `copy`/`copy=false`, and inline-code `{:lang}` suffixes. ` ```sh npm2yarn ` fences → ` ```package-install `.
59
+ Nextra's fence meta differs from Blume's — rewrite it: `filename="app.js"` → a space-separated title (` ```js app.js `); `showLineNumbers` → `lineNumbers`; line highlighting `{1,4-5}` carries over unchanged; **drop** word-highlight `/word/` and `copy`/`copy=false`. **Keep** inline-code `{:lang}` suffixes (`` `useState(){:js}` ``) — Blume highlights them natively. ` ```sh npm2yarn ` fences → ` ```package-install `.
60
60
 
61
61
  ## Math
62
62
 
@@ -12,7 +12,7 @@ Keep content where it is — set `content.root: "src/content/docs"`.
12
12
 
13
13
  ## Config: `starlight({…})` → `blume.config.ts`
14
14
 
15
- **Harvest the surrounding `astro.config.*` too, not just the `starlight()` call:** top-level Astro `redirects` → Blume `redirects`; `site` → leave unset (Blume auto-detects); other integrations → report.
15
+ **Harvest the surrounding `astro.config.*` too, not just the `starlight()` call:** top-level Astro `redirects` → Blume `redirects`; `site` → `deployment.site`, unless the target host is Vercel, Netlify, or Cloudflare Pages, which Blume auto-detects (see SKILL.md); other integrations → report.
16
16
 
17
17
  | Starlight option | Blume |
18
18
  | --- | --- |
@@ -70,7 +70,7 @@ Starlight's primary callout syntax is the `:::note`/`:::tip`/`:::caution`/`:::da
70
70
 
71
71
  ## Components
72
72
 
73
- - **Renames:** `<CardGrid>` → `<CardGroup>`; `<LinkCard>` → `<Card>` (its `description` prop drops — fold into the body); `<TabItem label="…">` → `<Tab title="…">`. `<Tabs>` and `<Card>` stay; a `<Tabs syncKey="…">` → strip the prop (Blume tabs sync by default).
73
+ - **Renames:** `<CardGrid>` → `<CardGroup>`; `<LinkCard>` → `<Card>` (its `description` prop drops — fold into the body); `<TabItem label="…">` → `<Tab title="…">`. `<Tabs>` and `<Card>` stay; **keep** a `<Tabs syncKey="…">` prop as is — Blume's `Tabs` takes `syncKey` with the same scoping (only groups sharing the key switch together). One difference: Blume groups without a key also sync, page-wide, by tab title, where Starlight leaves them independent — add `sync={false}` to a keyless group whose same-titled tabs must stay unlinked.
74
74
  - **`<Badge>` needs conversion, not pass-through:** Starlight puts content in a `text` prop and uses variants `note`/`tip`/`caution`/`danger`/`success`/`default` with sizes `small`/`medium`/`large`. Blume's `<Badge>` renders **children** with variants `default`/`accent`/`success`/`warning`/`danger` and sizes `xs`/`sm`/`md`/`lg`. Move `text` into the children; remap variant (`note`→`default`, `tip`→`accent`, `caution`→`warning`, `danger`→`danger`, `success`→`success`) and size (`small`→`sm`, `medium`→`md`, `large`→`lg`).
75
75
  - **Convert yourself:** `<Steps>` → Blume `<Steps>`/`<Step>`; `<FileTree>` → Blume `<FileTree>`; `<Code code={…}>` → a fenced code block; `<LinkButton>` → a Markdown link or `<Card>`.
76
76
  - Strip `import … from "@astrojs/starlight/*"` and `astro:assets` lines.
@@ -88,8 +88,8 @@ Starlight content is full of Expressive Code fence meta; Blume understands some
88
88
  ## Plugins — map, don't drop
89
89
 
90
90
  - `starlight-openapi` → an `openapi({ sources })` entry in Blume's `reference` list, imported from `blume/reference` (delete any generated pages; add the `navigation.tabs` entry).
91
- - `starlight-blog` → `type: blog` pages.
92
- - `starlight-versions` → `navigation.selectors` with `kind: "version"`.
91
+ - `starlight-blog` → `type: blog` pages (RSS at `/blog/rss.xml`). Blume generates **no** blog index, tag, or author pages: write a `blog/index.mdx` whose `CardGroup` links each post (see `docs/advanced/blog.mdx` in the installed package), and report the tag and author pages as dropped.
92
+ - `starlight-versions` → Blume's native versioning, not a `navigation.selectors` dropdown: each archived version's content goes in a top-level folder under `content.root` named for its id, listed in `versions.archived` (newest first), and Blume adds the switcher, the old-version notice, and version-scoped search. Ids must start with a letter (`1.0/` → `v1.0/`, with `redirects` from the old URLs), and a version-shaped folder left out of `versions.archived` only warns (`BLUME_VERSIONS_UNCONFIGURED_VERSION`) and publishes as current content. Full reference: `docs/content/versioning.mdx` in the installed package.
93
93
  - `starlight-image-zoom` → delete (Blume zooms content images by default).
94
94
  - `starlight-links-validator` → delete (`blume validate` covers it).
95
95
  - Anything else → report.
@@ -113,4 +113,4 @@ Remove `@astrojs/starlight` (and plugin deps) from deps, delete the Starlight bi
113
113
 
114
114
  ## Dropped — report these
115
115
 
116
- Non-GitHub socials, badge variants, sidebar/item `attrs` + `translations`, `customCss` beyond `theme.css`, `head` entries, `routeMiddleware`, splash/hero pages (rebuild as custom pages), aside custom icons, EC frames/collapse/text markers, prev/next toggles, unmapped plugins, any `<Icon>` name with no Lucide equivalent.
116
+ Non-GitHub socials, badge variants, sidebar/item `attrs` + `translations`, `customCss` beyond `theme.css`, `head` entries, `routeMiddleware`, splash/hero pages (rebuild as custom pages), starlight-blog's tag and author pages, aside custom icons, EC frames/collapse/text markers, prev/next toggles, unmapped plugins, any `<Icon>` name with no Lucide equivalent.
@@ -177,8 +177,8 @@ const RENAME = {
177
177
  };
178
178
 
179
179
  // Keys we deliberately do NOT auto-transform — they usually mean the page is an
180
- // OpenAPI endpoint stub that should be deleted (Blume generates operation pages)
181
- // or converted to `type: api`. Flag for the human; never guess.
180
+ // OpenAPI endpoint stub that should be deleted (Blume generates operation pages),
181
+ // or else a normal page that just loses the key. Flag for the human; never guess.
182
182
  const FLAG = new Set(["api", "asyncapi", "openapi"]);
183
183
 
184
184
  // Which change kinds actually edit the file. Report-only kinds (flags,
@@ -32,7 +32,7 @@ Skip the edit when the only available change is subjective polish, wording prefe
32
32
  - Preserve existing page order and `defineMeta` style; update `pages` arrays when adding, renaming, or removing pages.
33
33
  - Use the Blume components already present in the docs (callout directives, steps, cards) instead of inventing new markup patterns.
34
34
  - Match nearby code fences: filenames, language tags, and line numbers where the surrounding docs use them.
35
- - Keep internal links root-relative (`/docs/...`).
35
+ - Keep internal links root-relative (`/guides/setup`), in the form nearby pages already use.
36
36
  - Do not edit generated `.blume/` or `dist/` output.
37
37
 
38
38
  ## PR notes
@@ -34,7 +34,7 @@ const usagePolicy = (
34
34
  };
35
35
 
36
36
  /**
37
- * The advertised Ask AI URL. An external endpoint is not served under
37
+ * The advertised assistant URL. An external endpoint is not served under
38
38
  * `deployment.base`, so a root-relative one absolutizes against the site
39
39
  * origin alone; the built-in route gets site and base via `abs`.
40
40
  */
@@ -154,7 +154,7 @@ const wellKnownArtifacts = (
154
154
  /**
155
155
  * Build `agent-readability.json`: a root manifest that indexes the project's
156
156
  * agent-facing surface — llms.txt, the raw-Markdown mirrors, the JSON docs
157
- * API and its OpenAPI description, the MCP server, Ask AI, sitemap, and feeds
157
+ * API and its OpenAPI description, the MCP server, the assistant, sitemap, and feeds
158
158
  * — so agents can discover and cite the docs without
159
159
  * scraping HTML. URLs are absolute when a `site` is configured and root-relative
160
160
  * (still under `deployment.base`) otherwise. Returns null when the manifest is
@@ -194,8 +194,8 @@ export const buildAgentReadability = (
194
194
  url: abs(config.agents.mcp.route),
195
195
  };
196
196
  }
197
- if (config.ai.ask?.enabled) {
198
- artifacts.askApi = askApiUrl(config.ai.ask.endpoint, site, abs);
197
+ if (config.ai.assistant?.enabled) {
198
+ artifacts.askApi = askApiUrl(config.ai.assistant.endpoint, site, abs);
199
199
  }
200
200
  Object.assign(artifacts, wellKnownArtifacts(config, abs));
201
201
  if (site && config.seo.sitemap) {
@@ -0,0 +1,56 @@
1
+ import { routeIsTaken } from "../astro/pages.ts";
2
+ import type { BlumeProject } from "../core/project-graph.ts";
3
+ import type { ResolvedConfig } from "../core/schema.ts";
4
+
5
+ /**
6
+ * What a build actually serves of the agent surfaces whose config flag alone
7
+ * doesn't guarantee them.
8
+ */
9
+ export interface EmittedAgentSurface {
10
+ /** The MCP server was generated (see {@link servesMcp}). */
11
+ mcp: boolean;
12
+ /**
13
+ * A skills discovery index is served: generated from `agents.skills` (at
14
+ * least one valid skill), or shipped by the user in `public/`.
15
+ */
16
+ skills: boolean;
17
+ }
18
+
19
+ /**
20
+ * Whether the build generates the MCP server: it is enabled and no content
21
+ * or custom page owns its route. When one does, the generator skips the
22
+ * server with a warning rather than collide with the page (`planMcp`).
23
+ */
24
+ export const servesMcp = (
25
+ project: BlumeProject,
26
+ userPages: { pattern: string }[]
27
+ ): boolean =>
28
+ project.config.agents.mcp.enabled &&
29
+ !routeIsTaken(
30
+ userPages,
31
+ project.graph.pages,
32
+ project.config.agents.mcp.route
33
+ );
34
+
35
+ /**
36
+ * The config the discovery documents are built from: `agents.mcp` and
37
+ * `agents.skills` switched off when the build didn't emit them, so llms.txt,
38
+ * agent-readability.json, the catalogs, and the header rules only point at
39
+ * what is there. A config flag says what was asked for; the MCP server is
40
+ * skipped when a page owns its route, and skills publish nothing when their
41
+ * directory is missing or holds no valid skill.
42
+ */
43
+ export const advertisedConfig = (
44
+ config: ResolvedConfig,
45
+ emitted: EmittedAgentSurface
46
+ ): ResolvedConfig => ({
47
+ ...config,
48
+ agents: {
49
+ ...config.agents,
50
+ mcp: {
51
+ ...config.agents.mcp,
52
+ enabled: config.agents.mcp.enabled && emitted.mcp,
53
+ },
54
+ skills: emitted.skills ? config.agents.skills : undefined,
55
+ },
56
+ });
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Where the JSON docs API and its OpenAPI description are served. Base-less
3
3
  * (like every route Blume emits); callers layer `deployment.base` on top.
4
- * Under `/api/` alongside the Ask AI endpoint (`/api/ask`) so the namespace a
4
+ * Under `/api/` alongside the assistant endpoint (`/api/ask`) so the namespace a
5
5
  * Blume site reserves for live endpoints stays one prefix, and under its own
6
6
  * `docs` segment so a search provider's proxy at `/api/search` never collides.
7
7
  */
@@ -113,6 +113,7 @@ export interface ApiSpecDocument {
113
113
  }
114
114
 
115
115
  const JSON_TYPE = "application/json";
116
+ const EVENT_STREAM_TYPE = "text/event-stream";
116
117
  const MARKDOWN_TYPE = "text/markdown";
117
118
  const TEXT_TYPE = "text/plain";
118
119
 
@@ -623,14 +624,26 @@ export const buildApiSpec = (input: ApiSpecInput): ApiSpecDocument => {
623
624
  {
624
625
  post: {
625
626
  description:
626
- "The Model Context Protocol server (Streamable HTTP, stateless, JSON responses). Tools: `search_docs`, `get_page`, `list_pages`, `get_navigation` — the same operations this API exposes — plus every page as a `text/markdown` resource. Discovery document at `/.well-known/mcp.json`.",
627
+ "The Model Context Protocol server (Streamable HTTP, stateless, JSON responses). Send `Accept: application/json, text/event-stream`: the Streamable HTTP transport requires a client to accept both and answers `406` otherwise, though this server always replies with JSON. Tools: `search_docs`, `get_page`, `list_pages`, `get_navigation` — the same operations this API exposes — plus every page as a `text/markdown` resource. Discovery document at `/.well-known/mcp.json`.",
627
628
  operationId: "mcp",
628
629
  requestBody: {
629
630
  content: { [JSON_TYPE]: { schema: ref("JsonRpcRequest") } },
630
631
  required: true,
631
632
  },
632
633
  responses: {
633
- "200": jsonResponse("The JSON-RPC response.", "JsonRpcResponse"),
634
+ // Both media types, so a generated client sends the Accept header
635
+ // the transport requires; OpenAPI ignores an `Accept` parameter.
636
+ "200": {
637
+ content: {
638
+ [JSON_TYPE]: { schema: ref("JsonRpcResponse") },
639
+ [EVENT_STREAM_TYPE]: { schema: { type: "string" } },
640
+ },
641
+ description: "The JSON-RPC response.",
642
+ },
643
+ "406": jsonResponse(
644
+ "The request's `Accept` header doesn't list both `application/json` and `text/event-stream`.",
645
+ "JsonRpcResponse"
646
+ ),
634
647
  },
635
648
  summary: "Call the MCP server",
636
649
  tags: ["MCP"],
@@ -17,7 +17,13 @@ import { API_BASE, OPENAPI_PATH } from "./api/paths.ts";
17
17
  */
18
18
 
19
19
  export const API_CATALOG_PATH = "/.well-known/api-catalog";
20
- export const API_CATALOG_TYPE = "application/linkset+json";
20
+ /** The profile URI RFC 9727 registers for an API catalog linkset. */
21
+ export const API_CATALOG_PROFILE = "https://www.rfc-editor.org/info/rfc9727";
22
+ /**
23
+ * The catalog's media type: a linkset carrying the RFC 9727 profile
24
+ * parameter, which the RFC says an API catalog SHOULD be served with.
25
+ */
26
+ export const API_CATALOG_TYPE = `application/linkset+json; profile="${API_CATALOG_PROFILE}"`;
21
27
 
22
28
  /** An RFC 9264 linkset entry, restricted to the relations Blume emits. */
23
29
  interface LinksetEntry {
@@ -4,7 +4,7 @@ import type { FenceState } from "../core/code-fences.ts";
4
4
  import { buildOramaIndex, queryOramaIndex } from "../search/orama-index.ts";
5
5
  import type { OramaDoc } from "../search/orama-index.ts";
6
6
 
7
- /** A chat message as posted by the Ask AI island (`{ role, content }`). */
7
+ /** A chat message as posted by the assistant island (`{ role, content }`). */
8
8
  export interface AskMessage {
9
9
  content: string;
10
10
  role: string;
@@ -16,7 +16,7 @@ export interface AskPage {
16
16
  }
17
17
 
18
18
  /**
19
- * The self-contained snapshot the grounded Ask AI endpoint imports. Bundles the
19
+ * The self-contained snapshot the assistant's grounded endpoint imports. Bundles the
20
20
  * search documents so retrieval works regardless of the configured search
21
21
  * provider and needs no filesystem access at request time. Serialized to
22
22
  * `generated/ask-data.json` and built by {@link buildAskData}.
@@ -30,6 +30,13 @@ export interface AskData {
30
30
  defaultLocale?: string;
31
31
  documents: OramaDoc[];
32
32
  site: string | null;
33
+ /**
34
+ * Present on a versioned site, whose documents then carry their `version`
35
+ * (`""` for the current docs): retrieval keeps to the version the reader
36
+ * is viewing — the current docs unless they're on an archived page — as
37
+ * the search dialog does.
38
+ */
39
+ versioned?: boolean;
33
40
  }
34
41
 
35
42
  /** Documents retrieved per question and injected into the system prompt. */
@@ -47,7 +54,7 @@ const CONTEXT_BUDGET = 10_000;
47
54
  const MIN_EXCERPT_CHARS = 200;
48
55
 
49
56
  /**
50
- * How much retrieved documentation a question carries (the `ai.ask.retrieval`
57
+ * How much retrieved documentation a question carries (the `ai.assistant.retrieval`
51
58
  * config). Every field falls back to the built-in default, so a partial object
52
59
  * only changes what it names. Injected characters dominate time-to-first-token
53
60
  * on a self-hosted backend, and the three knobs aren't interchangeable: the
@@ -309,7 +316,7 @@ const interleave = (lists: OramaDoc[][], limit: number): OramaDoc[] => {
309
316
  *
310
317
  * Pages are indexed whole (one document each), so a naive head slice of a long
311
318
  * page returns its intro and misses sections below the fold — the exact failure
312
- * where "How does Ask AI work?" retrieves the right page but only sees its
319
+ * where "How does the assistant work?" retrieves the right page but only sees its
313
320
  * opening paragraph. This centers the window on the densest cluster of query
314
321
  * terms so the injected text is the part that actually answers the question.
315
322
  * Exported for testing; {@link createAskContext} is the runtime entry point.
@@ -585,7 +592,7 @@ export const sectionExcerpt = (
585
592
  ): string => excerptPage(parsePage(content), query, max);
586
593
 
587
594
  /**
588
- * Build the request-time grounding function for the Ask AI endpoint.
595
+ * Build the request-time grounding function for the assistant endpoint.
589
596
  *
590
597
  * Lexical retrieval over Orama (the same index/ranking the search dialog and MCP
591
598
  * server use). The index is built once and memoized across requests. Returns a
@@ -593,12 +600,12 @@ export const sectionExcerpt = (
593
600
  * viewing — or `undefined` when there is nothing to ground on, so the endpoint
594
601
  * can fall back to its plain prompt.
595
602
  *
596
- * `options.instructions` (the `ai.ask.instructions` config) is appended after
603
+ * `options.instructions` (the `ai.assistant.instructions` config) is appended after
597
604
  * the base instruction rather than replacing it: the base carries the
598
605
  * functional contract (answer only from the excerpts, cite pages as Markdown
599
606
  * links) that the panel's citation rendering depends on.
600
607
  *
601
- * `options.retrieval` (the `ai.ask.retrieval` config) sizes how much
608
+ * `options.retrieval` (the `ai.assistant.retrieval` config) sizes how much
602
609
  * documentation each question carries; omitted fields keep today's defaults.
603
610
  */
604
611
  export const createAskContext = (
@@ -644,12 +651,17 @@ export const createAskContext = (
644
651
  // which part of each page is quoted.
645
652
  const [query = ""] = queries;
646
653
 
647
- // The current page anchors retrieval to its locale and is injected first.
654
+ // The current page anchors retrieval to its locale and docs version, and
655
+ // is injected first. Without one, a versioned site grounds in the
656
+ // current docs rather than every archived copy of each page.
648
657
  const current = page?.path
649
658
  ? byRoute.get(normalizeRoute(page.path))
650
659
  : undefined;
651
660
  const db = await index();
652
- const filters = { locale: current?.locale || undefined };
661
+ const filters = {
662
+ locale: current?.locale || undefined,
663
+ version: data.versioned ? (current?.version ?? "") : undefined,
664
+ };
653
665
  const hits = interleave(
654
666
  await Promise.all(
655
667
  queries.map((text) => queryOramaIndex(db, text, maxResults, filters))
@@ -1,14 +1,17 @@
1
1
  import type { BlumeProject } from "../core/project-graph.ts";
2
2
  import { buildSearchDocuments } from "../search/documents.ts";
3
+ import type { OramaDoc } from "../search/orama-index.ts";
3
4
  import type { AskData } from "./ask-context.ts";
4
5
 
5
6
  /**
6
- * Build the grounding snapshot the Ask AI endpoint serves. Like the MCP server,
7
- * Ask AI is independent of on-page search, so documents are indexed even when the
8
- * search provider is `none` (`includeWhenDisabled`). `locale` is kept (unlike the
9
- * MCP snapshot) so retrieval can be filtered to the current page's language, and
10
- * content is kept as Markdown so grounding sees fenced code examples — the model
11
- * answers "what does the config look like?" from the docs instead of declining.
7
+ * Build the grounding snapshot the assistant endpoint serves. Like the MCP server,
8
+ * the assistant is independent of on-page search, so documents are indexed even when the
9
+ * search provider is `none` (`includeWhenDisabled`). `locale` is kept so
10
+ * retrieval can be filtered to the current page's language, and on a
11
+ * versioned site `version` too, so archived snapshots don't crowd the docs
12
+ * being read out of the answer. Content is kept as Markdown so grounding sees
13
+ * fenced code examples — the model answers "what does the config look like?"
14
+ * from the docs instead of declining.
12
15
  * The reader is an AI agent, so `<Visibility>` resolves for the agents audience
13
16
  * (web-only content removed, agents-only unwrapped) and components downlevel to
14
17
  * Markdown, both matching llms-full.txt.
@@ -19,15 +22,26 @@ export const buildAskData = async (project: BlumeProject): Promise<AskData> => {
19
22
  content: "markdown",
20
23
  includeWhenDisabled: true,
21
24
  });
22
- return {
25
+ const versioned = Boolean(project.config.versions);
26
+ const data: AskData = {
23
27
  defaultLocale: project.config.i18n?.defaultLocale,
24
- documents: documents.map((doc) => ({
25
- content: doc.content,
26
- description: doc.description,
27
- locale: doc.locale,
28
- route: doc.route,
29
- title: doc.title,
30
- })),
28
+ documents: documents.map((doc) => {
29
+ const document: OramaDoc = {
30
+ content: doc.content,
31
+ description: doc.description,
32
+ locale: doc.locale,
33
+ route: doc.route,
34
+ title: doc.title,
35
+ };
36
+ if (versioned) {
37
+ document.version = doc.version;
38
+ }
39
+ return document;
40
+ }),
31
41
  site: project.config.deployment.options.site ?? null,
32
42
  };
43
+ if (versioned) {
44
+ data.versioned = true;
45
+ }
46
+ return data;
33
47
  };