@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
|
@@ -6,8 +6,10 @@ import { templateById } from "../project-templates/repo.js";
|
|
|
6
6
|
import { updateTemplate } from "../project-templates/service.js";
|
|
7
7
|
import { ensureBaseline, saveRevision } from "../revisions/index.js";
|
|
8
8
|
import { currentRevisionId } from "../revisions/repo.js";
|
|
9
|
+
import { carryGateOnto } from "../template-studio/repo.js";
|
|
10
|
+
import { templateGate } from "../template-studio/schedule-gate.js";
|
|
9
11
|
import { configChoices, formChoices, retiredModelUsage, retiredStatus, } from "./usage.js";
|
|
10
|
-
function keepThinking(catalogue, provider, model, thinking) {
|
|
12
|
+
export function keepThinking(catalogue, provider, model, thinking) {
|
|
11
13
|
if (thinking === undefined)
|
|
12
14
|
return {};
|
|
13
15
|
const row = catalogue.llm.find((entry) => entry.provider === provider && entry.id === model);
|
|
@@ -103,32 +105,75 @@ export async function switchRetiredModel(deps, catalogue, request) {
|
|
|
103
105
|
}
|
|
104
106
|
}
|
|
105
107
|
function switchTemplate(deps, catalogue, request, templateId) {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
108
|
+
const template = templateById(deps.db, templateId);
|
|
109
|
+
if (template === undefined)
|
|
110
|
+
return { ok: false, message: changedMeanwhile };
|
|
111
|
+
try {
|
|
112
|
+
return transact(deps.db, () => switchTemplateIn(deps, catalogue, request, template));
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
if (!(error instanceof SwitchRefused))
|
|
116
|
+
throw error;
|
|
117
|
+
return {
|
|
118
|
+
ok: false,
|
|
119
|
+
message: error.reason === "missing-prompt"
|
|
120
|
+
? `The template "${template.name}" uses a prompt or intro/outro that was deleted, so it cannot be saved. Open it in Library → Templates, choose another, and save.`
|
|
121
|
+
: changedMeanwhile,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// A refused save inside the switch's transaction: thrown so the carried version written before
|
|
126
|
+
// it is rolled back with it.
|
|
127
|
+
class SwitchRefused extends Error {
|
|
128
|
+
reason;
|
|
129
|
+
constructor(reason) {
|
|
130
|
+
super(reason);
|
|
131
|
+
this.reason = reason;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
function switchTemplateIn(deps, catalogue, request, template) {
|
|
135
|
+
const form = switchForm(template.document.form, catalogue, request);
|
|
136
|
+
// The version schedules run, when it isn't the head (an unchecked edit waits on Mark ready).
|
|
137
|
+
const runs = templateGate(deps.db, template.id)?.runs ?? null;
|
|
138
|
+
const running = runs === null || runs === template.version
|
|
139
|
+
? undefined
|
|
140
|
+
: templateById(deps.db, template.id, runs);
|
|
141
|
+
const runningForm = running === undefined ? undefined : switchForm(running.document.form, catalogue, request);
|
|
142
|
+
if (form === undefined && runningForm === undefined)
|
|
143
|
+
return { ok: true, changed: false };
|
|
144
|
+
let base = template.version;
|
|
145
|
+
if (running !== undefined && runningForm !== undefined) {
|
|
146
|
+
// The version that runs, switched, carried from it: schedules never keep running a
|
|
147
|
+
// retired model while the person's newer edit waits to be marked ready.
|
|
148
|
+
const carried = updateTemplate(deps, {
|
|
114
149
|
id: template.id,
|
|
115
|
-
name:
|
|
116
|
-
document: { ...
|
|
117
|
-
baseVersion:
|
|
150
|
+
name: running.name,
|
|
151
|
+
document: { ...running.document, form: runningForm },
|
|
152
|
+
baseVersion: base,
|
|
118
153
|
mutationId: deps.uuid(),
|
|
119
154
|
});
|
|
120
|
-
if (!
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
155
|
+
if (!carried.ok)
|
|
156
|
+
throw new SwitchRefused(carried.reason);
|
|
157
|
+
carryGateOnto(deps.db, template.id, running.version, carried.value.version);
|
|
158
|
+
base = carried.value.version;
|
|
159
|
+
}
|
|
160
|
+
// The head stays the person's newest work: switched too when it picks the model, and
|
|
161
|
+
// written again above the carried version so it is still the newest one.
|
|
162
|
+
const saved = updateTemplate(deps, {
|
|
163
|
+
id: template.id,
|
|
164
|
+
name: template.name,
|
|
165
|
+
document: { ...template.document, form: form ?? template.document.form },
|
|
166
|
+
baseVersion: base,
|
|
167
|
+
mutationId: deps.uuid(),
|
|
131
168
|
});
|
|
169
|
+
if (!saved.ok)
|
|
170
|
+
throw new SwitchRefused(saved.reason);
|
|
171
|
+
// Slopify's own change: a schedule running the version it came from keeps running.
|
|
172
|
+
carryGateOnto(deps.db, template.id, template.version, saved.value.version);
|
|
173
|
+
deps.db
|
|
174
|
+
.prepare("UPDATE schedules SET template_version=?,version=version+1,updated_at=? WHERE template_id=? AND template_version=? AND deleted_at IS NULL AND status IN ('active','paused')")
|
|
175
|
+
.run(saved.value.version, deps.clock.now().toISOString(), template.id, template.version);
|
|
176
|
+
return { ok: true, changed: true };
|
|
132
177
|
}
|
|
133
178
|
function switchDraft(deps, catalogue, request) {
|
|
134
179
|
const row = draftRow(deps.db, request.id);
|
|
@@ -189,12 +234,12 @@ async function switchProject(deps, catalogue, request) {
|
|
|
189
234
|
};
|
|
190
235
|
}
|
|
191
236
|
// "Switch all": every listed use that has a suggestion and no reason to hold back, one by one.
|
|
192
|
-
export async function switchAllRetired(deps, catalogue) {
|
|
237
|
+
export async function switchAllRetired(deps, catalogue, lifecycle) {
|
|
193
238
|
let switched = 0;
|
|
194
239
|
const failed = [];
|
|
195
240
|
// Templates first: switching one also moves the schedules that follow it.
|
|
196
241
|
const order = ["template", "schedule", "draft", "project"];
|
|
197
|
-
const usages = [...retiredModelUsage(deps.db, catalogue)].sort((a, b) => order.indexOf(a.kind) - order.indexOf(b.kind));
|
|
242
|
+
const usages = [...retiredModelUsage(deps.db, catalogue, lifecycle)].sort((a, b) => order.indexOf(a.kind) - order.indexOf(b.kind));
|
|
198
243
|
for (const usage of usages) {
|
|
199
244
|
if (usage.blocked !== null || usage.replacement === null)
|
|
200
245
|
continue;
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { lifecycleReplacement } from "../../catalog/lifecycle.js";
|
|
2
3
|
import { isVideoModel } from "../../catalog/schema.js";
|
|
3
4
|
import { listProjects, stagesOf } from "../admission/repo.js";
|
|
4
5
|
import { draftRows } from "../play-drafts/repo.js";
|
|
5
6
|
import { documentOf } from "../play-drafts/service.js";
|
|
6
7
|
import { templateById } from "../project-templates/repo.js";
|
|
7
8
|
import { currentRevisionId, revisionById } from "../revisions/repo.js";
|
|
8
|
-
import { isUncataloguedProvider } from "../settings/model.js";
|
|
9
|
+
import { isSampleStandIn, isUncataloguedProvider } from "../settings/model.js";
|
|
10
|
+
import { runnableTemplate } from "../template-studio/schedule-gate.js";
|
|
9
11
|
import { usageSlots } from "./model.js";
|
|
10
12
|
export { slotLabels, usageKinds, usageSlots } from "./model.js";
|
|
11
13
|
function familyOf(slot) {
|
|
@@ -36,11 +38,13 @@ export function configChoices(config) {
|
|
|
36
38
|
};
|
|
37
39
|
}
|
|
38
40
|
// Whether a choice names a catalogued model that is no longer offered. Command-line tools
|
|
39
|
-
// list their own models and are checked by the health check instead
|
|
41
|
+
// list their own models and are checked by the health check instead; the samples' stand-ins
|
|
42
|
+
// were never catalogued.
|
|
40
43
|
export function retiredStatus(catalogue, slot, choice) {
|
|
41
44
|
if (choice.provider === "" ||
|
|
42
45
|
choice.model.trim() === "" ||
|
|
43
|
-
isUncataloguedProvider(choice.provider)
|
|
46
|
+
isUncataloguedProvider(choice.provider) ||
|
|
47
|
+
isSampleStandIn(choice.provider))
|
|
44
48
|
return null;
|
|
45
49
|
const row = catalogue[familyOf(slot)].find((model) => model.provider === choice.provider &&
|
|
46
50
|
model.id === choice.model &&
|
|
@@ -51,9 +55,17 @@ export function retiredStatus(catalogue, slot, choice) {
|
|
|
51
55
|
return "retired";
|
|
52
56
|
return row.enabled ? null : "unlisted";
|
|
53
57
|
}
|
|
54
|
-
// The
|
|
55
|
-
//
|
|
56
|
-
|
|
58
|
+
// The replacement models-lifecycle.yaml names, when it is live; else the closest active model
|
|
59
|
+
// from the same provider and list: the one sharing the longest start of its ID (a newer
|
|
60
|
+
// version of the same line), the catalogue's order breaking ties.
|
|
61
|
+
export function suggestReplacement(catalogue, slot, choice, lifecycle) {
|
|
62
|
+
const named = lifecycleReplacement(lifecycle, catalogue, {
|
|
63
|
+
family: familyOf(slot),
|
|
64
|
+
provider: choice.provider,
|
|
65
|
+
model: choice.model,
|
|
66
|
+
});
|
|
67
|
+
if (named !== undefined && named.id !== choice.model)
|
|
68
|
+
return named;
|
|
57
69
|
let best = null;
|
|
58
70
|
for (const row of catalogue[familyOf(slot)]) {
|
|
59
71
|
if (row.provider !== choice.provider ||
|
|
@@ -74,7 +86,7 @@ function sharedStart(a, b) {
|
|
|
74
86
|
index++;
|
|
75
87
|
return index;
|
|
76
88
|
}
|
|
77
|
-
function usagesOf(catalogue, base, choices, blocked) {
|
|
89
|
+
function usagesOf(catalogue, base, choices, blocked, lifecycle) {
|
|
78
90
|
const found = [];
|
|
79
91
|
for (const slot of usageSlots) {
|
|
80
92
|
const choice = choices[slot];
|
|
@@ -83,7 +95,7 @@ function usagesOf(catalogue, base, choices, blocked) {
|
|
|
83
95
|
const why = retiredStatus(catalogue, slot, choice);
|
|
84
96
|
if (why === null)
|
|
85
97
|
continue;
|
|
86
|
-
const replacement = suggestReplacement(catalogue, slot, choice);
|
|
98
|
+
const replacement = suggestReplacement(catalogue, slot, choice, lifecycle);
|
|
87
99
|
found.push({
|
|
88
100
|
...base,
|
|
89
101
|
key: `${base.kind}:${base.id}:${slot}`,
|
|
@@ -128,7 +140,10 @@ export function choiceSites(db) {
|
|
|
128
140
|
.prepare("SELECT id,name,template_id,template_version FROM schedules WHERE deleted_at IS NULL AND status IN ('active','paused') ORDER BY lower(name),id")
|
|
129
141
|
.all()) {
|
|
130
142
|
const row = scheduleRow.parse(raw);
|
|
131
|
-
|
|
143
|
+
// What the schedule actually runs (`template-studio/schedule-gate.ts`): with an unchecked
|
|
144
|
+
// head that is an older ready version, whose models are the ones its runs use.
|
|
145
|
+
const template = runnableTemplate(db, row.template_id) ??
|
|
146
|
+
templateById(db, row.template_id, row.template_version);
|
|
132
147
|
if (template === undefined)
|
|
133
148
|
continue;
|
|
134
149
|
const head = heads.get(row.template_id) ??
|
|
@@ -180,6 +195,6 @@ export function choiceSites(db) {
|
|
|
180
195
|
}
|
|
181
196
|
// Every template, schedule, draft and unfinished project that still picks a retired or
|
|
182
197
|
// unlisted model, with the suggested replacement. Nothing is changed here.
|
|
183
|
-
export function retiredModelUsage(db, catalogue) {
|
|
184
|
-
return choiceSites(db).flatMap((site) => usagesOf(catalogue, { kind: site.kind, id: site.id, name: site.name }, site.choices, site.blocked));
|
|
198
|
+
export function retiredModelUsage(db, catalogue, lifecycle) {
|
|
199
|
+
return choiceSites(db).flatMap((site) => usagesOf(catalogue, { kind: site.kind, id: site.id, name: site.name }, site.choices, site.blocked, lifecycle));
|
|
185
200
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { mkdirSync, rmSync } from "node:fs";
|
|
2
2
|
import { open, stat } from "node:fs/promises";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
+
import { errorText } from "../../kernel/errors.js";
|
|
4
5
|
import { runFfmpeg } from "../video/ffmpeg.js";
|
|
5
6
|
import { breathRate, scanBreaths, softenChunk } from "./breaths-detect.js";
|
|
6
7
|
// Soften breaths, made in the join (`breaths-model.ts` says why there). Each narration piece is
|
|
@@ -38,7 +39,7 @@ export async function softenBreaths(run, files, directory) {
|
|
|
38
39
|
catch (error) {
|
|
39
40
|
if (run.signal.aborted)
|
|
40
41
|
throw error;
|
|
41
|
-
throw new Error(`Soften breaths could not process narration piece ${String(index + 1)} (${
|
|
42
|
+
throw new Error(`Soften breaths could not process narration piece ${String(index + 1)} (${errorText(error)}), so the narration can't be joined together. Use Try again; if it fails again, turn off Soften breaths in Edit project → Pauses and volume and use Save changes, then use Download diagnostics in Settings and report it.`, { cause: error });
|
|
42
43
|
}
|
|
43
44
|
finally {
|
|
44
45
|
rmSync(raw, { force: true });
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { mkdirSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
+
import { errorText } from "../../kernel/errors.js";
|
|
3
4
|
import { runFfmpeg } from "../video/ffmpeg.js";
|
|
4
5
|
import { softenBreaths } from "./breaths.js";
|
|
5
6
|
import { deEsser } from "./breaths-model.js";
|
|
@@ -36,7 +37,7 @@ export async function deEssPieces(run, files, directory) {
|
|
|
36
37
|
catch (error) {
|
|
37
38
|
if (run.signal.aborted)
|
|
38
39
|
throw error;
|
|
39
|
-
throw new Error(`Soften S sounds could not process narration piece ${String(index + 1)} (${
|
|
40
|
+
throw new Error(`Soften S sounds could not process narration piece ${String(index + 1)} (${errorText(error)}), so the narration can't be joined together. Use Try again; if it fails again, turn off Soften S sounds in Edit project → Pauses and volume and use Save changes, then use Download diagnostics in Settings and report it.`, { cause: error });
|
|
40
41
|
}
|
|
41
42
|
written.push(output);
|
|
42
43
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { copyFileSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { dirname } from "node:path";
|
|
3
|
+
import { internalError } from "../../kernel/errors.js";
|
|
3
4
|
import { probeDurationMs, runFfmpeg } from "../video/ffmpeg.js";
|
|
4
5
|
// The concat demuxer's script format. A path is single-quoted, and the one character that
|
|
5
6
|
// can end the quoting is spelled out, so a folder with an apostrophe in it cannot become
|
|
@@ -46,7 +47,7 @@ export async function joinNarration(deps, input) {
|
|
|
46
47
|
const first = input.files[0];
|
|
47
48
|
if (first === undefined) {
|
|
48
49
|
// The stage refuses an empty narration before it gets here, so this is a bug.
|
|
49
|
-
throw new Error("
|
|
50
|
+
throw new Error(internalError("there is no narration audio to join"));
|
|
50
51
|
}
|
|
51
52
|
mkdirSync(dirname(input.output), { recursive: true, mode: 0o700 });
|
|
52
53
|
if (input.files.length === 1 && input.reencode !== true) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { execFile } from "node:child_process";
|
|
2
|
+
import { isDonePiece, readyOutput } from "../revisions/view.js";
|
|
2
3
|
// The live view's narration waveform: each finished narration piece as a row of peaks, in the
|
|
3
4
|
// order it is spoken, growing as pieces land. Once the whole narration is joined (or was
|
|
4
5
|
// uploaded) that one file replaces the pieces.
|
|
@@ -12,7 +13,7 @@ const decodeMaxBytes = 3 * 3600 * decodeRate * 2;
|
|
|
12
13
|
// The saved narration audio of a revision, in spoken order: the joined narration when it is
|
|
13
14
|
// ready, else each finished request of the intro, the body and the outro.
|
|
14
15
|
export function narrationAudio(view) {
|
|
15
|
-
const joined = view
|
|
16
|
+
const joined = readyOutput(view, { role: "audio_body" });
|
|
16
17
|
if (joined !== undefined)
|
|
17
18
|
return {
|
|
18
19
|
complete: true,
|
|
@@ -22,10 +23,8 @@ export function narrationAudio(view) {
|
|
|
22
23
|
return {
|
|
23
24
|
complete: false,
|
|
24
25
|
pieces: view.pieces
|
|
25
|
-
.filter((row) => row
|
|
26
|
-
row.available &&
|
|
26
|
+
.filter((row) => isDonePiece(row) &&
|
|
27
27
|
row.stageKind === "audio" &&
|
|
28
|
-
row.piece.state === "done" &&
|
|
29
28
|
row.assetId !== null &&
|
|
30
29
|
row.piece.payload !== null &&
|
|
31
30
|
spoken(row.piece.payload))
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { internalError } from "../../kernel/errors.js";
|
|
1
2
|
import { fingerprint } from "../../kernel/runner/work.js";
|
|
2
3
|
import { anchoredChunks, defaultChunkCharacters, defaultChunkWords, } from "./chunk.js";
|
|
3
4
|
import { pronunciationMatches } from "./pronunciation.js";
|
|
@@ -32,7 +33,7 @@ export function pronunciationChunks(source, chunking, entries, overriddenKeys =
|
|
|
32
33
|
const chunks = narrationChunkTexts(source, chunking, anchors).map((text) => {
|
|
33
34
|
const start = source.indexOf(text, offset);
|
|
34
35
|
if (start < 0)
|
|
35
|
-
throw new Error("
|
|
36
|
+
throw new Error(internalError("a narration chunk isn't in the article text"));
|
|
36
37
|
offset = start + text.length;
|
|
37
38
|
return { key: nextKey(text), text, start, end: offset };
|
|
38
39
|
});
|
|
@@ -85,7 +86,7 @@ export function pronunciationChunks(source, chunking, entries, overriddenKeys =
|
|
|
85
86
|
}
|
|
86
87
|
const chunk = chunks[index];
|
|
87
88
|
if (chunk === undefined)
|
|
88
|
-
throw new Error("
|
|
89
|
+
throw new Error(internalError("a narration chunk went missing"));
|
|
89
90
|
while ((matches[matchIndex]?.end ?? Infinity) <= chunk.end)
|
|
90
91
|
matchIndex++;
|
|
91
92
|
const match = matches[matchIndex];
|
|
@@ -97,7 +98,7 @@ export function pronunciationChunks(source, chunking, entries, overriddenKeys =
|
|
|
97
98
|
continue;
|
|
98
99
|
const first = chunks[from];
|
|
99
100
|
if (first === undefined)
|
|
100
|
-
throw new Error("
|
|
101
|
+
throw new Error(internalError("a group of narration chunks is empty"));
|
|
101
102
|
const text = source.slice(first.start, chunk.end);
|
|
102
103
|
result.push(from === index
|
|
103
104
|
? { key: chunk.key, text }
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { remark } from "remark";
|
|
2
2
|
import remarkGfm from "remark-gfm";
|
|
3
|
+
import { internalError } from "../../kernel/errors.js";
|
|
3
4
|
import { remembered } from "../../kernel/remembered.js";
|
|
4
5
|
export const currentPronunciationRules = 2;
|
|
5
6
|
export function pronunciationRulesOf(config) {
|
|
@@ -211,7 +212,7 @@ function matchPronunciations(source, entries, possessives = false) {
|
|
|
211
212
|
continue;
|
|
212
213
|
const entry = ordered.find((_, index) => match[index + 1] !== undefined);
|
|
213
214
|
if (entry === undefined)
|
|
214
|
-
throw new Error("
|
|
215
|
+
throw new Error(internalError("a pronunciation glossary term has no pronunciation"));
|
|
215
216
|
const possessive = possessives ? match[ordered.length + 1] : undefined;
|
|
216
217
|
matches.push({
|
|
217
218
|
start: match.index,
|
|
@@ -237,7 +238,7 @@ export function pronunciationSpans(source, entries, possessives = false) {
|
|
|
237
238
|
for (const [index, word] of words.entries()) {
|
|
238
239
|
const ipa = match.entry.ipa[index];
|
|
239
240
|
if (ipa === undefined)
|
|
240
|
-
throw new Error("
|
|
241
|
+
throw new Error(internalError("a pronunciation glossary term is missing a word"));
|
|
241
242
|
const start = match.start + word.index;
|
|
242
243
|
const spoken = match.possessive !== undefined && index === words.length - 1 ? withPossessive(ipa) : ipa;
|
|
243
244
|
spans.push({ start, end: start + word[0].length, text: `/${spoken}/` });
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { internalError } from "../../kernel/errors.js";
|
|
1
2
|
import { sourceSentences } from "./preparation.js";
|
|
2
3
|
const cannotFit = {
|
|
3
4
|
ok: false,
|
|
@@ -9,14 +10,14 @@ function atoms(source, from, to, spans) {
|
|
|
9
10
|
const span = spans.get(at);
|
|
10
11
|
if (span !== undefined) {
|
|
11
12
|
if (span.end > to || span.end <= at)
|
|
12
|
-
throw new Error("
|
|
13
|
+
throw new Error(internalError("a pronunciation fix spans more than one word"));
|
|
13
14
|
result.push({ text: span.text, spokenText: source.slice(at, span.end) });
|
|
14
15
|
at = span.end;
|
|
15
16
|
}
|
|
16
17
|
else {
|
|
17
18
|
const point = source.codePointAt(at);
|
|
18
19
|
if (point === undefined)
|
|
19
|
-
throw new Error("
|
|
20
|
+
throw new Error(internalError("a narration position is outside the article text"));
|
|
20
21
|
const text = String.fromCodePoint(point);
|
|
21
22
|
// An empty span is a later word of a multi-word alias (its spoken form sits on the first
|
|
22
23
|
// word), so the whitespace in front of it would leave two spaces where one word was.
|
|
@@ -45,7 +46,7 @@ function checkedSpans(source, pronunciation) {
|
|
|
45
46
|
span.end <= span.start ||
|
|
46
47
|
span.end > source.length ||
|
|
47
48
|
!/^[^\s\uD800-\uDFFF]+$/u.test(source.slice(span.start, span.end)))
|
|
48
|
-
throw new Error("
|
|
49
|
+
throw new Error(internalError("pronunciation fixes overlap or split a word"));
|
|
49
50
|
spans.set(span.start, span);
|
|
50
51
|
end = span.end;
|
|
51
52
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { errorText } from "../../kernel/errors.js";
|
|
1
2
|
import { redact } from "../../kernel/log.js";
|
|
2
3
|
import { webhookBody } from "./address.js";
|
|
3
4
|
import { autoPassNoticeText, noticeOf, noticeText, reviewNoticeText, runNotices, topicsNoticeText, } from "./rules.js";
|
|
@@ -84,7 +85,7 @@ export function createRunNotifier(deps) {
|
|
|
84
85
|
.catch((error) => {
|
|
85
86
|
deps.log.write("warn", "notification.failed", {
|
|
86
87
|
...about,
|
|
87
|
-
detail: `${kind} notification not delivered: ${
|
|
88
|
+
detail: `${kind} notification not delivered: ${errorText(error)}`,
|
|
88
89
|
});
|
|
89
90
|
})
|
|
90
91
|
.finally(() => {
|
|
@@ -123,7 +124,7 @@ export function createRunNotifier(deps) {
|
|
|
123
124
|
catch (error) {
|
|
124
125
|
deps.log.write("warn", "notification.failed", {
|
|
125
126
|
projectId: event.projectId,
|
|
126
|
-
detail: `notification skipped: ${
|
|
127
|
+
detail: `notification skipped: ${errorText(error)}`,
|
|
127
128
|
});
|
|
128
129
|
}
|
|
129
130
|
},
|
|
@@ -138,7 +139,7 @@ export function createRunNotifier(deps) {
|
|
|
138
139
|
}
|
|
139
140
|
catch (error) {
|
|
140
141
|
deps.log.write("warn", "notification.failed", {
|
|
141
|
-
detail: `topics notification skipped: ${
|
|
142
|
+
detail: `topics notification skipped: ${errorText(error)}`,
|
|
142
143
|
});
|
|
143
144
|
}
|
|
144
145
|
},
|
|
@@ -29,6 +29,7 @@ const reviewItemNames = {
|
|
|
29
29
|
narration: "the narration",
|
|
30
30
|
thumbnail: "the thumbnail",
|
|
31
31
|
shorts: "a short",
|
|
32
|
+
promise: "the article's opening (promise check)",
|
|
32
33
|
};
|
|
33
34
|
export function reviewNoticeText(subject) {
|
|
34
35
|
const title = subject.title.trim() === "" ? "Untitled project" : subject.title.trim();
|
|
@@ -48,6 +49,8 @@ export function reviewItemName(itemKey, imageOrder) {
|
|
|
48
49
|
return "the article";
|
|
49
50
|
if (itemKey === "narration")
|
|
50
51
|
return "the narration";
|
|
52
|
+
if (itemKey === "promise")
|
|
53
|
+
return "the article's opening (promise check)";
|
|
51
54
|
if (itemKey === "thumbnail:image")
|
|
52
55
|
return "the thumbnail";
|
|
53
56
|
const variant = /^thumbnail:image:(\d+)$/.exec(itemKey);
|
|
@@ -139,8 +142,8 @@ export function shortReason(reason) {
|
|
|
139
142
|
}
|
|
140
143
|
export function noticeText(kind, subject) {
|
|
141
144
|
const text = runNoticeText(kind, subject);
|
|
142
|
-
return subject.startedBy === "agent"
|
|
143
|
-
? { ...text, headline: `${text.headline} · started by
|
|
145
|
+
return subject.startedBy === "agent" || subject.startedBy === "assistant"
|
|
146
|
+
? { ...text, headline: `${text.headline} · started by ${subject.startedBy}` }
|
|
144
147
|
: text;
|
|
145
148
|
}
|
|
146
149
|
function runNoticeText(kind, subject) {
|
|
@@ -1,19 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { deleteSetting, readJsonSetting, writeSetting } from "../settings/repo.js";
|
|
2
3
|
import { notificationUrlProblem } from "./address.js";
|
|
3
4
|
// Its own row in the key/value `settings` table. Backups leave it out
|
|
4
5
|
// (`slices/storage/portable.ts`): an ntfy topic in the URL is as good as a password.
|
|
5
6
|
export const notificationUrlKey = "notificationUrl";
|
|
6
7
|
export function readNotificationUrl(db) {
|
|
7
|
-
const
|
|
8
|
-
if (stored === undefined)
|
|
9
|
-
return null;
|
|
10
|
-
let value;
|
|
11
|
-
try {
|
|
12
|
-
value = JSON.parse(stored);
|
|
13
|
-
}
|
|
14
|
-
catch {
|
|
15
|
-
return null;
|
|
16
|
-
}
|
|
8
|
+
const value = readJsonSetting(db, notificationUrlKey, z.unknown(), null);
|
|
17
9
|
// A hand-edited row that no longer passes the rules is treated as not set rather than
|
|
18
10
|
// POSTed to.
|
|
19
11
|
return typeof value === "string" && value !== "" && notificationUrlProblem(value) === undefined
|
|
@@ -26,7 +18,7 @@ export function saveNotificationUrl(db, raw) {
|
|
|
26
18
|
return { ok: false, message: problem };
|
|
27
19
|
const url = raw.trim();
|
|
28
20
|
if (url === "") {
|
|
29
|
-
db
|
|
21
|
+
deleteSetting(db, notificationUrlKey);
|
|
30
22
|
return { ok: true, url: null };
|
|
31
23
|
}
|
|
32
24
|
writeSetting(db, notificationUrlKey, JSON.stringify(url));
|
|
@@ -3,6 +3,7 @@ import { projectById, stagesOf } from "../admission/repo.js";
|
|
|
3
3
|
import { stepFailedWhileWaiting } from "../admission/state-words.js";
|
|
4
4
|
import { lastStarter } from "../agents/repo.js";
|
|
5
5
|
import { projectHolds } from "../reviews/holds.js";
|
|
6
|
+
import { isTemplateSample } from "../template-studio/repo.js";
|
|
6
7
|
import { uploadedAndSettled } from "../uploads/repo.js";
|
|
7
8
|
import { settledStatus } from "../uploads/rules.js";
|
|
8
9
|
import { atItsDay, failuresOf } from "./rules.js";
|
|
@@ -10,7 +11,7 @@ import { atItsDay, failuresOf } from "./rules.js";
|
|
|
10
11
|
// Projects list reads it with (`edge/http/projects.ts`).
|
|
11
12
|
export function noticeSubject(db, projectId) {
|
|
12
13
|
const project = projectById(db, projectId);
|
|
13
|
-
if (project === undefined)
|
|
14
|
+
if (project === undefined || isTemplateSample(db, projectId))
|
|
14
15
|
return undefined;
|
|
15
16
|
const stages = stagesOf(db, projectId);
|
|
16
17
|
const settled = uploadedAndSettled(db, projectId);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { copyFileSync, lstatSync, mkdirSync, readdirSync, rmSync } from "node:fs";
|
|
2
2
|
import { dirname, join, relative, sep } from "node:path";
|
|
3
3
|
import { transact } from "../../kernel/db/tx.js";
|
|
4
|
+
import { internalError } from "../../kernel/errors.js";
|
|
4
5
|
import { executionPlan } from "../rebuild/runtime-plan.js";
|
|
5
6
|
import { currentRevisionId } from "../revisions/repo.js";
|
|
6
7
|
import { getRevisionView } from "../revisions/view.js";
|
|
@@ -104,7 +105,7 @@ function rebind(deps, projectId) {
|
|
|
104
105
|
.prepare(`UPDATE ${table} SET ${column}=replace(${column},?,?) WHERE project_id=? AND instr(${column},?)>0`)
|
|
105
106
|
.run(before, after, projectId, before);
|
|
106
107
|
}
|
|
107
|
-
throw new Error("
|
|
108
|
+
throw new Error(internalError("the copy of the sample kept changing while its steps were matched up", "Delete the copy and try Make my own copy again"));
|
|
108
109
|
}
|
|
109
110
|
function requestOf(payload) {
|
|
110
111
|
try {
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { readinessIsUsable } from "../../kernel/ports/model.js";
|
|
2
2
|
import { templateById } from "../project-templates/repo.js";
|
|
3
|
+
import { notTemplateSample } from "../template-studio/repo.js";
|
|
3
4
|
import { starterPacks } from "./packs.js";
|
|
4
5
|
import { sampleProjectIds } from "./sample.js";
|
|
5
6
|
import { firstRunDismissed, readPackRecords } from "./state.js";
|
|
6
7
|
// The first-run screen shows on a fresh install and never again once it is skipped or a real
|
|
7
|
-
// project (anything but the samples) exists. Reading it writes nothing: a real project that
|
|
8
|
+
// project (anything but the samples and the template studio's hidden projects) exists. Reading it writes nothing: a real project that
|
|
8
9
|
// exists before the screen was recorded as done is reported as `settle`, and the client
|
|
9
10
|
// records it with POST /dismiss, so deleting every project later does not bring it back.
|
|
10
11
|
export function firstRunView(db, statuses) {
|
|
11
12
|
const samples = sampleProjectIds(db);
|
|
12
13
|
const real = db
|
|
13
|
-
.prepare(
|
|
14
|
+
.prepare(`SELECT 1 FROM projects WHERE id IS NOT ? AND id IS NOT ? AND id IS NOT ? AND ${notTemplateSample()} LIMIT 1`)
|
|
14
15
|
.get(samples.library, samples.audiobook, samples.podcast) !== undefined;
|
|
15
16
|
const dismissed = firstRunDismissed(db);
|
|
16
17
|
const packs = readPackRecords(db);
|
|
@@ -26,7 +26,7 @@ export function fullVideoDraft(deps, input) {
|
|
|
26
26
|
const config = project.config;
|
|
27
27
|
if (!usesShortMode(config))
|
|
28
28
|
return { ok: false, reason: "not-short" };
|
|
29
|
-
const topic = config.values.topic?.trim() || project.title;
|
|
29
|
+
const topic = config.values.Topic?.trim() || config.values.topic?.trim() || project.title;
|
|
30
30
|
const pack = shortPack(deps, config.articlePrompt ?? "");
|
|
31
31
|
const document = packDocument(deps, pack);
|
|
32
32
|
if (document === undefined)
|
|
@@ -46,7 +46,8 @@ export function fullVideoDraft(deps, input) {
|
|
|
46
46
|
form: {
|
|
47
47
|
...form,
|
|
48
48
|
title: project.title,
|
|
49
|
-
|
|
49
|
+
// {{Topic}} since 4.0; a pack installed before asks for {{topic}}.
|
|
50
|
+
values: { ...form.values, Topic: topic, topic },
|
|
50
51
|
llm: provider(config.llm, form.llm),
|
|
51
52
|
images: provider(config.images, form.images),
|
|
52
53
|
audio: config.audio === undefined
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { transact } from "../../kernel/db/tx.js";
|
|
2
|
+
import { internalError } from "../../kernel/errors.js";
|
|
2
3
|
import { detectSlots } from "../admission/substitute.js";
|
|
3
4
|
import { nameMax } from "../library/model.js";
|
|
4
5
|
import { insertPrompt, promptById, promptByName } from "../library/repo.js";
|
|
@@ -48,7 +49,7 @@ export function installPack(deps, packId, options = { template: true }) {
|
|
|
48
49
|
document: packTemplate(pack, names, voice.voiceId),
|
|
49
50
|
});
|
|
50
51
|
if (!created.ok)
|
|
51
|
-
throw new Error(`
|
|
52
|
+
throw new Error(internalError(`the ${pack.name} pack's template was refused: ${created.reason}`));
|
|
52
53
|
template = id;
|
|
53
54
|
added = true;
|
|
54
55
|
}
|
|
@@ -71,7 +72,7 @@ export function installPack(deps, packId, options = { template: true }) {
|
|
|
71
72
|
};
|
|
72
73
|
});
|
|
73
74
|
}
|
|
74
|
-
function placePrompt(deps, kind, name, body, at) {
|
|
75
|
+
export function placePrompt(deps, kind, name, body, at) {
|
|
75
76
|
for (let n = 1;; n += 1) {
|
|
76
77
|
const suffix = n === 1 ? "" : ` (${String(n)})`;
|
|
77
78
|
const candidate = `${name.slice(0, nameMax - suffix.length).trimEnd()}${suffix}`;
|
|
@@ -109,7 +110,7 @@ function placeVoice(deps, pack, before) {
|
|
|
109
110
|
});
|
|
110
111
|
return { id, voiceId: pack.voice.voiceId, added: true };
|
|
111
112
|
}
|
|
112
|
-
function freeTemplateName(deps, name) {
|
|
113
|
+
export function freeTemplateName(deps, name) {
|
|
113
114
|
const taken = new Set(templateSummaries(deps.db).map((row) => row.name.toLowerCase()));
|
|
114
115
|
for (let n = 1;; n += 1) {
|
|
115
116
|
const candidate = n === 1 ? name : `${name} (${String(n)})`;
|
|
@@ -63,22 +63,6 @@ export const quickShortInputSchema = z
|
|
|
63
63
|
export const fullVideoInputSchema = z
|
|
64
64
|
.object({ projectId: z.string().min(1).max(64), draftId: z.uuid() })
|
|
65
65
|
.strict();
|
|
66
|
-
export const quickShortResultSchema = z.object({
|
|
67
|
-
projectId: z.string(),
|
|
68
|
-
replayed: z.boolean(),
|
|
69
|
-
});
|
|
70
|
-
export const installedPackSchema = z.object({
|
|
71
|
-
packId: z.string(),
|
|
72
|
-
added: z.boolean(),
|
|
73
|
-
prompts: z.record(z.string(), z.string()),
|
|
74
|
-
templateId: z.string().nullable(),
|
|
75
|
-
voice: z.string().nullable(),
|
|
76
|
-
});
|
|
77
|
-
export const sampleCopySchema = z.object({ projectId: z.string() });
|
|
78
|
-
export const sampleStateSchema = z.object({
|
|
79
|
-
projectId: z.string().nullable(),
|
|
80
|
-
samples: sampleProjectsSchema,
|
|
81
|
-
});
|
|
82
66
|
// Make my own copy of one sample; without a project, the Library of Alexandria.
|
|
83
67
|
export const sampleCopyInputSchema = z
|
|
84
68
|
.object({ projectId: z.string().max(60).optional() })
|