videobook 0.0.0-stage → 0.1.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 (558) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/LICENSE +21 -0
  3. package/README.md +133 -2
  4. package/bin/videobook.js +7 -0
  5. package/dist/acestep/client.js +203 -0
  6. package/dist/acestep/config.js +62 -0
  7. package/dist/acestep/errors.js +8 -0
  8. package/dist/acestep/process.js +175 -0
  9. package/dist/alive-captions/analyze.js +117 -0
  10. package/dist/alive-captions/audio.js +179 -0
  11. package/dist/alive-captions/frames.js +59 -0
  12. package/dist/alive-captions/model.js +37 -0
  13. package/dist/alive-captions/schema.js +49 -0
  14. package/dist/alive-captions/track.js +9 -0
  15. package/dist/api-key.js +33 -0
  16. package/dist/app-state.js +56 -0
  17. package/dist/app.js +257 -0
  18. package/dist/archive-b2.js +332 -0
  19. package/dist/archive-store.js +169 -0
  20. package/dist/artifact-label.js +36 -0
  21. package/dist/artifact-refs.js +49 -0
  22. package/dist/asset-tag-extraction.js +169 -0
  23. package/dist/asset-tags.js +228 -0
  24. package/dist/asset-usage.js +23 -0
  25. package/dist/audio-cue.js +71 -0
  26. package/dist/audio-encoding.js +32 -0
  27. package/dist/audio-sync-request.js +1 -0
  28. package/dist/audio-sync.js +223 -0
  29. package/dist/audio-trim-range.js +31 -0
  30. package/dist/book-context.js +31 -0
  31. package/dist/book-manager.js +374 -0
  32. package/dist/catalog-gc.js +26 -0
  33. package/dist/chain-executor.js +815 -0
  34. package/dist/chain-generation.js +115 -0
  35. package/dist/chain-plan.js +746 -0
  36. package/dist/chain-step-review.js +60 -0
  37. package/dist/character-name.js +25 -0
  38. package/dist/chat-generation-routing.js +73 -0
  39. package/dist/chat-generation-settings.js +78 -0
  40. package/dist/chat-models.js +44 -0
  41. package/dist/chat-prompt-rewrite.js +67 -0
  42. package/dist/chat-router.js +628 -0
  43. package/dist/chat-view-actions.js +49 -0
  44. package/dist/cli/args.js +192 -0
  45. package/dist/cli/doctor-command.js +255 -0
  46. package/dist/cli/entry.js +2 -0
  47. package/dist/cli/main.js +91 -0
  48. package/dist/cli/mcp-command.js +82 -0
  49. package/dist/cli/mcp-relay.js +51 -0
  50. package/dist/cli/open-browser.js +14 -0
  51. package/dist/cli/run-command.js +187 -0
  52. package/dist/cli/serve-command.js +57 -0
  53. package/dist/cli/stdio-guard.js +8 -0
  54. package/dist/cold-open-model.js +7 -0
  55. package/dist/cold-open.js +79 -0
  56. package/dist/command-reference.js +95 -0
  57. package/dist/content-store.js +74 -0
  58. package/dist/cost.js +8 -0
  59. package/dist/crop-geometry.js +23 -0
  60. package/dist/dancing-workflow.js +446 -0
  61. package/dist/data-home.js +44 -0
  62. package/dist/diagnostics.js +109 -0
  63. package/dist/dialog-quality.js +34 -0
  64. package/dist/downloads-dest.js +56 -0
  65. package/dist/editing-moments.js +194 -0
  66. package/dist/elevenlabs-audio-extension.js +66 -0
  67. package/dist/engine.js +54 -0
  68. package/dist/env-secrets.js +184 -0
  69. package/dist/ffmpeg-binary.js +12 -0
  70. package/dist/ffmpeg.js +425 -0
  71. package/dist/ffprobe-binary.js +55 -0
  72. package/dist/forget-asset.js +216 -0
  73. package/dist/frame-utils.js +27 -0
  74. package/dist/generation-credit-error.js +11 -0
  75. package/dist/generation-input-mentions.js +117 -0
  76. package/dist/generation-input-policy.js +68 -0
  77. package/dist/generation-reference-mentions.js +97 -0
  78. package/dist/goal-characters.js +49 -0
  79. package/dist/goal-plan-v3.js +273 -0
  80. package/dist/goal-plan.js +220 -0
  81. package/dist/goal-planner-prompt.js +28 -0
  82. package/dist/goal-prompt-budget.js +4 -0
  83. package/dist/goal-reference-images.js +25 -0
  84. package/dist/goal-state.js +261 -0
  85. package/dist/goal-stills.js +153 -0
  86. package/dist/goal-store.js +144 -0
  87. package/dist/goal-styles.js +144 -0
  88. package/dist/goal-v3-runtime.js +157 -0
  89. package/dist/guides/character_schema_guide.md +70 -0
  90. package/dist/guides/gpt_image_2_5_prompting_guide.md +21 -0
  91. package/dist/guides/grok_imagine_prompting_guide.md +72 -0
  92. package/dist/guides/image_reproduction_guide.md +84 -0
  93. package/dist/guides/kling_3_0_prompting_guide.md +136 -0
  94. package/dist/guides/nano_banana_pro_prompting_guide.md +28 -0
  95. package/dist/guides/seedance_2_prompting_guide.md +172 -0
  96. package/dist/http-access.js +49 -0
  97. package/dist/http-byte-range.js +31 -0
  98. package/dist/image-compress.js +77 -0
  99. package/dist/image-edit-default.js +1 -0
  100. package/dist/image-edit-models.js +41 -0
  101. package/dist/image-edit-settings.js +11 -0
  102. package/dist/image-region-edit.js +32 -0
  103. package/dist/image-subject-map.js +523 -0
  104. package/dist/image.js +46 -0
  105. package/dist/index.js +12 -0
  106. package/dist/job-deadline.js +60 -0
  107. package/dist/jobs/_alibaba-upload.js +30 -0
  108. package/dist/jobs/_audio-chunks.js +31 -0
  109. package/dist/jobs/_download-into-asset.js +15 -0
  110. package/dist/jobs/_fal-shared.js +22 -0
  111. package/dist/jobs/_fal-upload.js +35 -0
  112. package/dist/jobs/_image-edit-adapter.js +213 -0
  113. package/dist/jobs/_kie-poll.js +119 -0
  114. package/dist/jobs/_kie-upload.js +32 -0
  115. package/dist/jobs/_lease.js +163 -0
  116. package/dist/jobs/_persist-output.js +19 -0
  117. package/dist/jobs/_storage-retry.js +21 -0
  118. package/dist/jobs/_transcribe.js +245 -0
  119. package/dist/jobs/_translate-transcript.js +270 -0
  120. package/dist/jobs/analyze-alive-captions.js +10 -0
  121. package/dist/jobs/analyze-editing-moments.js +104 -0
  122. package/dist/jobs/analyze-jokes.js +143 -0
  123. package/dist/jobs/analyze-keyword-placement.js +155 -0
  124. package/dist/jobs/analyze-music.js +14 -0
  125. package/dist/jobs/analyze-video.js +282 -0
  126. package/dist/jobs/apply-cuts.js +83 -0
  127. package/dist/jobs/apply-sfx.js +107 -0
  128. package/dist/jobs/archive-clip.js +457 -0
  129. package/dist/jobs/assemble-goal.js +98 -0
  130. package/dist/jobs/audio-boost.js +71 -0
  131. package/dist/jobs/audio-mix.js +161 -0
  132. package/dist/jobs/backfill-asset-tags.js +144 -0
  133. package/dist/jobs/burn-watermark.js +316 -0
  134. package/dist/jobs/change-video-speed.js +176 -0
  135. package/dist/jobs/clean-video-audio.js +207 -0
  136. package/dist/jobs/cold-open.js +166 -0
  137. package/dist/jobs/combine-goal.js +108 -0
  138. package/dist/jobs/complete-provider-task.js +185 -0
  139. package/dist/jobs/copy-library-asset.js +33 -0
  140. package/dist/jobs/cost-estimate-assessment.js +113 -0
  141. package/dist/jobs/crop-image.js +47 -0
  142. package/dist/jobs/crop-video.js +71 -0
  143. package/dist/jobs/describe-image.js +181 -0
  144. package/dist/jobs/detect-scenes.js +33 -0
  145. package/dist/jobs/doctor-fix.js +100 -0
  146. package/dist/jobs/download-video.js +426 -0
  147. package/dist/jobs/enqueue-search-index.js +24 -0
  148. package/dist/jobs/even-split.js +122 -0
  149. package/dist/jobs/export-sequence.js +365 -0
  150. package/dist/jobs/extend-audio.js +229 -0
  151. package/dist/jobs/extract-audio.js +72 -0
  152. package/dist/jobs/extract-frame.js +58 -0
  153. package/dist/jobs/extract-notebook-audio.js +82 -0
  154. package/dist/jobs/extract-notebook-frame.js +93 -0
  155. package/dist/jobs/extract-video-clip.js +8 -0
  156. package/dist/jobs/extract-video-poster.js +55 -0
  157. package/dist/jobs/extract-waveform.js +25 -0
  158. package/dist/jobs/finish-goal.js +255 -0
  159. package/dist/jobs/forget-asset.js +11 -0
  160. package/dist/jobs/generate-acestep-cover.js +219 -0
  161. package/dist/jobs/generate-media.js +70 -0
  162. package/dist/jobs/image-subjects.js +1059 -0
  163. package/dist/jobs/index.js +18 -0
  164. package/dist/jobs/inject-first-frame.js +175 -0
  165. package/dist/jobs/isolate-vocals.js +69 -0
  166. package/dist/jobs/kie-paygate.js +177 -0
  167. package/dist/jobs/label-music-sections.js +5 -0
  168. package/dist/jobs/osg-placement.js +135 -0
  169. package/dist/jobs/pad-video.js +72 -0
  170. package/dist/jobs/plan-goal.js +97 -0
  171. package/dist/jobs/post-record.js +21 -0
  172. package/dist/jobs/post-to-x.js +21 -0
  173. package/dist/jobs/prepare-search-reference.js +190 -0
  174. package/dist/jobs/prepare-temporal-search.js +16 -0
  175. package/dist/jobs/process-audio.js +67 -0
  176. package/dist/jobs/process-image.js +58 -0
  177. package/dist/jobs/process-upload.js +166 -0
  178. package/dist/jobs/process-video.js +438 -0
  179. package/dist/jobs/register-all.js +161 -0
  180. package/dist/jobs/relayout-notebook.js +78 -0
  181. package/dist/jobs/remove-sound.js +299 -0
  182. package/dist/jobs/render-project.js +380 -0
  183. package/dist/jobs/render-qr-outro.js +138 -0
  184. package/dist/jobs/render-timeline.js +283 -0
  185. package/dist/jobs/repair-search-indexes.js +42 -0
  186. package/dist/jobs/replace-video-audio.js +64 -0
  187. package/dist/jobs/restore-archive-clip.js +53 -0
  188. package/dist/jobs/reverse-video.js +53 -0
  189. package/dist/jobs/rewrite-script.js +173 -0
  190. package/dist/jobs/run-notebook.js +3335 -0
  191. package/dist/jobs/semantic-index.js +797 -0
  192. package/dist/jobs/smooth-scene-concat.js +257 -0
  193. package/dist/jobs/splice-video.js +280 -0
  194. package/dist/jobs/split-video.js +127 -0
  195. package/dist/jobs/suggest-cuts.js +149 -0
  196. package/dist/jobs/suggest-sfx.js +135 -0
  197. package/dist/jobs/sync-video-to-audio.js +329 -0
  198. package/dist/jobs/tag-asset.js +266 -0
  199. package/dist/jobs/task-failure.js +16 -0
  200. package/dist/jobs/timewarp-video.js +152 -0
  201. package/dist/jobs/transcribe-video-audio.js +117 -0
  202. package/dist/jobs/transcribe.js +35 -0
  203. package/dist/jobs/translate-transcript.js +55 -0
  204. package/dist/jobs/trim-audio.js +133 -0
  205. package/dist/jobs/trim-video.js +291 -0
  206. package/dist/jobs/xai-paygate.js +26 -0
  207. package/dist/keyword-placement-cache.js +74 -0
  208. package/dist/lazy-render.js +142 -0
  209. package/dist/library-browse.js +78 -0
  210. package/dist/lightning-defaults.js +206 -0
  211. package/dist/load-env.js +9 -0
  212. package/dist/local-search-models.js +206 -0
  213. package/dist/local-upload.js +318 -0
  214. package/dist/logger.js +69 -0
  215. package/dist/media/adapters/alibaba.js +20 -0
  216. package/dist/media/adapters/elevenlabs.js +58 -0
  217. package/dist/media/adapters/fal.js +45 -0
  218. package/dist/media/adapters/index.js +26 -0
  219. package/dist/media/adapters/kie.js +120 -0
  220. package/dist/media/adapters/pending.js +21 -0
  221. package/dist/media/adapters/types.js +5 -0
  222. package/dist/media/adapters/xai.js +18 -0
  223. package/dist/media/catalog.js +236 -0
  224. package/dist/media/complete.js +191 -0
  225. package/dist/media/cost.js +45 -0
  226. package/dist/media/descriptor.js +157 -0
  227. package/dist/media/endpoints.js +11 -0
  228. package/dist/media/frame-options.js +18 -0
  229. package/dist/media/insert-video-timing.js +17 -0
  230. package/dist/media/json-schema.js +75 -0
  231. package/dist/media/legacy-task-types.js +129 -0
  232. package/dist/media/listing.js +24 -0
  233. package/dist/media/model-id.js +14 -0
  234. package/dist/media/preview.js +86 -0
  235. package/dist/media/prompt-dialects.js +65 -0
  236. package/dist/media/ref-fields.js +106 -0
  237. package/dist/media/refs.js +131 -0
  238. package/dist/media/request.js +188 -0
  239. package/dist/media/types.js +6 -0
  240. package/dist/media/wire.js +161 -0
  241. package/dist/media-library.js +535 -0
  242. package/dist/media-output-path.js +33 -0
  243. package/dist/multyculty-workflow.js +757 -0
  244. package/dist/notebook-action-catalog.js +608 -0
  245. package/dist/notebook-cell-outputs.js +726 -0
  246. package/dist/notebook-credit-retry.js +45 -0
  247. package/dist/notebook-fixtures.js +8 -0
  248. package/dist/notebook-generation-contract.js +77 -0
  249. package/dist/notebook-generation-controls.js +145 -0
  250. package/dist/notebook-goal-layout.js +40 -0
  251. package/dist/notebook-graph.js +37 -0
  252. package/dist/notebook-image-edit.js +84 -0
  253. package/dist/notebook-initial-generation-prompt.js +222 -0
  254. package/dist/notebook-live-analysis.js +941 -0
  255. package/dist/notebook-media-ops.js +579 -0
  256. package/dist/notebook-mutations.js +20 -0
  257. package/dist/notebook-placement.js +41 -0
  258. package/dist/notebook-provider-failure.js +87 -0
  259. package/dist/notebook-published-post.js +26 -0
  260. package/dist/notebook-reference-resolver.js +227 -0
  261. package/dist/notebook-relayout.js +270 -0
  262. package/dist/notebook-run-plan.js +519 -0
  263. package/dist/notebook-shots.js +162 -0
  264. package/dist/notebook-workflow.js +856 -0
  265. package/dist/openai-intelligence.js +99 -0
  266. package/dist/original-media-file.js +12 -0
  267. package/dist/osg-assets.js +36 -0
  268. package/dist/osg-placement-cache.js +64 -0
  269. package/dist/osg-settings.js +27 -0
  270. package/dist/paid-tools.js +22 -0
  271. package/dist/platform-guidance.js +26 -0
  272. package/dist/posts/dropbox-auth.js +91 -0
  273. package/dist/posts/dropbox-upload.js +132 -0
  274. package/dist/posts/icloud-drive.js +134 -0
  275. package/dist/posts/icloud-status.js +64 -0
  276. package/dist/posts/post-contract.js +2 -0
  277. package/dist/posts/post-copy-format.js +43 -0
  278. package/dist/posts/post-copy.js +193 -0
  279. package/dist/posts/post-folder.js +18 -0
  280. package/dist/posts/post-metrics.js +119 -0
  281. package/dist/posts/post-store.js +340 -0
  282. package/dist/posts/x-post-target.js +43 -0
  283. package/dist/preview-payload.js +90 -0
  284. package/dist/prompt-surfaces.js +22 -0
  285. package/dist/provider-prompt-transform.js +77 -0
  286. package/dist/provider-status-link.js +21 -0
  287. package/dist/provider-task-record.js +78 -0
  288. package/dist/provider-task-status.js +47 -0
  289. package/dist/provider-usage.js +294 -0
  290. package/dist/queue.js +806 -0
  291. package/dist/reference-video-duration.js +17 -0
  292. package/dist/remotion/BlurFillVideo.js +51 -0
  293. package/dist/remotion/KeywordGraphicsOverlay.js +68 -0
  294. package/dist/remotion/OsgOverlay.js +30 -0
  295. package/dist/remotion/QrOutroComposition.js +47 -0
  296. package/dist/remotion/RenderComposition.js +11 -0
  297. package/dist/remotion/browser.js +59 -0
  298. package/dist/remotion/constants.js +35 -0
  299. package/dist/remotion/index.js +66 -0
  300. package/dist/remotion/keyword-graphics.js +151 -0
  301. package/dist/remotion/keyword-placement.js +182 -0
  302. package/dist/remotion/osg-spec.js +198 -0
  303. package/dist/remotion/public/qr-outro-impact.wav +0 -0
  304. package/dist/remotion/qr-outro-audio.js +1 -0
  305. package/dist/remotion/qr-outro-spec.js +211 -0
  306. package/dist/remotion/shared-bundle.js +37 -0
  307. package/dist/remotion/subtitles/AliveCaptions.js +83 -0
  308. package/dist/remotion/subtitles/Highlight.js +58 -0
  309. package/dist/remotion/subtitles/Impact.js +67 -0
  310. package/dist/remotion/subtitles/SubtitleOverlay.js +9 -0
  311. package/dist/remotion/subtitles/alive-layout.js +321 -0
  312. package/dist/remotion/subtitles/alive-types.js +17 -0
  313. package/dist/remotion/subtitles/chunker.js +68 -0
  314. package/dist/remotion/subtitles/segments.js +42 -0
  315. package/dist/remotion/subtitles/styles.js +4 -0
  316. package/dist/remotion/subtitles/types.js +1 -0
  317. package/dist/remotion/util.js +18 -0
  318. package/dist/remotion-cancellation.js +15 -0
  319. package/dist/rename-helpers.js +204 -0
  320. package/dist/rhythm/analyze.js +128 -0
  321. package/dist/rhythm/contract.js +14 -0
  322. package/dist/rhythm/draft-model.js +19 -0
  323. package/dist/rhythm/energy.js +133 -0
  324. package/dist/rhythm/fft.js +44 -0
  325. package/dist/rhythm/model.js +71 -0
  326. package/dist/rhythm/music-analysis.js +124 -0
  327. package/dist/rhythm/music-draft.js +261 -0
  328. package/dist/rhythm/onset.js +101 -0
  329. package/dist/rhythm/run-worker.js +51 -0
  330. package/dist/rhythm/score.js +47 -0
  331. package/dist/rhythm/section-labels.js +168 -0
  332. package/dist/rhythm/sequence-rhythm.js +67 -0
  333. package/dist/rhythm/synthesize.js +103 -0
  334. package/dist/rhythm/timing.js +98 -0
  335. package/dist/rhythm/track.js +320 -0
  336. package/dist/rhythm/visual-fit.js +4 -0
  337. package/dist/rhythm/worker.js +25 -0
  338. package/dist/scene-detect.js +200 -0
  339. package/dist/scene-transition.js +12 -0
  340. package/dist/scheduled-posts.js +200 -0
  341. package/dist/search-index-coverage.js +13 -0
  342. package/dist/search-index-media.js +71 -0
  343. package/dist/search-reference-store.js +60 -0
  344. package/dist/search-scoring.js +17 -0
  345. package/dist/serve.js +150 -0
  346. package/dist/server-lock.js +143 -0
  347. package/dist/server.js +42 -0
  348. package/dist/srt.js +16 -0
  349. package/dist/tag-backfill-state.js +121 -0
  350. package/dist/tag-settings.js +30 -0
  351. package/dist/tag-vocabulary.js +237 -0
  352. package/dist/test-queue-cleanup.js +1 -0
  353. package/dist/time-parse.js +50 -0
  354. package/dist/timeline-helpers.js +554 -0
  355. package/dist/timewarp.js +87 -0
  356. package/dist/tools/_image-inputs.js +9 -0
  357. package/dist/tools/_media-refs.js +84 -0
  358. package/dist/tools/_shared.js +59 -0
  359. package/dist/tools/_suggest-shared.js +279 -0
  360. package/dist/tools/add-timeline-audio.js +73 -0
  361. package/dist/tools/alive-captions.js +157 -0
  362. package/dist/tools/analyze-jokes.js +56 -0
  363. package/dist/tools/analyze-video.js +66 -0
  364. package/dist/tools/animate-keywords.js +217 -0
  365. package/dist/tools/api-status.js +42 -0
  366. package/dist/tools/application-commands.js +34 -0
  367. package/dist/tools/apply-cuts.js +112 -0
  368. package/dist/tools/apply-sfx.js +152 -0
  369. package/dist/tools/apply-watermark.js +670 -0
  370. package/dist/tools/archive-clip.js +74 -0
  371. package/dist/tools/asset-history.js +61 -0
  372. package/dist/tools/asset-manifest.js +24 -0
  373. package/dist/tools/asset-tags.js +151 -0
  374. package/dist/tools/assign-slot.js +97 -0
  375. package/dist/tools/audio-boost.js +107 -0
  376. package/dist/tools/audio-mix.js +121 -0
  377. package/dist/tools/book-usage.js +16 -0
  378. package/dist/tools/chain.js +136 -0
  379. package/dist/tools/change-video-speed.js +105 -0
  380. package/dist/tools/chat-history.js +5 -0
  381. package/dist/tools/chat.js +848 -0
  382. package/dist/tools/clean-video-audio.js +97 -0
  383. package/dist/tools/clear-failed-tasks.js +66 -0
  384. package/dist/tools/cold-open.js +114 -0
  385. package/dist/tools/command-plan.js +1680 -0
  386. package/dist/tools/commands.js +1666 -0
  387. package/dist/tools/concat-images.js +236 -0
  388. package/dist/tools/connect-service.js +55 -0
  389. package/dist/tools/copy-file-to-clipboard.js +58 -0
  390. package/dist/tools/create-character.js +114 -0
  391. package/dist/tools/create-qart.js +253 -0
  392. package/dist/tools/create-qr-outro.js +149 -0
  393. package/dist/tools/create-qrbtf.js +215 -0
  394. package/dist/tools/create-watermark.js +97 -0
  395. package/dist/tools/crop-asset.js +18 -0
  396. package/dist/tools/crop-image.js +120 -0
  397. package/dist/tools/crop-video.js +97 -0
  398. package/dist/tools/delete-asset.js +104 -0
  399. package/dist/tools/describe-image.js +69 -0
  400. package/dist/tools/detect-scenes.js +44 -0
  401. package/dist/tools/doctor.js +126 -0
  402. package/dist/tools/download-video.js +114 -0
  403. package/dist/tools/duplicate-asset.js +184 -0
  404. package/dist/tools/edit-timeline.js +59 -0
  405. package/dist/tools/editing-moments.js +105 -0
  406. package/dist/tools/estimate-cost.js +171 -0
  407. package/dist/tools/even-split.js +295 -0
  408. package/dist/tools/export-asset-file.js +22 -0
  409. package/dist/tools/export-asset.js +140 -0
  410. package/dist/tools/export-sequence.js +250 -0
  411. package/dist/tools/export-to-downloads.js +54 -0
  412. package/dist/tools/export-transcript-srt.js +79 -0
  413. package/dist/tools/extend-audio.js +100 -0
  414. package/dist/tools/extract-audio.js +174 -0
  415. package/dist/tools/extract-frame.js +108 -0
  416. package/dist/tools/extract-notebook-audio.js +173 -0
  417. package/dist/tools/extract-notebook-frame.js +160 -0
  418. package/dist/tools/extract-video-clip.js +101 -0
  419. package/dist/tools/generate-media.js +157 -0
  420. package/dist/tools/generation-payload.js +48 -0
  421. package/dist/tools/get-timeline.js +12 -0
  422. package/dist/tools/get-watermark-config.js +38 -0
  423. package/dist/tools/goal.js +644 -0
  424. package/dist/tools/image-subjects.js +711 -0
  425. package/dist/tools/index.js +323 -0
  426. package/dist/tools/inject-first-frame.js +154 -0
  427. package/dist/tools/invert-image.js +70 -0
  428. package/dist/tools/isolate-vocals.js +66 -0
  429. package/dist/tools/list-assets.js +98 -0
  430. package/dist/tools/list-cell-generations.js +225 -0
  431. package/dist/tools/list-elevenlabs-voices.js +163 -0
  432. package/dist/tools/log-wrapper.js +29 -0
  433. package/dist/tools/make-cover-song.js +95 -0
  434. package/dist/tools/mark-asset-seen.js +23 -0
  435. package/dist/tools/media-library.js +245 -0
  436. package/dist/tools/move-timeline-audio.js +35 -0
  437. package/dist/tools/music-analysis.js +60 -0
  438. package/dist/tools/music-draft.js +29 -0
  439. package/dist/tools/pad-video.js +87 -0
  440. package/dist/tools/post-record.js +83 -0
  441. package/dist/tools/post.js +168 -0
  442. package/dist/tools/prompt-history.js +164 -0
  443. package/dist/tools/provider-key-status.js +248 -0
  444. package/dist/tools/qrbtf-render.js +849 -0
  445. package/dist/tools/read-asset-metadata.js +26 -0
  446. package/dist/tools/read-file-at-commit.js +29 -0
  447. package/dist/tools/read-transcript.js +41 -0
  448. package/dist/tools/reconcile-project-work.js +1452 -0
  449. package/dist/tools/recover-asset.js +28 -0
  450. package/dist/tools/remove-sound.js +72 -0
  451. package/dist/tools/remove-timeline-audio.js +34 -0
  452. package/dist/tools/remove-timeline-slot.js +40 -0
  453. package/dist/tools/rename-all.js +434 -0
  454. package/dist/tools/rename-asset.js +34 -0
  455. package/dist/tools/render-settings.js +47 -0
  456. package/dist/tools/render-timeline.js +120 -0
  457. package/dist/tools/render.js +384 -0
  458. package/dist/tools/reorder-character-images.js +45 -0
  459. package/dist/tools/replace-video-audio.js +133 -0
  460. package/dist/tools/restore-archive-clips.js +209 -0
  461. package/dist/tools/restore-asset-version.js +37 -0
  462. package/dist/tools/retry-generation.js +54 -0
  463. package/dist/tools/reverse-video.js +74 -0
  464. package/dist/tools/rewrite-prompt.js +388 -0
  465. package/dist/tools/rewrite-script.js +67 -0
  466. package/dist/tools/schema-from-apicity.js +66 -0
  467. package/dist/tools/search-archive.js +150 -0
  468. package/dist/tools/semantic-search.js +1214 -0
  469. package/dist/tools/sequence-rhythm.js +43 -0
  470. package/dist/tools/set-character-metadata.js +84 -0
  471. package/dist/tools/set-env-secret.js +40 -0
  472. package/dist/tools/set-osg.js +143 -0
  473. package/dist/tools/show-folder.js +37 -0
  474. package/dist/tools/smooth-scene-concat.js +122 -0
  475. package/dist/tools/splice-video.js +149 -0
  476. package/dist/tools/split-video.js +202 -0
  477. package/dist/tools/suggest-cuts.js +45 -0
  478. package/dist/tools/suggest-sfx.js +43 -0
  479. package/dist/tools/sync-video-to-audio.js +115 -0
  480. package/dist/tools/tag-backfill.js +177 -0
  481. package/dist/tools/timewarp-video.js +85 -0
  482. package/dist/tools/tool-def.js +1 -0
  483. package/dist/tools/tool-json-schema.js +116 -0
  484. package/dist/tools/transcribe.js +90 -0
  485. package/dist/tools/translate-subtitles.js +59 -0
  486. package/dist/tools/trim-audio.js +139 -0
  487. package/dist/tools/trim-video.js +168 -0
  488. package/dist/tools/update-script.js +25 -0
  489. package/dist/tools/update-timeline-audio.js +40 -0
  490. package/dist/tools/upload-file.js +41 -0
  491. package/dist/tools/verify-x-mentions.js +141 -0
  492. package/dist/tools/video-editing-command-contract.js +291 -0
  493. package/dist/tools/video-source-reference.js +30 -0
  494. package/dist/tools/video-time-input.js +18 -0
  495. package/dist/tools/videobook-domain.js +2006 -0
  496. package/dist/tools/wait-for-asset-ready.js +143 -0
  497. package/dist/tools/workspace-actions.js +54 -0
  498. package/dist/transcript-projection.js +202 -0
  499. package/dist/transcript-srt.js +33 -0
  500. package/dist/upload.js +76 -0
  501. package/dist/usage-providers.js +25 -0
  502. package/dist/video-analysis-projection.js +46 -0
  503. package/dist/video-poster.js +33 -0
  504. package/dist/video-proxy.js +99 -0
  505. package/dist/vision-regions.js +111 -0
  506. package/dist/voice-actions.js +90 -0
  507. package/dist/voice-audio.js +55 -0
  508. package/dist/voice-config.js +122 -0
  509. package/dist/voice-continuation.js +54 -0
  510. package/dist/voice-contract.js +1 -0
  511. package/dist/voice-http.js +145 -0
  512. package/dist/voice-reply-progress.js +55 -0
  513. package/dist/voice-session.js +992 -0
  514. package/dist/watermark-badge.js +259 -0
  515. package/dist/watermark-config.js +111 -0
  516. package/dist/watermark-handle-position.js +55 -0
  517. package/dist/watermark-platform.js +15 -0
  518. package/dist/watermark-timing.js +16 -0
  519. package/dist/workspace-action-catalog.js +315 -0
  520. package/dist/workspace-action-contract.js +21 -0
  521. package/dist/workspace-action-groups.js +98 -0
  522. package/dist/workspace-action-surfaces.js +7 -0
  523. package/dist/x/account.js +88 -0
  524. package/dist/x/authenticated-handle.js +30 -0
  525. package/dist/x/oauth-flow.js +191 -0
  526. package/dist/x/post-contract.js +1 -0
  527. package/dist/x/post-metadata.js +44 -0
  528. package/dist/x/post-to-x.js +456 -0
  529. package/dist/x/published-post-cell.js +90 -0
  530. package/dist/x/x-tokens.js +69 -0
  531. package/dist/zod-slots.js +334 -0
  532. package/package.json +92 -4
  533. package/ui/assets/alive-captions-BWb5nLKj.css +1 -0
  534. package/ui/assets/alive-captions-DPEr1nKM.js +1 -0
  535. package/ui/assets/confirm-bodies-D8ouHXKy.js +1 -0
  536. package/ui/assets/confirm-bodies-DrMhaXC6.css +1 -0
  537. package/ui/assets/fullscreen-B7nw4YbE.js +1 -0
  538. package/ui/assets/goal-ui-DK-xTCK0.js +2 -0
  539. package/ui/assets/goal-ui-DXdUM2KF.css +1 -0
  540. package/ui/assets/index-DzPAnCUj.css +1 -0
  541. package/ui/assets/index-kS1905s5.js +37 -0
  542. package/ui/assets/inspector-MlzQbTVo.js +1 -0
  543. package/ui/assets/jobs-ui-CoinOWx0.js +1 -0
  544. package/ui/assets/music-video-Cbe80kmQ.js +1 -0
  545. package/ui/assets/music-video-DPaiKKEq.css +1 -0
  546. package/ui/assets/ui-Oirr9VOf.css +1 -0
  547. package/ui/assets/ui-xo_Y1yQg.js +2 -0
  548. package/ui/assets/vendor-D2rfiZ5j.css +1 -0
  549. package/ui/assets/vendor-DfTCWgKm.js +19 -0
  550. package/ui/assets/vendor-flow-BXbeWxW7.js +7 -0
  551. package/ui/assets/vendor-flow-BnuhLJ6X.css +1 -0
  552. package/ui/assets/vendor-icons-CGqhCIXV.js +1 -0
  553. package/ui/assets/vendor-mcp-BTlEJcHV.js +67 -0
  554. package/ui/assets/vendor-react-Dj7D1fD4.js +9 -0
  555. package/ui/assets/vendor-remotion-CH1HXrlc.js +95 -0
  556. package/ui/assets/videobook-Qlp9HQFu.js +20 -0
  557. package/ui/favicon.svg +8 -0
  558. package/ui/index.html +126 -0
