@bitcobblers/wod-wiki-tools 0.37.2137 → 0.37.2140

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 (58) hide show
  1. package/dist/bin/wod.cjs +224 -231
  2. package/dist/bin/wod.cjs.map +1 -1
  3. package/dist/bin/wod.mjs +4 -4
  4. package/dist/{chunk-NATJMTAW.mjs → chunk-IEW74LUO.mjs} +109 -187
  5. package/dist/chunk-IEW74LUO.mjs.map +1 -0
  6. package/dist/{chunk-CYKNTEGY.mjs → chunk-IWT7U3WX.mjs} +8 -3
  7. package/dist/chunk-IWT7U3WX.mjs.map +1 -0
  8. package/dist/{chunk-MA6BBTWC.mjs → chunk-RWNL6APX.mjs} +3 -3
  9. package/dist/{chunk-MA6BBTWC.mjs.map → chunk-RWNL6APX.mjs.map} +1 -1
  10. package/dist/{chunk-GBBJBDLS.mjs → chunk-UNJ6OZVO.mjs} +116 -42
  11. package/dist/chunk-UNJ6OZVO.mjs.map +1 -0
  12. package/dist/{chunk-SQAI6B4P.mjs → chunk-YO256WSO.mjs} +3 -3
  13. package/dist/chunk-YO256WSO.mjs.map +1 -0
  14. package/dist/compiler-E6HYL477.mjs +9 -0
  15. package/dist/{compiler-B77PITYH.mjs.map → compiler-E6HYL477.mjs.map} +1 -1
  16. package/dist/index.cjs +224 -231
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.mjs +5 -5
  19. package/dist/{scaffoldCatalog-LQOUCJ4X.mjs → scaffoldCatalog-TLYSPOQK.mjs} +3 -3
  20. package/dist/{scaffoldCatalog-LQOUCJ4X.mjs.map → scaffoldCatalog-TLYSPOQK.mjs.map} +1 -1
  21. package/dist/{server-JXECWS4A.mjs → server-2DVBA35J.mjs} +4 -4
  22. package/dist/{server-JXECWS4A.mjs.map → server-2DVBA35J.mjs.map} +1 -1
  23. package/dist/web/playground/assets/main-BUcjhK2w.css +2 -0
  24. package/dist/web/playground/assets/main-CT3-Winw.js +194 -0
  25. package/dist/web/playground/assets/{statementBuilderFlow-BL8OKlcb.js → statementBuilderFlow-CtxxN_h0.js} +2 -2
  26. package/dist/web/playground/assets/{vendor-CTANVdPW.js → vendor-DaJxNU_W.js} +19 -19
  27. package/dist/web/playground/assets/{vendor-codemirror-BlXDdJID.js → vendor-codemirror-BtDM22HA.js} +8 -8
  28. package/dist/web/playground/index.html +4 -4
  29. package/dist/web/playground/seed/core/chunks/canvas.3c75c4cb.json +1 -0
  30. package/dist/web/playground/seed/core/chunks/efforts.1422c1a6.json +1 -0
  31. package/dist/web/playground/seed/core/chunks/equipment.c4fb1d64.json +1 -0
  32. package/dist/web/playground/seed/core/chunks/{template.e5e0e82d.json → template.0120276c.json} +1 -1
  33. package/dist/web/playground/seed/core/manifest.json +24 -10
  34. package/dist/web/playground/seed/core/report.html +15 -13
  35. package/dist/web/server/assets/main-BUcjhK2w.css +2 -0
  36. package/dist/web/server/assets/main-C5jPewkG.js +193 -0
  37. package/dist/web/server/assets/{statementBuilderFlow-xqsK_3T8.js → statementBuilderFlow-Df5Scxwh.js} +2 -2
  38. package/dist/web/server/assets/{vendor-CTANVdPW.js → vendor-DaJxNU_W.js} +19 -19
  39. package/dist/web/server/assets/{vendor-codemirror-BlXDdJID.js → vendor-codemirror-BtDM22HA.js} +8 -8
  40. package/dist/web/server/index.html +4 -4
  41. package/dist/web/server/seed/core/chunks/canvas.3c75c4cb.json +1 -0
  42. package/dist/web/server/seed/core/chunks/efforts.1422c1a6.json +1 -0
  43. package/dist/web/server/seed/core/chunks/equipment.c4fb1d64.json +1 -0
  44. package/dist/web/server/seed/core/chunks/{template.e5e0e82d.json → template.0120276c.json} +1 -1
  45. package/dist/web/server/seed/core/manifest.json +24 -10
  46. package/dist/web/server/seed/core/report.html +15 -13
  47. package/package.json +6 -6
  48. package/dist/chunk-CYKNTEGY.mjs.map +0 -1
  49. package/dist/chunk-GBBJBDLS.mjs.map +0 -1
  50. package/dist/chunk-NATJMTAW.mjs.map +0 -1
  51. package/dist/chunk-SQAI6B4P.mjs.map +0 -1
  52. package/dist/compiler-B77PITYH.mjs +0 -9
  53. package/dist/web/playground/assets/main-CFDrblxn.css +0 -2
  54. package/dist/web/playground/assets/main-OGIV1avF.js +0 -188
  55. package/dist/web/playground/seed/core/chunks/canvas.a2e32d8c.json +0 -1
  56. package/dist/web/server/assets/main-BdUrlkaF.js +0 -187
  57. package/dist/web/server/assets/main-CFDrblxn.css +0 -2
  58. package/dist/web/server/seed/core/chunks/canvas.a2e32d8c.json +0 -1
package/dist/bin/wod.mjs CHANGED
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'module';
3
- import { cliMain } from '../chunk-GBBJBDLS.mjs';
4
- import '../chunk-NATJMTAW.mjs';
5
- import '../chunk-SQAI6B4P.mjs';
6
- import '../chunk-CYKNTEGY.mjs';
3
+ import { cliMain } from '../chunk-UNJ6OZVO.mjs';
4
+ import '../chunk-IEW74LUO.mjs';
5
+ import '../chunk-YO256WSO.mjs';
6
+ import '../chunk-IWT7U3WX.mjs';
7
7
  import '../chunk-6L5ZDZJ7.mjs';
8
8
 
