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,261 @@
|
|
|
1
|
+
import { notebookGridTag } from "videobook-engine/notebook-grid";
|
|
2
|
+
import { cancelChainRun, getChainRun } from "./chain-executor.js";
|
|
3
|
+
import { coldOpenSource } from "./cold-open.js";
|
|
4
|
+
import { emptyGoalEstimates, findGoalCell, goalContent, requireGoalContent, saveGoal, writeGoalContent } from "./goal-store.js";
|
|
5
|
+
import { GOAL_VIDEO_TOOL, refreshGoalPlanV3 } from "./goal-plan.js";
|
|
6
|
+
import { suggestedColdOpen } from "./lightning-defaults.js";
|
|
7
|
+
import { mutateNotebook } from "./notebook-mutations.js";
|
|
8
|
+
import { goalStageAttempts, goalStillStaleReason } from "./goal-stills.js";
|
|
9
|
+
export const LEGACY_GOAL_MESSAGE = "Goal mode now starts from character images. Start a new /goal.";
|
|
10
|
+
export function activeGoalStage(goal) {
|
|
11
|
+
return goal.stage === "assembly" ? "videos" : goal.stage;
|
|
12
|
+
}
|
|
13
|
+
function outputString(outputs, key) {
|
|
14
|
+
const value = outputs?.[key];
|
|
15
|
+
return typeof value === "string" ? value : null;
|
|
16
|
+
}
|
|
17
|
+
function producerCell(document, chainId, step) {
|
|
18
|
+
const tagged = document.cells.filter(cell => cell.inputs?.chainRunId === `${chainId}:${step.id}`).sort((a, b) => b.id.localeCompare(a.id))[0];
|
|
19
|
+
const outputId = outputString(step.outputs, "cell_id");
|
|
20
|
+
const edge = document.edges.find(candidate => candidate.target === outputId && candidate.targetInput === "media");
|
|
21
|
+
return tagged ?? document.cells.find(cell => cell.id === edge?.source);
|
|
22
|
+
}
|
|
23
|
+
function goalChainSteps(engine, document, chainId) {
|
|
24
|
+
const chain = chainId ? getChainRun(engine, chainId) : null;
|
|
25
|
+
return chain?.steps.map(step => {
|
|
26
|
+
const producer = producerCell(document, chain.chainId, step);
|
|
27
|
+
return {
|
|
28
|
+
id: step.id, chainId: chain.chainId, status: step.status, error: step.error,
|
|
29
|
+
artifactId: outputString(step.outputs, "asset_id") ?? outputString(step.outputs, "img_asset_id") ?? outputString(step.outputs, "vid_asset_id"),
|
|
30
|
+
cellId: producer?.id ?? null,
|
|
31
|
+
address: producer ? notebookGridTag(producer.slot) : outputString(step.outputs, "address"),
|
|
32
|
+
outputCellId: outputString(step.outputs, "cell_id"), startedAt: step.startedAt ?? null,
|
|
33
|
+
};
|
|
34
|
+
}) ?? [];
|
|
35
|
+
}
|
|
36
|
+
function stageOutputIndex(stepId) {
|
|
37
|
+
if (stepId === "frame" || stepId === "scene" || stepId === "video")
|
|
38
|
+
return 0;
|
|
39
|
+
return Number(/\d+$/u.exec(stepId)?.[0]) - 1;
|
|
40
|
+
}
|
|
41
|
+
function completedStageOutputs(engine, goal, document) {
|
|
42
|
+
return goalChainSteps(engine, document, goal.chainId).flatMap(step => {
|
|
43
|
+
if (step.status !== "completed" || !step.artifactId || step.id === "assemble")
|
|
44
|
+
return [];
|
|
45
|
+
const index = stageOutputIndex(step.id);
|
|
46
|
+
if (!Number.isInteger(index) || index < 0)
|
|
47
|
+
return [];
|
|
48
|
+
const cell = document.cells.find(candidate => candidate.id === step.outputCellId);
|
|
49
|
+
return [{ index, artifactId: step.artifactId, cellId: step.outputCellId, producerCellId: step.cellId, address: cell ? notebookGridTag(cell.slot) : null }];
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
function allGoalChainSteps(engine, document, chainId) {
|
|
53
|
+
return goalChainSteps(engine, document, chainId).flatMap(step => {
|
|
54
|
+
const producers = document.cells.filter(cell => cell.inputs?.chainRunId === `${chainId}:${step.id}`);
|
|
55
|
+
if (producers.length === 0)
|
|
56
|
+
return [step];
|
|
57
|
+
return producers.map(producer => {
|
|
58
|
+
const outputCellId = document.edges.find(edge => edge.source === producer.id && edge.targetInput === "media")?.target ?? null;
|
|
59
|
+
return { ...step, cellId: producer.id, outputCellId, address: notebookGridTag(producer.slot) };
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
export async function writeGoalCombinationState(engine, goal, error) {
|
|
64
|
+
if (!goal.combined)
|
|
65
|
+
return goal;
|
|
66
|
+
const updated = await mutateNotebook(engine, goal.notebookId, "goal_combine_complete", document => ({
|
|
67
|
+
...document, cells: document.cells.map(cell => cell.id === goal.combined?.cellId ? { ...cell, inputs: { ...cell.inputs, state: error ? "error" : "completed" } } : cell),
|
|
68
|
+
}));
|
|
69
|
+
if (!updated.ok)
|
|
70
|
+
throw new Error(updated.error.message);
|
|
71
|
+
return saveGoal(engine, { ...goal, combined: { ...goal.combined, status: error ? "failed" : "completed", error } });
|
|
72
|
+
}
|
|
73
|
+
export function reconcileFinish(engine, goal) {
|
|
74
|
+
const finish = goal.finish;
|
|
75
|
+
if (goal.planVersion !== 3 || !finish || finish.status !== "running")
|
|
76
|
+
return goal;
|
|
77
|
+
const job = finish.jobId ? engine.jobs.queue.get(finish.jobId) : null;
|
|
78
|
+
if (job && ["queued", "running", "completing"].includes(job.state))
|
|
79
|
+
return goal;
|
|
80
|
+
if (job?.state === "done") {
|
|
81
|
+
const result = job.result && typeof job.result === "object" ? job.result : null;
|
|
82
|
+
const finalArtifactId = finish.finalArtifactId ?? (typeof result?.finalArtifactId === "string" && result.finalArtifactId ? result.finalArtifactId : null);
|
|
83
|
+
if (finalArtifactId && engine.artifacts.get(finalArtifactId).ok) {
|
|
84
|
+
const coldOpenArtifactId = finish.coldOpenArtifactId ?? (typeof result?.coldOpenArtifactId === "string" ? result.coldOpenArtifactId : null);
|
|
85
|
+
return saveGoal(engine, { ...goal, status: "completed", error: null, finish: { ...finish, status: "completed", finalArtifactId, coldOpenArtifactId, error: null } });
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return saveGoal(engine, { ...goal, status: "review", finish: { ...finish, status: "failed", error: job?.error?.message ?? "Finishing was interrupted. Retry the cold open." } });
|
|
89
|
+
}
|
|
90
|
+
async function coldOpenReview(engine, goal) {
|
|
91
|
+
if (goal.planVersion !== 3 || !goal.finish?.sourceArtifactId)
|
|
92
|
+
return null;
|
|
93
|
+
try {
|
|
94
|
+
const source = await coldOpenSource(engine, goal.finish.sourceArtifactId, goal.finish.sourceObjectHash ?? undefined);
|
|
95
|
+
const approved = goal.finish.status !== "review" && goal.finish.startSeconds != null && goal.finish.endSeconds != null;
|
|
96
|
+
const range = approved
|
|
97
|
+
? { startSeconds: goal.finish.startSeconds, endSeconds: goal.finish.endSeconds }
|
|
98
|
+
: suggestedColdOpen(source.durationSeconds);
|
|
99
|
+
return { ...range, durationSeconds: source.durationSeconds, sourceObjectHash: source.file.objectHash, analysisUsd: 0 };
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
export async function reconcileGoal(engine, goal, document) {
|
|
106
|
+
if (goal.planVersion === 1) {
|
|
107
|
+
if (!["planning", "review", "running"].includes(goal.status))
|
|
108
|
+
return goal;
|
|
109
|
+
if (goal.chainId)
|
|
110
|
+
cancelChainRun(engine, goal.chainId);
|
|
111
|
+
if (goal.planningJobId)
|
|
112
|
+
await engine.jobs.queue.abort(goal.planningJobId, LEGACY_GOAL_MESSAGE);
|
|
113
|
+
return saveGoal(engine, { ...goal, status: "failed", error: LEGACY_GOAL_MESSAGE });
|
|
114
|
+
}
|
|
115
|
+
if (goal.combined?.status === "running") {
|
|
116
|
+
const job = goal.combined.jobId ? engine.jobs.queue.get(goal.combined.jobId) : null;
|
|
117
|
+
if (!job || ["failed", "aborted"].includes(job.state))
|
|
118
|
+
goal = await writeGoalCombinationState(engine, goal, job?.error?.message ?? "Combining was interrupted. Retry the combined video.");
|
|
119
|
+
}
|
|
120
|
+
if (["completed", "cancelled", "review"].includes(goal.status))
|
|
121
|
+
return goal;
|
|
122
|
+
if (goal.status === "planning") {
|
|
123
|
+
const job = goal.planningJobId ? engine.jobs.queue.get(goal.planningJobId) : null;
|
|
124
|
+
return job && ["failed", "aborted"].includes(job.state)
|
|
125
|
+
? saveGoal(engine, { ...goal, status: "failed", error: job.error?.message ?? "Planning was interrupted" }) : goal;
|
|
126
|
+
}
|
|
127
|
+
const stage = activeGoalStage(goal);
|
|
128
|
+
const run = goal.stages[stage];
|
|
129
|
+
const chain = run ? getChainRun(engine, run.chainId) : null;
|
|
130
|
+
if (!run || !chain)
|
|
131
|
+
return goal;
|
|
132
|
+
const merged = new Map(run.outputs.map(output => [output.index, output]));
|
|
133
|
+
for (const output of completedStageOutputs(engine, goal, document))
|
|
134
|
+
merged.set(output.index, output);
|
|
135
|
+
const outputs = [...merged.values()].sort((a, b) => a.index - b.index);
|
|
136
|
+
const attempts = run.attempts?.map(attempt => {
|
|
137
|
+
if (attempt.artifactId)
|
|
138
|
+
return attempt;
|
|
139
|
+
const step = goalChainSteps(engine, document, attempt.chainId).find(candidate => candidate.id === attempt.stepId);
|
|
140
|
+
return step?.status === "completed" && step.artifactId ? { ...attempt, artifactId: step.artifactId, cellId: step.outputCellId } : attempt;
|
|
141
|
+
});
|
|
142
|
+
let next = { ...goal, stages: { ...goal.stages, [stage]: { ...run, outputs, ...(attempts ? { attempts } : {}) } } };
|
|
143
|
+
const assembled = stage === "videos" && goal.assembly?.artifactIds && JSON.stringify(goal.assembly.artifactIds) === JSON.stringify(outputs.map(output => output.artifactId));
|
|
144
|
+
if (chain.status === "completed" || assembled && !goal.resumeStage) {
|
|
145
|
+
const content = requireGoalContent(engine, goal);
|
|
146
|
+
if (goal.planVersion === 3) {
|
|
147
|
+
const cleared = { resumeStage: null, resumeStatus: null, resumeOutputs: null, resumeFinish: null };
|
|
148
|
+
if (outputs.length !== 1)
|
|
149
|
+
next = { ...next, status: "failed", error: "The stage finished without all of its media outputs. Retry the stage.", ...cleared };
|
|
150
|
+
else if (stage === "videos") {
|
|
151
|
+
next = {
|
|
152
|
+
...next, status: "review", error: null, ...cleared,
|
|
153
|
+
finish: { status: "review", sourceArtifactId: outputs[0].artifactId, finalArtifactId: null, error: null },
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
const previousScene = run.outputs[0]?.artifactId ?? null;
|
|
158
|
+
await writeGoalContent(engine, goal, { ...content, revision: content.revision + 1 });
|
|
159
|
+
const sceneChanged = previousScene !== null && previousScene !== outputs[0].artifactId;
|
|
160
|
+
const finish = sceneChanged ? null : goal.finish ?? goal.resumeFinish ?? null;
|
|
161
|
+
const keepCompleted = finish?.status === "completed" && Boolean(finish.finalArtifactId);
|
|
162
|
+
next = {
|
|
163
|
+
...next, stage: goal.resumeStage ?? "videos", status: keepCompleted ? "completed" : "review", error: null, ...cleared,
|
|
164
|
+
finish,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
const stagedPlan = content.plan && "shots" in content.plan ? content.plan : null;
|
|
170
|
+
const shotCount = stagedPlan?.shots.length ?? 0;
|
|
171
|
+
const expected = stage === "frame" ? 1 : stage === "storyboards" && stagedPlan && "frameContinuity" in stagedPlan && stagedPlan.frameContinuity ? 2 * shotCount : shotCount;
|
|
172
|
+
if (outputs.length !== expected)
|
|
173
|
+
next = { ...next, status: "failed", error: "The stage finished without all of its media outputs. Retry the stage." };
|
|
174
|
+
else if (stage === "videos") {
|
|
175
|
+
next = { ...next, status: goal.assembly || expected === 1 || goal.resumeStage ? "completed" : "failed", error: goal.assembly || expected === 1 || goal.resumeStage ? null : "The finished clips still need to be assembled" };
|
|
176
|
+
if (goal.combined && JSON.stringify(run.outputs.map(output => output.artifactId)) !== JSON.stringify(outputs.map(output => output.artifactId)))
|
|
177
|
+
next.combined = { ...goal.combined, status: "failed", error: "Video selection changed. Assemble the selected clips before combining again." };
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
await writeGoalContent(engine, goal, { ...content, revision: content.revision + 1 });
|
|
181
|
+
next = { ...next, stage: goal.resumeStage ?? (stage === "frame" ? "storyboards" : "videos"), status: goal.resumeStatus ?? "review", error: null };
|
|
182
|
+
}
|
|
183
|
+
next = { ...next, resumeStage: null, resumeStatus: null, resumeOutputs: null };
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
else if (["failed", "interrupted", "cancelled"].includes(chain.status)) {
|
|
187
|
+
next = { ...next, status: chain.status, error: chain.error,
|
|
188
|
+
...(goal.resumeOutputs ? { stages: { ...next.stages, [stage]: { ...next.stages[stage], outputs: goal.resumeOutputs } } } : {}),
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
next = { ...next, stage: chain.steps.some(step => step.id === "assemble" && step.status === "running") ? "assembly" : stage, status: "running", error: null };
|
|
193
|
+
}
|
|
194
|
+
return JSON.stringify(next) === JSON.stringify(goal) ? goal : saveGoal(engine, next);
|
|
195
|
+
}
|
|
196
|
+
export async function publicGoal(engine, goal, document) {
|
|
197
|
+
const cell = findGoalCell(document, goal);
|
|
198
|
+
const content = cell ? goalContent(cell) : { brief: "", characters: [], revision: 0, plan: null, estimate: emptyGoalEstimates() };
|
|
199
|
+
const stages = Object.fromEntries(await Promise.all(Object.entries(goal.stages).map(async ([stage, run]) => [stage, {
|
|
200
|
+
...run,
|
|
201
|
+
...(stage === "videos" ? { attempts: goalStageAttempts(engine, goal, "videos") } : {}),
|
|
202
|
+
outputs: await Promise.all(run.outputs.map(async (output) => {
|
|
203
|
+
const outputCell = document.cells.find(candidate => candidate.id === output.cellId);
|
|
204
|
+
const versions = goalStageAttempts(engine, goal, stage).filter(attempt => attempt.index === output.index).slice().reverse().map(attempt => {
|
|
205
|
+
const versionCell = document.cells.find(candidate => candidate.id === attempt.cellId);
|
|
206
|
+
const step = getChainRun(engine, attempt.chainId)?.steps.find(candidate => candidate.id === attempt.stepId);
|
|
207
|
+
return {
|
|
208
|
+
...attempt, address: versionCell ? notebookGridTag(versionCell.slot) : null,
|
|
209
|
+
status: step?.status ?? "interrupted", current: attempt.artifactId === output.artifactId,
|
|
210
|
+
};
|
|
211
|
+
});
|
|
212
|
+
const stagedPlan = content.plan && "version" in content.plan && content.plan.version === 2 ? content.plan : null;
|
|
213
|
+
const stale = stagedPlan && (stage === "frame" || stage === "storyboards" || stage === "videos")
|
|
214
|
+
? await goalStillStaleReason(engine, goal, document, stagedPlan, content.characters, stage, output) : null;
|
|
215
|
+
return { ...output, address: outputCell ? notebookGridTag(outputCell.slot) : null, versions, stale };
|
|
216
|
+
})),
|
|
217
|
+
steps: goalChainSteps(engine, document, run.chainId),
|
|
218
|
+
allSteps: [...run.previousChainIds, run.chainId].flatMap(chainId => allGoalChainSteps(engine, document, chainId)),
|
|
219
|
+
}])));
|
|
220
|
+
const shotPlan = content.plan && "shots" in content.plan ? content.plan : null;
|
|
221
|
+
const stillCount = shotPlan ? shotPlan.shots.length * ("frameContinuity" in shotPlan && shotPlan.frameContinuity ? 2 : 1) : 1;
|
|
222
|
+
const displayedPlan = content.plan && "version" in content.plan && content.plan.version === 3 ? refreshGoalPlanV3(content.plan, document) : content.plan;
|
|
223
|
+
const v3Plan = displayedPlan && "version" in displayedPlan && displayedPlan.version === 3;
|
|
224
|
+
const still = v3Plan
|
|
225
|
+
? goal.stage === "videos" || goal.stage === "assembly" ? content.estimate.videos : content.estimate.frame
|
|
226
|
+
: goal.stage === "videos"
|
|
227
|
+
? { ...content.estimate.storyboards, usd: content.estimate.storyboards.usd === null ? null : content.estimate.storyboards.usd / stillCount }
|
|
228
|
+
: content.estimate.frame;
|
|
229
|
+
return {
|
|
230
|
+
kind: "video-goal", ...goal, ...content, plan: displayedPlan,
|
|
231
|
+
finish: goal.finish ?? null,
|
|
232
|
+
finalArtifactId: goal.finish?.finalArtifactId ?? null,
|
|
233
|
+
coldOpen: await coldOpenReview(engine, goal),
|
|
234
|
+
estimate: { ...content.estimate, still },
|
|
235
|
+
address: cell ? notebookGridTag(cell.slot) : null,
|
|
236
|
+
assemblyStale: goalAssemblyStale(engine, goal),
|
|
237
|
+
stages: stages,
|
|
238
|
+
steps: goalChainSteps(engine, document, goal.chainId),
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
export function goalAssemblyStale(engine, goal) {
|
|
242
|
+
if (!goal.assembly)
|
|
243
|
+
return false;
|
|
244
|
+
const clips = engine.sequences.getPrimary().clips;
|
|
245
|
+
const sources = goal.assembly.artifactIds ?? goal.clipIds.map(id => clips.find(clip => clip.clipId === id)?.source.artifactId ?? null);
|
|
246
|
+
return JSON.stringify(sources) !== JSON.stringify(completedGoalVideos(engine, goal));
|
|
247
|
+
}
|
|
248
|
+
export function completedGoalVideos(engine, goal) {
|
|
249
|
+
const run = goal.stages.videos;
|
|
250
|
+
const selected = new Map((run?.outputs ?? []).map(output => [output.index, output.artifactId]));
|
|
251
|
+
const chainId = run?.chainId ?? (goal.planVersion === 1 ? goal.chainId : null);
|
|
252
|
+
if (goal.status === "running" || selected.size === 0) {
|
|
253
|
+
for (const step of chainId ? getChainRun(engine, chainId)?.steps ?? [] : []) {
|
|
254
|
+
const id = outputString(step.outputs, "asset_id") ?? outputString(step.outputs, "vid_asset_id");
|
|
255
|
+
const index = stageOutputIndex(step.id);
|
|
256
|
+
if (step.tool === GOAL_VIDEO_TOOL && step.status === "completed" && id && Number.isInteger(index) && index >= 0)
|
|
257
|
+
selected.set(index, id);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
return [...selected.entries()].sort(([left], [right]) => left - right).map(([, id]) => id);
|
|
261
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { resolveNotebookCellArtifactId } from "videobook-engine";
|
|
2
|
+
import { notebookGridTag } from "videobook-engine/notebook-grid";
|
|
3
|
+
import { getChainRun } from "./chain-executor.js";
|
|
4
|
+
import { compileFrameSteps, compileStoryboardSteps, goalStillPrompt } from "./goal-plan.js";
|
|
5
|
+
import { goalReferenceHashes } from "./goal-reference-images.js";
|
|
6
|
+
function goalStepIndex(stage, stepId) {
|
|
7
|
+
if (stage === "frame" || stepId === "frame" || stepId === "scene" || stepId === "video")
|
|
8
|
+
return 0;
|
|
9
|
+
return Number(/\d+$/u.exec(stepId)?.[0]) - 1;
|
|
10
|
+
}
|
|
11
|
+
export async function goalV3Fingerprint(engine, plan, stage, sceneArtifactId) {
|
|
12
|
+
const ids = stage === "frame"
|
|
13
|
+
? plan.scene.imageRefs.map(reference => reference.artifactId)
|
|
14
|
+
: [...plan.video.imageRefs, ...plan.video.videoRefs].map(reference => reference.artifactId);
|
|
15
|
+
return JSON.stringify({
|
|
16
|
+
prompt: stage === "frame" ? plan.scene.prompt : plan.video.prompt,
|
|
17
|
+
settings: stage === "frame"
|
|
18
|
+
? { model: plan.scene.model, aspectRatio: plan.scene.aspectRatio, resolution: plan.scene.resolution, outputFormat: plan.scene.outputFormat }
|
|
19
|
+
: { aspectRatio: plan.video.aspectRatio, resolution: plan.video.resolution, duration: plan.video.durationSeconds, audio: plan.video.generateAudio, outputFormat: plan.video.outputFormat },
|
|
20
|
+
references: await goalReferenceHashes(engine, ids),
|
|
21
|
+
...(stage === "videos" ? { sceneArtifactId } : {}),
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
export async function goalStageFingerprint(engine, goal, plan, characters, stage, index) {
|
|
25
|
+
const ids = characters.map(character => character.artifactId);
|
|
26
|
+
if (stage !== "frame")
|
|
27
|
+
ids.push(goal.stages.frame?.outputs[0]?.artifactId ?? "");
|
|
28
|
+
if (stage === "videos") {
|
|
29
|
+
ids.push(goal.stages.storyboards?.outputs.find(output => output.index === index)?.artifactId ?? "");
|
|
30
|
+
if (plan.frameContinuity)
|
|
31
|
+
ids.push(goal.stages.storyboards?.outputs.find(output => output.index === index + plan.shots.length)?.artifactId ?? "");
|
|
32
|
+
}
|
|
33
|
+
return JSON.stringify({
|
|
34
|
+
prompt: stage === "videos" ? plan.shots[index]?.videoPrompt : goalStillPrompt(plan, stage, index),
|
|
35
|
+
aspectRatio: plan.aspectRatio, style: { id: plan.style.id, options: Object.entries(plan.style.options).sort() },
|
|
36
|
+
referenceRoles: plan.referenceRoles ?? [], references: await goalReferenceHashes(engine, ids),
|
|
37
|
+
...(stage === "videos" ? { duration: plan.shots[index]?.durationSeconds, resolution: plan.videoResolution, audio: true }
|
|
38
|
+
: { model: plan.imageModel, resolution: plan.imageResolution, ...(stage === "frame" ? { continuity: plan.continuity } : { layout: plan.storyboardLayout ?? "four-panel" }) }),
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
export async function goalAttemptFingerprints(engine, goal, plan, characters, stage, steps) {
|
|
42
|
+
return Object.fromEntries(await Promise.all(steps.filter(step => step.id !== "assemble").map(async (step) => [step.id, await goalStageFingerprint(engine, goal, plan, characters, stage, goalStepIndex(stage, step.id))])));
|
|
43
|
+
}
|
|
44
|
+
export function goalStageAttempts(engine, goal, stage) {
|
|
45
|
+
const run = goal.stages[stage];
|
|
46
|
+
const attempts = [...(run?.attempts ?? [])];
|
|
47
|
+
if (!run || stage !== "videos")
|
|
48
|
+
return attempts;
|
|
49
|
+
for (const chainId of [...run.previousChainIds, run.chainId]) {
|
|
50
|
+
for (const step of getChainRun(engine, chainId)?.steps ?? []) {
|
|
51
|
+
const artifactId = step.outputs?.asset_id ?? step.outputs?.vid_asset_id;
|
|
52
|
+
if (!/^shot\d+$/u.test(step.id) || step.status !== "completed" || typeof artifactId !== "string" || attempts.some(attempt => attempt.chainId === chainId && attempt.stepId === step.id))
|
|
53
|
+
continue;
|
|
54
|
+
attempts.push({
|
|
55
|
+
stage, index: goalStepIndex(stage, step.id), chainId, stepId: step.id, artifactId,
|
|
56
|
+
cellId: typeof step.outputs?.cell_id === "string" ? step.outputs.cell_id : null,
|
|
57
|
+
basePrompt: typeof step.params.prompt === "string" ? step.params.prompt.split("\n\n")[0] : "",
|
|
58
|
+
feedback: null, parentArtifactId: null, frameArtifactId: null, createdAt: run.approvedAt,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return attempts;
|
|
63
|
+
}
|
|
64
|
+
export function goalStillAttempts(goal, plan, stage, chainId, steps, createdAt, feedback = null, fingerprints, history = goal.stages[stage]?.attempts ?? []) {
|
|
65
|
+
return [...history, ...steps.filter(step => step.id !== "assemble").map(step => {
|
|
66
|
+
const index = goalStepIndex(stage, step.id);
|
|
67
|
+
return {
|
|
68
|
+
stage, index, chainId, stepId: step.id, artifactId: null, cellId: null,
|
|
69
|
+
basePrompt: stage === "videos" ? plan.shots[index].videoPrompt : goalStillPrompt(plan, stage, index), feedback,
|
|
70
|
+
...(fingerprints?.[step.id] ? { fingerprint: fingerprints[step.id] } : {}),
|
|
71
|
+
...(stage === "storyboards" && index < plan.shots.length ? { storyboardLayout: plan.storyboardLayout ?? "four-panel" } : {}),
|
|
72
|
+
parentArtifactId: feedback ? goal.stages[stage]?.outputs.find(output => output.index === index)?.artifactId ?? null : null,
|
|
73
|
+
frameArtifactId: stage === "storyboards" ? goal.stages.frame?.outputs[0]?.artifactId ?? null : null,
|
|
74
|
+
createdAt,
|
|
75
|
+
};
|
|
76
|
+
})];
|
|
77
|
+
}
|
|
78
|
+
function legacyStillPrompt(plan, characters, stage, index) {
|
|
79
|
+
const references = characters.map((character, position) => `@image${position + (stage === "storyboards" ? 2 : 1)} is Character ${position + 1}: ${character.label.replace(/@[\p{L}\p{N}_-]+/gu, "").slice(0, 160)}`);
|
|
80
|
+
if (stage === "frame")
|
|
81
|
+
return `${plan.continuity}\n\n${plan.frame.prompt}\n\nReferences: ${references.join("; ")}.`;
|
|
82
|
+
references.unshift("@image1 is the approved full frame; preserve its setting and visual style");
|
|
83
|
+
const shotIndex = index % plan.shots.length;
|
|
84
|
+
const shot = plan.shots[shotIndex];
|
|
85
|
+
const next = plan.shots[shotIndex + 1];
|
|
86
|
+
const ending = `Create one still image of the final moment of this shot, with the characters in their ending poses. ${shot.endingPrompt ?? shot.videoPrompt}${next ? `\nPrepare a natural transition into the next shot's opening composition: ${next.storyboardPrompt}` : "\nShow the final payoff with a clear, settled composition."}`;
|
|
87
|
+
return `${plan.continuity}\n\nShot ${shotIndex + 1}: ${shot.title}\n${index < plan.shots.length ? shot.storyboardPrompt : ending}\n\nReferences: ${references.join("; ")}.`;
|
|
88
|
+
}
|
|
89
|
+
function preStyleStillPrompt(plan, characters, stage, index) {
|
|
90
|
+
const references = characters.map((_, position) => `@image${position + (stage === "storyboards" ? 2 : 1)} is Character ${position + 1}`);
|
|
91
|
+
if (stage === "frame")
|
|
92
|
+
return `${plan.continuity}\n\n${plan.frame.prompt}\n\nReferences: ${references.join("; ")}.`;
|
|
93
|
+
references.unshift("@image1 is the full frame; keep its characters, setting and style");
|
|
94
|
+
const shot = plan.shots[index % plan.shots.length];
|
|
95
|
+
return `One ending frame. ${shot.endingPrompt ?? `Final moment: ${shot.videoPrompt}`}\n\nReferences: ${references.join("; ")}.`;
|
|
96
|
+
}
|
|
97
|
+
export async function goalStillStaleReason(engine, goal, document, plan, characters, stage, output) {
|
|
98
|
+
const cell = document.cells.find(candidate => candidate.id === output.cellId);
|
|
99
|
+
if (!cell || resolveNotebookCellArtifactId(document, cell) !== output.artifactId)
|
|
100
|
+
return "The selected output changed or was removed. Choose another version or regenerate it.";
|
|
101
|
+
if (characters.some(character => !document.cells.some(candidate => candidate.id === character.cellId && resolveNotebookCellArtifactId(document, candidate) === character.artifactId)))
|
|
102
|
+
return "A source reference changed or was removed.";
|
|
103
|
+
const attempt = goalStageAttempts(engine, goal, stage).find(item => item.index === output.index && item.artifactId === output.artifactId);
|
|
104
|
+
if (attempt?.fingerprint && attempt.fingerprint !== await goalStageFingerprint(engine, goal, plan, characters, stage, output.index))
|
|
105
|
+
return `${stage === "frame" ? "Scene" : stage === "storyboards" ? "Storyboard" : "Video"} uses older settings, prompts or references. Revise or regenerate it.`;
|
|
106
|
+
if (stage !== "frame") {
|
|
107
|
+
const frame = goal.stages.frame?.outputs[0];
|
|
108
|
+
if (!frame || await goalStillStaleReason(engine, goal, document, plan, characters, "frame", frame))
|
|
109
|
+
return "The scene has changed. Refresh it before continuing.";
|
|
110
|
+
}
|
|
111
|
+
if (stage === "videos") {
|
|
112
|
+
const indexes = [output.index, ...(plan.frameContinuity ? [output.index + plan.shots.length] : [])];
|
|
113
|
+
for (const index of indexes) {
|
|
114
|
+
const board = goal.stages.storyboards?.outputs.find(item => item.index === index);
|
|
115
|
+
if (!board || await goalStillStaleReason(engine, goal, document, plan, characters, "storyboards", board))
|
|
116
|
+
return "The storyboard has changed. Refresh it before generating video.";
|
|
117
|
+
}
|
|
118
|
+
if (attempt && !attempt.fingerprint) {
|
|
119
|
+
const step = getChainRun(engine, attempt.chainId)?.steps.find(item => item.id === attempt.stepId);
|
|
120
|
+
const expected = indexes.map(index => goal.stages.storyboards?.outputs.find(item => item.index === index)?.artifactId);
|
|
121
|
+
if (expected.some((id, index) => id !== step?.pins[index]?.artifactId))
|
|
122
|
+
return "Video uses an older storyboard. Revise or regenerate it.";
|
|
123
|
+
}
|
|
124
|
+
return attempt && attempt.basePrompt !== plan.shots[output.index]?.videoPrompt ? "Video uses older directions. Revise or regenerate it." : null;
|
|
125
|
+
}
|
|
126
|
+
if (attempt?.fingerprint)
|
|
127
|
+
return null;
|
|
128
|
+
const name = stage === "frame" ? "Full frame" : `${output.index >= plan.shots.length ? "Ending frame" : "Storyboard"} ${output.index % plan.shots.length + 1}`;
|
|
129
|
+
const run = goal.stages[stage];
|
|
130
|
+
if (stage === "storyboards" && output.index < plan.shots.length && attempt?.storyboardLayout !== (plan.storyboardLayout ?? "four-panel")) {
|
|
131
|
+
return `${name} is a legacy single-frame preview. Regenerate or revise it to create a four-panel storyboard.`;
|
|
132
|
+
}
|
|
133
|
+
const promptError = `${name} was made from an older prompt. Regenerate or revise it, or restore the prompt.`;
|
|
134
|
+
const frameError = `${name} was made from an older full frame. Regenerate the storyboards.`;
|
|
135
|
+
if (attempt) {
|
|
136
|
+
if (attempt.basePrompt !== goalStillPrompt(plan, stage, output.index))
|
|
137
|
+
return promptError;
|
|
138
|
+
if (stage === "storyboards" && attempt.frameArtifactId !== goal.stages.frame?.outputs[0]?.artifactId)
|
|
139
|
+
return frameError;
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
const source = run && [...run.previousChainIds, run.chainId].flatMap(id => getChainRun(engine, id)?.steps ?? [])
|
|
143
|
+
.find(step => step.id === (stage === "frame" ? "frame" : `storyboard${output.index + 1}`) && (step.outputs?.asset_id ?? step.outputs?.img_asset_id) === output.artifactId);
|
|
144
|
+
const frameOutput = goal.stages.frame?.outputs[0];
|
|
145
|
+
if (stage === "storyboards" && source?.pins[0]?.artifactId !== frameOutput?.artifactId)
|
|
146
|
+
return frameError;
|
|
147
|
+
const frameCell = document.cells.find(cell => cell.id === frameOutput?.cellId);
|
|
148
|
+
const compiled = stage === "frame" ? compileFrameSteps(plan, characters)[0]
|
|
149
|
+
: compileStoryboardSteps(plan, characters, frameCell ? notebookGridTag(frameCell.slot) : "", [output.index % plan.shots.length])
|
|
150
|
+
.find(step => step.id === `storyboard${output.index + 1}`);
|
|
151
|
+
return source?.params.prompt === compiled?.params.prompt || plan.style.id === "cinematic" && (source?.params.prompt === legacyStillPrompt(plan, characters, stage, output.index)
|
|
152
|
+
|| source?.params.prompt === preStyleStillPrompt(plan, characters, stage, output.index)) ? null : promptError;
|
|
153
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { firstEmptyNotebookGridSlot, notebookOccupiedSlots } from "videobook-engine/notebook-grid";
|
|
3
|
+
import { goalMediaRefSchema, goalPlanSchema, goalPlanV3Schema, goalStyleSchema, legacyGoalPlanSchema } from "./goal-plan.js";
|
|
4
|
+
import { mutateNotebook } from "./notebook-mutations.js";
|
|
5
|
+
import { arrangeGoalNotebook } from "./notebook-goal-layout.js";
|
|
6
|
+
const KEY = "application.goals.v2";
|
|
7
|
+
const LEGACY_KEY = "application.goals.v1";
|
|
8
|
+
const GOAL_TILE_LABEL = "Video goal";
|
|
9
|
+
const REMOVED_TILE_ERROR = "This goal's tile was removed from the notebook";
|
|
10
|
+
function goalStore(engine) {
|
|
11
|
+
const legacy = engine.settings.get(LEGACY_KEY) ?? {};
|
|
12
|
+
return {
|
|
13
|
+
...Object.fromEntries(Object.entries(legacy).map(([id, goal]) => [id, { ...goal, planVersion: 1, stage: "videos", stages: {} }])),
|
|
14
|
+
...(engine.settings.get(KEY) ?? {}),
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
function hasTile(goal) {
|
|
18
|
+
return typeof goal.cellId === "string";
|
|
19
|
+
}
|
|
20
|
+
export function listGoals(engine, notebookId) {
|
|
21
|
+
return Object.values(goalStore(engine))
|
|
22
|
+
.filter((goal) => goal.notebookId === notebookId && hasTile(goal))
|
|
23
|
+
.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
|
|
24
|
+
}
|
|
25
|
+
export function readGoal(engine, goalId) {
|
|
26
|
+
const goal = goalStore(engine)[goalId];
|
|
27
|
+
if (!goal || !hasTile(goal) || goal.bookId !== engine.book.get().bookId)
|
|
28
|
+
throw new Error("Goal not found in this book");
|
|
29
|
+
return goal;
|
|
30
|
+
}
|
|
31
|
+
export function saveGoal(engine, goal) {
|
|
32
|
+
const next = { ...goal, updatedAt: new Date().toISOString() };
|
|
33
|
+
const result = engine.settings.set(KEY, { ...(engine.settings.get(KEY) ?? {}), [goal.goalId]: next });
|
|
34
|
+
if (!result.ok)
|
|
35
|
+
throw new Error(result.error.message);
|
|
36
|
+
return next;
|
|
37
|
+
}
|
|
38
|
+
function estimateFrom(value) {
|
|
39
|
+
const record = value && typeof value === "object" ? value : {};
|
|
40
|
+
return {
|
|
41
|
+
usd: typeof record.usd === "number" && Number.isFinite(record.usd) ? record.usd : null,
|
|
42
|
+
warnings: Array.isArray(record.warnings) ? record.warnings.filter((entry) => typeof entry === "string") : [],
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
export function emptyGoalEstimates() {
|
|
46
|
+
return { frame: { usd: null, warnings: [] }, storyboards: { usd: null, warnings: [] }, videos: { usd: null, warnings: [] }, total: { usd: null, warnings: [] } };
|
|
47
|
+
}
|
|
48
|
+
function estimatesFrom(value) {
|
|
49
|
+
const record = value && typeof value === "object" ? value : {};
|
|
50
|
+
if (!("total" in record))
|
|
51
|
+
return { ...emptyGoalEstimates(), videos: estimateFrom(value), total: estimateFrom(value) };
|
|
52
|
+
return { frame: estimateFrom(record.frame), storyboards: estimateFrom(record.storyboards), videos: estimateFrom(record.videos), total: estimateFrom(record.total) };
|
|
53
|
+
}
|
|
54
|
+
function charactersFrom(value) {
|
|
55
|
+
if (!Array.isArray(value))
|
|
56
|
+
return [];
|
|
57
|
+
return value.filter((entry) => entry && typeof entry === "object"
|
|
58
|
+
&& ["artifactId", "cellId", "address", "label"].every(key => typeof entry[key] === "string"));
|
|
59
|
+
}
|
|
60
|
+
function mediaFrom(value) {
|
|
61
|
+
const parsed = z.array(z.unknown()).safeParse(value);
|
|
62
|
+
if (!parsed.success)
|
|
63
|
+
return [];
|
|
64
|
+
return parsed.data.flatMap(entry => {
|
|
65
|
+
const media = goalMediaRefSchema.safeParse(entry);
|
|
66
|
+
return media.success ? [media.data] : [];
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
export function goalContent(cell) {
|
|
70
|
+
const inputs = cell.inputs ?? {};
|
|
71
|
+
const plan = z.union([goalPlanV3Schema, goalPlanSchema, legacyGoalPlanSchema]).safeParse(inputs.plan);
|
|
72
|
+
const requestedStyle = goalStyleSchema.safeParse(inputs.requestedStyle);
|
|
73
|
+
const media = mediaFrom(inputs.media);
|
|
74
|
+
return {
|
|
75
|
+
brief: cell.prompt ?? "",
|
|
76
|
+
characters: charactersFrom(inputs.characters),
|
|
77
|
+
...(media.length > 0 ? { media } : {}),
|
|
78
|
+
revision: typeof inputs.revision === "number" && Number.isInteger(inputs.revision) ? inputs.revision : 0,
|
|
79
|
+
plan: plan.success ? plan.data : null,
|
|
80
|
+
...(!plan.success && requestedStyle.success ? { requestedStyle: requestedStyle.data } : {}),
|
|
81
|
+
estimate: estimatesFrom(inputs.estimate),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
function goalCellInputs(goalId, content) {
|
|
85
|
+
return { goalId, revision: content.revision, plan: content.plan, characters: content.characters, estimate: content.estimate,
|
|
86
|
+
...(content.media ? { media: content.media } : {}),
|
|
87
|
+
...(!content.plan && content.requestedStyle ? { requestedStyle: content.requestedStyle } : {}),
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function goalCellText(content) {
|
|
91
|
+
return { label: content.plan?.title ?? GOAL_TILE_LABEL, prompt: content.brief };
|
|
92
|
+
}
|
|
93
|
+
export function findGoalCell(document, goal) {
|
|
94
|
+
return document.cells.find((cell) => cell.id === goal.cellId && cell.type === "goal") ?? null;
|
|
95
|
+
}
|
|
96
|
+
export function readGoalCell(engine, goal) {
|
|
97
|
+
const notebook = engine.notebooks.read(goal.notebookId);
|
|
98
|
+
if (!notebook.ok)
|
|
99
|
+
throw new Error(notebook.error.message);
|
|
100
|
+
return findGoalCell(notebook.value, goal);
|
|
101
|
+
}
|
|
102
|
+
export function requireGoalContent(engine, goal) {
|
|
103
|
+
const cell = readGoalCell(engine, goal);
|
|
104
|
+
if (!cell)
|
|
105
|
+
throw new Error(REMOVED_TILE_ERROR);
|
|
106
|
+
return goalContent(cell);
|
|
107
|
+
}
|
|
108
|
+
export async function createGoalCell(engine, notebookId, goalId, content) {
|
|
109
|
+
const created = { cell: null };
|
|
110
|
+
const result = await mutateNotebook(engine, notebookId, "goal_create", (document) => {
|
|
111
|
+
const cell = engine.notebooks.createCell({
|
|
112
|
+
type: "goal",
|
|
113
|
+
...goalCellText(content),
|
|
114
|
+
slot: firstEmptyNotebookGridSlot(notebookOccupiedSlots(document.cells)),
|
|
115
|
+
inputs: goalCellInputs(goalId, content),
|
|
116
|
+
});
|
|
117
|
+
created.cell = cell;
|
|
118
|
+
const edges = content.characters.map((character, index) => engine.notebooks.createEdge({
|
|
119
|
+
source: character.cellId, target: cell.id, targetInput: index === 0 ? "character" : `character_${index + 1}`,
|
|
120
|
+
}));
|
|
121
|
+
const arranged = arrangeGoalNotebook({ ...document, cells: [...document.cells, cell], edges: [...document.edges, ...edges] });
|
|
122
|
+
created.cell = arranged.cells.find(candidate => candidate.id === cell.id);
|
|
123
|
+
return arranged;
|
|
124
|
+
}, { goalId });
|
|
125
|
+
if (!result.ok)
|
|
126
|
+
throw new Error(result.error.message);
|
|
127
|
+
if (!created.cell)
|
|
128
|
+
throw new Error("The goal tile could not be placed");
|
|
129
|
+
return created.cell;
|
|
130
|
+
}
|
|
131
|
+
export async function writeGoalContent(engine, goal, content) {
|
|
132
|
+
const result = await mutateNotebook(engine, goal.notebookId, "goal_plan", (document) => {
|
|
133
|
+
if (!findGoalCell(document, goal))
|
|
134
|
+
throw new Error(REMOVED_TILE_ERROR);
|
|
135
|
+
return {
|
|
136
|
+
...document,
|
|
137
|
+
cells: document.cells.map((cell) => cell.id === goal.cellId
|
|
138
|
+
? { ...cell, ...goalCellText(content), inputs: goalCellInputs(goal.goalId, content) }
|
|
139
|
+
: cell),
|
|
140
|
+
};
|
|
141
|
+
}, { goalId: goal.goalId });
|
|
142
|
+
if (!result.ok)
|
|
143
|
+
throw new Error(result.error.message);
|
|
144
|
+
}
|