blume 2.0.3 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (607) hide show
  1. package/AGENTS.md +1 -0
  2. package/CHANGELOG.md +142 -0
  3. package/README.md +1 -1
  4. package/dist/cli/{chunk-5f86nr5m.js → chunk-073rdvgb.js} +21 -48
  5. package/dist/cli/{chunk-5f86nr5m.js.map → chunk-073rdvgb.js.map} +4 -5
  6. package/dist/cli/{chunk-ga0pf4aj.js → chunk-0n9xkp3d.js} +12 -3
  7. package/dist/cli/{chunk-ga0pf4aj.js.map → chunk-0n9xkp3d.js.map} +3 -3
  8. package/dist/cli/chunk-150jk7km.js +52 -0
  9. package/dist/cli/chunk-150jk7km.js.map +10 -0
  10. package/dist/cli/{chunk-9t7a85s3.js → chunk-313vnn40.js} +30 -19
  11. package/dist/cli/chunk-313vnn40.js.map +10 -0
  12. package/dist/cli/{chunk-tkacnehg.js → chunk-3v3ffbrj.js} +2 -2
  13. package/dist/cli/{chunk-q58y5e6a.js → chunk-3x6x3pph.js} +46 -24
  14. package/dist/cli/chunk-3x6x3pph.js.map +10 -0
  15. package/dist/cli/{chunk-1d7ve1dm.js → chunk-42t4jxdx.js} +37 -5
  16. package/dist/cli/chunk-42t4jxdx.js.map +12 -0
  17. package/dist/cli/{chunk-8ktnccpt.js → chunk-54ztw1nj.js} +21 -2
  18. package/dist/cli/chunk-54ztw1nj.js.map +10 -0
  19. package/dist/cli/{chunk-hm3vjy5s.js → chunk-5vjtgs6e.js} +28 -10
  20. package/dist/cli/{chunk-hm3vjy5s.js.map → chunk-5vjtgs6e.js.map} +4 -4
  21. package/dist/cli/chunk-66w9j7p6.js +322 -0
  22. package/dist/cli/chunk-66w9j7p6.js.map +14 -0
  23. package/dist/cli/{chunk-2hsdwb9n.js → chunk-7ppf1rva.js} +34 -18
  24. package/dist/cli/chunk-7ppf1rva.js.map +10 -0
  25. package/dist/cli/{chunk-r9rcc4w7.js → chunk-8y2kmjv8.js} +7 -7
  26. package/dist/cli/{chunk-r20tn01b.js → chunk-c1y538kd.js} +8 -2
  27. package/dist/cli/{chunk-r20tn01b.js.map → chunk-c1y538kd.js.map} +3 -3
  28. package/dist/cli/{chunk-2eytanqx.js → chunk-c887fj0s.js} +2 -2
  29. package/dist/cli/{chunk-p3v96n38.js → chunk-cfyg47zg.js} +16 -6
  30. package/dist/cli/chunk-cfyg47zg.js.map +10 -0
  31. package/dist/cli/chunk-cm89scdv.js +443 -0
  32. package/dist/cli/chunk-cm89scdv.js.map +11 -0
  33. package/dist/cli/{chunk-akbpwfxc.js → chunk-dzwehpy7.js} +2 -2
  34. package/dist/cli/{chunk-wrr3j9w9.js → chunk-e6atmn4h.js} +299 -72
  35. package/dist/cli/chunk-e6atmn4h.js.map +36 -0
  36. package/dist/cli/{chunk-tzmab476.js → chunk-e8xw9qkh.js} +8 -6
  37. package/dist/cli/{chunk-tzmab476.js.map → chunk-e8xw9qkh.js.map} +3 -3
  38. package/dist/cli/{chunk-6dsbexzp.js → chunk-e9q7a2ak.js} +17 -15
  39. package/dist/cli/{chunk-6dsbexzp.js.map → chunk-e9q7a2ak.js.map} +2 -2
  40. package/dist/cli/{chunk-pv29h0wf.js → chunk-ehweg4fr.js} +5155 -1249
  41. package/dist/cli/chunk-ehweg4fr.js.map +218 -0
  42. package/dist/cli/{chunk-c8chx29p.js → chunk-ep6nd0rn.js} +390 -318
  43. package/dist/cli/chunk-ep6nd0rn.js.map +36 -0
  44. package/dist/cli/{chunk-p73c0m7w.js → chunk-fdrkhpjy.js} +18 -15
  45. package/dist/cli/{chunk-p73c0m7w.js.map → chunk-fdrkhpjy.js.map} +3 -3
  46. package/dist/cli/{chunk-2z928egk.js → chunk-ft9vfys6.js} +5 -5
  47. package/dist/cli/{chunk-5m5nmvyq.js → chunk-gb420vvz.js} +316 -79
  48. package/dist/cli/chunk-gb420vvz.js.map +17 -0
  49. package/dist/cli/{chunk-vg9r4eb9.js → chunk-hebn0tpx.js} +86 -13
  50. package/dist/cli/chunk-hebn0tpx.js.map +14 -0
  51. package/dist/cli/{chunk-35d4wj9f.js → chunk-htrwgabr.js} +41 -23
  52. package/dist/cli/chunk-htrwgabr.js.map +15 -0
  53. package/dist/cli/{chunk-g4hq16wv.js → chunk-hx3xqnk9.js} +16 -14
  54. package/dist/cli/{chunk-g4hq16wv.js.map → chunk-hx3xqnk9.js.map} +2 -2
  55. package/dist/cli/chunk-j134vrp2.js +65 -0
  56. package/dist/cli/chunk-j134vrp2.js.map +10 -0
  57. package/dist/cli/{chunk-a58773jm.js → chunk-kma9f6sf.js} +2 -2
  58. package/dist/cli/chunk-kwrg63tm.js +31 -0
  59. package/dist/cli/chunk-kwrg63tm.js.map +10 -0
  60. package/dist/cli/{chunk-ey84smr6.js → chunk-mrcccgnh.js} +6 -6
  61. package/dist/cli/{chunk-ey84smr6.js.map → chunk-mrcccgnh.js.map} +1 -1
  62. package/dist/cli/{chunk-yfyb25rh.js → chunk-n0v7m8ry.js} +24 -8
  63. package/dist/cli/chunk-n0v7m8ry.js.map +14 -0
  64. package/dist/cli/{chunk-j85vccga.js → chunk-ncj7w596.js} +576 -367
  65. package/dist/cli/chunk-ncj7w596.js.map +35 -0
  66. package/dist/cli/{chunk-5xvm6tfj.js → chunk-nq1d20w2.js} +17 -15
  67. package/dist/cli/{chunk-5xvm6tfj.js.map → chunk-nq1d20w2.js.map} +2 -2
  68. package/dist/cli/{chunk-pehfxfta.js → chunk-nrns10mj.js} +6 -98
  69. package/dist/cli/chunk-nrns10mj.js.map +10 -0
  70. package/dist/cli/{chunk-crgn1q09.js → chunk-sds923fa.js} +4 -4
  71. package/dist/cli/chunk-t2m5j4pr.js +104 -0
  72. package/dist/cli/chunk-t2m5j4pr.js.map +11 -0
  73. package/dist/cli/{chunk-acanzt5p.js → chunk-tdqhyxfz.js} +6 -6
  74. package/dist/cli/chunk-tphac74f.js +126 -0
  75. package/dist/cli/chunk-tphac74f.js.map +11 -0
  76. package/dist/cli/chunk-w1r4vase.js +18 -0
  77. package/dist/cli/chunk-w1r4vase.js.map +10 -0
  78. package/dist/cli/{chunk-3em5wd2y.js → chunk-zccbjcj0.js} +4 -3
  79. package/dist/cli/{chunk-3em5wd2y.js.map → chunk-zccbjcj0.js.map} +2 -2
  80. package/dist/cli/index.js +31 -20
  81. package/dist/cli/index.js.map +5 -5
  82. package/dist/types/ai/agent-surface.d.ts +8 -7
  83. package/dist/types/ai/ai-catalog.d.ts +7 -0
  84. package/dist/types/ai/ask-context.d.ts +26 -0
  85. package/dist/types/ai/ask.d.ts +271 -58
  86. package/dist/types/ai/component-markdown.d.ts +2 -0
  87. package/dist/types/ai/index.d.ts +2 -2
  88. package/dist/types/ai/openapi-components.d.ts +4 -1
  89. package/dist/types/ai/site-skill.d.ts +26 -0
  90. package/dist/types/ai/skills.d.ts +16 -0
  91. package/dist/types/astro/integration.d.ts +9 -0
  92. package/dist/types/astro/markdown-negotiation.d.ts +3 -0
  93. package/dist/types/astro/pages.d.ts +10 -0
  94. package/dist/types/captcha/hcaptcha.d.ts +27 -0
  95. package/dist/types/captcha/index.d.ts +28 -0
  96. package/dist/types/captcha/schema.d.ts +29 -0
  97. package/dist/types/captcha/turnstile.d.ts +28 -0
  98. package/dist/types/cli/init/scaffold.d.ts +1 -1
  99. package/dist/types/components/content/api-field.d.ts +62 -0
  100. package/dist/types/components/content/api-page.d.ts +100 -0
  101. package/dist/types/components/layout/nav-utils.d.ts +26 -0
  102. package/dist/types/components/openapi/code-samples.d.ts +29 -0
  103. package/dist/types/components/openapi/helpers.d.ts +158 -0
  104. package/dist/types/components/openapi/security.d.ts +95 -0
  105. package/dist/types/components/openapi/snippets.d.ts +60 -0
  106. package/dist/types/consent/ethyca.d.ts +48 -0
  107. package/dist/types/consent/index.d.ts +37 -0
  108. package/dist/types/consent/native.d.ts +28 -0
  109. package/dist/types/consent/osano.d.ts +42 -0
  110. package/dist/types/consent/schema.d.ts +110 -0
  111. package/dist/types/core/changelog-index.d.ts +8 -0
  112. package/dist/types/core/config-input.d.ts +217 -23
  113. package/dist/types/core/data.d.ts +53 -4
  114. package/dist/types/core/footer.d.ts +8 -0
  115. package/dist/types/core/i18n-ui.d.ts +88 -0
  116. package/dist/types/core/includes.d.ts +8 -2
  117. package/dist/types/core/links.d.ts +8 -0
  118. package/dist/types/core/localizable.d.ts +7 -0
  119. package/dist/types/core/page-modes.d.ts +29 -0
  120. package/dist/types/core/probe.d.ts +2 -0
  121. package/dist/types/core/project-graph.d.ts +6 -0
  122. package/dist/types/core/redirect-patterns.d.ts +152 -0
  123. package/dist/types/core/related.d.ts +40 -0
  124. package/dist/types/core/schema.d.ts +670 -56
  125. package/dist/types/core/sources/cache.d.ts +3 -0
  126. package/dist/types/core/sources/contentful-rich-text.d.ts +11 -2
  127. package/dist/types/core/sources/contentful.d.ts +17 -1
  128. package/dist/types/core/sources/lexical.d.ts +5 -0
  129. package/dist/types/core/sources/normalize.d.ts +20 -1
  130. package/dist/types/core/sources/read.d.ts +5 -0
  131. package/dist/types/core/sources/remote.d.ts +37 -10
  132. package/dist/types/core/sources/sanity.d.ts +1 -1
  133. package/dist/types/core/types.d.ts +18 -1
  134. package/dist/types/core/variables.d.ts +42 -0
  135. package/dist/types/deploy/adapter-output.d.ts +2 -1
  136. package/dist/types/deploy/adapters/cloudflare.d.ts +7 -5
  137. package/dist/types/deploy/adapters/node.d.ts +58 -23
  138. package/dist/types/deploy/adapters/registry.d.ts +10 -0
  139. package/dist/types/deploy/adapters/types.d.ts +3 -2
  140. package/dist/types/deploy/node-headers.d.ts +13 -2
  141. package/dist/types/deploy/platforms/cloudflare.d.ts +15 -7
  142. package/dist/types/deploy/platforms/netlify.d.ts +7 -0
  143. package/dist/types/deploy/platforms/node.d.ts +3 -1
  144. package/dist/types/deploy/platforms/types.d.ts +18 -7
  145. package/dist/types/deploy/platforms/vercel.d.ts +26 -1
  146. package/dist/types/deploy/redirects.d.ts +55 -11
  147. package/dist/types/deploy/sitemap.d.ts +2 -1
  148. package/dist/types/deploy/vercel-negotiation.d.ts +51 -21
  149. package/dist/types/markdown/code-title.d.ts +17 -0
  150. package/dist/types/markdown/features.d.ts +3 -2
  151. package/dist/types/narration/build.d.ts +70 -0
  152. package/dist/types/narration/provider.d.ts +26 -0
  153. package/dist/types/narration/script.d.ts +154 -0
  154. package/dist/types/openapi/checks.d.ts +27 -0
  155. package/dist/types/openapi/graphql.d.ts +6 -0
  156. package/dist/types/openapi/model.d.ts +27 -10
  157. package/dist/types/openapi/overlay.d.ts +54 -0
  158. package/dist/types/openapi/parse.d.ts +16 -0
  159. package/dist/types/openapi/references.d.ts +30 -4
  160. package/dist/types/ratelimit/cloudflare.d.ts +39 -0
  161. package/dist/types/ratelimit/index.d.ts +27 -0
  162. package/dist/types/ratelimit/memory.d.ts +36 -0
  163. package/dist/types/ratelimit/schema.d.ts +119 -0
  164. package/dist/types/ratelimit/upstash.d.ts +46 -0
  165. package/dist/types/ratelimit/wrangler.d.ts +23 -0
  166. package/dist/types/reference/asyncapi.d.ts +10 -10
  167. package/dist/types/reference/graphql.d.ts +89 -11
  168. package/dist/types/reference/index.d.ts +1 -1
  169. package/dist/types/reference/openapi.d.ts +33 -12
  170. package/dist/types/reference/options.d.ts +82 -6
  171. package/dist/types/reference/scalar.d.ts +13 -0
  172. package/dist/types/reference/schema.d.ts +144 -36
  173. package/dist/types/search/adapters/registry.d.ts +3 -0
  174. package/dist/types/search/adapters/typesense.d.ts +14 -4
  175. package/dist/types/search/build.d.ts +3 -1
  176. package/dist/types/search/documents.d.ts +12 -1
  177. package/dist/types/search/orama-index.d.ts +13 -9
  178. package/dist/types/search/sync/algolia.d.ts +5 -2
  179. package/dist/types/search/sync/index.d.ts +3 -1
  180. package/dist/types/search/sync/typesense.d.ts +11 -7
  181. package/dist/types/seo/metatags.d.ts +20 -0
  182. package/dist/types/sources/contentful.d.ts +16 -0
  183. package/dist/types/sources/github-releases.d.ts +8 -1
  184. package/dist/types/sources/payload.d.ts +2 -0
  185. package/dist/types/sources/registry.d.ts +54 -0
  186. package/dist/types/sources/shared.d.ts +3 -0
  187. package/dist/types/sources/strapi.d.ts +2 -0
  188. package/docs/01-quickstart.mdx +4 -2
  189. package/docs/02-deployment.mdx +71 -17
  190. package/docs/03-upgrading.mdx +4 -4
  191. package/docs/04-migrating.mdx +1 -1
  192. package/docs/advanced/changelog.mdx +13 -2
  193. package/docs/advanced/skills.mdx +15 -1
  194. package/docs/cli/audit.mdx +51 -8
  195. package/docs/cli/doctor.mdx +5 -1
  196. package/docs/cli/evals.mdx +4 -4
  197. package/docs/cli/index.mdx +1 -0
  198. package/docs/cli/translate.mdx +1 -0
  199. package/docs/cli/validate.mdx +4 -3
  200. package/docs/configuration/analytics.mdx +3 -1
  201. package/docs/configuration/assistant.mdx +194 -38
  202. package/docs/configuration/consent.mdx +100 -0
  203. package/docs/configuration/customization.mdx +8 -6
  204. package/docs/configuration/export.mdx +5 -3
  205. package/docs/configuration/index.mdx +64 -5
  206. package/docs/configuration/meta.ts +3 -0
  207. package/docs/configuration/narration.mdx +119 -0
  208. package/docs/configuration/rate-limiting.mdx +90 -0
  209. package/docs/configuration/search.mdx +63 -12
  210. package/docs/configuration/theming.mdx +3 -1
  211. package/docs/content/components.mdx +108 -2
  212. package/docs/content/frontmatter.mdx +80 -2
  213. package/docs/content/i18n.mdx +39 -4
  214. package/docs/content/includes.mdx +16 -0
  215. package/docs/content/meta.mdx +1 -0
  216. package/docs/content/meta.ts +1 -0
  217. package/docs/content/navigation.mdx +32 -10
  218. package/docs/content/sources/contentful.mdx +35 -0
  219. package/docs/content/sources/custom.mdx +43 -0
  220. package/docs/content/sources/github-releases.mdx +39 -0
  221. package/docs/content/sources/index.mdx +91 -0
  222. package/docs/content/sources/meta.ts +16 -0
  223. package/docs/content/sources/notion.mdx +32 -0
  224. package/docs/content/sources/obsidian.mdx +37 -0
  225. package/docs/content/sources/payload.mdx +31 -0
  226. package/docs/content/sources/remote-mdx.mdx +44 -0
  227. package/docs/content/sources/sanity.mdx +29 -0
  228. package/docs/content/sources/strapi.mdx +32 -0
  229. package/docs/content/syntax.mdx +69 -4
  230. package/docs/content/variables.mdx +41 -0
  231. package/docs/discoverability/agent-discovery.mdx +29 -2
  232. package/docs/discoverability/index.mdx +2 -2
  233. package/docs/discoverability/json-api.mdx +2 -0
  234. package/docs/discoverability/llms-txt.mdx +2 -2
  235. package/docs/discoverability/markdown.mdx +3 -1
  236. package/docs/discoverability/mcp.mdx +4 -0
  237. package/docs/discoverability/metadata.mdx +17 -0
  238. package/docs/discoverability/sitemap-and-robots.mdx +1 -1
  239. package/docs/references/api-pages.mdx +74 -0
  240. package/docs/references/asyncapi.mdx +4 -2
  241. package/docs/references/graphql.mdx +14 -2
  242. package/docs/references/meta.ts +1 -1
  243. package/docs/references/openapi.mdx +148 -7
  244. package/docs/references/scalar.mdx +3 -1
  245. package/package.json +43 -8
  246. package/skills/blume/SKILL.md +3 -0
  247. package/skills/blume-migrate/SKILL.md +6 -6
  248. package/skills/blume-migrate/references/docusaurus.md +7 -7
  249. package/skills/blume-migrate/references/fumadocs.md +17 -13
  250. package/skills/blume-migrate/references/mintlify.md +37 -19
  251. package/skills/blume-migrate/references/nextra.md +10 -7
  252. package/skills/blume-migrate/references/starlight.md +11 -8
  253. package/skills/blume-migrate/scripts/mintlify-codemod.mjs +60 -14
  254. package/skills/blume-write-skill/SKILL.md +82 -0
  255. package/src/ai/agent-readability.ts +2 -1
  256. package/src/ai/agent-surface.ts +9 -7
  257. package/src/ai/ai-catalog.ts +6 -3
  258. package/src/ai/ask-context.ts +103 -20
  259. package/src/ai/ask-data.ts +6 -0
  260. package/src/ai/ask-limits.ts +13 -0
  261. package/src/ai/ask-tools.ts +142 -0
  262. package/src/ai/ask.ts +354 -76
  263. package/src/ai/changelog-markdown.ts +11 -6
  264. package/src/ai/component-markdown.ts +76 -1
  265. package/src/ai/cors.ts +14 -3
  266. package/src/ai/index.ts +12 -0
  267. package/src/ai/llms.ts +6 -2
  268. package/src/ai/markdown.ts +2 -1
  269. package/src/ai/mcp/data.ts +6 -0
  270. package/src/ai/mcp/query.ts +14 -6
  271. package/src/ai/openapi-components.ts +36 -6
  272. package/src/ai/relative-links.ts +4 -38
  273. package/src/ai/site-skill.ts +274 -0
  274. package/src/ai/skills.ts +35 -2
  275. package/src/ai/write-skill.ts +97 -0
  276. package/src/astro/generate.ts +210 -66
  277. package/src/astro/index.ts +1 -0
  278. package/src/astro/integration.ts +42 -4
  279. package/src/astro/markdown-negotiation.ts +3 -0
  280. package/src/astro/module-types.ts +9 -1
  281. package/src/astro/pages.ts +23 -0
  282. package/src/astro/templates.ts +406 -108
  283. package/src/astro/variables.ts +31 -0
  284. package/src/audit/catalog.ts +38 -3
  285. package/src/audit/checks/contrast.ts +183 -0
  286. package/src/audit/checks/i18n.ts +2 -3
  287. package/src/audit/checks/indexability.ts +2 -3
  288. package/src/audit/checks/links.ts +19 -13
  289. package/src/audit/checks/network.ts +110 -6
  290. package/src/audit/checks/redirects.ts +6 -4
  291. package/src/audit/checks/robots.ts +58 -2
  292. package/src/audit/checks/sitemap.ts +2 -3
  293. package/src/audit/redirects.ts +46 -15
  294. package/src/audit/run.ts +5 -0
  295. package/src/audit/types.ts +4 -1
  296. package/src/audit/url.ts +14 -5
  297. package/src/blume-modules.d.ts +12 -1
  298. package/src/captcha/client.ts +152 -0
  299. package/src/captcha/hcaptcha.ts +36 -0
  300. package/src/captcha/index.ts +28 -0
  301. package/src/captcha/schema.ts +32 -0
  302. package/src/captcha/turnstile.ts +38 -0
  303. package/src/captcha/verify.ts +71 -0
  304. package/src/cli/args.ts +51 -0
  305. package/src/cli/build-failure.ts +23 -0
  306. package/src/cli/command-meta.ts +5 -0
  307. package/src/cli/commands/audit.ts +10 -1
  308. package/src/cli/commands/dev.ts +18 -2
  309. package/src/cli/commands/doctor.ts +67 -28
  310. package/src/cli/commands/eval.ts +36 -4
  311. package/src/cli/commands/init.ts +6 -4
  312. package/src/cli/commands/skill.ts +96 -0
  313. package/src/cli/commands/validate.ts +10 -1
  314. package/src/cli/index.ts +5 -0
  315. package/src/cli/init/scaffold.ts +3 -3
  316. package/src/cli/prepare.ts +6 -3
  317. package/src/cli/required-secrets.ts +72 -30
  318. package/src/components/BlumePage.astro +2 -0
  319. package/src/components/content/ApiEndpoint.astro +18 -0
  320. package/src/components/content/ApiField.astro +79 -0
  321. package/src/components/content/ApiPlayground.astro +66 -0
  322. package/src/components/content/ApiRail.astro +19 -0
  323. package/src/components/content/Color.astro +1 -0
  324. package/src/components/content/FileTree.astro +1 -0
  325. package/src/components/content/GithubInfo.astro +1 -0
  326. package/src/components/content/Panel.astro +1 -0
  327. package/src/components/content/ParamField.astro +25 -0
  328. package/src/components/content/RequestExample.astro +17 -0
  329. package/src/components/content/ResponseExample.astro +17 -0
  330. package/src/components/content/ResponseField.astro +32 -0
  331. package/src/components/content/Step.astro +1 -0
  332. package/src/components/content/Tile.astro +1 -0
  333. package/src/components/content/Tooltip.astro +1 -0
  334. package/src/components/content/Tree.astro +1 -0
  335. package/src/components/content/TypeTable.astro +4 -1
  336. package/src/components/content/View.astro +21 -0
  337. package/src/components/content/ViewSwitcher.astro +168 -0
  338. package/src/components/content/api-field.ts +103 -0
  339. package/src/components/content/api-page.ts +248 -0
  340. package/src/components/content/mermaid-element.ts +15 -1
  341. package/src/components/content/view-switcher.ts +71 -0
  342. package/src/components/index.ts +2 -0
  343. package/src/components/islands/Assistant.astro +10 -1
  344. package/src/components/islands/assistant.tsx +104 -14
  345. package/src/components/islands/code-question.ts +62 -0
  346. package/src/components/islands/hooks.ts +136 -21
  347. package/src/components/islands/support-link.ts +68 -0
  348. package/src/components/layout/Analytics.astro +11 -2
  349. package/src/components/layout/Banner.astro +14 -10
  350. package/src/components/layout/Breadcrumbs.astro +6 -2
  351. package/src/components/layout/ConsentBanner.astro +62 -0
  352. package/src/components/layout/ConsentHead.astro +38 -0
  353. package/src/components/layout/Directory.astro +94 -0
  354. package/src/components/layout/DrawerSwitchers.astro +51 -0
  355. package/src/components/layout/Empty.astro +2 -2
  356. package/src/components/layout/Header.astro +122 -80
  357. package/src/components/layout/LanguageSwitcher.astro +48 -15
  358. package/src/components/layout/NarrationPlayer.astro +1085 -0
  359. package/src/components/layout/NavSelector.astro +33 -7
  360. package/src/components/layout/PageActions.astro +139 -24
  361. package/src/components/layout/PageFeedback.astro +54 -49
  362. package/src/components/layout/PageLayout.astro +71 -3
  363. package/src/components/layout/ReferenceLayout.astro +17 -6
  364. package/src/components/layout/RelatedPages.astro +42 -0
  365. package/src/components/layout/RootLayout.astro +318 -47
  366. package/src/components/layout/Search.astro +47 -19
  367. package/src/components/layout/SiteFooter.astro +124 -0
  368. package/src/components/layout/SiteMetatags.astro +16 -0
  369. package/src/components/layout/TableOfContents.astro +24 -17
  370. package/src/components/layout/consent/native.ts +79 -0
  371. package/src/components/layout/consent/types.ts +37 -0
  372. package/src/components/layout/footer-links.ts +53 -0
  373. package/src/components/layout/footer-socials.ts +87 -0
  374. package/src/components/layout/head-scripts.ts +6 -1
  375. package/src/components/layout/locale-redirect.ts +107 -0
  376. package/src/components/layout/nav-utils.ts +83 -0
  377. package/src/components/layout/page-feedback.ts +96 -0
  378. package/src/components/layout/search/algolia.ts +10 -1
  379. package/src/components/layout/search/analytics.ts +126 -0
  380. package/src/components/layout/search/endpoint.ts +48 -5
  381. package/src/components/layout/search/flexsearch.ts +17 -5
  382. package/src/components/layout/search/orama-cloud.ts +26 -14
  383. package/src/components/layout/search/pagefind.ts +114 -5
  384. package/src/components/layout/search/types.ts +32 -0
  385. package/src/components/layout/search/typesense.ts +19 -3
  386. package/src/components/openapi/AsyncApiOperation.astro +14 -7
  387. package/src/components/openapi/Authorization.astro +10 -0
  388. package/src/components/openapi/GraphqlOperation.astro +5 -0
  389. package/src/components/openapi/Operation.astro +184 -13
  390. package/src/components/openapi/ParametersTable.astro +8 -4
  391. package/src/components/openapi/Playground.astro +7 -1
  392. package/src/components/openapi/RequestBody.astro +24 -5
  393. package/src/components/openapi/RequestPanel.astro +59 -7
  394. package/src/components/openapi/Responses.astro +7 -4
  395. package/src/components/openapi/SchemaTable.astro +15 -3
  396. package/src/components/openapi/async-snippets.ts +65 -9
  397. package/src/components/openapi/async.ts +123 -29
  398. package/src/components/openapi/code-samples.ts +97 -0
  399. package/src/components/openapi/graphql-helpers.ts +35 -12
  400. package/src/components/openapi/helpers.ts +36 -2
  401. package/src/components/openapi/message-model.ts +54 -11
  402. package/src/components/openapi/message.ts +14 -4
  403. package/src/components/openapi/operation-model.ts +16 -7
  404. package/src/components/openapi/playground-client.ts +24 -5
  405. package/src/components/openapi/playground-schema.ts +1 -1
  406. package/src/components/openapi/schema-tree.ts +44 -14
  407. package/src/components/openapi/security.ts +16 -3
  408. package/src/components/openapi/snippets.ts +873 -10
  409. package/src/components/openapi/validate-json.ts +4 -3
  410. package/src/components/props.ts +6 -0
  411. package/src/consent/client.ts +95 -0
  412. package/src/consent/clients.ts +19 -0
  413. package/src/consent/ethyca.ts +71 -0
  414. package/src/consent/head.ts +24 -0
  415. package/src/consent/index.ts +37 -0
  416. package/src/consent/init.ts +29 -0
  417. package/src/consent/native.ts +36 -0
  418. package/src/consent/osano.ts +59 -0
  419. package/src/consent/schema.ts +30 -0
  420. package/src/core/builtin-tags.ts +5 -0
  421. package/src/core/changelog-index.ts +31 -1
  422. package/src/core/client-address.ts +19 -0
  423. package/src/core/component-diagnostics.ts +53 -0
  424. package/src/core/component-overrides.ts +32 -0
  425. package/src/core/config-input.ts +225 -23
  426. package/src/core/data.ts +46 -4
  427. package/src/core/diagnostics.ts +8 -2
  428. package/src/core/footer.ts +26 -0
  429. package/src/core/graph.ts +39 -36
  430. package/src/core/i18n-ui.ts +84 -2
  431. package/src/core/includes.ts +21 -4
  432. package/src/core/links.ts +63 -19
  433. package/src/core/localizable.ts +26 -0
  434. package/src/core/navigation.ts +43 -12
  435. package/src/core/page-modes.ts +56 -0
  436. package/src/core/probe.ts +26 -6
  437. package/src/core/project-graph.ts +163 -16
  438. package/src/core/redirect-patterns.ts +520 -0
  439. package/src/core/related.ts +131 -0
  440. package/src/core/schema.ts +339 -66
  441. package/src/core/sources/cache.ts +6 -0
  442. package/src/core/sources/contentful-rich-text.ts +29 -6
  443. package/src/core/sources/contentful.ts +135 -25
  444. package/src/core/sources/filesystem.ts +26 -4
  445. package/src/core/sources/github-releases.ts +12 -1
  446. package/src/core/sources/lexical.ts +15 -10
  447. package/src/core/sources/mdx-remote.ts +62 -10
  448. package/src/core/sources/normalize.ts +228 -41
  449. package/src/core/sources/notion.ts +7 -1
  450. package/src/core/sources/obsidian.ts +16 -3
  451. package/src/core/sources/payload.ts +38 -15
  452. package/src/core/sources/read.ts +8 -3
  453. package/src/core/sources/remote.ts +72 -15
  454. package/src/core/sources/resolve.ts +11 -1
  455. package/src/core/sources/sanity.ts +43 -25
  456. package/src/core/sources/strapi.ts +2 -2
  457. package/src/core/types.ts +19 -1
  458. package/src/core/ui-packs/ar.ts +44 -0
  459. package/src/core/ui-packs/bg.ts +46 -0
  460. package/src/core/ui-packs/bn.ts +44 -0
  461. package/src/core/ui-packs/ca.ts +47 -0
  462. package/src/core/ui-packs/cs.ts +45 -0
  463. package/src/core/ui-packs/da.ts +46 -0
  464. package/src/core/ui-packs/de.ts +47 -0
  465. package/src/core/ui-packs/el.ts +46 -0
  466. package/src/core/ui-packs/es.ts +47 -0
  467. package/src/core/ui-packs/fa.ts +46 -0
  468. package/src/core/ui-packs/fi.ts +46 -0
  469. package/src/core/ui-packs/fr.ts +47 -0
  470. package/src/core/ui-packs/he.ts +44 -0
  471. package/src/core/ui-packs/hi.ts +45 -0
  472. package/src/core/ui-packs/hr.ts +46 -0
  473. package/src/core/ui-packs/hu.ts +45 -0
  474. package/src/core/ui-packs/id.ts +46 -0
  475. package/src/core/ui-packs/it.ts +46 -0
  476. package/src/core/ui-packs/ja.ts +46 -0
  477. package/src/core/ui-packs/ko.ts +45 -0
  478. package/src/core/ui-packs/nl.ts +47 -0
  479. package/src/core/ui-packs/no.ts +45 -0
  480. package/src/core/ui-packs/pl.ts +46 -0
  481. package/src/core/ui-packs/pt-br.ts +47 -0
  482. package/src/core/ui-packs/pt.ts +46 -0
  483. package/src/core/ui-packs/ro.ts +46 -0
  484. package/src/core/ui-packs/ru.ts +46 -0
  485. package/src/core/ui-packs/sk.ts +45 -0
  486. package/src/core/ui-packs/sr.ts +46 -0
  487. package/src/core/ui-packs/sv.ts +45 -0
  488. package/src/core/ui-packs/th.ts +44 -0
  489. package/src/core/ui-packs/tr.ts +46 -0
  490. package/src/core/ui-packs/uk.ts +46 -0
  491. package/src/core/ui-packs/vi.ts +46 -0
  492. package/src/core/ui-packs/zh-tw.ts +44 -0
  493. package/src/core/ui-packs/zh.ts +44 -0
  494. package/src/core/variables.ts +103 -0
  495. package/src/deploy/adapter-output.ts +7 -2
  496. package/src/deploy/adapters/cloudflare.ts +7 -5
  497. package/src/deploy/adapters/node.ts +47 -9
  498. package/src/deploy/adapters/types.ts +7 -3
  499. package/src/deploy/artifacts.ts +79 -9
  500. package/src/deploy/cloudflare-negotiation.ts +35 -5
  501. package/src/deploy/headers.ts +2 -1
  502. package/src/deploy/node-headers.ts +63 -9
  503. package/src/deploy/platforms/cloudflare.ts +45 -9
  504. package/src/deploy/platforms/netlify.ts +35 -2
  505. package/src/deploy/platforms/node.ts +12 -2
  506. package/src/deploy/platforms/types.ts +21 -7
  507. package/src/deploy/platforms/vercel.ts +149 -17
  508. package/src/deploy/redirects.ts +151 -24
  509. package/src/deploy/rss.ts +3 -1
  510. package/src/deploy/sitemap.ts +39 -5
  511. package/src/deploy/vercel-negotiation.ts +326 -102
  512. package/src/eval/agents.ts +18 -1
  513. package/src/eval/prompts.ts +6 -3
  514. package/src/eval/report.ts +34 -13
  515. package/src/eval/run.ts +5 -0
  516. package/src/markdown/api-rail.ts +259 -0
  517. package/src/markdown/code-title.ts +35 -9
  518. package/src/markdown/features.ts +3 -2
  519. package/src/markdown/fence-meta.ts +2 -0
  520. package/src/markdown/include.ts +11 -1
  521. package/src/markdown/index.ts +28 -5
  522. package/src/markdown/math.ts +4 -4
  523. package/src/markdown/relative-links.ts +3 -2
  524. package/src/markdown/variables.ts +56 -0
  525. package/src/markdown/views.ts +82 -0
  526. package/src/narration/build.ts +412 -0
  527. package/src/narration/player.ts +249 -0
  528. package/src/narration/provider.ts +29 -0
  529. package/src/narration/script.ts +592 -0
  530. package/src/og/card.ts +7 -6
  531. package/src/openapi/checks.ts +273 -0
  532. package/src/openapi/graphql-build.ts +21 -0
  533. package/src/openapi/graphql.ts +11 -0
  534. package/src/openapi/model.ts +72 -27
  535. package/src/openapi/overlay.ts +256 -0
  536. package/src/openapi/parse.ts +182 -4
  537. package/src/openapi/references.ts +64 -8
  538. package/src/openapi/render-mdx.ts +5 -1
  539. package/src/openapi/scalar.ts +40 -6
  540. package/src/openapi/source.ts +40 -15
  541. package/src/ratelimit/cloudflare.ts +54 -0
  542. package/src/ratelimit/index.ts +30 -0
  543. package/src/ratelimit/memory.ts +45 -0
  544. package/src/ratelimit/runtime.ts +247 -0
  545. package/src/ratelimit/schema.ts +28 -0
  546. package/src/ratelimit/upstash.ts +60 -0
  547. package/src/ratelimit/wrangler.ts +70 -0
  548. package/src/reference/asyncapi.ts +2 -2
  549. package/src/reference/graphql.ts +20 -3
  550. package/src/reference/index.ts +1 -0
  551. package/src/reference/openapi.ts +21 -7
  552. package/src/reference/options.ts +80 -8
  553. package/src/reference/scalar.ts +33 -8
  554. package/src/registry/eject.ts +23 -5
  555. package/src/registry/registry.ts +7 -0
  556. package/src/search/adapters/locale-scope.ts +30 -0
  557. package/src/search/adapters/typesense.ts +14 -4
  558. package/src/search/build.ts +21 -3
  559. package/src/search/documents.ts +26 -2
  560. package/src/search/orama-index.ts +191 -34
  561. package/src/search/pagefind-ranking.ts +39 -0
  562. package/src/search/source-pages.ts +29 -0
  563. package/src/search/sync/algolia.ts +111 -10
  564. package/src/search/sync/index.ts +52 -13
  565. package/src/search/sync/orama-cloud.ts +3 -0
  566. package/src/search/sync/typesense.ts +76 -26
  567. package/src/seo/metatags.ts +67 -0
  568. package/src/sources/contentful.ts +12 -0
  569. package/src/sources/github-releases.ts +7 -1
  570. package/src/sources/shared.ts +3 -0
  571. package/src/theme/chrome-icons.ts +1 -0
  572. package/src/theme/color.ts +500 -0
  573. package/src/theme/entry.ts +85 -6
  574. package/src/theme/palette.ts +121 -45
  575. package/src/translate/prompts.ts +1 -0
  576. package/src/translate/validate.ts +31 -3
  577. package/src/upgrade/upgrade.ts +4 -171
  578. package/dist/cli/chunk-1d7ve1dm.js.map +0 -12
  579. package/dist/cli/chunk-2hsdwb9n.js.map +0 -10
  580. package/dist/cli/chunk-35d4wj9f.js.map +0 -15
  581. package/dist/cli/chunk-364znk6q.js +0 -75
  582. package/dist/cli/chunk-364znk6q.js.map +0 -11
  583. package/dist/cli/chunk-5m5nmvyq.js.map +0 -13
  584. package/dist/cli/chunk-8ktnccpt.js.map +0 -10
  585. package/dist/cli/chunk-9t7a85s3.js.map +0 -10
  586. package/dist/cli/chunk-b07cmahc.js +0 -145
  587. package/dist/cli/chunk-b07cmahc.js.map +0 -11
  588. package/dist/cli/chunk-c8chx29p.js.map +0 -36
  589. package/dist/cli/chunk-e04dxsz1.js +0 -39
  590. package/dist/cli/chunk-e04dxsz1.js.map +0 -10
  591. package/dist/cli/chunk-j85vccga.js.map +0 -36
  592. package/dist/cli/chunk-p3v96n38.js.map +0 -10
  593. package/dist/cli/chunk-pehfxfta.js.map +0 -10
  594. package/dist/cli/chunk-pv29h0wf.js.map +0 -190
  595. package/dist/cli/chunk-q58y5e6a.js.map +0 -10
  596. package/dist/cli/chunk-vg9r4eb9.js.map +0 -14
  597. package/dist/cli/chunk-wrr3j9w9.js.map +0 -35
  598. package/dist/cli/chunk-yfyb25rh.js.map +0 -14
  599. package/docs/content/sources.mdx +0 -334
  600. /package/dist/cli/{chunk-tkacnehg.js.map → chunk-3v3ffbrj.js.map} +0 -0
  601. /package/dist/cli/{chunk-r9rcc4w7.js.map → chunk-8y2kmjv8.js.map} +0 -0
  602. /package/dist/cli/{chunk-2eytanqx.js.map → chunk-c887fj0s.js.map} +0 -0
  603. /package/dist/cli/{chunk-akbpwfxc.js.map → chunk-dzwehpy7.js.map} +0 -0
  604. /package/dist/cli/{chunk-2z928egk.js.map → chunk-ft9vfys6.js.map} +0 -0
  605. /package/dist/cli/{chunk-a58773jm.js.map → chunk-kma9f6sf.js.map} +0 -0
  606. /package/dist/cli/{chunk-crgn1q09.js.map → chunk-sds923fa.js.map} +0 -0
  607. /package/dist/cli/{chunk-acanzt5p.js.map → chunk-tdqhyxfz.js.map} +0 -0
