@gentbajko/slopify 3.25.9 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/account-limits.js +30 -0
- package/dist/adapters/alignment/audio.js +1 -1
- package/dist/adapters/alignment/cache.js +4 -6
- package/dist/adapters/alignment/ctc.js +1 -2
- package/dist/adapters/alignment/lock.js +4 -3
- package/dist/adapters/alignment/multilingual.js +2 -4
- package/dist/adapters/alignment/prefetch.js +2 -1
- package/dist/adapters/alignment/runner.js +1 -1
- package/dist/adapters/alignment/worker.js +3 -2
- package/dist/adapters/explain.js +10 -12
- package/dist/adapters/ffmpeg.js +19 -1
- package/dist/adapters/host-cli/index.js +21 -4
- package/dist/adapters/host-cli/transport.js +2 -1
- package/dist/adapters/http-failure.js +53 -0
- package/dist/adapters/image/bytes.js +2 -1
- package/dist/adapters/image/codex.js +42 -9
- package/dist/adapters/image/fal.js +21 -53
- package/dist/adapters/image/google.js +33 -56
- package/dist/adapters/image/models.js +2 -2
- package/dist/adapters/image/openai.js +22 -48
- package/dist/adapters/image/reference.js +36 -0
- package/dist/adapters/image/replicate.js +21 -49
- package/dist/adapters/image/video.js +2 -1
- package/dist/adapters/interest/search-interest.js +113 -0
- package/dist/adapters/key-probes.js +54 -3
- package/dist/adapters/llm/antigravity-models.js +1 -1
- package/dist/adapters/llm/antigravity.js +11 -6
- package/dist/adapters/llm/assistant-cli.js +388 -0
- package/dist/adapters/llm/child-session.js +83 -0
- package/dist/adapters/llm/claude-code-models.js +52 -99
- package/dist/adapters/llm/claude-code.js +16 -4
- package/dist/adapters/llm/codex-limits.js +27 -68
- package/dist/adapters/llm/codex-models.js +1 -1
- package/dist/adapters/llm/codex-server-models.js +61 -109
- package/dist/adapters/llm/codex.js +12 -1
- package/dist/adapters/llm/document-workspace.js +3 -2
- package/dist/adapters/llm/image-workspace.js +3 -2
- package/dist/adapters/llm/openrouter.js +12 -48
- package/dist/adapters/llm/run-cli.js +9 -24
- package/dist/adapters/llm/sse-lines.js +5 -1
- package/dist/adapters/model-access.js +37 -0
- package/dist/adapters/tts/cartesia.js +15 -46
- package/dist/adapters/tts/elevenlabs.js +20 -52
- package/dist/adapters/tts/gemini.js +21 -41
- package/dist/adapters/tts/inworld-async.js +6 -2
- package/dist/adapters/tts/inworld.js +6 -2
- package/dist/adapters/tts/openai.js +20 -50
- package/dist/adapters/tts/system.js +2 -1
- package/dist/assets/models-lifecycle.yaml +6 -0
- package/dist/assistant-wiring.js +60 -0
- package/dist/autopilot-timers.js +59 -0
- package/dist/catalog/lifecycle.js +52 -0
- package/dist/catalog/propose.js +204 -0
- package/dist/catalog/registry.js +23 -14
- package/dist/catalog/schema.js +4 -1
- package/dist/catalog/store.js +39 -0
- package/dist/catalog/validate.js +5 -2
- package/dist/edge/autostart/native.js +3 -5
- package/dist/edge/autostart/prompt.js +2 -1
- package/dist/edge/autostart/service.js +3 -4
- package/dist/edge/cli-args.js +3 -4
- package/dist/edge/cli.js +2 -1
- package/dist/edge/docker-install/apply.js +11 -11
- package/dist/edge/docker-install/run.js +2 -1
- package/dist/edge/docker-install/state.js +4 -3
- package/dist/edge/docker-install/tree.js +2 -4
- package/dist/edge/docker-install/volume.js +3 -2
- package/dist/edge/docker.js +5 -4
- package/dist/edge/events/hub.js +5 -5
- package/dist/edge/http/actions.js +11 -32
- package/dist/edge/http/actor.js +5 -3
- package/dist/edge/http/app.js +86 -11
- package/dist/edge/http/assistant.js +129 -0
- package/dist/edge/http/audio-preview.js +4 -11
- package/dist/edge/http/auditions.js +1 -1
- package/dist/edge/http/autostart.js +5 -5
- package/dist/edge/http/backups.js +2 -4
- package/dist/edge/http/channel-memory.js +9 -22
- package/dist/edge/http/channels.js +14 -27
- package/dist/edge/http/checkpoints.js +39 -21
- package/dist/edge/http/design-templates.js +167 -0
- package/dist/edge/http/designs.js +178 -0
- package/dist/edge/http/diagnostics.js +5 -1
- package/dist/edge/http/document-themes.js +5 -14
- package/dist/edge/http/draft-files.js +1 -3
- package/dist/edge/http/draft-problem.js +5 -10
- package/dist/edge/http/drafts.js +3 -3
- package/dist/edge/http/entries.js +6 -9
- package/dist/edge/http/extension-auth.js +27 -0
- package/dist/edge/http/external-reviews.js +12 -11
- package/dist/edge/http/files.js +5 -11
- package/dist/edge/http/folder-location.js +1 -4
- package/dist/edge/http/fonts.js +0 -7
- package/dist/edge/http/home.js +47 -14
- package/dist/edge/http/host-cli.js +18 -8
- package/dist/edge/http/ids.js +8 -0
- package/dist/edge/http/keywords.js +35 -0
- package/dist/edge/http/model-checks.js +132 -0
- package/dist/edge/http/narration-peaks.js +5 -13
- package/dist/edge/http/onboarding.js +30 -26
- package/dist/edge/http/open-folder.js +5 -10
- package/dist/edge/http/outputs.js +7 -14
- package/dist/edge/http/patch-notes.js +6 -12
- package/dist/edge/http/planning.js +3 -7
- package/dist/edge/http/problem.js +2 -4
- package/dist/edge/http/project-create.js +2 -1
- package/dist/edge/http/project-templates.js +31 -19
- package/dist/edge/http/projects.js +24 -16
- package/dist/edge/http/prompts.js +9 -16
- package/dist/edge/http/pronunciations.js +1 -2
- package/dist/edge/http/providers.js +48 -34
- package/dist/edge/http/refusal.js +29 -0
- package/dist/edge/http/remote-access.js +40 -0
- package/dist/edge/http/remote-guard.js +71 -0
- package/dist/edge/http/request-guard.js +91 -0
- package/dist/edge/http/reviews.js +12 -25
- package/dist/edge/http/revision-files.js +6 -11
- package/dist/edge/http/revisions.js +14 -19
- package/dist/edge/http/run-cost.js +1 -2
- package/dist/edge/http/same-page.js +80 -0
- package/dist/edge/http/schedules.js +69 -40
- package/dist/edge/http/settings.js +27 -14
- package/dist/edge/http/social.js +283 -0
- package/dist/edge/http/staging.js +3 -5
- package/dist/edge/http/storage-files.js +5 -7
- package/dist/edge/http/storage.js +33 -25
- package/dist/edge/http/studio.js +94 -69
- package/dist/edge/http/style-preview.js +3 -6
- package/dist/edge/http/subtitles.js +3 -17
- package/dist/edge/http/template-studio.js +436 -0
- package/dist/edge/http/trash.js +11 -12
- package/dist/edge/http/tutorial.js +1 -2
- package/dist/edge/http/tutorials.js +5 -11
- package/dist/edge/http/update.js +7 -13
- package/dist/edge/http/waveform.js +3 -6
- package/dist/edge/http/youtube-edits.js +3 -4
- package/dist/edge/mcp/assistant.js +279 -0
- package/dist/edge/mcp/attribution.js +8 -2
- package/dist/edge/mcp/call-route.js +11 -2
- package/dist/edge/mcp/excluded-routes.js +29 -3
- package/dist/edge/mcp/http.js +11 -2
- package/dist/edge/mcp/instructions.js +6 -4
- package/dist/edge/mcp/library-tools.js +9 -5
- package/dist/edge/mcp/remake-tools.js +7 -4
- package/dist/edge/mcp/route-tool.js +35 -15
- package/dist/edge/mcp/server.js +13 -8
- package/dist/edge/mcp/tools-channels.js +11 -9
- package/dist/edge/mcp/tools-designs.js +165 -0
- package/dist/edge/mcp/tools-library.js +19 -7
- package/dist/edge/mcp/tools-planning.js +40 -21
- package/dist/edge/mcp/tools-projects.js +38 -11
- package/dist/edge/mcp/tools-publishing.js +9 -9
- package/dist/edge/mcp/tools-runs.js +23 -10
- package/dist/edge/mcp/tools-schedules.js +32 -8
- package/dist/edge/mcp/tools-setup.js +75 -11
- package/dist/edge/mcp/tools-social.js +47 -0
- package/dist/edge/mcp/tools-storage.js +11 -3
- package/dist/edge/mcp/tools-template-studio.js +166 -0
- package/dist/edge/mcp/tools.js +6 -0
- package/dist/edge/remote-access/cli.js +71 -0
- package/dist/edge/remote-access/model.js +32 -0
- package/dist/edge/remote-access/rules.js +207 -0
- package/dist/edge/remote-access/service.js +203 -0
- package/dist/edge/remote-access/store.js +44 -0
- package/dist/edge/remote-access/views.js +43 -0
- package/dist/extension/slopify-studio-chrome.zip +0 -0
- package/dist/extension/slopify-studio-firefox.zip +0 -0
- package/dist/host-cli/install.js +2 -2
- package/dist/host-cli/open-folder.js +2 -2
- package/dist/host-cli/paths.js +2 -4
- package/dist/host-cli/server.js +4 -4
- package/dist/host-cli/service.js +3 -3
- package/dist/host-cli/status.js +7 -7
- package/dist/kernel/db/migrations/0063-model-checks.sql +20 -0
- package/dist/kernel/db/migrations/0064-template-studio.sql +46 -0
- package/dist/kernel/db/migrations/0065-promise-and-assistant-reviews.sql +58 -0
- package/dist/kernel/db/migrations/0066-assistant.sql +44 -0
- package/dist/kernel/db/migrations/0067-autopilot.sql +6 -0
- package/dist/kernel/db/migrations/0068-topic-scores.sql +17 -0
- package/dist/kernel/db/migrations/0070-designs.sql +53 -0
- package/dist/kernel/db/migrations/0071-design-usage.sql +33 -0
- package/dist/kernel/db/migrations/0072-design-templates.sql +33 -0
- package/dist/kernel/db/migrations/0073-schedule-design-kind.sql +5 -0
- package/dist/kernel/db/migrations/0074-template-bakeoffs.sql +44 -0
- package/dist/kernel/db/migrations/0075-social-posts.sql +25 -0
- package/dist/kernel/db/migrations/0076-channel-social.sql +5 -0
- package/dist/kernel/db/migrations/0077-post-prompts.sql +17 -0
- package/dist/kernel/db/migrations/0078-uploaded-from-links.sql +7 -0
- package/dist/kernel/db/tx.js +2 -4
- package/dist/kernel/errors.js +27 -1
- package/dist/kernel/json-answer.js +15 -0
- package/dist/kernel/lock.js +4 -9
- package/dist/kernel/paths.js +8 -0
- package/dist/kernel/pipeline.js +12 -0
- package/dist/kernel/ports/assistant-cli.js +4 -0
- package/dist/kernel/ports/host-cli.js +3 -0
- package/dist/kernel/ports/interest.js +4 -0
- package/dist/kernel/ports/languages.js +0 -3
- package/dist/kernel/ports/model.js +2 -0
- package/dist/kernel/ports/settings-places.js +31 -0
- package/dist/kernel/ports/system-speech.js +31 -3
- package/dist/kernel/runner/attempt.js +14 -4
- package/dist/kernel/runner/audition.js +3 -1
- package/dist/kernel/runner/checkpoint-authority.js +2 -1
- package/dist/kernel/runner/index.js +8 -10
- package/dist/kernel/runner/model-access.js +40 -0
- package/dist/kernel/runner/model-check.js +153 -0
- package/dist/kernel/runner/providers.js +18 -12
- package/dist/kernel/runner/standalone.js +11 -7
- package/dist/main.js +338 -21
- package/dist/model-catalog.js +20 -0
- package/dist/model-checks.js +166 -0
- package/dist/patch-notes/4.0.0.md +51 -0
- package/dist/patch-notes/4.1.0.md +42 -0
- package/dist/patch-notes/index.json +12 -0
- package/dist/slices/admission/heads.js +2 -1
- package/dist/slices/admission/listing-facts.js +95 -0
- package/dist/slices/admission/repo.js +11 -7
- package/dist/slices/admission/rules.js +50 -15
- package/dist/slices/admission/schema.js +8 -0
- package/dist/slices/admission/stage-writes.js +0 -3
- package/dist/slices/admission/start.js +48 -31
- package/dist/slices/admission/state-words.js +34 -5
- package/dist/slices/admission/substitute.js +7 -4
- package/dist/slices/agents/attention-posts.js +31 -0
- package/dist/slices/agents/attention-templates.js +33 -0
- package/dist/slices/agents/attention.js +10 -1
- package/dist/slices/agents/connection.js +2 -6
- package/dist/slices/agents/model.js +6 -3
- package/dist/slices/agents/repo.js +15 -7
- package/dist/slices/article/continuation.js +0 -63
- package/dist/slices/article/plain.js +3 -2
- package/dist/slices/article/segments.js +2 -62
- package/dist/slices/assistant/access.js +1 -0
- package/dist/slices/assistant/asks.js +80 -0
- package/dist/slices/assistant/cost.js +54 -0
- package/dist/slices/assistant/gate.js +222 -0
- package/dist/slices/assistant/model.js +86 -0
- package/dist/slices/assistant/names.js +23 -0
- package/dist/slices/assistant/prompt.js +74 -0
- package/dist/slices/assistant/repo.js +74 -0
- package/dist/slices/assistant/tokens.js +18 -0
- package/dist/slices/assistant/turn.js +344 -0
- package/dist/slices/autopilot/buffer.js +76 -0
- package/dist/slices/autopilot/model.js +14 -0
- package/dist/slices/autopilot/notify.js +27 -0
- package/dist/slices/autopilot/repo.js +34 -0
- package/dist/slices/autopilot/signals.js +194 -0
- package/dist/slices/autopilot/warnings.js +85 -0
- package/dist/slices/autopilot/weekly.js +100 -0
- package/dist/slices/backups/files.js +2 -6
- package/dist/slices/backups/repo.js +3 -15
- package/dist/slices/backups/service.js +8 -7
- package/dist/slices/channels/cast-images.js +3 -2
- package/dist/slices/channels/model.js +0 -1
- package/dist/slices/channels/rebrand.js +0 -3
- package/dist/slices/channels/repo.js +4 -0
- package/dist/slices/channels/schema.js +7 -1
- package/dist/slices/channels/service.js +10 -0
- package/dist/slices/channels/videos.js +3 -15
- package/dist/slices/checkpoints/index.js +0 -1
- package/dist/slices/control/providers.js +2 -28
- package/dist/slices/designs/artwork.js +66 -0
- package/dist/slices/designs/budget.js +23 -0
- package/dist/slices/designs/calls.js +124 -0
- package/dist/slices/designs/check-context.js +38 -0
- package/dist/slices/designs/check-text.js +43 -0
- package/dist/slices/designs/fields.js +88 -0
- package/dist/slices/designs/frames.js +34 -0
- package/dist/slices/designs/gate.js +130 -0
- package/dist/slices/designs/layout.js +293 -0
- package/dist/slices/designs/model.js +35 -0
- package/dist/slices/designs/pdf-job.js +23 -0
- package/dist/slices/designs/pdf-pages.js +30 -0
- package/dist/slices/designs/pdf-runner.js +68 -0
- package/dist/slices/designs/pdf-worker.js +24 -0
- package/dist/slices/designs/picture-size.js +79 -0
- package/dist/slices/designs/pictures.js +55 -0
- package/dist/slices/designs/quote.js +24 -0
- package/dist/slices/designs/render-args.js +36 -0
- package/dist/slices/designs/render-input.js +59 -0
- package/dist/slices/designs/render.js +215 -0
- package/dist/slices/designs/repo.js +101 -0
- package/dist/slices/designs/requests.js +80 -0
- package/dist/slices/designs/runner.js +239 -0
- package/dist/slices/designs/sample-repo.js +91 -0
- package/dist/slices/designs/sample.js +223 -0
- package/dist/slices/designs/schema.js +87 -0
- package/dist/slices/designs/sections.js +44 -0
- package/dist/slices/designs/service.js +233 -0
- package/dist/slices/designs/steps-repo.js +102 -0
- package/dist/slices/designs/studio-kind.js +39 -0
- package/dist/slices/designs/template-checks.js +44 -0
- package/dist/slices/designs/template-make.js +118 -0
- package/dist/slices/designs/templates.js +218 -0
- package/dist/slices/document/fonts.js +2 -1
- package/dist/slices/document/model.js +7 -4
- package/dist/slices/document/render.js +2 -1
- package/dist/slices/document/theme-schema.js +1 -1
- package/dist/slices/document/theme.js +49 -3
- package/dist/slices/episodes/summarize.js +6 -2
- package/dist/slices/estimate/index.js +72 -28
- package/dist/slices/estimate/requests.js +4 -4
- package/dist/slices/fixes/rules.js +3 -1
- package/dist/slices/fonts/catalog.js +5 -3
- package/dist/slices/fonts/coverage.js +2 -1
- package/dist/slices/fonts/discovery.js +3 -2
- package/dist/slices/fonts/files.js +2 -6
- package/dist/slices/fonts/index.js +0 -1
- package/dist/slices/fonts/sfnt.js +45 -10
- package/dist/slices/images/appearance.js +8 -16
- package/dist/slices/images/scenes.js +102 -28
- package/dist/slices/keywords/digest.js +85 -0
- package/dist/slices/keywords/facts.js +92 -0
- package/dist/slices/keywords/fill.js +80 -0
- package/dist/slices/keywords/model.js +75 -0
- package/dist/slices/keywords/rules.js +187 -0
- package/dist/slices/keywords/schema.js +28 -0
- package/dist/slices/keywords/specs.js +260 -0
- package/dist/slices/keywords/values.js +74 -0
- package/dist/slices/library/lint.js +29 -12
- package/dist/slices/library/model.js +2 -0
- package/dist/slices/library/photorealistic.js +4 -12
- package/dist/slices/library/rename.js +9 -7
- package/dist/slices/library/save.js +14 -10
- package/dist/slices/library/slots.js +37 -11
- package/dist/slices/library/transfer.js +5 -4
- package/dist/slices/library/used-by.js +25 -10
- package/dist/slices/loudness/loudnorm.js +53 -12
- package/dist/slices/loudness/model.js +3 -2
- package/dist/slices/loudness/sentence-level.js +2 -1
- package/dist/slices/model-checks/cost.js +61 -0
- package/dist/slices/model-checks/listing.js +124 -0
- package/dist/slices/model-checks/model.js +20 -0
- package/dist/slices/model-checks/record.js +32 -0
- package/dist/slices/model-checks/repo.js +120 -0
- package/dist/slices/model-checks/rules.js +125 -0
- package/dist/slices/model-checks/run.js +143 -0
- package/dist/slices/model-checks/service.js +198 -0
- package/dist/slices/model-upkeep/model.js +1 -1
- package/dist/slices/model-upkeep/switch.js +72 -27
- package/dist/slices/model-upkeep/usage.js +39 -13
- package/dist/slices/narration/breaths.js +3 -1
- package/dist/slices/narration/clean-pieces.js +3 -1
- package/dist/slices/narration/concat.js +2 -1
- package/dist/slices/narration/pauses-model.js +3 -2
- package/dist/slices/narration/peaks.js +3 -4
- package/dist/slices/narration/pronunciation-chunks.js +4 -3
- package/dist/slices/narration/pronunciation.js +6 -4
- package/dist/slices/narration/steering.js +4 -3
- package/dist/slices/notifications/notifier.js +4 -3
- package/dist/slices/notifications/rules.js +5 -2
- package/dist/slices/notifications/settings.js +4 -12
- package/dist/slices/notifications/subject.js +4 -3
- package/dist/slices/onboarding/copy.js +21 -3
- package/dist/slices/onboarding/first-run.js +16 -40
- package/dist/slices/onboarding/full-video.js +3 -2
- package/dist/slices/onboarding/install.js +6 -4
- package/dist/slices/onboarding/model.js +26 -37
- package/dist/slices/onboarding/packs.js +22 -22
- package/dist/slices/onboarding/preferred-model.js +14 -0
- package/dist/slices/onboarding/quick-short.js +105 -65
- package/dist/slices/onboarding/sample.js +4 -2
- package/dist/slices/onboarding/state.js +9 -11
- package/dist/slices/onboarding/template.js +8 -6
- package/dist/slices/outputs/add.js +3 -2
- package/dist/slices/outputs/service.js +2 -2
- package/dist/slices/patch-notes/library.js +4 -3
- package/dist/slices/play-drafts/convert.js +4 -0
- package/dist/slices/play-drafts/readiness.js +3 -3
- package/dist/slices/play-drafts/review-inputs.js +9 -3
- package/dist/slices/play-drafts/review.js +5 -4
- package/dist/slices/play-drafts/schema.js +4 -0
- package/dist/slices/play-drafts/service.js +17 -7
- package/dist/slices/project-templates/from-project.js +9 -2
- package/dist/slices/project-templates/next-chapter.js +2 -1
- package/dist/slices/project-templates/provider-defaults.js +22 -0
- package/dist/slices/project-templates/repo.js +6 -1
- package/dist/slices/project-templates/setup-sections.js +26 -0
- package/dist/slices/project-templates/setup.js +14 -1
- package/dist/slices/project-templates/stand-ins.js +22 -0
- package/dist/slices/rebuild/activity.js +2 -0
- package/dist/slices/rebuild/admission-repo.js +3 -2
- package/dist/slices/rebuild/narration-history.js +4 -5
- package/dist/slices/rebuild/narration-retry.js +2 -1
- package/dist/slices/rebuild/preview-details.js +32 -14
- package/dist/slices/rebuild/preview-plan.js +3 -8
- package/dist/slices/rebuild/recipe-build.js +8 -3
- package/dist/slices/rebuild/recipe-describe.js +3 -3
- package/dist/slices/rebuild/recipe-digest.js +58 -0
- package/dist/slices/rebuild/recipe-input-schema.js +10 -0
- package/dist/slices/rebuild/recipe-keywords.js +71 -0
- package/dist/slices/rebuild/recipe-legacy.js +5 -1
- package/dist/slices/rebuild/recipe-model.js +4 -0
- package/dist/slices/rebuild/recipe-narration-text.js +2 -1
- package/dist/slices/rebuild/recipe-preparation.js +4 -4
- package/dist/slices/rebuild/recipe-reference.js +8 -4
- package/dist/slices/rebuild/recipe-reviews.js +27 -7
- package/dist/slices/rebuild/recipe-save.js +8 -5
- package/dist/slices/rebuild/recipe-scenes.js +40 -11
- package/dist/slices/rebuild/recipe-shorts.js +8 -8
- package/dist/slices/rebuild/recipe-social.js +46 -0
- package/dist/slices/rebuild/recipe-text.js +64 -20
- package/dist/slices/rebuild/recipe-validation.js +102 -31
- package/dist/slices/rebuild/recipe-visual.js +55 -16
- package/dist/slices/rebuild/recipe-voices.js +3 -2
- package/dist/slices/rebuild/recipe-work.js +19 -7
- package/dist/slices/rebuild/recipe-youtube.js +4 -3
- package/dist/slices/rebuild/recovery-selection.js +3 -1
- package/dist/slices/rebuild/recovery.js +9 -8
- package/dist/slices/rebuild/remake-outdated.js +5 -5
- package/dist/slices/rebuild/repo.js +4 -3
- package/dist/slices/rebuild/review-promise.js +25 -0
- package/dist/slices/rebuild/review-redo.js +3 -2
- package/dist/slices/rebuild/runtime-admission.js +4 -3
- package/dist/slices/rebuild/runtime-agent-review.js +11 -5
- package/dist/slices/rebuild/runtime-animate.js +10 -9
- package/dist/slices/rebuild/runtime-article.js +7 -5
- package/dist/slices/rebuild/runtime-checkpoints.js +5 -4
- package/dist/slices/rebuild/runtime-document.js +11 -13
- package/dist/slices/rebuild/runtime-export-bed.js +8 -12
- package/dist/slices/rebuild/runtime-export-edit.js +8 -16
- package/dist/slices/rebuild/runtime-export-inputs.js +12 -11
- package/dist/slices/rebuild/runtime-export-short.js +9 -5
- package/dist/slices/rebuild/runtime-export.js +38 -15
- package/dist/slices/rebuild/runtime-figure-card.js +2 -1
- package/dist/slices/rebuild/runtime-image.js +8 -12
- package/dist/slices/rebuild/runtime-instructions.js +2 -0
- package/dist/slices/rebuild/runtime-keywords.js +59 -0
- package/dist/slices/rebuild/runtime-lines.js +2 -11
- package/dist/slices/rebuild/runtime-local.js +17 -22
- package/dist/slices/rebuild/runtime-narration-publication.js +2 -5
- package/dist/slices/rebuild/runtime-narration-reuse.js +9 -13
- package/dist/slices/rebuild/runtime-narration-text.js +13 -17
- package/dist/slices/rebuild/runtime-pictures.js +2 -4
- package/dist/slices/rebuild/runtime-piece-label.js +10 -6
- package/dist/slices/rebuild/runtime-plan.js +31 -5
- package/dist/slices/rebuild/runtime-provider.js +67 -25
- package/dist/slices/rebuild/runtime-publication.js +10 -9
- package/dist/slices/rebuild/runtime-review.js +39 -33
- package/dist/slices/rebuild/runtime-run.js +4 -1
- package/dist/slices/rebuild/runtime-shorts.js +31 -50
- package/dist/slices/rebuild/runtime-store.js +20 -10
- package/dist/slices/rebuild/runtime-subtitles.js +28 -25
- package/dist/slices/rebuild/runtime-voices.js +10 -16
- package/dist/slices/rebuild/runtime-youtube.js +14 -31
- package/dist/slices/rebuild/service-readiness.js +11 -3
- package/dist/slices/rebuild/transition-repo.js +6 -5
- package/dist/slices/rebuild/work-records.js +6 -0
- package/dist/slices/reruns/cascade.js +1 -2
- package/dist/slices/reruns/index.js +6 -9
- package/dist/slices/research/synthesis.js +3 -2
- package/dist/slices/reviews/external-model.js +4 -1
- package/dist/slices/reviews/external-repo.js +2 -1
- package/dist/slices/reviews/external-rows.js +2 -3
- package/dist/slices/reviews/holds.js +5 -4
- package/dist/slices/reviews/model.js +32 -11
- package/dist/slices/reviews/repo.js +2 -1
- package/dist/slices/reviews/rules.js +4 -3
- package/dist/slices/reviews/verdict.js +2 -1
- package/dist/slices/reviews/view.js +5 -2
- package/dist/slices/revisions/downloads.js +4 -5
- package/dist/slices/revisions/image-plan.js +1 -1
- package/dist/slices/revisions/mutation-assets.js +9 -5
- package/dist/slices/revisions/mutation-cues.js +2 -5
- package/dist/slices/revisions/mutations.js +3 -3
- package/dist/slices/revisions/repo.js +3 -1
- package/dist/slices/revisions/schema.js +1 -0
- package/dist/slices/revisions/view.js +20 -0
- package/dist/slices/run-cost/limits.js +5 -2
- package/dist/slices/run-cost/meter.js +12 -5
- package/dist/slices/run-cost/panel.js +8 -74
- package/dist/slices/run-cost/plan-readings.js +127 -0
- package/dist/slices/run-cost/plan-use.js +169 -0
- package/dist/slices/run-cost/pricing.js +3 -3
- package/dist/slices/run-cost/week.js +32 -4
- package/dist/slices/schedules/agenda.js +18 -7
- package/dist/slices/schedules/by-date.js +42 -0
- package/dist/slices/schedules/calendar.js +5 -0
- package/dist/slices/schedules/design-agenda.js +36 -0
- package/dist/slices/schedules/design-check.js +41 -0
- package/dist/slices/schedules/design-run.js +126 -0
- package/dist/slices/schedules/next-run.js +62 -0
- package/dist/slices/schedules/prepare.js +18 -2
- package/dist/slices/schedules/repo.js +30 -21
- package/dist/slices/schedules/rescore.js +35 -0
- package/dist/slices/schedules/scheduler.js +13 -3
- package/dist/slices/schedules/schema.js +57 -3
- package/dist/slices/schedules/score.js +107 -0
- package/dist/slices/schedules/service.js +57 -24
- package/dist/slices/schedules/topic-list.js +15 -0
- package/dist/slices/schedules/topic-scores.js +104 -0
- package/dist/slices/schedules/topics.js +53 -41
- package/dist/slices/settings/cli-paths.js +4 -6
- package/dist/slices/settings/first-run.js +8 -43
- package/dist/slices/settings/health.js +30 -15
- package/dist/slices/settings/key-test.js +1 -1
- package/dist/slices/settings/model-reach.js +3 -17
- package/dist/slices/settings/model.js +14 -2
- package/dist/slices/settings/playback.js +34 -23
- package/dist/slices/settings/probe-read.js +16 -0
- package/dist/slices/settings/repo.js +33 -0
- package/dist/slices/settings/tutorial.js +2 -2
- package/dist/slices/settings/voices.js +4 -12
- package/dist/slices/shorts/keep.js +2 -1
- package/dist/slices/shorts/pick.js +6 -18
- package/dist/slices/shorts/prompts.js +4 -14
- package/dist/slices/shorts/render.js +6 -2
- package/dist/slices/social/channel.js +44 -0
- package/dist/slices/social/defaults.js +17 -0
- package/dist/slices/social/due.js +36 -0
- package/dist/slices/social/extension.js +18 -0
- package/dist/slices/social/fit.js +115 -0
- package/dist/slices/social/limits.js +186 -0
- package/dist/slices/social/links.js +21 -0
- package/dist/slices/social/media.js +132 -0
- package/dist/slices/social/model.js +75 -0
- package/dist/slices/social/notice.js +19 -0
- package/dist/slices/social/pack.js +176 -0
- package/dist/slices/social/post-prompt.js +56 -0
- package/dist/slices/social/queue.js +31 -0
- package/dist/slices/social/repo.js +133 -0
- package/dist/slices/social/reshape.js +97 -0
- package/dist/slices/social/rules.js +5 -0
- package/dist/slices/social/schema.js +70 -0
- package/dist/slices/social/serve.js +51 -0
- package/dist/slices/social/service.js +129 -0
- package/dist/slices/social/settings.js +21 -0
- package/dist/slices/social/sources.js +114 -0
- package/dist/slices/social/state.js +110 -0
- package/dist/slices/social/text.js +149 -0
- package/dist/slices/storage/arrange.js +3 -1
- package/dist/slices/storage/assets.js +8 -10
- package/dist/slices/storage/backup-designs.js +74 -0
- package/dist/slices/storage/backup-export.js +8 -3
- package/dist/slices/storage/backup-format.js +10 -0
- package/dist/slices/storage/backup-import.js +22 -4
- package/dist/slices/storage/delete-project.js +6 -5
- package/dist/slices/storage/files-location.js +6 -8
- package/dist/slices/storage/layout.js +13 -2
- package/dist/slices/storage/model.js +3 -0
- package/dist/slices/storage/portable.js +17 -12
- package/dist/slices/storage/schema.js +2 -0
- package/dist/slices/storage/staging-refs.js +2 -1
- package/dist/slices/storage/staging.js +6 -9
- package/dist/slices/storage/trim.js +26 -9
- package/dist/slices/studio/calendar.js +7 -2
- package/dist/slices/studio/disclosure.js +4 -4
- package/dist/slices/studio/model.js +1 -1
- package/dist/slices/studio/pack.js +9 -8
- package/dist/slices/studio/pick.js +2 -11
- package/dist/slices/studio/plan.js +7 -16
- package/dist/slices/studio/queue.js +3 -14
- package/dist/slices/studio/releases.js +26 -0
- package/dist/slices/studio/settings.js +20 -57
- package/dist/slices/studio/videos.js +35 -4
- package/dist/slices/style-preview/render.js +37 -16
- package/dist/slices/style-preview/schema.js +14 -1
- package/dist/slices/style-preview/service.js +2 -1
- package/dist/slices/style-preview/settings.js +33 -5
- package/dist/slices/subtitles/captions.js +1 -1
- package/dist/slices/telemetry/collector-client.js +2 -4
- package/dist/slices/telemetry/flush.js +2 -4
- package/dist/slices/telemetry/model.js +0 -7
- package/dist/slices/telemetry/record.js +10 -3
- package/dist/slices/template-studio/anatomy-view.js +161 -0
- package/dist/slices/template-studio/anatomy.js +73 -0
- package/dist/slices/template-studio/bakeoff-make.js +225 -0
- package/dist/slices/template-studio/bakeoff-repo.js +83 -0
- package/dist/slices/template-studio/bakeoff.js +333 -0
- package/dist/slices/template-studio/budget.js +106 -0
- package/dist/slices/template-studio/cards.js +78 -0
- package/dist/slices/template-studio/checks.js +322 -0
- package/dist/slices/template-studio/document-sample.js +56 -0
- package/dist/slices/template-studio/edit.js +15 -0
- package/dist/slices/template-studio/for-all.js +161 -0
- package/dist/slices/template-studio/free-video.js +31 -0
- package/dist/slices/template-studio/free.js +176 -0
- package/dist/slices/template-studio/gate.js +40 -0
- package/dist/slices/template-studio/hidden.js +20 -0
- package/dist/slices/template-studio/jobs.js +79 -0
- package/dist/slices/template-studio/loudness.js +111 -0
- package/dist/slices/template-studio/make.js +40 -0
- package/dist/slices/template-studio/model.js +58 -0
- package/dist/slices/template-studio/pack-import.js +253 -0
- package/dist/slices/template-studio/pack-samples.js +60 -0
- package/dist/slices/template-studio/pack.js +207 -0
- package/dist/slices/template-studio/paid-view.js +66 -0
- package/dist/slices/template-studio/paid.js +355 -0
- package/dist/slices/template-studio/quote.js +155 -0
- package/dist/slices/template-studio/ready.js +104 -0
- package/dist/slices/template-studio/repo.js +134 -0
- package/dist/slices/template-studio/reviews-path.js +58 -0
- package/dist/slices/template-studio/runner.js +84 -0
- package/dist/slices/template-studio/save.js +236 -0
- package/dist/slices/template-studio/say-it-as.js +248 -0
- package/dist/slices/template-studio/schedule-gate.js +34 -0
- package/dist/slices/template-studio/schedule-price.js +32 -0
- package/dist/slices/template-studio/schedule-sample.js +91 -0
- package/dist/slices/template-studio/schema.js +243 -0
- package/dist/slices/template-studio/scope.js +124 -0
- package/dist/slices/template-studio/sections.js +176 -0
- package/dist/slices/template-studio/service.js +175 -0
- package/dist/slices/template-studio/status.js +191 -0
- package/dist/slices/template-studio/topic.js +223 -0
- package/dist/slices/thumbnail/by-llm.js +1 -1
- package/dist/slices/trash/designs.js +76 -0
- package/dist/slices/trash/model.js +13 -4
- package/dist/slices/trash/service.js +52 -2
- package/dist/slices/tutorials/library.js +3 -2
- package/dist/slices/uploads/repo.js +37 -1
- package/dist/slices/uploads/rules.js +3 -2
- package/dist/slices/video/ass-text.js +17 -0
- package/dist/slices/video/audio-export.js +2 -64
- package/dist/slices/video/edit-list.js +2 -2
- package/dist/slices/video/edit-settings.js +1 -1
- package/dist/slices/video/encoding.js +169 -0
- package/dist/slices/video/ffmpeg.js +23 -21
- package/dist/slices/video/figure-card.js +1 -15
- package/dist/slices/video/plan.js +2 -1
- package/dist/slices/video/slideshow.js +43 -18
- package/dist/slices/voices/attribution.js +3 -2
- package/dist/slices/voices/model.js +9 -8
- package/dist/slices/voices/palette.js +0 -3
- package/dist/slices/voices/script.js +2 -1
- package/dist/slices/youtube/answer.js +4 -16
- package/dist/slices/youtube/edits-repo.js +3 -12
- package/dist/tutorials/AI-CLIs.md +25 -25
- package/dist/tutorials/Agents-MCP.md +34 -33
- package/dist/tutorials/Assistant.md +42 -0
- package/dist/tutorials/Backups.md +7 -7
- package/dist/tutorials/Calendar.md +17 -25
- package/dist/tutorials/Cast-Library.md +19 -19
- package/dist/tutorials/Channels.md +42 -35
- package/dist/tutorials/Costs-and-Run-Cost.md +38 -40
- package/dist/tutorials/Create-Article.md +114 -0
- package/dist/tutorials/Create-Extras.md +112 -0
- package/dist/tutorials/Create-Images.md +165 -0
- package/dist/tutorials/Create-Narration.md +178 -0
- package/dist/tutorials/Create-Overview.md +244 -0
- package/dist/tutorials/Create-Video-and-Style.md +144 -0
- package/dist/tutorials/Docker.md +3 -3
- package/dist/tutorials/Document-Themes.md +32 -32
- package/dist/tutorials/Editing-a-Project.md +94 -94
- package/dist/tutorials/FAQ.md +18 -18
- package/dist/tutorials/First-Launch-and-Welcome.md +50 -64
- package/dist/tutorials/Home-and-Projects.md +115 -71
- package/dist/tutorials/Home.md +33 -33
- package/dist/tutorials/Install.md +14 -13
- package/dist/tutorials/Intros-and-Outros.md +33 -34
- package/dist/tutorials/Keyboard-Shortcuts-and-Command-Palette.md +62 -58
- package/dist/tutorials/Keywords-Slopify-Fills.md +87 -0
- package/dist/tutorials/Models.md +53 -21
- package/dist/tutorials/Multiple-Voices.md +41 -40
- package/dist/tutorials/Narration-Aliases-and-Glossary.md +14 -14
- package/dist/tutorials/Notifications.md +27 -17
- package/dist/tutorials/Other-Languages.md +15 -15
- package/dist/tutorials/PDF-Documents.md +38 -29
- package/dist/tutorials/Posting-to-Social-Sites.md +121 -0
- package/dist/tutorials/Project-Page.md +118 -120
- package/dist/tutorials/Prompts-and-Templates.md +84 -0
- package/dist/tutorials/Prompts.md +48 -44
- package/dist/tutorials/Providers-and-Keys.md +105 -98
- package/dist/tutorials/Publishing-to-YouTube.md +31 -31
- package/dist/tutorials/Recovery-and-Retries.md +31 -31
- package/dist/tutorials/Remote-Access.md +63 -0
- package/dist/tutorials/Reviews-and-Checkpoints.md +98 -90
- package/dist/tutorials/Schedules.md +46 -27
- package/dist/tutorials/Settings-Reference.md +194 -174
- package/dist/tutorials/Shorts.md +34 -33
- package/dist/tutorials/Start-at-Login.md +3 -3
- package/dist/tutorials/Studio-Extension.md +22 -24
- package/dist/tutorials/Template-Studio.md +128 -0
- package/dist/tutorials/Templates.md +51 -77
- package/dist/tutorials/Trash.md +4 -4
- package/dist/tutorials/Troubleshooting.md +44 -44
- package/dist/tutorials/Uninstalling-and-Moving.md +5 -5
- package/dist/tutorials/Updating-and-Patch-Notes.md +18 -18
- package/dist/tutorials/Video-Editing.md +34 -34
- package/dist/tutorials/Where-Your-Files-Live.md +10 -10
- package/dist/tutorials/YouTube-Description.md +26 -26
- package/dist/tutorials/Your-First-Short.md +35 -35
- package/dist/tutorials/_Sidebar.md +19 -14
- package/dist/updater/work-in-progress.js +42 -12
- package/dist/web/assets/index-BNftKQrA.css +1 -0
- package/dist/web/assets/index-Cpa58woP.js +459 -0
- package/dist/web/assets/pdf-BKh8f7R6.js +56 -0
- package/dist/web/assets/pdf.worker.min-BmVo14Nb.mjs +28 -0
- package/dist/web/assets/pdf.worker.min-D7i8o3wR.js +1 -0
- package/dist/web/index.html +2 -2
- package/package.json +6 -2
- package/dist/slices/article/provided-entries.js +0 -66
- package/dist/slices/article/run.js +0 -145
- package/dist/slices/images/run.js +0 -234
- package/dist/slices/narration/legacy-plan.js +0 -58
- package/dist/slices/narration/run.js +0 -270
- package/dist/slices/rebuild/runtime-actions.js +0 -90
- package/dist/slices/research/run.js +0 -224
- package/dist/slices/subtitles/prepare.js +0 -194
- package/dist/slices/subtitles/transcript.js +0 -34
- package/dist/slices/thumbnail/run.js +0 -219
- package/dist/slices/video/audio-inputs.js +0 -33
- package/dist/slices/video/reuse-audio.js +0 -62
- package/dist/slices/video/run.js +0 -78
- package/dist/slices/video/write-export.js +0 -158
- package/dist/slices/video/write-subtitles.js +0 -59
- package/dist/tutorials/Library-Overview.md +0 -76
- package/dist/tutorials/Play-Images.md +0 -161
- package/dist/tutorials/Play-Narration.md +0 -167
- package/dist/tutorials/Play-Outputs.md +0 -109
- package/dist/tutorials/Play-Overview.md +0 -227
- package/dist/tutorials/Play-Title-and-Article.md +0 -136
- package/dist/tutorials/Play-Video-and-Style.md +0 -143
- package/dist/web/assets/index-BadsoORk.css +0 -1
- package/dist/web/assets/index-D8LqNsCl.js +0 -326
- package/dist/web/assets/pdf-T7MCwjIv.js +0 -54
- package/dist/web/assets/pdf.worker.min-Dswkl-cV.mjs +0 -29
- package/dist/web/assets/pdf.worker.min-zC6nfbxG.js +0 -1
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { setupSectionNames } from "../../slices/project-templates/setup-sections.js";
|
|
2
|
+
import { choiceBody, linkBody, redditBody, textBody } from "../../slices/social/schema.js";
|
|
3
|
+
// A project's posts to X, LinkedIn, Instagram, TikTok, Reddit and Bluesky, as Copy for YouTube
|
|
4
|
+
// Studio shows them. Agents prepare them; Fill in <site> and posting are the person's.
|
|
5
|
+
export const socialTools = [
|
|
6
|
+
{
|
|
7
|
+
name: "get_post_packs",
|
|
8
|
+
route: "GET /api/social/packs/:projectId",
|
|
9
|
+
title: "Read the posts for other sites",
|
|
10
|
+
description: "Copy for YouTube Studio's posts: for each site the project posts to, the text as it goes in (with its count and limit), hashtags, link, media, AI label, when it goes out, warnings and where the post stands. The agent's work ends here: filling a site's form and posting are the person's.",
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
name: "set_post_choice",
|
|
14
|
+
route: "PUT /api/social/packs/:projectId/:platform/choice",
|
|
15
|
+
title: "Change what a post carries",
|
|
16
|
+
description: `The project's own settings for one site (platform: x, linkedin, instagram, tiktok, reddit or bluesky): its text source, media, hashtags and link; {off: true} to not post there; null to go back to the template's. A post prompt (text "prompt") is a paid step picked only in the template (Edit template → ${setupSectionNames.youtube}) or in Create, where Save shows its cost. Body: {choice}.`,
|
|
17
|
+
body: choiceBody,
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
name: "edit_post_text",
|
|
21
|
+
route: "PUT /api/social/packs/:projectId/:platform/text",
|
|
22
|
+
title: "Edit a post's text",
|
|
23
|
+
description: "Hand-edits one site's post text. Body: {text: the new text, base: the text you edited from (get_post_packs' generated)}.",
|
|
24
|
+
body: textBody,
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
name: "reset_post_text",
|
|
28
|
+
route: "DELETE /api/social/packs/:projectId/:platform/text",
|
|
29
|
+
title: "Drop a post's hand edit",
|
|
30
|
+
description: "Drops the hand edit of one site's post; the written text comes back.",
|
|
31
|
+
confirm: "This drops your hand edit of this post for good; the text Slopify wrote comes back.",
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
name: "set_reddit_post",
|
|
35
|
+
route: "PUT /api/social/packs/:projectId/:platform/reddit",
|
|
36
|
+
title: "Set the Reddit post's fields",
|
|
37
|
+
description: "The Reddit post's subreddit (without r/), title, flair and kind (link, text or media); platform must be reddit. Body: {reddit: {subreddit, title, flair, kind}}.",
|
|
38
|
+
body: redditBody,
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
name: "set_post_link",
|
|
42
|
+
route: "PUT /api/social/packs/:projectId/:platform/link",
|
|
43
|
+
title: "Record a post's link",
|
|
44
|
+
description: "Marks one site's post as posted with its link (a post the person made by hand, or one the extension missed); null removes the link so the post can be filled again. Body: {url: the post's address | null}.",
|
|
45
|
+
body: linkBody,
|
|
46
|
+
},
|
|
47
|
+
];
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { fullVideoInputSchema, quickShortInputSchema } from "../../slices/onboarding/model.js";
|
|
2
|
+
import { moveFilesBody } from "../http/storage-files.js";
|
|
3
|
+
import { manySchema } from "../http/trash.js";
|
|
1
4
|
import { formBody } from "./route-tool.js";
|
|
2
5
|
const storage = [
|
|
3
6
|
{
|
|
@@ -9,6 +12,7 @@ const storage = [
|
|
|
9
12
|
{
|
|
10
13
|
name: "move_files_folder",
|
|
11
14
|
route: "POST /api/storage/files/move",
|
|
15
|
+
body: moveFilesBody,
|
|
12
16
|
title: "Move the files folder",
|
|
13
17
|
description: "Body: {target: the new folder's full path; it must be empty or new}.",
|
|
14
18
|
confirm: "This moves every project and backup file to the new folder; Slopify refuses a folder that is not empty.",
|
|
@@ -34,6 +38,7 @@ const storage = [
|
|
|
34
38
|
{
|
|
35
39
|
name: "restore_from_trash_many",
|
|
36
40
|
route: "POST /api/trash/bulk/restore",
|
|
41
|
+
body: manySchema,
|
|
37
42
|
title: "Restore several from the trash",
|
|
38
43
|
description: "Restore for the ticked rows. Body: {items: [{kind, id}]}.",
|
|
39
44
|
},
|
|
@@ -47,6 +52,7 @@ const storage = [
|
|
|
47
52
|
{
|
|
48
53
|
name: "delete_from_trash_many",
|
|
49
54
|
route: "POST /api/trash/bulk/delete",
|
|
55
|
+
body: manySchema,
|
|
50
56
|
title: "Delete several for good",
|
|
51
57
|
description: "Delete now for the ticked rows. Body: {items: [{kind, id}]}.",
|
|
52
58
|
confirm: "The projects and every file they produced are removed from disk (deleted schedules keep their run history on Schedules). Nothing removed here can be restored. This cannot be undone.",
|
|
@@ -57,23 +63,25 @@ const onboarding = [
|
|
|
57
63
|
name: "get_onboarding",
|
|
58
64
|
route: "GET /api/onboarding",
|
|
59
65
|
title: "Read the welcome state",
|
|
60
|
-
description: "Starter
|
|
66
|
+
description: "Starter templates and what the welcome offers.",
|
|
61
67
|
},
|
|
62
68
|
{
|
|
63
69
|
name: "install_starter_pack",
|
|
64
70
|
route: "POST /api/onboarding/packs/:id",
|
|
65
|
-
title: "Install a starter
|
|
66
|
-
description: "Adds a starter
|
|
71
|
+
title: "Install a starter template",
|
|
72
|
+
description: "Adds a starter template's prompts and templates.",
|
|
67
73
|
},
|
|
68
74
|
{
|
|
69
75
|
name: "make_quick_short",
|
|
70
76
|
route: "POST /api/onboarding/short",
|
|
77
|
+
body: quickShortInputSchema,
|
|
71
78
|
title: "Make a quick short",
|
|
72
79
|
description: `${formBody("the welcome's Make a short")} It starts a paid run.`,
|
|
73
80
|
},
|
|
74
81
|
{
|
|
75
82
|
name: "make_full_video_draft",
|
|
76
83
|
route: "POST /api/onboarding/full-video",
|
|
84
|
+
body: fullVideoInputSchema,
|
|
77
85
|
title: "Draft a full video",
|
|
78
86
|
description: formBody("the welcome's Make a full video"),
|
|
79
87
|
},
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { bakeoffStartSchema } from "../../slices/template-studio/bakeoff.js";
|
|
2
|
+
import { studioSettingsSchema } from "../../slices/template-studio/budget.js";
|
|
3
|
+
import { samplesForAllSchema } from "../../slices/template-studio/for-all.js";
|
|
4
|
+
import { markReadySchema } from "../../slices/template-studio/ready.js";
|
|
5
|
+
import { makeSampleSchema, saveStudioSchema } from "../../slices/template-studio/save.js";
|
|
6
|
+
import { sayItAsSchema } from "../../slices/template-studio/say-it-as.js";
|
|
7
|
+
import { fullScriptSchema, topicSchema } from "../../slices/template-studio/topic.js";
|
|
8
|
+
// Edit template (Templates → a template → Edit template). Not the YouTube Studio tools.
|
|
9
|
+
export const templateStudioTools = [
|
|
10
|
+
{
|
|
11
|
+
name: "get_template_studio",
|
|
12
|
+
route: "GET /api/template-studio/:id",
|
|
13
|
+
title: "Read a template in Edit template",
|
|
14
|
+
description: "The template's sections with each sample's state (current, making, waiting, needs-fix, stale, off, provided), the sample topic, and which version schedules run. Its checks are read with get_template_checks.",
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
name: "get_template_checks",
|
|
18
|
+
route: "GET /api/template-studio/:id/checks",
|
|
19
|
+
title: "Read a template's checks",
|
|
20
|
+
description: "The free checks the template's current version passes before Approve for schedules, each failing one with what is wrong and where it is fixed: keywords filled, providers set up, a voice that is one of yours (Settings → Voices), release times, a known monthly cost, someone to answer each pause.",
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
name: "mark_template_ready",
|
|
24
|
+
route: "POST /api/template-studio/:id/ready",
|
|
25
|
+
body: markReadySchema,
|
|
26
|
+
title: "Approve a template for its schedules",
|
|
27
|
+
description: "Approves the template's newest version (pass it as version) for its schedules, so they run it from their next run on: Edit template's Approve for schedules. Refused, approving nothing, while a check fails or a section's sample isn't current, with each thing to fix (problems). A version already approved is answered again. Until a template's first approval its schedules run its newest version; from then on a schedule runs only a version approved for schedules, saved before Edit template, or carried over from one by Slopify, and each version saved later waits until it is approved.",
|
|
28
|
+
confirm: "Schedules run this version from their next run, and each version saved later waits until it is approved.",
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
name: "get_prompt_anatomy",
|
|
32
|
+
route: "GET /api/template-studio/:id/anatomy",
|
|
33
|
+
title: "Read a section's prompt anatomy",
|
|
34
|
+
description: "One of the prompts a template section sends (section: subject, script, voice, pictures, thumbnail, shorts, upload, reviews; item: the prompt's key from items), cut into segments: the person's own words (yours), their keywords' values (keyword), what Slopify fills itself (slopify) and what settings add (setting). Read from the prompt the sample sent when it was made from these settings.",
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: "quote_template_save",
|
|
38
|
+
route: "POST /api/template-studio/:id/quote",
|
|
39
|
+
title: "Price a template Save's sample",
|
|
40
|
+
description: 'Prices a sample before anything is spent. Send one of: document (what a Save of this template document would make), topic (a new sample topic, "next-queued" or "fixed": every section) or fullScript (the whole script switched on or off: the script and what follows). It answers the sections it outdates, each step\'s cost, the total high estimate, how many steps have no price, and whether it fits today\'s sample budget. Changes nothing. Pass its high as acknowledgedHigh to save_template_studio.',
|
|
41
|
+
unrecorded: true,
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: "save_template_studio",
|
|
45
|
+
route: "POST /api/template-studio/:id/save",
|
|
46
|
+
body: saveStudioSchema,
|
|
47
|
+
title: "Save a template in Edit template",
|
|
48
|
+
description: 'Saves the template document as its next version. With sample "make" it also makes the paid sample of what changed, which spends money: price it first with quote_template_save and pass that quote\'s high as acknowledgedHigh (and acknowledgedUnknown: true when the quote counts steps with no price). A higher price, an unaccepted unknown one or a sample past today\'s budget is refused with the new quote and nothing is saved. With sample "skip" only the free samples are made. Send the same mutationId to retry the very same Save.',
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
name: "make_template_sample",
|
|
52
|
+
route: "POST /api/template-studio/:id/samples/make",
|
|
53
|
+
body: makeSampleSchema,
|
|
54
|
+
title: "Make a template's paid sample again",
|
|
55
|
+
description: "Queues the paid sample of the template's current version again, which spends money: after it waited (a higher price, steps with no price, today's budget) or failed. Pass the version and the price get_template_studio shows for it as acknowledgedHigh, and acknowledgedUnknown: true to accept steps with no price. A sample that would cost more still waits.",
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
name: "set_sample_topic",
|
|
59
|
+
route: "PUT /api/template-studio/:id/topic",
|
|
60
|
+
body: topicSchema,
|
|
61
|
+
title: "Change a template's sample topic",
|
|
62
|
+
description: 'Changes the topic the template\'s samples are made about and remakes every section\'s paid sample, which spends money: a typed topic, "next-queued" for the next topic one of its schedules has queued, or "fixed" for the topic every sample starts on. Pass the price as acknowledgedHigh (and acknowledgedUnknown: true to accept steps with no price); a higher price, an unaccepted unknown one or one past today\'s budget is refused with the new quote and nothing changes.',
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
name: "set_sample_full_script",
|
|
66
|
+
route: "POST /api/template-studio/:id/full-script",
|
|
67
|
+
body: fullScriptSchema,
|
|
68
|
+
title: "Write a template sample's full script",
|
|
69
|
+
description: "Switches the template's sample between the whole script (fullScript: true) and the outline and first chapter (false), and remakes the script and what is made from it, which spends money. Pass the price as acknowledgedHigh; it is refused with the new quote at a higher price, unaccepted unknown prices or past today's budget.",
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
name: "get_sample_pronunciations",
|
|
73
|
+
route: "GET /api/template-studio/:id/pronunciations",
|
|
74
|
+
title: "Read the names a template's voice may say wrong",
|
|
75
|
+
description: "The names the template's sample script says that a voice may get wrong (its Pronunciation Glossary, and words the Pronunciation list (Settings → Voices → Pronunciation) already changes), each with its IPA, the first line it is said in and the alias it has (spokenAs). aliasesOn says whether the template's voice uses the Pronunciation list.",
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
name: "quote_say_it_as",
|
|
79
|
+
route: "POST /api/template-studio/:id/say-it-as/quote",
|
|
80
|
+
title: "Price saying a word another way",
|
|
81
|
+
description: "Prices voicing again, with written said as spoken, only the template sample's lines that say it: how many lines, the high estimate, steps with no price and whether it fits today's sample budget. Changes nothing. Pass its high as acknowledgedHigh to say_it_as.",
|
|
82
|
+
unrecorded: true,
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
name: "say_it_as",
|
|
86
|
+
route: "POST /api/template-studio/:id/say-it-as",
|
|
87
|
+
body: sayItAsSchema,
|
|
88
|
+
title: "Say a word another way",
|
|
89
|
+
description: "Writes a row of the Pronunciation list (Settings → Voices → Pronunciation) (written said as spoken, whole word, any case; it replaces one for the same word) and voices again only the template sample's lines that say it, which spends money: price it first with quote_say_it_as and pass its high as acknowledgedHigh. The alias applies to every project started after it. Refused, writing nothing, at a higher price, with unaccepted unknown prices, past today's budget, or when the template's voice doesn't use aliases.",
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
name: "get_template_studio_settings",
|
|
93
|
+
route: "GET /api/template-studio/settings",
|
|
94
|
+
title: "Read the template samples' budgets",
|
|
95
|
+
description: "The most Edit template's samples may spend in one day (dailyBudget, US dollars), whether they may run steps on a CLI plan (samplesUsePlans; off by default, such a sample waits; it applies to designed pieces' samples too), the most designed pieces' template samples may spend in one day (designDailyBudget, $1 by default), and what each spent today and has left (today, designToday).",
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
name: "update_template_studio_settings",
|
|
99
|
+
route: "PUT /api/template-studio/settings",
|
|
100
|
+
body: studioSettingsSchema,
|
|
101
|
+
title: "Change the template samples' daily budgets",
|
|
102
|
+
description: "Sets any of: dailyBudget, the most Edit template's samples may spend in one day, in US dollars (0 to 1000); designDailyBudget, the same for designed pieces' template samples (0 to 1000); samplesUsePlans, whether either may run steps on a Claude Code or Codex plan, which the dollar budgets can't limit. A field left out keeps what it was. A sample that would go over its budget, or needs a plan while plans are off, waits.",
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
name: "quote_samples_for_all",
|
|
106
|
+
route: "POST /api/template-studio/samples-for-all/quote",
|
|
107
|
+
title: "Price the samples of every template",
|
|
108
|
+
description: "Prices the paid sample of every template whose newest version has none (or changed since its last one), before anything is spent: each template's high estimate, whether it fits what is left of today's sample budget (spent in name order), the total and a sentence saying how many fit. Changes nothing. Pass its total as acknowledgedTotal to make_samples_for_all.",
|
|
109
|
+
unrecorded: true,
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
name: "make_samples_for_all",
|
|
113
|
+
route: "POST /api/template-studio/samples-for-all",
|
|
114
|
+
body: samplesForAllSchema,
|
|
115
|
+
title: "Make the samples of every template",
|
|
116
|
+
description: "Makes the paid sample of every template that needs one, which spends money: price them first with quote_samples_for_all and pass its total as acknowledgedTotal (and acknowledgedUnknown: true to accept steps with no price). The ones that fit today's budget are queued; the rest wait, saying so, until tomorrow or a higher budget. A higher total is refused with the new quote and nothing is queued.",
|
|
117
|
+
confirm: "This spends money on the samples of every template that needs one.",
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
name: "make_template_free_samples",
|
|
121
|
+
route: "POST /api/template-studio/:id/free-samples",
|
|
122
|
+
title: "Make a template's free samples",
|
|
123
|
+
description: "Queues the samples made on this computer at no cost for the template's current version: the 30-second video, the loudness before and after, the PDF, and the schedules' cost a month. Read them back with get_template_studio.",
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
name: "import_template_pack",
|
|
127
|
+
route: "POST /api/template-studio/packs/import",
|
|
128
|
+
title: "Import a template file",
|
|
129
|
+
description: "Makes a new template from a template file (the .zip Edit template's Export as a file (.zip) made, at most 30 MB): its prompts and intros join Prompts (a name taken by other text comes in as \"<name> (2)\" and the template names that one), its voice is used as it is, and it is not checked in Edit template yet: look its samples over and approve it for schedules (mark_template_ready). A file holding anything that looks like a key, a file a template file never has or a newer format is refused, writing nothing. Answers templateId, the name it got, how many prompts and intros it added and which were renamed, whether Settings → Voices has its voice (voiceKnown; when false, get_template_checks' voice check says what to do) and how many samples it brought.",
|
|
130
|
+
upload: "multipart",
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
name: "get_template_pack_samples",
|
|
134
|
+
route: "GET /api/template-studio/:id/pack-samples",
|
|
135
|
+
title: "List the samples a template's file brought",
|
|
136
|
+
description: "The samples an imported template file came with (role: thumbnail, picture or narration; name; url), shown in Edit template until the template makes its own. Empty for a template that didn't come from a file.",
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
name: "quote_bakeoff",
|
|
140
|
+
route: "POST /api/template-studio/:id/bakeoff/quote",
|
|
141
|
+
title: "Price comparing models on a template's sample",
|
|
142
|
+
description: "Prices making one section's sample again on one or two other models (section: script, voice or pictures; models: [{provider, model}], not the model the section uses now, which is compared from the current sample; voice models only of the template's voice provider). Needs a current sample of the newest version. Answers each model's high estimate, steps with no price, the total, today's sample budget and whether it fits. Changes nothing. Pass its high as acknowledgedHigh to start_bakeoff.",
|
|
143
|
+
unrecorded: true,
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
name: "start_bakeoff",
|
|
147
|
+
route: "POST /api/template-studio/:id/bakeoff",
|
|
148
|
+
body: bakeoffStartSchema,
|
|
149
|
+
title: "Compare models on a template's sample",
|
|
150
|
+
description: "Makes the section's sample again on each model, each on a hidden copy of the template's sample with only that section's work started, which spends money: price it first with quote_bakeoff and pass its high as acknowledgedHigh (and acknowledgedUnknown: true to accept steps with no price). A higher total, an unaccepted unknown price or a total past today's budget is refused with the new quote, starting nothing. The template doesn't change: read the results with get_bakeoff, then switch the model with save_template_studio and discard the copies with discard_bakeoff.",
|
|
151
|
+
confirm: "This spends money making the section's sample again on each model.",
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
name: "get_bakeoff",
|
|
155
|
+
route: "GET /api/template-studio/:id/bakeoff",
|
|
156
|
+
title: "Read a template's model bake-off",
|
|
157
|
+
description: "The template's bake-off, or null: its section, the version it was made for (stale when the template was saved since), its state (queued, making, done, held with why, failed with why) and one entry per model, the one in use first (state current), each with what it was charged (cost, US dollars), how long its section took (seconds), its failure, and what it made (outputs; article: the script's opening).",
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
name: "discard_bakeoff",
|
|
161
|
+
route: "DELETE /api/template-studio/:id/bakeoff",
|
|
162
|
+
title: "Discard a template's model bake-off",
|
|
163
|
+
description: "Removes the bake-off's copies and what they made. What they were charged today still counts against the sample budget. Refused while a copy still has work going.",
|
|
164
|
+
confirm: "The bake-off's copies and what they made are removed.",
|
|
165
|
+
},
|
|
166
|
+
];
|
package/dist/edge/mcp/tools.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { channelTools } from "./tools-channels.js";
|
|
2
|
+
import { designTools } from "./tools-designs.js";
|
|
2
3
|
import { libraryTools } from "./tools-library.js";
|
|
3
4
|
import { planningTools } from "./tools-planning.js";
|
|
4
5
|
import { projectTools } from "./tools-projects.js";
|
|
@@ -6,16 +7,21 @@ import { publishingTools } from "./tools-publishing.js";
|
|
|
6
7
|
import { runTools } from "./tools-runs.js";
|
|
7
8
|
import { scheduleTools } from "./tools-schedules.js";
|
|
8
9
|
import { setupTools } from "./tools-setup.js";
|
|
10
|
+
import { socialTools } from "./tools-social.js";
|
|
9
11
|
import { storageTools } from "./tools-storage.js";
|
|
12
|
+
import { templateStudioTools } from "./tools-template-studio.js";
|
|
10
13
|
// Every API route an agent may call, as a tool; `excluded-routes.ts` names the rest and why.
|
|
11
14
|
export const routeTools = [
|
|
12
15
|
...projectTools,
|
|
13
16
|
...publishingTools,
|
|
17
|
+
...socialTools,
|
|
14
18
|
...runTools,
|
|
15
19
|
...planningTools,
|
|
16
20
|
...scheduleTools,
|
|
17
21
|
...channelTools,
|
|
22
|
+
...designTools,
|
|
18
23
|
...libraryTools,
|
|
19
24
|
...setupTools,
|
|
20
25
|
...storageTools,
|
|
26
|
+
...templateStudioTools,
|
|
21
27
|
];
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
// Every command Slopify sends. Serve only: Funnel puts an address on the public internet, and
|
|
3
|
+
// Slopify has no login and holds API keys, so no path through Slopify may ever reach it.
|
|
4
|
+
export const tailscaleCommands = {
|
|
5
|
+
status: () => ["status", "--json"],
|
|
6
|
+
serveStatus: () => ["serve", "status", "--json"],
|
|
7
|
+
serveOn: (httpsPort, target) => [
|
|
8
|
+
"serve",
|
|
9
|
+
"--bg",
|
|
10
|
+
"--yes",
|
|
11
|
+
`--https=${httpsPort}`,
|
|
12
|
+
target,
|
|
13
|
+
],
|
|
14
|
+
serveOff: (httpsPort) => ["serve", "--yes", `--https=${httpsPort}`, "off"],
|
|
15
|
+
};
|
|
16
|
+
const allowed = new Set(["status", "serve"]);
|
|
17
|
+
// The last line of defence: a command that names Funnel, or isn't one of the above, never runs.
|
|
18
|
+
export function assertServeOnly(args) {
|
|
19
|
+
const [command] = args;
|
|
20
|
+
if (command === undefined || !allowed.has(command))
|
|
21
|
+
throw new Error(`Slopify only runs tailscale status and tailscale serve, not "${command}".`);
|
|
22
|
+
if (args.some((arg) => /funnel/iu.test(arg)))
|
|
23
|
+
throw new Error("Slopify never turns on Tailscale Funnel.");
|
|
24
|
+
}
|
|
25
|
+
export function guarded(run) {
|
|
26
|
+
return async (args) => {
|
|
27
|
+
assertServeOnly(args);
|
|
28
|
+
return run(args);
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
// Where the command is when it isn't on PATH: the macOS app bundle and the Windows installer.
|
|
32
|
+
export function tailscaleCandidates(platform) {
|
|
33
|
+
if (platform === "darwin")
|
|
34
|
+
return ["tailscale", "/Applications/Tailscale.app/Contents/MacOS/Tailscale"];
|
|
35
|
+
if (platform === "win32")
|
|
36
|
+
return ["tailscale", "C:\\Program Files\\Tailscale\\tailscale.exe"];
|
|
37
|
+
return ["tailscale"];
|
|
38
|
+
}
|
|
39
|
+
function execOnce(file, args, timeoutMs) {
|
|
40
|
+
return new Promise((resolve) => {
|
|
41
|
+
execFile(file, [...args], { windowsHide: true, timeout: timeoutMs, encoding: "utf8", maxBuffer: 4 * 1024 * 1024 }, (error, stdout, stderr) => {
|
|
42
|
+
if (error === null) {
|
|
43
|
+
resolve({ code: 0, stdout, stderr, missing: false, timedOut: false });
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const missing = error.code === "ENOENT";
|
|
47
|
+
const timedOut = error.killed === true && error.signal !== null;
|
|
48
|
+
resolve({
|
|
49
|
+
code: typeof error.code === "number" ? error.code : 1,
|
|
50
|
+
stdout,
|
|
51
|
+
stderr: stderr || error.message,
|
|
52
|
+
missing,
|
|
53
|
+
timedOut,
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
// ceiling: a status or serve call answers within a second on a healthy machine; a hung
|
|
59
|
+
// daemon must not hold a request, so each call is cut off.
|
|
60
|
+
export function nodeTailscaleRun(platform, timeoutMs = 10_000) {
|
|
61
|
+
const candidates = tailscaleCandidates(platform);
|
|
62
|
+
return guarded(async (args) => {
|
|
63
|
+
let last;
|
|
64
|
+
for (const file of candidates) {
|
|
65
|
+
last = await execOnce(file, args, timeoutMs);
|
|
66
|
+
if (!last.missing)
|
|
67
|
+
return last;
|
|
68
|
+
}
|
|
69
|
+
return last ?? { code: 127, stdout: "", stderr: "", missing: true, timedOut: false };
|
|
70
|
+
});
|
|
71
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// What Settings → Remote access shows. The web client imports this file, so it stays
|
|
2
|
+
// free of Node imports.
|
|
3
|
+
export const remoteAccessStates = [
|
|
4
|
+
// The switch is off: Slopify answers only on this computer.
|
|
5
|
+
"off",
|
|
6
|
+
// Tailscale serves Slopify's address on the tailnet.
|
|
7
|
+
"on",
|
|
8
|
+
// Slopify runs in Docker; the switch needs Slopify started on the computer itself.
|
|
9
|
+
"docker",
|
|
10
|
+
"not-installed",
|
|
11
|
+
"not-running",
|
|
12
|
+
"signed-out",
|
|
13
|
+
// The tailnet has no HTTPS certificates (MagicDNS and HTTPS in the admin console).
|
|
14
|
+
"https-off",
|
|
15
|
+
// Tailscale refused this user (Linux: not the operator).
|
|
16
|
+
"denied",
|
|
17
|
+
// Another serve setting already uses the HTTPS port.
|
|
18
|
+
"port-taken",
|
|
19
|
+
// Tailscale Funnel was found on Slopify's address; Slopify removed its own setting.
|
|
20
|
+
"funnel",
|
|
21
|
+
// The switch is on, but Slopify's address isn't in Tailscale right now.
|
|
22
|
+
"not-applied",
|
|
23
|
+
"failed",
|
|
24
|
+
];
|
|
25
|
+
export const defaultHttpsPort = 443;
|
|
26
|
+
// The ports Slopify offers when one is taken, in order. Any port works for Serve; these are the
|
|
27
|
+
// ones Tailscale's own documentation uses.
|
|
28
|
+
export const httpsPortChoices = [443, 8443, 10000];
|
|
29
|
+
// Settings rows: the switch as the person set it, and the exact serve handler Slopify added
|
|
30
|
+
// (removed again only when it is still exactly that).
|
|
31
|
+
export const remoteAccessKey = "remote-access";
|
|
32
|
+
export const remoteAccessAppliedKey = "remote-access.applied";
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { httpsPortChoices } from "./model.js";
|
|
3
|
+
export const installLink = "https://tailscale.com/download";
|
|
4
|
+
export const dnsAdminLink = "https://login.tailscale.com/admin/dns";
|
|
5
|
+
const statusShape = z
|
|
6
|
+
.object({
|
|
7
|
+
BackendState: z.string(),
|
|
8
|
+
Self: z
|
|
9
|
+
.object({ DNSName: z.string().optional(), UserID: z.number().optional() })
|
|
10
|
+
.loose()
|
|
11
|
+
.optional(),
|
|
12
|
+
User: z
|
|
13
|
+
.record(z.string(), z.object({ LoginName: z.string().optional() }).loose())
|
|
14
|
+
.nullable()
|
|
15
|
+
.optional(),
|
|
16
|
+
CertDomains: z.array(z.string()).nullable().optional(),
|
|
17
|
+
})
|
|
18
|
+
.loose();
|
|
19
|
+
const handlerShape = z.object({ Proxy: z.string().optional() }).loose();
|
|
20
|
+
const webShape = z.object({ Handlers: z.record(z.string(), handlerShape).optional() }).loose();
|
|
21
|
+
const tcpShape = z.object({ HTTPS: z.boolean().optional(), HTTP: z.boolean().optional() }).loose();
|
|
22
|
+
const configShape = z
|
|
23
|
+
.object({
|
|
24
|
+
TCP: z.record(z.string(), tcpShape).nullable().optional(),
|
|
25
|
+
Web: z.record(z.string(), webShape).nullable().optional(),
|
|
26
|
+
AllowFunnel: z.record(z.string(), z.boolean()).nullable().optional(),
|
|
27
|
+
})
|
|
28
|
+
.loose();
|
|
29
|
+
const serveShape = configShape
|
|
30
|
+
.extend({ Foreground: z.record(z.string(), configShape).nullable().optional() })
|
|
31
|
+
.loose();
|
|
32
|
+
const deniedPattern = /access denied|permission denied|operator|must be root|not permitted/iu;
|
|
33
|
+
const notRunningPattern = /failed to connect|doesn't appear to be running|is tailscaled running|connection refused|no such file or directory|cannot connect/iu;
|
|
34
|
+
// A failed command's own reason, in the person's words.
|
|
35
|
+
export function problemOf(result, platform) {
|
|
36
|
+
if (result.missing)
|
|
37
|
+
return {
|
|
38
|
+
state: "not-installed",
|
|
39
|
+
summary: "Tailscale isn't installed on this computer, so Slopify can't open it on your other devices.",
|
|
40
|
+
fix: "Install Tailscale from tailscale.com/download, sign in, then press Check again.",
|
|
41
|
+
link: installLink,
|
|
42
|
+
};
|
|
43
|
+
if (result.timedOut)
|
|
44
|
+
return {
|
|
45
|
+
state: "failed",
|
|
46
|
+
summary: "Tailscale didn't answer within 10 seconds.",
|
|
47
|
+
fix: "Make sure the Tailscale app or service is running (open the Tailscale app, or run tailscale status in a terminal), then press Check again.",
|
|
48
|
+
link: null,
|
|
49
|
+
};
|
|
50
|
+
const text = `${result.stderr}\n${result.stdout}`.trim();
|
|
51
|
+
if (deniedPattern.test(text))
|
|
52
|
+
return deniedProblem(platform);
|
|
53
|
+
if (notRunningPattern.test(text))
|
|
54
|
+
return notRunningProblem();
|
|
55
|
+
return {
|
|
56
|
+
state: "failed",
|
|
57
|
+
summary: `Tailscale refused: ${firstLine(text) || `it stopped with code ${result.code}`}.`,
|
|
58
|
+
fix: "Run tailscale status in a terminal to see what Tailscale reports, fix that, then press Check again.",
|
|
59
|
+
link: null,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
export function deniedProblem(platform) {
|
|
63
|
+
return {
|
|
64
|
+
state: "denied",
|
|
65
|
+
summary: "Tailscale won't let your user change its serve settings.",
|
|
66
|
+
fix: platform === "linux"
|
|
67
|
+
? "On Linux, allow your user once: run sudo tailscale set --operator=$USER in a terminal, then press Check again."
|
|
68
|
+
: "Open the Tailscale app as the user who signed in to it, then press Check again.",
|
|
69
|
+
link: null,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function notRunningProblem() {
|
|
73
|
+
return {
|
|
74
|
+
state: "not-running",
|
|
75
|
+
summary: "Tailscale is installed but not running.",
|
|
76
|
+
fix: "Open the Tailscale app and connect, or run tailscale up in a terminal, then press Check again.",
|
|
77
|
+
link: null,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function firstLine(text) {
|
|
81
|
+
return (text.split("\n").find((line) => line.trim() !== "") ?? "").trim().replace(/\.$/u, "");
|
|
82
|
+
}
|
|
83
|
+
// Which machine this is, or why Tailscale can't serve it yet.
|
|
84
|
+
export function machineOf(stdout) {
|
|
85
|
+
let parsed;
|
|
86
|
+
try {
|
|
87
|
+
parsed = statusShape.parse(JSON.parse(stdout));
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return {
|
|
91
|
+
state: "failed",
|
|
92
|
+
summary: "Slopify couldn't read tailscale status --json.",
|
|
93
|
+
fix: "Update Tailscale to a current version (tailscale.com/download), then press Check again.",
|
|
94
|
+
link: installLink,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
if (parsed.BackendState === "NeedsLogin" || parsed.BackendState === "NeedsMachineAuth")
|
|
98
|
+
return {
|
|
99
|
+
state: "signed-out",
|
|
100
|
+
summary: parsed.BackendState === "NeedsMachineAuth"
|
|
101
|
+
? "This computer is waiting for approval in your tailnet."
|
|
102
|
+
: "Tailscale is signed out on this computer.",
|
|
103
|
+
fix: parsed.BackendState === "NeedsMachineAuth"
|
|
104
|
+
? "Approve this computer in the Tailscale admin console (login.tailscale.com/admin/machines), then press Check again."
|
|
105
|
+
: "Open the Tailscale app and sign in, or run tailscale up in a terminal, then press Check again.",
|
|
106
|
+
link: null,
|
|
107
|
+
};
|
|
108
|
+
if (parsed.BackendState !== "Running")
|
|
109
|
+
return notRunningProblem();
|
|
110
|
+
const dnsName = (parsed.Self?.DNSName ?? "").replace(/\.$/u, "");
|
|
111
|
+
const certs = parsed.CertDomains ?? [];
|
|
112
|
+
if (dnsName === "" || !certs.includes(dnsName))
|
|
113
|
+
return {
|
|
114
|
+
state: "https-off",
|
|
115
|
+
summary: "Your tailnet has no HTTPS certificates, so Tailscale can't give Slopify an https address.",
|
|
116
|
+
fix: "In the Tailscale admin console open DNS (login.tailscale.com/admin/dns), turn on MagicDNS if it is off, then under HTTPS Certificates press Enable HTTPS. Then press Check again.",
|
|
117
|
+
link: dnsAdminLink,
|
|
118
|
+
};
|
|
119
|
+
const userId = parsed.Self?.UserID;
|
|
120
|
+
const owner = userId === undefined ? undefined : parsed.User?.[String(userId)]?.LoginName;
|
|
121
|
+
return owner === undefined || owner === "" ? { dnsName } : { dnsName, owner };
|
|
122
|
+
}
|
|
123
|
+
export function isProblem(value) {
|
|
124
|
+
return "state" in value;
|
|
125
|
+
}
|
|
126
|
+
export function parseServeStatus(stdout) {
|
|
127
|
+
const text = stdout.trim();
|
|
128
|
+
if (text === "")
|
|
129
|
+
return {};
|
|
130
|
+
try {
|
|
131
|
+
return serveShape.parse(JSON.parse(text));
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
return undefined;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
export const hostPort = (dnsName, httpsPort) => `${dnsName}:${httpsPort}`;
|
|
138
|
+
// The address a browser opens; 443 is https's own port, so it isn't written.
|
|
139
|
+
export function addressOf(dnsName, httpsPort) {
|
|
140
|
+
return httpsPort === 443 ? `https://${dnsName}` : `https://${dnsName}:${httpsPort}`;
|
|
141
|
+
}
|
|
142
|
+
const normal = (url) => url.replace(/\/+$/u, "");
|
|
143
|
+
function configsOf(status) {
|
|
144
|
+
return [status, ...Object.values(status.Foreground ?? {})];
|
|
145
|
+
}
|
|
146
|
+
// What uses an HTTPS port on this machine now, in the background config or a foreground
|
|
147
|
+
// `tailscale serve` still running in someone's terminal.
|
|
148
|
+
export function portUse(status, dnsName, httpsPort) {
|
|
149
|
+
const key = hostPort(dnsName, httpsPort);
|
|
150
|
+
const used = configsOf(status).filter((config) => config.TCP?.[String(httpsPort)] !== undefined || config.Web?.[key] !== undefined);
|
|
151
|
+
const [only] = used;
|
|
152
|
+
if (only === undefined)
|
|
153
|
+
return { kind: "free" };
|
|
154
|
+
const handlers = Object.entries(only.Web?.[key]?.Handlers ?? {});
|
|
155
|
+
const [first] = handlers;
|
|
156
|
+
if (used.length === 1 &&
|
|
157
|
+
only.TCP?.[String(httpsPort)]?.HTTPS === true &&
|
|
158
|
+
handlers.length === 1 &&
|
|
159
|
+
first !== undefined &&
|
|
160
|
+
first[0] === "/" &&
|
|
161
|
+
first[1].Proxy !== undefined)
|
|
162
|
+
return {
|
|
163
|
+
kind: "proxy",
|
|
164
|
+
target: normal(first[1].Proxy),
|
|
165
|
+
funnel: configsOf(status).some((config) => config.AllowFunnel?.[key] === true),
|
|
166
|
+
};
|
|
167
|
+
return {
|
|
168
|
+
kind: "other",
|
|
169
|
+
what: handlers.length === 0
|
|
170
|
+
? "a TCP forwarder"
|
|
171
|
+
: handlers
|
|
172
|
+
.map(([path, handler]) => `${path} → ${handler.Proxy ?? "a file or text"}`)
|
|
173
|
+
.join(", "),
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
export function sameTarget(a, b) {
|
|
177
|
+
return normal(a) === normal(b);
|
|
178
|
+
}
|
|
179
|
+
export function freePort(status, dnsName, except) {
|
|
180
|
+
return (httpsPortChoices.find((port) => port !== except && portUse(status, dnsName, port).kind === "free") ?? null);
|
|
181
|
+
}
|
|
182
|
+
export function portTakenProblem(httpsPort, use, target, suggestedPort) {
|
|
183
|
+
const instead = suggestedPort === null
|
|
184
|
+
? "Choose another HTTPS port below"
|
|
185
|
+
: `Press Use port ${suggestedPort} to give Slopify its own address`;
|
|
186
|
+
const what = use.kind === "proxy" ? `a proxy to ${use.target}` : use.what;
|
|
187
|
+
const yours = use.kind === "proxy" && sameTarget(use.target, target)
|
|
188
|
+
? " It already points at this Slopify, but you set it up outside Slopify, so Slopify leaves it alone."
|
|
189
|
+
: "";
|
|
190
|
+
return {
|
|
191
|
+
state: "port-taken",
|
|
192
|
+
summary: `HTTPS port ${httpsPort} on your tailnet address is already used by another Tailscale serve setting (${what}).${yours}`,
|
|
193
|
+
fix: `${instead}, or remove the other setting with tailscale serve --https=${httpsPort} off and press Check again.`,
|
|
194
|
+
link: null,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
export function serveRefusedProblem(result, platform) {
|
|
198
|
+
const text = `${result.stderr}\n${result.stdout}`;
|
|
199
|
+
if (!result.missing && !result.timedOut && /https|cert/iu.test(text) && !deniedPattern.test(text))
|
|
200
|
+
return {
|
|
201
|
+
state: "https-off",
|
|
202
|
+
summary: `Tailscale couldn't give Slopify an https address: ${firstLine(text)}.`,
|
|
203
|
+
fix: "In the Tailscale admin console open DNS (login.tailscale.com/admin/dns), turn on MagicDNS if it is off, then under HTTPS Certificates press Enable HTTPS. Then press Check again.",
|
|
204
|
+
link: dnsAdminLink,
|
|
205
|
+
};
|
|
206
|
+
return problemOf(result, platform);
|
|
207
|
+
}
|