@@ -0,0 +1,856 @@
1
+ import { notebookOccupiedSlots } from "videobook-engine/notebook-grid";
2
+ import { firstEmptyNotebookGridSlots, nextHorizontalSlotFrom, nextVerticalSlotFrom, } from "videobook-engine";
3
+ import { notebookGridTag } from "videobook-engine/notebook-grid";
4
+ import { isVerticalGenerationType, lastCreatedCellSlot, } from "./notebook-placement.js";
5
+ import { DEFAULT_ANIMATION_MODEL, normalizeCellActionFields, normalizeLegacyAnalyzeCell, } from "./notebook-action-catalog.js";
6
+ import { EXTRACT_AUDIO_OUTPUT_ROLE } from "./notebook-cell-outputs.js";
7
+ import { INTELLIGENCE_MODEL, OPENAI_ANALYSIS_TOOL, } from "./openai-intelligence.js";
8
+ import { normalizeShots, parseAnalysisShots, reconcileOwnedBranches, } from "./notebook-shots.js";
9
+ export const DEFAULT_ANALYSIS_PROMPT = "Detect shot boundaries from verified camera switches and audio continuity; cover the source exactly and label each shot from evidence.";
10
+ const LEGACY_ANALYSIS_PROMPTS = new Set([
11
+ "Segment the source into four continuous 15-second narrative shots with precise timestamps and concise visual context.",
12
+ "Segment the source into two continuous 15-second narrative shots with precise timestamps and concise visual context.",
13
+ ]);
14
+ function retainedAnalysisPrompt(existing) {
15
+ const prompt = existing?.prompt?.trim();
16
+ return !prompt || LEGACY_ANALYSIS_PROMPTS.has(prompt)
17
+ ? DEFAULT_ANALYSIS_PROMPT
18
+ : prompt;
19
+ }
20
+ export const MULTYCULTY_FEATURES = [
21
+ {
22
+ ordinal: 1,
23
+ id: "import-analyze",
24
+ label: "Import + Analyze",
25
+ feature: "Source import and automatic shot analysis",
26
+ caption: "FEATURE 01 · IMPORT + ANALYZE",
27
+ promptBrief: "Preserve the seated subject and original composition while a refined filmstrip, waveform, and precise scene markers materialize around the source. Show the app turning one imported video into an understood edit without adding text.",
28
+ column: 1,
29
+ },
30
+ {
31
+ ordinal: 2,
32
+ id: "split-extract",
33
+ label: "Split + Extract",
34
+ feature: "Scene splitting and reusable media extraction",
35
+ caption: "FEATURE 02 · SPLIT + EXTRACT",
36
+ promptBrief: "Preserve the people, car, and location while the moment separates into elegant first-frame, last-frame, and audio-wave components connected by clean editorial motion. Show reusable scene assets without adding text.",
37
+ column: 2,
38
+ },
39
+ {
40
+ ordinal: 3,
41
+ id: "prompt-animate",
42
+ label: "Prompt + Animate",
43
+ feature: "Asset-grounded prompt writing and animation",
44
+ caption: "FEATURE 03 · PROMPT + ANIMATE",
45
+ promptBrief: "Preserve the character performance and identity while an abstract prompt ribbon becomes controlled motion paths that travel from the first frame to the last frame. Show grounded animation direction without adding text.",
46
+ column: 4,
47
+ },
48
+ {
49
+ ordinal: 4,
50
+ id: "assemble-export",
51
+ label: "Concatenate",
52
+ feature: "Synchronized playable video concatenation",
53
+ caption: "FEATURE 04 · CONCATENATE",
54
+ promptBrief: "Preserve the dialogue scene and natural performance while four luminous editorial lanes converge into one synchronized landscape timeline and a polished finished master. Show completion and continuity without adding text.",
55
+ column: 5,
56
+ },
57
+ ];
58
+ function roleOf(cell) {
59
+ return typeof cell.inputs?.workflowRole === "string"
60
+ ? cell.inputs.workflowRole
61
+ : null;
62
+ }
63
+ function analysisOwnerId(cell) {
64
+ return typeof cell.inputs?.analysisCellId === "string"
65
+ ? cell.inputs.analysisCellId
66
+ : null;
67
+ }
68
+ function analysisOutputCell(document, producerCellId) {
69
+ const resultEdges = document.edges.filter((edge) => edge.source === producerCellId && edge.targetInput === "result");
70
+ if (resultEdges.length !== 1) {
71
+ throw new Error(`Analyze cell ${producerCellId} requires exactly one connected Analysis result cell`);
72
+ }
73
+ const result = document.cells.find((cell) => cell.id === resultEdges[0].target);
74
+ if (result?.type !== "analysis"
75
+ || result.inputs?.analysisRole !== "result"
76
+ || result.inputs?.producerCellId !== producerCellId) {
77
+ throw new Error(`Analyze cell ${producerCellId} has an invalid Analysis result connection`);
78
+ }
79
+ return result;
80
+ }
81
+ function outputVersionArtifactIds(cell, artifactId) {
82
+ const persisted = Array.isArray(cell.inputs?.outputVersionArtifactIds)
83
+ ? cell.inputs.outputVersionArtifactIds.filter((value) => typeof value === "string" && value.length > 0)
84
+ : [];
85
+ return [...new Set([
86
+ ...persisted,
87
+ ...(cell.outputArtifactId ? [cell.outputArtifactId] : []),
88
+ artifactId,
89
+ ])];
90
+ }
91
+ function splitVideoOwnerId(cell) {
92
+ return typeof cell.inputs?.splitVideoCellId === "string"
93
+ ? cell.inputs.splitVideoCellId
94
+ : null;
95
+ }
96
+ function featureForShot(shot) {
97
+ return MULTYCULTY_FEATURES[shot.ordinal - 1] ?? null;
98
+ }
99
+ function featureColumn(shot) {
100
+ return featureForShot(shot)?.column ?? (shot.ordinal - 1) * 2;
101
+ }
102
+ function stateForDerivedCell(cell) {
103
+ return cell?.outputArtifactId ? "stale" : "pending";
104
+ }
105
+ function branchRole(kind, ordinal) {
106
+ if (kind === "split-video")
107
+ return `split-video-${ordinal}`;
108
+ if (kind === "video")
109
+ return `scene-video-${ordinal}`;
110
+ if (kind === "first")
111
+ return `frame-first-${ordinal}`;
112
+ if (kind === "last")
113
+ return `frame-last-${ordinal}`;
114
+ if (kind === "extract-audio")
115
+ return `scene-extract-audio-${ordinal}`;
116
+ return `${kind}-${ordinal}`;
117
+ }
118
+ function sceneLabel(ordinal, suffix) {
119
+ return `Scene ${String(ordinal).padStart(2, "0")} ${suffix}`;
120
+ }
121
+ function matchesBranchChild(cell, kind) {
122
+ if (kind === "video")
123
+ return cell.type === "video";
124
+ if (kind === "first") {
125
+ return cell.type === "image" && cell.inputs?.frameRole === "first";
126
+ }
127
+ if (kind === "last") {
128
+ return cell.type === "image" && cell.inputs?.frameRole === "last";
129
+ }
130
+ if (kind === "extract-audio") {
131
+ return cell.type === "extract_audio"
132
+ || cell.inputs?.mediaRole === EXTRACT_AUDIO_OUTPUT_ROLE;
133
+ }
134
+ if (kind === "prompt")
135
+ return cell.type === "prompt";
136
+ return cell.type === "generate_video";
137
+ }
138
+ function existingBranchCell(document, analysisCellId, splitVideoCellId, kind, ordinal) {
139
+ const owned = document.cells.find((cell) => analysisOwnerId(cell) === analysisCellId
140
+ && splitVideoOwnerId(cell) === splitVideoCellId
141
+ && matchesBranchChild(cell, kind));
142
+ if (owned)
143
+ return owned;
144
+ return document.cells.find((cell) => analysisOwnerId(cell) === analysisCellId
145
+ && splitVideoOwnerId(cell) === null
146
+ && roleOf(cell) === branchRole(kind, ordinal)
147
+ && matchesBranchChild(cell, kind));
148
+ }
149
+ function existingBranchCells(document, analysisCellId, splitVideoCellId, ordinal) {
150
+ return {
151
+ video: existingBranchCell(document, analysisCellId, splitVideoCellId, "video", ordinal),
152
+ first: existingBranchCell(document, analysisCellId, splitVideoCellId, "first", ordinal),
153
+ last: existingBranchCell(document, analysisCellId, splitVideoCellId, "last", ordinal),
154
+ extractAudio: existingBranchCell(document, analysisCellId, splitVideoCellId, "extract-audio", ordinal),
155
+ prompt: existingBranchCell(document, analysisCellId, splitVideoCellId, "prompt", ordinal),
156
+ animate: existingBranchCell(document, analysisCellId, splitVideoCellId, "animate", ordinal),
157
+ };
158
+ }
159
+ function branchCellList(branch) {
160
+ return [
161
+ branch.splitVideo,
162
+ branch.video,
163
+ branch.first,
164
+ branch.last,
165
+ branch.extractAudio,
166
+ branch.prompt,
167
+ branch.animate,
168
+ ];
169
+ }
170
+ function slotKey(slot) {
171
+ return `${slot.row}:${slot.column}`;
172
+ }
173
+ function allocateBranchSlots(branch, retainedCellIds, occupiedSlots, sourceSlot) {
174
+ const created = branchCellList(branch).filter((cell) => !retainedCellIds.has(cell.id));
175
+ if (created.length === 0)
176
+ return branch;
177
+ const occupied = [...occupiedSlots].map((key) => {
178
+ const [row, column] = key.split(":").map(Number);
179
+ return { row: row, column: column };
180
+ });
181
+ const slotsByCellId = new Map();
182
+ let cursor = sourceSlot;
183
+ for (const cell of created) {
184
+ const slot = occupied.length === 0
185
+ ? firstEmptyNotebookGridSlots([], 1)[0]
186
+ : isVerticalGenerationType(cell.type)
187
+ ? nextVerticalSlotFrom(cursor ?? { row: 0, column: 0 }, occupied)
188
+ : nextHorizontalSlotFrom(cursor ?? { row: 0, column: 0 }, occupied);
189
+ slotsByCellId.set(cell.id, slot);
190
+ occupied.push(slot);
191
+ cursor = slot;
192
+ }
193
+ const allocate = (cell) => {
194
+ if (retainedCellIds.has(cell.id))
195
+ return cell;
196
+ return {
197
+ ...cell,
198
+ slot: slotsByCellId.get(cell.id),
199
+ };
200
+ };
201
+ const allocated = {
202
+ splitVideo: allocate(branch.splitVideo),
203
+ video: allocate(branch.video),
204
+ first: allocate(branch.first),
205
+ last: allocate(branch.last),
206
+ extractAudio: allocate(branch.extractAudio),
207
+ prompt: allocate(branch.prompt),
208
+ animate: allocate(branch.animate),
209
+ };
210
+ for (const cell of branchCellList(allocated)) {
211
+ occupiedSlots.add(slotKey(cell.slot));
212
+ }
213
+ return allocated;
214
+ }
215
+ function branchEdges(engine, source, analysis, assembly, branch, ordinal) {
216
+ const edges = [];
217
+ const add = (from, to, targetInput) => {
218
+ if (!from || !to)
219
+ return;
220
+ edges.push(engine.notebooks.createEdge({
221
+ source: from.id,
222
+ target: to.id,
223
+ targetInput,
224
+ }));
225
+ };
226
+ add(source, branch.splitVideo, "video");
227
+ add(analysis, branch.splitVideo, "analysis");
228
+ add(branch.splitVideo, branch.video, "media");
229
+ add(branch.video, branch.first, "segment");
230
+ add(branch.video, branch.last, "segment");
231
+ add(branch.video, branch.extractAudio, "segment");
232
+ add(analysis, branch.prompt, "analysis");
233
+ add(branch.first, branch.prompt, "first_frame");
234
+ add(branch.last, branch.prompt, "last_frame");
235
+ add(branch.extractAudio, branch.prompt, "scene_audio");
236
+ add(branch.prompt, branch.animate, "prompt");
237
+ add(branch.first, branch.animate, "first_frame");
238
+ add(branch.last, branch.animate, "last_frame");
239
+ add(branch.extractAudio, branch.animate, "replace_audio");
240
+ add(branch.animate, assembly, `clip:${ordinal - 1}`);
241
+ return edges;
242
+ }
243
+ function uniqueEdges(edges) {
244
+ const seen = new Set();
245
+ return edges.filter((edge) => {
246
+ const key = `${edge.source}:${edge.target}:${edge.targetInput}`;
247
+ if (seen.has(key))
248
+ return false;
249
+ seen.add(key);
250
+ return true;
251
+ });
252
+ }
253
+ function gridSlot(row, column) {
254
+ return { row, column };
255
+ }
256
+ function buildAnalysisScriptArtifact(input) {
257
+ const content = JSON.stringify({
258
+ version: 3,
259
+ request: input.request,
260
+ llmExchanges: input.llmExchanges ?? [],
261
+ raw: input.rawOutput,
262
+ shots: input.shots,
263
+ sourceDurationSeconds: input.sourceDurationSeconds,
264
+ evidence: input.evidence ?? null,
265
+ boundaries: input.boundaries ?? [],
266
+ normalizedAt: new Date().toISOString(),
267
+ }, null, 2);
268
+ const legacyAnalysis = {
269
+ scenes: input.shots.map((shot) => ({
270
+ title: shot.label,
271
+ timestamp: [shot.startSeconds, shot.endSeconds],
272
+ prompt: shot.prompt ?? "",
273
+ })),
274
+ };
275
+ return { content, legacyAnalysis };
276
+ }
277
+ function updateSplitVideoCell(engine, existing, analysisCellId, shot) {
278
+ const feature = featureForShot(shot);
279
+ const column = featureColumn(shot);
280
+ const base = existing ?? engine.notebooks.createCell({
281
+ type: "split_video",
282
+ label: sceneLabel(shot.ordinal, "split"),
283
+ slot: gridSlot(2, column),
284
+ });
285
+ return {
286
+ ...base,
287
+ type: "split_video",
288
+ label: base.label,
289
+ slot: base.slot,
290
+ provider: "local",
291
+ model: undefined,
292
+ operation: "split_range",
293
+ tool: "ffmpeg",
294
+ inputs: {
295
+ ...(base.inputs ?? {}),
296
+ analysisCellId,
297
+ workflowRole: branchRole("split-video", shot.ordinal),
298
+ startSeconds: shot.startSeconds,
299
+ endSeconds: shot.endSeconds,
300
+ ordinal: shot.ordinal,
301
+ label: shot.label,
302
+ featureId: feature?.id ?? `scene-${shot.ordinal}`,
303
+ featureLabel: feature?.label ?? shot.label,
304
+ state: stateForDerivedCell(existing),
305
+ },
306
+ };
307
+ }
308
+ function createBranchCells(engine, existing, analysisCellId, analysisPrompt, splitVideo, shot, shotCount) {
309
+ const feature = featureForShot(shot);
310
+ const column = featureColumn(shot);
311
+ const videoRow = 3 + (shot.ordinal - 1) * 3;
312
+ const extractionRow = videoRow + 1;
313
+ const promptRow = 3 + shotCount * 3;
314
+ const commonInputs = {
315
+ analysisCellId,
316
+ splitVideoCellId: splitVideo.id,
317
+ ordinal: shot.ordinal,
318
+ label: shot.label,
319
+ startSeconds: shot.startSeconds,
320
+ endSeconds: shot.endSeconds,
321
+ featureId: feature?.id ?? `scene-${shot.ordinal}`,
322
+ featureLabel: feature?.label ?? shot.label,
323
+ };
324
+ const videoExisting = existing.video;
325
+ const videoBase = videoExisting ?? engine.notebooks.createCell({
326
+ type: "video",
327
+ label: sceneLabel(shot.ordinal, "video"),
328
+ slot: gridSlot(videoRow, column),
329
+ });
330
+ const video = {
331
+ ...videoBase,
332
+ type: "video",
333
+ label: videoBase.label,
334
+ slot: videoBase.slot,
335
+ provider: undefined,
336
+ model: undefined,
337
+ operation: undefined,
338
+ tool: undefined,
339
+ inputs: {
340
+ ...(videoBase.inputs ?? {}),
341
+ ...commonInputs,
342
+ workflowRole: branchRole("video", shot.ordinal),
343
+ state: stateForDerivedCell(videoExisting),
344
+ },
345
+ };
346
+ const firstExisting = existing.first;
347
+ const firstBase = firstExisting ?? engine.notebooks.createCell({
348
+ type: "image",
349
+ label: sceneLabel(shot.ordinal, "first frame"),
350
+ slot: gridSlot(extractionRow, column - 1),
351
+ });
352
+ const first = {
353
+ ...firstBase,
354
+ type: "image",
355
+ label: firstBase.label,
356
+ slot: firstBase.slot,
357
+ provider: undefined,
358
+ model: undefined,
359
+ operation: undefined,
360
+ tool: undefined,
361
+ inputs: {
362
+ ...(firstBase.inputs ?? {}),
363
+ ...commonInputs,
364
+ workflowRole: branchRole("first", shot.ordinal),
365
+ frameRole: "first",
366
+ state: stateForDerivedCell(firstExisting),
367
+ },
368
+ };
369
+ const lastExisting = existing.last;
370
+ const lastBase = lastExisting ?? engine.notebooks.createCell({
371
+ type: "image",
372
+ label: sceneLabel(shot.ordinal, "last frame"),
373
+ slot: gridSlot(extractionRow, column),
374
+ });
375
+ const last = {
376
+ ...lastBase,
377
+ type: "image",
378
+ label: lastBase.label,
379
+ slot: lastBase.slot,
380
+ provider: undefined,
381
+ model: undefined,
382
+ operation: undefined,
383
+ tool: undefined,
384
+ inputs: {
385
+ ...(lastBase.inputs ?? {}),
386
+ ...commonInputs,
387
+ workflowRole: branchRole("last", shot.ordinal),
388
+ frameRole: "last",
389
+ state: stateForDerivedCell(lastExisting),
390
+ },
391
+ };
392
+ const extractAudioExisting = existing.extractAudio;
393
+ const extractAudioBase = extractAudioExisting
394
+ ?? engine.notebooks.createCell({
395
+ type: "audio",
396
+ label: sceneLabel(shot.ordinal, "audio extract"),
397
+ slot: gridSlot(extractionRow, column + 1),
398
+ });
399
+ const extractAudio = {
400
+ ...extractAudioBase,
401
+ type: "audio",
402
+ label: extractAudioBase.label,
403
+ slot: extractAudioBase.slot,
404
+ provider: undefined,
405
+ model: undefined,
406
+ operation: undefined,
407
+ tool: undefined,
408
+ inputs: {
409
+ ...(extractAudioBase.inputs ?? {}),
410
+ ...commonInputs,
411
+ workflowRole: branchRole("extract-audio", shot.ordinal),
412
+ mediaRole: EXTRACT_AUDIO_OUTPUT_ROLE,
413
+ audioRole: "scene",
414
+ state: stateForDerivedCell(extractAudioExisting),
415
+ },
416
+ };
417
+ const promptExisting = existing.prompt;
418
+ const promptBase = promptExisting ?? engine.notebooks.createCell({
419
+ type: "prompt",
420
+ label: sceneLabel(shot.ordinal, "prompt"),
421
+ slot: gridSlot(promptRow, column),
422
+ });
423
+ const promptBrief = feature?.promptBrief
424
+ ?? shot.prompt
425
+ ?? `Animate ${shot.label} while preserving the source subjects and composition.`;
426
+ const prompt = {
427
+ ...promptBase,
428
+ type: "prompt",
429
+ label: promptBase.label,
430
+ slot: promptBase.slot,
431
+ prompt: shot.prompt ?? promptExisting?.prompt ?? promptBrief,
432
+ provider: "openai",
433
+ model: INTELLIGENCE_MODEL,
434
+ operation: "rewrite_prompt",
435
+ tool: "rewrite_prompt",
436
+ inputs: {
437
+ ...(promptBase.inputs ?? {}),
438
+ ...commonInputs,
439
+ workflowRole: branchRole("prompt", shot.ordinal),
440
+ targetModel: "seedance25",
441
+ featureBrief: promptBrief,
442
+ analysisPrompt,
443
+ shotContext: {
444
+ title: shot.label,
445
+ startSeconds: shot.startSeconds,
446
+ endSeconds: shot.endSeconds,
447
+ durationSeconds: shot.endSeconds - shot.startSeconds,
448
+ },
449
+ audioContext: `Use the extracted ${shot.endSeconds - shot.startSeconds} second scene soundtrack for pacing and dialogue continuity.`,
450
+ requiresConfirmation: true,
451
+ state: stateForDerivedCell(promptExisting),
452
+ },
453
+ };
454
+ const animateExisting = existing.animate;
455
+ const animateBase = animateExisting ?? engine.notebooks.createCell({
456
+ type: "generate_video",
457
+ label: sceneLabel(shot.ordinal, "animation"),
458
+ slot: gridSlot(promptRow + 1, column),
459
+ });
460
+ const animate = {
461
+ ...animateBase,
462
+ type: "generate_video",
463
+ label: animateBase.label,
464
+ slot: animateBase.slot,
465
+ prompt: "",
466
+ provider: "kie",
467
+ model: DEFAULT_ANIMATION_MODEL,
468
+ operation: "image_to_video",
469
+ tool: "generate_video",
470
+ inputs: {
471
+ ...(animateBase.inputs ?? {}),
472
+ ...commonInputs,
473
+ workflowRole: branchRole("animate", shot.ordinal),
474
+ generationMode: "i2v",
475
+ generationSettings: {
476
+ duration: 15,
477
+ resolution: "720p",
478
+ aspect_ratio: "16:9",
479
+ generate_audio: false,
480
+ },
481
+ requiresConfirmation: true,
482
+ state: stateForDerivedCell(animateExisting),
483
+ },
484
+ };
485
+ return {
486
+ splitVideo,
487
+ video,
488
+ first,
489
+ last,
490
+ extractAudio,
491
+ prompt,
492
+ animate,
493
+ };
494
+ }
495
+ export async function applyAnalysisResults(engine, document, analysisCellId, input) {
496
+ const storedAnalysisCell = document.cells.find((cell) => cell.id === analysisCellId);
497
+ if (!storedAnalysisCell) {
498
+ throw new Error(`Analysis cell not found: ${analysisCellId}`);
499
+ }
500
+ const analysisCell = normalizeLegacyAnalyzeCell(storedAnalysisCell);
501
+ const resultCell = analysisOutputCell(document, analysisCellId);
502
+ const shots = normalizeShots(parseAnalysisShots(input.rawOutput), input.sourceDurationSeconds);
503
+ const script = buildAnalysisScriptArtifact({
504
+ request: input.request,
505
+ llmExchanges: input.llmExchanges,
506
+ rawOutput: input.rawOutput,
507
+ shots,
508
+ sourceDurationSeconds: input.sourceDurationSeconds,
509
+ ...(input.evidence ? { evidence: input.evidence } : {}),
510
+ ...(input.boundaries ? { boundaries: input.boundaries } : {}),
511
+ });
512
+ const scriptArtifact = await engine.artifacts.create({
513
+ kind: "script",
514
+ label: `${analysisCell.label ?? notebookGridTag(analysisCell.slot)} analysis`,
515
+ });
516
+ if (!scriptArtifact.ok)
517
+ throw new Error(scriptArtifact.error.message);
518
+ const written = await engine.files.write(scriptArtifact.value.artifactId, "analysis.json", script.content);
519
+ if (!written.ok)
520
+ throw new Error(written.error.message);
521
+ const metadata = await engine.metadata.artifacts.write(scriptArtifact.value.artifactId, "original", {
522
+ duration: input.sourceDurationSeconds,
523
+ analysisInfo: {
524
+ sourceDurationSeconds: input.sourceDurationSeconds,
525
+ shots,
526
+ boundaries: input.boundaries ?? [],
527
+ },
528
+ });
529
+ if (!metadata.ok)
530
+ throw new Error(metadata.error.message);
531
+ if (input.sourceArtifactId) {
532
+ await engine.files.write(input.sourceArtifactId, ".original.analysis.json", JSON.stringify(script.legacyAnalysis));
533
+ }
534
+ const updatedAnalysis = {
535
+ ...analysisCell,
536
+ outputArtifactId: scriptArtifact.value.artifactId,
537
+ provider: analysisCell.provider ?? "openai",
538
+ model: analysisCell.model ?? INTELLIGENCE_MODEL,
539
+ operation: analysisCell.operation ?? "analyze_source",
540
+ tool: analysisCell.tool ?? OPENAI_ANALYSIS_TOOL,
541
+ inputs: {
542
+ ...(analysisCell.inputs ?? {}),
543
+ shotCount: shots.length,
544
+ sourceDurationSeconds: input.sourceDurationSeconds,
545
+ state: "completed",
546
+ },
547
+ };
548
+ const updatedResult = {
549
+ ...resultCell,
550
+ outputArtifactId: scriptArtifact.value.artifactId,
551
+ inputs: {
552
+ ...(resultCell.inputs ?? {}),
553
+ analysisRole: "result",
554
+ producerCellId: analysisCellId,
555
+ shotCount: shots.length,
556
+ sourceDurationSeconds: input.sourceDurationSeconds,
557
+ outputVersionArtifactIds: outputVersionArtifactIds(resultCell, scriptArtifact.value.artifactId),
558
+ state: "completed",
559
+ },
560
+ };
561
+ if (!input.materializeWorkflow) {
562
+ const persisted = {
563
+ ...document,
564
+ cells: document.cells.map((cell) => cell.id === analysisCellId
565
+ ? updatedAnalysis
566
+ : cell.id === resultCell.id
567
+ ? updatedResult
568
+ : cell),
569
+ analysisRevision: scriptArtifact.value.artifactId,
570
+ };
571
+ return persisted;
572
+ }
573
+ const owned = document.cells.filter((cell) => analysisOwnerId(cell) === analysisCellId);
574
+ const ownedSplitVideos = owned.filter((cell) => cell.type === "split_video"
575
+ && cell.operation === "split_range");
576
+ const branches = ownedSplitVideos.map((cell) => ({
577
+ cellId: cell.id,
578
+ range: {
579
+ startSeconds: Number(cell.inputs?.startSeconds ?? 0),
580
+ endSeconds: Number(cell.inputs?.endSeconds ?? 0),
581
+ },
582
+ config: cell.inputs ?? {},
583
+ }));
584
+ const reconciliation = reconcileOwnedBranches(branches, shots);
585
+ const keptSplitIds = new Set(reconciliation.keep.map((entry) => entry.existing.cellId));
586
+ const removedSplitIds = new Set(reconciliation.remove.map((entry) => entry.cellId));
587
+ const removedCellIds = new Set(owned
588
+ .filter((cell) => removedSplitIds.has(cell.id)
589
+ || (splitVideoOwnerId(cell) !== null
590
+ && removedSplitIds.has(splitVideoOwnerId(cell))))
591
+ .map((cell) => cell.id));
592
+ const baseCells = document.cells.filter((cell) => {
593
+ if (removedCellIds.has(cell.id))
594
+ return false;
595
+ if (cell.operation === "split_range" && analysisOwnerId(cell) === analysisCellId) {
596
+ return keptSplitIds.has(cell.id);
597
+ }
598
+ return true;
599
+ });
600
+ const cellsWithoutOwnedBranches = baseCells.filter((cell) => cell.id !== analysisCellId
601
+ && cell.id !== resultCell.id
602
+ && analysisOwnerId(cell) !== analysisCellId);
603
+ const sourceCell = document.cells.find((cell) => roleOf(cell) === "source")
604
+ ?? document.cells.find((cell) => cell.type === "video");
605
+ const assemblyCell = document.cells.find((cell) => roleOf(cell) === "assembly")
606
+ ?? document.cells.find((cell) => cell.operation === "concat_video");
607
+ const branchCells = [];
608
+ const canonicalEdges = [];
609
+ const retainedCellIds = new Set(baseCells.map((cell) => cell.id));
610
+ const occupiedSlots = new Set(baseCells.map((cell) => slotKey(cell.slot)));
611
+ for (const shot of shots) {
612
+ const kept = reconciliation.keep.find((entry) => entry.shot.ordinal === shot.ordinal);
613
+ const existingSplit = kept
614
+ ? document.cells.find((cell) => cell.id === kept.existing.cellId)
615
+ : undefined;
616
+ const previousOrdinal = Number(existingSplit?.inputs?.ordinal);
617
+ const legacyOrdinal = Number.isInteger(previousOrdinal) && previousOrdinal > 0
618
+ ? previousOrdinal
619
+ : shot.ordinal;
620
+ const splitVideo = updateSplitVideoCell(engine, existingSplit, analysisCellId, shot);
621
+ const provisionalBranch = createBranchCells(engine, existingSplit
622
+ ? existingBranchCells(document, analysisCellId, existingSplit.id, legacyOrdinal)
623
+ : {}, analysisCellId, analysisCell.prompt ?? "", splitVideo, shot, shots.length);
624
+ const branch = allocateBranchSlots(provisionalBranch, retainedCellIds, occupiedSlots, sourceCell?.slot ?? lastCreatedCellSlot(baseCells));
625
+ branchCells.push(...branchCellList(branch));
626
+ canonicalEdges.push(...branchEdges(engine, sourceCell, updatedResult, assemblyCell, branch, shot.ordinal));
627
+ }
628
+ const canonicalCellIds = new Set([
629
+ ...owned.map((cell) => cell.id),
630
+ ...branchCells.map((cell) => cell.id),
631
+ ]);
632
+ const canonicalTargetInputs = new Set([
633
+ "source",
634
+ "video",
635
+ "analysis",
636
+ "media",
637
+ "segment",
638
+ "first_frame",
639
+ "last_frame",
640
+ "scene_audio",
641
+ "replace_audio",
642
+ "prompt",
643
+ ]);
644
+ const retainedEdges = document.edges.filter((edge) => {
645
+ if (removedCellIds.has(edge.source) || removedCellIds.has(edge.target)) {
646
+ return false;
647
+ }
648
+ if (canonicalCellIds.has(edge.target)
649
+ && canonicalTargetInputs.has(edge.targetInput)) {
650
+ return false;
651
+ }
652
+ if (canonicalCellIds.has(edge.source)
653
+ && (edge.target === assemblyCell?.id
654
+ || canonicalCellIds.has(edge.target))) {
655
+ return false;
656
+ }
657
+ return true;
658
+ });
659
+ const cells = [
660
+ updatedAnalysis,
661
+ updatedResult,
662
+ ...cellsWithoutOwnedBranches,
663
+ ...branchCells,
664
+ ];
665
+ const edges = uniqueEdges([...retainedEdges, ...canonicalEdges]);
666
+ const next = {
667
+ ...document,
668
+ cells,
669
+ edges,
670
+ workflowVersion: 7,
671
+ analysisRevision: scriptArtifact.value.artifactId,
672
+ };
673
+ return {
674
+ ...next,
675
+ cells: next.cells.map((cell) => normalizeCellActionFields(cell, next)),
676
+ };
677
+ }
678
+ function baseCell(engine, existing, input) {
679
+ const created = existing ?? engine.notebooks.createCell(input);
680
+ return {
681
+ ...created,
682
+ ...input,
683
+ id: created.id,
684
+ inputs: {
685
+ ...(created.inputs ?? {}),
686
+ ...(input.inputs ?? {}),
687
+ },
688
+ };
689
+ }
690
+ export function buildSevenStageScaffold(engine, document, sourceArtifactId) {
691
+ const roleCells = new Map();
692
+ for (const cell of document.cells) {
693
+ const role = roleOf(cell);
694
+ if (role && !roleCells.has(role))
695
+ roleCells.set(role, cell);
696
+ }
697
+ const occupiedSlots = notebookOccupiedSlots(document.cells);
698
+ let lastWork = lastCreatedCellSlot(document.cells);
699
+ const scaffoldSlot = (role) => {
700
+ const existing = roleCells.get(role);
701
+ if (existing)
702
+ return existing.slot;
703
+ const slot = occupiedSlots.length === 0
704
+ ? firstEmptyNotebookGridSlots([], 1)[0]
705
+ : nextHorizontalSlotFrom(lastWork ?? { row: 0, column: 0 }, occupiedSlots);
706
+ occupiedSlots.push(slot);
707
+ lastWork = slot;
708
+ return slot;
709
+ };
710
+ const source = baseCell(engine, roleCells.get("source"), {
711
+ type: "video",
712
+ label: "Source video",
713
+ slot: scaffoldSlot("source"),
714
+ provider: undefined,
715
+ operation: undefined,
716
+ tool: undefined,
717
+ ...(sourceArtifactId ? { outputArtifactId: sourceArtifactId } : {}),
718
+ inputs: {
719
+ workflowRole: "source",
720
+ state: sourceArtifactId ? "completed" : "pending",
721
+ },
722
+ });
723
+ const analysis = baseCell(engine, roleCells.get("analysis"), {
724
+ type: "analyze",
725
+ label: "Analyze source",
726
+ slot: scaffoldSlot("analysis"),
727
+ prompt: retainedAnalysisPrompt(roleCells.get("analysis")),
728
+ provider: "openai",
729
+ model: INTELLIGENCE_MODEL,
730
+ operation: "analyze_source",
731
+ tool: OPENAI_ANALYSIS_TOOL,
732
+ inputs: { workflowRole: "analysis", state: "pending" },
733
+ });
734
+ const analysisOutput = baseCell(engine, roleCells.get("analysis-output"), {
735
+ type: "analysis",
736
+ label: "Analysis result",
737
+ slot: scaffoldSlot("analysis-output"),
738
+ provider: undefined,
739
+ model: undefined,
740
+ operation: undefined,
741
+ tool: undefined,
742
+ inputs: {
743
+ workflowRole: "analysis-output",
744
+ analysisRole: "result",
745
+ producerCellId: analysis.id,
746
+ state: "pending",
747
+ },
748
+ });
749
+ const extractAudio = baseCell(engine, roleCells.get("source-extract-audio"), {
750
+ type: "audio",
751
+ label: "Source audio extract",
752
+ slot: scaffoldSlot("source-extract-audio"),
753
+ provider: undefined,
754
+ operation: undefined,
755
+ tool: undefined,
756
+ inputs: {
757
+ workflowRole: "source-extract-audio",
758
+ mediaRole: EXTRACT_AUDIO_OUTPUT_ROLE,
759
+ audioRole: "continuous-source",
760
+ state: "pending",
761
+ },
762
+ });
763
+ const assembly = baseCell(engine, roleCells.get("assembly"), {
764
+ type: "concat",
765
+ label: "Feature edit concat",
766
+ slot: scaffoldSlot("assembly"),
767
+ provider: "local",
768
+ operation: "concat_video",
769
+ tool: "ffmpeg",
770
+ inputs: {
771
+ workflowRole: "assembly",
772
+ captions: MULTYCULTY_FEATURES.map((feature) => feature.caption),
773
+ state: "pending",
774
+ },
775
+ });
776
+ const baseRoles = new Set([
777
+ "source",
778
+ "analysis",
779
+ "analysis-output",
780
+ "source-extract-audio",
781
+ "assembly",
782
+ ]);
783
+ const retiredRoles = new Set([
784
+ "source-audio",
785
+ ...MULTYCULTY_FEATURES.map((feature) => `label-${feature.ordinal}`),
786
+ ]);
787
+ const otherCells = document.cells.filter((cell) => {
788
+ const role = roleOf(cell);
789
+ return !role || (!baseRoles.has(role) && !retiredRoles.has(role));
790
+ });
791
+ const cells = [
792
+ source,
793
+ analysis,
794
+ analysisOutput,
795
+ extractAudio,
796
+ assembly,
797
+ ...otherCells,
798
+ ];
799
+ const baseIds = new Set([
800
+ source.id,
801
+ analysis.id,
802
+ analysisOutput.id,
803
+ extractAudio.id,
804
+ assembly.id,
805
+ ]);
806
+ const retainedEdges = document.edges.filter((edge) => {
807
+ if (!baseIds.has(edge.target))
808
+ return true;
809
+ if (edge.target === analysis.id && edge.targetInput === "source")
810
+ return false;
811
+ if (edge.target === analysisOutput.id
812
+ && edge.targetInput === "result") {
813
+ return false;
814
+ }
815
+ if (edge.target === extractAudio.id
816
+ && (edge.targetInput === "video" || edge.targetInput === "segment")) {
817
+ return false;
818
+ }
819
+ if (edge.target === assembly.id && edge.targetInput === "audio")
820
+ return false;
821
+ return true;
822
+ });
823
+ const edges = uniqueEdges([
824
+ ...retainedEdges,
825
+ engine.notebooks.createEdge({
826
+ source: source.id,
827
+ target: analysis.id,
828
+ targetInput: "source",
829
+ }),
830
+ engine.notebooks.createEdge({
831
+ source: analysis.id,
832
+ target: analysisOutput.id,
833
+ targetInput: "result",
834
+ }),
835
+ engine.notebooks.createEdge({
836
+ source: source.id,
837
+ target: extractAudio.id,
838
+ targetInput: "segment",
839
+ }),
840
+ engine.notebooks.createEdge({
841
+ source: extractAudio.id,
842
+ target: assembly.id,
843
+ targetInput: "audio",
844
+ }),
845
+ ]);
846
+ const next = {
847
+ ...document,
848
+ cells,
849
+ edges,
850
+ workflowVersion: 7,
851
+ };
852
+ return {
853
+ ...next,
854
+ cells: next.cells.map((cell) => normalizeCellActionFields(cell, next)),
855
+ };
856
+ }