blume 2.0.2 → 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 (601) hide show
  1. package/AGENTS.md +1 -0
  2. package/CHANGELOG.md +113 -0
  3. package/README.md +1 -1
  4. package/dist/cli/{chunk-6k4ftwze.js → chunk-0gz36akr.js} +18 -2
  5. package/dist/cli/{chunk-6k4ftwze.js.map → chunk-0gz36akr.js.map} +3 -3
  6. package/dist/cli/{chunk-zp79m0ts.js → chunk-1n228xqb.js} +2 -2
  7. package/dist/cli/{chunk-ddndchfr.js → chunk-2f3ndkpw.js} +57 -29
  8. package/dist/cli/chunk-2f3ndkpw.js.map +14 -0
  9. package/dist/cli/{chunk-fsmrqk8a.js → chunk-2f7n4qzt.js} +8 -2
  10. package/dist/cli/{chunk-fsmrqk8a.js.map → chunk-2f7n4qzt.js.map} +3 -3
  11. package/dist/cli/{chunk-ppzjqwx2.js → chunk-2n4ps1b3.js} +17 -18
  12. package/dist/cli/{chunk-ppzjqwx2.js.map → chunk-2n4ps1b3.js.map} +3 -3
  13. package/dist/cli/{chunk-5r8g91qn.js → chunk-43zcf4gz.js} +398 -159
  14. package/dist/cli/chunk-43zcf4gz.js.map +36 -0
  15. package/dist/cli/chunk-4ejxbzee.js +39 -0
  16. package/dist/cli/chunk-4ejxbzee.js.map +10 -0
  17. package/dist/cli/{chunk-hr8ne106.js → chunk-4h8z9vv5.js} +296 -77
  18. package/dist/cli/chunk-4h8z9vv5.js.map +16 -0
  19. package/dist/cli/{chunk-k7pj68a8.js → chunk-5cg2rzgf.js} +18 -16
  20. package/dist/cli/{chunk-k7pj68a8.js.map → chunk-5cg2rzgf.js.map} +2 -2
  21. package/dist/cli/{chunk-h2ez8dzb.js → chunk-5ffywsmb.js} +4 -4
  22. package/dist/cli/{chunk-g698a744.js → chunk-5wj2qwn2.js} +5 -5
  23. package/dist/cli/chunk-6bm0xpgd.js +18 -0
  24. package/dist/cli/chunk-6bm0xpgd.js.map +10 -0
  25. package/dist/cli/{chunk-3yce002v.js → chunk-713mngdq.js} +15 -8
  26. package/dist/cli/chunk-713mngdq.js.map +14 -0
  27. package/dist/cli/{chunk-91ws1n6j.js → chunk-9geymqns.js} +17 -15
  28. package/dist/cli/{chunk-91ws1n6j.js.map → chunk-9geymqns.js.map} +2 -2
  29. package/dist/cli/{chunk-6dtt0zfn.js → chunk-9xr4dgee.js} +27 -18
  30. package/dist/cli/chunk-9xr4dgee.js.map +10 -0
  31. package/dist/cli/{chunk-sqw4ekg1.js → chunk-amrb6hgh.js} +2 -2
  32. package/dist/cli/chunk-cm89scdv.js +443 -0
  33. package/dist/cli/chunk-cm89scdv.js.map +11 -0
  34. package/dist/cli/{chunk-wdrt2k2v.js → chunk-cmtcnh9f.js} +90 -26
  35. package/dist/cli/chunk-cmtcnh9f.js.map +10 -0
  36. package/dist/cli/chunk-cy5bm0j0.js +104 -0
  37. package/dist/cli/chunk-cy5bm0j0.js.map +11 -0
  38. package/dist/cli/{chunk-7mbqtmgb.js → chunk-e7vvk5ya.js} +21 -12
  39. package/dist/cli/chunk-e7vvk5ya.js.map +10 -0
  40. package/dist/cli/{chunk-qkb5a8sa.js → chunk-g2z9x01v.js} +6 -98
  41. package/dist/cli/chunk-g2z9x01v.js.map +10 -0
  42. package/dist/cli/{chunk-273ygyr4.js → chunk-ga0pf4aj.js} +7 -7
  43. package/dist/cli/{chunk-273ygyr4.js.map → chunk-ga0pf4aj.js.map} +3 -3
  44. package/dist/cli/{chunk-h7k3nq3v.js → chunk-gp84za0h.js} +2 -2
  45. package/dist/cli/{chunk-hqp2ajnh.js → chunk-h2a48yhd.js} +195 -73
  46. package/dist/cli/chunk-h2a48yhd.js.map +36 -0
  47. package/dist/cli/{chunk-pbg5a4s3.js → chunk-jnwj5kjj.js} +71 -47
  48. package/dist/cli/chunk-jnwj5kjj.js.map +19 -0
  49. package/dist/cli/chunk-kwrg63tm.js +31 -0
  50. package/dist/cli/chunk-kwrg63tm.js.map +10 -0
  51. package/dist/cli/{chunk-8g8ytmgx.js → chunk-nd1821sk.js} +21 -19
  52. package/dist/cli/{chunk-8g8ytmgx.js.map → chunk-nd1821sk.js.map} +2 -2
  53. package/dist/cli/{chunk-w4bxdvsa.js → chunk-ntv4qrt7.js} +17 -15
  54. package/dist/cli/{chunk-w4bxdvsa.js.map → chunk-ntv4qrt7.js.map} +2 -2
  55. package/dist/cli/{chunk-bfwp9vp6.js → chunk-p804f3pe.js} +7 -7
  56. package/dist/cli/{chunk-4e9b9ra6.js → chunk-py62fewh.js} +6 -6
  57. package/dist/cli/{chunk-4e9b9ra6.js.map → chunk-py62fewh.js.map} +1 -1
  58. package/dist/cli/chunk-q3wxxq39.js +126 -0
  59. package/dist/cli/chunk-q3wxxq39.js.map +11 -0
  60. package/dist/cli/{chunk-j85scx15.js → chunk-rekqz4qg.js} +142 -46
  61. package/dist/cli/chunk-rekqz4qg.js.map +10 -0
  62. package/dist/cli/{chunk-00gs3wqs.js → chunk-ta27feev.js} +1 -1
  63. package/dist/cli/{chunk-v6ya5kcb.js → chunk-xkz5xbtv.js} +4031 -1132
  64. package/dist/cli/chunk-xkz5xbtv.js.map +213 -0
  65. package/dist/cli/{chunk-bbnwccaz.js → chunk-y4ykbark.js} +2 -2
  66. package/dist/cli/{chunk-n1yg3tj3.js → chunk-y5h4r2y0.js} +6 -6
  67. package/dist/cli/{chunk-n1yg3tj3.js.map → chunk-y5h4r2y0.js.map} +3 -3
  68. package/dist/cli/{chunk-nfcyttvj.js → chunk-yj17vs39.js} +9 -9
  69. package/dist/cli/{chunk-nfcyttvj.js.map → chunk-yj17vs39.js.map} +1 -1
  70. package/dist/cli/{chunk-7vtckvaw.js → chunk-yxmk4pec.js} +16 -14
  71. package/dist/cli/{chunk-7vtckvaw.js.map → chunk-yxmk4pec.js.map} +2 -2
  72. package/dist/cli/{chunk-gs7r695n.js → chunk-zccbjcj0.js} +22 -8
  73. package/dist/cli/{chunk-gs7r695n.js.map → chunk-zccbjcj0.js.map} +3 -3
  74. package/dist/cli/{chunk-xh43dwgw.js → chunk-zf748avv.js} +415 -225
  75. package/dist/cli/chunk-zf748avv.js.map +37 -0
  76. package/dist/cli/{chunk-d1v5rhy0.js → chunk-zhvd6adm.js} +16 -14
  77. package/dist/cli/{chunk-d1v5rhy0.js.map → chunk-zhvd6adm.js.map} +2 -2
  78. package/dist/cli/index.js +28 -20
  79. package/dist/cli/index.js.map +5 -5
  80. package/dist/types/ai/agent-surface.d.ts +8 -7
  81. package/dist/types/ai/ai-catalog.d.ts +7 -0
  82. package/dist/types/ai/ask-context.d.ts +22 -0
  83. package/dist/types/ai/ask.d.ts +271 -58
  84. package/dist/types/ai/index.d.ts +2 -2
  85. package/dist/types/ai/link-headers.d.ts +8 -1
  86. package/dist/types/ai/openapi-components.d.ts +5 -2
  87. package/dist/types/ai/relative-links.d.ts +9 -7
  88. package/dist/types/ai/site-skill.d.ts +26 -0
  89. package/dist/types/ai/skills.d.ts +20 -1
  90. package/dist/types/ai/tar.d.ts +1 -3
  91. package/dist/types/analytics/index.d.ts +2 -0
  92. package/dist/types/analytics/one-dollar-stats.d.ts +48 -0
  93. package/dist/types/analytics/schema.d.ts +14 -0
  94. package/dist/types/astro/integration.d.ts +11 -2
  95. package/dist/types/captcha/hcaptcha.d.ts +27 -0
  96. package/dist/types/captcha/index.d.ts +28 -0
  97. package/dist/types/captcha/schema.d.ts +29 -0
  98. package/dist/types/captcha/turnstile.d.ts +28 -0
  99. package/dist/types/components/content/api-field.d.ts +59 -0
  100. package/dist/types/components/content/api-page.d.ts +95 -0
  101. package/dist/types/components/layout/nav-utils.d.ts +26 -0
  102. package/dist/types/components/openapi/helpers.d.ts +137 -0
  103. package/dist/types/components/openapi/security.d.ts +85 -0
  104. package/dist/types/consent/ethyca.d.ts +48 -0
  105. package/dist/types/consent/index.d.ts +37 -0
  106. package/dist/types/consent/native.d.ts +28 -0
  107. package/dist/types/consent/osano.d.ts +42 -0
  108. package/dist/types/consent/schema.d.ts +110 -0
  109. package/dist/types/core/base-path.d.ts +21 -7
  110. package/dist/types/core/config-input.d.ts +196 -27
  111. package/dist/types/core/data.d.ts +49 -4
  112. package/dist/types/core/directive-diagnostics.d.ts +12 -0
  113. package/dist/types/core/footer.d.ts +8 -0
  114. package/dist/types/core/heading-markers.d.ts +5 -7
  115. package/dist/types/core/i18n-ui.d.ts +86 -0
  116. package/dist/types/core/i18n.d.ts +2 -0
  117. package/dist/types/core/includes.d.ts +8 -2
  118. package/dist/types/core/last-modified.d.ts +10 -0
  119. package/dist/types/core/localizable.d.ts +7 -0
  120. package/dist/types/core/meta.d.ts +8 -0
  121. package/dist/types/core/page-modes.d.ts +29 -0
  122. package/dist/types/core/redirect-patterns.d.ts +144 -0
  123. package/dist/types/core/related.d.ts +40 -0
  124. package/dist/types/core/schema.d.ts +558 -56
  125. package/dist/types/core/sources/lower.d.ts +29 -16
  126. package/dist/types/core/sources/normalize.d.ts +13 -1
  127. package/dist/types/core/sources/read.d.ts +5 -0
  128. package/dist/types/core/sources/watch.d.ts +12 -5
  129. package/dist/types/core/standard-schema.d.ts +5 -0
  130. package/dist/types/core/types.d.ts +1 -1
  131. package/dist/types/core/variables.d.ts +42 -0
  132. package/dist/types/deploy/artifacts.d.ts +6 -4
  133. package/dist/types/deploy/headers.d.ts +5 -0
  134. package/dist/types/deploy/node-headers.d.ts +13 -2
  135. package/dist/types/deploy/platforms/cloudflare.d.ts +5 -0
  136. package/dist/types/deploy/platforms/netlify.d.ts +7 -0
  137. package/dist/types/deploy/platforms/types.d.ts +8 -0
  138. package/dist/types/deploy/platforms/vercel.d.ts +6 -0
  139. package/dist/types/deploy/redirects.d.ts +61 -22
  140. package/dist/types/deploy/vercel-negotiation.d.ts +9 -0
  141. package/dist/types/markdown/code-title.d.ts +17 -0
  142. package/dist/types/markdown/directives.d.ts +62 -0
  143. package/dist/types/markdown/features.d.ts +24 -2
  144. package/dist/types/markdown/mdast.d.ts +63 -0
  145. package/dist/types/narration/build.d.ts +70 -0
  146. package/dist/types/narration/provider.d.ts +26 -0
  147. package/dist/types/narration/script.d.ts +154 -0
  148. package/dist/types/openapi/asyncapi.d.ts +4 -2
  149. package/dist/types/openapi/model.d.ts +12 -6
  150. package/dist/types/openapi/overlay.d.ts +54 -0
  151. package/dist/types/openapi/parse.d.ts +13 -0
  152. package/dist/types/openapi/references.d.ts +14 -4
  153. package/dist/types/ratelimit/cloudflare.d.ts +39 -0
  154. package/dist/types/ratelimit/index.d.ts +27 -0
  155. package/dist/types/ratelimit/memory.d.ts +36 -0
  156. package/dist/types/ratelimit/schema.d.ts +111 -0
  157. package/dist/types/ratelimit/upstash.d.ts +21 -0
  158. package/dist/types/ratelimit/wrangler.d.ts +23 -0
  159. package/dist/types/reference/asyncapi.d.ts +10 -10
  160. package/dist/types/reference/graphql.d.ts +13 -10
  161. package/dist/types/reference/openapi.d.ts +33 -12
  162. package/dist/types/reference/options.d.ts +45 -5
  163. package/dist/types/reference/scalar.d.ts +13 -0
  164. package/dist/types/reference/schema.d.ts +60 -36
  165. package/dist/types/search/documents.d.ts +12 -1
  166. package/dist/types/search/orama-index.d.ts +4 -0
  167. package/dist/types/seo/metatags.d.ts +20 -0
  168. package/docs/02-deployment.mdx +44 -6
  169. package/docs/03-upgrading.mdx +4 -4
  170. package/docs/04-migrating.mdx +1 -1
  171. package/docs/08-faq.mdx +1 -1
  172. package/docs/advanced/changelog.mdx +2 -2
  173. package/docs/advanced/custom-pages.mdx +3 -3
  174. package/docs/advanced/skills.mdx +14 -0
  175. package/docs/cli/audit.mdx +38 -2
  176. package/docs/cli/evals.mdx +3 -3
  177. package/docs/cli/index.mdx +1 -0
  178. package/docs/cli/translate.mdx +3 -3
  179. package/docs/cli/version.mdx +1 -1
  180. package/docs/configuration/analytics.mdx +22 -1
  181. package/docs/configuration/assistant.mdx +188 -36
  182. package/docs/configuration/consent.mdx +100 -0
  183. package/docs/configuration/customization.mdx +6 -4
  184. package/docs/configuration/index.mdx +63 -5
  185. package/docs/configuration/meta.ts +3 -0
  186. package/docs/configuration/narration.mdx +119 -0
  187. package/docs/configuration/rate-limiting.mdx +69 -0
  188. package/docs/configuration/search.mdx +30 -2
  189. package/docs/configuration/theming.mdx +3 -1
  190. package/docs/content/components.mdx +107 -1
  191. package/docs/content/frontmatter.mdx +77 -1
  192. package/docs/content/i18n.mdx +40 -3
  193. package/docs/content/includes.mdx +16 -0
  194. package/docs/content/index.mdx +4 -2
  195. package/docs/content/islands.mdx +1 -1
  196. package/docs/content/meta.mdx +4 -1
  197. package/docs/content/meta.ts +1 -0
  198. package/docs/content/navigation.mdx +28 -6
  199. package/docs/content/sources/contentful.mdx +32 -0
  200. package/docs/content/sources/custom.mdx +39 -0
  201. package/docs/content/sources/github-releases.mdx +31 -0
  202. package/docs/content/sources/index.mdx +91 -0
  203. package/docs/content/sources/meta.ts +16 -0
  204. package/docs/content/sources/notion.mdx +32 -0
  205. package/docs/content/sources/obsidian.mdx +37 -0
  206. package/docs/content/sources/payload.mdx +30 -0
  207. package/docs/content/sources/remote-mdx.mdx +40 -0
  208. package/docs/content/sources/sanity.mdx +29 -0
  209. package/docs/content/sources/strapi.mdx +31 -0
  210. package/docs/content/syntax.mdx +81 -2
  211. package/docs/content/variables.mdx +41 -0
  212. package/docs/content/versioning.mdx +1 -1
  213. package/docs/discoverability/agent-discovery.mdx +30 -3
  214. package/docs/discoverability/index.mdx +3 -2
  215. package/docs/discoverability/llms-txt.mdx +1 -1
  216. package/docs/discoverability/markdown.mdx +2 -2
  217. package/docs/discoverability/metadata.mdx +17 -0
  218. package/docs/discoverability/open-graph.mdx +5 -3
  219. package/docs/discoverability/rss.mdx +1 -1
  220. package/docs/references/api-pages.mdx +74 -0
  221. package/docs/references/asyncapi.mdx +2 -2
  222. package/docs/references/graphql.mdx +3 -3
  223. package/docs/references/meta.ts +1 -1
  224. package/docs/references/openapi.mdx +106 -5
  225. package/docs/references/scalar.mdx +3 -1
  226. package/package.json +36 -1
  227. package/skills/blume/SKILL.md +3 -0
  228. package/skills/blume-migrate/SKILL.md +5 -5
  229. package/skills/blume-migrate/references/docusaurus.md +3 -3
  230. package/skills/blume-migrate/references/fumadocs.md +1 -1
  231. package/skills/blume-migrate/references/mintlify.md +37 -19
  232. package/skills/blume-migrate/references/nextra.md +3 -3
  233. package/skills/blume-migrate/references/starlight.md +2 -1
  234. package/skills/blume-migrate/scripts/mintlify-codemod.mjs +67 -16
  235. package/skills/blume-write-skill/SKILL.md +82 -0
  236. package/src/ai/agent-readability.ts +4 -3
  237. package/src/ai/agent-surface.ts +9 -7
  238. package/src/ai/ai-catalog.ts +12 -5
  239. package/src/ai/api/handlers.ts +2 -2
  240. package/src/ai/api/spec.ts +2 -2
  241. package/src/ai/api-catalog.ts +6 -2
  242. package/src/ai/ask-context.ts +73 -20
  243. package/src/ai/ask-data.ts +6 -0
  244. package/src/ai/ask-tools.ts +142 -0
  245. package/src/ai/ask.ts +354 -76
  246. package/src/ai/changelog-markdown.ts +2 -2
  247. package/src/ai/component-markdown.ts +75 -0
  248. package/src/ai/cors.ts +2 -0
  249. package/src/ai/index.ts +12 -0
  250. package/src/ai/link-headers.ts +14 -5
  251. package/src/ai/llms.ts +24 -9
  252. package/src/ai/markdown.ts +2 -1
  253. package/src/ai/mcp/data.ts +6 -0
  254. package/src/ai/mcp/discovery.ts +2 -2
  255. package/src/ai/mcp/query.ts +2 -2
  256. package/src/ai/mcp/server.ts +2 -2
  257. package/src/ai/openapi-components.ts +31 -9
  258. package/src/ai/relative-links.ts +42 -26
  259. package/src/ai/serializers.ts +2 -1
  260. package/src/ai/site-skill.ts +274 -0
  261. package/src/ai/skills.ts +49 -3
  262. package/src/ai/tar.ts +139 -12
  263. package/src/ai/write-skill.ts +97 -0
  264. package/src/analytics/head.ts +4 -0
  265. package/src/analytics/index.ts +5 -0
  266. package/src/analytics/one-dollar-stats.ts +86 -0
  267. package/src/analytics/schema.ts +2 -0
  268. package/src/astro/generate.ts +133 -19
  269. package/src/astro/include-hmr.ts +31 -12
  270. package/src/astro/include-refresh.ts +19 -8
  271. package/src/astro/index.ts +1 -0
  272. package/src/astro/integration.ts +143 -14
  273. package/src/astro/module-types.ts +6 -0
  274. package/src/astro/runtime-modules.ts +28 -13
  275. package/src/astro/templates.ts +364 -67
  276. package/src/astro/variables.ts +31 -0
  277. package/src/audit/catalog.ts +19 -0
  278. package/src/audit/checks/contrast.ts +183 -0
  279. package/src/audit/checks/i18n.ts +2 -3
  280. package/src/audit/checks/indexability.ts +2 -3
  281. package/src/audit/checks/links.ts +13 -13
  282. package/src/audit/checks/sitemap.ts +2 -3
  283. package/src/audit/graph.ts +3 -1
  284. package/src/audit/redirects.ts +46 -15
  285. package/src/audit/run.ts +14 -9
  286. package/src/audit/snapshot.ts +5 -0
  287. package/src/audit/types.ts +2 -1
  288. package/src/blume-modules.d.ts +7 -0
  289. package/src/captcha/client.ts +152 -0
  290. package/src/captcha/hcaptcha.ts +36 -0
  291. package/src/captcha/index.ts +28 -0
  292. package/src/captcha/schema.ts +32 -0
  293. package/src/captcha/turnstile.ts +38 -0
  294. package/src/captcha/verify.ts +71 -0
  295. package/src/cli/args.ts +32 -0
  296. package/src/cli/command-meta.ts +5 -0
  297. package/src/cli/commands/audit.ts +4 -1
  298. package/src/cli/commands/doctor.ts +25 -17
  299. package/src/cli/commands/eval.ts +19 -11
  300. package/src/cli/commands/skill.ts +96 -0
  301. package/src/cli/commands/translate.ts +9 -12
  302. package/src/cli/commands/validate.ts +3 -1
  303. package/src/cli/dev-lock.ts +157 -37
  304. package/src/cli/index.ts +5 -0
  305. package/src/cli/report-format.ts +11 -6
  306. package/src/cli/required-secrets.ts +71 -29
  307. package/src/components/BlumePage.astro +2 -0
  308. package/src/components/colors.ts +19 -0
  309. package/src/components/content/ApiEndpoint.astro +18 -0
  310. package/src/components/content/ApiField.astro +79 -0
  311. package/src/components/content/ApiPlayground.astro +62 -0
  312. package/src/components/content/ApiRail.astro +19 -0
  313. package/src/components/content/Badge.astro +5 -3
  314. package/src/components/content/Color.astro +1 -0
  315. package/src/components/content/Component.astro +2 -2
  316. package/src/components/content/FileTree.astro +1 -0
  317. package/src/components/content/GithubInfo.astro +1 -0
  318. package/src/components/content/Panel.astro +1 -0
  319. package/src/components/content/ParamField.astro +25 -0
  320. package/src/components/content/RequestExample.astro +17 -0
  321. package/src/components/content/ResponseExample.astro +17 -0
  322. package/src/components/content/ResponseField.astro +32 -0
  323. package/src/components/content/Step.astro +1 -0
  324. package/src/components/content/Tab.astro +0 -1
  325. package/src/components/content/Tabs.astro +4 -0
  326. package/src/components/content/Tile.astro +1 -0
  327. package/src/components/content/Tooltip.astro +1 -0
  328. package/src/components/content/Tree.astro +1 -0
  329. package/src/components/content/TypeTable.astro +4 -1
  330. package/src/components/content/View.astro +21 -0
  331. package/src/components/content/ViewSwitcher.astro +168 -0
  332. package/src/components/content/api-field.ts +100 -0
  333. package/src/components/content/api-page.ts +224 -0
  334. package/src/components/content/badge-color.ts +5 -2
  335. package/src/components/content/base-href.ts +13 -36
  336. package/src/components/content/view-switcher.ts +71 -0
  337. package/src/components/index.ts +2 -0
  338. package/src/components/islands/Assistant.astro +10 -1
  339. package/src/components/islands/assistant.tsx +125 -18
  340. package/src/components/islands/base-path.ts +47 -10
  341. package/src/components/islands/code-question.ts +62 -0
  342. package/src/components/islands/hooks.ts +145 -40
  343. package/src/components/islands/support-link.ts +68 -0
  344. package/src/components/islands/webmcp.ts +4 -2
  345. package/src/components/layout/Analytics.astro +11 -2
  346. package/src/components/layout/Banner.astro +14 -10
  347. package/src/components/layout/Breadcrumbs.astro +11 -4
  348. package/src/components/layout/ConsentBanner.astro +62 -0
  349. package/src/components/layout/ConsentHead.astro +38 -0
  350. package/src/components/layout/Directory.astro +94 -0
  351. package/src/components/layout/DiscoveryLinks.astro +9 -5
  352. package/src/components/layout/DrawerSwitchers.astro +51 -0
  353. package/src/components/layout/Empty.astro +2 -2
  354. package/src/components/layout/Header.astro +124 -82
  355. package/src/components/layout/LanguageSwitcher.astro +50 -17
  356. package/src/components/layout/NarrationPlayer.astro +1085 -0
  357. package/src/components/layout/NavSelector.astro +35 -9
  358. package/src/components/layout/NavTabMenu.astro +3 -3
  359. package/src/components/layout/NavTree.astro +16 -6
  360. package/src/components/layout/PageActions.astro +4 -3
  361. package/src/components/layout/PageFeedback.astro +54 -49
  362. package/src/components/layout/PageLayout.astro +78 -9
  363. package/src/components/layout/Pagination.astro +3 -3
  364. package/src/components/layout/ReferenceLayout.astro +17 -6
  365. package/src/components/layout/RelatedPages.astro +42 -0
  366. package/src/components/layout/RootLayout.astro +313 -50
  367. package/src/components/layout/Search.astro +64 -30
  368. package/src/components/layout/SiteFooter.astro +124 -0
  369. package/src/components/layout/SiteMetatags.astro +16 -0
  370. package/src/components/layout/VersionBanner.astro +2 -2
  371. package/src/components/layout/analytics-client.ts +12 -0
  372. package/src/components/layout/consent/native.ts +79 -0
  373. package/src/components/layout/consent/types.ts +37 -0
  374. package/src/components/layout/footer-links.ts +53 -0
  375. package/src/components/layout/footer-socials.ts +87 -0
  376. package/src/components/layout/locale-redirect.ts +107 -0
  377. package/src/components/layout/nav-utils.ts +83 -0
  378. package/src/components/layout/page-feedback.ts +96 -0
  379. package/src/components/layout/search/analytics.ts +98 -0
  380. package/src/components/layout/search/flexsearch.ts +17 -5
  381. package/src/components/layout/search/orama-cloud.ts +26 -14
  382. package/src/components/layout/search/types.ts +20 -0
  383. package/src/components/layout/search/typesense.ts +5 -1
  384. package/src/components/layout/toc-active.ts +41 -0
  385. package/src/components/layout/toc-element.ts +8 -14
  386. package/src/components/openapi/ApiTagOperations.astro +2 -2
  387. package/src/components/openapi/AsyncApiOperation.astro +7 -4
  388. package/src/components/openapi/GraphqlChip.astro +2 -2
  389. package/src/components/openapi/Operation.astro +163 -13
  390. package/src/components/openapi/Playground.astro +4 -4
  391. package/src/components/openapi/RequestBody.astro +6 -4
  392. package/src/components/openapi/RequestPanel.astro +63 -8
  393. package/src/components/openapi/Responses.astro +6 -4
  394. package/src/components/openapi/SchemaTable.astro +7 -0
  395. package/src/components/openapi/async-snippets.ts +4 -4
  396. package/src/components/openapi/async.ts +38 -6
  397. package/src/components/openapi/code-samples.ts +97 -0
  398. package/src/components/openapi/helpers.ts +19 -9
  399. package/src/components/openapi/message-composer.ts +6 -1
  400. package/src/components/openapi/message.ts +17 -2
  401. package/src/components/openapi/operation-model.ts +81 -11
  402. package/src/components/openapi/panel.ts +4 -2
  403. package/src/components/openapi/param-style.ts +181 -0
  404. package/src/components/openapi/playground-client.ts +73 -16
  405. package/src/components/openapi/request.ts +190 -26
  406. package/src/components/openapi/schema-tree.ts +30 -24
  407. package/src/components/openapi/security.ts +6 -3
  408. package/src/components/openapi/snippets.ts +953 -13
  409. package/src/components/openapi/ws-client.ts +18 -2
  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/base-path.ts +62 -16
  421. package/src/core/builtin-tags.ts +5 -0
  422. package/src/core/client-address.ts +19 -0
  423. package/src/core/config-input.ts +203 -27
  424. package/src/core/data.ts +44 -4
  425. package/src/core/diagnostics.ts +5 -2
  426. package/src/core/directive-diagnostics.ts +99 -0
  427. package/src/core/footer.ts +26 -0
  428. package/src/core/frontmatter.ts +21 -18
  429. package/src/core/graph.ts +39 -36
  430. package/src/core/heading-markers.ts +5 -18
  431. package/src/core/i18n-ui.ts +82 -2
  432. package/src/core/i18n.ts +31 -3
  433. package/src/core/includes.ts +20 -3
  434. package/src/core/last-modified.ts +25 -3
  435. package/src/core/links.ts +16 -2
  436. package/src/core/locale-links.ts +5 -1
  437. package/src/core/localizable.ts +26 -0
  438. package/src/core/meta.ts +33 -19
  439. package/src/core/navigation.ts +71 -20
  440. package/src/core/page-modes.ts +56 -0
  441. package/src/core/project-graph.ts +138 -10
  442. package/src/core/redirect-patterns.ts +491 -0
  443. package/src/core/related.ts +131 -0
  444. package/src/core/schema.ts +342 -68
  445. package/src/core/sources/contentful-rich-text.ts +27 -20
  446. package/src/core/sources/filesystem.ts +20 -2
  447. package/src/core/sources/github-releases.ts +25 -6
  448. package/src/core/sources/lexical.ts +23 -18
  449. package/src/core/sources/lower.ts +201 -34
  450. package/src/core/sources/mdx-remote.ts +51 -16
  451. package/src/core/sources/normalize.ts +327 -91
  452. package/src/core/sources/notion.ts +52 -25
  453. package/src/core/sources/obsidian.ts +23 -6
  454. package/src/core/sources/portable-text.ts +38 -21
  455. package/src/core/sources/read.ts +8 -3
  456. package/src/core/sources/strapi-blocks.ts +20 -16
  457. package/src/core/sources/watch.ts +20 -7
  458. package/src/core/standard-schema.ts +10 -6
  459. package/src/core/types.ts +1 -1
  460. package/src/core/ui-packs/ar.ts +43 -0
  461. package/src/core/ui-packs/bg.ts +45 -0
  462. package/src/core/ui-packs/bn.ts +43 -0
  463. package/src/core/ui-packs/ca.ts +46 -0
  464. package/src/core/ui-packs/cs.ts +44 -0
  465. package/src/core/ui-packs/da.ts +45 -0
  466. package/src/core/ui-packs/de.ts +46 -0
  467. package/src/core/ui-packs/el.ts +45 -0
  468. package/src/core/ui-packs/es.ts +46 -0
  469. package/src/core/ui-packs/fa.ts +45 -0
  470. package/src/core/ui-packs/fi.ts +45 -0
  471. package/src/core/ui-packs/fr.ts +46 -0
  472. package/src/core/ui-packs/he.ts +43 -0
  473. package/src/core/ui-packs/hi.ts +44 -0
  474. package/src/core/ui-packs/hr.ts +45 -0
  475. package/src/core/ui-packs/hu.ts +44 -0
  476. package/src/core/ui-packs/id.ts +45 -0
  477. package/src/core/ui-packs/it.ts +45 -0
  478. package/src/core/ui-packs/ja.ts +45 -0
  479. package/src/core/ui-packs/ko.ts +44 -0
  480. package/src/core/ui-packs/nl.ts +46 -0
  481. package/src/core/ui-packs/no.ts +44 -0
  482. package/src/core/ui-packs/pl.ts +45 -0
  483. package/src/core/ui-packs/pt-br.ts +46 -0
  484. package/src/core/ui-packs/pt.ts +45 -0
  485. package/src/core/ui-packs/ro.ts +45 -0
  486. package/src/core/ui-packs/ru.ts +45 -0
  487. package/src/core/ui-packs/sk.ts +44 -0
  488. package/src/core/ui-packs/sr.ts +45 -0
  489. package/src/core/ui-packs/sv.ts +44 -0
  490. package/src/core/ui-packs/th.ts +43 -0
  491. package/src/core/ui-packs/tr.ts +45 -0
  492. package/src/core/ui-packs/uk.ts +45 -0
  493. package/src/core/ui-packs/vi.ts +45 -0
  494. package/src/core/ui-packs/zh-tw.ts +43 -0
  495. package/src/core/ui-packs/zh.ts +43 -0
  496. package/src/core/variables.ts +103 -0
  497. package/src/core/version-cut.ts +52 -15
  498. package/src/deploy/artifacts.ts +104 -14
  499. package/src/deploy/cloudflare-negotiation.ts +39 -17
  500. package/src/deploy/headers.ts +10 -5
  501. package/src/deploy/node-headers.ts +64 -10
  502. package/src/deploy/platforms/cloudflare.ts +44 -3
  503. package/src/deploy/platforms/netlify.ts +34 -1
  504. package/src/deploy/platforms/node.ts +1 -0
  505. package/src/deploy/platforms/static.ts +1 -0
  506. package/src/deploy/platforms/types.ts +8 -0
  507. package/src/deploy/platforms/vercel.ts +38 -2
  508. package/src/deploy/redirects.ts +139 -36
  509. package/src/deploy/robots.ts +2 -2
  510. package/src/deploy/rss.ts +4 -3
  511. package/src/deploy/sitemap.ts +7 -5
  512. package/src/deploy/vercel-negotiation.ts +36 -0
  513. package/src/markdown/api-rail.ts +259 -0
  514. package/src/markdown/base-links.ts +34 -36
  515. package/src/markdown/code-title.ts +35 -9
  516. package/src/markdown/directives.ts +242 -36
  517. package/src/markdown/features.ts +20 -2
  518. package/src/markdown/fence-meta.ts +2 -0
  519. package/src/markdown/include.ts +11 -1
  520. package/src/markdown/index.ts +35 -11
  521. package/src/markdown/math.ts +4 -4
  522. package/src/markdown/mdast.ts +5 -2
  523. package/src/markdown/relative-links.ts +12 -4
  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 +136 -11
  531. package/src/og/derive.ts +41 -31
  532. package/src/og/index.ts +1 -0
  533. package/src/openapi/asyncapi.ts +4 -2
  534. package/src/openapi/model.ts +77 -36
  535. package/src/openapi/overlay.ts +256 -0
  536. package/src/openapi/parse.ts +55 -2
  537. package/src/openapi/proxy.ts +63 -10
  538. package/src/openapi/references.ts +21 -5
  539. package/src/openapi/render-mdx.ts +46 -3
  540. package/src/openapi/scalar.ts +40 -6
  541. package/src/openapi/source.ts +1 -1
  542. package/src/ratelimit/cloudflare.ts +54 -0
  543. package/src/ratelimit/index.ts +30 -0
  544. package/src/ratelimit/memory.ts +45 -0
  545. package/src/ratelimit/runtime.ts +229 -0
  546. package/src/ratelimit/schema.ts +28 -0
  547. package/src/ratelimit/upstash.ts +30 -0
  548. package/src/ratelimit/wrangler.ts +70 -0
  549. package/src/reference/asyncapi.ts +2 -2
  550. package/src/reference/graphql.ts +5 -2
  551. package/src/reference/openapi.ts +21 -7
  552. package/src/reference/options.ts +51 -7
  553. package/src/reference/scalar.ts +33 -8
  554. package/src/registry/eject.ts +201 -28
  555. package/src/registry/registry.ts +7 -0
  556. package/src/search/adapters/version-scope.ts +30 -0
  557. package/src/search/documents.ts +93 -28
  558. package/src/search/orama-index.ts +28 -3
  559. package/src/search/pagefind-ranking.ts +39 -0
  560. package/src/search/popular.ts +2 -1
  561. package/src/search/sync/algolia.ts +15 -4
  562. package/src/search/sync/orama-cloud.ts +3 -0
  563. package/src/search/sync/typesense.ts +5 -0
  564. package/src/seo/jsonld.ts +7 -3
  565. package/src/seo/metatags.ts +67 -0
  566. package/src/theme/chrome-icons.ts +1 -0
  567. package/src/theme/color.ts +500 -0
  568. package/src/theme/entry.ts +56 -3
  569. package/src/theme/palette.ts +121 -45
  570. package/src/translate/meta.ts +68 -24
  571. package/src/translate/prompts.ts +1 -0
  572. package/src/translate/run.ts +3 -3
  573. package/src/translate/validate.ts +12 -3
  574. package/src/translate/work-list.ts +56 -17
  575. package/src/upgrade/upgrade.ts +4 -171
  576. package/dist/cli/chunk-3yce002v.js.map +0 -14
  577. package/dist/cli/chunk-5r8g91qn.js.map +0 -34
  578. package/dist/cli/chunk-6dtt0zfn.js.map +0 -10
  579. package/dist/cli/chunk-7mbqtmgb.js.map +0 -10
  580. package/dist/cli/chunk-ddndchfr.js.map +0 -14
  581. package/dist/cli/chunk-esh98wmb.js +0 -23
  582. package/dist/cli/chunk-esh98wmb.js.map +0 -10
  583. package/dist/cli/chunk-hqp2ajnh.js.map +0 -35
  584. package/dist/cli/chunk-hr8ne106.js.map +0 -13
  585. package/dist/cli/chunk-j85scx15.js.map +0 -10
  586. package/dist/cli/chunk-mqc662a6.js +0 -75
  587. package/dist/cli/chunk-mqc662a6.js.map +0 -11
  588. package/dist/cli/chunk-pbg5a4s3.js.map +0 -19
  589. package/dist/cli/chunk-qkb5a8sa.js.map +0 -10
  590. package/dist/cli/chunk-v6ya5kcb.js.map +0 -189
  591. package/dist/cli/chunk-wdrt2k2v.js.map +0 -10
  592. package/dist/cli/chunk-xh43dwgw.js.map +0 -36
  593. package/docs/content/sources.mdx +0 -338
  594. /package/dist/cli/{chunk-zp79m0ts.js.map → chunk-1n228xqb.js.map} +0 -0
  595. /package/dist/cli/{chunk-h2ez8dzb.js.map → chunk-5ffywsmb.js.map} +0 -0
  596. /package/dist/cli/{chunk-g698a744.js.map → chunk-5wj2qwn2.js.map} +0 -0
  597. /package/dist/cli/{chunk-sqw4ekg1.js.map → chunk-amrb6hgh.js.map} +0 -0
  598. /package/dist/cli/{chunk-h7k3nq3v.js.map → chunk-gp84za0h.js.map} +0 -0
  599. /package/dist/cli/{chunk-bfwp9vp6.js.map → chunk-p804f3pe.js.map} +0 -0
  600. /package/dist/cli/{chunk-00gs3wqs.js.map → chunk-ta27feev.js.map} +0 -0
  601. /package/dist/cli/{chunk-bbnwccaz.js.map → chunk-y4ykbark.js.map} +0 -0
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/core/sources/watch.ts"],
4
+ "sourcesContent": [
5
+ "import type { WatchListener } from \"node:fs\";\n\n/**\n * Directory segments that are never authored content: VCS, dependency trees,\n * Blume's own generated project and build output, and framework/deploy caches.\n * Both the content scan and the dev watcher skip these unconditionally, on top\n * of the user's `content.exclude`.\n *\n * The scan needs them because a broadly-scoped `content.root` — `\".\"` or an app\n * dir that also holds `node_modules`/`dist`, the common shape when migrating a\n * docs app that lives at the repo or app root — would otherwise glob thousands\n * of stray markdown files out of dependencies and build artifacts. `content.root`\n * defaults to `docs/` where this rarely bites, but any wider root hits it.\n *\n * The watcher needs them because a recursive `fs.watch` rooted at the project\n * also sees Blume's own `.blume/` output, which the dev server rewrites on every\n * render (e.g. `.blume/.astro/data-store.json`). Left unfiltered, each such write\n * re-triggers a rescan + runtime regeneration whose writes land back under\n * `.blume/` and fire the watcher again: a self-sustaining loop that stalls page\n * renders and floods the console. `fs.watch` has no ignore option, so we filter\n * by the changed path in the callback.\n */\nexport const BLUME_IGNORE_DIRS = [\n \".blume\",\n // The isolated `blume check --isolated` runtime. A sibling of `.blume`, it is\n // written while a dev server runs; without this the content-layer watcher (or\n // a `.`-rooted fs.watch) would treat its generation as a content change and\n // reload — the very thing `--isolated` promises not to do.\n \".blume-verify\",\n \".cache\",\n \".git\",\n \".next\",\n \".turbo\",\n \".vercel\",\n \"dist\",\n \"node_modules\",\n];\n\n/**\n * Baseline scan-ignore globs applied to every filesystem source, unioned with\n * the user's `content.exclude`. Kept in sync with the watcher via the shared\n * {@link BLUME_IGNORE_DIRS} so `load()` and `watch()` never disagree on what is\n * content. `**\\/<dir>/**` matches the directory at the content root or nested.\n */\nexport const baselineScanIgnore = (): string[] =>\n BLUME_IGNORE_DIRS.map((dir) => `**/${dir}/**`);\n\n/**\n * Alias retained for the dev watcher's call site and its tests; the watcher and\n * the scan share the same never-content directory set.\n */\nexport const BLUME_WATCH_IGNORE_DIRS = BLUME_IGNORE_DIRS;\n\n/**\n * Extract root-anchored ignore dirs (`/foo`) from `foo/**`-style excludes. The\n * scan's glob `foo/**` matches `foo` at the source root only, so the watcher\n * skips that one directory: a nested `guides/foo/` is still content, and an\n * edit there must still reload.\n */\nexport const excludeDirSegments = (patterns: readonly string[]): string[] =>\n patterns\n .map((pattern) => /^(?<dir>[^*/]+)\\/\\*\\*$/u.exec(pattern)?.groups?.dir)\n .filter((dir): dir is string => dir !== undefined)\n .map((dir) => `/${dir}`);\n\n/**\n * Build a recursive-watch listener that fires `onChange` for content changes but\n * ignores events whose path crosses an ignored directory — a segment named in\n * `ignoreDirs` at any depth, or one `ignoreSegment` rejects, for a scan whose\n * skip rule is a shape (every dot-name) rather than a list. An entry written\n * with a leading slash (`/drafts`, see {@link excludeDirSegments}) names a\n * directory at the watched root only. A missing `filename` — rare; the\n * platform couldn't name the changed path — falls through to `onChange`\n * rather than silently dropping a real edit. Exported for testing.\n */\nexport const ignoringWatchListener = (\n onChange: () => void,\n ignoreDirs: Iterable<string> = BLUME_WATCH_IGNORE_DIRS,\n ignoreSegment: (segment: string) => boolean = () => false\n): WatchListener<string> => {\n const ignore = new Set(ignoreDirs);\n return (_event, filename) => {\n if (\n filename !== null &&\n filename\n .split(/[/\\\\]/u)\n .some(\n (segment, index) =>\n ignore.has(segment) ||\n (index === 0 && ignore.has(`/${segment}`)) ||\n ignoreSegment(segment)\n )\n ) {\n return;\n }\n onChange();\n };\n};\n"
6
+ ],
7
+ "mappings": ";;;AAsBO,IAAM,oBAAoB;AAAA,EAC/B;AAAA,EAKA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAQO,IAAM,qBAAqB,MAChC,kBAAkB,IAAI,CAAC,QAAQ,MAAM,QAAQ;AAMxC,IAAM,0BAA0B;AAQhC,IAAM,qBAAqB,CAAC,aACjC,SACG,IAAI,CAAC,YAAY,0BAA0B,KAAK,OAAO,GAAG,QAAQ,GAAG,EACrE,OAAO,CAAC,QAAuB,QAAQ,SAAS,EAChD,IAAI,CAAC,QAAQ,IAAI,KAAK;AAYpB,IAAM,wBAAwB,CACnC,UACA,aAA+B,yBAC/B,gBAA8C,MAAM,UAC1B;AAAA,EAC1B,MAAM,SAAS,IAAI,IAAI,UAAU;AAAA,EACjC,OAAO,CAAC,QAAQ,aAAa;AAAA,IAC3B,IACE,aAAa,QACb,SACG,MAAM,QAAQ,EACd,KACC,CAAC,SAAS,UACR,OAAO,IAAI,OAAO,KACjB,UAAU,KAAK,OAAO,IAAI,IAAI,SAAS,KACxC,cAAc,OAAO,CACzB,GACF;AAAA,MACA;AAAA,IACF;AAAA,IACA,SAAS;AAAA;AAAA;",
8
+ "debugId": "12AD3963BDF991A964756E2164756E21",
9
+ "names": []
10
+ }
@@ -1,13 +1,13 @@
1
1
  #!/usr/bin/env node
