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
@@ -0,0 +1,203 @@
1
+ import {
2
+ objectProperties,
3
+ refName,
4
+ resolveSchema,
5
+ typeLabel,
6
+ } from "./helpers.ts";
7
+ import type { SchemaLike, SpecValue } from "./helpers.ts";
8
+
9
+ /**
10
+ * The expansion plan behind the schema tables (`SchemaTable.astro` and
11
+ * `SchemaProperty.astro`). Every nested object is server-rendered in full
12
+ * inside a collapsed `<details>`, so the plan is the page's weight: expanding
13
+ * each named schema wherever it appears — stopping only at a model nested in
14
+ * itself — grows exponentially with cross-references (twelve schemas that
15
+ * each reference four others render tens of thousands of nested tables for
16
+ * one request body).
17
+ *
18
+ * So a named schema expands wherever it appears in the first
19
+ * {@link REPEAT_DEPTH} named levels, and deeper than that only where it
20
+ * appears first in the tree, breadth-first; a later mention shows its name
21
+ * alone. Beyond the first levels each named schema expands at most once, so
22
+ * the tree stays proportional to the spec instead of to the number of paths
23
+ * through it, while the shallow nesting typical specs use — `billing` and
24
+ * `shipping` both an `Address` — renders exactly as before.
25
+ */
26
+
27
+ /**
28
+ * Named-schema nesting depth (the root being 0) up to which a named schema
29
+ * expands at every mention, even one already expanded elsewhere in the tree.
30
+ */
31
+ export const REPEAT_DEPTH = 2;
32
+
33
+ /** A place in the tree a node is planned into; filled in breadth-first. */
34
+ export interface SchemaSlot {
35
+ node: SchemaNode;
36
+ }
37
+
38
+ /** One property row of an object table. */
39
+ export interface SchemaRow {
40
+ name: string;
41
+ required: boolean;
42
+ schema: SchemaLike;
43
+ /** The row's disclosure contents; absent when the row has nothing to show. */
44
+ children?: SchemaSlot;
45
+ }
46
+
47
+ /** What one schema table renders. */
48
+ export type SchemaNode =
49
+ /** A named schema nested inside itself. */
50
+ | { kind: "circular"; name: string }
51
+ /** A named schema expanded elsewhere in this tree: its name only. */
52
+ | { kind: "named"; name: string }
53
+ | { kind: "array"; itemsLabel: string; items?: SchemaSlot }
54
+ | {
55
+ kind: "branches";
56
+ label: "One of" | "Any of";
57
+ branches: { label: string; slot: SchemaSlot }[];
58
+ }
59
+ | { kind: "properties"; rows: SchemaRow[] }
60
+ | { kind: "type"; label: string };
61
+
62
+ const isString = (value: SpecValue): value is string =>
63
+ typeof value === "string";
64
+
65
+ const typesOf = (schema: SchemaLike): (string | undefined)[] =>
66
+ Array.isArray(schema.type) ? schema.type : [schema.type];
67
+
68
+ /** Whether a schema has nested fields a row can disclose. */
69
+ const hasNestedFields = (candidate: SchemaLike): boolean =>
70
+ Boolean(
71
+ candidate.properties ||
72
+ candidate.allOf ||
73
+ candidate.oneOf ||
74
+ candidate.anyOf ||
75
+ isString(candidate.$ref)
76
+ );
77
+
78
+ /** A named schema waiting for its breadth-first turn. */
79
+ interface PendingRef {
80
+ ancestors: string[];
81
+ name: string;
82
+ schema: SchemaLike;
83
+ slot: SchemaSlot;
84
+ }
85
+
86
+ /** Plan the table tree for one schema (a request body, a response, a payload). */
87
+ export const schemaTree = (
88
+ root: SchemaLike,
89
+ schemas: Record<string, SchemaLike>
90
+ ): SchemaNode => {
91
+ const queue: PendingRef[] = [];
92
+ const expanded = new Set<string>();
93
+
94
+ /**
95
+ * A table for `schema`, where `ancestors` are the named schemas already
96
+ * open above it. A `$ref` waits in the queue, so every mention at one depth
97
+ * is planned before any deeper one; `resolved` plans a dequeued schema's
98
+ * own body instead.
99
+ */
100
+ const table = (
101
+ schema: SchemaLike,
102
+ ancestors: string[],
103
+ resolved = false
104
+ ): SchemaSlot => {
105
+ if (!resolved && isString(schema.$ref)) {
106
+ const name = refName(schema.$ref);
107
+ if (ancestors.includes(name)) {
108
+ return { node: { kind: "circular", name } };
109
+ }
110
+ const slot: SchemaSlot = { node: { kind: "named", name } };
111
+ queue.push({ ancestors, name, schema, slot });
112
+ return slot;
113
+ }
114
+ if (typesOf(schema).includes("array")) {
115
+ // Items stay unresolved, so a self-referential item `$ref` is still
116
+ // recognized as the circle it is.
117
+ const { items } = schema;
118
+ return {
119
+ node: items
120
+ ? {
121
+ items: table(items, ancestors),
122
+ itemsLabel: typeLabel(items),
123
+ kind: "array",
124
+ }
125
+ : { itemsLabel: typeLabel({}), kind: "array" },
126
+ };
127
+ }
128
+ const branches = schema.oneOf ?? schema.anyOf;
129
+ if (branches) {
130
+ return {
131
+ node: {
132
+ branches: branches.map((branch, index) => ({
133
+ label: typeLabel(branch) || `Option ${index + 1}`,
134
+ slot: table(branch, ancestors),
135
+ })),
136
+ kind: "branches",
137
+ label: schema.oneOf ? "One of" : "Any of",
138
+ },
139
+ };
140
+ }
141
+ // A row discloses nested structure — never a model inside itself.
142
+ const rowChildren = (property: SchemaLike): SchemaSlot | undefined => {
143
+ if (
144
+ isString(property.$ref) &&
145
+ ancestors.includes(refName(property.$ref))
146
+ ) {
147
+ return undefined;
148
+ }
149
+ const target = resolveSchema(schemas, property);
150
+ const items = typesOf(target).includes("array")
151
+ ? resolveSchema(schemas, target.items)
152
+ : null;
153
+ return hasNestedFields(target) || (items && hasNestedFields(items))
154
+ ? table(property, ancestors)
155
+ : undefined;
156
+ };
157
+ const { properties, required } = objectProperties(schema, schemas);
158
+ if (properties.length > 0) {
159
+ return {
160
+ node: {
161
+ kind: "properties",
162
+ rows: properties.map(([name, property]) => ({
163
+ children: rowChildren(property),
164
+ name,
165
+ required: required.has(name),
166
+ schema: property,
167
+ })),
168
+ },
169
+ };
170
+ }
171
+ return { node: { kind: "type", label: typeLabel(schema) } };
172
+ };
173
+
174
+ const tree = table(root, []);
175
+ // The queue grows while it drains, in depth order: every mention at one
176
+ // named depth is queued before the first one at the next.
177
+ for (const pending of queue) {
178
+ const depth = pending.ancestors.length;
179
+ if (depth > REPEAT_DEPTH && expanded.has(pending.name)) {
180
+ continue;
181
+ }
182
+ expanded.add(pending.name);
183
+ pending.slot.node = table(
184
+ resolveSchema(schemas, pending.schema),
185
+ [...pending.ancestors, pending.name],
186
+ true
187
+ ).node;
188
+ }
189
+ return tree.node;
190
+ };
191
+
192
+ /**
193
+ * Whether a row gets a disclosure: it has nested structure, and that structure
194
+ * isn't just the name of a schema expanded elsewhere (directly, or as the
195
+ * items of an array).
196
+ */
197
+ export const rowExpands = (row: SchemaRow): boolean => {
198
+ const node = row.children?.node;
199
+ if (!node || node.kind === "named") {
200
+ return false;
201
+ }
202
+ return !(node.kind === "array" && node.items?.node.kind === "named");
203
+ };
@@ -22,26 +22,42 @@ const headerLines = (
22
22
  ): string[] =>
