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,98 @@
1
+ import { z } from "zod";
2
+ import { buildAssetList } from "./reconcile-project-work.js";
3
+ import { matchesTagFilter, } from "../asset-tags.js";
4
+ import { tagSelectorSchema } from "./asset-tags.js";
5
+ import { LIBRARY_BROWSE_STATUSES, isLibraryBrowseStatus, pageLibraryAssets, } from "../library-browse.js";
6
+ export function listAssetsDef(engine) {
7
+ return {
8
+ name: "list_assets",
9
+ description: "List a bounded asset page with media and thumbnail URLs, optionally including notebook and sequence-referenced assets outside the page.",
10
+ schema: {
11
+ book_id: z.string().describe("Book id"),
12
+ sort: z.enum(["newest", "oldest"]).optional().describe("Sort order by creation date"),
13
+ limit: z.number().int().positive().max(500).optional(),
14
+ offset: z.number().int().nonnegative().optional(),
15
+ include_referenced: z.boolean().optional(),
16
+ browse_status: z.enum(LIBRARY_BROWSE_STATUSES).optional()
17
+ .describe("Filter Library media by artifact status before paging. Omit to keep the unfiltered page, including notebooks and other non-media artifacts."),
18
+ tags_all: z.array(tagSelectorSchema).optional()
19
+ .describe("Only assets carrying every one of these tags"),
20
+ tags_any: z.array(tagSelectorSchema).optional()
21
+ .describe("Only assets carrying at least one of these tags"),
22
+ },
23
+ handler: async (args) => {
24
+ const { book_id, sort, limit, offset, include_referenced, browse_status, tags_all, tags_any, } = args;
25
+ const allAssets = await buildAssetList(engine, book_id, sort);
26
+ const tagFilter = {
27
+ ...(tags_all ? { all: tags_all } : {}),
28
+ ...(tags_any ? { any: tags_any } : {}),
29
+ };
30
+ let taggedAssets;
31
+ try {
32
+ taggedAssets = allAssets.filter((asset) => matchesTagFilter(asset.tags ?? undefined, tagFilter));
33
+ }
34
+ catch (cause) {
35
+ return {
36
+ isError: true,
37
+ content: [{
38
+ type: "text",
39
+ text: cause instanceof Error ? cause.message : String(cause),
40
+ }],
41
+ };
42
+ }
43
+ const browseStatus = isLibraryBrowseStatus(browse_status)
44
+ ? browse_status
45
+ : undefined;
46
+ const paged = pageLibraryAssets(taggedAssets, {
47
+ ...(browseStatus ? { browseStatus } : {}),
48
+ offset: offset ?? 0,
49
+ limit: limit ?? 200,
50
+ });
51
+ const pageArtifactIds = new Set(paged.pageAssets.map((asset) => asset.artifact_id));
52
+ const referencedArtifactIds = include_referenced
53
+ ? new Set(engine.notebooks
54
+ .list()
55
+ .flatMap((notebook) => notebook.cells.flatMap((cell) => {
56
+ const versionIds = Array.isArray(cell.inputs?.outputVersionArtifactIds)
57
+ ? cell.inputs.outputVersionArtifactIds.filter((id) => typeof id === "string" && id.length > 0)
58
+ : [];
59
+ return [
60
+ ...(cell.outputArtifactId ? [cell.outputArtifactId] : []),
61
+ ...(typeof cell.inputs?.firstFrameArtifactId === "string"
62
+ ? [cell.inputs.firstFrameArtifactId]
63
+ : []),
64
+ ...(typeof cell.inputs?.lastFrameArtifactId === "string"
65
+ ? [cell.inputs.lastFrameArtifactId]
66
+ : []),
67
+ ...(typeof cell.inputs?.providerArtifactId === "string"
68
+ ? [cell.inputs.providerArtifactId]
69
+ : []),
70
+ ...versionIds,
71
+ ];
72
+ })))
73
+ : new Set();
74
+ if (include_referenced) {
75
+ for (const clip of engine.sequences.getPrimary().clips) {
76
+ referencedArtifactIds.add(clip.source.artifactId);
77
+ }
78
+ }
79
+ // Hydration is deliberately unfiltered: a notebook needs the media it
80
+ // references whether or not that asset carries the filtered tags.
81
+ const referencedAssets = include_referenced
82
+ ? allAssets.filter((asset) => referencedArtifactIds.has(asset.artifact_id)
83
+ && !pageArtifactIds.has(asset.artifact_id))
84
+ : [];
85
+ const assets = [...paged.pageAssets, ...referencedAssets];
86
+ return {
87
+ content: [{
88
+ type: "text",
89
+ text: JSON.stringify({
90
+ assets,
91
+ page: paged.page,
92
+ status_counts: paged.statusCounts,
93
+ }),
94
+ }],
95
+ };
96
+ },
97
+ };
98
+ }
@@ -0,0 +1,225 @@
1
+ import { z } from "zod";
2
+ import { findGenerateAudioOutput, findGenerateImageOutput, findGenerateVideoOutput, listGenerateImageOutputs, listGenerateVideoOutputs, } from "../notebook-cell-outputs.js";
3
+ import { buildAssetList } from "./reconcile-project-work.js";
4
+ import { readProviderTaskStatus } from "../provider-task-status.js";
5
+ function generationArtifactIds(generations) {
6
+ return [...new Set(generations.flatMap((row) => [
7
+ ...(row.outputArtifactId ? [row.outputArtifactId] : []),
8
+ ...(row.providerArtifactId ? [row.providerArtifactId] : []),
9
+ ]))];
10
+ }
11
+ export function pairForCell(document, cellId) {
12
+ const cell = document.cells.find((candidate) => candidate.id === cellId);
13
+ if (!cell)
14
+ throw new Error(`Cell not found: ${cellId}`);
15
+ if (cell.type === "generate_video") {
16
+ const output = findGenerateVideoOutput(document, cell.id);
17
+ return { generateCell: cell, outputCell: output?.outputCell ?? null };
18
+ }
19
+ if (cell.type === "generate_image") {
20
+ const output = findGenerateImageOutput(document, cell.id);
21
+ return { generateCell: cell, outputCell: output?.outputCell ?? null };
22
+ }
23
+ if (cell.type === "generate_audio") {
24
+ const output = findGenerateAudioOutput(document, cell.id);
25
+ return { generateCell: cell, outputCell: output?.outputCell ?? null };
26
+ }
27
+ if (cell.type === "video") {
28
+ const producerEdge = document.edges.find((edge) => edge.target === cell.id
29
+ && (edge.targetInput === "output" || edge.targetInput === "media"));
30
+ const producer = producerEdge
31
+ ? document.cells.find((candidate) => candidate.id === producerEdge.source)
32
+ : undefined;
33
+ if (producer?.type === "generate_video") {
34
+ return { generateCell: producer, outputCell: cell };
35
+ }
36
+ }
37
+ if (cell.type === "image") {
38
+ const producerEdge = document.edges.find((edge) => edge.target === cell.id
39
+ && (edge.targetInput === "media" || edge.targetInput === "output"));
40
+ const producer = producerEdge
41
+ ? document.cells.find((candidate) => candidate.id === producerEdge.source)
42
+ : undefined;
43
+ if (producer?.type === "generate_image") {
44
+ return { generateCell: producer, outputCell: cell };
45
+ }
46
+ }
47
+ if (cell.type === "audio") {
48
+ const producerEdge = document.edges.find((edge) => edge.target === cell.id
49
+ && (edge.targetInput === "media" || edge.targetInput === "output"));
50
+ const producer = producerEdge
51
+ ? document.cells.find((candidate) => candidate.id === producerEdge.source)
52
+ : undefined;
53
+ if (producer?.type === "generate_audio") {
54
+ return { generateCell: producer, outputCell: cell };
55
+ }
56
+ }
57
+ return { generateCell: cell, outputCell: null };
58
+ }
59
+ const TRANSITION_SCAN_LIMIT = 500;
60
+ function generationTransitions(engine, generations) {
61
+ const wanted = new Set(generations.map((row) => row.generationId));
62
+ const transitions = new Map();
63
+ if (wanted.size === 0)
64
+ return transitions;
65
+ for (const revision of engine.history.revisions(TRANSITION_SCAN_LIMIT)) {
66
+ const details = revision.details ?? {};
67
+ const generationId = typeof details.generationId === "string"
68
+ ? details.generationId
69
+ : null;
70
+ if (!generationId || !wanted.has(generationId))
71
+ continue;
72
+ const status = typeof details.status === "string" ? details.status : null;
73
+ if (!status)
74
+ continue;
75
+ const entries = transitions.get(generationId) ?? [];
76
+ entries.push({
77
+ status: status,
78
+ commitHash: revision.hash,
79
+ commitDate: revision.date,
80
+ });
81
+ transitions.set(generationId, entries);
82
+ }
83
+ for (const entries of transitions.values())
84
+ entries.reverse();
85
+ return transitions;
86
+ }
87
+ export function listCellGenerationsDef(engine) {
88
+ return {
89
+ name: "list_cell_generations",
90
+ description: "List recorded generation attempts for a notebook cell: one attempt per dispatch, each with its per-attempt transition timeline.",
91
+ schema: {
92
+ book_id: z.string().describe("Book id"),
93
+ notebook_id: z.string().describe("Notebook id"),
94
+ cell_id: z.string().describe("Cell id (generate or output cell)"),
95
+ include_payloads: z.boolean().optional()
96
+ .describe("Include full generation-payload bodies (default false)"),
97
+ limit: z.number().int().positive().max(100).optional()
98
+ .describe("Max attempts to return (default 20)"),
99
+ },
100
+ handler: async (args) => {
101
+ try {
102
+ const { book_id, notebook_id, cell_id, include_payloads = false, limit = 20, } = args;
103
+ const read = engine.notebooks.read(notebook_id);
104
+ if (!read.ok) {
105
+ return {
106
+ isError: true,
107
+ content: [{ type: "text", text: read.error.message }],
108
+ };
109
+ }
110
+ const document = read.value;
111
+ const { generateCell, outputCell } = pairForCell(document, cell_id);
112
+ const outputCellIds = generateCell.type === "generate_image"
113
+ ? listGenerateImageOutputs(document, generateCell.id).map((item) => item.outputCell.id)
114
+ : generateCell.type === "generate_video"
115
+ ? listGenerateVideoOutputs(document, generateCell.id).map((item) => item.outputCell.id)
116
+ : outputCell ? [outputCell.id] : [];
117
+ const generationsResult = engine.generations.listForCell(notebook_id, generateCell.id, { limit });
118
+ if (!generationsResult.ok) {
119
+ return {
120
+ isError: true,
121
+ content: [{
122
+ type: "text",
123
+ text: generationsResult.error.message,
124
+ }],
125
+ };
126
+ }
127
+ const requestedResult = document.cells.find((cell) => cell.id === cell_id);
128
+ const filterToResult = requestedResult
129
+ && requestedResult.id !== generateCell.id
130
+ && outputCell?.id === requestedResult.id;
131
+ const rows = filterToResult
132
+ ? generationsResult.value.filter((row) => !row.outputCellId || row.outputCellId === requestedResult.id)
133
+ : generationsResult.value;
134
+ const transitions = generationTransitions(engine, rows);
135
+ const assets = await buildAssetList(engine, book_id);
136
+ const assetById = new Map(assets.map((asset) => [asset.artifact_id, asset]));
137
+ const attempts = [];
138
+ for (const row of rows) {
139
+ const joinArtifactId = row.outputArtifactId
140
+ ?? row.providerArtifactId
141
+ ?? null;
142
+ const asset = joinArtifactId
143
+ ? assetById.get(joinArtifactId)
144
+ : undefined;
145
+ let payloadAvailable = false;
146
+ let payload = null;
147
+ let commandPlan = null;
148
+ if (joinArtifactId) {
149
+ const payloadRes = await engine.metadata.artifacts.read(joinArtifactId, "generation-payload");
150
+ if (payloadRes.ok) {
151
+ payloadAvailable = true;
152
+ payload = payloadRes.value;
153
+ }
154
+ const planRes = await engine.metadata.artifacts.read(joinArtifactId, "command-plan");
155
+ if (planRes.ok)
156
+ commandPlan = planRes.value;
157
+ }
158
+ let error = row.error ?? null;
159
+ if (!error && joinArtifactId) {
160
+ const failRes = await engine.jobs.failures.read(joinArtifactId);
161
+ if (failRes.ok && failRes.value)
162
+ error = failRes.value.message;
163
+ }
164
+ attempts.push({
165
+ attemptId: row.generationId,
166
+ status: row.status,
167
+ runId: row.runId ?? null,
168
+ tool: row.tool,
169
+ provider: row.provider ?? null,
170
+ model: row.model ?? null,
171
+ prompt: row.prompt ?? null,
172
+ resolvedPrompt: row.resolvedPrompt ?? null,
173
+ artifactId: row.outputArtifactId ?? null,
174
+ providerArtifactId: row.providerArtifactId ?? null,
175
+ providerTask: await readProviderTaskStatus(engine, row.providerArtifactId ?? joinArtifactId, row),
176
+ error,
177
+ mediaUrl: asset?.media_url ?? null,
178
+ thumbnailUrl: asset?.thumbnail_url ?? null,
179
+ payloadAvailable,
180
+ ...(include_payloads ? { payload } : {}),
181
+ commandPlan,
182
+ transitions: transitions.get(row.generationId) ?? [],
183
+ createdAt: row.createdAt,
184
+ updatedAt: row.updatedAt,
185
+ });
186
+ }
187
+ const currentExecution = (outputCell
188
+ ? document.execution?.[outputCell.id]
189
+ : undefined)
190
+ ?? document.execution?.[generateCell.id]
191
+ ?? null;
192
+ const generationPlans = (document.generationPlans ?? []).filter((plan) => plan.cellId === generateCell.id
193
+ || (outputCell ? plan.cellId === outputCell.id : false));
194
+ const response = {
195
+ notebookId: notebook_id,
196
+ cellId: cell_id,
197
+ generateCellId: generateCell.id,
198
+ outputCellId: outputCell?.id ?? null,
199
+ outputCellIds,
200
+ attempts,
201
+ currentExecution,
202
+ generationPlans,
203
+ generations: {
204
+ count: rows.length,
205
+ latestStatus: rows[0]?.status ?? null,
206
+ artifactIds: generationArtifactIds(rows),
207
+ },
208
+ };
209
+ return {
210
+ content: [{
211
+ type: "text",
212
+ text: JSON.stringify(response),
213
+ }],
214
+ };
215
+ }
216
+ catch (cause) {
217
+ const message = cause instanceof Error ? cause.message : String(cause);
218
+ return {
219
+ isError: true,
220
+ content: [{ type: "text", text: message }],
221
+ };
222
+ }
223
+ },
224
+ };
225
+ }
@@ -0,0 +1,163 @@
1
+ import { createElevenLabs } from "../usage-providers.js";
2
+ import { getApiKey } from "../api-key.js";
3
+ export const GENERIC_FALLBACK_VOICES = [
4
+ { voice_id: "JBFqnCBsd6RMkjVDRZzb", name: "Generic", source: "generic" },
5
+ { voice_id: "21m00Tcm4TlvDq8ikWAM", name: "Rachel", source: "generic" },
6
+ { voice_id: "AZnzlk1XvdvUeBnXmlld", name: "Domi", source: "generic" },
7
+ { voice_id: "EXAVITQu4vr4xnSDxMaL", name: "Bella", source: "generic" },
8
+ { voice_id: "ErXwobaYiN019PkySvjV", name: "Antoni", source: "generic" },
9
+ { voice_id: "MF3mGyEYCl7XYWbV9V6O", name: "Elli", source: "generic" },
10
+ { voice_id: "TxGEqnHWrfWFTfGW9XjX", name: "Josh", source: "generic" },
11
+ { voice_id: "VR6AewLTigWG4xSOukaG", name: "Arnold", source: "generic" },
12
+ { voice_id: "pNInz6obpgDQGcFmaJgB", name: "Adam", source: "generic" },
13
+ { voice_id: "yoZ06aMxZJJ28mfd3POQ", name: "Sam", source: "generic" },
14
+ ];
15
+ function readConfiguredCustomVoices() {
16
+ const raw = process.env.ELEVENLABS_CUSTOM_VOICE_IDS ?? process.env.ELEVENLABS_CUSTOM_VOICES ?? "";
17
+ return raw
18
+ .split(/[\n,]+/)
19
+ .map((entry) => entry.trim())
20
+ .filter(Boolean)
21
+ .map(parseCustomVoice)
22
+ .filter((voice) => voice !== null);
23
+ }
24
+ function parseCustomVoice(entry) {
25
+ const parts = entry.split(/\s*(?:=|\||:)\s*/);
26
+ if (parts.length >= 2) {
27
+ const [name, ...idParts] = parts;
28
+ const voiceId = idParts.join(":").trim();
29
+ if (!voiceId)
30
+ return null;
31
+ return { voice_id: voiceId, name: name.trim() || voiceId, source: "custom" };
32
+ }
33
+ return { voice_id: entry, name: entry, source: "custom" };
34
+ }
35
+ function addUnique(target, seen, voice) {
36
+ const id = voice.voice_id.trim();
37
+ if (!id || seen.has(id))
38
+ return;
39
+ seen.add(id);
40
+ target.push({ ...voice, voice_id: id, name: voice.name.trim() || id });
41
+ }
42
+ function mergeVoiceGroups(...groups) {
43
+ const seen = new Set();
44
+ const voices = [];
45
+ for (const group of groups) {
46
+ for (const voice of group) {
47
+ addUnique(voices, seen, voice);
48
+ }
49
+ }
50
+ return voices;
51
+ }
52
+ function normalizeApiVoice(item, source) {
53
+ const voiceId = item.voice_id.trim();
54
+ if (!voiceId)
55
+ return null;
56
+ const name = item.name?.trim() || voiceId;
57
+ const category = item.category?.trim();
58
+ const previewUrl = item.preview_url?.trim();
59
+ return {
60
+ voice_id: voiceId,
61
+ name,
62
+ source,
63
+ ...(category ? { category } : {}),
64
+ ...(previewUrl ? { preview_url: previewUrl } : {}),
65
+ };
66
+ }
67
+ async function fetchVoiceGroup(apiKey, voiceType, fetchFn) {
68
+ const provider = createElevenLabs({ apiKey, timeout: 30_000, fetch: fetchFn });
69
+ const source = voiceType === "default" ? "generic" : "custom";
70
+ const voices = [];
71
+ let nextPageToken = null;
72
+ for (let page = 0; page < 10; page += 1) {
73
+ const body = await provider.v2.voices({
74
+ voice_type: voiceType,
75
+ page_size: 100,
76
+ include_total_count: false,
77
+ ...(nextPageToken ? { next_page_token: nextPageToken } : {}),
78
+ });
79
+ for (const item of body.voices) {
80
+ const normalized = normalizeApiVoice(item, source);
81
+ if (normalized)
82
+ voices.push(normalized);
83
+ }
84
+ nextPageToken = body.next_page_token?.trim()
85
+ ? body.next_page_token.trim()
86
+ : null;
87
+ if (!body.has_more || !nextPageToken)
88
+ break;
89
+ }
90
+ return voices;
91
+ }
92
+ export async function listElevenLabsVoices(fetchFn = fetch) {
93
+ const configuredCustom = readConfiguredCustomVoices();
94
+ const apiKey = getApiKey("ELEVENLABS_API_KEY");
95
+ if (!apiKey) {
96
+ return {
97
+ voices: mergeVoiceGroups(configuredCustom, GENERIC_FALLBACK_VOICES),
98
+ status: "fallback",
99
+ warning: "ELEVENLABS_API_KEY is not configured; showing configured custom IDs and generic fallback IDs.",
100
+ };
101
+ }
102
+ try {
103
+ const [custom, generic] = await Promise.all([
104
+ fetchVoiceGroup(apiKey, "non-default", fetchFn),
105
+ fetchVoiceGroup(apiKey, "default", fetchFn),
106
+ ]);
107
+ return {
108
+ voices: mergeVoiceGroups(configuredCustom, custom, generic.length > 0 ? generic : GENERIC_FALLBACK_VOICES),
109
+ status: "live",
110
+ warning: generic.length > 0 ? null : "No default voices were returned by ElevenLabs; generic fallback IDs are shown after custom voices.",
111
+ };
112
+ }
113
+ catch (error) {
114
+ return {
115
+ voices: mergeVoiceGroups(configuredCustom, GENERIC_FALLBACK_VOICES),
116
+ status: "fallback",
117
+ warning: error instanceof Error ? error.message : String(error),
118
+ };
119
+ }
120
+ }
121
+ const LIVE_VOICE_CACHE_TTL_MS = 5 * 60 * 1000;
122
+ let liveVoiceCache = null;
123
+ function voiceCredentialFingerprint() {
124
+ const customVoices = process.env.ELEVENLABS_CUSTOM_VOICE_IDS
125
+ ?? process.env.ELEVENLABS_CUSTOM_VOICES
126
+ ?? "";
127
+ return `${getApiKey("ELEVENLABS_API_KEY") ?? ""}\u0000${customVoices}`;
128
+ }
129
+ export function listElevenLabsVoicesDef() {
130
+ return {
131
+ name: "list_elevenlabs_voices",
132
+ description: "List available ElevenLabs voice IDs with custom voices first and generic voices after them",
133
+ schema: {},
134
+ handler: async () => {
135
+ const now = Date.now();
136
+ const credentialFingerprint = voiceCredentialFingerprint();
137
+ if (liveVoiceCache
138
+ && liveVoiceCache.expiresAt > now
139
+ && liveVoiceCache.credentialFingerprint === credentialFingerprint) {
140
+ return {
141
+ content: [{
142
+ type: "text",
143
+ text: JSON.stringify(liveVoiceCache.payload),
144
+ }],
145
+ };
146
+ }
147
+ const payload = await listElevenLabsVoices();
148
+ if (payload.status === "live") {
149
+ liveVoiceCache = {
150
+ expiresAt: now + LIVE_VOICE_CACHE_TTL_MS,
151
+ credentialFingerprint,
152
+ payload,
153
+ };
154
+ }
155
+ else {
156
+ liveVoiceCache = null;
157
+ }
158
+ return {
159
+ content: [{ type: "text", text: JSON.stringify(payload) }],
160
+ };
161
+ },
162
+ };
163
+ }
@@ -0,0 +1,29 @@
1
+ import { registerDiagnosticName } from "../diagnostics.js";
2
+ import { logger } from "../logger.js";
3
+ export function withLogging(def, _engine) {
4
+ registerDiagnosticName("tool", def.name);
5
+ return {
6
+ ...def,
7
+ handler: async (args) => {
8
+ const startedAt = performance.now();
9
+ try {
10
+ const result = await def.handler(args);
11
+ logger.info("mcp", {
12
+ tool: def.name,
13
+ status: result.isError ? "error" : "ok",
14
+ durationMs: Math.round(performance.now() - startedAt),
15
+ });
16
+ return result;
17
+ }
18
+ catch (error) {
19
+ logger.info("mcp", {
20
+ tool: def.name,
21
+ status: "error",
22
+ durationMs: Math.round(performance.now() - startedAt),
23
+ error,
24
+ });
25
+ throw error;
26
+ }
27
+ },
28
+ };
29
+ }
@@ -0,0 +1,95 @@
1
+ import { join } from "node:path";
2
+ import { findAudioFile, findVideoFile } from "videobook-engine";
3
+ import { z } from "zod";
4
+ import { checkAceStepAvailability } from "../acestep/config.js";
5
+ import { probeVideo } from "../ffmpeg.js";
6
+ import { queue } from "../queue.js";
7
+ import { toolError } from "./_shared.js";
8
+ const MIN_SOURCE_DURATION_MS = 10_000;
9
+ const MAX_SOURCE_DURATION_MS = 240_000;
10
+ function coverSongLabel(source) {
11
+ return `cover-song-${source.label?.trim() || source.artifactId}`;
12
+ }
13
+ export function makeCoverSongDef(engine) {
14
+ return {
15
+ name: "make_cover_song",
16
+ description: "Make a new drums-and-strings instrumental cover of 10-240 seconds of a video or audio asset's sound, generated locally with ACE-Step. The duration matches exactly; style matching is best-effort.",
17
+ schema: {
18
+ book_id: z.string().describe("Book UUID"),
19
+ asset_id: z.string().describe("Source video or audio artifact id"),
20
+ direction: z.string().trim().min(1).max(500).optional().describe("Optional additional musical direction"),
21
+ },
22
+ handler: async (args) => {
23
+ const availability = await checkAceStepAvailability();
24
+ if (!availability.available) {
25
+ return toolError(availability.reason);
26
+ }
27
+ const { asset_id, book_id, direction } = args;
28
+ const sourceAssetId = asset_id.replace(/^@/u, "");
29
+ const sourceArtifact = engine.artifacts.get(sourceAssetId);
30
+ if (!sourceArtifact.ok)
31
+ return toolError(sourceArtifact.error.message);
32
+ const sourceKind = sourceArtifact.value.kind;
33
+ const isVideo = sourceKind === "video";
34
+ const isAudio = sourceKind === "audio";
35
+ if (!isVideo && !isAudio) {
36
+ return toolError(`make_cover_song requires video or audio media; ${sourceAssetId} is ${sourceKind}`);
37
+ }
38
+ const manifest = await engine.files.manifest(sourceAssetId);
39
+ if (!manifest.ok)
40
+ return toolError(manifest.error.message);
41
+ const sourceFile = isVideo
42
+ ? findVideoFile(manifest.value.files)
43
+ : findAudioFile(manifest.value.files, sourceKind);
44
+ if (!sourceFile)
45
+ return toolError(`No ${isVideo ? "video" : "audio"} file found in artifact ${sourceAssetId}`);
46
+ let targetDurationMs;
47
+ try {
48
+ const probe = await probeVideo(join(manifest.value.path, sourceFile.name));
49
+ if (isVideo && (probe.videoStream === null || probe.videoCodec === null)) {
50
+ return toolError(`Video file ${sourceFile.name} has no video stream`);
51
+ }
52
+ if (!probe.hasAudio || probe.audioStream === null) {
53
+ return toolError(`Media file ${sourceFile.name} has no audio stream`);
54
+ }
55
+ const sourceDuration = isVideo ? probe.videoDuration : probe.audioDuration;
56
+ if (sourceDuration === null || !Number.isFinite(sourceDuration) || sourceDuration <= 0) {
57
+ return toolError(`Could not determine a valid media duration for ${sourceAssetId}`);
58
+ }
59
+ targetDurationMs = Math.round(sourceDuration * 1000);
60
+ }
61
+ catch (error) {
62
+ return toolError(`Failed to probe ${sourceAssetId}: ${error instanceof Error ? error.message : String(error)}`);
63
+ }
64
+ if (targetDurationMs < MIN_SOURCE_DURATION_MS || targetDurationMs > MAX_SOURCE_DURATION_MS) {
65
+ return toolError(`make_cover_song requires a media duration between 10.000s and 240.000s inclusive; got ${(targetDurationMs / 1000).toFixed(3)}s`);
66
+ }
67
+ const created = await engine.artifacts.create("audio", coverSongLabel(sourceArtifact.value));
68
+ if (!created.ok)
69
+ return toolError(`Failed to create audio asset: ${created.error.message}`);
70
+ const jobId = `make-cover-song-${created.value.artifactId}-${Date.now()}`;
71
+ await queue.enqueue(jobId, {
72
+ type: "generate_acestep_cover",
73
+ audAssetId: created.value.artifactId,
74
+ sourceAssetId,
75
+ sourceFilename: sourceFile.name,
76
+ targetDurationMs,
77
+ direction,
78
+ bookId: book_id,
79
+ });
80
+ return {
81
+ content: [{
82
+ type: "text",
83
+ text: JSON.stringify({
84
+ audio_asset_id: created.value.artifactId,
85
+ source_asset_id: sourceAssetId,
86
+ source_kind: sourceKind,
87
+ duration_seconds: targetDurationMs / 1000,
88
+ job_id: jobId,
89
+ status: "enqueued",
90
+ }),
91
+ }],
92
+ };
93
+ },
94
+ };
95
+ }
@@ -0,0 +1,23 @@
1
+ import { z } from "zod";
2
+ export function markAssetSeenDef(engine) {
3
+ return {
4
+ name: "mark_asset_seen",
5
+ description: "Mark an asset as seen so the sidebar's NEW badge clears. Idempotent: re-marking an already-seen asset is a no-op.",
6
+ schema: {
7
+ asset_id: z.string().describe("Asset ID to mark seen (e.g. img-cute-cat)"),
8
+ book_id: z.string().describe("Book id"),
9
+ },
10
+ handler: async (args) => {
11
+ const { asset_id, book_id } = args;
12
+ const updated = await engine.jobs.artifactWork.markSeen(book_id);
13
+ return {
14
+ content: [
15
+ {
16
+ type: "text",
17
+ text: JSON.stringify({ asset_id, updated }),
18
+ },
19
+ ],
20
+ };
21
+ },
22
+ };
23
+ }