videobook 0.0.0-stage → 0.2.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 (565) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/LICENSE +21 -0
  3. package/README.md +195 -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 +242 -0
  45. package/dist/cli/config-command.js +103 -0
  46. package/dist/cli/doctor-command.js +289 -0
  47. package/dist/cli/entry.js +2 -0
  48. package/dist/cli/key-report.js +16 -0
  49. package/dist/cli/main.js +104 -0
  50. package/dist/cli/mcp-command.js +88 -0
  51. package/dist/cli/mcp-relay.js +51 -0
  52. package/dist/cli/open-browser.js +14 -0
  53. package/dist/cli/run-command.js +231 -0
  54. package/dist/cli/serve-command.js +62 -0
  55. package/dist/cli/setup-command.js +60 -0
  56. package/dist/cli/stdio-guard.js +8 -0
  57. package/dist/cold-open-model.js +7 -0
  58. package/dist/cold-open.js +79 -0
  59. package/dist/command-reference.js +95 -0
  60. package/dist/content-store.js +74 -0
  61. package/dist/cost.js +8 -0
  62. package/dist/crop-geometry.js +23 -0
  63. package/dist/dancing-workflow.js +447 -0
  64. package/dist/data-home.js +44 -0
  65. package/dist/diagnostics.js +109 -0
  66. package/dist/dialog-quality.js +34 -0
  67. package/dist/downloads-dest.js +56 -0
  68. package/dist/editing-moments.js +194 -0
  69. package/dist/elevenlabs-audio-extension.js +66 -0
  70. package/dist/engine.js +54 -0
  71. package/dist/env-file.js +91 -0
  72. package/dist/env-secrets.js +148 -0
  73. package/dist/ffmpeg-binary.js +12 -0
  74. package/dist/ffmpeg.js +425 -0
  75. package/dist/ffprobe-binary.js +77 -0
  76. package/dist/forget-asset.js +216 -0
  77. package/dist/frame-utils.js +27 -0
  78. package/dist/generation-credit-error.js +11 -0
  79. package/dist/generation-input-mentions.js +117 -0
  80. package/dist/generation-input-policy.js +68 -0
  81. package/dist/generation-reference-mentions.js +97 -0
  82. package/dist/goal-characters.js +49 -0
  83. package/dist/goal-plan-v3.js +273 -0
  84. package/dist/goal-plan.js +220 -0
  85. package/dist/goal-planner-prompt.js +28 -0
  86. package/dist/goal-prompt-budget.js +4 -0
  87. package/dist/goal-reference-images.js +25 -0
  88. package/dist/goal-state.js +261 -0
  89. package/dist/goal-stills.js +153 -0
  90. package/dist/goal-store.js +144 -0
  91. package/dist/goal-styles.js +144 -0
  92. package/dist/goal-v3-runtime.js +157 -0
  93. package/dist/guides/character_schema_guide.md +70 -0
  94. package/dist/guides/gpt_image_2_5_prompting_guide.md +21 -0
  95. package/dist/guides/grok_imagine_prompting_guide.md +72 -0
  96. package/dist/guides/image_reproduction_guide.md +84 -0
  97. package/dist/guides/kling_3_0_prompting_guide.md +136 -0
  98. package/dist/guides/nano_banana_pro_prompting_guide.md +28 -0
  99. package/dist/guides/seedance_2_prompting_guide.md +172 -0
  100. package/dist/http-access.js +49 -0
  101. package/dist/http-byte-range.js +31 -0
  102. package/dist/hydration.js +56 -0
  103. package/dist/image-compress.js +77 -0
  104. package/dist/image-edit-default.js +1 -0
  105. package/dist/image-edit-models.js +41 -0
  106. package/dist/image-edit-settings.js +11 -0
  107. package/dist/image-region-edit.js +32 -0
  108. package/dist/image-subject-map.js +523 -0
  109. package/dist/image.js +46 -0
  110. package/dist/index.js +12 -0
  111. package/dist/job-deadline.js +60 -0
  112. package/dist/jobs/_alibaba-upload.js +30 -0
  113. package/dist/jobs/_audio-chunks.js +31 -0
  114. package/dist/jobs/_download-into-asset.js +15 -0
  115. package/dist/jobs/_fal-shared.js +22 -0
  116. package/dist/jobs/_fal-upload.js +35 -0
  117. package/dist/jobs/_image-edit-adapter.js +213 -0
  118. package/dist/jobs/_kie-poll.js +119 -0
  119. package/dist/jobs/_kie-upload.js +32 -0
  120. package/dist/jobs/_lease.js +163 -0
  121. package/dist/jobs/_persist-output.js +19 -0
  122. package/dist/jobs/_storage-retry.js +21 -0
  123. package/dist/jobs/_transcribe.js +245 -0
  124. package/dist/jobs/_translate-transcript.js +270 -0
  125. package/dist/jobs/analyze-alive-captions.js +10 -0
  126. package/dist/jobs/analyze-editing-moments.js +104 -0
  127. package/dist/jobs/analyze-jokes.js +143 -0
  128. package/dist/jobs/analyze-keyword-placement.js +155 -0
  129. package/dist/jobs/analyze-music.js +14 -0
  130. package/dist/jobs/analyze-video.js +282 -0
  131. package/dist/jobs/apply-cuts.js +83 -0
  132. package/dist/jobs/apply-sfx.js +107 -0
  133. package/dist/jobs/archive-clip.js +458 -0
  134. package/dist/jobs/assemble-goal.js +98 -0
  135. package/dist/jobs/audio-boost.js +71 -0
  136. package/dist/jobs/audio-mix.js +161 -0
  137. package/dist/jobs/backfill-asset-tags.js +144 -0
  138. package/dist/jobs/burn-watermark.js +316 -0
  139. package/dist/jobs/change-video-speed.js +176 -0
  140. package/dist/jobs/clean-video-audio.js +207 -0
  141. package/dist/jobs/cold-open.js +166 -0
  142. package/dist/jobs/combine-goal.js +108 -0
  143. package/dist/jobs/complete-provider-task.js +185 -0
  144. package/dist/jobs/copy-library-asset.js +33 -0
  145. package/dist/jobs/cost-estimate-assessment.js +113 -0
  146. package/dist/jobs/crop-image.js +47 -0
  147. package/dist/jobs/crop-video.js +71 -0
  148. package/dist/jobs/describe-image.js +181 -0
  149. package/dist/jobs/detect-scenes.js +33 -0
  150. package/dist/jobs/doctor-fix.js +100 -0
  151. package/dist/jobs/download-video.js +427 -0
  152. package/dist/jobs/enqueue-search-index.js +24 -0
  153. package/dist/jobs/even-split.js +122 -0
  154. package/dist/jobs/export-sequence.js +365 -0
  155. package/dist/jobs/extend-audio.js +229 -0
  156. package/dist/jobs/extract-audio.js +72 -0
  157. package/dist/jobs/extract-frame.js +58 -0
  158. package/dist/jobs/extract-notebook-audio.js +82 -0
  159. package/dist/jobs/extract-notebook-frame.js +93 -0
  160. package/dist/jobs/extract-video-clip.js +8 -0
  161. package/dist/jobs/extract-video-poster.js +55 -0
  162. package/dist/jobs/extract-waveform.js +25 -0
  163. package/dist/jobs/finish-goal.js +255 -0
  164. package/dist/jobs/forget-asset.js +11 -0
  165. package/dist/jobs/generate-acestep-cover.js +219 -0
  166. package/dist/jobs/generate-media.js +70 -0
  167. package/dist/jobs/image-subjects.js +1059 -0
  168. package/dist/jobs/index.js +18 -0
  169. package/dist/jobs/inject-first-frame.js +175 -0
  170. package/dist/jobs/isolate-vocals.js +69 -0
  171. package/dist/jobs/kie-paygate.js +177 -0
  172. package/dist/jobs/label-music-sections.js +5 -0
  173. package/dist/jobs/osg-placement.js +135 -0
  174. package/dist/jobs/pad-video.js +72 -0
  175. package/dist/jobs/plan-goal.js +97 -0
  176. package/dist/jobs/post-record.js +21 -0
  177. package/dist/jobs/post-to-x.js +21 -0
  178. package/dist/jobs/prepare-search-reference.js +190 -0
  179. package/dist/jobs/prepare-temporal-search.js +16 -0
  180. package/dist/jobs/process-audio.js +67 -0
  181. package/dist/jobs/process-image.js +58 -0
  182. package/dist/jobs/process-upload.js +166 -0
  183. package/dist/jobs/process-video.js +438 -0
  184. package/dist/jobs/register-all.js +161 -0
  185. package/dist/jobs/relayout-notebook.js +78 -0
  186. package/dist/jobs/remove-sound.js +299 -0
  187. package/dist/jobs/render-project.js +380 -0
  188. package/dist/jobs/render-qr-outro.js +138 -0
  189. package/dist/jobs/render-timeline.js +283 -0
  190. package/dist/jobs/repair-search-indexes.js +42 -0
  191. package/dist/jobs/replace-video-audio.js +64 -0
  192. package/dist/jobs/restore-archive-clip.js +53 -0
  193. package/dist/jobs/reverse-video.js +53 -0
  194. package/dist/jobs/rewrite-script.js +173 -0
  195. package/dist/jobs/run-notebook.js +3335 -0
  196. package/dist/jobs/semantic-index.js +797 -0
  197. package/dist/jobs/smooth-scene-concat.js +257 -0
  198. package/dist/jobs/splice-video.js +280 -0
  199. package/dist/jobs/split-video.js +127 -0
  200. package/dist/jobs/suggest-cuts.js +149 -0
  201. package/dist/jobs/suggest-sfx.js +135 -0
  202. package/dist/jobs/sync-video-to-audio.js +329 -0
  203. package/dist/jobs/tag-asset.js +266 -0
  204. package/dist/jobs/task-failure.js +16 -0
  205. package/dist/jobs/timewarp-video.js +152 -0
  206. package/dist/jobs/transcribe-video-audio.js +117 -0
  207. package/dist/jobs/transcribe.js +35 -0
  208. package/dist/jobs/translate-transcript.js +55 -0
  209. package/dist/jobs/trim-audio.js +133 -0
  210. package/dist/jobs/trim-video.js +291 -0
  211. package/dist/jobs/xai-paygate.js +26 -0
  212. package/dist/keyword-placement-cache.js +74 -0
  213. package/dist/lazy-render.js +142 -0
  214. package/dist/library-browse.js +78 -0
  215. package/dist/lightning-defaults.js +206 -0
  216. package/dist/load-env.js +12 -0
  217. package/dist/local-search-models.js +206 -0
  218. package/dist/local-upload.js +318 -0
  219. package/dist/logger.js +69 -0
  220. package/dist/media/adapters/alibaba.js +20 -0
  221. package/dist/media/adapters/elevenlabs.js +58 -0
  222. package/dist/media/adapters/fal.js +45 -0
  223. package/dist/media/adapters/index.js +26 -0
  224. package/dist/media/adapters/kie.js +120 -0
  225. package/dist/media/adapters/pending.js +21 -0
  226. package/dist/media/adapters/types.js +5 -0
  227. package/dist/media/adapters/xai.js +18 -0
  228. package/dist/media/catalog.js +236 -0
  229. package/dist/media/complete.js +191 -0
  230. package/dist/media/cost.js +45 -0
  231. package/dist/media/descriptor.js +157 -0
  232. package/dist/media/endpoints.js +11 -0
  233. package/dist/media/frame-options.js +18 -0
  234. package/dist/media/insert-video-timing.js +17 -0
  235. package/dist/media/json-schema.js +75 -0
  236. package/dist/media/legacy-task-types.js +129 -0
  237. package/dist/media/listing.js +24 -0
  238. package/dist/media/model-id.js +14 -0
  239. package/dist/media/preview.js +86 -0
  240. package/dist/media/prompt-dialects.js +65 -0
  241. package/dist/media/ref-fields.js +106 -0
  242. package/dist/media/refs.js +131 -0
  243. package/dist/media/request.js +188 -0
  244. package/dist/media/types.js +6 -0
  245. package/dist/media/wire.js +161 -0
  246. package/dist/media-library.js +535 -0
  247. package/dist/media-output-path.js +33 -0
  248. package/dist/multyculty-workflow.js +757 -0
  249. package/dist/notebook-action-catalog.js +608 -0
  250. package/dist/notebook-cell-outputs.js +726 -0
  251. package/dist/notebook-credit-retry.js +45 -0
  252. package/dist/notebook-fixtures.js +8 -0
  253. package/dist/notebook-generation-contract.js +77 -0
  254. package/dist/notebook-generation-controls.js +145 -0
  255. package/dist/notebook-goal-layout.js +40 -0
  256. package/dist/notebook-graph.js +37 -0
  257. package/dist/notebook-image-edit.js +84 -0
  258. package/dist/notebook-initial-generation-prompt.js +222 -0
  259. package/dist/notebook-live-analysis.js +941 -0
  260. package/dist/notebook-media-ops.js +579 -0
  261. package/dist/notebook-mutations.js +20 -0
  262. package/dist/notebook-placement.js +41 -0
  263. package/dist/notebook-provider-failure.js +87 -0
  264. package/dist/notebook-published-post.js +26 -0
  265. package/dist/notebook-reference-resolver.js +227 -0
  266. package/dist/notebook-relayout.js +270 -0
  267. package/dist/notebook-run-plan.js +519 -0
  268. package/dist/notebook-shots.js +162 -0
  269. package/dist/notebook-workflow.js +856 -0
  270. package/dist/one-password.js +200 -0
  271. package/dist/openai-intelligence.js +99 -0
  272. package/dist/original-media-file.js +12 -0
  273. package/dist/osg-assets.js +36 -0
  274. package/dist/osg-placement-cache.js +64 -0
  275. package/dist/osg-settings.js +27 -0
  276. package/dist/paid-tools.js +22 -0
  277. package/dist/platform-guidance.js +26 -0
  278. package/dist/posts/dropbox-auth.js +91 -0
  279. package/dist/posts/dropbox-upload.js +132 -0
  280. package/dist/posts/icloud-drive.js +134 -0
  281. package/dist/posts/icloud-status.js +64 -0
  282. package/dist/posts/post-contract.js +2 -0
  283. package/dist/posts/post-copy-format.js +43 -0
  284. package/dist/posts/post-copy.js +193 -0
  285. package/dist/posts/post-folder.js +18 -0
  286. package/dist/posts/post-metrics.js +119 -0
  287. package/dist/posts/post-store.js +340 -0
  288. package/dist/posts/x-post-target.js +43 -0
  289. package/dist/preview-payload.js +90 -0
  290. package/dist/prompt-surfaces.js +22 -0
  291. package/dist/provider-prompt-transform.js +77 -0
  292. package/dist/provider-status-link.js +21 -0
  293. package/dist/provider-task-record.js +78 -0
  294. package/dist/provider-task-status.js +47 -0
  295. package/dist/provider-usage.js +294 -0
  296. package/dist/queue.js +810 -0
  297. package/dist/reference-video-duration.js +17 -0
  298. package/dist/remotion/BlurFillVideo.js +51 -0
  299. package/dist/remotion/KeywordGraphicsOverlay.js +68 -0
  300. package/dist/remotion/OsgOverlay.js +30 -0
  301. package/dist/remotion/QrOutroComposition.js +47 -0
  302. package/dist/remotion/RenderComposition.js +11 -0
  303. package/dist/remotion/browser.js +59 -0
  304. package/dist/remotion/constants.js +35 -0
  305. package/dist/remotion/index.js +66 -0
  306. package/dist/remotion/keyword-graphics.js +151 -0
  307. package/dist/remotion/keyword-placement.js +182 -0
  308. package/dist/remotion/osg-spec.js +198 -0
  309. package/dist/remotion/public/qr-outro-impact.wav +0 -0
  310. package/dist/remotion/qr-outro-audio.js +1 -0
  311. package/dist/remotion/qr-outro-spec.js +211 -0
  312. package/dist/remotion/shared-bundle.js +37 -0
  313. package/dist/remotion/subtitles/AliveCaptions.js +83 -0
  314. package/dist/remotion/subtitles/Highlight.js +58 -0
  315. package/dist/remotion/subtitles/Impact.js +67 -0
  316. package/dist/remotion/subtitles/SubtitleOverlay.js +9 -0
  317. package/dist/remotion/subtitles/alive-layout.js +321 -0
  318. package/dist/remotion/subtitles/alive-types.js +17 -0
  319. package/dist/remotion/subtitles/chunker.js +68 -0
  320. package/dist/remotion/subtitles/segments.js +42 -0
  321. package/dist/remotion/subtitles/styles.js +4 -0
  322. package/dist/remotion/subtitles/types.js +1 -0
  323. package/dist/remotion/util.js +18 -0
  324. package/dist/remotion-cancellation.js +15 -0
  325. package/dist/rename-helpers.js +204 -0
  326. package/dist/rhythm/analyze.js +128 -0
  327. package/dist/rhythm/contract.js +14 -0
  328. package/dist/rhythm/draft-model.js +19 -0
  329. package/dist/rhythm/energy.js +133 -0
  330. package/dist/rhythm/fft.js +44 -0
  331. package/dist/rhythm/model.js +71 -0
  332. package/dist/rhythm/music-analysis.js +124 -0
  333. package/dist/rhythm/music-draft.js +261 -0
  334. package/dist/rhythm/onset.js +101 -0
  335. package/dist/rhythm/run-worker.js +51 -0
  336. package/dist/rhythm/score.js +47 -0
  337. package/dist/rhythm/section-labels.js +168 -0
  338. package/dist/rhythm/sequence-rhythm.js +67 -0
  339. package/dist/rhythm/synthesize.js +103 -0
  340. package/dist/rhythm/timing.js +98 -0
  341. package/dist/rhythm/track.js +320 -0
  342. package/dist/rhythm/visual-fit.js +4 -0
  343. package/dist/rhythm/worker.js +25 -0
  344. package/dist/scene-detect.js +200 -0
  345. package/dist/scene-transition.js +12 -0
  346. package/dist/scheduled-posts.js +200 -0
  347. package/dist/search-index-coverage.js +13 -0
  348. package/dist/search-index-media.js +71 -0
  349. package/dist/search-reference-store.js +60 -0
  350. package/dist/search-scoring.js +17 -0
  351. package/dist/serve.js +125 -0
  352. package/dist/server-lock.js +143 -0
  353. package/dist/server.js +42 -0
  354. package/dist/srt.js +16 -0
  355. package/dist/tag-backfill-state.js +121 -0
  356. package/dist/tag-settings.js +30 -0
  357. package/dist/tag-vocabulary.js +237 -0
  358. package/dist/test-queue-cleanup.js +1 -0
  359. package/dist/time-parse.js +50 -0
  360. package/dist/timeline-helpers.js +554 -0
  361. package/dist/timewarp.js +87 -0
  362. package/dist/tools/_image-inputs.js +9 -0
  363. package/dist/tools/_media-refs.js +84 -0
  364. package/dist/tools/_shared.js +59 -0
  365. package/dist/tools/_suggest-shared.js +279 -0
  366. package/dist/tools/add-timeline-audio.js +73 -0
  367. package/dist/tools/alive-captions.js +157 -0
  368. package/dist/tools/analyze-jokes.js +56 -0
  369. package/dist/tools/analyze-video.js +66 -0
  370. package/dist/tools/animate-keywords.js +217 -0
  371. package/dist/tools/api-status.js +42 -0
  372. package/dist/tools/application-commands.js +34 -0
  373. package/dist/tools/apply-cuts.js +112 -0
  374. package/dist/tools/apply-sfx.js +152 -0
  375. package/dist/tools/apply-watermark.js +670 -0
  376. package/dist/tools/archive-clip.js +74 -0
  377. package/dist/tools/asset-history.js +61 -0
  378. package/dist/tools/asset-manifest.js +24 -0
  379. package/dist/tools/asset-tags.js +151 -0
  380. package/dist/tools/assign-slot.js +97 -0
  381. package/dist/tools/audio-boost.js +107 -0
  382. package/dist/tools/audio-mix.js +121 -0
  383. package/dist/tools/book-usage.js +16 -0
  384. package/dist/tools/chain.js +136 -0
  385. package/dist/tools/change-video-speed.js +105 -0
  386. package/dist/tools/chat-history.js +5 -0
  387. package/dist/tools/chat.js +848 -0
  388. package/dist/tools/clean-video-audio.js +97 -0
  389. package/dist/tools/clear-failed-tasks.js +66 -0
  390. package/dist/tools/cold-open.js +114 -0
  391. package/dist/tools/command-plan.js +1680 -0
  392. package/dist/tools/commands.js +1666 -0
  393. package/dist/tools/concat-images.js +236 -0
  394. package/dist/tools/connect-service.js +55 -0
  395. package/dist/tools/copy-file-to-clipboard.js +58 -0
  396. package/dist/tools/create-character.js +114 -0
  397. package/dist/tools/create-qart.js +253 -0
  398. package/dist/tools/create-qr-outro.js +149 -0
  399. package/dist/tools/create-qrbtf.js +215 -0
  400. package/dist/tools/create-watermark.js +97 -0
  401. package/dist/tools/crop-asset.js +18 -0
  402. package/dist/tools/crop-image.js +120 -0
  403. package/dist/tools/crop-video.js +97 -0
  404. package/dist/tools/delete-asset.js +104 -0
  405. package/dist/tools/describe-image.js +69 -0
  406. package/dist/tools/detect-scenes.js +44 -0
  407. package/dist/tools/doctor.js +126 -0
  408. package/dist/tools/download-video.js +114 -0
  409. package/dist/tools/duplicate-asset.js +184 -0
  410. package/dist/tools/edit-timeline.js +59 -0
  411. package/dist/tools/editing-moments.js +105 -0
  412. package/dist/tools/estimate-cost.js +171 -0
  413. package/dist/tools/even-split.js +295 -0
  414. package/dist/tools/export-asset-file.js +22 -0
  415. package/dist/tools/export-asset.js +140 -0
  416. package/dist/tools/export-sequence.js +250 -0
  417. package/dist/tools/export-to-downloads.js +54 -0
  418. package/dist/tools/export-transcript-srt.js +79 -0
  419. package/dist/tools/extend-audio.js +100 -0
  420. package/dist/tools/extract-audio.js +174 -0
  421. package/dist/tools/extract-frame.js +108 -0
  422. package/dist/tools/extract-notebook-audio.js +173 -0
  423. package/dist/tools/extract-notebook-frame.js +160 -0
  424. package/dist/tools/extract-video-clip.js +101 -0
  425. package/dist/tools/generate-media.js +157 -0
  426. package/dist/tools/generation-payload.js +48 -0
  427. package/dist/tools/get-timeline.js +12 -0
  428. package/dist/tools/get-watermark-config.js +38 -0
  429. package/dist/tools/goal.js +644 -0
  430. package/dist/tools/image-subjects.js +711 -0
  431. package/dist/tools/index.js +323 -0
  432. package/dist/tools/inject-first-frame.js +154 -0
  433. package/dist/tools/invert-image.js +70 -0
  434. package/dist/tools/isolate-vocals.js +66 -0
  435. package/dist/tools/list-assets.js +98 -0
  436. package/dist/tools/list-cell-generations.js +225 -0
  437. package/dist/tools/list-elevenlabs-voices.js +163 -0
  438. package/dist/tools/log-wrapper.js +29 -0
  439. package/dist/tools/make-cover-song.js +95 -0
  440. package/dist/tools/mark-asset-seen.js +23 -0
  441. package/dist/tools/media-library.js +245 -0
  442. package/dist/tools/move-timeline-audio.js +35 -0
  443. package/dist/tools/music-analysis.js +60 -0
  444. package/dist/tools/music-draft.js +29 -0
  445. package/dist/tools/pad-video.js +87 -0
  446. package/dist/tools/post-record.js +83 -0
  447. package/dist/tools/post.js +168 -0
  448. package/dist/tools/prompt-history.js +164 -0
  449. package/dist/tools/provider-key-status.js +248 -0
  450. package/dist/tools/qrbtf-render.js +849 -0
  451. package/dist/tools/read-asset-metadata.js +26 -0
  452. package/dist/tools/read-file-at-commit.js +29 -0
  453. package/dist/tools/read-transcript.js +41 -0
  454. package/dist/tools/reconcile-project-work.js +1452 -0
  455. package/dist/tools/recover-asset.js +28 -0
  456. package/dist/tools/remove-sound.js +72 -0
  457. package/dist/tools/remove-timeline-audio.js +34 -0
  458. package/dist/tools/remove-timeline-slot.js +40 -0
  459. package/dist/tools/rename-all.js +434 -0
  460. package/dist/tools/rename-asset.js +34 -0
  461. package/dist/tools/render-settings.js +47 -0
  462. package/dist/tools/render-timeline.js +120 -0
  463. package/dist/tools/render.js +384 -0
  464. package/dist/tools/reorder-character-images.js +45 -0
  465. package/dist/tools/replace-video-audio.js +133 -0
  466. package/dist/tools/restore-archive-clips.js +209 -0
  467. package/dist/tools/restore-asset-version.js +37 -0
  468. package/dist/tools/retry-generation.js +54 -0
  469. package/dist/tools/reverse-video.js +74 -0
  470. package/dist/tools/rewrite-prompt.js +388 -0
  471. package/dist/tools/rewrite-script.js +67 -0
  472. package/dist/tools/schema-from-apicity.js +66 -0
  473. package/dist/tools/search-archive.js +150 -0
  474. package/dist/tools/semantic-search.js +1214 -0
  475. package/dist/tools/sequence-rhythm.js +43 -0
  476. package/dist/tools/set-character-metadata.js +84 -0
  477. package/dist/tools/set-env-secret.js +40 -0
  478. package/dist/tools/set-osg.js +143 -0
  479. package/dist/tools/show-folder.js +37 -0
  480. package/dist/tools/smooth-scene-concat.js +122 -0
  481. package/dist/tools/splice-video.js +149 -0
  482. package/dist/tools/split-video.js +202 -0
  483. package/dist/tools/suggest-cuts.js +45 -0
  484. package/dist/tools/suggest-sfx.js +43 -0
  485. package/dist/tools/sync-video-to-audio.js +115 -0
  486. package/dist/tools/tag-backfill.js +177 -0
  487. package/dist/tools/timewarp-video.js +85 -0
  488. package/dist/tools/tool-def.js +1 -0
  489. package/dist/tools/tool-json-schema.js +116 -0
  490. package/dist/tools/transcribe.js +90 -0
  491. package/dist/tools/translate-subtitles.js +59 -0
  492. package/dist/tools/trim-audio.js +139 -0
  493. package/dist/tools/trim-video.js +168 -0
  494. package/dist/tools/update-script.js +25 -0
  495. package/dist/tools/update-timeline-audio.js +40 -0
  496. package/dist/tools/upload-file.js +41 -0
  497. package/dist/tools/verify-x-mentions.js +141 -0
  498. package/dist/tools/video-editing-command-contract.js +291 -0
  499. package/dist/tools/video-source-reference.js +30 -0
  500. package/dist/tools/video-time-input.js +18 -0
  501. package/dist/tools/videobook-domain.js +2021 -0
  502. package/dist/tools/wait-for-asset-ready.js +143 -0
  503. package/dist/tools/workspace-actions.js +54 -0
  504. package/dist/transcript-projection.js +202 -0
  505. package/dist/transcript-srt.js +33 -0
  506. package/dist/upload.js +76 -0
  507. package/dist/usage-providers.js +25 -0
  508. package/dist/video-analysis-projection.js +46 -0
  509. package/dist/video-poster.js +33 -0
  510. package/dist/video-proxy.js +99 -0
  511. package/dist/vision-regions.js +111 -0
  512. package/dist/voice-actions.js +90 -0
  513. package/dist/voice-audio.js +55 -0
  514. package/dist/voice-config.js +122 -0
  515. package/dist/voice-continuation.js +54 -0
  516. package/dist/voice-contract.js +1 -0
  517. package/dist/voice-http.js +145 -0
  518. package/dist/voice-reply-progress.js +55 -0
  519. package/dist/voice-session.js +992 -0
  520. package/dist/watermark-badge.js +259 -0
  521. package/dist/watermark-config.js +111 -0
  522. package/dist/watermark-handle-position.js +55 -0
  523. package/dist/watermark-platform.js +15 -0
  524. package/dist/watermark-timing.js +16 -0
  525. package/dist/workspace-action-catalog.js +315 -0
  526. package/dist/workspace-action-contract.js +21 -0
  527. package/dist/workspace-action-groups.js +98 -0
  528. package/dist/workspace-action-surfaces.js +7 -0
  529. package/dist/x/account.js +88 -0
  530. package/dist/x/authenticated-handle.js +30 -0
  531. package/dist/x/oauth-flow.js +191 -0
  532. package/dist/x/post-contract.js +1 -0
  533. package/dist/x/post-metadata.js +44 -0
  534. package/dist/x/post-to-x.js +456 -0
  535. package/dist/x/published-post-cell.js +90 -0
  536. package/dist/x/x-tokens.js +69 -0
  537. package/dist/ytdlp-binary.js +65 -0
  538. package/dist/zod-slots.js +334 -0
  539. package/package.json +84 -4
  540. package/ui/assets/alive-captions-BWb5nLKj.css +1 -0
  541. package/ui/assets/alive-captions-DPEr1nKM.js +1 -0
  542. package/ui/assets/confirm-bodies-D8ouHXKy.js +1 -0
  543. package/ui/assets/confirm-bodies-DrMhaXC6.css +1 -0
  544. package/ui/assets/fullscreen-B7nw4YbE.js +1 -0
  545. package/ui/assets/goal-ui-DK-xTCK0.js +2 -0
  546. package/ui/assets/goal-ui-DXdUM2KF.css +1 -0
  547. package/ui/assets/index-DzPAnCUj.css +1 -0
  548. package/ui/assets/index-kS1905s5.js +37 -0
  549. package/ui/assets/inspector-MlzQbTVo.js +1 -0
  550. package/ui/assets/jobs-ui-CoinOWx0.js +1 -0
  551. package/ui/assets/music-video-Cbe80kmQ.js +1 -0
  552. package/ui/assets/music-video-DPaiKKEq.css +1 -0
  553. package/ui/assets/ui-Oirr9VOf.css +1 -0
  554. package/ui/assets/ui-xo_Y1yQg.js +2 -0
  555. package/ui/assets/vendor-D2rfiZ5j.css +1 -0
  556. package/ui/assets/vendor-DfTCWgKm.js +19 -0
  557. package/ui/assets/vendor-flow-BXbeWxW7.js +7 -0
  558. package/ui/assets/vendor-flow-BnuhLJ6X.css +1 -0
  559. package/ui/assets/vendor-icons-CGqhCIXV.js +1 -0
  560. package/ui/assets/vendor-mcp-BTlEJcHV.js +67 -0
  561. package/ui/assets/vendor-react-Dj7D1fD4.js +9 -0
  562. package/ui/assets/vendor-remotion-CH1HXrlc.js +95 -0
  563. package/ui/assets/videobook-Qlp9HQFu.js +20 -0
  564. package/ui/favicon.svg +8 -0
  565. package/ui/index.html +126 -0
