blume 1.7.0 → 1.7.2

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 (119) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/cli/{chunk-9qs6acpw.js → chunk-12dxjqk7.js} +32 -43
  3. package/dist/cli/{chunk-9qs6acpw.js.map → chunk-12dxjqk7.js.map} +2 -2
  4. package/dist/cli/{chunk-s5dsk8bj.js → chunk-196vjxp9.js} +65 -64
  5. package/dist/cli/chunk-196vjxp9.js.map +13 -0
  6. package/dist/cli/{chunk-27gtm2ym.js → chunk-2mzebbbz.js} +1 -1
  7. package/dist/cli/{chunk-s5e5jt53.js → chunk-2z47ypj8.js} +1 -1
  8. package/dist/cli/{chunk-tnskyrej.js → chunk-30e87n55.js} +15 -24
  9. package/dist/cli/{chunk-tnskyrej.js.map → chunk-30e87n55.js.map} +2 -2
  10. package/dist/cli/{chunk-4trphnvy.js → chunk-3w7b2vcx.js} +10 -13
  11. package/dist/cli/{chunk-4trphnvy.js.map → chunk-3w7b2vcx.js.map} +2 -2
  12. package/dist/cli/{chunk-v5mm027v.js → chunk-450a7rcr.js} +8 -8
  13. package/dist/cli/{chunk-v5mm027v.js.map → chunk-450a7rcr.js.map} +1 -1
  14. package/dist/cli/{chunk-5d4q7121.js → chunk-5n7t497w.js} +142 -134
  15. package/dist/cli/{chunk-5d4q7121.js.map → chunk-5n7t497w.js.map} +5 -5
  16. package/dist/cli/{chunk-xv91q4nm.js → chunk-61j18dwk.js} +37 -9
  17. package/dist/cli/{chunk-xv91q4nm.js.map → chunk-61j18dwk.js.map} +3 -3
  18. package/dist/cli/{chunk-3r94j3tc.js → chunk-688e0dde.js} +2 -2
  19. package/dist/cli/{chunk-vxv4x1n8.js → chunk-88by27n5.js} +2 -2
  20. package/dist/cli/{chunk-cfw6x4rm.js → chunk-8cd8tj54.js} +28 -35
  21. package/dist/cli/{chunk-cfw6x4rm.js.map → chunk-8cd8tj54.js.map} +2 -2
  22. package/dist/cli/{chunk-8gnpdsn1.js → chunk-9bkjd11x.js} +2 -2
  23. package/dist/cli/{chunk-qq9nm3qd.js → chunk-9he6crym.js} +21 -28
  24. package/dist/cli/{chunk-qq9nm3qd.js.map → chunk-9he6crym.js.map} +2 -2
  25. package/dist/cli/{chunk-jk1zwka1.js → chunk-aztttvb3.js} +27 -33
  26. package/dist/cli/{chunk-jk1zwka1.js.map → chunk-aztttvb3.js.map} +2 -2
  27. package/dist/cli/{chunk-ckh3a410.js → chunk-cvky9gb2.js} +18 -24
  28. package/dist/cli/{chunk-ckh3a410.js.map → chunk-cvky9gb2.js.map} +2 -2
  29. package/dist/cli/{chunk-kwx90v78.js → chunk-eevwt1sc.js} +23 -32
  30. package/dist/cli/{chunk-kwx90v78.js.map → chunk-eevwt1sc.js.map} +2 -2
  31. package/dist/cli/{chunk-agy5rzxy.js → chunk-ejjx8znq.js} +126 -77
  32. package/dist/cli/chunk-ejjx8znq.js.map +15 -0
  33. package/dist/cli/{chunk-ye9zdkgv.js → chunk-exeeb35e.js} +3 -3
  34. package/dist/cli/{chunk-v2ymm99c.js → chunk-fmceyezb.js} +41 -50
  35. package/dist/cli/{chunk-v2ymm99c.js.map → chunk-fmceyezb.js.map} +2 -2
  36. package/dist/cli/{chunk-s102bysw.js → chunk-hdm2dkd2.js} +209 -97
  37. package/dist/cli/{chunk-s102bysw.js.map → chunk-hdm2dkd2.js.map} +6 -5
  38. package/dist/cli/{chunk-zr3ygrq3.js → chunk-hs3gbh8p.js} +10 -15
  39. package/dist/cli/{chunk-zr3ygrq3.js.map → chunk-hs3gbh8p.js.map} +2 -2
  40. package/dist/cli/{chunk-n0nyat6g.js → chunk-jbj4qhfw.js} +3 -3
  41. package/dist/cli/{chunk-ev67ycx0.js → chunk-jq5n4avg.js} +1 -1
  42. package/dist/cli/{chunk-jxkxjsc1.js → chunk-mqb2ka8m.js} +22 -30
  43. package/dist/cli/{chunk-jxkxjsc1.js.map → chunk-mqb2ka8m.js.map} +2 -2
  44. package/dist/cli/{chunk-drke6t0h.js → chunk-mt76t7dj.js} +26 -34
  45. package/dist/cli/{chunk-drke6t0h.js.map → chunk-mt76t7dj.js.map} +2 -2
  46. package/dist/cli/{chunk-jtb45atp.js → chunk-n9sra6sy.js} +13 -13
  47. package/dist/cli/{chunk-jtb45atp.js.map → chunk-n9sra6sy.js.map} +1 -1
  48. package/dist/cli/{chunk-x66c5yjn.js → chunk-ppfvdcd4.js} +2 -2
  49. package/dist/cli/{chunk-wd27zjcz.js → chunk-q4rae3bg.js} +1 -1
  50. package/dist/cli/{chunk-pxj10x8y.js → chunk-ra1v2nc2.js} +1 -1
  51. package/dist/cli/{chunk-y3g15rvv.js → chunk-t3tj0dgr.js} +26 -33
  52. package/dist/cli/{chunk-y3g15rvv.js.map → chunk-t3tj0dgr.js.map} +2 -2
  53. package/dist/cli/{chunk-j6pxe0dt.js → chunk-tqa1s0k8.js} +4 -4
  54. package/dist/cli/{chunk-cbjnx4s8.js → chunk-vh9w1sgp.js} +1 -1
  55. package/dist/cli/{chunk-0qhq7b8q.js → chunk-vkrsvbr5.js} +13 -17
  56. package/dist/cli/{chunk-0qhq7b8q.js.map → chunk-vkrsvbr5.js.map} +2 -2
  57. package/dist/cli/{chunk-sbdqrjbb.js → chunk-vrfp10qk.js} +1 -1
  58. package/dist/cli/{chunk-ynacq3ev.js → chunk-wjt80jps.js} +27 -40
  59. package/dist/cli/{chunk-ynacq3ev.js.map → chunk-wjt80jps.js.map} +3 -4
  60. package/dist/cli/{chunk-18tjv4f7.js → chunk-xhtpx3ff.js} +21 -30
  61. package/dist/cli/{chunk-18tjv4f7.js.map → chunk-xhtpx3ff.js.map} +2 -2
  62. package/dist/cli/{chunk-5hs6gb7n.js → chunk-yzhm0j9q.js} +1 -1
  63. package/dist/cli/index.js +397 -34
  64. package/dist/cli/index.js.map +12 -4
  65. package/dist/types/components/layout/nav-utils.d.ts +15 -2
  66. package/dist/types/core/config-input.d.ts +33 -0
  67. package/dist/types/core/schema.d.ts +29 -3
  68. package/docs/08-faq.mdx +21 -0
  69. package/docs/configuration/ask-ai.mdx +63 -0
  70. package/docs/content/sources.mdx +2 -2
  71. package/package.json +1 -1
  72. package/src/ai/ask.ts +31 -4
  73. package/src/ai/cors.ts +87 -0
  74. package/src/astro/generate.ts +3 -0
  75. package/src/astro/templates.ts +192 -83
  76. package/src/components/content/YouTube.astro +1 -1
  77. package/src/components/layout/Header.astro +1 -1
  78. package/src/components/layout/NavTree.astro +75 -66
  79. package/src/components/layout/RootLayout.astro +4 -1
  80. package/src/components/layout/Search.astro +11 -0
  81. package/src/components/layout/nav-utils.ts +47 -15
  82. package/src/core/adapter.ts +61 -0
  83. package/src/core/config-input.ts +33 -0
  84. package/src/core/schema.ts +61 -0
  85. package/src/core/sources/assets.ts +162 -26
  86. package/src/core/sources/notion.ts +60 -1
  87. package/src/registry/eject.ts +3 -0
  88. package/src/theme/entry.ts +9 -0
  89. package/dist/cli/chunk-2aj8ddew.js +0 -72
  90. package/dist/cli/chunk-2aj8ddew.js.map +0 -10
  91. package/dist/cli/chunk-4xyggvgf.js +0 -21
  92. package/dist/cli/chunk-4xyggvgf.js.map +0 -10
  93. package/dist/cli/chunk-6kzzpsx8.js +0 -26
  94. package/dist/cli/chunk-6kzzpsx8.js.map +0 -10
  95. package/dist/cli/chunk-agy5rzxy.js.map +0 -15
  96. package/dist/cli/chunk-bcy492zc.js +0 -16
  97. package/dist/cli/chunk-bcy492zc.js.map +0 -10
  98. package/dist/cli/chunk-btfr9yvw.js +0 -41
  99. package/dist/cli/chunk-btfr9yvw.js.map +0 -10
  100. package/dist/cli/chunk-ey89bjj1.js +0 -209
  101. package/dist/cli/chunk-ey89bjj1.js.map +0 -11
  102. package/dist/cli/chunk-s5dsk8bj.js.map +0 -13
  103. package/dist/cli/chunk-vt8fgygt.js +0 -23
  104. package/dist/cli/chunk-vt8fgygt.js.map +0 -10
  105. /package/dist/cli/{chunk-27gtm2ym.js.map → chunk-2mzebbbz.js.map} +0 -0
  106. /package/dist/cli/{chunk-s5e5jt53.js.map → chunk-2z47ypj8.js.map} +0 -0
  107. /package/dist/cli/{chunk-3r94j3tc.js.map → chunk-688e0dde.js.map} +0 -0
  108. /package/dist/cli/{chunk-vxv4x1n8.js.map → chunk-88by27n5.js.map} +0 -0
  109. /package/dist/cli/{chunk-8gnpdsn1.js.map → chunk-9bkjd11x.js.map} +0 -0
  110. /package/dist/cli/{chunk-ye9zdkgv.js.map → chunk-exeeb35e.js.map} +0 -0
  111. /package/dist/cli/{chunk-n0nyat6g.js.map → chunk-jbj4qhfw.js.map} +0 -0
  112. /package/dist/cli/{chunk-ev67ycx0.js.map → chunk-jq5n4avg.js.map} +0 -0
  113. /package/dist/cli/{chunk-x66c5yjn.js.map → chunk-ppfvdcd4.js.map} +0 -0
  114. /package/dist/cli/{chunk-wd27zjcz.js.map → chunk-q4rae3bg.js.map} +0 -0
  115. /package/dist/cli/{chunk-pxj10x8y.js.map → chunk-ra1v2nc2.js.map} +0 -0
  116. /package/dist/cli/{chunk-j6pxe0dt.js.map → chunk-tqa1s0k8.js.map} +0 -0
  117. /package/dist/cli/{chunk-cbjnx4s8.js.map → chunk-vh9w1sgp.js.map} +0 -0
  118. /package/dist/cli/{chunk-sbdqrjbb.js.map → chunk-vrfp10qk.js.map} +0 -0
  119. /package/dist/cli/{chunk-5hs6gb7n.js.map → chunk-yzhm0j9q.js.map} +0 -0