23
23
  Object.entries(headers).map(([key, value]) => format(key, value));
24
24
 
25
+ /**
26
+ * A single-quoted POSIX shell word. Nothing expands inside single quotes — no
27
+ * `$`, backtick, `!`, or `\` — so a value reaches curl byte for byte; a
28
+ * literal `'` closes the quote, adds an escaped one, and reopens it.
29
+ */
30
+ const shellQuote = (value: string): string =>
31
+ `'${value.replaceAll("'", String.raw`'\''`)}'`;
32
+
33
+ /**
34
+ * A double-quoted string literal for the JavaScript and Python samples. JSON's
35
+ * string escapes are a subset of both languages' — a quote in a header value
36
+ * (`If-Match: "33a64df5"`) or a backslash becomes an escape rather than
37
+ * ending the literal early.
38
+ */
39
+ const stringLiteral = (value: string): string => JSON.stringify(value);
40
+
25
41
  const curlSnippet = (sample: RequestSample): string => {
26
42
  const lines = [
27
- `curl -X ${sample.method} "${sample.url}"`,
28
- ...headerLines(sample.headers, (key, value) => ` -H "${key}: ${value}"`),
43
+ `curl -X ${sample.method} ${shellQuote(sample.url)}`,
44
+ ...headerLines(
45
+ sample.headers,
46
+ (key, value) => ` -H ${shellQuote(`${key}: ${value}`)}`
47
+ ),
29
48
  ];
30
49
  if (sample.body) {
31
- // Close-quote/escaped-quote/reopen: the POSIX way to put a literal ' in a
32
- // single-quoted string, so an example like "it's" doesn't break the shell.
33
- const escapedBody = sample.body.replaceAll("'", String.raw`'\''`);
34
- lines.push(` -d '${escapedBody}'`);
50
+ lines.push(` -d ${shellQuote(sample.body)}`);
35
51
  }
36
52
  return lines.join(" \\\n");
37
53
  };