2
- import"./chunk-gs7r695n.js";
2
+ import"./chunk-zccbjcj0.js";
3
3
  import {
4
4
  resolveRuntimeDir
5
- } from "./chunk-v6ya5kcb.js";
5
+ } from "./chunk-xkz5xbtv.js";
6
6
  import {
7
7
  refreshBlumeContent,
8
8
  showBlumeErrorOverlay,
9
9
  generateRuntime
10
- } from "./chunk-xh43dwgw.js";
10
+ } from "./chunk-zf748avv.js";
11
11
  import {
12
12
  commandMeta,
13
13
  normalizeHost,
@@ -15,31 +15,33 @@ import {
15
15
  logger,
16
16
  reportDiagnostics
17
17
  } from "./index.js";
18
- import"./chunk-ddndchfr.js";
19
- import"./chunk-00gs3wqs.js";
20
- import"./chunk-jq5n4avg.js";
18
+ import"./chunk-2f3ndkpw.js";
21
19
  import {
22
20
  scanProject
23
- } from "./chunk-5r8g91qn.js";
24
- import"./chunk-hr8ne106.js";
25
- import"./chunk-fsmrqk8a.js";
26
- import"./chunk-sqw4ekg1.js";
21
+ } from "./chunk-43zcf4gz.js";
22
+ import"./chunk-ta27feev.js";
23
+ import"./chunk-jq5n4avg.js";
24
+ import"./chunk-4h8z9vv5.js";
25
+ import"./chunk-cm89scdv.js";
26
+ import"./chunk-2f7n4qzt.js";
27
+ import"./chunk-amrb6hgh.js";
28
+ import {
29
+ parsePort
30
+ } from "./chunk-4ejxbzee.js";
27
31
  import {
28
32
  DevLockHeldError,
29
33
  acquireDevLock,
30
34
  updateDevLockPort,
31
35
  describeDevLock
32
- } from "./chunk-wdrt2k2v.js";
36
+ } from "./chunk-cmtcnh9f.js";
33
37
  import {
34
38
  refuseIfEjected
35
- } from "./chunk-4e9b9ra6.js";
39
+ } from "./chunk-py62fewh.js";
36
40
  import {
37
41
  prepareProject
38
- } from "./chunk-h2ez8dzb.js";
39
- import {
40
- parsePort
41
- } from "./chunk-esh98wmb.js";
42
- import"./chunk-mqc662a6.js";
42
+ } from "./chunk-5ffywsmb.js";
43
+ import"./chunk-cy5bm0j0.js";
44
+ import"./chunk-6bm0xpgd.js";
43
45
 
