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.
- package/CHANGELOG.md +54 -0
- package/LICENSE +21 -0
- package/README.md +195 -2
- package/bin/videobook.js +7 -0
- package/dist/acestep/client.js +203 -0
- package/dist/acestep/config.js +62 -0
- package/dist/acestep/errors.js +8 -0
- package/dist/acestep/process.js +175 -0
- package/dist/alive-captions/analyze.js +117 -0
- package/dist/alive-captions/audio.js +179 -0
- package/dist/alive-captions/frames.js +59 -0
- package/dist/alive-captions/model.js +37 -0
- package/dist/alive-captions/schema.js +49 -0
- package/dist/alive-captions/track.js +9 -0
- package/dist/api-key.js +33 -0
- package/dist/app-state.js +56 -0
- package/dist/app.js +257 -0
- package/dist/archive-b2.js +332 -0
- package/dist/archive-store.js +169 -0
- package/dist/artifact-label.js +36 -0
- package/dist/artifact-refs.js +49 -0
- package/dist/asset-tag-extraction.js +169 -0
- package/dist/asset-tags.js +228 -0
- package/dist/asset-usage.js +23 -0
- package/dist/audio-cue.js +71 -0
- package/dist/audio-encoding.js +32 -0
- package/dist/audio-sync-request.js +1 -0
- package/dist/audio-sync.js +223 -0
- package/dist/audio-trim-range.js +31 -0
- package/dist/book-context.js +31 -0
- package/dist/book-manager.js +374 -0
- package/dist/catalog-gc.js +26 -0
- package/dist/chain-executor.js +815 -0
- package/dist/chain-generation.js +115 -0
- package/dist/chain-plan.js +746 -0
- package/dist/chain-step-review.js +60 -0
- package/dist/character-name.js +25 -0
- package/dist/chat-generation-routing.js +73 -0
- package/dist/chat-generation-settings.js +78 -0
- package/dist/chat-models.js +44 -0
- package/dist/chat-prompt-rewrite.js +67 -0
- package/dist/chat-router.js +628 -0
- package/dist/chat-view-actions.js +49 -0
- package/dist/cli/args.js +242 -0
- package/dist/cli/config-command.js +103 -0
- package/dist/cli/doctor-command.js +289 -0
- package/dist/cli/entry.js +2 -0
- package/dist/cli/key-report.js +16 -0
- package/dist/cli/main.js +104 -0
- package/dist/cli/mcp-command.js +88 -0
- package/dist/cli/mcp-relay.js +51 -0
- package/dist/cli/open-browser.js +14 -0
- package/dist/cli/run-command.js +231 -0
- package/dist/cli/serve-command.js +62 -0
- package/dist/cli/setup-command.js +60 -0
- package/dist/cli/stdio-guard.js +8 -0
- package/dist/cold-open-model.js +7 -0
- package/dist/cold-open.js +79 -0
- package/dist/command-reference.js +95 -0
- package/dist/content-store.js +74 -0
- package/dist/cost.js +8 -0
- package/dist/crop-geometry.js +23 -0
- package/dist/dancing-workflow.js +447 -0
- package/dist/data-home.js +44 -0
- package/dist/diagnostics.js +109 -0
- package/dist/dialog-quality.js +34 -0
- package/dist/downloads-dest.js +56 -0
- package/dist/editing-moments.js +194 -0
- package/dist/elevenlabs-audio-extension.js +66 -0
- package/dist/engine.js +54 -0
- package/dist/env-file.js +91 -0
- package/dist/env-secrets.js +148 -0
- package/dist/ffmpeg-binary.js +12 -0
- package/dist/ffmpeg.js +425 -0
- package/dist/ffprobe-binary.js +77 -0
- package/dist/forget-asset.js +216 -0
- package/dist/frame-utils.js +27 -0
- package/dist/generation-credit-error.js +11 -0
- package/dist/generation-input-mentions.js +117 -0
- package/dist/generation-input-policy.js +68 -0
- package/dist/generation-reference-mentions.js +97 -0
- package/dist/goal-characters.js +49 -0
- package/dist/goal-plan-v3.js +273 -0
- package/dist/goal-plan.js +220 -0
- package/dist/goal-planner-prompt.js +28 -0
- package/dist/goal-prompt-budget.js +4 -0
- package/dist/goal-reference-images.js +25 -0
- package/dist/goal-state.js +261 -0
- package/dist/goal-stills.js +153 -0
- package/dist/goal-store.js +144 -0
- package/dist/goal-styles.js +144 -0
- package/dist/goal-v3-runtime.js +157 -0
- package/dist/guides/character_schema_guide.md +70 -0
- package/dist/guides/gpt_image_2_5_prompting_guide.md +21 -0
- package/dist/guides/grok_imagine_prompting_guide.md +72 -0
- package/dist/guides/image_reproduction_guide.md +84 -0
- package/dist/guides/kling_3_0_prompting_guide.md +136 -0
- package/dist/guides/nano_banana_pro_prompting_guide.md +28 -0
- package/dist/guides/seedance_2_prompting_guide.md +172 -0
- package/dist/http-access.js +49 -0
- package/dist/http-byte-range.js +31 -0
- package/dist/hydration.js +56 -0
- package/dist/image-compress.js +77 -0
- package/dist/image-edit-default.js +1 -0
- package/dist/image-edit-models.js +41 -0
- package/dist/image-edit-settings.js +11 -0
- package/dist/image-region-edit.js +32 -0
- package/dist/image-subject-map.js +523 -0
- package/dist/image.js +46 -0
- package/dist/index.js +12 -0
- package/dist/job-deadline.js +60 -0
- package/dist/jobs/_alibaba-upload.js +30 -0
- package/dist/jobs/_audio-chunks.js +31 -0
- package/dist/jobs/_download-into-asset.js +15 -0
- package/dist/jobs/_fal-shared.js +22 -0
- package/dist/jobs/_fal-upload.js +35 -0
- package/dist/jobs/_image-edit-adapter.js +213 -0
- package/dist/jobs/_kie-poll.js +119 -0
- package/dist/jobs/_kie-upload.js +32 -0
- package/dist/jobs/_lease.js +163 -0
- package/dist/jobs/_persist-output.js +19 -0
- package/dist/jobs/_storage-retry.js +21 -0
- package/dist/jobs/_transcribe.js +245 -0
- package/dist/jobs/_translate-transcript.js +270 -0
- package/dist/jobs/analyze-alive-captions.js +10 -0
- package/dist/jobs/analyze-editing-moments.js +104 -0
- package/dist/jobs/analyze-jokes.js +143 -0
- package/dist/jobs/analyze-keyword-placement.js +155 -0
- package/dist/jobs/analyze-music.js +14 -0
- package/dist/jobs/analyze-video.js +282 -0
- package/dist/jobs/apply-cuts.js +83 -0
- package/dist/jobs/apply-sfx.js +107 -0
- package/dist/jobs/archive-clip.js +458 -0
- package/dist/jobs/assemble-goal.js +98 -0
- package/dist/jobs/audio-boost.js +71 -0
- package/dist/jobs/audio-mix.js +161 -0
- package/dist/jobs/backfill-asset-tags.js +144 -0
- package/dist/jobs/burn-watermark.js +316 -0
- package/dist/jobs/change-video-speed.js +176 -0
- package/dist/jobs/clean-video-audio.js +207 -0
- package/dist/jobs/cold-open.js +166 -0
- package/dist/jobs/combine-goal.js +108 -0
- package/dist/jobs/complete-provider-task.js +185 -0
- package/dist/jobs/copy-library-asset.js +33 -0
- package/dist/jobs/cost-estimate-assessment.js +113 -0
- package/dist/jobs/crop-image.js +47 -0
- package/dist/jobs/crop-video.js +71 -0
- package/dist/jobs/describe-image.js +181 -0
- package/dist/jobs/detect-scenes.js +33 -0
- package/dist/jobs/doctor-fix.js +100 -0
- package/dist/jobs/download-video.js +427 -0
- package/dist/jobs/enqueue-search-index.js +24 -0
- package/dist/jobs/even-split.js +122 -0
- package/dist/jobs/export-sequence.js +365 -0
- package/dist/jobs/extend-audio.js +229 -0
- package/dist/jobs/extract-audio.js +72 -0
- package/dist/jobs/extract-frame.js +58 -0
- package/dist/jobs/extract-notebook-audio.js +82 -0
- package/dist/jobs/extract-notebook-frame.js +93 -0
- package/dist/jobs/extract-video-clip.js +8 -0
- package/dist/jobs/extract-video-poster.js +55 -0
- package/dist/jobs/extract-waveform.js +25 -0
- package/dist/jobs/finish-goal.js +255 -0
- package/dist/jobs/forget-asset.js +11 -0
- package/dist/jobs/generate-acestep-cover.js +219 -0
- package/dist/jobs/generate-media.js +70 -0
- package/dist/jobs/image-subjects.js +1059 -0
- package/dist/jobs/index.js +18 -0
- package/dist/jobs/inject-first-frame.js +175 -0
- package/dist/jobs/isolate-vocals.js +69 -0
- package/dist/jobs/kie-paygate.js +177 -0
- package/dist/jobs/label-music-sections.js +5 -0
- package/dist/jobs/osg-placement.js +135 -0
- package/dist/jobs/pad-video.js +72 -0
- package/dist/jobs/plan-goal.js +97 -0
- package/dist/jobs/post-record.js +21 -0
- package/dist/jobs/post-to-x.js +21 -0
- package/dist/jobs/prepare-search-reference.js +190 -0
- package/dist/jobs/prepare-temporal-search.js +16 -0
- package/dist/jobs/process-audio.js +67 -0
- package/dist/jobs/process-image.js +58 -0
- package/dist/jobs/process-upload.js +166 -0
- package/dist/jobs/process-video.js +438 -0
- package/dist/jobs/register-all.js +161 -0
- package/dist/jobs/relayout-notebook.js +78 -0
- package/dist/jobs/remove-sound.js +299 -0
- package/dist/jobs/render-project.js +380 -0
- package/dist/jobs/render-qr-outro.js +138 -0
- package/dist/jobs/render-timeline.js +283 -0
- package/dist/jobs/repair-search-indexes.js +42 -0
- package/dist/jobs/replace-video-audio.js +64 -0
- package/dist/jobs/restore-archive-clip.js +53 -0
- package/dist/jobs/reverse-video.js +53 -0
- package/dist/jobs/rewrite-script.js +173 -0
- package/dist/jobs/run-notebook.js +3335 -0
- package/dist/jobs/semantic-index.js +797 -0
- package/dist/jobs/smooth-scene-concat.js +257 -0
- package/dist/jobs/splice-video.js +280 -0
- package/dist/jobs/split-video.js +127 -0
- package/dist/jobs/suggest-cuts.js +149 -0
- package/dist/jobs/suggest-sfx.js +135 -0
- package/dist/jobs/sync-video-to-audio.js +329 -0
- package/dist/jobs/tag-asset.js +266 -0
- package/dist/jobs/task-failure.js +16 -0
- package/dist/jobs/timewarp-video.js +152 -0
- package/dist/jobs/transcribe-video-audio.js +117 -0
- package/dist/jobs/transcribe.js +35 -0
- package/dist/jobs/translate-transcript.js +55 -0
- package/dist/jobs/trim-audio.js +133 -0
- package/dist/jobs/trim-video.js +291 -0
- package/dist/jobs/xai-paygate.js +26 -0
- package/dist/keyword-placement-cache.js +74 -0
- package/dist/lazy-render.js +142 -0
- package/dist/library-browse.js +78 -0
- package/dist/lightning-defaults.js +206 -0
- package/dist/load-env.js +12 -0
- package/dist/local-search-models.js +206 -0
- package/dist/local-upload.js +318 -0
- package/dist/logger.js +69 -0
- package/dist/media/adapters/alibaba.js +20 -0
- package/dist/media/adapters/elevenlabs.js +58 -0
- package/dist/media/adapters/fal.js +45 -0
- package/dist/media/adapters/index.js +26 -0
- package/dist/media/adapters/kie.js +120 -0
- package/dist/media/adapters/pending.js +21 -0
- package/dist/media/adapters/types.js +5 -0
- package/dist/media/adapters/xai.js +18 -0
- package/dist/media/catalog.js +236 -0
- package/dist/media/complete.js +191 -0
- package/dist/media/cost.js +45 -0
- package/dist/media/descriptor.js +157 -0
- package/dist/media/endpoints.js +11 -0
- package/dist/media/frame-options.js +18 -0
- package/dist/media/insert-video-timing.js +17 -0
- package/dist/media/json-schema.js +75 -0
- package/dist/media/legacy-task-types.js +129 -0
- package/dist/media/listing.js +24 -0
- package/dist/media/model-id.js +14 -0
- package/dist/media/preview.js +86 -0
- package/dist/media/prompt-dialects.js +65 -0
- package/dist/media/ref-fields.js +106 -0
- package/dist/media/refs.js +131 -0
- package/dist/media/request.js +188 -0
- package/dist/media/types.js +6 -0
- package/dist/media/wire.js +161 -0
- package/dist/media-library.js +535 -0
- package/dist/media-output-path.js +33 -0
- package/dist/multyculty-workflow.js +757 -0
- package/dist/notebook-action-catalog.js +608 -0
- package/dist/notebook-cell-outputs.js +726 -0
- package/dist/notebook-credit-retry.js +45 -0
- package/dist/notebook-fixtures.js +8 -0
- package/dist/notebook-generation-contract.js +77 -0
- package/dist/notebook-generation-controls.js +145 -0
- package/dist/notebook-goal-layout.js +40 -0
- package/dist/notebook-graph.js +37 -0
- package/dist/notebook-image-edit.js +84 -0
- package/dist/notebook-initial-generation-prompt.js +222 -0
- package/dist/notebook-live-analysis.js +941 -0
- package/dist/notebook-media-ops.js +579 -0
- package/dist/notebook-mutations.js +20 -0
- package/dist/notebook-placement.js +41 -0
- package/dist/notebook-provider-failure.js +87 -0
- package/dist/notebook-published-post.js +26 -0
- package/dist/notebook-reference-resolver.js +227 -0
- package/dist/notebook-relayout.js +270 -0
- package/dist/notebook-run-plan.js +519 -0
- package/dist/notebook-shots.js +162 -0
- package/dist/notebook-workflow.js +856 -0
- package/dist/one-password.js +200 -0
- package/dist/openai-intelligence.js +99 -0
- package/dist/original-media-file.js +12 -0
- package/dist/osg-assets.js +36 -0
- package/dist/osg-placement-cache.js +64 -0
- package/dist/osg-settings.js +27 -0
- package/dist/paid-tools.js +22 -0
- package/dist/platform-guidance.js +26 -0
- package/dist/posts/dropbox-auth.js +91 -0
- package/dist/posts/dropbox-upload.js +132 -0
- package/dist/posts/icloud-drive.js +134 -0
- package/dist/posts/icloud-status.js +64 -0
- package/dist/posts/post-contract.js +2 -0
- package/dist/posts/post-copy-format.js +43 -0
- package/dist/posts/post-copy.js +193 -0
- package/dist/posts/post-folder.js +18 -0
- package/dist/posts/post-metrics.js +119 -0
- package/dist/posts/post-store.js +340 -0
- package/dist/posts/x-post-target.js +43 -0
- package/dist/preview-payload.js +90 -0
- package/dist/prompt-surfaces.js +22 -0
- package/dist/provider-prompt-transform.js +77 -0
- package/dist/provider-status-link.js +21 -0
- package/dist/provider-task-record.js +78 -0
- package/dist/provider-task-status.js +47 -0
- package/dist/provider-usage.js +294 -0
- package/dist/queue.js +810 -0
- package/dist/reference-video-duration.js +17 -0
- package/dist/remotion/BlurFillVideo.js +51 -0
- package/dist/remotion/KeywordGraphicsOverlay.js +68 -0
- package/dist/remotion/OsgOverlay.js +30 -0
- package/dist/remotion/QrOutroComposition.js +47 -0
- package/dist/remotion/RenderComposition.js +11 -0
- package/dist/remotion/browser.js +59 -0
- package/dist/remotion/constants.js +35 -0
- package/dist/remotion/index.js +66 -0
- package/dist/remotion/keyword-graphics.js +151 -0
- package/dist/remotion/keyword-placement.js +182 -0
- package/dist/remotion/osg-spec.js +198 -0
- package/dist/remotion/public/qr-outro-impact.wav +0 -0
- package/dist/remotion/qr-outro-audio.js +1 -0
- package/dist/remotion/qr-outro-spec.js +211 -0
- package/dist/remotion/shared-bundle.js +37 -0
- package/dist/remotion/subtitles/AliveCaptions.js +83 -0
- package/dist/remotion/subtitles/Highlight.js +58 -0
- package/dist/remotion/subtitles/Impact.js +67 -0
- package/dist/remotion/subtitles/SubtitleOverlay.js +9 -0
- package/dist/remotion/subtitles/alive-layout.js +321 -0
- package/dist/remotion/subtitles/alive-types.js +17 -0
- package/dist/remotion/subtitles/chunker.js +68 -0
- package/dist/remotion/subtitles/segments.js +42 -0
- package/dist/remotion/subtitles/styles.js +4 -0
- package/dist/remotion/subtitles/types.js +1 -0
- package/dist/remotion/util.js +18 -0
- package/dist/remotion-cancellation.js +15 -0
- package/dist/rename-helpers.js +204 -0
- package/dist/rhythm/analyze.js +128 -0
- package/dist/rhythm/contract.js +14 -0
- package/dist/rhythm/draft-model.js +19 -0
- package/dist/rhythm/energy.js +133 -0
- package/dist/rhythm/fft.js +44 -0
- package/dist/rhythm/model.js +71 -0
- package/dist/rhythm/music-analysis.js +124 -0
- package/dist/rhythm/music-draft.js +261 -0
- package/dist/rhythm/onset.js +101 -0
- package/dist/rhythm/run-worker.js +51 -0
- package/dist/rhythm/score.js +47 -0
- package/dist/rhythm/section-labels.js +168 -0
- package/dist/rhythm/sequence-rhythm.js +67 -0
- package/dist/rhythm/synthesize.js +103 -0
- package/dist/rhythm/timing.js +98 -0
- package/dist/rhythm/track.js +320 -0
- package/dist/rhythm/visual-fit.js +4 -0
- package/dist/rhythm/worker.js +25 -0
- package/dist/scene-detect.js +200 -0
- package/dist/scene-transition.js +12 -0
- package/dist/scheduled-posts.js +200 -0
- package/dist/search-index-coverage.js +13 -0
- package/dist/search-index-media.js +71 -0
- package/dist/search-reference-store.js +60 -0
- package/dist/search-scoring.js +17 -0
- package/dist/serve.js +125 -0
- package/dist/server-lock.js +143 -0
- package/dist/server.js +42 -0
- package/dist/srt.js +16 -0
- package/dist/tag-backfill-state.js +121 -0
- package/dist/tag-settings.js +30 -0
- package/dist/tag-vocabulary.js +237 -0
- package/dist/test-queue-cleanup.js +1 -0
- package/dist/time-parse.js +50 -0
- package/dist/timeline-helpers.js +554 -0
- package/dist/timewarp.js +87 -0
- package/dist/tools/_image-inputs.js +9 -0
- package/dist/tools/_media-refs.js +84 -0
- package/dist/tools/_shared.js +59 -0
- package/dist/tools/_suggest-shared.js +279 -0
- package/dist/tools/add-timeline-audio.js +73 -0
- package/dist/tools/alive-captions.js +157 -0
- package/dist/tools/analyze-jokes.js +56 -0
- package/dist/tools/analyze-video.js +66 -0
- package/dist/tools/animate-keywords.js +217 -0
- package/dist/tools/api-status.js +42 -0
- package/dist/tools/application-commands.js +34 -0
- package/dist/tools/apply-cuts.js +112 -0
- package/dist/tools/apply-sfx.js +152 -0
- package/dist/tools/apply-watermark.js +670 -0
- package/dist/tools/archive-clip.js +74 -0
- package/dist/tools/asset-history.js +61 -0
- package/dist/tools/asset-manifest.js +24 -0
- package/dist/tools/asset-tags.js +151 -0
- package/dist/tools/assign-slot.js +97 -0
- package/dist/tools/audio-boost.js +107 -0
- package/dist/tools/audio-mix.js +121 -0
- package/dist/tools/book-usage.js +16 -0
- package/dist/tools/chain.js +136 -0
- package/dist/tools/change-video-speed.js +105 -0
- package/dist/tools/chat-history.js +5 -0
- package/dist/tools/chat.js +848 -0
- package/dist/tools/clean-video-audio.js +97 -0
- package/dist/tools/clear-failed-tasks.js +66 -0
- package/dist/tools/cold-open.js +114 -0
- package/dist/tools/command-plan.js +1680 -0
- package/dist/tools/commands.js +1666 -0
- package/dist/tools/concat-images.js +236 -0
- package/dist/tools/connect-service.js +55 -0
- package/dist/tools/copy-file-to-clipboard.js +58 -0
- package/dist/tools/create-character.js +114 -0
- package/dist/tools/create-qart.js +253 -0
- package/dist/tools/create-qr-outro.js +149 -0
- package/dist/tools/create-qrbtf.js +215 -0
- package/dist/tools/create-watermark.js +97 -0
- package/dist/tools/crop-asset.js +18 -0
- package/dist/tools/crop-image.js +120 -0
- package/dist/tools/crop-video.js +97 -0
- package/dist/tools/delete-asset.js +104 -0
- package/dist/tools/describe-image.js +69 -0
- package/dist/tools/detect-scenes.js +44 -0
- package/dist/tools/doctor.js +126 -0
- package/dist/tools/download-video.js +114 -0
- package/dist/tools/duplicate-asset.js +184 -0
- package/dist/tools/edit-timeline.js +59 -0
- package/dist/tools/editing-moments.js +105 -0
- package/dist/tools/estimate-cost.js +171 -0
- package/dist/tools/even-split.js +295 -0
- package/dist/tools/export-asset-file.js +22 -0
- package/dist/tools/export-asset.js +140 -0
- package/dist/tools/export-sequence.js +250 -0
- package/dist/tools/export-to-downloads.js +54 -0
- package/dist/tools/export-transcript-srt.js +79 -0
- package/dist/tools/extend-audio.js +100 -0
- package/dist/tools/extract-audio.js +174 -0
- package/dist/tools/extract-frame.js +108 -0
- package/dist/tools/extract-notebook-audio.js +173 -0
- package/dist/tools/extract-notebook-frame.js +160 -0
- package/dist/tools/extract-video-clip.js +101 -0
- package/dist/tools/generate-media.js +157 -0
- package/dist/tools/generation-payload.js +48 -0
- package/dist/tools/get-timeline.js +12 -0
- package/dist/tools/get-watermark-config.js +38 -0
- package/dist/tools/goal.js +644 -0
- package/dist/tools/image-subjects.js +711 -0
- package/dist/tools/index.js +323 -0
- package/dist/tools/inject-first-frame.js +154 -0
- package/dist/tools/invert-image.js +70 -0
- package/dist/tools/isolate-vocals.js +66 -0
- package/dist/tools/list-assets.js +98 -0
- package/dist/tools/list-cell-generations.js +225 -0
- package/dist/tools/list-elevenlabs-voices.js +163 -0
- package/dist/tools/log-wrapper.js +29 -0
- package/dist/tools/make-cover-song.js +95 -0
- package/dist/tools/mark-asset-seen.js +23 -0
- package/dist/tools/media-library.js +245 -0
- package/dist/tools/move-timeline-audio.js +35 -0
- package/dist/tools/music-analysis.js +60 -0
- package/dist/tools/music-draft.js +29 -0
- package/dist/tools/pad-video.js +87 -0
- package/dist/tools/post-record.js +83 -0
- package/dist/tools/post.js +168 -0
- package/dist/tools/prompt-history.js +164 -0
- package/dist/tools/provider-key-status.js +248 -0
- package/dist/tools/qrbtf-render.js +849 -0
- package/dist/tools/read-asset-metadata.js +26 -0
- package/dist/tools/read-file-at-commit.js +29 -0
- package/dist/tools/read-transcript.js +41 -0
- package/dist/tools/reconcile-project-work.js +1452 -0
- package/dist/tools/recover-asset.js +28 -0
- package/dist/tools/remove-sound.js +72 -0
- package/dist/tools/remove-timeline-audio.js +34 -0
- package/dist/tools/remove-timeline-slot.js +40 -0
- package/dist/tools/rename-all.js +434 -0
- package/dist/tools/rename-asset.js +34 -0
- package/dist/tools/render-settings.js +47 -0
- package/dist/tools/render-timeline.js +120 -0
- package/dist/tools/render.js +384 -0
- package/dist/tools/reorder-character-images.js +45 -0
- package/dist/tools/replace-video-audio.js +133 -0
- package/dist/tools/restore-archive-clips.js +209 -0
- package/dist/tools/restore-asset-version.js +37 -0
- package/dist/tools/retry-generation.js +54 -0
- package/dist/tools/reverse-video.js +74 -0
- package/dist/tools/rewrite-prompt.js +388 -0
- package/dist/tools/rewrite-script.js +67 -0
- package/dist/tools/schema-from-apicity.js +66 -0
- package/dist/tools/search-archive.js +150 -0
- package/dist/tools/semantic-search.js +1214 -0
- package/dist/tools/sequence-rhythm.js +43 -0
- package/dist/tools/set-character-metadata.js +84 -0
- package/dist/tools/set-env-secret.js +40 -0
- package/dist/tools/set-osg.js +143 -0
- package/dist/tools/show-folder.js +37 -0
- package/dist/tools/smooth-scene-concat.js +122 -0
- package/dist/tools/splice-video.js +149 -0
- package/dist/tools/split-video.js +202 -0
- package/dist/tools/suggest-cuts.js +45 -0
- package/dist/tools/suggest-sfx.js +43 -0
- package/dist/tools/sync-video-to-audio.js +115 -0
- package/dist/tools/tag-backfill.js +177 -0
- package/dist/tools/timewarp-video.js +85 -0
- package/dist/tools/tool-def.js +1 -0
- package/dist/tools/tool-json-schema.js +116 -0
- package/dist/tools/transcribe.js +90 -0
- package/dist/tools/translate-subtitles.js +59 -0
- package/dist/tools/trim-audio.js +139 -0
- package/dist/tools/trim-video.js +168 -0
- package/dist/tools/update-script.js +25 -0
- package/dist/tools/update-timeline-audio.js +40 -0
- package/dist/tools/upload-file.js +41 -0
- package/dist/tools/verify-x-mentions.js +141 -0
- package/dist/tools/video-editing-command-contract.js +291 -0
- package/dist/tools/video-source-reference.js +30 -0
- package/dist/tools/video-time-input.js +18 -0
- package/dist/tools/videobook-domain.js +2021 -0
- package/dist/tools/wait-for-asset-ready.js +143 -0
- package/dist/tools/workspace-actions.js +54 -0
- package/dist/transcript-projection.js +202 -0
- package/dist/transcript-srt.js +33 -0
- package/dist/upload.js +76 -0
- package/dist/usage-providers.js +25 -0
- package/dist/video-analysis-projection.js +46 -0
- package/dist/video-poster.js +33 -0
- package/dist/video-proxy.js +99 -0
- package/dist/vision-regions.js +111 -0
- package/dist/voice-actions.js +90 -0
- package/dist/voice-audio.js +55 -0
- package/dist/voice-config.js +122 -0
- package/dist/voice-continuation.js +54 -0
- package/dist/voice-contract.js +1 -0
- package/dist/voice-http.js +145 -0
- package/dist/voice-reply-progress.js +55 -0
- package/dist/voice-session.js +992 -0
- package/dist/watermark-badge.js +259 -0
- package/dist/watermark-config.js +111 -0
- package/dist/watermark-handle-position.js +55 -0
- package/dist/watermark-platform.js +15 -0
- package/dist/watermark-timing.js +16 -0
- package/dist/workspace-action-catalog.js +315 -0
- package/dist/workspace-action-contract.js +21 -0
- package/dist/workspace-action-groups.js +98 -0
- package/dist/workspace-action-surfaces.js +7 -0
- package/dist/x/account.js +88 -0
- package/dist/x/authenticated-handle.js +30 -0
- package/dist/x/oauth-flow.js +191 -0
- package/dist/x/post-contract.js +1 -0
- package/dist/x/post-metadata.js +44 -0
- package/dist/x/post-to-x.js +456 -0
- package/dist/x/published-post-cell.js +90 -0
- package/dist/x/x-tokens.js +69 -0
- package/dist/ytdlp-binary.js +65 -0
- package/dist/zod-slots.js +334 -0
- package/package.json +84 -4
- package/ui/assets/alive-captions-BWb5nLKj.css +1 -0
- package/ui/assets/alive-captions-DPEr1nKM.js +1 -0
- package/ui/assets/confirm-bodies-D8ouHXKy.js +1 -0
- package/ui/assets/confirm-bodies-DrMhaXC6.css +1 -0
- package/ui/assets/fullscreen-B7nw4YbE.js +1 -0
- package/ui/assets/goal-ui-DK-xTCK0.js +2 -0
- package/ui/assets/goal-ui-DXdUM2KF.css +1 -0
- package/ui/assets/index-DzPAnCUj.css +1 -0
- package/ui/assets/index-kS1905s5.js +37 -0
- package/ui/assets/inspector-MlzQbTVo.js +1 -0
- package/ui/assets/jobs-ui-CoinOWx0.js +1 -0
- package/ui/assets/music-video-Cbe80kmQ.js +1 -0
- package/ui/assets/music-video-DPaiKKEq.css +1 -0
- package/ui/assets/ui-Oirr9VOf.css +1 -0
- package/ui/assets/ui-xo_Y1yQg.js +2 -0
- package/ui/assets/vendor-D2rfiZ5j.css +1 -0
- package/ui/assets/vendor-DfTCWgKm.js +19 -0
- package/ui/assets/vendor-flow-BXbeWxW7.js +7 -0
- package/ui/assets/vendor-flow-BnuhLJ6X.css +1 -0
- package/ui/assets/vendor-icons-CGqhCIXV.js +1 -0
- package/ui/assets/vendor-mcp-BTlEJcHV.js +67 -0
- package/ui/assets/vendor-react-Dj7D1fD4.js +9 -0
- package/ui/assets/vendor-remotion-CH1HXrlc.js +95 -0
- package/ui/assets/videobook-Qlp9HQFu.js +20 -0
- package/ui/favicon.svg +8 -0
- package/ui/index.html +126 -0
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import sharp from "sharp";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { cropToFill, probeImage } from "../image.js";
|
|
4
|
+
import { findImageFile } from "./_image-inputs.js";
|
|
5
|
+
import { derivedLabel } from "../artifact-label.js";
|
|
6
|
+
const layoutOptions = ["horizontal", "vertical", "grid"];
|
|
7
|
+
const aspectRatioOptions = ["16:9", "9:16", "1:1", "4:3", "3:4"];
|
|
8
|
+
const concatImagesSchema = {
|
|
9
|
+
image_refs: z.array(z.string().nullable()).min(1).max(9).describe("Image artifact ids to concatenate. For a two-slot sheet, pass one id to leave the second slot empty or use null for an explicit empty slot."),
|
|
10
|
+
book_id: z.string().describe("Book id"),
|
|
11
|
+
layout: z.enum(layoutOptions).optional().describe("Cell layout. Defaults to horizontal for landscape two-slot sheets, vertical for portrait two-slot sheets, and grid for 3+ images."),
|
|
12
|
+
aspect_ratio: z.enum(aspectRatioOptions).optional().describe("Output aspect ratio. Defaults to 16:9 for video generation."),
|
|
13
|
+
name: z.string().optional().describe("Optional name for the generated image artifact"),
|
|
14
|
+
background: z.string().optional().describe("Background color for padding, e.g. #000000 or white. Defaults to #000000."),
|
|
15
|
+
};
|
|
16
|
+
const dimensionsByAspectRatio = {
|
|
17
|
+
"16:9": { width: 1920, height: 1080 },
|
|
18
|
+
"9:16": { width: 1080, height: 1920 },
|
|
19
|
+
"1:1": { width: 1080, height: 1080 },
|
|
20
|
+
"4:3": { width: 1440, height: 1080 },
|
|
21
|
+
"3:4": { width: 1080, height: 1440 },
|
|
22
|
+
};
|
|
23
|
+
export function concatImagesDef(engine) {
|
|
24
|
+
return {
|
|
25
|
+
name: "concat_images",
|
|
26
|
+
description: "Combine 1-9 image assets into one new image sheet, each fit without stretching; one or two inputs use a two-slot sheet (landscape side by side, portrait stacked).",
|
|
27
|
+
schema: concatImagesSchema,
|
|
28
|
+
handler: async (args) => {
|
|
29
|
+
const { image_refs, layout, aspect_ratio, name, background, } = args;
|
|
30
|
+
const sourceResult = await readSourceImages(engine, image_refs);
|
|
31
|
+
if (!sourceResult.ok)
|
|
32
|
+
return error(sourceResult.error);
|
|
33
|
+
if (!sourceResult.value.some((source) => source !== null)) {
|
|
34
|
+
return error("At least one image asset is required");
|
|
35
|
+
}
|
|
36
|
+
const resolvedAspectRatio = aspect_ratio ?? "16:9";
|
|
37
|
+
const resolvedLayout = layout ?? defaultLayout(resolvedAspectRatio, sourceResult.value.length);
|
|
38
|
+
const dimensions = dimensionsByAspectRatio[resolvedAspectRatio];
|
|
39
|
+
const resolvedBackground = background ?? "#000000";
|
|
40
|
+
const sourceImageIds = sourceResult.value.flatMap((source) => source ? [source.assetId] : []);
|
|
41
|
+
let output;
|
|
42
|
+
try {
|
|
43
|
+
output = await renderConcat(sourceResult.value, resolvedLayout, dimensions, resolvedBackground);
|
|
44
|
+
}
|
|
45
|
+
catch (e) {
|
|
46
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
47
|
+
return error(`Failed to concatenate images: ${message}`);
|
|
48
|
+
}
|
|
49
|
+
const assetName = name ?? deriveAssetName(engine, sourceImageIds);
|
|
50
|
+
const assetResult = await engine.artifacts.create("img", assetName);
|
|
51
|
+
if (!assetResult.ok)
|
|
52
|
+
return error(`Failed to create image asset: ${assetResult.error.message}`);
|
|
53
|
+
const imgAssetId = assetResult.value.artifactId;
|
|
54
|
+
const writeResult = await engine.files.write(imgAssetId, "original.png", output.buffer);
|
|
55
|
+
if (!writeResult.ok) {
|
|
56
|
+
await engine.artifacts.delete(imgAssetId).catch(() => undefined);
|
|
57
|
+
return error(writeResult.error.message);
|
|
58
|
+
}
|
|
59
|
+
const metadata = {
|
|
60
|
+
origin: "concat_images",
|
|
61
|
+
created_at: new Date().toISOString(),
|
|
62
|
+
width: output.dimensions.width,
|
|
63
|
+
height: output.dimensions.height,
|
|
64
|
+
layout: resolvedLayout,
|
|
65
|
+
aspect_ratio: resolvedAspectRatio,
|
|
66
|
+
source_images: sourceImageIds,
|
|
67
|
+
};
|
|
68
|
+
const metadataResult = await engine.metadata.artifacts.write(imgAssetId, "original", metadata);
|
|
69
|
+
if (!metadataResult.ok) {
|
|
70
|
+
await engine.artifacts.delete(imgAssetId).catch(() => undefined);
|
|
71
|
+
return error(metadataResult.error.message);
|
|
72
|
+
}
|
|
73
|
+
let variantsResult;
|
|
74
|
+
try {
|
|
75
|
+
variantsResult = await writeImageVariants(engine, imgAssetId, output.buffer);
|
|
76
|
+
}
|
|
77
|
+
catch (e) {
|
|
78
|
+
await engine.artifacts.delete(imgAssetId).catch(() => undefined);
|
|
79
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
80
|
+
return error(`Failed to write image variants: ${message}`);
|
|
81
|
+
}
|
|
82
|
+
if (!variantsResult.ok) {
|
|
83
|
+
await engine.artifacts.delete(imgAssetId).catch(() => undefined);
|
|
84
|
+
return error(variantsResult.error);
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
content: [{
|
|
88
|
+
type: "text",
|
|
89
|
+
text: JSON.stringify({
|
|
90
|
+
img_asset_id: imgAssetId,
|
|
91
|
+
asset_id: imgAssetId,
|
|
92
|
+
filename: "original.png",
|
|
93
|
+
width: output.dimensions.width,
|
|
94
|
+
height: output.dimensions.height,
|
|
95
|
+
layout: resolvedLayout,
|
|
96
|
+
aspect_ratio: resolvedAspectRatio,
|
|
97
|
+
source_images: sourceImageIds,
|
|
98
|
+
placements: output.placements,
|
|
99
|
+
}),
|
|
100
|
+
}],
|
|
101
|
+
};
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
async function readSourceImages(engine, rawRefs) {
|
|
106
|
+
const sources = [];
|
|
107
|
+
for (const rawRef of rawRefs) {
|
|
108
|
+
if (rawRef === null || rawRef.trim() === "") {
|
|
109
|
+
sources.push(null);
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
const assetId = rawRef.replace(/^@/, "");
|
|
113
|
+
const artifact = engine.artifacts.get(assetId);
|
|
114
|
+
if (!artifact.ok)
|
|
115
|
+
return { ok: false, error: artifact.error.message };
|
|
116
|
+
if (artifact.value.kind !== "image") {
|
|
117
|
+
return { ok: false, error: `image ref must be an image artifact, got ${artifact.value.kind}: ${assetId}` };
|
|
118
|
+
}
|
|
119
|
+
const manifestResult = await engine.files.manifest(assetId);
|
|
120
|
+
if (!manifestResult.ok)
|
|
121
|
+
return { ok: false, error: manifestResult.error.message };
|
|
122
|
+
const imageFile = findImageFile(manifestResult.value.files);
|
|
123
|
+
if (!imageFile)
|
|
124
|
+
return { ok: false, error: `No image file found in asset ${assetId}` };
|
|
125
|
+
const readResult = await engine.files.read(assetId, imageFile.name);
|
|
126
|
+
if (!readResult.ok)
|
|
127
|
+
return { ok: false, error: readResult.error.message };
|
|
128
|
+
const buffer = Buffer.isBuffer(readResult.value)
|
|
129
|
+
? readResult.value
|
|
130
|
+
: Buffer.from(readResult.value);
|
|
131
|
+
let dimensions;
|
|
132
|
+
try {
|
|
133
|
+
dimensions = await probeImage(buffer);
|
|
134
|
+
}
|
|
135
|
+
catch (e) {
|
|
136
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
137
|
+
return { ok: false, error: `Failed to read ${assetId}/${imageFile.name}: ${message}` };
|
|
138
|
+
}
|
|
139
|
+
if (dimensions.width <= 0 || dimensions.height <= 0) {
|
|
140
|
+
return { ok: false, error: `Could not determine dimensions for ${assetId}/${imageFile.name}` };
|
|
141
|
+
}
|
|
142
|
+
sources.push({ assetId, filename: imageFile.name, buffer });
|
|
143
|
+
}
|
|
144
|
+
return { ok: true, value: sources };
|
|
145
|
+
}
|
|
146
|
+
async function renderConcat(sources, layout, dimensions, background) {
|
|
147
|
+
const grid = resolveGrid(sources.length <= 2 ? 2 : sources.length, layout);
|
|
148
|
+
const composites = await Promise.all(sources.map(async (source, index) => {
|
|
149
|
+
if (!source)
|
|
150
|
+
return null;
|
|
151
|
+
const cell = cellFor(index, grid, dimensions);
|
|
152
|
+
const input = await sharp(source.buffer)
|
|
153
|
+
.rotate()
|
|
154
|
+
.resize(cell.width, cell.height, { fit: "contain", background })
|
|
155
|
+
.png()
|
|
156
|
+
.toBuffer();
|
|
157
|
+
return {
|
|
158
|
+
composite: { input, left: cell.x, top: cell.y },
|
|
159
|
+
placement: {
|
|
160
|
+
asset_id: source.assetId,
|
|
161
|
+
filename: source.filename,
|
|
162
|
+
cell,
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
}));
|
|
166
|
+
const populatedComposites = composites.filter((entry) => entry !== null);
|
|
167
|
+
const buffer = await sharp({
|
|
168
|
+
create: {
|
|
169
|
+
width: dimensions.width,
|
|
170
|
+
height: dimensions.height,
|
|
171
|
+
channels: 4,
|
|
172
|
+
background,
|
|
173
|
+
},
|
|
174
|
+
})
|
|
175
|
+
.composite(populatedComposites.map((entry) => entry.composite))
|
|
176
|
+
.png()
|
|
177
|
+
.toBuffer();
|
|
178
|
+
return {
|
|
179
|
+
buffer,
|
|
180
|
+
dimensions,
|
|
181
|
+
placements: populatedComposites.map((entry) => entry.placement),
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
function defaultLayout(aspectRatio, slotCount) {
|
|
185
|
+
if (slotCount > 2)
|
|
186
|
+
return "grid";
|
|
187
|
+
return aspectRatio === "9:16" || aspectRatio === "3:4" ? "vertical" : "horizontal";
|
|
188
|
+
}
|
|
189
|
+
function resolveGrid(count, layout) {
|
|
190
|
+
if (layout === "horizontal")
|
|
191
|
+
return { columns: count, rows: 1 };
|
|
192
|
+
if (layout === "vertical")
|
|
193
|
+
return { columns: 1, rows: count };
|
|
194
|
+
const columns = Math.ceil(Math.sqrt(count));
|
|
195
|
+
return { columns, rows: Math.ceil(count / columns) };
|
|
196
|
+
}
|
|
197
|
+
function cellFor(index, grid, dimensions) {
|
|
198
|
+
const column = index % grid.columns;
|
|
199
|
+
const row = Math.floor(index / grid.columns);
|
|
200
|
+
const x = Math.floor((dimensions.width * column) / grid.columns);
|
|
201
|
+
const y = Math.floor((dimensions.height * row) / grid.rows);
|
|
202
|
+
const nextX = Math.floor((dimensions.width * (column + 1)) / grid.columns);
|
|
203
|
+
const nextY = Math.floor((dimensions.height * (row + 1)) / grid.rows);
|
|
204
|
+
return {
|
|
205
|
+
x,
|
|
206
|
+
y,
|
|
207
|
+
width: nextX - x,
|
|
208
|
+
height: nextY - y,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
export async function writeImageVariants(engine, assetId, buffer) {
|
|
212
|
+
const [landscape, portrait, square] = await Promise.all([
|
|
213
|
+
cropToFill(buffer, 1920, 1080),
|
|
214
|
+
cropToFill(buffer, 1080, 1920),
|
|
215
|
+
cropToFill(buffer, 1080, 1080),
|
|
216
|
+
]);
|
|
217
|
+
const results = await Promise.all([
|
|
218
|
+
engine.files.write(assetId, "landscape.jpg", landscape),
|
|
219
|
+
engine.files.write(assetId, "portrait.jpg", portrait),
|
|
220
|
+
engine.files.write(assetId, "square.jpg", square),
|
|
221
|
+
]);
|
|
222
|
+
const failure = results.find((result) => !result.ok);
|
|
223
|
+
if (failure && !failure.ok)
|
|
224
|
+
return { ok: false, error: failure.error.message };
|
|
225
|
+
return { ok: true };
|
|
226
|
+
}
|
|
227
|
+
function deriveAssetName(engine, assetIds) {
|
|
228
|
+
const sources = assetIds.map((assetId) => {
|
|
229
|
+
const artifact = engine.artifacts.get(assetId);
|
|
230
|
+
return (artifact.ok ? artifact.value.label?.trim() : "") || assetId;
|
|
231
|
+
});
|
|
232
|
+
return derivedLabel("concat", sources.join(" + "));
|
|
233
|
+
}
|
|
234
|
+
function error(text) {
|
|
235
|
+
return { isError: true, content: [{ type: "text", text }] };
|
|
236
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { dropboxStatus, startDropboxConnect } from "../posts/dropbox-auth.js";
|
|
3
|
+
import { icloudStatus } from "../posts/icloud-drive.js";
|
|
4
|
+
import { getOAuthFlowStatus, startOAuthFlow } from "../x/oauth-flow.js";
|
|
5
|
+
function textResult(value) {
|
|
6
|
+
return { content: [{ type: "text", text: JSON.stringify(value) }] };
|
|
7
|
+
}
|
|
8
|
+
function toolError(error) {
|
|
9
|
+
return { isError: true, content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }] };
|
|
10
|
+
}
|
|
11
|
+
async function startConnection(service) {
|
|
12
|
+
if (service === "x")
|
|
13
|
+
return { authorize_url: (await startOAuthFlow()).authorize_url };
|
|
14
|
+
return startDropboxConnect();
|
|
15
|
+
}
|
|
16
|
+
async function readStatus(service, refreshAccount) {
|
|
17
|
+
if (service === "x")
|
|
18
|
+
return getOAuthFlowStatus(undefined, { refreshAccount });
|
|
19
|
+
return service === "dropbox" ? dropboxStatus() : icloudStatus();
|
|
20
|
+
}
|
|
21
|
+
export function connectServiceDef() {
|
|
22
|
+
return {
|
|
23
|
+
name: "connect_service",
|
|
24
|
+
description: "Start connecting an X or Dropbox account and return the authorize_url to open; poll service_status until connected. Credentials stay in application state, outside books.",
|
|
25
|
+
scope: "global",
|
|
26
|
+
schema: { service: z.enum(["x", "dropbox"]) },
|
|
27
|
+
handler: async (args) => {
|
|
28
|
+
try {
|
|
29
|
+
return textResult(await startConnection(args.service));
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
return toolError(error);
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export function serviceStatusDef() {
|
|
38
|
+
return {
|
|
39
|
+
name: "service_status",
|
|
40
|
+
description: "Read X, Dropbox or iCloud Drive delivery status without exposing credentials. X adds the account, its subscription tier and post_max_characters; iCloud adds the Videobook root folder and whether it is shared with the phones.",
|
|
41
|
+
scope: "global",
|
|
42
|
+
schema: {
|
|
43
|
+
service: z.enum(["x", "dropbox", "icloud"]),
|
|
44
|
+
refresh_account: z.boolean().optional().describe("X only: re-read the username and subscription tier instead of the cached copy"),
|
|
45
|
+
},
|
|
46
|
+
handler: async (args) => {
|
|
47
|
+
try {
|
|
48
|
+
return textResult(await readStatus(args.service, args.refresh_account === true));
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
return toolError(error);
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { exec } from "node:child_process";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { findOriginalMediaFile } from "../original-media-file.js";
|
|
5
|
+
export function copyFileToClipboardDef(engine) {
|
|
6
|
+
return {
|
|
7
|
+
name: "copy_file_to_clipboard",
|
|
8
|
+
description: "Copy an asset's original media file to the macOS pasteboard as a file reference",
|
|
9
|
+
schema: {
|
|
10
|
+
asset_id: z.string().describe("Artifact id"),
|
|
11
|
+
book_id: z.string().describe("Book UUID"),
|
|
12
|
+
},
|
|
13
|
+
handler: async (args) => {
|
|
14
|
+
const { asset_id, book_id: _book_id } = args;
|
|
15
|
+
const artifactResult = engine.artifacts.get(asset_id);
|
|
16
|
+
if (!artifactResult.ok) {
|
|
17
|
+
return {
|
|
18
|
+
isError: true,
|
|
19
|
+
content: [{ type: "text", text: artifactResult.error.message }],
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
const manifestResult = await engine.files.manifest(asset_id);
|
|
23
|
+
if (!manifestResult.ok) {
|
|
24
|
+
return {
|
|
25
|
+
isError: true,
|
|
26
|
+
content: [{ type: "text", text: manifestResult.error.message }],
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
const manifest = manifestResult.value;
|
|
30
|
+
const file = findOriginalMediaFile(manifest.files, artifactResult.value.kind);
|
|
31
|
+
if (!file) {
|
|
32
|
+
return {
|
|
33
|
+
isError: true,
|
|
34
|
+
content: [{ type: "text", text: "No original media file found for asset" }],
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
const absPath = join(manifest.path, file.name);
|
|
38
|
+
const fileName = file.name;
|
|
39
|
+
const escaped = absPath.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
40
|
+
const script = `set the clipboard to POSIX file "${escaped}"`;
|
|
41
|
+
return new Promise((resolve) => {
|
|
42
|
+
exec(`osascript -e '${script.replace(/'/g, "'\\''")}'`, (error) => {
|
|
43
|
+
if (error) {
|
|
44
|
+
resolve({
|
|
45
|
+
isError: true,
|
|
46
|
+
content: [{ type: "text", text: `Failed to copy to clipboard: ${error.message}` }],
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
resolve({
|
|
51
|
+
content: [{ type: "text", text: JSON.stringify({ status: "copied", path: absPath, file: fileName }) }],
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { findPrimaryMediaFile } from "videobook-engine";
|
|
3
|
+
import { resolveCharacterCreateName } from "../character-name.js";
|
|
4
|
+
export function createCharacterDef(engine) {
|
|
5
|
+
return {
|
|
6
|
+
name: "create_character",
|
|
7
|
+
description: "Create a new character artifact, optionally seeded from existing image artifacts",
|
|
8
|
+
schema: {
|
|
9
|
+
book_id: z.string().describe("Book id"),
|
|
10
|
+
args: z.array(z.string()).describe("Name of the character, OR one or more image artifact ids"),
|
|
11
|
+
},
|
|
12
|
+
handler: async (payload) => {
|
|
13
|
+
const { book_id: _book_id, args } = payload;
|
|
14
|
+
const imageSources = [];
|
|
15
|
+
// Parallel to imageSources: the free-text label each source carries, used
|
|
16
|
+
// as the character name stem when no explicit name is given.
|
|
17
|
+
const imageLabels = [];
|
|
18
|
+
const nameParts = [];
|
|
19
|
+
for (let arg of args) {
|
|
20
|
+
const isTagged = arg.startsWith("@");
|
|
21
|
+
if (isTagged)
|
|
22
|
+
arg = arg.slice(1);
|
|
23
|
+
const artifact = engine.artifacts.get(arg);
|
|
24
|
+
if (artifact.ok) {
|
|
25
|
+
if (artifact.value.kind !== "image") {
|
|
26
|
+
return {
|
|
27
|
+
isError: true,
|
|
28
|
+
content: [{ type: "text", text: `Non-image source provided (${artifact.value.kind}): ${arg}` }],
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
imageSources.push(arg);
|
|
32
|
+
imageLabels.push(artifact.value.label ?? "");
|
|
33
|
+
}
|
|
34
|
+
else if (isTagged) {
|
|
35
|
+
return {
|
|
36
|
+
isError: true,
|
|
37
|
+
content: [{ type: "text", text: `Unknown artifact reference: @${arg}` }],
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
nameParts.push(arg);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (nameParts.length === 0 && imageSources.length === 0) {
|
|
45
|
+
return {
|
|
46
|
+
isError: true,
|
|
47
|
+
content: [{ type: "text", text: `Provide a name or at least one image source.` }],
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
const displayName = resolveCharacterCreateName(nameParts, imageLabels);
|
|
51
|
+
const uniqueSources = new Set(imageSources);
|
|
52
|
+
if (uniqueSources.size !== imageSources.length) {
|
|
53
|
+
return {
|
|
54
|
+
isError: true,
|
|
55
|
+
content: [{ type: "text", text: `Duplicate sources provided` }],
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
const assetResult = await engine.artifacts.create("char", displayName);
|
|
59
|
+
if (!assetResult.ok) {
|
|
60
|
+
return {
|
|
61
|
+
isError: true,
|
|
62
|
+
content: [{ type: "text", text: `Failed to create character: ${assetResult.error.message}` }],
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
const asset_id = assetResult.value.artifactId;
|
|
66
|
+
for (let i = 0; i < imageSources.length; i++) {
|
|
67
|
+
const sourceId = imageSources[i];
|
|
68
|
+
const manifestResult = await engine.files.manifest(sourceId);
|
|
69
|
+
if (!manifestResult.ok) {
|
|
70
|
+
return {
|
|
71
|
+
isError: true,
|
|
72
|
+
content: [{ type: "text", text: `Missing source asset: ${sourceId}` }],
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
const primaryFile = findPrimaryMediaFile(manifestResult.value.files, "image");
|
|
76
|
+
if (!primaryFile) {
|
|
77
|
+
return {
|
|
78
|
+
isError: true,
|
|
79
|
+
content: [{ type: "text", text: `Source asset has no primary media: ${sourceId}` }],
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
const ext = primaryFile.name.split(".").pop();
|
|
83
|
+
const destFilename = `source-${String(i + 1).padStart(2, "0")}.${ext}`;
|
|
84
|
+
const copyResult = await engine.files.copy(sourceId, primaryFile.name, asset_id, destFilename);
|
|
85
|
+
if (!copyResult.ok) {
|
|
86
|
+
return {
|
|
87
|
+
isError: true,
|
|
88
|
+
content: [{ type: "text", text: `Failed to copy file from ${sourceId}: ${copyResult.error.message}` }],
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
const metaResult = await engine.metadata.artifacts.write(asset_id, "character", { display_name: displayName });
|
|
93
|
+
if (!metaResult.ok) {
|
|
94
|
+
return {
|
|
95
|
+
isError: true,
|
|
96
|
+
content: [{
|
|
97
|
+
type: "text",
|
|
98
|
+
text: `Created ${asset_id} but failed to write display_name: ${metaResult.error.message}`,
|
|
99
|
+
}],
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
content: [{
|
|
104
|
+
type: "text",
|
|
105
|
+
text: JSON.stringify({
|
|
106
|
+
asset_id,
|
|
107
|
+
display_name: displayName,
|
|
108
|
+
message: `Created character folder ${asset_id}${imageSources.length > 0 ? ` seeded from ${imageSources.length} images` : ""}`,
|
|
109
|
+
}),
|
|
110
|
+
}],
|
|
111
|
+
};
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
}
|