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.
- package/dist-cli/{chunk-UTFBENVA.js → chunk-7BH6QQNB.js} +10 -6
- package/dist-cli/chunk-K6N7F6GL.js +189 -0
- package/dist-cli/{extract-5JGICL3V.js → extract-6XRQDMNC.js} +1 -1
- package/dist-cli/index.js +43 -9
- package/dist-cli/{preview-UUWVOX5Y.js → preview-7AGBBMPI.js} +13 -24
- package/dist-cli/{render-T2UXDN25.js → render-LBIBW45Z.js} +1 -1
- package/dist-cli/{transform-SCT5EYPV.js → transform-L7OKE35T.js} +24 -5
- package/dist-cli/validate-curated-files-ZLNFHBXT.js +12 -0
- package/dist-lib/viewer/exports.cjs +151 -3
- package/dist-lib/viewer/exports.cjs.map +1 -1
- package/dist-lib/viewer/exports.js +152 -4
- package/dist-lib/viewer/exports.js.map +1 -1
- package/package.json +1 -1
|
@@ -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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
+
};
|
package/dist-cli/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
pullFromBoard,
|
|
5
5
|
syncStepOutputs,
|
|
6
6
|
syncTextFile
|
|
7
|
-
} from "./chunk-
|
|
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(
|
|
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-
|
|
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-
|
|
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-
|
|
1747
|
+
const { runTransform } = await import("./transform-L7OKE35T.js");
|
|
1714
1748
|
await runTransform({ projectDir, progress });
|
|
1715
|
-
const { runPreview: runPreview2 } = await import("./preview-
|
|
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-
|
|
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-
|
|
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
|
|
30
|
-
|
|
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(
|
|
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
|
|
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
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
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,
|
|
@@ -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-
|
|
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
|
+
};
|