@gentbajko/slopify 2.5.0 → 3.0.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/LICENSE +201 -21
- package/NOTICE +12 -0
- package/README.md +21 -40
- package/SUBTITLES.md +1 -1
- package/dist/adapter-registry.js +3 -0
- package/dist/adapters/alignment/cache.js +4 -1
- package/dist/adapters/alignment/ctc.js +25 -23
- package/dist/adapters/alignment/index.js +37 -6
- package/dist/adapters/alignment/multilingual.js +267 -0
- package/dist/adapters/alignment/protocol.js +11 -0
- package/dist/adapters/alignment/quality.js +4 -3
- package/dist/adapters/alignment/sentences.js +95 -0
- package/dist/adapters/alignment/spec.js +24 -0
- package/dist/adapters/alignment/spell.js +769 -0
- package/dist/adapters/alignment/text.js +56 -9
- package/dist/adapters/alignment/window.js +34 -30
- package/dist/adapters/alignment/worker.js +23 -21
- package/dist/adapters/explain.js +11 -11
- package/dist/adapters/host-cli/index.js +44 -5
- package/dist/adapters/host-cli/transport.js +7 -5
- package/dist/adapters/image/bytes.js +2 -2
- package/dist/adapters/image/codex-output.js +1 -1
- package/dist/adapters/image/codex.js +87 -22
- package/dist/adapters/image/fal.js +13 -5
- package/dist/adapters/image/google.js +11 -8
- package/dist/adapters/image/openai.js +14 -7
- package/dist/adapters/image/reference.js +34 -0
- package/dist/adapters/image/replicate.js +7 -2
- package/dist/adapters/image/video.js +2 -2
- package/dist/adapters/key-probes.js +36 -0
- package/dist/adapters/llm/claude-code.js +168 -32
- package/dist/adapters/llm/cli-login-error.js +1 -1
- package/dist/adapters/llm/codex-limits.js +157 -0
- package/dist/adapters/llm/codex.js +99 -12
- package/dist/adapters/llm/document-workspace.js +2 -2
- package/dist/adapters/llm/gemini-workspace.js +1 -1
- package/dist/adapters/llm/gemini.js +16 -3
- package/dist/adapters/llm/image-workspace.js +58 -0
- package/dist/adapters/llm/openrouter.js +11 -3
- package/dist/adapters/llm/run-cli.js +12 -7
- package/dist/adapters/tts/cartesia.js +10 -0
- package/dist/adapters/tts/elevenlabs.js +31 -9
- package/dist/adapters/tts/inworld-async.js +9 -5
- package/dist/adapters/tts/inworld.js +17 -3
- package/dist/adapters/tts/openai.js +3 -0
- package/dist/adapters/tts/voice-languages.js +80 -0
- package/dist/assets/fonts/noto/NotoSans-Regular.ttf +0 -0
- package/dist/assets/fonts/noto/NotoSansArabic-Regular.ttf +0 -0
- package/dist/assets/fonts/noto/NotoSansDevanagari-Regular.ttf +0 -0
- package/dist/assets/fonts/noto/NotoSansHebrew-Regular.ttf +0 -0
- package/dist/assets/fonts/noto/NotoSansThai-Regular.ttf +0 -0
- package/dist/assets/fonts/noto/OFL.txt +93 -0
- package/dist/assets/fonts/noto/SOURCE.txt +18 -0
- package/dist/assets/sample/sample-audiobook.tar +0 -0
- package/dist/assets/sample/sample-podcast.tar +0 -0
- package/dist/assets/sample/sample-project.tar +0 -0
- package/dist/catalog/merge.js +132 -0
- package/dist/catalog/registry.js +13 -13
- package/dist/catalog/schema.js +2 -0
- package/dist/catalog/store.js +147 -8
- package/dist/compose.yaml +71 -0
- package/dist/edge/autostart/docker-record.js +32 -0
- package/dist/edge/autostart/docker.js +50 -0
- package/dist/edge/autostart/index.js +78 -0
- package/dist/edge/autostart/launcher.js +176 -0
- package/dist/edge/autostart/model.js +3 -0
- package/dist/edge/autostart/native.js +210 -0
- package/dist/edge/autostart/prompt.js +66 -0
- package/dist/edge/autostart/service.js +81 -0
- package/dist/edge/cli.js +57 -51
- package/dist/edge/docker-install/activation.js +56 -0
- package/dist/edge/docker-install/apply.js +458 -0
- package/dist/edge/docker-install/engine.js +362 -0
- package/dist/edge/docker-install/run.js +154 -0
- package/dist/edge/docker-install/state.js +146 -0
- package/dist/edge/{docker-projects → docker-install}/volume.js +1 -5
- package/dist/edge/docker.js +14 -22
- package/dist/edge/host-cli.js +1 -1
- package/dist/edge/http/actions.js +32 -10
- package/dist/edge/http/app.js +58 -2
- package/dist/edge/http/auditions.js +70 -0
- package/dist/edge/http/autostart.js +37 -0
- package/dist/edge/http/channel-memory.js +92 -0
- package/dist/edge/http/channels.js +128 -0
- package/dist/edge/http/entries.js +22 -3
- package/dist/edge/http/files.js +1 -1
- package/dist/edge/http/folder-location.js +1 -1
- package/dist/edge/http/home.js +39 -0
- package/dist/edge/http/host-cli.js +29 -5
- package/dist/edge/http/narration-peaks.js +76 -0
- package/dist/edge/http/onboarding.js +152 -0
- package/dist/edge/http/open-folder.js +1 -1
- package/dist/edge/http/patch-notes.js +45 -0
- package/dist/edge/http/planning.js +4 -2
- package/dist/edge/http/project-create.js +87 -0
- package/dist/edge/http/projects.js +31 -99
- package/dist/edge/http/prompts.js +40 -3
- package/dist/edge/http/pronunciations.js +23 -4
- package/dist/edge/http/providers.js +86 -0
- package/dist/edge/http/reviews.js +121 -0
- package/dist/edge/http/revision-files.js +1 -1
- package/dist/edge/http/revisions.js +1 -1
- package/dist/edge/http/run-cost.js +25 -0
- package/dist/edge/http/schedules.js +111 -6
- package/dist/edge/http/settings.js +84 -6
- package/dist/edge/http/storage-files.js +50 -0
- package/dist/edge/http/storage.js +29 -2
- package/dist/edge/http/studio.js +207 -0
- package/dist/edge/http/style-preview.js +100 -0
- package/dist/edge/http/subtitles.js +1 -1
- package/dist/edge/http/trash.js +69 -0
- package/dist/edge/http/update.js +24 -3
- package/dist/edge/http/whats-new.js +15 -0
- package/dist/edge/http/youtube-edits.js +83 -0
- package/dist/edge/native-update.js +62 -0
- package/dist/host-cli/open-folder.js +10 -10
- package/dist/host-cli/runtime.js +9 -1
- package/dist/kernel/db/migrations/0025-automatic-reviews.sql +40 -0
- package/dist/kernel/db/migrations/0026-schedule-topic-generation.sql +23 -0
- package/dist/kernel/db/migrations/0027-run-cost.sql +58 -0
- package/dist/kernel/db/migrations/0030-automatic-retries.sql +18 -0
- package/dist/kernel/db/migrations/0031-prompt-history-and-description-edits.sql +33 -0
- package/dist/kernel/db/migrations/0032-channels.sql +65 -0
- package/dist/kernel/db/migrations/0034-script-prompts.sql +23 -0
- package/dist/kernel/db/migrations/0035-narration-aliases.sql +13 -0
- package/dist/kernel/db/migrations/0037-project-uploads.sql +8 -0
- package/dist/kernel/db/migrations/0038-voice-languages.sql +7 -0
- package/dist/kernel/db/migrations/0039-channel-essentials.sql +64 -0
- package/dist/kernel/db/migrations/0040-standalone-usage.sql +35 -0
- package/dist/kernel/paths.js +27 -6
- package/dist/kernel/pipeline.js +4 -1
- package/dist/kernel/ports/host-cli.js +122 -14
- package/dist/kernel/ports/key-probe.js +1 -0
- package/dist/kernel/ports/languages.js +157 -0
- package/dist/kernel/ports/model.js +5 -2
- package/dist/kernel/ports/narration-aliases.js +60 -0
- package/dist/kernel/ports/plan-limits.js +36 -0
- package/dist/kernel/runner/attempt.js +17 -8
- package/dist/kernel/runner/audition.js +36 -0
- package/dist/kernel/runner/graph.js +24 -5
- package/dist/kernel/runner/index.js +35 -5
- package/dist/kernel/runner/meter.js +1 -0
- package/dist/kernel/runner/providers.js +142 -7
- package/dist/kernel/runner/retry-policy.js +43 -0
- package/dist/kernel/runner/standalone.js +134 -0
- package/dist/kernel/runner/work-authority.js +28 -2
- package/dist/main.js +272 -16
- package/dist/patch-notes/0.4.2-to-1.0.md +93 -0
- package/dist/patch-notes/1.0-to-2.0.md +74 -0
- package/dist/patch-notes/2.0-to-3.0.md +257 -0
- package/dist/patch-notes/3.0.0.md +70 -0
- package/dist/patch-notes/index.json +26 -0
- package/dist/slices/admission/model.js +27 -0
- package/dist/slices/admission/repo.js +24 -4
- package/dist/slices/admission/rules.js +79 -1
- package/dist/slices/admission/schema.js +58 -1
- package/dist/slices/admission/short-mode.js +47 -0
- package/dist/slices/admission/start.js +41 -5
- package/dist/slices/article/continuation.js +2 -2
- package/dist/slices/article/provided-entries.js +2 -2
- package/dist/slices/article/run.js +6 -2
- package/dist/slices/article/segments.js +3 -3
- package/dist/slices/backups/folder.js +14 -6
- package/dist/slices/batch/index.js +7 -2
- package/dist/slices/cancel/index.js +1 -1
- package/dist/slices/channels/cast-images.js +110 -0
- package/dist/slices/channels/cast-match.js +32 -0
- package/dist/slices/channels/images.js +19 -0
- package/dist/slices/channels/model.js +5 -0
- package/dist/slices/channels/rebrand.js +100 -0
- package/dist/slices/channels/repo.js +218 -0
- package/dist/slices/channels/runs.js +129 -0
- package/dist/slices/channels/schema.js +129 -0
- package/dist/slices/channels/service.js +180 -0
- package/dist/slices/channels/studio-csv.js +110 -0
- package/dist/slices/channels/videos.js +120 -0
- package/dist/slices/checkpoints/recovery.js +10 -0
- package/dist/slices/control/index.js +2 -1
- package/dist/slices/document/fonts.js +1 -1
- package/dist/slices/document/render.js +1 -1
- package/dist/slices/episodes/related.js +90 -0
- package/dist/slices/episodes/repo.js +60 -0
- package/dist/slices/episodes/service.js +58 -0
- package/dist/slices/episodes/summarize.js +170 -0
- package/dist/slices/estimate/index.js +109 -28
- package/dist/slices/estimate/requests.js +60 -2
- package/dist/slices/fixes/rules.js +73 -0
- package/dist/slices/fonts/coverage.js +82 -0
- package/dist/slices/fonts/sfnt.js +74 -0
- package/dist/slices/images/run.js +8 -5
- package/dist/slices/images/scale.js +84 -0
- package/dist/slices/library/diff.js +122 -0
- package/dist/slices/library/history.js +100 -0
- package/dist/slices/library/model.js +3 -0
- package/dist/slices/library/photorealistic.js +49 -0
- package/dist/slices/library/repo.js +19 -14
- package/dist/slices/library/save.js +62 -12
- package/dist/slices/library/slots.js +7 -1
- package/dist/slices/library/used-by.js +153 -0
- package/dist/slices/loudness/level-pieces.js +41 -0
- package/dist/slices/loudness/loudnorm.js +164 -0
- package/dist/slices/loudness/model.js +153 -0
- package/dist/slices/model-upkeep/model.js +10 -0
- package/dist/slices/model-upkeep/switch.js +217 -0
- package/dist/slices/model-upkeep/usage.js +183 -0
- package/dist/slices/narration/aliases-library.js +31 -0
- package/dist/slices/narration/aliases-schema.js +53 -0
- package/dist/slices/narration/aliases.js +49 -0
- package/dist/slices/narration/blocks.js +352 -0
- package/dist/slices/narration/chunk.js +19 -7
- package/dist/slices/narration/concat.js +2 -2
- package/dist/slices/narration/describe.js +45 -0
- package/dist/slices/narration/pauses-model.js +63 -0
- package/dist/slices/narration/pauses.js +269 -0
- package/dist/slices/narration/peaks-model.js +1 -0
- package/dist/slices/narration/peaks.js +94 -0
- package/dist/slices/narration/preparation.js +21 -3
- package/dist/slices/narration/pronunciation-chunks.js +3 -3
- package/dist/slices/narration/pronunciation.js +72 -25
- package/dist/slices/narration/run.js +6 -6
- package/dist/slices/narration/shared-glossary.js +1 -1
- package/dist/slices/narration/steering.js +15 -4
- package/dist/slices/notifications/notifier.js +21 -3
- package/dist/slices/notifications/rules.js +22 -1
- package/dist/slices/onboarding/copy.js +143 -0
- package/dist/slices/onboarding/first-run.js +46 -0
- package/dist/slices/onboarding/install.js +119 -0
- package/dist/slices/onboarding/model.js +64 -0
- package/dist/slices/onboarding/packs.js +491 -0
- package/dist/slices/onboarding/quick-short.js +129 -0
- package/dist/slices/onboarding/sample.js +132 -0
- package/dist/slices/onboarding/state.js +68 -0
- package/dist/slices/onboarding/template.js +73 -0
- package/dist/slices/patch-notes/library.js +73 -0
- package/dist/slices/patch-notes/seen.js +77 -0
- package/dist/slices/play-drafts/convert.js +125 -6
- package/dist/slices/play-drafts/readiness.js +3 -0
- package/dist/slices/play-drafts/repo.js +2 -0
- package/dist/slices/play-drafts/review-inputs.js +20 -3
- package/dist/slices/play-drafts/schema.js +89 -0
- package/dist/slices/play-drafts/service.js +4 -1
- package/dist/slices/play-drafts/start.js +43 -18
- package/dist/slices/project-templates/from-project.js +50 -4
- package/dist/slices/project-templates/one-off.js +26 -0
- package/dist/slices/project-templates/repo.js +2 -1
- package/dist/slices/project-templates/service.js +15 -4
- package/dist/slices/project-templates/setup.js +18 -2
- package/dist/slices/rebuild/admission-repo.js +1 -1
- package/dist/slices/rebuild/model.js +6 -0
- package/dist/slices/rebuild/preview-details.js +46 -3
- package/dist/slices/rebuild/preview-plan.js +13 -6
- package/dist/slices/rebuild/recipe-audio-parts.js +40 -7
- package/dist/slices/rebuild/recipe-audio.js +66 -12
- package/dist/slices/rebuild/recipe-build.js +8 -4
- package/dist/slices/rebuild/recipe-cast.js +18 -0
- package/dist/slices/rebuild/recipe-checkpoints.js +11 -9
- package/dist/slices/rebuild/recipe-describe.js +93 -0
- package/dist/slices/rebuild/recipe-edit.js +13 -1
- package/dist/slices/rebuild/recipe-exports.js +62 -8
- package/dist/slices/rebuild/recipe-input-schema.js +35 -0
- package/dist/slices/rebuild/recipe-legacy.js +9 -0
- package/dist/slices/rebuild/recipe-loudness.js +45 -0
- package/dist/slices/rebuild/recipe-model.js +25 -6
- package/dist/slices/rebuild/recipe-pauses.js +7 -0
- package/dist/slices/rebuild/recipe-preparation.js +3 -3
- package/dist/slices/rebuild/recipe-provider-choice.js +11 -1
- package/dist/slices/rebuild/recipe-reference.js +15 -1
- package/dist/slices/rebuild/recipe-reviews.js +117 -0
- package/dist/slices/rebuild/recipe-save.js +4 -1
- package/dist/slices/rebuild/recipe-shorts.js +23 -3
- package/dist/slices/rebuild/recipe-text.js +114 -19
- package/dist/slices/rebuild/recipe-validation.js +14 -2
- package/dist/slices/rebuild/recipe-visual.js +96 -33
- package/dist/slices/rebuild/recipe-voices.js +286 -0
- package/dist/slices/rebuild/recipe-work.js +77 -6
- package/dist/slices/rebuild/recipe-youtube.js +2 -0
- package/dist/slices/rebuild/recovery-conflict.js +7 -3
- package/dist/slices/rebuild/recovery-model.js +3 -0
- package/dist/slices/rebuild/recovery-selection.js +28 -2
- package/dist/slices/rebuild/recovery.js +35 -17
- package/dist/slices/rebuild/repo.js +3 -3
- package/dist/slices/rebuild/retry.js +18 -0
- package/dist/slices/rebuild/review-redo.js +110 -0
- package/dist/slices/rebuild/runtime-actions.js +5 -0
- package/dist/slices/rebuild/runtime-admission.js +4 -1
- package/dist/slices/rebuild/runtime-animate.js +4 -4
- package/dist/slices/rebuild/runtime-article.js +5 -5
- package/dist/slices/rebuild/runtime-document.js +4 -4
- package/dist/slices/rebuild/runtime-export-bed.js +43 -0
- package/dist/slices/rebuild/runtime-export-edit.js +70 -11
- package/dist/slices/rebuild/runtime-export-inputs.js +52 -10
- package/dist/slices/rebuild/runtime-export-short.js +85 -0
- package/dist/slices/rebuild/runtime-export.js +84 -19
- package/dist/slices/rebuild/runtime-figure-card.js +87 -0
- package/dist/slices/rebuild/runtime-image.js +21 -2
- package/dist/slices/rebuild/runtime-local.js +148 -24
- package/dist/slices/rebuild/runtime-materialize.js +8 -0
- package/dist/slices/rebuild/runtime-narration-reuse.js +2 -1
- package/dist/slices/rebuild/runtime-narration-text.js +7 -7
- package/dist/slices/rebuild/runtime-pictures.js +28 -0
- package/dist/slices/rebuild/runtime-piece-label.js +27 -0
- package/dist/slices/rebuild/runtime-provider.js +126 -18
- package/dist/slices/rebuild/runtime-publication.js +21 -5
- package/dist/slices/rebuild/runtime-review.js +237 -0
- package/dist/slices/rebuild/runtime-run.js +17 -11
- package/dist/slices/rebuild/runtime-shorts.js +44 -17
- package/dist/slices/rebuild/runtime-store.js +39 -10
- package/dist/slices/rebuild/runtime-subtitles.js +72 -19
- package/dist/slices/rebuild/runtime-voices.js +103 -0
- package/dist/slices/rebuild/runtime-youtube.js +7 -6
- package/dist/slices/rebuild/soften.js +49 -0
- package/dist/slices/rebuild/transition-repo.js +9 -2
- package/dist/slices/research/run.js +4 -4
- package/dist/slices/research/synthesis.js +2 -2
- package/dist/slices/reviews/model.js +105 -0
- package/dist/slices/reviews/outcome.js +22 -0
- package/dist/slices/reviews/repo.js +106 -0
- package/dist/slices/reviews/rules.js +63 -0
- package/dist/slices/reviews/verdict.js +71 -0
- package/dist/slices/reviews/view.js +30 -0
- package/dist/slices/revisions/adopt-content.js +5 -2
- package/dist/slices/revisions/adopt.js +3 -1
- package/dist/slices/revisions/downloads.js +7 -1
- package/dist/slices/revisions/image-plan.js +183 -0
- package/dist/slices/revisions/mutation-assets.js +10 -0
- package/dist/slices/revisions/mutation-cues.js +71 -0
- package/dist/slices/revisions/mutation-request.js +2 -1
- package/dist/slices/revisions/mutations.js +97 -3
- package/dist/slices/revisions/schema.js +11 -1
- package/dist/slices/run-cost/limits.js +128 -0
- package/dist/slices/run-cost/meter.js +47 -0
- package/dist/slices/run-cost/panel.js +234 -0
- package/dist/slices/run-cost/pricing.js +92 -0
- package/dist/slices/run-cost/week.js +108 -0
- package/dist/slices/schedules/agenda.js +158 -0
- package/dist/slices/schedules/repo.js +58 -18
- package/dist/slices/schedules/scheduler.js +67 -16
- package/dist/slices/schedules/schema.js +138 -1
- package/dist/slices/schedules/service.js +43 -4
- package/dist/slices/schedules/similar.js +90 -0
- package/dist/slices/schedules/topic-list.js +163 -0
- package/dist/slices/schedules/topics.js +422 -0
- package/dist/slices/settings/first-run.js +102 -0
- package/dist/slices/settings/health.js +190 -0
- package/dist/slices/settings/key-guides.js +128 -0
- package/dist/slices/settings/key-test.js +85 -0
- package/dist/slices/settings/model.js +6 -1
- package/dist/slices/settings/playback.js +15 -0
- package/dist/slices/settings/repo.js +17 -3
- package/dist/slices/settings/voices.js +64 -4
- package/dist/slices/settings/whats-new.js +64 -0
- package/dist/slices/shorts/captions.js +9 -0
- package/dist/slices/shorts/pick.js +3 -3
- package/dist/slices/shorts/prompts.js +1 -1
- package/dist/slices/shorts/render.js +54 -5
- package/dist/slices/storage/asset-name.js +3 -0
- package/dist/slices/storage/backup-export.js +48 -9
- package/dist/slices/storage/backup-format.js +38 -1
- package/dist/slices/storage/backup-import.js +191 -19
- package/dist/slices/storage/delete-project.js +7 -4
- package/dist/slices/storage/documents.js +79 -0
- package/dist/slices/storage/files-location.js +531 -0
- package/dist/slices/storage/layout.js +14 -4
- package/dist/slices/storage/model.js +11 -0
- package/dist/slices/storage/portable.js +92 -12
- package/dist/slices/storage/reconcile.js +14 -1
- package/dist/slices/storage/repo.js +4 -1
- package/dist/slices/storage/schema.js +11 -0
- package/dist/slices/storage/trim.js +146 -0
- package/dist/slices/studio/disclosure.js +74 -0
- package/dist/slices/studio/model.js +28 -0
- package/dist/slices/studio/pack.js +209 -0
- package/dist/slices/studio/settings.js +133 -0
- package/dist/slices/style-preview/images.js +61 -0
- package/dist/slices/style-preview/render.js +161 -0
- package/dist/slices/style-preview/schema.js +45 -0
- package/dist/slices/style-preview/service.js +93 -0
- package/dist/slices/style-preview/settings.js +89 -0
- package/dist/slices/subtitles/captions.js +42 -9
- package/dist/slices/subtitles/model.js +22 -0
- package/dist/slices/subtitles/prepare.js +27 -16
- package/dist/slices/subtitles/transcript.js +1 -1
- package/dist/slices/thumbnail/run.js +7 -7
- package/dist/slices/trash/model.js +25 -0
- package/dist/slices/trash/service.js +273 -0
- package/dist/slices/uploads/repo.js +20 -0
- package/dist/slices/video/ambient-bed-schema.js +15 -0
- package/dist/slices/video/ambient-bed.js +95 -0
- package/dist/slices/video/ambient-mix.js +72 -0
- package/dist/slices/video/audio-inputs.js +2 -2
- package/dist/slices/video/cards.js +5 -2
- package/dist/slices/video/edit-list.js +23 -2
- package/dist/slices/video/edit-settings.js +13 -3
- package/dist/slices/video/ffmpeg.js +63 -9
- package/dist/slices/video/figure-card.js +492 -0
- package/dist/slices/video/figure-spans.js +51 -0
- package/dist/slices/video/plan.js +125 -13
- package/dist/slices/video/run.js +14 -12
- package/dist/slices/video/slideshow.js +39 -4
- package/dist/slices/voices/attribution.js +69 -0
- package/dist/slices/voices/audio-files.js +82 -0
- package/dist/slices/voices/audition.js +25 -0
- package/dist/slices/voices/cast.js +56 -0
- package/dist/slices/voices/grouping.js +49 -0
- package/dist/slices/voices/join.js +35 -0
- package/dist/slices/voices/languages.js +25 -0
- package/dist/slices/voices/model.js +179 -0
- package/dist/slices/voices/palette.js +26 -0
- package/dist/slices/voices/panel.js +91 -0
- package/dist/slices/voices/portraits.js +55 -0
- package/dist/slices/voices/script.js +136 -0
- package/dist/slices/voices/timing.js +58 -0
- package/dist/slices/youtube/answer.js +1 -1
- package/dist/slices/youtube/chapters.js +126 -0
- package/dist/slices/youtube/edits-repo.js +69 -0
- package/dist/slices/youtube/edits.js +89 -0
- package/dist/slices/youtube/placeholders.js +98 -0
- package/dist/slices/youtube/transcript.js +11 -4
- package/dist/updater/service.js +66 -21
- package/dist/web/assets/index-CUA2sUxU.css +1 -0
- package/dist/web/assets/index-CX590kE-.js +303 -0
- package/dist/web/assets/jetbrains-mono-cyrillic-400-normal-BEIGL1Tu.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-cyrillic-400-normal-ugxPyKxw.woff +0 -0
- package/dist/web/assets/jetbrains-mono-greek-400-normal-B9oWc5Lo.woff +0 -0
- package/dist/web/assets/jetbrains-mono-greek-400-normal-C190GLew.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-latin-400-normal-6-qcROiO.woff +0 -0
- package/dist/web/assets/jetbrains-mono-latin-400-normal-V6pRDFza.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-latin-ext-400-normal-Bc8Ftmh3.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-latin-ext-400-normal-fXTG6kC5.woff +0 -0
- package/dist/web/assets/jetbrains-mono-vietnamese-400-normal-CqNFfHCs.woff +0 -0
- package/dist/web/assets/{pdf-BLF2i8c2.js → pdf-BG8n_uc5.js} +1 -1
- package/dist/web/index.html +2 -2
- package/package.json +4 -4
- package/dist/edge/docker-launch.js +0 -81
- package/dist/edge/docker-projects/activation.js +0 -35
- package/dist/edge/docker-projects/claims.js +0 -85
- package/dist/edge/docker-projects/committed.js +0 -40
- package/dist/edge/docker-projects/engine.js +0 -461
- package/dist/edge/docker-projects/install.js +0 -254
- package/dist/edge/docker-projects/prune.js +0 -66
- package/dist/edge/docker-projects/recover.js +0 -100
- package/dist/edge/docker-projects/state.js +0 -225
- package/dist/web/assets/index-CktpxlJd.js +0 -171
- package/dist/web/assets/index-DB-vOnGU.css +0 -1
- package/scripts/docker-run.sh +0 -3
- /package/dist/edge/{docker-projects → docker-install}/tree.js +0 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
-- Every save of a Library prompt or intro/outro keeps a version, so History can show and
|
|
2
|
+
-- restore any of them. One table serves both libraries: `item_kind` says which, `kind` holds the
|
|
3
|
+
-- prompt's kind or the entry's category, and `mode` the entry's mode (NULL for a prompt). No
|
|
4
|
+
-- foreign key: the row it belongs to lives in one of two tables, and the save path deletes the
|
|
5
|
+
-- versions with the prompt or entry.
|
|
6
|
+
CREATE TABLE library_versions (
|
|
7
|
+
item_kind TEXT NOT NULL CHECK(item_kind IN ('prompt','entry')),
|
|
8
|
+
item_id TEXT NOT NULL,
|
|
9
|
+
version INTEGER NOT NULL CHECK(version >= 1),
|
|
10
|
+
kind TEXT NOT NULL,
|
|
11
|
+
mode TEXT CHECK(mode IS NULL OR mode IN ('text','llm')),
|
|
12
|
+
name TEXT NOT NULL,
|
|
13
|
+
body TEXT NOT NULL,
|
|
14
|
+
author TEXT NOT NULL,
|
|
15
|
+
restored_from INTEGER,
|
|
16
|
+
created_at TEXT NOT NULL,
|
|
17
|
+
PRIMARY KEY(item_kind,item_id,version)
|
|
18
|
+
);
|
|
19
|
+
-- What is saved today becomes version 1 of each.
|
|
20
|
+
INSERT INTO library_versions (item_kind,item_id,version,kind,mode,name,body,author,restored_from,created_at)
|
|
21
|
+
SELECT 'prompt',id,1,kind,NULL,name,body,'you',NULL,updated_at FROM prompts;
|
|
22
|
+
INSERT INTO library_versions (item_kind,item_id,version,kind,mode,name,body,author,restored_from,created_at)
|
|
23
|
+
SELECT 'entry',id,1,category,mode,name,body,'you',NULL,updated_at FROM entries;
|
|
24
|
+
-- The project page's hand edits to the YouTube description, chapters, hashtags and tags. Each
|
|
25
|
+
-- field keeps the user's text and the generated text it was edited from, so a regenerated
|
|
26
|
+
-- description can tell whether the user changed that field. `links_json` holds this project's
|
|
27
|
+
-- own channel links (such as "Previous video"), which win over the Settings list.
|
|
28
|
+
CREATE TABLE youtube_description_edits (
|
|
29
|
+
project_id TEXT PRIMARY KEY REFERENCES projects(id) ON DELETE CASCADE,
|
|
30
|
+
fields_json TEXT NOT NULL CHECK(json_valid(fields_json)),
|
|
31
|
+
links_json TEXT NOT NULL CHECK(json_valid(links_json)),
|
|
32
|
+
updated_at TEXT NOT NULL
|
|
33
|
+
);
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
-- Channels: the brand kit, the cast library and the series brief that templates, schedules
|
|
2
|
+
-- and projects belong to. Every install gets one default channel, "My channel", with a fixed
|
|
3
|
+
-- id so a backup made on one install names the same default on another, and everything that
|
|
4
|
+
-- exists moves into it. Nothing about a project's config changes, so no fingerprint does.
|
|
5
|
+
--
|
|
6
|
+
-- A template's channel is a plain column and a project's is a row of project_channels, neither
|
|
7
|
+
-- with a foreign key to channels: a backup can bring in a row naming a channel this install
|
|
8
|
+
-- never had, and such a row (like none at all) reads as the default channel. The projects
|
|
9
|
+
-- table itself is left as it is. A schedule's channel is its template's.
|
|
10
|
+
CREATE TABLE channels (
|
|
11
|
+
id TEXT PRIMARY KEY,
|
|
12
|
+
name TEXT NOT NULL CHECK(length(trim(name)) BETWEEN 1 AND 200),
|
|
13
|
+
is_default INTEGER NOT NULL DEFAULT 0 CHECK(is_default IN (0,1)),
|
|
14
|
+
brand_json TEXT NOT NULL DEFAULT '{}' CHECK(json_valid(brand_json)),
|
|
15
|
+
series_brief TEXT NOT NULL DEFAULT '',
|
|
16
|
+
version INTEGER NOT NULL DEFAULT 1 CHECK(version >= 1),
|
|
17
|
+
created_at TEXT NOT NULL,
|
|
18
|
+
updated_at TEXT NOT NULL
|
|
19
|
+
);
|
|
20
|
+
CREATE UNIQUE INDEX channels_one_default ON channels(is_default) WHERE is_default = 1;
|
|
21
|
+
INSERT INTO channels (id, name, is_default, created_at, updated_at) VALUES (
|
|
22
|
+
'00000000-0000-4000-8000-000000000001', 'My channel', 1,
|
|
23
|
+
strftime('%Y-%m-%dT%H:%M:%fZ', 'now'), strftime('%Y-%m-%dT%H:%M:%fZ', 'now')
|
|
24
|
+
);
|
|
25
|
+
-- The characters, creatures, places and objects a channel keeps drawing the same way.
|
|
26
|
+
CREATE TABLE cast_members (
|
|
27
|
+
id TEXT PRIMARY KEY,
|
|
28
|
+
channel_id TEXT NOT NULL REFERENCES channels(id) ON DELETE CASCADE,
|
|
29
|
+
kind TEXT NOT NULL CHECK(kind IN ('character','creature','place','object')),
|
|
30
|
+
name TEXT NOT NULL CHECK(length(trim(name)) BETWEEN 1 AND 200),
|
|
31
|
+
aliases_json TEXT NOT NULL DEFAULT '[]' CHECK(json_valid(aliases_json)),
|
|
32
|
+
description TEXT NOT NULL DEFAULT '',
|
|
33
|
+
version INTEGER NOT NULL DEFAULT 1 CHECK(version >= 1),
|
|
34
|
+
created_at TEXT NOT NULL,
|
|
35
|
+
updated_at TEXT NOT NULL
|
|
36
|
+
);
|
|
37
|
+
CREATE INDEX cast_members_channel ON cast_members(channel_id);
|
|
38
|
+
-- Picture bytes by content hash: cast reference images and the brand kit's end screen image.
|
|
39
|
+
-- A project names the hashes it was started with, so a row is never removed while it may be
|
|
40
|
+
-- named; the bytes are in the database so every database backup carries them.
|
|
41
|
+
CREATE TABLE image_blobs (
|
|
42
|
+
sha256 TEXT PRIMARY KEY,
|
|
43
|
+
mime TEXT NOT NULL CHECK(mime IN ('image/png','image/jpeg')),
|
|
44
|
+
bytes BLOB NOT NULL,
|
|
45
|
+
created_at TEXT NOT NULL
|
|
46
|
+
);
|
|
47
|
+
CREATE TABLE cast_images (
|
|
48
|
+
id TEXT PRIMARY KEY,
|
|
49
|
+
member_id TEXT NOT NULL REFERENCES cast_members(id) ON DELETE CASCADE,
|
|
50
|
+
source TEXT NOT NULL CHECK(source IN ('upload','generate')),
|
|
51
|
+
prompt TEXT,
|
|
52
|
+
state TEXT NOT NULL CHECK(state IN ('ready','generating','failed')),
|
|
53
|
+
error TEXT,
|
|
54
|
+
sha256 TEXT REFERENCES image_blobs(sha256),
|
|
55
|
+
created_at TEXT NOT NULL
|
|
56
|
+
);
|
|
57
|
+
CREATE INDEX cast_images_member ON cast_images(member_id);
|
|
58
|
+
ALTER TABLE project_templates ADD COLUMN channel_id TEXT;
|
|
59
|
+
CREATE TABLE project_channels (
|
|
60
|
+
project_id TEXT PRIMARY KEY REFERENCES projects(id) ON DELETE CASCADE,
|
|
61
|
+
channel_id TEXT NOT NULL
|
|
62
|
+
);
|
|
63
|
+
UPDATE project_templates SET channel_id = '00000000-0000-4000-8000-000000000001';
|
|
64
|
+
INSERT INTO project_channels (project_id, channel_id)
|
|
65
|
+
SELECT id, '00000000-0000-4000-8000-000000000001' FROM projects;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
-- Multiple voices.
|
|
2
|
+
--
|
|
3
|
+
-- Library prompts of the new "script" kind: what a multi-voice run (audiobook, podcast, radio
|
|
4
|
+
-- drama, interview) asks the text model for in place of an article - speaker turns. SQLite
|
|
5
|
+
-- cannot change a CHECK in place, so the table is copied into one whose CHECK lists the new
|
|
6
|
+
-- kind, like 0025 did for "review".
|
|
7
|
+
CREATE TABLE prompts_script_upgrade (
|
|
8
|
+
id TEXT PRIMARY KEY,
|
|
9
|
+
kind TEXT NOT NULL CHECK (kind IN ('article','image','thumbnail','narration','description','shorts','review','script')),
|
|
10
|
+
name TEXT NOT NULL,
|
|
11
|
+
body TEXT NOT NULL,
|
|
12
|
+
slots TEXT NOT NULL,
|
|
13
|
+
updated_at TEXT NOT NULL
|
|
14
|
+
);
|
|
15
|
+
INSERT INTO prompts_script_upgrade (id,kind,name,body,slots,updated_at)
|
|
16
|
+
SELECT id,kind,name,body,slots,updated_at FROM prompts;
|
|
17
|
+
DROP TABLE prompts;
|
|
18
|
+
ALTER TABLE prompts_script_upgrade RENAME TO prompts;
|
|
19
|
+
CREATE UNIQUE INDEX prompts_name ON prompts(kind,lower(name));
|
|
20
|
+
-- A cast member's voice: provider, model, voice, pace and pronunciations, so a character or a
|
|
21
|
+
-- channel's host sounds the same in every episode. NULL is no voice, which every member saved
|
|
22
|
+
-- before this has.
|
|
23
|
+
ALTER TABLE cast_members ADD COLUMN voice_json TEXT CHECK (voice_json IS NULL OR json_valid(voice_json));
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
-- Library → Aliases: words the narrator says differently from how they are written ("Dr." as
|
|
2
|
+
-- "Doctor"). A project keeps its own copy of the list it started with, so nothing references
|
|
3
|
+
-- these rows and editing them never changes a project behind its back. `position` is the
|
|
4
|
+
-- order the editor shows them in.
|
|
5
|
+
CREATE TABLE narration_aliases (
|
|
6
|
+
id TEXT PRIMARY KEY,
|
|
7
|
+
position INTEGER NOT NULL,
|
|
8
|
+
written TEXT NOT NULL CHECK (length(trim(written)) > 0),
|
|
9
|
+
spoken TEXT NOT NULL CHECK (length(trim(spoken)) > 0),
|
|
10
|
+
whole_word INTEGER NOT NULL CHECK (whole_word IN (0, 1)),
|
|
11
|
+
case_sensitive INTEGER NOT NULL CHECK (case_sensitive IN (0, 1)),
|
|
12
|
+
updated_at TEXT NOT NULL
|
|
13
|
+
);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
-- "Mark uploaded" on Home: the person says a finished video is on YouTube, so it leaves Ready
|
|
2
|
+
-- to upload. A row of its own rather than a projects column, like project_channels: nothing
|
|
3
|
+
-- about the project's config changes, so no fingerprint does, and deleting the project takes
|
|
4
|
+
-- the row with it.
|
|
5
|
+
CREATE TABLE project_uploads (
|
|
6
|
+
project_id TEXT PRIMARY KEY REFERENCES projects(id) ON DELETE CASCADE,
|
|
7
|
+
uploaded_at TEXT NOT NULL
|
|
8
|
+
);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
-- Other languages.
|
|
2
|
+
--
|
|
3
|
+
-- The languages a saved voice speaks, as a JSON array of primary language codes (["es"]):
|
|
4
|
+
-- looked up from the provider when the voice is added, or typed in Settings → Voices. Play
|
|
5
|
+
-- lists a project's voices by it. NULL is unknown, which every voice saved before this is,
|
|
6
|
+
-- and an unknown voice is offered for every language.
|
|
7
|
+
ALTER TABLE voices ADD COLUMN languages_json TEXT CHECK (languages_json IS NULL OR json_valid(languages_json));
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
-- Channel essentials.
|
|
2
|
+
--
|
|
3
|
+
-- Trash: deleting a project, a Library prompt or intro/outro, or a template now only stamps
|
|
4
|
+
-- `deleted_at`; Settings → Trash lists the stamped rows for 30 days, and a daily purge removes
|
|
5
|
+
-- them for good. Every list and lookup skips stamped rows. The name indexes only count rows
|
|
6
|
+
-- that are not in the trash, so a name can be reused while the old one waits there. A later
|
|
7
|
+
-- migration that rebuilds one of these tables must carry `deleted_at` over.
|
|
8
|
+
--
|
|
9
|
+
-- A project's stamp lives in its own table rather than a column: the projects table is read
|
|
10
|
+
-- and written positionally in many places, and a project has no name index to relax.
|
|
11
|
+
CREATE TABLE project_trash (
|
|
12
|
+
project_id TEXT PRIMARY KEY REFERENCES projects(id) ON DELETE CASCADE,
|
|
13
|
+
deleted_at TEXT NOT NULL
|
|
14
|
+
);
|
|
15
|
+
ALTER TABLE prompts ADD COLUMN deleted_at TEXT;
|
|
16
|
+
ALTER TABLE entries ADD COLUMN deleted_at TEXT;
|
|
17
|
+
ALTER TABLE project_templates ADD COLUMN deleted_at TEXT;
|
|
18
|
+
DROP INDEX prompts_name;
|
|
19
|
+
CREATE UNIQUE INDEX prompts_name ON prompts(kind,lower(name)) WHERE deleted_at IS NULL;
|
|
20
|
+
DROP INDEX entries_name;
|
|
21
|
+
CREATE UNIQUE INDEX entries_name ON entries(category,lower(name)) WHERE deleted_at IS NULL;
|
|
22
|
+
-- A schedule already kept a `deleted_at` (0010: its history outlives it). `purged_at` marks one
|
|
23
|
+
-- that has left the trash; every schedule deleted before the trash existed counts as left.
|
|
24
|
+
ALTER TABLE schedules ADD COLUMN purged_at TEXT;
|
|
25
|
+
UPDATE schedules SET purged_at = deleted_at WHERE deleted_at IS NOT NULL;
|
|
26
|
+
|
|
27
|
+
-- Episode memory: a short summary each finished project leaves on its channel, read back into
|
|
28
|
+
-- the article and script prompts of later related episodes while the channel's setting is on.
|
|
29
|
+
-- No foreign key to projects: the memory outlives the project it came from.
|
|
30
|
+
CREATE TABLE episode_memories (
|
|
31
|
+
id TEXT PRIMARY KEY,
|
|
32
|
+
channel_id TEXT NOT NULL REFERENCES channels(id) ON DELETE CASCADE,
|
|
33
|
+
project_id TEXT NOT NULL,
|
|
34
|
+
title TEXT NOT NULL,
|
|
35
|
+
summary TEXT NOT NULL CHECK(length(trim(summary)) > 0),
|
|
36
|
+
cast_json TEXT NOT NULL DEFAULT '[]' CHECK(json_valid(cast_json)),
|
|
37
|
+
source TEXT NOT NULL CHECK(source IN ('generated','edited')),
|
|
38
|
+
created_at TEXT NOT NULL,
|
|
39
|
+
updated_at TEXT NOT NULL
|
|
40
|
+
);
|
|
41
|
+
CREATE UNIQUE INDEX episode_memories_project ON episode_memories(project_id);
|
|
42
|
+
CREATE INDEX episode_memories_channel ON episode_memories(channel_id, created_at);
|
|
43
|
+
-- Off for every channel that exists; a channel made from now on starts with it on. A fresh
|
|
44
|
+
-- install (no project yet) counts its default channel as new.
|
|
45
|
+
ALTER TABLE channels ADD COLUMN episode_memory INTEGER NOT NULL DEFAULT 0 CHECK(episode_memory IN (0,1));
|
|
46
|
+
UPDATE channels SET episode_memory = 1 WHERE NOT EXISTS (SELECT 1 FROM projects);
|
|
47
|
+
-- YouTube's "Altered or synthetic content" answer Studio prep gives: 'auto' follows the rule in
|
|
48
|
+
-- slices/studio/disclosure.ts, 'yes' and 'no' override it for the channel.
|
|
49
|
+
ALTER TABLE channels ADD COLUMN ai_disclosure TEXT NOT NULL DEFAULT 'auto' CHECK(ai_disclosure IN ('auto','yes','no'));
|
|
50
|
+
|
|
51
|
+
-- The channel's videos made before (or outside) Slopify: titles pasted or imported from a
|
|
52
|
+
-- YouTube Studio CSV, so topic suggestions and duplicate checks skip them too.
|
|
53
|
+
CREATE TABLE channel_videos (
|
|
54
|
+
id TEXT PRIMARY KEY,
|
|
55
|
+
channel_id TEXT NOT NULL REFERENCES channels(id) ON DELETE CASCADE,
|
|
56
|
+
title TEXT NOT NULL CHECK(length(trim(title)) BETWEEN 1 AND 500),
|
|
57
|
+
created_at TEXT NOT NULL
|
|
58
|
+
);
|
|
59
|
+
CREATE UNIQUE INDEX channel_videos_title ON channel_videos(channel_id, lower(title));
|
|
60
|
+
|
|
61
|
+
-- Episode memory (appended): what a generated summary was made from, a SHA-256 of the prompt
|
|
62
|
+
-- version, title and article text, so finishing the same article again asks no LLM. A summary
|
|
63
|
+
-- the user edited is never replaced by a later finish.
|
|
64
|
+
ALTER TABLE episode_memories ADD COLUMN recipe TEXT;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
-- What every successful provider call made outside a project used and cost: a schedule's
|
|
2
|
+
-- topic generation, a channel's episode summary and its cast pictures. provider_usage cannot
|
|
3
|
+
-- hold them, since each of its rows belongs to a project. Priced the same way when the call
|
|
4
|
+
-- lands. There is no link to the schedule or channel: deleting one keeps what it cost this
|
|
5
|
+
-- week. `channel_id` is the channel the call was made for, resolved when it landed, for Home's
|
|
6
|
+
-- channel filter. A CLI's plan windows reported around the call ride along (`account`,
|
|
7
|
+
-- `reading_json`), so Home's plan standings read them beside a project's.
|
|
8
|
+
CREATE TABLE standalone_usage (
|
|
9
|
+
id TEXT PRIMARY KEY,
|
|
10
|
+
owner_kind TEXT NOT NULL CHECK(owner_kind IN ('schedule','channel')),
|
|
11
|
+
owner_id TEXT NOT NULL,
|
|
12
|
+
channel_id TEXT NOT NULL,
|
|
13
|
+
purpose TEXT NOT NULL,
|
|
14
|
+
kind TEXT NOT NULL CHECK(kind IN ('llm','tts','image','video')),
|
|
15
|
+
provider TEXT NOT NULL,
|
|
16
|
+
model TEXT NOT NULL,
|
|
17
|
+
tokens_in INTEGER,
|
|
18
|
+
tokens_out INTEGER,
|
|
19
|
+
tokens_cached INTEGER,
|
|
20
|
+
characters INTEGER,
|
|
21
|
+
images INTEGER,
|
|
22
|
+
seconds REAL,
|
|
23
|
+
size TEXT,
|
|
24
|
+
quality TEXT,
|
|
25
|
+
wall_ms INTEGER NOT NULL,
|
|
26
|
+
on_plan INTEGER NOT NULL DEFAULT 0 CHECK(on_plan IN (0,1)),
|
|
27
|
+
cost REAL,
|
|
28
|
+
api_model TEXT,
|
|
29
|
+
api_cost REAL,
|
|
30
|
+
price_json TEXT CHECK(price_json IS NULL OR json_valid(price_json)),
|
|
31
|
+
account TEXT,
|
|
32
|
+
reading_json TEXT CHECK(reading_json IS NULL OR json_valid(reading_json)),
|
|
33
|
+
created_at TEXT NOT NULL
|
|
34
|
+
);
|
|
35
|
+
CREATE INDEX standalone_usage_created ON standalone_usage(created_at);
|
package/dist/kernel/paths.js
CHANGED
|
@@ -1,18 +1,38 @@
|
|
|
1
1
|
import { chmodSync, mkdirSync } from "node:fs";
|
|
2
2
|
import { join, resolve } from "node:path";
|
|
3
|
-
export function layout(dataDir) {
|
|
3
|
+
export function layout(dataDir, files) {
|
|
4
4
|
const root = resolve(dataDir);
|
|
5
|
+
const projects = join(root, "projects");
|
|
5
6
|
return {
|
|
6
7
|
dataDir: root,
|
|
7
8
|
db: join(root, "slopify.db"),
|
|
8
|
-
projects:
|
|
9
|
+
projects: files?.projects ?? projects,
|
|
10
|
+
backups: files?.backups ?? join(projects, "Backups"),
|
|
11
|
+
exports: files === undefined ? null : files.exports,
|
|
9
12
|
staging: join(root, "staging"),
|
|
10
13
|
logs: join(root, "logs"),
|
|
11
14
|
lock: join(root, ".lock"),
|
|
12
15
|
};
|
|
13
16
|
}
|
|
17
|
+
// Points a running install's Paths at moved files. The one object every slice was handed is
|
|
18
|
+
// changed in place, so the next file each one reads or writes is in the new place.
|
|
19
|
+
export function repoint(paths, files) {
|
|
20
|
+
Object.assign(paths, {
|
|
21
|
+
projects: files.projects,
|
|
22
|
+
backups: files.backups,
|
|
23
|
+
exports: files.exports,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
14
26
|
export function ensureDirs(paths, options) {
|
|
15
|
-
|
|
27
|
+
ensureDataDirs(paths, options);
|
|
28
|
+
ensureOwnerOnly([paths.projects], options);
|
|
29
|
+
}
|
|
30
|
+
// The data dir's own folders, before it is known where the user-visible files go.
|
|
31
|
+
export function ensureDataDirs(paths, options) {
|
|
32
|
+
ensureOwnerOnly([paths.dataDir, paths.staging, paths.logs], options);
|
|
33
|
+
}
|
|
34
|
+
function ensureOwnerOnly(dirs, options) {
|
|
35
|
+
for (const dir of dirs) {
|
|
16
36
|
mkdirSync(dir, { recursive: true, mode: options.mode });
|
|
17
37
|
// mkdir's mode is masked by the umask and ignored for a directory that already
|
|
18
38
|
// exists; provider keys sit in this tree, so the mode has to be forced.
|
|
@@ -20,7 +40,8 @@ export function ensureDirs(paths, options) {
|
|
|
20
40
|
}
|
|
21
41
|
}
|
|
22
42
|
// The subtitle-timing model's cache. The app readies it at start and every captioned render
|
|
23
|
-
// reads it, so both name it through here.
|
|
24
|
-
|
|
25
|
-
|
|
43
|
+
// reads it, so both name it through here. Other languages use the multilingual model, kept
|
|
44
|
+
// in a folder of its own and downloaded on first use, never at start.
|
|
45
|
+
export function subtitleModelDir(dataDir, language = "en") {
|
|
46
|
+
return join(dataDir, "models", language === "en" ? "english-subtitles" : "multilingual-subtitles");
|
|
26
47
|
}
|
package/dist/kernel/pipeline.js
CHANGED
|
@@ -24,12 +24,15 @@ export const stageStates = [
|
|
|
24
24
|
"skipped",
|
|
25
25
|
];
|
|
26
26
|
// A persisted pause overrides the stage-derived status. A completed run need not
|
|
27
|
-
// include a video: all selected stages being satisfied is enough.
|
|
27
|
+
// include a video: all selected stages being satisfied is enough. `partial` is a run whose
|
|
28
|
+
// main output was made while another step failed (the video is there, its thumbnail is
|
|
29
|
+
// not): done with problems, not failed.
|
|
28
30
|
export const projectStates = [
|
|
29
31
|
"running",
|
|
30
32
|
"paused",
|
|
31
33
|
"canceled",
|
|
32
34
|
"failed",
|
|
35
|
+
"partial",
|
|
33
36
|
"done",
|
|
34
37
|
"pending",
|
|
35
38
|
];
|
|
@@ -5,7 +5,20 @@ import { llmDocumentsSchema } from "./llm-documents.js";
|
|
|
5
5
|
import { providerErrorKinds } from "./model.js";
|
|
6
6
|
export const hostLlmIds = ["claude-code", "codex", "gemini"];
|
|
7
7
|
export const hostCliIds = [...hostLlmIds, "codex-image"];
|
|
8
|
+
// The health answer's protocol stays 1: both sides read it as an exact value, so bumping it
|
|
9
|
+
// would lock an older app out of a newer helper and the other way round. Richer stream frames
|
|
10
|
+
// are negotiated per request instead, with `hostFramesHeader`.
|
|
8
11
|
export const hostCliProtocol = 1;
|
|
12
|
+
// Sent by the app on every LLM request: the frame version it can read. A helper puts the
|
|
13
|
+
// cached-token count, the answering model and the plan windows on the `done` frame only when
|
|
14
|
+
// this says 2 or more, because an app from before them rejects any field it does not know.
|
|
15
|
+
// An older helper ignores the header and sends the plain frame, which reads as "not reported".
|
|
16
|
+
export const hostFramesHeader = "x-slopify-frames";
|
|
17
|
+
export const hostFramesVersion = 2;
|
|
18
|
+
// What the Codex CLI reported spending on a bridged image (its tokens and plan windows), as
|
|
19
|
+
// base64url JSON. A header rather than a body change, so an older app just ignores it and a
|
|
20
|
+
// newer app reads a missing one as "not reported".
|
|
21
|
+
export const hostImageReportHeader = "x-slopify-image-report";
|
|
9
22
|
export const bridgeLimits = {
|
|
10
23
|
request: 16 * 1024 * 1024,
|
|
11
24
|
status: 64 * 1024,
|
|
@@ -39,6 +52,15 @@ export const hostLlmSchema = z
|
|
|
39
52
|
webSearch: z.boolean().optional(),
|
|
40
53
|
})
|
|
41
54
|
.strict();
|
|
55
|
+
const bridgedImage = z
|
|
56
|
+
.object({
|
|
57
|
+
mime: z.enum(["image/png", "image/jpeg"]),
|
|
58
|
+
base64: z
|
|
59
|
+
.string()
|
|
60
|
+
.max(Math.ceil(bridgeLimits.reference / 3) * 4)
|
|
61
|
+
.regex(/^[A-Za-z0-9+/]*={0,2}$/),
|
|
62
|
+
})
|
|
63
|
+
.strict();
|
|
42
64
|
export const hostImageSchema = z
|
|
43
65
|
.object({
|
|
44
66
|
// "codex-imagegen" is the Codex default; any other is one of the Codex CLI's models.
|
|
@@ -57,6 +79,18 @@ export const hostImageSchema = z
|
|
|
57
79
|
})
|
|
58
80
|
.strict()
|
|
59
81
|
.optional(),
|
|
82
|
+
// The cast members the brief mentions, with their pictures (`ImageRequest.cast`); the
|
|
83
|
+
// whole request still has to fit `bridgeLimits.request`.
|
|
84
|
+
cast: z
|
|
85
|
+
.array(z
|
|
86
|
+
.object({
|
|
87
|
+
name: z.string().min(1).max(200),
|
|
88
|
+
description: z.string().max(2000),
|
|
89
|
+
images: z.array(bridgedImage).min(1).max(4),
|
|
90
|
+
})
|
|
91
|
+
.strict())
|
|
92
|
+
.max(4)
|
|
93
|
+
.optional(),
|
|
60
94
|
})
|
|
61
95
|
.strict();
|
|
62
96
|
export const hostOpenFolderSchema = z
|
|
@@ -102,25 +136,99 @@ export const hostHealthSchema = z
|
|
|
102
136
|
accepting: z.boolean(),
|
|
103
137
|
})
|
|
104
138
|
.strict();
|
|
105
|
-
|
|
106
|
-
|
|
139
|
+
// Faults and frames are read leniently: a field this side does not know is dropped, never an
|
|
140
|
+
// error, so a newer helper can add optional fields without breaking this app. (Apps before
|
|
141
|
+
// frame version 2 read them strictly, which is why the helper asks before adding any.)
|
|
142
|
+
export const hostFaultSchema = z.object({
|
|
107
143
|
type: z.literal("error"),
|
|
108
144
|
kind: z.enum(providerErrorKinds),
|
|
109
145
|
message: z.string().max(4096),
|
|
110
|
-
})
|
|
111
|
-
|
|
146
|
+
});
|
|
147
|
+
const limitWindowSchema = z.object({
|
|
148
|
+
kind: z.enum(["five_hour", "weekly", "other"]),
|
|
149
|
+
usedPercent: z.number().min(0).max(1_000_000),
|
|
150
|
+
resetsAt: z.string().max(64).nullable(),
|
|
151
|
+
});
|
|
152
|
+
const limitWindowsSchema = z.array(limitWindowSchema).max(16);
|
|
153
|
+
const planLimitReadingSchema = z.object({
|
|
154
|
+
before: limitWindowsSchema.optional(),
|
|
155
|
+
after: limitWindowsSchema.optional(),
|
|
156
|
+
});
|
|
157
|
+
const usageSchema = z.object({
|
|
158
|
+
inputTokens: z.number().nonnegative(),
|
|
159
|
+
outputTokens: z.number().nonnegative(),
|
|
160
|
+
// Frame version 2 on; an older helper never sends them.
|
|
161
|
+
cachedInputTokens: z.number().nonnegative().optional(),
|
|
162
|
+
model: short.optional(),
|
|
163
|
+
});
|
|
112
164
|
export const hostFrameSchema = z.discriminatedUnion("type", [
|
|
113
|
-
z.object({ type: z.literal("delta"), text: z.string().max(bridgeLimits.frame) })
|
|
114
|
-
z.object({ type: z.literal("activity") })
|
|
115
|
-
z
|
|
116
|
-
.object({
|
|
165
|
+
z.object({ type: z.literal("delta"), text: z.string().max(bridgeLimits.frame) }),
|
|
166
|
+
z.object({ type: z.literal("activity") }),
|
|
167
|
+
z.object({
|
|
117
168
|
type: z.literal("done"),
|
|
118
|
-
usage:
|
|
119
|
-
.object({ inputTokens: z.number().nonnegative(), outputTokens: z.number().nonnegative() })
|
|
120
|
-
.strict()
|
|
121
|
-
.nullable(),
|
|
169
|
+
usage: usageSchema.nullable(),
|
|
122
170
|
finishReason: z.string().max(256).nullable(),
|
|
123
|
-
|
|
124
|
-
.
|
|
171
|
+
// Frame version 2 on.
|
|
172
|
+
limits: planLimitReadingSchema.optional(),
|
|
173
|
+
}),
|
|
125
174
|
hostFaultSchema,
|
|
126
175
|
]);
|
|
176
|
+
// The `done` frame the helper sends to an app that reads frame `version`. Version 1 is the
|
|
177
|
+
// original shape exactly; version 2 adds what the CLI reported, each part kept only when it is
|
|
178
|
+
// well formed so one odd value never costs the answer.
|
|
179
|
+
export function hostDoneFrame(event, version) {
|
|
180
|
+
const plain = event.usage === null
|
|
181
|
+
? null
|
|
182
|
+
: { inputTokens: event.usage.inputTokens, outputTokens: event.usage.outputTokens };
|
|
183
|
+
if (!(version >= 2))
|
|
184
|
+
return { type: "done", usage: plain, finishReason: event.finishReason };
|
|
185
|
+
const cached = z.number().nonnegative().safeParse(event.usage?.cachedInputTokens);
|
|
186
|
+
const model = short.safeParse(event.usage?.model);
|
|
187
|
+
const limits = planLimitReadingSchema.safeParse(event.limits);
|
|
188
|
+
return {
|
|
189
|
+
type: "done",
|
|
190
|
+
usage: plain === null
|
|
191
|
+
? null
|
|
192
|
+
: {
|
|
193
|
+
...plain,
|
|
194
|
+
...(cached.success ? { cachedInputTokens: cached.data } : {}),
|
|
195
|
+
...(model.success ? { model: model.data } : {}),
|
|
196
|
+
},
|
|
197
|
+
finishReason: event.finishReason,
|
|
198
|
+
...(event.limits !== undefined && limits.success ? { limits: limits.data } : {}),
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
const imageReportSchema = z.object({
|
|
202
|
+
usage: usageSchema.optional(),
|
|
203
|
+
limits: planLimitReadingSchema.optional(),
|
|
204
|
+
});
|
|
205
|
+
// The image report header's value, or undefined when there is nothing well formed to report.
|
|
206
|
+
export function encodeHostImageReport(image) {
|
|
207
|
+
const report = imageReportSchema.safeParse({
|
|
208
|
+
...(image.usage === undefined ? {} : { usage: image.usage }),
|
|
209
|
+
...(image.limits === undefined ? {} : { limits: image.limits }),
|
|
210
|
+
});
|
|
211
|
+
if (!report.success || (report.data.usage === undefined && report.data.limits === undefined))
|
|
212
|
+
return undefined;
|
|
213
|
+
const value = Buffer.from(JSON.stringify(report.data)).toString("base64url");
|
|
214
|
+
// Well inside Node's 16 KB header allowance; a larger report is dropped, never the image.
|
|
215
|
+
return value.length > 8192 ? undefined : value;
|
|
216
|
+
}
|
|
217
|
+
// The usage and plan windows a helper sent beside an image: empty when it sent none (an older
|
|
218
|
+
// helper) or something unreadable, which only costs the report.
|
|
219
|
+
export function decodeHostImageReport(value) {
|
|
220
|
+
if (typeof value !== "string" || value.length > 8192)
|
|
221
|
+
return {};
|
|
222
|
+
try {
|
|
223
|
+
const report = imageReportSchema.safeParse(JSON.parse(Buffer.from(value, "base64url").toString("utf8")));
|
|
224
|
+
if (!report.success)
|
|
225
|
+
return {};
|
|
226
|
+
return {
|
|
227
|
+
...(report.data.usage === undefined ? {} : { usage: report.data.usage }),
|
|
228
|
+
...(report.data.limits === undefined ? {} : { limits: report.data.limits }),
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
catch {
|
|
232
|
+
return {};
|
|
233
|
+
}
|
|
234
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|