blume 1.7.3 → 2.0.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 (673) hide show
  1. package/AGENTS.md +19 -0
  2. package/CHANGELOG.md +217 -0
  3. package/README.md +34 -21
  4. package/dist/cli/chunk-11j0384y.js +148 -0
  5. package/dist/cli/chunk-11j0384y.js.map +10 -0
  6. package/dist/cli/{chunk-rqy0s5wh.js → chunk-1w8dp3qb.js} +17 -16
  7. package/dist/cli/{chunk-rqy0s5wh.js.map → chunk-1w8dp3qb.js.map} +3 -3
  8. package/dist/cli/chunk-2q1dwty4.js +75 -0
  9. package/dist/cli/chunk-2q1dwty4.js.map +11 -0
  10. package/dist/cli/chunk-41za066z.js +122 -0
  11. package/dist/cli/chunk-41za066z.js.map +11 -0
  12. package/dist/cli/chunk-5a2z0198.js +133 -0
  13. package/dist/cli/chunk-5a2z0198.js.map +10 -0
  14. package/dist/cli/{chunk-5g0w1e2c.js → chunk-6k8vp3ta.js} +25 -13
  15. package/dist/cli/{chunk-5g0w1e2c.js.map → chunk-6k8vp3ta.js.map} +4 -4
  16. package/dist/cli/{chunk-5qk08vmp.js → chunk-79njf86q.js} +133 -54
  17. package/dist/cli/chunk-79njf86q.js.map +11 -0
  18. package/dist/cli/{chunk-e7f42gdj.js → chunk-7ez8ny0t.js} +2 -2
  19. package/dist/cli/{chunk-nn13znc2.js → chunk-88cpgt6h.js} +1 -1
  20. package/dist/cli/chunk-a9kptbw5.js +361 -0
  21. package/dist/cli/chunk-a9kptbw5.js.map +14 -0
  22. package/dist/cli/chunk-abh8yjkn.js +31 -0
  23. package/dist/cli/chunk-abh8yjkn.js.map +10 -0
  24. package/dist/cli/chunk-b5aj94ah.js +91 -0
  25. package/dist/cli/chunk-b5aj94ah.js.map +10 -0
  26. package/dist/cli/{chunk-b27xqwn9.js → chunk-bctazmbk.js} +9 -5
  27. package/dist/cli/chunk-bctazmbk.js.map +10 -0
  28. package/dist/cli/chunk-beat36xx.js +279 -0
  29. package/dist/cli/chunk-beat36xx.js.map +10 -0
  30. package/dist/cli/chunk-bnbmcwfb.js +145 -0
  31. package/dist/cli/chunk-bnbmcwfb.js.map +11 -0
  32. package/dist/cli/{chunk-0xjyb285.js → chunk-bw22s759.js} +15 -5
  33. package/dist/cli/{chunk-0xjyb285.js.map → chunk-bw22s759.js.map} +4 -4
  34. package/dist/cli/chunk-by2290sx.js +39 -0
  35. package/dist/cli/chunk-by2290sx.js.map +10 -0
  36. package/dist/cli/chunk-d1tadaw7.js +79 -0
  37. package/dist/cli/chunk-d1tadaw7.js.map +10 -0
  38. package/dist/cli/{chunk-ahnw3kxw.js → chunk-d80hr03s.js} +24 -19
  39. package/dist/cli/chunk-d80hr03s.js.map +15 -0
  40. package/dist/cli/chunk-ernrthtr.js +97 -0
  41. package/dist/cli/chunk-ernrthtr.js.map +10 -0
  42. package/dist/cli/chunk-f2972sbt.js +374 -0
  43. package/dist/cli/chunk-f2972sbt.js.map +10 -0
  44. package/dist/cli/{chunk-vacwm2hv.js → chunk-f7t03s3g.js} +2 -2
  45. package/dist/cli/{chunk-2z47ypj8.js → chunk-fa25z98p.js} +16 -3
  46. package/dist/cli/chunk-fa25z98p.js.map +11 -0
  47. package/dist/cli/{chunk-cjtn640a.js → chunk-fh5hj5jt.js} +43 -20
  48. package/dist/cli/chunk-fh5hj5jt.js.map +10 -0
  49. package/dist/cli/{chunk-yg63d42r.js → chunk-j8mw0za6.js} +86 -57
  50. package/dist/cli/chunk-j8mw0za6.js.map +35 -0
  51. package/dist/cli/{chunk-ct47dqpx.js → chunk-jts8mvcz.js} +67 -7
  52. package/dist/cli/{chunk-2mzebbbz.js.map → chunk-jts8mvcz.js.map} +6 -4
  53. package/dist/cli/{chunk-ps4m1xh4.js → chunk-mnqj32sj.js} +505 -542
  54. package/dist/cli/chunk-mnqj32sj.js.map +12 -0
  55. package/dist/cli/{chunk-8cjtbafj.js → chunk-mwt1k8n7.js} +100 -374
  56. package/dist/cli/chunk-mwt1k8n7.js.map +10 -0
  57. package/dist/cli/chunk-nk3ts2xk.js +51 -0
  58. package/dist/cli/chunk-nk3ts2xk.js.map +10 -0
  59. package/dist/cli/{chunk-3r45185y.js → chunk-pat2zzwc.js} +9 -11
  60. package/dist/cli/{chunk-3r45185y.js.map → chunk-pat2zzwc.js.map} +2 -2
  61. package/dist/cli/chunk-pnnvybbk.js +176 -0
  62. package/dist/cli/chunk-pnnvybbk.js.map +11 -0
  63. package/dist/cli/{chunk-4x36ddpw.js → chunk-sqn5t4q0.js} +81 -87
  64. package/dist/cli/chunk-sqn5t4q0.js.map +10 -0
  65. package/dist/cli/{chunk-bvwwhd84.js → chunk-tzne8qfq.js} +15 -15
  66. package/dist/cli/{chunk-bvwwhd84.js.map → chunk-tzne8qfq.js.map} +1 -1
  67. package/dist/cli/chunk-xaz13gwg.js +12449 -0
  68. package/dist/cli/chunk-xaz13gwg.js.map +182 -0
  69. package/dist/cli/chunk-y3e45rc8.js +102 -0
  70. package/dist/cli/chunk-y3e45rc8.js.map +10 -0
  71. package/dist/cli/chunk-z01ze5c1.js +261 -0
  72. package/dist/cli/chunk-z01ze5c1.js.map +10 -0
  73. package/dist/cli/{chunk-k79xp7av.js → chunk-z1f5arsg.js} +219 -689
  74. package/dist/cli/chunk-z1f5arsg.js.map +36 -0
  75. package/dist/cli/{chunk-1jefwnfs.js → chunk-zg2gtj10.js} +1076 -2592
  76. package/dist/cli/chunk-zg2gtj10.js.map +35 -0
  77. package/dist/cli/{chunk-dwgcp5sm.js → chunk-zxccj738.js} +1 -1
  78. package/dist/cli/index.js +214 -57
  79. package/dist/cli/index.js.map +8 -7
  80. package/dist/types/ai/agent-readability.d.ts +52 -0
  81. package/dist/types/ai/ai-catalog.d.ts +42 -0
  82. package/dist/types/ai/api/paths.d.ts +17 -0
  83. package/dist/types/ai/api-catalog.d.ts +18 -0
  84. package/dist/types/ai/ask.d.ts +368 -0
  85. package/dist/types/ai/changelog-markdown.d.ts +2 -0
  86. package/dist/types/ai/component-markdown.d.ts +2 -2
  87. package/dist/types/ai/index.d.ts +24 -0
  88. package/dist/types/ai/link-headers.d.ts +24 -0
  89. package/dist/types/ai/llms.d.ts +25 -0
  90. package/dist/types/ai/markdown.d.ts +45 -0
  91. package/dist/types/ai/mcp/discovery.d.ts +68 -0
  92. package/dist/types/ai/mcp/tools.d.ts +16 -0
  93. package/dist/types/ai/openapi-components.d.ts +43 -0
  94. package/dist/types/ai/relative-links.d.ts +26 -0
  95. package/dist/types/ai/serializers.d.ts +15 -0
  96. package/dist/types/ai/skills.d.ts +42 -0
  97. package/dist/types/ai/tar.d.ts +25 -0
  98. package/dist/types/ai/visibility.d.ts +17 -0
  99. package/dist/types/ai/web-bot-auth.d.ts +16 -0
  100. package/dist/types/analytics/adobe.d.ts +35 -0
  101. package/dist/types/analytics/amplitude.d.ts +50 -0
  102. package/dist/types/analytics/clarity.d.ts +31 -0
  103. package/dist/types/analytics/clearbit.d.ts +29 -0
  104. package/dist/types/analytics/cloudflare.d.ts +41 -0
  105. package/dist/types/analytics/fathom.d.ts +41 -0
  106. package/dist/types/analytics/google-analytics.d.ts +44 -0
  107. package/dist/types/analytics/google-tag-manager.d.ts +40 -0
  108. package/dist/types/analytics/head.d.ts +30 -0
  109. package/dist/types/analytics/heap.d.ts +40 -0
  110. package/dist/types/analytics/hightouch.d.ts +44 -0
  111. package/dist/types/analytics/hotjar.d.ts +33 -0
  112. package/dist/types/analytics/index.d.ts +61 -0
  113. package/dist/types/analytics/inline.d.ts +17 -0
  114. package/dist/types/analytics/logrocket.d.ts +44 -0
  115. package/dist/types/analytics/mixpanel.d.ts +67 -0
  116. package/dist/types/analytics/pirsch.d.ts +42 -0
  117. package/dist/types/analytics/plausible.d.ts +56 -0
  118. package/dist/types/analytics/posthog.d.ts +45 -0
  119. package/dist/types/analytics/schema.d.ts +320 -0
  120. package/dist/types/analytics/script.d.ts +46 -0
  121. package/dist/types/analytics/segment.d.ts +50 -0
  122. package/dist/types/analytics/vercel.d.ts +48 -0
  123. package/dist/types/astro/integration.d.ts +76 -0
  124. package/dist/types/astro/markdown-negotiation.d.ts +23 -0
  125. package/dist/types/astro/module-types.d.ts +14 -0
  126. package/dist/types/astro/pages.d.ts +44 -0
  127. package/dist/types/cli/env.d.ts +12 -0
  128. package/dist/types/cli/init/scaffold.d.ts +154 -0
  129. package/dist/types/components/layout/nav-utils.d.ts +11 -0
  130. package/dist/types/core/adapter.d.ts +47 -0
  131. package/dist/types/core/api-name.d.ts +7 -0
  132. package/dist/types/core/changelog-index.d.ts +13 -0
  133. package/dist/types/core/config-input.d.ts +186 -515
  134. package/dist/types/core/config.d.ts +60 -34
  135. package/dist/types/core/content-assets.d.ts +76 -0
  136. package/dist/types/core/custom-pages.d.ts +33 -0
  137. package/dist/types/core/data.d.ts +27 -12
  138. package/dist/types/core/define-components.d.ts +12 -9
  139. package/dist/types/core/deployment-env.d.ts +6 -11
  140. package/dist/types/core/frontmatter.d.ts +10 -0
  141. package/dist/types/core/graph.d.ts +18 -0
  142. package/dist/types/core/heading-markers.d.ts +54 -0
  143. package/dist/types/core/i18n-ui.d.ts +6 -2
  144. package/dist/types/core/i18n.d.ts +87 -0
  145. package/dist/types/core/includes.d.ts +138 -0
  146. package/dist/types/core/last-modified.d.ts +47 -0
  147. package/dist/types/core/links.d.ts +95 -0
  148. package/dist/types/core/locale-links.d.ts +60 -0
  149. package/dist/types/core/manifest.d.ts +17 -0
  150. package/dist/types/core/meta.d.ts +38 -0
  151. package/dist/types/core/nav-diagnostics.d.ts +26 -0
  152. package/dist/types/core/navigation.d.ts +6 -0
  153. package/dist/types/core/node-require.d.ts +19 -0
  154. package/dist/types/core/package-json.d.ts +13 -0
  155. package/dist/types/core/probe.d.ts +42 -0
  156. package/dist/types/core/project-graph.d.ts +51 -0
  157. package/dist/types/core/project.d.ts +2 -0
  158. package/dist/types/core/safe-href.d.ts +2 -0
  159. package/dist/types/core/safe-links.d.ts +26 -0
  160. package/dist/types/core/schema.d.ts +2282 -452
  161. package/dist/types/core/site-url.d.ts +16 -0
  162. package/dist/types/core/sources/assets.d.ts +36 -0
  163. package/dist/types/core/sources/cache.d.ts +37 -0
  164. package/dist/types/core/sources/collection.d.ts +28 -0
  165. package/dist/types/core/sources/contentful-rich-text.d.ts +31 -0
  166. package/dist/types/core/sources/contentful.d.ts +40 -0
  167. package/dist/types/core/sources/filesystem.d.ts +24 -0
  168. package/dist/types/core/sources/github-releases.d.ts +31 -0
  169. package/dist/types/core/sources/json.d.ts +30 -0
  170. package/dist/types/core/sources/lexical.d.ts +19 -0
  171. package/dist/types/core/sources/lower.d.ts +75 -0
  172. package/dist/types/core/sources/mdx-remote.d.ts +28 -0
  173. package/dist/types/core/sources/normalize.d.ts +147 -0
  174. package/dist/types/core/sources/notion.d.ts +131 -0
  175. package/dist/types/core/sources/obsidian.d.ts +46 -0
  176. package/dist/types/core/sources/payload.d.ts +39 -0
  177. package/dist/types/core/sources/portable-text.d.ts +42 -0
  178. package/dist/types/core/sources/read.d.ts +23 -0
  179. package/dist/types/core/sources/remote.d.ts +74 -0
  180. package/dist/types/core/sources/resolve.d.ts +19 -0
  181. package/dist/types/core/sources/sanity.d.ts +43 -0
  182. package/dist/types/core/sources/strapi-blocks.d.ts +12 -0
  183. package/dist/types/core/sources/strapi.d.ts +33 -0
  184. package/dist/types/core/sources/types.d.ts +7 -0
  185. package/dist/types/core/sources/watch.d.ts +45 -0
  186. package/dist/types/core/text-width.d.ts +11 -0
  187. package/dist/types/core/types.d.ts +15 -1
  188. package/dist/types/core/unrecognized-keys.d.ts +7 -0
  189. package/dist/types/core/versions.d.ts +72 -0
  190. package/dist/types/core/yaml.d.ts +9 -0
  191. package/dist/types/deploy/adapter-output.d.ts +45 -0
  192. package/dist/types/deploy/adapters/cloudflare.d.ts +40 -0
  193. package/dist/types/deploy/adapters/index.d.ts +29 -0
  194. package/dist/types/deploy/adapters/netlify.d.ts +37 -0
  195. package/dist/types/deploy/adapters/node.d.ts +37 -0
  196. package/dist/types/deploy/adapters/registry.d.ts +133 -0
  197. package/dist/types/deploy/adapters/types.d.ts +71 -0
  198. package/dist/types/deploy/adapters/vercel.d.ts +38 -0
  199. package/dist/types/deploy/artifacts.d.ts +65 -0
  200. package/dist/types/deploy/cloudflare-negotiation.d.ts +196 -0
  201. package/dist/types/deploy/function-bundle.d.ts +80 -0
  202. package/dist/types/deploy/headers.d.ts +50 -0
  203. package/dist/types/deploy/node-headers.d.ts +42 -0
  204. package/dist/types/deploy/platforms/cloudflare.d.ts +40 -0
  205. package/dist/types/deploy/platforms/index.d.ts +18 -0
  206. package/dist/types/deploy/platforms/netlify.d.ts +13 -0
  207. package/dist/types/deploy/platforms/node.d.ts +11 -0
  208. package/dist/types/deploy/platforms/paths.d.ts +27 -0
  209. package/dist/types/deploy/platforms/static.d.ts +10 -0
  210. package/dist/types/deploy/platforms/types.d.ts +104 -0
  211. package/dist/types/deploy/platforms/vercel.d.ts +32 -0
  212. package/dist/types/deploy/redirects.d.ts +53 -0
  213. package/dist/types/deploy/robots.d.ts +8 -0
  214. package/dist/types/deploy/rss.d.ts +31 -0
  215. package/dist/types/deploy/sitemap.d.ts +21 -0
  216. package/dist/types/deploy/vercel-negotiation.d.ts +109 -0
  217. package/dist/types/markdown/code-title.d.ts +32 -0
  218. package/dist/types/markdown/fence-meta.d.ts +23 -0
  219. package/dist/types/markdown/themes.d.ts +3 -3
  220. package/dist/types/openapi/asyncapi.d.ts +129 -0
  221. package/dist/types/openapi/graphql-build.d.ts +8 -0
  222. package/dist/types/openapi/graphql.d.ts +122 -0
  223. package/dist/types/openapi/model.d.ts +158 -0
  224. package/dist/types/openapi/parse.d.ts +57 -0
  225. package/dist/types/openapi/references.d.ts +37 -25
  226. package/dist/types/openapi/render-mdx.d.ts +33 -0
  227. package/dist/types/openapi/sentence.d.ts +7 -0
  228. package/dist/types/openapi/signature.d.ts +10 -0
  229. package/dist/types/openapi/source.d.ts +22 -0
  230. package/dist/types/openapi/spec-dependency-error.d.ts +10 -0
  231. package/dist/types/reference/asyncapi.d.ts +166 -0
  232. package/dist/types/reference/graphql.d.ts +181 -0
  233. package/dist/types/reference/index.d.ts +32 -0
  234. package/dist/types/reference/openapi.d.ts +165 -0
  235. package/dist/types/reference/options.d.ts +157 -0
  236. package/dist/types/reference/scalar.d.ts +136 -0
  237. package/dist/types/reference/schema.d.ts +630 -0
  238. package/dist/types/search/adapters/algolia.d.ts +32 -0
  239. package/dist/types/search/adapters/flexsearch.d.ts +12 -0
  240. package/dist/types/search/adapters/index.d.ts +31 -0
  241. package/dist/types/search/adapters/mixedbread.d.ts +22 -0
  242. package/dist/types/search/adapters/orama-cloud.d.ts +33 -0
  243. package/dist/types/search/adapters/orama.d.ts +13 -0
  244. package/dist/types/search/adapters/pagefind.d.ts +12 -0
  245. package/dist/types/search/adapters/registry.d.ts +228 -0
  246. package/dist/types/search/adapters/types.d.ts +34 -0
  247. package/dist/types/search/adapters/typesense.d.ts +42 -0
  248. package/dist/types/search/build.d.ts +23 -0
  249. package/dist/types/search/documents.d.ts +90 -0
  250. package/dist/types/search/facets.d.ts +3 -0
  251. package/dist/types/search/sync/algolia.d.ts +14 -0
  252. package/dist/types/search/sync/index.d.ts +14 -0
  253. package/dist/types/search/sync/orama-cloud.d.ts +10 -0
  254. package/dist/types/search/sync/typesense.d.ts +14 -0
  255. package/dist/types/sources/contentful.d.ts +68 -0
  256. package/dist/types/sources/custom.d.ts +20 -0
  257. package/dist/types/sources/filesystem.d.ts +42 -0
  258. package/dist/types/sources/github-releases.d.ts +46 -0
  259. package/dist/types/sources/index.d.ts +48 -0
  260. package/dist/types/sources/mdx-remote.d.ts +63 -0
  261. package/dist/types/sources/notion.d.ts +65 -0
  262. package/dist/types/sources/obsidian.d.ts +34 -0
  263. package/dist/types/sources/payload.d.ts +68 -0
  264. package/dist/types/sources/registry.d.ts +1414 -0
  265. package/dist/types/sources/sanity.d.ts +69 -0
  266. package/dist/types/sources/shared.d.ts +46 -0
  267. package/dist/types/sources/strapi.d.ts +66 -0
  268. package/dist/types/theme/icon-kind.d.ts +11 -0
  269. package/dist/types/theme/icons.d.ts +20 -0
  270. package/docs/01-quickstart.mdx +18 -18
  271. package/docs/02-deployment.mdx +50 -26
  272. package/docs/03-upgrading.mdx +351 -0
  273. package/docs/04-migrating.mdx +58 -0
  274. package/docs/08-faq.mdx +3 -3
  275. package/docs/advanced/blog.mdx +13 -6
  276. package/docs/advanced/changelog.mdx +23 -35
  277. package/docs/advanced/custom-pages.mdx +20 -8
  278. package/docs/advanced/meta.ts +1 -8
  279. package/docs/advanced/skills.mdx +8 -0
  280. package/docs/cli/audit.mdx +646 -0
  281. package/docs/cli/doctor.mdx +29 -0
  282. package/docs/{reference/eval.mdx → cli/evals.mdx} +9 -8
  283. package/docs/cli/index.mdx +105 -0
  284. package/docs/cli/meta.ts +7 -0
  285. package/docs/{reference → cli}/translate.mdx +1 -1
  286. package/docs/cli/validate.mdx +41 -0
  287. package/docs/cli/version.mdx +40 -0
  288. package/docs/configuration/analytics.mdx +350 -59
  289. package/docs/configuration/ask-ai.mdx +162 -61
  290. package/docs/configuration/customization.mdx +15 -9
  291. package/docs/configuration/index.mdx +50 -31
  292. package/docs/configuration/search.mdx +75 -54
  293. package/docs/configuration/theming.mdx +24 -15
  294. package/docs/content/components.mdx +21 -5
  295. package/docs/{reference → content}/frontmatter.mdx +35 -1
  296. package/docs/content/i18n.mdx +8 -6
  297. package/docs/content/includes.mdx +2 -4
  298. package/docs/content/index.mdx +1 -1
  299. package/docs/content/islands.mdx +10 -5
  300. package/docs/content/meta.mdx +1 -1
  301. package/docs/content/meta.ts +1 -0
  302. package/docs/content/navigation.mdx +9 -7
  303. package/docs/content/sources.mdx +145 -50
  304. package/docs/content/syntax.mdx +16 -12
  305. package/docs/content/versioning.mdx +3 -3
  306. package/docs/discoverability/agent-discovery.mdx +11 -11
  307. package/docs/discoverability/index.mdx +4 -4
  308. package/docs/discoverability/json-api.mdx +4 -4
  309. package/docs/discoverability/llms-txt.mdx +6 -6
  310. package/docs/discoverability/markdown.mdx +4 -4
  311. package/docs/discoverability/mcp.mdx +11 -11
  312. package/docs/discoverability/sitemap-and-robots.mdx +3 -3
  313. package/docs/index.mdx +2 -2
  314. package/docs/references/asyncapi.mdx +59 -0
  315. package/docs/{advanced → references}/graphql.mdx +45 -32
  316. package/docs/{reference → references}/meta.ts +2 -2
  317. package/docs/references/openapi.mdx +171 -0
  318. package/docs/references/scalar.mdx +64 -0
  319. package/package.json +42 -8
  320. package/skills/blume/SKILL.md +21 -8
  321. package/skills/blume-migrate/SKILL.md +22 -21
  322. package/skills/blume-migrate/assets/oxfmt@0.67.0.patch +49 -0
  323. package/skills/blume-migrate/references/docusaurus.md +5 -4
  324. package/skills/blume-migrate/references/fumadocs.md +4 -4
  325. package/skills/blume-migrate/references/mintlify.md +23 -8
  326. package/skills/blume-migrate/references/monorepo.md +6 -6
  327. package/skills/blume-migrate/references/starlight.md +4 -4
  328. package/src/ai/agent-readability.ts +21 -22
  329. package/src/ai/ai-catalog.ts +50 -32
  330. package/src/ai/api/handlers.ts +46 -11
  331. package/src/ai/api-catalog.ts +8 -8
  332. package/src/ai/ask-data.ts +1 -1
  333. package/src/ai/ask.ts +624 -100
  334. package/src/ai/changelog-markdown.ts +91 -0
  335. package/src/ai/component-markdown.ts +328 -12
  336. package/src/ai/index.ts +45 -0
  337. package/src/ai/link-headers.ts +7 -6
  338. package/src/ai/llms.ts +20 -15
  339. package/src/ai/markdown.ts +35 -5
  340. package/src/ai/mcp/data.ts +9 -5
  341. package/src/ai/openapi-components.ts +4 -1
  342. package/src/ai/relative-links.ts +170 -0
  343. package/src/ai/serializers.ts +2 -2
  344. package/src/ai/skills.ts +1 -1
  345. package/src/ai/web-bot-auth.ts +2 -2
  346. package/src/analytics/adobe.ts +46 -0
  347. package/src/analytics/amplitude.ts +79 -0
  348. package/src/analytics/clarity.ts +46 -0
  349. package/src/analytics/clearbit.ts +47 -0
  350. package/src/analytics/cloudflare.ts +67 -0
  351. package/src/analytics/fathom.ts +64 -0
  352. package/src/analytics/google-analytics.ts +84 -0
  353. package/src/analytics/google-tag-manager.ts +61 -0
  354. package/src/analytics/head.ts +130 -0
  355. package/src/analytics/heap.ts +65 -0
  356. package/src/analytics/hightouch.ts +77 -0
  357. package/src/analytics/hotjar.ts +47 -0
  358. package/src/analytics/index.ts +71 -0
  359. package/src/analytics/inline.ts +21 -0
  360. package/src/analytics/logrocket.ts +71 -0
  361. package/src/analytics/mixpanel.ts +92 -0
  362. package/src/analytics/pirsch.ts +66 -0
  363. package/src/analytics/plausible.ts +83 -0
  364. package/src/analytics/posthog.ts +78 -0
  365. package/src/analytics/schema.ts +60 -0
  366. package/src/analytics/script.ts +60 -0
  367. package/src/analytics/segment.ts +85 -0
  368. package/src/analytics/vercel.ts +50 -0
  369. package/src/astro/adapter-root.ts +7 -9
  370. package/src/astro/component-slots.ts +131 -91
  371. package/src/astro/generate.ts +112 -345
  372. package/src/astro/integration.ts +2 -6
  373. package/src/astro/pages.ts +13 -101
  374. package/src/astro/render-deps.ts +379 -0
  375. package/src/astro/runtime-deps.ts +201 -0
  376. package/src/astro/templates.ts +554 -541
  377. package/src/audit/agent.ts +24 -0
  378. package/src/audit/catalog.ts +2 -2
  379. package/src/audit/checks/assets.ts +2 -2
  380. package/src/audit/checks/dns-aid.ts +1 -1
  381. package/src/audit/checks/duplicates.ts +3 -1
  382. package/src/audit/checks/i18n.ts +1 -1
  383. package/src/audit/checks/indexability.ts +7 -7
  384. package/src/audit/checks/links.ts +2 -2
  385. package/src/audit/checks/llms.ts +6 -6
  386. package/src/audit/checks/network.ts +3 -3
  387. package/src/audit/checks/og-image.ts +2 -2
  388. package/src/audit/checks/robots.ts +1 -1
  389. package/src/audit/checks/sitemap.ts +2 -2
  390. package/src/audit/checks/social.ts +1 -1
  391. package/src/audit/run.ts +4 -3
  392. package/src/audit/terms.ts +31 -0
  393. package/src/audit/url.ts +13 -13
  394. package/src/cli/command-meta.ts +10 -0
  395. package/src/cli/commands/audit.ts +39 -20
  396. package/src/cli/commands/build.ts +71 -316
  397. package/src/cli/commands/check.ts +1 -0
  398. package/src/cli/commands/dev.ts +40 -1
  399. package/src/cli/commands/doctor.ts +90 -14
  400. package/src/cli/commands/eject.ts +44 -7
  401. package/src/cli/commands/eval.ts +2 -2
  402. package/src/cli/commands/init.ts +161 -41
  403. package/src/cli/commands/migrate.ts +121 -0
  404. package/src/cli/commands/preview.ts +7 -1
  405. package/src/cli/commands/translate.ts +2 -2
  406. package/src/cli/commands/upgrade.ts +141 -0
  407. package/src/cli/commands/version.ts +57 -44
  408. package/src/cli/eject-scripts.ts +121 -6
  409. package/src/cli/index.ts +11 -1
  410. package/src/cli/init/install.ts +70 -0
  411. package/src/cli/init/questions.ts +7 -0
  412. package/src/cli/init/scaffold.ts +459 -75
  413. package/src/cli/lazy-command.ts +37 -1
  414. package/src/cli/prepare.ts +40 -6
  415. package/src/cli/required-secrets.ts +38 -11
  416. package/src/cli/unknown-flags.ts +266 -0
  417. package/src/cli/yarn-pnp.ts +52 -0
  418. package/src/components/content/AccordionItem.astro +7 -1
  419. package/src/components/content/Card.astro +4 -3
  420. package/src/components/content/ColorItem.astro +22 -4
  421. package/src/components/content/GithubInfo.astro +2 -2
  422. package/src/components/content/Prompt.astro +25 -25
  423. package/src/components/content/Tabs.astro +3 -1
  424. package/src/components/content/Tile.astro +2 -3
  425. package/src/components/content/Tooltip.astro +57 -9
  426. package/src/components/content/content-strings.ts +34 -0
  427. package/src/components/content/diff.ts +1 -1
  428. package/src/components/content/mermaid-element.ts +13 -2
  429. package/src/components/content/prompt-markdown.ts +292 -0
  430. package/src/components/content/tooltip-id.ts +41 -0
  431. package/src/components/islands/hooks.ts +25 -2
  432. package/src/components/layout/Analytics.astro +21 -79
  433. package/src/components/layout/Banner.astro +3 -1
  434. package/src/components/layout/DiscoveryLinks.astro +69 -0
  435. package/src/components/layout/Header.astro +83 -20
  436. package/src/components/layout/LanguageSwitcher.astro +4 -1
  437. package/src/components/layout/Logo.astro +23 -2
  438. package/src/components/layout/NavSelector.astro +13 -2
  439. package/src/components/layout/NavTree.astro +12 -3
  440. package/src/components/layout/NavTreeScript.astro +17 -3
  441. package/src/components/layout/PageActions.astro +3 -3
  442. package/src/components/layout/PageFeedback.astro +11 -1
  443. package/src/components/layout/PageLayout.astro +52 -5
  444. package/src/components/layout/ReferenceLayout.astro +21 -12
  445. package/src/components/layout/RootLayout.astro +69 -66
  446. package/src/components/layout/Search.astro +30 -6
  447. package/src/components/layout/WebMcp.astro +1 -1
  448. package/src/components/layout/analytics-client.ts +72 -15
  449. package/src/components/layout/drawer-inert.ts +113 -15
  450. package/src/components/layout/dropdown-clamp.ts +105 -0
  451. package/src/components/layout/head-scripts.ts +15 -6
  452. package/src/components/layout/nav-utils.ts +17 -0
  453. package/src/components/layout/search/algolia.ts +8 -8
  454. package/src/components/layout/search/orama-cloud.ts +9 -7
  455. package/src/components/layout/search/typesense.ts +11 -17
  456. package/src/components/openapi/MessageComposer.astro +2 -2
  457. package/src/components/openapi/Playground.astro +2 -2
  458. package/src/components/openapi/playground-client.ts +79 -10
  459. package/src/core/changelog-index.ts +24 -0
  460. package/src/core/component-overrides.ts +399 -154
  461. package/src/core/config-input.ts +188 -553
  462. package/src/core/config.ts +130 -41
  463. package/src/core/custom-pages.ts +105 -0
  464. package/src/core/data.ts +31 -12
  465. package/src/core/define-components.ts +12 -9
  466. package/src/core/deployment-env.ts +18 -74
  467. package/src/core/diagnostics.ts +14 -7
  468. package/src/core/graph.ts +69 -25
  469. package/src/core/i18n-ui.ts +6 -2
  470. package/src/core/i18n.ts +17 -0
  471. package/src/core/includes.ts +156 -38
  472. package/src/core/last-modified.ts +6 -11
  473. package/src/core/links.ts +166 -2
  474. package/src/core/manifest.ts +10 -3
  475. package/src/core/navigation.ts +115 -16
  476. package/src/core/new-tab.ts +35 -0
  477. package/src/core/node-require.ts +21 -0
  478. package/src/core/project-graph.ts +42 -26
  479. package/src/core/project.ts +9 -4
  480. package/src/core/request-body.ts +61 -0
  481. package/src/core/safe-href.ts +28 -0
  482. package/src/core/safe-links.ts +68 -0
  483. package/src/core/schema.ts +517 -739
  484. package/src/core/server-features.ts +8 -9
  485. package/src/core/sources/assets.ts +47 -11
  486. package/src/core/sources/collection.ts +67 -0
  487. package/src/core/sources/contentful-rich-text.ts +285 -0
  488. package/src/core/sources/contentful.ts +173 -0
  489. package/src/core/sources/github-releases.ts +51 -1
  490. package/src/core/sources/json.ts +71 -0
  491. package/src/core/sources/lexical.ts +195 -0
  492. package/src/core/sources/lower.ts +226 -0
  493. package/src/core/sources/normalize.ts +52 -2
  494. package/src/core/sources/notion.ts +39 -28
  495. package/src/core/sources/payload.ts +135 -0
  496. package/src/core/sources/portable-text.ts +11 -16
  497. package/src/core/sources/remote.ts +226 -0
  498. package/src/core/sources/resolve.ts +104 -166
  499. package/src/core/sources/sanity.ts +16 -49
  500. package/src/core/sources/strapi-blocks.ts +124 -0
  501. package/src/core/sources/strapi.ts +191 -0
  502. package/src/core/sources/types.ts +12 -1
  503. package/src/core/types.ts +15 -1
  504. package/src/core/ui-packs/ar.ts +6 -2
  505. package/src/core/ui-packs/bg.ts +6 -2
  506. package/src/core/ui-packs/bn.ts +6 -2
  507. package/src/core/ui-packs/ca.ts +3 -1
  508. package/src/core/ui-packs/cs.ts +6 -2
  509. package/src/core/ui-packs/da.ts +6 -2
  510. package/src/core/ui-packs/de.ts +6 -2
  511. package/src/core/ui-packs/el.ts +3 -1
  512. package/src/core/ui-packs/es.ts +3 -1
  513. package/src/core/ui-packs/fa.ts +6 -2
  514. package/src/core/ui-packs/fi.ts +6 -2
  515. package/src/core/ui-packs/fr.ts +3 -1
  516. package/src/core/ui-packs/he.ts +6 -2
  517. package/src/core/ui-packs/hi.ts +6 -2
  518. package/src/core/ui-packs/hr.ts +6 -2
  519. package/src/core/ui-packs/hu.ts +6 -2
  520. package/src/core/ui-packs/id.ts +6 -2
  521. package/src/core/ui-packs/it.ts +3 -1
  522. package/src/core/ui-packs/ja.ts +3 -1
  523. package/src/core/ui-packs/ko.ts +3 -1
  524. package/src/core/ui-packs/nl.ts +6 -2
  525. package/src/core/ui-packs/no.ts +6 -2
  526. package/src/core/ui-packs/pl.ts +6 -2
  527. package/src/core/ui-packs/pt-br.ts +3 -1
  528. package/src/core/ui-packs/pt.ts +3 -1
  529. package/src/core/ui-packs/ro.ts +6 -2
  530. package/src/core/ui-packs/ru.ts +6 -2
  531. package/src/core/ui-packs/sk.ts +6 -2
  532. package/src/core/ui-packs/sr.ts +6 -2
  533. package/src/core/ui-packs/sv.ts +6 -2
  534. package/src/core/ui-packs/th.ts +3 -1
  535. package/src/core/ui-packs/tr.ts +6 -2
  536. package/src/core/ui-packs/uk.ts +6 -2
  537. package/src/core/ui-packs/vi.ts +3 -1
  538. package/src/core/ui-packs/zh-tw.ts +3 -1
  539. package/src/core/ui-packs/zh.ts +3 -1
  540. package/src/core/unrecognized-keys.ts +10 -0
  541. package/src/core/version-cut.ts +116 -8
  542. package/src/deploy/adapter-output.ts +57 -97
  543. package/src/deploy/adapters/cloudflare.ts +39 -0
  544. package/src/deploy/adapters/index.ts +41 -0
  545. package/src/deploy/adapters/netlify.ts +34 -0
  546. package/src/deploy/adapters/node.ts +34 -0
  547. package/src/deploy/adapters/registry.ts +127 -0
  548. package/src/deploy/adapters/types.ts +92 -0
  549. package/src/deploy/adapters/vercel.ts +35 -0
  550. package/src/deploy/artifacts.ts +55 -27
  551. package/src/deploy/cloudflare-negotiation.ts +179 -100
  552. package/src/deploy/function-bundle.ts +18 -3
  553. package/src/deploy/headers.ts +124 -23
  554. package/src/deploy/node-headers.ts +198 -0
  555. package/src/deploy/platforms/cloudflare.ts +312 -0
  556. package/src/deploy/platforms/index.ts +67 -0
  557. package/src/deploy/platforms/netlify.ts +52 -0
  558. package/src/deploy/platforms/node.ts +40 -0
  559. package/src/deploy/platforms/paths.ts +42 -0
  560. package/src/deploy/platforms/static.ts +29 -0
  561. package/src/deploy/platforms/types.ts +112 -0
  562. package/src/deploy/platforms/vercel.ts +193 -0
  563. package/src/deploy/redirects.ts +30 -18
  564. package/src/deploy/robots.ts +3 -3
  565. package/src/deploy/rss.ts +2 -2
  566. package/src/deploy/sitemap.ts +2 -2
  567. package/src/deploy/vercel-negotiation.ts +2 -2
  568. package/src/eval/agents.ts +32 -1
  569. package/src/eval/findings.ts +19 -11
  570. package/src/eval/report.ts +10 -2
  571. package/src/markdown/external-links.ts +65 -0
  572. package/src/markdown/include.ts +45 -27
  573. package/src/markdown/index.ts +34 -9
  574. package/src/markdown/inline-code.ts +12 -6
  575. package/src/markdown/relative-links.ts +324 -0
  576. package/src/markdown/themes.ts +3 -3
  577. package/src/migrate/migrate.ts +149 -0
  578. package/src/openapi/parse.ts +64 -16
  579. package/src/openapi/proxy.ts +62 -10
  580. package/src/openapi/references.ts +147 -147
  581. package/src/openapi/render-mdx.ts +32 -10
  582. package/src/openapi/scalar.ts +15 -13
  583. package/src/openapi/sentence.ts +14 -0
  584. package/src/openapi/source.ts +37 -21
  585. package/src/openapi/spec-dependency-error.ts +15 -0
  586. package/src/reference/asyncapi.ts +83 -0
  587. package/src/reference/graphql.ts +89 -0
  588. package/src/reference/index.ts +40 -0
  589. package/src/reference/openapi.ts +83 -0
  590. package/src/reference/options.ts +201 -0
  591. package/src/reference/scalar.ts +136 -0
  592. package/src/reference/schema.ts +88 -0
  593. package/src/registry/eject.ts +97 -42
  594. package/src/search/adapters/algolia.ts +46 -0
  595. package/src/search/adapters/flexsearch.ts +29 -0
  596. package/src/search/adapters/index.ts +39 -0
  597. package/src/search/adapters/mixedbread.ts +39 -0
  598. package/src/search/adapters/orama-cloud.ts +51 -0
  599. package/src/search/adapters/orama.ts +24 -0
  600. package/src/search/adapters/pagefind.ts +27 -0
  601. package/src/search/adapters/registry.ts +131 -0
  602. package/src/search/adapters/types.ts +46 -0
  603. package/src/search/adapters/typesense.ts +57 -0
  604. package/src/search/build.ts +8 -4
  605. package/src/search/documents.ts +6 -0
  606. package/src/search/sync/algolia.ts +12 -11
  607. package/src/search/sync/index.ts +35 -20
  608. package/src/search/sync/orama-cloud.ts +12 -9
  609. package/src/search/sync/typesense.ts +15 -13
  610. package/src/sources/contentful.ts +63 -0
  611. package/src/sources/custom.ts +38 -0
  612. package/src/sources/filesystem.ts +51 -0
  613. package/src/sources/github-releases.ts +52 -0
  614. package/src/sources/index.ts +60 -0
  615. package/src/sources/mdx-remote.ts +76 -0
  616. package/src/sources/notion.ts +63 -0
  617. package/src/sources/obsidian.ts +38 -0
  618. package/src/sources/payload.ts +60 -0
  619. package/src/sources/registry.ts +182 -0
  620. package/src/sources/sanity.ts +66 -0
  621. package/src/sources/shared.ts +52 -0
  622. package/src/sources/strapi.ts +58 -0
  623. package/src/theme/entry.ts +24 -2
  624. package/src/translate/report.ts +40 -7
  625. package/src/upgrade/upgrade.ts +499 -0
  626. package/dist/cli/chunk-0qymqwzz.js +0 -164
  627. package/dist/cli/chunk-0qymqwzz.js.map +0 -15
  628. package/dist/cli/chunk-1jefwnfs.js.map +0 -48
  629. package/dist/cli/chunk-2mzebbbz.js +0 -69
  630. package/dist/cli/chunk-2z47ypj8.js.map +0 -11
  631. package/dist/cli/chunk-4x36ddpw.js.map +0 -11
  632. package/dist/cli/chunk-5093q3n7.js +0 -68
  633. package/dist/cli/chunk-5093q3n7.js.map +0 -10
  634. package/dist/cli/chunk-5qk08vmp.js.map +0 -11
  635. package/dist/cli/chunk-7s8hm3b6.js +0 -5347
  636. package/dist/cli/chunk-7s8hm3b6.js.map +0 -58
  637. package/dist/cli/chunk-8cjtbafj.js.map +0 -13
  638. package/dist/cli/chunk-97r59kpr.js +0 -381
  639. package/dist/cli/chunk-97r59kpr.js.map +0 -12
  640. package/dist/cli/chunk-ahnw3kxw.js.map +0 -15
  641. package/dist/cli/chunk-b27xqwn9.js.map +0 -10
  642. package/dist/cli/chunk-bf6bt1xt.js +0 -185
  643. package/dist/cli/chunk-bf6bt1xt.js.map +0 -11
  644. package/dist/cli/chunk-cjtn640a.js.map +0 -10
  645. package/dist/cli/chunk-ct47dqpx.js.map +0 -11
  646. package/dist/cli/chunk-esphfr8p.js +0 -107
  647. package/dist/cli/chunk-esphfr8p.js.map +0 -11
  648. package/dist/cli/chunk-ex56aa81.js +0 -1016
  649. package/dist/cli/chunk-ex56aa81.js.map +0 -13
  650. package/dist/cli/chunk-garjf5z9.js +0 -30
  651. package/dist/cli/chunk-garjf5z9.js.map +0 -10
  652. package/dist/cli/chunk-js7saxwm.js +0 -1045
  653. package/dist/cli/chunk-js7saxwm.js.map +0 -22
  654. package/dist/cli/chunk-k79xp7av.js.map +0 -39
  655. package/dist/cli/chunk-ps4m1xh4.js.map +0 -15
  656. package/dist/cli/chunk-q4rae3bg.js +0 -60
  657. package/dist/cli/chunk-q4rae3bg.js.map +0 -10
  658. package/dist/cli/chunk-rz9jmfhz.js +0 -108
  659. package/dist/cli/chunk-rz9jmfhz.js.map +0 -10
  660. package/dist/cli/chunk-vh9w1sgp.js +0 -73
  661. package/dist/cli/chunk-vh9w1sgp.js.map +0 -10
  662. package/dist/cli/chunk-vrfp10qk.js +0 -81
  663. package/dist/cli/chunk-vrfp10qk.js.map +0 -10
  664. package/dist/cli/chunk-yg63d42r.js.map +0 -34
  665. package/docs/advanced/api-reference.mdx +0 -240
  666. package/docs/reference/cli.mdx +0 -197
  667. package/skills/blume-migrate/assets/oxfmt@0.55.0.patch +0 -20
  668. package/src/components/content/changelog-element.ts +0 -69
  669. package/src/search/providers.ts +0 -91
  670. /package/dist/cli/{chunk-e7f42gdj.js.map → chunk-7ez8ny0t.js.map} +0 -0
  671. /package/dist/cli/{chunk-nn13znc2.js.map → chunk-88cpgt6h.js.map} +0 -0
  672. /package/dist/cli/{chunk-vacwm2hv.js.map → chunk-f7t03s3g.js.map} +0 -0
  673. /package/dist/cli/{chunk-dwgcp5sm.js.map → chunk-zxccj738.js.map} +0 -0