44
46
  // src/cli/commands/dev.ts
45
47
  import { dev } from "astro";
@@ -183,5 +185,5 @@ export {
183
185
  devCommand
184
186
  };
185
187
 
186
- //# debugId=E6DA8A8FE27E0E6164756E2164756E21
187
- //# sourceMappingURL=chunk-8g8ytmgx.js.map
188
+ //# debugId=B868244539C2BD5E64756E2164756E21
189
+ //# sourceMappingURL=chunk-nd1821sk.js.map
@@ -4,7 +4,7 @@
4
4
  "sourcesContent": [
5
5
  "import { dev } from \"astro\";\nimport { watch } from \"chokidar\";\nimport { defineCommand } from \"citty\";\nimport { debounce } from \"perfect-debounce\";\n\nimport { generateRuntime } from \"../../astro/generate.ts\";\nimport {\n refreshBlumeContent,\n showBlumeErrorOverlay,\n} from \"../../astro/integration.ts\";\nimport { BlumeError } from \"../../core/diagnostics.ts\";\nimport { scanProject } from \"../../core/project-graph.ts\";\nimport { resolveRuntimeDir } from \"../../core/project.ts\";\nimport { parsePort } from \"../args.ts\";\nimport { commandMeta } from \"../command-meta.ts\";\nimport {\n acquireDevLock,\n describeDevLock,\n DevLockHeldError,\n updateDevLockPort,\n} from \"../dev-lock.ts\";\nimport { refuseIfEjected } from \"../eject-scripts.ts\";\nimport { normalizeHost } from \"../host-args.ts\";\nimport { logger, reportDiagnostics } from \"../log.ts\";\nimport { prepareProject } from \"../prepare.ts\";\n\n/**\n * A fingerprint of the route set: the sorted `path entryId` pairs. It changes\n * when a page is added, removed, or renamed (a folder rename shifts many at\n * once) but stays equal across pure body edits — so the dev loop can tell a\n * \"structural\" change (needs a content re-sync) from a hot-reloadable one.\n */\nconst routeSignature = (\n routes: readonly { entryId: string; path: string }[]\n): string =>\n routes\n .map((route) => `${route.path} ${route.entryId}`)\n .toSorted()\n .join(\"\\n\");\n\n/**\n * The port the dev server actually bound. Astro snapshots `address` when the\n * server first listens, but a config restart that lands during startup leaves\n * that snapshot null: the `astro.config.mjs` written just before the server\n * started can reach Astro's watcher late, and Astro restarts in place before\n * it ever listens. The live resolved URLs follow the restarted server, so read\n * the port from those, then fall back to the one that was asked for.\n */\nconst boundPortOf = (\n server: Awaited<ReturnType<typeof dev>>,\n requested: number\n): number => {\n // SAFETY: Astro types `address` as always set, but it is null at runtime\n // when a restart replaced the server before its first listen (see above).\n const address = server.address as typeof server.address | null;\n if (address) {\n return address.port;\n }\n for (const url of server.resolvedUrls.local) {\n const port = Number(new URL(url).port);\n if (port > 0) {\n return port;\n }\n }\n return requested;\n};\n\nexport const devCommand = defineCommand({\n args: {\n \"content-dir\": {\n description: \"Content folder to scan, overriding config (content.root).\",\n type: \"string\",\n },\n debug: {\n description: \"Verbose Astro/Vite logging for troubleshooting.\",\n type: \"boolean\",\n },\n host: { description: \"Network host to bind.\", type: \"string\" },\n open: { description: \"Open the browser on start.\", type: \"boolean\" },\n port: { description: \"Port to listen on.\", type: \"string\" },\n preview: {\n description: \"Include drafts and unpublished CMS content.\",\n type: \"boolean\",\n },\n strict: { description: \"Fail on diagnostics.\", type: \"boolean\" },\n },\n meta: commandMeta.dev,\n async run({ args }) {\n const root = process.cwd();\n await refuseIfEjected(root, \"dev\");\n const preview = args.preview ?? false;\n const overrides = args[\"content-dir\"]\n ? { contentRoot: args[\"content-dir\"] }\n : undefined;\n // Astro's dev server defaults to 4321 when no port is passed. Feeding the\n // resolved URL in as the `deployment.site` fallback lets site-gated features\n // (OG images, canonicals, sitemap) work locally without configuring a site.\n const explicitPort = parsePort(args.port);\n const port = explicitPort ?? 4321;\n let devServerUrl = `http://localhost:${port}`;\n\n // Claim the shared `.blume` dir BEFORE preparing: `prepareProject`\n // regenerates the runtime, so even a refused second dev server would\n // otherwise clobber the running one's generated tree (with this\n // invocation's port baked in) on its way out. The claim is atomic, so two\n // simultaneous starts can't both win. Dev never relocates the runtime dir,\n // so the lock always lives at `<root>/.blume`.\n const outDir = resolveRuntimeDir(root);\n let releaseLock: () => void;\n try {\n releaseLock = acquireDevLock(outDir, port);\n } catch (error) {\n if (error instanceof DevLockHeldError) {\n logger.error(\n `A \\`blume dev\\` server is already running${describeDevLock(error.lock)} in this project. Reuse that server instead of starting a second one — two dev servers would corrupt the shared .blume dir. If it crashed, delete .blume/dev.lock.`\n );\n process.exit(1);\n }\n throw error;\n }\n process.on(\"exit\", releaseLock);\n\n const project = await prepareProject({\n devServerUrl,\n mode: \"dev\",\n overrides,\n preview,\n root,\n strict: args.strict,\n });\n\n // A factory so the regenerate loop can recreate the server when a\n // structural (route-set) change can't be re-synced in place (see below).\n // `open` is honored on first boot only — a restart must not reopen the\n // browser.\n const createServer = (listenPort: number | undefined, open: boolean) =>\n dev({\n logLevel: args.debug ? \"debug\" : \"info\",\n root: project.context.outDir,\n server: { host: normalizeHost(args.host), open, port: listenPort },\n });\n\n let server = await createServer(explicitPort, args.open ?? false);\n\n // Vite bumps to the next free port when the default is taken, so record\n // the port the server actually bound — the lock's URL is what a refused\n // second invocation tells its caller to reuse. The site fallback baked\n // into the runtime also carries the port, so it must follow suit (below,\n // once the regeneration closure exists).\n const boundPort = boundPortOf(server, port);\n if (boundPort !== port) {\n updateDevLockPort(outDir, boundPort);\n devServerUrl = `http://localhost:${boundPort}`;\n }\n\n // Mirror any initial diagnostics into the browser overlay now the server\n // (and its HMR channel) is up.\n showBlumeErrorOverlay(project.diagnostics);\n\n let lastSignature = routeSignature(project.manifest.routes);\n\n // Watch user inputs and regenerate the runtime data on change. A body edit\n // hot-reloads via Vite (fast path). A route-set change also needs Astro's\n // content store re-synced: its glob watcher misses directory renames, so a\n // renamed page would 404 (`getEntry` reads a stale store). Astro hands the\n // integration `refreshContent` for exactly that — a full loader run\n // against the live server, after which Astro's own store watcher clears\n // the route cache and reloads the browser. Only a server that registered\n // no refresh (none since Astro 5) falls back to a cold restart: stop,\n // then bring up a fresh container whose cold sync re-globs everything.\n // perfect-debounce both debounces the watch burst (80ms) and\n // single-flights the scan: a\n // trigger during a run never starts a second run, only marks one trailing\n // rerun after the current settles. Both halves are load-bearing — a plain\n // debounce once let bursts stack overlapping scans until the heap was\n // exhausted (observed as an OOM after minutes of looping). The contract is\n // pinned by test/dev-debounce.test.ts. The task must not reject (the\n // library re-invokes it from an unhandled .finally), so the body catches\n // its own errors and always resolves.\n const regenerate = debounce(async () => {\n try {\n const next = await scanProject(root, {\n devServerUrl,\n mode: \"dev\",\n overrides,\n preview,\n });\n const nextSignature = routeSignature(next.manifest.routes);\n const structural = nextSignature !== lastSignature;\n // Generate first: the new runtime data (and any staged remote content)\n // is on disk and published before the store re-syncs against it.\n await generateRuntime(next);\n if (structural && !(await refreshBlumeContent())) {\n await server.stop();\n server = await createServer(boundPort, false);\n }\n // Commit the signature only after the (re)generation succeeded. If the\n // re-sync or restart above throws mid-sequence, the signature stays\n // stale so the next watch event retries the structural path.\n lastSignature = nextSignature;\n // Surface any content/config errors in the terminal AND the browser\n // overlay. The terminal report is not redundant: the overlay only\n // shows once the browser has connected, and it clears on the next HMR\n // update.\n reportDiagnostics(next.diagnostics, root);\n showBlumeErrorOverlay(next.diagnostics);\n } catch (error) {\n // A config error the generator raised (an unplannable `components.ts`\n // override, a missing font file) is a diagnostic: report it in the\n // terminal and the browser overlay like a scan-time error, so the fix\n // is visible where the edit happened.\n if (error instanceof BlumeError) {\n reportDiagnostics([error.diagnostic], root);\n showBlumeErrorOverlay([error.diagnostic]);\n return;\n }\n // SAFETY: regeneration failures come from the generator and Astro's\n // server API, which raise Error instances; only the message is shown.\n logger.error(`Regeneration failed: ${(error as Error).message}`);\n }\n }, 80);\n\n // The runtime prepared above baked the *requested* port into the site\n // fallback; if Vite bumped it, regenerate so OG images, canonicals, and\n // other site-gated URLs point at the port actually serving.\n if (boundPort !== port) {\n void regenerate();\n }\n\n // Content is watched per source (filesystem uses fs.watch; remote sources\n // are frozen for the session). The remaining project inputs — user pages,\n // config, theme, and component overrides — are watched directly.\n const dirTargets = [project.context.pagesRoot].filter(\n (target) => target !== null\n );\n const fileTargets = [\n project.context.configFile,\n project.context.themeFile,\n project.context.componentsFile,\n ].filter((target) => target !== null);\n\n // chokidar handles what raw fs.watch made us hand-roll: recursive\n // directory watching on every platform, and single files surviving a\n // rename-replace save (vim and most \"atomic save\" editors), which orphans\n // an inode-tracking fs.watch watcher after the first write.\n const projectWatcher = watch([...dirTargets, ...fileTargets], {\n ignoreInitial: true,\n }).on(\"all\", regenerate);\n const disposers = [\n ...project.sources.map((source) => source.watch?.(regenerate)),\n () => {\n void projectWatcher.close();\n },\n ].filter((dispose) => dispose !== undefined);\n\n const shutdown = async () => {\n for (const dispose of disposers) {\n dispose();\n }\n releaseLock();\n await server.stop();\n process.exit(0);\n };\n\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n },\n});\n"
6
6
  ],
