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,45 @@
1
+ import { isGenerationCreditError } from "./generation-credit-error.js";
2
+ export function creditRetryProducer(document, outputCellId) {
3
+ const output = document.cells.find((cell) => cell.id === outputCellId);
4
+ if (!output || !["image", "video", "audio"].includes(output.type))
5
+ return null;
6
+ const edge = document.edges.find((candidate) => candidate.target === output.id && candidate.targetInput === "media");
7
+ return document.cells.find((cell) => cell.id === edge?.source && cell.type === `generate_${output.type}`) ?? null;
8
+ }
9
+ export function removeCreditFailedOutput(engine, document, producerCellId, outputCellId) {
10
+ const producer = creditRetryProducer(document, outputCellId);
11
+ if (producer?.id !== producerCellId) {
12
+ throw new Error("The failed output no longer belongs to this generator");
13
+ }
14
+ if (producer.type === "generate_audio" && document.edges.some((edge) => edge.source === producer.id && edge.targetInput === "media" && edge.target !== outputCellId
15
+ && document.cells.some((cell) => cell.id === edge.target && cell.type === "audio"))) {
16
+ throw new Error("This generator has another audio output; retry would replace that media");
17
+ }
18
+ const output = document.cells.find((cell) => cell.id === outputCellId);
19
+ const state = document.execution?.[outputCellId];
20
+ const providerArtifactId = state?.providerArtifactId ?? output.outputArtifactId;
21
+ if ((output.outputArtifactId && output.outputArtifactId !== providerArtifactId)
22
+ || (Array.isArray(output.inputs?.outputVersionArtifactIds)
23
+ && output.inputs.outputVersionArtifactIds.some((id) => id !== providerArtifactId))) {
24
+ throw new Error("This output contains earlier media; run its generator to preserve those versions");
25
+ }
26
+ const failure = providerArtifactId ? engine.jobs.failures.read(providerArtifactId) : null;
27
+ const pending = providerArtifactId ? engine.jobs.pending.read(providerArtifactId) : null;
28
+ const message = failure?.ok && failure.value
29
+ ? `${failure.value.message} ${failure.value.failCode ?? ""}`
30
+ : state?.error;
31
+ if ((state && state.status !== "error")
32
+ || (providerArtifactId && (!failure?.ok || !failure.value))
33
+ || (pending?.ok && pending.value)
34
+ || !isGenerationCreditError(message)) {
35
+ throw new Error("Retry with deletion is only available for an out-of-credits failure");
36
+ }
37
+ const execution = { ...document.execution };
38
+ delete execution[outputCellId];
39
+ return {
40
+ ...document,
41
+ cells: document.cells.filter((cell) => cell.id !== outputCellId),
42
+ edges: document.edges.filter((edge) => edge.source !== outputCellId && edge.target !== outputCellId),
43
+ execution,
44
+ };
45
+ }
@@ -0,0 +1,8 @@
1
+ export const MULTYCULTY_FIXTURE_OWNER = "multyculty-default";
2
+ export function analysisFixtureForCell(cell) {
3
+ if (cell.inputs?.fixtureOwner === MULTYCULTY_FIXTURE_OWNER)
4
+ return null;
5
+ return cell.inputs?.fixtureAnalysis
6
+ ?? cell.inputs?.analysisFixture
7
+ ?? null;
8
+ }
@@ -0,0 +1,77 @@
1
+ import { generationModeInputError } from "./generation-input-policy.js";
2
+ function slotKind(role) {
3
+ if (role === "video")
4
+ return "video";
5
+ if (role === "audio")
6
+ return "audio";
7
+ return "image";
8
+ }
9
+ function modeSlots(model, roles) {
10
+ const slots = model.slots
11
+ .filter((slot) => roles.includes(slot.role))
12
+ .map((slot) => ({ field: slot.role, kind: slotKind(slot.role), targets: [slot.role], min: slot.min, max: slot.max }));
13
+ return model.media === "video"
14
+ ? [...slots, { field: "replace_audio", kind: "audio", targets: ["replace_audio"], min: 0, max: 1 }]
15
+ : slots;
16
+ }
17
+ export function notebookGenerationInputContract(model) {
18
+ return {
19
+ modes: model.modes.map((mode) => ({
20
+ id: mode.id,
21
+ slots: modeSlots(model, mode.roles),
22
+ requiredGroups: mode.requireAny && mode.requireAny.length > 0 ? [[...mode.requireAny]] : [],
23
+ })),
24
+ };
25
+ }
26
+ function cellInputKind(cell) {
27
+ if (cell.type === "image"
28
+ || cell.type === "generate_image")
29
+ return "image";
30
+ if (cell.type === "video"
31
+ || cell.type === "split_video"
32
+ || cell.type === "generate_video"
33
+ || cell.type === "concat"
34
+ || cell.type === "splice")
35
+ return "video";
36
+ if (cell.type === "audio"
37
+ || cell.type === "extract_audio"
38
+ || cell.type === "generate_audio")
39
+ return "audio";
40
+ return null;
41
+ }
42
+ function connectedInputTarget(kind, targetInput) {
43
+ if (targetInput === "first_frame" || targetInput === "last_frame") {
44
+ return targetInput;
45
+ }
46
+ if (kind === "audio" && targetInput === "replace_audio") {
47
+ return targetInput;
48
+ }
49
+ return kind;
50
+ }
51
+ function connectedInputs(document, cell) {
52
+ const cells = new Map(document.cells.map((candidate) => [candidate.id, candidate]));
53
+ return document.edges.flatMap((edge) => {
54
+ if (edge.target !== cell.id)
55
+ return [];
56
+ const source = cells.get(edge.source);
57
+ const kind = source ? cellInputKind(source) : null;
58
+ return kind
59
+ ? [{ kind, target: connectedInputTarget(kind, edge.targetInput) }]
60
+ : [];
61
+ });
62
+ }
63
+ export function notebookGenerationInputsAreCompatible(contract, document, cell, modeId) {
64
+ const inputs = connectedInputs(document, cell);
65
+ const configuredModes = modeId
66
+ ? contract.modes.filter((candidate) => candidate.id === modeId)
67
+ : contract.modes;
68
+ const modes = modeId === "default" && configuredModes.length === 0
69
+ ? contract.modes
70
+ : configuredModes;
71
+ return modes.some((candidate) => generationModeInputError(candidate, inputs) === null);
72
+ }
73
+ export function notebookGenerationInputError(contract, document, cell, modeId) {
74
+ const candidate = contract.modes.find((mode) => mode.id === modeId)
75
+ ?? (contract.modes.length === 1 ? contract.modes[0] : undefined);
76
+ return candidate ? generationModeInputError(candidate, connectedInputs(document, cell)) : null;
77
+ }
@@ -0,0 +1,145 @@
1
+ const connectionOwnedFields = new Set([
2
+ "book_id",
3
+ "project_slug",
4
+ "prompt",
5
+ "text",
6
+ "character_image_refs",
7
+ "image_refs",
8
+ "image_ref",
9
+ "first_frame_ref",
10
+ "last_frame_ref",
11
+ "end_frame_ref",
12
+ "video_refs",
13
+ "motion_video_refs",
14
+ "video_ref",
15
+ "first_clip_ref",
16
+ "audio_refs",
17
+ "audio_ref",
18
+ "driving_audio_ref",
19
+ "replace_audio_with",
20
+ "_provider",
21
+ ]);
22
+ function record(value) {
23
+ return typeof value === "object" && value !== null && !Array.isArray(value)
24
+ ? value
25
+ : null;
26
+ }
27
+ function controlValue(value) {
28
+ return typeof value === "string"
29
+ || typeof value === "number"
30
+ || typeof value === "boolean"
31
+ ? value
32
+ : undefined;
33
+ }
34
+ function labelFor(name) {
35
+ if (name === "model")
36
+ return "Variant";
37
+ if (name === "output_resolution")
38
+ return "Resolution";
39
+ return name
40
+ .replaceAll("_", " ")
41
+ .replace(/^./, (character) => character.toUpperCase());
42
+ }
43
+ function controlKind(property, options) {
44
+ if (options.length > 0) {
45
+ const valueType = options.every((value) => typeof value === "number")
46
+ ? "number"
47
+ : options.every((value) => typeof value === "boolean")
48
+ ? "boolean"
49
+ : "string";
50
+ return { kind: "select", valueType };
51
+ }
52
+ if (property.type === "boolean") {
53
+ return { kind: "boolean", valueType: "boolean" };
54
+ }
55
+ if (property.type === "integer" || property.type === "number") {
56
+ return { kind: "number", valueType: "number" };
57
+ }
58
+ if (property.type === "string") {
59
+ return { kind: "text", valueType: "string" };
60
+ }
61
+ return null;
62
+ }
63
+ export function notebookGenerationControls(value, overrides = {}) {
64
+ const schema = record(value);
65
+ const properties = record(schema?.properties);
66
+ if (!properties)
67
+ return [];
68
+ const required = new Set(Array.isArray(schema?.required)
69
+ ? schema.required.filter((entry) => typeof entry === "string")
70
+ : []);
71
+ const defaults = record(schema?.defaults) ?? {};
72
+ return Object.entries(properties).flatMap(([name, rawProperty]) => {
73
+ if (connectionOwnedFields.has(name))
74
+ return [];
75
+ const property = record(rawProperty);
76
+ if (!property)
77
+ return [];
78
+ const options = Array.isArray(property.enum)
79
+ ? property.enum.flatMap((entry) => {
80
+ const parsed = controlValue(entry);
81
+ return parsed === undefined ? [] : [parsed];
82
+ })
83
+ : [];
84
+ const type = controlKind(property, options);
85
+ if (!type)
86
+ return [];
87
+ const defaultValue = controlValue(overrides[name] ?? defaults[name] ?? property.default);
88
+ return [{
89
+ name,
90
+ label: labelFor(name),
91
+ ...type,
92
+ required: required.has(name),
93
+ ...(defaultValue === undefined ? {} : { defaultValue }),
94
+ ...(options.length === 0 ? {} : { options }),
95
+ ...(typeof property.minimum === "number"
96
+ ? { minimum: property.minimum }
97
+ : {}),
98
+ ...(typeof property.maximum === "number"
99
+ ? { maximum: property.maximum }
100
+ : {}),
101
+ ...(property.exclusiveMinimum === true ? { exclusiveMinimum: true } : {}),
102
+ ...(property.exclusiveMaximum === true ? { exclusiveMaximum: true } : {}),
103
+ description: typeof property.description === "string"
104
+ ? property.description
105
+ : labelFor(name),
106
+ }];
107
+ });
108
+ }
109
+ function optionControl(option) {
110
+ const options = option.enumValues.flatMap((value) => {
111
+ const parsed = controlValue(value);
112
+ return parsed === undefined ? [] : [parsed];
113
+ });
114
+ const kind = options.length > 0
115
+ ? "select"
116
+ : option.valueType === "boolean"
117
+ ? "boolean"
118
+ : option.valueType === "number" || option.valueType === "integer"
119
+ ? "number"
120
+ : option.valueType === "string" ? "text" : null;
121
+ if (!kind)
122
+ return null;
123
+ const valueType = options.length > 0
124
+ ? options.every((value) => typeof value === "number") ? "number" : "string"
125
+ : kind === "boolean" ? "boolean" : kind === "number" ? "number" : "string";
126
+ const defaultValue = controlValue(option.defaultValue);
127
+ return {
128
+ name: option.name,
129
+ label: labelFor(option.name),
130
+ kind,
131
+ valueType,
132
+ required: option.required,
133
+ ...(defaultValue === undefined ? {} : { defaultValue }),
134
+ ...(options.length === 0 ? {} : { options }),
135
+ ...(option.minimum !== undefined ? { minimum: option.minimum } : {}),
136
+ ...(option.maximum !== undefined ? { maximum: option.maximum } : {}),
137
+ description: option.description || labelFor(option.name),
138
+ };
139
+ }
140
+ export function controlsForModel(model) {
141
+ return model.options.flatMap((option) => {
142
+ const control = optionControl(option);
143
+ return control ? [control] : [];
144
+ });
145
+ }
@@ -0,0 +1,40 @@
1
+ import { NOTEBOOK_GRID_COLUMN_COUNT, NOTEBOOK_GRID_ROW_COUNT } from "videobook-engine/notebook-grid";
2
+ function readingOrder(left, right) {
3
+ return left.slot.row - right.slot.row || left.slot.column - right.slot.column || left.id.localeCompare(right.id);
4
+ }
5
+ export function arrangeGoalNotebook(document, reserve = {}) {
6
+ const goals = document.cells.filter(cell => cell.type === "goal").sort(readingOrder);
7
+ if (goals.length === 0)
8
+ return document;
9
+ const references = new Set(goals.flatMap(goal => Array.isArray(goal.inputs?.characters)
10
+ ? goal.inputs.characters.flatMap((character) => character && typeof character === "object" && "cellId" in character && typeof character.cellId === "string" ? [character.cellId] : [])
11
+ : []));
12
+ const outputs = new Set(document.edges.filter(edge => document.cells.some(cell => cell.id === edge.source && cell.type === "generate_image")).map(edge => edge.target));
13
+ const ordered = [...document.cells].sort((left, right) => left.id.localeCompare(right.id));
14
+ const referenceImages = document.cells.filter(cell => cell.type === "image" && (references.has(cell.id)
15
+ || !outputs.has(cell.id) && !cell.inputs?.producerCellId && !cell.inputs?.mediaRole)).sort(readingOrder);
16
+ const referenceIds = new Set(referenceImages.map(cell => cell.id));
17
+ const generators = ordered.filter(cell => cell.type.startsWith("generate_") || cell.type === "prompt");
18
+ const images = ordered.filter(cell => cell.type === "image" && !referenceIds.has(cell.id));
19
+ const videos = ordered.filter(cell => cell.type === "video");
20
+ const timelines = document.cells.filter(cell => cell.type === "timeline").sort(readingOrder);
21
+ const slots = new Map();
22
+ let row = 0;
23
+ const place = (cells, extra = 0, minimumRows = 1) => {
24
+ cells.forEach((cell, index) => slots.set(cell.id, { row: row + Math.floor(index / NOTEBOOK_GRID_COLUMN_COUNT), column: index % NOTEBOOK_GRID_COLUMN_COUNT }));
25
+ row += Math.max(minimumRows, Math.ceil((cells.length + extra) / NOTEBOOK_GRID_COLUMN_COUNT));
26
+ };
27
+ place(referenceImages, 0, 0);
28
+ place([...goals, ...generators], reserve.generators);
29
+ place(images, reserve.images);
30
+ place(videos, reserve.videos);
31
+ for (const timeline of timelines) {
32
+ slots.set(timeline.id, { row, column: 0 });
33
+ row += 1;
34
+ }
35
+ row += reserve.timelines ?? 0;
36
+ place(ordered.filter(cell => !slots.has(cell.id)), 0, 0);
37
+ if (row > NOTEBOOK_GRID_ROW_COUNT)
38
+ throw new Error(`The goal layout needs ${row} rows, but the grid supports ${NOTEBOOK_GRID_ROW_COUNT}. Remove unused cells before continuing.`);
39
+ return { ...document, cells: document.cells.map(cell => ({ ...cell, slot: slots.get(cell.id) })) };
40
+ }
@@ -0,0 +1,37 @@
1
+ export function notebookConnectionWouldCreateCycle(edges, sourceCellId, targetCellId) {
2
+ if (sourceCellId === targetCellId)
3
+ return true;
4
+ const children = new Map();
5
+ for (const edge of edges) {
6
+ const targets = children.get(edge.source) ?? [];
7
+ targets.push(edge.target);
8
+ children.set(edge.source, targets);
9
+ }
10
+ const visited = new Set();
11
+ const stack = [targetCellId];
12
+ while (stack.length > 0) {
13
+ const cellId = stack.pop();
14
+ if (!cellId || visited.has(cellId))
15
+ continue;
16
+ if (cellId === sourceCellId)
17
+ return true;
18
+ visited.add(cellId);
19
+ stack.push(...(children.get(cellId) ?? []));
20
+ }
21
+ return false;
22
+ }
23
+ export function notebookConnectionEdges(cells, edges, sourceCellId, targetCellId) {
24
+ if (!notebookConnectionWouldCreateCycle(edges, sourceCellId, targetCellId)) {
25
+ return edges;
26
+ }
27
+ const source = cells.find((cell) => cell.id === sourceCellId);
28
+ if (sourceCellId === targetCellId
29
+ || source?.type !== "image"
30
+ || !source.outputArtifactId)
31
+ return null;
32
+ const retained = edges.filter((edge) => edge.target !== sourceCellId
33
+ || !notebookConnectionWouldCreateCycle(edges, edge.source, targetCellId));
34
+ return notebookConnectionWouldCreateCycle(retained, sourceCellId, targetCellId)
35
+ ? null
36
+ : retained;
37
+ }
@@ -0,0 +1,84 @@
1
+ import { z } from "zod";
2
+ import { findImageEditModel } from "./image-edit-models.js";
3
+ import { resolveImageRef } from "./tools/_media-refs.js";
4
+ import { previewPlaceholderUrl } from "./preview-payload.js";
5
+ import { previewImageSubjectEditRequest } from "./jobs/image-subjects.js";
6
+ const boxSchema = z.object({
7
+ x: z.number().min(0).max(1), y: z.number().min(0).max(1),
8
+ width: z.number().positive().max(1), height: z.number().positive().max(1),
9
+ }).refine((box) => box.x + box.width <= 1.000001 && box.y + box.height <= 1.000001, { message: "Edit regions must fit inside the image" });
10
+ const editInputsSchema = z.object({
11
+ generationMode: z.enum(["whole-image", "subject-edit", "subject-remove", "region-edit", "region-remove", "region-replace"]),
12
+ sourceArtifactId: z.string().min(1),
13
+ sourceObjectHash: z.string().min(1),
14
+ subjectIds: z.array(z.string().min(1)).default([]),
15
+ editRegions: z.array(boxSchema).optional(),
16
+ regions: z.array(z.object({
17
+ box: boxSchema.optional(), subjectId: z.string().optional(),
18
+ replacementArtifactId: z.string().min(1), note: z.string().optional(),
19
+ }).refine((region) => Boolean(region.box || region.subjectId))).optional(),
20
+ });
21
+ export async function prepareNotebookImageEdit(engine, document, cell, prompt) {
22
+ const inputs = editInputsSchema.parse(cell.inputs);
23
+ const incoming = document.edges.filter((edge) => edge.target === cell.id);
24
+ const source = incoming.length === 1 ? document.cells.find((candidate) => candidate.id === incoming[0].source) : null;
25
+ if (!source || (source.outputArtifactId !== inputs.sourceArtifactId
26
+ && !(Array.isArray(source.inputs?.outputVersionArtifactIds)
27
+ && source.inputs.outputVersionArtifactIds.includes(inputs.sourceArtifactId)))) {
28
+ throw new Error("This edit requires its original connected source image. Open the image editor to choose a different source.");
29
+ }
30
+ const mode = inputs.generationMode;
31
+ const regional = mode === "region-edit" || mode === "region-remove";
32
+ if (regional && !inputs.editRegions?.length)
33
+ throw new Error("This edit has no saved regions");
34
+ if (mode === "region-replace" && !inputs.regions?.length)
35
+ throw new Error("This edit has no saved replacement regions");
36
+ const local = mode === "subject-remove";
37
+ const model = findImageEditModel(cell.model ?? "");
38
+ if (!local && !model)
39
+ throw new Error(`Unknown image edit model: ${cell.model}`);
40
+ const replacementIds = mode === "region-replace"
41
+ ? [...new Set(inputs.regions.map((region) => region.replacementArtifactId))] : [];
42
+ if (model?.maxInputImages !== null && model?.maxInputImages !== undefined
43
+ && 1 + replacementIds.length > model.maxInputImages) {
44
+ throw new Error(`${model.label} accepts at most ${model.maxInputImages} image inputs`);
45
+ }
46
+ const replacementRefs = [];
47
+ for (const id of replacementIds) {
48
+ const ref = await resolveImageRef(engine, id);
49
+ if (!ref.ok)
50
+ throw new Error(ref.error);
51
+ replacementRefs.push(ref.value);
52
+ }
53
+ const jobInput = {
54
+ sourceArtifactId: inputs.sourceArtifactId,
55
+ sourceObjectHash: inputs.sourceObjectHash,
56
+ subjectIds: inputs.subjectIds,
57
+ operation: mode === "whole-image" ? "whole_image"
58
+ : mode === "region-replace" ? "replace"
59
+ : mode.endsWith("remove") ? "remove" : "edit",
60
+ prompt,
61
+ ...(regional ? { editRegions: inputs.editRegions } : {}),
62
+ ...(mode === "region-replace" ? { regions: inputs.regions, replacementRefs } : {}),
63
+ ...(local ? {} : { modelId: model.id }),
64
+ };
65
+ const refs = [inputs.sourceArtifactId, ...replacementIds];
66
+ const request = await previewImageSubjectEditRequest(engine, jobInput, refs.map(previewPlaceholderUrl));
67
+ const previewInput = Object.fromEntries(Object.entries(request.input).map(([key, value]) => [
68
+ key, Array.isArray(value) && (key === "image_urls" || key === "input_urls")
69
+ ? value.map((url) => {
70
+ const id = refs.find((ref) => previewPlaceholderUrl(ref) === url);
71
+ return id ? `@${id}` : url;
72
+ }) : value,
73
+ ]));
74
+ const provider = local ? "local" : request.model === "grok-imagine-image-2-0/image-edit" ? "kie" : model.provider;
75
+ return {
76
+ jobInput,
77
+ input: { prompt, model: request.model, operation: jobInput.operation, image_refs: refs },
78
+ provider,
79
+ model: request.model,
80
+ providerPayload: provider === "fal"
81
+ ? { endpoint_id: request.model, input: previewInput }
82
+ : { model: request.model, input: previewInput },
83
+ };
84
+ }
@@ -0,0 +1,222 @@
1
+ import { NOTEBOOK_GRID_ADDRESS_SOURCE } from "videobook-engine/notebook-mentions";
2
+ import { generationInputMentions } from "./generation-input-mentions.js";
3
+ const INITIAL_PROMPT_KEY = "initialGenerationPrompt";
4
+ const INITIAL_PROMPT_VERSION = 1;
5
+ function generationKind(cell) {
6
+ if (cell.type === "generate_image")
7
+ return "image";
8
+ if (cell.type === "generate_video")
9
+ return "video";
10
+ return null;
11
+ }
12
+ function mediaKind(cell) {
13
+ if (cell.type === "image" || cell.type === "generate_image")
14
+ return "image";
15
+ if (cell.type === "video"
16
+ || cell.type === "generate_video"
17
+ || cell.type === "split_video"
18
+ || cell.type === "concat"
19
+ || cell.type === "splice")
20
+ return "video";
21
+ if (cell.type === "audio"
22
+ || cell.type === "generate_audio"
23
+ || cell.type === "extract_audio")
24
+ return "audio";
25
+ return null;
26
+ }
27
+ function initialPromptRecord(cell) {
28
+ const value = cell.inputs?.[INITIAL_PROMPT_KEY];
29
+ if (!value || typeof value !== "object" || Array.isArray(value))
30
+ return null;
31
+ const record = value;
32
+ return typeof record.prompt === "string"
33
+ && typeof record.version === "number"
34
+ ? { prompt: record.prompt, version: record.version }
35
+ : null;
36
+ }
37
+ function cleanCue(value) {
38
+ const cue = value
39
+ ?.replace(new RegExp(` ?@${NOTEBOOK_GRID_ADDRESS_SOURCE}(?![\\w-])`, "giu"), "")
40
+ .replace(/ ?@[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}(?![\w-])/giu, "")
41
+ .replace(/ ?@(?:(?:image|video|audio)\d+|firstframe|lastframe)(?![\w-])/giu, "")
42
+ .replace(/\s+/gu, " ")
43
+ .trim()
44
+ .replace(/^(?:please\s+)?(?:create|generate|make|render)\s+(?:(?:a|an|the)\s+)?(?:(?:image|video|picture|photo|clip)\s+)?(?:of\s+)?/iu, "")
45
+ .replace(/^(?:a|an|the)\s+/iu, "")
46
+ .replace(/[.!?]+$/u, "")
47
+ .trim();
48
+ return cue || null;
49
+ }
50
+ function cellPrompt(cell) {
51
+ if (cell.prompt?.trim())
52
+ return cell.prompt;
53
+ const resolved = cell.inputs?.resolvedPrompt;
54
+ if (typeof resolved === "string" && resolved.trim())
55
+ return resolved;
56
+ return undefined;
57
+ }
58
+ function promptInputs(document, cell) {
59
+ const cells = new Map(document.cells.map((candidate) => [candidate.id, candidate]));
60
+ const targetOrder = new Map([
61
+ ["first_frame", 0],
62
+ ["last_frame", 1],
63
+ ["image", 2],
64
+ ["video", 3],
65
+ ["audio", 4],
66
+ ["replace_audio", 5],
67
+ ]);
68
+ const tokens = new Map(generationInputMentions(cell.id, document.cells, document.edges, typeof cell.inputs?.generationMode === "string" ? cell.inputs.generationMode : undefined)
69
+ .map((mention) => [`${mention.sourceCellId}:${mention.targetInput}`, mention.token]));
70
+ return document.edges
71
+ .filter((edge) => edge.target === cell.id && edge.targetInput !== "media")
72
+ .flatMap((edge) => {
73
+ const source = cells.get(edge.source);
74
+ const kind = source ? mediaKind(source) : null;
75
+ const producerId = source?.inputs?.producerCellId;
76
+ const producer = typeof producerId === "string"
77
+ ? cells.get(producerId)
78
+ : undefined;
79
+ return source && kind
80
+ ? [{
81
+ cell: source,
82
+ token: tokens.get(`${edge.source}:${edge.targetInput}`) ?? null,
83
+ cue: cleanCue(cellPrompt(producer ?? source) ?? cellPrompt(source)),
84
+ kind,
85
+ targetInput: edge.targetInput,
86
+ }]
87
+ : [];
88
+ })
89
+ .sort((left, right) => {
90
+ const targetDifference = (targetOrder.get(left.targetInput) ?? 99)
91
+ - (targetOrder.get(right.targetInput) ?? 99);
92
+ if (targetDifference !== 0)
93
+ return targetDifference;
94
+ if (left.cell.slot.row !== right.cell.slot.row) {
95
+ return left.cell.slot.row - right.cell.slot.row;
96
+ }
97
+ return left.cell.slot.column - right.cell.slot.column;
98
+ });
99
+ }
100
+ function inputRole(generation, input) {
101
+ if (input.targetInput === "first_frame")
102
+ return "Start frame";
103
+ if (input.targetInput === "last_frame")
104
+ return "End frame";
105
+ if (input.targetInput === "replace_audio")
106
+ return "Replacement audio";
107
+ if (input.kind === "image") {
108
+ return generation === "video" ? "Subject image" : "Reference image";
109
+ }
110
+ if (input.kind === "video") {
111
+ return generation === "video" ? "Motion video" : "Scene video";
112
+ }
113
+ if (input.kind === "audio")
114
+ return "Audio";
115
+ return "Source";
116
+ }
117
+ function describeInput(generation, input) {
118
+ return `${inputRole(generation, input)}${input.token ? ` @${input.token}` : ""}`
119
+ + `${input.cue ? `: ${input.cue}` : ""}.`;
120
+ }
121
+ function fallbackPrompt(kind) {
122
+ if (kind === "image")
123
+ return "Clear subject, coherent scene.";
124
+ return "Clear subject, coherent motion.";
125
+ }
126
+ function buildInitialGenerationPrompt(document, cell) {
127
+ const kind = generationKind(cell);
128
+ if (!kind)
129
+ return cell.prompt?.trim() ?? "";
130
+ const inputs = promptInputs(document, cell);
131
+ if (inputs.length === 0)
132
+ return fallbackPrompt(kind);
133
+ const descriptions = inputs.map((input) => describeInput(kind, input));
134
+ if (kind === "image") {
135
+ return [
136
+ ...descriptions,
137
+ "Preserve subject, composition.",
138
+ "Render clean image.",
139
+ ].join(" ");
140
+ }
141
+ const directives = [];
142
+ const firstFrame = inputs.some((input) => input.targetInput === "first_frame");
143
+ const lastFrame = inputs.some((input) => input.targetInput === "last_frame");
144
+ const hasImage = inputs.some((input) => input.kind === "image");
145
+ const hasVideo = inputs.some((input) => input.kind === "video");
146
+ const hasAudio = inputs.some((input) => input.kind === "audio");
147
+ if (firstFrame && lastFrame)
148
+ directives.push("Animate smooth frame transition.");
149
+ else if (hasImage)
150
+ directives.push("Animate subject.");
151
+ if (hasVideo)
152
+ directives.push("Match motion, timing.");
153
+ if (hasAudio)
154
+ directives.push("Sync action, timing.");
155
+ if (hasImage)
156
+ directives.push("Preserve identity, composition.");
157
+ directives.push("Render coherent video.");
158
+ return [...descriptions, ...directives].join(" ");
159
+ }
160
+ export function resolvedInitialGenerationPrompt(document, cell) {
161
+ const prompt = cell.prompt?.trim() ?? "";
162
+ const record = initialPromptRecord(cell);
163
+ if (record && prompt === record.prompt.trim()) {
164
+ return buildInitialGenerationPrompt(document, cell);
165
+ }
166
+ return prompt || buildInitialGenerationPrompt(document, cell);
167
+ }
168
+ export function seedInitialGenerationPrompt(document, cellId) {
169
+ const target = document.cells.find((cell) => cell.id === cellId);
170
+ if (!target || !generationKind(target))
171
+ return document;
172
+ const record = initialPromptRecord(target);
173
+ const currentPrompt = target.prompt?.trim() ?? "";
174
+ if (currentPrompt && (!record || currentPrompt !== record.prompt.trim())) {
175
+ return document;
176
+ }
177
+ const prompt = buildInitialGenerationPrompt(document, target);
178
+ if (currentPrompt === prompt
179
+ && record?.prompt === prompt
180
+ && record.version === INITIAL_PROMPT_VERSION)
181
+ return document;
182
+ return {
183
+ ...document,
184
+ cells: document.cells.map((cell) => cell.id === cellId
185
+ ? {
186
+ ...cell,
187
+ prompt,
188
+ inputs: {
189
+ ...(cell.inputs ?? {}),
190
+ [INITIAL_PROMPT_KEY]: {
191
+ prompt,
192
+ version: INITIAL_PROMPT_VERSION,
193
+ },
194
+ },
195
+ }
196
+ : cell),
197
+ };
198
+ }
199
+ export function refreshInitialGenerationPrompts(document) {
200
+ return document.cells.reduce((current, cell) => initialPromptRecord(cell)
201
+ ? seedInitialGenerationPrompt(current, cell.id)
202
+ : current, document);
203
+ }
204
+ export function reconcileInitialGenerationPrompt(previous, next) {
205
+ const record = initialPromptRecord(next) ?? initialPromptRecord(previous);
206
+ if (!record)
207
+ return next;
208
+ if ((next.prompt?.trim() ?? "") === record.prompt.trim()) {
209
+ return initialPromptRecord(next)
210
+ ? next
211
+ : {
212
+ ...next,
213
+ inputs: {
214
+ ...(next.inputs ?? {}),
215
+ [INITIAL_PROMPT_KEY]: record,
216
+ },
217
+ };
218
+ }
219
+ const inputs = { ...(next.inputs ?? {}) };
220
+ delete inputs[INITIAL_PROMPT_KEY];
221
+ return { ...next, inputs };
222
+ }