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,87 @@
1
+ import { parseModelId } from "./media/model-id.js";
2
+ const PROVIDER_LABELS = {
3
+ alibaba: "Alibaba",
4
+ elevenlabs: "ElevenLabs",
5
+ fal: "Fal",
6
+ kie: "Kie",
7
+ openai: "OpenAI",
8
+ workflow: "Workflow",
9
+ xai: "xAI",
10
+ };
11
+ const SENSITIVE_ENV_KEY = /(?:^|_)(?:api_key|access_key_id|secret_access_key|token|secret|password|authorization|credential)(?:_|$)/i;
12
+ const SENSITIVE_FIELD = /((?:api[_-]?key|secret[_-]?access[_-]?key|access[_-]?key(?:[_-]?id)?|access[_-]?token|refresh[_-]?token|token|secret|password|authorization|credential)\s*["']?\s*[:=]\s*)(?:"[^"]*"|'[^']*'|Bearer\s+[^\s,;}\]]+|[^\s,;}\]]+)/gi;
13
+ const SENSITIVE_QUERY = /([?&](?:api[_-]?key|key|token|access[_-]?token|refresh[_-]?token|signature|sig|credential|x-amz-credential|x-amz-signature|x-goog-signature)=)[^&\s"'<>]*/gi;
14
+ function providerCell(engine, reference) {
15
+ const notebook = engine.notebooks.read(reference.notebookId);
16
+ if (!notebook.ok)
17
+ return null;
18
+ return notebook.value.cells.find((cell) => cell.id === reference.cellId) ?? null;
19
+ }
20
+ function providerLabel(cell) {
21
+ const key = cell?.provider?.trim() || parseModelId(cell?.model ?? "")?.provider;
22
+ if (!key)
23
+ return "Provider";
24
+ return PROVIDER_LABELS[key.toLowerCase()]
25
+ ?? key.replaceAll("_", " ").replace(/^./, (character) => character.toUpperCase());
26
+ }
27
+ function redactEnvironmentSecrets(message) {
28
+ let safe = message;
29
+ for (const [key, value] of Object.entries(process.env)) {
30
+ if (!value || value.length < 8 || !SENSITIVE_ENV_KEY.test(key))
31
+ continue;
32
+ safe = safe.replaceAll(value, "[redacted]");
33
+ }
34
+ return safe;
35
+ }
36
+ function sanitizeProviderFailureMessage(message) {
37
+ const safe = redactEnvironmentSecrets(message
38
+ .replace(SENSITIVE_FIELD, "$1[redacted]")
39
+ .replace(SENSITIVE_QUERY, "$1[redacted]"))
40
+ .replace(/\bBearer\s+[A-Za-z0-9._~+/=-]+/gi, "Bearer [redacted]")
41
+ .replace(/\bsk-[A-Za-z0-9_-]{16,}\b/g, "[redacted]")
42
+ .replace(/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/g, "[redacted]")
43
+ .replace(/\p{Cc}+/gu, " ")
44
+ .replace(/\s+/g, " ")
45
+ .trim();
46
+ return safe.length > 800 ? `${safe.slice(0, 799)}…` : safe;
47
+ }
48
+ export function notebookProviderFailureMessage(engine, reference) {
49
+ const fallback = `Provider output ${reference.providerArtifactId} failed`;
50
+ const failure = engine.jobs.failures.read(reference.providerArtifactId);
51
+ if (!failure.ok || !failure.value)
52
+ return fallback;
53
+ const message = sanitizeProviderFailureMessage(failure.value.message);
54
+ const failCode = failure.value.failCode
55
+ ? sanitizeProviderFailureMessage(failure.value.failCode).slice(0, 120)
56
+ : "";
57
+ if (!message && !failCode)
58
+ return fallback;
59
+ const technical = message || failCode;
60
+ const detail = failCode && !technical.toLowerCase().includes(failCode.toLowerCase())
61
+ ? `${technical} (${failCode})`
62
+ : technical;
63
+ const prefix = `${providerLabel(providerCell(engine, reference))} failed: ${detail}`;
64
+ return prefix;
65
+ }
66
+ export function hydrateNotebookProviderFailures(engine, document) {
67
+ const execution = document.execution ?? {};
68
+ let changed = false;
69
+ const hydrated = Object.fromEntries(Object.entries(execution).map(([cellId, state]) => {
70
+ const providerArtifactId = state.providerArtifactId;
71
+ if (state.status !== "error"
72
+ || !providerArtifactId
73
+ || state.error !== `Provider output ${providerArtifactId} failed`) {
74
+ return [cellId, state];
75
+ }
76
+ const error = notebookProviderFailureMessage(engine, {
77
+ notebookId: document.id,
78
+ cellId,
79
+ providerArtifactId,
80
+ });
81
+ if (error === state.error)
82
+ return [cellId, state];
83
+ changed = true;
84
+ return [cellId, { ...state, error }];
85
+ }));
86
+ return changed ? { ...document, execution: hydrated } : document;
87
+ }
@@ -0,0 +1,26 @@
1
+ export const PUBLISHED_POST_SOURCE_OPERATION = "post_to_x";
2
+ export const PUBLISHED_POST_TARGET_INPUT = "post";
3
+ export function isPublishedPostCell(cell) {
4
+ return cell.type === "post" || cell.inputs?.sourceOperation === PUBLISHED_POST_SOURCE_OPERATION;
5
+ }
6
+ export function sourceCellForPostedArtifact(notebook, artifactId, cellType) {
7
+ const holders = notebook.cells.filter((cell) => cell.outputArtifactId === artifactId && !isPublishedPostCell(cell));
8
+ if (cellType) {
9
+ const typed = holders.find((cell) => cell.type === cellType);
10
+ if (typed)
11
+ return typed;
12
+ }
13
+ return holders.find((cell) => cell.type === "video" || cell.type === "image")
14
+ ?? holders[0]
15
+ ?? null;
16
+ }
17
+ export function resolvePublishedPostSourceCell(document, cell) {
18
+ if (!isPublishedPostCell(cell))
19
+ return cell;
20
+ const sourceId = cell.type === "post" ? cell.inputs?.post?.source?.cellId : typeof cell.inputs?.sourceCellId === "string"
21
+ ? cell.inputs.sourceCellId
22
+ : null;
23
+ if (!sourceId)
24
+ return cell;
25
+ return document.cells.find((candidate) => candidate.id === sourceId) ?? cell;
26
+ }
@@ -0,0 +1,227 @@
1
+ import { isUuidV7, resolveNotebookCellArtifactId, } from "videobook-engine";
2
+ import { notebookGridAddress, notebookGridTag, parseNotebookGridAddress, } from "videobook-engine/notebook-grid";
3
+ import { NOTEBOOK_GRID_ADDRESS_SOURCE, normalizeNotebookReference, replaceNotebookMentions, scanNotebookMentions, } from "videobook-engine/notebook-mentions";
4
+ import { generationInputMentions, scanGenerationInputTokens, } from "./generation-input-mentions.js";
5
+ function mediaType(cell) {
6
+ if (cell.type === "image"
7
+ || cell.type === "generate_image")
8
+ return "image";
9
+ if (cell.type === "audio"
10
+ || cell.type === "extract_audio"
11
+ || cell.type === "generate_audio")
12
+ return "audio";
13
+ if (cell.type === "video"
14
+ || cell.type === "split_video"
15
+ || cell.type === "generate_video"
16
+ || cell.type === "concat"
17
+ || cell.type === "splice")
18
+ return "video";
19
+ return null;
20
+ }
21
+ function artifactRecord(engine, artifactId) {
22
+ if (!engine)
23
+ return { artifactId };
24
+ const artifact = engine.artifacts.get(artifactId);
25
+ return artifact.ok
26
+ ? {
27
+ artifactId: artifact.value.artifactId,
28
+ ...(artifact.value.label ? { artifactLabel: artifact.value.label } : {}),
29
+ }
30
+ : null;
31
+ }
32
+ function directArtifact(engine, reference) {
33
+ if (!engine || !isUuidV7(reference))
34
+ return null;
35
+ return artifactRecord(engine, reference);
36
+ }
37
+ function cellMatches(documents, reference) {
38
+ const slot = parseNotebookGridAddress(reference);
39
+ if (slot) {
40
+ return documents.flatMap((document) => {
41
+ const cell = document.cells.find((candidate) => candidate.slot.row === slot.row
42
+ && candidate.slot.column === slot.column);
43
+ return cell ? [{ document, cell }] : [];
44
+ });
45
+ }
46
+ const exact = documents.flatMap((document) => document.cells
47
+ .filter((cell) => cell.id.toLowerCase() === reference)
48
+ .map((cell) => ({ document, cell })));
49
+ if (exact.length > 0)
50
+ return exact;
51
+ return documents.flatMap((document) => document.cells
52
+ .filter((cell) => cell.id.toLowerCase().startsWith(reference))
53
+ .map((cell) => ({ document, cell })));
54
+ }
55
+ function issue(mention, reference, code, message) {
56
+ return { mention, reference, code, message };
57
+ }
58
+ export function resolveNotebookArtifactReference(input) {
59
+ const reference = normalizeNotebookReference(input.reference);
60
+ const mention = `@${reference}`;
61
+ if (!reference) {
62
+ return issue(mention, reference, "not_found", "Notebook reference is required");
63
+ }
64
+ const direct = directArtifact(input.engine, reference);
65
+ if (direct)
66
+ return { mention, reference, ...direct };
67
+ const matches = cellMatches(input.documents, reference);
68
+ if (matches.length === 0) {
69
+ return issue(mention, reference, "not_found", `Notebook reference ${mention} was not found`);
70
+ }
71
+ const mediaMatches = input.requireMedia === false
72
+ ? matches
73
+ : matches.filter(({ cell }) => mediaType(cell) !== null);
74
+ if (mediaMatches.length === 0) {
75
+ return issue(mention, reference, "not_media", `${mention} is not a media-producing cell`);
76
+ }
77
+ const outputMatches = mediaMatches.flatMap(({ document, cell }) => {
78
+ const artifactId = resolveNotebookCellArtifactId(document, cell);
79
+ return typeof artifactId === "string"
80
+ ? [{ document, cell, artifactId }]
81
+ : [];
82
+ });
83
+ if (outputMatches.length === 0) {
84
+ return issue(mention, reference, "no_output", `${mention} does not have media output yet`);
85
+ }
86
+ const artifactIds = [...new Set(outputMatches.map(({ artifactId }) => artifactId))];
87
+ if (artifactIds.length > 1) {
88
+ return issue(mention, reference, "ambiguous", `Notebook reference ${mention} is ambiguous; include notebook_id or a longer cell id`);
89
+ }
90
+ const artifact = artifactRecord(input.engine, artifactIds[0]);
91
+ if (!artifact) {
92
+ return issue(mention, reference, "not_found", `Media output for ${mention} was not found`);
93
+ }
94
+ const match = outputMatches[0];
95
+ return {
96
+ mention,
97
+ reference,
98
+ ...artifact,
99
+ cellId: match.cell.id,
100
+ cellAddress: notebookGridTag(match.cell.slot),
101
+ };
102
+ }
103
+ export function resolveNotebookPromptReferences(input) {
104
+ const resolved = [];
105
+ const unresolved = [];
106
+ const seen = new Set();
107
+ for (const mention of scanNotebookMentions(input.prompt)) {
108
+ if (seen.has(mention.reference))
109
+ continue;
110
+ seen.add(mention.reference);
111
+ const result = resolveNotebookArtifactReference({
112
+ engine: input.engine,
113
+ documents: [input.document],
114
+ reference: mention.reference,
115
+ requireMedia: input.requireMedia,
116
+ });
117
+ if ("code" in result) {
118
+ unresolved.push({ ...result, mention: mention.raw });
119
+ }
120
+ else {
121
+ resolved.push({ ...result, mention: mention.raw });
122
+ }
123
+ }
124
+ const prompt = replaceNotebookMentions(input.prompt, resolved.map((item) => ({
125
+ reference: item.reference,
126
+ replacement: `@${item.artifactId}`,
127
+ })));
128
+ const unconnected = input.connectedArtifactIds
129
+ ? resolved
130
+ .filter((item) => !input.connectedArtifactIds.has(item.artifactId))
131
+ .map((item) => ({
132
+ ...item,
133
+ message: `${item.mention} is referenced but not connected`,
134
+ }))
135
+ : [];
136
+ return { prompt, resolved, unresolved, unconnected };
137
+ }
138
+ function inputTokenResolution(engine, document, token, sourceCellId) {
139
+ const mention = `@${token}`;
140
+ if (!sourceCellId) {
141
+ return issue(mention, token, "not_found", `${mention} is not a connected input`);
142
+ }
143
+ const cell = document.cells.find((candidate) => candidate.id === sourceCellId);
144
+ const artifactId = cell ? resolveNotebookCellArtifactId(document, cell) : undefined;
145
+ if (!cell || typeof artifactId !== "string") {
146
+ return issue(mention, token, "no_output", `${mention} does not have media output yet`);
147
+ }
148
+ const artifact = artifactRecord(engine, artifactId);
149
+ if (!artifact) {
150
+ return issue(mention, token, "not_found", `Media output for ${mention} was not found`);
151
+ }
152
+ return {
153
+ mention,
154
+ reference: token,
155
+ ...artifact,
156
+ cellId: cell.id,
157
+ cellAddress: notebookGridTag(cell.slot),
158
+ };
159
+ }
160
+ function gridAddressIssues(prompt) {
161
+ const seen = new Set();
162
+ return scanNotebookMentions(prompt).flatMap((mention) => {
163
+ if (seen.has(mention.reference))
164
+ return [];
165
+ seen.add(mention.reference);
166
+ return [issue(mention.raw, mention.reference, "not_found", `${mention.raw} is a grid address; name connected inputs as @image1, @video1, @audio1`)];
167
+ });
168
+ }
169
+ /** Resolve "@image1"-style input tokens in a generation prompt to
170
+ * "@<artifact-id>". Grid addresses are not inputs and stay unresolved. */
171
+ export function resolveGenerationInputReferences(input) {
172
+ const sources = new Map(generationInputMentions(input.cell.id, input.document.cells, input.document.edges, typeof input.cell.inputs?.generationMode === "string" ? input.cell.inputs.generationMode : undefined)
173
+ .map((mention) => [mention.token, mention.sourceCellId]));
174
+ if (input.cell.inputs?.generationMode === "r2v") {
175
+ for (const mention of generationInputMentions(input.cell.id, input.document.cells, input.document.edges, "i2v")) {
176
+ if (mention.token === "firstframe" || mention.token === "lastframe") {
177
+ sources.set(mention.token, mention.sourceCellId);
178
+ }
179
+ }
180
+ }
181
+ const resolved = [];
182
+ const unresolved = [];
183
+ for (const token of new Set(scanGenerationInputTokens(input.prompt))) {
184
+ const result = inputTokenResolution(input.engine, input.document, token, sources.get(token));
185
+ if ("code" in result)
186
+ unresolved.push(result);
187
+ else
188
+ resolved.push(result);
189
+ }
190
+ const prompt = replaceNotebookMentions(input.prompt, resolved.map((item) => ({
191
+ reference: item.reference,
192
+ replacement: `@${item.artifactId}`,
193
+ })));
194
+ return {
195
+ prompt,
196
+ resolved,
197
+ unresolved: [...unresolved, ...gridAddressIssues(prompt)],
198
+ unconnected: [],
199
+ };
200
+ }
201
+ // A spoken or typed request names a cell the way the grid labels it: "the image
202
+ // at A1". Bare like that it is prose, so nothing above resolves it, the draft
203
+ // connects no inputs, and the generation prompt keeps words where an address
204
+ // belongs. Tagging closes that gap, but only for addresses this notebook can
205
+ // actually answer -- an unmatched token stays prose.
206
+ const BARE_GRID_ADDRESS = new RegExp(`(?<![\\w@-])(?:${NOTEBOOK_GRID_ADDRESS_SOURCE})(?![\\w-])`, "giu");
207
+ /** Addresses of cells that already hold media this notebook can reference. */
208
+ export function notebookMediaAddresses(document) {
209
+ const addresses = new Set();
210
+ for (const cell of document.cells) {
211
+ if (mediaType(cell) === null)
212
+ continue;
213
+ if (typeof resolveNotebookCellArtifactId(document, cell) !== "string") {
214
+ continue;
215
+ }
216
+ addresses.add(notebookGridAddress(cell.slot));
217
+ }
218
+ return addresses;
219
+ }
220
+ export function tagNotebookGridAddresses(text, addresses) {
221
+ if (addresses.size === 0)
222
+ return text;
223
+ return text.replace(BARE_GRID_ADDRESS, (match) => {
224
+ const address = match.toLowerCase();
225
+ return addresses.has(address) ? `@${address}` : match;
226
+ });
227
+ }
@@ -0,0 +1,270 @@
1
+ import { notebookCellOccupiedSlots, nearestOriginNotebookGridSlot, nextHorizontalSlotFrom, nextVerticalSlotFrom, nextWaveTileSlot, NOTEBOOK_GRID_COLUMN_COUNT, } from "videobook-engine";
2
+ import { ensureGenerationMediaOutputs, findGenerateAudioOutput, findGenerateImageOutput, findGenerateVideoOutput, } from "./notebook-cell-outputs.js";
3
+ import { slotBelow, slotRight } from "./notebook-placement.js";
4
+ import { arrangeGoalNotebook } from "./notebook-goal-layout.js";
5
+ function bySlotThenId(left, right) {
6
+ if (left.slot.row !== right.slot.row)
7
+ return left.slot.row - right.slot.row;
8
+ if (left.slot.column !== right.slot.column) {
9
+ return left.slot.column - right.slot.column;
10
+ }
11
+ return left.id.localeCompare(right.id);
12
+ }
13
+ function isGenerateVideoOutputCell(document, cell) {
14
+ if (cell.type !== "video")
15
+ return false;
16
+ if (cell.inputs?.mediaRole === "generate-video-output")
17
+ return true;
18
+ const producerId = cell.inputs?.producerCellId;
19
+ if (typeof producerId !== "string")
20
+ return false;
21
+ return document.cells.some((candidate) => candidate.id === producerId && candidate.type === "generate_video");
22
+ }
23
+ function isGenerateImageOutputCell(document, cell) {
24
+ if (cell.type !== "image")
25
+ return false;
26
+ if (cell.inputs?.mediaRole === "generate-image-output")
27
+ return true;
28
+ const producerId = cell.inputs?.producerCellId;
29
+ if (typeof producerId !== "string")
30
+ return false;
31
+ return document.cells.some((candidate) => candidate.id === producerId && candidate.type === "generate_image");
32
+ }
33
+ function isGenerateAudioOutputCell(document, cell) {
34
+ if (cell.type !== "audio")
35
+ return false;
36
+ if (cell.inputs?.mediaRole === "generate-audio-output")
37
+ return true;
38
+ const producerId = cell.inputs?.producerCellId;
39
+ if (typeof producerId !== "string")
40
+ return false;
41
+ return document.cells.some((candidate) => candidate.id === producerId && candidate.type === "generate_audio");
42
+ }
43
+ function isExtractFrameOutputCell(cell) {
44
+ return cell.type === "image"
45
+ && cell.inputs?.mediaRole === "extract-frame-output";
46
+ }
47
+ function migrateGenerationArtifacts(engine, document) {
48
+ return ensureGenerationMediaOutputs(engine, document);
49
+ }
50
+ function assignDirectionalSlots(document) {
51
+ const newSlots = new Map();
52
+ const occupied = [];
53
+ function claim(cellId, slot) {
54
+ newSlots.set(cellId, slot);
55
+ occupied.push(slot);
56
+ }
57
+ const cells = [...document.cells].sort(bySlotThenId);
58
+ for (const cell of cells) {
59
+ if (cell.type !== "timeline")
60
+ continue;
61
+ newSlots.set(cell.id, cell.slot);
62
+ occupied.push(...notebookCellOccupiedSlots(cell));
63
+ }
64
+ for (const cell of cells) {
65
+ if (cell.type !== "image"
66
+ || isExtractFrameOutputCell(cell)
67
+ || isGenerateImageOutputCell(document, cell)) {
68
+ continue;
69
+ }
70
+ claim(cell.id, nextHorizontalSlotFrom({ row: 0, column: 0 }, occupied));
71
+ }
72
+ for (const cell of cells) {
73
+ if (cell.type !== "video" || isGenerateVideoOutputCell(document, cell)) {
74
+ continue;
75
+ }
76
+ claim(cell.id, nextVerticalSlotFrom({ row: 0, column: 0 }, occupied));
77
+ }
78
+ for (const cell of cells) {
79
+ if (cell.type !== "audio" || isGenerateAudioOutputCell(document, cell)) {
80
+ continue;
81
+ }
82
+ claim(cell.id, nearestOriginNotebookGridSlot(occupied));
83
+ }
84
+ // Wave/lane placement, dependency-ordered so a generation lands below its
85
+ // sources and a frame chain continues its source video's column. Passes
86
+ // repeat until nothing new can be placed (unplaceable cells fall through
87
+ // to the catch-all).
88
+ function cellSources(target) {
89
+ const sources = [];
90
+ for (const edge of document.edges) {
91
+ if (edge.target !== target.id)
92
+ continue;
93
+ const source = document.cells.find((cell) => cell.id === edge.source);
94
+ if (!source)
95
+ continue;
96
+ sources.push(source);
97
+ }
98
+ return sources.every((source) => newSlots.has(source.id))
99
+ ? sources
100
+ : null;
101
+ }
102
+ function claimGenerateImagePair(tile, tileSlot) {
103
+ claim(tile.id, tileSlot);
104
+ const output = findGenerateImageOutput(document, tile.id);
105
+ if (output && !newSlots.has(output.outputCell.id)) {
106
+ claim(output.outputCell.id, nextHorizontalSlotFrom(slotRight(tileSlot), occupied));
107
+ }
108
+ }
109
+ function claimGenerateAudioPair(tile, tileSlot) {
110
+ claim(tile.id, tileSlot);
111
+ const output = findGenerateAudioOutput(document, tile.id);
112
+ if (output && !newSlots.has(output.outputCell.id)) {
113
+ claim(output.outputCell.id, nextHorizontalSlotFrom(slotRight(tileSlot), occupied));
114
+ }
115
+ }
116
+ let progressed = true;
117
+ while (progressed) {
118
+ progressed = false;
119
+ for (const tile of cells) {
120
+ if (tile.type !== "generate_image" || newSlots.has(tile.id))
121
+ continue;
122
+ const sources = cellSources(tile);
123
+ if (!sources)
124
+ continue;
125
+ const sourceSlots = sources.map((source) => newSlots.get(source.id));
126
+ const anchor = sourceSlots.length === 0
127
+ ? tile.slot
128
+ : {
129
+ row: Math.min(...sourceSlots.map((slot) => slot.row)),
130
+ column: Math.min(Math.max(...sourceSlots.map((slot) => slot.column)) + 1, NOTEBOOK_GRID_COLUMN_COUNT - 1),
131
+ };
132
+ claimGenerateImagePair(tile, nextHorizontalSlotFrom(anchor, occupied));
133
+ progressed = true;
134
+ }
135
+ for (const tile of cells) {
136
+ if (tile.type !== "generate_audio" || newSlots.has(tile.id))
137
+ continue;
138
+ const sources = cellSources(tile);
139
+ if (!sources)
140
+ continue;
141
+ const sourceSlots = sources.map((source) => newSlots.get(source.id));
142
+ const anchor = sourceSlots.length === 0
143
+ ? tile.slot
144
+ : {
145
+ row: Math.min(...sourceSlots.map((slot) => slot.row)),
146
+ column: Math.min(Math.max(...sourceSlots.map((slot) => slot.column)) + 1, NOTEBOOK_GRID_COLUMN_COUNT - 1),
147
+ };
148
+ claimGenerateAudioPair(tile, nextHorizontalSlotFrom(anchor, occupied));
149
+ progressed = true;
150
+ }
151
+ for (const tile of cells) {
152
+ if (tile.type !== "generate_video" || newSlots.has(tile.id))
153
+ continue;
154
+ const sources = cellSources(tile);
155
+ if (!sources)
156
+ continue;
157
+ const sourceSlots = sources.map((source) => newSlots.get(source.id));
158
+ const waveRow = sourceSlots.length > 0
159
+ ? Math.max(...sourceSlots.map((slot) => slot.row)) + 1
160
+ : tile.slot.row;
161
+ const baseRowSources = sourceSlots.length > 0
162
+ && sourceSlots.every((slot) => slot.row === 0);
163
+ const startColumn = sourceSlots.length === 0
164
+ ? tile.slot.column
165
+ : baseRowSources
166
+ ? 0
167
+ : sourceSlots[0].column;
168
+ const tileSlot = sourceSlots.length === 0
169
+ ? nextVerticalSlotFrom(tile.slot, occupied)
170
+ : nextWaveTileSlot(waveRow, startColumn, occupied);
171
+ claim(tile.id, tileSlot);
172
+ const output = findGenerateVideoOutput(document, tile.id);
173
+ if (output && !newSlots.has(output.outputCell.id)) {
174
+ claim(output.outputCell.id, nextVerticalSlotFrom(slotBelow(tileSlot), occupied));
175
+ }
176
+ progressed = true;
177
+ }
178
+ for (const action of cells) {
179
+ if (!isExtractFrameOutputCell(action) || newSlots.has(action.id))
180
+ continue;
181
+ const sourceEdge = document.edges.find((edge) => edge.target === action.id && edge.targetInput === "segment");
182
+ const sourceCellId = sourceEdge?.source
183
+ ?? (typeof action.inputs?.sourceCellId === "string"
184
+ ? action.inputs.sourceCellId
185
+ : undefined);
186
+ const sourceCell = sourceCellId
187
+ ? document.cells.find((cell) => cell.id === sourceCellId)
188
+ : undefined;
189
+ let videoSlot = null;
190
+ if (sourceCell?.type === "generate_video") {
191
+ const output = findGenerateVideoOutput(document, sourceCell.id);
192
+ const anchorCell = output?.outputCell ?? sourceCell;
193
+ videoSlot = newSlots.get(anchorCell.id) ?? null;
194
+ }
195
+ else if (sourceCell) {
196
+ videoSlot = newSlots.get(sourceCell.id) ?? null;
197
+ }
198
+ if (sourceCell && !videoSlot)
199
+ continue;
200
+ const anchor = videoSlot ?? { row: 0, column: 0 };
201
+ const actionSlot = nextHorizontalSlotFrom(slotRight(anchor), occupied);
202
+ claim(action.id, actionSlot);
203
+ progressed = true;
204
+ }
205
+ }
206
+ for (const cell of cells) {
207
+ if (newSlots.has(cell.id))
208
+ continue;
209
+ if (cell.type === "generate_image") {
210
+ claimGenerateImagePair(cell, nextHorizontalSlotFrom(cell.slot, occupied));
211
+ continue;
212
+ }
213
+ if (cell.type === "generate_audio") {
214
+ claimGenerateAudioPair(cell, nextHorizontalSlotFrom(cell.slot, occupied));
215
+ continue;
216
+ }
217
+ claim(cell.id, nearestOriginNotebookGridSlot(occupied));
218
+ }
219
+ return {
220
+ ...document,
221
+ cells: document.cells.map((cell) => ({
222
+ ...cell,
223
+ slot: newSlots.get(cell.id) ?? cell.slot,
224
+ })),
225
+ };
226
+ }
227
+ export function relayoutNotebookDocument(engine, document) {
228
+ const migrated = migrateGenerationArtifacts(engine, document);
229
+ if (migrated.cells.some(cell => cell.type === "goal"))
230
+ return arrangeGoalNotebook(migrated);
231
+ return assignDirectionalSlots(migrated);
232
+ }
233
+ export function notebookDocumentsEqual(left, right) {
234
+ const leftCells = [...left.cells]
235
+ .map((cell) => ({
236
+ id: cell.id,
237
+ type: cell.type,
238
+ slot: cell.slot,
239
+ outputArtifactId: cell.outputArtifactId ?? null,
240
+ inputs: cell.inputs ?? {},
241
+ }))
242
+ .sort((a, b) => a.id.localeCompare(b.id));
243
+ const rightCells = [...right.cells]
244
+ .map((cell) => ({
245
+ id: cell.id,
246
+ type: cell.type,
247
+ slot: cell.slot,
248
+ outputArtifactId: cell.outputArtifactId ?? null,
249
+ inputs: cell.inputs ?? {},
250
+ }))
251
+ .sort((a, b) => a.id.localeCompare(b.id));
252
+ const leftEdges = [...left.edges]
253
+ .map((edge) => ({
254
+ source: edge.source,
255
+ target: edge.target,
256
+ targetInput: edge.targetInput,
257
+ }))
258
+ .sort((a, b) => `${a.source}:${a.target}:${a.targetInput}`
259
+ .localeCompare(`${b.source}:${b.target}:${b.targetInput}`));
260
+ const rightEdges = [...right.edges]
261
+ .map((edge) => ({
262
+ source: edge.source,
263
+ target: edge.target,
264
+ targetInput: edge.targetInput,
265
+ }))
266
+ .sort((a, b) => `${a.source}:${a.target}:${a.targetInput}`
267
+ .localeCompare(`${b.source}:${b.target}:${b.targetInput}`));
268
+ return JSON.stringify({ cells: leftCells, edges: leftEdges })
269
+ === JSON.stringify({ cells: rightCells, edges: rightEdges });
270
+ }