@@ -1,10 +1,19 @@
1
- import { existsSync } from "node:fs";
2
- import { mkdir, writeFile } from "node:fs/promises";
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
3
3
 
4
4
  import { detect } from "package-manager-detector/detect";
5
5
  import { basename, dirname, isAbsolute, join, relative } from "pathe";
6
6
 
7
7
  import { blumePackageJson, toPackageName } from "../../core/package-json.ts";
8
+ import { contentful } from "../../sources/contentful.ts";
9
+ import { githubReleases } from "../../sources/github-releases.ts";
10
+ import { mdxRemote } from "../../sources/mdx-remote.ts";
11
+ import { notion } from "../../sources/notion.ts";
12
+ import { obsidian } from "../../sources/obsidian.ts";
13
+ import { payload } from "../../sources/payload.ts";
14
+ import type { AnySourceAdapter } from "../../sources/registry.ts";
15
+ import { sanity } from "../../sources/sanity.ts";
16
+ import { strapi } from "../../sources/strapi.ts";
8
17
 
9
18
  export const TEMPLATES = ["docs", "api", "sdk", "changelog"] as const;
10
19
  export type Template = (typeof TEMPLATES)[number];
@@ -19,6 +28,9 @@ export const SOURCE_KINDS = [
19
28
  "github-releases",
20
29
  "notion",
21
30
  "sanity",
31
+ "contentful",
32
+ "payload",
33
+ "strapi",
22
34
  "mdx-remote",
23
35
  ] as const;
