@gentbajko/slopify 3.25.9 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/account-limits.js +30 -0
- package/dist/adapters/alignment/cache.js +3 -5
- package/dist/adapters/alignment/ctc.js +1 -2
- package/dist/adapters/alignment/lock.js +4 -3
- package/dist/adapters/alignment/multilingual.js +0 -3
- package/dist/adapters/alignment/prefetch.js +2 -1
- package/dist/adapters/alignment/worker.js +2 -1
- package/dist/adapters/explain.js +0 -3
- package/dist/adapters/ffmpeg.js +19 -1
- package/dist/adapters/host-cli/index.js +19 -3
- package/dist/adapters/http-failure.js +53 -0
- package/dist/adapters/image/codex.js +36 -4
- package/dist/adapters/image/fal.js +17 -50
- package/dist/adapters/image/google.js +31 -55
- package/dist/adapters/image/openai.js +20 -47
- package/dist/adapters/image/reference.js +36 -0
- package/dist/adapters/image/replicate.js +18 -47
- package/dist/adapters/interest/search-interest.js +113 -0
- package/dist/adapters/key-probes.js +53 -2
- package/dist/adapters/llm/antigravity.js +4 -0
- 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 +51 -98
- package/dist/adapters/llm/claude-code.js +13 -2
- package/dist/adapters/llm/codex-limits.js +27 -68
- package/dist/adapters/llm/codex-server-models.js +61 -109
- package/dist/adapters/llm/codex.js +12 -1
- package/dist/adapters/llm/openrouter.js +10 -47
- package/dist/adapters/llm/run-cli.js +6 -22
- 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 +19 -40
- package/dist/adapters/tts/inworld-async.js +4 -1
- package/dist/adapters/tts/inworld.js +3 -0
- package/dist/adapters/tts/openai.js +20 -50
- 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 +3 -1
- package/dist/catalog/schema.js +2 -0
- package/dist/catalog/store.js +39 -0
- 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 +4 -25
- package/dist/edge/http/actor.js +5 -3
- package/dist/edge/http/app.js +85 -10
- package/dist/edge/http/assistant.js +127 -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 +1 -3
- package/dist/edge/http/channel-memory.js +7 -20
- package/dist/edge/http/channels.js +13 -26
- package/dist/edge/http/checkpoints.js +33 -17
- 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 +2 -11
- package/dist/edge/http/draft-files.js +1 -3
- package/dist/edge/http/draft-problem.js +4 -9
- 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 +38 -13
- 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 +1 -14
- package/dist/edge/http/open-folder.js +5 -10
- package/dist/edge/http/outputs.js +4 -12
- package/dist/edge/http/patch-notes.js +4 -10
- package/dist/edge/http/planning.js +2 -6
- package/dist/edge/http/problem.js +2 -4
- package/dist/edge/http/project-create.js +1 -0
- package/dist/edge/http/project-templates.js +29 -17
- package/dist/edge/http/projects.js +2 -12
- package/dist/edge/http/prompts.js +7 -14
- package/dist/edge/http/pronunciations.js +1 -2
- package/dist/edge/http/providers.js +39 -24
- 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 +11 -24
- package/dist/edge/http/revision-files.js +5 -10
- package/dist/edge/http/revisions.js +10 -15
- package/dist/edge/http/run-cost.js +1 -2
- package/dist/edge/http/same-page.js +80 -0
- package/dist/edge/http/schedules.js +59 -32
- package/dist/edge/http/settings.js +22 -13
- package/dist/edge/http/social.js +282 -0
- package/dist/edge/http/staging.js +2 -4
- package/dist/edge/http/storage-files.js +5 -7
- package/dist/edge/http/storage.js +23 -23
- package/dist/edge/http/studio.js +23 -50
- package/dist/edge/http/style-preview.js +1 -4
- package/dist/edge/http/subtitles.js +3 -17
- package/dist/edge/http/template-studio.js +433 -0
- package/dist/edge/http/trash.js +10 -11
- 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 +2 -3
- 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 +25 -0
- package/dist/edge/mcp/http.js +11 -2
- package/dist/edge/mcp/instructions.js +5 -3
- package/dist/edge/mcp/library-tools.js +1 -0
- package/dist/edge/mcp/route-tool.js +35 -15
- package/dist/edge/mcp/server.js +13 -8
- package/dist/edge/mcp/tools-channels.js +2 -0
- package/dist/edge/mcp/tools-designs.js +165 -0
- package/dist/edge/mcp/tools-library.js +14 -2
- package/dist/edge/mcp/tools-planning.js +23 -4
- package/dist/edge/mcp/tools-projects.js +28 -1
- package/dist/edge/mcp/tools-runs.js +14 -1
- package/dist/edge/mcp/tools-schedules.js +28 -4
- package/dist/edge/mcp/tools-setup.js +61 -3
- package/dist/edge/mcp/tools-social.js +46 -0
- package/dist/edge/mcp/tools-storage.js +8 -0
- 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/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/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/runner/attempt.js +3 -1
- 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 +15 -10
- package/dist/kernel/runner/standalone.js +9 -5
- package/dist/main.js +334 -19
- package/dist/model-checks.js +166 -0
- package/dist/patch-notes/4.0.0.md +51 -0
- package/dist/patch-notes/index.json +6 -0
- package/dist/slices/admission/heads.js +2 -1
- package/dist/slices/admission/repo.js +2 -1
- package/dist/slices/admission/rules.js +43 -8
- 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/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 +79 -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 +342 -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 +4 -3
- package/dist/slices/channels/cast-images.js +2 -1
- 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 +6 -0
- package/dist/slices/channels/service.js +10 -0
- package/dist/slices/channels/videos.js +2 -14
- package/dist/slices/checkpoints/index.js +0 -1
- package/dist/slices/control/providers.js +0 -26
- 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 +128 -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 +222 -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/episodes/summarize.js +5 -1
- package/dist/slices/estimate/index.js +45 -7
- package/dist/slices/fonts/catalog.js +3 -2
- 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 +6 -15
- package/dist/slices/images/scenes.js +100 -27
- package/dist/slices/keywords/digest.js +84 -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 +2 -1
- package/dist/slices/library/used-by.js +25 -10
- package/dist/slices/loudness/loudnorm.js +51 -11
- 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 +112 -0
- package/dist/slices/model-checks/run.js +143 -0
- package/dist/slices/model-checks/service.js +198 -0
- package/dist/slices/model-upkeep/switch.js +70 -25
- package/dist/slices/model-upkeep/usage.js +26 -11
- package/dist/slices/narration/breaths.js +2 -1
- package/dist/slices/narration/clean-pieces.js +2 -1
- package/dist/slices/narration/concat.js +2 -1
- package/dist/slices/narration/peaks.js +3 -4
- package/dist/slices/narration/pronunciation-chunks.js +4 -3
- package/dist/slices/narration/pronunciation.js +3 -2
- 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 +2 -1
- package/dist/slices/onboarding/copy.js +2 -1
- package/dist/slices/onboarding/first-run.js +3 -2
- package/dist/slices/onboarding/full-video.js +3 -2
- package/dist/slices/onboarding/install.js +4 -3
- package/dist/slices/onboarding/model.js +0 -16
- package/dist/slices/onboarding/packs.js +22 -22
- package/dist/slices/onboarding/quick-short.js +2 -1
- package/dist/slices/onboarding/sample.js +0 -1
- package/dist/slices/onboarding/state.js +2 -11
- package/dist/slices/onboarding/template.js +2 -1
- package/dist/slices/patch-notes/library.js +3 -2
- package/dist/slices/play-drafts/convert.js +4 -0
- package/dist/slices/play-drafts/review-inputs.js +8 -2
- package/dist/slices/play-drafts/review.js +5 -4
- package/dist/slices/play-drafts/schema.js +4 -0
- package/dist/slices/project-templates/from-project.js +9 -2
- package/dist/slices/project-templates/repo.js +6 -1
- package/dist/slices/project-templates/setup.js +8 -0
- 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 +27 -9
- 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 +3 -3
- 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 +6 -3
- 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 +98 -28
- package/dist/slices/rebuild/recipe-visual.js +55 -16
- package/dist/slices/rebuild/recipe-work.js +15 -3
- package/dist/slices/rebuild/recipe-youtube.js +4 -3
- package/dist/slices/rebuild/recovery-selection.js +3 -1
- package/dist/slices/rebuild/recovery.js +3 -2
- package/dist/slices/rebuild/repo.js +4 -3
- package/dist/slices/rebuild/review-promise.js +25 -0
- package/dist/slices/rebuild/review-redo.js +2 -1
- 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 +9 -8
- package/dist/slices/rebuild/runtime-article.js +3 -2
- package/dist/slices/rebuild/runtime-checkpoints.js +5 -4
- package/dist/slices/rebuild/runtime-document.js +8 -11
- package/dist/slices/rebuild/runtime-export-bed.js +6 -11
- package/dist/slices/rebuild/runtime-export-edit.js +6 -15
- package/dist/slices/rebuild/runtime-export-inputs.js +7 -7
- package/dist/slices/rebuild/runtime-export-short.js +8 -4
- package/dist/slices/rebuild/runtime-export.js +34 -12
- package/dist/slices/rebuild/runtime-figure-card.js +2 -1
- package/dist/slices/rebuild/runtime-image.js +4 -9
- 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 +14 -20
- 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 +10 -15
- 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 +60 -19
- package/dist/slices/rebuild/runtime-publication.js +10 -9
- package/dist/slices/rebuild/runtime-review.js +33 -28
- package/dist/slices/rebuild/runtime-run.js +4 -1
- package/dist/slices/rebuild/runtime-shorts.js +25 -45
- package/dist/slices/rebuild/runtime-store.js +3 -8
- package/dist/slices/rebuild/runtime-subtitles.js +16 -14
- package/dist/slices/rebuild/runtime-voices.js +8 -15
- package/dist/slices/rebuild/runtime-youtube.js +11 -29
- 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/reviews/external-model.js +3 -0
- package/dist/slices/reviews/external-repo.js +2 -1
- package/dist/slices/reviews/external-rows.js +2 -3
- package/dist/slices/reviews/model.js +26 -8
- package/dist/slices/reviews/repo.js +2 -1
- package/dist/slices/reviews/rules.js +1 -0
- package/dist/slices/reviews/view.js +5 -2
- package/dist/slices/revisions/downloads.js +4 -5
- package/dist/slices/revisions/mutation-assets.js +7 -4
- package/dist/slices/revisions/mutation-cues.js +2 -5
- package/dist/slices/revisions/mutations.js +0 -1
- 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 +11 -2
- 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 +24 -16
- package/dist/slices/schedules/rescore.js +35 -0
- package/dist/slices/schedules/scheduler.js +13 -3
- package/dist/slices/schedules/schema.js +54 -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 +48 -36
- package/dist/slices/settings/cli-paths.js +4 -6
- package/dist/slices/settings/first-run.js +2 -11
- package/dist/slices/settings/model-reach.js +3 -17
- package/dist/slices/settings/model.js +10 -0
- package/dist/slices/settings/playback.js +33 -22
- 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/pick.js +2 -15
- package/dist/slices/shorts/prompts.js +2 -13
- package/dist/slices/shorts/render.js +3 -0
- 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 +131 -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 +55 -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 +128 -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 +20 -2
- 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 +16 -11
- 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 +10 -3
- package/dist/slices/studio/calendar.js +4 -1
- package/dist/slices/studio/pick.js +2 -11
- package/dist/slices/studio/plan.js +6 -15
- package/dist/slices/studio/queue.js +3 -14
- package/dist/slices/studio/releases.js +26 -0
- package/dist/slices/studio/settings.js +14 -51
- package/dist/slices/studio/videos.js +12 -0
- package/dist/slices/style-preview/render.js +34 -13
- package/dist/slices/style-preview/schema.js +13 -0
- package/dist/slices/style-preview/service.js +2 -1
- package/dist/slices/style-preview/settings.js +33 -5
- 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 +118 -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 +103 -0
- package/dist/slices/template-studio/checks.js +273 -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 +54 -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 +205 -0
- package/dist/slices/template-studio/paid-view.js +66 -0
- package/dist/slices/template-studio/paid.js +348 -0
- package/dist/slices/template-studio/quote.js +148 -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 +30 -0
- package/dist/slices/template-studio/schedule-sample.js +87 -0
- package/dist/slices/template-studio/schema.js +218 -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 +173 -0
- package/dist/slices/template-studio/status.js +174 -0
- package/dist/slices/template-studio/topic.js +223 -0
- 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/video/ass-text.js +17 -0
- package/dist/slices/video/audio-export.js +2 -64
- package/dist/slices/video/encoding.js +160 -0
- package/dist/slices/video/ffmpeg.js +23 -21
- package/dist/slices/video/figure-card.js +1 -15
- package/dist/slices/video/slideshow.js +43 -18
- package/dist/slices/voices/palette.js +0 -3
- package/dist/slices/youtube/answer.js +2 -15
- package/dist/slices/youtube/edits-repo.js +2 -11
- package/dist/tutorials/Agents-MCP.md +2 -1
- package/dist/tutorials/Assistant.md +42 -0
- package/dist/tutorials/Channels.md +2 -0
- package/dist/tutorials/Home-and-Projects.md +19 -0
- package/dist/tutorials/Install.md +1 -0
- package/dist/tutorials/Keywords-Slopify-Fills.md +87 -0
- package/dist/tutorials/Models.md +33 -1
- package/dist/tutorials/Notifications.md +6 -0
- package/dist/tutorials/Play-Images.md +4 -0
- package/dist/tutorials/Posting-to-Social-Sites.md +121 -0
- package/dist/tutorials/Prompts.md +10 -6
- package/dist/tutorials/Remote-Access.md +63 -0
- package/dist/tutorials/Reviews-and-Checkpoints.md +13 -2
- package/dist/tutorials/Schedules.md +21 -1
- package/dist/tutorials/Settings-Reference.md +50 -8
- package/dist/tutorials/Template-Studio.md +125 -0
- package/dist/tutorials/Templates.md +3 -0
- package/dist/tutorials/_Sidebar.md +5 -0
- package/dist/updater/work-in-progress.js +42 -12
- package/dist/web/assets/index-CkAI_2E7.css +1 -0
- package/dist/web/assets/index-DcD0cdfo.js +334 -0
- package/dist/web/assets/{pdf-T7MCwjIv.js → pdf-TODRwF31.js} +1 -1
- package/dist/web/index.html +2 -2
- package/package.json +5 -1
- 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/web/assets/index-BadsoORk.css +0 -1
- package/dist/web/assets/index-D8LqNsCl.js +0 -326
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { keyProbes } from "./adapters/key-probes.js";
|
|
2
|
+
import { emptyLifecycle, retirementOf } from "./catalog/lifecycle.js";
|
|
3
|
+
import { thinkingModes } from "./kernel/ports/llm.js";
|
|
4
|
+
import { readinessIsUsable } from "./kernel/ports/model.js";
|
|
5
|
+
import { checkModel } from "./kernel/runner/model-check.js";
|
|
6
|
+
import { modelSources } from "./model-catalog.js";
|
|
7
|
+
import { isVideoTarget, spentOn } from "./slices/model-checks/cost.js";
|
|
8
|
+
import { createListing } from "./slices/model-checks/listing.js";
|
|
9
|
+
import { createModelChecks } from "./slices/model-checks/service.js";
|
|
10
|
+
import { isLocalCliProvider, systemVoiceProvider, } from "./slices/settings/model.js";
|
|
11
|
+
import { listVoices } from "./slices/settings/repo.js";
|
|
12
|
+
// The composition layer's check recipes: what the smallest request is for each kind of model.
|
|
13
|
+
// A reply of one word at the lowest thinking setting, a voice saying "Hi", a one-to-one grey
|
|
14
|
+
// dot. Image-to-video models are listed only, never generated.
|
|
15
|
+
export const checkPrompt = "Reply with OK.";
|
|
16
|
+
export const checkSpeech = "Hi";
|
|
17
|
+
export const checkPicture = "a small grey dot";
|
|
18
|
+
// A voice every account of these providers has, for a check made before any voice is saved.
|
|
19
|
+
const defaultVoices = {
|
|
20
|
+
"openai-tts": "alloy",
|
|
21
|
+
"google-tts": "Kore",
|
|
22
|
+
// ElevenLabs' premade "Rachel".
|
|
23
|
+
elevenlabs: "21m00Tcm4TlvDq8ikWAM",
|
|
24
|
+
};
|
|
25
|
+
function lowest(modes) {
|
|
26
|
+
if (modes === undefined || modes.length === 0)
|
|
27
|
+
return undefined;
|
|
28
|
+
return thinkingModes.find((mode) => modes.includes(mode));
|
|
29
|
+
}
|
|
30
|
+
export async function recipeFor(deps, target) {
|
|
31
|
+
const catalogue = deps.catalogue();
|
|
32
|
+
const { provider, model } = target;
|
|
33
|
+
if (target.family === "llm") {
|
|
34
|
+
let modes;
|
|
35
|
+
if (isLocalCliProvider(provider))
|
|
36
|
+
modes = (await deps.cliModels(provider, "llm").catch(() => [])).find((m) => m.id === model)?.thinkingModes;
|
|
37
|
+
else {
|
|
38
|
+
const row = catalogue.llm.find((m) => m.provider === provider && m.id === model);
|
|
39
|
+
modes = row?.llm.thinking === undefined ? undefined : Object.keys(row.llm.thinking);
|
|
40
|
+
}
|
|
41
|
+
const thinking = lowest(modes);
|
|
42
|
+
return {
|
|
43
|
+
kind: "call",
|
|
44
|
+
call: {
|
|
45
|
+
kind: "llm",
|
|
46
|
+
provider,
|
|
47
|
+
model,
|
|
48
|
+
prompt: checkPrompt,
|
|
49
|
+
...(thinking === undefined ? {} : { thinking }),
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
if (target.family === "tts") {
|
|
54
|
+
if (provider === systemVoiceProvider)
|
|
55
|
+
return (await deps.systemVoiceReady())
|
|
56
|
+
? { kind: "free-works" }
|
|
57
|
+
: { kind: "skip", reason: "No speech program was found on this computer." };
|
|
58
|
+
const voiceId = deps.voices().find((voice) => voice.provider === provider)?.voiceId ??
|
|
59
|
+
(Object.hasOwn(defaultVoices, provider) ? defaultVoices[provider] : undefined);
|
|
60
|
+
if (voiceId === undefined)
|
|
61
|
+
return {
|
|
62
|
+
kind: "skip",
|
|
63
|
+
reason: "Add a voice for this provider in Settings → Voices, then choose Check models.",
|
|
64
|
+
};
|
|
65
|
+
return { kind: "call", call: { kind: "tts", provider, model, voiceId, text: checkSpeech } };
|
|
66
|
+
}
|
|
67
|
+
if (isVideoTarget(catalogue, target))
|
|
68
|
+
return { kind: "skip", reason: "Image-to-video models are listed, never checked." };
|
|
69
|
+
const row = catalogue.image.find((m) => m.provider === provider && m.id === model);
|
|
70
|
+
const ratios = row?.image.aspectRatios ?? ["1:1"];
|
|
71
|
+
const aspect = ratios.includes("1:1") ? "1:1" : (ratios[0] ?? "1:1");
|
|
72
|
+
let thinking;
|
|
73
|
+
if (isLocalCliProvider(provider))
|
|
74
|
+
thinking = lowest((await deps.cliModels(provider, "image").catch(() => [])).find((m) => m.id === model)
|
|
75
|
+
?.thinkingModes);
|
|
76
|
+
return {
|
|
77
|
+
kind: "call",
|
|
78
|
+
call: {
|
|
79
|
+
kind: "image",
|
|
80
|
+
provider,
|
|
81
|
+
model,
|
|
82
|
+
prompt: checkPicture,
|
|
83
|
+
aspect,
|
|
84
|
+
...(thinking === undefined ? {} : { thinking }),
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
export function modelChecker(deps) {
|
|
89
|
+
return async (target, signal) => {
|
|
90
|
+
const recipe = await recipeFor(deps, target);
|
|
91
|
+
if (recipe.kind === "skip")
|
|
92
|
+
return { kind: "skipped", reason: recipe.reason };
|
|
93
|
+
if (recipe.kind === "free-works")
|
|
94
|
+
return { kind: "checked", verdict: "works", sentence: null, stopProvider: false, spent: 0 };
|
|
95
|
+
const answer = await checkModel(deps, recipe.call, signal);
|
|
96
|
+
return {
|
|
97
|
+
kind: "checked",
|
|
98
|
+
verdict: answer.verdict,
|
|
99
|
+
sentence: answer.sentence,
|
|
100
|
+
stopProvider: answer.stopProvider,
|
|
101
|
+
// A failure the provider may have billed is counted at the estimate the check showed.
|
|
102
|
+
spent: answer.verdict === "works"
|
|
103
|
+
? spentOn(deps.catalogue(), target, answer.use)
|
|
104
|
+
: answer.mayHaveBilled
|
|
105
|
+
? spentOn(deps.catalogue(), target, null)
|
|
106
|
+
: 0,
|
|
107
|
+
};
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
// The model-checks service as main.ts runs it: free listings from the providers' own model
|
|
111
|
+
// endpoints, and checks made through the recipes above.
|
|
112
|
+
export function wireModelChecks(deps) {
|
|
113
|
+
const { modelsFor } = modelSources(deps.registry);
|
|
114
|
+
const listing = createListing({
|
|
115
|
+
db: deps.db,
|
|
116
|
+
clock: deps.clock,
|
|
117
|
+
fetch: deps.fetch,
|
|
118
|
+
probes: keyProbes,
|
|
119
|
+
known: (provider, family) => deps
|
|
120
|
+
.catalogue()[family].filter((row) => row.provider === provider && row.enabled && !row.deprecated)
|
|
121
|
+
.map((row) => row.id),
|
|
122
|
+
cliModels: async (provider, family) => (await modelsFor(provider, family)).map((m) => m.id),
|
|
123
|
+
});
|
|
124
|
+
const checks = createModelChecks({
|
|
125
|
+
db: deps.db,
|
|
126
|
+
clock: deps.clock,
|
|
127
|
+
log: deps.log,
|
|
128
|
+
catalogue: deps.catalogue,
|
|
129
|
+
listing,
|
|
130
|
+
providerModels: modelsFor,
|
|
131
|
+
retiring: (model) => retirementOf(deps.lifecycle?.() ?? emptyLifecycle, deps.catalogue(), model),
|
|
132
|
+
check: modelChecker({
|
|
133
|
+
registry: deps.registry,
|
|
134
|
+
clock: deps.clock,
|
|
135
|
+
log: deps.log,
|
|
136
|
+
catalogue: deps.catalogue,
|
|
137
|
+
voices: () => listVoices(deps.db),
|
|
138
|
+
cliModels: modelsFor,
|
|
139
|
+
systemVoiceReady: async () => (await deps.statuses()).some((status) => status.id === systemVoiceProvider && readinessIsUsable(status.readiness)),
|
|
140
|
+
}),
|
|
141
|
+
});
|
|
142
|
+
return { checks, listing };
|
|
143
|
+
}
|
|
144
|
+
// A CLI that has become usable - installed and signed in - since the last look, or one that is
|
|
145
|
+
// usable and was never listed, is checked as if it had just been added.
|
|
146
|
+
export function cliWatcher(checks, statuses, known) {
|
|
147
|
+
const usable = new Map();
|
|
148
|
+
return async () => {
|
|
149
|
+
for (const status of await statuses()) {
|
|
150
|
+
if (status.readiness.kind !== "cli")
|
|
151
|
+
continue;
|
|
152
|
+
const now = readinessIsUsable(status.readiness);
|
|
153
|
+
const before = usable.get(status.id);
|
|
154
|
+
usable.set(status.id, now);
|
|
155
|
+
if (now && (before === false || (before === undefined && !known(status.id))))
|
|
156
|
+
await checks.automatic("cli-added", status.id);
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
// The hourly look. The weekly look goes first: it lists and checks every provider, a CLI
|
|
161
|
+
// among them, so a CLI it has just checked is known and isn't checked again as newly added.
|
|
162
|
+
export async function lookAtModels(checks, lookForClis) {
|
|
163
|
+
if (checks.weeklyDue())
|
|
164
|
+
await checks.automatic("weekly");
|
|
165
|
+
await lookForClis();
|
|
166
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Slopify 4.0.0
|
|
2
|
+
|
|
3
|
+
Released 18 October 2026.
|
|
4
|
+
|
|
5
|
+
## Template Studio
|
|
6
|
+
|
|
7
|
+
- **Set a template up once, with real samples.** Library → Templates → Open studio shows a template section by section: Subject, Script, Voice, Pictures, Video & captions, Thumbnail & title, Shorts, Document, Reviews & checkpoints, Upload pack and Schedule. Each Save makes a short sample of the sections it changed with your own providers. The sample is the opening of the script, about 30 seconds of narration, 4 pictures, a 30-second clip, a short, the PDF and the upload text, so you see and hear the result before a schedule uses it.
|
|
8
|
+
- Every paid Save shows its price on the button. A daily sample budget (Settings → Template studio, $2 by default) holds samples that would go over it. CLI plans are used only when you turn on "Samples may use my CLI plans".
|
|
9
|
+
- **Mark ready.** Once you mark a version ready in the studio, schedules run the newest ready version and later edits wait until you mark them ready. Templates you never mark ready keep following their newest version, as before.
|
|
10
|
+
- **Compare models** makes one section's sample with 2–3 models side by side, with cost and time. **Say it as…** fixes a name the voice mispronounces. **Export pack** and **Import pack** share a ready template with its samples.
|
|
11
|
+
- Create opens on template + topic + Start. More settings opens the full form.
|
|
12
|
+
|
|
13
|
+
## Posting to X, LinkedIn, Instagram, TikTok, Bluesky and Reddit
|
|
14
|
+
|
|
15
|
+
- Prepare upload has a **Where** choice: YouTube plus each site the project posts to. Each post shows its text, its media in the site's shape, a live character count and plain warnings. Templates set the defaults in Template Studio → Upload pack.
|
|
16
|
+
- **Fill in <site>** opens the site and the Slopify Studio extension fills the post: text, media, the site's AI label, and its own scheduler where it has one (X, LinkedIn, TikTok). You press Post. On Instagram, Bluesky and Reddit, which have no scheduler, the extension fills the post at its release time and notifies you.
|
|
17
|
+
- The extension never presses Post, Share or Publish, and it only fills tabs Slopify opened. Allow each site in the extension's options with "Allow posting on …". Reddit has not been checked live yet.
|
|
18
|
+
|
|
19
|
+
## Pictures and designed pieces
|
|
20
|
+
|
|
21
|
+
- **Edit a picture** you upload with an instruction, and keep editing the result. Every step is a version you can go back to.
|
|
22
|
+
- **Design posters and flyers.** The AI makes the artwork and Slopify sets the names, dates and prices in real fonts, so they are always spelled right. Download PNG or a print-ready PDF in A4, A3, A5 and social sizes. A design template with fields (event, date, venue…) makes a piece per row ahead of its date, or one at a time with Make a piece.
|
|
23
|
+
|
|
24
|
+
## Keywords Slopify fills
|
|
25
|
+
|
|
26
|
+
- New built-in keywords such as {{Slopify_Title}}, {{Slopify_Summary}}, {{Slopify_Hook}}, {{Slopify_Chapters}}, {{Slopify_Setting}} and {{Slopify_Thumbnail_Text}}. The Insert bar above each prompt lists the ones that work there, with an example and what they cost. {{Scene}} and {{Appearance}} keep working; the editor offers to update them to {{Slopify_Scene}} and {{Slopify_Appearance}}.
|
|
27
|
+
|
|
28
|
+
## Assistant, health and checks
|
|
29
|
+
|
|
30
|
+
- **Assistant.** A chat panel that runs on your Claude Code or Codex and can only use Slopify's own tools. It asks before anything that costs money, deletes or sends something, and shows what it will do. Its changes show as "by assistant".
|
|
31
|
+
- **Autopilot on Home** says how many days of videos are ready, when a schedule's topics run out, and warns before something breaks: a CLI signed out, a plan near its limit, disk filling, a model being retired. A weekly report can go to your notification URL (off by default).
|
|
32
|
+
- **Models that work for you.** Model pickers show which models your key or plan can actually run, with Check models and a weekly free check. Models that are being retired show their replacement.
|
|
33
|
+
- **Promise check.** An optional cheap review before narration: does the opening deliver what the title and thumbnail promise.
|
|
34
|
+
- **Topic ranking.** Schedules can rank new topics by what your library already covers, or also by public search interest (sends topic titles to Google, DuckDuckGo and Wikipedia; off by default).
|
|
35
|
+
|
|
36
|
+
## Remote access and rendering
|
|
37
|
+
|
|
38
|
+
- **Open Slopify on your phone or laptop** through Tailscale (Settings → General → Remote access). Only devices on your own tailnet can open it, never the public internet. Keys, imports and updates can only be changed on this computer.
|
|
39
|
+
- **Render settings** (Settings → Production defaults → Rendering): video encoder (processor or NVIDIA graphics card), clip encoding speed and render priority.
|
|
40
|
+
|
|
41
|
+
## Fixes
|
|
42
|
+
|
|
43
|
+
- A run's share of your Claude or Codex plan is now its own use only, never above 100%.
|
|
44
|
+
- Narration levelling now reaches the target loudness (−14 LUFS lands within 0.1 LU).
|
|
45
|
+
- The extension reads A/B test results again after it sets up A/B Testing.
|
|
46
|
+
|
|
47
|
+
## Upgrading from 3.25.9
|
|
48
|
+
|
|
49
|
+
- Your projects, templates and schedules carry over unchanged; existing projects are not remade. Every template version you had counts as "Not checked in the studio" and keeps running.
|
|
50
|
+
- The extension goes to 2.0.0. Posting needs its new optional permissions, granted in its options; YouTube works as before without them.
|
|
51
|
+
- `/mcp` now answers only on this computer: connect agents to `http://127.0.0.1:<port>/mcp`, not through a proxy.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { notTemplateSample } from "../template-studio/repo.js";
|
|
2
3
|
import { bookSchema } from "../voices/model.js";
|
|
3
4
|
import { formats } from "./model.js";
|
|
4
5
|
import { liveProject } from "./repo.js";
|
|
@@ -33,7 +34,7 @@ const headSelect = `SELECT projects.id, projects.title, projects.format, project
|
|
|
33
34
|
FROM projects LEFT JOIN project_controls ON project_controls.project_id = projects.id`;
|
|
34
35
|
export function listProjectHeads(db) {
|
|
35
36
|
return db
|
|
36
|
-
.prepare(`${headSelect} WHERE ${liveProject()} ORDER BY created_at DESC, id DESC`)
|
|
37
|
+
.prepare(`${headSelect} WHERE ${liveProject()} AND ${notTemplateSample()} ORDER BY created_at DESC, id DESC`)
|
|
37
38
|
.all()
|
|
38
39
|
.map((raw) => {
|
|
39
40
|
const row = headRow.parse(raw);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { failureId, stageKinds, stageStates } from "../../kernel/pipeline.js";
|
|
3
|
+
import { notTemplateSample } from "../template-studio/repo.js";
|
|
3
4
|
import { admittedInItsState, parkedOnReview } from "./admitted-work.js";
|
|
4
5
|
import { formats, stageSources } from "./model.js";
|
|
5
6
|
import { runConfigSchema } from "./schema.js";
|
|
@@ -78,7 +79,7 @@ export function projectExists(db, id) {
|
|
|
78
79
|
// Newest first.
|
|
79
80
|
export function listProjects(db) {
|
|
80
81
|
return db
|
|
81
|
-
.prepare(`${projectSelect} WHERE ${liveProject()} ORDER BY created_at DESC, id DESC`)
|
|
82
|
+
.prepare(`${projectSelect} WHERE ${liveProject()} AND ${notTemplateSample()} ORDER BY created_at DESC, id DESC`)
|
|
82
83
|
.all()
|
|
83
84
|
.map((row) => toProject(projectRow.parse(row)));
|
|
84
85
|
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { stageKinds } from "../../kernel/pipeline.js";
|
|
2
2
|
import { imageScaleProblem } from "../images/scale.js";
|
|
3
|
+
import { placedProblems } from "../keywords/rules.js";
|
|
3
4
|
import { loudnessFields } from "../loudness/model.js";
|
|
4
5
|
import { pauseFields } from "../narration/pauses-model.js";
|
|
5
6
|
import { reviewFields } from "../reviews/rules.js";
|
|
6
7
|
import { shortsSettingsProblems } from "../shorts/model.js";
|
|
8
|
+
import { usesPostPrompt } from "../social/rules.js";
|
|
7
9
|
import { ambientBedProblems, usesAmbientBed } from "../video/ambient-bed.js";
|
|
8
10
|
import { usesAnimation, videoEditProblems } from "../video/edit-settings.js";
|
|
9
11
|
import { usesVoices, voicesProblems } from "../voices/model.js";
|
|
@@ -75,6 +77,8 @@ export function admit(input) {
|
|
|
75
77
|
else if (draft.title.length > titleMax) {
|
|
76
78
|
fields.push({ field: "title", message: `Keep the title to ${titleMax} characters or fewer.` });
|
|
77
79
|
}
|
|
80
|
+
// Slopify fills its keywords from the title, so the title can't use them.
|
|
81
|
+
fields.push(...placedProblems([{ field: "title", place: "title", body: draft.title }], draft.values));
|
|
78
82
|
for (const kind of stageKinds) {
|
|
79
83
|
if (!allowedSources[kind].includes(sourceOf(sources, kind))) {
|
|
80
84
|
fields.push({
|
|
@@ -83,7 +87,7 @@ export function admit(input) {
|
|
|
83
87
|
});
|
|
84
88
|
}
|
|
85
89
|
}
|
|
86
|
-
if (needsLlmFor(draft) && !chosen(draft.llm)) {
|
|
90
|
+
if (needsLlmFor(draft, input.keywordUses) && !chosen(draft.llm)) {
|
|
87
91
|
fields.push({ field: "llm", message: "Choose a text (LLM) provider and model." });
|
|
88
92
|
}
|
|
89
93
|
if (sources.article === "generate" && blank(draft.articlePrompt)) {
|
|
@@ -132,7 +136,7 @@ export function admit(input) {
|
|
|
132
136
|
fields.push(...reviewFields(draft));
|
|
133
137
|
if (usesReference(draft) && draft.reference?.source === "provide")
|
|
134
138
|
checkFile(input.staged, draft.provided.reference, "images", "provided.reference", "Upload the establishing image, or set Establishing image to Off in the Images section.", fields);
|
|
135
|
-
checkProvided(draft, input.staged, fields);
|
|
139
|
+
checkProvided(draft, input.staged, fields, input.keywordUses);
|
|
136
140
|
checkValues(draft, input.requiredSlots, fields);
|
|
137
141
|
if (!Number.isFinite(draft.silenceGapSeconds) ||
|
|
138
142
|
draft.silenceGapSeconds < 0 ||
|
|
@@ -219,7 +223,7 @@ function checkImagePrompts(draft, fields) {
|
|
|
219
223
|
if (scaleProblem !== undefined)
|
|
220
224
|
fields.push({ field: "imageScale", message: scaleProblem });
|
|
221
225
|
}
|
|
222
|
-
function checkProvided(draft, staged, fields) {
|
|
226
|
+
function checkProvided(draft, staged, fields, uses = {}) {
|
|
223
227
|
const { sources, provided } = draft;
|
|
224
228
|
if (sources.research === "provide" && blank(provided.research)) {
|
|
225
229
|
fields.push({
|
|
@@ -230,7 +234,7 @@ function checkProvided(draft, staged, fields) {
|
|
|
230
234
|
if (sources.article === "provide" && blank(provided.article)) {
|
|
231
235
|
fields.push({ field: "provided.article", message: "Paste the article." });
|
|
232
236
|
}
|
|
233
|
-
fields.push(...articleOffFields(draft));
|
|
237
|
+
fields.push(...articleOffFields(draft, uses));
|
|
234
238
|
if (sources.audio === "provide") {
|
|
235
239
|
checkFile(staged, provided.audio, "audio", "provided.audio", "Pick an audio file.", fields);
|
|
236
240
|
}
|
|
@@ -318,7 +322,7 @@ function checkValues(draft, requiredSlots, fields) {
|
|
|
318
322
|
function blank(value) {
|
|
319
323
|
return value === undefined || value.trim() === "";
|
|
320
324
|
}
|
|
321
|
-
export function llmUses(draft) {
|
|
325
|
+
export function llmUses(draft, keywords = {}) {
|
|
322
326
|
const sources = draft.sources;
|
|
323
327
|
const uses = [];
|
|
324
328
|
if (sources.research === "generate")
|
|
@@ -341,10 +345,16 @@ export function llmUses(draft) {
|
|
|
341
345
|
uses.push({ section: "outputs", label: "writing the YouTube description" });
|
|
342
346
|
if (usesShorts(draft))
|
|
343
347
|
uses.push({ section: "outputs", label: "picking the shorts" });
|
|
348
|
+
if (usesPostPrompt(draft))
|
|
349
|
+
uses.push({ section: "outputs", label: "writing the posts for other sites" });
|
|
350
|
+
if (keywords.scenes !== undefined)
|
|
351
|
+
uses.push({ section: "outputs", label: "writing image scenes" });
|
|
352
|
+
if (keywords.digest !== undefined)
|
|
353
|
+
uses.push({ section: "outputs", label: "writing the keyword digest" });
|
|
344
354
|
return uses;
|
|
345
355
|
}
|
|
346
|
-
export function needsLlmFor(draft) {
|
|
347
|
-
return llmUses(draft).length > 0;
|
|
356
|
+
export function needsLlmFor(draft, keywords = {}) {
|
|
357
|
+
return llmUses(draft, keywords).length > 0;
|
|
348
358
|
}
|
|
349
359
|
export function usesNarrationPreparation(draft) {
|
|
350
360
|
return draft.sources.audio === "generate" && !blank(draft.narrationPrompt);
|
|
@@ -506,7 +516,7 @@ export function usesPronunciationGlossary(draft) {
|
|
|
506
516
|
}
|
|
507
517
|
// Article Off: a project of images or a thumbnail from prompts, with no text at all. What reads
|
|
508
518
|
// the article can't be on with it.
|
|
509
|
-
export function articleOffFields(draft) {
|
|
519
|
+
export function articleOffFields(draft, keywords = {}) {
|
|
510
520
|
const { sources } = draft;
|
|
511
521
|
if (sources.article !== "off")
|
|
512
522
|
return [];
|
|
@@ -569,5 +579,30 @@ export function articleOffFields(draft) {
|
|
|
569
579
|
},
|
|
570
580
|
]
|
|
571
581
|
: []),
|
|
582
|
+
// The keywords Slopify writes from the article (`keywords/specs.ts`).
|
|
583
|
+
...(keywords.digest === undefined
|
|
584
|
+
? []
|
|
585
|
+
: [
|
|
586
|
+
{
|
|
587
|
+
field: keywords.digest,
|
|
588
|
+
message: `{{Slopify_Summary}}, {{Slopify_Hook}} and the other digest keywords are written from the article, and Article is Off. ${fix}, or remove them from this prompt.`,
|
|
589
|
+
},
|
|
590
|
+
]),
|
|
591
|
+
...(keywords.chapters === undefined
|
|
592
|
+
? []
|
|
593
|
+
: [
|
|
594
|
+
{
|
|
595
|
+
field: keywords.chapters,
|
|
596
|
+
message: `{{Slopify_Chapters}} lists the article's chapters, and Article is Off. ${fix}, or remove it from this prompt.`,
|
|
597
|
+
},
|
|
598
|
+
]),
|
|
599
|
+
...(keywords.scenes === undefined
|
|
600
|
+
? []
|
|
601
|
+
: [
|
|
602
|
+
{
|
|
603
|
+
field: keywords.scenes,
|
|
604
|
+
message: `{{Slopify_Scene}}, {{Slopify_Setting}} and {{Slopify_Mood}} are written from the article, and Article is Off. ${fix}, or remove them from this prompt.`,
|
|
605
|
+
},
|
|
606
|
+
]),
|
|
572
607
|
];
|
|
573
608
|
}
|
|
@@ -4,9 +4,11 @@ import { thinkingModes } from "../../kernel/ports/llm.js";
|
|
|
4
4
|
import { castSnapshotSchema } from "../channels/schema.js";
|
|
5
5
|
import { checkpointStageSchema } from "../checkpoints/schema.js";
|
|
6
6
|
import { documentSettingsSchema } from "../document/theme-schema.js";
|
|
7
|
+
import { keywordFactsSchema } from "../keywords/schema.js";
|
|
7
8
|
import { narrationAliasesSchema } from "../narration/aliases-schema.js";
|
|
8
9
|
import { chunkModes } from "../narration/chunk.js";
|
|
9
10
|
import { reviewModes, reviewStages } from "../reviews/model.js";
|
|
11
|
+
import { socialSettingsSchema } from "../social/schema.js";
|
|
10
12
|
import { subtitleConfigSchema } from "../subtitles/model.js";
|
|
11
13
|
import { ambientBedSchema } from "../video/ambient-bed-schema.js";
|
|
12
14
|
import { animateModes, atmospheres, colorGrades, cutModes, lookLevels, transitionKinds, } from "../video/edit-settings.js";
|
|
@@ -156,6 +158,7 @@ export const runDraftSchema = z.object({
|
|
|
156
158
|
.array(z.object({ title: z.string(), summary: z.string() }))
|
|
157
159
|
.readonly()
|
|
158
160
|
.optional(),
|
|
161
|
+
keywordFacts: keywordFactsSchema.optional(),
|
|
159
162
|
titleStyle: z
|
|
160
163
|
.object({
|
|
161
164
|
fontId: z
|
|
@@ -193,6 +196,11 @@ export const runDraftSchema = z.object({
|
|
|
193
196
|
levelSentences: z.boolean().optional(),
|
|
194
197
|
// Absent is English (`kernel/ports/languages.ts`).
|
|
195
198
|
language: languageSchema.optional(),
|
|
199
|
+
// Posting to other sites (`slices/social`); absent is posting nowhere.
|
|
200
|
+
social: socialSettingsSchema.optional(),
|
|
201
|
+
// A template studio sample (`slices/template-studio/scope.ts`): its steps make a short taste
|
|
202
|
+
// of the video, not all of it. Absent on every other project, whose steps it never changes.
|
|
203
|
+
sample: z.object({ fullScript: z.boolean() }).strict().optional(),
|
|
196
204
|
});
|
|
197
205
|
export const runConfigSchema = runDraftSchema.extend({
|
|
198
206
|
rendered: z.record(z.string(), z.string()),
|
|
@@ -16,6 +16,3 @@ export function finishStage(db, stageId, state, failureReason, at) {
|
|
|
16
16
|
export function resetStage(db, stageId) {
|
|
17
17
|
db.prepare("UPDATE stages SET state = 'pending', failure_reason = NULL, failure_kind = NULL, retry_at = NULL, attempt_count = 0, progress_current = NULL, progress_total = NULL, started_at = NULL, finished_at = NULL WHERE id = ?").run(stageId);
|
|
18
18
|
}
|
|
19
|
-
export function setStageProgress(db, stageId, current, total) {
|
|
20
|
-
db.prepare("UPDATE stages SET progress_current = ?, progress_total = ? WHERE id = ?").run(current, total, stageId);
|
|
21
|
-
}
|
|
@@ -4,6 +4,8 @@ import { storeArticleText } from "../article/store.js";
|
|
|
4
4
|
import { resolveChannelId, setProjectChannel } from "../channels/repo.js";
|
|
5
5
|
import { defaultDocumentTheme } from "../document/model.js";
|
|
6
6
|
import { earlierEpisodesFor } from "../episodes/related.js";
|
|
7
|
+
import { keywordFactsFor } from "../keywords/facts.js";
|
|
8
|
+
import { usesFacts } from "../keywords/rules.js";
|
|
7
9
|
import { listNarrationAliases } from "../narration/aliases-library.js";
|
|
8
10
|
import { currentPronunciationRules } from "../narration/pronunciation.js";
|
|
9
11
|
import { collectSharedGlossary } from "../narration/shared-glossary.js";
|
|
@@ -33,37 +35,8 @@ export function initialState(source) {
|
|
|
33
35
|
export function startRun(deps, draft, rendered, retainStaged = false, templates) {
|
|
34
36
|
const id = deps.ids.next();
|
|
35
37
|
const at = deps.clock.now().toISOString();
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
: [];
|
|
39
|
-
// Library → Aliases as they are now: later edits there never change this project.
|
|
40
|
-
const aliases = draft.sources.audio === "generate" && draft.audio?.useNarrationAliases === true
|
|
41
|
-
? listNarrationAliases(deps.db)
|
|
42
|
-
: [];
|
|
43
|
-
// The title may name keywords too ("History: {{Topic}}"), filled like a prompt's, so a
|
|
44
|
-
// template or Play keeps the pattern and each project gets its own title.
|
|
45
|
-
const title = render(draft.title, draft.values).trim() || draft.title;
|
|
46
|
-
// The channel's related earlier episodes as they are now (`slices/episodes`): later edits
|
|
47
|
-
// there never change this project. A draft never brings its own.
|
|
48
|
-
const { earlierEpisodes: _carried, ...fresh } = draft;
|
|
49
|
-
const earlier = earlierEpisodesFor(deps.db, draft, title);
|
|
50
|
-
const config = {
|
|
51
|
-
...fresh,
|
|
52
|
-
title,
|
|
53
|
-
...(title !== draft.title && detectSlots(draft.title).names.length > 0
|
|
54
|
-
? { titlePattern: draft.title }
|
|
55
|
-
: {}),
|
|
56
|
-
// A new project always names its document theme: a config without one reads as the
|
|
57
|
-
// DiceMaster of older projects (see documentThemeOf), which no new project should get.
|
|
58
|
-
...(sourceOf(draft.sources, "document") === "generate" && draft.document === undefined
|
|
59
|
-
? { document: { theme: defaultDocumentTheme } }
|
|
60
|
-
: {}),
|
|
61
|
-
rendered,
|
|
62
|
-
...(shared.length === 0 ? {} : { sharedGlossary: shared }),
|
|
63
|
-
...(aliases.length === 0 ? {} : { narrationAliases: aliases }),
|
|
64
|
-
pronunciationRules: currentPronunciationRules,
|
|
65
|
-
...(earlier === undefined ? {} : { earlierEpisodes: earlier }),
|
|
66
|
-
};
|
|
38
|
+
const config = configOf(deps, draft, rendered, deps.clock.now(), templates);
|
|
39
|
+
const { title } = config;
|
|
67
40
|
const project = {
|
|
68
41
|
id,
|
|
69
42
|
title,
|
|
@@ -130,6 +103,50 @@ export function startRun(deps, draft, rendered, retainStaged = false, templates)
|
|
|
130
103
|
}
|
|
131
104
|
return { project, stages };
|
|
132
105
|
}
|
|
106
|
+
// The config a run starts with: the draft as filled, with what Slopify copies in when it starts
|
|
107
|
+
// (the shared glossary, Library → Aliases, the pronunciation rules, the channel's earlier
|
|
108
|
+
// episodes) as they are now. The template studio saves its sample's next revision from it.
|
|
109
|
+
export function configOf(deps, draft, rendered, now, templates,
|
|
110
|
+
// The project the config is for when it exists already (a template sample's next
|
|
111
|
+
// revision): it is neither its own previous video nor one it covered before.
|
|
112
|
+
projectId) {
|
|
113
|
+
const shared = usesPronunciationGlossary(draft) && draft.audio?.shareGlossary === true
|
|
114
|
+
? collectSharedGlossary(deps).entries
|
|
115
|
+
: [];
|
|
116
|
+
// Library → Aliases as they are now: later edits there never change this project.
|
|
117
|
+
const aliases = draft.sources.audio === "generate" && draft.audio?.useNarrationAliases === true
|
|
118
|
+
? listNarrationAliases(deps.db)
|
|
119
|
+
: [];
|
|
120
|
+
// The title may name keywords too ("History: {{Topic}}"), filled like a prompt's, so a
|
|
121
|
+
// template or Play keeps the pattern and each project gets its own title.
|
|
122
|
+
const title = render(draft.title, draft.values).trim() || draft.title;
|
|
123
|
+
// The channel's related earlier episodes as they are now (`slices/episodes`): later edits
|
|
124
|
+
// there never change this project. A draft never brings its own.
|
|
125
|
+
const { earlierEpisodes: _carried, keywordFacts: _facts, ...fresh } = draft;
|
|
126
|
+
const earlier = earlierEpisodesFor(deps.db, draft, title);
|
|
127
|
+
const titlePattern = title !== draft.title && detectSlots(draft.title).names.length > 0 ? draft.title : undefined;
|
|
128
|
+
// The facts the keywords Slopify fills come from, as they are now, and only when a picked
|
|
129
|
+
// prompt asks for one: a run that uses none saves the config it always did.
|
|
130
|
+
const facts = usesFacts(Object.values(templates ?? rendered))
|
|
131
|
+
? keywordFactsFor(deps, { ...draft, title, titlePattern }, now, projectId)
|
|
132
|
+
: undefined;
|
|
133
|
+
return {
|
|
134
|
+
...fresh,
|
|
135
|
+
title,
|
|
136
|
+
...(titlePattern === undefined ? {} : { titlePattern }),
|
|
137
|
+
// A new project always names its document theme: a config without one reads as the
|
|
138
|
+
// DiceMaster of older projects (see documentThemeOf), which no new project should get.
|
|
139
|
+
...(sourceOf(draft.sources, "document") === "generate" && draft.document === undefined
|
|
140
|
+
? { document: { theme: defaultDocumentTheme } }
|
|
141
|
+
: {}),
|
|
142
|
+
rendered,
|
|
143
|
+
...(shared.length === 0 ? {} : { sharedGlossary: shared }),
|
|
144
|
+
...(aliases.length === 0 ? {} : { narrationAliases: aliases }),
|
|
145
|
+
pronunciationRules: currentPronunciationRules,
|
|
146
|
+
...(earlier === undefined ? {} : { earlierEpisodes: earlier }),
|
|
147
|
+
...(facts === undefined ? {} : { keywordFacts: facts }),
|
|
148
|
+
};
|
|
149
|
+
}
|
|
133
150
|
function attachProvided(deps, projectId, draft, collected, retainStaged) {
|
|
134
151
|
const { sources, provided } = draft;
|
|
135
152
|
if (sources.research === "provide" && provided.research !== undefined) {
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// name case-sensitive and free to hold anything but `{`, `}` and a newline (so
|
|
3
3
|
// `{{Middle of Words}}` is one name). There is no escape syntax. Hand-rolled on purpose: a
|
|
4
4
|
// template library would bring its own grammar.
|
|
5
|
+
import { keywordNames, legacyNames } from "../keywords/specs.js";
|
|
5
6
|
export const slotLintKinds = ["unclosed", "empty", "nested"];
|
|
6
7
|
export const fieldGroups = ["common", "text", "image"];
|
|
7
8
|
// A well-formed slot: no brace and no newline between the delimiters.
|
|
@@ -38,16 +39,18 @@ export function detectSlots(body) {
|
|
|
38
39
|
return { names, errors };
|
|
39
40
|
}
|
|
40
41
|
// Filled by Slopify, never by the person: each image's own scene, which the project's AI model
|
|
41
|
-
// writes from the article when an image prompt asks for it (`images/scenes.ts`).
|
|
42
|
+
// writes from the article when an image prompt asks for it (`images/scenes.ts`). The old name
|
|
43
|
+
// of {{Slopify_Scene}}, which keeps its own meaning (`keywords/specs.ts`).
|
|
42
44
|
export const sceneKeyword = "Scene";
|
|
43
45
|
// Filled by Slopify too: how the video's subject and the characters in an image look, which the
|
|
44
46
|
// project's AI model looks up on the web when a prompt asks for it (`images/appearance.ts`).
|
|
45
47
|
export const appearanceKeyword = "Appearance";
|
|
46
|
-
// The keywords Slopify fills itself, which are never fields for the person
|
|
47
|
-
|
|
48
|
+
// The keywords Slopify fills itself, which are never fields for the person: every `Slopify_`
|
|
49
|
+
// keyword and the two old names. An unknown `Slopify_` name is not one of them.
|
|
50
|
+
export const filledKeywords = [...keywordNames, ...legacyNames];
|
|
48
51
|
// One field per distinct name; Common when a name is used on both sides, otherwise Text or
|
|
49
52
|
// Image. The order is first appearance, which is why both sides arrive as ordered lists of
|
|
50
|
-
// bodies rather than as sets. The
|
|
53
|
+
// bodies rather than as sets. The keywords Slopify fills are not fields.
|
|
51
54
|
export function collectFields(textBodies, imageBodies) {
|
|
52
55
|
const text = namesOf(textBodies);
|
|
53
56
|
const image = namesOf(imageBodies);
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { projectById } from "../admission/repo.js";
|
|
2
|
+
import { platformLabels } from "../social/model.js";
|
|
3
|
+
import { postsIn } from "../social/repo.js";
|
|
4
|
+
// Posts the extension filled in a site's form, waiting for the person to press Post (or
|
|
5
|
+
// Schedule) there, and fills that stopped. Posting is the person's: an agent reports them.
|
|
6
|
+
export function postsWaiting(deps) {
|
|
7
|
+
return postsIn(deps.db, ["filled", "failed"]).flatMap((post) => {
|
|
8
|
+
const project = projectById(deps.db, post.projectId);
|
|
9
|
+
if (project === undefined)
|
|
10
|
+
return [];
|
|
11
|
+
const site = platformLabels[post.platform];
|
|
12
|
+
const filled = post.state === "filled";
|
|
13
|
+
return [
|
|
14
|
+
{
|
|
15
|
+
kind: filled ? "post-due" : "extension-failure",
|
|
16
|
+
since: (filled ? post.filledAt : post.updatedAt) ?? post.updatedAt ?? "",
|
|
17
|
+
projectId: post.projectId,
|
|
18
|
+
title: project.title,
|
|
19
|
+
stage: "video",
|
|
20
|
+
itemKey: `social:${post.platform}`,
|
|
21
|
+
reason: filled
|
|
22
|
+
? `The ${site} post is filled in ${site}'s form and waits for the person to press Post there. Posting is the person's: report it.`
|
|
23
|
+
: `Filling the ${site} post failed: ${post.message ?? "the extension gave no reason."} Fixing it is the extension's or the person's: report it.`,
|
|
24
|
+
autoRetryInFlight: false,
|
|
25
|
+
agentCanAct: false,
|
|
26
|
+
ids: { projectId: post.projectId, platform: post.platform },
|
|
27
|
+
tools: ["get_post_packs"],
|
|
28
|
+
},
|
|
29
|
+
];
|
|
30
|
+
});
|
|
31
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { notReadySentence } from "../template-studio/schedule-gate.js";
|
|
3
|
+
import { rowsOf } from "./attention-work.js";
|
|
4
|
+
const scheduleRow = z.object({ id: z.string(), name: z.string(), template_id: z.string() });
|
|
5
|
+
// An active schedule whose gated template has no version it may run skips every run until the
|
|
6
|
+
// person marks one ready: the agent reports it. The gate keeps no time it began, so it is dated
|
|
7
|
+
// when it is read.
|
|
8
|
+
export function templatesNotReady(db, now, skip, notReady = (id) => notReadySentence(db, id)) {
|
|
9
|
+
const rows = db
|
|
10
|
+
.prepare("SELECT id, name, template_id FROM schedules WHERE deleted_at IS NULL AND status='active' AND template_kind='project' ORDER BY lower(name), id")
|
|
11
|
+
.all();
|
|
12
|
+
return rowsOf(rows, "schedules", skip, (value) => {
|
|
13
|
+
const row = scheduleRow.parse(value);
|
|
14
|
+
const sentence = notReady(row.template_id);
|
|
15
|
+
return sentence === undefined
|
|
16
|
+
? []
|
|
17
|
+
: [
|
|
18
|
+
{
|
|
19
|
+
kind: "template-not-ready",
|
|
20
|
+
since: now.toISOString(),
|
|
21
|
+
projectId: null,
|
|
22
|
+
title: row.name,
|
|
23
|
+
stage: null,
|
|
24
|
+
itemKey: null,
|
|
25
|
+
reason: `${sentence} Marking a version ready is the person's: report it.`,
|
|
26
|
+
autoRetryInFlight: false,
|
|
27
|
+
agentCanAct: false,
|
|
28
|
+
ids: { id: row.id, templateId: row.template_id },
|
|
29
|
+
tools: ["get_schedule", "get_template_checks"],
|
|
30
|
+
},
|
|
31
|
+
];
|
|
32
|
+
});
|
|
33
|
+
}
|