blume 1.5.3 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (209) hide show
  1. package/CHANGELOG.md +94 -0
  2. package/dist/cli/index.js +3949 -1403
  3. package/dist/cli/index.js.map +111 -96
  4. package/dist/types/ai/component-markdown.d.ts +79 -0
  5. package/dist/types/components/layout/nav-utils.d.ts +60 -0
  6. package/dist/types/core/base-path.d.ts +9 -0
  7. package/dist/types/core/config-input.d.ts +206 -4
  8. package/dist/types/core/config.d.ts +6 -4
  9. package/dist/types/core/data.d.ts +33 -2
  10. package/dist/types/core/github.d.ts +35 -0
  11. package/dist/types/core/i18n-ui.d.ts +10 -0
  12. package/dist/types/core/navigation.d.ts +69 -0
  13. package/dist/types/core/schema.d.ts +122 -1
  14. package/dist/types/core/sources/types.d.ts +31 -6
  15. package/dist/types/core/types.d.ts +29 -2
  16. package/dist/types/markdown/features.d.ts +21 -0
  17. package/dist/types/openapi/references.d.ts +26 -1
  18. package/dist/types/seo/jsonld.d.ts +105 -0
  19. package/dist/types/theme/fonts.d.ts +34 -4
  20. package/docs/07-faq.mdx +9 -9
  21. package/docs/_snippets/include-demo.mdx +7 -0
  22. package/docs/advanced/api-reference.mdx +13 -4
  23. package/docs/advanced/custom-pages.mdx +4 -2
  24. package/docs/advanced/graphql.mdx +84 -0
  25. package/docs/advanced/meta.ts +8 -1
  26. package/docs/configuration/ai.mdx +25 -3
  27. package/docs/configuration/index.mdx +24 -0
  28. package/docs/configuration/search.mdx +13 -1
  29. package/docs/configuration/seo.mdx +30 -3
  30. package/docs/configuration/theming.mdx +23 -0
  31. package/docs/content/components.mdx +15 -1
  32. package/docs/content/includes.mdx +68 -0
  33. package/docs/content/meta.ts +1 -0
  34. package/docs/content/navigation.mdx +25 -0
  35. package/docs/content/sources.mdx +42 -1
  36. package/docs/content/syntax.mdx +69 -1
  37. package/docs/content/versioning.mdx +15 -9
  38. package/docs/reference/cli.mdx +2 -1
  39. package/package.json +66 -57
  40. package/skills/blume-migrate/SKILL.md +16 -7
  41. package/skills/blume-migrate/references/docusaurus.md +5 -3
  42. package/skills/blume-migrate/references/fumadocs.md +10 -2
  43. package/skills/blume-migrate/references/mintlify.md +3 -2
  44. package/skills/blume-migrate/references/nextra.md +2 -2
  45. package/skills/blume-migrate/references/starlight.md +1 -1
  46. package/src/ai/agent-readability.ts +2 -1
  47. package/src/ai/ask-data.ts +2 -1
  48. package/src/ai/component-markdown.ts +199 -36
  49. package/src/ai/llms.ts +93 -6
  50. package/src/ai/markdown.ts +2 -2
  51. package/src/ai/mcp/discovery.ts +10 -2
  52. package/src/ai/mcp/server.ts +74 -2
  53. package/src/astro/examples.ts +29 -2
  54. package/src/astro/generate.ts +282 -177
  55. package/src/astro/include-hmr.ts +81 -0
  56. package/src/astro/include-refresh.ts +0 -0
  57. package/src/astro/index.ts +10 -5
  58. package/src/astro/markdown-negotiation.ts +1 -1
  59. package/src/astro/runtime-modules.ts +196 -0
  60. package/src/astro/templates.ts +365 -113
  61. package/src/cli/commands/build.ts +91 -16
  62. package/src/cli/commands/dev.ts +6 -3
  63. package/src/cli/host-args.ts +18 -0
  64. package/src/cli/index.ts +2 -1
  65. package/src/cli/init/questions.ts +1 -0
  66. package/src/cli/init/scaffold.ts +27 -4
  67. package/src/components/colors.ts +142 -0
  68. package/src/components/content/Badge.astro +5 -12
  69. package/src/components/content/Callout.astro +19 -36
  70. package/src/components/content/Card.astro +15 -21
  71. package/src/components/content/Component.astro +10 -1
  72. package/src/components/content/GithubInfo.astro +28 -9
  73. package/src/components/content/Tabs.astro +27 -5
  74. package/src/components/content/github-info.ts +20 -5
  75. package/src/components/copy-feedback.ts +93 -9
  76. package/src/components/dropdown-dismiss.ts +122 -0
  77. package/src/components/islands/ask-ai.tsx +4 -1
  78. package/src/components/islands/hooks.ts +3 -1
  79. package/src/components/layout/Fonts.astro +15 -8
  80. package/src/components/layout/Header.astro +44 -0
  81. package/src/components/layout/LanguageSwitcher.astro +9 -1
  82. package/src/components/layout/NavSelector.astro +12 -3
  83. package/src/components/layout/NavTree.astro +6 -18
  84. package/src/components/layout/PageActions.astro +54 -22
  85. package/src/components/layout/PageLayout.astro +2 -0
  86. package/src/components/layout/ReferenceLayout.astro +6 -1
  87. package/src/components/layout/RootLayout.astro +42 -15
  88. package/src/components/layout/Search.astro +36 -4
  89. package/src/components/layout/TableOfContents.astro +8 -2
  90. package/src/components/layout/head-scripts.ts +30 -1
  91. package/src/components/openapi/ApiOverview.astro +13 -3
  92. package/src/components/openapi/AsyncApiOperation.astro +7 -14
  93. package/src/components/openapi/GraphqlChip.astro +33 -0
  94. package/src/components/openapi/GraphqlFieldsTable.astro +111 -0
  95. package/src/components/openapi/GraphqlOperation.astro +186 -0
  96. package/src/components/openapi/GraphqlType.astro +154 -0
  97. package/src/components/openapi/MethodBadge.astro +3 -14
  98. package/src/components/openapi/Operation.astro +12 -5
  99. package/src/components/openapi/OperationPanel.astro +43 -0
  100. package/src/components/openapi/RequestPanel.astro +5 -10
  101. package/src/components/openapi/Responses.astro +1 -16
  102. package/src/components/openapi/graphql-helpers.ts +466 -0
  103. package/src/components/openapi/playground-client.ts +15 -0
  104. package/src/components/openapi/sample-panels.ts +45 -0
  105. package/src/components/openapi/snippets.ts +13 -35
  106. package/src/core/base-path.ts +11 -0
  107. package/src/core/config-input.ts +209 -2
  108. package/src/core/config.ts +6 -4
  109. package/src/core/content-assets.ts +15 -4
  110. package/src/core/data.ts +28 -3
  111. package/src/core/define-components.ts +2 -0
  112. package/src/core/diagnostics.ts +8 -0
  113. package/src/core/frontmatter.ts +20 -8
  114. package/src/core/github.ts +71 -0
  115. package/src/core/graph.ts +22 -8
  116. package/src/core/heading-markers.ts +96 -0
  117. package/src/core/i18n-ui.ts +12 -0
  118. package/src/core/includes.ts +633 -0
  119. package/src/core/last-modified.ts +36 -11
  120. package/src/core/links.ts +79 -13
  121. package/src/core/manifest.ts +10 -0
  122. package/src/core/meta.ts +2 -1
  123. package/src/core/nav-diagnostics.ts +11 -2
  124. package/src/core/navigation.ts +27 -6
  125. package/src/core/project-graph.ts +61 -9
  126. package/src/core/schema.ts +235 -36
  127. package/src/core/server-features.ts +5 -9
  128. package/src/core/sources/github-releases.ts +2 -2
  129. package/src/core/sources/normalize.ts +502 -115
  130. package/src/core/sources/notion.ts +43 -8
  131. package/src/core/sources/obsidian.ts +1038 -0
  132. package/src/core/sources/read.ts +36 -1
  133. package/src/core/sources/resolve.ts +34 -1
  134. package/src/core/sources/types.ts +28 -6
  135. package/src/core/sources/watch.ts +12 -8
  136. package/src/core/tsconfig-aliases.ts +48 -35
  137. package/src/core/types.ts +31 -2
  138. package/src/core/ui-packs/ar.ts +2 -0
  139. package/src/core/ui-packs/bg.ts +3 -0
  140. package/src/core/ui-packs/bn.ts +2 -0
  141. package/src/core/ui-packs/ca.ts +3 -0
  142. package/src/core/ui-packs/cs.ts +2 -0
  143. package/src/core/ui-packs/da.ts +2 -0
  144. package/src/core/ui-packs/de.ts +3 -0
  145. package/src/core/ui-packs/el.ts +3 -0
  146. package/src/core/ui-packs/es.ts +3 -0
  147. package/src/core/ui-packs/fa.ts +2 -0
  148. package/src/core/ui-packs/fi.ts +2 -0
  149. package/src/core/ui-packs/fr.ts +3 -0
  150. package/src/core/ui-packs/he.ts +2 -0
  151. package/src/core/ui-packs/hi.ts +2 -0
  152. package/src/core/ui-packs/hr.ts +3 -0
  153. package/src/core/ui-packs/hu.ts +3 -0
  154. package/src/core/ui-packs/id.ts +3 -0
  155. package/src/core/ui-packs/it.ts +2 -0
  156. package/src/core/ui-packs/ja.ts +3 -0
  157. package/src/core/ui-packs/ko.ts +3 -0
  158. package/src/core/ui-packs/nl.ts +3 -0
  159. package/src/core/ui-packs/no.ts +3 -0
  160. package/src/core/ui-packs/pl.ts +3 -0
  161. package/src/core/ui-packs/pt-br.ts +3 -0
  162. package/src/core/ui-packs/pt.ts +3 -0
  163. package/src/core/ui-packs/ro.ts +3 -0
  164. package/src/core/ui-packs/ru.ts +3 -0
  165. package/src/core/ui-packs/sk.ts +2 -0
  166. package/src/core/ui-packs/sr.ts +2 -0
  167. package/src/core/ui-packs/sv.ts +3 -0
  168. package/src/core/ui-packs/th.ts +2 -0
  169. package/src/core/ui-packs/tr.ts +3 -0
  170. package/src/core/ui-packs/uk.ts +3 -0
  171. package/src/core/ui-packs/vi.ts +2 -0
  172. package/src/core/ui-packs/zh-tw.ts +2 -0
  173. package/src/core/ui-packs/zh.ts +2 -0
  174. package/src/core/version-cut.ts +26 -6
  175. package/src/core/yaml.ts +26 -0
  176. package/src/deploy/function-bundle.ts +251 -0
  177. package/src/deploy/vercel-negotiation.ts +49 -6
  178. package/src/eval/schema.ts +3 -1
  179. package/src/markdown/code-title.ts +22 -16
  180. package/src/markdown/features.ts +21 -0
  181. package/src/markdown/fence-meta.ts +50 -0
  182. package/src/markdown/heading-anchors.ts +198 -37
  183. package/src/markdown/include.ts +247 -0
  184. package/src/markdown/index.ts +43 -34
  185. package/src/markdown/language-icon.ts +2 -2
  186. package/src/markdown/mdast.ts +7 -3
  187. package/src/markdown/ts2js.ts +264 -0
  188. package/src/og/card.ts +1 -1
  189. package/src/openapi/asyncapi.ts +4 -1
  190. package/src/openapi/graphql-build.ts +293 -0
  191. package/src/openapi/graphql.ts +212 -0
  192. package/src/openapi/model.ts +38 -5
  193. package/src/openapi/parse.ts +34 -0
  194. package/src/openapi/proxy.ts +30 -5
  195. package/src/openapi/references.ts +97 -13
  196. package/src/openapi/render-mdx.ts +66 -12
  197. package/src/openapi/scalar.ts +5 -16
  198. package/src/openapi/source.ts +91 -23
  199. package/src/registry/eject.ts +47 -17
  200. package/src/search/documents.ts +229 -37
  201. package/src/search/orama-index.ts +9 -5
  202. package/src/seo/jsonld.ts +293 -51
  203. package/src/theme/code-block-padding.ts +16 -0
  204. package/src/theme/entry.ts +67 -13
  205. package/src/theme/fonts.ts +189 -16
  206. package/src/theme/sources.ts +49 -0
  207. package/src/translate/prompts.ts +2 -0
  208. package/src/translate/run.ts +7 -0
  209. package/src/translate/work-list.ts +0 -0