9
9
  if (typeof globalThis.require === 'undefined') {
@@ -1,5 +1,5 @@
1
1
  import { createRequire } from 'module';
2
- import { parseScript, whiteboardParser, isEffortDiscipline } from '@bitcobblers/wod-wiki-lang';
2
+ import { parseScript, whiteboardParser, parseEffortFile, parseEquipmentFile, createReferenceIndex, slugifyRefLabel, extractStatementRefs } from '@bitcobblers/wod-wiki-lang';
3
3
  import { reconcileNoteBlocks, KNOWN_SECTION_WIDGETS, parseDocumentSections, blockContentId } from '@bitcobblers/wod-wiki-core';
4
4
  import { parseDashboardNote, buildDashboardDocument, isDashboardWidgetType, resolveWidgetType, parseQuery } from '@bitcobblers/wod-wiki-wql';
5
5
  import { execSync } from 'child_process';
@@ -10,9 +10,10 @@ import { createHash } from 'crypto';
10
10
  if (typeof globalThis.require === 'undefined') {
11
11
  try { globalThis.require = createRequire(import.meta.url); } catch {}
12
12
  }
13
- var SEED_SCHEMA = 8;
13
+ var SEED_SCHEMA = 9;
14
14
  var SEED_REGISTERED_WIDGETS = KNOWN_SECTION_WIDGETS;
15
15
  var EFFORTS_CHUNK_ID = "efforts";
16
+ var EQUIPMENT_CHUNK_ID = "equipment";
16
17
  var CANVAS_CHUNK_ID = "canvas";
17
18
  var DASHBOARDS_CHUNK_ID = "dashboards";
18
19
  var TEMPLATE_CHUNK_ID = "template";
@@ -32,6 +33,7 @@ function seedNoteSourceId(path, content, chunkId) {
32
33
  if (chunkId === CANVAS_CHUNK_ID) return `guides:${canvasRouteSlug(content) ?? under}`;
33
34
  if (chunkId === DASHBOARDS_CHUNK_ID) return "dashboards";
34
35
  if (chunkId === EFFORTS_CHUNK_ID) return "efforts";
36
+ if (chunkId === EQUIPMENT_CHUNK_ID) return "equipment";
35
37
  if (chunkId === TEMPLATE_CHUNK_ID) return "playground";
36
38
  if (chunkId.startsWith("collection.")) {
37
39
  const catalog = catalogForChunkId(chunkId);
@@ -41,24 +43,6 @@ function seedNoteSourceId(path, content, chunkId) {
41
43
  return void 0;
42
44
  }
43
45
 
44
- // src/seedbuild/effort-slugs.ts
45
- function extractEffortSlugs(statements) {
46
- const slugs = /* @__PURE__ */ new Set();
47
- for (const statement of statements) {
48
- if (statement.exerciseId) {
49
- slugs.add(statement.exerciseId);
50
- } else {
51
- const effortMetric = statement.metrics?.getMetric?.("effort");
52
- const effort = effortMetric && typeof effortMetric.value === "string" ? effortMetric.value : void 0;
53
- if (effort) {
54
- const slug = effort.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
55
- if (slug) slugs.add(slug);
56
- }
57
- }
58
- }
59
- return Array.from(slugs);
60
- }
61
-
62
46
  // src/seedbuild/filename.ts
63
47
  var FILE_TITLE_STOP_WORDS = {
64
48
  and: true,
@@ -99,141 +83,6 @@ function fileToDisplayName(filename) {
99
83
  }
100
84
  return titled.join(" ");
101
85
  }
102
-
103
- // src/seedbuild/frontmatter.ts
104
- var FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/;
105
- function unquote(value) {
106
- return value.replace(
107
- /^(['"])(.*)\1$/,
108
- (_match, quote, inner) => quote === '"' ? inner.replace(/\\(["\\])/g, "$1") : inner
109
- );
110
- }
111
- function parseFrontmatter(raw) {
112
- const match = raw.match(FRONTMATTER_RE);
113
- if (!match) return { meta: {}, body: raw };
114
- return { meta: parseMetaLines(match[1].split(/\r?\n/)), body: raw.slice(match[0].length) };
115
- }
116
- function parseMetaLines(lines) {
117
- const meta = {};
118
- for (let i = 0; i < lines.length; i++) {
119
- const keyMatch = lines[i].match(/^([A-Za-z][\w.-]*)\s*:(.*)$/);
120
- if (!keyMatch) continue;
121
- const key = keyMatch[1];
122
- const rawVal = keyMatch[2].trim();
123
- if (rawVal === "") {
124
- const items = [];
125
- while (i + 1 < lines.length) {
126
- const itemMatch = lines[i + 1].match(/^\s+-\s+(.+)$/);
127
- if (!itemMatch) break;
128
- items.push(itemMatch[1].trim());
129
- i++;
130
- }
131
- meta[key] = items.length > 0 ? items : "";
132
- } else {
133
- const wasQuoted = /^(['"])(.*)\1$/.test(rawVal);
134
- const value = unquote(rawVal);
135
- const num = Number(value);
136
- meta[key] = !wasQuoted && value !== "" && !isNaN(num) ? num : value;
137
- }
138
- }
139
- return meta;
140
- }
141
- function getScalar(meta, key) {
142
- const value = meta[key];
143
- return typeof value === "string" || typeof value === "number" ? value : void 0;
144
- }
145
- function getList(meta, key) {
146
- const value = meta[key];
147
- return Array.isArray(value) ? value : [];
148
- }
149
-
150
- // src/seedbuild/effort-file.ts
151
- function parseDiscipline(val) {
152
- if (!val) return void 0;
153
- const normalized = unquoteYaml(val.trim()).toLowerCase();
154
- if (isEffortDiscipline(normalized)) return normalized;
155
- console.warn(`[effort-file] unknown discipline '${val}' \u2014 treating as unset`);
156
- return void 0;
157
- }
158
- function unquoteYaml(val) {
159
- if (val.startsWith('"') && val.endsWith('"')) {
160
- return val.slice(1, -1).replace(/\\(["\\])/g, "$1");
161
- }
162
- if (val.startsWith("'") && val.endsWith("'")) {
163
- return val.slice(1, -1).replace(/\\'/g, "'");
164
- }
165
- return val;
166
- }
167
- function coerceNestedScalar(raw) {
168
- if (raw === "true") return true;
169
- if (raw === "false") return false;
170
- if (raw !== "" && !Number.isNaN(Number(raw))) return Number(raw);
171
- return raw;
172
- }
173
- function readNestedSection(lines, key) {
174
- const start = lines.findIndex((l) => new RegExp(`^${key}:\\s*$`).test(l));
175
- if (start === -1) return void 0;
176
- const result = {};
177
- let subKey = null;
178
- for (let i = start + 1; i < lines.length; i++) {
179
- const line = lines[i];
180
- if (/^\S/.test(line)) break;
181
- const trimmed = line.trim();
182
- if (!trimmed || trimmed.startsWith("#")) continue;
183
- const indent = line.length - line.trimStart().length;
184
- const m = trimmed.match(/^([\w.-]+):\s*(.*)$/);
185
- if (!m) continue;
186
- const [, k, rawVal] = m;
187
- if (indent === 2) {
188
- if (rawVal === "") {
189
- subKey = k;
190
- result[k] = {};
191
- } else {
192
- subKey = null;
193
- result[k] = coerceNestedScalar(rawVal);
194
- }
195
- } else if (indent >= 4 && subKey !== null) {
196
- result[subKey][k] = coerceNestedScalar(rawVal);
197
- }
198
- }
199
- return Object.keys(result).length > 0 ? result : void 0;
200
- }
201
- function parseEffortFile(raw) {
202
- const blockMatch = raw.match(/^---\r?\n([\s\S]*?)\r?\n---/);
203
- if (!blockMatch) return null;
204
- const { meta, body } = parseFrontmatter(raw);
205
- const innerLines = blockMatch[1].split(/\r?\n/);
206
- const id = getScalar(meta, "id");
207
- const slug = getScalar(meta, "slug");
208
- const label = getScalar(meta, "label");
209
- const aliases = getList(meta, "aliases");
210
- const baseAttrs = readNestedSection(innerLines, "baseAttributes");
211
- const hints = readNestedSection(innerLines, "hints");
212
- const derivation = readNestedSection(innerLines, "derivation");
213
- const metRaw = baseAttrs?.met;
214
- const met = typeof metRaw === "number" ? metRaw : Number(metRaw);
215
- if (!id || !slug || !label || metRaw === void 0 || Number.isNaN(met)) return null;
216
- const discipline = parseDiscipline(
217
- typeof baseAttrs?.discipline === "string" ? baseAttrs.discipline : void 0
218
- );
219
- const intensityTier = baseAttrs?.intensityTier;
220
- const trimmedBody = body.trim();
221
- return {
222
- id: String(id),
223
- slug: String(slug),
224
- label: String(label),
225
- aliases,
226
- baseAttributes: {
227
- met,
228
- ...discipline ? { discipline } : {},
229
- ...intensityTier ? { intensityTier } : {}
230
- },
231
- registrySource: "bundled",
232
- ...trimmedBody ? { body: trimmedBody } : {},
233
- ...hints ? { hints } : {},
234
- ...derivation ? { derivation } : {}
235
- };
236
- }
237
86
  var UNKNOWN_GIT_VERSION = {
238
87
  version: 0,
239
88
  versionLabel: "unknown",
@@ -312,6 +161,49 @@ ${manifest.chunks.map(rowHtml).join("\n")}
312
161
  writeFileSync(file, html, "utf8");
313
162
  return file;
314
163
  }
164
+
165
+ // src/seedbuild/frontmatter.ts
166
+ var FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/;
167
+ function unquote(value) {
168
+ return value.replace(
169
+ /^(['"])(.*)\1$/,
170
+ (_match, quote, inner) => quote === '"' ? inner.replace(/\\(["\\])/g, "$1") : inner
171
+ );
172
+ }
173
+ function parseFrontmatter(raw) {
174
+ const match = raw.match(FRONTMATTER_RE);
175
+ if (!match) return { meta: {}, body: raw };
176
+ return { meta: parseMetaLines(match[1].split(/\r?\n/)), body: raw.slice(match[0].length) };
177
+ }
178
+ function parseMetaLines(lines) {
179
+ const meta = {};
180
+ for (let i = 0; i < lines.length; i++) {
181
+ const keyMatch = lines[i].match(/^([A-Za-z][\w.-]*)\s*:(.*)$/);
182
+ if (!keyMatch) continue;
183
+ const key = keyMatch[1];
184
+ const rawVal = keyMatch[2].trim();
185
+ if (rawVal === "") {
186
+ const items = [];
187
+ while (i + 1 < lines.length) {
188
+ const itemMatch = lines[i + 1].match(/^\s+-\s+(.+)$/);
189
+ if (!itemMatch) break;
190
+ items.push(itemMatch[1].trim());
191
+ i++;
192
+ }
193
+ meta[key] = items.length > 0 ? items : "";
194
+ } else {
195
+ const wasQuoted = /^(['"])(.*)\1$/.test(rawVal);
196
+ const value = unquote(rawVal);
197
+ const num = Number(value);
198
+ meta[key] = !wasQuoted && value !== "" && !isNaN(num) ? num : value;
199
+ }
200
+ }
201
+ return meta;
202
+ }
203
+ function getScalar(meta, key) {
204
+ const value = meta[key];
205
+ return typeof value === "string" || typeof value === "number" ? value : void 0;
206
+ }
315
207
  function object(value) {
316
208
  return typeof value === "object" && value !== null && !Array.isArray(value);
317
209
  }
@@ -352,6 +244,7 @@ function chunkIdFor(relPath) {
352
244
  case "canvas":
353
245
  case "dashboards":
354
246
  case "efforts":
247
+ case "equipment":
355
248
  return corpus;
356
249
  case "collections":
357
250
  return parts.length === 3 ? `collection._root` : `collection.${slug}`;
@@ -370,7 +263,7 @@ function partitionIntoChunks(paths) {
370
263
  const id = chunkIdFor(p);
371
264
  if (id === null) {
372
265
  throw new Error(
373
- `[generate-seed] Parity failure: '${p}' is not part of any known corpus (canvas | dashboards | efforts | collections | feeds). Extend chunkIdFor() if this is a new corpus.`
266
+ `[generate-seed] Parity failure: '${p}' is not part of any known corpus (canvas | dashboards | efforts | equipment | collections | feeds). Extend chunkIdFor() if this is a new corpus.`
374
267
  );
375
268
  }
376
269
  const list = byId.get(id);
@@ -452,7 +345,7 @@ function compileSeedRow(path, content, metadata = {}) {
452
345
  const section = sections.find((section2) => section2.from === block.from && section2.to === block.to);
453
346
  return { id: `${noteId}:${block.id}`, noteId, blockId: block.id, blockVersion: 1, sourceRevision: 1, from: block.from, to: block.to, position, dataType: block.kind, ...block.kind === "wod" ? { blockContentId: blockContentId(section?.scriptBlock?.content ?? content.slice(block.from, block.to)) } : {}, rawContent: content.slice(block.from, block.to), noteTitle: metadata.noteTitle ?? fileToDisplayName(path.split("/").at(-1) ?? path), createdAt: metadata.createdAt ?? 0, isStatic: true, sourceId: metadata.sourceId, sourcePath: path, routeId: metadata.routeId };
454
347
  });
455
- return { path, content, blocks, blockIndex, blockEfforts: [] };
348
+ return { path, content, blocks, blockIndex, blockEfforts: [], blockEquipment: [] };
456
349
  }
457
350
  function buildBlockIndexRows(markdownDir, corpusRoot) {
458
351
  const rows = [];
@@ -548,41 +441,37 @@ function formatDiscoveredLabel(raw) {
548
441
  const clean = raw.replace(/[-_]+/g, " ").trim();
549
442
  return clean.split(/\s+/).map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()).join(" ");
550
443
  }
551
- function loadExistingEffortMap(markdownDir) {
552
- const slugs = /* @__PURE__ */ new Set();
553
- const aliasToCanonical = /* @__PURE__ */ new Map();
444
+ function loadCorpusReferenceCatalog(markdownDir) {
445
+ const efforts = [];
446
+ const equipment = [];
554
447
  const effortsDir = join(markdownDir, "efforts");
555
448
  for (const file of listMarkdownFiles(effortsDir)) {
556
- const raw = readFileSync(join(effortsDir, file), "utf8");
557
- const parsed = parseEffortFile(raw);
558
- if (!parsed) continue;
559
- slugs.add(parsed.slug);
560
- aliasToCanonical.set(parsed.slug, parsed.slug);
561
- aliasToCanonical.set(parsed.label.toLowerCase(), parsed.slug);
562
- aliasToCanonical.set(parsed.slug.replace(/-/g, " "), parsed.slug);
563
- for (const alias of parsed.aliases) {
564
- aliasToCanonical.set(alias.toLowerCase(), parsed.slug);
565
- aliasToCanonical.set(alias.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, ""), parsed.slug);
566
- }
449
+ const parsed = parseEffortFile(readFileSync(join(effortsDir, file), "utf8"));
450
+ if (parsed) efforts.push(parsed);
451
+ }
452
+ const equipmentDir = join(markdownDir, "equipment");
453
+ for (const file of listMarkdownFiles(equipmentDir)) {
454
+ const parsed = parseEquipmentFile(readFileSync(join(equipmentDir, file), "utf8"));
455
+ if (parsed) equipment.push(parsed);
567
456
  }
568
- return { slugs, aliasToCanonical };
457
+ return { efforts, equipment };
569
458
  }
570
459
  function discoverUncatalogedEfforts(markdownDir, corpusRoot) {
571
- const { slugs, aliasToCanonical } = loadExistingEffortMap(markdownDir);
460
+ const catalog = loadCorpusReferenceCatalog(markdownDir);
461
+ const index = createReferenceIndex(catalog);
572
462
  const blocks = buildBlockIndexRows(markdownDir, corpusRoot);
573
463
  const discovered = /* @__PURE__ */ new Map();
574
464
  for (const block of blocks) {
575
465
  if (block.dataType !== "wod" || !block.rawContent) continue;
576
466
  const section = parseDocumentSections(block.rawContent, { registeredWidgets: SEED_REGISTERED_WIDGETS }).find((section2) => section2.scriptBlock);
577
- const script = parseScript(section?.scriptBlock?.content ?? block.rawContent);
467
+ const script = parseScript(section?.scriptBlock?.content ?? block.rawContent, { references: index });
578
468
  for (const statement of script.statements) {
579
469
  const effortMetric = statement.metrics?.getMetric?.("effort");
580
470
  const effortLabel = (effortMetric && typeof effortMetric.value === "string" ? effortMetric.value : void 0) ?? statement.exerciseId;
581
471
  if (!effortLabel) continue;
582
- const slugified = effortLabel.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "");
472
+ const slugified = slugifyRefLabel(effortLabel);
583
473
  if (!slugified || NON_EFFORT_SLUGS[slugified]) continue;
584
- const canonical = aliasToCanonical.get(slugified) ?? aliasToCanonical.get(effortLabel.toLowerCase());
585
- if (canonical && slugs.has(canonical)) continue;
474
+ if (index.resolveEffort(slugified) || index.resolveEffort(effortLabel)) continue;
586
475
  const existing = discovered.get(slugified);
587
476
  if (existing) {
588
477
  existing.rawLabels.add(effortLabel);
@@ -632,17 +521,16 @@ ${aliases.join("\n")}` : "aliases: []",
632
521
  }
633
522
  function buildBlockEffortRows(markdownDir, corpusRoot, blocks = buildBlockIndexRows(markdownDir, corpusRoot)) {
634
523
  const efforts = [];
635
- const { aliasToCanonical } = loadExistingEffortMap(markdownDir);
524
+ const index = createReferenceIndex(loadCorpusReferenceCatalog(markdownDir));
636
525
  for (const block of blocks) {
637
526
  if (block.dataType !== "wod" || !block.rawContent) continue;
638
527
  const section = parseDocumentSections(block.rawContent, { registeredWidgets: SEED_REGISTERED_WIDGETS }).find((section2) => section2.scriptBlock);
639
- const script = parseScript(section?.scriptBlock?.content ?? block.rawContent);
640
- const effortSlugs = extractEffortSlugs(script.statements);
528
+ const script = parseScript(section?.scriptBlock?.content ?? block.rawContent, { references: index });
641
529
  const linked = /* @__PURE__ */ new Set();
642
- for (const rawSlug of effortSlugs) {
643
- const norm = rawSlug.toLowerCase().trim();
644
- const canonicalSlug = aliasToCanonical.get(norm) ?? aliasToCanonical.get(norm.replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "")) ?? norm.replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "");
645
- if (!canonicalSlug || NON_EFFORT_SLUGS[canonicalSlug] || NON_EFFORT_SLUGS[norm]) {
530
+ for (const rawSlug of extractStatementRefs(script.statements).efforts) {
531
+ const canonical = index.resolveEffort(rawSlug);
532
+ const canonicalSlug = canonical?.slug;
533
+ if (!canonicalSlug || NON_EFFORT_SLUGS[canonicalSlug] || NON_EFFORT_SLUGS[rawSlug]) {
646
534
  continue;
647
535
  }
648
536
  if (linked.has(canonicalSlug)) continue;
@@ -661,6 +549,32 @@ function buildBlockEffortRows(markdownDir, corpusRoot, blocks = buildBlockIndexR
661
549
  }
662
550
  return efforts;
663
551
  }
552
+ function buildBlockEquipmentRows(markdownDir, corpusRoot, blocks = buildBlockIndexRows(markdownDir, corpusRoot)) {
553
+ const links = [];
554
+ const index = createReferenceIndex(loadCorpusReferenceCatalog(markdownDir));
555
+ for (const block of blocks) {
556
+ if (block.dataType !== "wod" || !block.rawContent) continue;
557
+ const section = parseDocumentSections(block.rawContent, { registeredWidgets: SEED_REGISTERED_WIDGETS }).find((s) => s.scriptBlock);
558
+ const script = parseScript(section?.scriptBlock?.content ?? block.rawContent, { references: index });
559
+ const linked = /* @__PURE__ */ new Set();
560
+ for (const rawSlug of extractStatementRefs(script.statements).equipment) {
561
+ const canonicalSlug = index.resolveEquipment(rawSlug)?.slug;
562
+ if (!canonicalSlug || linked.has(canonicalSlug)) continue;
563
+ linked.add(canonicalSlug);
564
+ links.push({
565
+ id: `${block.id}:${canonicalSlug}`,
566
+ noteId: block.noteId,
567
+ blockId: block.blockId,
568
+ blockContentId: block.blockContentId,
569
+ equipmentSlug: canonicalSlug,
570
+ isStatic: block.isStatic,
571
+ sourcePath: block.sourcePath,
572
+ createdAt: block.createdAt
573
+ });
574
+ }
575
+ }
576
+ return links;
577
+ }
664
578
  function sha256Hex(data) {
665
579
  return createHash("sha256").update(data).digest("hex");
666
580
  }
@@ -712,9 +626,11 @@ ${shown}${more}`);
712
626
  const manifestChunks = [];
713
627
  const tBlockEfforts = Date.now();
714
628
  const effortRows = buildBlockEffortRows(markdownDir, corpusRoot, blockRows);
629
+ const equipmentRows = buildBlockEquipmentRows(markdownDir, corpusRoot, blockRows);
715
630
  passMs.blockEfforts = Date.now() - tBlockEfforts;
716
631
  const blocksByPath = /* @__PURE__ */ new Map();
717
632
  const effortsByPath = /* @__PURE__ */ new Map();
633
+ const equipmentByPath = /* @__PURE__ */ new Map();
718
634
  for (const row of blockRows) {
719
635
  const rows = blocksByPath.get(row.sourcePath) ?? [];
720
636
  rows.push(row);
@@ -725,6 +641,11 @@ ${shown}${more}`);
725
641
  rows.push(row);
726
642
  effortsByPath.set(row.sourcePath, rows);
727
643
  }
644
+ for (const row of equipmentRows) {
645
+ const rows = equipmentByPath.get(row.sourcePath) ?? [];
646
+ rows.push(row);
647
+ equipmentByPath.set(row.sourcePath, rows);
648
+ }
728
649
  let totalFiles = 0;
729
650
  const tWrite = Date.now();
730
651
  for (const { id, files } of groups) {
@@ -735,6 +656,7 @@ ${shown}${more}`);
735
656
  const compiled = compileSeedRow(p, content);
736
657
  compiled.blockIndex = blocksByPath.get(p) ?? compiled.blockIndex;
737
658
  compiled.blockEfforts = effortsByPath.get(p) ?? [];
659
+ compiled.blockEquipment = equipmentByPath.get(p) ?? [];
738
660
  return compiled;
739
661
  });
740
662
  const bytes = Buffer.from(JSON.stringify(rows), "utf8");
@@ -767,6 +689,6 @@ ${shown}${more}`);
767
689
  return { manifest, outDir, totalFiles, reportPath, passMs };
768
690
  }
769
691
 
770
- export { SEED_SCHEMA, buildBlockEffortRows, buildBlockIndexRows, chunkIdFor, collectCorpusMarkdown, compileSeedRow, discoverUncatalogedEfforts, feedDateToCreatedAt, frontmatterDateToCreatedAt, generateSeed, loadExistingEffortMap, partitionIntoChunks, scaffoldDiscoveredEfforts, validateDashboardNote, validateWodBlockSyntax, writeBuildReport };
771
- //# sourceMappingURL=chunk-NATJMTAW.mjs.map
772
- //# sourceMappingURL=chunk-NATJMTAW.mjs.map
692
+ export { SEED_SCHEMA, buildBlockEffortRows, buildBlockEquipmentRows, buildBlockIndexRows, chunkIdFor, collectCorpusMarkdown, compileSeedRow, discoverUncatalogedEfforts, feedDateToCreatedAt, frontmatterDateToCreatedAt, generateSeed, loadCorpusReferenceCatalog, partitionIntoChunks, scaffoldDiscoveredEfforts, validateDashboardNote, validateWodBlockSyntax, writeBuildReport };
693
+ //# sourceMappingURL=chunk-IEW74LUO.mjs.map
694
+ //# sourceMappingURL=chunk-IEW74LUO.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/seedbuild/contract.ts","../src/seedbuild/filename.ts","../src/seedbuild/git-version.ts","../src/seedbuild/report.ts","../src/seedbuild/frontmatter.ts","../src/seedbuild/validation.ts","../src/seedbuild/compiler.ts"],"names":["join","execSync","parseDocumentSections","section","blockContentId","writeFileSync"],"mappings":"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","file":"chunk-IEW74LUO.mjs","sourcesContent":["import type { BlockEffort, BlockEquipment, BlockIndexRow, NoteBlock } from '@bitcobblers/wod-wiki-core';\nimport { KNOWN_SECTION_WIDGETS } from '@bitcobblers/wod-wiki-core';\n\nexport const SEED_SCHEMA = 9;\nexport const SEED_REGISTERED_WIDGETS = KNOWN_SECTION_WIDGETS;\n\n/** Source and all current derived rows commit as one chunk. */\nexport interface SeedRow {\n path: string;\n content: string;\n blocks: Record<string, NoteBlock>;\n blockIndex: BlockIndexRow[];\n blockEfforts: BlockEffort[];\n blockEquipment: BlockEquipment[];\n}\n\nexport type ChunkKind = 'notes';\nexport interface ManifestChunk {\n id: string;\n path: string;\n sha256: string;\n bytes: number;\n count: number;\n kind?: ChunkKind;\n}\nexport interface SeedManifest {\n name?: string;\n description?: string;\n repositoryUrl?: string;\n schema: number;\n version: number;\n versionLabel?: string;\n commit?: string;\n dirty?: boolean;\n builtAt: string;\n chunks: ManifestChunk[];\n}\nexport type SeedPrecedenceTier = 'core' | 'community' | 'imported' | 'user';\nexport const SEED_PRECEDENCE_RANK: Readonly<Record<SeedPrecedenceTier, number>> = {\n core: 0,\n community: 1,\n imported: 2,\n user: 3,\n};\nexport function seedSourceTier(sourceIdOrMetaKey?: string | null, explicitTier?: SeedPrecedenceTier): SeedPrecedenceTier {\n if (explicitTier) return explicitTier;\n if (!sourceIdOrMetaKey) return 'core';\n if (sourceIdOrMetaKey === 'user') return 'user';\n const id = sourceIdOrMetaKey.startsWith('seed:') ? sourceIdOrMetaKey.slice(5) : sourceIdOrMetaKey;\n if (id === 'core' || id === 'efforts' || id === 'equipment') return 'core';\n if (id === 'community' || id.startsWith('community-') || id === 'common') return 'community';\n return 'imported';\n}\nexport function seedPrecedenceRank(sourceIdOrMetaKey?: string | null, explicitTier?: SeedPrecedenceTier): number {\n return SEED_PRECEDENCE_RANK[seedSourceTier(sourceIdOrMetaKey, explicitTier)];\n}\nexport interface SeedMetaRecord {\n key: string;\n schema: number;\n seedVersion: number;\n builtAt: string;\n importedAt: number;\n chunks: Record<string, { sha256: string; noteIds?: string[] }>;\n claim?: { owner: string; at: number } | null;\n tier?: SeedPrecedenceTier;\n}\nexport const SEED_BROADCAST_CHANNEL = 'wodwiki.seed';\nexport const EFFORTS_CHUNK_ID = 'efforts';\nexport const EQUIPMENT_CHUNK_ID = 'equipment';\nexport const CANVAS_CHUNK_ID = 'canvas';\nexport const DASHBOARDS_CHUNK_ID = 'dashboards';\nexport const TEMPLATE_CHUNK_ID = 'template';\nexport function seedMetaKey(sourceId: string): string { return `seed:${sourceId}`; }\nexport function emptySeedMeta(key: string): SeedMetaRecord {\n return { key, schema: SEED_SCHEMA, seedVersion: 0, builtAt: '', importedAt: 0, chunks: {}, claim: null };\n}\nexport function catalogForChunkId(chunkId: string): string | undefined {\n const value = /^(?:collection|feed)\\.(.+)$/.exec(chunkId)?.[1];\n return value && value !== '_root' ? value : undefined;\n}\nexport function canvasRouteSlug(content: string): string | null {\n const fm = /^---\\r?\\n([\\s\\S]*?)\\r?\\n---/.exec(content);\n if (fm?.[1] && !/^template:\\s*canvas\\s*$/m.test(fm[1])) return null;\n return fm?.[1]?.match(/^route:\\s*(\\S+)\\s*$/m)?.[1]?.replace(/^\\//, '') || null;\n}\nexport function seedNoteSourceId(path: string, content: string, chunkId: string): string | undefined {\n const parts = path.split('/');\n const stem = (parts.at(-1) ?? '').replace(/\\.md$/i, '');\n const under = parts.slice(2).map((p) => p.replace(/\\.md$/i, '')).join('/');\n if (chunkId === CANVAS_CHUNK_ID) return `guides:${canvasRouteSlug(content) ?? under}`;\n if (chunkId === DASHBOARDS_CHUNK_ID) return 'dashboards';\n if (chunkId === EFFORTS_CHUNK_ID) return 'efforts';\n if (chunkId === EQUIPMENT_CHUNK_ID) return 'equipment';\n if (chunkId === TEMPLATE_CHUNK_ID) return 'playground';\n if (chunkId.startsWith('collection.')) {\n const catalog = catalogForChunkId(chunkId);\n return !catalog ? 'collection:_root' : stem.toLowerCase() === 'readme' ? `collection:${catalog}` : `collection:${catalog}/${stem}`;\n }\n if (chunkId.startsWith('feed.')) return `feed:feeds/${under}`;\n return undefined;\n}\n","/**\n * fileToDisplayName — port of wod-wiki's\n * apps/playground/src/repositories/groupings.ts (display-name derivation\n * only). Block-index rows carry the same note titles the app renders, so\n * titles must derive identically on both sides.\n */\n\n/** Lowercased mid-title words — \"and\", \"of\", \"70.3\"-style fragments read wrong capped. */\nconst FILE_TITLE_STOP_WORDS: Record<string, true> = {\n and: true, or: true, of: true, for: true, to: true, in: true, on: true,\n at: true, by: true, with: true, the: true, a: true, an: true,\n};\n\n/**\n * Parse a filename into a display name.\n * \"simple-and-sinister.md\" -> \"Simple and Sinister\"\n */\nexport function fileToDisplayName(filename: string): string {\n const base = filename.replace(/\\.md$/, '');\n if (base.toUpperCase() === 'README') return 'Overview';\n // Strip leading \"day-01-\" prefixes if present, then humanise\n const cleaned = base.replace(/^day-\\d+-/, '');\n const tokens = cleaned.split(/[-_]/);\n const titled: string[] = [];\n for (let i = 0; i < tokens.length; i++) {\n const token = tokens[i]!;\n const next = tokens[i + 1];\n const after = tokens[i + 2];\n const prev = tokens[i - 1];\n // Race distances keep their dot: a lone 1-2-digit pair (\"70-3\" -> \"70.3\").\n // Longer numeric runs are dates (2009-12-01) or rep ladders (5-3-1) —\n // only an isolated pair between words is a distance.\n if (\n /^\\d{1,2}$/.test(token) && /^\\d{1,2}$/.test(next ?? '')\n && !/^\\d+$/.test(prev ?? '') && !/^\\d+$/.test(after ?? '')\n ) {\n titled.push(`${token}.${next}`);\n i++;\n continue;\n }\n if (titled.length > 0 && FILE_TITLE_STOP_WORDS[token.toLowerCase()]) {\n titled.push(token.toLowerCase());\n continue;\n }\n titled.push(token.charAt(0).toUpperCase() + token.slice(1));\n }\n return titled.join(' ');\n}\n","/**\n * Git-derived versioning — the seed artifact's version IS this repo's git\n * history. Every merged MR advances `version` (commit count), and\n * `versionLabel`/`commit` make an artifact traceable to its exact source\n * tree, so the app (and humans diffing manifests) can answer \"what changed\n * and what needs syncing\" from the manifest alone.\n */\nimport { execSync } from 'node:child_process';\n\nexport interface GitVersion {\n /** Monotonic commit count — the import-order version stamped on the manifest. */\n version: number;\n /** `git describe --tags --long --always --dirty`, e.g. `v1.2.0-4-gdeadbee`. */\n versionLabel: string;\n /** Full HEAD sha. */\n commit: string;\n /** True when built with uncommitted working-tree changes. */\n dirty: boolean;\n}\n\n/** Unversioned fallback for source trees without git history (e.g. exported tarballs). */\nexport const UNKNOWN_GIT_VERSION: GitVersion = {\n version: 0,\n versionLabel: 'unknown',\n commit: '',\n dirty: false,\n};\n\nexport function resolveGitVersion(repoRoot: string): GitVersion {\n try {\n const run = (args: string): string =>\n execSync(`git ${args}`, { cwd: repoRoot, encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim();\n const count = Number(run('rev-list --count HEAD'));\n return {\n version: Number.isFinite(count) && count > 0 ? count : 0,\n versionLabel: run('describe --tags --long --always --dirty'),\n commit: run('rev-parse HEAD'),\n dirty: run('status --porcelain') !== '',\n };\n } catch {\n return UNKNOWN_GIT_VERSION;\n }\n}\n","/**\n * Build report — a static HTML benchmark page for each seed build\n * (`dist/report.html`). Per-chunk sizes, row counts, pass timings, and the\n * git version stamp, so CI and contributors see build health at a glance.\n * Deliberately dependency-free (one string template + a file write).\n */\nimport { writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport type { SeedManifest } from './contract';\n\nexport interface BuildReportData {\n manifest: SeedManifest;\n /** Wall-clock ms for the full build. */\n totalMs: number;\n /** Per-pass timings (ms): corpus scan, block-index derivation, effort-row derivation, chunk writes. */\n passMs: { scan: number; blockIndex: number; parseGate: number; blockEfforts: number; write: number };\n /** Number of corpus markdown files. */\n fileCount: number;\n outDir: string;\n}\n\nfunction escapeHtml(s: string): string {\n return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\n}\n\nfunction rowHtml(c: SeedManifest['chunks'][number]): string {\n const kind = c.kind ?? 'notes';\n return `<tr><td>${escapeHtml(c.id)}</td><td>${kind}</td><td>${c.count}</td><td>${(c.bytes / 1024).toFixed(1)} KB</td><td><code>${c.sha256.slice(0, 8)}</code></td></tr>`;\n}\n\nexport function writeBuildReport(outDir: string, data: BuildReportData): string {\n const { manifest, totalMs, passMs, fileCount } = data;\n const totalBytes = manifest.chunks.reduce((s, c) => s + c.bytes, 0);\n const dirtyBadge = manifest.dirty\n ? ' <strong style=\"color:#b45309\">(dirty working tree — not reproducible from <code>' + escapeHtml(manifest.commit ?? '') + '</code>)</strong>'\n : '';\n const html = `<!doctype html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\" />\n<title>Seed build report</title>\n<style>\n body { font-family: system-ui, sans-serif; max-width: 960px; margin: 2rem auto; padding: 0 1rem; color: #1f2937; }\n h1 { font-size: 1.4rem; } h2 { font-size: 1.1rem; margin-top: 2rem; }\n table { border-collapse: collapse; width: 100%; font-size: 0.9rem; }\n th, td { text-align: left; padding: 0.3rem 0.6rem; border-bottom: 1px solid #e5e7eb; }\n code { font-size: 0.85em; }\n dl { display: grid; grid-template-columns: max-content 1fr; gap: 0.2rem 1rem; font-size: 0.95rem; }\n dt { font-weight: 600; }\n</style>\n</head>\n<body>\n<h1>Seed build report</h1>\n<h2>Version</h2>\n<dl>\n <dt>version</dt><dd>${manifest.version} <code>${escapeHtml(manifest.versionLabel ?? '')}</code>${dirtyBadge}</dd>\n <dt>commit</dt><dd><code>${escapeHtml(manifest.commit ?? 'unknown')}</code></dd>\n <dt>built at</dt><dd>${escapeHtml(manifest.builtAt)}</dd>\n <dt>schema</dt><dd>v${manifest.schema}</dd>\n</dl>\n<h2>Benchmarks</h2>\n<dl>\n <dt>total</dt><dd>${totalMs} ms</dd>\n <dt>corpus scan + partition</dt><dd>${passMs.scan} ms (${fileCount} files)</dd>\n <dt>block-index derivation</dt><dd>${passMs.blockIndex} ms</dd>\n <dt>block syntax gate</dt><dd>${passMs.parseGate} ms</dd>\n <dt>block-efforts derivation</dt><dd>${passMs.blockEfforts} ms</dd>\n <dt>chunk writes</dt><dd>${passMs.write} ms</dd>\n</dl>\n<h2>Chunks (${manifest.chunks.length}, ${(totalBytes / 1024).toFixed(0)} KB total)</h2>\n<table>\n<thead><tr><th>id</th><th>kind</th><th>rows</th><th>size</th><th>sha256</th></tr></thead>\n<tbody>\n${manifest.chunks.map(rowHtml).join('\\n')}\n</tbody>\n</table>\n</body>\n</html>\n`;\n const file = join(outDir, 'report.html');\n writeFileSync(file, html, 'utf8');\n return file;\n}\n","/**\n * Frontmatter parser — port of wod-wiki's apps/playground/src/lib/frontmatter.ts\n * (parseFrontmatter/getScalar/getList only; the editor-only helpers\n * (LinkWidget, YouTube, serialize) stay in the app).\n *\n * ponytail: semantics must match the app's parser exactly — the seed\n * compiler and the app runtime derive frontmatter from the same corpus.\n * Upgrade path: publish the parser in @bitcobblers/wod-wiki-core and import\n * from both sides.\n */\n\nexport interface ParsedFrontmatter {\n meta: Record<string, string | number | string[]>\n body: string\n}\n\n/** Leading `---` … `---` block; body is everything after the closing delimiter. */\nconst FRONTMATTER_RE = /^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?/;\n\n/** Strip matched wrapping quotes: `\"x\"` / `'x'` → `x`; mismatched quotes are kept.\n * Double-quoted values also collapse the serializer's escapes (`\\\\\"`, `\\\\\\\\`). */\nfunction unquote(value: string): string {\n return value.replace(/^(['\"])(.*)\\1$/, (_match, quote: string, inner: string) =>\n quote === '\"' ? inner.replace(/\\\\([\"\\\\])/g, '$1') : inner,\n );\n}\n\n/**\n * Parse the leading YAML frontmatter block of a markdown string.\n *\n * Semantics (mirrors the app):\n * - Scalar `key: value` (key `/^[A-Za-z][\\w.-]*$/`, dots allow flat nested\n * keys like `book.title`): wrapping quotes stripped; bare numeric strings\n * become `number`, quoted scalars always stay strings.\n * - `key:` with empty value followed by indented `- item` lines → `string[]`.\n * - `key:` with empty value and no list items → `''`.\n * - Inline `key: [a, b]` stays a plain scalar string.\n */\nexport function parseFrontmatter(raw: string): ParsedFrontmatter {\n const match = raw.match(FRONTMATTER_RE);\n if (!match) return { meta: {}, body: raw };\n return { meta: parseMetaLines(match[1].split(/\\r?\\n/)), body: raw.slice(match[0].length) };\n}\n\nfunction parseMetaLines(lines: string[]): ParsedFrontmatter['meta'] {\n const meta: ParsedFrontmatter['meta'] = {};\n\n for (let i = 0; i < lines.length; i++) {\n const keyMatch = lines[i].match(/^([A-Za-z][\\w.-]*)\\s*:(.*)$/);\n if (!keyMatch) continue; // indented/nested/list lines are not top-level keys\n\n const key = keyMatch[1];\n const rawVal = keyMatch[2].trim();\n\n if (rawVal === '') {\n const items: string[] = [];\n while (i + 1 < lines.length) {\n const itemMatch = lines[i + 1].match(/^\\s+-\\s+(.+)$/);\n if (!itemMatch) break;\n items.push(itemMatch[1].trim());\n i++;\n }\n meta[key] = items.length > 0 ? items : '';\n } else {\n const wasQuoted = /^(['\"])(.*)\\1$/.test(rawVal);\n const value = unquote(rawVal);\n const num = Number(value);\n meta[key] = !wasQuoted && value !== '' && !isNaN(num) ? num : value;\n }\n }\n\n return meta;\n}\n\n/** Scalar value at `key`, or `undefined` when absent or a list. */\nexport function getScalar(\n meta: ParsedFrontmatter['meta'],\n key: string,\n): string | number | undefined {\n const value = meta[key];\n return typeof value === 'string' || typeof value === 'number' ? value : undefined;\n}\n\n/** List value at `key`, or `[]` when absent or a scalar. */\nexport function getList(meta: ParsedFrontmatter['meta'], key: string): string[] {\n const value = meta[key];\n return Array.isArray(value) ? value : [];\n}\n","import { blockContentId, parseDocumentSections, validateNoteBlocks } from '@bitcobblers/wod-wiki-core';\nimport { SEED_REGISTERED_WIDGETS, SEED_SCHEMA, type SeedManifest, type SeedRow } from './contract';\n\nfunction object(value: unknown): value is Record<string, unknown> { return typeof value === 'object' && value !== null && !Array.isArray(value); }\nfunction positive(value: unknown): value is number { return typeof value === 'number' && Number.isSafeInteger(value) && value > 0; }\nfunction nonnegative(value: unknown): value is number { return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0; }\nexport function assertSeedManifest(value: unknown): SeedManifest {\n if (!object(value) || value.schema !== SEED_SCHEMA) throw new Error('Incompatible seed schema; rebuild seed artifacts');\n if (!nonnegative(value.version) || typeof value.builtAt !== 'string' || !Number.isFinite(Date.parse(value.builtAt)) || !Array.isArray(value.chunks)) throw new Error('seed manifest failed shape validation');\n for (const key of ['versionLabel', 'commit', 'name', 'description']) if (value[key] !== undefined && typeof value[key] !== 'string') throw new Error('invalid seed manifest metadata');\n if (value.repositoryUrl !== undefined && (typeof value.repositoryUrl !== 'string' || !/^https:\\/\\//.test(value.repositoryUrl) || new URL(value.repositoryUrl).username || new URL(value.repositoryUrl).password)) throw new Error('invalid seed repository URL');\n if (value.dirty !== undefined && typeof value.dirty !== 'boolean') throw new Error('invalid seed manifest metadata');\n const ids = new Set<string>(), paths = new Set<string>();\n for (const chunk of value.chunks) {\n if (!object(chunk) || typeof chunk.id !== 'string' || !chunk.id || typeof chunk.path !== 'string' || !/^chunks\\/[a-zA-Z0-9._-]+\\.json$/.test(chunk.path) || typeof chunk.sha256 !== 'string' || !/^[0-9a-f]{64}$/.test(chunk.sha256) || !nonnegative(chunk.bytes) || !nonnegative(chunk.count) || (chunk.kind !== undefined && chunk.kind !== 'notes') || ids.has(chunk.id) || paths.has(chunk.path)) throw new Error('seed manifest failed shape validation');\n ids.add(chunk.id); paths.add(chunk.path);\n }\n return value as unknown as SeedManifest;\n}\nexport function assertSeedRows(value: unknown): SeedRow[] {\n if (!Array.isArray(value)) throw new Error('seed chunk is not an array');\n const paths = new Set<string>();\n for (const row of value) {\n if (!object(row) || typeof row.path !== 'string' || !row.path || row.path.startsWith('/') || row.path.split('/').includes('..') || paths.has(row.path) || typeof row.content !== 'string' || !object(row.blocks) || !Array.isArray(row.blockIndex) || !Array.isArray(row.blockEfforts)) throw new Error('seed chunk row failed shape validation');\n paths.add(row.path);\n for (const [id, block] of Object.entries(row.blocks)) {\n if (!object(block) || block.id !== id || !id || block.version !== 1 || block.sourceRevision !== 1 || !nonnegative(block.from) || !positive(block.to) || block.from >= block.to || block.to > row.content.length || !['wod', 'query', 'widget', 'embed'].includes(String(block.kind)) || (block.kind === 'wod' ? !['time', 'log'].includes(String(block.dialect)) : block.dialect !== undefined) || (block.sport !== undefined && typeof block.sport !== 'string')) throw new Error('invalid seed block range or revision');\n }\n validateNoteBlocks(row.content, row.blocks as SeedRow['blocks'], 1, { registeredWidgets: SEED_REGISTERED_WIDGETS });\n const indexed = new Set<string>();\n const sections = parseDocumentSections(row.content, { registeredWidgets: SEED_REGISTERED_WIDGETS });\n for (const projection of row.blockIndex) {\n if (!object(projection) || typeof projection.blockId !== 'string') throw new Error('invalid seed projection');\n const block = row.blocks[projection.blockId];\n if (!object(block) || indexed.has(projection.blockId) || typeof projection.id !== 'string' || typeof projection.noteId !== 'string' || projection.id !== `${projection.noteId}:${projection.blockId}` || projection.blockVersion !== 1 || projection.sourceRevision !== 1 || projection.from !== block.from || projection.to !== block.to || projection.dataType !== block.kind || projection.rawContent !== row.content.slice(Number(block.from), Number(block.to)) || typeof projection.noteTitle !== 'string' || typeof projection.createdAt !== 'number' || !Number.isFinite(projection.createdAt) || projection.sourcePath !== row.path || projection.isStatic !== true) throw new Error('orphan or incompatible seed projection');\n if ('segmentId' in projection || 'segmentVersion' in projection) throw new Error('incompatible seed projection');\n for (const key of ['sourceId', 'routeId', 'blockContentId']) if (projection[key] !== undefined && typeof projection[key] !== 'string') throw new Error('invalid seed projection metadata');\n if (projection.position !== undefined && !nonnegative(projection.position)) throw new Error('invalid seed projection position');\n if (block.kind === 'wod') {\n const section = sections.find((s) => s.from === block.from && s.to === block.to);\n if (projection.blockContentId !== blockContentId(section?.scriptBlock?.content ?? row.content.slice(Number(block.from), Number(block.to)))) throw new Error('invalid seed workout fingerprint');\n } else if (projection.blockContentId !== undefined) throw new Error('non-workout seed fingerprint');\n indexed.add(projection.blockId);\n }\n if (indexed.size !== Object.keys(row.blocks).length) throw new Error('missing actionable seed projection');\n const links = new Set<string>();\n for (const link of row.blockEfforts) {\n if (!object(link) || typeof link.blockId !== 'string' || typeof link.noteId !== 'string' || typeof link.effortSlug !== 'string' || !link.effortSlug) throw new Error('invalid seed effort identity');\n const block = row.blocks[link.blockId];\n if (link.id !== `${link.noteId}:${link.blockId}:${link.effortSlug}` || links.has(String(link.id)) || !object(block) || block.kind !== 'wod' || !indexed.has(link.blockId) || link.sourcePath !== row.path || link.isStatic !== true || typeof link.createdAt !== 'number') throw new Error('orphan or incompatible seed effort link');\n const projection = row.blockIndex.find((p: unknown) => object(p) && p.blockId === link.blockId);\n if (!object(projection) || link.noteId !== projection.noteId || link.blockContentId !== projection.blockContentId || !Number.isFinite(link.createdAt)) throw new Error('invalid seed effort metadata');\n links.add(String(link.id));\n }\n }\n return value as SeedRow[];\n}","/** Compiles exact source, occurrence maps and sparse projections into atomic notes chunks. */\nimport { parseScript, whiteboardParser } from '@bitcobblers/wod-wiki-lang';\nimport { blockContentId, parseDocumentSections, reconcileNoteBlocks } from '@bitcobblers/wod-wiki-core';\nimport type { BlockEffort, BlockEquipment, BlockIndexRow } from '@bitcobblers/wod-wiki-storage';\nimport {\n buildDashboardDocument,\n isDashboardWidgetType,\n parseDashboardNote,\n parseQuery,\n resolveWidgetType,\n} from '@bitcobblers/wod-wiki-wql';\nimport {\n DASHBOARDS_CHUNK_ID,\n SEED_SCHEMA,\n SEED_REGISTERED_WIDGETS,\n TEMPLATE_CHUNK_ID,\n canvasRouteSlug,\n seedNoteSourceId,\n type ManifestChunk,\n type SeedManifest,\n type SeedRow,\n} from './contract';\nimport { fileToDisplayName } from './filename';\nimport { createReferenceIndex, extractStatementRefs, parseEffortFile, parseEquipmentFile, slugifyRefLabel, type IEffort, type IEquipment } from '@bitcobblers/wod-wiki-lang';\nimport { resolveGitVersion } from './git-version';\nimport { writeBuildReport } from './report';\nimport { getScalar, parseFrontmatter } from './frontmatter';\nimport { assertSeedManifest } from './validation';\nimport { createHash } from 'node:crypto';\nimport { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from 'node:fs';\nimport { execSync } from 'node:child_process';\nimport { join, relative } from 'node:path';\n\n// BlockEffort/BlockIndexRow row types come from @bitcobblers/wod-wiki-storage\n// (type-only import — chunk rows are plain JSON applied structurally by the\n// app, mirroring cli/seed.ts).\n\n/** Scan `dir` recursively for `*.md` files; returns POSIX paths relative to `dir`, sorted. */\nfunction listMarkdownFiles(dir: string, prefix = ''): string[] {\n if (!existsSync(dir)) return [];\n const out: string[] = [];\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const rel = prefix ? `${prefix}/${entry.name}` : entry.name;\n if (entry.isDirectory()) out.push(...listMarkdownFiles(join(dir, entry.name), rel));\n else if (entry.isFile() && entry.name.endsWith('.md')) out.push(rel);\n }\n return out.sort();\n}\n\n// ── Types ─────────────────────────────────────────────────────────────────\n\nexport interface ChunkGroup {\n id: string;\n files: string[];\n}\n\nexport interface GenerateSeedOptions {\n /** The corpus directory (`markdown/`). Defaults to `<corpusRoot>/markdown`. */\n markdownDir?: string;\n /** Optional playground template file — the host passes its own; standalone builds omit the `template` chunk. */\n templateFile?: string;\n /**\n * Row path recorded for the template chunk (the runtime derives the\n * template note's id from it, so it must stay stable across builds). The\n * host pins its historical in-repo path; defaults to the path relative to\n * `corpusRoot`.\n */\n templateRowPath?: string;\n /** Output directory. Defaults to `<corpusRoot>/dist`. */\n outDir?: string;\n /**\n * Explicit manifest version (tests). Defaults to the corpus repo's git\n * commit count — see git-version.ts.\n */\n version?: number;\n /** Repo root the corpus paths resolve against and versioning derives from. Defaults to cwd. */\n corpusRoot?: string;\n /** Automatically scaffold markdown files for newly discovered efforts. */\n scaffoldDiscoveredEfforts?: boolean;\n}\n\nexport interface GenerateSeedResult {\n manifest: SeedManifest;\n outDir: string;\n totalFiles: number;\n reportPath: string;\n /** ms timings per pass (mirrored into report.html). */\n passMs: { scan: number; blockIndex: number; parseGate: number; blockEfforts: number; write: number };\n}\n\n// ── Corpus partition ──────────────────────────────────────────────────────\n\n/**\n * Map one `markdown/…` path to its chunk id. Returns null for files outside\n * the known corpora — callers MUST treat that as a parity failure so new\n * content directories cannot bypass the seed.\n */\nexport function chunkIdFor(relPath: string): string | null {\n const parts = relPath.split('/');\n if (parts[0] !== 'markdown' || parts.length < 2) return null;\n const corpus = parts[1];\n // markdown/<corpus>/<rest…>; a file directly under markdown/ has no corpus.\n if (parts.length === 2) return null;\n const slug = parts[2]?.replace(/\\.md$/, '');\n switch (corpus) {\n case 'canvas':\n case 'dashboards':\n case 'efforts':\n case 'equipment':\n return corpus;\n case 'collections':\n return parts.length === 3 ? `collection._root` : `collection.${slug}`;\n case 'feeds':\n return parts.length === 3 ? `feed._root` : `feed.${slug}`;\n default:\n return null;\n }\n}\n\n/** Scan the markdown corpus; returns repo-relative POSIX paths of all .md files. */\nexport function collectCorpusMarkdown(markdownDir: string): string[] {\n return listMarkdownFiles(markdownDir).map((p) => `markdown/${p}`);\n}\n\n/** Group markdown corpus paths into chunk groups; throws on paths outside the known corpora. */\nexport function partitionIntoChunks(paths: string[]): ChunkGroup[] {\n const byId = new Map<string, string[]>();\n for (const p of paths) {\n const id = chunkIdFor(p);\n if (id === null) {\n throw new Error(\n `[generate-seed] Parity failure: '${p}' is not part of any known corpus ` +\n `(canvas | dashboards | efforts | equipment | collections | feeds). ` +\n `Extend chunkIdFor() if this is a new corpus.`,\n );\n }\n const list = byId.get(id);\n if (list) list.push(p);\n else byId.set(id, [p]);\n }\n return [...byId.entries()]\n .sort(([a], [b]) => (a < b ? -1 : 1))\n .map(([id, files]) => ({ id, files }));\n}\n\n// ── Dashboard gate (#906) ─────────────────────────────────────────────────\n\n/**\n * Validate one dashboard note in the locked #899 format: dashboard\n * frontmatter, a title, known widget types, WQL bodies that parse (and are\n * aggregate queries, not find queries), and every `$token` reference\n * declared. Returns the problems found (empty = valid).\n */\nexport function validateDashboardNote(raw: string): string[] {\n const problems: string[] = [];\n const { meta } = parseFrontmatter(raw);\n const { sections } = parseDashboardNote(raw);\n const doc = buildDashboardDocument(sections, meta);\n if (!doc.isDashboard) return ['file is not a dashboard note (missing dashboard frontmatter)'];\n if (doc.title === undefined) problems.push('dashboard has no title');\n if (doc.widgets.length < 3) problems.push(`dashboard has only ${doc.widgets.length} widgets (the locked format has ≥ 3)`);\n const declared = new Set(doc.tokens.map((t) => t.name));\n for (const widget of doc.widgets) {\n const where = `widget '${widget.title ?? widget.body.slice(0, 40)}'`;\n if (widget.title === undefined) problems.push(`${where}: missing title`);\n if (!isDashboardWidgetType(resolveWidgetType(widget.type))) {\n problems.push(`${where}: unknown widget type '${widget.type}'`);\n }\n const parsed = parseQuery(widget.body);\n if (parsed.error !== undefined) problems.push(`${where}: WQL parse error: ${parsed.error}`);\n for (const ref of [\n ...widget.body.matchAll(/\\$([A-Za-z][\\w-]*)/g),\n ...Object.values(widget.attributes).flatMap((v) => [...String(v).matchAll(/\\$([A-Za-z][\\w-]*)/g)]),\n ]) {\n if (!declared.has(ref[1])) problems.push(`${where}: undeclared token $${ref[1]}`);\n }\n }\n return problems;\n}\n\n/** Validate every dashboard file in a chunk group; throws on the first invalid file. */\nfunction gateDashboards(groups: ChunkGroup[], corpusRoot: string): void {\n for (const group of groups) {\n if (group.id !== DASHBOARDS_CHUNK_ID) continue;\n for (const p of group.files) {\n const problems = validateDashboardNote(readFileSync(join(corpusRoot, p), 'utf8'));\n if (problems.length > 0) {\n throw new Error(`[generate-seed] Dashboard validation failed for '${p}':\\n - ${problems.join('\\n - ')}`);\n }\n }\n }\n}\n\n// ── Block index derivation ────────────────────────────────────────────────\n\n\n/** Created-at from the corpus repo's git history (collections/guides), 0 fallback when unknown. */\nfunction getFileCreatedAt(file: string, repoRoot: string): number {\n try {\n const out = execSync(`git log -1 --format=%ct -- '${file}'`, { cwd: repoRoot, encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim();\n const ts = Number(out) * 1000;\n return Number.isFinite(ts) && ts > 0 ? ts : 0;\n } catch {\n return 0;\n }\n}\n\n/**\n * Frontmatter `date: YYYY-MM-DD` → epoch ms at noon UTC (mirrors the seed\n * importer's Note.date, so the block and note planes place a post on the\n * same civil day). Absent/empty → undefined; anything else that is not a\n * real calendar day throws — the build fails loudly instead of silently\n * misdating or rolling the post to another day.\n */\nexport function frontmatterDateToCreatedAt(raw: string, path: string): number | undefined {\n const value = getScalar(parseFrontmatter(raw).meta, 'date');\n if (value === undefined || value === '') return undefined;\n const text = String(value);\n const parts = text.match(/^(\\d{4})-(\\d{2})-(\\d{2})$/);\n const ts = parts ? Date.parse(`${text}T12:00:00Z`) : NaN;\n // Some engines roll impossible days (2026-02-30 → March 2) instead of\n // failing — round-trip the UTC components so the post can never silently\n // move to another day.\n const valid = !!parts && Number.isFinite(ts)\n && new Date(ts).getUTCMonth() === Number(parts[2]) - 1\n && new Date(ts).getUTCDate() === Number(parts[3]);\n if (!valid) {\n throw new Error(`[wod build] invalid frontmatter date '${text}' in '${path}' — expected a real calendar day (YYYY-MM-DD)`);\n }\n return ts;\n}\n\n/** Created-at timestamp for a feed entry's date key (`yyyy-mm-dd` from the path). */\nexport function feedDateToCreatedAt(dateKey: string): number {\n if (!/^\\d{4}-\\d{2}-\\d{2}$/.test(dateKey)) return 0;\n const ts = Date.parse(`${dateKey}T00:00:00Z`);\n return Number.isNaN(ts) ? 0 : ts;\n}\n\n// canvasRouteSlug lives in contract.ts — one derivation shared by the\n// block plane (here) and the app's importer (note plane).\n\n\nexport function compileSeedRow(path: string, content: string, metadata: { routeId?: string; noteTitle?: string; sourceId?: string; createdAt?: number } = {}): SeedRow {\n let ordinal = 0;\n const blocks = reconcileNoteBlocks(content, { sourceRevision: 1, registeredWidgets: SEED_REGISTERED_WIDGETS, createId: () => `seed:${path}:${ordinal++}` });\n const noteId = metadata.routeId ?? path;\n const sections = parseDocumentSections(content);\n const blockIndex: BlockIndexRow[] = Object.values(blocks).map((block, position) => {\n const section = sections.find((section) => section.from === block.from && section.to === block.to);\n return { id: `${noteId}:${block.id}`, noteId, blockId: block.id, blockVersion: 1, sourceRevision: 1, from: block.from, to: block.to, position, dataType: block.kind, ...(block.kind === 'wod' ? { blockContentId: blockContentId(section?.scriptBlock?.content ?? content.slice(block.from, block.to)) } : {}), rawContent: content.slice(block.from, block.to), noteTitle: metadata.noteTitle ?? fileToDisplayName(path.split('/').at(-1) ?? path), createdAt: metadata.createdAt ?? 0, isStatic: true, sourceId: metadata.sourceId, sourcePath: path, routeId: metadata.routeId };\n });\n return { path, content, blocks, blockIndex, blockEfforts: [], blockEquipment: [] };\n}\n\nexport function buildBlockIndexRows(markdownDir: string, corpusRoot: string): BlockIndexRow[] {\n const rows: BlockIndexRow[] = [];\n for (const path of collectCorpusMarkdown(markdownDir)) {\n const chunkId = chunkIdFor(path);\n if (!chunkId) continue;\n const content = readFileSync(join(corpusRoot, path), 'utf8');\n const parts = path.split('/');\n const stem = (parts.at(-1) ?? '').replace(/\\.md$/, '');\n const catalog = parts[2];\n const routeId = chunkId === 'canvas' ? canvasRouteSlug(content) ?? undefined : chunkId.startsWith('collection.') ? (stem.toLowerCase() === 'readme' ? catalog : `${catalog}/${stem}`) : chunkId.startsWith('feed.') ? parts.slice(1).join('/').replace(/\\.md$/, '') : undefined;\n const sourceId = seedNoteSourceId(path, content, chunkId);\n // Authored frontmatter date wins regardless of filename/directory; undated\n // feeds keep their historical path-date placement, everything else falls\n // back to the corpus repo's git history.\n const createdAt = frontmatterDateToCreatedAt(content, path)\n ?? (chunkId.startsWith('feed.') ? feedDateToCreatedAt(parts.at(-2) ?? '') : getFileCreatedAt(path, corpusRoot));\n rows.push(...compileSeedRow(path, content, { routeId, sourceId, createdAt }).blockIndex);\n }\n return rows;\n}\n\n/**\n * Syntax gate — every `wod` block's script must parse cleanly.\n *\n * Plain fences get a strict scan of the Lezer tree for error nodes\n * (`WhiteboardScript.errors` only carries mapper exceptions; the parser\n * recovers silently, so the tree is scanned directly) with `path:line`\n * diagnostics. Dialect-fenced blocks (`log:climbing`, …) are owned by the\n * dialect stack — their `key: value` lines are recovered by dialect\n * handlers, not the base grammar — so those gate on the exception channel\n * of a dialect-aware parse instead, matching how the app consumes them.\n */\nexport function validateWodBlockSyntax(blocks: BlockIndexRow[]): string[] {\n const problems: string[] = [];\n for (const block of blocks) {\n if (block.dataType !== 'wod' || !block.rawContent?.trim()) continue;\n const section = parseDocumentSections(block.rawContent, { registeredWidgets: SEED_REGISTERED_WIDGETS })\n .find((s) => s.scriptBlock);\n const source = section?.scriptBlock?.content ?? block.rawContent;\n if (!source.trim()) continue;\n\n const where = block.sourcePath ?? block.noteId;\n if (section?.sport) {\n const parsed = parseScript(source, { sport: section.sport });\n for (const error of parsed.errors ?? []) {\n problems.push(`${where}: ${error.message}`);\n }\n continue;\n }\n\n const doc = source.endsWith('\\n') ? source : source + '\\n';\n const tree = whiteboardParser.parse(doc);\n tree.iterate({\n enter: (node) => {\n if (!node.type.isError) return;\n const line = doc.slice(0, node.from).split('\\n').length;\n const snippet = source.slice(node.from, Math.min(node.to, node.from + 60)).split('\\n')[0];\n problems.push(`${where}:${line} \\`${snippet}\\``);\n },\n });\n }\n return problems;\n}\n\n/**\n * Uncataloged effort discovered during workout block analysis.\n */\nexport interface DiscoveredEffort {\n slug: string;\n label: string;\n rawLabels: string[];\n}\n\n/** Static lookup — syntax/structure keywords and known non-effort labels that must never scaffold. */\nconst NON_EFFORT_SLUGS: Record<string, true> = {\n 'amrap': true, 'emom': true, 'tabata': true, 'for-time': true, 'rounds': true, 'sets': true,\n 'repetitions': true, 'count-down': true, 'total-reps': true,\n 'warmup': true, 'cooldown': true, 'cool-down': true, 'transition': true, 'rest': true, 'break': true, 'work': true,\n 'i-suck-at-this': true, 'isuckatthis': true, 'movement': true, 'movement-you': true, 'selected-exercise': true,\n 'training-setup': true, 'grade-system': true, 'hangs': true, 'warm-light-wind': true, 'basin': true, 'rock-canyon': true,\n 'b-onsight': true, 'a-redpoint': true, 'd-redpoint': true, 'v0-flash': true, 'v2-flash': true, 'v7-redpoint': true,\n 'avgrpe-mean': true, 'calculate': true, 'totalload-sum': true, 'query': true, 'by': true,\n '': true, '-': true, '...': true, 'x': true, 's': true, 'bw': true,\n};\n\nfunction formatDiscoveredLabel(raw: string): string {\n const clean = raw.replace(/[-_]+/g, ' ').trim();\n return clean\n .split(/\\s+/)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())\n .join(' ');\n}\n\n/**\n * ONE corpus reference catalog — both definition families parsed once into\n * real arrays, the direct feed for lang's `createReferenceIndex`. Effort and\n * equipment containment rows, discovery and the runtime all resolve through\n * that single index, so the static plane and runtime agree on canonical\n * slugs with no per-family copies.\n */\nexport function loadCorpusReferenceCatalog(markdownDir: string): { efforts: IEffort[]; equipment: IEquipment[] } {\n const efforts: IEffort[] = [];\n const equipment: IEquipment[] = [];\n const effortsDir = join(markdownDir, 'efforts');\n for (const file of listMarkdownFiles(effortsDir)) {\n const parsed = parseEffortFile(readFileSync(join(effortsDir, file), 'utf8'));\n if (parsed) efforts.push(parsed);\n }\n const equipmentDir = join(markdownDir, 'equipment');\n for (const file of listMarkdownFiles(equipmentDir)) {\n const parsed = parseEquipmentFile(readFileSync(join(equipmentDir, file), 'utf8'));\n if (parsed) equipment.push(parsed);\n }\n return { efforts, equipment };\n}\n\nexport function discoverUncatalogedEfforts(markdownDir: string, corpusRoot: string): DiscoveredEffort[] {\n const catalog = loadCorpusReferenceCatalog(markdownDir);\n const index = createReferenceIndex(catalog);\n const blocks = buildBlockIndexRows(markdownDir, corpusRoot);\n const discovered = new Map<string, { label: string; rawLabels: Set<string> }>();\n\n for (const block of blocks) {\n if (block.dataType !== 'wod' || !block.rawContent) continue;\n const section = parseDocumentSections(block.rawContent, { registeredWidgets: SEED_REGISTERED_WIDGETS }).find((section) => section.scriptBlock);\n const script = parseScript(section?.scriptBlock?.content ?? block.rawContent, { references: index });\n for (const statement of script.statements) {\n const effortMetric = statement.metrics?.getMetric?.('effort');\n const effortLabel = (effortMetric && typeof effortMetric.value === 'string' ? effortMetric.value : undefined) ?? statement.exerciseId;\n if (!effortLabel) continue;\n\n const slugified = slugifyRefLabel(effortLabel);\n if (!slugified || NON_EFFORT_SLUGS[slugified]) continue;\n\n // Known efforts are exactly the catalog's canonical slugs — discovery\n // only reports labels the shared index cannot resolve.\n if (index.resolveEffort(slugified) || index.resolveEffort(effortLabel)) continue;\n\n const existing = discovered.get(slugified);\n if (existing) {\n existing.rawLabels.add(effortLabel);\n } else {\n discovered.set(slugified, {\n label: formatDiscoveredLabel(effortLabel),\n rawLabels: new Set([effortLabel]),\n });\n }\n }\n }\n\n return Array.from(discovered.entries()).map(([slug, data]) => ({\n slug,\n label: data.label,\n rawLabels: Array.from(data.rawLabels),\n }));\n}\n\nexport function scaffoldDiscoveredEfforts(\n discovered: DiscoveredEffort[],\n markdownDir: string,\n): string[] {\n const targetDir = join(markdownDir, 'efforts', 'discovered');\n if (!existsSync(targetDir)) {\n mkdirSync(targetDir, { recursive: true });\n }\n\n const createdPaths: string[] = [];\n for (const effort of discovered) {\n const filePath = join(targetDir, `${effort.slug}.md`);\n if (existsSync(filePath)) continue;\n\n const aliases = effort.rawLabels\n .filter((l) => l.toLowerCase() !== effort.label.toLowerCase())\n .map((l) => ` - \"${l.replace(/\"/g, '\\\\\"')}\"`);\n\n const content = [\n '---',\n `id: effort-bundled-${effort.slug}`,\n `slug: ${effort.slug}`,\n `label: \"${effort.label.replace(/\"/g, '\\\\\"')}\"`,\n aliases.length > 0 ? `aliases:\\n${aliases.join('\\n')}` : 'aliases: []',\n 'baseAttributes:',\n ' met: 5.0',\n ' discipline: general',\n ' intensityTier: moderate',\n 'registrySource: bundled',\n '---',\n '',\n ].join('\\n');\n\n writeFileSync(filePath, content, 'utf8');\n createdPaths.push(filePath);\n }\n\n return createdPaths;\n}\n\n/**\n * Derive BlockEffort[] containment rows from the block-index row set.\n * Requires a second pass over the source markdown to parse the script AST\n * (with the corpus reference index configured, so statements carry canonical\n * refs), which is safe because the corpus is static and compile-time.\n *\n * Only VALIDATED refs enter the durable index: a slug that survives is\n * confirmed by the shared index (`resolveEffort`); uncataloged movements\n * produce no durable link — that is discovery's reporting job.\n */\nexport function buildBlockEffortRows(markdownDir: string, corpusRoot: string, blocks: BlockIndexRow[] = buildBlockIndexRows(markdownDir, corpusRoot)): BlockEffort[] {\n const efforts: BlockEffort[] = [];\n const index = createReferenceIndex(loadCorpusReferenceCatalog(markdownDir));\n for (const block of blocks) {\n if (block.dataType !== 'wod' || !block.rawContent) continue;\n const section = parseDocumentSections(block.rawContent, { registeredWidgets: SEED_REGISTERED_WIDGETS }).find((section) => section.scriptBlock);\n const script = parseScript(section?.scriptBlock?.content ?? block.rawContent, { references: index });\n const linked = new Set<string>();\n for (const rawSlug of extractStatementRefs(script.statements).efforts) {\n const canonical = index.resolveEffort(rawSlug);\n const canonicalSlug = canonical?.slug;\n if (!canonicalSlug || NON_EFFORT_SLUGS[canonicalSlug] || NON_EFFORT_SLUGS[rawSlug]) {\n continue;\n }\n if (linked.has(canonicalSlug)) continue;\n linked.add(canonicalSlug);\n efforts.push({\n id: `${block.id}:${canonicalSlug}`,\n noteId: block.noteId,\n blockId: block.blockId,\n blockContentId: block.blockContentId,\n effortSlug: canonicalSlug,\n isStatic: block.isStatic,\n sourcePath: block.sourcePath,\n createdAt: block.createdAt,\n });\n }\n }\n return efforts;\n}\n\n/**\n * Derive BlockEquipment[] containment rows — the equipment twin of\n * {@link buildBlockEffortRows}. Parsed with the corpus reference index so\n * statements carry canonical equipment refs; only slugs the shared index\n * confirms (`resolveEquipment`) produce a durable link. Unknown equipment\n * stays visible as authored source + parser diagnostics.\n */\nexport function buildBlockEquipmentRows(markdownDir: string, corpusRoot: string, blocks: BlockIndexRow[] = buildBlockIndexRows(markdownDir, corpusRoot)): BlockEquipment[] {\n const links: BlockEquipment[] = [];\n const index = createReferenceIndex(loadCorpusReferenceCatalog(markdownDir));\n for (const block of blocks) {\n if (block.dataType !== 'wod' || !block.rawContent) continue;\n const section = parseDocumentSections(block.rawContent, { registeredWidgets: SEED_REGISTERED_WIDGETS }).find((s) => s.scriptBlock);\n const script = parseScript(section?.scriptBlock?.content ?? block.rawContent, { references: index });\n const linked = new Set<string>();\n for (const rawSlug of extractStatementRefs(script.statements).equipment) {\n const canonicalSlug = index.resolveEquipment(rawSlug)?.slug;\n if (!canonicalSlug || linked.has(canonicalSlug)) continue;\n linked.add(canonicalSlug);\n links.push({\n id: `${block.id}:${canonicalSlug}`,\n noteId: block.noteId,\n blockId: block.blockId,\n blockContentId: block.blockContentId,\n equipmentSlug: canonicalSlug,\n isStatic: block.isStatic,\n sourcePath: block.sourcePath,\n createdAt: block.createdAt,\n });\n }\n }\n return links;\n}\n\n\n// ── Generation ────────────────────────────────────────────────────────────\n\nfunction sha256Hex(data: string | Buffer): string {\n return createHash('sha256').update(data).digest('hex');\n}\n\nexport function generateSeed(options: GenerateSeedOptions = {}): GenerateSeedResult {\n const t0 = Date.now();\n const passMs = { scan: 0, blockIndex: 0, parseGate: 0, blockEfforts: 0, write: 0 };\n const corpusRoot = options.corpusRoot ?? process.cwd();\n const markdownDir = options.markdownDir ?? join(corpusRoot, 'markdown');\n const outDir = options.outDir ?? join(corpusRoot, 'dist');\n const gitVersion = options.version !== undefined\n ? { ...resolveGitVersion(corpusRoot), version: options.version }\n : resolveGitVersion(corpusRoot);\n const packageFile = join(corpusRoot, 'package.json');\n const packageMetadata: unknown = existsSync(packageFile) ? JSON.parse(readFileSync(packageFile, 'utf8')) : {};\n const metadata = packageMetadata && typeof packageMetadata === 'object' ? packageMetadata : {};\n const repository = 'repository' in metadata ? metadata.repository : undefined;\n const repositoryUrl = typeof repository === 'string' ? repository : repository && typeof repository === 'object' && 'url' in repository && typeof repository.url === 'string' ? repository.url : undefined;\n const webRepositoryUrl = repositoryUrl?.replace(/^git\\+/, '').replace(/\\.git$/, '');\n const repositoryLink = webRepositoryUrl && URL.canParse(webRepositoryUrl) ? new URL(webRepositoryUrl) : undefined;\n if (options.scaffoldDiscoveredEfforts) {\n const discovered = discoverUncatalogedEfforts(markdownDir, corpusRoot);\n if (discovered.length > 0) {\n scaffoldDiscoveredEfforts(discovered, markdownDir);\n }\n }\n\n const tScan = Date.now();\n const paths = collectCorpusMarkdown(markdownDir);\n const groups = partitionIntoChunks(paths);\n gateDashboards(groups, corpusRoot);\n if (options.templateFile && existsSync(options.templateFile)) {\n const templateRowPath = options.templateRowPath\n ?? relative(corpusRoot, options.templateFile).split('\\\\').join('/');\n groups.push({ id: TEMPLATE_CHUNK_ID, files: [templateRowPath] });\n }\n passMs.scan = Date.now() - tScan;\n\n const tBlockIndex = Date.now();\n const blockRows = buildBlockIndexRows(markdownDir, corpusRoot);\n passMs.blockIndex = Date.now() - tBlockIndex;\n const tParseGate = Date.now();\n const syntaxProblems = validateWodBlockSyntax(blockRows);\n passMs.parseGate = Date.now() - tParseGate;\n if (syntaxProblems.length > 0) {\n const shown = syntaxProblems.slice(0, 20).map((p) => ` ${p}`).join('\\n');\n const more = syntaxProblems.length > 20 ? `\\n … and ${syntaxProblems.length - 20} more` : '';\n throw new Error(`[wod build] block syntax gate failed — ${syntaxProblems.length} block(s) do not parse:\\n${shown}${more}`);\n }\n\n const chunksDir = join(outDir, 'chunks');\n rmSync(outDir, { recursive: true, force: true });\n mkdirSync(chunksDir, { recursive: true });\n\n const manifestChunks: ManifestChunk[] = [];\n const tBlockEfforts = Date.now();\n const effortRows = buildBlockEffortRows(markdownDir, corpusRoot, blockRows);\n const equipmentRows = buildBlockEquipmentRows(markdownDir, corpusRoot, blockRows);\n passMs.blockEfforts = Date.now() - tBlockEfforts;\n const blocksByPath = new Map<string, BlockIndexRow[]>();\n const effortsByPath = new Map<string, BlockEffort[]>();\n const equipmentByPath = new Map<string, BlockEquipment[]>();\n for (const row of blockRows) {\n const rows = blocksByPath.get(row.sourcePath!) ?? [];\n rows.push(row); blocksByPath.set(row.sourcePath!, rows);\n }\n for (const row of effortRows) {\n const rows = effortsByPath.get(row.sourcePath!) ?? [];\n rows.push(row); effortsByPath.set(row.sourcePath!, rows);\n }\n for (const row of equipmentRows) {\n const rows = equipmentByPath.get(row.sourcePath!) ?? [];\n rows.push(row); equipmentByPath.set(row.sourcePath!, rows);\n }\n let totalFiles = 0;\n\n const tWrite = Date.now();\n for (const { id, files } of groups) {\n // The template chunk's row path is the host-pinned historical identity,\n // not a path inside this repo — read it from the template file itself.\n const templateSource = id === TEMPLATE_CHUNK_ID ? options.templateFile : undefined;\n const rows: SeedRow[] = files.map((p) => {\n const raw = readFileSync(templateSource ?? join(corpusRoot, p), 'utf8');\n const content = id === TEMPLATE_CHUNK_ID ? raw.replace(/\\$CURSOR/g, '') : raw;\n const compiled = compileSeedRow(p, content);\n compiled.blockIndex = blocksByPath.get(p) ?? compiled.blockIndex;\n compiled.blockEfforts = effortsByPath.get(p) ?? [];\n compiled.blockEquipment = equipmentByPath.get(p) ?? [];\n return compiled;\n });\n const bytes = Buffer.from(JSON.stringify(rows), 'utf8');\n const sha = sha256Hex(bytes);\n const file = `chunks/${id}.${sha.slice(0, 8)}.json`;\n writeFileSync(join(outDir, file), bytes);\n manifestChunks.push({ id, path: file, sha256: sha, bytes: bytes.length, count: rows.length });\n totalFiles += rows.length;\n }\n\n passMs.write = Date.now() - tWrite;\n\n const manifest: SeedManifest = {\n name: 'name' in metadata && typeof metadata.name === 'string' ? metadata.name : undefined,\n description: 'description' in metadata && typeof metadata.description === 'string' ? metadata.description : undefined,\n repositoryUrl: repositoryLink?.protocol === 'https:' && !repositoryLink.username && !repositoryLink.password ? repositoryLink.href : undefined,\n schema: SEED_SCHEMA,\n version: gitVersion.version,\n versionLabel: gitVersion.versionLabel,\n commit: gitVersion.commit,\n dirty: gitVersion.dirty,\n builtAt: new Date().toISOString(),\n chunks: manifestChunks,\n };\n assertSeedManifest(manifest);\n writeFileSync(join(outDir, 'manifest.json'), JSON.stringify(manifest, null, 2) + '\\n');\n\n const reportPath = writeBuildReport(outDir, {\n manifest,\n totalMs: Date.now() - t0,\n passMs,\n fileCount: paths.length,\n outDir,\n });\n\n return { manifest, outDir, totalFiles, reportPath, passMs };\n}\n"]}