7
- "mappings": "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",
8
- "debugId": "E6DA8A8FE27E0E6164756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "B868244539C2BD5E64756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -3,30 +3,32 @@ import {
3
3
  resolveRuntimeDir,
4
4
  resolveProjectContext,
5
5
  loadConfig
6
- } from "./chunk-v6ya5kcb.js";
7
- import"./chunk-gs7r695n.js";
6
+ } from "./chunk-xkz5xbtv.js";
7
+ import"./chunk-zccbjcj0.js";
8
8
  import {
9
9
  commandMeta,
10
10
  logger
11
11
  } from "./index.js";
12
12
  import {
13
13
  readDevLock
14
- } from "./chunk-wdrt2k2v.js";
15
- import"./chunk-hr8ne106.js";
14
+ } from "./chunk-cmtcnh9f.js";
15
+ import"./chunk-4h8z9vv5.js";
16
16
  import {
17
17
  refuseIfEjected
18
- } from "./chunk-4e9b9ra6.js";
19
- import"./chunk-xh43dwgw.js";
20
- import"./chunk-ddndchfr.js";
21
- import"./chunk-00gs3wqs.js";
18
+ } from "./chunk-py62fewh.js";
19
+ import"./chunk-zf748avv.js";
20
+ import"./chunk-2f3ndkpw.js";
21
+ import"./chunk-43zcf4gz.js";
22
+ import"./chunk-ta27feev.js";
22
23
  import"./chunk-jq5n4avg.js";
