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,388 @@
1
+ import { z } from "zod";
2
+ import { readFile } from "node:fs/promises";
3
+ import { join, dirname } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { textPart, imageUrlPart } from "@apicity/openai";
6
+ import { modelEntry } from "../media/catalog.js";
7
+ import { platformGuidance } from "../platform-guidance.js";
8
+ import { expandTimelineSlotRefs, timelineSlotArtifactIds } from "../timeline-helpers.js";
9
+ import { resolveArtifactRefs } from "../artifact-refs.js";
10
+ import { buildIntelligenceResponses, firstResponseText, intelligenceRequest, } from "../openai-intelligence.js";
11
+ const __dirname = dirname(fileURLToPath(import.meta.url));
12
+ const GUIDES_DIR = join(__dirname, "../guides");
13
+ const GUIDE_FILES = {
14
+ nano_banana: "nano_banana_pro_prompting_guide.md",
15
+ gpt_image: "gpt_image_2_5_prompting_guide.md",
16
+ kling30: "kling_3_0_prompting_guide.md",
17
+ grok_imagine: "grok_imagine_prompting_guide.md",
18
+ grok_image: "grok_imagine_prompting_guide.md",
19
+ seedance2: "seedance_2_prompting_guide.md",
20
+ seedance25: "seedance_2_prompting_guide.md",
21
+ };
22
+ const SUPPORTED_MODELS = Object.keys(GUIDE_FILES).sort();
23
+ // --- Pure helpers ---
24
+ export function loadGuide(model) {
25
+ const filename = GUIDE_FILES[model];
26
+ if (!filename) {
27
+ throw new Error(`No prompting guide available for model: ${model}. Supported models: ${SUPPORTED_MODELS.join(", ")}`);
28
+ }
29
+ return readFile(join(GUIDES_DIR, filename), "utf-8");
30
+ }
31
+ function guideFilename(model) {
32
+ return GUIDE_FILES[model] ?? "";
33
+ }
34
+ const IMAGE_CLEANUP_DIRECTIVE = "IMAGE CLEANUP: The reference image(s) may contain AI-generation artifacts " +
35
+ "(plasticky skin, oversharpened or haloed edges, waxy textures, mushy background detail) " +
36
+ "or low-resolution noise (blocking, chroma banding, jpeg ringing). Describe the intended " +
37
+ "subject/scene rather than replicating these artifacts. Produce a prompt that guides the " +
38
+ "target model to render the scene cleanly at full fidelity, honoring the platform aesthetic above.";
39
+ function previousErrorSection(error) {
40
+ const failCodeLine = error.failCode
41
+ ? `Provider fail code: ${error.failCode}\n`
42
+ : "";
43
+ return ("\n--- PREVIOUS GENERATION ERROR ---\n" +
44
+ "A previous generation attempt with this exact prompt FAILED with the provider error below.\n" +
45
+ failCodeLine +
46
+ `Error message: ${error.message}\n` +
47
+ "Rework the prompt so it will not trigger this failure again, while preserving the creative intent:\n" +
48
+ "- Infer which element of the prompt (or its references) most plausibly triggered the error and rewrite or generalize that element (e.g. a PROMINENT_PEOPLE / celebrity-likeness filter -> describe a generic fictional person; a sensitive-content filter -> reframe or tone down the flagged concept)\n" +
49
+ "- Keep every part of the prompt unrelated to the failure intact in spirit\n" +
50
+ "- Do NOT mention the error, the filter, the provider, or these instructions in the rewritten prompt text\n" +
51
+ "--- END PREVIOUS GENERATION ERROR ---\n");
52
+ }
53
+ export function buildRewritePromptText(guide, prompt, extras = {}) {
54
+ const { maxChars, platform, customPrompt, hasImages, previousError } = extras;
55
+ let charLimitRule = "";
56
+ if (maxChars) {
57
+ charLimitRule =
58
+ `- HARD LIMIT: The rewritten prompt MUST be under ${maxChars} characters (API max is 500)\n` +
59
+ "- Be concise and visually specific — cut filler words, focus on key actions and details\n";
60
+ }
61
+ const platformSection = platform
62
+ ? `\n--- PLATFORM STYLE ---\n${platformGuidance(platform)}\n--- END PLATFORM STYLE ---\n` +
63
+ (hasImages ? `\n${IMAGE_CLEANUP_DIRECTIVE}\n` : "")
64
+ : "";
65
+ const instructionSection = customPrompt
66
+ ? `\nADDITIONAL INSTRUCTION: ${customPrompt}\n`
67
+ : "";
68
+ const errorSection = previousError ? previousErrorSection(previousError) : "";
69
+ const userPromptBlock = prompt
70
+ ? `USER PROMPT TO REWRITE:\n${prompt}`
71
+ : "USER PROMPT TO REWRITE: (none — describe the reference image(s) directly, applying the guide above)";
72
+ return ("You are a prompt engineering expert. Using the model-specific prompting guide below, " +
73
+ "rewrite the user's prompt to follow best practices for this model.\n\n" +
74
+ "RULES:\n" +
75
+ "- Output ONLY the rewritten prompt text, nothing else\n" +
76
+ "- Do not include explanations, labels, or commentary\n" +
77
+ charLimitRule +
78
+ "- Preserve the user's creative intent while improving structure and detail\n" +
79
+ "- Apply the guide's recommended prompt structure and techniques\n" +
80
+ "- If images are provided, incorporate visual details you observe into the prompt\n\n" +
81
+ `--- PROMPTING GUIDE ---\n${guide}\n--- END GUIDE ---\n` +
82
+ platformSection +
83
+ instructionSection +
84
+ errorSection +
85
+ `\n${userPromptBlock}`);
86
+ }
87
+ export function buildRewriteMessages(guide, prompt, extras = {}) {
88
+ return [{ role: "user", content: buildRewritePromptText(guide, prompt, extras) }];
89
+ }
90
+ export function buildVisionMessages(guide, prompt, imageDataUris, extras = {}) {
91
+ const content = imageDataUris.map((uri) => imageUrlPart(uri));
92
+ content.push(textPart(buildRewritePromptText(guide, prompt, { ...extras, hasImages: true })));
93
+ return [{ role: "user", content }];
94
+ }
95
+ export function buildResult(model, originalPrompt, rewrittenPrompt, guideFile, previousError) {
96
+ const result = {
97
+ model,
98
+ original_prompt: originalPrompt,
99
+ rewritten_prompt: rewrittenPrompt,
100
+ guide_used: guideFile,
101
+ };
102
+ if (previousError) {
103
+ result.previous_error = {
104
+ message: previousError.message,
105
+ ...(previousError.failCode ? { fail_code: previousError.failCode } : {}),
106
+ };
107
+ }
108
+ return result;
109
+ }
110
+ export function normalizePromptForMatch(p) {
111
+ return p.replace(/\s+/g, " ").trim();
112
+ }
113
+ const ERROR_RECENCY_MS = 7 * 24 * 60 * 60 * 1000;
114
+ export async function findPreviousErrorForPrompt(engine, prompt) {
115
+ const result = await engine.jobs.failures.findAll();
116
+ if (!result.ok)
117
+ return null;
118
+ const normalized = normalizePromptForMatch(prompt);
119
+ const cutoff = Date.now() - ERROR_RECENCY_MS;
120
+ const matching = result.value.filter((e) => typeof e.prompt === "string" &&
121
+ normalizePromptForMatch(e.prompt) === normalized &&
122
+ e.failedAt > cutoff);
123
+ if (matching.length === 0)
124
+ return null;
125
+ return matching.reduce((latest, current) => current.failedAt > latest.failedAt ? current : latest);
126
+ }
127
+ function requestOptions(request) {
128
+ return request.options ?? {};
129
+ }
130
+ function sceneElements(options) {
131
+ const elements = Array.isArray(options.elements) ? options.elements : [];
132
+ return elements.map((element) => ({ name: String(element.name ?? ""), desc: String(element.description ?? "") }));
133
+ }
134
+ export function extractSceneContext(request) {
135
+ const options = requestOptions(request);
136
+ const multiPrompt = Array.isArray(options.multi_prompt) ? options.multi_prompt : [];
137
+ const scenes = multiPrompt.length > 0
138
+ ? multiPrompt
139
+ : [{ prompt: typeof request.prompt === "string" ? request.prompt : "", duration: Number(options.duration ?? 5) }];
140
+ return { scenes, elements: sceneElements(options) };
141
+ }
142
+ export function validateSceneRewrite(request, sceneIndex) {
143
+ const model = typeof request.model === "string" ? request.model : undefined;
144
+ if (model === undefined || modelEntry(model)?.guide !== "kling30") {
145
+ throw new Error(`Scene rewrite requires a Kling 3.0 asset, got model: ${model}`);
146
+ }
147
+ const nScenes = extractSceneContext(request).scenes.length;
148
+ if (sceneIndex < 0 || sceneIndex >= nScenes) {
149
+ throw new Error(`scene_index ${sceneIndex} out of range (0-${nScenes - 1})`);
150
+ }
151
+ }
152
+ export function buildSceneRewriteText(guide, scenes, elements, sceneIndex, instruction) {
153
+ const lines = [
154
+ "You are a prompt engineering expert specializing in multi-shot video generation. " +
155
+ "Using the model-specific prompting guide below, rewrite the TARGET scene prompt " +
156
+ "to follow best practices.\n",
157
+ "RULES:",
158
+ "- Output ONLY the rewritten scene prompt text, nothing else",
159
+ "- Do not include explanations, labels, scene numbers, or commentary",
160
+ "- HARD LIMIT: The rewritten prompt MUST be under 400 characters (API max is 500)",
161
+ "- Be concise and visually specific — cut filler words, focus on key actions and details",
162
+ "- Preserve @element_name references exactly as they appear",
163
+ "- Maintain narrative continuity with the other scenes",
164
+ "- Preserve the user's creative intent while improving structure and detail",
165
+ "- Apply the guide's recommended prompt structure and techniques",
166
+ "- If images are provided, incorporate visual details you observe into the prompt\n",
167
+ `--- PROMPTING GUIDE ---\n${guide}\n--- END GUIDE ---\n`,
168
+ ];
169
+ lines.push("--- ALL SCENES ---");
170
+ for (let i = 0; i < scenes.length; i++) {
171
+ const marker = i === sceneIndex ? " <<<< TARGET — REWRITE THIS SCENE" : "";
172
+ lines.push(`Scene ${i} (${scenes[i].duration ?? "?"}s): ${scenes[i].prompt}${marker}`);
173
+ }
174
+ lines.push("--- END SCENES ---\n");
175
+ if (elements.length > 0) {
176
+ lines.push("--- ELEMENTS ---");
177
+ for (const elem of elements) {
178
+ lines.push(`@${elem.name}: ${elem.desc}`);
179
+ }
180
+ lines.push("--- END ELEMENTS ---\n");
181
+ }
182
+ if (instruction) {
183
+ lines.push(`ADDITIONAL INSTRUCTION: ${instruction}\n`);
184
+ }
185
+ return lines.join("\n");
186
+ }
187
+ function buildSceneResult(sceneIndex, originalScenePrompt, rewritten, guideFile, scenes) {
188
+ const updatedMultiPrompt = scenes.map((scene, i) => i === sceneIndex ? { ...scene, prompt: rewritten } : { ...scene });
189
+ return {
190
+ model: "kling30",
191
+ scene_index: sceneIndex,
192
+ original_scene_prompt: originalScenePrompt,
193
+ rewritten_prompt: rewritten,
194
+ guide_used: guideFile,
195
+ updated_multi_prompt: updatedMultiPrompt,
196
+ };
197
+ }
198
+ async function resolveImageDataUris(imageRefs, engine) {
199
+ const { resolved } = await resolveArtifactRefs(engine, imageRefs);
200
+ const dataUris = [];
201
+ for (const asset of resolved) {
202
+ if (!asset.filePath)
203
+ continue;
204
+ const readResult = await engine.files.read(asset.artifactId, asset.filePath.split("/").pop());
205
+ if (!readResult.ok)
206
+ continue;
207
+ const buf = Buffer.from(readResult.value);
208
+ const ext = asset.filePath.split(".").pop()?.toLowerCase() ?? "png";
209
+ const mime = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : ext === "webp" ? "image/webp" : "image/png";
210
+ dataUris.push(`data:${mime};base64,${buf.toString("base64")}`);
211
+ }
212
+ return dataUris;
213
+ }
214
+ // --- Tool definition ---
215
+ export function rewritePromptDef(engine) {
216
+ return {
217
+ name: "rewrite_prompt",
218
+ description: "Rewrite a generation prompt using model-specific best practices. " +
219
+ "Supports standard mode (rewrite any prompt) and scene mode (rewrite a " +
220
+ "specific scene in a Kling 3.0 multi-shot asset).",
221
+ schema: {
222
+ prompt: z.string().optional().describe("Prompt to rewrite. In scene mode, serves as optional creative direction."),
223
+ model: z
224
+ .enum(["nano_banana", "gpt_image", "kling30", "grok_imagine", "grok_image", "seedance2", "seedance25"])
225
+ .default("kling30")
226
+ .describe("Target model for prompt optimization"),
227
+ image_refs: z
228
+ .array(z.string())
229
+ .optional()
230
+ .describe("Optional image artifact ids for visual context"),
231
+ book_id: z.string().describe("Book id"),
232
+ asset_ref: z.string().optional().describe("Artifact id for scene-context rewrite (requires scene_index)"),
233
+ scene_index: z.number().int().optional().describe("0-based scene index to rewrite (requires asset_ref)"),
234
+ platform: z
235
+ .enum(["ig", "tiktok", "youtube"])
236
+ .optional()
237
+ .describe("Optional platform aesthetic preset (Instagram/TikTok/YouTube)"),
238
+ custom_prompt: z
239
+ .string()
240
+ .max(500)
241
+ .optional()
242
+ .describe("Optional free-form additional instruction (max 500 chars)"),
243
+ previous_error: z
244
+ .string()
245
+ .max(2000)
246
+ .min(1)
247
+ .optional()
248
+ .describe("Explicit error message to adapt the rewritten prompt around. When omitted, " +
249
+ "the tool auto-looks up the latest matching generation error by prompt text."),
250
+ },
251
+ handler: async (args) => {
252
+ const { prompt, model, image_refs, asset_ref, scene_index, platform, custom_prompt, previous_error, } = args;
253
+ const apiKey = process.env.OPENAI_API_KEY;
254
+ if (!apiKey) {
255
+ return {
256
+ isError: true,
257
+ content: [{ type: "text", text: "OPENAI_API_KEY environment variable is not set" }],
258
+ };
259
+ }
260
+ // Scene rewrite mode
261
+ if (asset_ref !== undefined && scene_index !== undefined) {
262
+ return handleSceneRewrite(engine, apiKey, asset_ref, scene_index, prompt);
263
+ }
264
+ // Standard rewrite mode — require prompt OR reference images
265
+ const hasImages = !!image_refs && image_refs.length > 0;
266
+ if (!prompt && !hasImages) {
267
+ return {
268
+ isError: true,
269
+ content: [{
270
+ type: "text",
271
+ text: "Provide a prompt, or reference image_refs (for vision-based description), or both.",
272
+ }],
273
+ };
274
+ }
275
+ // Auto-lookup previous error BEFORE @s01 slot expansion (stored failed
276
+ // prompts are pre-expansion). Skipped when previous_error was passed
277
+ // explicitly.
278
+ let previousError;
279
+ if (previous_error) {
280
+ previousError = { message: previous_error };
281
+ }
282
+ else if (prompt) {
283
+ const found = await findPreviousErrorForPrompt(engine, prompt);
284
+ if (found) {
285
+ previousError = {
286
+ message: found.message,
287
+ ...(found.failCode ? { failCode: found.failCode } : {}),
288
+ };
289
+ }
290
+ }
291
+ // Expand @s01 slot refs → @<artifact-id> tokens
292
+ let expandedPrompt = prompt ?? "";
293
+ if (expandedPrompt) {
294
+ expandedPrompt = expandTimelineSlotRefs(expandedPrompt, timelineSlotArtifactIds(engine));
295
+ }
296
+ return handleStandardRewrite(engine, apiKey, expandedPrompt, model, image_refs, platform, custom_prompt, previousError);
297
+ },
298
+ };
299
+ }
300
+ async function handleStandardRewrite(engine, apiKey, prompt, model, imageRefs, platform, customPrompt, previousError) {
301
+ let guide;
302
+ let guideFile;
303
+ try {
304
+ guide = await loadGuide(model);
305
+ guideFile = guideFilename(model);
306
+ }
307
+ catch (e) {
308
+ return {
309
+ isError: true,
310
+ content: [{ type: "text", text: e.message }],
311
+ };
312
+ }
313
+ const maxChars = model === "kling30" ? 400 : undefined;
314
+ const responses = buildIntelligenceResponses(apiKey, { timeout: 60_000 });
315
+ const extras = { maxChars, platform, customPrompt, previousError };
316
+ let messages;
317
+ if (imageRefs && imageRefs.length > 0) {
318
+ const dataUris = await resolveImageDataUris(imageRefs, engine);
319
+ if (dataUris.length === 0) {
320
+ return {
321
+ isError: true,
322
+ content: [{ type: "text", text: "Could not resolve any image files from provided refs" }],
323
+ };
324
+ }
325
+ messages = buildVisionMessages(guide, prompt, dataUris, extras);
326
+ }
327
+ else {
328
+ messages = buildRewriteMessages(guide, prompt, extras);
329
+ }
330
+ const result = await responses(intelligenceRequest({
331
+ input: responseInputFromMessages(messages),
332
+ text: { format: { type: "text" } },
333
+ max_output_tokens: 1024,
334
+ }));
335
+ const rewritten = firstResponseText(result);
336
+ const output = buildResult(model, prompt, rewritten, guideFile, previousError);
337
+ return {
338
+ content: [{ type: "text", text: JSON.stringify(output) }],
339
+ };
340
+ }
341
+ async function handleSceneRewrite(engine, apiKey, assetRef, sceneIndex, instruction) {
342
+ const assetId = assetRef.replace(/^@/, "");
343
+ const metaResult = await engine.metadata.artifacts.read(assetId, "generation-request");
344
+ if (!metaResult.ok || metaResult.value === null) {
345
+ return {
346
+ isError: true,
347
+ content: [{ type: "text", text: `No generation-request found for ${assetRef}; scene rewrite needs a video made with generate_video` }],
348
+ };
349
+ }
350
+ const request = metaResult.value;
351
+ try {
352
+ validateSceneRewrite(request, sceneIndex);
353
+ }
354
+ catch (e) {
355
+ return {
356
+ isError: true,
357
+ content: [{ type: "text", text: e.message }],
358
+ };
359
+ }
360
+ const { scenes, elements } = extractSceneContext(request);
361
+ const guide = await loadGuide("kling30");
362
+ const text = buildSceneRewriteText(guide, scenes, elements, sceneIndex, instruction);
363
+ const responses = buildIntelligenceResponses(apiKey, { timeout: 60_000 });
364
+ const result = await responses(intelligenceRequest({
365
+ input: [{ role: "user", content: text }],
366
+ text: { format: { type: "text" } },
367
+ max_output_tokens: 1024,
368
+ }));
369
+ const rewritten = firstResponseText(result);
370
+ const output = buildSceneResult(sceneIndex, scenes[sceneIndex].prompt, rewritten, guideFilename("kling30"), scenes);
371
+ return {
372
+ content: [{ type: "text", text: JSON.stringify(output) }],
373
+ };
374
+ }
375
+ function responseInputFromMessages(messages) {
376
+ return messages.map((message) => ({
377
+ role: message.role,
378
+ content: typeof message.content === "string"
379
+ ? message.content
380
+ : message.content.map((part) => part.type === "text"
381
+ ? { type: "input_text", text: part.text }
382
+ : {
383
+ type: "input_image",
384
+ image_url: part.image_url.url,
385
+ detail: part.image_url.detail ?? "auto",
386
+ }),
387
+ }));
388
+ }
@@ -0,0 +1,67 @@
1
+ import { z } from "zod";
2
+ import { queue } from "../queue.js";
3
+ import { requireArtifactKind } from "./_shared.js";
4
+ const CUSTOM_PROMPT_MAX = 500;
5
+ function error(text) {
6
+ return { isError: true, content: [{ type: "text", text }] };
7
+ }
8
+ export function rewriteScriptDef(engine) {
9
+ return {
10
+ name: "rewrite_script",
11
+ description: "Rewrite a script asset's markdown in place without re-reading the source image: variant full (reproduction prompt and breakdown) or tldr (one or two sentences), with an optional platform preset and custom_prompt instruction. Asynchronous; earlier versions stay in history.",
12
+ schema: {
13
+ asset_id: z.string().describe("Script artifact id"),
14
+ variant: z.enum(["full", "tldr"]).describe("Rewrite style"),
15
+ platform: z.enum(["ig", "tiktok", "youtube"]).optional()
16
+ .describe("Platform preset — tunes authentic-capture cues for the target feed"),
17
+ custom_prompt: z.string().max(CUSTOM_PROMPT_MAX).optional()
18
+ .describe("Optional transformation instruction, e.g. 'replace the pig with a man in a blue suit'"),
19
+ book_id: z.string().describe("Book id"),
20
+ },
21
+ handler: async (args) => {
22
+ const { asset_id, variant, platform, custom_prompt, book_id } = args;
23
+ const kindGate = await requireArtifactKind(engine, asset_id, ["script"], "rewrite_script");
24
+ if (kindGate)
25
+ return kindGate;
26
+ const originalResult = await engine.metadata.artifacts.read(asset_id, "original");
27
+ if (!originalResult.ok) {
28
+ return error(`Script ${asset_id} has no native original metadata — cannot determine origin`);
29
+ }
30
+ const { origin, sourceAssetId } = originalResult.value;
31
+ if (origin !== "describe_image" || !sourceAssetId) {
32
+ return error(`rewrite_script currently supports scripts created by describe_image. Got origin=${origin ?? "unknown"}`);
33
+ }
34
+ if (!process.env.OPENAI_API_KEY) {
35
+ return error("OPENAI_API_KEY is not set");
36
+ }
37
+ const scriptManifest = await engine.files.manifest(asset_id);
38
+ if (!scriptManifest.ok) {
39
+ return error(scriptManifest.error.message);
40
+ }
41
+ const jobId = `rewrite-script-${variant}-${asset_id}-${Date.now()}`;
42
+ await queue.enqueue(jobId, {
43
+ type: "rewrite_script",
44
+ assetId: asset_id,
45
+ sourceAssetId,
46
+ bookId: book_id,
47
+ tldr: variant === "tldr",
48
+ platform: platform ?? null,
49
+ customPrompt: custom_prompt ?? null,
50
+ });
51
+ return {
52
+ content: [{
53
+ type: "text",
54
+ text: JSON.stringify({
55
+ source_asset_id: sourceAssetId,
56
+ script_asset_id: asset_id,
57
+ job_id: jobId,
58
+ status: "enqueued",
59
+ variant,
60
+ ...(platform ? { platform } : {}),
61
+ ...(custom_prompt ? { custom_prompt } : {}),
62
+ }),
63
+ }],
64
+ };
65
+ },
66
+ };
67
+ }
@@ -0,0 +1,66 @@
1
+ import { z } from "zod";
2
+ import { readSlotConstraints, zodEnumOptionsOrNull, zodFiniteNumberOptions, zodIsBoolean, zodNumberRange, zodStringMaxLength, zodStringMinLength, zodUnionEnumOptions, } from "../zod-slots.js";
3
+ function buildCore(schema) {
4
+ const enumOpts = zodEnumOptionsOrNull(schema);
5
+ if (enumOpts)
6
+ return z.enum(enumOpts);
7
+ if (zodIsBoolean(schema))
8
+ return z.boolean();
9
+ const finiteNumbers = zodFiniteNumberOptions(schema);
10
+ if (finiteNumbers) {
11
+ const literals = z.literal(finiteNumbers);
12
+ return z.preprocess((value) => typeof value === "string" && value.trim() !== "" ? Number(value) : value, literals);
13
+ }
14
+ const range = zodNumberRange(schema);
15
+ if (range) {
16
+ let n = z.coerce.number();
17
+ if (range.int)
18
+ n = n.int();
19
+ if (range.min !== undefined)
20
+ n = range.exclusiveMin ? n.gt(range.min) : n.min(range.min);
21
+ if (range.max !== undefined)
22
+ n = range.exclusiveMax ? n.lt(range.max) : n.max(range.max);
23
+ return n;
24
+ }
25
+ let s = z.string();
26
+ const min = zodStringMinLength(schema);
27
+ if (min !== undefined)
28
+ s = s.min(min);
29
+ const max = zodStringMaxLength(schema);
30
+ if (max !== undefined)
31
+ s = s.max(max);
32
+ return s;
33
+ }
34
+ export function apicityField(schema, describe, opts) {
35
+ const core = buildCore(schema);
36
+ const described = describe ? core.describe(describe) : core;
37
+ return opts?.required ? described : described.optional();
38
+ }
39
+ export function apicityStringNumberField(schema, describe, opts) {
40
+ const values = zodFiniteNumberOptions(schema);
41
+ if (!values)
42
+ throw new Error("apicityStringNumberField: schema is not a finite numeric domain");
43
+ const core = z.enum(values.map(String));
44
+ const described = describe ? core.describe(describe) : core;
45
+ return opts?.required ? described : described.optional();
46
+ }
47
+ export function apicityStringArrayField(schema, describe, opts) {
48
+ const slots = readSlotConstraints(schema, { whenPresent: true });
49
+ if (!slots)
50
+ throw new Error("apicityStringArrayField: schema is not an array");
51
+ let core = z.array(z.string());
52
+ if (slots.min > 0)
53
+ core = core.min(slots.min);
54
+ if (slots.max !== null)
55
+ core = core.max(slots.max);
56
+ const described = describe ? core.describe(describe) : core;
57
+ return opts?.required ? described : described.optional();
58
+ }
59
+ export function apicityUnionEnumField(schema, describe, opts) {
60
+ const options = zodUnionEnumOptions(schema);
61
+ if (!options)
62
+ throw new Error("apicityUnionEnumField: schema has no enum union branch");
63
+ const core = z.enum(options);
64
+ const described = describe ? core.describe(describe) : core;
65
+ return opts?.required ? described : described.optional();
66
+ }
@@ -0,0 +1,150 @@
1
+ import { z } from "zod";
2
+ import { archiveKey, archiveTags, indexKey, } from "../archive-b2.js";
3
+ import { getArchiveStore } from "../archive-store.js";
4
+ function markerShaFromKey(key) {
5
+ const match = /\/([a-f0-9]{64})-[^/]+\.json$/i.exec(key);
6
+ return match?.[1]?.toLowerCase() ?? null;
7
+ }
8
+ function includesQuery(index, transcript, query) {
9
+ const q = query?.trim().toLowerCase();
10
+ if (!q)
11
+ return true;
12
+ const haystack = [
13
+ index.title ?? "",
14
+ ...index.topics.map((topic) => topic.label),
15
+ ...index.people.map((person) => person.label),
16
+ transcript ?? "",
17
+ ].join("\n").toLowerCase();
18
+ return haystack.includes(q);
19
+ }
20
+ function excerptFor(transcript, query) {
21
+ if (!transcript)
22
+ return null;
23
+ const clean = transcript.replace(/\s+/g, " ").trim();
24
+ if (!clean)
25
+ return null;
26
+ const q = query?.trim().toLowerCase();
27
+ if (!q)
28
+ return clean.slice(0, 280);
29
+ const idx = clean.toLowerCase().indexOf(q);
30
+ if (idx < 0)
31
+ return clean.slice(0, 280);
32
+ const start = Math.max(0, idx - 100);
33
+ return clean.slice(start, start + 320);
34
+ }
35
+ async function loadMarkerSeeds(args) {
36
+ const seeds = [];
37
+ for (const key of args.keys) {
38
+ const objects = await args.store.list(archiveKey(args.store, `${args.kind}/${key}/`));
39
+ for (const object of objects) {
40
+ const marker = await args.store.getJson(object.key);
41
+ const sha256 = marker?.sha256 ?? markerShaFromKey(object.key);
42
+ if (!sha256)
43
+ continue;
44
+ seeds.push({
45
+ sha256,
46
+ indexKey: marker?.index_key ?? indexKey(args.store, sha256),
47
+ });
48
+ }
49
+ }
50
+ return seeds;
51
+ }
52
+ async function loadAllIndexSeeds(args) {
53
+ const objects = await args.store.list(archiveKey(args.store, "clips/"));
54
+ return objects
55
+ .filter((object) => /\/archive\.json$/.test(object.key))
56
+ .map((object) => {
57
+ const match = /(?:^|\/)clips\/([a-f0-9]{64})\/archive\.json$/i.exec(object.key);
58
+ return match?.[1]
59
+ ? { sha256: match[1].toLowerCase(), indexKey: object.key }
60
+ : null;
61
+ })
62
+ .filter((seed) => seed !== null);
63
+ }
64
+ export function searchArchiveDef() {
65
+ return {
66
+ name: "search_archive",
67
+ description: "Search the global clip archive (B2 if configured, otherwise the local archive folder) by topics, named people, or text query.",
68
+ schema: {
69
+ topics: z.array(z.string()).optional().default([]).describe("Topics to match; multiple values use match-any semantics"),
70
+ people: z.array(z.string()).optional().default([]).describe("Named people to match; multiple values use match-any semantics"),
71
+ query: z.string().optional().describe("Optional case-insensitive title/topic/person/transcript substring search"),
72
+ limit: z.number().int().positive().max(100).optional().default(20),
73
+ offset: z.number().int().min(0).optional().default(0),
74
+ sort: z.enum(["newest", "oldest"]).optional().default("newest").describe("Sort archived clips by archive updated time"),
75
+ include_transcript: z.boolean().optional().default(false).describe("Include full transcript text in results"),
76
+ presign_media: z.boolean().optional().default(true).describe("Return a playable media URL (temporary B2 URL or local server path)"),
77
+ },
78
+ handler: async (args) => {
79
+ const { topics, people, query, limit, offset, sort, include_transcript, presign_media, } = args;
80
+ const store = getArchiveStore();
81
+ const topicKeys = archiveTags(topics, "manual").map((topic) => topic.key);
82
+ const personKeys = archiveTags(people, "manual").map((person) => person.key);
83
+ const seeds = topicKeys.length > 0 || personKeys.length > 0
84
+ ? [
85
+ ...await loadMarkerSeeds({ kind: "topics", keys: topicKeys, store }),
86
+ ...await loadMarkerSeeds({ kind: "people", keys: personKeys, store }),
87
+ ]
88
+ : await loadAllIndexSeeds({ store });
89
+ const byHash = new Map();
90
+ for (const seed of seeds) {
91
+ if (!byHash.has(seed.sha256))
92
+ byHash.set(seed.sha256, seed);
93
+ }
94
+ const hits = [];
95
+ for (const seed of byHash.values()) {
96
+ const index = await store.getJson(seed.indexKey);
97
+ if (!index)
98
+ continue;
99
+ const transcript = (query || include_transcript) && index.transcript
100
+ ? await store.getText(index.transcript.text_key)
101
+ : null;
102
+ if (!includesQuery(index, transcript, query))
103
+ continue;
104
+ hits.push({
105
+ sortAt: index.updated_at || index.created_at,
106
+ result: {
107
+ archive_id: index.archive_id,
108
+ sha256: index.sha256,
109
+ title: index.title,
110
+ topics: index.topics,
111
+ people: index.people,
112
+ sources: index.sources,
113
+ duration: index.duration,
114
+ media: {
115
+ key: index.media.key,
116
+ content_type: index.media.content_type,
117
+ size_bytes: index.media.size_bytes,
118
+ url: null,
119
+ expires_at: null,
120
+ },
121
+ transcript_excerpt: excerptFor(transcript, query),
122
+ ...(include_transcript ? { transcript } : {}),
123
+ },
124
+ });
125
+ }
126
+ hits.sort((a, b) => sort === "newest" ? b.sortAt.localeCompare(a.sortAt) : a.sortAt.localeCompare(b.sortAt));
127
+ const paged = hits.slice(offset, offset + limit).map((hit) => hit.result);
128
+ if (presign_media) {
129
+ for (const result of paged) {
130
+ const media = result.media;
131
+ const signed = store.presignGet(media.key, 3600);
132
+ media.url = signed?.url ?? null;
133
+ media.expires_at = signed?.expiresAt ?? null;
134
+ }
135
+ }
136
+ return {
137
+ content: [{
138
+ type: "text",
139
+ text: JSON.stringify({
140
+ results: paged,
141
+ total: hits.length,
142
+ offset,
143
+ limit,
144
+ has_more: offset + paged.length < hits.length,
145
+ }),
146
+ }],
147
+ };
148
+ },
149
+ };
150
+ }