miriad-viz 0.9.1 → 0.9.3

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.
@@ -144,12 +144,15 @@ var STEP_FILE_MAP = {
144
144
  // render output is the final video — too large for board
145
145
  };
146
146
  var ALWAYS_SYNC = [".miriad-viz.json"];
147
- async function syncStepOutputs(config, step, dataDir) {
147
+ var OUTPUT_DIR_STEPS = /* @__PURE__ */ new Set(["transform"]);
148
+ async function syncStepOutputs(config, step, dataDir, outputDir) {
149
+ const stepDir = OUTPUT_DIR_STEPS.has(step) && outputDir ? outputDir : dataDir;
148
150
  const files = STEP_FILE_MAP[step] ?? [];
149
151
  const allFiles = [.../* @__PURE__ */ new Set([...files, ...ALWAYS_SYNC])];
150
152
  let synced = 0;
151
153
  for (const file of allFiles) {
152
- const localPath = resolve(dataDir, file);
154
+ const dir = ALWAYS_SYNC.includes(file) ? dataDir : stepDir;
155
+ const localPath = resolve(dir, file);
153
156
  if (!existsSync(localPath)) continue;
154
157
  await syncTextFile(config, localPath, file);
155
158
  synced++;
@@ -169,7 +172,7 @@ async function syncStepOutputs(config, step, dataDir) {
169
172
  console.log(` \u2601 Synced ${synced} file${synced > 1 ? "s" : ""} to board`);
170
173
  }
171
174
  }
172
- async function pullFromBoard(config, dataDir) {
175
+ async function pullFromBoard(config, dataDir, outputDir) {
173
176
  const warnings = [];
174
177
  let pulled = 0;
175
178
  try {
@@ -226,7 +229,7 @@ async function pullFromBoard(config, dataDir) {
226
229
  if (existsSync(progressPath)) {
227
230
  try {
228
231
  const progress = JSON.parse(readFileSync(progressPath, "utf-8"));
229
- const validationWarnings = validateProgressConsistency(progress, dataDir);
232
+ const validationWarnings = validateProgressConsistency(progress, dataDir, outputDir);
230
233
  warnings.push(...validationWarnings);
231
234
  } catch {
232
235
  warnings.push("Failed to parse .miriad-viz.json for consistency check");
@@ -248,7 +251,7 @@ var STEP_REQUIRED_FILES = {
248
251
  "sound-design": ["audio-manifest.json"],
249
252
  transform: ["viz-data.json"]
250
253
  };
251
- function validateProgressConsistency(progress, dataDir) {
254
+ function validateProgressConsistency(progress, dataDir, outputDir) {
252
255
  const warnings = [];
253
256
  const steps = progress.steps;
254
257
  if (!steps) return warnings;
@@ -268,7 +271,8 @@ function validateProgressConsistency(progress, dataDir) {
268
271
  continue;
269
272
  }
270
273
  for (const file of requiredFiles) {
271
- if (!existsSync(resolve(dataDir, file))) {
274
+ const checkDir = OUTPUT_DIR_STEPS.has(step) && outputDir ? outputDir : dataDir;
275
+ if (!existsSync(resolve(checkDir, file))) {
272
276
  warnings.push(`Step '${step}' marked complete but ${file} missing \u2014 resetting to pending`);
273
277
  state.status = "pending";
274
278
  break;
@@ -0,0 +1,189 @@
1
+ // src/cli/guided/validate-curated-files.ts
2
+ function validateTimelineEvents(data) {
3
+ const errors = [];
4
+ const warnings = [];
5
+ if (data === null || typeof data !== "object" || !Array.isArray(data.events)) {
6
+ errors.push("timeline-events.json: `events` must be an array");
7
+ return { errors, warnings };
8
+ }
9
+ const events = data.events;
10
+ const messageBeanEvents = events.filter((e) => {
11
+ if (e === null || typeof e !== "object") return false;
12
+ const type = e.type;
13
+ return type === "message" || type === "beam";
14
+ });
15
+ if (messageBeanEvents.length === 0) {
16
+ errors.push(
17
+ "0 message/beam events \u2014 no chat pills will render. Add events with type 'message' or 'beam', fields: { type, t, from, to }."
18
+ );
19
+ }
20
+ const missingT = events.filter((e) => {
21
+ if (e === null || typeof e !== "object") return true;
22
+ return !e.t;
23
+ });
24
+ if (missingT.length > 0) {
25
+ warnings.push(
26
+ `${missingT.length} event(s) missing 't' field (timestamp) \u2014 events without timestamps may not render correctly`
27
+ );
28
+ }
29
+ const messageBeanMissingFields = messageBeanEvents.filter((e) => {
30
+ const ev = e;
31
+ return !ev.from || !ev.to;
32
+ });
33
+ if (messageBeanMissingFields.length > 0) {
34
+ warnings.push(
35
+ `${messageBeanMissingFields.length} message/beam event(s) missing 'from' or 'to' field \u2014 chat pills need both fields to render correctly`
36
+ );
37
+ }
38
+ if (messageBeanEvents.length === 0 && events.length > 0) {
39
+ const milestoneEvents = events.filter((e) => {
40
+ if (e === null || typeof e !== "object") return false;
41
+ return e.type === "milestone";
42
+ });
43
+ if (milestoneEvents.length > 0) {
44
+ warnings.push(
45
+ "Only milestone events found. Milestones render as markers, NOT chat pills. Add message/beam events for chat pills."
46
+ );
47
+ }
48
+ }
49
+ return { errors, warnings };
50
+ }
51
+ function validateRetroPageData(data) {
52
+ const errors = [];
53
+ const warnings = [];
54
+ if (data === null || typeof data !== "object") {
55
+ errors.push("retro-page-data.json: `meta` is missing or not an object");
56
+ return { errors, warnings };
57
+ }
58
+ const d = data;
59
+ if (d.meta === null || d.meta === void 0 || typeof d.meta !== "object") {
60
+ errors.push("retro-page-data.json: `meta` is missing or not an object");
61
+ return { errors, warnings };
62
+ }
63
+ const meta = d.meta;
64
+ if (!meta.title) {
65
+ errors.push("meta.title is required");
66
+ }
67
+ if (!meta.subtitle) {
68
+ errors.push("meta.subtitle is required");
69
+ }
70
+ if (!meta.startDate) {
71
+ errors.push(
72
+ "meta.startDate is required \u2014 transform uses this to calculate the project time span"
73
+ );
74
+ }
75
+ if (!meta.endDate) {
76
+ errors.push(
77
+ "meta.endDate is required \u2014 transform uses this to calculate the project time span"
78
+ );
79
+ }
80
+ if (!d.teamAssembly || !Array.isArray(d.teamAssembly) || d.teamAssembly.length === 0) {
81
+ warnings.push("No team assembly entries");
82
+ } else {
83
+ const teamAssembly = d.teamAssembly;
84
+ for (let i = 0; i < teamAssembly.length; i++) {
85
+ const entry = teamAssembly[i];
86
+ if (entry === null || typeof entry !== "object") continue;
87
+ const e = entry;
88
+ if (!e.agent) {
89
+ errors.push(`teamAssembly[${i}] missing 'agent' field \u2014 use 'agent', not 'name'`);
90
+ }
91
+ if (!e.time) {
92
+ warnings.push(
93
+ `teamAssembly[${i}] missing 'time' field \u2014 agent join timestamp will be null`
94
+ );
95
+ }
96
+ }
97
+ }
98
+ if (!d.phases || !Array.isArray(d.phases) || d.phases.length === 0) {
99
+ warnings.push("No phases defined \u2014 timeline will have no phase labels");
100
+ } else {
101
+ const phases = d.phases;
102
+ for (let i = 0; i < phases.length; i++) {
103
+ const phase = phases[i];
104
+ if (phase === null || typeof phase !== "object") continue;
105
+ const p = phase;
106
+ if (!p.start || !p.end) {
107
+ warnings.push(`phases[${i}] missing start/end timestamps`);
108
+ }
109
+ }
110
+ }
111
+ if (!d.milestones || !Array.isArray(d.milestones) || d.milestones.length === 0) {
112
+ warnings.push("No milestones defined");
113
+ }
114
+ if (!d.trustArc || !Array.isArray(d.trustArc) || d.trustArc.length === 0) {
115
+ warnings.push("No trust arc data");
116
+ }
117
+ if (!d.editorialNarration || !Array.isArray(d.editorialNarration) || d.editorialNarration.length === 0) {
118
+ warnings.push("No editorial narration \u2014 generic phase-based narration will be used");
119
+ }
120
+ return { errors, warnings };
121
+ }
122
+ function validateRetroPageQuotes(data) {
123
+ const errors = [];
124
+ const warnings = [];
125
+ if (data === null || typeof data !== "object" || Array.isArray(data)) {
126
+ errors.push("retro-page-quotes.json: must be an object (not an array or primitive)");
127
+ return { errors, warnings };
128
+ }
129
+ const d = data;
130
+ const categories = ["good", "bad", "ugly"];
131
+ const foundCategories = categories.filter(
132
+ (cat) => Array.isArray(d[cat]) && d[cat].length > 0
133
+ );
134
+ if (foundCategories.length === 0) {
135
+ warnings.push("No quote categories found");
136
+ return { errors, warnings };
137
+ }
138
+ for (const cat of foundCategories) {
139
+ const entries = d[cat];
140
+ for (let i = 0; i < entries.length; i++) {
141
+ const entry = entries[i];
142
+ if (entry === null || typeof entry !== "object") continue;
143
+ const e = entry;
144
+ if (e.speaker !== void 0 && e.author === void 0) {
145
+ warnings.push(`quotes[${i}] uses 'speaker' \u2014 should be 'author'`);
146
+ }
147
+ if (!e.text) {
148
+ warnings.push(`quotes[${i}] missing 'text' field`);
149
+ }
150
+ if (!e.timestamp) {
151
+ warnings.push(`quotes[${i}] missing 'timestamp' field`);
152
+ }
153
+ }
154
+ }
155
+ return { errors, warnings };
156
+ }
157
+ function validateCuratedFiles(timelineEvents, retroPageData, retroPageQuotes) {
158
+ const errors = [];
159
+ const warnings = [];
160
+ if (timelineEvents === null) {
161
+ errors.push("timeline-events.json: could not be read or parsed");
162
+ } else {
163
+ const r = validateTimelineEvents(timelineEvents);
164
+ errors.push(...r.errors);
165
+ warnings.push(...r.warnings);
166
+ }
167
+ if (retroPageData === null) {
168
+ errors.push("retro-page-data.json: could not be read or parsed");
169
+ } else {
170
+ const r = validateRetroPageData(retroPageData);
171
+ errors.push(...r.errors);
172
+ warnings.push(...r.warnings);
173
+ }
174
+ if (retroPageQuotes === null) {
175
+ errors.push("retro-page-quotes.json: could not be read or parsed");
176
+ } else {
177
+ const r = validateRetroPageQuotes(retroPageQuotes);
178
+ errors.push(...r.errors);
179
+ warnings.push(...r.warnings);
180
+ }
181
+ return { errors, warnings };
182
+ }
183
+
184
+ export {
185
+ validateTimelineEvents,
186
+ validateRetroPageData,
187
+ validateRetroPageQuotes,
188
+ validateCuratedFiles
189
+ };
@@ -12,7 +12,7 @@ import {
12
12
  canSync,
13
13
  getBoardSyncConfig,
14
14
  syncStepOutputs
15
- } from "./chunk-UTFBENVA.js";
15
+ } from "./chunk-7BH6QQNB.js";
16
16
  import {
17
17
  markComplete,
18
18
  markError,
package/dist-cli/index.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  pullFromBoard,
5
5
  syncStepOutputs,
6
6
  syncTextFile
7
- } from "./chunk-UTFBENVA.js";
7
+ } from "./chunk-7BH6QQNB.js";
8
8
  import {
9
9
  PROGRESS_FILENAME,
10
10
  STEPS,
@@ -1544,7 +1544,11 @@ async function runNext(flags) {
1544
1544
  const syncConfig = getBoardSyncConfig(progress.project.dataDir);
1545
1545
  if (syncConfig) {
1546
1546
  console.log("\n\u2601 Checking board for existing pipeline state...");
1547
- const { pulled, warnings } = await pullFromBoard(syncConfig, dataDir);
1547
+ const { pulled, warnings } = await pullFromBoard(
1548
+ syncConfig,
1549
+ dataDir,
1550
+ resolve3(projectDir, progress.project.outputDir)
1551
+ );
1548
1552
  if (pulled > 0) {
1549
1553
  console.log(` \u2713 Pulled ${pulled} file${pulled > 1 ? "s" : ""} from board`);
1550
1554
  if (existsSync3(progressPath)) {
@@ -1579,6 +1583,7 @@ async function runNext(flags) {
1579
1583
  "audio-approved": flags["audio-approved"] === true || void 0,
1580
1584
  // v2 gate flags
1581
1585
  "script-approved": flags["script-approved"] === true || void 0,
1586
+ "curate-approved": flags["curate-approved"] === true || void 0,
1582
1587
  "voices-approved": flags["voices-approved"] === true || void 0,
1583
1588
  "timing-approved": flags["timing-approved"] === true || void 0,
1584
1589
  "sound-approved": flags["sound-approved"] === true || void 0,
@@ -1597,6 +1602,34 @@ async function runNext(flags) {
1597
1602
  progress.project.dataDir,
1598
1603
  progress.project.outputDir
1599
1604
  );
1605
+ if (flags["curate-approved"]) {
1606
+ const { validateCuratedFiles } = await import("./validate-curated-files-ZLNFHBXT.js");
1607
+ const curateDataDir = resolve3(projectDir, progress.project.dataDir);
1608
+ const tryReadJSON = (filename) => {
1609
+ try {
1610
+ return JSON.parse(readFileSync2(resolve3(curateDataDir, filename), "utf-8"));
1611
+ } catch {
1612
+ return null;
1613
+ }
1614
+ };
1615
+ const validation = validateCuratedFiles(
1616
+ tryReadJSON("timeline-events.json"),
1617
+ tryReadJSON("retro-page-data.json"),
1618
+ tryReadJSON("retro-page-quotes.json")
1619
+ );
1620
+ if (validation.errors.length > 0) {
1621
+ console.log("\n\u2717 Curation validation failed:\n");
1622
+ for (const e of validation.errors) console.log(` \u2717 ${e}`);
1623
+ for (const w of validation.warnings) console.log(` \u26A0 ${w}`);
1624
+ console.log("\nFix the errors above and try again.");
1625
+ process.exit(1);
1626
+ }
1627
+ if (validation.warnings.length > 0) {
1628
+ console.log("\n\u26A0 Curation warnings:\n");
1629
+ for (const w of validation.warnings) console.log(` \u26A0 ${w}`);
1630
+ console.log("");
1631
+ }
1632
+ }
1600
1633
  const result = computeNext(
1601
1634
  progress,
1602
1635
  existingFiles,
@@ -1614,8 +1647,9 @@ async function runNext(flags) {
1614
1647
  const syncConfig = getBoardSyncConfig(result.progress.project.dataDir);
1615
1648
  if (syncConfig) {
1616
1649
  const dataDir2 = resolve3(projectDir, result.progress.project.dataDir);
1650
+ const outputDir = resolve3(projectDir, result.progress.project.outputDir);
1617
1651
  if (result.step && (result.action === "completed_and_chained" || result.action === "creative_stop")) {
1618
- await syncStepOutputs(syncConfig, result.step, dataDir2);
1652
+ await syncStepOutputs(syncConfig, result.step, dataDir2, outputDir);
1619
1653
  } else {
1620
1654
  const progressPath = resolve3(projectDir, ".miriad-viz.json");
1621
1655
  if (existsSync3(progressPath)) {
@@ -1661,7 +1695,7 @@ async function main() {
1661
1695
  }
1662
1696
  case "extract": {
1663
1697
  const { projectDir, progress } = requireProject();
1664
- const { runExtract } = await import("./extract-5JGICL3V.js");
1698
+ const { runExtract } = await import("./extract-6XRQDMNC.js");
1665
1699
  await runExtract({
1666
1700
  projectDir,
1667
1701
  progress,
@@ -1682,7 +1716,7 @@ async function main() {
1682
1716
  case "transform": {
1683
1717
  const { projectDir, progress } = requireProject();
1684
1718
  const { parseDuration } = await import("./parse-duration-NVLCEFAF.js");
1685
- const { runTransform } = await import("./transform-SCT5EYPV.js");
1719
+ const { runTransform } = await import("./transform-L7OKE35T.js");
1686
1720
  const padding = {};
1687
1721
  if (typeof flags["pad-start"] === "string") {
1688
1722
  padding.padStartMs = parseDuration(flags["pad-start"]);
@@ -1710,19 +1744,19 @@ async function main() {
1710
1744
  console.log("");
1711
1745
  console.log(chainResult.previewTable);
1712
1746
  }
1713
- const { runTransform } = await import("./transform-SCT5EYPV.js");
1747
+ const { runTransform } = await import("./transform-L7OKE35T.js");
1714
1748
  await runTransform({ projectDir, progress });
1715
- const { runPreview: runPreview2 } = await import("./preview-UUWVOX5Y.js");
1749
+ const { runPreview: runPreview2 } = await import("./preview-7AGBBMPI.js");
1716
1750
  await runPreview2({ projectDir, progress, port, noOpen: flags["no-open"] === true });
1717
1751
  break;
1718
1752
  }
1719
- const { runPreview } = await import("./preview-UUWVOX5Y.js");
1753
+ const { runPreview } = await import("./preview-7AGBBMPI.js");
1720
1754
  await runPreview({ projectDir, progress, port, noOpen: flags["no-open"] === true });
1721
1755
  break;
1722
1756
  }
1723
1757
  case "render": {
1724
1758
  const { projectDir, progress } = requireProject();
1725
- const { runRender } = await import("./render-T2UXDN25.js");
1759
+ const { runRender } = await import("./render-LBIBW45Z.js");
1726
1760
  await runRender({ projectDir, progress, draft: flags.draft === true });
1727
1761
  break;
1728
1762
  }
@@ -8,11 +8,10 @@ import {
8
8
  } from "./chunk-GLABTDMO.js";
9
9
 
10
10
  // src/cli/guided/steps/preview.ts
11
- import { execSync } from "child_process";
12
11
  import { copyFileSync, existsSync, mkdirSync, readdirSync } from "fs";
13
12
  import { resolve } from "path";
14
13
  function copyPreviewAssets(options) {
15
- const { outputDir, audioDir, viewerDir } = options;
14
+ const { outputDir, dataDir, audioDir, viewerDir } = options;
16
15
  const viewerDataDir = resolve(viewerDir, "public", "data");
17
16
  const viewerAudioDir = resolve(viewerDir, "public", "audio");
18
17
  const result = {
@@ -26,10 +25,12 @@ function copyPreviewAssets(options) {
26
25
  copyFileSync(vizDataPath, resolve(viewerDataDir, "viz-data.json"));
27
26
  result.copiedVizData = true;
28
27
  }
29
- const timingPath = resolve(outputDir, "timing.json");
30
- if (existsSync(timingPath)) {
28
+ const timingOutputPath = resolve(outputDir, "timing.json");
29
+ const timingDataPath = resolve(dataDir, "timing.json");
30
+ const timingSource = existsSync(timingOutputPath) ? timingOutputPath : existsSync(timingDataPath) ? timingDataPath : null;
31
+ if (timingSource) {
31
32
  mkdirSync(viewerDataDir, { recursive: true });
32
- copyFileSync(timingPath, resolve(viewerDataDir, "timing.json"));
33
+ copyFileSync(timingSource, resolve(viewerDataDir, "timing.json"));
33
34
  result.copiedTiming = true;
34
35
  }
35
36
  if (existsSync(audioDir)) {
@@ -74,7 +75,8 @@ async function runPreview(options) {
74
75
  }
75
76
  }
76
77
  const audioDir = resolve(projectDir, "audio");
77
- const copyResult = copyPreviewAssets({ outputDir: outDir, audioDir, viewerDir });
78
+ const dataDir = resolve(projectDir, progress.project.dataDir);
79
+ const copyResult = copyPreviewAssets({ outputDir: outDir, dataDir, audioDir, viewerDir });
78
80
  if (copyResult.copiedVizData) {
79
81
  console.log(" \u2713 Copied viz-data.json to viewer/public/data/");
80
82
  }
@@ -84,26 +86,13 @@ async function runPreview(options) {
84
86
  if (copyResult.audioFileCount > 0) {
85
87
  console.log(` \u2713 Copied ${copyResult.audioFileCount} audio file(s) to viewer/public/audio/`);
86
88
  }
87
- const nodeModules = resolve(viewerDir, "node_modules");
88
- if (!existsSync(nodeModules)) {
89
- console.log(" Installing viewer dependencies...");
90
- execSync("pnpm install", { cwd: viewerDir, stdio: "inherit" });
91
- console.log(" \u2713 Dependencies installed");
92
- }
93
- const port = options.port || 5174;
94
89
  markComplete(progress, "preview");
95
90
  writeProgress(projectDir, progress);
96
- console.log(`
97
- Starting preview server on port ${port}...`);
98
- console.log(` Viewer: http://localhost:${port}`);
99
- console.log("\n Press Ctrl+C to stop.\n");
100
- try {
101
- execSync(`npx vite --port ${port}${options.noOpen ? "" : " --open"}`, {
102
- cwd: viewerDir,
103
- stdio: "inherit"
104
- });
105
- } catch {
106
- }
91
+ console.log("\n To start the preview server:");
92
+ console.log(
93
+ " cd viewer && pnpm install && nohup npx vite --host 0.0.0.0 --port 5174 > /tmp/vite.log 2>&1 &"
94
+ );
95
+ console.log("\n Then get a tunnel URL to share with the human.");
107
96
  }
108
97
  export {
109
98
  copyPreviewAssets,
@@ -2,7 +2,7 @@ import {
2
2
  canSync,
3
3
  getBoardSyncConfig,
4
4
  syncStepOutputs
5
- } from "./chunk-UTFBENVA.js";
5
+ } from "./chunk-7BH6QQNB.js";
6
6
  import {
7
7
  markComplete,
8
8
  markError,
@@ -1,3 +1,9 @@
1
+ import {
2
+ TimingFileSchema
3
+ } from "./chunk-SKRQW7PY.js";
4
+ import {
5
+ validateCuratedFiles
6
+ } from "./chunk-K6N7F6GL.js";
1
7
  import {
2
8
  buildArtifactData
3
9
  } from "./chunk-JITEBF25.js";
@@ -5,7 +11,7 @@ import {
5
11
  canSync,
6
12
  getBoardSyncConfig,
7
13
  syncStepOutputs
8
- } from "./chunk-UTFBENVA.js";
14
+ } from "./chunk-7BH6QQNB.js";
9
15
  import {
10
16
  transformToRawData
11
17
  } from "./chunk-WP7ZSXBZ.js";
@@ -15,9 +21,6 @@ import {
15
21
  markInProgress,
16
22
  writeProgress
17
23
  } from "./chunk-GLABTDMO.js";
18
- import {
19
- TimingFileSchema
20
- } from "./chunk-SKRQW7PY.js";
21
24
 
22
25
  // src/cli/guided/steps/transform.ts
23
26
  import { resolve as resolve2 } from "path";
@@ -659,6 +662,22 @@ function printDataInventory(summary, warnings) {
659
662
  }
660
663
  function runPipeline(dataDir, outDir, options) {
661
664
  const { sources, warnings } = loadSources(dataDir);
665
+ const curationValidation = validateCuratedFiles(
666
+ sources.timelineEvents,
667
+ sources.retroPageData,
668
+ sources.retroPageQuotes
669
+ );
670
+ if (curationValidation.errors.length > 0) {
671
+ console.warn("\n\u26A0 Curated file validation issues:\n");
672
+ for (const e of curationValidation.errors) console.warn(` \u2717 ${e}`);
673
+ for (const w of curationValidation.warnings) console.warn(` \u26A0 ${w}`);
674
+ console.warn("\n Transform will continue, but output may be incomplete.");
675
+ console.warn(" Fix the issues above and re-run for best results.\n");
676
+ } else if (curationValidation.warnings.length > 0) {
677
+ console.warn("\n\u26A0 Curated file warnings:\n");
678
+ for (const w of curationValidation.warnings) console.warn(` \u26A0 ${w}`);
679
+ console.warn("");
680
+ }
662
681
  const summary = validateSources(sources);
663
682
  printDataInventory(summary, warnings);
664
683
  const rawData = transformToRawData(sources);
@@ -747,7 +766,7 @@ Output written to ${progress.project.outputDir}/:`);
747
766
  if (canSync()) {
748
767
  const syncConfig = getBoardSyncConfig(progress.project.dataDir);
749
768
  if (syncConfig) {
750
- await syncStepOutputs(syncConfig, "transform", outDir);
769
+ await syncStepOutputs(syncConfig, "transform", dataDir, outDir);
751
770
  }
752
771
  }
753
772
  console.log("\n\u2713 Transform complete. Proceed to the preview step.");
@@ -0,0 +1,12 @@
1
+ import {
2
+ validateCuratedFiles,
3
+ validateRetroPageData,
4
+ validateRetroPageQuotes,
5
+ validateTimelineEvents
6
+ } from "./chunk-K6N7F6GL.js";
7
+ export {
8
+ validateCuratedFiles,
9
+ validateRetroPageData,
10
+ validateRetroPageQuotes,
11
+ validateTimelineEvents
12
+ };