38
54
 
39
55
  const fetchSnippet = (sample: RequestSample): string => {
40
- const options = [` method: "${sample.method}"`];
56
+ const options = [` method: ${stringLiteral(sample.method)}`];
41
57
  if (Object.keys(sample.headers).length > 0) {
42
58
  const headers = headerLines(
43
59
  sample.headers,
44
- (key, value) => ` "${key}": "${value}"`
60
+ (key, value) => ` ${stringLiteral(key)}: ${stringLiteral(value)}`
45
61
  ).join(",\n");
46
62
  options.push(` headers: {\n${headers}\n }`);
47
63
  }
@@ -53,28 +69,27 @@ const fetchSnippet = (sample: RequestSample): string => {
53
69
  // and an id past 2^53 loses digits through a JS number. The string
54
70
  // literal also stays syntactically valid while the editor holds mid-edit
55
71
  // text that isn't JSON yet.
56
- options.push(` body: ${JSON.stringify(sample.body)}`);
72
+ options.push(` body: ${stringLiteral(sample.body)}`);
57
73
  }
58
- return `const response = await fetch("${sample.url}", {\n${options.join(
74
+ return `const response = await fetch(${stringLiteral(sample.url)}, {\n${options.join(
59
75
  ",\n"
60
76
  )}\n});`;
61
77
  };
62
78
 
63
79
  const pythonSnippet = (sample: RequestSample): string => {
64
- const args = [` "${sample.url}"`];
80
+ const args = [` ${stringLiteral(sample.url)}`];
65
81
  if (Object.keys(sample.headers).length > 0) {
66
82
  const headers = headerLines(
67
83
  sample.headers,
68
- (key, value) => ` "${key}": "${value}"`
84
+ (key, value) => ` ${stringLiteral(key)}: ${stringLiteral(value)}`
69
85
  ).join(",\n");
70
86
  args.push(` headers={\n${headers}\n }`);
71
87
  }
72
88
  if (sample.body) {
73
89
  // Same rule as the fetch snippet: the raw text travels as a string via
74
- // `data=` (JSON string escapes are a subset of Python's, so the literal is
75
- // valid) rather than a `json=` dict — a Python literal re-serializes
90
+ // `data=` rather than a `json=` dict — a Python literal re-serializes
76
91
  // `1e400` as `Infinity` and would otherwise diverge from the live send.
77
- args.push(` data=${JSON.stringify(sample.body)}`);
92
+ args.push(` data=${stringLiteral(sample.body)}`);
78
93
  }
79
94
  return `import requests\n\nresponse = requests.${sample.method.toLowerCase()}(\n${args.join(
80
95
  ",\n"
@@ -74,7 +74,7 @@ const walk = (
74
74
  path: string,
75
75
  errors: string[]
76
76
  ): void => {
77
- if (!schema) {
77
+ if (!schema || (value === null && schema.nullable === true)) {
78
78
  return;
79
79
  }
80
80
  if (schema.type !== undefined && !matchesType(value, schema.type)) {
@@ -88,6 +88,21 @@ export const withBasePath = (basePath: string, route: string): string => {
88
88
  return route === "/" ? basePath : `${basePath}${route}`;
89
89
  };
90
90
 
91
+ /**
92
+ * Mount a route Blume generates from content under `basePath`,
93
+ * unconditionally. {@link withBasePath} leaves a route that already starts
94
+ * with the base alone, which is right for a link an author based by hand but
95
+ * wrong for a content route: with `basePath: "/docs"`, `docs/guide.md` routes
96
+ * to `/docs/guide` before the base and publishes at `/docs/docs/guide`, not on
97
+ * top of the root `guide.md`.
98
+ */
99
+ export const mountBasePath = (basePath: string, route: string): string => {
100
+ if (!basePath) {
101
+ return route;
102
+ }
103
+ return route === "/" ? basePath : `${basePath}${route}`;
104
+ };
105
+
91
106
  /**
92
107
  * {@link withBasePath} for the composed `deployment.base` + `basePath` stack
93
108
  * (`/base` + `/docs` serves pages at `/base/docs/x`). The hand-written-base
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Fenced-code state for line scanners. Kept free of imports so request-time
3
- * code (the Ask AI grounding excerpts) can share it with the build-time source
3
+ * code (the assistant's grounding excerpts) can share it with the build-time source
4
4
  * scanners without pulling the filesystem and schema modules along.
5
5
  *
6
6
  * CommonMark allows backtick *and* tilde fences, three or more characters
@@ -2,7 +2,7 @@ import type { AstroIntegration } from "astro";
2
2
  import type { z } from "zod";
3
3
 
4
4
  import type { AskRetrievalOptions } from "../ai/ask-context.ts";
5
- import type { AskAdapter } from "../ai/ask.ts";
5
+ import type { AssistantAdapter } from "../ai/ask.ts";
6
6
  import type { ComponentMarkdown } from "../ai/component-markdown.ts";
7
7
  import type { AnalyticsAdapter } from "../analytics/schema.ts";
8
8
  import type { DeploymentInput } from "../deploy/adapters/registry.ts";
@@ -488,16 +488,16 @@ export type SearchConfig = SearchProviderConfig | SearchOptions;
488
488
  // AI
489
489
  // ---------------------------------------------------------------------------
490
490
 
491
- /** An empty-state prompt shown before the first Ask AI question. */
492
- export interface AskSuggestion {
491
+ /** An empty-state prompt shown before the first question to the assistant. */
492
+ export interface AssistantSuggestion {
493
493
  /** Lucide icon name shown beside the suggestion. */
494
494
  icon?: string;
495
495
  /** The clickable suggestion text. */
496
496
  label: string;
497
497
  }
498
498
 
499
- /** How much retrieved documentation each Ask AI question carries. */
500
- export interface AskRetrievalConfig {
499
+ /** How much retrieved documentation each question to the assistant carries. */
500
+ export interface AssistantRetrievalConfig {
501
501
  /**
502
502
  * Total injected documentation characters, across all excerpts. Defaults to
503
503
  * `10000`. The single biggest lever on time-to-first-token — the model reads
@@ -518,8 +518,8 @@ export interface AskRetrievalConfig {
518
518
  maxResults?: number;
519
519
  }
520
520
 
521
- /** The Ask AI chat assistant. */
522
- export interface AskConfig {
521
+ /** The chat assistant. */
522
+ export interface AssistantConfig {
523
523
  /**
524
524
  * Origins allowed to call the generated endpoint from another site — a
525
525
  * marketing page that embeds an ask box, for example — or `"*"` to allow
@@ -532,10 +532,10 @@ export interface AskConfig {
532
532
  * combined with it.
533
533
  */
534
534
  cors?: string[];
535
- /** Turn Ask AI on. Defaults to `false`. */
535
+ /** Turn the assistant on. Defaults to `false`. */
536
536
  enabled?: boolean;
537
537
  /**
538
- * Existing Ask AI endpoint to call instead of generating one. This keeps a
538
+ * Existing assistant endpoint to call instead of generating one. This keeps a
539
539
  * Blume site static while an API backend owns retrieval, model access, rate
540
540
  * limiting, and streaming. Accepts an absolute URL or root-relative path.
541
541
  */
@@ -555,15 +555,15 @@ export interface AskConfig {
555
555
  * mapping, and `providerOptions` passthrough. Defaults to
556
556
  * `gateway({ model: "openai/gpt-5.5" })`.
557
557
  */
558
- provider?: AskAdapter;
558
+ provider?: AssistantAdapter;
559
559
  /**
560
560
  * How much documentation each question carries into the model's prompt.
561
561
  * Lower values cut time-to-first-token — which dominates on a self-hosted
562
562
  * backend — at the cost of recall. Defaults keep the built-in behavior.
563
563
  */
564
- retrieval?: AskRetrievalConfig;
564
+ retrieval?: AssistantRetrievalConfig;
565
565
  /** Starter prompts shown before the first question. */
566
- suggestions?: AskSuggestion[];
566
+ suggestions?: AssistantSuggestion[];
567
567
  }
568
568
 
569
569
  /** What the AI Catalog (ARD) manifest carries. */
@@ -596,14 +596,14 @@ export interface LlmsTxtConfig {
596
596
  /**
597
597
  * Markdown placed after the title and summary in `llms.txt`, before the
598
598
  * page sections — the llms.txt spec's "details" block. Use it to tell
599
- * agents when to reach for the product and how to call it (a "When to use"
600
- * heading, the install command, the package name). Blank values are
601
- * dropped.
599
+ * agents when to reach for the product and how to call it (the install
600
+ * command, the package name). The spec allows any Markdown there but
601
+ * headings. Blank values are dropped.
602
602
  *
603
603
  * ```ts
604
604
  * agents: {
605
605
  * llmsTxt: {
606
- * details: "## When to use Acme\n\nUse Acme when…",
606
+ * details: "Use Acme when…",
607
607
  * },
608
608
  * }
609
609
  * ```
@@ -631,10 +631,10 @@ export interface McpConfig {
631
631
  route?: string;
632
632
  }
633
633
 
634
- /** Model-facing features: the Ask AI assistant and the "Open in chat" action. */
634
+ /** Model-facing features: the assistant and the "Open in chat" action. */
635
635
  export interface AiConfig {
636
- /** The Ask AI chat assistant. */
637
- ask?: AskConfig;
636
+ /** The chat assistant. */
637
+ assistant?: AssistantConfig;
638
638
  /**
639
639
  * The "Open in chat" page action, which opens the current page in an AI
640
640
  * assistant pre-filled with a prompt pointing at its raw Markdown.
@@ -833,7 +833,7 @@ export type ContentSignalsConfig =
833
833
  /**
834
834
  * The machine-readable surface agents consume: the JSON API, `llms.txt`, the
835
835
  * MCP server, published skills, discovery manifests, and the robots.txt usage
836
- * policy. The reader-facing model features (Ask AI, Open in chat) live under
836
+ * policy. The reader-facing model features (the assistant, Open in chat) live under
837
837
  * `ai`.
838
838
  */
839
839
  export interface AgentsConfig {
@@ -1331,7 +1331,7 @@ export type TocConfig =
1331
1331
  export interface BlumeConfig {
1332
1332
  /** The machine-readable surface for agents: JSON API, `llms.txt`, MCP, skills, discovery. */
1333
1333
  agents?: AgentsConfig;
1334
- /** Model-facing features: the Ask AI assistant and the "Open in chat" action. */
1334
+ /** Model-facing features: the assistant and the "Open in chat" action. */
1335
1335
  ai?: AiConfig;
1336
1336
  /**
1337
1337
  * Analytics adapters from `blume/analytics`, emitted into `<head>` of every
@@ -1452,10 +1452,10 @@ type _NoExtraOrMissingKeys = AssertExtends<
1452
1452
  // endpoint and silently ignored at request time). `Required` makes a rename in
1453
1453
  // either copy a missing property, which stops compiling.
1454
1454
  type _AskRetrievalMatchesRuntime = AssertExtends<
1455
- Required<AskRetrievalConfig>,
1455
+ Required<AssistantRetrievalConfig>,
1456
1456
  Required<AskRetrievalOptions>
1457
1457
  >;
1458
1458
  type _AskRuntimeMatchesRetrieval = AssertExtends<
1459
1459
  Required<AskRetrievalOptions>,
1460
- Required<AskRetrievalConfig>
1460
+ Required<AssistantRetrievalConfig>
1461
1461
  >;
@@ -1,5 +1,6 @@
1
1
  import { existsSync, readFileSync } from "node:fs";
2
2
 
3
+ import { basename } from "pathe";
3
4
  import { z } from "zod";
4
5
 
5
6
  import type { BlumeConfig } from "./config-input.ts";
@@ -9,7 +10,7 @@ import {
9
10
  diagnosticsFromIssues,
10
11
  diagnosticsFromZod,
11
12
  } from "./diagnostics.ts";
12
- import { createModuleLoader } from "./load-module.ts";
13
+ import { createDefaultExportLoader } from "./load-module.ts";
13
14
  import { findConfigFile } from "./project.ts";
14
15
  import { blumeConfigSchema } from "./schema.ts";
15
16
  import type { ResolvedConfig } from "./schema.ts";
@@ -68,8 +69,8 @@ import type { Diagnostic } from "./types.ts";
68
69
  * - `theme` — `accent` color, `fonts` (curated slugs, any provider family, or
69
70
  * local font files), `radius`,
70
71
  * `mode` (`system`/`light`/`dark`), and `background`.
71
- * - `markdown` — `code` (language icons, inline highlighting, line wrap),
72
- * `headingAnchors`, `imageZoom`, and opt-in KaTeX `math`.
72
+ * - `markdown` — `code` (language icons, light/dark Shiki `theme`, line
73
+ * `wrap`), `externalLinks`, `headingAnchors`, and `imageZoom`.
73
74
  * - `toc` — on-page table of contents; `true`/`false` or a heading-level range.
74
75
  * - `lastModified` — "Last updated" stamps from `git` history or frontmatter.
75
76
  * - `feedback` — the per-page "Was this helpful?" widget (on by default).
@@ -87,7 +88,7 @@ import type { Diagnostic } from "./types.ts";
87
88
  * `flexsearch()`, `pagefind()`, `algolia({…})`, `oramaCloud({…})`,
88
89
  * `typesense({…})`, `mixedbread({…})`, or `false`), or `{ provider,
89
90
  * popular, indexing }` to add curated links and indexing settings.
90
- * - `ai` — what faces a model at read time: `ask` (the Ask AI assistant, with
91
+ * - `ai` — what faces a model at read time: `assistant` (the chat assistant, with
91
92
  * a provider adapter from `blume/ai` such as `gateway()` or `openrouter()`)
92
93
  * and `openInChat` (the "Open in chat" page action).
93
94
  * - `agents` — the machine-readable surface: `llmsTxt`, the JSON `api`, the
@@ -146,7 +147,7 @@ import type { Diagnostic } from "./types.ts";
146
147
  * });
147
148
  * ```
148
149
  *
149
- * @example An OpenAPI reference with the Ask AI assistant enabled.
150
+ * @example An OpenAPI reference with the assistant enabled.
150
151
  * ```ts
151
152
  * import { openapi } from "blume/reference";
152
153
  *
@@ -159,7 +160,7 @@ import type { Diagnostic } from "./types.ts";
159
160
  * }),
160
161
  * ],
161
162
  * agents: { llmsTxt: true },
162
- * ai: { ask: { enabled: true } },
163
+ * ai: { assistant: { enabled: true } },
163
164
  * });
164
165
  * ```
165
166
  *
@@ -199,7 +200,7 @@ export interface ConfigLoadResult {
199
200
  themeFontsConfigured: boolean;
200
201
  }
201
202
 
202
- const importConfigModule = createModuleLoader();
203
+ const importConfigModule = createDefaultExportLoader();
203
204
 
204
205
  /**
205
206
  * The slice of a user config module probed before schema defaults apply:
@@ -290,6 +291,19 @@ export const loadConfig = async (
290
291
  severity: "error",
291
292
  });
292
293
  }
294
+ // Validating whatever else the module holds would build a silent default
295
+ // site (a bare `defineConfig({…})` call) or reject a named `config` export
296
+ // as an unknown key, neither of which names the actual mistake.
297
+ if (raw === undefined) {
298
+ throw new BlumeError({
299
+ code: "BLUME_CONFIG_INVALID",
300
+ file: configFile,
301
+ message: `${basename(configFile)} has no default export, so Blume can't read its config.`,
302
+ severity: "error",
303
+ suggestion:
304
+ "Export the config as the file's default: `export default defineConfig({ … })`.",
305
+ });
306
+ }
293
307
  }
294
308
 
295
309
  // Read before parsing: schema defaults erase the set-vs-defaulted distinction.
package/src/core/data.ts CHANGED
@@ -122,10 +122,10 @@ export interface BlumeDataConfig {
122
122
  analytics: ResolvedConfig["analytics"];
123
123
  /** Apple touch icon, or `null` when none is configured/detected. */
124
124
  appleIcon: BlumeFavicon | null;
125
- /** Ask AI empty-state suggestions, or `null` when Ask AI is off. */
126
- ask: {
125
+ /** The assistant's empty-state suggestions, or `null` when the assistant is off. */
126
+ assistant: {
127
127
  endpoint: string | null;
128
- suggestions: NonNullable<ResolvedConfig["ai"]["ask"]>["suggestions"];
128
+ suggestions: NonNullable<ResolvedConfig["ai"]["assistant"]>["suggestions"];
129
129
  } | null;
130
130
  banner: BlumeBanner | null;
131
131
  /** Site-wide route mount point, normalized to `""` or `/seg` (see config). */