@@ -3,7 +3,7 @@ import { readFile } from "node:fs/promises";
3
3
  import { rewriteRelativeImages } from "../core/content-assets.ts";
4
4
  import matter from "../core/frontmatter.ts";
5
5
  import type { BlumeProject } from "../core/project-graph.ts";
6
- import { readEntryText } from "../core/sources/read.ts";
6
+ import { readExpandedEntryText } from "../core/sources/read.ts";
7
7
  import type { RouteManifestEntry } from "../core/types.ts";
8
8
  import {
9
9
  downlevelComponents,
@@ -65,7 +65,7 @@ export const buildRawMarkdown = async (
65
65
  const readRoute = async (route: RouteManifestEntry): Promise<string> => {
66
66
  const page = pageById.get(route.id);
67
67
  if (page) {
68
- return await readEntryText(project, page);
68
+ return await readExpandedEntryText(project, page);
69
69
  }
70
70
  return route.sourcePath ? await readFile(route.sourcePath, "utf-8") : "";
71
71
  };
@@ -103,7 +103,10 @@ const HTTP_URL = /^https?:\/\//u;
103
103
  */
104
104
  export interface McpServerCard {
105
105
  $schema: string;
106
- capabilities: { tools: { listChanged: boolean } };
106
+ capabilities: {
107
+ resources: { listChanged: boolean; subscribe: boolean };
108
+ tools: { listChanged: boolean };
109
+ };
107
110
  description: string;
108
111
  name: string;
109
112
  /** Absolute endpoints only — present when a `site` is configured. */
@@ -122,7 +125,12 @@ export const buildMcpServerCard = (input: McpDiscoveryInput): McpServerCard => {
122
125
  const url = serverUrl(input);
123
126
  const card: McpServerCard = {
124
127
  $schema: SERVER_CARD_SCHEMA,
125
- capabilities: { tools: { listChanged: false } },
128
+ // Resources mirror the page list (one `text/markdown` resource per page);
129
+ // a rebuilt site replaces the server wholesale, so nothing changes live.
130
+ capabilities: {
131
+ resources: { listChanged: false, subscribe: false },
132
+ tools: { listChanged: false },
133
+ },
126
134
  description: truncate(
127
135
  `Model Context Protocol server for the ${input.name} documentation.`
128
136
  ),
@@ -3,7 +3,10 @@ import type { ServerOptions } from "@modelcontextprotocol/sdk/server/index.js";
3
3
  import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
4
4
  import {
5
5
  CallToolRequestSchema,
6
+ ListResourcesRequestSchema,
6
7
  ListToolsRequestSchema,
8
+ McpError,
9
+ ReadResourceRequestSchema,
7
10
  } from "@modelcontextprotocol/sdk/types.js";
8
11
  import { z } from "zod";
9
12
 
@@ -33,6 +36,12 @@ const DEFAULT_SEARCH_LIMIT = 8;
33
36
  const MAX_SEARCH_LIMIT = 20;
34
37
  /** Excerpt length when a page has no description. */
35
38
  const EXCERPT_LENGTH = 200;
39
+ /** Every page resource is the page's agent Markdown. */
40
+ const RESOURCE_MIME_TYPE = "text/markdown";
41
+ /** The MCP spec's JSON-RPC code for an unknown resource URI. */
42
+ const RESOURCE_NOT_FOUND = -32_002;
43
+ /** URI scheme for page resources when no `deployment.site` is configured. */
44
+ const LOCAL_RESOURCE_SCHEME = "blume:";
36
45
 
37
46
  const CORS_HEADERS = {
38
47
  "Access-Control-Allow-Headers":
@@ -191,6 +200,15 @@ interface SearchHitPayload {
191
200
  version?: string;
192
201
  }
193
202
 
203
+ /** One `resources/list` entry: a page served as `text/markdown`. */
204
+ interface PageResource {
205
+ description?: string;
206
+ mimeType: string;
207
+ name: string;
208
+ title: string;
209
+ uri: string;
210
+ }
211
+
194
212
  /** One `list_pages` entry; `version` only appears on versioned sites. */
195
213
  interface PageListingPayload {
196
214
  contentType: string;
@@ -288,6 +306,26 @@ const urlFor = (route: string, data: McpData): string => {
288
306
  return data.site ? absoluteUrl(data.site, path) : path;
289
307
  };
290
308
 
309
+ /**
310
+ * A page's resource URI. Resource URIs must be absolute, so this is the page's
311
+ * served URL when a site is configured (the same URL `search_docs` and
312
+ * `list_pages` emit, so an agent can hand either back to `resources/read`),
313
+ * and a `blume:` URI carrying the based route otherwise.
314
+ */
315
+ const resourceUri = (route: string, data: McpData): string =>
316
+ data.site
317
+ ? urlFor(route, data)
318
+ : `${LOCAL_RESOURCE_SCHEME}${withBasePath(data.base, route)}`;
319
+
320
+ /** The `pages` key a resource URI (either form, or a bare route) names. */
321
+ const resourceRoute = (uri: string, data: McpData): string =>
322
+ normalizeRoute(
323
+ uri.startsWith(LOCAL_RESOURCE_SCHEME)
324
+ ? uri.slice(LOCAL_RESOURCE_SCHEME.length)
325
+ : uri,
326
+ data
327
+ );
328
+
291
329
  /** A hit's excerpt: its description, else the head of its content with an
292
330
  * ellipsis only when something was actually cut off. */
293
331
  const excerptFor = (doc: OramaDoc): string => {
@@ -331,9 +369,10 @@ export const buildServer = (
331
369
  data: McpData,
332
370
  index: OramaIndexProvider
333
371
  ): Server => {
372
+ const capabilities = { resources: {}, tools: {} };
334
373
  const serverOptions: ServerOptions = data.instructions
335
- ? { capabilities: { tools: {} }, instructions: data.instructions }
336
- : { capabilities: { tools: {} } };
374
+ ? { capabilities, instructions: data.instructions }
375
+ : { capabilities };
337
376
  const server = new Server(
338
377
  { name: data.name, version: data.version },
339
378
  serverOptions
@@ -343,6 +382,39 @@ export const buildServer = (
343
382
  tools: TOOL_DEFINITIONS,
344
383
  }));
345
384
 
385
+ // Every page doubles as a resource, so a client that attaches context by
386
+ // URI (rather than calling tools) can browse and read the docs too. The
387
+ // list is the same route set `list_pages` returns; reading one serves the
388
+ // same agent Markdown `get_page` does.
389
+ server.setRequestHandler(ListResourcesRequestSchema, () => ({
390
+ resources: data.routes.map((route) => {
391
+ const resource: PageResource = {
392
+ mimeType: RESOURCE_MIME_TYPE,
393
+ name: route.title,
394
+ title: route.title,
395
+ uri: resourceUri(route.route, data),
396
+ };
397
+ if (route.description) {
398
+ resource.description = route.description;
399
+ }
400
+ return resource;
401
+ }),
402
+ }));
403
+
404
+ server.setRequestHandler(ReadResourceRequestSchema, (request) => {
405
+ const { uri } = request.params;
406
+ const markdown = data.pages[resourceRoute(uri, data)];
407
+ if (markdown === undefined) {
408
+ throw new McpError(
409
+ RESOURCE_NOT_FOUND,
410
+ `No page found at "${uri}". Use resources/list or list_pages to find valid URIs.`
411
+ );
412
+ }
413
+ return {
414
+ contents: [{ mimeType: RESOURCE_MIME_TYPE, text: markdown, uri }],
415
+ };
416
+ });
417
+
346
418
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
347
419
  const { arguments: args = {}, name } = request.params;
348
420
 
@@ -1,7 +1,7 @@
1
1
  import { readFile } from "node:fs/promises";
2
2
 
3
3
  import pMap from "p-map";
4
- import { join, relative } from "pathe";
4
+ import { isAbsolute, join, relative } from "pathe";
5
5
  import { glob } from "tinyglobby";
6
6
 
7
7
  import type { ExampleLookup } from "../core/types.ts";
@@ -28,6 +28,11 @@ export interface ExampleSpec {
28
28
  }
29
29
 
30
30
  export interface ExampleDiscovery {
31
+ /**
32
+ * Absolute directory the examples were discovered under: the configured
33
+ * `examples.source` (or a glob's static prefix) resolved against the root.
34
+ */
35
+ dir: string;
31
36
  examples: ExampleSpec[];
32
37
  warnings: string[];
33
38
  }
@@ -56,6 +61,28 @@ const DEFAULT_EXAMPLE_GLOB = "**/*.{astro,jsx,svelte,tsx,vue}";
56
61
  /** Ceiling on concurrent example-file reads; unbounded fan-out risks EMFILE. */
57
62
  const READ_CONCURRENCY = 16;
58
63
 
64
+ /**
65
+ * Files the preview-frame Tailwind entry scans for utility classes, appended
66
+ * to each directory from `exampleScanRoots`.
67
+ */
68
+ export const EXAMPLE_SCAN_GLOB = "**/*.{astro,jsx,svelte,ts,tsx,vue}";
69
+
70
+ /**
71
+ * Directories the `<Component />` preview sheet scans for utility classes:
72
+ * the project root, plus the examples directory when it lives outside the
73
+ * root (a sibling workspace package, say). Tailwind's `@source` is a file
74
+ * glob, not an import graph, so an out-of-root examples directory would
75
+ * otherwise contribute no utilities and previews would render half-styled.
76
+ */
77
+ export const exampleScanRoots = (
78
+ root: string,
79
+ examplesDir: string
80
+ ): string[] => {
81
+ const path = relative(root, examplesDir);
82
+ const outside = path.startsWith("..") || isAbsolute(path);
83
+ return outside ? [root, examplesDir] : [root];
84
+ };
85
+
59
86
  // Glob magic that turns `examples` from a plain directory into a pattern. `()`,
60
87
  // `@`, and `+` are excluded so literal path segments (npm scopes, parens) keep
61
88
  // resolving as directories; the extglob leads `*?!` still trigger here.
@@ -153,7 +180,7 @@ export const discoverExamples = async (
153
180
  collectExample(file, sources[index] ?? "");
154
181
  }
155
182
 
156
- return { examples, warnings };
183
+ return { dir, examples, warnings };
157
184
  };
158
185
 
159
186
  /**