package/AGENTS.md CHANGED
@@ -5,6 +5,7 @@ This package ships agent skills for working with Blume documentation projects. B
5
5
  - `./skills/blume/SKILL.md` — build and maintain a Blume site: scaffolding, writing Markdown/MDX, `blume.config.ts`, navigation, search, theming, SEO, and the `blume` CLI.
6
6
  - `./skills/blume-migrate/SKILL.md` — migrate an existing docs site (Mintlify, Fumadocs, Docusaurus, Starlight, Nextra, or another framework) to Blume. `blume migrate [source] --codex` (or `--claude`) opens an agent on it.
7
7
  - `./skills/blume-update-docs/SKILL.md` — audit a Blume docs site against the product it documents, fix stale pages, and open a maintenance pull request.
8
+ - `./skills/blume-write-skill/SKILL.md` — write the docs site's own agent skill from its docs, in place of the page map Blume generates at `/skill.md`. `blume skill --codex` (or `--claude`) opens an agent on it.
8
9
 
9
10
  Use the relevant `SKILL.md` as the source of truth for Blume-specific workflows. The full Blume documentation is bundled under `./docs/`, and the `blume` skill points at it.
10
11
 
package/CHANGELOG.md CHANGED
@@ -1,5 +1,147 @@
1
1
  # blume