package/dist/cli/index.js CHANGED
@@ -1,26 +1,165 @@
1
1
  #!/usr/bin/env node
2
- import {
3
- normalizeHostArgs
4
- } from "./chunk-bcy492zc.js";
5
- import {
6
- reportInternalError
7
- } from "./chunk-btfr9yvw.js";
8
- import {
9
- loadEnvFiles
10
- } from "./chunk-vt8fgygt.js";
11
- import {
12
- getBlumeVersion
13
- } from "./chunk-4xyggvgf.js";
14
- import"./chunk-6kzzpsx8.js";
15
- import"./chunk-ey89bjj1.js";
16
- import {
17
- __require,
18
- commandMeta
19
- } from "./chunk-2aj8ddew.js";
20
2
 
21
3
  // src/cli/index.ts
22
4
  import { defineCommand, runMain } from "citty";
23
5
 
6
+ // src/core/version.ts
7
+ import { readFileSync } from "node:fs";
8
+ import { join as join2 } from "pathe";
9
+
10
+ // src/core/package-root.ts
11
+ import { existsSync } from "node:fs";
12
+ import { dirname, join } from "pathe";
13
+ var findPackageRoot = (start) => {
14
+ let dir = start;
15
+ while (!existsSync(join(dir, "package.json"))) {
16
+ const parent = dirname(dir);
17
+ if (parent === dir) {
18
+ throw new Error("blume: unable to locate the package root");
19
+ }
20
+ dir = parent;
21
+ }
22
+ return dir;
23
+ };
24
+ var cached;
25
+ var packageRoot = () => {
26
+ cached ??= findPackageRoot(import.meta.dirname);
27
+ return cached;
28
+ };
29
+
30
+ // src/core/version.ts
31
+ var cached2;
32
+ var getBlumeVersion = () => {
33
+ if (cached2 === undefined) {
34
+ const pkgPath = join2(packageRoot(), "package.json");
35
+ cached2 = JSON.parse(readFileSync(pkgPath, "utf-8")).version;
36
+ }
37
+ return cached2;
38
+ };
39
+
40
+ // src/cli/command-meta.ts
41
+ var commandMeta = {
42
+ add: {
43
+ description: "Install a source component or template from the registry.",
44
+ name: "add"
45
+ },
46
+ audit: {
47
+ description: "Audit the built site for SEO and site-health issues.",
48
+ name: "audit"
49
+ },
50
+ build: {
51
+ description: "Build the docs site for production.",
52
+ name: "build"
53
+ },
54
+ check: {
55
+ description: "Type-check the docs site with astro check.",
56
+ name: "check"
57
+ },
58
+ dev: {
59
+ description: "Start the Blume development server.",
60
+ name: "dev"
61
+ },
62
+ doctor: {
63
+ description: "Diagnose common configuration and content problems.",
64
+ name: "doctor"
65
+ },
66
+ eject: {
67
+ description: "Promote the generated runtime into an owned Astro project.",
68
+ name: "eject"
69
+ },
70
+ eval: {
71
+ description: "Test the docs: an agent answers your questions using only the documentation.",
72
+ name: "eval"
73
+ },
74
+ init: {
75
+ description: "Scaffold a minimal Blume project.",
76
+ name: "init"
77
+ },
78
+ "mcp-stdio": {
79
+ description: "Serve an MCP data snapshot over stdio (internal, used by `blume eval`).",
80
+ name: "mcp-stdio"
81
+ },
82
+ preview: {
83
+ description: "Preview the last production build.",
84
+ name: "preview"
85
+ },
86
+ sync: {
87
+ description: "Re-fetch remote content sources and regenerate the runtime.",
88
+ name: "sync"
89
+ },
90
+ translate: {
91
+ description: "Translate docs into the configured locales with a local agent CLI.",
92
+ name: "translate"
93
+ },
94
+ validate: {
95
+ description: "Validate internal, anchor, asset, and external links.",
96
+ name: "validate"
97
+ },
98
+ version: {
99
+ description: "Freeze the current docs as an archived version.",
100
+ name: "version"
101
+ }
102
+ };
103
+
104
+ // src/cli/env.ts
105
+ import { existsSync as existsSync2 } from "node:fs";
106
+ import { config } from "dotenv";
107
+ import { dirname as dirname2, join as join3, resolve } from "pathe";
108
+ var loadEnvFiles = (startDir) => {
109
+ const paths = [];
110
+ let dir = resolve(startDir);
111
+ let done = false;
112
+ while (!done) {
113
+ paths.push(join3(dir, ".env.local"), join3(dir, ".env"));
114
+ const parent = dirname2(dir);
115
+ done = existsSync2(join3(dir, ".git")) || parent === dir;
116
+ dir = parent;
117
+ }
118
+ config({ path: paths, quiet: true });
119
+ };
120
+
121
+ // src/cli/host-args.ts
122
+ var normalizeHostArgs = (rawArgs) => rawArgs.map((arg, index) => {
123
+ if (arg !== "--host") {
124
+ return arg;
125
+ }
126
+ const next = rawArgs[index + 1];
127
+ return next === undefined || next.startsWith("-") ? "--host=" : arg;
128
+ });
129
+ var normalizeHost = (host) => host === "" ? true : host ?? false;
130
+
131
+ // src/cli/internal-error.ts
132
+ import { colors } from "consola/utils";
133
+ var ISSUES_URL = "https://github.com/haydenbleasel/blume/issues";
134
+ var BLUME_FRAME = /(?<abs>(?:\/[^\s()]*\/|[A-Za-z]:\\[^\s()]*\\)\.blume[/\\][^\s()]*)/gu;
135
+ var BLUME_MARKER = /[/\\]\.blume[/\\]/u;
136
+ var remapBlumeStack = (stack) => stack.replaceAll(BLUME_FRAME, (match) => {
137
+ const marker = match.search(BLUME_MARKER);
138
+ return `${match.slice(marker + 1)} (generated)`;
139
+ });
140
+ var reportInternalError = (error) => {
141
+ const err = error instanceof Error ? error : new Error(String(error));
142
+ const lines = [
143
+ `${colors.red(colors.bold("BLUME_INTERNAL"))} An unexpected error occurred.`,
144
+ ` ${err.message}`
145
+ ];
146
+ const stack = remapBlumeStack(err.stack ?? "").split(`
147
+ `).slice(1, 5).map((line) => line.trim()).filter(Boolean);
148
+ if (stack.length > 0) {
149
+ lines.push("", colors.dim(stack.join(`
150
+ `)));
151
+ }
152
+ lines.push("", "This is likely a bug in Blume. Please report it with the details below:", colors.dim([
153
+ ` Blume: ${getBlumeVersion()}`,
154
+ ` Node: ${process.version}`,
155
+ ` Platform: ${process.platform} ${process.arch}`
156
+ ].join(`
157
+ `)), ` ${ISSUES_URL}`);
158
+ process.stderr.write(`${lines.join(`
159
+ `)}
160
+ `);
161
+ };
162
+
24
163
  // src/cli/lazy-command.ts