23
- import"./chunk-5r8g91qn.js";
24
- import"./chunk-fsmrqk8a.js";
25
- import"./chunk-sqw4ekg1.js";
24
+ import"./chunk-cm89scdv.js";
25
+ import"./chunk-2f7n4qzt.js";
26
+ import"./chunk-amrb6hgh.js";
26
27
  import {
27
28
  prepareProject
28
- } from "./chunk-h2ez8dzb.js";
29
- import"./chunk-mqc662a6.js";
29
+ } from "./chunk-5ffywsmb.js";
30
+ import"./chunk-cy5bm0j0.js";
31
+ import"./chunk-6bm0xpgd.js";
30
32
 
31
33
  // src/cli/commands/sync.ts
32
34
  import { rm } from "node:fs/promises";
@@ -71,5 +73,5 @@ export {
71
73
  syncCommand
72
74
  };
73
75
 
74
- //# debugId=F5C42A750ABEF23664756E2164756E21
75
- //# sourceMappingURL=chunk-w4bxdvsa.js.map
76
+ //# debugId=67B7B6A961A6206764756E2164756E21
77
+ //# sourceMappingURL=chunk-ntv4qrt7.js.map
@@ -4,7 +4,7 @@
4
4
  "sourcesContent": [
5
5
  "import { rm } from \"node:fs/promises\";\n\nimport { defineCommand } from \"citty\";\nimport { join } from \"pathe\";\n\nimport { loadConfig } from \"../../core/config.ts\";\nimport {\n resolveProjectContext,\n resolveRuntimeDir,\n} from \"../../core/project.ts\";\nimport { commandMeta } from \"../command-meta.ts\";\nimport { readDevLock } from \"../dev-lock.ts\";\nimport { refuseIfEjected } from \"../eject-scripts.ts\";\nimport { logger } from \"../log.ts\";\nimport { prepareProject } from \"../prepare.ts\";\n\nexport const syncCommand = defineCommand({\n args: {\n force: {\n description: \"Clear the source cache before refetching.\",\n type: \"boolean\",\n },\n preview: {\n description: \"Include drafts and unpublished CMS content.\",\n type: \"boolean\",\n },\n strict: { description: \"Fail on diagnostics.\", type: \"boolean\" },\n },\n meta: commandMeta.sync,\n async run({ args }) {\n const root = process.cwd();\n await refuseIfEjected(root, \"sync\");\n\n // `--force` drops the snapshots so a stale or corrupt cache can't be served;\n // scoped to `.blume/cache`, so a running dev server's runtime is untouched.\n if (args.force) {\n const { config } = await loadConfig(root);\n const context = resolveProjectContext(root, config);\n await rm(join(context.outDir, \"cache\"), { force: true, recursive: true });\n logger.info(\"Cleared source cache.\");\n }\n\n // Dev mode keeps drafts and skips the static-build gate; `refresh` forces\n // remote sources to re-fetch rather than serve their cached snapshot. A\n // running dev server hot-reloads from the regenerated runtime — so when one\n // is live, regenerate with the same site fallback (its URL) it used, else\n // its astro.config loses `site` (dropping OG and canonicals) and Astro\n // restarts cold.\n const lock = readDevLock(resolveRuntimeDir(root));\n const devServerUrl = lock?.port\n ? `http://localhost:${lock.port}`\n : undefined;\n await prepareProject({\n devServerUrl,\n mode: \"dev\",\n preview: args.preview,\n refresh: true,\n root,\n strict: args.strict,\n });\n\n logger.success(\"Synced content sources.\");\n },\n});\n"
6
6
  ],