2
2
 
3
+ ## 2.1.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 579ae91: The Algolia sync no longer fails on long pages. Algolia caps a record at 10 KB on its Build and Grow plans and rejects the whole upload when one page's record is larger, so the sync now splits a longer page into several records, each carrying the page's title, description, and URL with a stretch of its text. It sets the index's `attributeForDistinct` to `url` (unless you set your own), so a split page appears once in results, at its best-matching record.
8
+ - dc89029: On hand-written API pages, an optional body field with no `default` or `placeholder` now starts empty in the Try it panel and stays out of the request samples, instead of being sent as `"string"`, `0`, or `true`.
9
+ - 29abb61: The assistant route now exposes `Retry-After` to the origins listed in `ai.assistant.cors`, so a page on another site can read how long to wait after a `429` from the rate limit. Browsers hid the header from cross-origin callers before.
10
+ - 05b0acf: The assistant keeps a question asked outside the docs, such as from the homepage or another site, to one language. It searched every translation before, so on a translated site the translations of each page crowded out the answer. Retrieval and the assistant's own searches now keep to the locale the page's URL names (`/ja`), or the default locale.
11
+ - 3ea55bb: Long conversations with the assistant keep working. The panel sent the whole conversation with every question, and once it passed the route's 24,000 characters or 40 messages, every answer failed. It now sends the latest turns that fit, dropping the oldest first; the reader still sees the whole conversation. `useAssistant` does the same.
12
+ - 075d362: Update `@astrojs/react` to 7. Its `babel` option is gone, so the React Compiler now runs on Oxc (`oxc-transform-react`) instead of Babel (`babel-plugin-react-compiler`). It still ships with Blume and stays on by default; `react: { compiler: false }` still turns it off.
13
+ - 9772956: AsyncAPI `kcat` samples now follow the Kafka bindings and the server's security. A channel binding's `topic` replaces the channel address, a message binding's `key` keys the message (`key|payload` with `-K '|'`), and a server that declares a SASL scheme adds the `-X` settings librdkafka needs, reading the credentials from `$KAFKA_USERNAME` and `$KAFKA_PASSWORD`, with TLS for `kafka-secure`. When a channel's servers declare different security, the Authorization section names the servers each scheme applies to and those that need none, instead of marking every scheme required everywhere.
14
+ - cf1f04a: `blume audit --url` now requests each configured redirect's old URL on the live site and reports `BLUME_AUDIT_REDIRECT_NOT_SERVED` when it isn't redirected to the configured destination: an error when the old URL fails, and a warning when the host serves the build's meta-refresh page instead of an HTTP redirect.
15
+ - 4561f51: `blume audit` no longer says a page always wins over a redirect configured from the same path. Which one readers get depends on the host, so the finding and its fix now say so.
16
+ - 6c7a96e: `blume audit` now reads every `User-agent` group in robots.txt, not only `*`, and warns with `BLUME_AUDIT_ROBOTS_BLOCKS_CRAWLER` when a rule aimed at one crawler blocks it from pages the sitemap advertises.
17
+ - a0041e5: `blume audit` no longer reports a full URL on the site's own host but outside `deployment.base` as a broken link: it names another app on that host, which is how the navigation docs say to link one.
18
+ - ed324f3: `blume audit` no longer says a page nothing links to (a `sidebar.hidden` page, say) is "reachable only from the sidebar", and the fix for an indexable page missing from the sitemap now mentions a `public/sitemap.xml` that replaces the generated one.
19
+ - 08b514f: The generated `/changelog` index's "No changelog entries yet." line is now a UI string (`changelog.empty`), translated in every built-in language pack and overridable under `i18n.ui`, instead of always showing in English.
20
+ - 605e65f: A new top-level `changelog` config sets the generated `/changelog` index's `title` and `description`, each a string or a per-locale map, so a site can rename its changelog without overriding UI strings under `i18n.ui`. They also title the index's OG card and its Markdown mirror.
21
+ - 2495c48: `--budget-js`, `--budget-css`, `--analyze`, and `blume audit` now read a `cloudflare()` server build with `base` set from `dist/client/<base>/`, where the adapter writes it. They read `dist/client` before, so a budget measured nothing and passed, and the audit reported every page's links and assets as broken.
22
+ - 351f29c: `contentful()` renders an embedded file that isn't an image, like a PDF, as a link to it instead of a broken image, and warns with `BLUME_SOURCE_UNRESOLVED_LINK` when a page embeds or links an asset or entry the Delivery API didn't return (an unpublished one, say) instead of dropping it silently. An embed of another entry of the same content type now resolves. New `host` and `previewHost` options reach a space with EU data residency, and `fields.order` on `contentful()`, `payload()`, and `strapi()` reads a page's sidebar order from a number field.
23
+ - 0d7a9dc: A `contentful()` rich text link to another entry of the source's content type now links to that entry's page, at the route it's built at (prefix, nested slug, and locale included). A link to an entry of any other content type still keeps only its text, and a link to an entry the Delivery API didn't return (an unpublished one, say) warns with `BLUME_SOURCE_UNRESOLVED_LINK`.
24
+ - 3e3e65f: `blume dev` now answers an exact redirect with its configured `status`, as the production outputs do, instead of a `301` for every redirect to a docs page.
25
+ - 2d13649: `blume dev` now watches the local spec and overlay files your API references read, so saving a spec updates its reference without restarting the server.
26
+ - e69a55e: `blume doctor` now reports a tab, selector item, featured link, header action, or call to action whose path matches no page (`BLUME_NAV_MISSING_PAGE`), the same warning `blume dev` and `blume build` print. It checks against every route the site serves, custom `.astro` pages, the generated changelog, and references included.
27
+ - c82742b: `codeSamples: []` on `openapi()` or `graphql()` now shows no generated code samples, like `codeSamples: false`, instead of falling back to the default cURL, JavaScript, and Python.
28
+ - 2dda5fe: EPUB export now names the site as the book's author and publisher and uses the page's language, instead of "anonymous" and English. Links to other pages point at the live site, and an image the browser can't fetch is left out with a console warning instead of failing the whole export.
29
+ - 7ab09df: `blume eval --agent claude` no longer loads your Claude Code settings files or `CLAUDE.md` into the reader and judge, the way Codex runs already skip your Codex config. Hooks, plugins, and memory could hand the reader context your docs never gave it. Your Claude Code login still works; set any other variables it needs, such as `ANTHROPIC_API_KEY`, in your shell rather than in `settings.json`.
30
+ - bec8930: `blume eval --agent claude` now runs the reader and judge with every Claude Code built-in tool turned off, so the reader has only the docs tools. Its list of blocked tools had fallen behind Claude Code, which left newer tools such as `Monitor` (which runs shell commands) and `Skill` (which loads your installed skills) available to it.
31
+ - 8dc7ed3: `blume eval --fix` now tells the agent to verify its edits with the same `--agent`, `--file`, `--threshold`, and `--timeout` the run used. It used to say a bare `blume eval`, which graded `evals.yaml` with Codex even when the run being fixed used Claude Code or another evals file.
32
+ - 35af3c6: A missed `severity: warning` question in `blume eval` now reads as the warning it is. Its line shows `⚠ warn` instead of `✖ fail`, the summary counts it as warned rather than failed, and its finding prints as a `⚠` line instead of a `fix:` line, matching the exit code, which already ignored it. Each question in the `--json` results now carries its `severity`.
33
+ - d5ef2f0: An exact redirect from a page's own URL now warns with `BLUME_REDIRECT_MATCHES_PAGE` in `blume validate`, `doctor`, `dev`, and `build`: the redirect takes the URL over, so the page never publishes. Before, only a pattern redirect was flagged.
34
+ - e09dcd4: `blume validate --external` and `blume audit --external` now fail a link only when it's dead: a 404 or 410, or a host name that doesn't resolve. A refused or dropped connection is a warning, like a timeout or any other error status, since it's more often the other site or the runner's network than the link. The finding also names the reason a request failed (`getaddrinfo ENOTFOUND …`) instead of Node's bare "fetch failed".
35
+ - b28119d: Frontmatter that isn't valid YAML, such as an unquoted value holding `: `, is now reported as `BLUME_FRONTMATTER_INVALID` at its file and line instead of failing `blume validate`, `doctor`, `audit`, `build`, and `dev` with `BLUME_INTERNAL`.
36
+ - c505dbe: `githubReleases()` takes a `baseUrl` for a repository on GitHub Enterprise Server, and tags a draft release it includes (with `drafts: true`) `Draft` instead of `Release`. An RSS item now falls back to the page's `seo.description`, so the releases feed describes each release with the summary of its notes.
37
+ - 4cda96b: GraphQL example variables start at each argument's declared default, so `first: Int = 20` is `20` rather than `0`, and input objects fill their fields' defaults the same way. Generated example queries and responses leave deprecated fields out.
38
+
39
+ `graphql()` takes an `auth` option, in the shape of `api.auth` for hand-written endpoint pages: `{ method: "bearer" }`, `"basic"`, or `"key"` with the header `name` (`x-api-key` by default). With it, every operation page shows an Authorization section, the Try it panel gets a credential field, and the code samples send a placeholder credential. A per-source `auth` overrides the adapter's.
40
+ - 922d680: The `BLUME_INCLUDE_MALFORMED` suggestion no longer says only `lang` and `meta` attributes are read; it says attributes need lowercase names and quoted values, and that any other attribute is a prop.
41
+ - aa7539b: `blume init` now adds `.env.local`, where Blume says to put local secrets, to `.gitignore`.
42
+ - 86da6d4: `blume init`'s pnpm workspace note now says pnpm 11 and later stop the install over an unapproved esbuild build script; pnpm 10 only warns.
43
+ - 0a38c27: The MCP `search_docs` and `list_pages` tools now match a number or boolean in `filters` against the facet's string form, the way facet values are stored, so `{"priority": 1}` finds pages with `priority: 1`. Such a value used to be dropped, and the tool answered as if no filter had been sent.
44
+ - 12c2213: `mdxRemote()` fixes: `blume validate` resolves a link between remote files (`./02-errors.mdx`) to the page it publishes at instead of reporting it broken, a `!` pattern in `include` now excludes what it matches as it does for `filesystem()` instead of including every file, a `github.path` with nothing under it at the ref warns with `BLUME_SOURCE_PATH_MISSING`, and the `BLUME_SOURCE_TRUNCATED` warning no longer suggests narrowing `path`, which can't help.
45
+ - c8820c2: A Mermaid diagram that fails to parse now logs Mermaid's parser error to the browser console, and `blume dev` shows it under the "Could not render this diagram." message, so you can find the line to fix. Mermaid's "Syntax error in text" graphic no longer appears at the bottom of the page.
46
+ - f442afe: The `blume-migrate` skill's Docusaurus reference now replaces `<DocCardList />` and generated-index categories with a folder's `directory: "card"` listing, and turns an `id` that differs from its filename into a `slug`, so the page keeps the URL Docusaurus built from its ID.
47
+ - 2f798ce: The `blume-migrate` skill's Fumadocs reference now redirects URLs that lose a numeric filename prefix, hides the pages a `meta.json` `pages` list without `"..."` left out of the sidebar, maps `full: true` to `mode: wide`, and reads newer scaffolds: collections in `lib/source.ts`, a `baseUrl` constant, `components/mdx.tsx`, and the header title, GitHub link, and links in `lib/layout.shared.tsx`.
48
+ - 22c4f41: The `blume-migrate` skill now keeps a source's inline math inline, rewriting `$x$` as `$$x$$` inside its sentence. It used to treat inline math as unsupported and move each formula onto its own line or drop it, though Blume renders `$$…$$` inline.
49
+ - 449d11b: The `blume-migrate` skill's Nextra reference now moves a Nextra 4 default-locale folder (`content/en/`) up to the content root, keeps each page's heading as its `title` with the `_meta` label as `sidebar.label`, maps `layout: "full"` to `mode: wide`, and keeps `_meta` ordering in nested folders with `display: "group"`.
50
+ - b02e9a4: The `blume-migrate` skill's Starlight reference now carries `head` meta tags (site verification, `theme-color`, and the like) over to `seo.metatags` instead of dropping them.
51
+ - 74546a6: The `blume-migrate` skill's Starlight reference now reads the sidebar's `items: [{ autogenerate }]` shape from Starlight 0.39 on, carries Discord, X, and other social links over to `footer.socials`, maps a `Footer` override to Blume's `PageFooter` slot rather than the site footer, keeps per-fence `wrap`, and approximates splash pages with `mode: center`.
52
+ - 258a9aa: A `<Component path>` that names no example now gets a `BLUME_EXAMPLE_NOT_FOUND` warning at its line from `blume dev`, `blume build`, and `blume doctor`, instead of only a "No example found" box on the page. A `components.ts` override or island named `Component` replaces the built-in, so its `path` isn't checked.
53
+ - 1dd0e1e: Mixedbread search results now link to their pages. The endpoint read each result's link from metadata nothing sets, so every result pointed back at the current page; it now finds the page whose file `mxbai store sync` uploaded, shows that page's title, and lists each page once. When the search endpoint fails, the dialog shows its error message instead of "No results".
54
+ - ea6591b: With Mixedbread search, the search dialog now waits for the reader to pause typing before it sends a query, and cancels a query the reader has typed past. A search costs a request or a few instead of one per letter, which keeps readers under the search endpoint's rate limit, and a slow earlier response can no longer replace newer results. `useSearch()` and the WebMCP search tool still send each query at once.
55
+ - 3d96865: The Mixedbread search endpoint now checks `rateLimit` in `blume dev` and `blume build`, answering `429 Too Many Requests` past the limit. Only `blume eject` used to limit it.
56
+ - 458b6e6: `node()` takes `allowedDomains`, set as Astro's `security.allowedDomains`, for a server behind a reverse proxy. Astro only reads the reader's address from `X-Forwarded-For` for a host listed there, so every reader behind a proxy shared one rate limit count; with the proxy's host listed, each reader gets their own.
57
+ - 62c4ec8: OpenAPI 3.2 specs now render as written, and a `query` operation, for the HTTP `QUERY` method, gets a page, Try it, and code samples like any other method. The 3.2 additions Blume doesn't render yet, `additionalOperations` and `in: querystring` parameters, log a `BLUME_OPENAPI_UNSUPPORTED` warning instead of dropping out without a sign.
58
+ - 66abad4: An operation's Callbacks section now lists each callback's parameters, such as a signature header, beside its request body and responses. A 3.1 or later spec that still keeps its webhooks under `x-webhooks`, which renders none of them, now logs a `BLUME_OPENAPI_X_WEBHOOKS` warning that says to rename the field to `webhooks`.
59
+ - 8ac7650: An operation's own `x-codeSamples` now reach its Markdown copy, so `llms-full.txt`, the MCP server, and the assistant see your SDK calls, and site search indexes them like any code block. A sample whose `source` is a `$ref` to a file is read relative to the spec, and one that can't be read logs a `BLUME_OPENAPI_CODE_SAMPLE_REF` warning instead of disappearing.
60
+ - ac5b593: OpenAPI references now warn about spec mistakes that used to render wrong without a sign: a `{name}` in a path with no path parameter of that name (`BLUME_OPENAPI_PATH_PARAMETER_MISSING`), a path parameter the path never uses (`BLUME_OPENAPI_PATH_PARAMETER_UNUSED`), and a `security` requirement naming a scheme that `components.securitySchemes` doesn't define (`BLUME_OPENAPI_UNKNOWN_SECURITY_SCHEME`). The pages still build.
61
+ - cea759c: Page actions now show in windows narrower than 1,280px and on phones. Edit on GitHub, Copy as Markdown, Export, Open in chat, and Connect to MCP sit at the bottom of the "On this page" dropdown above the content, their menus opening in place, and that dropdown now shows on a page with no headings too. The actions render once per page and move between the right rail and that dropdown as the window crosses 1,280px. A `TableOfContents` layout override receives the place they move into as children of its `mobile` variant, so render a `<slot />` there to keep them.
62
+ - e6713a4: `blume build` with `pagefind()` now reports how many pages the search index holds. The "Indexed N page(s) for search" line used to count every HTML file in the build, including search-excluded pages, hidden pages, and the 404 page, which the index leaves out.
63
+ - b86f051: With `pagefind()`, search now follows a switch to another language. Pagefind read the page's language once, on the first search, so after picking another language in the switcher, which swaps the page without a reload, search kept returning results in the first language until a full page load.
64
+ - 904eb98: Pagefind search results now link to each page's own URL. They ended in a slash (`/quickstart/`), which Blume doesn't serve, so a host redirected every result and `blume preview` answered Not Found. With `deployment.base` set, they also carried the base twice (`/docs/docs/quickstart/`).
65
+ - 1b89b4e: API reference parameter tables and the Try it panel now show a parameter's description when the spec puts it on the parameter's schema, as Elysia and oRPC do. A description on the parameter itself still wins.
66
+ - 8bfb639: `payload()` now warns with `BLUME_SOURCE_UNSUPPORTED_NODE` when a page's Lexical body holds a node it leaves out as a comment, like a block with no serializer or a relationship, naming the page and the node, instead of dropping it without a word.
67
+ - 00ce3b9: The API playground's built-in proxy now checks `rateLimit` in `blume dev` and `blume build`, answering `429 Too Many Requests` past the limit. Only `blume eject` used to limit it.
68
+ - e12b668: Printing a page, or exporting it to PDF, now leaves out everything after the article (last updated, feedback, previous and next links, the site footer) and the buttons on code blocks, prints collapsed `expandable` code blocks in full, and prints a page read in the dark theme in the light one.
69
+ - f5151c7: A redirect from one page to another now moves the page's raw Markdown too: `/old.md` and `/old.mdx` redirect to `/new.md` and `/new.mdx` with the same status, in `blume dev`, the redirect files a static build writes, and every server build. They used to 404.
70
+ - c5f25f5: A reference source's `label` now names its sidebar group as written (`GitHub OAuth (v2)`, not "Github OAuth V2" from its route), and a reference's tag groups follow the spec's declared tag order in the sidebar, the same order as its overview page, instead of sorting alphabetically.
71
+ - 0dc7156: API reference schema tables now match the examples beside them: request body tables leave out `readOnly` properties, and response tables leave out `writeOnly` ones. A webhook's or callback's body, which your API sends, keeps its `readOnly` properties.
72
+ - 0ff3d0e: A `sanity()` body held in a Markdown string field now renders as Markdown instead of an empty page. A query that finds no documents while `SANITY_TOKEN` is unset now warns with `BLUME_MISSING_SECRET`, since a private dataset answers a query without a token with nothing rather than an error.
73
+ - 4562581: The site stylesheet now scans your project's `.jsx` files for Tailwind classes, as the theming docs say, so a class used only in a `.jsx` island is generated. Ejected apps scan them too.
74
+ - 2c6022a: The search dialog's "All languages" toggle now works with `pagefind()`: it merges every language's index into the search, where it used to return the page's language alone. With `mixedbread()`, which can't limit a search to one language, the dialog no longer shows the toggle, since every search already spans every language.
75
+ - fa68c94: Search analytics can keep query text away from your analytics providers. With `search: { analytics: { queries: false } }`, the `search` and `search_select` events carry the query's length as `queryChars` instead of its text, and the text travels only on the `blume:track` DOM event, the way the assistant handles questions. By default queries are still sent as typed.
76
+ - 7beba3e: Search now finds translations in a non-Latin script on a site whose default language is written in Latin script, such as the Japanese and Hindi pages of an English site. Each of those locales' pages is indexed with its own word-segmenting tokenizer, so the search dialog, the MCP server's `search_docs`, and the assistant match them, whether the search is scoped to one language or runs across all of them. Latin-script pages keep the tokenizer they had.
77
+ - 05a06e3: A failed search sync now fails the build when its admin key is set. Algolia, Orama Cloud, and Typesense syncs used to only warn when the upload failed, so a site could deploy against an index the build never updated; they now stop `blume build` with `BLUME_SEARCH_SYNC_FAILED`. Without the key (or, for Orama Cloud, without `indexId`), the build still warns and skips the sync, so a build without secrets keeps working.
78
+ - 55b417c: API references now read a field whose schema is an `allOf` with one member, the way drf-spectacular writes enums and nested serializers, as that member: it's labeled with the member's name or type instead of `object`, lists its allowed values, and the Try it panel gives it the member's type and choices. A model that points back at itself through such a wrapper no longer crashes the build.
79
+ - e47a621: The sitemap now leaves out a page whose `seo.canonical` names another URL, so following the duplicate-content fix no longer trips `BLUME_AUDIT_NON_CANONICAL_IN_SITEMAP`. An archived-version page whose own `seo.canonical` names itself stays listed.
80
+ - 2b14092: A content source's missing token or SDK is now reported as itself on a fresh build, instead of as `BLUME_SOURCE_FETCH_FAILED` with the API's error. `blume dev`, `blume build`, and `blume doctor` warn about unset variables before any source fetches, `notion()` and `contentful()` stop before their first request with `BLUME_MISSING_SECRET` when their token is unset, and a missing SDK fails as `BLUME_SOURCE_SDK_MISSING`.
81
+ - 3114c92: `BLUME_MDX_CURLY_ANCHOR` now also catches the spaced `{ #id }` and kramdown `{: #id }` heading anchors in `.mdx` pages, which fail the compile the same way `{#id}` does, and quotes the marker as written. Only the unspaced `{#id}` pins an anchor in `.md`.
82
+ - 00c4707: With fallbacks off (`fallbackLocale: null`), the language switcher no longer links to a translation that doesn't exist. A language the page isn't translated into is left out of the switcher, where it used to link to a 404.
83
+ - 492fdf2: `blume translate` no longer copies a page's `seo.canonical` into its translations. The canonical names the source-language page, so every translation used to canonicalize to it and drop out of search in its own language; a translation now gets the default canonical, its own URL.
84
+ - 68ed70d: The Try it panel's CORS message now names the right setting for the page it's on: `playground: { proxy: true }` on the `openapi()` or `graphql()` reference, or `api: { playground: { proxy: true } }` for hand-written API pages. It also says the proxy needs server output.
85
+ - 0ea988e: Typesense syncs no longer take search down while they run. Each `blume build` imports your pages into a new collection, then points an alias with your `collection` name at it and drops the collection it replaced, so searches keep reading the previous collection until the new one is complete, and a failed sync leaves it serving instead of leaving no collection at all. On the first sync, a collection that already has that name is replaced by the alias, and search keys scoped to the name keep working. The admin key needs to manage aliases as well as collections.
86
+ - 7d904d4: `typesense()` takes a `locale`, a two-letter language code such as `"ja"`, `"zh"`, or `"th"`. The sync then tokenizes the collection's searched text fields for that language, so a query in a script written without spaces matches words inside a run of text, not only at its start.
87
+ - ef2ebd4: Typesense results rank by relevance again. The dialog sorted by relevance in ten buckets and then by `search.boost`, which ranked pages inside each bucket by boost alone, so with equal boosts the best match could land behind weaker ones. It now sorts by relevance first and uses the boost to order results that match equally well.
88
+ - d4087e8: A `layout` override in `components.ts` whose key isn't a layout slot (a typo, or `footer` for `Footer`) now logs a warning that lists the slots, instead of being ignored silently.
89
+ - b780c28: Update dependencies: `@astrojs/vercel` 11.0.11, `@pierre/diffs` 1.5.1, `@scalar/astro` 0.4.26, `dompurify` 3.4.16, and `js-yaml` 5.4.2.
90
+ - d1668f0: `upstash()` rate limiting now counts a request and sets its window in one step. A window that ended mid-request could leave the reader's count with no expiry, which locked them out of that route for good; a count left that way now gets a window again on the reader's next request.
91
+ - 7790b31: `upstash()` takes `urlEnv` and `tokenEnv`, the names of the env vars its REST endpoint and token are read from, so a database added from Vercel's Marketplace works with the `KV_REST_API_URL` and `KV_REST_API_TOKEN` it sets: `upstash({ urlEnv: "KV_REST_API_URL", tokenEnv: "KV_REST_API_TOKEN" })`. `blume build` warns about the variables you name.
92
+ - 95ff53e: Add `--ignore <glob>` to `blume validate` and `blume audit`. With `--external`, an external link whose URL matches the glob is never requested or reported, so a placeholder domain, a local server, or a site that turns bots away no longer fails the check: `--ignore "https://api.acme.example/**"`. Repeat the flag for more patterns. Internal links are always checked.
93
+ - d0db71f: `blume validate` now checks every link form Markdown and MDX render, not only one-line inline links: reference-style links (at their `[label]: /target` definition), autolinks like `<https://example.com>`, links whose label wraps onto the next line, and lowercase HTML `<a href>` tags. An `<a href>` ships as written, so its relative path resolves against the page's URL, as a browser reads it, and no `basePath` is added to it.
94
+ - 6b7366b: `Accept: text/markdown` negotiation on a Vercel server build now reads media types in any case and honors q-values the way `blume dev` and Cloudflare do: `text/markdown;q=0` gets HTML, and so does a header that weighs `text/html` above Markdown. The prerendered 404's JSON twin negotiates the same way. When Markdown and HTML both carry a q-value below 1, Vercel's routing rules can't compare them and serve HTML. `blume dev` now sends `Vary: Accept` on the HTML answer at a negotiated URL too, not only on the Markdown one.
95
+ - 916861d: A `vercel()` server build with `base` set now serves the site under it. `@astrojs/vercel` ignores the base: it left the static files and routes at the root, so every page asset and server route 404'd, and its redirects came out as `^/docsold$` → `/docs/docs/new`. The build now moves the static files to `.vercel/output/static/<base>/` and the routes and redirects under the base.
96
+
97
+ ## 2.1.0
98
+
99
+ ### Minor Changes
100
+
101
+ - 99119e7: API references can generate code samples in 18 languages: cURL, Python, JavaScript, Node.js, TypeScript, PHP, Go, Java, Ruby, PowerShell, Swift, C#, .NET, C, C++, Kotlin, Rust, and Dart. List them in `codeSamples` on `openapi()` or `graphql()` in the order you want them, by id or by a common alias such as `golang`, `c#`, or `ts`. Each sample quotes values by its own language's string rules and updates live with the Try it form. `node` and `typescript` now generate their own samples (axios, and typed `fetch`) instead of repeating the JavaScript one.
102
+
103
+ Operations also render the spec's own `x-codeSamples` (or `x-code-samples`) as tabs ahead of the generated samples, for SDK snippets written by hand or by Speakeasy or Stainless. Set `codeSamples: false` to show only those.
104
+ - f4854ef: Add a bot check for the assistant. `ai.assistant.captcha` takes an adapter from `blume/captcha`, `turnstile({ siteKey })` or `hcaptcha({ siteKey })`, run invisibly: the provider's script loads with a reader's first question, the panel sends a fresh token with each question, and the generated route verifies it (with `TURNSTILE_SECRET_KEY` or `HCAPTCHA_SECRET_KEY`) before the model runs. A failed check answers `403`, which the panel shows as a translated "we couldn't check that you're human"; a missing secret answers with the assistant's "not configured" notice, and `blume build` warns. With an external `endpoint`, the token is sent as `captcha` in the request body for that backend to verify. `useAssistant` takes the `captcha` settings and a `verifyMessage` too.
105
+ - 253ad9e: The assistant can now search the docs and read whole pages itself. Beyond the pages retrieved up front, the model gets a `search_docs` tool and a `read_page` tool, and can search, read, and search again before it answers, within one question and at most five steps. The tools run on your server against the assistant's snapshot and keep to the reader's language and docs version. When nothing matches a question up front, the assistant now searches instead of saying it doesn't know. They're on by default, except for `openai()` with a `baseUrl`, whose model may not support tool calling. Set `ai.assistant.tools` to change either.
106
+ - 6653f72: The assistant can now call OpenAI, Anthropic, Gemini, and Grok directly. `openai({ model })`, `anthropic({ model })`, `gemini({ model })`, and `grok({ model })` from `blume/ai` send each question to the provider's own API with your key, through its AI SDK package (`@ai-sdk/openai`, `@ai-sdk/anthropic`, `@ai-sdk/google`, or `@ai-sdk/xai`, installed as needed). They read `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `GEMINI_API_KEY`, and `XAI_API_KEY`, turn the docs tools on, and send `reasoning` as each model's own control. `openai()` also takes a `baseUrl` for any OpenAI-compatible endpoint, which it calls through `@ai-sdk/openai-compatible` with the docs tools off, as `openaiCompatible()` did. `openaiCompatible()` still works and now returns the same adapter.
107
+ - aca5ac9: Add content variables. Define values under `variables` in `blume.config.ts`, like `{ version: "2.1.0", "api-url": "https://api.example.com" }`, and `{{version}}` anywhere in a page reads the value: in prose, headings, links, code, and component props, in `.md` and `.mdx` pages and the files they include. Search, the `.md` mirrors, and `llms-full.txt` show the value too. An undefined name in prose fails the build at its line (`BLUME_UNDEFINED_VARIABLE`); inside code it's left as written. Sites that define no variables are unaffected.
108
+ - 9ac2262: Add cookie consent. `consent` in `blume.config.ts` takes an adapter from `blume/consent`, and with it set every `analytics` adapter waits for the reader: its tags stay in the page as inert `text/plain` until the reader allows analytics, then run in order, once per page load, and Vercel Web Analytics sends nothing until then. `native()` is Blume's own banner, a card with Accept and Decline side by side and an optional `policy` link, translated in every built-in language and shown in `blume dev` too. `osano({ customerId, configId })` and `ethyca({ privacyCenter, propertyId, notice })` load Osano or Ethyca's Fides instead, and follow the answers readers give there. The site footer gains a Cookie settings link that reopens the banner or the manager's preferences (any element with `data-blume-consent-open` works in a custom footer), and a reader who takes consent back gets a reload so analytics stops. The "Was this page helpful?" rating, which reports through analytics too, only shows for readers who allowed analytics. Your own scripts can wait the same way with `type="text/plain" data-blume-consent="analytics"`, or listen for the `blume:consent` event.
109
+ - c3e1cd3: Add directory listings. `directory` in a folder's `meta.ts`, or on a group in an explicit `navigation.sidebar`, lists the group's pages below the content of its own page (a folder's `index` page, or the group's `root`): `card` as a grid of cards with each page's icon and description, `accordion` as rows with each subgroup a section that opens to its pages, and `none`, the default, as nothing. Nested groups inherit the nearest setting, so one `directory` in the content root's `meta.ts` gives every section a listing, and any folder can set its own. The values match Mintlify's `directory`.
110
+ - 0036165: Add components for documenting endpoints by hand. `<ParamField>` is a request parameter, named by where it goes (`<ParamField query="limit" type="integer" default={20}>`, or `path`, `header`, `body`), and `<ResponseField name="id" type="string">` is a field of the response, with optional `pre` and `post` labels. Both take `type`, `required`, `deprecated`, and `default`, hold their description as content, and nest an object's fields inside an `<Expandable>`. They render like the OpenAPI reference's rows, and a page's Markdown copy lists each field with its type and flags. `<RequestExample>` and `<ResponseExample>` hold code blocks as tabs (or a language menu with `dropdown`); on a wide screen they pin to a column beside the page, request above response, and stay in view while the reader scrolls, the way an OpenAPI operation's examples do. A page with `api` frontmatter (`api: POST /v1/users`) documents one endpoint without a spec: it shows the method and path at the top, and its `<ParamField>`s build a Try it panel and request samples in cURL, JavaScript, and Python, the same ones an OpenAPI operation gets, with nested fields as the properties of a JSON body. `authMethod` and `playground` frontmatter tune a page, and a new top-level `api` config sets the `server` a path joins, the default `auth`, and the `playground`, whose `proxy: true` routes sends through the built-in CORS proxy for those origins. The names and props match Mintlify's, so migrated pages keep them as written.
111
+ - 72f7cf5: Slim the header down to icon buttons, making room in it. Search is now an icon button beside the theme toggle and the assistant, in place of the search field, and each icon button names itself in a tooltip on hover and keyboard focus: "Search (⌘K)" (`Ctrl K` off Apple devices), "Toggle theme", and "Open assistant". The GitHub link leaves the header for the new site footer, which is now the one place the site links its repository and social profiles; `navigation.repo` works as before and applies there. The header's tabs now sit at its center on wide screens. The version and language pickers lose their border to match the icon buttons, the header's right-hand controls sit closer together, and the language switcher drops its globe icon and always shows the language's name. Its menu now widens to fit, so a long language name no longer runs into the "Not translated" note beside it. A `Header` override is unaffected. The "Open assistant" tooltip is a new `assistant.open` UI string, translated in every built-in language pack.
112
+ - f8bd737: Pass props to an `<include>`: every attribute other than `lang` and `meta` becomes a value the included file reads with `{{name}}`, like `<include plan="Pro" feature="SSO">./_snippets/upgrade.mdx</include>`. Props reach the partial's own nested includes and take precedence over a site-wide variable with the same name.
113
+ - 0758eaa: OpenAPI references now document webhooks and callbacks. Each webhook in a 3.1 spec's `webhooks` gets its own page, filed under its first tag or a Webhooks group. The page shows its payload schema, the responses your endpoint should send, and an example payload in place of the Try it panel. It lists only the security the webhook itself declares, since the spec's root `security` guards calls to the API, not the requests it sends. Webhook pages are in search, `llms.txt`, and the MCP server, and their Markdown marks them as requests the API sends. An operation's `callbacks`, inline or `$ref`'d from `components.callbacks`, render in a Callbacks section on its page with their URL expression, method, request body, and responses. Specs with webhooks no longer log a warning that they're missing from the reference.
114
+ - 2153f6b: Add page layout modes. `mode` in a page's frontmatter sets what it shows around its content: `wide` drops the table of contents and lets the content take its width, `center` drops the sidebar too and centers a wider column, `custom` keeps only the header for a landing page written in MDX, and `frame` is `custom` with the sidebar. `custom` and `frame` pages render no title, description, breadcrumbs, page-end links, or site footer, so they bring their own heading. Every mode stays in search and keeps its Markdown copy. The values match Mintlify's; its full-page `assistant` mode has no equivalent.
115
+ - ecbfb0e: Add narration: a "Listen to this page" player that reads each page aloud and highlights the sentence being read. Turn it on with `narration: true` to use the reader's browser voices, which need no key and work on any host. Or pass `narration: { provider: gateway({ model: "openai/tts-1-hd", voice: "alloy" }) }` to generate neural audio at build: one cached clip per sentence, shipped as static files, with browser voices as the fallback in `blume dev` or when the key is missing.
116
+
117
+ The player announces callouts, steps, tabs, and collapsible sections with short spoken cues, and skips code, tables, media, and type tables. It opens a closed section or switches to a hidden tab when narration reaches it, and keeps the sentence in view until the reader scrolls away. It offers speeds from 0.8× to 2×, and stops when the reader opens another page. Set `narration: false` in a page's frontmatter to leave it out, or add `data-blume-narration="skip"` to keep any element out of narration.
118
+ - aea605b: Add pattern redirects. A redirect's `from` can now cover many paths, written the way Mintlify and `vercel.json` write them: `:name` matches one segment (`/blog/:slug`), `:name*` as the last segment matches the rest of the path (`/beta/:slug*` sends `/beta/a/b` to `/v2/a/b` and `/beta` to `/v2`), and `*` ending a segment matches the rest from there (`/old/article-*`). `to` reads the captures (`/v2/:slug*`, `/new/article-*`). Every host gets them in its own syntax: `_redirects` splats, `vercel.json` sources, and the routing config of a Vercel or Netlify server build, while the Node and Cloudflare servers and `blume dev` match them directly. Exact redirects win over a pattern that covers the same path. A pattern that also matches a page fails the build (`BLUME_REDIRECT_MATCHES_PAGE`), since hosts disagree on which answers, and links into a pattern count as valid in `blume validate` and `blume audit`.
119
+ - 09efac4: Add rate limiting to the server routes a reader can call: the assistant, the API playground proxy, and Mixedbread search. Each reader, by IP address, gets 30 requests per route every 10 minutes by default, and past that the route answers `429 Too Many Requests` with a `Retry-After` header, which the assistant turns into a translated "try again in a few minutes". `rateLimit` in `blume.config.ts` takes an adapter from `blume/ratelimit`: `memory()`, the default, counts in the server's memory (exact on `node()`, per instance on serverless hosts); `upstash()` shares the count through Upstash Redis's REST API (`UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`); and `cloudflare()` counts with Workers rate limiting, declaring the binding in the built Worker's config. Each takes `requests` and `window` (seconds). A request whose address the host can't tell is let through, and so is one a shared store fails to count. `rateLimit: false` turns it off.
120
+ - 0dd30af: Add a site footer: one row, as tall as the header, below the content on every page. Your repository link moves there from the header (see the header changes), as the first of the footer's icons, and `footer` in `blume.config.ts` adds the rest: `links`, a list of `{ label, href }` shown on one side, and `socials`, profile URLs keyed by platform (`x`, `discord`, `linkedin`, `youtube`, `website`, and more) shown as brand icons on the other, both in the order written. A `github` social replaces the repository link, and `navigation.repo` still hides it or points it elsewhere. Custom pages built on `PageLayout` show the footer too, unless they fill the layout's `footer` slot. A `Footer` layout override still replaces it, and `blume add footer` copies the built-in into your project to edit. A site with no repository, links, or profiles has no footer.
121
+
122
+ ### Patch Changes
123
+
124
+ - ade0397: Add an Ask button to code blocks when the assistant is on. It opens the assistant with the block attached as a chip above the input; the question goes to the model with the code as a fenced block (up to 6,000 characters), and an empty question asks it to explain the code. The conversation shows the attached code under the question, and the button's label and the chip's text are translated in every built-in language. Code groups get one button in their tab strip, which asks about the tab that's showing.
125
+ - 57db488: Add a support handoff to the assistant. `ai.assistant.support` takes a `mailto:` address, a URL, or a page on your site, and once there's a conversation the panel shows a translated "Contact support" link: an email starts with the conversation as its body, and a link gets the conversation's id as a `thread` query parameter. The assistant's `ask`, `ask_answer`, and `ask_error` analytics events now carry the same `thread`, and `useAssistant` returns it.
126
+ - 0654705: Add `blume skill`, which writes your docs site's agent skill with a coding agent. `blume skill --claude` (or `--codex`) opens the agent on the new `blume-write-skill` skill. The agent writes a `SKILL.md` grounded in the docs that teaches an agent to use the product: setup, core concepts, common tasks, and gotchas, each linked to its page. The file goes under `agents.skills`, named after the site so it replaces the generated skill at `/skill.md`. Run it again to refresh the skill after big docs changes.
127
+ - c3e1cd3: Add `wrap` and `expandable` to code fences. `wrap` after the language (` ```ts wrap `) wraps one block's long lines instead of scrolling them, the way `markdown.code.wrap` does for every block. `expandable` collapses a long block to its first lines under a fade, with a Show more toggle that opens it in full, no inner scroll, and Show less to close it again; a block under 16 lines renders as usual. Both compose with a title, line numbers, and each other, and the toggle's labels are translated in every built-in language.
128
+ - a7c8ceb: Fix header controls overlapping on narrow screens. With many controls on (tabs, a version selector, the language switcher, search, and the icon buttons), the version and language pills squeezed on top of each other on phones, and the tab bar ran into them on tablets. Below the desktop breakpoint, selectors, the version selector, and the language switcher now sit at the top of the navigation drawer, full width. The remaining header controls keep their size, and only the site title truncates to make room.
129
+ - 553a58f: Apply OpenAPI Overlays to a spec before it renders. List `overlays` beside `spec` in `openapi()` or `scalar()`, or on each source, as local paths or `http(s)` URLs, applied in order. Overlay Specification 1.0 and 1.1 are supported: `update`, `copy`, and `remove` actions, with targets as RFC 9535 JSONPath. Overlays apply to the spec as written, before it's upgraded to OpenAPI 3.1, and everything built from the spec sees the result. An overlay that fails stops its reference from rendering, the way an unreadable spec does, so it can't publish what it was meant to hide.
130
+ - d6190ee: OpenAPI overlays can now add a property named `constructor` (it used to fail with a merge error), and a `__proto__` key in an overlay no longer reaches `Object.prototype`. Parsing a long run of digits in a theme color no longer takes quadratic time.
131
+ - c3e1cd3: Add `pagination: false` to page frontmatter, which leaves the previous and next links off that page. The page keeps its place in the order, so its neighbors still link to it. The Mintlify migration maps `hideFooterPagination: true` to it.
132
+ - 7f9fa4a: Add `<View>` for pages written for several audiences, such as one per programming language. Each distinct `title` becomes an option in a picker above the page's content, and only the chosen view's blocks show. Prose outside any `<View>` shows in every view, and headings in hidden views drop out of the table of contents. The reader's pick is remembered across pages and written to the URL as `?view=`, a link to a heading opens its view, and the choice applies before the page paints. The agent-facing Markdown includes every view under its name.
133
+ - 0a29cb2: Translate the banner, header links, and footer per locale. The banner's `content` and link `text`, `navigation.actions`, `navigation.cta`, and `navigation.featured` labels, and `footer` link labels now accept a map of locale code to text, like tab labels do. Each page shows its locale's entry and falls back to the default locale's. Internal footer links now move into the reader's locale whenever that locale serves the page, as header links already did.
134
+ - 4e4b258: Add related pages. `related` in a page's frontmatter lists up to ten pages to suggest at its foot, shown as cards under a translated "Related pages" heading: a root-relative path shows that page's title and description (its translation, on a translated page), a `{ Title: link }` entry names the card itself, and an absolute URL links off the site. Paths are checked like the page's other links, so `blume validate` reports one that matches no page. The key matches Mintlify's.
135
+ - 8f040cd: Add `i18n.routeByBrowserLanguage`, which sends visitors who land on the default language's home page to the home page in their browser's preferred language. Blume tries each language the browser prefers, in order, matching an exact locale code and then the base language, and a visitor whose first match is the default language stays. Picking a language with the switcher stops the routing for that reader, and only visitors arriving from outside the site are routed. The redirect runs in the browser before the page paints, so it works on static hosts. It's off by default.
136
+ - 169966c: Report search to your analytics. Once a query settles (a second without typing, or the reader picks a result or closes the dialog), the search dialog sends a `search` event with the `query`, its number of `results`, and the `path`, so queries with no results are easy to find. Picking a result sends `search_select` with the `query`, the result's `position`, and its `url`. Both go through every analytics adapter with an event API and as `blume:track` events.
137
+ - 0f8a46e: Rank pages with `search.boost` and `search.keywords` frontmatter. `boost` multiplies a page's search relevance: above 1 moves it up, below 1 moves it down. The default Orama search, FlexSearch, the MCP server, and the assistant apply it exactly. Pagefind weighs a boosted page's text more heavily, Algolia and Typesense sort by it among close matches, and Orama Cloud re-sorts a wider set of results. `keywords` are extra terms a page is found by, beyond its own text. Blume 1 accepted `search.boost` without reading it, so a page that still sets it now ranks by it. The Mintlify migration moves `keywords`, `boost`, and `searchable: false` into the `search` block.
138
+ - aa2babe: Add `seo.metatags` for tags written into every page's head: site-verification tokens, `theme-color`, an app banner, and anything else Blume has no setting for. Open Graph families render with `property` and everything else with `name`. A tag Blume writes itself, such as `description`, `robots`, `og:image`, or a `twitter:` card tag, is refused, and the build names the setting that controls it.
139
+ - 7dee91b: Publish an agent skill for every site. The build writes a `SKILL.md` named after the site's title, served at `/skill.md` and listed in the skills discovery index, `llms.txt`, and the AI catalog. It's built from what Blume already knows, with no model call: how to read any page as Markdown, `llms.txt`, the MCP server, the API references, the changelog, and a map of the docs with each page's description. It needs `deployment.site` for its absolute links. A skill of the same name in `agents.skills` replaces it, and `agents.skillMd: false` turns it off.
140
+ - 7a58b53: Meet WCAG AA contrast with the accent colors, and check a site's theme colors in `blume audit`. Each accent preset now has a darker light-mode shade and a lighter dark-mode shade, so accent text and button labels reach 4.5:1 in both modes. Blue is the default, so this changes sites that set no accent too. Labels on accent and action fills are white while white reaches AA on that color, and dark otherwise. A light accent, and every preset in dark mode, now gets dark labels instead of unreadable white ones. A new `accessibility` category in `blume audit` measures a custom `theme.accent`, `theme.action`, or `theme.background` against the same bar in both modes, and says when it can't read a color.
141
+ - 0c0acd5: Tell the translation agent to keep frontmatter valid YAML by quoting a translated value that contains a colon or starts with a quote or backtick, and name the YAML error and its line and column when `blume translate` rejects a page whose frontmatter doesn't parse.
142
+ - f50ef8a: The `BLUME_WIKILINK_UNRESOLVED` and `BLUME_WIKILINK_AMBIGUOUS` diagnostics now link to the Obsidian source page instead of the content sources overview.
143
+ - aecd4b9: Add written feedback. `feedback: { comments: true }` offers a box after the "Was this page helpful?" rating where the reader can say what worked or what's missing. A comment is sent as a `feedback_comment` event, with the rating, path, title, and the comment (up to 1,000 characters), through every analytics adapter with an event API and as a `blume:track` event. The box's label and button are UI strings, translated in every built-in language. `feedback: true` and `false` work as before, and the `Feedback` layout slot now receives a `comments` prop.
144
+
3
145
  ## 2.0.3
4
146
 
5
147
  ### Patch Changes
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Blume
2
2
 
3
- [![npm downloads](https://img.shields.io/npm/dm/blume.svg)](https://www.npmjs.com/package/blume) [![Socket Badge](https://socket.dev/api/badge/npm/package/blume)](https://socket.dev/npm/package/blume) ![CodeRabbit Pull Request Reviews](https://img.shields.io/coderabbit/prs/github/haydenbleasel/blume?utm_source=oss&utm_medium=github&utm_campaign=haydenbleasel%2Fblume&labelColor=171717&color=FF570A&link=https%3A%2F%2Fcoderabbit.ai&label=CodeRabbit+Reviews)
3
+ [![npm downloads](https://img.shields.io/npm/dm/blume.svg)](https://www.npmjs.com/package/blume) [![Socket Badge](https://badge.socket.dev/npm/package/blume/latest)](https://socket.dev/npm/package/blume/overview/latest) ![CodeRabbit Pull Request Reviews](https://img.shields.io/coderabbit/prs/github/haydenbleasel/blume?utm_source=oss&utm_medium=github&utm_campaign=haydenbleasel%2Fblume&labelColor=171717&color=FF570A&link=https%3A%2F%2Fcoderabbit.ai&label=CodeRabbit+Reviews)
4
4
 
5
5
  **The open-source docs framework for humans and agents.** Fast, AI-ready, and zero-config. Free and open source, forever.
6
6
 
@@ -7,45 +7,50 @@ import {
7
7
  } from "./index.js";
8
8
  import {
9
9
  deployPlatform
10
- } from "./chunk-pv29h0wf.js";
11
- import"./chunk-3em5wd2y.js";
12
- import"./chunk-j85vccga.js";
10
+ } from "./chunk-ehweg4fr.js";
11
+ import"./chunk-zccbjcj0.js";
12
+ import"./chunk-ncj7w596.js";
13
13
  import {
14
14
  publishBuildProject,
15
15
  ogCacheDir,
16
16
  pruneCardCache,
17
17
  cardCacheTally
18
- } from "./chunk-c8chx29p.js";
19
- import"./chunk-yfyb25rh.js";
18
+ } from "./chunk-ep6nd0rn.js";
19
+ import"./chunk-n0v7m8ry.js";
20
20
  import {
21
21
  deployOutputDir,
22
22
  deployStaticDir,
23
23
  surfaceAdapterOutput
24
- } from "./chunk-5m5nmvyq.js";
24
+ } from "./chunk-gb420vvz.js";
25
25
  import {
26
26
  ensureGitignore
27
27
  } from "./chunk-yzhm0j9q.js";
28
- import"./chunk-8ktnccpt.js";
28
+ import"./chunk-54ztw1nj.js";
29
29
  import {
30
30
  removedBuildFlags,
31
31
  flagList,
32
32
  removedBuildFlagsAdvice
33
- } from "./chunk-pehfxfta.js";
33
+ } from "./chunk-nrns10mj.js";
34
+ import {
35
+ astroBuildDiagnostics
36
+ } from "./chunk-150jk7km.js";
34
37
  import {
35
38
  refuseIfDevRunning
36
- } from "./chunk-akbpwfxc.js";
39
+ } from "./chunk-dzwehpy7.js";
37
40
  import {
38
41
  refuseIfEjected
39
- } from "./chunk-ey84smr6.js";
42
+ } from "./chunk-mrcccgnh.js";
43
+ import"./chunk-66w9j7p6.js";
40
44
  import"./chunk-jq5n4avg.js";
41
- import"./chunk-r20tn01b.js";
42
- import"./chunk-b07cmahc.js";
45
+ import"./chunk-cm89scdv.js";
46
+ import"./chunk-c1y538kd.js";
43
47
  import {
44
48
  prepareProject
45
- } from "./chunk-tzmab476.js";
49
+ } from "./chunk-e8xw9qkh.js";
46
50
  import {
47
51
  serverFeatures
48
- } from "./chunk-364znk6q.js";
52
+ } from "./chunk-t2m5j4pr.js";
53
+ import"./chunk-w1r4vase.js";
49
54
 
50
55
  // src/cli/commands/build.ts
51
56
  import { existsSync } from "node:fs";
@@ -53,38 +58,6 @@ import { readdir, stat } from "node:fs/promises";
53
58
  import { build } from "astro";
54
59
  import { defineCommand } from "citty";
55
60
  import { join } from "pathe";
56
-
57
- // src/cli/build-failure.ts
58
- import { z } from "zod";
59
- var buildErrorSchema = z.looseObject({
60
- errors: z.array(z.instanceof(Error)).optional(),
61
- id: z.string().optional(),
62
- loc: z.looseObject({
63
- column: z.number().optional(),
64
- file: z.string().optional(),
65
- line: z.number().optional()
66
- }).optional()
67
- });
68
- var failureDiagnostic = (error) => {
69
- const parsed = buildErrorSchema.safeParse(error);
70
- const { id, loc } = parsed.success ? parsed.data : {};
71
- const name = error.name === "Error" ? "" : `${error.name}: `;
72
- return {
73
- code: "BLUME_BUILD_FAILED",
74
- column: loc?.column,
75
- file: loc?.file ?? id,
76
- line: loc?.line,
77
- message: `${name}${error.message}`,
78
- severity: "error"
79
- };
80
- };
81
- var astroBuildDiagnostics = (error) => {
82
- const parsed = buildErrorSchema.safeParse(error);
83
- const failures = parsed.success ? parsed.data.errors ?? [] : [];
84
- return (failures.length > 0 ? failures : [error]).map(failureDiagnostic);
85
- };
86
-
87
- // src/cli/commands/build.ts
88
61
  var BUDGET_JS = "budget-js";
89
62
  var BUDGET_CSS = "budget-css";
90
63
  var validateBudgetFlags = (args) => {
@@ -298,5 +271,5 @@ export {
298
271
  runClientAssetChecks
299
272
  };
300
273
 
301
- //# debugId=D6CABD020883D7E964756E2164756E21
302
- //# sourceMappingURL=chunk-5f86nr5m.js.map
274
+ //# debugId=5EAF9E033A01BFBE64756E2164756E21
275
+ //# sourceMappingURL=chunk-073rdvgb.js.map
@@ -1,11 +1,10 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/cli/commands/build.ts", "../src/cli/build-failure.ts"],
3
+ "sources": ["../src/cli/commands/build.ts"],
4
4
  "sourcesContent": [
5
- "import { existsSync } from \"node:fs\";\nimport { readdir, stat } from \"node:fs/promises\";\n\nimport { build } from \"astro\";\nimport { defineCommand } from \"citty\";\nimport { join } from \"pathe\";\n\nimport { publishBuildProject } from \"../../astro/integration.ts\";\nimport { BlumeError } from \"../../core/diagnostics.ts\";\nimport { ensureGitignore } from \"../../core/gitignore.ts\";\nimport type { BlumeProject } from \"../../core/project-graph.ts\";\nimport { serverFeatures } from \"../../core/server-features.ts\";\nimport {\n deployOutputDir,\n deployStaticDir,\n surfaceAdapterOutput,\n} from \"../../deploy/adapter-output.ts\";\nimport { deployPlatform } from \"../../deploy/platforms/index.ts\";\nimport { cardCacheTally, ogCacheDir, pruneCardCache } from \"../../og/cache.ts\";\nimport {\n flagList,\n removedBuildFlags,\n removedBuildFlagsAdvice,\n} from \"../../upgrade/upgrade.ts\";\nimport { astroBuildDiagnostics } from \"../build-failure.ts\";\nimport { commandMeta } from \"../command-meta.ts\";\nimport { refuseIfDevRunning } from \"../dev-lock.ts\";\nimport { refuseIfEjected } from \"../eject-scripts.ts\";\nimport { logger, reportDiagnostics } from \"../log.ts\";\nimport { prepareProject } from \"../prepare.ts\";\n\nconst BUDGET_JS = \"budget-js\";\nconst BUDGET_CSS = \"budget-css\";\n\ninterface BudgetArgs {\n \"budget-css\"?: string;\n \"budget-js\"?: string;\n}\n\n/**\n * Reject a non-numeric performance budget. `Number(\"250kb\")` is `NaN` and\n * `total > NaN` is always false, so a typo'd flag would silently pass the gate;\n * fail up front instead.\n */\nconst validateBudgetFlags = (args: BudgetArgs): void => {\n for (const flag of [BUDGET_JS, BUDGET_CSS] as const) {\n const value = args[flag];\n const parsed = Number(value);\n // Equivalent to `!(parsed > 0)` but without the inverted check: this must\n // also reject `NaN` (a typo'd flag like \"250kb\"), which `parsed <= 0` alone\n // would let through since `NaN <= 0` is false.\n if (value !== undefined && (Number.isNaN(parsed) || parsed <= 0)) {\n logger.error(\n `Invalid --${flag} \"${value}\" (expected a positive number of kB).`\n );\n process.exit(1);\n }\n }\n};\n\n/**\n * Report how many OG cards the build read back from the on-disk cache against\n * how many it rendered (the endpoint tallies both), so a warm rebuild shows\n * where the time went. With `prune`, also drop the cached cards this build\n * never asked for — renamed pages, edited descriptions, cards from an earlier\n * Blume version — so a persisted cache holds exactly the current site's cards.\n */\nconst reportCardCache = async (\n project: BlumeProject,\n prune: boolean\n): Promise<void> => {\n const cards = cardCacheTally();\n if (!cards) {\n return;\n }\n logger.info(\n `OG cards: ${cards.hits} reused from the cache, ${cards.misses} rendered`\n );\n if (prune) {\n await pruneCardCache(ogCacheDir(project.context));\n }\n};\n\nconst formatBytes = (bytes: number): string => {\n if (bytes < 1024) {\n return `${bytes} B`;\n }\n const digits = bytes < 1024 * 100 ? 1 : 0;\n return `${(bytes / 1024).toFixed(digits)} kB`;\n};\n\n/** Sizes of `dist/_astro/*.<ext>`, largest first (empty when none exist). */\nconst astroAssets = async (\n distDir: string,\n ext: string\n): Promise<{ name: string; size: number }[]> => {\n const astroDir = join(distDir, \"_astro\");\n if (!existsSync(astroDir)) {\n return [];\n }\n const entries = await readdir(astroDir);\n const files = entries.filter((name) => name.endsWith(`.${ext}`));\n const sized = await Promise.all(\n files.map(async (name) => {\n const info = await stat(join(astroDir, name));\n return { name, size: info.size };\n })\n );\n return sized.toSorted((a, b) => b.size - a.size);\n};\n\nconst totalSize = (assets: { size: number }[]): number =>\n assets.reduce((sum, asset) => sum + asset.size, 0);\n\n/**\n * Print the client JavaScript Astro shipped, largest first, plus the total. A\n * dependency-free bundle report — the interactive weight of a docs site is its\n * `_astro/*.js`, so this surfaces regressions without a visualizer.\n */\nconst reportBundleSizes = async (distDir: string): Promise<void> => {\n const sized = await astroAssets(distDir, \"js\");\n if (sized.length === 0) {\n logger.info(\"No client JavaScript emitted — the site ships zero JS.\");\n return;\n }\n const rows = sized\n .slice(0, 15)\n .map((file) => ` ${formatBytes(file.size).padStart(8)} ${file.name}`);\n logger.box(\n [\n `Client JavaScript — ${sized.length} file(s), ${formatBytes(totalSize(sized))} total`,\n \"\",\n ...rows,\n sized.length > 15 ? ` … and ${sized.length - 15} more` : null,\n ]\n .filter((line) => line !== null)\n .join(\"\\n\")\n );\n};\n\n/**\n * Enforce a performance budget on the built client assets: fail the build when\n * total `_astro/*.js` (or `*.css`) exceeds the given kB cap. Budgets that would\n * otherwise be \"documented, not measured\" become a real CI gate. Returns whether\n * every budget passed.\n */\nconst enforceBudget = async (\n distDir: string,\n args: BudgetArgs\n): Promise<\"fail\" | \"pass\" | \"skip\"> => {\n const checks: { ext: string; limitKb: number; name: string }[] = [\n ...(args[BUDGET_JS]\n ? [{ ext: \"js\", limitKb: Number(args[BUDGET_JS]), name: \"JavaScript\" }]\n : []),\n ...(args[BUDGET_CSS]\n ? [{ ext: \"css\", limitKb: Number(args[BUDGET_CSS]), name: \"CSS\" }]\n : []),\n ];\n if (checks.length === 0) {\n return \"skip\";\n }\n let passed = true;\n for (const check of checks) {\n // oxlint-disable-next-line no-await-in-loop -- a couple of sequential reads\n const total = totalSize(await astroAssets(distDir, check.ext));\n const limit = check.limitKb * 1024;\n if (total > limit) {\n passed = false;\n logger.error(\n `${check.name} budget exceeded: ${formatBytes(total)} > ${check.limitKb} kB`\n );\n } else {\n logger.success(\n `${check.name} budget: ${formatBytes(total)} / ${check.limitKb} kB`\n );\n }\n }\n return passed ? \"pass\" : \"fail\";\n};\n\n/**\n * Run the optional bundle report (`--analyze`) and performance-budget gate\n * against the directory whose `_astro/` client assets the deploy serves.\n * Shared by real and isolated builds — an isolated CI run passing\n * `--budget-js` must still fail on an exceeded budget rather than silently\n * skipping the check. Exits non-zero when a budget is exceeded.\n */\nexport const runClientAssetChecks = async (\n staticDir: string,\n args: { analyze?: boolean } & BudgetArgs\n): Promise<void> => {\n if (args.analyze) {\n await reportBundleSizes(staticDir);\n }\n if ((await enforceBudget(staticDir, args)) === \"fail\") {\n process.exit(1);\n }\n};\n\n/**\n * Print the build summary box and run the optional bundle report / budget\n * gate against the served static dir. The deploy artifacts themselves\n * (search index, llms.txt, sitemap, robots, redirect and header files, …)\n * were written by the integration's `astro:build:done` hook during\n * `build()` — see `deploy/artifacts.ts`. Exits non-zero if a budget is\n * exceeded.\n */\nconst reportBuild = async (\n project: BlumeProject,\n distDir: string,\n args: { analyze?: boolean } & BudgetArgs\n): Promise<void> => {\n const { config } = project;\n const features = serverFeatures(config);\n // The sitemap needs both the flag and a `site` (absolute URLs) — only the\n // latter deserves the remediation hint.\n const sitemapNote = config.seo.sitemap\n ? \"no (set deployment.site)\"\n : \"no (seo.sitemap is false)\";\n const rows: [label: string, value: string | number][] = [\n [\"Output\", config.deployment.options.output],\n [\"Adapter\", config.deployment.kind],\n [\"Site\", config.deployment.options.site ?? \"not set\"],\n [\"Search\", config.search.provider.kind],\n [\"Redirects\", config.redirects.length],\n [\n \"Sitemap\",\n config.deployment.options.site && config.seo.sitemap\n ? \"yes\"\n : sitemapNote,\n ],\n [\"Robots\", config.seo.robots ? \"yes\" : \"no\"],\n [\"Agent JSON\", config.agents.agentReadability ? \"yes\" : \"no\"],\n [\"LLM files\", config.agents.llmsTxt.enabled ? \"yes\" : \"no\"],\n [\"Server features\", features.length > 0 ? features.join(\", \") : \"none\"],\n ];\n // One label column for every row, sized by the longest label.\n const labelWidth = Math.max(...rows.map(([label]) => label.length)) + 2;\n logger.box(\n rows\n .map(([label, value]) => `${label.padEnd(labelWidth)}${value}`)\n .join(\"\\n\")\n );\n\n await runClientAssetChecks(distDir, args);\n\n // Only reachable with --no-strict (strict aborts earlier): repeat the missing\n // count next to the success banner so it can't scroll away unseen.\n if (project.droppedPages > 0) {\n logger.warn(\n `${project.droppedPages} page(s) failed frontmatter validation and are missing from this build.`\n );\n }\n logger.success(`Built to ${distDir}`);\n};\n\nexport const buildCommand = defineCommand({\n args: {\n analyze: {\n description: \"Report client JavaScript bundle sizes after the build.\",\n type: \"boolean\",\n },\n [BUDGET_CSS]: {\n description: \"Fail if total client CSS exceeds this many kB.\",\n type: \"string\",\n },\n [BUDGET_JS]: {\n description: \"Fail if total client JavaScript exceeds this many kB.\",\n type: \"string\",\n },\n isolated: {\n description:\n \"Build into an isolated .blume-verify runtime (and its own dist) so a running dev server and the real dist/ are untouched. For verifying changes while `blume dev` runs.\",\n type: \"boolean\",\n },\n preview: {\n description: \"Include drafts and unpublished CMS content.\",\n type: \"boolean\",\n },\n strict: {\n default: true,\n description:\n \"Fail on error diagnostics (default; pass --no-strict to build anyway, dropping pages that fail validation).\",\n type: \"boolean\",\n },\n },\n meta: commandMeta.build,\n async run({ args, rawArgs }) {\n const root = process.cwd();\n\n // citty accepts unknown flags, so a Blume 1 `--adapter vercel --output\n // server` would otherwise build a static site without a word.\n const removed = removedBuildFlags(rawArgs);\n if (removed.length > 0) {\n logger.error(\n `blume build no longer takes ${flagList(removed)}. ${removedBuildFlagsAdvice(removed)}`\n );\n process.exit(1);\n }\n await refuseIfEjected(root, \"build\");\n\n // `--isolated` (or BLUME_RUNTIME_DIR) relocates the whole runtime to a\n // sibling dir so this build never touches a live dev server's `.blume/` or\n // the user's real `dist/`. A non-default runtime dir has no dev lock, so the\n // refusal below lets it proceed; a plain build still refuses.\n const runtimeDir = args.isolated\n ? \".blume-verify\"\n : process.env.BLUME_RUNTIME_DIR;\n refuseIfDevRunning(root, \"building\", { isolatedHint: true, runtimeDir });\n if (args.isolated) {\n await ensureGitignore(root, [\".blume-verify/\"]);\n }\n\n validateBudgetFlags(args);\n\n const project = await prepareProject({\n mode: \"build\",\n preview: args.preview,\n root,\n runtimeDir,\n strict: args.strict,\n });\n\n logger.start(\n `Building ${project.graph.pages.length} page(s) (${project.config.deployment.options.output} output)`\n );\n\n // Hand the scanned project to the integration: its `astro:build:done`\n // hook writes the deploy artifacts (search index, llms.txt, sitemap, …)\n // into Astro's client output during the build. An isolated build is a\n // throwaway verify that only needs to confirm the site compiles and\n // renders, so it publishes nothing — no network post-steps (a hosted\n // search sync would push), no deploy artifacts.\n if (!runtimeDir) {\n publishBuildProject(project);\n }\n\n try {\n await build({\n logLevel: \"info\",\n root: project.context.outDir,\n });\n } catch (error) {\n // Astro rejects when the site fails to compile or render (MDX that\n // doesn't parse, a component that throws): report that as a build error\n // at the file it names, not as an internal error blaming Blume. A\n // BlumeError keeps its own diagnostic.\n if (error instanceof BlumeError || !(error instanceof Error)) {\n throw error;\n }\n reportDiagnostics(astroBuildDiagnostics(error), root);\n process.exit(1);\n }\n\n // A real build also prunes the cache; an isolated verify must not evict\n // cards a live dev server is still serving.\n await reportCardCache(project, !runtimeDir);\n\n // Everything the deploy target does differently after `astro build` comes\n // off its platform (see `deploy/platforms/*`): a server build's post-build\n // step (Vercel's function-bundle audit and negotiation routes, Cloudflare's\n // wrapper Worker), and where its bundle and static assets landed.\n const { deployment } = project.config;\n const platform = deployPlatform(deployment);\n const server = deployment.options.output === \"server\";\n const finalize = async (isolated: boolean): Promise<void> => {\n if (\n server &&\n platform.finalizeBuild &&\n !(await platform.finalizeBuild({ isolated, log: logger, project }))\n ) {\n process.exit(1);\n }\n };\n\n // The bundle report and budget gate still run for an isolated build —\n // `blume build --isolated --budget-js 100` exiting 0 without measuring\n // anything would be a silent false pass in CI. An isolated build never\n // surfaces the adapter bundle to the project root, so its output dirs\n // resolve under the relocated runtime.\n if (runtimeDir) {\n await finalize(true);\n await runClientAssetChecks(\n deployStaticDir(project.config, project.context),\n args\n );\n logger.success(\n `Isolated build OK — output at ${deployOutputDir(project.config, project.context)} (not published).`\n );\n return;\n }\n\n // A server adapter's deploy bundle is a build artifact — keep it out of\n // version control (Vercel's own CLI ignores `.vercel/` for the same reason).\n // Ignoring it is independent of whether the bundle had to be moved below:\n // Vercel writes straight to the project root, Netlify does not.\n const { ignoreDir } = platform.hiddenRuntime;\n if (server && ignoreDir) {\n await ensureGitignore(root, [ignoreDir]);\n }\n\n // Netlify writes its deploy bundle relative to the Astro root — which Blume\n // points at the hidden `.blume` runtime — so the bundle lands where the\n // deploy platform never looks. Surface it up to the project root before\n // publishing artifacts into the served static dir.\n const surfaced = await surfaceAdapterOutput(\n project.config,\n project.context\n );\n if (surfaced.moved) {\n logger.success(`Surfaced ${deployment.kind} output to ${surfaced.to}`);\n }\n\n await finalize(false);\n\n await reportBuild(\n project,\n deployStaticDir(project.config, project.context),\n args\n );\n },\n});\n",
6
- "import { z } from \"zod\";\n\nimport type { Diagnostic } from \"../core/types.ts\";\n\n/**\n * The fields of an `astro build` rejection the report reads. Rolldown bundles\n * every plugin failure (an MDX compile error, say) into one error whose\n * `errors` holds each; a failure carries `loc` where the compiler pinned it,\n * or only `id`, the module that failed.\n */\nconst buildErrorSchema = z.looseObject({\n errors: z.array(z.instanceof(Error)).optional(),\n id: z.string().optional(),\n loc: z\n .looseObject({\n column: z.number().optional(),\n file: z.string().optional(),\n line: z.number().optional(),\n })\n .optional(),\n});\n\n/** One failure as a diagnostic at the file (and position) it names. */\nconst failureDiagnostic = (error: Error): Diagnostic => {\n const parsed = buildErrorSchema.safeParse(error);\n const { id, loc } = parsed.success ? parsed.data : {};\n // A named error (`MDXError`, `CompilerError`) says which step failed.\n const name = error.name === \"Error\" ? \"\" : `${error.name}: `;\n return {\n code: \"BLUME_BUILD_FAILED\",\n column: loc?.column,\n file: loc?.file ?? id,\n line: loc?.line,\n message: `${name}${error.message}`,\n severity: \"error\",\n };\n};\n\n/**\n * What `astro build` rejected with, as build diagnostics: one per failure\n * Rolldown collected, else the error itself. A page Blume's own checks pass\n * can still fail Astro's compile (MDX that doesn't parse) or render, and that\n * is a problem in the site, reported at its file, rather than an internal\n * error blaming Blume.\n */\nexport const astroBuildDiagnostics = (error: Error): Diagnostic[] => {\n const parsed = buildErrorSchema.safeParse(error);\n const failures = parsed.success ? (parsed.data.errors ?? []) : [];\n return (failures.length > 0 ? failures : [error]).map(failureDiagnostic);\n};\n"
5
+ "import { existsSync } from \"node:fs\";\nimport { readdir, stat } from \"node:fs/promises\";\n\nimport { build } from \"astro\";\nimport { defineCommand } from \"citty\";\nimport { join } from \"pathe\";\n\nimport { publishBuildProject } from \"../../astro/integration.ts\";\nimport { BlumeError } from \"../../core/diagnostics.ts\";\nimport { ensureGitignore } from \"../../core/gitignore.ts\";\nimport type { BlumeProject } from \"../../core/project-graph.ts\";\nimport { serverFeatures } from \"../../core/server-features.ts\";\nimport {\n deployOutputDir,\n deployStaticDir,\n surfaceAdapterOutput,\n} from \"../../deploy/adapter-output.ts\";\nimport { deployPlatform } from \"../../deploy/platforms/index.ts\";\nimport { cardCacheTally, ogCacheDir, pruneCardCache } from \"../../og/cache.ts\";\nimport {\n flagList,\n removedBuildFlags,\n removedBuildFlagsAdvice,\n} from \"../../upgrade/upgrade.ts\";\nimport { astroBuildDiagnostics } from \"../build-failure.ts\";\nimport { commandMeta } from \"../command-meta.ts\";\nimport { refuseIfDevRunning } from \"../dev-lock.ts\";\nimport { refuseIfEjected } from \"../eject-scripts.ts\";\nimport { logger, reportDiagnostics } from \"../log.ts\";\nimport { prepareProject } from \"../prepare.ts\";\n\nconst BUDGET_JS = \"budget-js\";\nconst BUDGET_CSS = \"budget-css\";\n\ninterface BudgetArgs {\n \"budget-css\"?: string;\n \"budget-js\"?: string;\n}\n\n/**\n * Reject a non-numeric performance budget. `Number(\"250kb\")` is `NaN` and\n * `total > NaN` is always false, so a typo'd flag would silently pass the gate;\n * fail up front instead.\n */\nconst validateBudgetFlags = (args: BudgetArgs): void => {\n for (const flag of [BUDGET_JS, BUDGET_CSS] as const) {\n const value = args[flag];\n const parsed = Number(value);\n // Equivalent to `!(parsed > 0)` but without the inverted check: this must\n // also reject `NaN` (a typo'd flag like \"250kb\"), which `parsed <= 0` alone\n // would let through since `NaN <= 0` is false.\n if (value !== undefined && (Number.isNaN(parsed) || parsed <= 0)) {\n logger.error(\n `Invalid --${flag} \"${value}\" (expected a positive number of kB).`\n );\n process.exit(1);\n }\n }\n};\n\n/**\n * Report how many OG cards the build read back from the on-disk cache against\n * how many it rendered (the endpoint tallies both), so a warm rebuild shows\n * where the time went. With `prune`, also drop the cached cards this build\n * never asked for — renamed pages, edited descriptions, cards from an earlier\n * Blume version — so a persisted cache holds exactly the current site's cards.\n */\nconst reportCardCache = async (\n project: BlumeProject,\n prune: boolean\n): Promise<void> => {\n const cards = cardCacheTally();\n if (!cards) {\n return;\n }\n logger.info(\n `OG cards: ${cards.hits} reused from the cache, ${cards.misses} rendered`\n );\n if (prune) {\n await pruneCardCache(ogCacheDir(project.context));\n }\n};\n\nconst formatBytes = (bytes: number): string => {\n if (bytes < 1024) {\n return `${bytes} B`;\n }\n const digits = bytes < 1024 * 100 ? 1 : 0;\n return `${(bytes / 1024).toFixed(digits)} kB`;\n};\n\n/** Sizes of `dist/_astro/*.<ext>`, largest first (empty when none exist). */\nconst astroAssets = async (\n distDir: string,\n ext: string\n): Promise<{ name: string; size: number }[]> => {\n const astroDir = join(distDir, \"_astro\");\n if (!existsSync(astroDir)) {\n return [];\n }\n const entries = await readdir(astroDir);\n const files = entries.filter((name) => name.endsWith(`.${ext}`));\n const sized = await Promise.all(\n files.map(async (name) => {\n const info = await stat(join(astroDir, name));\n return { name, size: info.size };\n })\n );\n return sized.toSorted((a, b) => b.size - a.size);\n};\n\nconst totalSize = (assets: { size: number }[]): number =>\n assets.reduce((sum, asset) => sum + asset.size, 0);\n\n/**\n * Print the client JavaScript Astro shipped, largest first, plus the total. A\n * dependency-free bundle report — the interactive weight of a docs site is its\n * `_astro/*.js`, so this surfaces regressions without a visualizer.\n */\nconst reportBundleSizes = async (distDir: string): Promise<void> => {\n const sized = await astroAssets(distDir, \"js\");\n if (sized.length === 0) {\n logger.info(\"No client JavaScript emitted — the site ships zero JS.\");\n return;\n }\n const rows = sized\n .slice(0, 15)\n .map((file) => ` ${formatBytes(file.size).padStart(8)} ${file.name}`);\n logger.box(\n [\n `Client JavaScript — ${sized.length} file(s), ${formatBytes(totalSize(sized))} total`,\n \"\",\n ...rows,\n sized.length > 15 ? ` … and ${sized.length - 15} more` : null,\n ]\n .filter((line) => line !== null)\n .join(\"\\n\")\n );\n};\n\n/**\n * Enforce a performance budget on the built client assets: fail the build when\n * total `_astro/*.js` (or `*.css`) exceeds the given kB cap. Budgets that would\n * otherwise be \"documented, not measured\" become a real CI gate. Returns whether\n * every budget passed.\n */\nconst enforceBudget = async (\n distDir: string,\n args: BudgetArgs\n): Promise<\"fail\" | \"pass\" | \"skip\"> => {\n const checks: { ext: string; limitKb: number; name: string }[] = [\n ...(args[BUDGET_JS]\n ? [{ ext: \"js\", limitKb: Number(args[BUDGET_JS]), name: \"JavaScript\" }]\n : []),\n ...(args[BUDGET_CSS]\n ? [{ ext: \"css\", limitKb: Number(args[BUDGET_CSS]), name: \"CSS\" }]\n : []),\n ];\n if (checks.length === 0) {\n return \"skip\";\n }\n let passed = true;\n for (const check of checks) {\n // oxlint-disable-next-line no-await-in-loop -- a couple of sequential reads\n const total = totalSize(await astroAssets(distDir, check.ext));\n const limit = check.limitKb * 1024;\n if (total > limit) {\n passed = false;\n logger.error(\n `${check.name} budget exceeded: ${formatBytes(total)} > ${check.limitKb} kB`\n );\n } else {\n logger.success(\n `${check.name} budget: ${formatBytes(total)} / ${check.limitKb} kB`\n );\n }\n }\n return passed ? \"pass\" : \"fail\";\n};\n\n/**\n * Run the optional bundle report (`--analyze`) and performance-budget gate\n * against the directory whose `_astro/` client assets the deploy serves.\n * Shared by real and isolated builds — an isolated CI run passing\n * `--budget-js` must still fail on an exceeded budget rather than silently\n * skipping the check. Exits non-zero when a budget is exceeded.\n */\nexport const runClientAssetChecks = async (\n staticDir: string,\n args: { analyze?: boolean } & BudgetArgs\n): Promise<void> => {\n if (args.analyze) {\n await reportBundleSizes(staticDir);\n }\n if ((await enforceBudget(staticDir, args)) === \"fail\") {\n process.exit(1);\n }\n};\n\n/**\n * Print the build summary box and run the optional bundle report / budget\n * gate against the served static dir. The deploy artifacts themselves\n * (search index, llms.txt, sitemap, robots, redirect and header files, …)\n * were written by the integration's `astro:build:done` hook during\n * `build()` — see `deploy/artifacts.ts`. Exits non-zero if a budget is\n * exceeded.\n */\nconst reportBuild = async (\n project: BlumeProject,\n distDir: string,\n args: { analyze?: boolean } & BudgetArgs\n): Promise<void> => {\n const { config } = project;\n const features = serverFeatures(config);\n // The sitemap needs both the flag and a `site` (absolute URLs) — only the\n // latter deserves the remediation hint.\n const sitemapNote = config.seo.sitemap\n ? \"no (set deployment.site)\"\n : \"no (seo.sitemap is false)\";\n const rows: [label: string, value: string | number][] = [\n [\"Output\", config.deployment.options.output],\n [\"Adapter\", config.deployment.kind],\n [\"Site\", config.deployment.options.site ?? \"not set\"],\n [\"Search\", config.search.provider.kind],\n [\"Redirects\", config.redirects.length],\n [\n \"Sitemap\",\n config.deployment.options.site && config.seo.sitemap\n ? \"yes\"\n : sitemapNote,\n ],\n [\"Robots\", config.seo.robots ? \"yes\" : \"no\"],\n [\"Agent JSON\", config.agents.agentReadability ? \"yes\" : \"no\"],\n [\"LLM files\", config.agents.llmsTxt.enabled ? \"yes\" : \"no\"],\n [\"Server features\", features.length > 0 ? features.join(\", \") : \"none\"],\n ];\n // One label column for every row, sized by the longest label.\n const labelWidth = Math.max(...rows.map(([label]) => label.length)) + 2;\n logger.box(\n rows\n .map(([label, value]) => `${label.padEnd(labelWidth)}${value}`)\n .join(\"\\n\")\n );\n\n await runClientAssetChecks(distDir, args);\n\n // Only reachable with --no-strict (strict aborts earlier): repeat the missing\n // count next to the success banner so it can't scroll away unseen.\n if (project.droppedPages > 0) {\n logger.warn(\n `${project.droppedPages} page(s) failed frontmatter validation and are missing from this build.`\n );\n }\n logger.success(`Built to ${distDir}`);\n};\n\nexport const buildCommand = defineCommand({\n args: {\n analyze: {\n description: \"Report client JavaScript bundle sizes after the build.\",\n type: \"boolean\",\n },\n [BUDGET_CSS]: {\n description: \"Fail if total client CSS exceeds this many kB.\",\n type: \"string\",\n },\n [BUDGET_JS]: {\n description: \"Fail if total client JavaScript exceeds this many kB.\",\n type: \"string\",\n },\n isolated: {\n description:\n \"Build into an isolated .blume-verify runtime (and its own dist) so a running dev server and the real dist/ are untouched. For verifying changes while `blume dev` runs.\",\n type: \"boolean\",\n },\n preview: {\n description: \"Include drafts and unpublished CMS content.\",\n type: \"boolean\",\n },\n strict: {\n default: true,\n description:\n \"Fail on error diagnostics (default; pass --no-strict to build anyway, dropping pages that fail validation).\",\n type: \"boolean\",\n },\n },\n meta: commandMeta.build,\n async run({ args, rawArgs }) {\n const root = process.cwd();\n\n // citty accepts unknown flags, so a Blume 1 `--adapter vercel --output\n // server` would otherwise build a static site without a word.\n const removed = removedBuildFlags(rawArgs);\n if (removed.length > 0) {\n logger.error(\n `blume build no longer takes ${flagList(removed)}. ${removedBuildFlagsAdvice(removed)}`\n );\n process.exit(1);\n }\n await refuseIfEjected(root, \"build\");\n\n // `--isolated` (or BLUME_RUNTIME_DIR) relocates the whole runtime to a\n // sibling dir so this build never touches a live dev server's `.blume/` or\n // the user's real `dist/`. A non-default runtime dir has no dev lock, so the\n // refusal below lets it proceed; a plain build still refuses.\n const runtimeDir = args.isolated\n ? \".blume-verify\"\n : process.env.BLUME_RUNTIME_DIR;\n refuseIfDevRunning(root, \"building\", { isolatedHint: true, runtimeDir });\n if (args.isolated) {\n await ensureGitignore(root, [\".blume-verify/\"]);\n }\n\n validateBudgetFlags(args);\n\n const project = await prepareProject({\n mode: \"build\",\n preview: args.preview,\n root,\n runtimeDir,\n strict: args.strict,\n });\n\n logger.start(\n `Building ${project.graph.pages.length} page(s) (${project.config.deployment.options.output} output)`\n );\n\n // Hand the scanned project to the integration: its `astro:build:done`\n // hook writes the deploy artifacts (search index, llms.txt, sitemap, …)\n // into Astro's client output during the build. An isolated build is a\n // throwaway verify that only needs to confirm the site compiles and\n // renders, so it publishes nothing — no network post-steps (a hosted\n // search sync would push), no deploy artifacts.\n if (!runtimeDir) {\n publishBuildProject(project);\n }\n\n try {\n await build({\n logLevel: \"info\",\n root: project.context.outDir,\n });\n } catch (error) {\n // Astro rejects when the site fails to compile or render (MDX that\n // doesn't parse, a component that throws): report that as a build error\n // at the file it names, not as an internal error blaming Blume. A\n // BlumeError keeps its own diagnostic.\n if (error instanceof BlumeError || !(error instanceof Error)) {\n throw error;\n }\n reportDiagnostics(astroBuildDiagnostics(error), root);\n process.exit(1);\n }\n\n // A real build also prunes the cache; an isolated verify must not evict\n // cards a live dev server is still serving.\n await reportCardCache(project, !runtimeDir);\n\n // Everything the deploy target does differently after `astro build` comes\n // off its platform (see `deploy/platforms/*`): a server build's post-build\n // step (Vercel's function-bundle audit and negotiation routes, Cloudflare's\n // wrapper Worker), and where its bundle and static assets landed.\n const { deployment } = project.config;\n const platform = deployPlatform(deployment);\n const server = deployment.options.output === \"server\";\n const finalize = async (isolated: boolean): Promise<void> => {\n if (\n server &&\n platform.finalizeBuild &&\n !(await platform.finalizeBuild({ isolated, log: logger, project }))\n ) {\n process.exit(1);\n }\n };\n\n // The bundle report and budget gate still run for an isolated build —\n // `blume build --isolated --budget-js 100` exiting 0 without measuring\n // anything would be a silent false pass in CI. An isolated build never\n // surfaces the adapter bundle to the project root, so its output dirs\n // resolve under the relocated runtime.\n if (runtimeDir) {\n await finalize(true);\n await runClientAssetChecks(\n deployStaticDir(project.config, project.context),\n args\n );\n logger.success(\n `Isolated build OK — output at ${deployOutputDir(project.config, project.context)} (not published).`\n );\n return;\n }\n\n // A server adapter's deploy bundle is a build artifact — keep it out of\n // version control (Vercel's own CLI ignores `.vercel/` for the same reason).\n // Ignoring it is independent of whether the bundle had to be moved below:\n // Vercel writes straight to the project root, Netlify does not.\n const { ignoreDir } = platform.hiddenRuntime;\n if (server && ignoreDir) {\n await ensureGitignore(root, [ignoreDir]);\n }\n\n // Netlify writes its deploy bundle relative to the Astro root — which Blume\n // points at the hidden `.blume` runtime — so the bundle lands where the\n // deploy platform never looks. Surface it up to the project root before\n // publishing artifacts into the served static dir.\n const surfaced = await surfaceAdapterOutput(\n project.config,\n project.context\n );\n if (surfaced.moved) {\n logger.success(`Surfaced ${deployment.kind} output to ${surfaced.to}`);\n }\n\n await finalize(false);\n\n await reportBuild(\n project,\n deployStaticDir(project.config, project.context),\n args\n );\n },\n});\n"
7
6
  ],
8
- "mappings": "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",
9
- "debugId": "D6CABD020883D7E964756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "5EAF9E033A01BFBE64756E2164756E21",
10
9
  "names": []
11
10
  }
