@gentbajko/slopify 3.25.8 → 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/3.25.9.md +5 -0
- package/dist/patch-notes/4.0.0.md +51 -0
- package/dist/patch-notes/index.json +12 -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 +34 -50
- 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
|
@@ -85,13 +85,28 @@ export const scheduleReleaseSchema = z
|
|
|
85
85
|
.strict()
|
|
86
86
|
.readonly();
|
|
87
87
|
const releases = z.array(scheduleReleaseSchema).max(7).readonly();
|
|
88
|
+
// How generated topics are ranked (`score.ts`): not at all, by what the library already
|
|
89
|
+
// covers, or also by public search interest (topic titles go to Google, DuckDuckGo and
|
|
90
|
+
// Wikipedia). Off is what every schedule saved before it has.
|
|
91
|
+
export const topicScorings = ["off", "library", "search"];
|
|
88
92
|
// Enough for a year of daily runs, pasted as one list.
|
|
89
93
|
export const queueMax = 500;
|
|
94
|
+
// What a schedule makes: projects from a project template (every schedule before designs), or
|
|
95
|
+
// designed pieces from a design template, one per row ahead of its date.
|
|
96
|
+
export const scheduleTemplateKinds = ["project", "design"];
|
|
97
|
+
// A project template's id is a UUID (checked by the service); a design template's may be any
|
|
98
|
+
// id its creator chose.
|
|
99
|
+
const templateId = z
|
|
100
|
+
.string()
|
|
101
|
+
.min(1)
|
|
102
|
+
.max(64)
|
|
103
|
+
.regex(/^[A-Za-z0-9_-]+$/);
|
|
90
104
|
export const scheduleCreateSchema = z
|
|
91
105
|
.object({
|
|
92
106
|
id,
|
|
93
107
|
name: z.string().trim().min(1).max(200),
|
|
94
|
-
|
|
108
|
+
templateKind: z.enum(scheduleTemplateKinds).default("project"),
|
|
109
|
+
templateId,
|
|
95
110
|
templateVersion: z.number().int().positive(),
|
|
96
111
|
cadence: cadenceSchema,
|
|
97
112
|
timezone: z
|
|
@@ -112,6 +127,9 @@ export const scheduleCreateSchema = z
|
|
|
112
127
|
brief: z.string().trim().max(briefMax).nullable().default(null),
|
|
113
128
|
topicGeneration: topicGenerationSchema.default(topicGenerationOff),
|
|
114
129
|
releases: releases.default([]),
|
|
130
|
+
// Absent: off for a new schedule, unchanged on a save, so a caller that doesn't know it
|
|
131
|
+
// never turns it off.
|
|
132
|
+
topicScoring: z.enum(topicScorings).optional(),
|
|
115
133
|
})
|
|
116
134
|
.strict()
|
|
117
135
|
.readonly();
|
|
@@ -120,6 +138,12 @@ export const scheduleUpdateSchema = scheduleCreateSchema
|
|
|
120
138
|
.extend({ baseVersion: z.number().int().positive(), mutationId: id })
|
|
121
139
|
.strict()
|
|
122
140
|
.readonly();
|
|
141
|
+
// The bodies the schedule routes take: a save names its schedule in the path, and pause,
|
|
142
|
+
// resume, cancel and delete carry only the version they were read at.
|
|
143
|
+
export const scheduleSaveBodySchema = scheduleUpdateSchema.unwrap().omit({ id: true });
|
|
144
|
+
export const scheduleVersionBodySchema = z
|
|
145
|
+
.object({ baseVersion: z.number().int().positive() })
|
|
146
|
+
.strict();
|
|
123
147
|
export const scheduleDeleteSchema = z
|
|
124
148
|
.object({ id, baseVersion: z.number().int().positive() })
|
|
125
149
|
.strict()
|
|
@@ -128,11 +152,21 @@ export const scheduleControlSchema = z
|
|
|
128
152
|
.object({ id, baseVersion: z.number().int().positive() })
|
|
129
153
|
.strict()
|
|
130
154
|
.readonly();
|
|
155
|
+
export const scheduleTemplateGateSchema = z
|
|
156
|
+
.object({
|
|
157
|
+
head: z.number().int().positive(),
|
|
158
|
+
runs: z.number().int().positive().nullable(),
|
|
159
|
+
gated: z.boolean(),
|
|
160
|
+
gate: z.enum(["legacy", "ready", "carried", "unchecked"]),
|
|
161
|
+
})
|
|
162
|
+
.strict()
|
|
163
|
+
.readonly();
|
|
131
164
|
export const scheduleSummarySchema = z
|
|
132
165
|
.object({
|
|
133
166
|
id,
|
|
134
167
|
name: z.string(),
|
|
135
|
-
|
|
168
|
+
templateKind: z.enum(scheduleTemplateKinds).default("project"),
|
|
169
|
+
templateId,
|
|
136
170
|
templateVersion: z.number().int().positive(),
|
|
137
171
|
cadence: cadenceSchema,
|
|
138
172
|
timezone: z.string(),
|
|
@@ -145,6 +179,7 @@ export const scheduleSummarySchema = z
|
|
|
145
179
|
brief: z.string().nullable().default(null),
|
|
146
180
|
topicGeneration: topicGenerationSchema.default(topicGenerationOff),
|
|
147
181
|
releases: releases.default([]),
|
|
182
|
+
topicScoring: z.enum(topicScorings).default("off"),
|
|
148
183
|
// The generation's own state: how many topics wait for approval, whether an LLM is being
|
|
149
184
|
// asked now, and the last failure's plain reason (cleared by the next success).
|
|
150
185
|
topics: topicState.default(topicStateIdle),
|
|
@@ -154,6 +189,11 @@ export const scheduleSummarySchema = z
|
|
|
154
189
|
createdAt: z.string(),
|
|
155
190
|
updatedAt: z.string(),
|
|
156
191
|
deletedAt: z.string().datetime({ offset: true }).nullable(),
|
|
192
|
+
// Which version of its template the schedule runs (`runs`): the newest one until a version
|
|
193
|
+
// was first marked ready (`gated`), then the newest legacy, ready or carried one (null when
|
|
194
|
+
// none is); the template's newest (`head`) and the gate of the one that runs. Absent from a
|
|
195
|
+
// Slopify before the template studio.
|
|
196
|
+
templateGate: scheduleTemplateGateSchema.optional(),
|
|
157
197
|
})
|
|
158
198
|
.strict()
|
|
159
199
|
.readonly();
|
|
@@ -165,6 +205,8 @@ export const scheduleRunSchema = z
|
|
|
165
205
|
status: z.enum(["running", "succeeded", "failed", "skipped"]),
|
|
166
206
|
requestId: id.nullable(),
|
|
167
207
|
projectIds: z.array(z.string()).readonly(),
|
|
208
|
+
// The designed pieces a design schedule's run made. Older servers leave it out.
|
|
209
|
+
designIds: z.array(z.string()).readonly().default([]),
|
|
168
210
|
estimate: z.unknown().nullable(),
|
|
169
211
|
startedAt: z.string().datetime({ offset: true }),
|
|
170
212
|
endedAt: z.string().datetime({ offset: true }).nullable(),
|
|
@@ -217,7 +259,7 @@ export const calendarRunSchema = z
|
|
|
217
259
|
scheduleName: z.string(),
|
|
218
260
|
scheduleVersion: z.number().int().positive(),
|
|
219
261
|
paused: z.boolean(),
|
|
220
|
-
templateId
|
|
262
|
+
templateId,
|
|
221
263
|
templateVersion: z.number().int().positive(),
|
|
222
264
|
templateName: z.string().nullable(),
|
|
223
265
|
// The topic's position in the schedule's queue, for reordering; null without one.
|
|
@@ -231,6 +273,15 @@ export const calendarRunSchema = z
|
|
|
231
273
|
// The project prepared ahead for this run (Prepare), which its day continues. Older servers
|
|
232
274
|
// leave it out.
|
|
233
275
|
prepared: z.string().nullable().default(null),
|
|
276
|
+
// No version of its template is marked ready (or saved before the template studio), so
|
|
277
|
+
// this run is skipped unless one is by then. Older servers leave it out.
|
|
278
|
+
notReady: z.boolean().default(false),
|
|
279
|
+
// A design schedule's run makes a designed piece on its day, never a video: it has nothing
|
|
280
|
+
// to prepare ahead and fills no video slot. Older servers leave it out.
|
|
281
|
+
templateKind: z.enum(scheduleTemplateKinds).default("project"),
|
|
282
|
+
// The schedule's time zone: its runs are shown on that zone's clock. Older servers leave
|
|
283
|
+
// it out, and the browser's is used.
|
|
284
|
+
timezone: z.string().optional(),
|
|
234
285
|
})
|
|
235
286
|
.strict()
|
|
236
287
|
.readonly();
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
// Topic scoring: how new a generated topic is next to what the library already covers, and,
|
|
2
|
+
// when the person opted in, how much public search interest it has. Pure, so the web bundle
|
|
3
|
+
// can import it too. Never reads a channel's analytics.
|
|
4
|
+
import { normaliseTopic, topicWords } from "./similar.js";
|
|
5
|
+
// A suggestion names the topic when it holds every word of it.
|
|
6
|
+
export function readingOf(topic, result) {
|
|
7
|
+
const words = topicWords(topic);
|
|
8
|
+
const matching = result.suggestions?.slice(0, 10).filter((suggestion) => {
|
|
9
|
+
const said = topicWords(suggestion);
|
|
10
|
+
return words.size > 0 && [...words].every((word) => said.has(word));
|
|
11
|
+
}) ?? null;
|
|
12
|
+
return {
|
|
13
|
+
suggestHits: matching === null ? null : matching.length,
|
|
14
|
+
examples: matching?.filter((one) => normaliseTopic(one) !== normaliseTopic(topic)).slice(0, 2) ?? [],
|
|
15
|
+
wikiViews: result.wikiViews,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
// The key a topic's score is kept by: its normalised title, so a recased or repunctuated
|
|
19
|
+
// topic keeps its score.
|
|
20
|
+
export function topicKey(title) {
|
|
21
|
+
return normaliseTopic(title);
|
|
22
|
+
}
|
|
23
|
+
function overlap(a, b) {
|
|
24
|
+
if (a.size === 0 || b.size === 0)
|
|
25
|
+
return 0;
|
|
26
|
+
let common = 0;
|
|
27
|
+
for (const word of a)
|
|
28
|
+
if (b.has(word))
|
|
29
|
+
common += 1;
|
|
30
|
+
// A known title that holds every word of the topic covers it, however long the title is.
|
|
31
|
+
return common === a.size ? 1 : common / (a.size + b.size - common);
|
|
32
|
+
}
|
|
33
|
+
export function noveltyOf(topic, known) {
|
|
34
|
+
const words = topicWords(topic);
|
|
35
|
+
let nearest;
|
|
36
|
+
for (const title of [...known.topics, ...known.projects]) {
|
|
37
|
+
const share = overlap(words, topicWords(title));
|
|
38
|
+
if (share > 0 && (nearest === undefined || share > nearest.overlap))
|
|
39
|
+
nearest = { title, overlap: share };
|
|
40
|
+
}
|
|
41
|
+
return nearest === undefined
|
|
42
|
+
? { value: 1 }
|
|
43
|
+
: { value: Math.max(0, 1 - nearest.overlap), nearest };
|
|
44
|
+
}
|
|
45
|
+
// ceiling: ten million views a month (log10 7) is as popular as a topic gets here.
|
|
46
|
+
const viewsCeiling = 7;
|
|
47
|
+
export function interestOf(reading) {
|
|
48
|
+
if (reading === null)
|
|
49
|
+
return null;
|
|
50
|
+
const views = Math.min(1, Math.log10((reading.wikiViews ?? 0) + 1) / viewsCeiling);
|
|
51
|
+
const hits = Math.min(10, reading.suggestHits ?? 0) / 10;
|
|
52
|
+
return 0.6 * views + 0.4 * hits;
|
|
53
|
+
}
|
|
54
|
+
export function scoreOf(interest, novelty) {
|
|
55
|
+
return Math.round(100 * (interest === null ? novelty : 0.6 * interest + 0.4 * novelty));
|
|
56
|
+
}
|
|
57
|
+
function views(count) {
|
|
58
|
+
if (count >= 1_000_000)
|
|
59
|
+
return `${(count / 1_000_000).toFixed(1).replace(/\.0$/, "")}M`;
|
|
60
|
+
if (count >= 1000)
|
|
61
|
+
return `${String(Math.round(count / 1000))}k`;
|
|
62
|
+
return String(count);
|
|
63
|
+
}
|
|
64
|
+
// Why a topic scored as it did, one line per signal, as the score chip shows them.
|
|
65
|
+
export function reasonsOf(novelty, reading, search) {
|
|
66
|
+
const lines = [];
|
|
67
|
+
if (search === "read" && reading !== null) {
|
|
68
|
+
if (reading.suggestHits !== null) {
|
|
69
|
+
const example = reading.examples[0];
|
|
70
|
+
lines.push(`Search: ${String(reading.suggestHits)} of 10 suggestions match${example === undefined ? "" : `, e.g. “${example}”`}`);
|
|
71
|
+
}
|
|
72
|
+
lines.push(reading.wikiViews === null
|
|
73
|
+
? "Wikipedia: no article found"
|
|
74
|
+
: `Wikipedia: ${views(reading.wikiViews)} views last month`);
|
|
75
|
+
}
|
|
76
|
+
if (search === "unreachable")
|
|
77
|
+
lines.push("Search interest unknown: no connection to Google, DuckDuckGo or Wikipedia");
|
|
78
|
+
lines.push(novelty.nearest === undefined
|
|
79
|
+
? "Library: new; nothing like it made or queued"
|
|
80
|
+
: novelty.value === 0
|
|
81
|
+
? `Library: already covered by “${novelty.nearest.title}”`
|
|
82
|
+
: `Library: new; nearest “${novelty.nearest.title}” (${String(Math.round(novelty.nearest.overlap * 100))}% overlap)`);
|
|
83
|
+
return lines;
|
|
84
|
+
}
|
|
85
|
+
export function topicScore(novelty, reading, search) {
|
|
86
|
+
const interest = search === "read" ? interestOf(reading) : null;
|
|
87
|
+
return {
|
|
88
|
+
score: scoreOf(interest, novelty.value),
|
|
89
|
+
interest,
|
|
90
|
+
novelty: novelty.value,
|
|
91
|
+
reasons: reasonsOf(novelty, reading, search),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
// The queue once scored: topics the person added or moved keep their place at the front in
|
|
95
|
+
// their own order, then the scored ones, best first. Stable: equal scores keep their order.
|
|
96
|
+
export function orderQueue(items, scores) {
|
|
97
|
+
const kept = [];
|
|
98
|
+
const scored = [];
|
|
99
|
+
for (const item of items) {
|
|
100
|
+
const found = scores.get(topicKey(item.title));
|
|
101
|
+
if (found === undefined || found.pinned)
|
|
102
|
+
kept.push(item);
|
|
103
|
+
else
|
|
104
|
+
scored.push({ item, score: found.score });
|
|
105
|
+
}
|
|
106
|
+
return [...kept, ...scored.toSorted((a, b) => b.score - a.score).map((one) => one.item)];
|
|
107
|
+
}
|
|
@@ -1,12 +1,24 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { transact } from "../../kernel/db/tx.js";
|
|
3
3
|
import { requestHash } from "../play-drafts/repo.js";
|
|
4
|
-
import {
|
|
4
|
+
import { checkDesign } from "./design-check.js";
|
|
5
|
+
import { nextRunOf } from "./next-run.js";
|
|
5
6
|
import { insertSchedule, runsForSchedule, scheduleById, scheduleRows, setScheduleStatus, tombstoneScheduleRow, updateScheduleRow, } from "./repo.js";
|
|
6
7
|
import { scheduleControlSchema, scheduleCreateSchema, scheduleDeleteSchema, scheduleUpdateSchema, topicStateIdle, } from "./schema.js";
|
|
7
|
-
import {
|
|
8
|
+
import { scheduleKeywords, topicRowProblems } from "./topic-list.js";
|
|
8
9
|
export function listSchedules(deps) {
|
|
9
|
-
|
|
10
|
+
const rows = scheduleRows(deps.db);
|
|
11
|
+
const gateOf = deps.templateGate;
|
|
12
|
+
if (gateOf === undefined)
|
|
13
|
+
return rows;
|
|
14
|
+
return rows.map((schedule) => {
|
|
15
|
+
// The template studio's gate is a project template's; a design schedule's template is
|
|
16
|
+
// a design template, readied by the designs.
|
|
17
|
+
if (schedule.templateKind !== "project")
|
|
18
|
+
return schedule;
|
|
19
|
+
const templateGate = gateOf(schedule.templateId);
|
|
20
|
+
return templateGate === undefined ? schedule : { ...schedule, templateGate };
|
|
21
|
+
});
|
|
10
22
|
}
|
|
11
23
|
export function listScheduleRuns(deps, id) {
|
|
12
24
|
if (!z.uuid().safeParse(id).success)
|
|
@@ -35,18 +47,16 @@ export function createSchedule(deps, input) {
|
|
|
35
47
|
? { ok: true, value: scheduleById(deps.db, parsed.data.id) }
|
|
36
48
|
: { ok: false, reason: "conflict" };
|
|
37
49
|
}
|
|
38
|
-
const checked =
|
|
50
|
+
const checked = checkKind(deps, parsed.data, []);
|
|
39
51
|
if (!checked.ok)
|
|
40
52
|
return checked;
|
|
41
|
-
const topics = checkTopics(deps, parsed.data, []);
|
|
42
|
-
if (!topics.ok)
|
|
43
|
-
return topics;
|
|
44
53
|
const now = deps.clock.now();
|
|
45
|
-
const next =
|
|
46
|
-
|
|
54
|
+
const next = nextRunOf(deps.db, parsed.data, now);
|
|
55
|
+
// A design schedule with no row still to come waits for rows; any other has to run.
|
|
56
|
+
if (next === null && parsed.data.templateKind === "project")
|
|
47
57
|
return { ok: false, reason: "not-due" };
|
|
48
58
|
// The version it was saved against, for the record; runs use the newest.
|
|
49
|
-
const value = summary({ ...parsed.data, templateVersion: checked.value }, next
|
|
59
|
+
const value = summary({ ...parsed.data, templateVersion: checked.value }, next?.toISOString() ?? null, now.toISOString());
|
|
50
60
|
insertSchedule(deps.db, value, hash);
|
|
51
61
|
return { ok: true, value };
|
|
52
62
|
});
|
|
@@ -78,22 +88,25 @@ export function updateSchedule(deps, input) {
|
|
|
78
88
|
return { ok: false, reason: "conflict" };
|
|
79
89
|
if (previous.status === "canceled" || previous.status === "completed")
|
|
80
90
|
return { ok: false, reason: "conflict" };
|
|
81
|
-
|
|
91
|
+
if (parsed.data.templateKind !== previous.templateKind)
|
|
92
|
+
return {
|
|
93
|
+
ok: false,
|
|
94
|
+
reason: "invalid-input",
|
|
95
|
+
message: "A schedule can't switch between making videos and making designed pieces. Make a new schedule for the other kind.",
|
|
96
|
+
};
|
|
97
|
+
const checked = checkKind(deps, parsed.data, previous.items);
|
|
82
98
|
if (!checked.ok)
|
|
83
99
|
return checked;
|
|
84
|
-
const topics = checkTopics(deps, parsed.data, previous.items);
|
|
85
|
-
if (!topics.ok)
|
|
86
|
-
return topics;
|
|
87
100
|
const now = deps.clock.now();
|
|
88
101
|
const next = previous.status === "active"
|
|
89
|
-
?
|
|
90
|
-
: previous.nextRunAt === null
|
|
102
|
+
? nextRunOf(deps.db, parsed.data, now)
|
|
103
|
+
: previous.nextRunAt === null && previous.templateKind === "project"
|
|
91
104
|
? null
|
|
92
|
-
:
|
|
105
|
+
: nextRunOf(deps.db, parsed.data, now);
|
|
93
106
|
// The version it was saved against, for the record; runs use the newest.
|
|
94
107
|
const value = summary({ ...parsed.data, templateVersion: checked.value }, next?.toISOString() ?? null, now.toISOString(), previous.status, previous.version + 1,
|
|
95
108
|
// Saving clears a recorded generation failure, so the next tick tries again.
|
|
96
|
-
{ ...previous.topics, failedAt: null, error: null });
|
|
109
|
+
{ ...previous.topics, failedAt: null, error: null }, previous.topicScoring);
|
|
97
110
|
if (!updateScheduleRow(deps.db, value, parsed.data.mutationId, hash, parsed.data.baseVersion))
|
|
98
111
|
return { ok: false, reason: "conflict" };
|
|
99
112
|
return { ok: true, value };
|
|
@@ -113,8 +126,9 @@ export function resumeSchedule(deps, input) {
|
|
|
113
126
|
return { ok: false, reason: "conflict" };
|
|
114
127
|
if (previous.version !== parsed.data.baseVersion || previous.status !== "paused")
|
|
115
128
|
return { ok: false, reason: "conflict" };
|
|
116
|
-
const next =
|
|
117
|
-
|
|
129
|
+
const next = nextRunOf(deps.db, previous, deps.clock.now());
|
|
130
|
+
// A design schedule with no row to come stays active, waiting for rows.
|
|
131
|
+
const status = next === null && previous.templateKind === "project" ? "completed" : "active";
|
|
118
132
|
if (!setScheduleStatus(deps.db, previous.id, previous.version, status, next?.toISOString() ?? null, deps.clock.now().toISOString()))
|
|
119
133
|
return { ok: false, reason: "conflict" };
|
|
120
134
|
return { ok: true, value: scheduleById(deps.db, previous.id) };
|
|
@@ -157,6 +171,24 @@ function control(deps, input, status) {
|
|
|
157
171
|
return { ok: false, reason: "conflict" };
|
|
158
172
|
return { ok: true, value: scheduleById(deps.db, previous.id) };
|
|
159
173
|
}
|
|
174
|
+
// Answers the template's newest version when a schedule may use it, and checks its queue
|
|
175
|
+
// against that template: a project template's keywords, or a design template's fields and
|
|
176
|
+
// dates.
|
|
177
|
+
function checkKind(deps, input, kept) {
|
|
178
|
+
if (input.templateKind === "design")
|
|
179
|
+
return checkDesign(deps, input);
|
|
180
|
+
// Exactly as before design schedules: a project template's id is a UUID, and its schedule
|
|
181
|
+
// runs once, daily or weekly.
|
|
182
|
+
if (!z.uuid().safeParse(input.templateId).success || input.cadence.kind === "by-date")
|
|
183
|
+
return { ok: false, reason: "invalid-input" };
|
|
184
|
+
const checked = checkTemplate(deps, input.templateId);
|
|
185
|
+
if (!checked.ok)
|
|
186
|
+
return checked;
|
|
187
|
+
const topics = checkTopics(deps, input, kept);
|
|
188
|
+
if (!topics.ok)
|
|
189
|
+
return topics;
|
|
190
|
+
return checked;
|
|
191
|
+
}
|
|
160
192
|
// Answers the template's newest version when a schedule may use it.
|
|
161
193
|
function checkTemplate(deps, id) {
|
|
162
194
|
const template = deps.template(id);
|
|
@@ -178,10 +210,9 @@ function checkTemplate(deps, id) {
|
|
|
178
210
|
// the template doesn't use would silently do nothing. Topics saved before, unchanged, are left
|
|
179
211
|
// alone, so a queue from before this check still saves.
|
|
180
212
|
function checkTopics(deps, input, kept) {
|
|
181
|
-
const
|
|
182
|
-
if (
|
|
213
|
+
const keywords = scheduleKeywords(deps, input.templateId);
|
|
214
|
+
if (keywords === undefined)
|
|
183
215
|
return { ok: false, reason: "missing-template" };
|
|
184
|
-
const keywords = templateKeywords(template.document.form);
|
|
185
216
|
const named = keywords.length === 0 ? "none" : keywords.map((one) => `“${one}”`).join(", ");
|
|
186
217
|
const problems = [];
|
|
187
218
|
if (input.topicKeyword !== null && !keywords.includes(input.topicKeyword))
|
|
@@ -200,10 +231,11 @@ function checkTopics(deps, input, kept) {
|
|
|
200
231
|
message: `The schedule wasn't saved. ${shown.join(" ")}${more > 0 ? ` And ${String(more)} more like these.` : ""}`,
|
|
201
232
|
};
|
|
202
233
|
}
|
|
203
|
-
function summary(input, nextRunAt, now, status = "active", version = 1, topics = topicStateIdle) {
|
|
234
|
+
function summary(input, nextRunAt, now, status = "active", version = 1, topics = topicStateIdle, topicScoring = "off") {
|
|
204
235
|
return {
|
|
205
236
|
id: input.id,
|
|
206
237
|
name: input.name,
|
|
238
|
+
templateKind: input.templateKind,
|
|
207
239
|
templateId: input.templateId,
|
|
208
240
|
templateVersion: input.templateVersion,
|
|
209
241
|
cadence: input.cadence,
|
|
@@ -217,6 +249,7 @@ function summary(input, nextRunAt, now, status = "active", version = 1, topics =
|
|
|
217
249
|
brief: input.brief === null || input.brief === "" ? null : input.brief,
|
|
218
250
|
topicGeneration: input.topicGeneration,
|
|
219
251
|
releases: input.releases,
|
|
252
|
+
topicScoring: input.topicScoring ?? topicScoring,
|
|
220
253
|
topics,
|
|
221
254
|
status,
|
|
222
255
|
version,
|
|
@@ -161,3 +161,18 @@ export function formatTopicList(rows, topicKeyword) {
|
|
|
161
161
|
: { [topicKeyword]: row.title, ...row.values });
|
|
162
162
|
return stringify(items, { lineWidth: 0 });
|
|
163
163
|
}
|
|
164
|
+
// The keywords a schedule's topics may fill: the version it runs, and the newest one, which a
|
|
165
|
+
// schedule may be set up for before it is marked ready (a keyword the run doesn't use is
|
|
166
|
+
// filled and left unused).
|
|
167
|
+
export function scheduleKeywords(deps, templateId) {
|
|
168
|
+
const runs = deps.template(templateId);
|
|
169
|
+
if (runs === undefined)
|
|
170
|
+
return undefined;
|
|
171
|
+
const head = deps.templateHead?.(templateId);
|
|
172
|
+
return [
|
|
173
|
+
...new Set([
|
|
174
|
+
...templateKeywords(runs.document.form),
|
|
175
|
+
...(head === undefined ? [] : templateKeywords(head.document.form)),
|
|
176
|
+
]),
|
|
177
|
+
];
|
|
178
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { noveltyOf, orderQueue, readingOf, topicKey, topicScore, } from "./score.js";
|
|
3
|
+
// ceiling: three topics asked at once, and the whole scoring of one generation stops after
|
|
4
|
+
// 15 seconds; what wasn't read by then is scored by novelty alone, never held up.
|
|
5
|
+
const concurrency = 3;
|
|
6
|
+
export const scoringBudgetMs = 15_000;
|
|
7
|
+
const scoreRow = z.object({
|
|
8
|
+
topic_key: z.string(),
|
|
9
|
+
title: z.string(),
|
|
10
|
+
score: z.number(),
|
|
11
|
+
reasons: z.string(),
|
|
12
|
+
pinned: z.number(),
|
|
13
|
+
});
|
|
14
|
+
export function scoresOf(db, scheduleId) {
|
|
15
|
+
return new Map(db
|
|
16
|
+
.prepare("SELECT topic_key,title,score,reasons,pinned FROM topic_scores WHERE schedule_id=?")
|
|
17
|
+
.all(scheduleId)
|
|
18
|
+
.map((raw) => {
|
|
19
|
+
const row = scoreRow.parse(raw);
|
|
20
|
+
return [
|
|
21
|
+
row.topic_key,
|
|
22
|
+
{
|
|
23
|
+
title: row.title,
|
|
24
|
+
score: row.score,
|
|
25
|
+
reasons: z.array(z.string()).parse(JSON.parse(row.reasons)),
|
|
26
|
+
pinned: row.pinned === 1,
|
|
27
|
+
},
|
|
28
|
+
];
|
|
29
|
+
}));
|
|
30
|
+
}
|
|
31
|
+
// A topic scored again keeps whether the person pinned it. `pinNew` scores topics that had no
|
|
32
|
+
// score (ones the person added) without moving them.
|
|
33
|
+
export function saveScores(db, scheduleId, scores, at, pinNew = false) {
|
|
34
|
+
const upsert = db.prepare(`INSERT INTO topic_scores (schedule_id,topic_key,title,score,interest,novelty,reasons,pinned,scored_at)
|
|
35
|
+
VALUES (?,?,?,?,?,?,?,${pinNew ? 1 : 0},?)
|
|
36
|
+
ON CONFLICT(schedule_id,topic_key) DO UPDATE SET title=excluded.title,score=excluded.score,
|
|
37
|
+
interest=excluded.interest,novelty=excluded.novelty,reasons=excluded.reasons,
|
|
38
|
+
scored_at=excluded.scored_at`);
|
|
39
|
+
for (const [title, score] of scores)
|
|
40
|
+
upsert.run(scheduleId, topicKey(title), title, score.score, score.interest, score.novelty, JSON.stringify(score.reasons), at);
|
|
41
|
+
}
|
|
42
|
+
// A topic the person moved stays where they put it.
|
|
43
|
+
export function pinTopic(db, scheduleId, title) {
|
|
44
|
+
db.prepare("UPDATE topic_scores SET pinned=1 WHERE schedule_id=? AND topic_key=?").run(scheduleId, topicKey(title));
|
|
45
|
+
}
|
|
46
|
+
// The queue in score order (`orderQueue`), from the scores kept for it.
|
|
47
|
+
export function rankedItems(db, scheduleId, items) {
|
|
48
|
+
return orderQueue(items, scoresOf(db, scheduleId));
|
|
49
|
+
}
|
|
50
|
+
// Scores each title: its novelty against the library, and with "search" its public interest.
|
|
51
|
+
// "library" never asks anything outside this computer. Never throws: a topic search didn't
|
|
52
|
+
// answer for in time is scored by novelty and says so.
|
|
53
|
+
export async function scoreTopics(deps, scoring, titles, known, language, signal) {
|
|
54
|
+
const readings = new Map();
|
|
55
|
+
const interest = deps.interest;
|
|
56
|
+
if (scoring === "search" && interest !== undefined) {
|
|
57
|
+
const budget = AbortSignal.any([
|
|
58
|
+
AbortSignal.timeout(scoringBudgetMs),
|
|
59
|
+
...(signal === undefined ? [] : [signal]),
|
|
60
|
+
]);
|
|
61
|
+
const queue = [...titles];
|
|
62
|
+
const worker = async () => {
|
|
63
|
+
for (let title = queue.shift(); title !== undefined; title = queue.shift()) {
|
|
64
|
+
if (budget.aborted)
|
|
65
|
+
return;
|
|
66
|
+
try {
|
|
67
|
+
readings.set(title, await interest(title, language, budget));
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
// The port never throws; a broken adapter is treated as no connection.
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
await Promise.race([
|
|
75
|
+
Promise.all(Array.from({ length: concurrency }, worker)),
|
|
76
|
+
new Promise((resolve) => budget.addEventListener("abort", () => resolve(), { once: true })),
|
|
77
|
+
]);
|
|
78
|
+
}
|
|
79
|
+
return new Map(titles.map((title) => {
|
|
80
|
+
// A queued topic is in the library's list itself; it is compared with the others.
|
|
81
|
+
const novelty = noveltyOf(title, {
|
|
82
|
+
topics: known.topics.filter((other) => topicKey(other) !== topicKey(title)),
|
|
83
|
+
projects: known.projects,
|
|
84
|
+
});
|
|
85
|
+
if (scoring === "library")
|
|
86
|
+
return [title, topicScore(novelty, null, "off")];
|
|
87
|
+
const result = readings.get(title);
|
|
88
|
+
const reading = result?.ok === true ? readingOf(title, result) : null;
|
|
89
|
+
return [
|
|
90
|
+
title,
|
|
91
|
+
topicScore(novelty, reading, reading === null ? "unreachable" : "read"),
|
|
92
|
+
];
|
|
93
|
+
}));
|
|
94
|
+
}
|
|
95
|
+
// The scores kept for these titles, by key, as the schedule page and agents read them.
|
|
96
|
+
export function scoresFor(db, scheduleId, titles) {
|
|
97
|
+
const kept = scoresOf(db, scheduleId);
|
|
98
|
+
return Object.fromEntries(titles.flatMap((title) => {
|
|
99
|
+
const found = kept.get(topicKey(title));
|
|
100
|
+
return found === undefined
|
|
101
|
+
? []
|
|
102
|
+
: [[topicKey(title), { score: found.score, reasons: found.reasons }]];
|
|
103
|
+
}));
|
|
104
|
+
}
|