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,746 @@
1
+ import { createHash } from "node:crypto";
2
+ import { z } from "zod";
3
+ import { findAudioFile, findVideoFile, } from "videobook-engine";
4
+ import { notebookGridAddress, parseNotebookGridAddress, } from "videobook-engine/notebook-grid";
5
+ import { NOTEBOOK_GRID_ADDRESS_SOURCE, normalizeNotebookReference, } from "videobook-engine/notebook-mentions";
6
+ import { resolveNotebookArtifactReference } from "./notebook-reference-resolver.js";
7
+ import { toolSpendsMoney } from "./paid-tools.js";
8
+ const CHAIN_VERSION = 1;
9
+ const CHAIN_MIN_STEPS = 1;
10
+ const CHAIN_MAX_STEPS = 16;
11
+ const CHAIN_UNSUPPORTED_TOOLS = new Set(["chain", "chat"]);
12
+ const GENERATION_OUTPUTS = {
13
+ asset_id: "artifact",
14
+ model: "string",
15
+ cell_id: "string",
16
+ address: "string",
17
+ job_id: "string",
18
+ status: "string",
19
+ };
20
+ export const CHAIN_TOOL_CATALOG = {
21
+ generate_image: {
22
+ outputs: GENERATION_OUTPUTS,
23
+ completion: "generation",
24
+ gridFields: ["refs.image"],
25
+ inputTypes: { model: "string", prompt: "string", image: "artifact", options: "json" },
26
+ placement: "generate_image",
27
+ artifactOutput: "asset_id",
28
+ },
29
+ generate_video: {
30
+ outputs: GENERATION_OUTPUTS,
31
+ completion: "generation",
32
+ gridFields: ["refs.first_frame", "refs.last_frame", "refs.image", "refs.video", "refs.audio", "replace_audio_with"],
33
+ inputTypes: {
34
+ model: "string",
35
+ prompt: "string",
36
+ first_frame: "artifact",
37
+ last_frame: "artifact",
38
+ image: "artifact",
39
+ video: "artifact",
40
+ audio: "artifact",
41
+ replace_audio_with: "artifact",
42
+ options: "json",
43
+ },
44
+ placement: "generate_video",
45
+ artifactOutput: "asset_id",
46
+ },
47
+ generate_audio: {
48
+ outputs: GENERATION_OUTPUTS,
49
+ completion: "generation",
50
+ gridFields: ["refs.video", "refs.audio"],
51
+ inputTypes: { model: "string", prompt: "string", video: "artifact", audio: "artifact", options: "json" },
52
+ placement: "generate_audio",
53
+ artifactOutput: "asset_id",
54
+ },
55
+ assemble_goal: {
56
+ outputs: { sequence_id: "string", status: "string" },
57
+ completion: "sync",
58
+ gridFields: ["artifact_ids"],
59
+ inputTypes: { goal_id: "string", artifact_ids: "artifact" },
60
+ },
61
+ extract_audio: {
62
+ outputs: {
63
+ audio_asset_id: "artifact",
64
+ source_video: "artifact",
65
+ job_id: "string",
66
+ status: "string",
67
+ },
68
+ completion: "extract_audio",
69
+ gridFields: ["asset_id"],
70
+ inputTypes: { asset_id: "artifact" },
71
+ },
72
+ replace_video_audio: {
73
+ outputs: {
74
+ asset_id: "artifact",
75
+ audio_asset_id: "artifact",
76
+ job_id: "string",
77
+ status: "string",
78
+ },
79
+ completion: "replace_video_audio",
80
+ gridFields: ["asset_id", "audio_asset_id"],
81
+ inputTypes: {
82
+ asset_id: "artifact",
83
+ audio_asset_id: "artifact",
84
+ },
85
+ },
86
+ audio_mix: {
87
+ outputs: {
88
+ target_asset_id: "artifact",
89
+ layer_asset_id: "artifact",
90
+ volume: "number",
91
+ job_id: "string",
92
+ status: "string",
93
+ },
94
+ completion: "audio_mix",
95
+ gridFields: ["target_asset_id", "layer_asset_id"],
96
+ inputTypes: { target_asset_id: "artifact", layer_asset_id: "artifact", volume: "number" },
97
+ },
98
+ apply_sfx: {
99
+ outputs: { asset_id: "artifact", job_id: "string", status: "string", applied: "number", dropped: "number" },
100
+ completion: "apply_sfx",
101
+ gridFields: ["asset_id"],
102
+ inputTypes: { asset_id: "artifact", sfx: "json" },
103
+ },
104
+ trim_video: {
105
+ outputs: {
106
+ asset_id: "artifact",
107
+ job_id: "string",
108
+ status: "string",
109
+ },
110
+ completion: "trim_video",
111
+ gridFields: ["asset_id"],
112
+ inputTypes: { asset_id: "artifact" },
113
+ },
114
+ extract_frame: {
115
+ outputs: {
116
+ image_asset_id: "artifact",
117
+ source_video: "artifact",
118
+ job_id: "string",
119
+ status: "string",
120
+ },
121
+ completion: "extract_frame",
122
+ gridFields: ["asset_id"],
123
+ inputTypes: { asset_id: "artifact", frame: "string", timestamp: "number" },
124
+ },
125
+ asset_manifest: {
126
+ outputs: {
127
+ artifactId: "artifact",
128
+ path: "string",
129
+ files: "json",
130
+ },
131
+ completion: "sync",
132
+ gridFields: ["asset_id"],
133
+ inputTypes: { asset_id: "artifact" },
134
+ },
135
+ read_asset_metadata: {
136
+ outputs: {
137
+ value: "json",
138
+ },
139
+ completion: "sync",
140
+ gridFields: ["asset_id"],
141
+ inputTypes: { asset_id: "artifact", name: "string" },
142
+ },
143
+ };
144
+ const GRID_TOKEN = NOTEBOOK_GRID_ADDRESS_SOURCE;
145
+ const GRID_PATTERN = new RegExp(`^@?(${GRID_TOKEN})$`, "iu");
146
+ const PLACEHOLDER_ARTIFACT = "01900000-0000-7000-8000-000000000001";
147
+ const chainRefSchema = z.object({
148
+ $ref: z.object({
149
+ step_id: z.string().min(1),
150
+ output: z.string().min(1),
151
+ }),
152
+ });
153
+ export const chainStepSchema = z.object({
154
+ id: z.string().min(1).max(64).regex(/^[A-Za-z][A-Za-z0-9_-]*$/),
155
+ tool: z.string().min(1),
156
+ params: z.record(z.string(), z.unknown()),
157
+ });
158
+ const chainRunInputSchema = z.object({
159
+ action: z.literal("run"),
160
+ version: z.literal(CHAIN_VERSION),
161
+ book_id: z.string().uuid(),
162
+ notebook_id: z.string().uuid().optional(),
163
+ request_id: z.string().min(1).optional(),
164
+ steps: z.array(chainStepSchema).min(CHAIN_MIN_STEPS).max(CHAIN_MAX_STEPS),
165
+ });
166
+ export const chainStatusInputSchema = z.object({
167
+ action: z.literal("status"),
168
+ book_id: z.string().uuid(),
169
+ chain_id: z.string().uuid(),
170
+ });
171
+ export const chainCancelInputSchema = z.object({
172
+ action: z.literal("cancel"),
173
+ book_id: z.string().uuid(),
174
+ chain_id: z.string().uuid(),
175
+ });
176
+ export const chainApproveInputSchema = z.object({
177
+ action: z.literal("approve"),
178
+ book_id: z.string().uuid(),
179
+ chain_id: z.string().uuid(),
180
+ step_id: z.string().min(1).max(64),
181
+ actor: z.enum(["chat", "voice", "api"]).optional(),
182
+ });
183
+ export function readChainParam(params, path) {
184
+ let current = params;
185
+ for (const segment of path.split(".")) {
186
+ if (current === null || typeof current !== "object" || Array.isArray(current))
187
+ return undefined;
188
+ current = current[segment];
189
+ }
190
+ return current;
191
+ }
192
+ export function writeChainParam(params, path, value) {
193
+ const [head, ...rest] = path.split(".");
194
+ if (rest.length === 0)
195
+ return { ...params, [head]: value };
196
+ const child = params[head];
197
+ const nested = child !== null && typeof child === "object" && !Array.isArray(child)
198
+ ? child
199
+ : {};
200
+ return { ...params, [head]: writeChainParam(nested, rest.join("."), value) };
201
+ }
202
+ export function isChainRef(value) {
203
+ return chainRefSchema.safeParse(value).success;
204
+ }
205
+ export function supportedChainTool(name) {
206
+ if (CHAIN_UNSUPPORTED_TOOLS.has(name))
207
+ return null;
208
+ return CHAIN_TOOL_CATALOG[name] ?? null;
209
+ }
210
+ export function chainPlanFingerprint(input) {
211
+ return createHash("sha256")
212
+ .update(JSON.stringify({
213
+ version: input.version,
214
+ notebookId: input.notebookId ?? null,
215
+ steps: input.steps,
216
+ }))
217
+ .digest("hex");
218
+ }
219
+ function typesCompatible(output, input) {
220
+ if (output === input)
221
+ return true;
222
+ return output === "artifact" && input === "string";
223
+ }
224
+ function walkValues(value, visit, path = "") {
225
+ visit(value, path);
226
+ if (Array.isArray(value)) {
227
+ value.forEach((entry, index) => walkValues(entry, visit, `${path}[${index}]`));
228
+ return;
229
+ }
230
+ if (value && typeof value === "object" && !isChainRef(value)) {
231
+ for (const [key, child] of Object.entries(value)) {
232
+ walkValues(child, visit, path ? `${path}.${key}` : key);
233
+ }
234
+ }
235
+ }
236
+ const CHAIN_STEP_ID = /^[A-Za-z][A-Za-z0-9_-]{0,63}$/;
237
+ function chainStepRecord(value) {
238
+ if (!value || typeof value !== "object" || Array.isArray(value))
239
+ return null;
240
+ return value;
241
+ }
242
+ function chainStepId(value) {
243
+ return typeof value === "string" && CHAIN_STEP_ID.test(value) ? value : null;
244
+ }
245
+ function unusedChainStepId(preferred, used, index) {
246
+ for (const candidate of preferred) {
247
+ if (candidate && !used.has(candidate))
248
+ return candidate;
249
+ }
250
+ let number = index + 1;
251
+ while (used.has(`step${number}`))
252
+ number += 1;
253
+ return `step${number}`;
254
+ }
255
+ function chainStepIndexAlias(token, count) {
256
+ const numbered = /^(?:step[_-]?)?(\d+)$/iu.exec(token);
257
+ if (!numbered)
258
+ return null;
259
+ const number = Number(numbered[1]);
260
+ if (token === "0")
261
+ return count > 0 ? 0 : null;
262
+ if (number >= 1 && number <= count)
263
+ return number - 1;
264
+ return null;
265
+ }
266
+ export function ensureChainStepIds(steps) {
267
+ if (!Array.isArray(steps))
268
+ return steps;
269
+ const records = steps.map(chainStepRecord);
270
+ const explicit = records.map((record) => chainStepId(record?.id));
271
+ const used = new Set(explicit.filter((id) => id !== null));
272
+ const toolCounts = new Map();
273
+ for (const record of records) {
274
+ const tool = typeof record?.tool === "string" ? record.tool : "";
275
+ if (!tool)
276
+ continue;
277
+ toolCounts.set(tool, (toolCounts.get(tool) ?? 0) + 1);
278
+ }
279
+ const ids = records.map((record, index) => {
280
+ if (!record)
281
+ return null;
282
+ const current = explicit[index];
283
+ if (current)
284
+ return current;
285
+ const tool = typeof record.tool === "string" ? record.tool : "";
286
+ const toolId = toolCounts.get(tool) === 1 ? chainStepId(tool) : null;
287
+ const alias = chainStepId(record.step_id) ?? chainStepId(record.name);
288
+ const id = unusedChainStepId([alias, toolId], used, index);
289
+ used.add(id);
290
+ return id;
291
+ });
292
+ const idSet = new Set(ids.filter((id) => id !== null));
293
+ const toolIds = new Map();
294
+ records.forEach((record, index) => {
295
+ const tool = typeof record?.tool === "string" ? record.tool : "";
296
+ const id = ids[index];
297
+ if (!tool || !id || toolCounts.get(tool) !== 1)
298
+ return;
299
+ toolIds.set(tool, id);
300
+ });
301
+ const resolveRef = (token) => {
302
+ if (idSet.has(token))
303
+ return token;
304
+ const fromTool = toolIds.get(token);
305
+ if (fromTool)
306
+ return fromTool;
307
+ const index = chainStepIndexAlias(token, ids.length);
308
+ return index === null ? token : ids[index] ?? token;
309
+ };
310
+ let refsChanged = false;
311
+ const next = steps.map((entry, index) => {
312
+ const record = records[index];
313
+ const id = ids[index];
314
+ if (!record || !id)
315
+ return entry;
316
+ const params = chainStepRecord(record.params);
317
+ const nextParams = params
318
+ ? mapChainParams(params, (node) => {
319
+ if (!isChainRef(node))
320
+ return node;
321
+ const stepId = resolveRef(node.$ref.step_id);
322
+ if (stepId === node.$ref.step_id)
323
+ return node;
324
+ refsChanged = true;
325
+ return { $ref: { step_id: stepId, output: node.$ref.output } };
326
+ })
327
+ : record.params;
328
+ if (record.id === id && !refsChanged)
329
+ return entry;
330
+ return { ...record, id, params: nextParams };
331
+ });
332
+ const unchanged = !refsChanged && next.every((entry, index) => entry === steps[index]);
333
+ return unchanged ? steps : next;
334
+ }
335
+ function chainInputWithStepIds(input) {
336
+ if (!input || typeof input !== "object" || Array.isArray(input))
337
+ return input;
338
+ const record = input;
339
+ if (!Object.hasOwn(record, "steps"))
340
+ return input;
341
+ const steps = ensureChainStepIds(record.steps);
342
+ return steps === record.steps ? input : { ...record, steps };
343
+ }
344
+ function mapChainParams(value, map, path = "") {
345
+ const mapped = map(value, path);
346
+ if (mapped !== value)
347
+ return mapped;
348
+ if (Array.isArray(value)) {
349
+ return value.map((entry, index) => mapChainParams(entry, map, `${path}[${index}]`));
350
+ }
351
+ if (value && typeof value === "object" && !isChainRef(value)) {
352
+ const next = {};
353
+ for (const [key, child] of Object.entries(value)) {
354
+ next[key] = mapChainParams(child, map, path ? `${path}.${key}` : key);
355
+ }
356
+ return next;
357
+ }
358
+ return value;
359
+ }
360
+ export function substituteChainRefs(params, outputs) {
361
+ return mapChainParams(params, (node) => {
362
+ if (!isChainRef(node))
363
+ return node;
364
+ const stepOutputs = outputs.get(node.$ref.step_id);
365
+ if (!stepOutputs || !(node.$ref.output in stepOutputs)) {
366
+ throw new Error(`Missing output ${node.$ref.output} from step ${node.$ref.step_id}`);
367
+ }
368
+ return stepOutputs[node.$ref.output];
369
+ });
370
+ }
371
+ function looksLikeGridAttempt(value) {
372
+ return value.startsWith("@") || GRID_PATTERN.test(value.trim());
373
+ }
374
+ function asGridAddress(value) {
375
+ const slot = parseNotebookGridAddress(normalizeNotebookReference(value));
376
+ return slot ? notebookGridAddress(slot) : null;
377
+ }
378
+ async function primaryObjectHash(engine, artifactId) {
379
+ const artifact = engine.artifacts.get(artifactId);
380
+ if (!artifact.ok)
381
+ return null;
382
+ const manifest = await engine.files.manifest(artifactId);
383
+ if (!manifest.ok)
384
+ return null;
385
+ const file = findVideoFile(manifest.value.files)
386
+ ?? findAudioFile(manifest.value.files, artifact.value.kind)
387
+ ?? manifest.value.files.find((entry) => entry.name.startsWith("original."))
388
+ ?? manifest.value.files[0];
389
+ return file?.objectHash ?? null;
390
+ }
391
+ async function resolvePinnedTarget(context, field, index, raw) {
392
+ const notebookId = context.notebookId;
393
+ let notebook = null;
394
+ if (notebookId) {
395
+ const read = context.engine.notebooks.read(notebookId);
396
+ if (!read.ok)
397
+ return read.error.message;
398
+ notebook = read.value;
399
+ }
400
+ const documents = notebook
401
+ ? [notebook]
402
+ : context.engine.notebooks.list();
403
+ const resolved = resolveNotebookArtifactReference({
404
+ engine: context.engine,
405
+ documents,
406
+ reference: raw,
407
+ requireMedia: false,
408
+ });
409
+ if ("code" in resolved) {
410
+ return resolved.message;
411
+ }
412
+ const objectHash = await primaryObjectHash(context.engine, resolved.artifactId);
413
+ return {
414
+ field,
415
+ index,
416
+ address: resolved.cellAddress ?? normalizeNotebookReference(raw),
417
+ cellId: resolved.cellId ?? null,
418
+ artifactId: resolved.artifactId,
419
+ objectHash,
420
+ };
421
+ }
422
+ /**
423
+ * Resolve one grid-addressable value to a pin, or report why it cannot be one.
424
+ * Anything that is neither an address attempt nor an id is left alone for the
425
+ * tool's own schema to judge.
426
+ */
427
+ async function pinGridField(context, stepId, field, index, raw) {
428
+ if (looksLikeGridAttempt(raw) && !asGridAddress(raw) && !raw.includes("-")) {
429
+ return `Step ${stepId} field ${field} is not a valid @a1-@bl8 target`;
430
+ }
431
+ if (!looksLikeGridAttempt(raw) && !raw.includes("-"))
432
+ return null;
433
+ const pinned = await resolvePinnedTarget(context, field, index, raw);
434
+ return typeof pinned === "string" ? `Step ${stepId} ${pinned}` : pinned;
435
+ }
436
+ function collectRefs(params) {
437
+ const refs = [];
438
+ walkValues(params, (node, path) => {
439
+ if (!isChainRef(node))
440
+ return;
441
+ const field = path.split("[")[0].split(".").pop() ?? path;
442
+ refs.push({ path, ref: node, field });
443
+ });
444
+ return refs;
445
+ }
446
+ function withRefPlaceholders(params) {
447
+ return mapChainParams(params, (node) => {
448
+ if (!isChainRef(node))
449
+ return node;
450
+ return PLACEHOLDER_ARTIFACT;
451
+ });
452
+ }
453
+ export async function preflightChainPlan(input, context) {
454
+ if (typeof input === "object"
455
+ && input !== null
456
+ && "action" in input
457
+ && input.action !== undefined
458
+ && input.action !== "run") {
459
+ return { ok: false, error: "Chain preflight only accepts action=run" };
460
+ }
461
+ const parsed = chainRunInputSchema.safeParse(chainInputWithStepIds(input));
462
+ if (!parsed.success) {
463
+ return { ok: false, error: z.prettifyError(parsed.error) };
464
+ }
465
+ const data = parsed.data;
466
+ if (data.book_id !== context.bookId) {
467
+ return { ok: false, error: "Chain book_id does not match the active book" };
468
+ }
469
+ if (data.notebook_id && context.notebookId && data.notebook_id !== context.notebookId) {
470
+ return {
471
+ ok: false,
472
+ error: "Chain notebook_id does not match the active notebook",
473
+ };
474
+ }
475
+ const notebookId = data.notebook_id ?? context.notebookId ?? null;
476
+ const ids = data.steps.map((step) => step.id);
477
+ if (new Set(ids).size !== ids.length) {
478
+ return { ok: false, error: "Chain step ids must be unique" };
479
+ }
480
+ const declared = new Map();
481
+ const preflightSteps = [];
482
+ for (const [index, step] of data.steps.entries()) {
483
+ if (CHAIN_UNSUPPORTED_TOOLS.has(step.tool)) {
484
+ return {
485
+ ok: false,
486
+ error: `Unsupported chain tool: ${step.tool}`,
487
+ };
488
+ }
489
+ const spec = supportedChainTool(step.tool);
490
+ if (!spec) {
491
+ return {
492
+ ok: false,
493
+ error: `Unknown or unsupported chain tool: ${step.tool}`,
494
+ };
495
+ }
496
+ const schema = context.toolSchemas.get(step.tool);
497
+ if (!schema) {
498
+ return { ok: false, error: `Unknown or unsupported chain tool: ${step.tool}` };
499
+ }
500
+ if (typeof step.params.book_id === "string" && step.params.book_id !== context.bookId) {
501
+ return {
502
+ ok: false,
503
+ error: `Step ${step.id} overrides book_id and cannot dispatch cross-book`,
504
+ };
505
+ }
506
+ if (typeof step.params.notebook_id === "string"
507
+ && notebookId
508
+ && step.params.notebook_id !== notebookId) {
509
+ return {
510
+ ok: false,
511
+ error: `Step ${step.id} overrides notebook_id and cannot dispatch cross-notebook`,
512
+ };
513
+ }
514
+ const refs = collectRefs(step.params);
515
+ for (const { ref, field, path } of refs) {
516
+ if (ref.$ref.step_id === step.id) {
517
+ return {
518
+ ok: false,
519
+ error: `Step ${step.id} cannot reference its own output at ${path}`,
520
+ };
521
+ }
522
+ const earlier = declared.get(ref.$ref.step_id);
523
+ if (!earlier) {
524
+ const later = data.steps.some((candidate) => candidate.id === ref.$ref.step_id);
525
+ return {
526
+ ok: false,
527
+ error: later
528
+ ? `Step ${step.id} has a forward reference to ${ref.$ref.step_id} at ${path}`
529
+ : `Step ${step.id} references unknown step ${ref.$ref.step_id} at ${path}`,
530
+ };
531
+ }
532
+ if (earlier.index >= index) {
533
+ return {
534
+ ok: false,
535
+ error: `Step ${step.id} has a forward reference to ${ref.$ref.step_id} at ${path}`,
536
+ };
537
+ }
538
+ const outputType = earlier.spec.outputs[ref.$ref.output];
539
+ if (!outputType) {
540
+ return {
541
+ ok: false,
542
+ error: `Step ${step.id} references unavailable output ${ref.$ref.step_id}.${ref.$ref.output}`,
543
+ };
544
+ }
545
+ const inputType = spec.inputTypes[field] ?? "string";
546
+ if (!typesCompatible(outputType, inputType)) {
547
+ return {
548
+ ok: false,
549
+ error: `Step ${step.id} input ${field} is incompatible with ${ref.$ref.step_id}.${ref.$ref.output}`,
550
+ };
551
+ }
552
+ }
553
+ const pins = [];
554
+ for (const field of spec.gridFields) {
555
+ const raw = readChainParam(step.params, field);
556
+ if (isChainRef(raw) || raw === undefined)
557
+ continue;
558
+ const entries = Array.isArray(raw)
559
+ ? raw.map((value, position) => ({ index: position, value }))
560
+ : [{ index: null, value: raw }];
561
+ for (const entry of entries) {
562
+ if (isChainRef(entry.value))
563
+ continue;
564
+ if (typeof entry.value !== "string") {
565
+ return {
566
+ ok: false,
567
+ error: `Step ${step.id} field ${field} must be a string or {$ref}`,
568
+ };
569
+ }
570
+ const pinned = await pinGridField(context, step.id, field, entry.index, entry.value);
571
+ if (typeof pinned === "string")
572
+ return { ok: false, error: pinned };
573
+ if (pinned)
574
+ pins.push(pinned);
575
+ }
576
+ }
577
+ const literalParams = withRefPlaceholders(step.params);
578
+ const validated = z.object(schema).safeParse({
579
+ ...literalParams,
580
+ book_id: context.bookId,
581
+ ...(notebookId && schema.notebook_id !== undefined
582
+ ? { notebook_id: notebookId }
583
+ : {}),
584
+ });
585
+ if (!validated.success) {
586
+ return {
587
+ ok: false,
588
+ error: `Invalid parameters for ${step.tool}: ${z.prettifyError(validated.error)}`,
589
+ };
590
+ }
591
+ declared.set(step.id, { index, spec });
592
+ const effect = context.effectForTool(step.tool);
593
+ const autoApplyStep = context.autoApplyTools.has(step.tool) || effect === "read";
594
+ preflightSteps.push({
595
+ id: step.id,
596
+ tool: step.tool,
597
+ params: step.params,
598
+ spec,
599
+ pins,
600
+ autoApply: autoApplyStep,
601
+ effect,
602
+ requiresApproval: !autoApplyStep && toolSpendsMoney(step.tool),
603
+ });
604
+ }
605
+ const effect = preflightSteps.some((step) => step.effect === "generation")
606
+ ? "generation"
607
+ : preflightSteps.some((step) => step.effect === "mutation")
608
+ ? "mutation"
609
+ : "read";
610
+ // A step that stops for its own review does not also need the combined sheet.
611
+ // A free in-place mutation still does, or it would run with no review at all.
612
+ const autoApply = preflightSteps.every((step) => step.autoApply || step.requiresApproval);
613
+ return {
614
+ ok: true,
615
+ plan: {
616
+ version: CHAIN_VERSION,
617
+ bookId: context.bookId,
618
+ notebookId,
619
+ requestId: data.request_id ?? null,
620
+ steps: preflightSteps,
621
+ fingerprint: chainPlanFingerprint({
622
+ version: CHAIN_VERSION,
623
+ notebookId,
624
+ steps: data.steps,
625
+ }),
626
+ autoApply,
627
+ effect,
628
+ },
629
+ };
630
+ }
631
+ export async function revalidatePinnedTargets(engine, notebookId, pins) {
632
+ for (const pin of pins) {
633
+ if (pin.cellId && notebookId) {
634
+ const notebook = engine.notebooks.read(notebookId);
635
+ if (!notebook.ok)
636
+ return notebook.error.message;
637
+ const cell = notebook.value.cells.find((candidate) => candidate.id === pin.cellId);
638
+ if (!cell)
639
+ return `Pinned cell for ${pin.address} is gone`;
640
+ if (cell.outputArtifactId !== pin.artifactId) {
641
+ return `Pinned target ${pin.address} no longer points at the same artifact`;
642
+ }
643
+ }
644
+ const artifact = engine.artifacts.get(pin.artifactId);
645
+ if (!artifact.ok)
646
+ return `Pinned artifact ${pin.artifactId} is gone`;
647
+ const hash = await primaryObjectHash(engine, pin.artifactId);
648
+ if (pin.objectHash && hash && hash !== pin.objectHash) {
649
+ return `Pinned target ${pin.address} changed since planning`;
650
+ }
651
+ }
652
+ return null;
653
+ }
654
+ function uniqueGridMentions(query) {
655
+ const matches = [
656
+ ...query.matchAll(new RegExp(`@(${GRID_TOKEN})(?![\\w-])`, "giu")),
657
+ ...query.matchAll(new RegExp(`\\b(${GRID_TOKEN})\\b`, "giu")),
658
+ ];
659
+ const seen = new Set();
660
+ const mentions = [];
661
+ for (const match of matches) {
662
+ const token = match[1]?.toLowerCase();
663
+ if (!token || !parseNotebookGridAddress(token) || seen.has(token))
664
+ continue;
665
+ seen.add(token);
666
+ mentions.push(token);
667
+ }
668
+ return mentions;
669
+ }
670
+ function gridAfter(query, pattern) {
671
+ const match = pattern.exec(query);
672
+ const token = match?.[1]?.toLowerCase();
673
+ return token && parseNotebookGridAddress(token) ? token : null;
674
+ }
675
+ function extractAudioReplacePlan(query) {
676
+ if (!/\bextract(?:\s+the)?\s+audio\b/i.test(query))
677
+ return null;
678
+ if (!/\breplace(?:\s+the)?\s+audio\b/i.test(query))
679
+ return null;
680
+ const source = gridAfter(query, new RegExp(`\\bfrom\\s+@?(${GRID_TOKEN})\\b`, "iu")) ?? uniqueGridMentions(query)[0] ?? null;
681
+ const target = gridAfter(query, new RegExp(`\\b(?:in|on)\\s+(?:the\\s+video\\s+(?:in|on)\\s+)?@?(${GRID_TOKEN})\\b`, "iu")) ?? uniqueGridMentions(query)[1] ?? null;
682
+ if (!source || !target || source === target)
683
+ return null;
684
+ return {
685
+ message: "Extracting audio and replacing the target soundtrack.",
686
+ steps: [
687
+ {
688
+ id: "extract",
689
+ tool: "extract_audio",
690
+ params: { asset_id: `@${source}` },
691
+ },
692
+ {
693
+ id: "replace",
694
+ tool: "replace_video_audio",
695
+ params: {
696
+ asset_id: `@${target}`,
697
+ audio_asset_id: {
698
+ $ref: { step_id: "extract", output: "audio_asset_id" },
699
+ },
700
+ },
701
+ },
702
+ ],
703
+ };
704
+ }
705
+ function trimThenExtractPlan(query) {
706
+ if (!/\btrim\b/i.test(query))
707
+ return null;
708
+ if (!/\bextract(?:\s+the)?\s+audio\b/i.test(query))
709
+ return null;
710
+ if (/\breplace(?:\s+the)?\s+audio\b/i.test(query))
711
+ return null;
712
+ const mentions = uniqueGridMentions(query);
713
+ const source = mentions[0];
714
+ if (!source)
715
+ return null;
716
+ const seconds = query.match(/\b(\d+(?:\.\d+)?)\s*(?:s|sec|seconds)?\b/i)?.[1];
717
+ const trimEnd = seconds ? Number(seconds) : 1;
718
+ if (!Number.isFinite(trimEnd) || trimEnd <= 0)
719
+ return null;
720
+ return {
721
+ message: "Trimming the clip then extracting audio.",
722
+ steps: [
723
+ {
724
+ id: "trim",
725
+ tool: "trim_video",
726
+ params: {
727
+ asset_id: `@${source}`,
728
+ trim_start: 0,
729
+ trim_end: trimEnd,
730
+ },
731
+ },
732
+ {
733
+ id: "extract",
734
+ tool: "extract_audio",
735
+ params: {
736
+ asset_id: {
737
+ $ref: { step_id: "trim", output: "asset_id" },
738
+ },
739
+ },
740
+ },
741
+ ],
742
+ };
743
+ }
744
+ export function planStackedChainFromQuery(query) {
745
+ return extractAudioReplacePlan(query) ?? trimThenExtractPlan(query);
746
+ }