@@ -98,7 +98,16 @@ var writeMcpConfig = async (dir, snapshotPath, launcher) => {
98
98
  var CLAUDE_READER_MAX_TURNS = "25";
99
99
  var CLAUDE_JUDGE_MAX_TURNS = "1";
100
100
  var claudeArgs = (context) => {
101
- const base = ["-p", "--output-format", "json", "--strict-mcp-config"];
101
+ const base = [
102
+ "-p",
103
+ "--output-format",
104
+ "json",
105
+ "--strict-mcp-config",
106
+ "--tools",
107
+ "",
108
+ "--setting-sources",
109
+ ""
110
+ ];
102
111
  if (context.mcp) {
103
112
  const allowed = MCP_TOOL_NAMES.map((tool) => `mcp__${MCP_SERVER_NAME}__${tool}`).join(",");
104
113
  return [
@@ -237,5 +246,5 @@ var parseVerdict = (text) => {
237
246
 
238
247
  export { seconds, money, duration, DISALLOWED_TOOLS, runAgentHeadless, writeMcpConfig, CODEX_LOCKDOWN, agentArgs, readAgentOutput, parseVerdict };
239
248
 
240
- //# debugId=DE4C096172619DD564756E2164756E21
241
- //# sourceMappingURL=chunk-ga0pf4aj.js.map
249
+ //# debugId=8D2BC67DC28F6A0064756E2164756E21
250
+ //# sourceMappingURL=chunk-0n9xkp3d.js.map