venice-video-harness 2.4.0

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 (264) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/LICENSE +21 -0
  3. package/README.md +598 -0
  4. package/dist/assembly/manifest-builder.d.ts +8 -0
  5. package/dist/assembly/manifest-builder.d.ts.map +1 -0
  6. package/dist/assembly/manifest-builder.js +196 -0
  7. package/dist/assembly/manifest-builder.js.map +1 -0
  8. package/dist/assembly/remotion-scaffold.d.ts +14 -0
  9. package/dist/assembly/remotion-scaffold.d.ts.map +1 -0
  10. package/dist/assembly/remotion-scaffold.js +292 -0
  11. package/dist/assembly/remotion-scaffold.js.map +1 -0
  12. package/dist/assembly/types.d.ts +67 -0
  13. package/dist/assembly/types.d.ts.map +1 -0
  14. package/dist/assembly/types.js +5 -0
  15. package/dist/assembly/types.js.map +1 -0
  16. package/dist/characters/describer.d.ts +32 -0
  17. package/dist/characters/describer.d.ts.map +1 -0
  18. package/dist/characters/describer.js +309 -0
  19. package/dist/characters/describer.js.map +1 -0
  20. package/dist/characters/extractor.d.ts +27 -0
  21. package/dist/characters/extractor.d.ts.map +1 -0
  22. package/dist/characters/extractor.js +274 -0
  23. package/dist/characters/extractor.js.map +1 -0
  24. package/dist/characters/reference-manager.d.ts +95 -0
  25. package/dist/characters/reference-manager.d.ts.map +1 -0
  26. package/dist/characters/reference-manager.js +346 -0
  27. package/dist/characters/reference-manager.js.map +1 -0
  28. package/dist/cli.d.ts +3 -0
  29. package/dist/cli.d.ts.map +1 -0
  30. package/dist/cli.js +310 -0
  31. package/dist/cli.js.map +1 -0
  32. package/dist/config.d.ts +22 -0
  33. package/dist/config.d.ts.map +1 -0
  34. package/dist/config.js +66 -0
  35. package/dist/config.js.map +1 -0
  36. package/dist/editing/aligner.d.ts +44 -0
  37. package/dist/editing/aligner.d.ts.map +1 -0
  38. package/dist/editing/aligner.js +201 -0
  39. package/dist/editing/aligner.js.map +1 -0
  40. package/dist/editing/edl.d.ts +45 -0
  41. package/dist/editing/edl.d.ts.map +1 -0
  42. package/dist/editing/edl.js +133 -0
  43. package/dist/editing/edl.js.map +1 -0
  44. package/dist/editing/overlays.d.ts +97 -0
  45. package/dist/editing/overlays.d.ts.map +1 -0
  46. package/dist/editing/overlays.js +41 -0
  47. package/dist/editing/overlays.js.map +1 -0
  48. package/dist/editing/packer.d.ts +52 -0
  49. package/dist/editing/packer.d.ts.map +1 -0
  50. package/dist/editing/packer.js +170 -0
  51. package/dist/editing/packer.js.map +1 -0
  52. package/dist/editing/providers/whisper-cpp.d.ts +32 -0
  53. package/dist/editing/providers/whisper-cpp.d.ts.map +1 -0
  54. package/dist/editing/providers/whisper-cpp.js +239 -0
  55. package/dist/editing/providers/whisper-cpp.js.map +1 -0
  56. package/dist/editing/render.d.ts +36 -0
  57. package/dist/editing/render.d.ts.map +1 -0
  58. package/dist/editing/render.js +227 -0
  59. package/dist/editing/render.js.map +1 -0
  60. package/dist/editing/self-eval.d.ts +48 -0
  61. package/dist/editing/self-eval.d.ts.map +1 -0
  62. package/dist/editing/self-eval.js +293 -0
  63. package/dist/editing/self-eval.js.map +1 -0
  64. package/dist/editing/silence.d.ts +76 -0
  65. package/dist/editing/silence.d.ts.map +1 -0
  66. package/dist/editing/silence.js +189 -0
  67. package/dist/editing/silence.js.map +1 -0
  68. package/dist/editing/types.d.ts +178 -0
  69. package/dist/editing/types.d.ts.map +1 -0
  70. package/dist/editing/types.js +13 -0
  71. package/dist/editing/types.js.map +1 -0
  72. package/dist/index.d.ts +6 -0
  73. package/dist/index.d.ts.map +1 -0
  74. package/dist/index.js +5 -0
  75. package/dist/index.js.map +1 -0
  76. package/dist/interactive.d.ts +12 -0
  77. package/dist/interactive.d.ts.map +1 -0
  78. package/dist/interactive.js +78 -0
  79. package/dist/interactive.js.map +1 -0
  80. package/dist/mini-drama/assembler.d.ts +61 -0
  81. package/dist/mini-drama/assembler.d.ts.map +1 -0
  82. package/dist/mini-drama/assembler.js +466 -0
  83. package/dist/mini-drama/assembler.js.map +1 -0
  84. package/dist/mini-drama/audio-mix.d.ts +65 -0
  85. package/dist/mini-drama/audio-mix.d.ts.map +1 -0
  86. package/dist/mini-drama/audio-mix.js +118 -0
  87. package/dist/mini-drama/audio-mix.js.map +1 -0
  88. package/dist/mini-drama/cli.d.ts +3 -0
  89. package/dist/mini-drama/cli.d.ts.map +1 -0
  90. package/dist/mini-drama/cli.js +2869 -0
  91. package/dist/mini-drama/cli.js.map +1 -0
  92. package/dist/mini-drama/fcpxml-export.d.ts +2 -0
  93. package/dist/mini-drama/fcpxml-export.d.ts.map +1 -0
  94. package/dist/mini-drama/fcpxml-export.js +5 -0
  95. package/dist/mini-drama/fcpxml-export.js.map +1 -0
  96. package/dist/mini-drama/generation-planner.d.ts +24 -0
  97. package/dist/mini-drama/generation-planner.d.ts.map +1 -0
  98. package/dist/mini-drama/generation-planner.js +304 -0
  99. package/dist/mini-drama/generation-planner.js.map +1 -0
  100. package/dist/mini-drama/location-generator.d.ts +23 -0
  101. package/dist/mini-drama/location-generator.d.ts.map +1 -0
  102. package/dist/mini-drama/location-generator.js +144 -0
  103. package/dist/mini-drama/location-generator.js.map +1 -0
  104. package/dist/mini-drama/music-cues.d.ts +96 -0
  105. package/dist/mini-drama/music-cues.d.ts.map +1 -0
  106. package/dist/mini-drama/music-cues.js +332 -0
  107. package/dist/mini-drama/music-cues.js.map +1 -0
  108. package/dist/mini-drama/panel-fixer.d.ts +12 -0
  109. package/dist/mini-drama/panel-fixer.d.ts.map +1 -0
  110. package/dist/mini-drama/panel-fixer.js +319 -0
  111. package/dist/mini-drama/panel-fixer.js.map +1 -0
  112. package/dist/mini-drama/prompt-builder.d.ts +149 -0
  113. package/dist/mini-drama/prompt-builder.d.ts.map +1 -0
  114. package/dist/mini-drama/prompt-builder.js +722 -0
  115. package/dist/mini-drama/prompt-builder.js.map +1 -0
  116. package/dist/mini-drama/reference-slots.d.ts +31 -0
  117. package/dist/mini-drama/reference-slots.d.ts.map +1 -0
  118. package/dist/mini-drama/reference-slots.js +161 -0
  119. package/dist/mini-drama/reference-slots.js.map +1 -0
  120. package/dist/mini-drama/shot-paths.d.ts +77 -0
  121. package/dist/mini-drama/shot-paths.d.ts.map +1 -0
  122. package/dist/mini-drama/shot-paths.js +101 -0
  123. package/dist/mini-drama/shot-paths.js.map +1 -0
  124. package/dist/mini-drama/storyboard-reference-generator.d.ts +47 -0
  125. package/dist/mini-drama/storyboard-reference-generator.d.ts.map +1 -0
  126. package/dist/mini-drama/storyboard-reference-generator.js +293 -0
  127. package/dist/mini-drama/storyboard-reference-generator.js.map +1 -0
  128. package/dist/mini-drama/subtitle-generator.d.ts +12 -0
  129. package/dist/mini-drama/subtitle-generator.d.ts.map +1 -0
  130. package/dist/mini-drama/subtitle-generator.js +139 -0
  131. package/dist/mini-drama/subtitle-generator.js.map +1 -0
  132. package/dist/mini-drama/timeline-export/davinci-fcpxml.d.ts +3 -0
  133. package/dist/mini-drama/timeline-export/davinci-fcpxml.d.ts.map +1 -0
  134. package/dist/mini-drama/timeline-export/davinci-fcpxml.js +150 -0
  135. package/dist/mini-drama/timeline-export/davinci-fcpxml.js.map +1 -0
  136. package/dist/mini-drama/timeline-export/fcpxml.d.ts +11 -0
  137. package/dist/mini-drama/timeline-export/fcpxml.d.ts.map +1 -0
  138. package/dist/mini-drama/timeline-export/fcpxml.js +140 -0
  139. package/dist/mini-drama/timeline-export/fcpxml.js.map +1 -0
  140. package/dist/mini-drama/timeline-export/index.d.ts +13 -0
  141. package/dist/mini-drama/timeline-export/index.d.ts.map +1 -0
  142. package/dist/mini-drama/timeline-export/index.js +26 -0
  143. package/dist/mini-drama/timeline-export/index.js.map +1 -0
  144. package/dist/mini-drama/timeline-export/premiere-xmeml.d.ts +3 -0
  145. package/dist/mini-drama/timeline-export/premiere-xmeml.d.ts.map +1 -0
  146. package/dist/mini-drama/timeline-export/premiere-xmeml.js +211 -0
  147. package/dist/mini-drama/timeline-export/premiere-xmeml.js.map +1 -0
  148. package/dist/mini-drama/timeline-export/probe.d.ts +53 -0
  149. package/dist/mini-drama/timeline-export/probe.d.ts.map +1 -0
  150. package/dist/mini-drama/timeline-export/probe.js +89 -0
  151. package/dist/mini-drama/timeline-export/probe.js.map +1 -0
  152. package/dist/mini-drama/timeline-export/types.d.ts +57 -0
  153. package/dist/mini-drama/timeline-export/types.d.ts.map +1 -0
  154. package/dist/mini-drama/timeline-export/types.js +14 -0
  155. package/dist/mini-drama/timeline-export/types.js.map +1 -0
  156. package/dist/mini-drama/video-generator.d.ts +22 -0
  157. package/dist/mini-drama/video-generator.d.ts.map +1 -0
  158. package/dist/mini-drama/video-generator.js +1305 -0
  159. package/dist/mini-drama/video-generator.js.map +1 -0
  160. package/dist/mini-drama/voice-reference.d.ts +42 -0
  161. package/dist/mini-drama/voice-reference.d.ts.map +1 -0
  162. package/dist/mini-drama/voice-reference.js +170 -0
  163. package/dist/mini-drama/voice-reference.js.map +1 -0
  164. package/dist/output/html-renderer.d.ts +2 -0
  165. package/dist/output/html-renderer.d.ts.map +1 -0
  166. package/dist/output/html-renderer.js +37 -0
  167. package/dist/output/html-renderer.js.map +1 -0
  168. package/dist/parsers/fountain-parser.d.ts +34 -0
  169. package/dist/parsers/fountain-parser.d.ts.map +1 -0
  170. package/dist/parsers/fountain-parser.js +71 -0
  171. package/dist/parsers/fountain-parser.js.map +1 -0
  172. package/dist/parsers/pdf-parser.d.ts +24 -0
  173. package/dist/parsers/pdf-parser.d.ts.map +1 -0
  174. package/dist/parsers/pdf-parser.js +237 -0
  175. package/dist/parsers/pdf-parser.js.map +1 -0
  176. package/dist/parsers/scene-extractor.d.ts +41 -0
  177. package/dist/parsers/scene-extractor.d.ts.map +1 -0
  178. package/dist/parsers/scene-extractor.js +400 -0
  179. package/dist/parsers/scene-extractor.js.map +1 -0
  180. package/dist/series/manager.d.ts +64 -0
  181. package/dist/series/manager.d.ts.map +1 -0
  182. package/dist/series/manager.js +282 -0
  183. package/dist/series/manager.js.map +1 -0
  184. package/dist/series/types.d.ts +641 -0
  185. package/dist/series/types.d.ts.map +1 -0
  186. package/dist/series/types.js +304 -0
  187. package/dist/series/types.js.map +1 -0
  188. package/dist/storyboard/assembler.d.ts +134 -0
  189. package/dist/storyboard/assembler.d.ts.map +1 -0
  190. package/dist/storyboard/assembler.js +319 -0
  191. package/dist/storyboard/assembler.js.map +1 -0
  192. package/dist/storyboard/prompt-builder.d.ts +113 -0
  193. package/dist/storyboard/prompt-builder.d.ts.map +1 -0
  194. package/dist/storyboard/prompt-builder.js +578 -0
  195. package/dist/storyboard/prompt-builder.js.map +1 -0
  196. package/dist/storyboard/shot-planner.d.ts +34 -0
  197. package/dist/storyboard/shot-planner.d.ts.map +1 -0
  198. package/dist/storyboard/shot-planner.js +446 -0
  199. package/dist/storyboard/shot-planner.js.map +1 -0
  200. package/dist/user-config.d.ts +15 -0
  201. package/dist/user-config.d.ts.map +1 -0
  202. package/dist/user-config.js +103 -0
  203. package/dist/user-config.js.map +1 -0
  204. package/dist/venice/audio-preflight.d.ts +80 -0
  205. package/dist/venice/audio-preflight.d.ts.map +1 -0
  206. package/dist/venice/audio-preflight.js +142 -0
  207. package/dist/venice/audio-preflight.js.map +1 -0
  208. package/dist/venice/audio.d.ts +88 -0
  209. package/dist/venice/audio.d.ts.map +1 -0
  210. package/dist/venice/audio.js +234 -0
  211. package/dist/venice/audio.js.map +1 -0
  212. package/dist/venice/client.d.ts +86 -0
  213. package/dist/venice/client.d.ts.map +1 -0
  214. package/dist/venice/client.js +375 -0
  215. package/dist/venice/client.js.map +1 -0
  216. package/dist/venice/edit.d.ts +57 -0
  217. package/dist/venice/edit.d.ts.map +1 -0
  218. package/dist/venice/edit.js +100 -0
  219. package/dist/venice/edit.js.map +1 -0
  220. package/dist/venice/generate.d.ts +47 -0
  221. package/dist/venice/generate.d.ts.map +1 -0
  222. package/dist/venice/generate.js +150 -0
  223. package/dist/venice/generate.js.map +1 -0
  224. package/dist/venice/image-bytes.d.ts +26 -0
  225. package/dist/venice/image-bytes.d.ts.map +1 -0
  226. package/dist/venice/image-bytes.js +101 -0
  227. package/dist/venice/image-bytes.js.map +1 -0
  228. package/dist/venice/models.d.ts +143 -0
  229. package/dist/venice/models.d.ts.map +1 -0
  230. package/dist/venice/models.js +984 -0
  231. package/dist/venice/models.js.map +1 -0
  232. package/dist/venice/multi-edit.d.ts +40 -0
  233. package/dist/venice/multi-edit.d.ts.map +1 -0
  234. package/dist/venice/multi-edit.js +97 -0
  235. package/dist/venice/multi-edit.js.map +1 -0
  236. package/dist/venice/provenance.d.ts +66 -0
  237. package/dist/venice/provenance.d.ts.map +1 -0
  238. package/dist/venice/provenance.js +151 -0
  239. package/dist/venice/provenance.js.map +1 -0
  240. package/dist/venice/recipe.d.ts +69 -0
  241. package/dist/venice/recipe.d.ts.map +1 -0
  242. package/dist/venice/recipe.js +103 -0
  243. package/dist/venice/recipe.js.map +1 -0
  244. package/dist/venice/rejection.d.ts +63 -0
  245. package/dist/venice/rejection.d.ts.map +1 -0
  246. package/dist/venice/rejection.js +111 -0
  247. package/dist/venice/rejection.js.map +1 -0
  248. package/dist/venice/seedance-preflight.d.ts +38 -0
  249. package/dist/venice/seedance-preflight.d.ts.map +1 -0
  250. package/dist/venice/seedance-preflight.js +29 -0
  251. package/dist/venice/seedance-preflight.js.map +1 -0
  252. package/dist/venice/types.d.ts +212 -0
  253. package/dist/venice/types.d.ts.map +1 -0
  254. package/dist/venice/types.js +9 -0
  255. package/dist/venice/types.js.map +1 -0
  256. package/dist/venice/video.d.ts +77 -0
  257. package/dist/venice/video.d.ts.map +1 -0
  258. package/dist/venice/video.js +163 -0
  259. package/dist/venice/video.js.map +1 -0
  260. package/dist/venice/voices.d.ts +40 -0
  261. package/dist/venice/voices.d.ts.map +1 -0
  262. package/dist/venice/voices.js +194 -0
  263. package/dist/venice/voices.js.map +1 -0
  264. package/package.json +79 -0
