blume 2.0.3 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (455) hide show
  1. package/AGENTS.md +1 -0
  2. package/CHANGELOG.md +48 -0
  3. package/README.md +1 -1
  4. package/dist/cli/{chunk-1d7ve1dm.js → chunk-0gz36akr.js} +18 -2
  5. package/dist/cli/{chunk-1d7ve1dm.js.map → chunk-0gz36akr.js.map} +3 -3
  6. package/dist/cli/{chunk-2eytanqx.js → chunk-1n228xqb.js} +2 -2
  7. package/dist/cli/{chunk-yfyb25rh.js → chunk-2f3ndkpw.js} +24 -8
  8. package/dist/cli/chunk-2f3ndkpw.js.map +14 -0
  9. package/dist/cli/{chunk-r20tn01b.js → chunk-2f7n4qzt.js} +8 -2
  10. package/dist/cli/{chunk-r20tn01b.js.map → chunk-2f7n4qzt.js.map} +3 -3
  11. package/dist/cli/{chunk-35d4wj9f.js → chunk-2n4ps1b3.js} +7 -7
  12. package/dist/cli/{chunk-j85vccga.js → chunk-43zcf4gz.js} +97 -57
  13. package/dist/cli/{chunk-j85vccga.js.map → chunk-43zcf4gz.js.map} +6 -6
  14. package/dist/cli/{chunk-e04dxsz1.js → chunk-4ejxbzee.js} +1 -1
  15. package/dist/cli/{chunk-5m5nmvyq.js → chunk-4h8z9vv5.js} +233 -39
  16. package/dist/cli/chunk-4h8z9vv5.js.map +16 -0
  17. package/dist/cli/{chunk-5f86nr5m.js → chunk-5cg2rzgf.js} +18 -16
  18. package/dist/cli/{chunk-5f86nr5m.js.map → chunk-5cg2rzgf.js.map} +2 -2
  19. package/dist/cli/{chunk-tzmab476.js → chunk-5ffywsmb.js} +4 -4
  20. package/dist/cli/{chunk-2z928egk.js → chunk-5wj2qwn2.js} +5 -5
  21. package/dist/cli/chunk-6bm0xpgd.js +18 -0
  22. package/dist/cli/chunk-6bm0xpgd.js.map +10 -0
  23. package/dist/cli/{chunk-vg9r4eb9.js → chunk-713mngdq.js} +12 -5
  24. package/dist/cli/{chunk-vg9r4eb9.js.map → chunk-713mngdq.js.map} +3 -3
  25. package/dist/cli/{chunk-5xvm6tfj.js → chunk-9geymqns.js} +17 -15
  26. package/dist/cli/{chunk-5xvm6tfj.js.map → chunk-9geymqns.js.map} +2 -2
  27. package/dist/cli/{chunk-q58y5e6a.js → chunk-9xr4dgee.js} +26 -17
  28. package/dist/cli/chunk-9xr4dgee.js.map +10 -0
  29. package/dist/cli/{chunk-b07cmahc.js → chunk-amrb6hgh.js} +2 -2
  30. package/dist/cli/chunk-cm89scdv.js +443 -0
  31. package/dist/cli/chunk-cm89scdv.js.map +11 -0
  32. package/dist/cli/{chunk-akbpwfxc.js → chunk-cmtcnh9f.js} +2 -2
  33. package/dist/cli/chunk-cy5bm0j0.js +104 -0
  34. package/dist/cli/chunk-cy5bm0j0.js.map +11 -0
  35. package/dist/cli/{chunk-crgn1q09.js → chunk-e7vvk5ya.js} +4 -4
  36. package/dist/cli/{chunk-pehfxfta.js → chunk-g2z9x01v.js} +6 -98
  37. package/dist/cli/chunk-g2z9x01v.js.map +10 -0
  38. package/dist/cli/{chunk-tkacnehg.js → chunk-gp84za0h.js} +2 -2
  39. package/dist/cli/{chunk-wrr3j9w9.js → chunk-h2a48yhd.js} +186 -63
  40. package/dist/cli/chunk-h2a48yhd.js.map +36 -0
  41. package/dist/cli/{chunk-hm3vjy5s.js → chunk-jnwj5kjj.js} +14 -9
  42. package/dist/cli/{chunk-hm3vjy5s.js.map → chunk-jnwj5kjj.js.map} +4 -4
  43. package/dist/cli/chunk-kwrg63tm.js +31 -0
  44. package/dist/cli/chunk-kwrg63tm.js.map +10 -0
  45. package/dist/cli/{chunk-2hsdwb9n.js → chunk-nd1821sk.js} +18 -16
  46. package/dist/cli/{chunk-2hsdwb9n.js.map → chunk-nd1821sk.js.map} +2 -2
  47. package/dist/cli/{chunk-6dsbexzp.js → chunk-ntv4qrt7.js} +17 -15
  48. package/dist/cli/{chunk-6dsbexzp.js.map → chunk-ntv4qrt7.js.map} +2 -2
  49. package/dist/cli/{chunk-r9rcc4w7.js → chunk-p804f3pe.js} +7 -7
  50. package/dist/cli/{chunk-ey84smr6.js → chunk-py62fewh.js} +6 -6
  51. package/dist/cli/{chunk-ey84smr6.js.map → chunk-py62fewh.js.map} +1 -1
  52. package/dist/cli/chunk-q3wxxq39.js +126 -0
  53. package/dist/cli/chunk-q3wxxq39.js.map +11 -0
  54. package/dist/cli/{chunk-9t7a85s3.js → chunk-rekqz4qg.js} +23 -13
  55. package/dist/cli/chunk-rekqz4qg.js.map +10 -0
  56. package/dist/cli/{chunk-8ktnccpt.js → chunk-ta27feev.js} +1 -1
  57. package/dist/cli/{chunk-pv29h0wf.js → chunk-xkz5xbtv.js} +3476 -822
  58. package/dist/cli/chunk-xkz5xbtv.js.map +213 -0
  59. package/dist/cli/{chunk-a58773jm.js → chunk-y4ykbark.js} +2 -2
  60. package/dist/cli/{chunk-p3v96n38.js → chunk-y5h4r2y0.js} +4 -4
  61. package/dist/cli/{chunk-acanzt5p.js → chunk-yj17vs39.js} +6 -6
  62. package/dist/cli/{chunk-p73c0m7w.js → chunk-yxmk4pec.js} +16 -14
  63. package/dist/cli/{chunk-p73c0m7w.js.map → chunk-yxmk4pec.js.map} +2 -2
  64. package/dist/cli/{chunk-3em5wd2y.js → chunk-zccbjcj0.js} +4 -3
  65. package/dist/cli/{chunk-3em5wd2y.js.map → chunk-zccbjcj0.js.map} +2 -2
  66. package/dist/cli/{chunk-c8chx29p.js → chunk-zf748avv.js} +384 -207
  67. package/dist/cli/chunk-zf748avv.js.map +37 -0
  68. package/dist/cli/{chunk-g4hq16wv.js → chunk-zhvd6adm.js} +16 -14
  69. package/dist/cli/{chunk-g4hq16wv.js.map → chunk-zhvd6adm.js.map} +2 -2
  70. package/dist/cli/index.js +26 -20
  71. package/dist/cli/index.js.map +5 -5
  72. package/dist/types/ai/agent-surface.d.ts +8 -7
  73. package/dist/types/ai/ai-catalog.d.ts +7 -0
  74. package/dist/types/ai/ask-context.d.ts +22 -0
  75. package/dist/types/ai/ask.d.ts +271 -58
  76. package/dist/types/ai/index.d.ts +2 -2
  77. package/dist/types/ai/site-skill.d.ts +26 -0
  78. package/dist/types/ai/skills.d.ts +16 -0
  79. package/dist/types/astro/integration.d.ts +8 -0
  80. package/dist/types/captcha/hcaptcha.d.ts +27 -0
  81. package/dist/types/captcha/index.d.ts +28 -0
  82. package/dist/types/captcha/schema.d.ts +29 -0
  83. package/dist/types/captcha/turnstile.d.ts +28 -0
  84. package/dist/types/components/content/api-field.d.ts +59 -0
  85. package/dist/types/components/content/api-page.d.ts +95 -0
  86. package/dist/types/components/layout/nav-utils.d.ts +26 -0
  87. package/dist/types/components/openapi/helpers.d.ts +137 -0
  88. package/dist/types/components/openapi/security.d.ts +85 -0
  89. package/dist/types/consent/ethyca.d.ts +48 -0
  90. package/dist/types/consent/index.d.ts +37 -0
  91. package/dist/types/consent/native.d.ts +28 -0
  92. package/dist/types/consent/osano.d.ts +42 -0
  93. package/dist/types/consent/schema.d.ts +110 -0
  94. package/dist/types/core/config-input.d.ts +187 -20
  95. package/dist/types/core/data.d.ts +49 -4
  96. package/dist/types/core/footer.d.ts +8 -0
  97. package/dist/types/core/i18n-ui.d.ts +86 -0
  98. package/dist/types/core/includes.d.ts +8 -2
  99. package/dist/types/core/localizable.d.ts +7 -0
  100. package/dist/types/core/page-modes.d.ts +29 -0
  101. package/dist/types/core/redirect-patterns.d.ts +144 -0
  102. package/dist/types/core/related.d.ts +40 -0
  103. package/dist/types/core/schema.d.ts +551 -56
  104. package/dist/types/core/sources/read.d.ts +5 -0
  105. package/dist/types/core/types.d.ts +1 -1
  106. package/dist/types/core/variables.d.ts +42 -0
  107. package/dist/types/deploy/node-headers.d.ts +13 -2
  108. package/dist/types/deploy/platforms/cloudflare.d.ts +5 -0
  109. package/dist/types/deploy/platforms/netlify.d.ts +7 -0
  110. package/dist/types/deploy/platforms/vercel.d.ts +6 -0
  111. package/dist/types/deploy/redirects.d.ts +39 -11
  112. package/dist/types/deploy/vercel-negotiation.d.ts +9 -0
  113. package/dist/types/markdown/code-title.d.ts +17 -0
  114. package/dist/types/markdown/features.d.ts +3 -2
  115. package/dist/types/narration/build.d.ts +70 -0
  116. package/dist/types/narration/provider.d.ts +26 -0
  117. package/dist/types/narration/script.d.ts +154 -0
  118. package/dist/types/openapi/model.d.ts +12 -6
  119. package/dist/types/openapi/overlay.d.ts +54 -0
  120. package/dist/types/openapi/parse.d.ts +13 -0
  121. package/dist/types/openapi/references.d.ts +14 -4
  122. package/dist/types/ratelimit/cloudflare.d.ts +39 -0
  123. package/dist/types/ratelimit/index.d.ts +27 -0
  124. package/dist/types/ratelimit/memory.d.ts +36 -0
  125. package/dist/types/ratelimit/schema.d.ts +111 -0
  126. package/dist/types/ratelimit/upstash.d.ts +21 -0
  127. package/dist/types/ratelimit/wrangler.d.ts +23 -0
  128. package/dist/types/reference/asyncapi.d.ts +10 -10
  129. package/dist/types/reference/graphql.d.ts +13 -10
  130. package/dist/types/reference/openapi.d.ts +33 -12
  131. package/dist/types/reference/options.d.ts +45 -5
  132. package/dist/types/reference/scalar.d.ts +13 -0
  133. package/dist/types/reference/schema.d.ts +60 -36
  134. package/dist/types/search/documents.d.ts +12 -1
  135. package/dist/types/search/orama-index.d.ts +4 -0
  136. package/dist/types/seo/metatags.d.ts +20 -0
  137. package/docs/02-deployment.mdx +41 -5
  138. package/docs/03-upgrading.mdx +4 -4
  139. package/docs/04-migrating.mdx +1 -1
  140. package/docs/advanced/changelog.mdx +2 -2
  141. package/docs/advanced/skills.mdx +14 -0
  142. package/docs/cli/audit.mdx +21 -1
  143. package/docs/cli/index.mdx +1 -0
  144. package/docs/configuration/analytics.mdx +3 -1
  145. package/docs/configuration/assistant.mdx +188 -36
  146. package/docs/configuration/consent.mdx +100 -0
  147. package/docs/configuration/customization.mdx +4 -4
  148. package/docs/configuration/index.mdx +63 -5
  149. package/docs/configuration/meta.ts +3 -0
  150. package/docs/configuration/narration.mdx +119 -0
  151. package/docs/configuration/rate-limiting.mdx +69 -0
  152. package/docs/configuration/search.mdx +29 -1
  153. package/docs/configuration/theming.mdx +3 -1
  154. package/docs/content/components.mdx +106 -0
  155. package/docs/content/frontmatter.mdx +76 -0
  156. package/docs/content/i18n.mdx +38 -3
  157. package/docs/content/includes.mdx +16 -0
  158. package/docs/content/meta.mdx +1 -0
  159. package/docs/content/meta.ts +1 -0
  160. package/docs/content/navigation.mdx +28 -6
  161. package/docs/content/sources/contentful.mdx +32 -0
  162. package/docs/content/sources/custom.mdx +39 -0
  163. package/docs/content/sources/github-releases.mdx +31 -0
  164. package/docs/content/sources/index.mdx +91 -0
  165. package/docs/content/sources/meta.ts +16 -0
  166. package/docs/content/sources/notion.mdx +32 -0
  167. package/docs/content/sources/obsidian.mdx +37 -0
  168. package/docs/content/sources/payload.mdx +30 -0
  169. package/docs/content/sources/remote-mdx.mdx +40 -0
  170. package/docs/content/sources/sanity.mdx +29 -0
  171. package/docs/content/sources/strapi.mdx +31 -0
  172. package/docs/content/syntax.mdx +67 -2
  173. package/docs/content/variables.mdx +41 -0
  174. package/docs/discoverability/agent-discovery.mdx +29 -2
  175. package/docs/discoverability/index.mdx +1 -1
  176. package/docs/discoverability/llms-txt.mdx +1 -1
  177. package/docs/discoverability/metadata.mdx +17 -0
  178. package/docs/references/api-pages.mdx +74 -0
  179. package/docs/references/asyncapi.mdx +1 -1
  180. package/docs/references/graphql.mdx +2 -2
  181. package/docs/references/meta.ts +1 -1
  182. package/docs/references/openapi.mdx +102 -3
  183. package/docs/references/scalar.mdx +3 -1
  184. package/package.json +36 -1
  185. package/skills/blume/SKILL.md +3 -0
  186. package/skills/blume-migrate/SKILL.md +5 -5
  187. package/skills/blume-migrate/references/docusaurus.md +3 -3
  188. package/skills/blume-migrate/references/mintlify.md +37 -19
  189. package/skills/blume-migrate/references/nextra.md +2 -2
  190. package/skills/blume-migrate/references/starlight.md +2 -1
  191. package/skills/blume-migrate/scripts/mintlify-codemod.mjs +60 -14
  192. package/skills/blume-write-skill/SKILL.md +82 -0
  193. package/src/ai/agent-readability.ts +2 -1
  194. package/src/ai/agent-surface.ts +9 -7
  195. package/src/ai/ai-catalog.ts +6 -3
  196. package/src/ai/ask-context.ts +73 -20
  197. package/src/ai/ask-data.ts +6 -0
  198. package/src/ai/ask-tools.ts +142 -0
  199. package/src/ai/ask.ts +354 -76
  200. package/src/ai/component-markdown.ts +75 -0
  201. package/src/ai/cors.ts +2 -0
  202. package/src/ai/index.ts +12 -0
  203. package/src/ai/llms.ts +6 -2
  204. package/src/ai/markdown.ts +2 -1
  205. package/src/ai/mcp/data.ts +6 -0
  206. package/src/ai/openapi-components.ts +9 -3
  207. package/src/ai/site-skill.ts +274 -0
  208. package/src/ai/skills.ts +35 -2
  209. package/src/ai/write-skill.ts +97 -0
  210. package/src/astro/generate.ts +132 -18
  211. package/src/astro/index.ts +1 -0
  212. package/src/astro/integration.ts +35 -0
  213. package/src/astro/module-types.ts +6 -0
  214. package/src/astro/templates.ts +283 -30
  215. package/src/astro/variables.ts +31 -0
  216. package/src/audit/catalog.ts +19 -0
  217. package/src/audit/checks/contrast.ts +183 -0
  218. package/src/audit/checks/i18n.ts +2 -3
  219. package/src/audit/checks/indexability.ts +2 -3
  220. package/src/audit/checks/links.ts +5 -12
  221. package/src/audit/checks/sitemap.ts +2 -3
  222. package/src/audit/redirects.ts +46 -15
  223. package/src/audit/run.ts +2 -0
  224. package/src/audit/types.ts +2 -1
  225. package/src/blume-modules.d.ts +7 -0
  226. package/src/captcha/client.ts +152 -0
  227. package/src/captcha/hcaptcha.ts +36 -0
  228. package/src/captcha/index.ts +28 -0
  229. package/src/captcha/schema.ts +32 -0
  230. package/src/captcha/turnstile.ts +38 -0
  231. package/src/captcha/verify.ts +71 -0
  232. package/src/cli/command-meta.ts +5 -0
  233. package/src/cli/commands/doctor.ts +22 -16
  234. package/src/cli/commands/skill.ts +96 -0
  235. package/src/cli/index.ts +5 -0
  236. package/src/cli/required-secrets.ts +71 -29
  237. package/src/components/BlumePage.astro +2 -0
  238. package/src/components/content/ApiEndpoint.astro +18 -0
  239. package/src/components/content/ApiField.astro +79 -0
  240. package/src/components/content/ApiPlayground.astro +62 -0
  241. package/src/components/content/ApiRail.astro +19 -0
  242. package/src/components/content/Color.astro +1 -0
  243. package/src/components/content/FileTree.astro +1 -0
  244. package/src/components/content/GithubInfo.astro +1 -0
  245. package/src/components/content/Panel.astro +1 -0
  246. package/src/components/content/ParamField.astro +25 -0
  247. package/src/components/content/RequestExample.astro +17 -0
  248. package/src/components/content/ResponseExample.astro +17 -0
  249. package/src/components/content/ResponseField.astro +32 -0
  250. package/src/components/content/Step.astro +1 -0
  251. package/src/components/content/Tile.astro +1 -0
  252. package/src/components/content/Tooltip.astro +1 -0
  253. package/src/components/content/Tree.astro +1 -0
  254. package/src/components/content/TypeTable.astro +4 -1
  255. package/src/components/content/View.astro +21 -0
  256. package/src/components/content/ViewSwitcher.astro +168 -0
  257. package/src/components/content/api-field.ts +100 -0
  258. package/src/components/content/api-page.ts +224 -0
  259. package/src/components/content/view-switcher.ts +71 -0
  260. package/src/components/index.ts +2 -0
  261. package/src/components/islands/Assistant.astro +10 -1
  262. package/src/components/islands/assistant.tsx +104 -14
  263. package/src/components/islands/code-question.ts +62 -0
  264. package/src/components/islands/hooks.ts +110 -21
  265. package/src/components/islands/support-link.ts +68 -0
  266. package/src/components/layout/Analytics.astro +11 -2
  267. package/src/components/layout/Banner.astro +14 -10
  268. package/src/components/layout/Breadcrumbs.astro +6 -2
  269. package/src/components/layout/ConsentBanner.astro +62 -0
  270. package/src/components/layout/ConsentHead.astro +38 -0
  271. package/src/components/layout/Directory.astro +94 -0
  272. package/src/components/layout/DrawerSwitchers.astro +51 -0
  273. package/src/components/layout/Empty.astro +2 -2
  274. package/src/components/layout/Header.astro +122 -80
  275. package/src/components/layout/LanguageSwitcher.astro +48 -15
  276. package/src/components/layout/NarrationPlayer.astro +1085 -0
  277. package/src/components/layout/NavSelector.astro +33 -7
  278. package/src/components/layout/PageFeedback.astro +54 -49
  279. package/src/components/layout/PageLayout.astro +71 -3
  280. package/src/components/layout/ReferenceLayout.astro +17 -6
  281. package/src/components/layout/RelatedPages.astro +42 -0
  282. package/src/components/layout/RootLayout.astro +308 -45
  283. package/src/components/layout/Search.astro +31 -17
  284. package/src/components/layout/SiteFooter.astro +124 -0
  285. package/src/components/layout/SiteMetatags.astro +16 -0
  286. package/src/components/layout/consent/native.ts +79 -0
  287. package/src/components/layout/consent/types.ts +37 -0
  288. package/src/components/layout/footer-links.ts +53 -0
  289. package/src/components/layout/footer-socials.ts +87 -0
  290. package/src/components/layout/locale-redirect.ts +107 -0
  291. package/src/components/layout/nav-utils.ts +83 -0
  292. package/src/components/layout/page-feedback.ts +96 -0
  293. package/src/components/layout/search/analytics.ts +98 -0
  294. package/src/components/layout/search/flexsearch.ts +17 -5
  295. package/src/components/layout/search/orama-cloud.ts +26 -14
  296. package/src/components/layout/search/types.ts +20 -0
  297. package/src/components/layout/search/typesense.ts +5 -1
  298. package/src/components/openapi/Operation.astro +161 -13
  299. package/src/components/openapi/RequestBody.astro +6 -4
  300. package/src/components/openapi/RequestPanel.astro +59 -7
  301. package/src/components/openapi/Responses.astro +6 -4
  302. package/src/components/openapi/async-snippets.ts +4 -4
  303. package/src/components/openapi/code-samples.ts +97 -0
  304. package/src/components/openapi/security.ts +6 -3
  305. package/src/components/openapi/snippets.ts +869 -8
  306. package/src/components/props.ts +6 -0
  307. package/src/consent/client.ts +95 -0
  308. package/src/consent/clients.ts +19 -0
  309. package/src/consent/ethyca.ts +71 -0
  310. package/src/consent/head.ts +24 -0
  311. package/src/consent/index.ts +37 -0
  312. package/src/consent/init.ts +29 -0
  313. package/src/consent/native.ts +36 -0
  314. package/src/consent/osano.ts +59 -0
  315. package/src/consent/schema.ts +30 -0
  316. package/src/core/builtin-tags.ts +5 -0
  317. package/src/core/client-address.ts +19 -0
  318. package/src/core/config-input.ts +194 -20
  319. package/src/core/data.ts +44 -4
  320. package/src/core/diagnostics.ts +3 -2
  321. package/src/core/footer.ts +26 -0
  322. package/src/core/graph.ts +39 -36
  323. package/src/core/i18n-ui.ts +82 -2
  324. package/src/core/includes.ts +20 -3
  325. package/src/core/links.ts +16 -2
  326. package/src/core/localizable.ts +26 -0
  327. package/src/core/navigation.ts +43 -12
  328. package/src/core/page-modes.ts +56 -0
  329. package/src/core/project-graph.ts +111 -5
  330. package/src/core/redirect-patterns.ts +491 -0
  331. package/src/core/related.ts +131 -0
  332. package/src/core/schema.ts +318 -64
  333. package/src/core/sources/normalize.ts +2 -1
  334. package/src/core/sources/read.ts +8 -3
  335. package/src/core/types.ts +1 -1
  336. package/src/core/ui-packs/ar.ts +43 -0
  337. package/src/core/ui-packs/bg.ts +45 -0
  338. package/src/core/ui-packs/bn.ts +43 -0
  339. package/src/core/ui-packs/ca.ts +46 -0
  340. package/src/core/ui-packs/cs.ts +44 -0
  341. package/src/core/ui-packs/da.ts +45 -0
  342. package/src/core/ui-packs/de.ts +46 -0
  343. package/src/core/ui-packs/el.ts +45 -0
  344. package/src/core/ui-packs/es.ts +46 -0
  345. package/src/core/ui-packs/fa.ts +45 -0
  346. package/src/core/ui-packs/fi.ts +45 -0
  347. package/src/core/ui-packs/fr.ts +46 -0
  348. package/src/core/ui-packs/he.ts +43 -0
  349. package/src/core/ui-packs/hi.ts +44 -0
  350. package/src/core/ui-packs/hr.ts +45 -0
  351. package/src/core/ui-packs/hu.ts +44 -0
  352. package/src/core/ui-packs/id.ts +45 -0
  353. package/src/core/ui-packs/it.ts +45 -0
  354. package/src/core/ui-packs/ja.ts +45 -0
  355. package/src/core/ui-packs/ko.ts +44 -0
  356. package/src/core/ui-packs/nl.ts +46 -0
  357. package/src/core/ui-packs/no.ts +44 -0
  358. package/src/core/ui-packs/pl.ts +45 -0
  359. package/src/core/ui-packs/pt-br.ts +46 -0
  360. package/src/core/ui-packs/pt.ts +45 -0
  361. package/src/core/ui-packs/ro.ts +45 -0
  362. package/src/core/ui-packs/ru.ts +45 -0
  363. package/src/core/ui-packs/sk.ts +44 -0
  364. package/src/core/ui-packs/sr.ts +45 -0
  365. package/src/core/ui-packs/sv.ts +44 -0
  366. package/src/core/ui-packs/th.ts +43 -0
  367. package/src/core/ui-packs/tr.ts +45 -0
  368. package/src/core/ui-packs/uk.ts +45 -0
  369. package/src/core/ui-packs/vi.ts +45 -0
  370. package/src/core/ui-packs/zh-tw.ts +43 -0
  371. package/src/core/ui-packs/zh.ts +43 -0
  372. package/src/core/variables.ts +103 -0
  373. package/src/deploy/artifacts.ts +77 -8
  374. package/src/deploy/cloudflare-negotiation.ts +35 -5
  375. package/src/deploy/headers.ts +2 -1
  376. package/src/deploy/node-headers.ts +63 -9
  377. package/src/deploy/platforms/cloudflare.ts +32 -0
  378. package/src/deploy/platforms/netlify.ts +33 -1
  379. package/src/deploy/platforms/vercel.ts +37 -2
  380. package/src/deploy/redirects.ts +91 -24
  381. package/src/deploy/vercel-negotiation.ts +36 -0
  382. package/src/markdown/api-rail.ts +259 -0
  383. package/src/markdown/code-title.ts +35 -9
  384. package/src/markdown/features.ts +3 -2
  385. package/src/markdown/fence-meta.ts +2 -0
  386. package/src/markdown/include.ts +11 -1
  387. package/src/markdown/index.ts +28 -5
  388. package/src/markdown/math.ts +4 -4
  389. package/src/markdown/variables.ts +56 -0
  390. package/src/markdown/views.ts +82 -0
  391. package/src/narration/build.ts +412 -0
  392. package/src/narration/player.ts +249 -0
  393. package/src/narration/provider.ts +29 -0
  394. package/src/narration/script.ts +592 -0
  395. package/src/og/card.ts +7 -6
  396. package/src/openapi/model.ts +57 -24
  397. package/src/openapi/overlay.ts +256 -0
  398. package/src/openapi/parse.ts +55 -2
  399. package/src/openapi/references.ts +21 -5
  400. package/src/openapi/render-mdx.ts +5 -1
  401. package/src/openapi/scalar.ts +40 -6
  402. package/src/openapi/source.ts +1 -1
  403. package/src/ratelimit/cloudflare.ts +54 -0
  404. package/src/ratelimit/index.ts +30 -0
  405. package/src/ratelimit/memory.ts +45 -0
  406. package/src/ratelimit/runtime.ts +229 -0
  407. package/src/ratelimit/schema.ts +28 -0
  408. package/src/ratelimit/upstash.ts +30 -0
  409. package/src/ratelimit/wrangler.ts +70 -0
  410. package/src/reference/asyncapi.ts +2 -2
  411. package/src/reference/graphql.ts +5 -2
  412. package/src/reference/openapi.ts +21 -7
  413. package/src/reference/options.ts +51 -7
  414. package/src/reference/scalar.ts +33 -8
  415. package/src/registry/eject.ts +20 -4
  416. package/src/registry/registry.ts +7 -0
  417. package/src/search/documents.ts +26 -2
  418. package/src/search/orama-index.ts +28 -3
  419. package/src/search/pagefind-ranking.ts +39 -0
  420. package/src/search/sync/algolia.ts +15 -4
  421. package/src/search/sync/orama-cloud.ts +3 -0
  422. package/src/search/sync/typesense.ts +5 -0
  423. package/src/seo/metatags.ts +67 -0
  424. package/src/theme/chrome-icons.ts +1 -0
  425. package/src/theme/color.ts +500 -0
  426. package/src/theme/entry.ts +56 -3
  427. package/src/theme/palette.ts +121 -45
  428. package/src/translate/prompts.ts +1 -0
  429. package/src/translate/validate.ts +8 -2
  430. package/src/upgrade/upgrade.ts +4 -171
  431. package/dist/cli/chunk-364znk6q.js +0 -75
  432. package/dist/cli/chunk-364znk6q.js.map +0 -11
  433. package/dist/cli/chunk-5m5nmvyq.js.map +0 -13
  434. package/dist/cli/chunk-9t7a85s3.js.map +0 -10
  435. package/dist/cli/chunk-c8chx29p.js.map +0 -36
  436. package/dist/cli/chunk-pehfxfta.js.map +0 -10
  437. package/dist/cli/chunk-pv29h0wf.js.map +0 -190
  438. package/dist/cli/chunk-q58y5e6a.js.map +0 -10
  439. package/dist/cli/chunk-wrr3j9w9.js.map +0 -35
  440. package/dist/cli/chunk-yfyb25rh.js.map +0 -14
  441. package/docs/content/sources.mdx +0 -334
  442. /package/dist/cli/{chunk-2eytanqx.js.map → chunk-1n228xqb.js.map} +0 -0
  443. /package/dist/cli/{chunk-35d4wj9f.js.map → chunk-2n4ps1b3.js.map} +0 -0
  444. /package/dist/cli/{chunk-e04dxsz1.js.map → chunk-4ejxbzee.js.map} +0 -0
  445. /package/dist/cli/{chunk-tzmab476.js.map → chunk-5ffywsmb.js.map} +0 -0
  446. /package/dist/cli/{chunk-2z928egk.js.map → chunk-5wj2qwn2.js.map} +0 -0
  447. /package/dist/cli/{chunk-b07cmahc.js.map → chunk-amrb6hgh.js.map} +0 -0
  448. /package/dist/cli/{chunk-akbpwfxc.js.map → chunk-cmtcnh9f.js.map} +0 -0
  449. /package/dist/cli/{chunk-crgn1q09.js.map → chunk-e7vvk5ya.js.map} +0 -0
  450. /package/dist/cli/{chunk-tkacnehg.js.map → chunk-gp84za0h.js.map} +0 -0
  451. /package/dist/cli/{chunk-r9rcc4w7.js.map → chunk-p804f3pe.js.map} +0 -0
  452. /package/dist/cli/{chunk-8ktnccpt.js.map → chunk-ta27feev.js.map} +0 -0
  453. /package/dist/cli/{chunk-a58773jm.js.map → chunk-y4ykbark.js.map} +0 -0
  454. /package/dist/cli/{chunk-p3v96n38.js.map → chunk-y5h4r2y0.js.map} +0 -0
  455. /package/dist/cli/{chunk-acanzt5p.js.map → chunk-yj17vs39.js.map} +0 -0