24
36
  export type SourceKind = (typeof SOURCE_KINDS)[number];
@@ -49,6 +61,8 @@ export interface ScaffoldLog {
49
61
  /** A starter: a config fragment plus seed content files (paths relative to root). */
50
62
  interface Starter {
51
63
  configExtra: string;
64
+ /** Import lines the fragment needs, placed after the `defineConfig` import. */
65
+ configImports: string[];
52
66
  files: (contentDir: string) => { content: string; path: string }[];
53
67
  }
54
68
 
@@ -58,22 +72,24 @@ const page = (title: string, description: string, body: string): string =>
58
72
  export const STARTERS = {
59
73
  api: {
60
74
  configExtra: `
61
- openapi: {
62
- enabled: true,
63
- route: "/api",
64
- sources: [
65
- {
66
- label: "Petstore",
67
- spec: "https://petstore3.swagger.io/api/v3/openapi.json",
68
- },
69
- ],
70
- },`,
75
+ reference: [
76
+ openapi({
77
+ route: "/api",
78
+ sources: [
79
+ {
80
+ label: "Petstore",
81
+ spec: "https://petstore3.swagger.io/api/v3/openapi.json",
82
+ },
83
+ ],
84
+ }),
85
+ ],`,
86
+ configImports: ['import { openapi } from "blume/reference";'],
71
87
  files: (dir) => [
72
88
  {
73
89
  content: page(
74
90
  "API Reference",
75
- "Explore the API.",
76
- "# API Reference\n\nYour OpenAPI spec renders at [`/api`](/api). Point `openapi.sources` at your own spec in `blume.config.ts`."
91
+ "Reference documentation for the API, generated from its OpenAPI spec, with every endpoint, its parameters, request bodies, and responses.",
92
+ "Your OpenAPI spec renders at [`/api`](/api). Point `openapi()` at your own spec in `blume.config.ts`."
77
93
  ),
78
94
  path: join(dir, "index.mdx"),
79
95
  },
@@ -87,29 +103,31 @@ export const STARTERS = {
87
103
  { label: "Changelog", path: "/changelog" },
88
104
  ],
89
105
  },`,
106
+ configImports: [],
90
107
  files: (dir) => [
91
108
  {
92
109
  content: page(
93
110
  "Introduction",
94
- "Welcome to your new Blume docs.",
95
- "# Introduction\n\nWrite your docs here, and log releases under `changelog/`."
111
+ "Welcome to your new documentation site. Write guides as Markdown pages here, and log each release as an entry in the changelog folder.",
112
+ "Write your docs here, and log releases under `changelog/`: each entry joins the [changelog](/changelog), newest first."
96
113
  ),
97
114
  path: join(dir, "index.mdx"),
98
115
  },
99
116
  {
100
- content: `---\ntitle: v1.0.0\ntype: changelog\ndate: 2026-01-01\n---\n\nThe first release. Edit \`${dir}/changelog/v1-0-0.mdx\` or add new entries beside it.\n`,
117
+ content: `---\ntitle: v1.0.0\ndescription: The first release of the project. Replace this entry with your own release notes, and add a new file beside it for every version.\ntype: changelog\ndate: 2026-01-01\n---\n\nThe first release. Edit \`${dir}/changelog/v1-0-0.mdx\` or add new entries beside it.\n`,
101
118
  path: join(dir, "changelog", "v1-0-0.mdx"),
102
119
  },
103
120
  ],
104
121
  },
105
122
  docs: {
106
123
  configExtra: "",
124
+ configImports: [],
107
125
  files: (dir) => [
108
126
  {
109
127
  content: page(
110
128
  "Introduction",
111
- "Welcome to your new Blume docs.",
112
- `# Introduction\n\nWelcome to **Blume** — markdown-first docs powered by Astro and Vite.\n\nEdit \`${dir}/index.mdx\` to get started, then run \`blume dev\`.`
129
+ "Welcome to your new documentation site. Edit this page or add Markdown files beside it, and Blume turns each file into a page.",
130
+ `Welcome to **Blume**, the open-source docs framework for humans and agents.\n\nEdit \`${dir}/index.mdx\` and save: this page reloads with your changes.`
113
131
  ),
114
132
  path: join(dir, "index.mdx"),
115
133
  },
@@ -117,20 +135,21 @@ export const STARTERS = {
117
135
  },
118
136
  sdk: {
119
137
  configExtra: "",
138
+ configImports: [],
120
139
  files: (dir) => [
121
140
  {
122
141
  content: page(
123
142
  "Introduction",
124
- "Get started with the SDK.",
125
- "# Introduction\n\nInstall the SDK and make your first call. See [Installation](/installation)."
143
+ "Get started with the SDK. Install the package, configure a client, and make your first call in a few lines of code in your own app.",
144
+ "Install the SDK and make your first call. See [Installation](/installation)."
126
145
  ),
127
146
  path: join(dir, "index.mdx"),
128
147
  },
129
148
  {
130
149
  content: page(
131
150
  "Installation",
132
- "Install the SDK.",
133
- "# Installation\n\n```package-install\nyour-sdk\n```"
151
+ "Install the SDK with the package manager your project already uses, then import it into your code to start making requests to the API.",
152
+ "```package-install\nyour-sdk\n```"
134
153
  ),
135
154
  path: join(dir, "installation.mdx"),
136
155
  },
@@ -139,11 +158,13 @@ export const STARTERS = {
139
158
  } satisfies Record<Template, Starter>;
140
159
 
141
160
  /**
142
- * Install + dev commands to print for the chosen package manager, plus the
161
+ * Add, install, and dev commands to print for the chosen package manager, plus the
143
162
  * prefix that runs a locally installed bin (`exec`, e.g. `npx blume eject`) —
144
163
  * dependency bins aren't on PATH, so a bare `blume …` hint would not run.
145
164
  */
146
165
  export const commandsFor = (pm: PackageManager) => ({
166
+ // Adds a dependency: npm spells the verb `install`, the others `add`.
167
+ add: pm === "npm" ? "npm install" : `${pm} add`,
147
168
  // `bun build` invokes Bun's bundler, not the package.json `build` script —
148
169
  // unlike `bun dev`, the script name is shadowed by a builtin subcommand.
149
170
  build: pm === "npm" || pm === "bun" ? `${pm} run build` : `${pm} build`,
@@ -166,6 +187,25 @@ export const detectPackageManager = (userAgent?: string): PackageManager => {
166
187
  return name !== undefined && isPackageManager(name) ? name : "npm";
167
188
  };
168
189
 
190
+ /**
191
+ * The nearest directory at or above `root` holding `.git` (a directory, or
192
+ * the file a worktree or submodule carries), or null outside a repository.
193
+ * Checked by presence rather than by asking git, so no path spelling is ever
194
+ * compared: git prints its toplevel with symlinks and Windows 8.3 short
195
+ * names resolved, which nothing in Node canonicalizes to.
196
+ */
197
+ const repositoryRootOf = (root: string): string | null => {
198
+ let dir = root;
199
+ while (!existsSync(join(dir, ".git"))) {
200
+ const parent = dirname(dir);
201
+ if (parent === dir) {
202
+ return null;
203
+ }
204
+ dir = parent;
205
+ }
206
+ return dir;
207
+ };
208
+
169
209
  /**
170
210
  * Detect an existing project's package manager from its lockfile /
171
211
  * `packageManager` field (package-manager-detector), falling back to the
@@ -177,7 +217,15 @@ export const detectPackageManager = (userAgent?: string): PackageManager => {
177
217
  export const detectProjectPackageManager = async (
178
218
  root: string
179
219
  ): Promise<PackageManager> => {
180
- const detected = await detect({ cwd: root });
220
+ // A workspace package keeps its lockfile and `packageManager` field at the
221
+ // repository root, so the walk climbs that far — but no further, or a
222
+ // `package.json` in an unrelated ancestor (a user's home directory, say)
223
+ // decides the project's commands. Outside a repository the project root is
224
+ // the only directory that can be trusted.
225
+ const detected = await detect({
226
+ cwd: root,
227
+ stopDir: repositoryRootOf(root) ?? root,
228
+ });
181
229
  const name = detected?.name;
182
230
  return name !== undefined && isPackageManager(name)
183
231
  ? name
@@ -218,59 +266,141 @@ export const titleize = (raw: string): string => {
218
266
  const needsExplicitSources = (sources: SourceKind[]): boolean =>
219
267
  sources.some((source) => source !== "filesystem");
220
268
 
269
+ /** The `blume/sources` factory each source kind is written with. */
270
+ const SOURCE_FACTORIES = {
271
+ contentful: "contentful",
272
+ filesystem: "filesystem",
273
+ "github-releases": "githubReleases",
274
+ "mdx-remote": "mdxRemote",
275
+ notion: "notion",
276
+ obsidian: "obsidian",
277
+ payload: "payload",
278
+ sanity: "sanity",
279
+ strapi: "strapi",
280
+ } satisfies Record<SourceKind, string>;
281
+
282
+ /**
283
+ * The descriptor each remote source kind scaffolds — the same placeholder
284
+ * options the emitted snippet shows — so the SDK deps and env vars `init`
285
+ * sets up are read off the adapter rather than kept in a parallel table.
286
+ */
287
+ const SOURCE_DESCRIPTORS = {
288
+ contentful: contentful({
289
+ contentType: "doc",
290
+ prefix: "contentful",
291
+ space: "your-space-id",
292
+ }),
293
+ "github-releases": githubReleases({
294
+ owner: "your-org",
295
+ prefix: "changelog",
296
+ repo: "your-repo",
297
+ }),
298
+ "mdx-remote": mdxRemote({
299
+ github: { owner: "your-org", path: "docs", repo: "your-repo" },
300
+ prefix: "remote",
301
+ }),
302
+ notion: notion({ database: "your-database-id", prefix: "notion" }),
303
+ obsidian: obsidian({ prefix: "notes", vault: "vault" }),
304
+ payload: payload({
305
+ collection: "docs",
306
+ prefix: "payload",
307
+ url: "https://cms.example.com",
308
+ }),
309
+ sanity: sanity({
310
+ dataset: "production",
311
+ prefix: "sanity",
312
+ projectId: "your-project-id",
313
+ query: '*[_type == "doc"]',
314
+ }),
315
+ strapi: strapi({
316
+ contentType: "docs",
317
+ prefix: "strapi",
318
+ url: "https://cms.example.com",
319
+ }),
320
+ } satisfies Record<Exclude<SourceKind, "filesystem">, AnySourceAdapter>;
321
+
221
322
  /**
222
323
  * Config snippets for each remote source kind, with placeholder values to
223
324
  * replace and comments naming the env var each source authenticates with.
224
325
  */
225
326
  const SOURCE_SNIPPETS = {
327
+ contentful: ` // Entries of a Contentful content type. Reads CONTENTFUL_ACCESS_TOKEN
328
+ // from the environment.
329
+ contentful({
330
+ space: "your-space-id",
331
+ contentType: "doc",
332
+ prefix: "contentful",
333
+ }),`,
226
334
  "github-releases": ` // Changelog entries from GitHub Releases. Private repos read
227
335
  // GITHUB_TOKEN from the environment.
228
- {
229
- type: "github-releases",
336
+ githubReleases({
230
337
  owner: "your-org",
231
338
  repo: "your-repo",
232
339
  prefix: "changelog",
233
- },`,
340
+ }),`,
234
341
  "mdx-remote": ` // MDX fetched from a GitHub repo. Private repos read GITHUB_TOKEN
235
342
  // from the environment.
236
- {
237
- type: "mdx-remote",
343
+ mdxRemote({
238
344
  github: { owner: "your-org", repo: "your-repo", path: "docs" },
239
345
  prefix: "remote",
240
- },`,
346
+ }),`,
241
347
  notion: ` // Pages from a Notion database. Reads NOTION_TOKEN from the environment.
242
- {
243
- type: "notion",
348
+ notion({
244
349
  database: "your-database-id",
245
350
  prefix: "notion",
246
- },`,
351
+ }),`,
247
352
  obsidian: ` // An Obsidian vault, read in place. No export step, and no
248
353
  // generated notes in your repo. Point \`vault\` at your vault directory,
249
354
  // relative to this config file.
250
- {
251
- type: "obsidian",
355
+ obsidian({
252
356
  vault: "vault",
253
357
  prefix: "notes",
254
- },`,
358
+ }),`,
359
+ payload: ` // Documents from a Payload collection. Reads PAYLOAD_API_KEY from
360
+ // the environment.
361
+ payload({
362
+ url: "https://cms.example.com",
363
+ collection: "docs",
364
+ prefix: "payload",
365
+ }),`,
255
366
  sanity: ` // Documents from a Sanity dataset. Private datasets read SANITY_TOKEN
256
367
  // from the environment.
257
- {
258
- type: "sanity",
368
+ sanity({
259
369
  projectId: "your-project-id",
260
370
  dataset: "production",
261
371
  query: \`*[_type == "doc"]\`,
262
372
  prefix: "sanity",
263
- },`,
373
+ }),`,
374
+ strapi: ` // Entries of a Strapi content type. Reads STRAPI_API_TOKEN from
375
+ // the environment.
376
+ strapi({
377
+ url: "https://cms.example.com",
378
+ contentType: "docs",
379
+ prefix: "strapi",
380
+ }),`,
264
381
  } satisfies Record<Exclude<SourceKind, "filesystem">, string>;
265
382
 
383
+ /** The selected kinds in canonical order (the multiselect returns pick order). */
384
+ const orderedSources = (sources: SourceKind[]): SourceKind[] =>
385
+ SOURCE_KINDS.filter((kind) => sources.includes(kind));
386
+
387
+ /** The `blume/sources` import line for the selected kinds, in canonical order. */
388
+ const sourcesImportFor = (sources: SourceKind[]): string =>
389
+ `import { ${orderedSources(sources)
390
+ .map((kind) => SOURCE_FACTORIES[kind])
391
+ .join(", ")} } from "blume/sources";\n`;
392
+
393
+ /** The chosen source kinds; no selection means the implicit local source. */
394
+ const selectedSources = (answers: InitAnswers): SourceKind[] =>
395
+ answers.sources.length === 0 ? ["filesystem"] : answers.sources;
396
+
266
397
  /**
267
398
  * The `content` block for the generated config, or an empty string when the
268
399
  * defaults (filesystem source, `docs` root) apply — keeping the default
269
400
  * scaffold byte-identical to a config with no `content` key at all.
270
401
  */
271
402
  const contentBlockFor = (answers: InitAnswers): string => {
272
- const sources =
273
- answers.sources.length === 0 ? ["filesystem" as const] : answers.sources;
403
+ const sources = selectedSources(answers);
274
404
  if (!needsExplicitSources(sources)) {
275
405
  return answers.contentDir === "docs"
276
406
  ? ""
@@ -281,11 +411,10 @@ const contentBlockFor = (answers: InitAnswers): string => {
281
411
  }
282
412
  // Explicit sources replace the implicit filesystem desugar, so the local
283
413
  // content dir must be listed alongside the other sources to stay included.
284
- const entries = SOURCE_KINDS.filter((kind) => sources.includes(kind)).map(
285
- (kind) =>
286
- kind === "filesystem"
287
- ? ` { type: "filesystem", root: ${JSON.stringify(answers.contentDir)} },`
288
- : SOURCE_SNIPPETS[kind]
414
+ const entries = orderedSources(sources).map((kind) =>
415
+ kind === "filesystem"
416
+ ? ` filesystem({ root: ${JSON.stringify(answers.contentDir)} }),`
417
+ : SOURCE_SNIPPETS[kind]
289
418
  );
290
419
  return `
291
420
  content: {
@@ -296,32 +425,202 @@ ${entries.join("\n")}
296
425
  };
297
426
 
298
427
  /** The full `blume.config.ts` text for the chosen answers. */
299
- export const buildConfig = (
300
- answers: InitAnswers
301
- ): string => `import { defineConfig } from "blume";
302
-
428
+ export const buildConfig = (answers: InitAnswers): string => {
429
+ const starter = STARTERS[answers.template];
430
+ const sources = selectedSources(answers);
431
+ // Only an explicit `sources` array calls factories; the shorthand `root`
432
+ // (or no content block at all) needs no import.
433
+ const sourcesImport = needsExplicitSources(sources)
434
+ ? sourcesImportFor(sources)
435
+ : "";
436
+ const imports = [
437
+ 'import { defineConfig } from "blume";',
438
+ ...starter.configImports,
439
+ ].join("\n");
440
+ return `${imports}
441
+ ${sourcesImport}
303
442
  export default defineConfig({
304
443
  title: ${JSON.stringify(answers.title)},
305
- description: "Documentation powered by Blume.",${STARTERS[answers.template].configExtra}${contentBlockFor(answers)}
444
+ description: "Documentation powered by Blume.",${starter.configExtra}${contentBlockFor(answers)}
306
445
  });
307
446
  `;
447
+ };
448
+
449
+ /** The version range `init` pins for each SDK an adapter declares. */
450
+ const SDK_VERSIONS = new Map([
451
+ ["@notionhq/client", "^5.26.0"],
452
+ ["@sanity/client", "^8.6.1"],
453
+ ]);
454
+
455
+ /** The scaffolded descriptors for the selected remote source kinds. */
456
+ const descriptorsFor = (sources: SourceKind[]): AnySourceAdapter[] =>
457
+ orderedSources(sources).flatMap((kind) =>
458
+ kind === "filesystem" ? [] : [SOURCE_DESCRIPTORS[kind]]
459
+ );
308
460
 
309
- /** SDK dependencies required by the selected remote sources. */
461
+ /** SDK dependencies the selected sources declare, read off their descriptors. */
310
462
  const extraDepsFor = (sources: SourceKind[]) => {
311
463
  const deps: Record<string, string> = {};
312
- if (sources.includes("notion")) {
313
- deps["@notionhq/client"] = "^2.2.15";
314
- }
315
- if (sources.includes("sanity")) {
316
- deps["@sanity/client"] = "^7.25.0";
464
+ for (const descriptor of descriptorsFor(sources)) {
465
+ for (const dep of descriptor.runtimeDeps) {
466
+ deps[dep] = SDK_VERSIONS.get(dep) ?? "latest";
467
+ }
317
468
  }
318
469
  return deps;
319
470
  };
320
471
 
472
+ /**
473
+ * `pnpm-workspace.yaml` for a new pnpm project. pnpm runs a dependency's
474
+ * build script only once it's approved, and fails the install over any it
475
+ * wasn't told about. esbuild's postinstall checks its platform binary;
476
+ * `@scarf/scarf` is a telemetry postinstall a transitive dependency pulls in,
477
+ * and Blume doesn't need it to run.
478
+ */
479
+ const PNPM_WORKSPACE = `allowBuilds:
480
+ esbuild: true
481
+ "@scarf/scarf": false
482
+ `;
483
+
484
+ /**
485
+ * `.yarnrc.yml` for a new Yarn Berry project. Berry installs with Plug'n'Play
486
+ * by default, which writes no `node_modules`; Blume's generated Astro project
487
+ * resolves its packages from one. Yarn Classic never reads this file.
488
+ */
489
+ const YARNRC = `# Blume's generated Astro project resolves packages from node_modules, which
490
+ # Yarn's default Plug'n'Play install doesn't create.
491
+ nodeLinker: node-modules
492
+ `;
493
+
494
+ /**
495
+ * The nearest directory at or above `root` where `found` holds, searching up
496
+ * to the repository root — or to the filesystem root outside a repository,
497
+ * where a workspace can still enclose the project.
498
+ */
499
+ const nearestAncestor = (
500
+ root: string,
501
+ found: (dir: string) => boolean
502
+ ): string | null => {
503
+ const stop = repositoryRootOf(root);
504
+ let dir = root;
505
+ while (!found(dir)) {
506
+ const parent = dirname(dir);
507
+ if (dir === stop || parent === dir) {
508
+ return null;
509
+ }
510
+ dir = parent;
511
+ }
512
+ return dir;
513
+ };
514
+
515
+ /** Read a file, or `""` when it can't be read. */
516
+ const readText = (path: string): string => {
517
+ try {
518
+ return readFileSync(path, "utf-8");
519
+ } catch {
520
+ return "";
521
+ }
522
+ };
523
+
524
+ /** The pnpm workspace enclosing `root`: the directory of its `pnpm-workspace.yaml`. */
525
+ const pnpmWorkspaceRoot = (root: string): string | null =>
526
+ nearestAncestor(root, (dir) => existsSync(join(dir, "pnpm-workspace.yaml")));
527
+
528
+ /**
529
+ * The Yarn project enclosing `root`: a directory holding a lockfile, a
530
+ * `.yarnrc.yml`, or a `package.json` that declares workspaces.
531
+ */
532
+ const yarnProjectRoot = (root: string): string | null =>
533
+ nearestAncestor(
534
+ root,
535
+ (dir) =>
536
+ existsSync(join(dir, "yarn.lock")) ||
537
+ existsSync(join(dir, ".yarnrc.yml")) ||
538
+ /"workspaces"\s*:/u.test(readText(join(dir, "package.json")))
539
+ );
540
+
541
+ /**
542
+ * The major version of the Yarn that ran `init`, read off the npm user agent
543
+ * (`yarn/4.5.1 npm/? node/v22…`), or undefined when something else ran it.
544
+ */
545
+ export const yarnMajor = (userAgent?: string): number | undefined => {
546
+ const match = /^yarn\/(?<major>\d+)\./u.exec(userAgent ?? "");
547
+ return match?.groups?.major === undefined
548
+ ? undefined
549
+ : Number(match.groups.major);
550
+ };
551
+
552
+ /** Environment `buildPlan` and `workspaceNote` read, injectable for tests. */
553
+ export interface PlanEnvironment {
554
+ /** `npm_config_user_agent` of the process that ran `init`. */
555
+ userAgent?: string;
556
+ }
557
+
558
+ /**
559
+ * The package-manager config file a project `init` creates from scratch
560
+ * needs: pnpm's build approvals, or Yarn Berry's `node_modules` linker. An
561
+ * existing package.json, or a workspace the project joins, already owns that
562
+ * decision (see {@link workspaceNote}); Yarn Classic ignores `.yarnrc.yml`, so
563
+ * a user agent naming Yarn 1 skips it.
564
+ */
565
+ const packageManagerConfigFor = (
566
+ root: string,
567
+ answers: InitAnswers,
568
+ env: PlanEnvironment
569
+ ): ScaffoldFile[] => {
570
+ if (existsSync(join(root, "package.json"))) {
571
+ return [];
572
+ }
573
+ if (answers.packageManager === "pnpm" && pnpmWorkspaceRoot(root) === null) {
574
+ return [
575
+ { content: PNPM_WORKSPACE, path: join(root, "pnpm-workspace.yaml") },
576
+ ];
577
+ }
578
+ if (
579
+ answers.packageManager === "yarn" &&
580
+ yarnMajor(env.userAgent) !== 1 &&
581
+ yarnProjectRoot(root) === null
582
+ ) {
583
+ return [{ content: YARNRC, path: join(root, ".yarnrc.yml") }];
584
+ }
585
+ return [];
586
+ };
587
+
588
+ /**
589
+ * What the project still needs from a workspace it joins, when `init` left
590
+ * that workspace's config alone: pnpm's approval for esbuild's build script
591
+ * (pnpm 10 and later fail the install without it), or Yarn Berry's
592
+ * `node_modules` linker. Undefined when the workspace already has it, or the
593
+ * project doesn't sit in one.
594
+ */
595
+ export const workspaceNote = (
596
+ root: string,
597
+ answers: InitAnswers,
598
+ env: PlanEnvironment = {}
599
+ ): string | undefined => {
600
+ if (answers.packageManager === "pnpm") {
601
+ const workspace = pnpmWorkspaceRoot(root);
602
+ const file = workspace && join(workspace, "pnpm-workspace.yaml");
603
+ if (!file || readText(file).includes("esbuild")) {
604
+ return;
605
+ }
606
+ return `This project joins the pnpm workspace at ${file}. Approve esbuild's build script there before installing, or pnpm 10 and later stop the install:\n\n allowBuilds:\n esbuild: true`;
607
+ }
608
+ if (answers.packageManager !== "yarn" || yarnMajor(env.userAgent) === 1) {
609
+ return;
610
+ }
611
+ const project = yarnProjectRoot(root);
612
+ const rc = project && join(project, ".yarnrc.yml");
613
+ if (!rc || /^nodeLinker:\s*["']?(?:node-modules|pnpm)/mu.test(readText(rc))) {
614
+ return;
615
+ }
616
+ return `This project joins the Yarn project at ${project}. With Yarn 2 or later, set its linker in ${rc} so installs write the node_modules Blume's generated Astro project resolves packages from:\n\n nodeLinker: node-modules`;
617
+ };
618
+
321
619
  /** Every file `init` should write for the given answers, package.json first. */
322
620
  export const buildPlan = (
323
621
  root: string,
324
- answers: InitAnswers
622
+ answers: InitAnswers,
623
+ env: PlanEnvironment = {}
325
624
  ): ScaffoldFile[] => {
326
625
  const files: ScaffoldFile[] = [
327
626
  {
@@ -331,6 +630,7 @@ export const buildPlan = (
331
630
  ),
332
631
  path: join(root, "package.json"),
333
632
  },
633
+ ...packageManagerConfigFor(root, answers, env),
334
634
  { content: buildConfig(answers), path: join(root, "blume.config.ts") },
335
635
  ];
336
636
  // Seed pages only make sense when a local filesystem source will read them.
@@ -370,7 +670,7 @@ const writeFileSafe = async (
370
670
 
371
671
  /**
372
672
  * Write the plan's files, skipping any that already exist. Reports whether a
373
- * `package.json` was newly created (it decides the install next-step).
673
+ * `package.json` was newly created (it decides whether `init` installs).
374
674
  */
375
675
  export const applyPlan = async (
376
676
  files: ScaffoldFile[],
@@ -385,34 +685,118 @@ export const applyPlan = async (
385
685
  return { createdPackage };
386
686
  };
387
687
 
388
- /** Env vars the selected sources read, in a stable order. */
389
- const envVarsFor = (sources: SourceKind[]): string[] =>
390
- [
391
- ["GITHUB_TOKEN", ["github-releases", "mdx-remote"]] as const,
392
- ["NOTION_TOKEN", ["notion"]] as const,
393
- ["SANITY_TOKEN", ["sanity"]] as const,
394
- ]
395
- .filter(([, kinds]) => kinds.some((kind) => sources.includes(kind)))
396
- .map(([envVar]) => envVar);
397
-
398
- /** The next-steps message: `cd` hint, install/dev commands, and token setup. */
688
+ /** Env vars the selected sources declare, deduplicated in a stable order. */
689
+ const envVarsFor = (sources: SourceKind[]): string[] => [
690
+ ...new Set(
691
+ descriptorsFor(sources).flatMap((descriptor) => descriptor.requiredSecrets)
692
+ ),
693
+ ];
694
+
695
+ /** What an existing package.json — one `init` left alone — already wires up. */
696
+ export interface ExistingPackage {
697
+ /**
698
+ * Whether `blume` is installed where the project resolves it: its own
699
+ * `node_modules`, or an ancestor's in a hoisted workspace. Listing it isn't
700
+ * enough — a rerun of `init --no-install` lists it without installing it.
701
+ */
702
+ blumeInstalled: boolean;
703
+ /** Every package it lists in `dependencies` or `devDependencies`. */
704
+ dependencies: string[];
705
+ /** Whether its `dev` script runs Blume. */
706
+ devRunsBlume: boolean;
707
+ }
708
+
709
+ /** Whether a `node_modules/blume` sits in `root` or any directory above it. */
710
+ const blumeResolves = (root: string): boolean => {
711
+ let dir = root;
712
+ while (!existsSync(join(dir, "node_modules", "blume", "package.json"))) {
713
+ const parent = dirname(dir);
714
+ if (parent === dir) {
715
+ return false;
716
+ }
717
+ dir = parent;
718
+ }
719
+ return true;
720
+ };
721
+
722
+ /**
723
+ * Read the package.json `init` didn't write. An unreadable or malformed one
724
+ * reads as wiring nothing up, so the next steps list everything to add.
725
+ */
726
+ export const readExistingPackage = async (
727
+ root: string
728
+ ): Promise<ExistingPackage> => {
729
+ try {
730
+ // SAFETY: only the two dependency maps and the `dev` script are read, all
731
+ // optional; `String()` absorbs a script that isn't a string.
732
+ const pkg = JSON.parse(
733
+ await readFile(join(root, "package.json"), "utf-8")
734
+ ) as {
735
+ dependencies?: Record<string, string>;
736
+ devDependencies?: Record<string, string>;
737
+ scripts?: Record<string, string>;
738
+ };
739
+ return {
740
+ blumeInstalled: blumeResolves(root),
741
+ dependencies: Object.keys({
742
+ ...pkg.dependencies,
743
+ ...pkg.devDependencies,
744
+ }),
745
+ devRunsBlume: String(pkg.scripts?.dev ?? "").includes("blume"),
746
+ };
747
+ } catch {
748
+ return {
749
+ blumeInstalled: blumeResolves(root),
750
+ dependencies: [],
751
+ devRunsBlume: false,
752
+ };
753
+ }
754
+ };
755
+
756
+ /**
757
+ * The next-steps message: `cd` hint, the install command when `init` did not
758
+ * run it itself, the dev command, and token setup. With an `existing`
759
+ * package.json — which `init` never edits — it first adds whatever of `blume`
760
+ * and the sources' SDKs isn't listed yet (or installs, when everything is
761
+ * listed but `blume` was never installed), then starts the dev server through
762
+ * the package runner unless its `dev` script already runs Blume. A `note` —
763
+ * what a workspace the project joins still needs — closes the message.
764
+ */
399
765
  export const nextSteps = (
400
766
  answers: InitAnswers,
401
- createdPackage: boolean
767
+ needsInstall: boolean,
768
+ existing?: ExistingPackage,
769
+ note?: string
402
770
  ): string => {
403
771
  const commands = commandsFor(answers.packageManager);
404
772
  const lines: string[] = [];
405
773
  if (answers.directory !== ".") {
406
774
  lines.push(`cd ${answers.directory}`);
407
775
  }
408
- if (createdPackage) {
776
+ if (needsInstall) {
409
777
  lines.push(commands.install);
410
778
  }
411
- lines.push(commands.dev);
779
+ if (existing) {
780
+ const missing = [
781
+ "blume",
782
+ ...Object.keys(extraDepsFor(answers.sources)),
783
+ ].filter((dep) => !existing.dependencies.includes(dep));
784
+ if (missing.length > 0) {
785
+ lines.push(`${commands.add} ${missing.join(" ")}`);
786
+ } else if (!(needsInstall || existing.blumeInstalled)) {
787
+ lines.push(commands.install);
788
+ }
789
+ }
790
+ lines.push(
791
+ existing && !existing.devRunsBlume
792
+ ? `${commands.exec} blume dev`
793
+ : commands.dev
794
+ );
412
795
  const envVars = envVarsFor(answers.sources);
413
796
  const auth =
414
797
  envVars.length > 0
415
798
  ? `\nSet ${envVars.join(" and ")} in .env.local so your sources can authenticate.\n`
416
799
  : "";
417
- return `Next steps:\n\n ${lines.join("\n ")}\n${auth}`;
800
+ const workspace = note ? `\n${note}\n` : "";
801
+ return `Next steps:\n\n ${lines.join("\n ")}\n${auth}${workspace}`;
418
802
  };