@@ -0,0 +1,227 @@
1
+ /**
2
+ * EDL renderer.
3
+ *
4
+ * Turns an Edl into a single mp4 file via ffmpeg. Produces 30ms audio
5
+ * fades at every cut boundary (video-use's "no pops" rule). Supports
6
+ * hard cuts, crossfades, and fade-to-black transitions.
7
+ *
8
+ * Archive-first per workspace rule `.cursor/rules/shot-asset-safety.mdc`:
9
+ * any existing output file is renamed to `<stem>-v<N>.<ext>` before the
10
+ * new render lands.
11
+ */
12
+ import { execSync } from 'node:child_process';
13
+ import { existsSync, mkdirSync, renameSync } from 'node:fs';
14
+ import { basename, dirname, extname, join, resolve } from 'node:path';
15
+ import { DEFAULT_TRANSITION_MS, effectiveDurationSec, validateEdl, } from './edl.js';
16
+ /** Archive existing output as `<stem>-v<N>.<ext>` and return the new path. */
17
+ function archiveExisting(path) {
18
+ if (!existsSync(path))
19
+ return null;
20
+ const ext = extname(path);
21
+ const stem = basename(path, ext);
22
+ const dir = dirname(path);
23
+ let n = 1;
24
+ let candidate = join(dir, `${stem}-v${n}${ext}`);
25
+ while (existsSync(candidate)) {
26
+ n += 1;
27
+ candidate = join(dir, `${stem}-v${n}${ext}`);
28
+ }
29
+ renameSync(path, candidate);
30
+ return candidate;
31
+ }
32
+ /**
33
+ * Build the filter_complex graph for an EDL.
34
+ *
35
+ * Each input is labeled [N:v] [N:a]. For each clip we:
36
+ * 1. Trim the video + audio to the clip range
37
+ * 2. Apply head/tail trim for filler removal
38
+ * 3. Apply per-clip fades (the 30ms audio fade + any crossfade/fade-to-black)
39
+ * 4. Chain into xfade (video) and acrossfade (audio) for crossfades,
40
+ * or plain concat for hard cuts.
41
+ *
42
+ * We keep the graph explicit rather than clever — maintainability wins over
43
+ * filter-length golf.
44
+ */
45
+ function buildFilterGraph(edl, takeById) {
46
+ const inputFiles = [];
47
+ const inputIndexByFile = new Map();
48
+ const getInputIndex = (file) => {
49
+ if (inputIndexByFile.has(file))
50
+ return inputIndexByFile.get(file);
51
+ const idx = inputFiles.length;
52
+ inputFiles.push(file);
53
+ inputIndexByFile.set(file, idx);
54
+ return idx;
55
+ };
56
+ const fadeSec = edl.audioFadeMs / 1000;
57
+ const filters = [];
58
+ // Stage 1: per-clip trimmed + faded streams.
59
+ const clipVLabels = [];
60
+ const clipALabels = [];
61
+ let totalDurSec = 0;
62
+ edl.clips.forEach((clip, i) => {
63
+ const take = takeById.get(clip.sourceId);
64
+ if (!take)
65
+ throw new Error(`Unknown sourceId ${clip.sourceId} at clip ${i}`);
66
+ const fileIdx = getInputIndex(take.file);
67
+ const trimStartAdjust = (clip.trimStartMs ?? 0) / 1000;
68
+ const trimEndAdjust = (clip.trimEndMs ?? 0) / 1000;
69
+ const startSec = clip.startSec + trimStartAdjust;
70
+ const endSec = clip.endSec - trimEndAdjust;
71
+ const durSec = Math.max(0, endSec - startSec);
72
+ totalDurSec += durSec;
73
+ const vIn = `${fileIdx}:v`;
74
+ const aIn = `${fileIdx}:a`;
75
+ // Video: trim + setpts + ensure consistent format / fps
76
+ const vTrim = `[${vIn}]trim=start=${startSec}:end=${endSec},setpts=PTS-STARTPTS,format=yuv420p[v${i}t]`;
77
+ filters.push(vTrim);
78
+ // Audio: atrim + asetpts + always apply a small head/tail fade to kill pops
79
+ const aFadeOut = Math.min(fadeSec, durSec / 3);
80
+ const aFadeOutStart = Math.max(0, durSec - aFadeOut);
81
+ const aTrim = `[${aIn}]atrim=start=${startSec}:end=${endSec},asetpts=PTS-STARTPTS,afade=t=in:st=0:d=${fadeSec.toFixed(3)},afade=t=out:st=${aFadeOutStart.toFixed(3)}:d=${aFadeOut.toFixed(3)}[a${i}t]`;
82
+ filters.push(aTrim);
83
+ clipVLabels.push(`[v${i}t]`);
84
+ clipALabels.push(`[a${i}t]`);
85
+ });
86
+ // Stage 2: apply color grade if present.
87
+ let gradedVLabels = clipVLabels;
88
+ if (edl.colorGrade?.filter) {
89
+ gradedVLabels = clipVLabels.map((label, i) => {
90
+ const out = `[v${i}g]`;
91
+ filters.push(`${label}${edl.colorGrade.filter}${out}`);
92
+ return out;
93
+ });
94
+ }
95
+ // Stage 3: chain clips via concat or xfade/acrossfade.
96
+ //
97
+ // If every transitionIn is 'cut', we can use the single concat filter which
98
+ // is faster. Otherwise we iteratively xfade + acrossfade.
99
+ const allHardCuts = edl.clips.every((c, i) => i === 0 || !c.transitionIn || c.transitionIn === 'cut');
100
+ let finalVLabel;
101
+ let finalALabel;
102
+ if (allHardCuts) {
103
+ const concatInputs = gradedVLabels
104
+ .map((vl, i) => `${vl}${clipALabels[i]}`)
105
+ .join('');
106
+ filters.push(`${concatInputs}concat=n=${edl.clips.length}:v=1:a=1[vcat][acat]`);
107
+ finalVLabel = '[vcat]';
108
+ finalALabel = '[acat]';
109
+ }
110
+ else {
111
+ // Iterative xfade chain. xfade's "offset" is the time (in the first stream)
112
+ // at which the transition begins. For clip 0 that's (dur0 - t_ms/1000).
113
+ let prevV = gradedVLabels[0];
114
+ let prevA = clipALabels[0];
115
+ let runningDur = effectiveDurationSec(edl.clips[0]);
116
+ for (let i = 1; i < edl.clips.length; i++) {
117
+ const clip = edl.clips[i];
118
+ const tMs = clip.transitionIn && clip.transitionIn !== 'cut'
119
+ ? clip.transitionMs ?? DEFAULT_TRANSITION_MS
120
+ : 0;
121
+ const tSec = tMs / 1000;
122
+ const clipDur = effectiveDurationSec(clip);
123
+ if (tMs === 0) {
124
+ const outV = `[vc${i}]`;
125
+ const outA = `[ac${i}]`;
126
+ filters.push(`${prevV}${gradedVLabels[i]}concat=n=2:v=1:a=0${outV}`);
127
+ filters.push(`${prevA}${clipALabels[i]}concat=n=2:v=0:a=1${outA}`);
128
+ prevV = outV;
129
+ prevA = outA;
130
+ runningDur += clipDur;
131
+ }
132
+ else {
133
+ const offset = Math.max(0, runningDur - tSec);
134
+ const transition = clip.transitionIn === 'fade-to-black' ? 'fadeblack' : 'fade';
135
+ const outV = `[vx${i}]`;
136
+ const outA = `[ax${i}]`;
137
+ filters.push(`${prevV}${gradedVLabels[i]}xfade=transition=${transition}:duration=${tSec.toFixed(3)}:offset=${offset.toFixed(3)}${outV}`);
138
+ filters.push(`${prevA}${clipALabels[i]}acrossfade=d=${tSec.toFixed(3)}:c1=tri:c2=tri${outA}`);
139
+ prevV = outV;
140
+ prevA = outA;
141
+ runningDur = runningDur - tSec + clipDur;
142
+ totalDurSec -= tSec;
143
+ }
144
+ }
145
+ finalVLabel = prevV;
146
+ finalALabel = prevA;
147
+ }
148
+ return {
149
+ graph: filters.join(';'),
150
+ inputFiles,
151
+ totalDurSec,
152
+ finalVLabel,
153
+ finalALabel,
154
+ };
155
+ }
156
+ export function renderEdl(edl, takes, options = {}) {
157
+ const errs = validateEdl(edl, takes);
158
+ if (errs.length > 0) {
159
+ throw new Error(`EDL validation failed:\n${errs.map((e) => ` clip ${e.clipIndex}: ${e.message}`).join('\n')}`);
160
+ }
161
+ const takeById = new Map(takes.map((t) => [t.id, t]));
162
+ // Filter down to a single clip in onlyClipIndex mode.
163
+ let workEdl = edl;
164
+ let outputPath = resolve(options.outputPath ?? 'output/edit/final-edit.mp4');
165
+ if (options.onlyClipIndex !== undefined) {
166
+ const onlyIdx = options.onlyClipIndex;
167
+ if (onlyIdx < 0 || onlyIdx >= edl.clips.length) {
168
+ throw new Error(`onlyClipIndex ${onlyIdx} out of range`);
169
+ }
170
+ workEdl = {
171
+ ...edl,
172
+ clips: [edl.clips[onlyIdx]],
173
+ };
174
+ const ext = extname(outputPath);
175
+ const stem = basename(outputPath, ext);
176
+ outputPath = join(dirname(outputPath), `${stem}.clip-${onlyIdx}${ext}`);
177
+ }
178
+ const { graph, inputFiles, totalDurSec, finalVLabel, finalALabel } = buildFilterGraph(workEdl, takeById);
179
+ mkdirSync(dirname(outputPath), { recursive: true });
180
+ let archived = null;
181
+ if (!options.skipArchive) {
182
+ archived = archiveExisting(outputPath);
183
+ }
184
+ const inputArgs = inputFiles.flatMap((f) => ['-i', `"${f}"`]);
185
+ // Always append trailing passthroughs that emit stable [vout] / [aout]
186
+ // labels regardless of which chain path (concat vs xfade) produced them.
187
+ const remappedGraph = `${graph};${finalVLabel}null[vout];${finalALabel}aformat=sample_rates=48000:channel_layouts=stereo[aout]`;
188
+ const outputArgs = [
189
+ '-map', '"[vout]"',
190
+ '-map', '"[aout]"',
191
+ '-c:v', workEdl.output.videoCodec,
192
+ '-preset', 'slow',
193
+ '-crf', String(workEdl.output.crf),
194
+ '-pix_fmt', 'yuv420p',
195
+ '-c:a', workEdl.output.audioCodec,
196
+ '-b:a', '192k',
197
+ '-movflags', '+faststart',
198
+ ];
199
+ if (workEdl.output.fps)
200
+ outputArgs.push('-r', String(workEdl.output.fps));
201
+ if (workEdl.output.width && workEdl.output.height) {
202
+ outputArgs.push('-s', `${workEdl.output.width}x${workEdl.output.height}`);
203
+ }
204
+ const cmd = [
205
+ 'ffmpeg',
206
+ '-y',
207
+ '-hide_banner',
208
+ '-loglevel', 'error',
209
+ ...inputArgs,
210
+ '-filter_complex', `"${remappedGraph}"`,
211
+ ...outputArgs,
212
+ `"${outputPath}"`,
213
+ ].join(' ');
214
+ const result = {
215
+ outputPath,
216
+ archivedPath: archived,
217
+ filterGraph: remappedGraph,
218
+ command: cmd,
219
+ durationEstSec: totalDurSec,
220
+ };
221
+ if (options.dryRun) {
222
+ return result;
223
+ }
224
+ execSync(cmd, { stdio: 'inherit' });
225
+ return result;
226
+ }
227
+ //# sourceMappingURL=render.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.js","sourceRoot":"","sources":["../../src/editing/render.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Self-evaluation driver for the editing pipeline.
3
+ *
4
+ * The cut-qa agent (`.claude/agents/cut-qa.md`) is the intelligent layer;
5
+ * this module is the mechanical layer that:
6
+ * 1. Enumerates cut boundaries from an EDL
7
+ * 2. Runs each boundary through the six programmatic checks
8
+ * 3. Produces a `CutQaReport` consumable by the agent
9
+ * 4. Persists iterations to `session.json`
10
+ *
11
+ * The agent then reads the report, proposes fixes, and the orchestrator
12
+ * applies them and re-renders. Hard cap: 3 iterations.
13
+ */
14
+ import type { CutQaFinding, CutQaReport, EditSession, Edl, EdlClip, Take, WordTiming } from './types.js';
15
+ export declare const MAX_ITERATIONS = 3;
16
+ export interface CutBoundary {
17
+ index: number;
18
+ trailerTimeSec: number;
19
+ outgoingClip: EdlClip;
20
+ incomingClip: EdlClip;
21
+ }
22
+ /** Cumulative trailer-time position of each clip boundary. */
23
+ export declare function enumerateCutBoundaries(edl: Edl): CutBoundary[];
24
+ export interface AspectSpec {
25
+ width: number;
26
+ height: number;
27
+ }
28
+ export declare function checkAspectRegression(renderedPath: string, expectedRatio: '16:9' | '9:16' | '1:1'): CutQaFinding[];
29
+ export declare function checkVisualJump(renderedPath: string, boundaries: CutBoundary[]): CutQaFinding[];
30
+ export declare function checkVoTruncation(script: string, asrWords: WordTiming[]): CutQaFinding[];
31
+ export declare function checkAudioPops(renderedPath: string, boundaries: CutBoundary[], fadeMs: number): CutQaFinding[];
32
+ export declare function checkLightingDiscontinuity(renderedPath: string, boundaries: CutBoundary[]): CutQaFinding[];
33
+ export interface RunCutQaInput {
34
+ renderedPath: string;
35
+ edl: Edl;
36
+ takes: Take[];
37
+ iteration: number;
38
+ aspectRatio?: '16:9' | '9:16' | '1:1';
39
+ /** Ground-truth script for VO truncation check. */
40
+ groundTruthScript?: string;
41
+ /** ASR words from the rendered output (pre-transcribed) for truncation check. */
42
+ renderedAsrWords?: WordTiming[];
43
+ }
44
+ export declare function runCutQa(input: RunCutQaInput): CutQaReport;
45
+ export declare function loadSession(path: string): EditSession | null;
46
+ export declare function saveSession(session: EditSession, path: string): void;
47
+ export declare function summarizeReport(report: CutQaReport): string;
48
+ //# sourceMappingURL=self-eval.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"self-eval.d.ts","sourceRoot":"","sources":["../../src/editing/self-eval.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,OAAO,KAAK,EACV,YAAY,EACZ,WAAW,EACX,WAAW,EACX,GAAG,EACH,OAAO,EACP,IAAI,EACJ,UAAU,EACX,MAAM,YAAY,CAAC;AAIpB,eAAO,MAAM,cAAc,IAAI,CAAC;AAEhC,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,OAAO,CAAC;IACtB,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,8DAA8D;AAC9D,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,GAAG,GAAG,WAAW,EAAE,CAmB9D;AAMD,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAQD,wBAAgB,qBAAqB,CACnC,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,GAAG,MAAM,GAAG,KAAK,GACrC,YAAY,EAAE,CAkChB;AAiDD,wBAAgB,eAAe,CAC7B,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,WAAW,EAAE,GACxB,YAAY,EAAE,CAoBhB;AAMD,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,UAAU,EAAE,GACrB,YAAY,EAAE,CAYhB;AAMD,wBAAgB,cAAc,CAC5B,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,WAAW,EAAE,EACzB,MAAM,EAAE,MAAM,GACb,YAAY,EAAE,CA+BhB;AAoBD,wBAAgB,0BAA0B,CACxC,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,WAAW,EAAE,GACxB,YAAY,EAAE,CAmBhB;AAMD,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,GAAG,EAAE,GAAG,CAAC;IACT,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;IACtC,mDAAmD;IACnD,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iFAAiF;IACjF,gBAAgB,CAAC,EAAE,UAAU,EAAE,CAAC;CACjC;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,WAAW,CAuB1D;AAMD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAG5D;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAIpE;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAyB3D"}
@@ -0,0 +1,293 @@
1
+ /**
2
+ * Self-evaluation driver for the editing pipeline.
3
+ *
4
+ * The cut-qa agent (`.claude/agents/cut-qa.md`) is the intelligent layer;
5
+ * this module is the mechanical layer that:
6
+ * 1. Enumerates cut boundaries from an EDL
7
+ * 2. Runs each boundary through the six programmatic checks
8
+ * 3. Produces a `CutQaReport` consumable by the agent
9
+ * 4. Persists iterations to `session.json`
10
+ *
11
+ * The agent then reads the report, proposes fixes, and the orchestrator
12
+ * applies them and re-renders. Hard cap: 3 iterations.
13
+ */
14
+ import { execSync } from 'node:child_process';
15
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
16
+ import { dirname } from 'node:path';
17
+ import { detectTruncation } from './aligner.js';
18
+ import { effectiveDurationSec } from './edl.js';
19
+ export const MAX_ITERATIONS = 3;
20
+ /** Cumulative trailer-time position of each clip boundary. */
21
+ export function enumerateCutBoundaries(edl) {
22
+ const boundaries = [];
23
+ let cursor = 0;
24
+ for (let i = 0; i < edl.clips.length; i++) {
25
+ const clip = edl.clips[i];
26
+ if (i > 0) {
27
+ boundaries.push({
28
+ index: i,
29
+ trailerTimeSec: cursor,
30
+ outgoingClip: edl.clips[i - 1],
31
+ incomingClip: clip,
32
+ });
33
+ }
34
+ cursor += effectiveDurationSec(clip);
35
+ if (i > 0 && clip.transitionIn && clip.transitionIn !== 'cut') {
36
+ cursor -= (clip.transitionMs ?? 250) / 1000;
37
+ }
38
+ }
39
+ return boundaries;
40
+ }
41
+ const ASPECT_MAP = {
42
+ '16:9': { width: 16, height: 9 },
43
+ '9:16': { width: 9, height: 16 },
44
+ '1:1': { width: 1, height: 1 },
45
+ };
46
+ export function checkAspectRegression(renderedPath, expectedRatio) {
47
+ if (!existsSync(renderedPath))
48
+ return [];
49
+ const raw = execSync(`ffprobe -v error -select_streams v:0 -show_entries stream=width,height -of csv=p=0 "${renderedPath}"`, { encoding: 'utf-8' }).trim();
50
+ const [wStr, hStr] = raw.split(',');
51
+ const w = parseInt(wStr, 10);
52
+ const h = parseInt(hStr, 10);
53
+ if (!w || !h) {
54
+ return [
55
+ {
56
+ kind: 'aspect-regression',
57
+ atSec: 0,
58
+ severity: 'warn',
59
+ message: `Could not read video dimensions from ${renderedPath}`,
60
+ },
61
+ ];
62
+ }
63
+ const actualRatio = w / h;
64
+ const expected = ASPECT_MAP[expectedRatio];
65
+ const expectedRatioVal = expected.width / expected.height;
66
+ const delta = Math.abs(actualRatio - expectedRatioVal);
67
+ if (delta > 0.01) {
68
+ return [
69
+ {
70
+ kind: 'aspect-regression',
71
+ atSec: 0,
72
+ severity: 'fail',
73
+ message: `Output is ${w}x${h} (ratio ${actualRatio.toFixed(3)}) but series is ${expectedRatio} (ratio ${expectedRatioVal.toFixed(3)}). Delta ${delta.toFixed(3)}.`,
74
+ },
75
+ ];
76
+ }
77
+ return [];
78
+ }
79
+ // ---------------------------------------------------------------------------
80
+ // Check: visual jump at boundary
81
+ // ---------------------------------------------------------------------------
82
+ function extractFrameHash(file, atSec) {
83
+ // Extract a small PNG and hash it with a crude 16x16 dhash.
84
+ // Using ffmpeg's grayscale downscale avoids pulling in an imaging library.
85
+ const tmp = `/tmp/cq-${Date.now()}-${Math.random().toString(36).slice(2, 8)}.pgm`;
86
+ try {
87
+ execSync(`ffmpeg -y -hide_banner -loglevel error -ss ${atSec} -i "${file}" -frames:v 1 -vf "scale=16:16,format=gray" "${tmp}"`, { stdio: 'inherit' });
88
+ const buf = readFileSync(tmp);
89
+ // PGM header: P5\n<w> <h>\n255\n<binary>
90
+ // Find end of header — second newline after the magic.
91
+ let offset = 0;
92
+ let newlines = 0;
93
+ while (offset < buf.length && newlines < 3) {
94
+ if (buf[offset] === 0x0a)
95
+ newlines++;
96
+ offset++;
97
+ }
98
+ const pixels = buf.slice(offset);
99
+ const arr = Array.from(pixels.slice(0, 256));
100
+ return arr;
101
+ }
102
+ finally {
103
+ try {
104
+ execSync(`rm -f "${tmp}"`);
105
+ }
106
+ catch {
107
+ // ignore
108
+ }
109
+ }
110
+ }
111
+ function hashDistance(a, b) {
112
+ if (a.length !== b.length)
113
+ return 256;
114
+ const meanA = a.reduce((s, v) => s + v, 0) / a.length;
115
+ const meanB = b.reduce((s, v) => s + v, 0) / b.length;
116
+ let bitsDiff = 0;
117
+ for (let i = 0; i < a.length; i++) {
118
+ const bitA = a[i] >= meanA ? 1 : 0;
119
+ const bitB = b[i] >= meanB ? 1 : 0;
120
+ if (bitA !== bitB)
121
+ bitsDiff++;
122
+ }
123
+ return bitsDiff;
124
+ }
125
+ export function checkVisualJump(renderedPath, boundaries) {
126
+ if (!existsSync(renderedPath))
127
+ return [];
128
+ const findings = [];
129
+ for (const b of boundaries) {
130
+ // Skip transitions with crossfades — the blend smooths any hash delta.
131
+ if (b.incomingClip.transitionIn && b.incomingClip.transitionIn !== 'cut')
132
+ continue;
133
+ const outgoing = extractFrameHash(renderedPath, Math.max(0, b.trailerTimeSec - 0.04));
134
+ const incoming = extractFrameHash(renderedPath, b.trailerTimeSec);
135
+ const dist = hashDistance(outgoing, incoming);
136
+ if (dist >= 64) {
137
+ findings.push({
138
+ kind: 'visual-jump',
139
+ atSec: b.trailerTimeSec,
140
+ clipIndex: b.index,
141
+ severity: 'warn',
142
+ message: `Frame hash distance ${dist}/256 between outgoing and incoming clips at cut ${b.index}. Probable visual jump.`,
143
+ });
144
+ }
145
+ }
146
+ return findings;
147
+ }
148
+ // ---------------------------------------------------------------------------
149
+ // Check: VO truncation against ground-truth script
150
+ // ---------------------------------------------------------------------------
151
+ export function checkVoTruncation(script, asrWords) {
152
+ const r = detectTruncation(script, asrWords);
153
+ if (!r.truncated)
154
+ return [];
155
+ const preview = r.lostWords.slice(0, 12).join(' ');
156
+ return [
157
+ {
158
+ kind: 'vo-truncation',
159
+ atSec: r.lastAlignedSec,
160
+ severity: 'fail',
161
+ message: `VO ended at ${r.lastAlignedSec.toFixed(2)}s but script has ${r.lostWords.length} unaligned words after: "${preview}${r.lostWords.length > 12 ? '...' : ''}". Likely doubled-ellipsis bug (AGENTS.md rule 26).`,
162
+ },
163
+ ];
164
+ }
165
+ // ---------------------------------------------------------------------------
166
+ // Check: audio pop at boundary
167
+ // ---------------------------------------------------------------------------
168
+ export function checkAudioPops(renderedPath, boundaries, fadeMs) {
169
+ if (!existsSync(renderedPath))
170
+ return [];
171
+ const findings = [];
172
+ for (const b of boundaries) {
173
+ // Scan a 100ms window centered at the boundary, excluding the fade region.
174
+ const winStart = Math.max(0, b.trailerTimeSec - 0.05);
175
+ const winDur = 0.1;
176
+ try {
177
+ const out = execSync(`ffmpeg -hide_banner -nostats -ss ${winStart} -i "${renderedPath}" -t ${winDur} -af "astats=metadata=1:reset=1" -f null - 2>&1 | grep -E "Peak level"`, { encoding: 'utf-8' });
178
+ // Parse peak level dB (rough)
179
+ const m = out.match(/Peak level dB: ([-\d.]+)/);
180
+ if (m) {
181
+ const peak = parseFloat(m[1]);
182
+ if (peak > -6 && fadeMs < 50) {
183
+ findings.push({
184
+ kind: 'audio-pop',
185
+ atSec: b.trailerTimeSec,
186
+ clipIndex: b.index,
187
+ severity: 'fail',
188
+ message: `Peak ${peak.toFixed(1)} dBFS at cut ${b.index}. Audio fade (${fadeMs}ms) did not catch this click.`,
189
+ });
190
+ }
191
+ }
192
+ }
193
+ catch {
194
+ // astats parse failure is non-fatal
195
+ }
196
+ }
197
+ return findings;
198
+ }
199
+ // ---------------------------------------------------------------------------
200
+ // Check: lighting discontinuity
201
+ // ---------------------------------------------------------------------------
202
+ function measureMeanLuma(file, atSec) {
203
+ try {
204
+ const out = execSync(`ffmpeg -hide_banner -nostats -ss ${atSec} -i "${file}" -frames:v 1 -vf "signalstats" -f null - 2>&1 | grep "YAVG"`, { encoding: 'utf-8' });
205
+ const m = out.match(/YAVG:([\d.]+)/);
206
+ if (m)
207
+ return parseFloat(m[1]) / 255;
208
+ }
209
+ catch {
210
+ return null;
211
+ }
212
+ return null;
213
+ }
214
+ export function checkLightingDiscontinuity(renderedPath, boundaries) {
215
+ if (!existsSync(renderedPath))
216
+ return [];
217
+ const findings = [];
218
+ for (const b of boundaries) {
219
+ const before = measureMeanLuma(renderedPath, Math.max(0, b.trailerTimeSec - 0.04));
220
+ const after = measureMeanLuma(renderedPath, b.trailerTimeSec + 0.04);
221
+ if (before === null || after === null)
222
+ continue;
223
+ const delta = Math.abs(before - after);
224
+ if (delta > 0.18) {
225
+ findings.push({
226
+ kind: 'lighting-discontinuity',
227
+ atSec: b.trailerTimeSec,
228
+ clipIndex: b.index,
229
+ severity: 'warn',
230
+ message: `Mean luma delta ${delta.toFixed(3)} at cut ${b.index} (before=${before.toFixed(2)}, after=${after.toFixed(2)}). Possible lighting mismatch.`,
231
+ });
232
+ }
233
+ }
234
+ return findings;
235
+ }
236
+ export function runCutQa(input) {
237
+ const boundaries = enumerateCutBoundaries(input.edl);
238
+ const findings = [];
239
+ if (input.aspectRatio) {
240
+ findings.push(...checkAspectRegression(input.renderedPath, input.aspectRatio));
241
+ }
242
+ findings.push(...checkVisualJump(input.renderedPath, boundaries));
243
+ findings.push(...checkLightingDiscontinuity(input.renderedPath, boundaries));
244
+ findings.push(...checkAudioPops(input.renderedPath, boundaries, input.edl.audioFadeMs));
245
+ if (input.groundTruthScript && input.renderedAsrWords) {
246
+ findings.push(...checkVoTruncation(input.groundTruthScript, input.renderedAsrWords));
247
+ }
248
+ const passed = findings.every((f) => f.severity !== 'fail');
249
+ return {
250
+ iteration: input.iteration,
251
+ generatedAt: new Date().toISOString(),
252
+ findings,
253
+ passed,
254
+ };
255
+ }
256
+ // ---------------------------------------------------------------------------
257
+ // Session persistence
258
+ // ---------------------------------------------------------------------------
259
+ export function loadSession(path) {
260
+ if (!existsSync(path))
261
+ return null;
262
+ return JSON.parse(readFileSync(path, 'utf-8'));
263
+ }
264
+ export function saveSession(session, path) {
265
+ mkdirSync(dirname(path), { recursive: true });
266
+ session.updatedAt = new Date().toISOString();
267
+ writeFileSync(path, JSON.stringify(session, null, 2), 'utf-8');
268
+ }
269
+ export function summarizeReport(report) {
270
+ if (report.findings.length === 0) {
271
+ return `cut-qa iteration ${report.iteration} — 0 findings — PASS`;
272
+ }
273
+ const fails = report.findings.filter((f) => f.severity === 'fail');
274
+ const warns = report.findings.filter((f) => f.severity === 'warn');
275
+ const lines = [];
276
+ lines.push(`cut-qa iteration ${report.iteration} — ${report.findings.length} findings — ${report.passed ? 'PASS (warnings only)' : 'FAIL'}`);
277
+ if (fails.length > 0) {
278
+ lines.push('');
279
+ lines.push(`FAIL (${fails.length}):`);
280
+ for (const f of fails) {
281
+ lines.push(` - [${f.kind}] at ${f.atSec.toFixed(2)}s: ${f.message}`);
282
+ }
283
+ }
284
+ if (warns.length > 0) {
285
+ lines.push('');
286
+ lines.push(`WARN (${warns.length}):`);
287
+ for (const f of warns) {
288
+ lines.push(` - [${f.kind}] at ${f.atSec.toFixed(2)}s: ${f.message}`);
289
+ }
290
+ }
291
+ return lines.join('\n');
292
+ }
293
+ //# sourceMappingURL=self-eval.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"self-eval.js","sourceRoot":"","sources":["../../src/editing/self-eval.ts"],"names":[],"mappings":"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"}