7
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAEA;AACA;AAaO,IAAM,cAAc,cAAc;AAAA,EACvC,MAAM;AAAA,IACJ,OAAO;AAAA,MACL,aAAa;AAAA,MACb,MAAM;AAAA,IACR;AAAA,IACA,SAAS;AAAA,MACP,aAAa;AAAA,MACb,MAAM;AAAA,IACR;AAAA,IACA,QAAQ,EAAE,aAAa,wBAAwB,MAAM,UAAU;AAAA,EACjE;AAAA,EACA,MAAM,YAAY;AAAA,OACZ,IAAG,GAAG,QAAQ;AAAA,IAClB,MAAM,OAAO,QAAQ,IAAI;AAAA,IACzB,MAAM,gBAAgB,MAAM,MAAM;AAAA,IAIlC,IAAI,KAAK,OAAO;AAAA,MACd,QAAQ,WAAW,MAAM,WAAW,IAAI;AAAA,MACxC,MAAM,UAAU,sBAAsB,MAAM,MAAM;AAAA,MAClD,MAAM,GAAG,KAAK,QAAQ,QAAQ,OAAO,GAAG,EAAE,OAAO,MAAM,WAAW,KAAK,CAAC;AAAA,MACxE,OAAO,KAAK,uBAAuB;AAAA,IACrC;AAAA,IAQA,MAAM,OAAO,YAAY,kBAAkB,IAAI,CAAC;AAAA,IAChD,MAAM,eAAe,MAAM,OACvB,oBAAoB,KAAK,SACzB;AAAA,IACJ,MAAM,eAAe;AAAA,MACnB;AAAA,MACA,MAAM;AAAA,MACN,SAAS,KAAK;AAAA,MACd,SAAS;AAAA,MACT;AAAA,MACA,QAAQ,KAAK;AAAA,IACf,CAAC;AAAA,IAED,OAAO,QAAQ,yBAAyB;AAAA;AAE5C,CAAC;",
8
- "debugId": "F5C42A750ABEF23664756E2164756E21",
7
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAEA;AACA;AAaO,IAAM,cAAc,cAAc;AAAA,EACvC,MAAM;AAAA,IACJ,OAAO;AAAA,MACL,aAAa;AAAA,MACb,MAAM;AAAA,IACR;AAAA,IACA,SAAS;AAAA,MACP,aAAa;AAAA,MACb,MAAM;AAAA,IACR;AAAA,IACA,QAAQ,EAAE,aAAa,wBAAwB,MAAM,UAAU;AAAA,EACjE;AAAA,EACA,MAAM,YAAY;AAAA,OACZ,IAAG,GAAG,QAAQ;AAAA,IAClB,MAAM,OAAO,QAAQ,IAAI;AAAA,IACzB,MAAM,gBAAgB,MAAM,MAAM;AAAA,IAIlC,IAAI,KAAK,OAAO;AAAA,MACd,QAAQ,WAAW,MAAM,WAAW,IAAI;AAAA,MACxC,MAAM,UAAU,sBAAsB,MAAM,MAAM;AAAA,MAClD,MAAM,GAAG,KAAK,QAAQ,QAAQ,OAAO,GAAG,EAAE,OAAO,MAAM,WAAW,KAAK,CAAC;AAAA,MACxE,OAAO,KAAK,uBAAuB;AAAA,IACrC;AAAA,IAQA,MAAM,OAAO,YAAY,kBAAkB,IAAI,CAAC;AAAA,IAChD,MAAM,eAAe,MAAM,OACvB,oBAAoB,KAAK,SACzB;AAAA,IACJ,MAAM,eAAe;AAAA,MACnB;AAAA,MACA,MAAM;AAAA,MACN,SAAS,KAAK;AAAA,MACd,SAAS;AAAA,MACT;AAAA,MACA,QAAQ,KAAK;AAAA,IACf,CAAC;AAAA,IAED,OAAO,QAAQ,yBAAyB;AAAA;AAE5C,CAAC;",
8
+ "debugId": "67B7B6A961A6206764756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -10,13 +10,13 @@ import {
10
10
  import {
11
11
  AGENTS,
12
12
  launchInstalledAgent
13
- } from "./chunk-6k4ftwze.js";
14
- import"./chunk-00gs3wqs.js";
13
+ } from "./chunk-0gz36akr.js";
14
+ import"./chunk-ta27feev.js";
15
15
  import {
16
16
  commandsFor,
17
17
  detectProjectPackageManager
18
- } from "./chunk-v6ya5kcb.js";
19
- import"./chunk-gs7r695n.js";
18
+ } from "./chunk-xkz5xbtv.js";
19
+ import"./chunk-zccbjcj0.js";
20
20
  import {
21
21
  UPGRADE_GUIDE_URL,
22
22
  UPGRADE_GUIDE_FILE,
@@ -25,10 +25,10 @@ import {
25
25
  isOutsideBlumeProject,
26
26
  collectUpgradeFindings,
27
27
  upgradePrompt
28
- } from "./chunk-qkb5a8sa.js";
28
+ } from "./chunk-g2z9x01v.js";
29
29
  import {
30
30
  installDependencies
31
- } from "./chunk-h7k3nq3v.js";
31
+ } from "./chunk-gp84za0h.js";
32
32
 
33
33
  // src/cli/commands/upgrade.ts
34
34
  import { defineCommand } from "citty";
@@ -138,4 +138,4 @@ export {
138
138
  };
139
139
 
140
140
  //# debugId=38BC7BC8832D718964756E2164756E21
141
- //# sourceMappingURL=chunk-bfwp9vp6.js.map
141
+ //# sourceMappingURL=chunk-p804f3pe.js.map
@@ -2,14 +2,14 @@
2
2
  import {
3
3
  commandsFor,
4
4
  detectProjectPackageManager
5
- } from "./chunk-v6ya5kcb.js";
5
+ } from "./chunk-xkz5xbtv.js";
6
+ import {
7
+ EJECTED_CONFIG_HEADER
8
+ } from "./chunk-4h8z9vv5.js";
6
9
  import {
7
10
  packageRoot,
8
11
  logger
9
12
  } from "./index.js";
10
- import {
11
- EJECTED_CONFIG_HEADER
12
- } from "./chunk-hr8ne106.js";
13
13
 
14
14
  // src/cli/eject-scripts.ts
15
15
  import { existsSync, readFileSync } from "node:fs";
@@ -85,5 +85,5 @@ var refuseIfEjected = async (root, command) => {
85
85
 
86
86
  export { updatePackageScripts, isEjectedProject, refuseIfEjected };
87
87
 
88
- //# debugId=F07EB9DD3957B57764756E2164756E21
89
- //# sourceMappingURL=chunk-4e9b9ra6.js.map
88
+ //# debugId=BFC7CE556CF94E8564756E2164756E21
89
+ //# sourceMappingURL=chunk-py62fewh.js.map
@@ -5,6 +5,6 @@
5
5
  "import { existsSync, readFileSync } from \"node:fs\";\nimport { readFile, writeFile } from \"node:fs/promises\";\n\nimport { join } from \"pathe\";\n\nimport { EJECTED_CONFIG_HEADER } from \"../astro/templates.ts\";\nimport { packageRoot } from \"../core/package-root.ts\";\nimport { commandsFor, detectProjectPackageManager } from \"./init/scaffold.ts\";\nimport type { PackageManager } from \"./init/scaffold.ts\";\nimport { logger } from \"./log.ts\";\n\n/** A JSON value, as `JSON.parse` of a manifest can return. */\ntype JsonValue =\n | string\n | number\n | boolean\n | null\n | JsonValue[]\n | { [key: string]: JsonValue };\n\n/** The slice of package.json the rewrite touches; the rest rides along. */\ninterface PackageManifest {\n [key: string]: JsonValue | undefined;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n optionalDependencies?: Record<string, string>;\n peerDependencies?: Record<string, string>;\n scripts?: Record<string, string>;\n}\n\n/** Package name → the semver range to depend on it at. */\nexport interface DependencyRanges {\n [name: string]: string;\n}\n\n/**\n * The version range Blume itself uses for each package it depends on or\n * accepts as a peer, plus `blume` at the installed version — what an ejected\n * app should pin so it keeps building against the same majors.\n */\nexport const blumeDependencyRanges = (): DependencyRanges => {\n // SAFETY: blume's own package.json, which declares its version and both\n // dependency maps; nothing else is read.\n const manifest = JSON.parse(\n readFileSync(join(packageRoot(), \"package.json\"), \"utf-8\")\n ) as {\n dependencies: Record<string, string>;\n peerDependencies: Record<string, string>;\n version: string;\n };\n return {\n ...manifest.peerDependencies,\n ...manifest.dependencies,\n blume: `^${manifest.version}`,\n };\n};\n\n/** Whether the manifest already lists `name` in any dependency field. */\nconst declares = (pkg: PackageManifest, name: string): boolean =>\n [\n pkg.dependencies,\n pkg.devDependencies,\n pkg.optionalDependencies,\n pkg.peerDependencies,\n ].some((field) => field !== undefined && Object.hasOwn(field, name));\n\n/**\n * Point the project's package.json at the ejected app. Its scripts run Astro\n * directly: after an eject the Blume CLI no longer manages the runtime, so\n * scaffolded scripts like `\"dev\": \"blume dev\"` would rebuild the removed\n * `.blume` tree instead of serving the ejected app. And every package the\n * ejected app imports by bare name (`dependencies`, from `eject()`) that the\n * project doesn't list yet becomes a dependency at the range Blume itself\n * uses (`ranges`).\n *\n * Returns the names it added, so the caller can ask for an install. A missing\n * or unreadable package.json is left alone.\n */\nexport const updatePackageScripts = async (\n root: string,\n dependencies: string[] = [],\n ranges: DependencyRanges = blumeDependencyRanges()\n): Promise<string[]> => {\n const pkgPath = join(root, \"package.json\");\n let pkg: PackageManifest;\n try {\n pkg = JSON.parse(await readFile(pkgPath, \"utf-8\"));\n } catch {\n return [];\n }\n const scripts = pkg.scripts ?? {};\n pkg.scripts = {\n ...scripts,\n build: \"astro build\",\n dev: \"astro dev\",\n preview: \"astro preview\",\n };\n const added = dependencies.filter((name) => !declares(pkg, name));\n if (added.length > 0) {\n // Sorted, the way package managers write the field.\n pkg.dependencies = Object.fromEntries(\n Object.entries({\n ...pkg.dependencies,\n ...Object.fromEntries(added.map((name) => [name, ranges[name] ?? \"*\"])),\n }).toSorted(([a], [b]) => (a < b ? -1 : 1))\n );\n }\n await writeFile(pkgPath, `${JSON.stringify(pkg, null, 2)}\\n`, \"utf-8\");\n return added;\n};\n\n/**\n * The first line Blume 1's `blume eject` wrote into the ejected\n * `astro.config.mjs` — the hidden runtime's own header, carried over. Blume 2's\n * hidden runtime keeps it under `.blume/`, never at the project root, so a root\n * config that opens with it is an app Blume 1 ejected.\n */\nconst BLUME_1_EJECTED_CONFIG_HEADER =\n \"// Generated by Blume. Do not edit; this file is recreated on each run.\";\n\n/**\n * Whether `root` holds an app `blume eject` already wrote: a root\n * `astro.config.mjs` whose first line is eject's header, or the header Blume 1\n * ejected with. The header is the only signal: a Blume project may keep its own\n * `astro.config.mjs` and a codegen `src/generated/` folder beside its content,\n * and neither makes it an ejected app.\n */\nexport const isEjectedProject = (root: string): boolean => {\n const config = join(root, \"astro.config.mjs\");\n if (!existsSync(config)) {\n return false;\n }\n const source = readFileSync(config, \"utf-8\");\n return (\n source.startsWith(EJECTED_CONFIG_HEADER) ||\n source.startsWith(BLUME_1_EJECTED_CONFIG_HEADER)\n );\n};\n\n/** The Blume commands that run the hidden `.blume/` copy of the site. */\nexport type RuntimeCommand = \"build\" | \"check\" | \"dev\" | \"preview\" | \"sync\";\n\n/**\n * What an ejected app runs in place of each {@link RuntimeCommand}: its own\n * `dev`/`build`/`preview` scripts (eject writes them), or Astro's CLI for the\n * check and the content sync.\n */\nconst ejectedEquivalent = (\n pm: PackageManager,\n command: RuntimeCommand\n): string => {\n const { build, dev, exec } = commandsFor(pm);\n return {\n build,\n check: `${exec} astro check`,\n dev,\n // Spelled like `dev`: npm runs a custom script only through `run`.\n preview: pm === \"npm\" ? \"npm run preview\" : `${pm} preview`,\n sync: `${exec} astro sync`,\n }[command];\n};\n\n/**\n * Stop a command that works on the hidden runtime in an ejected app. `dev`,\n * `build`, `check`, and `sync` would regenerate `.blume/` from\n * `blume.config.ts` and run that hidden copy, ignoring every edit made to the\n * app since eject, and `preview` would look for that copy's build; point at\n * the app's own command under the project's package manager instead.\n */\nexport const refuseIfEjected = async (\n root: string,\n command: RuntimeCommand\n): Promise<void> => {\n if (!isEjectedProject(root)) {\n return;\n }\n const pm = await detectProjectPackageManager(root);\n logger.error(\n `This project was ejected to a standalone Astro app, so \\`blume ${command}\\` would run a regenerated copy of the site instead of it. Run \\`${ejectedEquivalent(pm, command)}\\` instead.`\n );\n process.exit(1);\n};\n"
6
6
  ],
