@gentbajko/slopify 3.25.9 → 4.1.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/dist/adapters/account-limits.js +30 -0
- package/dist/adapters/alignment/audio.js +1 -1
- package/dist/adapters/alignment/cache.js +4 -6
- package/dist/adapters/alignment/ctc.js +1 -2
- package/dist/adapters/alignment/lock.js +4 -3
- package/dist/adapters/alignment/multilingual.js +2 -4
- package/dist/adapters/alignment/prefetch.js +2 -1
- package/dist/adapters/alignment/runner.js +1 -1
- package/dist/adapters/alignment/worker.js +3 -2
- package/dist/adapters/explain.js +10 -12
- package/dist/adapters/ffmpeg.js +19 -1
- package/dist/adapters/host-cli/index.js +21 -4
- package/dist/adapters/host-cli/transport.js +2 -1
- package/dist/adapters/http-failure.js +53 -0
- package/dist/adapters/image/bytes.js +2 -1
- package/dist/adapters/image/codex.js +42 -9
- package/dist/adapters/image/fal.js +21 -53
- package/dist/adapters/image/google.js +33 -56
- package/dist/adapters/image/models.js +2 -2
- package/dist/adapters/image/openai.js +22 -48
- package/dist/adapters/image/reference.js +36 -0
- package/dist/adapters/image/replicate.js +21 -49
- package/dist/adapters/image/video.js +2 -1
- package/dist/adapters/interest/search-interest.js +113 -0
- package/dist/adapters/key-probes.js +54 -3
- package/dist/adapters/llm/antigravity-models.js +1 -1
- package/dist/adapters/llm/antigravity.js +11 -6
- package/dist/adapters/llm/assistant-cli.js +388 -0
- package/dist/adapters/llm/child-session.js +83 -0
- package/dist/adapters/llm/claude-code-models.js +52 -99
- package/dist/adapters/llm/claude-code.js +16 -4
- package/dist/adapters/llm/codex-limits.js +27 -68
- package/dist/adapters/llm/codex-models.js +1 -1
- package/dist/adapters/llm/codex-server-models.js +61 -109
- package/dist/adapters/llm/codex.js +12 -1
- package/dist/adapters/llm/document-workspace.js +3 -2
- package/dist/adapters/llm/image-workspace.js +3 -2
- package/dist/adapters/llm/openrouter.js +12 -48
- package/dist/adapters/llm/run-cli.js +9 -24
- package/dist/adapters/llm/sse-lines.js +5 -1
- package/dist/adapters/model-access.js +37 -0
- package/dist/adapters/tts/cartesia.js +15 -46
- package/dist/adapters/tts/elevenlabs.js +20 -52
- package/dist/adapters/tts/gemini.js +21 -41
- package/dist/adapters/tts/inworld-async.js +6 -2
- package/dist/adapters/tts/inworld.js +6 -2
- package/dist/adapters/tts/openai.js +20 -50
- package/dist/adapters/tts/system.js +2 -1
- package/dist/assets/models-lifecycle.yaml +6 -0
- package/dist/assistant-wiring.js +60 -0
- package/dist/autopilot-timers.js +59 -0
- package/dist/catalog/lifecycle.js +52 -0
- package/dist/catalog/propose.js +204 -0
- package/dist/catalog/registry.js +23 -14
- package/dist/catalog/schema.js +4 -1
- package/dist/catalog/store.js +39 -0
- package/dist/catalog/validate.js +5 -2
- package/dist/edge/autostart/native.js +3 -5
- package/dist/edge/autostart/prompt.js +2 -1
- package/dist/edge/autostart/service.js +3 -4
- package/dist/edge/cli-args.js +3 -4
- package/dist/edge/cli.js +2 -1
- package/dist/edge/docker-install/apply.js +11 -11
- package/dist/edge/docker-install/run.js +2 -1
- package/dist/edge/docker-install/state.js +4 -3
- package/dist/edge/docker-install/tree.js +2 -4
- package/dist/edge/docker-install/volume.js +3 -2
- package/dist/edge/docker.js +5 -4
- package/dist/edge/events/hub.js +5 -5
- package/dist/edge/http/actions.js +11 -32
- package/dist/edge/http/actor.js +5 -3
- package/dist/edge/http/app.js +86 -11
- package/dist/edge/http/assistant.js +129 -0
- package/dist/edge/http/audio-preview.js +4 -11
- package/dist/edge/http/auditions.js +1 -1
- package/dist/edge/http/autostart.js +5 -5
- package/dist/edge/http/backups.js +2 -4
- package/dist/edge/http/channel-memory.js +9 -22
- package/dist/edge/http/channels.js +14 -27
- package/dist/edge/http/checkpoints.js +39 -21
- package/dist/edge/http/design-templates.js +167 -0
- package/dist/edge/http/designs.js +178 -0
- package/dist/edge/http/diagnostics.js +5 -1
- package/dist/edge/http/document-themes.js +5 -14
- package/dist/edge/http/draft-files.js +1 -3
- package/dist/edge/http/draft-problem.js +5 -10
- package/dist/edge/http/drafts.js +3 -3
- package/dist/edge/http/entries.js +6 -9
- package/dist/edge/http/extension-auth.js +27 -0
- package/dist/edge/http/external-reviews.js +12 -11
- package/dist/edge/http/files.js +5 -11
- package/dist/edge/http/folder-location.js +1 -4
- package/dist/edge/http/fonts.js +0 -7
- package/dist/edge/http/home.js +47 -14
- package/dist/edge/http/host-cli.js +18 -8
- package/dist/edge/http/ids.js +8 -0
- package/dist/edge/http/keywords.js +35 -0
- package/dist/edge/http/model-checks.js +132 -0
- package/dist/edge/http/narration-peaks.js +5 -13
- package/dist/edge/http/onboarding.js +30 -26
- package/dist/edge/http/open-folder.js +5 -10
- package/dist/edge/http/outputs.js +7 -14
- package/dist/edge/http/patch-notes.js +6 -12
- package/dist/edge/http/planning.js +3 -7
- package/dist/edge/http/problem.js +2 -4
- package/dist/edge/http/project-create.js +2 -1
- package/dist/edge/http/project-templates.js +31 -19
- package/dist/edge/http/projects.js +24 -16
- package/dist/edge/http/prompts.js +9 -16
- package/dist/edge/http/pronunciations.js +1 -2
- package/dist/edge/http/providers.js +48 -34
- package/dist/edge/http/refusal.js +29 -0
- package/dist/edge/http/remote-access.js +40 -0
- package/dist/edge/http/remote-guard.js +71 -0
- package/dist/edge/http/request-guard.js +91 -0
- package/dist/edge/http/reviews.js +12 -25
- package/dist/edge/http/revision-files.js +6 -11
- package/dist/edge/http/revisions.js +14 -19
- package/dist/edge/http/run-cost.js +1 -2
- package/dist/edge/http/same-page.js +80 -0
- package/dist/edge/http/schedules.js +69 -40
- package/dist/edge/http/settings.js +27 -14
- package/dist/edge/http/social.js +283 -0
- package/dist/edge/http/staging.js +3 -5
- package/dist/edge/http/storage-files.js +5 -7
- package/dist/edge/http/storage.js +33 -25
- package/dist/edge/http/studio.js +94 -69
- package/dist/edge/http/style-preview.js +3 -6
- package/dist/edge/http/subtitles.js +3 -17
- package/dist/edge/http/template-studio.js +436 -0
- package/dist/edge/http/trash.js +11 -12
- package/dist/edge/http/tutorial.js +1 -2
- package/dist/edge/http/tutorials.js +5 -11
- package/dist/edge/http/update.js +7 -13
- package/dist/edge/http/waveform.js +3 -6
- package/dist/edge/http/youtube-edits.js +3 -4
- package/dist/edge/mcp/assistant.js +279 -0
- package/dist/edge/mcp/attribution.js +8 -2
- package/dist/edge/mcp/call-route.js +11 -2
- package/dist/edge/mcp/excluded-routes.js +29 -3
- package/dist/edge/mcp/http.js +11 -2
- package/dist/edge/mcp/instructions.js +6 -4
- package/dist/edge/mcp/library-tools.js +9 -5
- package/dist/edge/mcp/remake-tools.js +7 -4
- package/dist/edge/mcp/route-tool.js +35 -15
- package/dist/edge/mcp/server.js +13 -8
- package/dist/edge/mcp/tools-channels.js +11 -9
- package/dist/edge/mcp/tools-designs.js +165 -0
- package/dist/edge/mcp/tools-library.js +19 -7
- package/dist/edge/mcp/tools-planning.js +40 -21
- package/dist/edge/mcp/tools-projects.js +38 -11
- package/dist/edge/mcp/tools-publishing.js +9 -9
- package/dist/edge/mcp/tools-runs.js +23 -10
- package/dist/edge/mcp/tools-schedules.js +32 -8
- package/dist/edge/mcp/tools-setup.js +75 -11
- package/dist/edge/mcp/tools-social.js +47 -0
- package/dist/edge/mcp/tools-storage.js +11 -3
- package/dist/edge/mcp/tools-template-studio.js +166 -0
- package/dist/edge/mcp/tools.js +6 -0
- package/dist/edge/remote-access/cli.js +71 -0
- package/dist/edge/remote-access/model.js +32 -0
- package/dist/edge/remote-access/rules.js +207 -0
- package/dist/edge/remote-access/service.js +203 -0
- package/dist/edge/remote-access/store.js +44 -0
- package/dist/edge/remote-access/views.js +43 -0
- package/dist/extension/slopify-studio-chrome.zip +0 -0
- package/dist/extension/slopify-studio-firefox.zip +0 -0
- package/dist/host-cli/install.js +2 -2
- package/dist/host-cli/open-folder.js +2 -2
- package/dist/host-cli/paths.js +2 -4
- package/dist/host-cli/server.js +4 -4
- package/dist/host-cli/service.js +3 -3
- package/dist/host-cli/status.js +7 -7
- package/dist/kernel/db/migrations/0063-model-checks.sql +20 -0
- package/dist/kernel/db/migrations/0064-template-studio.sql +46 -0
- package/dist/kernel/db/migrations/0065-promise-and-assistant-reviews.sql +58 -0
- package/dist/kernel/db/migrations/0066-assistant.sql +44 -0
- package/dist/kernel/db/migrations/0067-autopilot.sql +6 -0
- package/dist/kernel/db/migrations/0068-topic-scores.sql +17 -0
- package/dist/kernel/db/migrations/0070-designs.sql +53 -0
- package/dist/kernel/db/migrations/0071-design-usage.sql +33 -0
- package/dist/kernel/db/migrations/0072-design-templates.sql +33 -0
- package/dist/kernel/db/migrations/0073-schedule-design-kind.sql +5 -0
- package/dist/kernel/db/migrations/0074-template-bakeoffs.sql +44 -0
- package/dist/kernel/db/migrations/0075-social-posts.sql +25 -0
- package/dist/kernel/db/migrations/0076-channel-social.sql +5 -0
- package/dist/kernel/db/migrations/0077-post-prompts.sql +17 -0
- package/dist/kernel/db/migrations/0078-uploaded-from-links.sql +7 -0
- package/dist/kernel/db/tx.js +2 -4
- package/dist/kernel/errors.js +27 -1
- package/dist/kernel/json-answer.js +15 -0
- package/dist/kernel/lock.js +4 -9
- package/dist/kernel/paths.js +8 -0
- package/dist/kernel/pipeline.js +12 -0
- package/dist/kernel/ports/assistant-cli.js +4 -0
- package/dist/kernel/ports/host-cli.js +3 -0
- package/dist/kernel/ports/interest.js +4 -0
- package/dist/kernel/ports/languages.js +0 -3
- package/dist/kernel/ports/model.js +2 -0
- package/dist/kernel/ports/settings-places.js +31 -0
- package/dist/kernel/ports/system-speech.js +31 -3
- package/dist/kernel/runner/attempt.js +14 -4
- package/dist/kernel/runner/audition.js +3 -1
- package/dist/kernel/runner/checkpoint-authority.js +2 -1
- package/dist/kernel/runner/index.js +8 -10
- package/dist/kernel/runner/model-access.js +40 -0
- package/dist/kernel/runner/model-check.js +153 -0
- package/dist/kernel/runner/providers.js +18 -12
- package/dist/kernel/runner/standalone.js +11 -7
- package/dist/main.js +338 -21
- package/dist/model-catalog.js +20 -0
- package/dist/model-checks.js +166 -0
- package/dist/patch-notes/4.0.0.md +51 -0
- package/dist/patch-notes/4.1.0.md +42 -0
- package/dist/patch-notes/index.json +12 -0
- package/dist/slices/admission/heads.js +2 -1
- package/dist/slices/admission/listing-facts.js +95 -0
- package/dist/slices/admission/repo.js +11 -7
- package/dist/slices/admission/rules.js +50 -15
- package/dist/slices/admission/schema.js +8 -0
- package/dist/slices/admission/stage-writes.js +0 -3
- package/dist/slices/admission/start.js +48 -31
- package/dist/slices/admission/state-words.js +34 -5
- package/dist/slices/admission/substitute.js +7 -4
- package/dist/slices/agents/attention-posts.js +31 -0
- package/dist/slices/agents/attention-templates.js +33 -0
- package/dist/slices/agents/attention.js +10 -1
- package/dist/slices/agents/connection.js +2 -6
- package/dist/slices/agents/model.js +6 -3
- package/dist/slices/agents/repo.js +15 -7
- package/dist/slices/article/continuation.js +0 -63
- package/dist/slices/article/plain.js +3 -2
- package/dist/slices/article/segments.js +2 -62
- package/dist/slices/assistant/access.js +1 -0
- package/dist/slices/assistant/asks.js +80 -0
- package/dist/slices/assistant/cost.js +54 -0
- package/dist/slices/assistant/gate.js +222 -0
- package/dist/slices/assistant/model.js +86 -0
- package/dist/slices/assistant/names.js +23 -0
- package/dist/slices/assistant/prompt.js +74 -0
- package/dist/slices/assistant/repo.js +74 -0
- package/dist/slices/assistant/tokens.js +18 -0
- package/dist/slices/assistant/turn.js +344 -0
- package/dist/slices/autopilot/buffer.js +76 -0
- package/dist/slices/autopilot/model.js +14 -0
- package/dist/slices/autopilot/notify.js +27 -0
- package/dist/slices/autopilot/repo.js +34 -0
- package/dist/slices/autopilot/signals.js +194 -0
- package/dist/slices/autopilot/warnings.js +85 -0
- package/dist/slices/autopilot/weekly.js +100 -0
- package/dist/slices/backups/files.js +2 -6
- package/dist/slices/backups/repo.js +3 -15
- package/dist/slices/backups/service.js +8 -7
- package/dist/slices/channels/cast-images.js +3 -2
- package/dist/slices/channels/model.js +0 -1
- package/dist/slices/channels/rebrand.js +0 -3
- package/dist/slices/channels/repo.js +4 -0
- package/dist/slices/channels/schema.js +7 -1
- package/dist/slices/channels/service.js +10 -0
- package/dist/slices/channels/videos.js +3 -15
- package/dist/slices/checkpoints/index.js +0 -1
- package/dist/slices/control/providers.js +2 -28
- package/dist/slices/designs/artwork.js +66 -0
- package/dist/slices/designs/budget.js +23 -0
- package/dist/slices/designs/calls.js +124 -0
- package/dist/slices/designs/check-context.js +38 -0
- package/dist/slices/designs/check-text.js +43 -0
- package/dist/slices/designs/fields.js +88 -0
- package/dist/slices/designs/frames.js +34 -0
- package/dist/slices/designs/gate.js +130 -0
- package/dist/slices/designs/layout.js +293 -0
- package/dist/slices/designs/model.js +35 -0
- package/dist/slices/designs/pdf-job.js +23 -0
- package/dist/slices/designs/pdf-pages.js +30 -0
- package/dist/slices/designs/pdf-runner.js +68 -0
- package/dist/slices/designs/pdf-worker.js +24 -0
- package/dist/slices/designs/picture-size.js +79 -0
- package/dist/slices/designs/pictures.js +55 -0
- package/dist/slices/designs/quote.js +24 -0
- package/dist/slices/designs/render-args.js +36 -0
- package/dist/slices/designs/render-input.js +59 -0
- package/dist/slices/designs/render.js +215 -0
- package/dist/slices/designs/repo.js +101 -0
- package/dist/slices/designs/requests.js +80 -0
- package/dist/slices/designs/runner.js +239 -0
- package/dist/slices/designs/sample-repo.js +91 -0
- package/dist/slices/designs/sample.js +223 -0
- package/dist/slices/designs/schema.js +87 -0
- package/dist/slices/designs/sections.js +44 -0
- package/dist/slices/designs/service.js +233 -0
- package/dist/slices/designs/steps-repo.js +102 -0
- package/dist/slices/designs/studio-kind.js +39 -0
- package/dist/slices/designs/template-checks.js +44 -0
- package/dist/slices/designs/template-make.js +118 -0
- package/dist/slices/designs/templates.js +218 -0
- package/dist/slices/document/fonts.js +2 -1
- package/dist/slices/document/model.js +7 -4
- package/dist/slices/document/render.js +2 -1
- package/dist/slices/document/theme-schema.js +1 -1
- package/dist/slices/document/theme.js +49 -3
- package/dist/slices/episodes/summarize.js +6 -2
- package/dist/slices/estimate/index.js +72 -28
- package/dist/slices/estimate/requests.js +4 -4
- package/dist/slices/fixes/rules.js +3 -1
- package/dist/slices/fonts/catalog.js +5 -3
- package/dist/slices/fonts/coverage.js +2 -1
- package/dist/slices/fonts/discovery.js +3 -2
- package/dist/slices/fonts/files.js +2 -6
- package/dist/slices/fonts/index.js +0 -1
- package/dist/slices/fonts/sfnt.js +45 -10
- package/dist/slices/images/appearance.js +8 -16
- package/dist/slices/images/scenes.js +102 -28
- package/dist/slices/keywords/digest.js +85 -0
- package/dist/slices/keywords/facts.js +92 -0
- package/dist/slices/keywords/fill.js +80 -0
- package/dist/slices/keywords/model.js +75 -0
- package/dist/slices/keywords/rules.js +187 -0
- package/dist/slices/keywords/schema.js +28 -0
- package/dist/slices/keywords/specs.js +260 -0
- package/dist/slices/keywords/values.js +74 -0
- package/dist/slices/library/lint.js +29 -12
- package/dist/slices/library/model.js +2 -0
- package/dist/slices/library/photorealistic.js +4 -12
- package/dist/slices/library/rename.js +9 -7
- package/dist/slices/library/save.js +14 -10
- package/dist/slices/library/slots.js +37 -11
- package/dist/slices/library/transfer.js +5 -4
- package/dist/slices/library/used-by.js +25 -10
- package/dist/slices/loudness/loudnorm.js +53 -12
- package/dist/slices/loudness/model.js +3 -2
- package/dist/slices/loudness/sentence-level.js +2 -1
- package/dist/slices/model-checks/cost.js +61 -0
- package/dist/slices/model-checks/listing.js +124 -0
- package/dist/slices/model-checks/model.js +20 -0
- package/dist/slices/model-checks/record.js +32 -0
- package/dist/slices/model-checks/repo.js +120 -0
- package/dist/slices/model-checks/rules.js +125 -0
- package/dist/slices/model-checks/run.js +143 -0
- package/dist/slices/model-checks/service.js +198 -0
- package/dist/slices/model-upkeep/model.js +1 -1
- package/dist/slices/model-upkeep/switch.js +72 -27
- package/dist/slices/model-upkeep/usage.js +39 -13
- package/dist/slices/narration/breaths.js +3 -1
- package/dist/slices/narration/clean-pieces.js +3 -1
- package/dist/slices/narration/concat.js +2 -1
- package/dist/slices/narration/pauses-model.js +3 -2
- package/dist/slices/narration/peaks.js +3 -4
- package/dist/slices/narration/pronunciation-chunks.js +4 -3
- package/dist/slices/narration/pronunciation.js +6 -4
- package/dist/slices/narration/steering.js +4 -3
- package/dist/slices/notifications/notifier.js +4 -3
- package/dist/slices/notifications/rules.js +5 -2
- package/dist/slices/notifications/settings.js +4 -12
- package/dist/slices/notifications/subject.js +4 -3
- package/dist/slices/onboarding/copy.js +21 -3
- package/dist/slices/onboarding/first-run.js +16 -40
- package/dist/slices/onboarding/full-video.js +3 -2
- package/dist/slices/onboarding/install.js +6 -4
- package/dist/slices/onboarding/model.js +26 -37
- package/dist/slices/onboarding/packs.js +22 -22
- package/dist/slices/onboarding/preferred-model.js +14 -0
- package/dist/slices/onboarding/quick-short.js +105 -65
- package/dist/slices/onboarding/sample.js +4 -2
- package/dist/slices/onboarding/state.js +9 -11
- package/dist/slices/onboarding/template.js +8 -6
- package/dist/slices/outputs/add.js +3 -2
- package/dist/slices/outputs/service.js +2 -2
- package/dist/slices/patch-notes/library.js +4 -3
- package/dist/slices/play-drafts/convert.js +4 -0
- package/dist/slices/play-drafts/readiness.js +3 -3
- package/dist/slices/play-drafts/review-inputs.js +9 -3
- package/dist/slices/play-drafts/review.js +5 -4
- package/dist/slices/play-drafts/schema.js +4 -0
- package/dist/slices/play-drafts/service.js +17 -7
- package/dist/slices/project-templates/from-project.js +9 -2
- package/dist/slices/project-templates/next-chapter.js +2 -1
- package/dist/slices/project-templates/provider-defaults.js +22 -0
- package/dist/slices/project-templates/repo.js +6 -1
- package/dist/slices/project-templates/setup-sections.js +26 -0
- package/dist/slices/project-templates/setup.js +14 -1
- package/dist/slices/project-templates/stand-ins.js +22 -0
- package/dist/slices/rebuild/activity.js +2 -0
- package/dist/slices/rebuild/admission-repo.js +3 -2
- package/dist/slices/rebuild/narration-history.js +4 -5
- package/dist/slices/rebuild/narration-retry.js +2 -1
- package/dist/slices/rebuild/preview-details.js +32 -14
- package/dist/slices/rebuild/preview-plan.js +3 -8
- package/dist/slices/rebuild/recipe-build.js +8 -3
- package/dist/slices/rebuild/recipe-describe.js +3 -3
- package/dist/slices/rebuild/recipe-digest.js +58 -0
- package/dist/slices/rebuild/recipe-input-schema.js +10 -0
- package/dist/slices/rebuild/recipe-keywords.js +71 -0
- package/dist/slices/rebuild/recipe-legacy.js +5 -1
- package/dist/slices/rebuild/recipe-model.js +4 -0
- package/dist/slices/rebuild/recipe-narration-text.js +2 -1
- package/dist/slices/rebuild/recipe-preparation.js +4 -4
- package/dist/slices/rebuild/recipe-reference.js +8 -4
- package/dist/slices/rebuild/recipe-reviews.js +27 -7
- package/dist/slices/rebuild/recipe-save.js +8 -5
- package/dist/slices/rebuild/recipe-scenes.js +40 -11
- package/dist/slices/rebuild/recipe-shorts.js +8 -8
- package/dist/slices/rebuild/recipe-social.js +46 -0
- package/dist/slices/rebuild/recipe-text.js +64 -20
- package/dist/slices/rebuild/recipe-validation.js +102 -31
- package/dist/slices/rebuild/recipe-visual.js +55 -16
- package/dist/slices/rebuild/recipe-voices.js +3 -2
- package/dist/slices/rebuild/recipe-work.js +19 -7
- package/dist/slices/rebuild/recipe-youtube.js +4 -3
- package/dist/slices/rebuild/recovery-selection.js +3 -1
- package/dist/slices/rebuild/recovery.js +9 -8
- package/dist/slices/rebuild/remake-outdated.js +5 -5
- package/dist/slices/rebuild/repo.js +4 -3
- package/dist/slices/rebuild/review-promise.js +25 -0
- package/dist/slices/rebuild/review-redo.js +3 -2
- package/dist/slices/rebuild/runtime-admission.js +4 -3
- package/dist/slices/rebuild/runtime-agent-review.js +11 -5
- package/dist/slices/rebuild/runtime-animate.js +10 -9
- package/dist/slices/rebuild/runtime-article.js +7 -5
- package/dist/slices/rebuild/runtime-checkpoints.js +5 -4
- package/dist/slices/rebuild/runtime-document.js +11 -13
- package/dist/slices/rebuild/runtime-export-bed.js +8 -12
- package/dist/slices/rebuild/runtime-export-edit.js +8 -16
- package/dist/slices/rebuild/runtime-export-inputs.js +12 -11
- package/dist/slices/rebuild/runtime-export-short.js +9 -5
- package/dist/slices/rebuild/runtime-export.js +38 -15
- package/dist/slices/rebuild/runtime-figure-card.js +2 -1
- package/dist/slices/rebuild/runtime-image.js +8 -12
- package/dist/slices/rebuild/runtime-instructions.js +2 -0
- package/dist/slices/rebuild/runtime-keywords.js +59 -0
- package/dist/slices/rebuild/runtime-lines.js +2 -11
- package/dist/slices/rebuild/runtime-local.js +17 -22
- package/dist/slices/rebuild/runtime-narration-publication.js +2 -5
- package/dist/slices/rebuild/runtime-narration-reuse.js +9 -13
- package/dist/slices/rebuild/runtime-narration-text.js +13 -17
- package/dist/slices/rebuild/runtime-pictures.js +2 -4
- package/dist/slices/rebuild/runtime-piece-label.js +10 -6
- package/dist/slices/rebuild/runtime-plan.js +31 -5
- package/dist/slices/rebuild/runtime-provider.js +67 -25
- package/dist/slices/rebuild/runtime-publication.js +10 -9
- package/dist/slices/rebuild/runtime-review.js +39 -33
- package/dist/slices/rebuild/runtime-run.js +4 -1
- package/dist/slices/rebuild/runtime-shorts.js +31 -50
- package/dist/slices/rebuild/runtime-store.js +20 -10
- package/dist/slices/rebuild/runtime-subtitles.js +28 -25
- package/dist/slices/rebuild/runtime-voices.js +10 -16
- package/dist/slices/rebuild/runtime-youtube.js +14 -31
- package/dist/slices/rebuild/service-readiness.js +11 -3
- package/dist/slices/rebuild/transition-repo.js +6 -5
- package/dist/slices/rebuild/work-records.js +6 -0
- package/dist/slices/reruns/cascade.js +1 -2
- package/dist/slices/reruns/index.js +6 -9
- package/dist/slices/research/synthesis.js +3 -2
- package/dist/slices/reviews/external-model.js +4 -1
- package/dist/slices/reviews/external-repo.js +2 -1
- package/dist/slices/reviews/external-rows.js +2 -3
- package/dist/slices/reviews/holds.js +5 -4
- package/dist/slices/reviews/model.js +32 -11
- package/dist/slices/reviews/repo.js +2 -1
- package/dist/slices/reviews/rules.js +4 -3
- package/dist/slices/reviews/verdict.js +2 -1
- package/dist/slices/reviews/view.js +5 -2
- package/dist/slices/revisions/downloads.js +4 -5
- package/dist/slices/revisions/image-plan.js +1 -1
- package/dist/slices/revisions/mutation-assets.js +9 -5
- package/dist/slices/revisions/mutation-cues.js +2 -5
- package/dist/slices/revisions/mutations.js +3 -3
- package/dist/slices/revisions/repo.js +3 -1
- package/dist/slices/revisions/schema.js +1 -0
- package/dist/slices/revisions/view.js +20 -0
- package/dist/slices/run-cost/limits.js +5 -2
- package/dist/slices/run-cost/meter.js +12 -5
- package/dist/slices/run-cost/panel.js +8 -74
- package/dist/slices/run-cost/plan-readings.js +127 -0
- package/dist/slices/run-cost/plan-use.js +169 -0
- package/dist/slices/run-cost/pricing.js +3 -3
- package/dist/slices/run-cost/week.js +32 -4
- package/dist/slices/schedules/agenda.js +18 -7
- package/dist/slices/schedules/by-date.js +42 -0
- package/dist/slices/schedules/calendar.js +5 -0
- package/dist/slices/schedules/design-agenda.js +36 -0
- package/dist/slices/schedules/design-check.js +41 -0
- package/dist/slices/schedules/design-run.js +126 -0
- package/dist/slices/schedules/next-run.js +62 -0
- package/dist/slices/schedules/prepare.js +18 -2
- package/dist/slices/schedules/repo.js +30 -21
- package/dist/slices/schedules/rescore.js +35 -0
- package/dist/slices/schedules/scheduler.js +13 -3
- package/dist/slices/schedules/schema.js +57 -3
- package/dist/slices/schedules/score.js +107 -0
- package/dist/slices/schedules/service.js +57 -24
- package/dist/slices/schedules/topic-list.js +15 -0
- package/dist/slices/schedules/topic-scores.js +104 -0
- package/dist/slices/schedules/topics.js +53 -41
- package/dist/slices/settings/cli-paths.js +4 -6
- package/dist/slices/settings/first-run.js +8 -43
- package/dist/slices/settings/health.js +30 -15
- package/dist/slices/settings/key-test.js +1 -1
- package/dist/slices/settings/model-reach.js +3 -17
- package/dist/slices/settings/model.js +14 -2
- package/dist/slices/settings/playback.js +34 -23
- package/dist/slices/settings/probe-read.js +16 -0
- package/dist/slices/settings/repo.js +33 -0
- package/dist/slices/settings/tutorial.js +2 -2
- package/dist/slices/settings/voices.js +4 -12
- package/dist/slices/shorts/keep.js +2 -1
- package/dist/slices/shorts/pick.js +6 -18
- package/dist/slices/shorts/prompts.js +4 -14
- package/dist/slices/shorts/render.js +6 -2
- package/dist/slices/social/channel.js +44 -0
- package/dist/slices/social/defaults.js +17 -0
- package/dist/slices/social/due.js +36 -0
- package/dist/slices/social/extension.js +18 -0
- package/dist/slices/social/fit.js +115 -0
- package/dist/slices/social/limits.js +186 -0
- package/dist/slices/social/links.js +21 -0
- package/dist/slices/social/media.js +132 -0
- package/dist/slices/social/model.js +75 -0
- package/dist/slices/social/notice.js +19 -0
- package/dist/slices/social/pack.js +176 -0
- package/dist/slices/social/post-prompt.js +56 -0
- package/dist/slices/social/queue.js +31 -0
- package/dist/slices/social/repo.js +133 -0
- package/dist/slices/social/reshape.js +97 -0
- package/dist/slices/social/rules.js +5 -0
- package/dist/slices/social/schema.js +70 -0
- package/dist/slices/social/serve.js +51 -0
- package/dist/slices/social/service.js +129 -0
- package/dist/slices/social/settings.js +21 -0
- package/dist/slices/social/sources.js +114 -0
- package/dist/slices/social/state.js +110 -0
- package/dist/slices/social/text.js +149 -0
- package/dist/slices/storage/arrange.js +3 -1
- package/dist/slices/storage/assets.js +8 -10
- package/dist/slices/storage/backup-designs.js +74 -0
- package/dist/slices/storage/backup-export.js +8 -3
- package/dist/slices/storage/backup-format.js +10 -0
- package/dist/slices/storage/backup-import.js +22 -4
- package/dist/slices/storage/delete-project.js +6 -5
- package/dist/slices/storage/files-location.js +6 -8
- package/dist/slices/storage/layout.js +13 -2
- package/dist/slices/storage/model.js +3 -0
- package/dist/slices/storage/portable.js +17 -12
- package/dist/slices/storage/schema.js +2 -0
- package/dist/slices/storage/staging-refs.js +2 -1
- package/dist/slices/storage/staging.js +6 -9
- package/dist/slices/storage/trim.js +26 -9
- package/dist/slices/studio/calendar.js +7 -2
- package/dist/slices/studio/disclosure.js +4 -4
- package/dist/slices/studio/model.js +1 -1
- package/dist/slices/studio/pack.js +9 -8
- package/dist/slices/studio/pick.js +2 -11
- package/dist/slices/studio/plan.js +7 -16
- package/dist/slices/studio/queue.js +3 -14
- package/dist/slices/studio/releases.js +26 -0
- package/dist/slices/studio/settings.js +20 -57
- package/dist/slices/studio/videos.js +35 -4
- package/dist/slices/style-preview/render.js +37 -16
- package/dist/slices/style-preview/schema.js +14 -1
- package/dist/slices/style-preview/service.js +2 -1
- package/dist/slices/style-preview/settings.js +33 -5
- package/dist/slices/subtitles/captions.js +1 -1
- package/dist/slices/telemetry/collector-client.js +2 -4
- package/dist/slices/telemetry/flush.js +2 -4
- package/dist/slices/telemetry/model.js +0 -7
- package/dist/slices/telemetry/record.js +10 -3
- package/dist/slices/template-studio/anatomy-view.js +161 -0
- package/dist/slices/template-studio/anatomy.js +73 -0
- package/dist/slices/template-studio/bakeoff-make.js +225 -0
- package/dist/slices/template-studio/bakeoff-repo.js +83 -0
- package/dist/slices/template-studio/bakeoff.js +333 -0
- package/dist/slices/template-studio/budget.js +106 -0
- package/dist/slices/template-studio/cards.js +78 -0
- package/dist/slices/template-studio/checks.js +322 -0
- package/dist/slices/template-studio/document-sample.js +56 -0
- package/dist/slices/template-studio/edit.js +15 -0
- package/dist/slices/template-studio/for-all.js +161 -0
- package/dist/slices/template-studio/free-video.js +31 -0
- package/dist/slices/template-studio/free.js +176 -0
- package/dist/slices/template-studio/gate.js +40 -0
- package/dist/slices/template-studio/hidden.js +20 -0
- package/dist/slices/template-studio/jobs.js +79 -0
- package/dist/slices/template-studio/loudness.js +111 -0
- package/dist/slices/template-studio/make.js +40 -0
- package/dist/slices/template-studio/model.js +58 -0
- package/dist/slices/template-studio/pack-import.js +253 -0
- package/dist/slices/template-studio/pack-samples.js +60 -0
- package/dist/slices/template-studio/pack.js +207 -0
- package/dist/slices/template-studio/paid-view.js +66 -0
- package/dist/slices/template-studio/paid.js +355 -0
- package/dist/slices/template-studio/quote.js +155 -0
- package/dist/slices/template-studio/ready.js +104 -0
- package/dist/slices/template-studio/repo.js +134 -0
- package/dist/slices/template-studio/reviews-path.js +58 -0
- package/dist/slices/template-studio/runner.js +84 -0
- package/dist/slices/template-studio/save.js +236 -0
- package/dist/slices/template-studio/say-it-as.js +248 -0
- package/dist/slices/template-studio/schedule-gate.js +34 -0
- package/dist/slices/template-studio/schedule-price.js +32 -0
- package/dist/slices/template-studio/schedule-sample.js +91 -0
- package/dist/slices/template-studio/schema.js +243 -0
- package/dist/slices/template-studio/scope.js +124 -0
- package/dist/slices/template-studio/sections.js +176 -0
- package/dist/slices/template-studio/service.js +175 -0
- package/dist/slices/template-studio/status.js +191 -0
- package/dist/slices/template-studio/topic.js +223 -0
- package/dist/slices/thumbnail/by-llm.js +1 -1
- package/dist/slices/trash/designs.js +76 -0
- package/dist/slices/trash/model.js +13 -4
- package/dist/slices/trash/service.js +52 -2
- package/dist/slices/tutorials/library.js +3 -2
- package/dist/slices/uploads/repo.js +37 -1
- package/dist/slices/uploads/rules.js +3 -2
- package/dist/slices/video/ass-text.js +17 -0
- package/dist/slices/video/audio-export.js +2 -64
- package/dist/slices/video/edit-list.js +2 -2
- package/dist/slices/video/edit-settings.js +1 -1
- package/dist/slices/video/encoding.js +169 -0
- package/dist/slices/video/ffmpeg.js +23 -21
- package/dist/slices/video/figure-card.js +1 -15
- package/dist/slices/video/plan.js +2 -1
- package/dist/slices/video/slideshow.js +43 -18
- package/dist/slices/voices/attribution.js +3 -2
- package/dist/slices/voices/model.js +9 -8
- package/dist/slices/voices/palette.js +0 -3
- package/dist/slices/voices/script.js +2 -1
- package/dist/slices/youtube/answer.js +4 -16
- package/dist/slices/youtube/edits-repo.js +3 -12
- package/dist/tutorials/AI-CLIs.md +25 -25
- package/dist/tutorials/Agents-MCP.md +34 -33
- package/dist/tutorials/Assistant.md +42 -0
- package/dist/tutorials/Backups.md +7 -7
- package/dist/tutorials/Calendar.md +17 -25
- package/dist/tutorials/Cast-Library.md +19 -19
- package/dist/tutorials/Channels.md +42 -35
- package/dist/tutorials/Costs-and-Run-Cost.md +38 -40
- package/dist/tutorials/Create-Article.md +114 -0
- package/dist/tutorials/Create-Extras.md +112 -0
- package/dist/tutorials/Create-Images.md +165 -0
- package/dist/tutorials/Create-Narration.md +178 -0
- package/dist/tutorials/Create-Overview.md +244 -0
- package/dist/tutorials/Create-Video-and-Style.md +144 -0
- package/dist/tutorials/Docker.md +3 -3
- package/dist/tutorials/Document-Themes.md +32 -32
- package/dist/tutorials/Editing-a-Project.md +94 -94
- package/dist/tutorials/FAQ.md +18 -18
- package/dist/tutorials/First-Launch-and-Welcome.md +50 -64
- package/dist/tutorials/Home-and-Projects.md +115 -71
- package/dist/tutorials/Home.md +33 -33
- package/dist/tutorials/Install.md +14 -13
- package/dist/tutorials/Intros-and-Outros.md +33 -34
- package/dist/tutorials/Keyboard-Shortcuts-and-Command-Palette.md +62 -58
- package/dist/tutorials/Keywords-Slopify-Fills.md +87 -0
- package/dist/tutorials/Models.md +53 -21
- package/dist/tutorials/Multiple-Voices.md +41 -40
- package/dist/tutorials/Narration-Aliases-and-Glossary.md +14 -14
- package/dist/tutorials/Notifications.md +27 -17
- package/dist/tutorials/Other-Languages.md +15 -15
- package/dist/tutorials/PDF-Documents.md +38 -29
- package/dist/tutorials/Posting-to-Social-Sites.md +121 -0
- package/dist/tutorials/Project-Page.md +118 -120
- package/dist/tutorials/Prompts-and-Templates.md +84 -0
- package/dist/tutorials/Prompts.md +48 -44
- package/dist/tutorials/Providers-and-Keys.md +105 -98
- package/dist/tutorials/Publishing-to-YouTube.md +31 -31
- package/dist/tutorials/Recovery-and-Retries.md +31 -31
- package/dist/tutorials/Remote-Access.md +63 -0
- package/dist/tutorials/Reviews-and-Checkpoints.md +98 -90
- package/dist/tutorials/Schedules.md +46 -27
- package/dist/tutorials/Settings-Reference.md +194 -174
- package/dist/tutorials/Shorts.md +34 -33
- package/dist/tutorials/Start-at-Login.md +3 -3
- package/dist/tutorials/Studio-Extension.md +22 -24
- package/dist/tutorials/Template-Studio.md +128 -0
- package/dist/tutorials/Templates.md +51 -77
- package/dist/tutorials/Trash.md +4 -4
- package/dist/tutorials/Troubleshooting.md +44 -44
- package/dist/tutorials/Uninstalling-and-Moving.md +5 -5
- package/dist/tutorials/Updating-and-Patch-Notes.md +18 -18
- package/dist/tutorials/Video-Editing.md +34 -34
- package/dist/tutorials/Where-Your-Files-Live.md +10 -10
- package/dist/tutorials/YouTube-Description.md +26 -26
- package/dist/tutorials/Your-First-Short.md +35 -35
- package/dist/tutorials/_Sidebar.md +19 -14
- package/dist/updater/work-in-progress.js +42 -12
- package/dist/web/assets/index-BNftKQrA.css +1 -0
- package/dist/web/assets/index-Cpa58woP.js +459 -0
- package/dist/web/assets/pdf-BKh8f7R6.js +56 -0
- package/dist/web/assets/pdf.worker.min-BmVo14Nb.mjs +28 -0
- package/dist/web/assets/pdf.worker.min-D7i8o3wR.js +1 -0
- package/dist/web/index.html +2 -2
- package/package.json +6 -2
- package/dist/slices/article/provided-entries.js +0 -66
- package/dist/slices/article/run.js +0 -145
- package/dist/slices/images/run.js +0 -234
- package/dist/slices/narration/legacy-plan.js +0 -58
- package/dist/slices/narration/run.js +0 -270
- package/dist/slices/rebuild/runtime-actions.js +0 -90
- package/dist/slices/research/run.js +0 -224
- package/dist/slices/subtitles/prepare.js +0 -194
- package/dist/slices/subtitles/transcript.js +0 -34
- package/dist/slices/thumbnail/run.js +0 -219
- package/dist/slices/video/audio-inputs.js +0 -33
- package/dist/slices/video/reuse-audio.js +0 -62
- package/dist/slices/video/run.js +0 -78
- package/dist/slices/video/write-export.js +0 -158
- package/dist/slices/video/write-subtitles.js +0 -59
- package/dist/tutorials/Library-Overview.md +0 -76
- package/dist/tutorials/Play-Images.md +0 -161
- package/dist/tutorials/Play-Narration.md +0 -167
- package/dist/tutorials/Play-Outputs.md +0 -109
- package/dist/tutorials/Play-Overview.md +0 -227
- package/dist/tutorials/Play-Title-and-Article.md +0 -136
- package/dist/tutorials/Play-Video-and-Style.md +0 -143
- package/dist/web/assets/index-BadsoORk.css +0 -1
- package/dist/web/assets/index-D8LqNsCl.js +0 -326
- package/dist/web/assets/pdf-T7MCwjIv.js +0 -54
- package/dist/web/assets/pdf.worker.min-Dswkl-cV.mjs +0 -29
- package/dist/web/assets/pdf.worker.min-zC6nfbxG.js +0 -1
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { derive, progressOf } from "../../kernel/runner/graph.js";
|
|
3
3
|
import { liveProject, stageStandingsByProject } from "../admission/repo.js";
|
|
4
|
-
import { readsByWaitBesideFailure } from "../admission/state-words.js";
|
|
4
|
+
import { readsByWaitBesideFailure, retryingAt } from "../admission/state-words.js";
|
|
5
5
|
import { queueEntries } from "../batch/index.js";
|
|
6
6
|
import { sampleIds } from "../onboarding/model.js";
|
|
7
7
|
import { readSampleRecord } from "../onboarding/state.js";
|
|
8
8
|
import { projectHolds } from "../reviews/holds.js";
|
|
9
9
|
import { limitWaitsByProject, listingWait } from "../run-cost/panel.js";
|
|
10
|
-
import {
|
|
10
|
+
import { notTemplateSample } from "../template-studio/repo.js";
|
|
11
|
+
import { setAsideProjects, settledProjects, uploadedProjects } from "../uploads/repo.js";
|
|
11
12
|
import { settledStatus } from "../uploads/rules.js";
|
|
12
13
|
import { nextOccurrence } from "./calendar.js";
|
|
14
|
+
import { upcomingDesignRuns } from "./design-agenda.js";
|
|
13
15
|
import { preparedProject } from "./prepare.js";
|
|
14
16
|
import { scheduleRows } from "./repo.js";
|
|
15
17
|
import { calendarMaxDays, } from "./schema.js";
|
|
@@ -49,6 +51,8 @@ function upcomingRuns(deps, schedule, now, from, to) {
|
|
|
49
51
|
return [];
|
|
50
52
|
if (schedule.status !== "active" && schedule.status !== "paused")
|
|
51
53
|
return [];
|
|
54
|
+
if (schedule.cadence.kind === "by-date")
|
|
55
|
+
return upcomingDesignRuns(deps.db, schedule, now, from, to);
|
|
52
56
|
const paused = schedule.status === "paused";
|
|
53
57
|
// A paused schedule resumes from the next occurrence after the moment Resume is pressed.
|
|
54
58
|
let at = schedule.nextRunAt === null
|
|
@@ -58,6 +62,7 @@ function upcomingRuns(deps, schedule, now, from, to) {
|
|
|
58
62
|
: new Date(schedule.nextRunAt);
|
|
59
63
|
const template = deps.template(schedule.templateId);
|
|
60
64
|
const templateName = template?.name ?? null;
|
|
65
|
+
const notReady = deps.notReady?.(schedule.templateId) !== undefined;
|
|
61
66
|
const form = template?.document.form;
|
|
62
67
|
const { items } = schedule;
|
|
63
68
|
const generation = schedule.topicGeneration.mode;
|
|
@@ -91,10 +96,13 @@ function upcomingRuns(deps, schedule, now, from, to) {
|
|
|
91
96
|
? "held"
|
|
92
97
|
: "generated",
|
|
93
98
|
renderedTitle: title,
|
|
99
|
+
templateKind: "project",
|
|
100
|
+
timezone: schedule.timezone,
|
|
94
101
|
// Prepared ahead (`prepare.ts`): the project the day continues.
|
|
95
102
|
prepared: title === null || queuedTopic === undefined
|
|
96
103
|
? null
|
|
97
104
|
: (preparedProject(deps.db, schedule.id, title)?.projectId ?? null),
|
|
105
|
+
notReady,
|
|
98
106
|
});
|
|
99
107
|
if (schedule.cadence.kind === "once")
|
|
100
108
|
break;
|
|
@@ -143,8 +151,8 @@ function sampleProjectIds(db) {
|
|
|
143
151
|
// What a project on the calendar asks of the person, if anything. The same readings Home's
|
|
144
152
|
// Needs you uses: a failed run, a paused run, one a restart stopped (Continue the run), or one
|
|
145
153
|
// waiting for a review. A step failed beside a wait reads by that wait and is listed apart
|
|
146
|
-
// (`stepFailed`). One Kept as is asks nothing, nor does an uploaded one that reads
|
|
147
|
-
// (`
|
|
154
|
+
// (`stepFailed`). One Kept as is asks nothing, nor does an uploaded or edited one that reads
|
|
155
|
+
// Done (`settledProjects`).
|
|
148
156
|
function needsOf(state, ask) {
|
|
149
157
|
if (state === "failed")
|
|
150
158
|
return "failed";
|
|
@@ -162,7 +170,7 @@ function needsOf(state, ask) {
|
|
|
162
170
|
// the range, with what each needs from the person and whether its video is ready to upload.
|
|
163
171
|
function projectsIn(deps, from, to) {
|
|
164
172
|
const standings = stageStandingsByProject(deps.db);
|
|
165
|
-
const settled =
|
|
173
|
+
const settled = settledProjects(deps.db);
|
|
166
174
|
const holds = projectHolds(deps.db, { standings, settled });
|
|
167
175
|
const reviewing = awaitingReview(deps.db, holds);
|
|
168
176
|
const uploads = uploadedProjects(deps.db);
|
|
@@ -186,7 +194,8 @@ function projectsIn(deps, from, to) {
|
|
|
186
194
|
COALESCE(project_controls.paused,0) AS paused,max(stages.finished_at) AS finished_at
|
|
187
195
|
FROM projects LEFT JOIN stages ON stages.project_id=projects.id
|
|
188
196
|
LEFT JOIN project_controls ON project_controls.project_id=projects.id
|
|
189
|
-
WHERE projects.created_at<? AND ${liveProject()}
|
|
197
|
+
WHERE projects.created_at<? AND ${liveProject()} AND ${notTemplateSample()}
|
|
198
|
+
GROUP BY projects.id
|
|
190
199
|
HAVING COALESCE(project_controls.paused,0)=1 OR count(stages.id)=0
|
|
191
200
|
OR sum(stages.state IN ('pending','running'))>0
|
|
192
201
|
OR COALESCE(max(stages.finished_at),projects.created_at)>=?
|
|
@@ -215,6 +224,7 @@ function projectsIn(deps, from, to) {
|
|
|
215
224
|
!uploads.has(project.id) &&
|
|
216
225
|
!samples.has(project.id);
|
|
217
226
|
const waiting = waits.get(project.id);
|
|
227
|
+
const retry = state === "running" ? retryingAt(standings.get(project.id) ?? []) : undefined;
|
|
218
228
|
return [
|
|
219
229
|
{
|
|
220
230
|
id: project.id,
|
|
@@ -233,6 +243,7 @@ function projectsIn(deps, from, to) {
|
|
|
233
243
|
...(readsByWaitBesideFailure(state, standings.get(project.id) ?? [])
|
|
234
244
|
? { stepFailed: true }
|
|
235
245
|
: {}),
|
|
246
|
+
...(retry === undefined ? {} : { retryAt: retry }),
|
|
236
247
|
...(waiting === undefined ? {} : { limitWaits: waiting.map(listingWait) }),
|
|
237
248
|
},
|
|
238
249
|
];
|
|
@@ -244,7 +255,7 @@ function queued(deps) {
|
|
|
244
255
|
return [];
|
|
245
256
|
const row = deps.db
|
|
246
257
|
.prepare(`SELECT projects.title, batches.created_at FROM projects, batches
|
|
247
|
-
WHERE projects.id=? AND batches.id=? AND ${liveProject()}`)
|
|
258
|
+
WHERE projects.id=? AND batches.id=? AND ${liveProject()} AND ${notTemplateSample()}`)
|
|
248
259
|
.get(entry.projectId, entry.batchId);
|
|
249
260
|
if (row === undefined)
|
|
250
261
|
return [];
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/// <reference lib="esnext.temporal" />
|
|
2
|
+
import { validTimeZone } from "./calendar.js";
|
|
3
|
+
export function rowDate(row, dateField) {
|
|
4
|
+
const value = (row.values[dateField] ?? "").trim();
|
|
5
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(value))
|
|
6
|
+
return undefined;
|
|
7
|
+
try {
|
|
8
|
+
return Temporal.PlainDate.from(value, { overflow: "reject" });
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export function designOccurrences(rows, dateField, daysBefore, time, timeZone, now) {
|
|
15
|
+
if (!validTimeZone(timeZone))
|
|
16
|
+
return [];
|
|
17
|
+
const today = Temporal.Instant.fromEpochMilliseconds(now.valueOf())
|
|
18
|
+
.toZonedDateTimeISO(timeZone)
|
|
19
|
+
.toPlainDate();
|
|
20
|
+
const wanted = Temporal.PlainTime.from(time);
|
|
21
|
+
const found = [];
|
|
22
|
+
for (const [index, row] of rows.entries()) {
|
|
23
|
+
const date = rowDate(row, dateField);
|
|
24
|
+
if (date === undefined)
|
|
25
|
+
continue;
|
|
26
|
+
const over = Temporal.PlainDate.compare(date, today) < 0;
|
|
27
|
+
const planned = date
|
|
28
|
+
.subtract({ days: daysBefore })
|
|
29
|
+
.toPlainDateTime(wanted)
|
|
30
|
+
.toZonedDateTime(timeZone, { disambiguation: "compatible" }).epochMilliseconds;
|
|
31
|
+
found.push({
|
|
32
|
+
at: new Date(over ? now.valueOf() : Math.max(planned, now.valueOf())),
|
|
33
|
+
index,
|
|
34
|
+
over,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
// Soonest first; rows due at the same moment keep their table order.
|
|
38
|
+
return found.toSorted((a, b) => a.at.valueOf() - b.at.valueOf() || a.index - b.index);
|
|
39
|
+
}
|
|
40
|
+
export function nextDesignOccurrence(rows, dateField, daysBefore, time, timeZone, now) {
|
|
41
|
+
return designOccurrences(rows, dateField, daysBefore, time, timeZone, now)[0] ?? null;
|
|
42
|
+
}
|
|
@@ -12,6 +12,11 @@ export const cadenceSchema = z.discriminatedUnion("kind", [
|
|
|
12
12
|
days: z.array(z.number().int().min(0).max(6)).min(1).max(7).readonly(),
|
|
13
13
|
})
|
|
14
14
|
.strict(),
|
|
15
|
+
// A design schedule: each row of its table is made ahead of the date it holds, at this time
|
|
16
|
+
// (`by-date.ts`). Only design schedules use it, and `nextOccurrence` is never asked about it.
|
|
17
|
+
z
|
|
18
|
+
.object({ kind: z.literal("by-date"), time: z.string().regex(/^([01]\d|2[0-3]):[0-5]\d$/) })
|
|
19
|
+
.strict(),
|
|
15
20
|
]);
|
|
16
21
|
export function validTimeZone(timeZone) {
|
|
17
22
|
try {
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { designOccurrences } from "./by-date.js";
|
|
2
|
+
import { designPlanOf } from "./next-run.js";
|
|
3
|
+
// The calendar's runs of a design schedule: one per row still to make, on the day it is made,
|
|
4
|
+
// named by the row's title. A row whose date is over isn't shown; the scheduler skips it.
|
|
5
|
+
export function upcomingDesignRuns(db, schedule, now, from, to) {
|
|
6
|
+
if (schedule.cadence.kind !== "by-date")
|
|
7
|
+
return [];
|
|
8
|
+
const plan = designPlanOf(db, schedule.templateId);
|
|
9
|
+
if (plan === undefined)
|
|
10
|
+
return [];
|
|
11
|
+
return designOccurrences(schedule.items, plan.dateField, plan.daysBefore, schedule.cadence.time, schedule.timezone, now)
|
|
12
|
+
.filter((one) => !one.over && one.at >= from && one.at < to)
|
|
13
|
+
.map((one) => {
|
|
14
|
+
const row = schedule.items[one.index];
|
|
15
|
+
return {
|
|
16
|
+
at: one.at.toISOString(),
|
|
17
|
+
scheduleId: schedule.id,
|
|
18
|
+
scheduleName: schedule.name,
|
|
19
|
+
scheduleVersion: schedule.version,
|
|
20
|
+
paused: schedule.status === "paused",
|
|
21
|
+
templateId: schedule.templateId,
|
|
22
|
+
templateVersion: plan.readyVersion ?? plan.headVersion,
|
|
23
|
+
templateName: plan.name,
|
|
24
|
+
index: one.index,
|
|
25
|
+
topic: row?.title ?? null,
|
|
26
|
+
topicSource: "queued",
|
|
27
|
+
renderedTitle: row?.title ?? null,
|
|
28
|
+
prepared: null,
|
|
29
|
+
templateKind: "design",
|
|
30
|
+
timezone: schedule.timezone,
|
|
31
|
+
// A design template's readiness is the designs' own (runnableDesignVersion), not the
|
|
32
|
+
// template studio's.
|
|
33
|
+
notReady: false,
|
|
34
|
+
};
|
|
35
|
+
});
|
|
36
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { designFields } from "../designs/fields.js";
|
|
2
|
+
import { getTemplate } from "../designs/templates.js";
|
|
3
|
+
import { rowDate } from "./by-date.js";
|
|
4
|
+
import { designPlanOf } from "./next-run.js";
|
|
5
|
+
export function checkDesign(deps, input) {
|
|
6
|
+
const refuse = (message) => ({ ok: false, reason: "invalid-topics", message });
|
|
7
|
+
if (input.cadence.kind !== "by-date" ||
|
|
8
|
+
input.topicGeneration.mode !== "off" ||
|
|
9
|
+
input.topicKeyword !== null ||
|
|
10
|
+
input.releases.length > 0)
|
|
11
|
+
return {
|
|
12
|
+
ok: false,
|
|
13
|
+
reason: "invalid-input",
|
|
14
|
+
message: "A poster schedule makes each row's poster ahead of its date: it has no cadence, topic generation or release days. Choose Ahead of each date.",
|
|
15
|
+
};
|
|
16
|
+
const template = getTemplate(deps.db, input.templateId);
|
|
17
|
+
if (template === undefined)
|
|
18
|
+
return { ok: false, reason: "missing-template" };
|
|
19
|
+
const plan = designPlanOf(deps.db, input.templateId);
|
|
20
|
+
if (plan === undefined)
|
|
21
|
+
return refuse(`The schedule wasn't saved. ${template.name} doesn't say which keyword holds each date. Open it from Templates → Poster templates, choose the date keyword under Schedule, save it, then save the schedule again.`);
|
|
22
|
+
const fields = designFields(plan.document);
|
|
23
|
+
const named = fields.length === 0 ? "none" : fields.map((one) => `{{${one}}}`).join(", ");
|
|
24
|
+
const problems = [];
|
|
25
|
+
for (const keyword of Object.keys(input.values))
|
|
26
|
+
if (!fields.includes(keyword))
|
|
27
|
+
problems.push(`{{${keyword}}} (for every row) is not a keyword of this template (its keywords are ${named}). Remove it.`);
|
|
28
|
+
for (const [index, row] of input.items.entries()) {
|
|
29
|
+
const where = `Row ${String(index + 1)} (${row.title})`;
|
|
30
|
+
for (const keyword of Object.keys(row.values))
|
|
31
|
+
if (!fields.includes(keyword))
|
|
32
|
+
problems.push(`${where} fills {{${keyword}}}, which this template doesn't use (its keywords are ${named}). Remove that column.`);
|
|
33
|
+
if (rowDate(row, plan.dateField) === undefined)
|
|
34
|
+
problems.push(`${where} has no date in {{${plan.dateField}}}. Write it as YYYY-MM-DD, for example 2026-11-14.`);
|
|
35
|
+
}
|
|
36
|
+
if (problems.length === 0)
|
|
37
|
+
return { ok: true, value: template.headVersion };
|
|
38
|
+
const shown = problems.slice(0, 5);
|
|
39
|
+
const more = problems.length - shown.length;
|
|
40
|
+
return refuse(`The schedule wasn't saved. ${shown.join(" ")}${more > 0 ? ` And ${String(more)} more like these.` : ""}`);
|
|
41
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/// <reference lib="esnext.temporal" />
|
|
2
|
+
import { transact } from "../../kernel/db/tx.js";
|
|
3
|
+
import { missingValues } from "../designs/fields.js";
|
|
4
|
+
import { makeFromTemplate, quoteDocument } from "../designs/template-make.js";
|
|
5
|
+
import { designOccurrences } from "./by-date.js";
|
|
6
|
+
import { nextOccurrence } from "./calendar.js";
|
|
7
|
+
import { designPlanOf, missedGraceMs, nextRunOf } from "./next-run.js";
|
|
8
|
+
import { insertRun, scheduleById, updateRun } from "./repo.js";
|
|
9
|
+
// One due run of a design schedule, all at once and in one transaction: it takes the row due
|
|
10
|
+
// soonest, makes its piece from the template's ready version and starts the artwork (the only
|
|
11
|
+
// paid step, made in the background by the design runner), removes the row and records the
|
|
12
|
+
// design on the run. Nothing here waits on a provider, so the tick moves on at once.
|
|
13
|
+
//
|
|
14
|
+
// A row whose date is over is removed with a skipped run that says so. A run that can't start
|
|
15
|
+
// (no ready version, a value missing, over the spend limit, no image provider) keeps its row,
|
|
16
|
+
// records why, and tries again at the same time the next day; marking a version ready tries
|
|
17
|
+
// again at once (`refreshDesignSchedules`). None of this reaches needs_attention: it shows on
|
|
18
|
+
// the schedule's runs.
|
|
19
|
+
export function claimDesignRun(deps, schedule, now) {
|
|
20
|
+
const designs = deps.designs?.();
|
|
21
|
+
transact(deps.db, () => {
|
|
22
|
+
const current = scheduleById(deps.db, schedule.id);
|
|
23
|
+
if (current === undefined ||
|
|
24
|
+
current.version !== schedule.version ||
|
|
25
|
+
current.nextRunAt !== schedule.nextRunAt ||
|
|
26
|
+
current.status !== "active" ||
|
|
27
|
+
current.cadence.kind !== "by-date")
|
|
28
|
+
return;
|
|
29
|
+
const time = current.cadence.time;
|
|
30
|
+
const plan = designPlanOf(deps.db, current.templateId);
|
|
31
|
+
const due = plan === undefined
|
|
32
|
+
? undefined
|
|
33
|
+
: designOccurrences(current.items, plan.dateField, plan.daysBefore, time, current.timezone, now)[0];
|
|
34
|
+
// Rows edited meanwhile: nothing is due yet, so only the next run moves.
|
|
35
|
+
if (plan === undefined || due === undefined || due.at > now) {
|
|
36
|
+
setNext(deps, current, nextRunOf(deps.db, current, now), current.items, now);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const row = current.items[due.index];
|
|
40
|
+
if (row === undefined)
|
|
41
|
+
return;
|
|
42
|
+
const run = (status, error) => ({
|
|
43
|
+
id: deps.uuid(),
|
|
44
|
+
scheduleId: current.id,
|
|
45
|
+
scheduledFor: schedule.nextRunAt ?? now.toISOString(),
|
|
46
|
+
status,
|
|
47
|
+
requestId: null,
|
|
48
|
+
projectIds: [],
|
|
49
|
+
designIds: [],
|
|
50
|
+
estimate: null,
|
|
51
|
+
startedAt: now.toISOString(),
|
|
52
|
+
endedAt: status === "running" ? null : now.toISOString(),
|
|
53
|
+
error,
|
|
54
|
+
});
|
|
55
|
+
const without = current.items.filter((_item, index) => index !== due.index);
|
|
56
|
+
const date = row.values[plan.dateField] ?? "";
|
|
57
|
+
if (due.over) {
|
|
58
|
+
insertRun(deps.db, run("skipped", `Skipped: ${row.title} on ${date} is already over.`));
|
|
59
|
+
setNext(deps, current, nextRunOf(deps.db, { ...current, items: without }, now), without, now);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const tomorrow = () => {
|
|
63
|
+
const next = nextOccurrence({ kind: "daily", time }, current.timezone, now);
|
|
64
|
+
const soonest = nextRunOf(deps.db, current, new Date(now.valueOf() + 1000));
|
|
65
|
+
return next === null ? soonest : soonest === null || soonest < next ? next : soonest;
|
|
66
|
+
};
|
|
67
|
+
const keep = (status, error) => {
|
|
68
|
+
insertRun(deps.db, run(status, error));
|
|
69
|
+
setNext(deps, current, tomorrow(), current.items, now);
|
|
70
|
+
};
|
|
71
|
+
// A run Slopify wasn't open for, like a project schedule's: skipped when the schedule skips
|
|
72
|
+
// missed runs. The row stays and is tried again at the same time the next day.
|
|
73
|
+
const scheduledFor = schedule.nextRunAt === null ? now : new Date(schedule.nextRunAt);
|
|
74
|
+
if (current.missedPolicy === "skip" && now.valueOf() - scheduledFor.valueOf() > missedGraceMs)
|
|
75
|
+
return keep("skipped", `Skipped: Slopify wasn't open at ${time} when ${row.title}'s poster was due, and this schedule skips the runs it misses. It tries again at ${time} tomorrow; to make a missed poster as soon as Slopify opens, set Missed run to Run once when Slopify reopens in Templates → Poster templates → ${plan.name} → Schedule.`);
|
|
76
|
+
if (designs === undefined)
|
|
77
|
+
return keep("failed", "Not started: designs aren't available in this copy of Slopify. Restart Slopify; if it keeps happening, reinstall it.");
|
|
78
|
+
if (plan.readyVersion === null)
|
|
79
|
+
return keep("skipped", `Not started: ${plan.name} has no version approved for schedules. Open it in Templates → Poster templates and press Approve for schedules.`);
|
|
80
|
+
const missing = missingValues(plan.document, row.values);
|
|
81
|
+
if (missing.length > 0) {
|
|
82
|
+
const list = missing.map((name) => `{{${name}}}`).join(", ");
|
|
83
|
+
return keep("failed", `Not started: ${row.title} has no ${list} in its row. Fill ${missing.length === 1 ? "it" : "them"} in under Schedules → ${current.name}; the next try is at ${time}.`);
|
|
84
|
+
}
|
|
85
|
+
const quote = quoteDocument(designs.catalogue(), plan.document);
|
|
86
|
+
if (current.spendLimitCents !== null &&
|
|
87
|
+
(quote.unknown > 0 || quote.high * 100 > current.spendLimitCents))
|
|
88
|
+
return keep("failed", `Not started: ${row.title}'s poster costs up to $${quote.high.toFixed(2)}${quote.unknown > 0 ? " and some prices are unknown" : ""}, over this schedule's spend limit. Raise the spend limit or choose an image model with a known, lower price.`);
|
|
89
|
+
const started = run("running", null);
|
|
90
|
+
if (!insertRun(deps.db, started))
|
|
91
|
+
return;
|
|
92
|
+
const made = makeFromTemplate(designs, current.templateId, {
|
|
93
|
+
mutationId: `schedule-${started.id}`,
|
|
94
|
+
values: row.values,
|
|
95
|
+
acknowledgedHigh: quote.high,
|
|
96
|
+
// A schedule with no spend limit makes pieces whose price is unknown, as it always has.
|
|
97
|
+
acknowledgedUnknown: quote.unknown > 0,
|
|
98
|
+
version: plan.readyVersion,
|
|
99
|
+
name: row.title,
|
|
100
|
+
}, { scheduleId: current.id, scheduleRunId: started.id });
|
|
101
|
+
if (!made.ok) {
|
|
102
|
+
updateRun(deps.db, {
|
|
103
|
+
...started,
|
|
104
|
+
status: "failed",
|
|
105
|
+
endedAt: now.toISOString(),
|
|
106
|
+
error: `Not started: ${made.message}`,
|
|
107
|
+
});
|
|
108
|
+
setNext(deps, current, tomorrow(), current.items, now);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
updateRun(deps.db, {
|
|
112
|
+
...started,
|
|
113
|
+
status: "succeeded",
|
|
114
|
+
designIds: [made.value.id],
|
|
115
|
+
estimate: [quote],
|
|
116
|
+
endedAt: now.toISOString(),
|
|
117
|
+
});
|
|
118
|
+
setNext(deps, current, nextRunOf(deps.db, { ...current, items: without }, now), without, now);
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
// A design schedule stays active when its table empties: rows added later run as they come.
|
|
122
|
+
function setNext(deps, schedule, next, items, now) {
|
|
123
|
+
deps.db
|
|
124
|
+
.prepare("UPDATE schedules SET items_json=?, next_run_at=?, version=version+1, updated_at=? WHERE id=? AND version=?")
|
|
125
|
+
.run(JSON.stringify(items), next?.toISOString() ?? null, now.toISOString(), schedule.id, schedule.version);
|
|
126
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { runnableDesignVersion } from "../designs/gate.js";
|
|
2
|
+
import { getTemplate } from "../designs/templates.js";
|
|
3
|
+
import { nextDesignOccurrence } from "./by-date.js";
|
|
4
|
+
import { nextOccurrence } from "./calendar.js";
|
|
5
|
+
// How late a run may start and still count as on time; later, it was missed (Slopify was
|
|
6
|
+
// closed), and a schedule that skips missed runs skips it.
|
|
7
|
+
export const missedGraceMs = 60_000;
|
|
8
|
+
export function designPlanOf(db, templateId) {
|
|
9
|
+
const template = getTemplate(db, templateId);
|
|
10
|
+
if (template === undefined)
|
|
11
|
+
return undefined;
|
|
12
|
+
const ready = runnableDesignVersion(db, templateId);
|
|
13
|
+
const document = ready?.document ?? template.document;
|
|
14
|
+
const schedule = document.schedule;
|
|
15
|
+
if (schedule === undefined)
|
|
16
|
+
return undefined;
|
|
17
|
+
return {
|
|
18
|
+
name: ready?.name ?? template.name,
|
|
19
|
+
dateField: schedule.dateField,
|
|
20
|
+
daysBefore: schedule.daysBefore,
|
|
21
|
+
readyVersion: ready?.version ?? null,
|
|
22
|
+
headVersion: template.headVersion,
|
|
23
|
+
document,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export function nextRunOf(db, schedule, now) {
|
|
27
|
+
if (schedule.cadence.kind !== "by-date")
|
|
28
|
+
return nextOccurrence(schedule.cadence, schedule.timezone, now);
|
|
29
|
+
const plan = designPlanOf(db, schedule.templateId);
|
|
30
|
+
if (plan === undefined)
|
|
31
|
+
return null;
|
|
32
|
+
return (nextDesignOccurrence(schedule.items, plan.dateField, plan.daysBefore, schedule.cadence.time, schedule.timezone, now)?.at ?? null);
|
|
33
|
+
}
|
|
34
|
+
// Every active design schedule of a template takes its next run again, for when a version is
|
|
35
|
+
// marked ready or the template's dates change.
|
|
36
|
+
export function refreshDesignSchedules(db, templateId, now) {
|
|
37
|
+
const rows = db
|
|
38
|
+
.prepare(`SELECT id FROM schedules WHERE template_kind='design' AND template_id=? AND status='active' AND deleted_at IS NULL`)
|
|
39
|
+
.all(templateId)
|
|
40
|
+
.map((row) => String(row.id));
|
|
41
|
+
let changed = 0;
|
|
42
|
+
for (const id of rows) {
|
|
43
|
+
const raw = db
|
|
44
|
+
.prepare("SELECT cadence_json, timezone, items_json, next_run_at FROM schedules WHERE id=?")
|
|
45
|
+
.get(id);
|
|
46
|
+
if (raw === undefined)
|
|
47
|
+
continue;
|
|
48
|
+
const next = nextRunOf(db, {
|
|
49
|
+
templateKind: "design",
|
|
50
|
+
templateId,
|
|
51
|
+
timezone: String(raw.timezone),
|
|
52
|
+
cadence: JSON.parse(String(raw.cadence_json)),
|
|
53
|
+
items: JSON.parse(String(raw.items_json)),
|
|
54
|
+
}, now);
|
|
55
|
+
const at = next?.toISOString() ?? null;
|
|
56
|
+
if (at === raw.next_run_at)
|
|
57
|
+
continue;
|
|
58
|
+
db.prepare("UPDATE schedules SET next_run_at=?, version=version+1, updated_at=? WHERE id=?").run(at, now.toISOString(), id);
|
|
59
|
+
changed += 1;
|
|
60
|
+
}
|
|
61
|
+
return changed;
|
|
62
|
+
}
|
|
@@ -8,6 +8,7 @@ import { createDraft } from "../play-drafts/service.js";
|
|
|
8
8
|
import { startPlayDraft } from "../play-drafts/start.js";
|
|
9
9
|
import { freshTemplateDraft } from "../project-templates/setup.js";
|
|
10
10
|
import { currentRevisionId } from "../revisions/repo.js";
|
|
11
|
+
import { notTemplateSample } from "../template-studio/repo.js";
|
|
11
12
|
import { scheduleById } from "./repo.js";
|
|
12
13
|
import { renderedTitle, scheduledValues } from "./topic-list.js";
|
|
13
14
|
// The draft a schedule's run starts for one topic: the template as it is now, the topic in its
|
|
@@ -43,9 +44,19 @@ export async function prepareTopic(deps, input) {
|
|
|
43
44
|
const schedule = scheduleById(deps.db, input.scheduleId);
|
|
44
45
|
if (schedule === undefined)
|
|
45
46
|
return { ok: false, reason: "not-found" };
|
|
47
|
+
// A design schedule's piece is made on its day; there is no video to hold back.
|
|
48
|
+
if (schedule.templateKind === "design")
|
|
49
|
+
return { ok: false, reason: "design" };
|
|
50
|
+
// A paused schedule makes nothing, ahead or on its day.
|
|
51
|
+
if (schedule.status === "paused")
|
|
52
|
+
return { ok: false, reason: "paused" };
|
|
46
53
|
const topic = schedule.items.find((item) => item.title === input.title);
|
|
47
54
|
if (topic === undefined)
|
|
48
55
|
return { ok: false, reason: "not-found" };
|
|
56
|
+
// Prepared ahead is the schedule's run made early: it waits for a ready version too.
|
|
57
|
+
const notReady = deps.notReady?.(schedule.templateId);
|
|
58
|
+
if (notReady !== undefined)
|
|
59
|
+
return { ok: false, reason: "not-ready", detail: notReady };
|
|
49
60
|
const document = scheduledDocument(deps, schedule, topic);
|
|
50
61
|
if (document === undefined)
|
|
51
62
|
return { ok: false, reason: "missing-template" };
|
|
@@ -104,9 +115,13 @@ const ended = new Set(["done", "partial", "failed", "canceled"]);
|
|
|
104
115
|
// run the same title, so only a prepared project counts there.
|
|
105
116
|
export function preparedProject(db, scheduleId, title, byTitle = true) {
|
|
106
117
|
const live = "project_id NOT IN (SELECT project_id FROM project_trash)";
|
|
118
|
+
// A template studio sample is titled from the template's next queued topic, so it can have
|
|
119
|
+
// the run's title; it is the studio's alone and never the run's to continue.
|
|
107
120
|
const prepared = db
|
|
108
121
|
.prepare(`SELECT project_id, added_checkpoint FROM prepared_videos
|
|
109
|
-
WHERE schedule_id=? AND title=? AND ${live}
|
|
122
|
+
WHERE schedule_id=? AND title=? AND ${live}
|
|
123
|
+
AND ${notTemplateSample("prepared_videos", "project_id")}
|
|
124
|
+
ORDER BY prepared_at DESC LIMIT 1`)
|
|
110
125
|
.get(scheduleId, title);
|
|
111
126
|
// A prepared project canceled since is no video to continue: the day makes a new one.
|
|
112
127
|
if (typeof prepared?.project_id === "string" &&
|
|
@@ -115,7 +130,8 @@ export function preparedProject(db, scheduleId, title, byTitle = true) {
|
|
|
115
130
|
if (!byTitle)
|
|
116
131
|
return undefined;
|
|
117
132
|
for (const row of db
|
|
118
|
-
.prepare(
|
|
133
|
+
.prepare(`SELECT id FROM projects WHERE title=? AND id NOT IN (SELECT project_id FROM project_trash)
|
|
134
|
+
AND ${notTemplateSample()} ORDER BY created_at DESC`)
|
|
119
135
|
.all(title)) {
|
|
120
136
|
const id = String(row.id);
|
|
121
137
|
if (!ended.has(derive(stagesOf(db, id), projectPaused(db, id))))
|
|
@@ -4,10 +4,12 @@ import { transact } from "../../kernel/db/tx.js";
|
|
|
4
4
|
import { derive } from "../../kernel/runner/graph.js";
|
|
5
5
|
import { projectExists, projectPaused, stagesOf } from "../admission/repo.js";
|
|
6
6
|
import { readStartReceipt } from "../play-drafts/start-repo.js";
|
|
7
|
+
import { setupSectionNames } from "../project-templates/setup-sections.js";
|
|
7
8
|
import { scheduleRunSchema, scheduleSummarySchema, } from "./schema.js";
|
|
8
9
|
const rowSchema = z.object({
|
|
9
10
|
id: z.string(),
|
|
10
11
|
name: z.string(),
|
|
12
|
+
template_kind: z.string(),
|
|
11
13
|
template_id: z.string(),
|
|
12
14
|
template_version: z.number(),
|
|
13
15
|
cadence_json: z.string(),
|
|
@@ -33,12 +35,13 @@ const rowSchema = z.object({
|
|
|
33
35
|
topics_failed_at: z.string().nullable(),
|
|
34
36
|
topics_error: z.string().nullable(),
|
|
35
37
|
releases_json: z.string().nullable(),
|
|
38
|
+
topic_scoring: z.string(),
|
|
36
39
|
held_topics: z.number(),
|
|
37
40
|
});
|
|
38
|
-
const scheduleColumns = `id,name,template_id,template_version,cadence_json,timezone,missed_policy,
|
|
41
|
+
const scheduleColumns = `id,name,template_kind,template_id,template_version,cadence_json,timezone,missed_policy,
|
|
39
42
|
overlap_policy,spend_limit_cents,items_json,topic_keyword,values_json,status,version,next_run_at,
|
|
40
43
|
created_at,updated_at,deleted_at,brief,topic_mode,topic_min,topic_llm_json,topics_generating_at,
|
|
41
|
-
topics_generated_at,topics_failed_at,topics_error,releases_json,
|
|
44
|
+
topics_generated_at,topics_failed_at,topics_error,releases_json,topic_scoring,
|
|
42
45
|
(SELECT count(*) FROM schedule_topics AS held
|
|
43
46
|
WHERE held.schedule_id=schedules.id AND held.state='held') AS held_topics`;
|
|
44
47
|
export function scheduleById(db, id) {
|
|
@@ -66,11 +69,11 @@ export function dueSchedules(db, now) {
|
|
|
66
69
|
}
|
|
67
70
|
export function insertSchedule(db, schedule, creationHash) {
|
|
68
71
|
db.prepare(`INSERT INTO schedules
|
|
69
|
-
(id,name,template_id,template_version,cadence_json,timezone,missed_policy,
|
|
70
|
-
spend_limit_cents,items_json,topic_keyword,values_json,status,version,
|
|
71
|
-
next_run_at,created_at,updated_at,deleted_at,brief,topic_mode,topic_min,
|
|
72
|
-
releases_json)
|
|
73
|
-
VALUES (
|
|
72
|
+
(id,name,template_kind,template_id,template_version,cadence_json,timezone,missed_policy,
|
|
73
|
+
overlap_policy,spend_limit_cents,items_json,topic_keyword,values_json,status,version,
|
|
74
|
+
creation_hash,next_run_at,created_at,updated_at,deleted_at,brief,topic_mode,topic_min,
|
|
75
|
+
topic_llm_json,releases_json,topic_scoring)
|
|
76
|
+
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`).run(schedule.id, schedule.name, schedule.templateKind, schedule.templateId, schedule.templateVersion, JSON.stringify(schedule.cadence), schedule.timezone, schedule.missedPolicy, schedule.overlapPolicy, schedule.spendLimitCents, JSON.stringify(schedule.items), schedule.topicKeyword, JSON.stringify(schedule.values), schedule.status, schedule.version, creationHash, schedule.nextRunAt, schedule.createdAt, schedule.updatedAt, schedule.deletedAt, ...generationColumns(schedule));
|
|
74
77
|
}
|
|
75
78
|
function generationColumns(schedule) {
|
|
76
79
|
const generation = schedule.topicGeneration;
|
|
@@ -80,18 +83,20 @@ function generationColumns(schedule) {
|
|
|
80
83
|
generation.keepAtLeast,
|
|
81
84
|
generation.llm === null ? null : JSON.stringify(generation.llm),
|
|
82
85
|
schedule.releases.length === 0 ? null : JSON.stringify(schedule.releases),
|
|
86
|
+
schedule.topicScoring,
|
|
83
87
|
];
|
|
84
88
|
}
|
|
85
89
|
export function updateScheduleRow(db, schedule, mutationId, mutationHash, baseVersion) {
|
|
86
90
|
const changed = db
|
|
87
|
-
.prepare(`UPDATE schedules SET name=?,template_id=?,template_version=?,cadence_json=?,timezone=?,
|
|
91
|
+
.prepare(`UPDATE schedules SET name=?,template_kind=?,template_id=?,template_version=?,cadence_json=?,timezone=?,
|
|
88
92
|
missed_policy=?,overlap_policy=?,spend_limit_cents=?,items_json=?,topic_keyword=?,
|
|
89
93
|
values_json=?,status=?,version=?,
|
|
90
94
|
next_run_at=?,updated_at=?,mutation_id=?,mutation_hash=?,
|
|
91
|
-
brief=?,topic_mode=?,topic_min=?,topic_llm_json=?,releases_json=?,
|
|
95
|
+
brief=?,topic_mode=?,topic_min=?,topic_llm_json=?,releases_json=?,topic_scoring=?,
|
|
96
|
+
topics_failed_at=NULL,
|
|
92
97
|
topics_error=NULL
|
|
93
98
|
WHERE id=? AND version=? AND deleted_at IS NULL`)
|
|
94
|
-
.run(schedule.name, schedule.templateId, schedule.templateVersion, JSON.stringify(schedule.cadence), schedule.timezone, schedule.missedPolicy, schedule.overlapPolicy, schedule.spendLimitCents, JSON.stringify(schedule.items), schedule.topicKeyword, JSON.stringify(schedule.values), schedule.status, schedule.version, schedule.nextRunAt, schedule.updatedAt, mutationId, mutationHash, ...generationColumns(schedule), schedule.id, baseVersion);
|
|
99
|
+
.run(schedule.name, schedule.templateKind, schedule.templateId, schedule.templateVersion, JSON.stringify(schedule.cadence), schedule.timezone, schedule.missedPolicy, schedule.overlapPolicy, schedule.spendLimitCents, JSON.stringify(schedule.items), schedule.topicKeyword, JSON.stringify(schedule.values), schedule.status, schedule.version, schedule.nextRunAt, schedule.updatedAt, mutationId, mutationHash, ...generationColumns(schedule), schedule.id, baseVersion);
|
|
95
100
|
return Number(changed.changes) === 1;
|
|
96
101
|
}
|
|
97
102
|
export function tombstoneScheduleRow(db, id, version, deletedAt) {
|
|
@@ -111,8 +116,8 @@ export function setScheduleStatus(db, id, version, status, nextRunAt, updatedAt)
|
|
|
111
116
|
export function insertRun(db, run) {
|
|
112
117
|
try {
|
|
113
118
|
db.prepare(`INSERT INTO schedule_runs
|
|
114
|
-
(id,schedule_id,scheduled_for,status,request_id,project_ids_json,estimate_json,started_at,ended_at,error)
|
|
115
|
-
VALUES (
|
|
119
|
+
(id,schedule_id,scheduled_for,status,request_id,project_ids_json,design_ids_json,estimate_json,started_at,ended_at,error)
|
|
120
|
+
VALUES (?,?,?,?,?,?,?,?,?,?,?)`).run(run.id, run.scheduleId, run.scheduledFor, run.status, run.requestId, JSON.stringify(run.projectIds), JSON.stringify(run.designIds), run.estimate === null ? null : JSON.stringify(run.estimate), run.startedAt, run.endedAt, run.error);
|
|
116
121
|
return true;
|
|
117
122
|
}
|
|
118
123
|
catch (error) {
|
|
@@ -122,8 +127,8 @@ export function insertRun(db, run) {
|
|
|
122
127
|
}
|
|
123
128
|
}
|
|
124
129
|
export function updateRun(db, run) {
|
|
125
|
-
db.prepare(`UPDATE schedule_runs SET status=?,request_id=?,project_ids_json=?,
|
|
126
|
-
ended_at=?,error=? WHERE id=?`).run(run.status, run.requestId, JSON.stringify(run.projectIds), run.estimate === null ? null : JSON.stringify(run.estimate), run.endedAt, run.error, run.id);
|
|
130
|
+
db.prepare(`UPDATE schedule_runs SET status=?,request_id=?,project_ids_json=?,design_ids_json=?,
|
|
131
|
+
estimate_json=?,ended_at=?,error=? WHERE id=?`).run(run.status, run.requestId, JSON.stringify(run.projectIds), JSON.stringify(run.designIds), run.estimate === null ? null : JSON.stringify(run.estimate), run.endedAt, run.error, run.id);
|
|
127
132
|
}
|
|
128
133
|
export function recordRunStartIdentity(db, run) {
|
|
129
134
|
if (run.requestId === null)
|
|
@@ -174,8 +179,8 @@ function consumeTopic(db, scheduleId, used, updatedAt) {
|
|
|
174
179
|
}
|
|
175
180
|
export function runsForSchedule(db, scheduleId) {
|
|
176
181
|
return db
|
|
177
|
-
.prepare(`SELECT id,schedule_id,scheduled_for,status,request_id,project_ids_json,
|
|
178
|
-
started_at,ended_at,error FROM schedule_runs WHERE schedule_id=? ORDER BY started_at DESC,id DESC`)
|
|
182
|
+
.prepare(`SELECT id,schedule_id,scheduled_for,status,request_id,project_ids_json,design_ids_json,
|
|
183
|
+
estimate_json,started_at,ended_at,error FROM schedule_runs WHERE schedule_id=? ORDER BY started_at DESC,id DESC`)
|
|
179
184
|
.all(scheduleId)
|
|
180
185
|
.map(parseRun);
|
|
181
186
|
}
|
|
@@ -288,6 +293,7 @@ function parseSchedule(row) {
|
|
|
288
293
|
return scheduleSummarySchema.parse({
|
|
289
294
|
id: value.id,
|
|
290
295
|
name: value.name,
|
|
296
|
+
templateKind: value.template_kind,
|
|
291
297
|
templateId: value.template_id,
|
|
292
298
|
templateVersion: value.template_version,
|
|
293
299
|
cadence: JSON.parse(value.cadence_json),
|
|
@@ -305,6 +311,7 @@ function parseSchedule(row) {
|
|
|
305
311
|
llm: value.topic_llm_json === null ? null : JSON.parse(value.topic_llm_json),
|
|
306
312
|
},
|
|
307
313
|
releases: value.releases_json === null ? [] : JSON.parse(value.releases_json),
|
|
314
|
+
topicScoring: value.topic_scoring,
|
|
308
315
|
topics: {
|
|
309
316
|
held: value.held_topics,
|
|
310
317
|
generatingSince: value.topics_generating_at,
|
|
@@ -329,6 +336,7 @@ function parseRun(row) {
|
|
|
329
336
|
status: z.string(),
|
|
330
337
|
request_id: z.string().nullable(),
|
|
331
338
|
project_ids_json: z.string(),
|
|
339
|
+
design_ids_json: z.string(),
|
|
332
340
|
estimate_json: z.string().nullable(),
|
|
333
341
|
started_at: z.string(),
|
|
334
342
|
ended_at: z.string().nullable(),
|
|
@@ -342,6 +350,7 @@ function parseRun(row) {
|
|
|
342
350
|
status: value.status,
|
|
343
351
|
requestId: value.request_id,
|
|
344
352
|
projectIds: JSON.parse(value.project_ids_json),
|
|
353
|
+
designIds: JSON.parse(value.design_ids_json),
|
|
345
354
|
estimate: value.estimate_json === null ? null : JSON.parse(value.estimate_json),
|
|
346
355
|
startedAt: value.started_at,
|
|
347
356
|
endedAt: value.ended_at,
|
|
@@ -353,12 +362,12 @@ function parseRun(row) {
|
|
|
353
362
|
const internalRunError = "Slopify hit an internal error while starting this run. The next run will try again; if it keeps happening, use Download diagnostics in Settings and report it.";
|
|
354
363
|
const runErrors = {
|
|
355
364
|
"missing-template": "The template this schedule uses was deleted or changed. Edit the schedule and choose a template again.",
|
|
356
|
-
"unsupported-media":
|
|
365
|
+
"unsupported-media": `This template uses audio, images, a thumbnail, shorts background music or an ambient sound file you supplied, which scheduled runs cannot use. Pick a template that generates these instead, or open this one in Edit template, remove the music under ${setupSectionNames.shorts} (or pick Rain, Fireplace or Wind as the Ambient sound under ${setupSectionNames.video}) and save it again.`,
|
|
357
366
|
"spend-limit": "Not started: the estimated cost was above this schedule's spend limit, or some prices were unknown. Raise the spend limit or choose models with known prices.",
|
|
358
|
-
readiness: "Not started: a provider was not ready, for example a missing API key, model or voice. Check Settings →
|
|
359
|
-
"not-found": "The template's settings are no longer valid, for example a prompt or voice it uses was deleted. Fix the template in
|
|
360
|
-
"invalid-draft": "The template's settings are no longer valid, for example a prompt or voice it uses was deleted. Fix the template in
|
|
361
|
-
"invalid-edit": "The template's settings are no longer valid, for example a prompt or voice it uses was deleted. Fix the template in
|
|
367
|
+
readiness: "Not started: a provider was not ready, for example a missing API key, model or voice. Check Settings → Keys & services; the next run will try again.",
|
|
368
|
+
"not-found": "The template's settings are no longer valid, for example a prompt or voice it uses was deleted. Fix the template in Templates → Edit template and save it.",
|
|
369
|
+
"invalid-draft": "The template's settings are no longer valid, for example a prompt or voice it uses was deleted. Fix the template in Templates → Edit template and save it.",
|
|
370
|
+
"invalid-edit": "The template's settings are no longer valid, for example a prompt or voice it uses was deleted. Fix the template in Templates → Edit template and save it.",
|
|
362
371
|
conflict: internalRunError,
|
|
363
372
|
"pending-start": internalRunError,
|
|
364
373
|
"already-started": internalRunError,
|