@gentbajko/slopify 2.5.0 → 3.0.1
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 +24 -41
- package/SUBTITLES.md +1 -1
- package/dist/adapter-registry.js +31 -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 +85 -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/gemini.js +206 -0
- 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/pcm-mp3.js +62 -0
- package/dist/adapters/tts/system.js +147 -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/models.yaml +38 -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/assets/style-preview/narration.mp3 +0 -0
- package/dist/assets/style-preview/tall-1.jpg +0 -0
- package/dist/assets/style-preview/tall-2.jpg +0 -0
- package/dist/assets/style-preview/tall-3.jpg +0 -0
- package/dist/assets/style-preview/wide-1.jpg +0 -0
- package/dist/assets/style-preview/wide-2.jpg +0 -0
- package/dist/assets/style-preview/wide-3.jpg +0 -0
- package/dist/catalog/merge.js +132 -0
- package/dist/catalog/registry.js +17 -14
- package/dist/catalog/schema.js +2 -0
- package/dist/catalog/store.js +147 -8
- package/dist/catalog/validate.js +2 -2
- package/dist/compose.yaml +71 -0
- package/dist/edge/autostart/docker-record.js +32 -0
- package/dist/edge/autostart/docker.js +118 -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 +72 -0
- package/dist/edge/autostart/service.js +90 -0
- package/dist/edge/cli-args.js +71 -0
- package/dist/edge/cli.js +64 -63
- 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 +160 -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/events/hub.js +3 -1
- package/dist/edge/host-cli.js +1 -1
- package/dist/edge/http/actions.js +38 -11
- package/dist/edge/http/app.js +60 -2
- package/dist/edge/http/auditions.js +70 -0
- package/dist/edge/http/autostart.js +37 -0
- package/dist/edge/http/byte-range.js +42 -0
- package/dist/edge/http/channel-memory.js +92 -0
- package/dist/edge/http/channels.js +128 -0
- package/dist/edge/http/diagnostics.js +1 -0
- package/dist/edge/http/draft-files.js +2 -4
- package/dist/edge/http/entries.js +22 -3
- package/dist/edge/http/files.js +11 -7
- 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 +212 -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/project-templates.js +19 -2
- package/dist/edge/http/projects.js +37 -100
- package/dist/edge/http/prompts.js +40 -3
- package/dist/edge/http/pronunciations.js +23 -4
- package/dist/edge/http/providers.js +119 -3
- package/dist/edge/http/reviews.js +131 -0
- package/dist/edge/http/revision-files.js +3 -5
- package/dist/edge/http/revisions.js +1 -1
- package/dist/edge/http/run-cost.js +25 -0
- package/dist/edge/http/schedules.js +115 -6
- package/dist/edge/http/settings.js +84 -6
- package/dist/edge/http/storage-files.js +50 -0
- package/dist/edge/http/storage.js +43 -2
- package/dist/edge/http/studio.js +287 -0
- package/dist/edge/http/style-preview.js +61 -0
- package/dist/edge/http/subtitles.js +1 -1
- package/dist/edge/http/trash.js +69 -0
- package/dist/edge/http/tutorials.js +59 -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 +92 -0
- package/dist/edge/native-update.js +62 -0
- package/dist/extension/slopify-studio-chrome.zip +0 -0
- package/dist/extension/slopify-studio-firefox.zip +0 -0
- package/dist/host-cli/gemini-login.js +83 -0
- package/dist/host-cli/open-folder.js +10 -10
- package/dist/host-cli/runtime.js +9 -1
- package/dist/host-cli/status.js +4 -2
- 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/db/migrations/0041-cast-hosts.sql +3 -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 +10 -5
- package/dist/kernel/ports/narration-aliases.js +60 -0
- package/dist/kernel/ports/plan-limits.js +36 -0
- package/dist/kernel/ports/system-speech.js +203 -0
- package/dist/kernel/runner/attempt.js +17 -8
- package/dist/kernel/runner/audition.js +36 -0
- package/dist/kernel/runner/graph.js +40 -5
- package/dist/kernel/runner/index.js +39 -9
- 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 +277 -16
- package/dist/model-catalog.js +2 -0
- 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/3.0.1.md +105 -0
- package/dist/patch-notes/index.json +32 -0
- package/dist/slices/admission/model.js +27 -0
- package/dist/slices/admission/repo.js +24 -4
- package/dist/slices/admission/rules.js +80 -2
- package/dist/slices/admission/schema.js +58 -1
- package/dist/slices/admission/short-mode.js +47 -0
- package/dist/slices/admission/start.js +42 -6
- 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 +221 -0
- package/dist/slices/channels/runs.js +129 -0
- package/dist/slices/channels/schema.js +152 -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 +5 -2
- package/dist/slices/control/providers.js +4 -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 +68 -2
- package/dist/slices/eta/history.js +56 -0
- package/dist/slices/eta/model.js +63 -0
- package/dist/slices/eta/view.js +25 -0
- 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 +185 -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 +47 -3
- package/dist/slices/notifications/rules.js +48 -3
- package/dist/slices/onboarding/copy.js +143 -0
- package/dist/slices/onboarding/first-run.js +72 -0
- package/dist/slices/onboarding/full-video.js +81 -0
- package/dist/slices/onboarding/install.js +119 -0
- package/dist/slices/onboarding/model.js +85 -0
- package/dist/slices/onboarding/packs.js +491 -0
- package/dist/slices/onboarding/quick-short.js +144 -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 +127 -8
- package/dist/slices/play-drafts/readiness.js +4 -1
- 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 +59 -6
- package/dist/slices/project-templates/next-chapter.js +94 -0
- package/dist/slices/project-templates/one-off.js +26 -0
- package/dist/slices/project-templates/repo.js +2 -1
- package/dist/slices/project-templates/schema.js +7 -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 +67 -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 +125 -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 +267 -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 +62 -11
- 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/service-readiness.js +3 -3
- 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 +118 -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 +256 -0
- package/dist/slices/run-cost/pricing.js +95 -0
- package/dist/slices/run-cost/week.js +108 -0
- package/dist/slices/schedules/agenda.js +222 -0
- package/dist/slices/schedules/repo.js +58 -18
- package/dist/slices/schedules/scheduler.js +68 -17
- package/dist/slices/schedules/schema.js +179 -1
- package/dist/slices/schedules/service.js +43 -4
- package/dist/slices/schedules/similar.js +128 -0
- package/dist/slices/schedules/topic-list.js +163 -0
- package/dist/slices/schedules/topics.js +523 -0
- package/dist/slices/settings/first-run.js +106 -0
- package/dist/slices/settings/health.js +247 -0
- package/dist/slices/settings/key-guides.js +138 -0
- package/dist/slices/settings/key-test.js +93 -0
- package/dist/slices/settings/keys.js +10 -5
- package/dist/slices/settings/model-reach.js +52 -0
- package/dist/slices/settings/model.js +55 -1
- package/dist/slices/settings/models.js +5 -1
- package/dist/slices/settings/playback.js +15 -0
- package/dist/slices/settings/readiness.js +14 -2
- package/dist/slices/settings/repo.js +17 -3
- package/dist/slices/settings/tutorial-schema.js +5 -0
- 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 +63 -13
- 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 +87 -0
- package/dist/slices/storage/downloads.js +33 -1
- 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 +94 -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 +30 -0
- package/dist/slices/studio/pack.js +211 -0
- package/dist/slices/studio/queue.js +69 -0
- package/dist/slices/studio/settings.js +170 -0
- package/dist/slices/style-preview/images.js +61 -0
- package/dist/slices/style-preview/narration.js +33 -0
- package/dist/slices/style-preview/render.js +148 -0
- package/dist/slices/style-preview/schema.js +59 -0
- package/dist/slices/style-preview/service.js +92 -0
- package/dist/slices/style-preview/settings.js +139 -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/tutorials/anchors.js +57 -0
- package/dist/slices/tutorials/library.js +185 -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 +87 -0
- package/dist/slices/voices/audition.js +25 -0
- package/dist/slices/voices/cast.js +74 -0
- package/dist/slices/voices/grouping.js +59 -0
- package/dist/slices/voices/join.js +35 -0
- package/dist/slices/voices/languages.js +25 -0
- package/dist/slices/voices/model.js +218 -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 +84 -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/tutorials/AI-CLIs.md +146 -0
- package/dist/tutorials/Backups.md +121 -0
- package/dist/tutorials/Calendar.md +103 -0
- package/dist/tutorials/Cast-Library.md +112 -0
- package/dist/tutorials/Channels.md +148 -0
- package/dist/tutorials/Costs-and-Run-Cost.md +136 -0
- package/dist/tutorials/Docker.md +171 -0
- package/dist/tutorials/Document-Themes.md +207 -0
- package/dist/tutorials/Editing-a-Project.md +204 -0
- package/dist/tutorials/FAQ.md +134 -0
- package/dist/tutorials/First-Launch-and-Welcome.md +153 -0
- package/dist/tutorials/Home-and-Projects.md +174 -0
- package/dist/tutorials/Home.md +119 -0
- package/dist/tutorials/Install.md +154 -0
- package/dist/tutorials/Intros-and-Outros.md +86 -0
- package/dist/tutorials/Keyboard-Shortcuts-and-Command-Palette.md +215 -0
- package/dist/tutorials/Library-Overview.md +75 -0
- package/dist/tutorials/Models.md +133 -0
- package/dist/tutorials/Multiple-Voices.md +161 -0
- package/dist/tutorials/Narration-Aliases-and-Glossary.md +129 -0
- package/dist/tutorials/Notifications.md +86 -0
- package/dist/tutorials/Other-Languages.md +110 -0
- package/dist/tutorials/PDF-Documents.md +100 -0
- package/dist/tutorials/Play-Images.md +135 -0
- package/dist/tutorials/Play-Narration.md +167 -0
- package/dist/tutorials/Play-Outputs.md +109 -0
- package/dist/tutorials/Play-Overview.md +216 -0
- package/dist/tutorials/Play-Title-and-Article.md +135 -0
- package/dist/tutorials/Play-Video-and-Style.md +143 -0
- package/dist/tutorials/Project-Page.md +228 -0
- package/dist/tutorials/Prompts.md +136 -0
- package/dist/tutorials/Providers-and-Keys.md +290 -0
- package/dist/tutorials/Publishing-to-YouTube.md +135 -0
- package/dist/tutorials/Recovery-and-Retries.md +141 -0
- package/dist/tutorials/Reviews-and-Checkpoints.md +143 -0
- package/dist/tutorials/Schedules.md +154 -0
- package/dist/tutorials/Settings-Reference.md +258 -0
- package/dist/tutorials/Shorts.md +116 -0
- package/dist/tutorials/Start-at-Login.md +126 -0
- package/dist/tutorials/Studio-Extension.md +146 -0
- package/dist/tutorials/Templates.md +146 -0
- package/dist/tutorials/Trash.md +87 -0
- package/dist/tutorials/Troubleshooting.md +149 -0
- package/dist/tutorials/Uninstalling-and-Moving.md +113 -0
- package/dist/tutorials/Updating-and-Patch-Notes.md +120 -0
- package/dist/tutorials/Video-Editing.md +135 -0
- package/dist/tutorials/Where-Your-Files-Live.md +149 -0
- package/dist/tutorials/YouTube-Description.md +132 -0
- package/dist/tutorials/Your-First-Short.md +125 -0
- package/dist/tutorials/_Footer.md +1 -0
- package/dist/tutorials/_Sidebar.md +69 -0
- package/dist/updater/service.js +66 -21
- package/dist/web/assets/index-DBLSfqA-.css +1 -0
- package/dist/web/assets/index-DFdIhmm0.js +307 -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-B9OY1ioX.js} +1 -1
- package/dist/web/index.html +2 -2
- package/package.json +5 -5
- 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
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { zValidator } from "@hono/zod-validator";
|
|
2
2
|
import { Hono } from "hono";
|
|
3
3
|
import { z } from "zod";
|
|
4
|
+
import { versionsOrCurrent } from "../../slices/library/history.js";
|
|
4
5
|
import { promptKinds } from "../../slices/library/model.js";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
6
|
+
import { setPromptPhotorealistic, withPhotorealistic, } from "../../slices/library/photorealistic.js";
|
|
7
|
+
import { listPrompts, promptById } from "../../slices/library/repo.js";
|
|
8
|
+
import { createPrompt, removePrompt, restorePrompt, updatePrompt, } from "../../slices/library/save.js";
|
|
9
|
+
import { usedBy } from "../../slices/library/used-by.js";
|
|
7
10
|
import { onInvalid, problem, titleOf } from "./problem.js";
|
|
8
11
|
const idParam = z.object({
|
|
9
12
|
id: z
|
|
@@ -12,6 +15,8 @@ const idParam = z.object({
|
|
|
12
15
|
.max(64)
|
|
13
16
|
.regex(/^[0-9A-Za-z_-]+$/),
|
|
14
17
|
});
|
|
18
|
+
// History's Restore names the version by its number.
|
|
19
|
+
export const versionParam = idParam.extend({ version: z.coerce.number().int().positive() });
|
|
15
20
|
// Shape only. The rules - trimming, emptiness, length, the slot lint - are the slice's,
|
|
16
21
|
// so one set of messages reaches the editor.
|
|
17
22
|
const promptBody = z.object({
|
|
@@ -26,7 +31,7 @@ export function promptRoutes(deps) {
|
|
|
26
31
|
return (new Hono()
|
|
27
32
|
// Every kind in one list: 04 Prompts filters by tab, and Duplicate needs the body it
|
|
28
33
|
// is copying.
|
|
29
|
-
.get("/", (c) => c.json({ prompts: listPrompts(deps.db) }))
|
|
34
|
+
.get("/", (c) => c.json({ prompts: withPhotorealistic(deps.db, listPrompts(deps.db)) }))
|
|
30
35
|
.post("/", zValidator("json", promptBody, onInvalid), (c) => {
|
|
31
36
|
const result = createPrompt(library, c.req.valid("json"));
|
|
32
37
|
return result.ok ? c.json(result.value, 201) : refused(c, result, "prompt");
|
|
@@ -34,6 +39,38 @@ export function promptRoutes(deps) {
|
|
|
34
39
|
.put("/:id", zValidator("param", idParam, onInvalid), zValidator("json", promptBody, onInvalid), (c) => {
|
|
35
40
|
const result = updatePrompt(library, c.req.valid("param").id, c.req.valid("json"));
|
|
36
41
|
return result.ok ? c.json(result.value) : refused(c, result, "prompt");
|
|
42
|
+
})
|
|
43
|
+
// An Image prompt's "Draws photorealistic pictures" tick (`slices/library/photorealistic.ts`).
|
|
44
|
+
.put("/:id/photorealistic", zValidator("param", idParam, onInvalid), zValidator("json", z.object({ photorealistic: z.boolean() }), onInvalid), (c) => {
|
|
45
|
+
const result = setPromptPhotorealistic(deps.db, c.req.valid("param").id, c.req.valid("json").photorealistic);
|
|
46
|
+
if (result.ok)
|
|
47
|
+
return c.body(null, 204);
|
|
48
|
+
return result.reason === "not-found"
|
|
49
|
+
? refused(c, { ok: false, reason: "not-found" }, "prompt")
|
|
50
|
+
: problem(c, {
|
|
51
|
+
status: 400,
|
|
52
|
+
title: titleOf(400),
|
|
53
|
+
detail: "Only an Image prompt can be marked photorealistic. Open the prompt from the Image tab in Library → Prompts.",
|
|
54
|
+
});
|
|
55
|
+
})
|
|
56
|
+
// Every saved version, newest first (`slices/library/history.ts`).
|
|
57
|
+
.get("/:id/history", zValidator("param", idParam, onInvalid), (c) => {
|
|
58
|
+
const prompt = promptById(deps.db, c.req.valid("param").id);
|
|
59
|
+
return prompt === undefined
|
|
60
|
+
? refused(c, { ok: false, reason: "not-found" }, "prompt")
|
|
61
|
+
: c.json({ versions: versionsOrCurrent(deps.db, "prompt", prompt) });
|
|
62
|
+
})
|
|
63
|
+
.post("/:id/history/:version/restore", zValidator("param", versionParam, onInvalid), (c) => {
|
|
64
|
+
const { id, version } = c.req.valid("param");
|
|
65
|
+
const result = restorePrompt(library, id, version);
|
|
66
|
+
return result.ok ? c.json(result.value) : refused(c, result, "prompt");
|
|
67
|
+
})
|
|
68
|
+
// The templates, schedules and projects that name it.
|
|
69
|
+
.get("/:id/used-by", zValidator("param", idParam, onInvalid), (c) => {
|
|
70
|
+
const prompt = promptById(deps.db, c.req.valid("param").id);
|
|
71
|
+
return prompt === undefined
|
|
72
|
+
? refused(c, { ok: false, reason: "not-found" }, "prompt")
|
|
73
|
+
: c.json(usedBy(deps.db, { item: "prompt", kind: prompt.kind, name: prompt.name }));
|
|
37
74
|
})
|
|
38
75
|
// A project holds its own rendered text, so nothing cascades and a
|
|
39
76
|
// template used by past projects is deleted like any other.
|
|
@@ -1,17 +1,36 @@
|
|
|
1
1
|
import { zValidator } from "@hono/zod-validator";
|
|
2
2
|
import { Hono } from "hono";
|
|
3
3
|
import { z } from "zod";
|
|
4
|
+
import { aliasCountMax } from "../../kernel/ports/narration-aliases.js";
|
|
5
|
+
import { listNarrationAliases, saveNarrationAliases, } from "../../slices/narration/aliases-library.js";
|
|
4
6
|
import { collectSharedGlossary } from "../../slices/narration/shared-glossary.js";
|
|
5
|
-
import { onInvalid } from "./problem.js";
|
|
7
|
+
import { onInvalid, problem, titleOf } from "./problem.js";
|
|
6
8
|
// The pronunciations of every project's glossary, merged, for Edit project to copy into a
|
|
7
9
|
// project that shares them. `except` leaves out the project being edited, whose own glossary
|
|
8
|
-
// already comes first.
|
|
10
|
+
// already comes first. Library → Aliases lives here too: the other way to change how a word
|
|
11
|
+
// is said.
|
|
9
12
|
export function pronunciationRoutes(deps) {
|
|
10
|
-
|
|
13
|
+
const library = { db: deps.db, ids: deps.ids, clock: deps.clock };
|
|
14
|
+
return (new Hono()
|
|
15
|
+
.get("/shared", zValidator("query", z.object({
|
|
11
16
|
except: z
|
|
12
17
|
.string()
|
|
13
18
|
.max(64)
|
|
14
19
|
.regex(/^[0-9A-Za-z_-]*$/)
|
|
15
20
|
.optional(),
|
|
16
|
-
}), onInvalid), (c) => c.json(collectSharedGlossary(deps, c.req.valid("query").except)))
|
|
21
|
+
}), onInvalid), (c) => c.json(collectSharedGlossary(deps, c.req.valid("query").except)))
|
|
22
|
+
.get("/aliases", (c) => c.json({ aliases: listNarrationAliases(deps.db) }))
|
|
23
|
+
// The editor saves the whole ordered list at once; each row is checked in the slice, so
|
|
24
|
+
// the editor gets "Alias 3: …" sentences rather than schema paths.
|
|
25
|
+
.put("/aliases", zValidator("json", z.object({ aliases: z.array(z.unknown()).max(aliasCountMax * 2) }), onInvalid), (c) => {
|
|
26
|
+
const result = saveNarrationAliases(library, c.req.valid("json").aliases);
|
|
27
|
+
if (result.ok)
|
|
28
|
+
return c.json({ aliases: result.aliases });
|
|
29
|
+
return problem(c, {
|
|
30
|
+
status: 400,
|
|
31
|
+
title: titleOf(400),
|
|
32
|
+
detail: `These aliases can't be saved yet: ${result.fields.map((field) => field.message).join(" ")}`,
|
|
33
|
+
extensions: { fields: result.fields },
|
|
34
|
+
});
|
|
35
|
+
}));
|
|
17
36
|
}
|
|
@@ -1,19 +1,40 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
1
2
|
import { zValidator } from "@hono/zod-validator";
|
|
2
3
|
import { Hono } from "hono";
|
|
3
4
|
import { z } from "zod";
|
|
5
|
+
import { keyProbes } from "../../adapters/key-probes.js";
|
|
4
6
|
import { videoModelsOf } from "../../catalog/schema.js";
|
|
7
|
+
import { defaultSpeechVoice, detectSpeechCached } from "../../kernel/ports/system-speech.js";
|
|
8
|
+
import { switchAllRetired, switchRetiredModel } from "../../slices/model-upkeep/switch.js";
|
|
9
|
+
import { retiredModelUsage, usageKinds, usageSlots } from "../../slices/model-upkeep/usage.js";
|
|
5
10
|
import { cliPathMaxLength, saveCliPath } from "../../slices/settings/cli-paths.js";
|
|
11
|
+
import { dismissFirstRun, firstRunStatus } from "../../slices/settings/first-run.js";
|
|
12
|
+
import { checkProviderHealth } from "../../slices/settings/health.js";
|
|
13
|
+
import { keyGuides } from "../../slices/settings/key-guides.js";
|
|
14
|
+
import { testProviderKey } from "../../slices/settings/key-test.js";
|
|
6
15
|
import { keyStatus, removeProviderKey, saveProviderKey } from "../../slices/settings/keys.js";
|
|
7
|
-
import {
|
|
16
|
+
import { isUncataloguedProvider, providerById, providerIds } from "../../slices/settings/model.js";
|
|
8
17
|
import { createModelCatalog } from "../../slices/settings/models.js";
|
|
9
18
|
import { providerStatuses } from "../../slices/settings/readiness.js";
|
|
10
19
|
import { onInvalid, problem, titleOf } from "./problem.js";
|
|
11
20
|
const providerParam = z.object({ id: z.enum(providerIds) });
|
|
21
|
+
const healthQuery = z.object({ provider: z.enum(providerIds).optional() });
|
|
12
22
|
// ceiling: no format check is allowed on a key, so the only thing said about the value is
|
|
13
23
|
// that it is a string of a length a key could plausibly have. Raise the bound if a provider
|
|
14
24
|
// ever issues something longer.
|
|
15
25
|
const pathBody = z.object({ path: z.string().max(cliPathMaxLength) });
|
|
16
26
|
const keyBody = z.object({ key: z.string().min(1).max(4096) });
|
|
27
|
+
const modelId = z.string().min(1).max(200);
|
|
28
|
+
const switchBody = z
|
|
29
|
+
.object({
|
|
30
|
+
kind: z.enum(usageKinds),
|
|
31
|
+
id: z.string().min(1).max(64),
|
|
32
|
+
slot: z.enum(usageSlots),
|
|
33
|
+
from: z.object({ provider: z.string().min(1).max(64), model: modelId }).strict(),
|
|
34
|
+
to: modelId,
|
|
35
|
+
})
|
|
36
|
+
.strict();
|
|
37
|
+
const noFetch = "Slopify cannot reach the internet from here yet because it is still starting. Wait a moment, reload the page and try again.";
|
|
17
38
|
// The return type is inferred so Hono keeps the route types the SPA's client is
|
|
18
39
|
// generated from; see stagingRoutes.
|
|
19
40
|
export function providerRoutes(deps) {
|
|
@@ -22,6 +43,7 @@ export function providerRoutes(deps) {
|
|
|
22
43
|
db: deps.db,
|
|
23
44
|
probe: deps.probe,
|
|
24
45
|
hostCliStatus: deps.hostCliStatus,
|
|
46
|
+
host: deps.speechHost,
|
|
25
47
|
};
|
|
26
48
|
const catalog = createModelCatalog({
|
|
27
49
|
load: deps.modelsFor ?? (() => Promise.reject(new Error("Model catalog unavailable"))),
|
|
@@ -29,7 +51,67 @@ export function providerRoutes(deps) {
|
|
|
29
51
|
now: () => deps.clock.now().getTime(),
|
|
30
52
|
report: (provider) => deps.log.write("warn", "model-catalog", { detail: `Could not load models for ${provider}` }),
|
|
31
53
|
});
|
|
54
|
+
const upkeep = () => ({ ...deps, uuid: deps.drafts?.uuid ?? randomUUID });
|
|
32
55
|
return (new Hono()
|
|
56
|
+
// The step lists Settings → Providers shows beside each key field.
|
|
57
|
+
.get("/key-guides", (c) => c.json({ guides: keyGuides }))
|
|
58
|
+
// What the first launch found, and the providers Play picks by default.
|
|
59
|
+
.get("/first-run", async (c) => {
|
|
60
|
+
c.header("Cache-Control", "no-store");
|
|
61
|
+
return c.json(await firstRunStatus({ db: deps.db, ...(deps.modelsFor === undefined ? {} : { modelsFor: deps.modelsFor }) }, await providerStatuses(readiness)));
|
|
62
|
+
})
|
|
63
|
+
.post("/first-run/dismiss", (c) => {
|
|
64
|
+
dismissFirstRun(deps.db);
|
|
65
|
+
return c.body(null, 204);
|
|
66
|
+
})
|
|
67
|
+
// "Check all": every CLI signed in, every key valid, every chosen model still offered and
|
|
68
|
+
// answering for the key. `?provider=codex` checks that one only (its row's Check again,
|
|
69
|
+
// or a sign-in fix-it's).
|
|
70
|
+
.post("/health", zValidator("query", healthQuery, onInvalid), async (c) => {
|
|
71
|
+
if (deps.fetch === undefined)
|
|
72
|
+
return problem(c, { status: 503, title: titleOf(503), detail: noFetch });
|
|
73
|
+
const catalogue = deps.catalogue;
|
|
74
|
+
return c.json(await checkProviderHealth({
|
|
75
|
+
...readiness,
|
|
76
|
+
clock: deps.clock,
|
|
77
|
+
fetch: deps.fetch,
|
|
78
|
+
probes: keyProbes,
|
|
79
|
+
...(catalogue === undefined ? {} : { catalogue: () => catalogue.read() }),
|
|
80
|
+
...(deps.modelsFor === undefined ? {} : { modelsFor: deps.modelsFor }),
|
|
81
|
+
...(deps.cliLogin === undefined ? {} : { login: deps.cliLogin }),
|
|
82
|
+
}, c.req.valid("query").provider));
|
|
83
|
+
})
|
|
84
|
+
// Checks for new, repriced and retired models now instead of waiting for the daily check.
|
|
85
|
+
.post("/catalogue/check", async (c) => {
|
|
86
|
+
if (!deps.catalogue?.sync)
|
|
87
|
+
return problem(c, {
|
|
88
|
+
status: 503,
|
|
89
|
+
title: titleOf(503),
|
|
90
|
+
detail: "The model list (models.yaml) is not loaded yet. Wait a moment and reload the page; if it stays like this, restart Slopify.",
|
|
91
|
+
});
|
|
92
|
+
await deps.catalogue.sync();
|
|
93
|
+
return c.json(deps.catalogue.status());
|
|
94
|
+
})
|
|
95
|
+
// Every template, schedule, draft and unfinished project still using a retired model.
|
|
96
|
+
.get("/catalogue/retired", (c) => {
|
|
97
|
+
c.header("Cache-Control", "no-store");
|
|
98
|
+
return c.json({
|
|
99
|
+
usages: deps.catalogue === undefined ? [] : retiredModelUsage(deps.db, deps.catalogue.read()),
|
|
100
|
+
});
|
|
101
|
+
})
|
|
102
|
+
.post("/catalogue/retired/switch", zValidator("json", switchBody, onInvalid), async (c) => {
|
|
103
|
+
if (deps.catalogue === undefined)
|
|
104
|
+
return problem(c, { status: 503, title: titleOf(503), detail: noFetch });
|
|
105
|
+
const result = await switchRetiredModel(upkeep(), deps.catalogue.read(), c.req.valid("json"));
|
|
106
|
+
if (!result.ok)
|
|
107
|
+
return problem(c, { status: 409, title: titleOf(409), detail: result.message });
|
|
108
|
+
return c.json(result);
|
|
109
|
+
})
|
|
110
|
+
.post("/catalogue/retired/switch-all", async (c) => {
|
|
111
|
+
if (deps.catalogue === undefined)
|
|
112
|
+
return problem(c, { status: 503, title: titleOf(503), detail: noFetch });
|
|
113
|
+
return c.json(await switchAllRetired(upkeep(), deps.catalogue.read()));
|
|
114
|
+
})
|
|
33
115
|
.get("/catalogue", (c) => c.json(deps.catalogue?.status() ?? {
|
|
34
116
|
warning: "The model list (models.yaml) is not loaded yet. Wait a moment and reload the page; if it stays like this, restart Slopify.",
|
|
35
117
|
}))
|
|
@@ -55,6 +137,19 @@ export function providerRoutes(deps) {
|
|
|
55
137
|
// What Settings draws its rails from and Play its dropdowns: every provider, with
|
|
56
138
|
// the one fact that decides whether it is selectable.
|
|
57
139
|
.get("/", async (c) => c.json({ providers: await providerStatuses(readiness) }))
|
|
140
|
+
// The system voice's speech programs and their voices, for Settings → Voices' picker.
|
|
141
|
+
.get("/system-voice/voices", async (c) => {
|
|
142
|
+
const found = await detectSpeechCached(deps.probe, deps.speechHost ?? process);
|
|
143
|
+
return c.json({
|
|
144
|
+
engines: found.engines.map((engine) => ({
|
|
145
|
+
id: engine.id,
|
|
146
|
+
name: engine.name,
|
|
147
|
+
voices: engine.voices,
|
|
148
|
+
defaultVoice: defaultSpeechVoice(engine)?.id ?? null,
|
|
149
|
+
})),
|
|
150
|
+
issue: found.issue ?? null,
|
|
151
|
+
});
|
|
152
|
+
})
|
|
58
153
|
.get("/:id/models", zValidator("param", providerParam, onInvalid), async (c) => {
|
|
59
154
|
const { id } = c.req.valid("param");
|
|
60
155
|
// Animate images lists the provider's image-to-video models, which only the catalogue
|
|
@@ -64,7 +159,7 @@ export function providerRoutes(deps) {
|
|
|
64
159
|
models: deps.catalogue === undefined ? [] : videoModelsOf(deps.catalogue.read(), id),
|
|
65
160
|
allowsCustom: false,
|
|
66
161
|
});
|
|
67
|
-
if (deps.catalogue && !
|
|
162
|
+
if (deps.catalogue && !isUncataloguedProvider(id))
|
|
68
163
|
return c.json({
|
|
69
164
|
models: deps.catalogue.models(id, providerById(id).family).map((m) => ({
|
|
70
165
|
...m,
|
|
@@ -101,6 +196,25 @@ export function providerRoutes(deps) {
|
|
|
101
196
|
catalog.invalidate(id);
|
|
102
197
|
// The response says a key is stored and shows the mask, never the value.
|
|
103
198
|
return c.json(keyStatus(keys, id));
|
|
199
|
+
})
|
|
200
|
+
// The Test button: the cheapest read the provider offers, answered in plain words. With
|
|
201
|
+
// a `key` in the body, that pasted key is tried instead of the saved one and is neither
|
|
202
|
+
// stored nor logged; with no body, the saved key is.
|
|
203
|
+
.post("/:id/key/test", zValidator("param", providerParam, onInvalid), async (c) => {
|
|
204
|
+
const { id } = c.req.valid("param");
|
|
205
|
+
if (providerById(id).auth !== "key")
|
|
206
|
+
return refusal(c, id, "cli-provider");
|
|
207
|
+
if (deps.fetch === undefined)
|
|
208
|
+
return problem(c, { status: 503, title: titleOf(503), detail: noFetch });
|
|
209
|
+
const raw = await c.req.json().catch(() => undefined);
|
|
210
|
+
const candidate = raw === undefined ? undefined : keyBody.safeParse(raw);
|
|
211
|
+
if (candidate !== undefined && !candidate.success)
|
|
212
|
+
return problem(c, {
|
|
213
|
+
status: 400,
|
|
214
|
+
title: titleOf(400),
|
|
215
|
+
detail: `The pasted ${providerById(id).displayName} key could not be tested: it is empty or longer than any key. Paste the whole key in Settings → Providers → ${providerById(id).displayName}, then choose Test again.`,
|
|
216
|
+
});
|
|
217
|
+
return c.json(await testProviderKey({ db: deps.db, clock: deps.clock, fetch: deps.fetch, probes: keyProbes }, id, candidate?.data.key));
|
|
104
218
|
})
|
|
105
219
|
.delete("/:id/key", zValidator("param", providerParam, onInvalid), (c) => {
|
|
106
220
|
const { id } = c.req.valid("param");
|
|
@@ -118,7 +232,9 @@ function refusal(c, id, reason) {
|
|
|
118
232
|
return problem(c, {
|
|
119
233
|
status: 400,
|
|
120
234
|
title: titleOf(400),
|
|
121
|
-
detail:
|
|
235
|
+
detail: providerById(id).auth === "local"
|
|
236
|
+
? `${name} is your computer's own speech, so it has no API key to save. It works as soon as a speech program is installed.`
|
|
237
|
+
: `${name} signs in through its own command-line tool, so it has no API key to save here. Sign in with that tool on your computer instead.`,
|
|
122
238
|
});
|
|
123
239
|
}
|
|
124
240
|
if (reason === "absent") {
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { zValidator } from "@hono/zod-validator";
|
|
2
|
+
import { Hono } from "hono";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { revisionControlSchema } from "../../slices/control/revision-control-schema.js";
|
|
5
|
+
import { recoverProject } from "../../slices/rebuild/recovery.js";
|
|
6
|
+
import { redoStarting } from "../../slices/rebuild/review-redo.js";
|
|
7
|
+
import { actOnVerdict, listVerdicts, verdictById } from "../../slices/reviews/repo.js";
|
|
8
|
+
import { latestReviews } from "../../slices/reviews/view.js";
|
|
9
|
+
import { currentRevisionId } from "../../slices/revisions/repo.js";
|
|
10
|
+
import { getRevisionView } from "../../slices/revisions/view.js";
|
|
11
|
+
import { onInvalid, problem, titleOf } from "./problem.js";
|
|
12
|
+
const id = z
|
|
13
|
+
.string()
|
|
14
|
+
.min(1)
|
|
15
|
+
.max(64)
|
|
16
|
+
.regex(/^[0-9A-Za-z_-]+$/);
|
|
17
|
+
const projectParam = z.object({ id });
|
|
18
|
+
const verdictParam = projectParam.extend({ verdictId: id });
|
|
19
|
+
// The project page's review column: each reviewed item's latest verdict with its reasons,
|
|
20
|
+
// Overrule to accept a failed item as it is, and Redo to have it made again through the
|
|
21
|
+
// same path as More → make it again in its section.
|
|
22
|
+
export function reviewRoutes(deps) {
|
|
23
|
+
const gone = (c) => problem(c, {
|
|
24
|
+
status: 404,
|
|
25
|
+
title: titleOf(404),
|
|
26
|
+
detail: "This review no longer exists; the project may have been deleted or restored from a backup. Reload the project page.",
|
|
27
|
+
});
|
|
28
|
+
const notify = (projectId) => {
|
|
29
|
+
try {
|
|
30
|
+
deps.hub.emit(projectId, { type: "project.updated", projectId });
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
deps.log.write("error", "review.notify", {
|
|
34
|
+
projectId,
|
|
35
|
+
detail: error instanceof Error ? error.message : String(error),
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
return new Hono()
|
|
40
|
+
.get("/:id/reviews", zValidator("param", projectParam, onInvalid), (c) => {
|
|
41
|
+
const projectId = c.req.valid("param").id;
|
|
42
|
+
const head = currentRevisionId(deps.db, projectId);
|
|
43
|
+
const view = head === undefined ? undefined : getRevisionView(deps, projectId, head);
|
|
44
|
+
const outputs = (view?.outputs ?? [])
|
|
45
|
+
.filter((row) => row.selected)
|
|
46
|
+
.map((row) => ({
|
|
47
|
+
workKey: row.workKey,
|
|
48
|
+
fingerprint: row.fingerprint,
|
|
49
|
+
outputId: row.output.id,
|
|
50
|
+
}));
|
|
51
|
+
return c.json({ reviews: latestReviews(listVerdicts(deps.db, projectId), outputs) });
|
|
52
|
+
})
|
|
53
|
+
.post("/:id/reviews/:verdictId/overrule", zValidator("param", verdictParam, onInvalid), (c) => {
|
|
54
|
+
const { id: projectId, verdictId } = c.req.valid("param");
|
|
55
|
+
const busy = () => problem(c, {
|
|
56
|
+
status: 409,
|
|
57
|
+
title: titleOf(409),
|
|
58
|
+
detail: "This verdict can't be overruled: it passed, or Slopify has already started making the item again. Wait for the new version to land, then reload the project page and overrule its review if it fails again.",
|
|
59
|
+
extensions: { reason: "conflict" },
|
|
60
|
+
});
|
|
61
|
+
// Checked and changed in one synchronous step, so a redo cannot start in between.
|
|
62
|
+
if (redoStarting(verdictId))
|
|
63
|
+
return busy();
|
|
64
|
+
const result = actOnVerdict(deps.db, projectId, verdictId, "overruled", deps.clock.now().toISOString());
|
|
65
|
+
if (!result.ok)
|
|
66
|
+
return result.reason === "not-found" ? gone(c) : busy();
|
|
67
|
+
// A called-off redo released the work that was waiting on the item.
|
|
68
|
+
try {
|
|
69
|
+
deps.runner.tick(projectId);
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
// The next tick of this project picks the released work up.
|
|
73
|
+
}
|
|
74
|
+
notify(projectId);
|
|
75
|
+
return c.json({ review: result.value });
|
|
76
|
+
})
|
|
77
|
+
.post("/:id/reviews/:verdictId/redo", zValidator("param", verdictParam, onInvalid), zValidator("json", revisionControlSchema, onInvalid), async (c) => {
|
|
78
|
+
const { id: projectId, verdictId } = c.req.valid("param");
|
|
79
|
+
const verdict = verdictById(deps.db, projectId, verdictId);
|
|
80
|
+
if (verdict === undefined)
|
|
81
|
+
return gone(c);
|
|
82
|
+
if (deps.rebuild === undefined)
|
|
83
|
+
return problem(c, {
|
|
84
|
+
status: 503,
|
|
85
|
+
title: titleOf(503),
|
|
86
|
+
detail: "Redo is not ready yet because Slopify is still starting. Wait a moment, reload the page and try again.",
|
|
87
|
+
});
|
|
88
|
+
if (verdict.redoState === "pending" || verdict.redoState === "started")
|
|
89
|
+
return problem(c, {
|
|
90
|
+
status: 409,
|
|
91
|
+
title: titleOf(409),
|
|
92
|
+
detail: "Slopify is already making this item again. Wait for it to land, then reload the project page.",
|
|
93
|
+
extensions: { reason: "conflict" },
|
|
94
|
+
});
|
|
95
|
+
const result = await recoverProject(deps.rebuild, projectId, {
|
|
96
|
+
...c.req.valid("json"),
|
|
97
|
+
action: { kind: "redo", item: verdict.itemKey },
|
|
98
|
+
});
|
|
99
|
+
if (!result.ok)
|
|
100
|
+
return refused(c, result, projectId);
|
|
101
|
+
actOnVerdict(deps.db, projectId, verdictId, "redone", deps.clock.now().toISOString());
|
|
102
|
+
notify(projectId);
|
|
103
|
+
return c.json(result, 202);
|
|
104
|
+
});
|
|
105
|
+
function refused(c, result, projectId) {
|
|
106
|
+
const status = result.reason === "no-project"
|
|
107
|
+
? 404
|
|
108
|
+
: result.reason === "invalid-selection" || result.reason === "invalid-edit"
|
|
109
|
+
? 400
|
|
110
|
+
: 409;
|
|
111
|
+
const lead = result.reason === "running"
|
|
112
|
+
? "This item, or work that depends on it, is still running. Wait for it to finish, or Pause the project, then use Redo again."
|
|
113
|
+
: result.reason === "readiness"
|
|
114
|
+
? "Slopify can't make this item again yet. Fix what is listed in Settings → Providers or Edit project, then use Redo again."
|
|
115
|
+
: result.reason === "conflict" || result.reason === "control-changed"
|
|
116
|
+
? "This project changed since the page loaded. Reload the project page, then use Redo again."
|
|
117
|
+
: result.reason === "invalid-selection"
|
|
118
|
+
? "This item can't be made again."
|
|
119
|
+
: "Slopify couldn't make this item again.";
|
|
120
|
+
return problem(c, {
|
|
121
|
+
status,
|
|
122
|
+
title: titleOf(status),
|
|
123
|
+
detail: [lead, ...(result.fields ?? []).map((row) => row.message)].join(" "),
|
|
124
|
+
extensions: {
|
|
125
|
+
reason: result.reason,
|
|
126
|
+
fields: result.fields ?? [],
|
|
127
|
+
currentRevisionId: currentRevisionId(deps.db, projectId) ?? null,
|
|
128
|
+
},
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { createReadStream } from "node:fs";
|
|
2
|
-
import { Readable } from "node:stream";
|
|
3
1
|
import { zValidator } from "@hono/zod-validator";
|
|
4
2
|
import { Hono } from "hono";
|
|
5
3
|
import { z } from "zod";
|
|
6
4
|
import { findRevisionDownload, revisionImagesZip } from "../../slices/revisions/downloads.js";
|
|
5
|
+
import { fileResponse } from "./byte-range.js";
|
|
7
6
|
import { replyForFolder } from "./folder-location.js";
|
|
8
7
|
import { onInvalid, problem, titleOf } from "./problem.js";
|
|
9
8
|
const id = z
|
|
@@ -36,9 +35,8 @@ export function revisionFileRoutes(deps) {
|
|
|
36
35
|
// `?inline=1` lets the project page open a PDF in a browser tab instead of saving
|
|
37
36
|
// it. Only PDFs: anything else the browser might render stays a download.
|
|
38
37
|
const inline = c.req.query("inline") === "1" && value.contentType === "application/pdf";
|
|
39
|
-
return c
|
|
38
|
+
return fileResponse(c, value.path, value.bytes, {
|
|
40
39
|
"content-type": value.contentType,
|
|
41
|
-
"content-length": String(value.bytes),
|
|
42
40
|
"content-disposition": `${inline ? "inline" : "attachment"}; filename="${value.filename}"`,
|
|
43
41
|
"x-content-type-options": "nosniff",
|
|
44
42
|
});
|
|
@@ -65,7 +63,7 @@ function unavailable(c, reason) {
|
|
|
65
63
|
status: 404,
|
|
66
64
|
title: titleOf(404),
|
|
67
65
|
detail: reason === "missing-file"
|
|
68
|
-
? "This file was deleted or moved from the project folder. In the Edit tab, use
|
|
66
|
+
? "This file was deleted or moved from the project folder. In the Edit tab, use Choose what to remake (in the project's More menu) to make it again."
|
|
69
67
|
: "This file is no longer part of the project. Reload the page to see its current files.",
|
|
70
68
|
extensions: { reason },
|
|
71
69
|
});
|
|
@@ -37,7 +37,7 @@ const details = {
|
|
|
37
37
|
conflict: "This project changed while you were editing. Reload the page to see the latest, then make your change again.",
|
|
38
38
|
"idempotency-conflict": "This change was already sent with different details. Reload the page, then try again.",
|
|
39
39
|
"invalid-edit": "Some of your changes are not valid. Fix the highlighted fields and save again.",
|
|
40
|
-
"stale-preview": "What needs rebuilding changed since you opened this review. Cancel it and open
|
|
40
|
+
"stale-preview": "What needs rebuilding changed since you opened this review. Cancel it and open Choose what to remake (in the project's More menu) again to see the latest.",
|
|
41
41
|
"invalid-selection": "Some of the outputs you picked can no longer be rebuilt. Reload the page and choose again.",
|
|
42
42
|
"review-required": 'This rebuild touches content you supplied yourself. Tick "Keep the provided content" for each item in the review, then choose Start rebuild.',
|
|
43
43
|
"cost-ack-required": "Some costs for this rebuild are unknown. Tick the box confirming you understand, then choose Start rebuild.",
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { zValidator } from "@hono/zod-validator";
|
|
2
|
+
import { Hono } from "hono";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { projectExists } from "../../slices/admission/repo.js";
|
|
5
|
+
import { runCostOf } from "../../slices/run-cost/panel.js";
|
|
6
|
+
import { onInvalid, problem, titleOf } from "./problem.js";
|
|
7
|
+
const idParam = z.object({ id: z.string().min(1).max(64) });
|
|
8
|
+
// The project's Run cost tab and its "Waiting for … limits" line: what the run's provider
|
|
9
|
+
// calls used and cost, and any CLI plan limit a stage is waiting on. Read from the stored
|
|
10
|
+
// calls alone; nothing here reaches a provider.
|
|
11
|
+
//
|
|
12
|
+
// The return type is inferred so Hono keeps the route types the SPA's client is generated
|
|
13
|
+
// from; see stagingRoutes.
|
|
14
|
+
export function runCostRoutes(deps) {
|
|
15
|
+
return new Hono().get("/:id/run-cost", zValidator("param", idParam, onInvalid), (c) => {
|
|
16
|
+
const id = c.req.valid("param").id;
|
|
17
|
+
if (!projectExists(deps.db, id))
|
|
18
|
+
return problem(c, {
|
|
19
|
+
status: 404,
|
|
20
|
+
title: titleOf(404),
|
|
21
|
+
detail: "This project no longer exists. Go back to Projects to pick another.",
|
|
22
|
+
});
|
|
23
|
+
return c.json(runCostOf(deps.db, id));
|
|
24
|
+
});
|
|
25
|
+
}
|