7
7
  "mappings": ";;;;;;;;;;;;;;AAAA;AACA;AAEA;AAqCO,IAAM,wBAAwB,MAAwB;AAAA,EAG3D,MAAM,WAAW,KAAK,MACpB,aAAa,KAAK,YAAY,GAAG,cAAc,GAAG,OAAO,CAC3D;AAAA,EAKA,OAAO;AAAA,OACF,SAAS;AAAA,OACT,SAAS;AAAA,IACZ,OAAO,IAAI,SAAS;AAAA,EACtB;AAAA;AAIF,IAAM,WAAW,CAAC,KAAsB,SACtC;AAAA,EACE,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN,EAAE,KAAK,CAAC,UAAU,UAAU,aAAa,OAAO,OAAO,OAAO,IAAI,CAAC;AAc9D,IAAM,uBAAuB,OAClC,MACA,eAAyB,CAAC,GAC1B,SAA2B,sBAAsB,MAC3B;AAAA,EACtB,MAAM,UAAU,KAAK,MAAM,cAAc;AAAA,EACzC,IAAI;AAAA,EACJ,IAAI;AAAA,IACF,MAAM,KAAK,MAAM,MAAM,SAAS,SAAS,OAAO,CAAC;AAAA,IACjD,MAAM;AAAA,IACN,OAAO,CAAC;AAAA;AAAA,EAEV,MAAM,UAAU,IAAI,WAAW,CAAC;AAAA,EAChC,IAAI,UAAU;AAAA,OACT;AAAA,IACH,OAAO;AAAA,IACP,KAAK;AAAA,IACL,SAAS;AAAA,EACX;AAAA,EACA,MAAM,QAAQ,aAAa,OAAO,CAAC,SAAS,CAAC,SAAS,KAAK,IAAI,CAAC;AAAA,EAChE,IAAI,MAAM,SAAS,GAAG;AAAA,IAEpB,IAAI,eAAe,OAAO,YACxB,OAAO,QAAQ;AAAA,SACV,IAAI;AAAA,SACJ,OAAO,YAAY,MAAM,IAAI,CAAC,SAAS,CAAC,MAAM,OAAO,SAAS,GAAG,CAAC,CAAC;AAAA,IACxE,CAAC,EAAE,SAAS,EAAE,KAAK,OAAQ,IAAI,IAAI,KAAK,CAAE,CAC5C;AAAA,EACF;AAAA,EACA,MAAM,UAAU,SAAS,GAAG,KAAK,UAAU,KAAK,MAAM,CAAC;AAAA,GAAO,OAAO;AAAA,EACrE,OAAO;AAAA;AAST,IAAM,gCACJ;AASK,IAAM,mBAAmB,CAAC,SAA0B;AAAA,EACzD,MAAM,SAAS,KAAK,MAAM,kBAAkB;AAAA,EAC5C,IAAI,CAAC,WAAW,MAAM,GAAG;AAAA,IACvB,OAAO;AAAA,EACT;AAAA,EACA,MAAM,SAAS,aAAa,QAAQ,OAAO;AAAA,EAC3C,OACE,OAAO,WAAW,qBAAqB,KACvC,OAAO,WAAW,6BAA6B;AAAA;AAYnD,IAAM,oBAAoB,CACxB,IACA,YACW;AAAA,EACX,QAAQ,OAAO,KAAK,SAAS,YAAY,EAAE;AAAA,EAC3C,OAAO;AAAA,IACL;AAAA,IACA,OAAO,GAAG;AAAA,IACV;AAAA,IAEA,SAAS,OAAO,QAAQ,oBAAoB,GAAG;AAAA,IAC/C,MAAM,GAAG;AAAA,EACX,EAAE;AAAA;AAUG,IAAM,kBAAkB,OAC7B,MACA,YACkB;AAAA,EAClB,IAAI,CAAC,iBAAiB,IAAI,GAAG;AAAA,IAC3B;AAAA,EACF;AAAA,EACA,MAAM,KAAK,MAAM,4BAA4B,IAAI;AAAA,EACjD,OAAO,MACL,kEAAkE,2EAA2E,kBAAkB,IAAI,OAAO,cAC5K;AAAA,EACA,QAAQ,KAAK,CAAC;AAAA;",