@@ -8,6 +8,7 @@ import { buildRssFeeds } from "../deploy/rss.ts";
8
8
  import { AI_CATALOG_PATH, hasAiCatalog } from "./ai-catalog.ts";
9
9
  import { hasApiCatalog } from "./api-catalog.ts";
10
10
  import { API_PAGES_PATH, API_SEARCH_PATH, OPENAPI_PATH } from "./api/paths.ts";
11
+ import { servesSkillsIndex } from "./skills.ts";
11
12
 
12
13
  /** Token map for the machine-readable content-usage echo. */
13
14
  const USAGE_TOKENS: [keyof ContentSignalPolicy, string][] = [
@@ -145,7 +146,7 @@ const wellKnownArtifacts = (
145
146
  if (hasApiCatalog(config)) {
146
147
  artifacts.apiCatalog = abs("/.well-known/api-catalog");
147
148
  }
148
- if (config.agents.skills) {
149
+ if (servesSkillsIndex(config)) {
149
150
  artifacts.agentSkills = abs("/.well-known/agent-skills/index.json");
150
151
  }
151
152
  return artifacts;
@@ -11,7 +11,8 @@ export interface EmittedAgentSurface {
11
11
  mcp: boolean;
12
12
  /**
13
13
  * A skills discovery index is served: generated from `agents.skills` (at
14
- * least one valid skill), or shipped by the user in `public/`.
14
+ * least one valid skill) or the site skill (`agents.skillMd`), or shipped
15
+ * by the user in `public/`.
15
16
  */
16
17
  skills: boolean;
17
18
  }
@@ -33,12 +34,12 @@ export const servesMcp = (
33
34
  );
34
35
 
35
36
  /**
36
- * The config the discovery documents are built from: `agents.mcp` and
37
- * `agents.skills` switched off when the build didn't emit them, so llms.txt,
38
- * agent-readability.json, the catalogs, and the header rules only point at
39
- * what is there. A config flag says what was asked for; the MCP server is
40
- * skipped when a page owns its route, and skills publish nothing when their
41
- * directory is missing or holds no valid skill.
37
+ * The config the discovery documents are built from: `agents.mcp`,
38
+ * `agents.skills`, and `agents.skillMd` switched off when the build didn't
39
+ * emit them, so llms.txt, agent-readability.json, the catalogs, and the
40
+ * header rules only point at what is there. A config flag says what was asked
41
+ * for; the MCP server is skipped when a page owns its route, and skills
42
+ * publish nothing when their directory is missing or holds no valid skill.
42
43
  */
43
44
  export const advertisedConfig = (
44
45
  config: ResolvedConfig,
@@ -51,6 +52,7 @@ export const advertisedConfig = (
51
52
  ...config.agents.mcp,
52
53
  enabled: config.agents.mcp.enabled && emitted.mcp,
53
54
  },
55
+ skillMd: config.agents.skillMd && emitted.skills,
54
56
  skills: emitted.skills ? config.agents.skills : undefined,
55
57
  },
56
58
  });
@@ -10,7 +10,7 @@ import { resolveReferences } from "../openapi/references.ts";
10
10
  import { API_CATALOG_PATH, hasApiCatalog } from "./api-catalog.ts";
11
11
  import { OPENAPI_PATH } from "./api/paths.ts";
12
12
  import { asciiSlugify } from "./mcp/discovery.ts";
13
- import { AGENT_SKILLS_DIR } from "./skills.ts";
13
+ import { AGENT_SKILLS_DIR, servesSkillsIndex } from "./skills.ts";
14
14
  import type { SkillArtifact } from "./skills.ts";
15
15
 
16
16
  /**
@@ -86,7 +86,7 @@ export const hasAiCatalog = (config: ResolvedConfig): boolean =>
86
86
  (config.agents.mcp.enabled ||
87
87
  config.agents.api ||
88
88
  config.agents.llmsTxt.enabled ||
89
- Boolean(config.agents.skills) ||
89
+ servesSkillsIndex(config) ||
90
90
  resolveReferences(config).length > 0);
91
91
 
92
92
  /**
@@ -118,7 +118,10 @@ const NAMES_DOCS = /\b(?:docs|documentation)$/iu;
118
118
  * reads "the Acme documentation" and "Acme Docs" reads "the Acme Docs", not
119
119
  * "the Acme Docs docs".
120
120
  */
121
- const docsPhrase = (title: string, noun: "docs" | "documentation"): string =>
121
+ export const docsPhrase = (
122
+ title: string,
123
+ noun: "docs" | "documentation"
124
+ ): string =>
122
125
  NAMES_DOCS.test(title.trim()) ? `the ${title}` : `the ${title} ${noun}`;
123
126
 
124
127
  const entrySeeds = (
@@ -228,6 +228,17 @@ const queryTerms = (query: string): string[] =>
228
228
  const BASE_INSTRUCTION =
229
229
  "You are a helpful documentation assistant for this project. Answer the user's question using ONLY the documentation excerpts below. Each excerpt is headed by its page as `## Page Title (/route)`. If the answer is not covered by the excerpts, say you don't know and suggest where in the docs to look — do not invent details. Always cite the pages you drew from, and write every citation as a Markdown link to that page using its route, e.g. [Page Title](/route).";
230
230
 
231
+ /**
232
+ * Appended when the endpoint gives the model the docs tools (see
233
+ * `ask-tools.ts`): the excerpts are a head start, not the whole of the docs.
234
+ */
235
+ const TOOL_INSTRUCTION =
236
+ "You can also search the documentation yourself. When the excerpts don't fully answer the question, call search_docs with a focused query to find other pages, and read_page to read a page in full (one an excerpt cuts off, say) before you answer. Treat tool results exactly like the excerpts: answer only from them, and cite the pages you drew from the same way.";
237
+
238
+ /** Said instead of the excerpts when retrieval found none but tools can look. */
239
+ const NO_EXCERPTS_WITH_TOOLS =
240
+ "No documentation excerpts matched this question up front. Use search_docs to look before you answer.";
241
+
231
242
  /** The non-empty user turns, oldest first. Assistant turns never seed retrieval. */
232
243
  const userTurns = (messages: AskMessage[]): string[] =>
233
244
  messages
@@ -591,6 +602,48 @@ export const sectionExcerpt = (
591
602
  max: number
592
603
  ): string => excerptPage(parsePage(content), query, max);
593
604
 
605
+ // One Orama index per snapshot, shared by the grounding function and the
606
+ // docs tools so a cold endpoint builds it once.
607
+ const indexes = new WeakMap<AskData, ReturnType<typeof buildOramaIndex>>();
608
+
609
+ /** The search index over an assistant snapshot, built on first use. */
610
+ export const askIndex = (data: AskData): ReturnType<typeof buildOramaIndex> => {
611
+ let index = indexes.get(data);
612
+ if (!index) {
613
+ index = buildOramaIndex(data.documents, data.defaultLocale);
614
+ indexes.set(data, index);
615
+ }
616
+ return index;
617
+ };
618
+
619
+ /** The page the reader is on, and the search filters it implies. */
620
+ export interface ReaderScope {
621
+ current: OramaDoc | undefined;
622
+ filters: { locale: string | undefined; version: string | undefined };
623
+ }
624
+
625
+ /**
626
+ * Where the reader is: their page, when it's in the snapshot, and the locale
627
+ * and docs version retrieval keeps to. Without a page, a versioned site
628
+ * grounds in the current docs rather than every archived copy of each page.
629
+ */
630
+ export const readerScope = (
631
+ data: AskData,
632
+ byRoute: ReadonlyMap<string, OramaDoc>,
633
+ page?: AskPage
634
+ ): ReaderScope => {
635
+ const current = page?.path
636
+ ? byRoute.get(normalizeRoute(page.path))
637
+ : undefined;
638
+ return {
639
+ current,
640
+ filters: {
641
+ locale: current?.locale || undefined,
642
+ version: data.versioned ? (current?.version ?? "") : undefined,
643
+ },
644
+ };
645
+ };
646
+
594
647
  /**
595
648
  * Build the request-time grounding function for the assistant endpoint.
596
649
  *
@@ -607,20 +660,22 @@ export const sectionExcerpt = (
607
660
  *
608
661
  * `options.retrieval` (the `ai.assistant.retrieval` config) sizes how much
609
662
  * documentation each question carries; omitted fields keep today's defaults.
663
+ *
664
+ * `options.tools` says the endpoint also hands the model the docs tools: the
665
+ * prompt then says so, and a question retrieval found nothing for still gets
666
+ * a grounded prompt, since the model can go and search.
610
667
  */
611
668
  export const createAskContext = (
612
669
  data: AskData,
613
- options?: { instructions?: string; retrieval?: AskRetrievalOptions }
670
+ options?: {
671
+ instructions?: string;
672
+ retrieval?: AskRetrievalOptions;
673
+ tools?: boolean;
674
+ }
614
675
  ): ((
615
676
  messages: AskMessage[],
616
677
  page?: AskPage
617
678
  ) => Promise<string | undefined>) => {
618
- let dbPromise: Promise<Awaited<ReturnType<typeof buildOramaIndex>>> | null =
619
- null;
620
- const index = () => {
621
- dbPromise ??= buildOramaIndex(data.documents, data.defaultLocale);
622
- return dbPromise;
623
- };
624
679
  const byRoute = new Map(data.documents.map((doc) => [doc.route, doc]));
625
680
  // Section splitting and tokenizing are per page, not per question, so each
626
681
  // page is parsed on first use and reused for the life of the endpoint.
@@ -633,9 +688,12 @@ export const createAskContext = (
633
688
  }
634
689
  return page;
635
690
  };
636
- const instruction = options?.instructions
637
- ? `${BASE_INSTRUCTION}\n\n${options.instructions}`
691
+ const base = options?.tools
692
+ ? `${BASE_INSTRUCTION} ${TOOL_INSTRUCTION}`
638
693
  : BASE_INSTRUCTION;
694
+ const instruction = options?.instructions
695
+ ? `${base}\n\n${options.instructions}`
696
+ : base;
639
697
  const maxResults = options?.retrieval?.maxResults ?? MAX_RESULTS;
640
698
  const excerptChars = options?.retrieval?.excerptChars ?? EXCERPT_CHARS;
641
699
  const contextBudget = options?.retrieval?.contextBudget ?? CONTEXT_BUDGET;
@@ -652,16 +710,9 @@ export const createAskContext = (
652
710
  const [query = ""] = queries;
653
711
 
654
712
  // The current page anchors retrieval to its locale and docs version, and
655
- // is injected first. Without one, a versioned site grounds in the
656
- // current docs rather than every archived copy of each page.
657
- const current = page?.path
658
- ? byRoute.get(normalizeRoute(page.path))
659
- : undefined;
660
- const db = await index();
661
- const filters = {
662
- locale: current?.locale || undefined,
663
- version: data.versioned ? (current?.version ?? "") : undefined,
664
- };
713
+ // is injected first.
714
+ const { current, filters } = readerScope(data, byRoute, page);
715
+ const db = await askIndex(data);
665
716
  const hits = interleave(
666
717
  await Promise.all(
667
718
  queries.map((text) => queryOramaIndex(db, text, maxResults, filters))
@@ -700,7 +751,9 @@ export const createAskContext = (
700
751
  }
701
752
 
702
753
  if (sections.length === 0) {
703
- return;
754
+ return options?.tools
755
+ ? `${instruction}\n\n${NO_EXCERPTS_WITH_TOOLS}`
756
+ : undefined;
704
757
  }
705
758
  return `${instruction}\n\n<docs>\n${sections.join("\n\n")}\n</docs>`;
706
759
  };
@@ -36,6 +36,12 @@ export const buildAskData = async (project: BlumeProject): Promise<AskData> => {
36
36
  if (versioned) {
37
37
  document.version = doc.version;
38
38
  }
39
+ if (doc.boost !== undefined) {
40
+ document.boost = doc.boost;
41
+ }
42
+ if (doc.keywords) {
43
+ document.keywords = doc.keywords;
44
+ }
39
45
  return document;
40
46
  }),
41
47
  site: project.config.deployment.options.site ?? null,
@@ -0,0 +1,142 @@
1
+ import { jsonSchema, tool } from "ai";
2
+
3
+ import { normalizeRoute } from "../core/base-path.ts";
4
+ import { queryOramaIndex } from "../search/orama-index.ts";
5
+ import type { OramaDoc } from "../search/orama-index.ts";
6
+ import { askIndex, readerScope, sectionExcerpt } from "./ask-context.ts";
7
+ import type { AskData, AskPage, ReaderScope } from "./ask-context.ts";
8
+
9
+ /**
10
+ * The assistant's docs tools: what lets it look beyond the excerpts the
11
+ * endpoint injects up front. `search_docs` runs the same Orama search the
12
+ * grounding does, scoped to the reader's language and docs version;
13
+ * `read_page` returns a whole page, for when an excerpt stops short of the
14
+ * answer. Both read the assistant snapshot the endpoint already imports, so
15
+ * they add no build output and no network call.
16
+ *
17
+ * The generated `/api/ask` route passes them to `streamText` with a step cap
18
+ * ({@link ASK_MAX_STEPS}), so the model can search, read, and then answer
19
+ * within one request.
20
+ */
21
+
22
+ /**
23
+ * The most model steps one answer may take: up to four rounds of tool calls,
24
+ * then the answer. Enough to search, read a page or two, and search again,
25
+ * while bounding what one question can spend.
26
+ */
27
+ export const ASK_MAX_STEPS = 5;
28
+
29
+ /** Pages one search returns. */
30
+ const SEARCH_RESULTS = 5;
31
+
32
+ /** Characters of each search result's most relevant excerpt. */
33
+ const SEARCH_EXCERPT_CHARS = 700;
34
+
35
+ /** Characters of a page `read_page` returns; a longer page is cut here. */
36
+ const PAGE_CHARS = 20_000;
37
+
38
+ /** A result block, headed the way the injected excerpts are, for citing. */
39
+ const block = (doc: OramaDoc, body: string): string =>
40
+ `## ${doc.title} (${doc.route})\n${body}`;
41
+
42
+ /**
43
+ * Search the docs for `query` within the reader's scope: the most relevant
44
+ * excerpt of each of the top pages, or a note that nothing matched.
45
+ */
46
+ export const searchDocs = async (
47
+ data: AskData,
48
+ scope: ReaderScope,
49
+ query: string
50
+ ): Promise<string> => {
51
+ const hits = await queryOramaIndex(
52
+ await askIndex(data),
53
+ query,
54
+ SEARCH_RESULTS,
55
+ scope.filters
56
+ );
57
+ if (hits.length === 0) {
58
+ return `No pages matched "${query}". Try other words, or a broader query.`;
59
+ }
60
+ return hits
61
+ .map((doc) =>
62
+ block(doc, sectionExcerpt(doc.content, query, SEARCH_EXCERPT_CHARS))
63
+ )
64
+ .join("\n\n");
65
+ };
66
+
67
+ /**
68
+ * The route a model asked for, as the snapshot keys it: a full URL on the
69
+ * site becomes its path, and a query string or fragment is dropped.
70
+ */
71
+ const routeOf = (data: AskData, requested: string): string => {
72
+ let path = requested.trim();
73
+ if (data.site && path.startsWith(data.site)) {
74
+ path = path.slice(data.site.replace(/\/$/u, "").length) || "/";
75
+ }
76
+ path = path.replace(/[?#].*$/u, "");
77
+ return normalizeRoute(path.startsWith("/") ? path : `/${path}`);
78
+ };
79
+
80
+ /** A whole page by route, cut at {@link PAGE_CHARS}, or a note that it doesn't exist. */
81
+ export const readPage = (
82
+ data: AskData,
83
+ byRoute: ReadonlyMap<string, OramaDoc>,
84
+ requested: string
85
+ ): string => {
86
+ const route = routeOf(data, requested);
87
+ const doc = byRoute.get(route);
88
+ if (!doc) {
89
+ return `There is no page at ${route}. Use search_docs to find the right one.`;
90
+ }
91
+ const text =
92
+ doc.content.length > PAGE_CHARS
93
+ ? `${doc.content.slice(0, PAGE_CHARS)}\n\n[The page continues; this is its first ${PAGE_CHARS.toLocaleString("en-US")} characters.]`
94
+ : doc.content;
95
+ return block(doc, text);
96
+ };
97
+
98
+ /**
99
+ * The tools for one request, given the page the reader is on. Built per
100
+ * request because the search scope follows the reader's locale and version.
101
+ */
102
+ export const createAskTools = (data: AskData) => {
103
+ const byRoute = new Map(data.documents.map((doc) => [doc.route, doc]));
104
+ return (page?: AskPage) => {
105
+ const scope = readerScope(data, byRoute, page);
106
+ return {
107
+ read_page: tool({
108
+ description:
109
+ "Read one documentation page in full, by its route (the path in parentheses after a page title, such as /docs/getting-started).",
110
+ execute: ({ route }) => Promise.resolve(readPage(data, byRoute, route)),
111
+ inputSchema: jsonSchema<{ route: string }>({
112
+ additionalProperties: false,
113
+ properties: {
114
+ route: {
115
+ description: "The page's route, such as /docs/getting-started.",
116
+ type: "string",
117
+ },
118
+ },
119
+ required: ["route"],
120
+ type: "object",
121
+ }),
122
+ }),
123
+ search_docs: tool({
124
+ description:
125
+ "Search this project's documentation. Returns the most relevant excerpt of each matching page, headed by its title and route.",
126
+ execute: ({ query }) => searchDocs(data, scope, query),
127
+ inputSchema: jsonSchema<{ query: string }>({
128
+ additionalProperties: false,
129
+ properties: {
130
+ query: {
131
+ description:
132
+ "A few focused keywords, such as the feature or option the question is about.",
133
+ type: "string",
134
+ },
135
+ },
136
+ required: ["query"],
137
+ type: "object",
138
+ }),
139
+ }),
140
+ };
141
+ };
142
+ };