@gentbajko/slopify 4.0.0 → 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 +1 -1
- package/dist/adapters/alignment/audio.js +1 -1
- package/dist/adapters/alignment/cache.js +1 -1
- package/dist/adapters/alignment/multilingual.js +2 -1
- package/dist/adapters/alignment/runner.js +1 -1
- package/dist/adapters/alignment/worker.js +1 -1
- package/dist/adapters/explain.js +10 -9
- package/dist/adapters/host-cli/index.js +2 -1
- package/dist/adapters/host-cli/transport.js +2 -1
- package/dist/adapters/image/bytes.js +2 -1
- package/dist/adapters/image/codex.js +6 -5
- package/dist/adapters/image/fal.js +4 -3
- package/dist/adapters/image/google.js +3 -2
- package/dist/adapters/image/models.js +2 -2
- package/dist/adapters/image/openai.js +2 -1
- package/dist/adapters/image/replicate.js +3 -2
- package/dist/adapters/image/video.js +2 -1
- package/dist/adapters/key-probes.js +1 -1
- package/dist/adapters/llm/antigravity-models.js +1 -1
- package/dist/adapters/llm/antigravity.js +7 -6
- package/dist/adapters/llm/assistant-cli.js +1 -1
- package/dist/adapters/llm/claude-code-models.js +1 -1
- package/dist/adapters/llm/claude-code.js +3 -2
- package/dist/adapters/llm/codex-models.js +1 -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 +2 -1
- package/dist/adapters/llm/run-cli.js +3 -2
- package/dist/adapters/tts/gemini.js +2 -1
- package/dist/adapters/tts/inworld-async.js +2 -1
- package/dist/adapters/tts/inworld.js +3 -2
- package/dist/adapters/tts/system.js +2 -1
- package/dist/catalog/registry.js +20 -13
- package/dist/catalog/schema.js +2 -1
- package/dist/catalog/validate.js +5 -2
- package/dist/edge/http/actions.js +7 -7
- package/dist/edge/http/app.js +3 -3
- package/dist/edge/http/assistant.js +3 -1
- package/dist/edge/http/backups.js +1 -1
- package/dist/edge/http/channel-memory.js +2 -2
- package/dist/edge/http/channels.js +1 -1
- package/dist/edge/http/checkpoints.js +7 -5
- package/dist/edge/http/design-templates.js +3 -3
- package/dist/edge/http/designs.js +1 -1
- package/dist/edge/http/document-themes.js +3 -3
- package/dist/edge/http/draft-problem.js +1 -1
- package/dist/edge/http/extension-auth.js +1 -1
- package/dist/edge/http/home.js +9 -1
- package/dist/edge/http/model-checks.js +4 -4
- package/dist/edge/http/onboarding.js +29 -12
- package/dist/edge/http/outputs.js +3 -2
- package/dist/edge/http/patch-notes.js +2 -2
- package/dist/edge/http/planning.js +1 -1
- package/dist/edge/http/project-create.js +1 -1
- package/dist/edge/http/project-templates.js +2 -2
- package/dist/edge/http/projects.js +22 -4
- package/dist/edge/http/prompts.js +2 -2
- package/dist/edge/http/providers.js +9 -10
- package/dist/edge/http/refusal.js +1 -1
- package/dist/edge/http/remote-access.js +4 -4
- package/dist/edge/http/remote-guard.js +2 -2
- package/dist/edge/http/reviews.js +1 -1
- package/dist/edge/http/revision-files.js +1 -1
- package/dist/edge/http/revisions.js +4 -4
- package/dist/edge/http/schedules.js +13 -11
- package/dist/edge/http/settings.js +6 -2
- package/dist/edge/http/social.js +5 -4
- package/dist/edge/http/staging.js +1 -1
- package/dist/edge/http/storage.js +12 -4
- package/dist/edge/http/studio.js +71 -19
- package/dist/edge/http/style-preview.js +2 -2
- package/dist/edge/http/template-studio.js +12 -9
- package/dist/edge/http/trash.js +1 -1
- package/dist/edge/http/youtube-edits.js +1 -1
- package/dist/edge/mcp/excluded-routes.js +4 -3
- package/dist/edge/mcp/instructions.js +3 -3
- package/dist/edge/mcp/library-tools.js +8 -5
- package/dist/edge/mcp/remake-tools.js +7 -4
- package/dist/edge/mcp/server.js +1 -1
- package/dist/edge/mcp/tools-channels.js +9 -9
- package/dist/edge/mcp/tools-designs.js +9 -9
- package/dist/edge/mcp/tools-library.js +7 -7
- package/dist/edge/mcp/tools-planning.js +18 -18
- package/dist/edge/mcp/tools-projects.js +10 -10
- package/dist/edge/mcp/tools-publishing.js +9 -9
- package/dist/edge/mcp/tools-runs.js +9 -9
- package/dist/edge/mcp/tools-schedules.js +6 -6
- package/dist/edge/mcp/tools-setup.js +20 -14
- package/dist/edge/mcp/tools-social.js +5 -4
- package/dist/edge/mcp/tools-storage.js +3 -3
- package/dist/edge/mcp/tools-template-studio.js +18 -18
- package/dist/edge/remote-access/model.js +1 -1
- package/dist/extension/slopify-studio-chrome.zip +0 -0
- package/dist/extension/slopify-studio-firefox.zip +0 -0
- package/dist/kernel/db/migrations/0078-uploaded-from-links.sql +7 -0
- package/dist/kernel/pipeline.js +12 -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 +11 -3
- package/dist/kernel/runner/providers.js +3 -2
- package/dist/kernel/runner/standalone.js +2 -2
- package/dist/main.js +5 -3
- package/dist/model-catalog.js +20 -0
- package/dist/patch-notes/4.0.0.md +13 -13
- package/dist/patch-notes/4.1.0.md +42 -0
- package/dist/patch-notes/index.json +6 -0
- package/dist/slices/admission/listing-facts.js +95 -0
- package/dist/slices/admission/repo.js +9 -6
- package/dist/slices/admission/rules.js +7 -7
- package/dist/slices/admission/state-words.js +34 -5
- package/dist/slices/assistant/cost.js +1 -1
- package/dist/slices/assistant/model.js +10 -3
- package/dist/slices/assistant/turn.js +5 -3
- package/dist/slices/autopilot/warnings.js +1 -1
- package/dist/slices/backups/service.js +5 -5
- package/dist/slices/channels/cast-images.js +1 -1
- package/dist/slices/channels/schema.js +1 -1
- package/dist/slices/channels/videos.js +1 -1
- package/dist/slices/control/providers.js +2 -2
- package/dist/slices/designs/budget.js +1 -1
- package/dist/slices/designs/calls.js +2 -2
- package/dist/slices/designs/check-context.js +4 -4
- package/dist/slices/designs/fields.js +4 -4
- package/dist/slices/designs/gate.js +7 -5
- package/dist/slices/designs/render-input.js +1 -1
- package/dist/slices/designs/requests.js +1 -1
- package/dist/slices/designs/runner.js +1 -1
- package/dist/slices/designs/sample.js +2 -1
- package/dist/slices/designs/service.js +1 -1
- package/dist/slices/designs/template-checks.js +2 -2
- package/dist/slices/designs/template-make.js +3 -3
- package/dist/slices/designs/templates.js +3 -3
- package/dist/slices/document/fonts.js +1 -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 +2 -2
- package/dist/slices/estimate/index.js +28 -22
- package/dist/slices/estimate/requests.js +4 -4
- package/dist/slices/fixes/rules.js +3 -1
- package/dist/slices/fonts/catalog.js +2 -1
- package/dist/slices/fonts/coverage.js +2 -1
- package/dist/slices/images/appearance.js +2 -1
- package/dist/slices/images/scenes.js +2 -1
- package/dist/slices/keywords/digest.js +2 -1
- package/dist/slices/keywords/rules.js +2 -2
- package/dist/slices/keywords/specs.js +5 -5
- package/dist/slices/keywords/values.js +1 -1
- package/dist/slices/library/transfer.js +3 -3
- package/dist/slices/loudness/loudnorm.js +2 -1
- package/dist/slices/loudness/model.js +3 -2
- package/dist/slices/loudness/sentence-level.js +2 -1
- package/dist/slices/model-checks/rules.js +13 -0
- package/dist/slices/model-upkeep/model.js +1 -1
- package/dist/slices/model-upkeep/switch.js +3 -3
- package/dist/slices/model-upkeep/usage.js +13 -2
- package/dist/slices/narration/breaths.js +2 -1
- package/dist/slices/narration/clean-pieces.js +2 -1
- package/dist/slices/narration/pauses-model.js +3 -2
- package/dist/slices/narration/pronunciation.js +3 -2
- package/dist/slices/notifications/subject.js +2 -2
- package/dist/slices/onboarding/copy.js +19 -2
- package/dist/slices/onboarding/first-run.js +13 -38
- package/dist/slices/onboarding/install.js +2 -1
- package/dist/slices/onboarding/model.js +26 -21
- package/dist/slices/onboarding/preferred-model.js +14 -0
- package/dist/slices/onboarding/quick-short.js +103 -64
- package/dist/slices/onboarding/sample.js +4 -1
- package/dist/slices/onboarding/state.js +7 -0
- package/dist/slices/onboarding/template.js +6 -5
- package/dist/slices/outputs/add.js +3 -2
- package/dist/slices/outputs/service.js +2 -2
- package/dist/slices/patch-notes/library.js +1 -1
- package/dist/slices/play-drafts/readiness.js +3 -3
- package/dist/slices/play-drafts/review-inputs.js +1 -1
- package/dist/slices/play-drafts/service.js +17 -7
- 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/setup-sections.js +26 -0
- package/dist/slices/project-templates/setup.js +6 -1
- package/dist/slices/rebuild/preview-details.js +5 -5
- package/dist/slices/rebuild/recipe-preparation.js +1 -1
- package/dist/slices/rebuild/recipe-save.js +2 -2
- package/dist/slices/rebuild/recipe-validation.js +5 -4
- package/dist/slices/rebuild/recipe-voices.js +3 -2
- package/dist/slices/rebuild/recipe-work.js +4 -4
- package/dist/slices/rebuild/recovery.js +6 -6
- package/dist/slices/rebuild/remake-outdated.js +5 -5
- package/dist/slices/rebuild/review-redo.js +1 -1
- package/dist/slices/rebuild/runtime-animate.js +2 -2
- package/dist/slices/rebuild/runtime-article.js +4 -3
- package/dist/slices/rebuild/runtime-document.js +5 -4
- package/dist/slices/rebuild/runtime-export-bed.js +2 -1
- package/dist/slices/rebuild/runtime-export-edit.js +2 -1
- package/dist/slices/rebuild/runtime-export-inputs.js +5 -4
- package/dist/slices/rebuild/runtime-export-short.js +1 -1
- package/dist/slices/rebuild/runtime-export.js +4 -3
- package/dist/slices/rebuild/runtime-image.js +4 -3
- package/dist/slices/rebuild/runtime-local.js +3 -2
- package/dist/slices/rebuild/runtime-narration-text.js +3 -2
- package/dist/slices/rebuild/runtime-provider.js +7 -6
- package/dist/slices/rebuild/runtime-review.js +6 -5
- package/dist/slices/rebuild/runtime-shorts.js +6 -5
- package/dist/slices/rebuild/runtime-store.js +17 -2
- package/dist/slices/rebuild/runtime-subtitles.js +13 -12
- package/dist/slices/rebuild/runtime-voices.js +2 -1
- package/dist/slices/rebuild/runtime-youtube.js +3 -2
- package/dist/slices/rebuild/service-readiness.js +11 -3
- package/dist/slices/research/synthesis.js +3 -2
- package/dist/slices/reviews/external-model.js +1 -1
- package/dist/slices/reviews/holds.js +5 -4
- package/dist/slices/reviews/model.js +8 -5
- package/dist/slices/reviews/rules.js +3 -3
- package/dist/slices/reviews/verdict.js +2 -1
- package/dist/slices/revisions/image-plan.js +1 -1
- package/dist/slices/revisions/mutation-assets.js +2 -1
- package/dist/slices/revisions/mutations.js +3 -2
- package/dist/slices/schedules/agenda.js +7 -5
- package/dist/slices/schedules/design-check.js +4 -4
- package/dist/slices/schedules/design-run.js +3 -3
- package/dist/slices/schedules/repo.js +6 -5
- package/dist/slices/schedules/schema.js +3 -0
- package/dist/slices/schedules/topics.js +5 -5
- package/dist/slices/settings/first-run.js +6 -32
- package/dist/slices/settings/health.js +30 -15
- package/dist/slices/settings/key-test.js +1 -1
- package/dist/slices/settings/model.js +4 -2
- package/dist/slices/settings/playback.js +2 -2
- package/dist/slices/shorts/keep.js +2 -1
- package/dist/slices/shorts/pick.js +4 -3
- package/dist/slices/shorts/prompts.js +2 -1
- package/dist/slices/shorts/render.js +3 -2
- package/dist/slices/social/media.js +5 -4
- package/dist/slices/social/pack.js +1 -1
- package/dist/slices/social/post-prompt.js +2 -1
- package/dist/slices/social/reshape.js +2 -2
- package/dist/slices/social/serve.js +1 -1
- package/dist/slices/social/service.js +3 -2
- package/dist/slices/social/state.js +1 -1
- package/dist/slices/storage/backup-import.js +2 -2
- package/dist/slices/storage/portable.js +1 -1
- package/dist/slices/storage/trim.js +23 -13
- package/dist/slices/studio/calendar.js +3 -1
- 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/plan.js +1 -1
- package/dist/slices/studio/settings.js +6 -6
- package/dist/slices/studio/videos.js +23 -4
- package/dist/slices/style-preview/render.js +3 -3
- package/dist/slices/style-preview/schema.js +1 -1
- package/dist/slices/subtitles/captions.js +1 -1
- package/dist/slices/template-studio/anatomy-view.js +46 -3
- package/dist/slices/template-studio/bakeoff.js +3 -3
- package/dist/slices/template-studio/budget.js +6 -3
- package/dist/slices/template-studio/cards.js +78 -0
- package/dist/slices/template-studio/checks.js +99 -50
- package/dist/slices/template-studio/for-all.js +5 -5
- package/dist/slices/template-studio/free-video.js +1 -1
- package/dist/slices/template-studio/free.js +5 -5
- package/dist/slices/template-studio/model.js +19 -15
- package/dist/slices/template-studio/pack-import.js +14 -14
- package/dist/slices/template-studio/pack.js +9 -7
- package/dist/slices/template-studio/paid.js +12 -5
- package/dist/slices/template-studio/quote.js +18 -11
- package/dist/slices/template-studio/ready.js +7 -7
- package/dist/slices/template-studio/runner.js +1 -1
- package/dist/slices/template-studio/save.js +12 -12
- package/dist/slices/template-studio/say-it-as.js +3 -3
- package/dist/slices/template-studio/schedule-gate.js +1 -1
- package/dist/slices/template-studio/schedule-price.js +3 -1
- package/dist/slices/template-studio/schedule-sample.js +5 -1
- package/dist/slices/template-studio/schema.js +25 -0
- package/dist/slices/template-studio/service.js +3 -1
- package/dist/slices/template-studio/status.js +26 -9
- package/dist/slices/template-studio/topic.js +3 -3
- package/dist/slices/thumbnail/by-llm.js +1 -1
- package/dist/slices/uploads/repo.js +37 -1
- package/dist/slices/uploads/rules.js +3 -2
- package/dist/slices/video/edit-list.js +2 -2
- package/dist/slices/video/edit-settings.js +1 -1
- package/dist/slices/video/encoding.js +14 -5
- package/dist/slices/video/ffmpeg.js +2 -2
- package/dist/slices/video/plan.js +2 -1
- package/dist/slices/video/slideshow.js +1 -1
- package/dist/slices/voices/attribution.js +3 -2
- package/dist/slices/voices/model.js +9 -8
- package/dist/slices/voices/script.js +2 -1
- package/dist/slices/youtube/answer.js +2 -1
- package/dist/slices/youtube/edits-repo.js +1 -1
- package/dist/tutorials/AI-CLIs.md +25 -25
- package/dist/tutorials/Agents-MCP.md +32 -32
- package/dist/tutorials/Assistant.md +5 -5
- 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 +40 -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 +101 -76
- package/dist/tutorials/Home.md +33 -33
- package/dist/tutorials/Install.md +13 -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 +21 -21
- package/dist/tutorials/Models.md +27 -27
- package/dist/tutorials/Multiple-Voices.md +41 -40
- package/dist/tutorials/Narration-Aliases-and-Glossary.md +14 -14
- package/dist/tutorials/Notifications.md +21 -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 +12 -12
- package/dist/tutorials/Project-Page.md +118 -120
- package/dist/tutorials/Prompts-and-Templates.md +84 -0
- package/dist/tutorials/Prompts.md +45 -45
- 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 +2 -2
- package/dist/tutorials/Reviews-and-Checkpoints.md +90 -93
- package/dist/tutorials/Schedules.md +27 -28
- package/dist/tutorials/Settings-Reference.md +182 -204
- 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 +45 -42
- package/dist/tutorials/Templates.md +50 -79
- 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 +15 -15
- 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 +2 -2
- package/dist/tutorials/Library-Overview.md +0 -76
- package/dist/tutorials/Play-Images.md +0 -165
- 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-CkAI_2E7.css +0 -1
- package/dist/web/assets/index-DcD0cdfo.js +0 -334
- package/dist/web/assets/pdf-TODRwF31.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
|
@@ -21,6 +21,7 @@ const standingRow = z.object({
|
|
|
21
21
|
progress_current: z.number().nullable(),
|
|
22
22
|
progress_total: z.number().nullable(),
|
|
23
23
|
source: z.enum(stageSources),
|
|
24
|
+
retry_at: z.string().nullable(),
|
|
24
25
|
admitted: z.number(),
|
|
25
26
|
parked: z.number(),
|
|
26
27
|
});
|
|
@@ -83,14 +84,15 @@ export function listProjects(db) {
|
|
|
83
84
|
.all()
|
|
84
85
|
.map((row) => toProject(projectRow.parse(row)));
|
|
85
86
|
}
|
|
86
|
-
// What 07 Projects needs of every project's stages and no more: the state each one is in
|
|
87
|
-
//
|
|
88
|
-
//
|
|
89
|
-
//
|
|
90
|
-
//
|
|
87
|
+
// What 07 Projects needs of every project's stages and no more: the state each one is in,
|
|
88
|
+
// how far through itself a running one is, and when one waiting to run again by itself tries
|
|
89
|
+
// (without it, `derive` reads that run as waiting its turn while its own page says Running).
|
|
90
|
+
// One statement for the whole list rather than `stagesOf` per row, and a few columns rather
|
|
91
|
+
// than the whole stage table, because the screen shows a status word and a meter and reads
|
|
92
|
+
// nothing else from a stage. One project's alone when `projectId` is given.
|
|
91
93
|
export function stageStandingsByProject(db, projectId) {
|
|
92
94
|
const grouped = new Map();
|
|
93
|
-
const select = `SELECT project_id, kind, state, progress_current, progress_total, source, ${admittedInItsState("stages")} AS admitted, ${parkedOnReview("stages")} AS parked FROM stages${projectId === undefined ? "" : " WHERE project_id=?"} ORDER BY rowid`;
|
|
95
|
+
const select = `SELECT project_id, kind, state, progress_current, progress_total, source, retry_at, ${admittedInItsState("stages")} AS admitted, ${parkedOnReview("stages")} AS parked FROM stages${projectId === undefined ? "" : " WHERE project_id=?"} ORDER BY rowid`;
|
|
94
96
|
const rows = projectId === undefined ? db.prepare(select).all() : db.prepare(select).all(projectId);
|
|
95
97
|
for (const row of rows) {
|
|
96
98
|
const parsed = standingRow.parse(row);
|
|
@@ -100,6 +102,7 @@ export function stageStandingsByProject(db, projectId) {
|
|
|
100
102
|
progressCurrent: parsed.progress_current,
|
|
101
103
|
progressTotal: parsed.progress_total,
|
|
102
104
|
source: parsed.source,
|
|
105
|
+
...(parsed.retry_at === null ? {} : { retryAt: parsed.retry_at }),
|
|
103
106
|
...(parsed.admitted === 1 ? { admitted: true } : {}),
|
|
104
107
|
...(parsed.parked === 1 ? { parked: true } : {}),
|
|
105
108
|
};
|
|
@@ -88,7 +88,7 @@ export function admit(input) {
|
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
if (needsLlmFor(draft, input.keywordUses) && !chosen(draft.llm)) {
|
|
91
|
-
fields.push({ field: "llm", message: "Choose a
|
|
91
|
+
fields.push({ field: "llm", message: "Choose a Service and a Model under Written by." });
|
|
92
92
|
}
|
|
93
93
|
if (sources.article === "generate" && blank(draft.articlePrompt)) {
|
|
94
94
|
fields.push({ field: "articlePrompt", message: "Pick an article prompt." });
|
|
@@ -98,7 +98,7 @@ export function admit(input) {
|
|
|
98
98
|
fields.push(...voicesFields(draft));
|
|
99
99
|
if (sources.audio === "generate") {
|
|
100
100
|
if (voiced === undefined || !chosen(voiced)) {
|
|
101
|
-
fields.push({ field: "audio", message: "Choose a
|
|
101
|
+
fields.push({ field: "audio", message: "Choose a Service and a Model under Read by." });
|
|
102
102
|
}
|
|
103
103
|
else if (voiced.voice.trim() === "") {
|
|
104
104
|
fields.push({ field: "audio.voice", message: "Choose a voice for the narration." });
|
|
@@ -113,7 +113,7 @@ export function admit(input) {
|
|
|
113
113
|
usesShorts(draft) ||
|
|
114
114
|
usesAnimation(draft)) &&
|
|
115
115
|
!chosen(draft.images)) {
|
|
116
|
-
fields.push({ field: "images", message: "Choose
|
|
116
|
+
fields.push({ field: "images", message: "Choose a Service and a Model under Images by." });
|
|
117
117
|
}
|
|
118
118
|
if ((sources.thumbnail === "from_prompt" || sources.thumbnail === "prompt_by_llm") &&
|
|
119
119
|
blank(draft.thumbnailPrompt)) {
|
|
@@ -122,7 +122,7 @@ export function admit(input) {
|
|
|
122
122
|
if (sources.audio === "off" && draft.subtitles !== undefined && draft.subtitles.mode !== "off") {
|
|
123
123
|
fields.push({
|
|
124
124
|
field: "subtitles.mode",
|
|
125
|
-
message: "
|
|
125
|
+
message: "Captions need narration. Turn narration on, or turn captions off.",
|
|
126
126
|
});
|
|
127
127
|
}
|
|
128
128
|
fields.push(...youtubeDescriptionFields(draft));
|
|
@@ -381,7 +381,7 @@ export function voicesFields(draft) {
|
|
|
381
381
|
!draft.voices.speakers.some((speaker) => speaker.voice.provider === "inworld" && speaker.voice.model === "inworld-tts-2"))
|
|
382
382
|
fields.push({
|
|
383
383
|
field: "narrationPrompt",
|
|
384
|
-
message: "Narration preparation adds delivery cues only to speakers on Inworld's TTS-2 model, and no speaker uses it. Choose that model for a speaker under Speakers, or
|
|
384
|
+
message: "Narration preparation adds delivery cues only to speakers on Inworld's TTS-2 model, and no speaker uses it. Choose that model for a speaker under Speakers, or set Narration preparation to Off under Narration → More narration settings.",
|
|
385
385
|
});
|
|
386
386
|
return fields;
|
|
387
387
|
}
|
|
@@ -489,8 +489,8 @@ export function ambientBedFields(draft, staged) {
|
|
|
489
489
|
function chosen(choice) {
|
|
490
490
|
return choice !== undefined && choice.provider.trim() !== "" && choice.model.trim() !== "";
|
|
491
491
|
}
|
|
492
|
-
// The aliases a run narrates with: its copied
|
|
493
|
-
// on for generated audio, otherwise none. Any voice provider: an alias is plain text.
|
|
492
|
+
// The aliases a run narrates with: its copied Pronunciation list while Use your pronunciation
|
|
493
|
+
// list is on for generated audio, otherwise none. Any voice provider: an alias is plain text.
|
|
494
494
|
export function narrationAliasesOf(draft) {
|
|
495
495
|
return draft.sources.audio === "generate" && draft.audio?.useNarrationAliases === true
|
|
496
496
|
? (draft.narrationAliases ?? [])
|
|
@@ -28,8 +28,13 @@ export const stageStateWords = {
|
|
|
28
28
|
export const heldWord = "Waiting for your review";
|
|
29
29
|
export const waitingForAgentWord = "Waiting for the agent";
|
|
30
30
|
export const stoppedWord = "Stopped";
|
|
31
|
-
|
|
31
|
+
// Made ahead by its schedule (Make ahead): everything but the video is made, and the video is
|
|
32
|
+
// put together on the run's day.
|
|
33
|
+
export const preparedWord = "Waiting for its day";
|
|
32
34
|
export const keptAsIsWord = "Kept as is";
|
|
35
|
+
// A running run whose only movement is a step that failed on something time can fix (a rate
|
|
36
|
+
// limit, a dropped connection) and runs again by itself at a set time.
|
|
37
|
+
export const retryingWord = "Waiting to try again";
|
|
33
38
|
export const heldStateWords = [
|
|
34
39
|
heldWord,
|
|
35
40
|
waitingForAgentWord,
|
|
@@ -38,15 +43,25 @@ export const heldStateWords = [
|
|
|
38
43
|
keptAsIsWord,
|
|
39
44
|
];
|
|
40
45
|
// A run that ran and is held: a waiting project with some of its run done (`progress` is the
|
|
41
|
-
// run's share done, `progressOf`) or a step failed,
|
|
42
|
-
// before it
|
|
46
|
+
// run's share done, `progressOf`) or a step failed, one a checkpoint holds (it reached it with
|
|
47
|
+
// every step before it supplied), or one stopped or parked on an agent's review before it got
|
|
48
|
+
// going. One with none done that waits for none of these is Queued, waiting its turn.
|
|
43
49
|
export function heldRun(project) {
|
|
44
50
|
return (project.status === "pending" &&
|
|
45
51
|
(project.progress > 0 ||
|
|
46
52
|
project.stepFailed === true ||
|
|
53
|
+
(project.holding?.length ?? 0) > 0 ||
|
|
47
54
|
project.stopped === true ||
|
|
48
55
|
project.waitingForAgent === true));
|
|
49
56
|
}
|
|
57
|
+
// When the run tries again by itself: the soonest wait of a step that failed on something time
|
|
58
|
+
// can fix, while no step runs. Undefined while one runs (the run reads Running) or none waits.
|
|
59
|
+
export function retryingAt(stages) {
|
|
60
|
+
if (stages.some((stage) => stage.state === "running"))
|
|
61
|
+
return undefined;
|
|
62
|
+
const waits = stages.flatMap((stage) => stage.state === "pending" && typeof stage.retryAt === "string" ? [stage.retryAt] : []);
|
|
63
|
+
return waits.toSorted()[0];
|
|
64
|
+
}
|
|
50
65
|
// Whether the person is the one it waits for (to approve, or to Continue the run): not when it
|
|
51
66
|
// is Kept as is, waits for an agent or for its scheduled day.
|
|
52
67
|
function heldForPerson(project) {
|
|
@@ -78,9 +93,18 @@ export function runningNow(project) {
|
|
|
78
93
|
export function queuedRun(project) {
|
|
79
94
|
return project.status === "pending" && !heldRun(project);
|
|
80
95
|
}
|
|
81
|
-
//
|
|
96
|
+
// A settled project already reads "done" from the projects route (`settledProjects`). A
|
|
97
|
+
// running run that only waits to try a step again says so.
|
|
82
98
|
export function projectStateWord(project) {
|
|
83
|
-
|
|
99
|
+
if (heldRun(project))
|
|
100
|
+
return heldStateWord(project);
|
|
101
|
+
if (retryingRun(project))
|
|
102
|
+
return retryingWord;
|
|
103
|
+
return projectStateWords[project.status];
|
|
104
|
+
}
|
|
105
|
+
// Running, and the one thing it does is wait to try a failed step again at a set time.
|
|
106
|
+
export function retryingRun(project) {
|
|
107
|
+
return project.status === "running" && project.retryAt !== undefined;
|
|
84
108
|
}
|
|
85
109
|
// A run that ran and now waits for the person, held or paused: Home's Needs you, the Projects
|
|
86
110
|
// "Needs you" filter and its waiting-first sort.
|
|
@@ -108,3 +132,8 @@ export function stepFailedWhileWaiting(status, stages) {
|
|
|
108
132
|
export function failedRun(project) {
|
|
109
133
|
return project.status === "failed" || project.stepFailed === true;
|
|
110
134
|
}
|
|
135
|
+
// Everything a run asks of the person, the one set Home's Needs you lists and the Projects
|
|
136
|
+
// "Needs you" filter holds: a decision (approve, Continue the run, resume) or a failure to fix.
|
|
137
|
+
export function needsYou(project) {
|
|
138
|
+
return waitsForPerson(project) || failedRun(project);
|
|
139
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
// The cost sentence on an ask card, from the estimate the preview (Choose what to
|
|
2
|
+
// The cost sentence on an ask card, from the estimate the preview (Choose what to make again) or
|
|
3
3
|
// Play's review already showed for this exact work.
|
|
4
4
|
const money = (value) => `$${value.toFixed(2)}`;
|
|
5
5
|
function range(low, high) {
|
|
@@ -37,7 +37,7 @@ export const turnStates = ["running", "done", "failed", "stopped"];
|
|
|
37
37
|
const providersFix = {
|
|
38
38
|
kind: "settings",
|
|
39
39
|
section: "providers",
|
|
40
|
-
label: "Open Settings →
|
|
40
|
+
label: "Open Settings → Keys & services",
|
|
41
41
|
};
|
|
42
42
|
const signIn = {
|
|
43
43
|
"claude-code": "claude auth login",
|
|
@@ -46,13 +46,20 @@ const signIn = {
|
|
|
46
46
|
function blocked(cli, state) {
|
|
47
47
|
const name = assistantCliNames[cli];
|
|
48
48
|
if (!state.installed)
|
|
49
|
-
return `The assistant can't start: ${name} isn't installed on this computer. Install it, then set it up in Settings →
|
|
49
|
+
return `The assistant can't start: ${name} isn't installed on this computer. Install it, then set it up in Settings → Keys & services.`;
|
|
50
50
|
if (state.issue !== undefined)
|
|
51
51
|
return `The assistant can't start: ${state.issue}`;
|
|
52
52
|
if (state.login === "signed-out")
|
|
53
53
|
return `The assistant can't start: ${name} is signed out. Run "${signIn[cli]}" in a terminal, then send your message again.`;
|
|
54
54
|
return undefined;
|
|
55
55
|
}
|
|
56
|
+
// The CLIs that could answer now, in Auto's order: the panel offers "Answer with" only when
|
|
57
|
+
// there are two to choose between.
|
|
58
|
+
export function readyClis(states, container) {
|
|
59
|
+
if (container)
|
|
60
|
+
return [];
|
|
61
|
+
return assistantClis.filter((cli) => blocked(cli, states[cli]) === undefined);
|
|
62
|
+
}
|
|
56
63
|
// Auto takes Claude Code when it is ready, else Codex. A sign-in that couldn't be read is not
|
|
57
64
|
// a refusal: the CLI says so itself if it really is signed out.
|
|
58
65
|
export function assistantCliOf(states, preference, container) {
|
|
@@ -73,7 +80,7 @@ export function assistantCliOf(states, preference, container) {
|
|
|
73
80
|
return { ok: true, cli };
|
|
74
81
|
return {
|
|
75
82
|
ok: false,
|
|
76
|
-
reason: "The assistant runs on Claude Code or Codex, and neither is ready on this computer. Set up Claude Code or Codex in Settings →
|
|
83
|
+
reason: "The assistant runs on Claude Code or Codex, and neither is ready on this computer. Set up Claude Code or Codex in Settings → Keys & services.",
|
|
77
84
|
fix: providersFix,
|
|
78
85
|
};
|
|
79
86
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { causedBy } from "../../kernel/errors.js";
|
|
2
2
|
import { redact } from "../../kernel/log.js";
|
|
3
3
|
import { asksOf, consumeGrant, decideAsk, openAsk } from "./asks.js";
|
|
4
|
-
import { assistantCliNames, assistantCliOf, } from "./model.js";
|
|
4
|
+
import { assistantCliNames, assistantCliOf, readyClis, } from "./model.js";
|
|
5
5
|
import { screenNames } from "./names.js";
|
|
6
6
|
import { assistantSystemPrompt, turnPrompt } from "./prompt.js";
|
|
7
7
|
import { addMessage, cliPreferenceOf, createSession, latestSessionId, messagesOf, sessionExists, transcriptOf, } from "./repo.js";
|
|
@@ -182,7 +182,7 @@ export function createAssistant(deps) {
|
|
|
182
182
|
if (self.stoppedBy === undefined) {
|
|
183
183
|
const detail = redact(causedBy(error));
|
|
184
184
|
deps.log.write("warn", "assistant.turn", { detail });
|
|
185
|
-
say(sessionId, turnId, "error", `Slopify couldn't run the assistant's CLI: ${detail}. Check it in Settings →
|
|
185
|
+
say(sessionId, turnId, "error", `Slopify couldn't run the assistant's CLI: ${detail}. Check it in Settings → Keys & services, then send your message again.`, { kind: "cli" });
|
|
186
186
|
}
|
|
187
187
|
}
|
|
188
188
|
if (self.stoppedBy !== undefined) {
|
|
@@ -264,9 +264,11 @@ export function createAssistant(deps) {
|
|
|
264
264
|
tokens: deps.tokens,
|
|
265
265
|
status: async () => {
|
|
266
266
|
const preference = cliPreferenceOf(deps.db);
|
|
267
|
+
const states = await deps.clis();
|
|
267
268
|
return {
|
|
268
269
|
preference,
|
|
269
|
-
choice: assistantCliOf(
|
|
270
|
+
choice: assistantCliOf(states, preference, deps.container),
|
|
271
|
+
ready: readyClis(states, deps.container),
|
|
270
272
|
};
|
|
271
273
|
},
|
|
272
274
|
session: (id) => {
|
|
@@ -51,7 +51,7 @@ export function warningsOf(signals, snoozes, now) {
|
|
|
51
51
|
found.push({
|
|
52
52
|
key: `template-not-ready:${schedule.id}`,
|
|
53
53
|
severity: "problem",
|
|
54
|
-
text: `“${schedule.name}” skips its runs because its template “${schedule.notReadyTemplate}” has no version
|
|
54
|
+
text: `“${schedule.name}” skips its runs because its template “${schedule.notReadyTemplate}” has no version approved for schedules. Open it from Templates with Edit template, then choose More → Approve for schedules.`,
|
|
55
55
|
fix: { kind: "templates", label: "Open Templates" },
|
|
56
56
|
});
|
|
57
57
|
if (schedule.topicsError !== null && schedule.generation !== "off")
|
|
@@ -60,7 +60,7 @@ export function createBackupService(deps) {
|
|
|
60
60
|
}
|
|
61
61
|
catch (error) {
|
|
62
62
|
deps.log.write("warn", "backups.prune", { detail: String(error) });
|
|
63
|
-
detail = `The backup was saved, but older backups in ${folder} could not be removed (${errnoCode(error) ?? "unknown error"}), so more than ${settings.keep} are kept. Check Slopify can delete files in that folder, or pick another Folder in Settings →
|
|
63
|
+
detail = `The backup was saved, but older backups in ${folder} could not be removed (${errnoCode(error) ?? "unknown error"}), so more than ${settings.keep} are kept. Check Slopify can delete files in that folder, or pick another Folder in Settings → Backup & storage.`;
|
|
64
64
|
}
|
|
65
65
|
record({
|
|
66
66
|
...attempt,
|
|
@@ -273,17 +273,17 @@ function named(projects) {
|
|
|
273
273
|
.join(", ");
|
|
274
274
|
return projects.length > 3 ? `${titles} and ${projects.length - 3} more` : titles;
|
|
275
275
|
}
|
|
276
|
-
// What failed, why, and what to change - the sentence Settings →
|
|
276
|
+
// What failed, why, and what to change - the sentence Settings → Backup & storage shows.
|
|
277
277
|
export function explain(error, folder, retries, signal) {
|
|
278
|
-
const fix = "Pick another Folder in Settings →
|
|
278
|
+
const fix = "Pick another Folder in Settings → Backup & storage, or leave it empty to use the default";
|
|
279
279
|
if (signal?.aborted === true && error === signal.reason)
|
|
280
280
|
return "The backup was not saved: Slopify stopped while writing it, and the unfinished file was removed. It runs again after Slopify starts.";
|
|
281
281
|
if (error instanceof NoSpaceError)
|
|
282
|
-
return `The backup was not saved: it needs about ${bytes(error.needed)}, but the disk holding ${folder} has ${bytes(error.free)} free. Free up space there, lower "Keep last" in Settings →
|
|
282
|
+
return `The backup was not saved: it needs about ${bytes(error.needed)}, but the disk holding ${folder} has ${bytes(error.free)} free. Free up space there, lower "Keep last" in Settings → Backup & storage, or pick another Folder.`;
|
|
283
283
|
switch (errnoCode(error)) {
|
|
284
284
|
case "ENOSPC":
|
|
285
285
|
case "EDQUOT":
|
|
286
|
-
return `The backup was not saved: the disk holding ${folder} ran out of space. Free up space there, lower "Keep last" in Settings →
|
|
286
|
+
return `The backup was not saved: the disk holding ${folder} ran out of space. Free up space there, lower "Keep last" in Settings → Backup & storage, or pick another Folder.`;
|
|
287
287
|
case "EACCES":
|
|
288
288
|
case "EPERM":
|
|
289
289
|
case "EROFS":
|
|
@@ -61,7 +61,7 @@ export function generateCastImage(deps, memberId, input) {
|
|
|
61
61
|
}, (error) => {
|
|
62
62
|
const reason = errorText(error);
|
|
63
63
|
deps.log?.write("warn", "channels.cast-image.failed", { detail: reason.slice(0, 500) });
|
|
64
|
-
fail(deps, id, `The picture couldn't be made: ${reason.slice(0, 500)} Check the image
|
|
64
|
+
fail(deps, id, `The picture couldn't be made: ${reason.slice(0, 500)} Check the image service in Settings → Keys & services, then press Make the picture again.`);
|
|
65
65
|
});
|
|
66
66
|
return { ok: true, value: imageRow(deps, id) };
|
|
67
67
|
}
|
|
@@ -10,7 +10,7 @@ import { castKinds } from "./model.js";
|
|
|
10
10
|
const id = z.uuid();
|
|
11
11
|
const colour = z
|
|
12
12
|
.string()
|
|
13
|
-
.regex(/^#[0-9a-fA-F]{6}$/, "Use a
|
|
13
|
+
.regex(/^#[0-9a-fA-F]{6}$/, "Use a color like #FFD700.")
|
|
14
14
|
.transform((value) => value.toUpperCase());
|
|
15
15
|
const optionalText = (max) => z.string().trim().max(max).optional();
|
|
16
16
|
const fontId = z
|
|
@@ -17,7 +17,7 @@ const importSchema = z
|
|
|
17
17
|
// The preview's "Keep only titles containing…" text, remembered for the next import.
|
|
18
18
|
filter: z
|
|
19
19
|
.string()
|
|
20
|
-
.max(importFilterMax, `The filter is too long to remember. Shorten "Keep only titles containing…" on the channel's
|
|
20
|
+
.max(importFilterMax, `The filter is too long to remember. Shorten "Keep only titles containing…" on the channel's Titles to avoid tab to at most ${importFilterMax} characters.`)
|
|
21
21
|
.optional(),
|
|
22
22
|
})
|
|
23
23
|
.strict();
|
|
@@ -24,8 +24,8 @@ export function validateLocalProviderChanges(changes, current) {
|
|
|
24
24
|
"Install this command-line tool on your computer and sign in to it, then try again.")
|
|
25
25
|
: provider.readiness.kind === "local"
|
|
26
26
|
? (provider.readiness.issue ??
|
|
27
|
-
"No speech program was found on this computer. Install
|
|
28
|
-
: "Add this provider's API key in Settings →
|
|
27
|
+
"No speech program was found on this computer. Install the free program eSpeak NG, or choose a voice service with a key in Settings → Keys & services.")
|
|
28
|
+
: "Add this provider's API key in Settings → Keys & services first.",
|
|
29
29
|
});
|
|
30
30
|
}
|
|
31
31
|
}
|
|
@@ -14,7 +14,7 @@ export function dailySampleBudget(db, log) {
|
|
|
14
14
|
export function budgetSentence(total, budget) {
|
|
15
15
|
return `Waiting: this sample would take today's sample spending to $${total.toFixed(2)}, over the $${budget.toFixed(2)} a day samples may spend. Press Make sample to make it anyway; the limit starts again at midnight.`;
|
|
16
16
|
}
|
|
17
|
-
// Settings →
|
|
17
|
+
// Settings → Production defaults shows it beside the budget: what design samples spent since local
|
|
18
18
|
// midnight and what is left of today's budget.
|
|
19
19
|
export function designBudgetRoom(db, now, timeZone) {
|
|
20
20
|
const budget = dailySampleBudget(db);
|
|
@@ -11,7 +11,7 @@ import { settleStep, stepById } from "./steps-repo.js";
|
|
|
11
11
|
// The background half of the runner: each "making" step's provider call, at most two at once,
|
|
12
12
|
// settled into its step (and made the design's current version when it lands).
|
|
13
13
|
export const maxConcurrentDesignCalls = 2;
|
|
14
|
-
export const noProviderMessage = "No image
|
|
14
|
+
export const noProviderMessage = "No image service is set up. Add one in Settings → Keys & services, then press the button again.";
|
|
15
15
|
export function createDesignCalls(deps) {
|
|
16
16
|
let running = 0;
|
|
17
17
|
const waiting = [];
|
|
@@ -119,6 +119,6 @@ function failedSentence(error, reason) {
|
|
|
119
119
|
if (kind === "unsupported")
|
|
120
120
|
return `The picture couldn't be made: ${reason}${reason.includes("Made with") ? "" : " Choose another image model under Made with … · change."}`;
|
|
121
121
|
if (kind === "auth" || kind === "missing_key")
|
|
122
|
-
return `The picture couldn't be made: ${reason}${/Settings/.test(reason) ? "" : " Check the provider's key in Settings →
|
|
122
|
+
return `The picture couldn't be made: ${reason}${/Settings/.test(reason) ? "" : " Check the provider's key in Settings → Keys & services, then press Try again."}`;
|
|
123
123
|
return `The picture couldn't be made: ${reason} Press Try again, or choose another image model under Made with … · change.`;
|
|
124
124
|
}
|
|
@@ -22,16 +22,16 @@ export function designCheckContext(deps) {
|
|
|
22
22
|
statuses = await deps.providers();
|
|
23
23
|
}
|
|
24
24
|
catch (error) {
|
|
25
|
-
return `Slopify couldn't check the image
|
|
25
|
+
return `Slopify couldn't check the image service: ${errorText(error)} Open Settings → Keys & services, then press Approve for schedules again.`;
|
|
26
26
|
}
|
|
27
27
|
const status = statuses.find((one) => one.id === provider);
|
|
28
28
|
if (status === undefined)
|
|
29
|
-
return `The image
|
|
29
|
+
return `The image service “${provider}” isn't one this Slopify knows. Choose another image model under Picture.`;
|
|
30
30
|
const readiness = status.readiness;
|
|
31
31
|
if (readiness.kind === "keyed" && !readiness.hasKey)
|
|
32
|
-
return `${status.displayName} has no API key, so the picture can't be made. Add the key in Settings →
|
|
32
|
+
return `${status.displayName} has no API key, so the picture can't be made. Add the key in Settings → Keys & services, then press Approve for schedules again.`;
|
|
33
33
|
if (readiness.kind === "cli" && (!readiness.installed || readiness.issue !== undefined))
|
|
34
|
-
return `${status.displayName} can't be used yet: ${readiness.issue ?? "it isn't installed on this computer."} Fix it in Settings →
|
|
34
|
+
return `${status.displayName} can't be used yet: ${readiness.issue ?? "it isn't installed on this computer."} Fix it in Settings → Keys & services, then press Approve for schedules again.`;
|
|
35
35
|
return null;
|
|
36
36
|
},
|
|
37
37
|
};
|
|
@@ -26,7 +26,7 @@ export function designFields(doc) {
|
|
|
26
26
|
const slotSentences = {
|
|
27
27
|
unclosed: "has a {{ without its }}",
|
|
28
28
|
empty: "has an empty {{}}",
|
|
29
|
-
nested: "has a { or } inside a {{
|
|
29
|
+
nested: "has a { or } inside a {{keyword}}",
|
|
30
30
|
};
|
|
31
31
|
export function fieldProblems(doc) {
|
|
32
32
|
const problems = [];
|
|
@@ -36,7 +36,7 @@ export function fieldProblems(doc) {
|
|
|
36
36
|
kind: "slot",
|
|
37
37
|
where: body.where,
|
|
38
38
|
error: error.kind,
|
|
39
|
-
sentence: `The ${body.where.replace(/^the /, "")} ${slotSentences[error.kind]}. Fix it so every
|
|
39
|
+
sentence: `The ${body.where.replace(/^the /, "")} ${slotSentences[error.kind]}. Fix it so every keyword reads {{Name}}.`,
|
|
40
40
|
});
|
|
41
41
|
const names = designFields(doc);
|
|
42
42
|
for (const name of names)
|
|
@@ -51,7 +51,7 @@ export function fieldProblems(doc) {
|
|
|
51
51
|
problems.push({
|
|
52
52
|
kind: "date-field",
|
|
53
53
|
name: dateField,
|
|
54
|
-
sentence: `The schedule reads each row's date from {{${dateField}}}, but no text uses it. Put {{${dateField}}} in a text block, or choose another date
|
|
54
|
+
sentence: `The schedule reads each row's date from {{${dateField}}}, but no text uses it. Put {{${dateField}}} in a text block, or choose another date keyword under Schedule.`,
|
|
55
55
|
});
|
|
56
56
|
return problems;
|
|
57
57
|
}
|
|
@@ -64,7 +64,7 @@ export function missingSentence(missing) {
|
|
|
64
64
|
const named = list.length === 1
|
|
65
65
|
? `${list[0] ?? ""} has`
|
|
66
66
|
: `${list.slice(0, -1).join(", ")} and ${list.at(-1) ?? ""} have`;
|
|
67
|
-
return `${named} no value. Fill ${list.length === 1 ? "it" : "them"} in under
|
|
67
|
+
return `${named} no value. Fill ${list.length === 1 ? "it" : "them"} in under Keywords, then press Make.`;
|
|
68
68
|
}
|
|
69
69
|
// Every text with its fields filled. Values are inserted verbatim, never read as fields.
|
|
70
70
|
export function fillDocument(doc, values) {
|
|
@@ -33,8 +33,10 @@ export async function contextChecks(doc, templateId, ctx) {
|
|
|
33
33
|
checks.push({
|
|
34
34
|
id: "provider",
|
|
35
35
|
ok: problem === null,
|
|
36
|
-
sentence: problem ?? "The image
|
|
37
|
-
fix: problem === null
|
|
36
|
+
sentence: problem ?? "The image service is ready.",
|
|
37
|
+
fix: problem === null
|
|
38
|
+
? null
|
|
39
|
+
: { label: "Open Keys & services", href: "/settings?section=providers" },
|
|
38
40
|
});
|
|
39
41
|
}
|
|
40
42
|
else {
|
|
@@ -56,7 +58,7 @@ export async function contextChecks(doc, templateId, ctx) {
|
|
|
56
58
|
ok: used,
|
|
57
59
|
sentence: used
|
|
58
60
|
? `Each row's date is read from {{${schedule.dateField}}}.`
|
|
59
|
-
: `The schedule reads each date from {{${schedule.dateField}}}, but the template doesn't use that
|
|
61
|
+
: `The schedule reads each date from {{${schedule.dateField}}}, but the template doesn't use that keyword. Choose a keyword it uses under Schedule.`,
|
|
60
62
|
fix: used ? null : at("schedule"),
|
|
61
63
|
});
|
|
62
64
|
}
|
|
@@ -107,12 +109,12 @@ export async function contextChecks(doc, templateId, ctx) {
|
|
|
107
109
|
});
|
|
108
110
|
return checks;
|
|
109
111
|
}
|
|
110
|
-
//
|
|
112
|
+
// Approve for schedules asks for the version's own sample, made, as Edit template does: the
|
|
111
113
|
// person has seen what a schedule will make before it makes it.
|
|
112
114
|
export function sampleCheck(db, templateId, version) {
|
|
113
115
|
const row = sampleRow(db, templateId);
|
|
114
116
|
const made = row?.state === "done" && row.version === version;
|
|
115
|
-
const how = "Make its sample, look it over beside the settings, then press
|
|
117
|
+
const how = "Make its sample, look it over beside the settings, then press Approve for schedules.";
|
|
116
118
|
return {
|
|
117
119
|
id: "sample",
|
|
118
120
|
ok: made,
|
|
@@ -9,7 +9,7 @@ export function prepare(db, designId, format) {
|
|
|
9
9
|
return {
|
|
10
10
|
ok: false,
|
|
11
11
|
reason: "not-found",
|
|
12
|
-
message: "This design no longer exists.
|
|
12
|
+
message: "This design no longer exists. Go back to Designs to choose another.",
|
|
13
13
|
};
|
|
14
14
|
const parsed = designDocumentSchema.safeParse(design.document);
|
|
15
15
|
if (!parsed.success)
|
|
@@ -13,7 +13,7 @@ const sha256 = z.string().regex(/^[a-f0-9]{64}$/);
|
|
|
13
13
|
export const designValuesSchema = z
|
|
14
14
|
.record(z.string().min(1).max(100), z.string().max(2000))
|
|
15
15
|
.refine((values) => Object.keys(values).length <= 100, {
|
|
16
|
-
message: "A design has at most 100
|
|
16
|
+
message: "A design has at most 100 keywords.",
|
|
17
17
|
});
|
|
18
18
|
export const createDesignSchema = z
|
|
19
19
|
.object({
|
|
@@ -14,7 +14,7 @@ const noProvider = {
|
|
|
14
14
|
const notFound = {
|
|
15
15
|
ok: false,
|
|
16
16
|
reason: "not-found",
|
|
17
|
-
message: "This design no longer exists.
|
|
17
|
+
message: "This design no longer exists. Go back to Designs to choose another.",
|
|
18
18
|
};
|
|
19
19
|
export function createDesignRunner(deps) {
|
|
20
20
|
const calls = createDesignCalls(deps);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { transact } from "../../kernel/db/tx.js";
|
|
2
|
+
import { plansSwitch } from "../template-studio/budget.js";
|
|
2
3
|
import { budgetSentence } from "./budget.js";
|
|
3
4
|
import { missingValues } from "./fields.js";
|
|
4
5
|
import { costChanged, costChangedMessage } from "./quote.js";
|
|
@@ -56,7 +57,7 @@ export function createDesignSamples(deps) {
|
|
|
56
57
|
const spent = sampleSpentToday(db, now(), deps.timeZone()) + sampleReserved(db, templateId);
|
|
57
58
|
const budget = deps.budget();
|
|
58
59
|
return quote.rows.some((one) => one.onPlan === true) && !deps.plans()
|
|
59
|
-
?
|
|
60
|
+
? `Waiting: this sample's picture runs on your Claude Code or Codex plan, and samples may not use it. Turn on ${plansSwitch} in Settings → Production defaults, or press Make sample to make it anyway.`
|
|
60
61
|
: quote.unknown > 0
|
|
61
62
|
? "Waiting: the price of this sample's picture isn't known, so Slopify didn't make it. Press Make sample to make it anyway."
|
|
62
63
|
: quote.high > holdSlack(acknowledgedHigh)
|
|
@@ -16,7 +16,7 @@ export const reusedMessage = "This request id was already used for a different c
|
|
|
16
16
|
const notFound = {
|
|
17
17
|
ok: false,
|
|
18
18
|
reason: "not-found",
|
|
19
|
-
message: "This design no longer exists.
|
|
19
|
+
message: "This design no longer exists. Go back to Designs to choose another.",
|
|
20
20
|
};
|
|
21
21
|
export function mutationHash(input) {
|
|
22
22
|
return createHash("sha256").update(JSON.stringify(input)).digest("hex");
|
|
@@ -21,14 +21,14 @@ export function documentChecks(doc, templateId) {
|
|
|
21
21
|
{
|
|
22
22
|
id: "fields",
|
|
23
23
|
ok: problems.length === 0,
|
|
24
|
-
sentence: problems[0]?.sentence ?? "Every
|
|
24
|
+
sentence: problems[0]?.sentence ?? "Every keyword is written as {{Name}}.",
|
|
25
25
|
fix: problems.length === 0 ? null : at("text"),
|
|
26
26
|
},
|
|
27
27
|
{
|
|
28
28
|
id: "samples",
|
|
29
29
|
ok: missing.length === 0,
|
|
30
30
|
sentence: missing.length === 0
|
|
31
|
-
? "Every
|
|
31
|
+
? "Every keyword has a sample value."
|
|
32
32
|
: `${missing.map((name) => `{{${name}}}`).join(", ")} ${missing.length === 1 ? "has" : "have"} no sample value. Fill ${missing.length === 1 ? "it" : "them"} in under Text → Sample values.`,
|
|
33
33
|
fix: missing.length === 0 ? null : at("text"),
|
|
34
34
|
},
|
|
@@ -27,7 +27,7 @@ export const makeFromTemplateSchema = z
|
|
|
27
27
|
const notFound = {
|
|
28
28
|
ok: false,
|
|
29
29
|
reason: "not-found",
|
|
30
|
-
message: "This design template no longer exists. Open
|
|
30
|
+
message: "This design template no longer exists. Open Templates → Poster templates to choose another.",
|
|
31
31
|
};
|
|
32
32
|
// What one piece made from this document costs: its artwork, or nothing when the template
|
|
33
33
|
// keeps its own picture.
|
|
@@ -53,7 +53,7 @@ export function makeFromTemplate(deps, templateId, raw, origin = {}) {
|
|
|
53
53
|
return {
|
|
54
54
|
ok: false,
|
|
55
55
|
reason: "invalid",
|
|
56
|
-
message: `The
|
|
56
|
+
message: `The poster can't be made: ${parsed.error.issues[0]?.message ?? "a keyword is missing"}.`,
|
|
57
57
|
};
|
|
58
58
|
const input = parsed.data;
|
|
59
59
|
const template = getTemplate(deps.service.db, templateId);
|
|
@@ -78,7 +78,7 @@ export function makeFromTemplate(deps, templateId, raw, origin = {}) {
|
|
|
78
78
|
return {
|
|
79
79
|
ok: false,
|
|
80
80
|
reason: "cost-changed",
|
|
81
|
-
message: costChangedMessage(quote, "this
|
|
81
|
+
message: costChangedMessage(quote, "this poster"),
|
|
82
82
|
current: quote,
|
|
83
83
|
};
|
|
84
84
|
const own = doc.picture.source === "picture" ? doc.picture.sha256 : undefined;
|
|
@@ -109,7 +109,7 @@ export function listTemplates(db) {
|
|
|
109
109
|
const notFound = {
|
|
110
110
|
ok: false,
|
|
111
111
|
reason: "not-found",
|
|
112
|
-
message: "This design template no longer exists. Open
|
|
112
|
+
message: "This design template no longer exists. Open Templates → Poster templates to choose another.",
|
|
113
113
|
};
|
|
114
114
|
function invalid(error) {
|
|
115
115
|
return {
|
|
@@ -187,7 +187,7 @@ export function saveTemplate(deps, templateId, raw) {
|
|
|
187
187
|
export async function markTemplateReady(deps, templateId, raw, more = async () => []) {
|
|
188
188
|
const parsed = markReadySchema.safeParse(raw);
|
|
189
189
|
if (!parsed.success)
|
|
190
|
-
return { ok: false, reason: "invalid", message: "Say which version to
|
|
190
|
+
return { ok: false, reason: "invalid", message: "Say which version to approve for schedules." };
|
|
191
191
|
if (getTemplate(deps.db, templateId) === undefined)
|
|
192
192
|
return notFound;
|
|
193
193
|
const revision = templateRevision(deps.db, templateId, parsed.data.version);
|
|
@@ -210,7 +210,7 @@ export async function markTemplateReady(deps, templateId, raw, more = async () =
|
|
|
210
210
|
return {
|
|
211
211
|
ok: false,
|
|
212
212
|
reason: "not-ready",
|
|
213
|
-
message: `Version ${String(parsed.data.version)} can't be
|
|
213
|
+
message: `Version ${String(parsed.data.version)} can't be approved for schedules yet: ${failed.map((check) => check.sentence).join(" ")}`,
|
|
214
214
|
current: failed,
|
|
215
215
|
};
|
|
216
216
|
const template = getTemplate(deps.db, templateId);
|
|
@@ -33,7 +33,7 @@ export function readDocumentAssets() {
|
|
|
33
33
|
};
|
|
34
34
|
}
|
|
35
35
|
catch (error) {
|
|
36
|
-
throw new Error(`Slopify couldn't read the fonts and page texture it makes documents with (${errorText(error)}). Its installation is incomplete: reinstall or update Slopify, then use Try again on
|
|
36
|
+
throw new Error(`Slopify couldn't read the fonts and page texture it makes documents with (${errorText(error)}). Its installation is incomplete: reinstall or update Slopify, then use Try again on PDF.`, { cause: error });
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
export function registerFonts(doc, fonts) {
|