25
164
  var lazyCommand = (meta, load, key) => {
26
165
  const command = async () => {
@@ -48,6 +187,211 @@ var lazyCommand = (meta, load, key) => {
48
187
  };
49
188
  };
50
189
 
190
+ // src/cli/log.ts
191
+ import { consola } from "consola";
192
+ import { relative as relative2 } from "pathe";
193
+
194
+ // src/core/diagnostics.ts
195
+ import { colors as colors2 } from "consola/utils";
196
+ import { relative } from "pathe";
197
+
198
+ class BlumeError extends Error {
199
+ diagnostic;
200
+ constructor(diagnostic) {
201
+ super(diagnostic.message);
202
+ this.name = "BlumeError";
203
+ this.diagnostic = diagnostic;
204
+ }
205
+ }
206
+ var DOCS_BASE = "https://useblume.dev";
207
+ var DOCS_DEPLOYMENT = "/docs/deployment";
208
+ var DOCS_REFERENCE_CLI = "/docs/reference/cli";
209
+ var DOCS_CONTENT_SOURCES = "/docs/content/sources";
210
+ var DOCS_CONTENT_NAVIGATION = "/docs/content/navigation";
211
+ var DOCS_CONTENT_INCLUDES = "/docs/content/includes";
212
+ var DOCS_PATHS = new Map(Object.entries({
213
+ BLUME_ADAPTER_REQUIRED: DOCS_DEPLOYMENT,
214
+ BLUME_ASSETS_UNCHECKED: DOCS_REFERENCE_CLI,
215
+ BLUME_ASSET_FETCH_FAILED: DOCS_CONTENT_SOURCES,
216
+ BLUME_BROKEN_ANCHOR: DOCS_REFERENCE_CLI,
217
+ BLUME_BROKEN_ASSET: DOCS_REFERENCE_CLI,
218
+ BLUME_BROKEN_LINK: DOCS_REFERENCE_CLI,
219
+ BLUME_CONFIG_INVALID: "/docs/configuration",
220
+ BLUME_CONFIG_LOAD_FAILED: "/docs/configuration",
221
+ BLUME_CONTENT_ROOT_MISSING: DOCS_CONTENT_SOURCES,
222
+ BLUME_DEAD_LINK: DOCS_REFERENCE_CLI,
223
+ BLUME_DUPLICATE_ROUTE: DOCS_CONTENT_NAVIGATION,
224
+ BLUME_DUPLICATE_SIDEBAR_ORDER: DOCS_CONTENT_NAVIGATION,
225
+ BLUME_FRONTMATTER_INVALID: "/docs/reference/frontmatter",
226
+ BLUME_INCLUDE_CYCLE: DOCS_CONTENT_INCLUDES,
227
+ BLUME_INCLUDE_NOT_FOUND: DOCS_CONTENT_INCLUDES,
228
+ BLUME_INCLUDE_OUTSIDE_ROOT: DOCS_CONTENT_INCLUDES,
229
+ BLUME_MDX_CURLY_ANCHOR: "/docs/content/syntax",
230
+ BLUME_META_INVALID: "/docs/content/meta",
231
+ BLUME_META_LOAD_FAILED: "/docs/content/meta",
232
+ BLUME_MISSING_SECRET: DOCS_DEPLOYMENT,
233
+ BLUME_NAV_DUPLICATE_LABEL: DOCS_CONTENT_NAVIGATION,
234
+ BLUME_NAV_HIDDEN_IN_SIDEBAR: DOCS_CONTENT_NAVIGATION,
235
+ BLUME_NAV_INDEX_TITLE_MISMATCH: DOCS_CONTENT_NAVIGATION,
236
+ BLUME_NAV_MISSING_PAGE: DOCS_CONTENT_NAVIGATION,
237
+ BLUME_NODE_VERSION: "/docs/quickstart",
238
+ BLUME_SERVER_FEATURE_REQUIRED: DOCS_DEPLOYMENT,
239
+ BLUME_SIDEBAR_DISPLAY_IGNORED: DOCS_CONTENT_NAVIGATION,
240
+ BLUME_SOURCE_FETCH_FAILED: DOCS_CONTENT_SOURCES,
241
+ BLUME_SOURCE_MISCONFIGURED: DOCS_CONTENT_SOURCES,
242
+ BLUME_SOURCE_OFFLINE: DOCS_CONTENT_SOURCES,
243
+ BLUME_SOURCE_SDK_MISSING: DOCS_CONTENT_SOURCES,
244
+ BLUME_SOURCE_UNAVAILABLE: DOCS_CONTENT_SOURCES,
245
+ BLUME_UNKNOWN_COMPONENT: "/docs/configuration/customization",
246
+ BLUME_UNKNOWN_ICON: DOCS_CONTENT_NAVIGATION,
247
+ BLUME_WIKILINK_AMBIGUOUS: DOCS_CONTENT_SOURCES,
248
+ BLUME_WIKILINK_UNRESOLVED: DOCS_CONTENT_SOURCES
249
+ }));
250
+ var resolveDocsUrl = (code) => {
251
+ const path = DOCS_PATHS.get(code);
252
+ return path ? `${DOCS_BASE}${path}` : undefined;
253
+ };
254
+ var enrichDiagnostic = (diagnostic) => diagnostic.docsUrl ? diagnostic : { ...diagnostic, docsUrl: resolveDocsUrl(diagnostic.code) };
255
+ var REGEXP_SPECIAL = /[$()*+.?[\\\]^{|}]/gu;
256
+ var escapeRegExp = (value) => value.replaceAll(REGEXP_SPECIAL, String.raw`\$&`);
257
+ var isKeySegment = (segment) => typeof segment === "string";
258
+ var stepSegment = (source, segment, cursor) => {
259
+ if (!isKeySegment(segment)) {
260
+ return { index: -1, next: cursor, stop: false };
261
+ }
262
+ const matcher = new RegExp(`(?<![\\w$])${escapeRegExp(segment)}\\s*[:=]`, "gu");
263
+ matcher.lastIndex = cursor;
264
+ const match = matcher.exec(source);
265
+ if (!match) {
266
+ return { index: -1, next: cursor, stop: true };
267
+ }
268
+ return { index: match.index, next: matcher.lastIndex, stop: false };
269
+ };
270
+ var locatePath = (source, path) => {
271
+ let cursor = 0;
272
+ let found = -1;
273
+ for (const segment of path) {
274
+ const step = stepSegment(source, segment, cursor);
275
+ if (step.stop) {
276
+ break;
277
+ }
278
+ cursor = step.next;
279
+ if (step.index >= 0) {
280
+ found = step.index;
281
+ }
282
+ }
283
+ if (found < 0) {
284
+ return;
285
+ }
286
+ const before = source.slice(0, found);
287
+ const lastNewline = before.lastIndexOf(`
288
+ `);
289
+ return { column: found - lastNewline, line: before.split(`
290
+ `).length };
291
+ };
292
+ var FRONTMATTER = /^---\r?\n(?<body>[\s\S]*?)\r?\n---/u;
293
+ var locateFrontmatterKey = (source, path) => {
294
+ const block = FRONTMATTER.exec(source);
295
+ if (!block) {
296
+ return;
297
+ }
298
+ const position = locatePath(block.groups?.body ?? "", path);
299
+ return position && { column: position.column, line: position.line + 1 };
300
+ };
301
+ var diagnosticsFromIssues = (issues, options) => issues.map((issue) => {
302
+ const schemaPath = issue.path.join(".");
303
+ const position = options.source ? locatePath(options.source, issue.path) : undefined;
304
+ return {
305
+ code: options.code,
306
+ column: position?.column,
307
+ file: options.file,
308
+ line: position?.line,
309
+ message: schemaPath ? `${schemaPath}: ${issue.message}` : issue.message,
310
+ schemaPath: schemaPath || undefined,
311
+ severity: "error"
312
+ };
313
+ });
314
+ var diagnosticsFromZod = (error, options) => diagnosticsFromIssues(error.issues.map((issue) => ({
315
+ message: issue.message,
316
+ path: issue.path.filter((segment) => typeof segment !== "symbol")
317
+ })), options);
318
+ var severityColor = (severity) => {
319
+ if (severity === "error") {
320
+ return colors2.red;
321
+ }
322
+ if (severity === "warning") {
323
+ return colors2.yellow;
324
+ }
325
+ return colors2.blue;
326
+ };
327
+ var formatDiagnostic = (diagnostic, root) => {
328
+ const color = severityColor(diagnostic.severity);
329
+ const lines = [
330
+ `${color(colors2.bold(diagnostic.code))} ${diagnostic.message}`
331
+ ];
332
+ if (diagnostic.url) {
333
+ lines.push(` ${colors2.dim(`at ${diagnostic.url}`)}`);
334
+ }
335
+ if (diagnostic.file) {
336
+ const location = root ? relative(root, diagnostic.file) : diagnostic.file;
337
+ const column = diagnostic.column === undefined ? "" : `:${diagnostic.column}`;
338
+ const position = diagnostic.line === undefined ? "" : `:${diagnostic.line}${column}`;
339
+ const label = diagnostic.url ? "in" : "at";
340
+ lines.push(` ${colors2.dim(`${label} ${location}${position}`)}`);
341
+ }
342
+ if (diagnostic.suggestion) {
343
+ lines.push(` ${colors2.cyan(`fix: ${diagnostic.suggestion}`)}`);
344
+ }
345
+ if (diagnostic.docsUrl) {
346
+ lines.push(` ${colors2.dim(`docs: ${diagnostic.docsUrl}`)}`);
347
+ }
348
+ return lines.join(`
349
+ `);
350
+ };
351
+ var hasErrors = (diagnostics) => diagnostics.some((d) => d.severity === "error");
352
+ var countBySeverity = (diagnostics) => {
353
+ const counts = { error: 0, info: 0, warning: 0 };
354
+ for (const diagnostic of diagnostics) {
355
+ counts[diagnostic.severity] += 1;
356
+ }
357
+ return counts;
358
+ };
359
+
360
+ // src/cli/log.ts
361
+ var logger = consola.withTag("blume");
362
+ var flushStdout = () => new Promise((resolve) => {
363
+ process.stdout.write("", () => resolve());
364
+ });
365
+ var reportDiagnosticsJson = (diagnostics, root) => {
366
+ const enriched = diagnostics.map((diagnostic) => {
367
+ const withDocs = enrichDiagnostic(diagnostic);
368
+ return withDocs.file && root ? { ...withDocs, file: relative2(root, withDocs.file) } : withDocs;
369
+ });
370
+ process.stdout.write(`${JSON.stringify({ diagnostics: enriched, summary: countBySeverity(diagnostics) }, null, 2)}
371
+ `);
372
+ return hasErrors(diagnostics);
373
+ };
374
+ var reportDiagnostics = (diagnostics, root) => {
375
+ if (diagnostics.length === 0) {
376
+ return false;
377
+ }
378
+ for (const diagnostic of diagnostics) {
379
+ process.stderr.write(`${formatDiagnostic(enrichDiagnostic(diagnostic), root)}
380
+ `);
381
+ }
382
+ const counts = countBySeverity(diagnostics);
383
+ const summary = [
384
+ counts.error ? `${counts.error} error(s)` : null,
385
+ counts.warning ? `${counts.warning} warning(s)` : null
386
+ ].filter(Boolean).join(", ");
387
+ if (summary) {
388
+ process.stderr.write(`
389
+ ${summary}
390
+ `);
391
+ }
392
+ return hasErrors(diagnostics);
393
+ };
394
+
51
395
  // src/cli/index.ts
52
396
  var main = defineCommand({
53
397
  meta: {
@@ -56,21 +400,21 @@ var main = defineCommand({
56
400
  version: getBlumeVersion()
57
401
  },
58
402
  subCommands: {
59
- add: lazyCommand(commandMeta.add, () => import("./chunk-4trphnvy.js"), "addCommand"),
60
- audit: lazyCommand(commandMeta.audit, () => import("./chunk-cfw6x4rm.js"), "auditCommand"),
61
- build: lazyCommand(commandMeta.build, () => import("./chunk-v2ymm99c.js"), "buildCommand"),
62
- check: lazyCommand(commandMeta.check, () => import("./chunk-18tjv4f7.js"), "checkCommand"),
63
- dev: lazyCommand(commandMeta.dev, () => import("./chunk-9qs6acpw.js"), "devCommand"),
64
- doctor: lazyCommand(commandMeta.doctor, () => import("./chunk-tnskyrej.js"), "doctorCommand"),
65
- eject: lazyCommand(commandMeta.eject, () => import("./chunk-jxkxjsc1.js"), "ejectCommand"),
66
- eval: lazyCommand(commandMeta.eval, () => import("./chunk-y3g15rvv.js"), "evalCommand"),
67
- init: lazyCommand(commandMeta.init, () => import("./chunk-drke6t0h.js"), "initCommand"),
68
- "mcp-stdio": lazyCommand(commandMeta["mcp-stdio"], () => import("./chunk-jtb45atp.js"), "mcpStdioCommand"),
69
- preview: lazyCommand(commandMeta.preview, () => import("./chunk-zr3ygrq3.js"), "previewCommand"),
70
- sync: lazyCommand(commandMeta.sync, () => import("./chunk-kwx90v78.js"), "syncCommand"),
71
- translate: lazyCommand(commandMeta.translate, () => import("./chunk-qq9nm3qd.js"), "translateCommand"),
72
- validate: lazyCommand(commandMeta.validate, () => import("./chunk-jk1zwka1.js"), "validateCommand"),
73
- version: lazyCommand(commandMeta.version, () => import("./chunk-ckh3a410.js"), "versionCommand")
403
+ add: lazyCommand(commandMeta.add, () => import("./chunk-3w7b2vcx.js"), "addCommand"),
404
+ audit: lazyCommand(commandMeta.audit, () => import("./chunk-8cd8tj54.js"), "auditCommand"),
405
+ build: lazyCommand(commandMeta.build, () => import("./chunk-fmceyezb.js"), "buildCommand"),
406
+ check: lazyCommand(commandMeta.check, () => import("./chunk-xhtpx3ff.js"), "checkCommand"),
407
+ dev: lazyCommand(commandMeta.dev, () => import("./chunk-12dxjqk7.js"), "devCommand"),
408
+ doctor: lazyCommand(commandMeta.doctor, () => import("./chunk-30e87n55.js"), "doctorCommand"),
409
+ eject: lazyCommand(commandMeta.eject, () => import("./chunk-mqb2ka8m.js"), "ejectCommand"),
410
+ eval: lazyCommand(commandMeta.eval, () => import("./chunk-t3tj0dgr.js"), "evalCommand"),
411
+ init: lazyCommand(commandMeta.init, () => import("./chunk-mt76t7dj.js"), "initCommand"),
412
+ "mcp-stdio": lazyCommand(commandMeta["mcp-stdio"], () => import("./chunk-n9sra6sy.js"), "mcpStdioCommand"),
413
+ preview: lazyCommand(commandMeta.preview, () => import("./chunk-hs3gbh8p.js"), "previewCommand"),
414
+ sync: lazyCommand(commandMeta.sync, () => import("./chunk-eevwt1sc.js"), "syncCommand"),
415
+ translate: lazyCommand(commandMeta.translate, () => import("./chunk-9he6crym.js"), "translateCommand"),
416
+ validate: lazyCommand(commandMeta.validate, () => import("./chunk-aztttvb3.js"), "validateCommand"),
417
+ version: lazyCommand(commandMeta.version, () => import("./chunk-cvky9gb2.js"), "versionCommand")
74
418
  }
75
419
  });
76
420
  loadEnvFiles(process.cwd());
@@ -83,6 +427,25 @@ process.on("unhandledRejection", (error) => {
83
427
  process.exit(1);
84
428
  });
85
429
  runMain(main, { rawArgs: normalizeHostArgs(process.argv.slice(2)) });
430
+ export {
431
+ packageRoot,
432
+ getBlumeVersion,
433
+ commandMeta,
434
+ loadEnvFiles,
435
+ normalizeHost,
436
+ reportInternalError,
437
+ BlumeError,
438
+ enrichDiagnostic,
439
+ locateFrontmatterKey,
440
+ diagnosticsFromIssues,
441
+ diagnosticsFromZod,
442
+ hasErrors,
443
+ countBySeverity,
444
+ logger,
445
+ flushStdout,
446
+ reportDiagnosticsJson,
447
+ reportDiagnostics
448
+ };
86
449
 
87
- //# debugId=1D180DF0EF7A648564756E2164756E21
450
+ //# debugId=3D851F7CCD64619664756E2164756E21
88
451
  //# sourceMappingURL=index.js.map
@@ -1,11 +1,19 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/cli/index.ts", "../src/cli/lazy-command.ts"],
3
+ "sources": ["../src/cli/index.ts", "../src/core/version.ts", "../src/core/package-root.ts", "../src/cli/command-meta.ts", "../src/cli/env.ts", "../src/cli/host-args.ts", "../src/cli/internal-error.ts", "../src/cli/lazy-command.ts", "../src/cli/log.ts", "../src/core/diagnostics.ts"],
4
4
  "sourcesContent": [
5
5
  "import { defineCommand, runMain } from \"citty\";\n\nimport { getBlumeVersion } from \"../core/version.ts\";\nimport { commandMeta } from \"./command-meta.ts\";\nimport { loadEnvFiles } from \"./env.ts\";\nimport { normalizeHostArgs } from \"./host-args.ts\";\nimport { reportInternalError } from \"./internal-error.ts\";\nimport { lazyCommand } from \"./lazy-command.ts\";\n// consola reads CONSOLA_LEVEL / NODE_ENV / TEST / CI / DEBUG when its module\n// evaluates. Import the logger here, ahead of `loadEnvFiles`, so those values\n// come from the real environment — never from a project `.env`, which would\n// otherwise silence or restyle every command's output. The commands are loaded\n// lazily below, so without this line consola would first evaluate after `.env`\n// had been applied.\nimport \"./log.ts\";\n\nconst main = defineCommand({\n meta: {\n description: \"Markdown-first documentation powered by Astro and Vite.\",\n name: \"blume\",\n version: getBlumeVersion(),\n },\n subCommands: {\n add: lazyCommand(\n commandMeta.add,\n () => import(\"./commands/add.ts\"),\n \"addCommand\"\n ),\n audit: lazyCommand(\n commandMeta.audit,\n () => import(\"./commands/audit.ts\"),\n \"auditCommand\"\n ),\n build: lazyCommand(\n commandMeta.build,\n () => import(\"./commands/build.ts\"),\n \"buildCommand\"\n ),\n check: lazyCommand(\n commandMeta.check,\n () => import(\"./commands/check.ts\"),\n \"checkCommand\"\n ),\n dev: lazyCommand(\n commandMeta.dev,\n () => import(\"./commands/dev.ts\"),\n \"devCommand\"\n ),\n doctor: lazyCommand(\n commandMeta.doctor,\n () => import(\"./commands/doctor.ts\"),\n \"doctorCommand\"\n ),\n eject: lazyCommand(\n commandMeta.eject,\n () => import(\"./commands/eject.ts\"),\n \"ejectCommand\"\n ),\n eval: lazyCommand(\n commandMeta.eval,\n () => import(\"./commands/eval.ts\"),\n \"evalCommand\"\n ),\n init: lazyCommand(\n commandMeta.init,\n () => import(\"./commands/init.ts\"),\n \"initCommand\"\n ),\n \"mcp-stdio\": lazyCommand(\n commandMeta[\"mcp-stdio\"],\n () => import(\"./commands/mcp-stdio.ts\"),\n \"mcpStdioCommand\"\n ),\n preview: lazyCommand(\n commandMeta.preview,\n () => import(\"./commands/preview.ts\"),\n \"previewCommand\"\n ),\n sync: lazyCommand(\n commandMeta.sync,\n () => import(\"./commands/sync.ts\"),\n \"syncCommand\"\n ),\n translate: lazyCommand(\n commandMeta.translate,\n () => import(\"./commands/translate.ts\"),\n \"translateCommand\"\n ),\n validate: lazyCommand(\n commandMeta.validate,\n () => import(\"./commands/validate.ts\"),\n \"validateCommand\"\n ),\n version: lazyCommand(\n commandMeta.version,\n () => import(\"./commands/version.ts\"),\n \"versionCommand\"\n ),\n },\n});\n\nloadEnvFiles(process.cwd());\n\nprocess.on(\"uncaughtException\", (error) => {\n reportInternalError(error);\n process.exit(1);\n});\nprocess.on(\"unhandledRejection\", (error) => {\n reportInternalError(error);\n process.exit(1);\n});\n\nrunMain(main, { rawArgs: normalizeHostArgs(process.argv.slice(2)) });\n",
6
- "import type { ArgsDef, CommandDef, CommandMeta } from \"citty\";\n\n/**\n * Wrap a command so its module is imported only when citty needs its `args`\n * or runs it. `meta` stays static (from `command-meta.ts`), so rendering root\n * usage, matching an unknown name, and `blume <cmd> --help` for *another*\n * command never touch this one's dependency graph.\n *\n * `load` imports the command's module and `key` names its export, so the call\n * site stays a plain `() => import(\"./commands/x.ts\")`.\n *\n * Only `args`, `setup`, `run`, and `cleanup` are forwarded: no Blume command\n * declares `default`, `plugins`, or nested `subCommands`.\n */\nexport const lazyCommand = <Args extends ArgsDef, Key extends string>(\n meta: CommandMeta,\n load: () => Promise<Record<Key, CommandDef<Args>>>,\n key: Key\n): CommandDef<Args> => {\n const command = async () => {\n const module = await load();\n return module[key];\n };\n return {\n args: async () => {\n const { args } = await command();\n // SAFETY: every Blume command passes `args` to `defineCommand` as a plain\n // object literal (the \"command registry\" test checks it); citty's\n // `Resolvable` widening is the only reason the type also admits a thunk\n // or a promise here.\n return args as Args;\n },\n cleanup: async (context) => {\n const loaded = await command();\n await loaded.cleanup?.(context);\n },\n meta,\n run: async (context) => {\n const loaded = await command();\n await loaded.run?.(context);\n },\n setup: async (context) => {\n const loaded = await command();\n await loaded.setup?.(context);\n },\n };\n};\n"
6
+ "import { readFileSync } from \"node:fs\";\n\nimport { join } from \"pathe\";\n\nimport { packageRoot } from \"./package-root.ts\";\n\nlet cached: string | undefined;\n\n/**\n * The installed Blume package version, read lazily from its `package.json`.\n *\n * Computed on demand (not at module load) so importing the `blume` barrel has no\n * filesystem side effect, and anchored at the package root so it resolves the\n * same whether running from source or the bundled CLI.\n */\nexport const getBlumeVersion = (): string => {\n if (cached === undefined) {\n const pkgPath = join(packageRoot(), \"package.json\");\n // SAFETY: this reads blume's own package.json, which always declares a\n // `version` (publishing requires it).\n cached = (JSON.parse(readFileSync(pkgPath, \"utf-8\")) as { version: string })\n .version;\n }\n return cached;\n};\n",
7
+ "import { existsSync } from \"node:fs\";\n\nimport { dirname, join } from \"pathe\";\n\n/**\n * Walk up from `start` until a directory containing a `package.json` is found.\n *\n * Exported for testing; call sites should use {@link packageRoot}.\n */\nexport const findPackageRoot = (start: string): string => {\n let dir = start;\n while (!existsSync(join(dir, \"package.json\"))) {\n const parent = dirname(dir);\n if (parent === dir) {\n throw new Error(\"blume: unable to locate the package root\");\n }\n dir = parent;\n }\n return dir;\n};\n\nlet cached: string | undefined;\n\n/**\n * Absolute path to the installed Blume package root (the directory holding its\n * `package.json`), found by walking up from this module.\n *\n * Anchoring here — rather than at a fixed offset from `import.meta` — keeps the\n * package's own `src/`, assets, and `node_modules` locatable whether the code\n * runs from source under Bun (`src/...`) or from the published, bundled CLI\n * (`dist/cli/*.js`). The two layouts sit at different depths, so a relative\n * `../..` resolves to different places; locating `package.json` does not.\n */\nexport const packageRoot = (): string => {\n cached ??= findPackageRoot(import.meta.dirname);\n return cached;\n};\n",
8
+ "import type { CommandMeta } from \"citty\";\n\n/**\n * Every command's `meta`, held apart from the command modules themselves.\n *\n * The CLI entry loads each command lazily (see `lazy-command.ts`), but citty\n * still reads every subcommand's `meta` to render `blume --help` and to match\n * an unknown name against aliases. Keeping that table here lets those paths\n * run without importing a single command module — `dev` alone drags in Astro,\n * `mcp-stdio` the MCP SDK. The command modules read their `meta` from this\n * table too, so the entry and the command can't drift.\n */\nexport const commandMeta = {\n add: {\n description: \"Install a source component or template from the registry.\",\n name: \"add\",\n },\n audit: {\n description: \"Audit the built site for SEO and site-health issues.\",\n name: \"audit\",\n },\n build: {\n description: \"Build the docs site for production.\",\n name: \"build\",\n },\n check: {\n description: \"Type-check the docs site with astro check.\",\n name: \"check\",\n },\n dev: {\n description: \"Start the Blume development server.\",\n name: \"dev\",\n },\n doctor: {\n description: \"Diagnose common configuration and content problems.\",\n name: \"doctor\",\n },\n eject: {\n description: \"Promote the generated runtime into an owned Astro project.\",\n name: \"eject\",\n },\n eval: {\n description:\n \"Test the docs: an agent answers your questions using only the documentation.\",\n name: \"eval\",\n },\n init: {\n description: \"Scaffold a minimal Blume project.\",\n name: \"init\",\n },\n \"mcp-stdio\": {\n description:\n \"Serve an MCP data snapshot over stdio (internal, used by `blume eval`).\",\n name: \"mcp-stdio\",\n },\n preview: {\n description: \"Preview the last production build.\",\n name: \"preview\",\n },\n sync: {\n description: \"Re-fetch remote content sources and regenerate the runtime.\",\n name: \"sync\",\n },\n translate: {\n description:\n \"Translate docs into the configured locales with a local agent CLI.\",\n name: \"translate\",\n },\n validate: {\n description: \"Validate internal, anchor, asset, and external links.\",\n name: \"validate\",\n },\n version: {\n description: \"Freeze the current docs as an archived version.\",\n name: \"version\",\n },\n} satisfies Record<string, CommandMeta>;\n",
9
+ "import { existsSync } from \"node:fs\";\n\nimport { config } from \"dotenv\";\nimport { dirname, join, resolve } from \"pathe\";\n\n// Blume's remote sources (GitHub Releases, mdx-remote, Sanity, Notion…) read\n// their tokens from `process.env` during the content scan — which runs before\n// Astro/Vite boots, so Vite's own `.env` loading is too late. This loader fills\n// that gap: it cascades `.env`/`.env.local` from the working dir up to the repo\n// root, so a monorepo can keep one `.env` at the root and every app picks it up.\n\n/**\n * Load `.env`/`.env.local`, cascading from `startDir` up to the repository root\n * (the first ancestor containing a `.git`) or the filesystem root. The ordered\n * path list is handed to dotenv, whose `config` is first-wins, never clobbers\n * existing `process.env` values, and treats unreadable files as best-effort —\n * so shell/CI overrides are never lost, `.env.local` layers over `.env`, and a\n * bad file never aborts a build. dotenv is also the parser Vite runs over\n * these files at build time, so a value means the same thing to the pre-boot\n * content scan and the built site — including multi-line double-quoted values\n * (PEM keys), which a line-based parser silently truncates.\n */\nexport const loadEnvFiles = (startDir: string): void => {\n const paths: string[] = [];\n let dir = resolve(startDir);\n let done = false;\n while (!done) {\n paths.push(join(dir, \".env.local\"), join(dir, \".env\"));\n const parent = dirname(dir);\n // Stop at the repo root (nearest `.git`) or the filesystem root.\n done = existsSync(join(dir, \".git\")) || parent === dir;\n dir = parent;\n }\n config({ path: paths, quiet: true });\n};\n",
10
+ "/**\n * Rewrite a bare `--host` in the raw argv to `--host=` before citty parses it.\n *\n * `host` is a string arg (citty has no mixed string/boolean type), and citty\n * 0.2 parses with `node:util.parseArgs`, where a string option consumes the\n * next token as its value even when that token is another flag: `blume dev\n * --host --open` would bind the literal hostname \"--open\" and drop `--open`.\n * The `--host=` spelling parses as `\"\"` without touching its neighbor, which\n * `normalizeHost` then maps to Astro's \"bind all interfaces\".\n */\nexport const normalizeHostArgs = (rawArgs: readonly string[]): string[] =>\n rawArgs.map((arg, index) => {\n if (arg !== \"--host\") {\n return arg;\n }\n const next = rawArgs[index + 1];\n return next === undefined || next.startsWith(\"-\") ? \"--host=\" : arg;\n });\n\n/**\n * Resolve a `--host` flag value into what Astro/Vite's `server.host` expects.\n * citty has no mixed string/boolean arg type, so `host` is declared as a\n * string and a bare `--host` parses as `\"\"` (`normalizeHostArgs` rewrites it\n * to `--host=` first) — Node would bind all interfaces for `\"\"`, but Vite's\n * `resolveHostname` treats it as a literal hostname and prints malformed URLs\n * like `http://:4321/`. Match Astro's own `--host` semantics instead: bare\n * flag → `true` (bind all interfaces), `--host 10.0.0.1` → that address,\n * absent → `false` (localhost only).\n *\n * Lives beside `normalizeHostArgs` rather than in `commands/dev.ts` so\n * `preview` can share it without importing the whole dev command graph.\n */\nexport const normalizeHost = (host?: string): boolean | string =>\n host === \"\" ? true : (host ?? false);\n",
11
+ "import { colors } from \"consola/utils\";\n\nimport { getBlumeVersion } from \"../core/version.ts\";\n\nconst ISSUES_URL = \"https://github.com/haydenbleasel/blume/issues\";\n\n// Absolute paths into the hidden generated runtime — POSIX (`…/.blume/…`) or\n// Windows drive-letter (`C:\\…\\.blume\\…`) — including any trailing `:line:col`,\n// stopping at whitespace or a closing paren.\nconst BLUME_FRAME =\n /(?<abs>(?:\\/[^\\s()]*\\/|[A-Za-z]:\\\\[^\\s()]*\\\\)\\.blume[/\\\\][^\\s()]*)/gu;\n\n// The separator immediately before `.blume/` (or `.blume\\`) in a matched path.\nconst BLUME_MARKER = /[/\\\\]\\.blume[/\\\\]/u;\n\n/**\n * Rewrite `.blume/` frames in a stack so the generated runtime reads clearly:\n * the machine-absolute prefix is dropped to a project-relative `.blume/…` path\n * and tagged `(generated)`, keeping the reader oriented instead of staring at a\n * long path into a hidden directory. Frames in the user's own source (custom\n * pages keep their real location; wrappers import user files by their real path)\n * are untouched, so the actionable frame stays intact.\n */\nexport const remapBlumeStack = (stack: string): string =>\n stack.replaceAll(BLUME_FRAME, (match) => {\n const marker = match.search(BLUME_MARKER);\n return `${match.slice(marker + 1)} (generated)`;\n });\n\n/**\n * Print an unexpected (non-{@link BlumeError}) failure in a stable, reportable\n * shape instead of a bare stack trace: a fixed `BLUME_INTERNAL` code, the\n * message, a trimmed stack, and an environment dump for bug reports. Callers\n * exit after this — it doesn't exit itself, so it's testable.\n */\n// oxlint-disable-next-line anti-slop/no-unknown-parameters -- last-resort handler for whatever a catch clause caught; anything narrower would force casts at every call site\nexport const reportInternalError = (error: unknown): void => {\n const err = error instanceof Error ? error : new Error(String(error));\n const lines = [\n `${colors.red(colors.bold(\"BLUME_INTERNAL\"))} An unexpected error occurred.`,\n ` ${err.message}`,\n ];\n\n // A few frames are enough to locate the fault without burying the report;\n // `.blume/` frames are relativized so the hidden runtime reads clearly.\n const stack = remapBlumeStack(err.stack ?? \"\")\n .split(\"\\n\")\n .slice(1, 5)\n .map((line) => line.trim())\n .filter(Boolean);\n if (stack.length > 0) {\n lines.push(\"\", colors.dim(stack.join(\"\\n\")));\n }\n\n lines.push(\n \"\",\n \"This is likely a bug in Blume. Please report it with the details below:\",\n colors.dim(\n [\n ` Blume: ${getBlumeVersion()}`,\n ` Node: ${process.version}`,\n ` Platform: ${process.platform} ${process.arch}`,\n ].join(\"\\n\")\n ),\n ` ${ISSUES_URL}`\n );\n\n process.stderr.write(`${lines.join(\"\\n\")}\\n`);\n};\n",
12
+ "import type { ArgsDef, CommandDef, CommandMeta } from \"citty\";\n\n/**\n * Wrap a command so its module is imported only when citty needs its `args`\n * or runs it. `meta` stays static (from `command-meta.ts`), so rendering root\n * usage, matching an unknown name, and `blume <cmd> --help` for *another*\n * command never touch this one's dependency graph.\n *\n * `load` imports the command's module and `key` names its export, so the call\n * site stays a plain `() => import(\"./commands/x.ts\")`.\n *\n * Only `args`, `setup`, `run`, and `cleanup` are forwarded: no Blume command\n * declares `default`, `plugins`, or nested `subCommands`.\n */\nexport const lazyCommand = <Args extends ArgsDef, Key extends string>(\n meta: CommandMeta,\n load: () => Promise<Record<Key, CommandDef<Args>>>,\n key: Key\n): CommandDef<Args> => {\n const command = async () => {\n const module = await load();\n return module[key];\n };\n return {\n args: async () => {\n const { args } = await command();\n // SAFETY: every Blume command passes `args` to `defineCommand` as a plain\n // object literal (the \"command registry\" test checks it); citty's\n // `Resolvable` widening is the only reason the type also admits a thunk\n // or a promise here.\n return args as Args;\n },\n cleanup: async (context) => {\n const loaded = await command();\n await loaded.cleanup?.(context);\n },\n meta,\n run: async (context) => {\n const loaded = await command();\n await loaded.run?.(context);\n },\n setup: async (context) => {\n const loaded = await command();\n await loaded.setup?.(context);\n },\n };\n};\n",
13
+ "import { consola } from \"consola\";\nimport { relative } from \"pathe\";\n\nimport {\n countBySeverity,\n enrichDiagnostic,\n formatDiagnostic,\n hasErrors,\n} from \"../core/diagnostics.ts\";\nimport type { Diagnostic } from \"../core/types.ts\";\n\nexport const logger = consola.withTag(\"blume\");\n\n/**\n * Resolve once stdout has drained. `process.exit` doesn't flush a piped stdout,\n * so await this before exiting non-zero after writing machine-readable output\n * (e.g. `--json`), otherwise the payload can be truncated in CI.\n */\nexport const flushStdout = (): Promise<void> =>\n // oxlint-disable-next-line promise/avoid-new -- adapt stdout's write callback\n new Promise((resolve) => {\n process.stdout.write(\"\", () => resolve());\n });\n\n/**\n * Print diagnostics as a JSON document on stdout for CI and editors: each is\n * enriched with its `docsUrl` and its `file` made root-relative. Returns whether\n * any were errors, matching {@link reportDiagnostics}.\n */\nexport const reportDiagnosticsJson = (\n diagnostics: Diagnostic[],\n root?: string\n): boolean => {\n const enriched = diagnostics.map((diagnostic) => {\n const withDocs = enrichDiagnostic(diagnostic);\n return withDocs.file && root\n ? { ...withDocs, file: relative(root, withDocs.file) }\n : withDocs;\n });\n process.stdout.write(\n `${JSON.stringify(\n { diagnostics: enriched, summary: countBySeverity(diagnostics) },\n null,\n 2\n )}\\n`\n );\n return hasErrors(diagnostics);\n};\n\n/** Print a batch of diagnostics and return whether any were errors. */\nexport const reportDiagnostics = (\n diagnostics: Diagnostic[],\n root?: string\n): boolean => {\n if (diagnostics.length === 0) {\n return false;\n }\n\n for (const diagnostic of diagnostics) {\n process.stderr.write(\n `${formatDiagnostic(enrichDiagnostic(diagnostic), root)}\\n`\n );\n }\n\n const counts = countBySeverity(diagnostics);\n const summary = [\n counts.error ? `${counts.error} error(s)` : null,\n counts.warning ? `${counts.warning} warning(s)` : null,\n ]\n .filter(Boolean)\n .join(\", \");\n if (summary) {\n process.stderr.write(`\\n${summary}\\n`);\n }\n\n return hasErrors(diagnostics);\n};\n",
14
+ "import { colors } from \"consola/utils\";\nimport { relative } from \"pathe\";\nimport type { ZodError } from \"zod\";\n\nimport type { Diagnostic } from \"./types.ts\";\n\n/** A recoverable error carrying a structured diagnostic. */\nexport class BlumeError extends Error {\n readonly diagnostic: Diagnostic;\n\n constructor(diagnostic: Diagnostic) {\n super(diagnostic.message);\n this.name = \"BlumeError\";\n this.diagnostic = diagnostic;\n }\n}\n\nexport const createDiagnostic = (diagnostic: Diagnostic): Diagnostic =>\n diagnostic;\n\n/** Docs site base; diagnostic help links resolve against it. */\nconst DOCS_BASE = \"https://useblume.dev\";\n\nconst DOCS_DEPLOYMENT = \"/docs/deployment\";\nconst DOCS_REFERENCE_CLI = \"/docs/reference/cli\";\nconst DOCS_CONTENT_SOURCES = \"/docs/content/sources\";\nconst DOCS_CONTENT_NAVIGATION = \"/docs/content/navigation\";\nconst DOCS_CONTENT_INCLUDES = \"/docs/content/includes\";\n\n/** Diagnostic code → the docs page that explains it. */\nconst DOCS_PATHS = new Map(\n Object.entries({\n BLUME_ADAPTER_REQUIRED: DOCS_DEPLOYMENT,\n BLUME_ASSETS_UNCHECKED: DOCS_REFERENCE_CLI,\n BLUME_ASSET_FETCH_FAILED: DOCS_CONTENT_SOURCES,\n BLUME_BROKEN_ANCHOR: DOCS_REFERENCE_CLI,\n BLUME_BROKEN_ASSET: DOCS_REFERENCE_CLI,\n BLUME_BROKEN_LINK: DOCS_REFERENCE_CLI,\n BLUME_CONFIG_INVALID: \"/docs/configuration\",\n BLUME_CONFIG_LOAD_FAILED: \"/docs/configuration\",\n BLUME_CONTENT_ROOT_MISSING: DOCS_CONTENT_SOURCES,\n BLUME_DEAD_LINK: DOCS_REFERENCE_CLI,\n BLUME_DUPLICATE_ROUTE: DOCS_CONTENT_NAVIGATION,\n BLUME_DUPLICATE_SIDEBAR_ORDER: DOCS_CONTENT_NAVIGATION,\n BLUME_FRONTMATTER_INVALID: \"/docs/reference/frontmatter\",\n BLUME_INCLUDE_CYCLE: DOCS_CONTENT_INCLUDES,\n BLUME_INCLUDE_NOT_FOUND: DOCS_CONTENT_INCLUDES,\n BLUME_INCLUDE_OUTSIDE_ROOT: DOCS_CONTENT_INCLUDES,\n BLUME_MDX_CURLY_ANCHOR: \"/docs/content/syntax\",\n\n BLUME_META_INVALID: \"/docs/content/meta\",\n BLUME_META_LOAD_FAILED: \"/docs/content/meta\",\n BLUME_MISSING_SECRET: DOCS_DEPLOYMENT,\n BLUME_NAV_DUPLICATE_LABEL: DOCS_CONTENT_NAVIGATION,\n BLUME_NAV_HIDDEN_IN_SIDEBAR: DOCS_CONTENT_NAVIGATION,\n BLUME_NAV_INDEX_TITLE_MISMATCH: DOCS_CONTENT_NAVIGATION,\n BLUME_NAV_MISSING_PAGE: DOCS_CONTENT_NAVIGATION,\n BLUME_NODE_VERSION: \"/docs/quickstart\",\n BLUME_SERVER_FEATURE_REQUIRED: DOCS_DEPLOYMENT,\n BLUME_SIDEBAR_DISPLAY_IGNORED: DOCS_CONTENT_NAVIGATION,\n BLUME_SOURCE_FETCH_FAILED: DOCS_CONTENT_SOURCES,\n BLUME_SOURCE_MISCONFIGURED: DOCS_CONTENT_SOURCES,\n BLUME_SOURCE_OFFLINE: DOCS_CONTENT_SOURCES,\n BLUME_SOURCE_SDK_MISSING: DOCS_CONTENT_SOURCES,\n BLUME_SOURCE_UNAVAILABLE: DOCS_CONTENT_SOURCES,\n BLUME_UNKNOWN_COMPONENT: \"/docs/configuration/customization\",\n BLUME_UNKNOWN_ICON: DOCS_CONTENT_NAVIGATION,\n BLUME_WIKILINK_AMBIGUOUS: DOCS_CONTENT_SOURCES,\n BLUME_WIKILINK_UNRESOLVED: DOCS_CONTENT_SOURCES,\n })\n);\n\n/** The docs URL that explains a diagnostic code, if one is mapped. */\nexport const resolveDocsUrl = (code: string): string | undefined => {\n const path = DOCS_PATHS.get(code);\n return path ? `${DOCS_BASE}${path}` : undefined;\n};\n\n/** Fill in `docsUrl` from the code map where a diagnostic doesn't set its own. */\nexport const enrichDiagnostic = (diagnostic: Diagnostic): Diagnostic =>\n diagnostic.docsUrl\n ? diagnostic\n : { ...diagnostic, docsUrl: resolveDocsUrl(diagnostic.code) };\n\nconst REGEXP_SPECIAL = /[$()*+.?[\\\\\\]^{|}]/gu;\nconst escapeRegExp = (value: string): string =>\n value.replaceAll(REGEXP_SPECIAL, String.raw`\\$&`);\n\n/** A key segment scans the source text; an array index has no key to find. */\nconst isKeySegment = (segment: string | number): segment is string =>\n typeof segment === \"string\";\n\n/**\n * Best-effort source position for a Zod issue path (e.g. `[\"seo\", \"title\"]`) in\n * the raw config / frontmatter text. Narrows key-by-key — finding each string\n * segment as a `key:`/`key =` at or after the previous match — so a nested key\n * lands under its parent. Array indices are skipped. Returns 1-based line/column,\n * or undefined when nothing matches.\n */\nconst stepSegment = (\n source: string,\n segment: string | number,\n cursor: number\n) => {\n // A non-string path segment (array index) is skipped without moving on.\n if (!isKeySegment(segment)) {\n return { index: -1, next: cursor, stop: false };\n }\n // The negative lookbehind keeps a segment like `title` from matching the\n // tail of an unrelated key such as `subtitle:`.\n const matcher = new RegExp(\n `(?<![\\\\w$])${escapeRegExp(segment)}\\\\s*[:=]`,\n \"gu\"\n );\n matcher.lastIndex = cursor;\n const match = matcher.exec(source);\n if (!match) {\n return { index: -1, next: cursor, stop: true };\n }\n return { index: match.index, next: matcher.lastIndex, stop: false };\n};\n\nconst locatePath = (\n source: string,\n path: readonly (string | number)[]\n): { column: number; line: number } | undefined => {\n let cursor = 0;\n let found = -1;\n for (const segment of path) {\n const step = stepSegment(source, segment, cursor);\n if (step.stop) {\n break;\n }\n cursor = step.next;\n if (step.index >= 0) {\n found = step.index;\n }\n }\n if (found < 0) {\n return;\n }\n const before = source.slice(0, found);\n const lastNewline = before.lastIndexOf(\"\\n\");\n return { column: found - lastNewline, line: before.split(\"\\n\").length };\n};\n\n/** The YAML front matter block of a `.md`/`.mdx` source, if it has one. */\nconst FRONTMATTER = /^---\\r?\\n(?<body>[\\s\\S]*?)\\r?\\n---/u;\n\n/**\n * Locate a front matter key in a content file, e.g. `[\"seo\", \"description\"]` in\n * `docs/api.mdx`. Scoped to the front matter block so a `title:` written in the\n * page body can't be mistaken for the front matter key of the same name; returns\n * undefined when the file has no front matter or the key isn't set (a missing\n * key has no line to point at — callers anchor to the file instead).\n */\nexport const locateFrontmatterKey = (\n source: string,\n path: readonly (string | number)[]\n): { column: number; line: number } | undefined => {\n const block = FRONTMATTER.exec(source);\n if (!block) {\n return;\n }\n // `locatePath` reports lines 1-based within the text it was given, and the\n // front matter body starts one line below the opening `---`.\n const position = locatePath(block.groups?.body ?? \"\", path);\n return position && { column: position.column, line: position.line + 1 };\n};\n\n/**\n * Convert generic validation issues (message + path, the shape shared by Zod\n * and Standard Schema issues) into Blume diagnostics, anchored to a file.\n */\nexport const diagnosticsFromIssues = (\n issues: readonly {\n message: string;\n path: readonly (string | number)[];\n }[],\n options: { code: string; file?: string; source?: string }\n): Diagnostic[] =>\n issues.map((issue) => {\n const schemaPath = issue.path.join(\".\");\n const position = options.source\n ? locatePath(options.source, issue.path)\n : undefined;\n return {\n code: options.code,\n column: position?.column,\n file: options.file,\n line: position?.line,\n message: schemaPath ? `${schemaPath}: ${issue.message}` : issue.message,\n schemaPath: schemaPath || undefined,\n severity: \"error\",\n } satisfies Diagnostic;\n });\n\n/** Convert a ZodError into Blume diagnostics, anchored to a file. */\nexport const diagnosticsFromZod = (\n error: ZodError,\n options: { code: string; file?: string; source?: string }\n): Diagnostic[] =>\n diagnosticsFromIssues(\n error.issues.map((issue) => ({\n message: issue.message,\n // Zod 4 paths are PropertyKey[]; a symbol segment has no place in a\n // dotted schema path or a source-position scan.\n path: issue.path.filter(\n (segment): segment is string | number => typeof segment !== \"symbol\"\n ),\n })),\n options\n );\n\nconst severityColor = (severity: Diagnostic[\"severity\"]) => {\n if (severity === \"error\") {\n return colors.red;\n }\n if (severity === \"warning\") {\n return colors.yellow;\n }\n return colors.blue;\n};\n\n/** Format a single diagnostic for terminal output. */\nexport const formatDiagnostic = (\n diagnostic: Diagnostic,\n root?: string\n): string => {\n const color = severityColor(diagnostic.severity);\n const lines: string[] = [\n `${color(colors.bold(diagnostic.code))} ${diagnostic.message}`,\n ];\n\n // An audit finding is about a built URL, and names the source file that fixes\n // it as a second line (\"at /docs/api\" / \"in docs/api.mdx:3:2\"). Everything\n // else is about a file alone, and keeps the original single `at file` line.\n if (diagnostic.url) {\n lines.push(` ${colors.dim(`at ${diagnostic.url}`)}`);\n }\n if (diagnostic.file) {\n const location = root ? relative(root, diagnostic.file) : diagnostic.file;\n const column =\n diagnostic.column === undefined ? \"\" : `:${diagnostic.column}`;\n const position =\n diagnostic.line === undefined ? \"\" : `:${diagnostic.line}${column}`;\n const label = diagnostic.url ? \"in\" : \"at\";\n lines.push(` ${colors.dim(`${label} ${location}${position}`)}`);\n }\n\n if (diagnostic.suggestion) {\n lines.push(` ${colors.cyan(`fix: ${diagnostic.suggestion}`)}`);\n }\n\n if (diagnostic.docsUrl) {\n lines.push(` ${colors.dim(`docs: ${diagnostic.docsUrl}`)}`);\n }\n\n return lines.join(\"\\n\");\n};\n\nexport const hasErrors = (diagnostics: Diagnostic[]): boolean =>\n diagnostics.some((d) => d.severity === \"error\");\n\nexport const countBySeverity = (diagnostics: Diagnostic[]) => {\n const counts = { error: 0, info: 0, warning: 0 } satisfies Record<\n Diagnostic[\"severity\"],\n number\n >;\n for (const diagnostic of diagnostics) {\n counts[diagnostic.severity] += 1;\n }\n return counts;\n};\n"
7
15
  ],
8
- "mappings": ";;;;;;;;;;;;;;;;;;;;;AAAA;;;ACcO,IAAM,cAAc,CACzB,MACA,MACA,QACqB;AAAA,EACrB,MAAM,UAAU,YAAY;AAAA,IAC1B,MAAM,SAAS,MAAM,KAAK;AAAA,IAC1B,OAAO,OAAO;AAAA;AAAA,EAEhB,OAAO;AAAA,IACL,MAAM,YAAY;AAAA,MAChB,QAAQ,SAAS,MAAM,QAAQ;AAAA,MAK/B,OAAO;AAAA;AAAA,IAET,SAAS,OAAO,YAAY;AAAA,MAC1B,MAAM,SAAS,MAAM,QAAQ;AAAA,MAC7B,MAAM,OAAO,UAAU,OAAO;AAAA;AAAA,IAEhC;AAAA,IACA,KAAK,OAAO,YAAY;AAAA,MACtB,MAAM,SAAS,MAAM,QAAQ;AAAA,MAC7B,MAAM,OAAO,MAAM,OAAO;AAAA;AAAA,IAE5B,OAAO,OAAO,YAAY;AAAA,MACxB,MAAM,SAAS,MAAM,QAAQ;AAAA,MAC7B,MAAM,OAAO,QAAQ,OAAO;AAAA;AAAA,EAEhC;AAAA;;;AD7BF,IAAM,OAAO,cAAc;AAAA,EACzB,MAAM;AAAA,IACJ,aAAa;AAAA,IACb,MAAM;AAAA,IACN,SAAS,gBAAgB;AAAA,EAC3B;AAAA,EACA,aAAa;AAAA,IACX,KAAK,YACH,YAAY,KACZ,MAAa,+BACb,YACF;AAAA,IACA,OAAO,YACL,YAAY,OACZ,MAAa,+BACb,cACF;AAAA,IACA,OAAO,YACL,YAAY,OACZ,MAAa,+BACb,cACF;AAAA,IACA,OAAO,YACL,YAAY,OACZ,MAAa,+BACb,cACF;AAAA,IACA,KAAK,YACH,YAAY,KACZ,MAAa,+BACb,YACF;AAAA,IACA,QAAQ,YACN,YAAY,QACZ,MAAa,+BACb,eACF;AAAA,IACA,OAAO,YACL,YAAY,OACZ,MAAa,+BACb,cACF;AAAA,IACA,MAAM,YACJ,YAAY,MACZ,MAAa,+BACb,aACF;AAAA,IACA,MAAM,YACJ,YAAY,MACZ,MAAa,+BACb,aACF;AAAA,IACA,aAAa,YACX,YAAY,cACZ,MAAa,+BACb,iBACF;AAAA,IACA,SAAS,YACP,YAAY,SACZ,MAAa,+BACb,gBACF;AAAA,IACA,MAAM,YACJ,YAAY,MACZ,MAAa,+BACb,aACF;AAAA,IACA,WAAW,YACT,YAAY,WACZ,MAAa,+BACb,kBACF;AAAA,IACA,UAAU,YACR,YAAY,UACZ,MAAa,+BACb,iBACF;AAAA,IACA,SAAS,YACP,YAAY,SACZ,MAAa,+BACb,gBACF;AAAA,EACF;AACF,CAAC;AAED,aAAa,QAAQ,IAAI,CAAC;AAE1B,QAAQ,GAAG,qBAAqB,CAAC,UAAU;AAAA,EACzC,oBAAoB,KAAK;AAAA,EACzB,QAAQ,KAAK,CAAC;AAAA,CACf;AACD,QAAQ,GAAG,sBAAsB,CAAC,UAAU;AAAA,EAC1C,oBAAoB,KAAK;AAAA,EACzB,QAAQ,KAAK,CAAC;AAAA,CACf;AAED,QAAQ,MAAM,EAAE,SAAS,kBAAkB,QAAQ,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC;",
9
- "debugId": "1D180DF0EF7A648564756E2164756E21",
16
+ "mappings": "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",
17
+ "debugId": "3D851F7CCD64619664756E2164756E21",
10
18
  "names": []
11
19
  }
@@ -78,15 +78,28 @@ export interface NavVariant {
78
78
  locale: string;
79
79
  navigation: Navigation;
80
80
  }
81
+ /**
82
+ * The locale whose code must not appear as a fragment URL segment: the
83
+ * default locale while its URL prefix is hidden. Astro's i18n routing 404s any
84
+ * page URL carrying that locale's code as a segment (it expects the default
85
+ * locale to be unprefixed), so its trees are keyed `default` instead, the same
86
+ * way its page routes drop the prefix. `null` when every locale is prefixed
87
+ * or the site is single-locale.
88
+ */
89
+ export declare const hiddenDefaultLocale: (i18n: {
90
+ defaultLocale: string;
91
+ hideDefaultLocalePrefix: boolean;
92
+ } | null) => string | null;
81
93
  /**
82
94
  * Every navigation tree the runtime data holds — the default, each locale's,
83
95
  * and each archived version's per locale — keyed the way the deferred
84
96
  * sidebar fragments' URLs are (`/blume-nav/<version>/<locale>/…`). An
85
97
  * unlocalized version tree is keyed by `""` in the data; it maps to
86
- * `default` here.
98
+ * `default` here, as does the hidden-prefix default locale's (see
99
+ * `hiddenDefaultLocale`), whose current tree is `data.navigation` already.
87
100
  */
88
101
  export declare const navVariants: (data: {
89
102
  navigation: Navigation;
90
103
  navigationByLocale: Record<string, Navigation>;
91
104
  navigationByVersion: Record<string, Record<string, Navigation>>;
92
- }) => NavVariant[];
105
+ }, hiddenDefault?: string | null) => NavVariant[];