8
- "debugId": "F07EB9DD3957B57764756E2164756E21",
8
+ "debugId": "BFC7CE556CF94E8564756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -0,0 +1,126 @@
1
+ #!/usr/bin/env node
2
+ import"./chunk-xkz5xbtv.js";
3
+ import"./chunk-zccbjcj0.js";
4
+ import {
5
+ packageRoot,
6
+ getBlumeVersion,
7
+ commandMeta,
8
+ reportInternalError,
9
+ BlumeError,
10
+ logger,
11
+ reportDiagnostics
12
+ } from "./index.js";
13
+ import {
14
+ AGENTS,
15
+ launchInstalledAgent
16
+ } from "./chunk-0gz36akr.js";
17
+ import {
18
+ scanProject
19
+ } from "./chunk-43zcf4gz.js";
20
+ import {
21
+ siteSkillName
22
+ } from "./chunk-6bm0xpgd.js";
23
+
24
+ // src/cli/commands/skill.ts
25
+ import { defineCommand } from "citty";
26
+ import { join as join2 } from "pathe";
27
+
28
+ // src/ai/write-skill.ts
29
+ import { existsSync } from "node:fs";
30
+ import { join, relative, resolve } from "pathe";
31
+ var WRITE_SKILL_DIR = join("skills", "blume-write-skill");
32
+ var DEFAULT_SKILLS_DIR = "skills";
33
+ var planSkill = (project) => {
34
+ const { config, context } = project;
35
+ const name = siteSkillName(project);
36
+ const file = resolve(context.root, config.agents.skills ?? DEFAULT_SKILLS_DIR, name, "SKILL.md");
37
+ const plan = {
38
+ configFile: context.configFile ? relative(context.root, context.configFile) : "blume.config.ts",
39
+ contentRoot: relative(context.root, context.contentRoot) || ".",
40
+ exists: existsSync(file),
41
+ file: relative(context.root, file),
42
+ name,
43
+ site: config.deployment.options.site,
44
+ title: config.title
45
+ };
46
+ return config.agents.skills ? plan : { ...plan, configure: `./${DEFAULT_SKILLS_DIR}` };
47
+ };
48
+ var writeSkillPrompt = (plan, options) => {
49
+ const { skillDir, version } = options;
50
+ const lines = [
51
+ `Write the agent skill for the ${plan.title} docs, a Blume ${version} site.`,
52
+ "",
53
+ `Follow the blume-write-skill skill: read ${join(skillDir, "SKILL.md")} first and work through its workflow.`,
54
+ "",
55
+ plan.exists ? `A skill already exists at ${plan.file}. Update it against the current docs rather than starting over, and keep what's still true.` : `Write it to ${plan.file}.`,
56
+ `Its frontmatter \`name\` must be \`${plan.name}\`: that's the name of the skill Blume generates for this site, and a skill with the same name replaces it.`
57
+ ];
58
+ if (plan.configure) {
59
+ lines.push(`Then set \`agents.skills: "${plan.configure}"\` in ${plan.configFile} so the build publishes it.`);
60
+ }
61
+ lines.push("", `The docs source is in ${plan.contentRoot}.`, plan.site ? `The site is served at ${plan.site}, so link pages as ${plan.site.replace(/\/$/u, "")}<route>.md.` : `The config has no \`deployment.site\`, and the skill's links must be absolute. Ask me for the site's URL, and set it as \`deployment.site\` in ${plan.configFile}.`);
62
+ return lines.join(`
63
+ `);
64
+ };
65
+
66
+ // src/cli/commands/skill.ts
67
+ var skillCommand = defineCommand({
68
+ args: {
69
+ claude: {
70
+ description: "Write the skill with Claude Code.",
71
+ type: "boolean"
72
+ },
73
+ codex: {
74
+ description: "Write the skill with Codex.",
75
+ type: "boolean"
76
+ }
77
+ },
78
+ meta: commandMeta.skill,
79
+ async run({ args }) {
80
+ const root = process.cwd();
81
+ const agents = Object.keys(AGENTS).filter((kind) => args[kind]);
82
+ if (agents.length > 1) {
83
+ logger.error("Pass at most one of --codex or --claude.");
84
+ process.exit(1);
85
+ }
86
+ const [agent] = agents;
87
+ try {
88
+ const plan = planSkill(await scanProject(root, { mode: "build" }));
89
+ const skillDir = join2(packageRoot(), WRITE_SKILL_DIR);
90
+ process.stderr.write(` ${plan.exists ? "Updating" : "Writing"} the "${plan.name}" skill at ${plan.file}.
91
+ `);
92
+ if (!agent) {
93
+ process.stderr.write(` blume skill writes it with a coding agent: rerun with --codex or --claude.
94
+ Using another agent? Point it at ${join2(skillDir, "SKILL.md")},
95
+ or install the skill where your agent looks for skills: npx skills add haydenbleasel/blume --skill blume-write-skill
96
+ `);
97
+ return;
98
+ }
99
+ const cli = AGENTS[agent];
100
+ process.stderr.write(` Handing it to ${cli.name}…
101
+
102
+ `);
103
+ const code = await launchInstalledAgent(cli.bin, writeSkillPrompt(plan, { skillDir, version: getBlumeVersion() }));
104
+ if (code === null) {
105
+ logger.error(`${cli.name} (\`${cli.bin}\`) was not found on PATH. Install it with \`${cli.install}\`.`);
106
+ process.exit(1);
107
+ }
108
+ if (code !== 0) {
109
+ process.exit(code);
110
+ }
111
+ } catch (error) {
112
+ if (error instanceof BlumeError) {
113
+ reportDiagnostics([error.diagnostic], root);
114
+ process.exit(1);
115
+ }
116
+ reportInternalError(error);
117
+ process.exit(1);
118
+ }
119
+ }
120
+ });
121
+ export {
122
+ skillCommand
123
+ };
124
+
125
+ //# debugId=3CB1C251215B1BE964756E2164756E21
126
+ //# sourceMappingURL=chunk-q3wxxq39.js.map
@@ -0,0 +1,11 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/cli/commands/skill.ts", "../src/ai/write-skill.ts"],
4
+ "sourcesContent": [
5
+ "import { defineCommand } from \"citty\";\nimport { join } from \"pathe\";\n\nimport {\n planSkill,\n WRITE_SKILL_DIR,\n writeSkillPrompt,\n} from \"../../ai/write-skill.ts\";\nimport { AGENTS, launchInstalledAgent } from \"../../audit/agent.ts\";\nimport type { AgentKind } from \"../../audit/agent.ts\";\nimport { BlumeError } from \"../../core/diagnostics.ts\";\nimport { packageRoot } from \"../../core/package-root.ts\";\nimport { scanProject } from \"../../core/project-graph.ts\";\nimport { getBlumeVersion } from \"../../core/version.ts\";\nimport { commandMeta } from \"../command-meta.ts\";\nimport { reportInternalError } from \"../internal-error.ts\";\nimport { logger, reportDiagnostics } from \"../log.ts\";\n\n/**\n * `blume skill` — write the docs site's agent skill with a coding agent. Every\n * build publishes a generated skill at `/skill.md` (a map of the docs); this\n * opens Claude Code or Codex on the `blume-write-skill` skill bundled in this\n * package to write the richer one, grounded in the docs, under the same name\n * so it takes the generated one's place. The judgment stays in the skill; the\n * command is the front door, like `blume migrate`. Status lines go straight to\n * stderr: consola drops info-level lines in test and CI environments.\n */\nexport const skillCommand = defineCommand({\n args: {\n claude: {\n description: \"Write the skill with Claude Code.\",\n type: \"boolean\",\n },\n codex: {\n description: \"Write the skill with Codex.\",\n type: \"boolean\",\n },\n },\n meta: commandMeta.skill,\n async run({ args }) {\n const root = process.cwd();\n // SAFETY: AGENTS is a closed record keyed by AgentKind, so its keys are\n // exactly the agent kinds.\n const agents = (Object.keys(AGENTS) as AgentKind[]).filter(\n (kind) => args[kind]\n );\n if (agents.length > 1) {\n logger.error(\"Pass at most one of --codex or --claude.\");\n process.exit(1);\n }\n const [agent] = agents;\n\n try {\n // A scan, not `prepareProject`: the agent reads the content tree and\n // the runtime isn't touched, so a running dev server is left alone.\n const plan = planSkill(await scanProject(root, { mode: \"build\" }));\n const skillDir = join(packageRoot(), WRITE_SKILL_DIR);\n process.stderr.write(\n ` ${plan.exists ? \"Updating\" : \"Writing\"} the \"${plan.name}\" skill at ${plan.file}.\\n`\n );\n\n // Without an agent flag the command is the pointer for any other agent:\n // the bundled skill's path, and the install line that puts the skill\n // where agents look for it.\n if (!agent) {\n process.stderr.write(\n ` blume skill writes it with a coding agent: rerun with --codex or --claude.\\n Using another agent? Point it at ${join(skillDir, \"SKILL.md\")},\\n or install the skill where your agent looks for skills: npx skills add haydenbleasel/blume --skill blume-write-skill\\n`\n );\n return;\n }\n\n const cli = AGENTS[agent];\n process.stderr.write(` Handing it to ${cli.name}…\\n\\n`);\n const code = await launchInstalledAgent(\n cli.bin,\n writeSkillPrompt(plan, { skillDir, version: getBlumeVersion() })\n );\n if (code === null) {\n logger.error(\n `${cli.name} (\\`${cli.bin}\\`) was not found on PATH. Install it with \\`${cli.install}\\`.`\n );\n process.exit(1);\n }\n if (code !== 0) {\n process.exit(code);\n }\n } catch (error) {\n if (error instanceof BlumeError) {\n reportDiagnostics([error.diagnostic], root);\n process.exit(1);\n }\n reportInternalError(error);\n process.exit(1);\n }\n },\n});\n",
6
+ "import { existsSync } from \"node:fs\";\n\nimport { join, relative, resolve } from \"pathe\";\n\nimport type { BlumeProject } from \"../core/project-graph.ts\";\nimport { siteSkillName } from \"./site-skill.ts\";\n\n/**\n * `blume skill`'s logic, kept out of the command module so it runs (and is\n * covered) in-process. Writing a product skill is judgment work — what the\n * product is, which tasks matter, where it bites — so it lives in the\n * `blume-write-skill` skill, shipped inside the package. This module only\n * works out where the skill goes and writes the prompt that points a coding\n * agent at the skill and the docs.\n */\n\n/** The skill's directory inside the published package. */\nexport const WRITE_SKILL_DIR = join(\"skills\", \"blume-write-skill\");\n\n/** Where `agents.skills` points when the config doesn't set it. */\nconst DEFAULT_SKILLS_DIR = \"skills\";\n\n/** Where the skill goes, and what the agent needs to know to write it. */\nexport interface SkillPlan {\n /** The `agents.skills` value to add, when the config has none. */\n configure?: string;\n /** The config file to add it to, relative to the project root. */\n configFile: string;\n /** The content root, relative to the project root. */\n contentRoot: string;\n /** Whether a skill is already there to update. */\n exists: boolean;\n /** Where to write the skill, relative to the project root. */\n file: string;\n /** The skill's name: the generated site skill's, so it replaces it. */\n name: string;\n /** The site's URL, for the skill's absolute links. */\n site?: string;\n title: string;\n}\n\n/** Plan the skill for a scanned project. */\nexport const planSkill = (project: BlumeProject): SkillPlan => {\n const { config, context } = project;\n const name = siteSkillName(project);\n const file = resolve(\n context.root,\n config.agents.skills ?? DEFAULT_SKILLS_DIR,\n name,\n \"SKILL.md\"\n );\n const plan: SkillPlan = {\n configFile: context.configFile\n ? relative(context.root, context.configFile)\n : \"blume.config.ts\",\n contentRoot: relative(context.root, context.contentRoot) || \".\",\n exists: existsSync(file),\n file: relative(context.root, file),\n name,\n site: config.deployment.options.site,\n title: config.title,\n };\n return config.agents.skills\n ? plan\n : { ...plan, configure: `./${DEFAULT_SKILLS_DIR}` };\n};\n\n/** The prompt that hands the plan to a coding agent. */\nexport const writeSkillPrompt = (\n plan: SkillPlan,\n options: { skillDir: string; version: string }\n): string => {\n const { skillDir, version } = options;\n const lines = [\n `Write the agent skill for the ${plan.title} docs, a Blume ${version} site.`,\n \"\",\n `Follow the blume-write-skill skill: read ${join(skillDir, \"SKILL.md\")} first and work through its workflow.`,\n \"\",\n plan.exists\n ? `A skill already exists at ${plan.file}. Update it against the current docs rather than starting over, and keep what's still true.`\n : `Write it to ${plan.file}.`,\n `Its frontmatter \\`name\\` must be \\`${plan.name}\\`: that's the name of the skill Blume generates for this site, and a skill with the same name replaces it.`,\n ];\n if (plan.configure) {\n lines.push(\n `Then set \\`agents.skills: \"${plan.configure}\"\\` in ${plan.configFile} so the build publishes it.`\n );\n }\n lines.push(\n \"\",\n `The docs source is in ${plan.contentRoot}.`,\n plan.site\n ? `The site is served at ${plan.site}, so link pages as ${plan.site.replace(/\\/$/u, \"\")}<route>.md.`\n : `The config has no \\`deployment.site\\`, and the skill's links must be absolute. Ask me for the site's URL, and set it as \\`deployment.site\\` in ${plan.configFile}.`\n );\n return lines.join(\"\\n\");\n};\n"
7
+ ],
8
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;AAAA;AACA,iBAAS;;;ACDT;AAEA;AAeO,IAAM,kBAAkB,KAAK,UAAU,mBAAmB;AAGjE,IAAM,qBAAqB;AAsBpB,IAAM,YAAY,CAAC,YAAqC;AAAA,EAC7D,QAAQ,QAAQ,YAAY;AAAA,EAC5B,MAAM,OAAO,cAAc,OAAO;AAAA,EAClC,MAAM,OAAO,QACX,QAAQ,MACR,OAAO,OAAO,UAAU,oBACxB,MACA,UACF;AAAA,EACA,MAAM,OAAkB;AAAA,IACtB,YAAY,QAAQ,aAChB,SAAS,QAAQ,MAAM,QAAQ,UAAU,IACzC;AAAA,IACJ,aAAa,SAAS,QAAQ,MAAM,QAAQ,WAAW,KAAK;AAAA,IAC5D,QAAQ,WAAW,IAAI;AAAA,IACvB,MAAM,SAAS,QAAQ,MAAM,IAAI;AAAA,IACjC;AAAA,IACA,MAAM,OAAO,WAAW,QAAQ;AAAA,IAChC,OAAO,OAAO;AAAA,EAChB;AAAA,EACA,OAAO,OAAO,OAAO,SACjB,OACA,KAAK,MAAM,WAAW,KAAK,qBAAqB;AAAA;AAI/C,IAAM,mBAAmB,CAC9B,MACA,YACW;AAAA,EACX,QAAQ,UAAU,YAAY;AAAA,EAC9B,MAAM,QAAQ;AAAA,IACZ,iCAAiC,KAAK,uBAAuB;AAAA,IAC7D;AAAA,IACA,4CAA4C,KAAK,UAAU,UAAU;AAAA,IACrE;AAAA,IACA,KAAK,SACD,6BAA6B,KAAK,oGAClC,eAAe,KAAK;AAAA,IACxB,sCAAsC,KAAK;AAAA,EAC7C;AAAA,EACA,IAAI,KAAK,WAAW;AAAA,IAClB,MAAM,KACJ,8BAA8B,KAAK,mBAAmB,KAAK,uCAC7D;AAAA,EACF;AAAA,EACA,MAAM,KACJ,IACA,yBAAyB,KAAK,gBAC9B,KAAK,OACD,yBAAyB,KAAK,0BAA0B,KAAK,KAAK,QAAQ,QAAQ,EAAE,iBACpF,kJAAkJ,KAAK,aAC7J;AAAA,EACA,OAAO,MAAM,KAAK;AAAA,CAAI;AAAA;;;ADpEjB,IAAM,eAAe,cAAc;AAAA,EACxC,MAAM;AAAA,IACJ,QAAQ;AAAA,MACN,aAAa;AAAA,MACb,MAAM;AAAA,IACR;AAAA,IACA,OAAO;AAAA,MACL,aAAa;AAAA,MACb,MAAM;AAAA,IACR;AAAA,EACF;AAAA,EACA,MAAM,YAAY;AAAA,OACZ,IAAG,GAAG,QAAQ;AAAA,IAClB,MAAM,OAAO,QAAQ,IAAI;AAAA,IAGzB,MAAM,SAAU,OAAO,KAAK,MAAM,EAAkB,OAClD,CAAC,SAAS,KAAK,KACjB;AAAA,IACA,IAAI,OAAO,SAAS,GAAG;AAAA,MACrB,OAAO,MAAM,0CAA0C;AAAA,MACvD,QAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,IACA,OAAO,SAAS;AAAA,IAEhB,IAAI;AAAA,MAGF,MAAM,OAAO,UAAU,MAAM,YAAY,MAAM,EAAE,MAAM,QAAQ,CAAC,CAAC;AAAA,MACjE,MAAM,WAAW,MAAK,YAAY,GAAG,eAAe;AAAA,MACpD,QAAQ,OAAO,MACb,KAAK,KAAK,SAAS,aAAa,kBAAkB,KAAK,kBAAkB,KAAK;AAAA,CAChF;AAAA,MAKA,IAAI,CAAC,OAAO;AAAA,QACV,QAAQ,OAAO,MACb;AAAA,qCAAoH,MAAK,UAAU,UAAU;AAAA;AAAA,CAC/I;AAAA,QACA;AAAA,MACF;AAAA,MAEA,MAAM,MAAM,OAAO;AAAA,MACnB,QAAQ,OAAO,MAAM,mBAAmB,IAAI;AAAA;AAAA,CAAW;AAAA,MACvD,MAAM,OAAO,MAAM,qBACjB,IAAI,KACJ,iBAAiB,MAAM,EAAE,UAAU,SAAS,gBAAgB,EAAE,CAAC,CACjE;AAAA,MACA,IAAI,SAAS,MAAM;AAAA,QACjB,OAAO,MACL,GAAG,IAAI,WAAW,IAAI,mDAAmD,IAAI,YAC/E;AAAA,QACA,QAAQ,KAAK,CAAC;AAAA,MAChB;AAAA,MACA,IAAI,SAAS,GAAG;AAAA,QACd,QAAQ,KAAK,IAAI;AAAA,MACnB;AAAA,MACA,OAAO,OAAO;AAAA,MACd,IAAI,iBAAiB,YAAY;AAAA,QAC/B,kBAAkB,CAAC,MAAM,UAAU,GAAG,IAAI;AAAA,QAC1C,QAAQ,KAAK,CAAC;AAAA,MAChB;AAAA,MACA,oBAAoB,KAAK;AAAA,MACzB,QAAQ,KAAK,CAAC;AAAA;AAAA;AAGpB,CAAC;",
9
+ "debugId": "3CB1C251215B1BE964756E2164756E21",
10
+ "names": []
11
+ }