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
package/CHANGELOG.md ADDED
@@ -0,0 +1,54 @@
1
+ # Changelog
2
+
3
+ All notable changes to the `videobook` npm package are documented here.
4
+ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
5
+ and the package uses [Semantic Versioning](https://semver.org/).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [0.2.0] - 2026-10-19
10
+
11
+ ### Added
12
+
13
+ - `videobook config` lists where every provider key comes from, with secret
14
+ values masked; `config get`, `config set` and `config unset` edit the
15
+ data-home `.env` atomically.
16
+ - 1Password support: `op://` references in the environment or `.env` resolve
17
+ through the 1Password CLI when a server starts, and
18
+ `videobook setup 1password --op-vault <vault>` reads every key from a vault
19
+ whose items are named after the keys. `videobook doctor` reports the setup
20
+ and which keys 1Password supplied.
21
+ - `VIDEOBOOK_YTDLP_PATH` selects the yt-dlp binary.
22
+ - `list_jobs` accepts `job_keys`, the `job_id` strings other tools return.
23
+
24
+ ### Changed
25
+
26
+ - ffprobe now comes from `@ffprobe-installer/ffprobe`, which installs one
27
+ native build for the current platform instead of `ffprobe-static`'s builds
28
+ for every platform. Apple Silicon and Linux arm64 get a bundled ffprobe, and
29
+ the install is about 300 MB smaller. When npm skips the package's chmod
30
+ script, videobook marks the binary executable itself.
31
+ - The npm page no longer links to the private source repository, which
32
+ anonymous visitors cannot open; its homepage is the npm package page.
33
+ - The README states that Windows is not supported yet, and why, instead of
34
+ calling it untested.
35
+
36
+ ### Fixed
37
+
38
+ - Downloading videos from URLs works when npm blocked the yt-dlp download:
39
+ videobook falls back to `yt-dlp` on `PATH`, passes yt-dlp the resolved
40
+ ffmpeg so format merges work, and fails with install instructions when no
41
+ yt-dlp exists. `videobook doctor` shows which yt-dlp is used.
42
+ - `videobook run` waits for queued jobs on an already running server too,
43
+ instead of returning while the job runs, and reports how the job ended.
44
+
45
+ ## [0.1.0] - 2026-10-19
46
+
47
+ ### Added
48
+
49
+ - `videobook` command-line interface: `serve` runs the MCP server with the
50
+ bundled web UI (or `--headless` for MCP and API only), `mcp` serves MCP over
51
+ stdio for agent hosts, `run` and `tools` call MCP tools from the shell,
52
+ `gc-books` reclaims catalog storage, and `doctor` checks the local
53
+ environment.
54
+ - Installed data defaults to `~/.videobook`, overridable with `VIDEOBOOK_HOME`.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Justin Tanner
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,196 @@
1
- # Temporary Holding Version
1
+ # videobook
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Videobook is a local-first notebook studio for generative media: images,
4
+ videos, audio, prompts, characters and scenes live as cells in an executable
5
+ graph, and every change is recorded as a revision. This package installs one
6
+ `videobook` command that runs the Videobook MCP server three ways:
7
+
8
+ - with the web UI at `http://127.0.0.1:3001/`
9
+ - headless, serving MCP and the HTTP API only
10
+ - over stdio, for agent hosts such as Claude Code
11
+
12
+ ## Requirements
13
+
14
+ - Node.js 22 or newer.
15
+ - macOS (Apple Silicon or Intel) or Linux (x64 or arm64). Windows is not
16
+ supported yet; see the platform notes.
17
+ - About 800 MB of disk. Installing downloads the ffmpeg and yt-dlp binaries
18
+ from GitHub, and the first video render downloads Chrome Headless Shell
19
+ (about 150 MB) into `~/.cache/videobook/remotion`.
20
+ - Native ffmpeg, ffprobe and yt-dlp builds come with the package. Every
21
+ platform falls back to `ffmpeg`, `ffprobe` and `yt-dlp` on `PATH` when a
22
+ bundled binary is missing.
23
+
24
+ ## Install
25
+
26
+ ```bash
27
+ npm install -g videobook
28
+ videobook doctor
29
+ ```
30
+
31
+ npm 12 and newer skip dependency install scripts unless you approve them.
32
+ Approve the six that videobook needs, either per install or once for your
33
+ user:
34
+
35
+ ```bash
36
+ npm install -g videobook --allow-scripts=ffmpeg-static,ytdlp-nodejs,@dolthub/doltlite,usearch,onnxruntime-node,esbuild
37
+ npm config set allow-scripts=ffmpeg-static,ytdlp-nodejs,@dolthub/doltlite,usearch,onnxruntime-node,esbuild --location=user
38
+ ```
39
+
40
+ - `ffmpeg-static` downloads ffmpeg, which every media operation needs.
41
+ - `ytdlp-nodejs` downloads yt-dlp, which downloading videos from URLs needs.
42
+ Without it, videobook uses `yt-dlp` on `PATH` or `VIDEOBOOK_YTDLP_PATH`.
43
+ - `@dolthub/doltlite`, `usearch` and `onnxruntime-node` use prebuilt native
44
+ binaries and only compile or fetch extras on unusual platforms.
45
+ - `esbuild` checks its platform binary for the Remotion renderer.
46
+
47
+ npm also reports the install script of `@ffprobe-installer/<platform>`, for
48
+ example `@ffprobe-installer/darwin-arm64`. It only marks ffprobe executable,
49
+ which videobook does itself when it starts, so it can stay unapproved. With
50
+ `--strict-allow-scripts`, approve it too.
51
+
52
+ `videobook doctor` reports anything missing and prints the fix.
53
+
54
+ ## Run
55
+
56
+ ```bash
57
+ videobook # same as videobook serve
58
+ videobook serve --open # serve MCP and the web UI, open a browser
59
+ videobook serve --headless # MCP and HTTP API only
60
+ videobook mcp # MCP over stdio for agent hosts
61
+ videobook run list_books # call one MCP tool and print its result
62
+ videobook run create_book name=demo
63
+ videobook tools # list tools and their parameters
64
+ videobook gc-books # reclaim catalog storage in every book
65
+ videobook doctor # check Node, binaries, native modules and keys
66
+ videobook config # show where each provider key comes from
67
+ videobook config set FAL_API_KEY op://Private/FAL_API_KEY/password
68
+ videobook setup 1password --op-vault Private
69
+ videobook --version
70
+ ```
71
+
72
+ Every command accepts `--port <n>` (default 3001), `--library <dir>`,
73
+ `--home <dir>` and `--log-level <silent|error|warn|info|debug>`. Tool
74
+ arguments are `key=value`; values that parse as JSON are passed as JSON. When
75
+ a tool queues a job, `run` waits for it to finish, up to `--timeout <s>`
76
+ (default 600), and exits 1 if the job fails. `--no-wait` returns at once,
77
+ except on a server that `run` started for itself, which stops when `run`
78
+ exits. Exit codes are 0 for success, 1 for a failure and 2 for a usage error.
79
+
80
+ ## Agent hosts
81
+
82
+ ```bash
83
+ claude mcp add videobook -- videobook mcp
84
+ ```
85
+
86
+ Other hosts take the same command, for example
87
+ `{ "command": "videobook", "args": ["mcp"] }`. stdio accepts clients that
88
+ start with the 2025-era `initialize` and clients that use MCP 2026-07-28.
89
+ While `videobook serve` runs, HTTP clients can connect to
90
+ `http://127.0.0.1:3001/mcp`, which speaks MCP 2026-07-28 only.
91
+
92
+ ## One server per library
93
+
94
+ A library is owned by one videobook process at a time, recorded in
95
+ `<library>/.videobook-server.json`. A second `videobook serve` for the same
96
+ library exits and names the running URL. `videobook mcp` and `videobook run`
97
+ relay to the running server when there is one; otherwise they start one in
98
+ their own process, which `videobook mcp` keeps serving HTTP and the web UI
99
+ for as long as the agent host keeps it open. `videobook gc-books` refuses to
100
+ run while a server owns the library.
101
+
102
+ ## Data and configuration
103
+
104
+ Installed data lives in `~/.videobook`:
105
+
106
+ - `books/`, the library of books
107
+ - `app-state.json`, connected X and Dropbox accounts
108
+ - `.env`, provider keys, also editable from Settings in the web UI
109
+
110
+ `VIDEOBOOK_HOME` or `--home` moves all three. `VIDEOBOOK_LIBRARY_DIR`,
111
+ `VIDEOBOOK_APP_STATE_PATH` and `VIDEOBOOK_ENV_PATH` move one each; `--home`
112
+ overrides any of them inherited from your shell. Set `VIDEOBOOK_HOME` and
113
+ `VIDEOBOOK_ENV_PATH` in the environment, not in `.env`, because they decide
114
+ which `.env` is read.
115
+
116
+ Caches live in `~/.cache/videobook`. Other settings: `PORT`,
117
+ `VIDEOBOOK_FFMPEG_PATH`, `VIDEOBOOK_FFPROBE_PATH`, `VIDEOBOOK_YTDLP_PATH`,
118
+ `VIDEOBOOK_REMOTION_CACHE_DIR`, `VIDEOBOOK_MODEL_CACHE_DIR`,
119
+ `VIDEOBOOK_DOWNLOADS_DIR` and `VIDEOBOOK_LOG_LEVEL`.
120
+
121
+ ## Provider keys
122
+
123
+ The keys are `OPENAI_API_KEY`, `KIE_API_KEY`, `XAI_API_KEY`, `FAL_API_KEY`,
124
+ `DASHSCOPE_API_KEY`, `ELEVENLABS_API_KEY`, `KIMI_CODING_API_KEY`,
125
+ `X_CLIENT_ID` and `X_CLIENT_SECRET`, `DROPBOX_CLIENT_ID` and
126
+ `DROPBOX_CLIENT_SECRET`, and the `B2_*` storage settings. The server starts
127
+ without any of them; tools that need one report which.
128
+
129
+ A key can come from four places. The first one that has it wins:
130
+
131
+ 1. The environment of the videobook process.
132
+ 2. A value in `.env`, set with `videobook config set <KEY> <value>` or from
133
+ Settings in the web UI.
134
+ 3. A 1Password secret reference in `.env`, such as
135
+ `op://Private/FAL_API_KEY/password`.
136
+ 4. A 1Password vault whose items are named after the keys.
137
+
138
+ `videobook config` lists every key with its source and masks secret values.
139
+ `config get`, `config set` and `config unset` work on one key and edit
140
+ `.env` atomically. `config set` refuses a key that your shell already
141
+ exports, because the exported value would win.
142
+
143
+ ### 1Password
144
+
145
+ References and vaults need the [1Password CLI](https://developer.1password.com/docs/cli/)
146
+ (`op`). When a server starts, videobook resolves every `op://` value in the
147
+ environment and `.env`, and every key the vault has, in one `op inject` run.
148
+ `videobook run` and `videobook mcp` skip this when they relay to a running
149
+ server.
150
+
151
+ ```bash
152
+ videobook setup 1password --op-vault Private # use op's own sign-in
153
+ videobook setup 1password --op-vault Apicity --op-token env:OP_SERVICE_ACCOUNT_TOKEN
154
+ videobook doctor # shows which keys came from 1Password
155
+ videobook setup 1password --remove
156
+ ```
157
+
158
+ `setup 1password` saves `VIDEOBOOK_OP_VAULT` and `VIDEOBOOK_OP_SERVICE_TOKEN`
159
+ in `.env`, then lists the vault to report which keys it holds; `--no-verify`
160
+ skips the listing. A vault item supplies a key when its title is the key name,
161
+ and the value is read from its `password` field, for example
162
+ `op://Apicity/OPENAI_API_KEY/password`.
163
+
164
+ The token setting takes `env:VAR`, `$VAR` or a literal service-account
165
+ token. Prefer `env:VAR`, which keeps the token out of the file. When
166
+ `OP_SERVICE_ACCOUNT_TOKEN` is exported, setup records
167
+ `env:OP_SERVICE_ACCOUNT_TOKEN`. Without a token, `op` uses its own sign-in.
168
+ The token reaches `op` only through its environment, never its arguments.
169
+
170
+ A reference that does not resolve is left unset, so it is never sent to a
171
+ provider as a key. The server and `videobook doctor` report it. Keys that
172
+ come from 1Password are read-only in Settings.
173
+
174
+ ## Platform notes
175
+
176
+ - macOS on Apple Silicon is the primary platform.
177
+ - macOS on Intel works, but ONNX Runtime has no Intel Mac build, so semantic
178
+ search is unavailable there.
179
+ - Linux x64 and arm64 are supported.
180
+ - Windows is not supported yet. Every native dependency has a Windows x64
181
+ build, but the release smoke test has not passed on Windows. Windows has no
182
+ SIGTERM, so stopping `videobook serve` from another process ends it without
183
+ a clean shutdown, and the next start replaces the lock file it leaves. The
184
+ Release check workflow runs the smoke test on Windows for every release tag
185
+ without blocking the release.
186
+
187
+ ## Security
188
+
189
+ Videobook is a local, single-user service. It listens on `127.0.0.1` only and
190
+ accepts requests from loopback hosts and origins. It has no user
191
+ authentication, so do not expose it to other machines or share it between
192
+ users.
193
+
194
+ ## License
195
+
196
+ MIT
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ const major = Number(process.versions.node.split(".")[0]);
3
+ if (major < 22) {
4
+ process.stderr.write(`videobook needs Node.js 22 or newer; this is ${process.version}.\nInstall Node.js 22+ from https://nodejs.org or your version manager, then run videobook again.\n`);
5
+ process.exit(1);
6
+ }
7
+ await import(new URL("../dist/cli/entry.js", import.meta.url).href);
@@ -0,0 +1,203 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { AceStepError } from "./errors.js";
3
+ // The live ace-server job flow (tools/ace-server.cpp, verified against version
4
+ // 9761469): POST /synth returns {"id"} immediately, a FIFO worker thread runs
5
+ // the GPU job, GET /job?id reports running|done|failed|cancelled, GET
6
+ // /job?id&result=1 serves the multipart/mixed body (fixed boundary
7
+ // "ace-batch-boundary": one audio part plus one latent part per track), and
8
+ // POST /job?id&cancel=1 cancels a running job. Completed jobs are evicted FIFO
9
+ // past 32, so the result is fetched immediately after the poll reports done.
10
+ const DEFAULT_SYNTH_TIMEOUT_MS = 30 * 60_000;
11
+ const DEFAULT_POLL_INTERVAL_MS = 3_000;
12
+ const SUBMIT_TIMEOUT_MS = 60_000;
13
+ const POLL_TIMEOUT_MS = 5_000;
14
+ const RESULT_TIMEOUT_MS = 120_000;
15
+ const ERROR_BODY_PREVIEW_CHARS = 500;
16
+ export async function isHealthy(baseUrl, timeoutMs = 500) {
17
+ try {
18
+ const response = await fetch(`${baseUrl}/health`, { signal: AbortSignal.timeout(timeoutMs) });
19
+ return response.ok;
20
+ }
21
+ catch {
22
+ return false;
23
+ }
24
+ }
25
+ function wireRequest(request) {
26
+ return {
27
+ caption: request.caption,
28
+ lyrics: request.lyrics,
29
+ task_type: request.taskType,
30
+ output_format: request.outputFormat,
31
+ seed: request.seed,
32
+ inference_steps: request.inferenceSteps,
33
+ audio_cover_strength: request.audioCoverStrength,
34
+ synth_batch_size: request.synthBatchSize,
35
+ synth_model: request.synthModel,
36
+ duration: request.duration,
37
+ };
38
+ }
39
+ function headerRecord(headerBlock) {
40
+ const headers = {};
41
+ for (const line of headerBlock.split("\r\n")) {
42
+ const colon = line.indexOf(":");
43
+ if (colon === -1)
44
+ continue;
45
+ headers[line.slice(0, colon).trim().toLowerCase()] = line.slice(colon + 1).trim();
46
+ }
47
+ return headers;
48
+ }
49
+ export function parseMultipartMixed(body, contentType) {
50
+ const boundaryMatch = /boundary="?([^";]+)"?/u.exec(contentType);
51
+ if (boundaryMatch === null) {
52
+ throw new AceStepError("malformed_response", `ace-server response has no multipart boundary (content-type: "${contentType}")`);
53
+ }
54
+ const delimiter = Buffer.from(`--${boundaryMatch[1]}`);
55
+ const parts = [];
56
+ let offset = body.indexOf(delimiter);
57
+ while (offset !== -1) {
58
+ const afterDelimiter = offset + delimiter.length;
59
+ if (body.subarray(afterDelimiter, afterDelimiter + 2).toString("latin1") === "--")
60
+ break;
61
+ const boundaryLineEnd = body.indexOf("\r\n", afterDelimiter);
62
+ const headerEnd = body.indexOf("\r\n\r\n", afterDelimiter);
63
+ const next = headerEnd === -1 ? -1 : body.indexOf(delimiter, headerEnd + 4);
64
+ if (boundaryLineEnd === -1 || headerEnd === -1 || next === -1) {
65
+ throw new AceStepError("malformed_response", "ace-server multipart response is truncated");
66
+ }
67
+ const headerBlock = body.subarray(boundaryLineEnd + 2, headerEnd).toString("utf8");
68
+ let dataEnd = next;
69
+ if (body.subarray(dataEnd - 2, dataEnd).toString("latin1") === "\r\n")
70
+ dataEnd -= 2;
71
+ parts.push({ headers: headerRecord(headerBlock), data: body.subarray(headerEnd + 4, dataEnd) });
72
+ offset = next;
73
+ }
74
+ if (parts.length === 0) {
75
+ throw new AceStepError("malformed_response", "ace-server multipart response contained no parts");
76
+ }
77
+ return parts;
78
+ }
79
+ function describeFetchError(error) {
80
+ if (error instanceof Error) {
81
+ const cause = error.cause instanceof Error ? `: ${error.cause.message}` : "";
82
+ return `${error.message}${cause}`;
83
+ }
84
+ return String(error);
85
+ }
86
+ async function readErrorPreview(response) {
87
+ const bodyText = await response.text().catch(() => "");
88
+ return bodyText.slice(0, ERROR_BODY_PREVIEW_CHARS);
89
+ }
90
+ async function submitSynthJob(baseUrl, srcWavPath, request, signal) {
91
+ const sourceBytes = await readFile(srcWavPath);
92
+ const form = new FormData();
93
+ form.set("request", new Blob([JSON.stringify(wireRequest(request))], { type: "application/json" }), "request.json");
94
+ form.set("audio", new Blob([sourceBytes], { type: "audio/wav" }), "source.wav");
95
+ const response = await fetch(`${baseUrl}/synth`, { method: "POST", body: form, signal });
96
+ if (!response.ok) {
97
+ throw new AceStepError("synth_http_error", `ace-server /synth returned ${response.status}: ${await readErrorPreview(response)}`);
98
+ }
99
+ const body = (await response.json().catch(() => null));
100
+ if (typeof body?.id !== "string" || body.id.length === 0) {
101
+ throw new AceStepError("malformed_response", "ace-server /synth returned no job id");
102
+ }
103
+ return body.id;
104
+ }
105
+ async function readJobStatus(baseUrl, jobId) {
106
+ const response = await fetch(`${baseUrl}/job?id=${encodeURIComponent(jobId)}`, {
107
+ signal: AbortSignal.timeout(POLL_TIMEOUT_MS),
108
+ });
109
+ if (!response.ok) {
110
+ throw new AceStepError("synth_http_error", `ace-server /job returned ${response.status}: ${await readErrorPreview(response)}`);
111
+ }
112
+ const body = (await response.json().catch(() => null));
113
+ if (typeof body?.status !== "string") {
114
+ throw new AceStepError("malformed_response", "ace-server /job returned no status");
115
+ }
116
+ return body.status;
117
+ }
118
+ async function cancelSynthJob(baseUrl, jobId) {
119
+ try {
120
+ await fetch(`${baseUrl}/job?id=${encodeURIComponent(jobId)}&cancel=1`, {
121
+ method: "POST",
122
+ signal: AbortSignal.timeout(POLL_TIMEOUT_MS),
123
+ });
124
+ }
125
+ catch {
126
+ // Best-effort: the job also dies with the server, and an orphaned
127
+ // generation is discarded when its result is never fetched.
128
+ }
129
+ }
130
+ async function fetchSynthResult(baseUrl, jobId) {
131
+ const response = await fetch(`${baseUrl}/job?id=${encodeURIComponent(jobId)}&result=1`, {
132
+ signal: AbortSignal.timeout(RESULT_TIMEOUT_MS),
133
+ });
134
+ if (!response.ok) {
135
+ throw new AceStepError("synth_http_error", `ace-server /job result returned ${response.status}: ${await readErrorPreview(response)}`);
136
+ }
137
+ const contentType = response.headers.get("content-type") ?? "";
138
+ const body = Buffer.from(await response.arrayBuffer());
139
+ if (contentType.startsWith("audio/")) {
140
+ return { audio: body, audioContentType: contentType, latents: null };
141
+ }
142
+ const parts = parseMultipartMixed(body, contentType);
143
+ const audioPart = parts.find((part) => (part.headers["content-type"] ?? "").startsWith("audio/"));
144
+ if (audioPart === undefined) {
145
+ throw new AceStepError("malformed_response", "ace-server synth result contained no audio part");
146
+ }
147
+ const latentPart = parts.find((part) => (part.headers["content-type"] ?? "").startsWith("application/octet-stream"));
148
+ return {
149
+ audio: audioPart.data,
150
+ audioContentType: audioPart.headers["content-type"] ?? "audio/wav",
151
+ latents: latentPart?.data ?? null,
152
+ };
153
+ }
154
+ async function delay(ms, signal) {
155
+ await new Promise((resolve, reject) => {
156
+ const timer = setTimeout(() => {
157
+ signal.removeEventListener("abort", onAbort);
158
+ resolve();
159
+ }, ms);
160
+ const onAbort = () => {
161
+ clearTimeout(timer);
162
+ reject(signal.reason instanceof Error ? signal.reason : new Error("Aborted"));
163
+ };
164
+ signal.addEventListener("abort", onAbort, { once: true });
165
+ });
166
+ }
167
+ export async function synthCover(baseUrl, srcWavPath, request, options = {}) {
168
+ const timeoutMs = options.timeoutMs ?? DEFAULT_SYNTH_TIMEOUT_MS;
169
+ const pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
170
+ const deadlineSignal = AbortSignal.timeout(timeoutMs);
171
+ const signal = options.signal
172
+ ? AbortSignal.any([options.signal, deadlineSignal])
173
+ : deadlineSignal;
174
+ let jobId = null;
175
+ try {
176
+ jobId = await submitSynthJob(baseUrl, srcWavPath, request, AbortSignal.any([signal, AbortSignal.timeout(SUBMIT_TIMEOUT_MS)]));
177
+ for (;;) {
178
+ const status = await readJobStatus(baseUrl, jobId);
179
+ if (status === "done")
180
+ return await fetchSynthResult(baseUrl, jobId);
181
+ if (status === "failed") {
182
+ throw new AceStepError("synth_failed", "ace-server reported the cover synthesis job as failed; the reason is in the [ace-step] logs above");
183
+ }
184
+ if (status === "cancelled") {
185
+ throw new AceStepError("synth_failed", "ace-server cancelled the cover synthesis job");
186
+ }
187
+ signal.throwIfAborted();
188
+ await delay(pollIntervalMs, signal);
189
+ }
190
+ }
191
+ catch (error) {
192
+ if (error instanceof AceStepError)
193
+ throw error;
194
+ if (jobId !== null && signal.aborted)
195
+ await cancelSynthJob(baseUrl, jobId);
196
+ if (options.signal?.aborted)
197
+ throw error;
198
+ if (deadlineSignal.aborted) {
199
+ throw new AceStepError("synth_timeout", `ace-server cover synthesis did not finish within ${timeoutMs}ms`);
200
+ }
201
+ throw new AceStepError("server_exited", `ace-server request failed: ${describeFetchError(error)}. The server may have crashed or been stopped; check [ace-step] logs.`);
202
+ }
203
+ }
@@ -0,0 +1,62 @@
1
+ import { existsSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { isHealthy } from "./client.js";
5
+ const DEFAULT_PORT = 8317;
6
+ const DEFAULT_MODEL = "acestep-v15-turbo-Q4_K_M.gguf";
7
+ const TEXT_ENCODER_MODEL = "Qwen3-Embedding-0.6B-Q8_0.gguf";
8
+ const VAE_MODEL = "vae-BF16.gguf";
9
+ const GATE_HEALTH_TIMEOUT_MS = 500;
10
+ function acestepRoot() {
11
+ return join(homedir(), ".cache", "videobook", "acestep");
12
+ }
13
+ export function aceStepConfig() {
14
+ const baseUrl = process.env.VIDEOBOOK_ACESTEP_BASE_URL?.trim();
15
+ const parsedPort = Number.parseInt(process.env.VIDEOBOOK_ACESTEP_PORT ?? "", 10);
16
+ return {
17
+ baseUrl: baseUrl ? baseUrl.replace(/\/+$/u, "") : null,
18
+ serverPath: process.env.VIDEOBOOK_ACESTEP_SERVER_PATH?.trim() || join(acestepRoot(), "bin", "ace-server"),
19
+ modelsDir: process.env.VIDEOBOOK_ACESTEP_MODELS_DIR?.trim() || join(acestepRoot(), "models"),
20
+ port: Number.isFinite(parsedPort) && parsedPort > 0 ? parsedPort : DEFAULT_PORT,
21
+ model: process.env.VIDEOBOOK_ACESTEP_MODEL?.trim() || DEFAULT_MODEL,
22
+ keepLoaded: process.env.VIDEOBOOK_ACESTEP_KEEP_LOADED === "1",
23
+ };
24
+ }
25
+ function requiredModelFiles(config = aceStepConfig()) {
26
+ return [config.model, TEXT_ENCODER_MODEL, VAE_MODEL];
27
+ }
28
+ export function checkLocalAvailability(config = aceStepConfig()) {
29
+ if (!existsSync(config.serverPath)) {
30
+ return {
31
+ available: false,
32
+ kind: "binary_missing",
33
+ reason: `acestep.cpp runtime is not installed: ace-server not found at ${config.serverPath}. ` +
34
+ `Run "npm run install:acestep", or set VIDEOBOOK_ACESTEP_SERVER_PATH / VIDEOBOOK_ACESTEP_BASE_URL.`,
35
+ };
36
+ }
37
+ const missing = requiredModelFiles(config).filter((name) => !existsSync(join(config.modelsDir, name)));
38
+ if (missing.length > 0) {
39
+ return {
40
+ available: false,
41
+ kind: "models_missing",
42
+ reason: `ACE-Step models missing from ${config.modelsDir}: ${missing.join(", ")}. Run "npm run install:acestep".`,
43
+ };
44
+ }
45
+ return { available: true };
46
+ }
47
+ export async function checkAceStepAvailability() {
48
+ const config = aceStepConfig();
49
+ if (config.baseUrl !== null) {
50
+ const healthy = await isHealthy(config.baseUrl, GATE_HEALTH_TIMEOUT_MS);
51
+ if (!healthy) {
52
+ return {
53
+ available: false,
54
+ kind: "unreachable",
55
+ reason: `ace-server at ${config.baseUrl} did not answer /health within ${GATE_HEALTH_TIMEOUT_MS}ms ` +
56
+ `(VIDEOBOOK_ACESTEP_BASE_URL). Start it or unset the variable.`,
57
+ };
58
+ }
59
+ return { available: true };
60
+ }
61
+ return checkLocalAvailability(config);
62
+ }
@@ -0,0 +1,8 @@
1
+ export class AceStepError extends Error {
2
+ kind;
3
+ constructor(kind, message) {
4
+ super(message);
5
+ this.name = "AceStepError";
6
+ this.kind = kind;
7
+ }
8
+ }