@@ -0,0 +1,261 @@
1
+ import { notebookGridTag } from "videobook-engine/notebook-grid";
2
+ import { cancelChainRun, getChainRun } from "./chain-executor.js";
3
+ import { coldOpenSource } from "./cold-open.js";
4
+ import { emptyGoalEstimates, findGoalCell, goalContent, requireGoalContent, saveGoal, writeGoalContent } from "./goal-store.js";
5
+ import { GOAL_VIDEO_TOOL, refreshGoalPlanV3 } from "./goal-plan.js";
6
+ import { suggestedColdOpen } from "./lightning-defaults.js";
7
+ import { mutateNotebook } from "./notebook-mutations.js";
8
+ import { goalStageAttempts, goalStillStaleReason } from "./goal-stills.js";
9
+ export const LEGACY_GOAL_MESSAGE = "Goal mode now starts from character images. Start a new /goal.";
10
+ export function activeGoalStage(goal) {
11
+ return goal.stage === "assembly" ? "videos" : goal.stage;
12
+ }
13
+ function outputString(outputs, key) {
14
+ const value = outputs?.[key];
15
+ return typeof value === "string" ? value : null;
16
+ }
17
+ function producerCell(document, chainId, step) {
18
+ const tagged = document.cells.filter(cell => cell.inputs?.chainRunId === `${chainId}:${step.id}`).sort((a, b) => b.id.localeCompare(a.id))[0];
19
+ const outputId = outputString(step.outputs, "cell_id");
20
+ const edge = document.edges.find(candidate => candidate.target === outputId && candidate.targetInput === "media");
21
+ return tagged ?? document.cells.find(cell => cell.id === edge?.source);
22
+ }
23
+ function goalChainSteps(engine, document, chainId) {
24
+ const chain = chainId ? getChainRun(engine, chainId) : null;
25
+ return chain?.steps.map(step => {
26
+ const producer = producerCell(document, chain.chainId, step);
27
+ return {
28
+ id: step.id, chainId: chain.chainId, status: step.status, error: step.error,
29
+ artifactId: outputString(step.outputs, "asset_id") ?? outputString(step.outputs, "img_asset_id") ?? outputString(step.outputs, "vid_asset_id"),
30
+ cellId: producer?.id ?? null,
31
+ address: producer ? notebookGridTag(producer.slot) : outputString(step.outputs, "address"),
32
+ outputCellId: outputString(step.outputs, "cell_id"), startedAt: step.startedAt ?? null,
33
+ };
34
+ }) ?? [];
35
+ }
36
+ function stageOutputIndex(stepId) {
37
+ if (stepId === "frame" || stepId === "scene" || stepId === "video")
38
+ return 0;
39
+ return Number(/\d+$/u.exec(stepId)?.[0]) - 1;
40
+ }
41
+ function completedStageOutputs(engine, goal, document) {
42
+ return goalChainSteps(engine, document, goal.chainId).flatMap(step => {
43
+ if (step.status !== "completed" || !step.artifactId || step.id === "assemble")
44
+ return [];
45
+ const index = stageOutputIndex(step.id);
46
+ if (!Number.isInteger(index) || index < 0)
47
+ return [];
48
+ const cell = document.cells.find(candidate => candidate.id === step.outputCellId);
49
+ return [{ index, artifactId: step.artifactId, cellId: step.outputCellId, producerCellId: step.cellId, address: cell ? notebookGridTag(cell.slot) : null }];
50
+ });
51
+ }
52
+ function allGoalChainSteps(engine, document, chainId) {
53
+ return goalChainSteps(engine, document, chainId).flatMap(step => {
54
+ const producers = document.cells.filter(cell => cell.inputs?.chainRunId === `${chainId}:${step.id}`);
55
+ if (producers.length === 0)
56
+ return [step];
57
+ return producers.map(producer => {
58
+ const outputCellId = document.edges.find(edge => edge.source === producer.id && edge.targetInput === "media")?.target ?? null;
59
+ return { ...step, cellId: producer.id, outputCellId, address: notebookGridTag(producer.slot) };
60
+ });
61
+ });
62
+ }
63
+ export async function writeGoalCombinationState(engine, goal, error) {
64
+ if (!goal.combined)
65
+ return goal;
66
+ const updated = await mutateNotebook(engine, goal.notebookId, "goal_combine_complete", document => ({
67
+ ...document, cells: document.cells.map(cell => cell.id === goal.combined?.cellId ? { ...cell, inputs: { ...cell.inputs, state: error ? "error" : "completed" } } : cell),
68
+ }));
69
+ if (!updated.ok)
70
+ throw new Error(updated.error.message);
71
+ return saveGoal(engine, { ...goal, combined: { ...goal.combined, status: error ? "failed" : "completed", error } });
72
+ }
73
+ export function reconcileFinish(engine, goal) {
74
+ const finish = goal.finish;
75
+ if (goal.planVersion !== 3 || !finish || finish.status !== "running")
76
+ return goal;
77
+ const job = finish.jobId ? engine.jobs.queue.get(finish.jobId) : null;
78
+ if (job && ["queued", "running", "completing"].includes(job.state))
79
+ return goal;
80
+ if (job?.state === "done") {
81
+ const result = job.result && typeof job.result === "object" ? job.result : null;
82
+ const finalArtifactId = finish.finalArtifactId ?? (typeof result?.finalArtifactId === "string" && result.finalArtifactId ? result.finalArtifactId : null);
83
+ if (finalArtifactId && engine.artifacts.get(finalArtifactId).ok) {
84
+ const coldOpenArtifactId = finish.coldOpenArtifactId ?? (typeof result?.coldOpenArtifactId === "string" ? result.coldOpenArtifactId : null);
85
+ return saveGoal(engine, { ...goal, status: "completed", error: null, finish: { ...finish, status: "completed", finalArtifactId, coldOpenArtifactId, error: null } });
86
+ }
87
+ }
88
+ return saveGoal(engine, { ...goal, status: "review", finish: { ...finish, status: "failed", error: job?.error?.message ?? "Finishing was interrupted. Retry the cold open." } });
89
+ }
90
+ async function coldOpenReview(engine, goal) {
91
+ if (goal.planVersion !== 3 || !goal.finish?.sourceArtifactId)
92
+ return null;
93
+ try {
94
+ const source = await coldOpenSource(engine, goal.finish.sourceArtifactId, goal.finish.sourceObjectHash ?? undefined);
95
+ const approved = goal.finish.status !== "review" && goal.finish.startSeconds != null && goal.finish.endSeconds != null;
96
+ const range = approved
97
+ ? { startSeconds: goal.finish.startSeconds, endSeconds: goal.finish.endSeconds }
98
+ : suggestedColdOpen(source.durationSeconds);
99
+ return { ...range, durationSeconds: source.durationSeconds, sourceObjectHash: source.file.objectHash, analysisUsd: 0 };
100
+ }
101
+ catch {
102
+ return null;
103
+ }
104
+ }
105
+ export async function reconcileGoal(engine, goal, document) {
106
+ if (goal.planVersion === 1) {
107
+ if (!["planning", "review", "running"].includes(goal.status))
108
+ return goal;
109
+ if (goal.chainId)
110
+ cancelChainRun(engine, goal.chainId);
111
+ if (goal.planningJobId)
112
+ await engine.jobs.queue.abort(goal.planningJobId, LEGACY_GOAL_MESSAGE);
113
+ return saveGoal(engine, { ...goal, status: "failed", error: LEGACY_GOAL_MESSAGE });
114
+ }
115
+ if (goal.combined?.status === "running") {
116
+ const job = goal.combined.jobId ? engine.jobs.queue.get(goal.combined.jobId) : null;
117
+ if (!job || ["failed", "aborted"].includes(job.state))
118
+ goal = await writeGoalCombinationState(engine, goal, job?.error?.message ?? "Combining was interrupted. Retry the combined video.");
119
+ }
120
+ if (["completed", "cancelled", "review"].includes(goal.status))
121
+ return goal;
122
+ if (goal.status === "planning") {
123
+ const job = goal.planningJobId ? engine.jobs.queue.get(goal.planningJobId) : null;
124
+ return job && ["failed", "aborted"].includes(job.state)
125
+ ? saveGoal(engine, { ...goal, status: "failed", error: job.error?.message ?? "Planning was interrupted" }) : goal;
126
+ }
127
+ const stage = activeGoalStage(goal);
128
+ const run = goal.stages[stage];
129
+ const chain = run ? getChainRun(engine, run.chainId) : null;
130
+ if (!run || !chain)
131
+ return goal;
132
+ const merged = new Map(run.outputs.map(output => [output.index, output]));
133
+ for (const output of completedStageOutputs(engine, goal, document))
134
+ merged.set(output.index, output);
135
+ const outputs = [...merged.values()].sort((a, b) => a.index - b.index);
136
+ const attempts = run.attempts?.map(attempt => {
137
+ if (attempt.artifactId)
138
+ return attempt;
139
+ const step = goalChainSteps(engine, document, attempt.chainId).find(candidate => candidate.id === attempt.stepId);
140
+ return step?.status === "completed" && step.artifactId ? { ...attempt, artifactId: step.artifactId, cellId: step.outputCellId } : attempt;
141
+ });
142
+ let next = { ...goal, stages: { ...goal.stages, [stage]: { ...run, outputs, ...(attempts ? { attempts } : {}) } } };
143
+ const assembled = stage === "videos" && goal.assembly?.artifactIds && JSON.stringify(goal.assembly.artifactIds) === JSON.stringify(outputs.map(output => output.artifactId));
144
+ if (chain.status === "completed" || assembled && !goal.resumeStage) {
145
+ const content = requireGoalContent(engine, goal);
146
+ if (goal.planVersion === 3) {
147
+ const cleared = { resumeStage: null, resumeStatus: null, resumeOutputs: null, resumeFinish: null };
148
+ if (outputs.length !== 1)
149
+ next = { ...next, status: "failed", error: "The stage finished without all of its media outputs. Retry the stage.", ...cleared };
150
+ else if (stage === "videos") {
151
+ next = {
152
+ ...next, status: "review", error: null, ...cleared,
153
+ finish: { status: "review", sourceArtifactId: outputs[0].artifactId, finalArtifactId: null, error: null },
154
+ };
155
+ }
156
+ else {
157
+ const previousScene = run.outputs[0]?.artifactId ?? null;
158
+ await writeGoalContent(engine, goal, { ...content, revision: content.revision + 1 });
159
+ const sceneChanged = previousScene !== null && previousScene !== outputs[0].artifactId;
160
+ const finish = sceneChanged ? null : goal.finish ?? goal.resumeFinish ?? null;
161
+ const keepCompleted = finish?.status === "completed" && Boolean(finish.finalArtifactId);
162
+ next = {
163
+ ...next, stage: goal.resumeStage ?? "videos", status: keepCompleted ? "completed" : "review", error: null, ...cleared,
164
+ finish,
165
+ };
166
+ }
167
+ }
168
+ else {
169
+ const stagedPlan = content.plan && "shots" in content.plan ? content.plan : null;
170
+ const shotCount = stagedPlan?.shots.length ?? 0;
171
+ const expected = stage === "frame" ? 1 : stage === "storyboards" && stagedPlan && "frameContinuity" in stagedPlan && stagedPlan.frameContinuity ? 2 * shotCount : shotCount;
172
+ if (outputs.length !== expected)
173
+ next = { ...next, status: "failed", error: "The stage finished without all of its media outputs. Retry the stage." };
174
+ else if (stage === "videos") {
175
+ next = { ...next, status: goal.assembly || expected === 1 || goal.resumeStage ? "completed" : "failed", error: goal.assembly || expected === 1 || goal.resumeStage ? null : "The finished clips still need to be assembled" };
176
+ if (goal.combined && JSON.stringify(run.outputs.map(output => output.artifactId)) !== JSON.stringify(outputs.map(output => output.artifactId)))
177
+ next.combined = { ...goal.combined, status: "failed", error: "Video selection changed. Assemble the selected clips before combining again." };
178
+ }
179
+ else {
180
+ await writeGoalContent(engine, goal, { ...content, revision: content.revision + 1 });
181
+ next = { ...next, stage: goal.resumeStage ?? (stage === "frame" ? "storyboards" : "videos"), status: goal.resumeStatus ?? "review", error: null };
182
+ }
183
+ next = { ...next, resumeStage: null, resumeStatus: null, resumeOutputs: null };
184
+ }
185
+ }
186
+ else if (["failed", "interrupted", "cancelled"].includes(chain.status)) {
187
+ next = { ...next, status: chain.status, error: chain.error,
188
+ ...(goal.resumeOutputs ? { stages: { ...next.stages, [stage]: { ...next.stages[stage], outputs: goal.resumeOutputs } } } : {}),
189
+ };
190
+ }
191
+ else {
192
+ next = { ...next, stage: chain.steps.some(step => step.id === "assemble" && step.status === "running") ? "assembly" : stage, status: "running", error: null };
193
+ }
194
+ return JSON.stringify(next) === JSON.stringify(goal) ? goal : saveGoal(engine, next);
195
+ }
196
+ export async function publicGoal(engine, goal, document) {
197
+ const cell = findGoalCell(document, goal);
198
+ const content = cell ? goalContent(cell) : { brief: "", characters: [], revision: 0, plan: null, estimate: emptyGoalEstimates() };
199
+ const stages = Object.fromEntries(await Promise.all(Object.entries(goal.stages).map(async ([stage, run]) => [stage, {
200
+ ...run,
201
+ ...(stage === "videos" ? { attempts: goalStageAttempts(engine, goal, "videos") } : {}),
202
+ outputs: await Promise.all(run.outputs.map(async (output) => {
203
+ const outputCell = document.cells.find(candidate => candidate.id === output.cellId);
204
+ const versions = goalStageAttempts(engine, goal, stage).filter(attempt => attempt.index === output.index).slice().reverse().map(attempt => {
205
+ const versionCell = document.cells.find(candidate => candidate.id === attempt.cellId);
206
+ const step = getChainRun(engine, attempt.chainId)?.steps.find(candidate => candidate.id === attempt.stepId);
207
+ return {
208
+ ...attempt, address: versionCell ? notebookGridTag(versionCell.slot) : null,
209
+ status: step?.status ?? "interrupted", current: attempt.artifactId === output.artifactId,
210
+ };
211
+ });
212
+ const stagedPlan = content.plan && "version" in content.plan && content.plan.version === 2 ? content.plan : null;
213
+ const stale = stagedPlan && (stage === "frame" || stage === "storyboards" || stage === "videos")
214
+ ? await goalStillStaleReason(engine, goal, document, stagedPlan, content.characters, stage, output) : null;
215
+ return { ...output, address: outputCell ? notebookGridTag(outputCell.slot) : null, versions, stale };
216
+ })),
217
+ steps: goalChainSteps(engine, document, run.chainId),
218
+ allSteps: [...run.previousChainIds, run.chainId].flatMap(chainId => allGoalChainSteps(engine, document, chainId)),
219
+ }])));
220
+ const shotPlan = content.plan && "shots" in content.plan ? content.plan : null;
221
+ const stillCount = shotPlan ? shotPlan.shots.length * ("frameContinuity" in shotPlan && shotPlan.frameContinuity ? 2 : 1) : 1;
222
+ const displayedPlan = content.plan && "version" in content.plan && content.plan.version === 3 ? refreshGoalPlanV3(content.plan, document) : content.plan;
223
+ const v3Plan = displayedPlan && "version" in displayedPlan && displayedPlan.version === 3;
224
+ const still = v3Plan
225
+ ? goal.stage === "videos" || goal.stage === "assembly" ? content.estimate.videos : content.estimate.frame
226
+ : goal.stage === "videos"
227
+ ? { ...content.estimate.storyboards, usd: content.estimate.storyboards.usd === null ? null : content.estimate.storyboards.usd / stillCount }
228
+ : content.estimate.frame;
229
+ return {
230
+ kind: "video-goal", ...goal, ...content, plan: displayedPlan,
231
+ finish: goal.finish ?? null,
232
+ finalArtifactId: goal.finish?.finalArtifactId ?? null,
233
+ coldOpen: await coldOpenReview(engine, goal),
234
+ estimate: { ...content.estimate, still },
235
+ address: cell ? notebookGridTag(cell.slot) : null,
236
+ assemblyStale: goalAssemblyStale(engine, goal),
237
+ stages: stages,
238
+ steps: goalChainSteps(engine, document, goal.chainId),
239
+ };
240
+ }
241
+ export function goalAssemblyStale(engine, goal) {
242
+ if (!goal.assembly)
243
+ return false;
244
+ const clips = engine.sequences.getPrimary().clips;
245
+ const sources = goal.assembly.artifactIds ?? goal.clipIds.map(id => clips.find(clip => clip.clipId === id)?.source.artifactId ?? null);
246
+ return JSON.stringify(sources) !== JSON.stringify(completedGoalVideos(engine, goal));
247
+ }
248
+ export function completedGoalVideos(engine, goal) {
249
+ const run = goal.stages.videos;
250
+ const selected = new Map((run?.outputs ?? []).map(output => [output.index, output.artifactId]));
251
+ const chainId = run?.chainId ?? (goal.planVersion === 1 ? goal.chainId : null);
252
+ if (goal.status === "running" || selected.size === 0) {
253
+ for (const step of chainId ? getChainRun(engine, chainId)?.steps ?? [] : []) {
254
+ const id = outputString(step.outputs, "asset_id") ?? outputString(step.outputs, "vid_asset_id");
255
+ const index = stageOutputIndex(step.id);
256
+ if (step.tool === GOAL_VIDEO_TOOL && step.status === "completed" && id && Number.isInteger(index) && index >= 0)
257
+ selected.set(index, id);
258
+ }
259
+ }
260
+ return [...selected.entries()].sort(([left], [right]) => left - right).map(([, id]) => id);
261
+ }
@@ -0,0 +1,153 @@
1
+ import { resolveNotebookCellArtifactId } from "videobook-engine";
2
+ import { notebookGridTag } from "videobook-engine/notebook-grid";
3
+ import { getChainRun } from "./chain-executor.js";
4
+ import { compileFrameSteps, compileStoryboardSteps, goalStillPrompt } from "./goal-plan.js";
5
+ import { goalReferenceHashes } from "./goal-reference-images.js";
6
+ function goalStepIndex(stage, stepId) {
7
+ if (stage === "frame" || stepId === "frame" || stepId === "scene" || stepId === "video")
8
+ return 0;
9
+ return Number(/\d+$/u.exec(stepId)?.[0]) - 1;
10
+ }
11
+ export async function goalV3Fingerprint(engine, plan, stage, sceneArtifactId) {
12
+ const ids = stage === "frame"
13
+ ? plan.scene.imageRefs.map(reference => reference.artifactId)
14
+ : [...plan.video.imageRefs, ...plan.video.videoRefs].map(reference => reference.artifactId);
15
+ return JSON.stringify({
16
+ prompt: stage === "frame" ? plan.scene.prompt : plan.video.prompt,
17
+ settings: stage === "frame"
18
+ ? { model: plan.scene.model, aspectRatio: plan.scene.aspectRatio, resolution: plan.scene.resolution, outputFormat: plan.scene.outputFormat }
19
+ : { aspectRatio: plan.video.aspectRatio, resolution: plan.video.resolution, duration: plan.video.durationSeconds, audio: plan.video.generateAudio, outputFormat: plan.video.outputFormat },
20
+ references: await goalReferenceHashes(engine, ids),
21
+ ...(stage === "videos" ? { sceneArtifactId } : {}),
22
+ });
23
+ }
24
+ export async function goalStageFingerprint(engine, goal, plan, characters, stage, index) {
25
+ const ids = characters.map(character => character.artifactId);
26
+ if (stage !== "frame")
27
+ ids.push(goal.stages.frame?.outputs[0]?.artifactId ?? "");
28
+ if (stage === "videos") {
29
+ ids.push(goal.stages.storyboards?.outputs.find(output => output.index === index)?.artifactId ?? "");
30
+ if (plan.frameContinuity)
31
+ ids.push(goal.stages.storyboards?.outputs.find(output => output.index === index + plan.shots.length)?.artifactId ?? "");
32
+ }
33
+ return JSON.stringify({
34
+ prompt: stage === "videos" ? plan.shots[index]?.videoPrompt : goalStillPrompt(plan, stage, index),
35
+ aspectRatio: plan.aspectRatio, style: { id: plan.style.id, options: Object.entries(plan.style.options).sort() },
36
+ referenceRoles: plan.referenceRoles ?? [], references: await goalReferenceHashes(engine, ids),
37
+ ...(stage === "videos" ? { duration: plan.shots[index]?.durationSeconds, resolution: plan.videoResolution, audio: true }
38
+ : { model: plan.imageModel, resolution: plan.imageResolution, ...(stage === "frame" ? { continuity: plan.continuity } : { layout: plan.storyboardLayout ?? "four-panel" }) }),
39
+ });
40
+ }
41
+ export async function goalAttemptFingerprints(engine, goal, plan, characters, stage, steps) {
42
+ return Object.fromEntries(await Promise.all(steps.filter(step => step.id !== "assemble").map(async (step) => [step.id, await goalStageFingerprint(engine, goal, plan, characters, stage, goalStepIndex(stage, step.id))])));
43
+ }
44
+ export function goalStageAttempts(engine, goal, stage) {
45
+ const run = goal.stages[stage];
46
+ const attempts = [...(run?.attempts ?? [])];
47
+ if (!run || stage !== "videos")
48
+ return attempts;
49
+ for (const chainId of [...run.previousChainIds, run.chainId]) {
50
+ for (const step of getChainRun(engine, chainId)?.steps ?? []) {
51
+ const artifactId = step.outputs?.asset_id ?? step.outputs?.vid_asset_id;
52
+ if (!/^shot\d+$/u.test(step.id) || step.status !== "completed" || typeof artifactId !== "string" || attempts.some(attempt => attempt.chainId === chainId && attempt.stepId === step.id))
53
+ continue;
54
+ attempts.push({
55
+ stage, index: goalStepIndex(stage, step.id), chainId, stepId: step.id, artifactId,
56
+ cellId: typeof step.outputs?.cell_id === "string" ? step.outputs.cell_id : null,
57
+ basePrompt: typeof step.params.prompt === "string" ? step.params.prompt.split("\n\n")[0] : "",
58
+ feedback: null, parentArtifactId: null, frameArtifactId: null, createdAt: run.approvedAt,
59
+ });
60
+ }
61
+ }
62
+ return attempts;
63
+ }
64
+ export function goalStillAttempts(goal, plan, stage, chainId, steps, createdAt, feedback = null, fingerprints, history = goal.stages[stage]?.attempts ?? []) {
65
+ return [...history, ...steps.filter(step => step.id !== "assemble").map(step => {
66
+ const index = goalStepIndex(stage, step.id);
67
+ return {
68
+ stage, index, chainId, stepId: step.id, artifactId: null, cellId: null,
69
+ basePrompt: stage === "videos" ? plan.shots[index].videoPrompt : goalStillPrompt(plan, stage, index), feedback,
70
+ ...(fingerprints?.[step.id] ? { fingerprint: fingerprints[step.id] } : {}),
71
+ ...(stage === "storyboards" && index < plan.shots.length ? { storyboardLayout: plan.storyboardLayout ?? "four-panel" } : {}),
72
+ parentArtifactId: feedback ? goal.stages[stage]?.outputs.find(output => output.index === index)?.artifactId ?? null : null,
73
+ frameArtifactId: stage === "storyboards" ? goal.stages.frame?.outputs[0]?.artifactId ?? null : null,
74
+ createdAt,
75
+ };
76
+ })];
77
+ }
78
+ function legacyStillPrompt(plan, characters, stage, index) {
79
+ const references = characters.map((character, position) => `@image${position + (stage === "storyboards" ? 2 : 1)} is Character ${position + 1}: ${character.label.replace(/@[\p{L}\p{N}_-]+/gu, "").slice(0, 160)}`);
80
+ if (stage === "frame")
81
+ return `${plan.continuity}\n\n${plan.frame.prompt}\n\nReferences: ${references.join("; ")}.`;
82
+ references.unshift("@image1 is the approved full frame; preserve its setting and visual style");
83
+ const shotIndex = index % plan.shots.length;
84
+ const shot = plan.shots[shotIndex];
85
+ const next = plan.shots[shotIndex + 1];
86
+ const ending = `Create one still image of the final moment of this shot, with the characters in their ending poses. ${shot.endingPrompt ?? shot.videoPrompt}${next ? `\nPrepare a natural transition into the next shot's opening composition: ${next.storyboardPrompt}` : "\nShow the final payoff with a clear, settled composition."}`;
87
+ return `${plan.continuity}\n\nShot ${shotIndex + 1}: ${shot.title}\n${index < plan.shots.length ? shot.storyboardPrompt : ending}\n\nReferences: ${references.join("; ")}.`;
88
+ }
89
+ function preStyleStillPrompt(plan, characters, stage, index) {
90
+ const references = characters.map((_, position) => `@image${position + (stage === "storyboards" ? 2 : 1)} is Character ${position + 1}`);
91
+ if (stage === "frame")
92
+ return `${plan.continuity}\n\n${plan.frame.prompt}\n\nReferences: ${references.join("; ")}.`;
93
+ references.unshift("@image1 is the full frame; keep its characters, setting and style");
94
+ const shot = plan.shots[index % plan.shots.length];
95
+ return `One ending frame. ${shot.endingPrompt ?? `Final moment: ${shot.videoPrompt}`}\n\nReferences: ${references.join("; ")}.`;
96
+ }
97
+ export async function goalStillStaleReason(engine, goal, document, plan, characters, stage, output) {
98
+ const cell = document.cells.find(candidate => candidate.id === output.cellId);
99
+ if (!cell || resolveNotebookCellArtifactId(document, cell) !== output.artifactId)
100
+ return "The selected output changed or was removed. Choose another version or regenerate it.";
101
+ if (characters.some(character => !document.cells.some(candidate => candidate.id === character.cellId && resolveNotebookCellArtifactId(document, candidate) === character.artifactId)))
102
+ return "A source reference changed or was removed.";
103
+ const attempt = goalStageAttempts(engine, goal, stage).find(item => item.index === output.index && item.artifactId === output.artifactId);
104
+ if (attempt?.fingerprint && attempt.fingerprint !== await goalStageFingerprint(engine, goal, plan, characters, stage, output.index))
105
+ return `${stage === "frame" ? "Scene" : stage === "storyboards" ? "Storyboard" : "Video"} uses older settings, prompts or references. Revise or regenerate it.`;
106
+ if (stage !== "frame") {
107
+ const frame = goal.stages.frame?.outputs[0];
108
+ if (!frame || await goalStillStaleReason(engine, goal, document, plan, characters, "frame", frame))
109
+ return "The scene has changed. Refresh it before continuing.";
110
+ }
111
+ if (stage === "videos") {
112
+ const indexes = [output.index, ...(plan.frameContinuity ? [output.index + plan.shots.length] : [])];
113
+ for (const index of indexes) {
114
+ const board = goal.stages.storyboards?.outputs.find(item => item.index === index);
115
+ if (!board || await goalStillStaleReason(engine, goal, document, plan, characters, "storyboards", board))
116
+ return "The storyboard has changed. Refresh it before generating video.";
117
+ }
118
+ if (attempt && !attempt.fingerprint) {
119
+ const step = getChainRun(engine, attempt.chainId)?.steps.find(item => item.id === attempt.stepId);
120
+ const expected = indexes.map(index => goal.stages.storyboards?.outputs.find(item => item.index === index)?.artifactId);
121
+ if (expected.some((id, index) => id !== step?.pins[index]?.artifactId))
122
+ return "Video uses an older storyboard. Revise or regenerate it.";
123
+ }
124
+ return attempt && attempt.basePrompt !== plan.shots[output.index]?.videoPrompt ? "Video uses older directions. Revise or regenerate it." : null;
125
+ }
126
+ if (attempt?.fingerprint)
127
+ return null;
128
+ const name = stage === "frame" ? "Full frame" : `${output.index >= plan.shots.length ? "Ending frame" : "Storyboard"} ${output.index % plan.shots.length + 1}`;
129
+ const run = goal.stages[stage];
130
+ if (stage === "storyboards" && output.index < plan.shots.length && attempt?.storyboardLayout !== (plan.storyboardLayout ?? "four-panel")) {
131
+ return `${name} is a legacy single-frame preview. Regenerate or revise it to create a four-panel storyboard.`;
132
+ }
133
+ const promptError = `${name} was made from an older prompt. Regenerate or revise it, or restore the prompt.`;
134
+ const frameError = `${name} was made from an older full frame. Regenerate the storyboards.`;
135
+ if (attempt) {
136
+ if (attempt.basePrompt !== goalStillPrompt(plan, stage, output.index))
137
+ return promptError;
138
+ if (stage === "storyboards" && attempt.frameArtifactId !== goal.stages.frame?.outputs[0]?.artifactId)
139
+ return frameError;
140
+ return null;
141
+ }
142
+ const source = run && [...run.previousChainIds, run.chainId].flatMap(id => getChainRun(engine, id)?.steps ?? [])
143
+ .find(step => step.id === (stage === "frame" ? "frame" : `storyboard${output.index + 1}`) && (step.outputs?.asset_id ?? step.outputs?.img_asset_id) === output.artifactId);
144
+ const frameOutput = goal.stages.frame?.outputs[0];
145
+ if (stage === "storyboards" && source?.pins[0]?.artifactId !== frameOutput?.artifactId)
146
+ return frameError;
147
+ const frameCell = document.cells.find(cell => cell.id === frameOutput?.cellId);
148
+ const compiled = stage === "frame" ? compileFrameSteps(plan, characters)[0]
149
+ : compileStoryboardSteps(plan, characters, frameCell ? notebookGridTag(frameCell.slot) : "", [output.index % plan.shots.length])
150
+ .find(step => step.id === `storyboard${output.index + 1}`);
151
+ return source?.params.prompt === compiled?.params.prompt || plan.style.id === "cinematic" && (source?.params.prompt === legacyStillPrompt(plan, characters, stage, output.index)
152
+ || source?.params.prompt === preStyleStillPrompt(plan, characters, stage, output.index)) ? null : promptError;
153
+ }
@@ -0,0 +1,144 @@
1
+ import { z } from "zod";
2
+ import { firstEmptyNotebookGridSlot, notebookOccupiedSlots } from "videobook-engine/notebook-grid";
3
+ import { goalMediaRefSchema, goalPlanSchema, goalPlanV3Schema, goalStyleSchema, legacyGoalPlanSchema } from "./goal-plan.js";
4
+ import { mutateNotebook } from "./notebook-mutations.js";
5
+ import { arrangeGoalNotebook } from "./notebook-goal-layout.js";
6
+ const KEY = "application.goals.v2";
7
+ const LEGACY_KEY = "application.goals.v1";
8
+ const GOAL_TILE_LABEL = "Video goal";
9
+ const REMOVED_TILE_ERROR = "This goal's tile was removed from the notebook";
10
+ function goalStore(engine) {
11
+ const legacy = engine.settings.get(LEGACY_KEY) ?? {};
12
+ return {
13
+ ...Object.fromEntries(Object.entries(legacy).map(([id, goal]) => [id, { ...goal, planVersion: 1, stage: "videos", stages: {} }])),
14
+ ...(engine.settings.get(KEY) ?? {}),
15
+ };
16
+ }
17
+ function hasTile(goal) {
18
+ return typeof goal.cellId === "string";
19
+ }
20
+ export function listGoals(engine, notebookId) {
21
+ return Object.values(goalStore(engine))
22
+ .filter((goal) => goal.notebookId === notebookId && hasTile(goal))
23
+ .sort((a, b) => b.createdAt.localeCompare(a.createdAt));
24
+ }
25
+ export function readGoal(engine, goalId) {
26
+ const goal = goalStore(engine)[goalId];
27
+ if (!goal || !hasTile(goal) || goal.bookId !== engine.book.get().bookId)
28
+ throw new Error("Goal not found in this book");
29
+ return goal;
30
+ }
31
+ export function saveGoal(engine, goal) {
32
+ const next = { ...goal, updatedAt: new Date().toISOString() };
33
+ const result = engine.settings.set(KEY, { ...(engine.settings.get(KEY) ?? {}), [goal.goalId]: next });
34
+ if (!result.ok)
35
+ throw new Error(result.error.message);
36
+ return next;
37
+ }
38
+ function estimateFrom(value) {
39
+ const record = value && typeof value === "object" ? value : {};
40
+ return {
41
+ usd: typeof record.usd === "number" && Number.isFinite(record.usd) ? record.usd : null,
42
+ warnings: Array.isArray(record.warnings) ? record.warnings.filter((entry) => typeof entry === "string") : [],
43
+ };
44
+ }
45
+ export function emptyGoalEstimates() {
46
+ return { frame: { usd: null, warnings: [] }, storyboards: { usd: null, warnings: [] }, videos: { usd: null, warnings: [] }, total: { usd: null, warnings: [] } };
47
+ }
48
+ function estimatesFrom(value) {
49
+ const record = value && typeof value === "object" ? value : {};
50
+ if (!("total" in record))
51
+ return { ...emptyGoalEstimates(), videos: estimateFrom(value), total: estimateFrom(value) };
52
+ return { frame: estimateFrom(record.frame), storyboards: estimateFrom(record.storyboards), videos: estimateFrom(record.videos), total: estimateFrom(record.total) };
53
+ }
54
+ function charactersFrom(value) {
55
+ if (!Array.isArray(value))
56
+ return [];
57
+ return value.filter((entry) => entry && typeof entry === "object"
58
+ && ["artifactId", "cellId", "address", "label"].every(key => typeof entry[key] === "string"));
59
+ }
60
+ function mediaFrom(value) {
61
+ const parsed = z.array(z.unknown()).safeParse(value);
62
+ if (!parsed.success)
63
+ return [];
64
+ return parsed.data.flatMap(entry => {
65
+ const media = goalMediaRefSchema.safeParse(entry);
66
+ return media.success ? [media.data] : [];
67
+ });
68
+ }
69
+ export function goalContent(cell) {
70
+ const inputs = cell.inputs ?? {};
71
+ const plan = z.union([goalPlanV3Schema, goalPlanSchema, legacyGoalPlanSchema]).safeParse(inputs.plan);
72
+ const requestedStyle = goalStyleSchema.safeParse(inputs.requestedStyle);
73
+ const media = mediaFrom(inputs.media);
74
+ return {
75
+ brief: cell.prompt ?? "",
76
+ characters: charactersFrom(inputs.characters),
77
+ ...(media.length > 0 ? { media } : {}),
78
+ revision: typeof inputs.revision === "number" && Number.isInteger(inputs.revision) ? inputs.revision : 0,
79
+ plan: plan.success ? plan.data : null,
80
+ ...(!plan.success && requestedStyle.success ? { requestedStyle: requestedStyle.data } : {}),
81
+ estimate: estimatesFrom(inputs.estimate),
82
+ };
83
+ }
84
+ function goalCellInputs(goalId, content) {
85
+ return { goalId, revision: content.revision, plan: content.plan, characters: content.characters, estimate: content.estimate,
86
+ ...(content.media ? { media: content.media } : {}),
87
+ ...(!content.plan && content.requestedStyle ? { requestedStyle: content.requestedStyle } : {}),
88
+ };
89
+ }
90
+ function goalCellText(content) {
91
+ return { label: content.plan?.title ?? GOAL_TILE_LABEL, prompt: content.brief };
92
+ }
93
+ export function findGoalCell(document, goal) {
94
+ return document.cells.find((cell) => cell.id === goal.cellId && cell.type === "goal") ?? null;
95
+ }
96
+ export function readGoalCell(engine, goal) {
97
+ const notebook = engine.notebooks.read(goal.notebookId);
98
+ if (!notebook.ok)
99
+ throw new Error(notebook.error.message);
100
+ return findGoalCell(notebook.value, goal);
101
+ }
102
+ export function requireGoalContent(engine, goal) {
103
+ const cell = readGoalCell(engine, goal);
104
+ if (!cell)
105
+ throw new Error(REMOVED_TILE_ERROR);
106
+ return goalContent(cell);
107
+ }
108
+ export async function createGoalCell(engine, notebookId, goalId, content) {
109
+ const created = { cell: null };
110
+ const result = await mutateNotebook(engine, notebookId, "goal_create", (document) => {
111
+ const cell = engine.notebooks.createCell({
112
+ type: "goal",
113
+ ...goalCellText(content),
114
+ slot: firstEmptyNotebookGridSlot(notebookOccupiedSlots(document.cells)),
115
+ inputs: goalCellInputs(goalId, content),
116
+ });
117
+ created.cell = cell;
118
+ const edges = content.characters.map((character, index) => engine.notebooks.createEdge({
119
+ source: character.cellId, target: cell.id, targetInput: index === 0 ? "character" : `character_${index + 1}`,
120
+ }));
121
+ const arranged = arrangeGoalNotebook({ ...document, cells: [...document.cells, cell], edges: [...document.edges, ...edges] });
122
+ created.cell = arranged.cells.find(candidate => candidate.id === cell.id);
123
+ return arranged;
124
+ }, { goalId });
125
+ if (!result.ok)
126
+ throw new Error(result.error.message);
127
+ if (!created.cell)
128
+ throw new Error("The goal tile could not be placed");
129
+ return created.cell;
130
+ }
131
+ export async function writeGoalContent(engine, goal, content) {
132
+ const result = await mutateNotebook(engine, goal.notebookId, "goal_plan", (document) => {
133
+ if (!findGoalCell(document, goal))
134
+ throw new Error(REMOVED_TILE_ERROR);
135
+ return {
136
+ ...document,
137
+ cells: document.cells.map((cell) => cell.id === goal.cellId
138
+ ? { ...cell, ...goalCellText(content), inputs: goalCellInputs(goal.goalId, content) }
139
+ : cell),
140
+ };
141
+ }, { goalId: goal.goalId });
142
+ if (!result.ok)
143
+ throw new Error(result.error.message);
144
+ }