@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.
Files changed (718) hide show
  1. package/dist/adapters/account-limits.js +30 -0
  2. package/dist/adapters/alignment/audio.js +1 -1
  3. package/dist/adapters/alignment/cache.js +4 -6
  4. package/dist/adapters/alignment/ctc.js +1 -2
  5. package/dist/adapters/alignment/lock.js +4 -3
  6. package/dist/adapters/alignment/multilingual.js +2 -4
  7. package/dist/adapters/alignment/prefetch.js +2 -1
  8. package/dist/adapters/alignment/runner.js +1 -1
  9. package/dist/adapters/alignment/worker.js +3 -2
  10. package/dist/adapters/explain.js +10 -12
  11. package/dist/adapters/ffmpeg.js +19 -1
  12. package/dist/adapters/host-cli/index.js +21 -4
  13. package/dist/adapters/host-cli/transport.js +2 -1
  14. package/dist/adapters/http-failure.js +53 -0
  15. package/dist/adapters/image/bytes.js +2 -1
  16. package/dist/adapters/image/codex.js +42 -9
  17. package/dist/adapters/image/fal.js +21 -53
  18. package/dist/adapters/image/google.js +33 -56
  19. package/dist/adapters/image/models.js +2 -2
  20. package/dist/adapters/image/openai.js +22 -48
  21. package/dist/adapters/image/reference.js +36 -0
  22. package/dist/adapters/image/replicate.js +21 -49
  23. package/dist/adapters/image/video.js +2 -1
  24. package/dist/adapters/interest/search-interest.js +113 -0
  25. package/dist/adapters/key-probes.js +54 -3
  26. package/dist/adapters/llm/antigravity-models.js +1 -1
  27. package/dist/adapters/llm/antigravity.js +11 -6
  28. package/dist/adapters/llm/assistant-cli.js +388 -0
  29. package/dist/adapters/llm/child-session.js +83 -0
  30. package/dist/adapters/llm/claude-code-models.js +52 -99
  31. package/dist/adapters/llm/claude-code.js +16 -4
  32. package/dist/adapters/llm/codex-limits.js +27 -68
  33. package/dist/adapters/llm/codex-models.js +1 -1
  34. package/dist/adapters/llm/codex-server-models.js +61 -109
  35. package/dist/adapters/llm/codex.js +12 -1
  36. package/dist/adapters/llm/document-workspace.js +3 -2
  37. package/dist/adapters/llm/image-workspace.js +3 -2
  38. package/dist/adapters/llm/openrouter.js +12 -48
  39. package/dist/adapters/llm/run-cli.js +9 -24
  40. package/dist/adapters/llm/sse-lines.js +5 -1
  41. package/dist/adapters/model-access.js +37 -0
  42. package/dist/adapters/tts/cartesia.js +15 -46
  43. package/dist/adapters/tts/elevenlabs.js +20 -52
  44. package/dist/adapters/tts/gemini.js +21 -41
  45. package/dist/adapters/tts/inworld-async.js +6 -2
  46. package/dist/adapters/tts/inworld.js +6 -2
  47. package/dist/adapters/tts/openai.js +20 -50
  48. package/dist/adapters/tts/system.js +2 -1
  49. package/dist/assets/models-lifecycle.yaml +6 -0
  50. package/dist/assistant-wiring.js +60 -0
  51. package/dist/autopilot-timers.js +59 -0
  52. package/dist/catalog/lifecycle.js +52 -0
  53. package/dist/catalog/propose.js +204 -0
  54. package/dist/catalog/registry.js +23 -14
  55. package/dist/catalog/schema.js +4 -1
  56. package/dist/catalog/store.js +39 -0
  57. package/dist/catalog/validate.js +5 -2
  58. package/dist/edge/autostart/native.js +3 -5
  59. package/dist/edge/autostart/prompt.js +2 -1
  60. package/dist/edge/autostart/service.js +3 -4
  61. package/dist/edge/cli-args.js +3 -4
  62. package/dist/edge/cli.js +2 -1
  63. package/dist/edge/docker-install/apply.js +11 -11
  64. package/dist/edge/docker-install/run.js +2 -1
  65. package/dist/edge/docker-install/state.js +4 -3
  66. package/dist/edge/docker-install/tree.js +2 -4
  67. package/dist/edge/docker-install/volume.js +3 -2
  68. package/dist/edge/docker.js +5 -4
  69. package/dist/edge/events/hub.js +5 -5
  70. package/dist/edge/http/actions.js +11 -32
  71. package/dist/edge/http/actor.js +5 -3
  72. package/dist/edge/http/app.js +86 -11
  73. package/dist/edge/http/assistant.js +129 -0
  74. package/dist/edge/http/audio-preview.js +4 -11
  75. package/dist/edge/http/auditions.js +1 -1
  76. package/dist/edge/http/autostart.js +5 -5
  77. package/dist/edge/http/backups.js +2 -4
  78. package/dist/edge/http/channel-memory.js +9 -22
  79. package/dist/edge/http/channels.js +14 -27
  80. package/dist/edge/http/checkpoints.js +39 -21
  81. package/dist/edge/http/design-templates.js +167 -0
  82. package/dist/edge/http/designs.js +178 -0
  83. package/dist/edge/http/diagnostics.js +5 -1
  84. package/dist/edge/http/document-themes.js +5 -14
  85. package/dist/edge/http/draft-files.js +1 -3
  86. package/dist/edge/http/draft-problem.js +5 -10
  87. package/dist/edge/http/drafts.js +3 -3
  88. package/dist/edge/http/entries.js +6 -9
  89. package/dist/edge/http/extension-auth.js +27 -0
  90. package/dist/edge/http/external-reviews.js +12 -11
  91. package/dist/edge/http/files.js +5 -11
  92. package/dist/edge/http/folder-location.js +1 -4
  93. package/dist/edge/http/fonts.js +0 -7
  94. package/dist/edge/http/home.js +47 -14
  95. package/dist/edge/http/host-cli.js +18 -8
  96. package/dist/edge/http/ids.js +8 -0
  97. package/dist/edge/http/keywords.js +35 -0
  98. package/dist/edge/http/model-checks.js +132 -0
  99. package/dist/edge/http/narration-peaks.js +5 -13
  100. package/dist/edge/http/onboarding.js +30 -26
  101. package/dist/edge/http/open-folder.js +5 -10
  102. package/dist/edge/http/outputs.js +7 -14
  103. package/dist/edge/http/patch-notes.js +6 -12
  104. package/dist/edge/http/planning.js +3 -7
  105. package/dist/edge/http/problem.js +2 -4
  106. package/dist/edge/http/project-create.js +2 -1
  107. package/dist/edge/http/project-templates.js +31 -19
  108. package/dist/edge/http/projects.js +24 -16
  109. package/dist/edge/http/prompts.js +9 -16
  110. package/dist/edge/http/pronunciations.js +1 -2
  111. package/dist/edge/http/providers.js +48 -34
  112. package/dist/edge/http/refusal.js +29 -0
  113. package/dist/edge/http/remote-access.js +40 -0
  114. package/dist/edge/http/remote-guard.js +71 -0
  115. package/dist/edge/http/request-guard.js +91 -0
  116. package/dist/edge/http/reviews.js +12 -25
  117. package/dist/edge/http/revision-files.js +6 -11
  118. package/dist/edge/http/revisions.js +14 -19
  119. package/dist/edge/http/run-cost.js +1 -2
  120. package/dist/edge/http/same-page.js +80 -0
  121. package/dist/edge/http/schedules.js +69 -40
  122. package/dist/edge/http/settings.js +27 -14
  123. package/dist/edge/http/social.js +283 -0
  124. package/dist/edge/http/staging.js +3 -5
  125. package/dist/edge/http/storage-files.js +5 -7
  126. package/dist/edge/http/storage.js +33 -25
  127. package/dist/edge/http/studio.js +94 -69
  128. package/dist/edge/http/style-preview.js +3 -6
  129. package/dist/edge/http/subtitles.js +3 -17
  130. package/dist/edge/http/template-studio.js +436 -0
  131. package/dist/edge/http/trash.js +11 -12
  132. package/dist/edge/http/tutorial.js +1 -2
  133. package/dist/edge/http/tutorials.js +5 -11
  134. package/dist/edge/http/update.js +7 -13
  135. package/dist/edge/http/waveform.js +3 -6
  136. package/dist/edge/http/youtube-edits.js +3 -4
  137. package/dist/edge/mcp/assistant.js +279 -0
  138. package/dist/edge/mcp/attribution.js +8 -2
  139. package/dist/edge/mcp/call-route.js +11 -2
  140. package/dist/edge/mcp/excluded-routes.js +29 -3
  141. package/dist/edge/mcp/http.js +11 -2
  142. package/dist/edge/mcp/instructions.js +6 -4
  143. package/dist/edge/mcp/library-tools.js +9 -5
  144. package/dist/edge/mcp/remake-tools.js +7 -4
  145. package/dist/edge/mcp/route-tool.js +35 -15
  146. package/dist/edge/mcp/server.js +13 -8
  147. package/dist/edge/mcp/tools-channels.js +11 -9
  148. package/dist/edge/mcp/tools-designs.js +165 -0
  149. package/dist/edge/mcp/tools-library.js +19 -7
  150. package/dist/edge/mcp/tools-planning.js +40 -21
  151. package/dist/edge/mcp/tools-projects.js +38 -11
  152. package/dist/edge/mcp/tools-publishing.js +9 -9
  153. package/dist/edge/mcp/tools-runs.js +23 -10
  154. package/dist/edge/mcp/tools-schedules.js +32 -8
  155. package/dist/edge/mcp/tools-setup.js +75 -11
  156. package/dist/edge/mcp/tools-social.js +47 -0
  157. package/dist/edge/mcp/tools-storage.js +11 -3
  158. package/dist/edge/mcp/tools-template-studio.js +166 -0
  159. package/dist/edge/mcp/tools.js +6 -0
  160. package/dist/edge/remote-access/cli.js +71 -0
  161. package/dist/edge/remote-access/model.js +32 -0
  162. package/dist/edge/remote-access/rules.js +207 -0
  163. package/dist/edge/remote-access/service.js +203 -0
  164. package/dist/edge/remote-access/store.js +44 -0
  165. package/dist/edge/remote-access/views.js +43 -0
  166. package/dist/extension/slopify-studio-chrome.zip +0 -0
  167. package/dist/extension/slopify-studio-firefox.zip +0 -0
  168. package/dist/host-cli/install.js +2 -2
  169. package/dist/host-cli/open-folder.js +2 -2
  170. package/dist/host-cli/paths.js +2 -4
  171. package/dist/host-cli/server.js +4 -4
  172. package/dist/host-cli/service.js +3 -3
  173. package/dist/host-cli/status.js +7 -7
  174. package/dist/kernel/db/migrations/0063-model-checks.sql +20 -0
  175. package/dist/kernel/db/migrations/0064-template-studio.sql +46 -0
  176. package/dist/kernel/db/migrations/0065-promise-and-assistant-reviews.sql +58 -0
  177. package/dist/kernel/db/migrations/0066-assistant.sql +44 -0
  178. package/dist/kernel/db/migrations/0067-autopilot.sql +6 -0
  179. package/dist/kernel/db/migrations/0068-topic-scores.sql +17 -0
  180. package/dist/kernel/db/migrations/0070-designs.sql +53 -0
  181. package/dist/kernel/db/migrations/0071-design-usage.sql +33 -0
  182. package/dist/kernel/db/migrations/0072-design-templates.sql +33 -0
  183. package/dist/kernel/db/migrations/0073-schedule-design-kind.sql +5 -0
  184. package/dist/kernel/db/migrations/0074-template-bakeoffs.sql +44 -0
  185. package/dist/kernel/db/migrations/0075-social-posts.sql +25 -0
  186. package/dist/kernel/db/migrations/0076-channel-social.sql +5 -0
  187. package/dist/kernel/db/migrations/0077-post-prompts.sql +17 -0
  188. package/dist/kernel/db/migrations/0078-uploaded-from-links.sql +7 -0
  189. package/dist/kernel/db/tx.js +2 -4
  190. package/dist/kernel/errors.js +27 -1
  191. package/dist/kernel/json-answer.js +15 -0
  192. package/dist/kernel/lock.js +4 -9
  193. package/dist/kernel/paths.js +8 -0
  194. package/dist/kernel/pipeline.js +12 -0
  195. package/dist/kernel/ports/assistant-cli.js +4 -0
  196. package/dist/kernel/ports/host-cli.js +3 -0
  197. package/dist/kernel/ports/interest.js +4 -0
  198. package/dist/kernel/ports/languages.js +0 -3
  199. package/dist/kernel/ports/model.js +2 -0
  200. package/dist/kernel/ports/settings-places.js +31 -0
  201. package/dist/kernel/ports/system-speech.js +31 -3
  202. package/dist/kernel/runner/attempt.js +14 -4
  203. package/dist/kernel/runner/audition.js +3 -1
  204. package/dist/kernel/runner/checkpoint-authority.js +2 -1
  205. package/dist/kernel/runner/index.js +8 -10
  206. package/dist/kernel/runner/model-access.js +40 -0
  207. package/dist/kernel/runner/model-check.js +153 -0
  208. package/dist/kernel/runner/providers.js +18 -12
  209. package/dist/kernel/runner/standalone.js +11 -7
  210. package/dist/main.js +338 -21
  211. package/dist/model-catalog.js +20 -0
  212. package/dist/model-checks.js +166 -0
  213. package/dist/patch-notes/4.0.0.md +51 -0
  214. package/dist/patch-notes/4.1.0.md +42 -0
  215. package/dist/patch-notes/index.json +12 -0
  216. package/dist/slices/admission/heads.js +2 -1
  217. package/dist/slices/admission/listing-facts.js +95 -0
  218. package/dist/slices/admission/repo.js +11 -7
  219. package/dist/slices/admission/rules.js +50 -15
  220. package/dist/slices/admission/schema.js +8 -0
  221. package/dist/slices/admission/stage-writes.js +0 -3
  222. package/dist/slices/admission/start.js +48 -31
  223. package/dist/slices/admission/state-words.js +34 -5
  224. package/dist/slices/admission/substitute.js +7 -4
  225. package/dist/slices/agents/attention-posts.js +31 -0
  226. package/dist/slices/agents/attention-templates.js +33 -0
  227. package/dist/slices/agents/attention.js +10 -1
  228. package/dist/slices/agents/connection.js +2 -6
  229. package/dist/slices/agents/model.js +6 -3
  230. package/dist/slices/agents/repo.js +15 -7
  231. package/dist/slices/article/continuation.js +0 -63
  232. package/dist/slices/article/plain.js +3 -2
  233. package/dist/slices/article/segments.js +2 -62
  234. package/dist/slices/assistant/access.js +1 -0
  235. package/dist/slices/assistant/asks.js +80 -0
  236. package/dist/slices/assistant/cost.js +54 -0
  237. package/dist/slices/assistant/gate.js +222 -0
  238. package/dist/slices/assistant/model.js +86 -0
  239. package/dist/slices/assistant/names.js +23 -0
  240. package/dist/slices/assistant/prompt.js +74 -0
  241. package/dist/slices/assistant/repo.js +74 -0
  242. package/dist/slices/assistant/tokens.js +18 -0
  243. package/dist/slices/assistant/turn.js +344 -0
  244. package/dist/slices/autopilot/buffer.js +76 -0
  245. package/dist/slices/autopilot/model.js +14 -0
  246. package/dist/slices/autopilot/notify.js +27 -0
  247. package/dist/slices/autopilot/repo.js +34 -0
  248. package/dist/slices/autopilot/signals.js +194 -0
  249. package/dist/slices/autopilot/warnings.js +85 -0
  250. package/dist/slices/autopilot/weekly.js +100 -0
  251. package/dist/slices/backups/files.js +2 -6
  252. package/dist/slices/backups/repo.js +3 -15
  253. package/dist/slices/backups/service.js +8 -7
  254. package/dist/slices/channels/cast-images.js +3 -2
  255. package/dist/slices/channels/model.js +0 -1
  256. package/dist/slices/channels/rebrand.js +0 -3
  257. package/dist/slices/channels/repo.js +4 -0
  258. package/dist/slices/channels/schema.js +7 -1
  259. package/dist/slices/channels/service.js +10 -0
  260. package/dist/slices/channels/videos.js +3 -15
  261. package/dist/slices/checkpoints/index.js +0 -1
  262. package/dist/slices/control/providers.js +2 -28
  263. package/dist/slices/designs/artwork.js +66 -0
  264. package/dist/slices/designs/budget.js +23 -0
  265. package/dist/slices/designs/calls.js +124 -0
  266. package/dist/slices/designs/check-context.js +38 -0
  267. package/dist/slices/designs/check-text.js +43 -0
  268. package/dist/slices/designs/fields.js +88 -0
  269. package/dist/slices/designs/frames.js +34 -0
  270. package/dist/slices/designs/gate.js +130 -0
  271. package/dist/slices/designs/layout.js +293 -0
  272. package/dist/slices/designs/model.js +35 -0
  273. package/dist/slices/designs/pdf-job.js +23 -0
  274. package/dist/slices/designs/pdf-pages.js +30 -0
  275. package/dist/slices/designs/pdf-runner.js +68 -0
  276. package/dist/slices/designs/pdf-worker.js +24 -0
  277. package/dist/slices/designs/picture-size.js +79 -0
  278. package/dist/slices/designs/pictures.js +55 -0
  279. package/dist/slices/designs/quote.js +24 -0
  280. package/dist/slices/designs/render-args.js +36 -0
  281. package/dist/slices/designs/render-input.js +59 -0
  282. package/dist/slices/designs/render.js +215 -0
  283. package/dist/slices/designs/repo.js +101 -0
  284. package/dist/slices/designs/requests.js +80 -0
  285. package/dist/slices/designs/runner.js +239 -0
  286. package/dist/slices/designs/sample-repo.js +91 -0
  287. package/dist/slices/designs/sample.js +223 -0
  288. package/dist/slices/designs/schema.js +87 -0
  289. package/dist/slices/designs/sections.js +44 -0
  290. package/dist/slices/designs/service.js +233 -0
  291. package/dist/slices/designs/steps-repo.js +102 -0
  292. package/dist/slices/designs/studio-kind.js +39 -0
  293. package/dist/slices/designs/template-checks.js +44 -0
  294. package/dist/slices/designs/template-make.js +118 -0
  295. package/dist/slices/designs/templates.js +218 -0
  296. package/dist/slices/document/fonts.js +2 -1
  297. package/dist/slices/document/model.js +7 -4
  298. package/dist/slices/document/render.js +2 -1
  299. package/dist/slices/document/theme-schema.js +1 -1
  300. package/dist/slices/document/theme.js +49 -3
  301. package/dist/slices/episodes/summarize.js +6 -2
  302. package/dist/slices/estimate/index.js +72 -28
  303. package/dist/slices/estimate/requests.js +4 -4
  304. package/dist/slices/fixes/rules.js +3 -1
  305. package/dist/slices/fonts/catalog.js +5 -3
  306. package/dist/slices/fonts/coverage.js +2 -1
  307. package/dist/slices/fonts/discovery.js +3 -2
  308. package/dist/slices/fonts/files.js +2 -6
  309. package/dist/slices/fonts/index.js +0 -1
  310. package/dist/slices/fonts/sfnt.js +45 -10
  311. package/dist/slices/images/appearance.js +8 -16
  312. package/dist/slices/images/scenes.js +102 -28
  313. package/dist/slices/keywords/digest.js +85 -0
  314. package/dist/slices/keywords/facts.js +92 -0
  315. package/dist/slices/keywords/fill.js +80 -0
  316. package/dist/slices/keywords/model.js +75 -0
  317. package/dist/slices/keywords/rules.js +187 -0
  318. package/dist/slices/keywords/schema.js +28 -0
  319. package/dist/slices/keywords/specs.js +260 -0
  320. package/dist/slices/keywords/values.js +74 -0
  321. package/dist/slices/library/lint.js +29 -12
  322. package/dist/slices/library/model.js +2 -0
  323. package/dist/slices/library/photorealistic.js +4 -12
  324. package/dist/slices/library/rename.js +9 -7
  325. package/dist/slices/library/save.js +14 -10
  326. package/dist/slices/library/slots.js +37 -11
  327. package/dist/slices/library/transfer.js +5 -4
  328. package/dist/slices/library/used-by.js +25 -10
  329. package/dist/slices/loudness/loudnorm.js +53 -12
  330. package/dist/slices/loudness/model.js +3 -2
  331. package/dist/slices/loudness/sentence-level.js +2 -1
  332. package/dist/slices/model-checks/cost.js +61 -0
  333. package/dist/slices/model-checks/listing.js +124 -0
  334. package/dist/slices/model-checks/model.js +20 -0
  335. package/dist/slices/model-checks/record.js +32 -0
  336. package/dist/slices/model-checks/repo.js +120 -0
  337. package/dist/slices/model-checks/rules.js +125 -0
  338. package/dist/slices/model-checks/run.js +143 -0
  339. package/dist/slices/model-checks/service.js +198 -0
  340. package/dist/slices/model-upkeep/model.js +1 -1
  341. package/dist/slices/model-upkeep/switch.js +72 -27
  342. package/dist/slices/model-upkeep/usage.js +39 -13
  343. package/dist/slices/narration/breaths.js +3 -1
  344. package/dist/slices/narration/clean-pieces.js +3 -1
  345. package/dist/slices/narration/concat.js +2 -1
  346. package/dist/slices/narration/pauses-model.js +3 -2
  347. package/dist/slices/narration/peaks.js +3 -4
  348. package/dist/slices/narration/pronunciation-chunks.js +4 -3
  349. package/dist/slices/narration/pronunciation.js +6 -4
  350. package/dist/slices/narration/steering.js +4 -3
  351. package/dist/slices/notifications/notifier.js +4 -3
  352. package/dist/slices/notifications/rules.js +5 -2
  353. package/dist/slices/notifications/settings.js +4 -12
  354. package/dist/slices/notifications/subject.js +4 -3
  355. package/dist/slices/onboarding/copy.js +21 -3
  356. package/dist/slices/onboarding/first-run.js +16 -40
  357. package/dist/slices/onboarding/full-video.js +3 -2
  358. package/dist/slices/onboarding/install.js +6 -4
  359. package/dist/slices/onboarding/model.js +26 -37
  360. package/dist/slices/onboarding/packs.js +22 -22
  361. package/dist/slices/onboarding/preferred-model.js +14 -0
  362. package/dist/slices/onboarding/quick-short.js +105 -65
  363. package/dist/slices/onboarding/sample.js +4 -2
  364. package/dist/slices/onboarding/state.js +9 -11
  365. package/dist/slices/onboarding/template.js +8 -6
  366. package/dist/slices/outputs/add.js +3 -2
  367. package/dist/slices/outputs/service.js +2 -2
  368. package/dist/slices/patch-notes/library.js +4 -3
  369. package/dist/slices/play-drafts/convert.js +4 -0
  370. package/dist/slices/play-drafts/readiness.js +3 -3
  371. package/dist/slices/play-drafts/review-inputs.js +9 -3
  372. package/dist/slices/play-drafts/review.js +5 -4
  373. package/dist/slices/play-drafts/schema.js +4 -0
  374. package/dist/slices/play-drafts/service.js +17 -7
  375. package/dist/slices/project-templates/from-project.js +9 -2
  376. package/dist/slices/project-templates/next-chapter.js +2 -1
  377. package/dist/slices/project-templates/provider-defaults.js +22 -0
  378. package/dist/slices/project-templates/repo.js +6 -1
  379. package/dist/slices/project-templates/setup-sections.js +26 -0
  380. package/dist/slices/project-templates/setup.js +14 -1
  381. package/dist/slices/project-templates/stand-ins.js +22 -0
  382. package/dist/slices/rebuild/activity.js +2 -0
  383. package/dist/slices/rebuild/admission-repo.js +3 -2
  384. package/dist/slices/rebuild/narration-history.js +4 -5
  385. package/dist/slices/rebuild/narration-retry.js +2 -1
  386. package/dist/slices/rebuild/preview-details.js +32 -14
  387. package/dist/slices/rebuild/preview-plan.js +3 -8
  388. package/dist/slices/rebuild/recipe-build.js +8 -3
  389. package/dist/slices/rebuild/recipe-describe.js +3 -3
  390. package/dist/slices/rebuild/recipe-digest.js +58 -0
  391. package/dist/slices/rebuild/recipe-input-schema.js +10 -0
  392. package/dist/slices/rebuild/recipe-keywords.js +71 -0
  393. package/dist/slices/rebuild/recipe-legacy.js +5 -1
  394. package/dist/slices/rebuild/recipe-model.js +4 -0
  395. package/dist/slices/rebuild/recipe-narration-text.js +2 -1
  396. package/dist/slices/rebuild/recipe-preparation.js +4 -4
  397. package/dist/slices/rebuild/recipe-reference.js +8 -4
  398. package/dist/slices/rebuild/recipe-reviews.js +27 -7
  399. package/dist/slices/rebuild/recipe-save.js +8 -5
  400. package/dist/slices/rebuild/recipe-scenes.js +40 -11
  401. package/dist/slices/rebuild/recipe-shorts.js +8 -8
  402. package/dist/slices/rebuild/recipe-social.js +46 -0
  403. package/dist/slices/rebuild/recipe-text.js +64 -20
  404. package/dist/slices/rebuild/recipe-validation.js +102 -31
  405. package/dist/slices/rebuild/recipe-visual.js +55 -16
  406. package/dist/slices/rebuild/recipe-voices.js +3 -2
  407. package/dist/slices/rebuild/recipe-work.js +19 -7
  408. package/dist/slices/rebuild/recipe-youtube.js +4 -3
  409. package/dist/slices/rebuild/recovery-selection.js +3 -1
  410. package/dist/slices/rebuild/recovery.js +9 -8
  411. package/dist/slices/rebuild/remake-outdated.js +5 -5
  412. package/dist/slices/rebuild/repo.js +4 -3
  413. package/dist/slices/rebuild/review-promise.js +25 -0
  414. package/dist/slices/rebuild/review-redo.js +3 -2
  415. package/dist/slices/rebuild/runtime-admission.js +4 -3
  416. package/dist/slices/rebuild/runtime-agent-review.js +11 -5
  417. package/dist/slices/rebuild/runtime-animate.js +10 -9
  418. package/dist/slices/rebuild/runtime-article.js +7 -5
  419. package/dist/slices/rebuild/runtime-checkpoints.js +5 -4
  420. package/dist/slices/rebuild/runtime-document.js +11 -13
  421. package/dist/slices/rebuild/runtime-export-bed.js +8 -12
  422. package/dist/slices/rebuild/runtime-export-edit.js +8 -16
  423. package/dist/slices/rebuild/runtime-export-inputs.js +12 -11
  424. package/dist/slices/rebuild/runtime-export-short.js +9 -5
  425. package/dist/slices/rebuild/runtime-export.js +38 -15
  426. package/dist/slices/rebuild/runtime-figure-card.js +2 -1
  427. package/dist/slices/rebuild/runtime-image.js +8 -12
  428. package/dist/slices/rebuild/runtime-instructions.js +2 -0
  429. package/dist/slices/rebuild/runtime-keywords.js +59 -0
  430. package/dist/slices/rebuild/runtime-lines.js +2 -11
  431. package/dist/slices/rebuild/runtime-local.js +17 -22
  432. package/dist/slices/rebuild/runtime-narration-publication.js +2 -5
  433. package/dist/slices/rebuild/runtime-narration-reuse.js +9 -13
  434. package/dist/slices/rebuild/runtime-narration-text.js +13 -17
  435. package/dist/slices/rebuild/runtime-pictures.js +2 -4
  436. package/dist/slices/rebuild/runtime-piece-label.js +10 -6
  437. package/dist/slices/rebuild/runtime-plan.js +31 -5
  438. package/dist/slices/rebuild/runtime-provider.js +67 -25
  439. package/dist/slices/rebuild/runtime-publication.js +10 -9
  440. package/dist/slices/rebuild/runtime-review.js +39 -33
  441. package/dist/slices/rebuild/runtime-run.js +4 -1
  442. package/dist/slices/rebuild/runtime-shorts.js +31 -50
  443. package/dist/slices/rebuild/runtime-store.js +20 -10
  444. package/dist/slices/rebuild/runtime-subtitles.js +28 -25
  445. package/dist/slices/rebuild/runtime-voices.js +10 -16
  446. package/dist/slices/rebuild/runtime-youtube.js +14 -31
  447. package/dist/slices/rebuild/service-readiness.js +11 -3
  448. package/dist/slices/rebuild/transition-repo.js +6 -5
  449. package/dist/slices/rebuild/work-records.js +6 -0
  450. package/dist/slices/reruns/cascade.js +1 -2
  451. package/dist/slices/reruns/index.js +6 -9
  452. package/dist/slices/research/synthesis.js +3 -2
  453. package/dist/slices/reviews/external-model.js +4 -1
  454. package/dist/slices/reviews/external-repo.js +2 -1
  455. package/dist/slices/reviews/external-rows.js +2 -3
  456. package/dist/slices/reviews/holds.js +5 -4
  457. package/dist/slices/reviews/model.js +32 -11
  458. package/dist/slices/reviews/repo.js +2 -1
  459. package/dist/slices/reviews/rules.js +4 -3
  460. package/dist/slices/reviews/verdict.js +2 -1
  461. package/dist/slices/reviews/view.js +5 -2
  462. package/dist/slices/revisions/downloads.js +4 -5
  463. package/dist/slices/revisions/image-plan.js +1 -1
  464. package/dist/slices/revisions/mutation-assets.js +9 -5
  465. package/dist/slices/revisions/mutation-cues.js +2 -5
  466. package/dist/slices/revisions/mutations.js +3 -3
  467. package/dist/slices/revisions/repo.js +3 -1
  468. package/dist/slices/revisions/schema.js +1 -0
  469. package/dist/slices/revisions/view.js +20 -0
  470. package/dist/slices/run-cost/limits.js +5 -2
  471. package/dist/slices/run-cost/meter.js +12 -5
  472. package/dist/slices/run-cost/panel.js +8 -74
  473. package/dist/slices/run-cost/plan-readings.js +127 -0
  474. package/dist/slices/run-cost/plan-use.js +169 -0
  475. package/dist/slices/run-cost/pricing.js +3 -3
  476. package/dist/slices/run-cost/week.js +32 -4
  477. package/dist/slices/schedules/agenda.js +18 -7
  478. package/dist/slices/schedules/by-date.js +42 -0
  479. package/dist/slices/schedules/calendar.js +5 -0
  480. package/dist/slices/schedules/design-agenda.js +36 -0
  481. package/dist/slices/schedules/design-check.js +41 -0
  482. package/dist/slices/schedules/design-run.js +126 -0
  483. package/dist/slices/schedules/next-run.js +62 -0
  484. package/dist/slices/schedules/prepare.js +18 -2
  485. package/dist/slices/schedules/repo.js +30 -21
  486. package/dist/slices/schedules/rescore.js +35 -0
  487. package/dist/slices/schedules/scheduler.js +13 -3
  488. package/dist/slices/schedules/schema.js +57 -3
  489. package/dist/slices/schedules/score.js +107 -0
  490. package/dist/slices/schedules/service.js +57 -24
  491. package/dist/slices/schedules/topic-list.js +15 -0
  492. package/dist/slices/schedules/topic-scores.js +104 -0
  493. package/dist/slices/schedules/topics.js +53 -41
  494. package/dist/slices/settings/cli-paths.js +4 -6
  495. package/dist/slices/settings/first-run.js +8 -43
  496. package/dist/slices/settings/health.js +30 -15
  497. package/dist/slices/settings/key-test.js +1 -1
  498. package/dist/slices/settings/model-reach.js +3 -17
  499. package/dist/slices/settings/model.js +14 -2
  500. package/dist/slices/settings/playback.js +34 -23
  501. package/dist/slices/settings/probe-read.js +16 -0
  502. package/dist/slices/settings/repo.js +33 -0
  503. package/dist/slices/settings/tutorial.js +2 -2
  504. package/dist/slices/settings/voices.js +4 -12
  505. package/dist/slices/shorts/keep.js +2 -1
  506. package/dist/slices/shorts/pick.js +6 -18
  507. package/dist/slices/shorts/prompts.js +4 -14
  508. package/dist/slices/shorts/render.js +6 -2
  509. package/dist/slices/social/channel.js +44 -0
  510. package/dist/slices/social/defaults.js +17 -0
  511. package/dist/slices/social/due.js +36 -0
  512. package/dist/slices/social/extension.js +18 -0
  513. package/dist/slices/social/fit.js +115 -0
  514. package/dist/slices/social/limits.js +186 -0
  515. package/dist/slices/social/links.js +21 -0
  516. package/dist/slices/social/media.js +132 -0
  517. package/dist/slices/social/model.js +75 -0
  518. package/dist/slices/social/notice.js +19 -0
  519. package/dist/slices/social/pack.js +176 -0
  520. package/dist/slices/social/post-prompt.js +56 -0
  521. package/dist/slices/social/queue.js +31 -0
  522. package/dist/slices/social/repo.js +133 -0
  523. package/dist/slices/social/reshape.js +97 -0
  524. package/dist/slices/social/rules.js +5 -0
  525. package/dist/slices/social/schema.js +70 -0
  526. package/dist/slices/social/serve.js +51 -0
  527. package/dist/slices/social/service.js +129 -0
  528. package/dist/slices/social/settings.js +21 -0
  529. package/dist/slices/social/sources.js +114 -0
  530. package/dist/slices/social/state.js +110 -0
  531. package/dist/slices/social/text.js +149 -0
  532. package/dist/slices/storage/arrange.js +3 -1
  533. package/dist/slices/storage/assets.js +8 -10
  534. package/dist/slices/storage/backup-designs.js +74 -0
  535. package/dist/slices/storage/backup-export.js +8 -3
  536. package/dist/slices/storage/backup-format.js +10 -0
  537. package/dist/slices/storage/backup-import.js +22 -4
  538. package/dist/slices/storage/delete-project.js +6 -5
  539. package/dist/slices/storage/files-location.js +6 -8
  540. package/dist/slices/storage/layout.js +13 -2
  541. package/dist/slices/storage/model.js +3 -0
  542. package/dist/slices/storage/portable.js +17 -12
  543. package/dist/slices/storage/schema.js +2 -0
  544. package/dist/slices/storage/staging-refs.js +2 -1
  545. package/dist/slices/storage/staging.js +6 -9
  546. package/dist/slices/storage/trim.js +26 -9
  547. package/dist/slices/studio/calendar.js +7 -2
  548. package/dist/slices/studio/disclosure.js +4 -4
  549. package/dist/slices/studio/model.js +1 -1
  550. package/dist/slices/studio/pack.js +9 -8
  551. package/dist/slices/studio/pick.js +2 -11
  552. package/dist/slices/studio/plan.js +7 -16
  553. package/dist/slices/studio/queue.js +3 -14
  554. package/dist/slices/studio/releases.js +26 -0
  555. package/dist/slices/studio/settings.js +20 -57
  556. package/dist/slices/studio/videos.js +35 -4
  557. package/dist/slices/style-preview/render.js +37 -16
  558. package/dist/slices/style-preview/schema.js +14 -1
  559. package/dist/slices/style-preview/service.js +2 -1
  560. package/dist/slices/style-preview/settings.js +33 -5
  561. package/dist/slices/subtitles/captions.js +1 -1
  562. package/dist/slices/telemetry/collector-client.js +2 -4
  563. package/dist/slices/telemetry/flush.js +2 -4
  564. package/dist/slices/telemetry/model.js +0 -7
  565. package/dist/slices/telemetry/record.js +10 -3
  566. package/dist/slices/template-studio/anatomy-view.js +161 -0
  567. package/dist/slices/template-studio/anatomy.js +73 -0
  568. package/dist/slices/template-studio/bakeoff-make.js +225 -0
  569. package/dist/slices/template-studio/bakeoff-repo.js +83 -0
  570. package/dist/slices/template-studio/bakeoff.js +333 -0
  571. package/dist/slices/template-studio/budget.js +106 -0
  572. package/dist/slices/template-studio/cards.js +78 -0
  573. package/dist/slices/template-studio/checks.js +322 -0
  574. package/dist/slices/template-studio/document-sample.js +56 -0
  575. package/dist/slices/template-studio/edit.js +15 -0
  576. package/dist/slices/template-studio/for-all.js +161 -0
  577. package/dist/slices/template-studio/free-video.js +31 -0
  578. package/dist/slices/template-studio/free.js +176 -0
  579. package/dist/slices/template-studio/gate.js +40 -0
  580. package/dist/slices/template-studio/hidden.js +20 -0
  581. package/dist/slices/template-studio/jobs.js +79 -0
  582. package/dist/slices/template-studio/loudness.js +111 -0
  583. package/dist/slices/template-studio/make.js +40 -0
  584. package/dist/slices/template-studio/model.js +58 -0
  585. package/dist/slices/template-studio/pack-import.js +253 -0
  586. package/dist/slices/template-studio/pack-samples.js +60 -0
  587. package/dist/slices/template-studio/pack.js +207 -0
  588. package/dist/slices/template-studio/paid-view.js +66 -0
  589. package/dist/slices/template-studio/paid.js +355 -0
  590. package/dist/slices/template-studio/quote.js +155 -0
  591. package/dist/slices/template-studio/ready.js +104 -0
  592. package/dist/slices/template-studio/repo.js +134 -0
  593. package/dist/slices/template-studio/reviews-path.js +58 -0
  594. package/dist/slices/template-studio/runner.js +84 -0
  595. package/dist/slices/template-studio/save.js +236 -0
  596. package/dist/slices/template-studio/say-it-as.js +248 -0
  597. package/dist/slices/template-studio/schedule-gate.js +34 -0
  598. package/dist/slices/template-studio/schedule-price.js +32 -0
  599. package/dist/slices/template-studio/schedule-sample.js +91 -0
  600. package/dist/slices/template-studio/schema.js +243 -0
  601. package/dist/slices/template-studio/scope.js +124 -0
  602. package/dist/slices/template-studio/sections.js +176 -0
  603. package/dist/slices/template-studio/service.js +175 -0
  604. package/dist/slices/template-studio/status.js +191 -0
  605. package/dist/slices/template-studio/topic.js +223 -0
  606. package/dist/slices/thumbnail/by-llm.js +1 -1
  607. package/dist/slices/trash/designs.js +76 -0
  608. package/dist/slices/trash/model.js +13 -4
  609. package/dist/slices/trash/service.js +52 -2
  610. package/dist/slices/tutorials/library.js +3 -2
  611. package/dist/slices/uploads/repo.js +37 -1
  612. package/dist/slices/uploads/rules.js +3 -2
  613. package/dist/slices/video/ass-text.js +17 -0
  614. package/dist/slices/video/audio-export.js +2 -64
  615. package/dist/slices/video/edit-list.js +2 -2
  616. package/dist/slices/video/edit-settings.js +1 -1
  617. package/dist/slices/video/encoding.js +169 -0
  618. package/dist/slices/video/ffmpeg.js +23 -21
  619. package/dist/slices/video/figure-card.js +1 -15
  620. package/dist/slices/video/plan.js +2 -1
  621. package/dist/slices/video/slideshow.js +43 -18
  622. package/dist/slices/voices/attribution.js +3 -2
  623. package/dist/slices/voices/model.js +9 -8
  624. package/dist/slices/voices/palette.js +0 -3
  625. package/dist/slices/voices/script.js +2 -1
  626. package/dist/slices/youtube/answer.js +4 -16
  627. package/dist/slices/youtube/edits-repo.js +3 -12
  628. package/dist/tutorials/AI-CLIs.md +25 -25
  629. package/dist/tutorials/Agents-MCP.md +34 -33
  630. package/dist/tutorials/Assistant.md +42 -0
  631. package/dist/tutorials/Backups.md +7 -7
  632. package/dist/tutorials/Calendar.md +17 -25
  633. package/dist/tutorials/Cast-Library.md +19 -19
  634. package/dist/tutorials/Channels.md +42 -35
  635. package/dist/tutorials/Costs-and-Run-Cost.md +38 -40
  636. package/dist/tutorials/Create-Article.md +114 -0
  637. package/dist/tutorials/Create-Extras.md +112 -0
  638. package/dist/tutorials/Create-Images.md +165 -0
  639. package/dist/tutorials/Create-Narration.md +178 -0
  640. package/dist/tutorials/Create-Overview.md +244 -0
  641. package/dist/tutorials/Create-Video-and-Style.md +144 -0
  642. package/dist/tutorials/Docker.md +3 -3
  643. package/dist/tutorials/Document-Themes.md +32 -32
  644. package/dist/tutorials/Editing-a-Project.md +94 -94
  645. package/dist/tutorials/FAQ.md +18 -18
  646. package/dist/tutorials/First-Launch-and-Welcome.md +50 -64
  647. package/dist/tutorials/Home-and-Projects.md +115 -71
  648. package/dist/tutorials/Home.md +33 -33
  649. package/dist/tutorials/Install.md +14 -13
  650. package/dist/tutorials/Intros-and-Outros.md +33 -34
  651. package/dist/tutorials/Keyboard-Shortcuts-and-Command-Palette.md +62 -58
  652. package/dist/tutorials/Keywords-Slopify-Fills.md +87 -0
  653. package/dist/tutorials/Models.md +53 -21
  654. package/dist/tutorials/Multiple-Voices.md +41 -40
  655. package/dist/tutorials/Narration-Aliases-and-Glossary.md +14 -14
  656. package/dist/tutorials/Notifications.md +27 -17
  657. package/dist/tutorials/Other-Languages.md +15 -15
  658. package/dist/tutorials/PDF-Documents.md +38 -29
  659. package/dist/tutorials/Posting-to-Social-Sites.md +121 -0
  660. package/dist/tutorials/Project-Page.md +118 -120
  661. package/dist/tutorials/Prompts-and-Templates.md +84 -0
  662. package/dist/tutorials/Prompts.md +48 -44
  663. package/dist/tutorials/Providers-and-Keys.md +105 -98
  664. package/dist/tutorials/Publishing-to-YouTube.md +31 -31
  665. package/dist/tutorials/Recovery-and-Retries.md +31 -31
  666. package/dist/tutorials/Remote-Access.md +63 -0
  667. package/dist/tutorials/Reviews-and-Checkpoints.md +98 -90
  668. package/dist/tutorials/Schedules.md +46 -27
  669. package/dist/tutorials/Settings-Reference.md +194 -174
  670. package/dist/tutorials/Shorts.md +34 -33
  671. package/dist/tutorials/Start-at-Login.md +3 -3
  672. package/dist/tutorials/Studio-Extension.md +22 -24
  673. package/dist/tutorials/Template-Studio.md +128 -0
  674. package/dist/tutorials/Templates.md +51 -77
  675. package/dist/tutorials/Trash.md +4 -4
  676. package/dist/tutorials/Troubleshooting.md +44 -44
  677. package/dist/tutorials/Uninstalling-and-Moving.md +5 -5
  678. package/dist/tutorials/Updating-and-Patch-Notes.md +18 -18
  679. package/dist/tutorials/Video-Editing.md +34 -34
  680. package/dist/tutorials/Where-Your-Files-Live.md +10 -10
  681. package/dist/tutorials/YouTube-Description.md +26 -26
  682. package/dist/tutorials/Your-First-Short.md +35 -35
  683. package/dist/tutorials/_Sidebar.md +19 -14
  684. package/dist/updater/work-in-progress.js +42 -12
  685. package/dist/web/assets/index-BNftKQrA.css +1 -0
  686. package/dist/web/assets/index-Cpa58woP.js +459 -0
  687. package/dist/web/assets/pdf-BKh8f7R6.js +56 -0
  688. package/dist/web/assets/pdf.worker.min-BmVo14Nb.mjs +28 -0
  689. package/dist/web/assets/pdf.worker.min-D7i8o3wR.js +1 -0
  690. package/dist/web/index.html +2 -2
  691. package/package.json +6 -2
  692. package/dist/slices/article/provided-entries.js +0 -66
  693. package/dist/slices/article/run.js +0 -145
  694. package/dist/slices/images/run.js +0 -234
  695. package/dist/slices/narration/legacy-plan.js +0 -58
  696. package/dist/slices/narration/run.js +0 -270
  697. package/dist/slices/rebuild/runtime-actions.js +0 -90
  698. package/dist/slices/research/run.js +0 -224
  699. package/dist/slices/subtitles/prepare.js +0 -194
  700. package/dist/slices/subtitles/transcript.js +0 -34
  701. package/dist/slices/thumbnail/run.js +0 -219
  702. package/dist/slices/video/audio-inputs.js +0 -33
  703. package/dist/slices/video/reuse-audio.js +0 -62
  704. package/dist/slices/video/run.js +0 -78
  705. package/dist/slices/video/write-export.js +0 -158
  706. package/dist/slices/video/write-subtitles.js +0 -59
  707. package/dist/tutorials/Library-Overview.md +0 -76
  708. package/dist/tutorials/Play-Images.md +0 -161
  709. package/dist/tutorials/Play-Narration.md +0 -167
  710. package/dist/tutorials/Play-Outputs.md +0 -109
  711. package/dist/tutorials/Play-Overview.md +0 -227
  712. package/dist/tutorials/Play-Title-and-Article.md +0 -136
  713. package/dist/tutorials/Play-Video-and-Style.md +0 -143
  714. package/dist/web/assets/index-BadsoORk.css +0 -1
  715. package/dist/web/assets/index-D8LqNsCl.js +0 -326
  716. package/dist/web/assets/pdf-T7MCwjIv.js +0 -54
  717. package/dist/web/assets/pdf.worker.min-Dswkl-cV.mjs +0 -29
  718. package/dist/web/assets/pdf.worker.min-zC6nfbxG.js +0 -1
@@ -0,0 +1,166 @@
1
+ import { keyProbes } from "./adapters/key-probes.js";
2
+ import { emptyLifecycle, retirementOf } from "./catalog/lifecycle.js";
3
+ import { thinkingModes } from "./kernel/ports/llm.js";
4
+ import { readinessIsUsable } from "./kernel/ports/model.js";
5
+ import { checkModel } from "./kernel/runner/model-check.js";
6
+ import { modelSources } from "./model-catalog.js";
7
+ import { isVideoTarget, spentOn } from "./slices/model-checks/cost.js";
8
+ import { createListing } from "./slices/model-checks/listing.js";
9
+ import { createModelChecks } from "./slices/model-checks/service.js";
10
+ import { isLocalCliProvider, systemVoiceProvider, } from "./slices/settings/model.js";
11
+ import { listVoices } from "./slices/settings/repo.js";
12
+ // The composition layer's check recipes: what the smallest request is for each kind of model.
13
+ // A reply of one word at the lowest thinking setting, a voice saying "Hi", a one-to-one grey
14
+ // dot. Image-to-video models are listed only, never generated.
15
+ export const checkPrompt = "Reply with OK.";
16
+ export const checkSpeech = "Hi";
17
+ export const checkPicture = "a small grey dot";
18
+ // A voice every account of these providers has, for a check made before any voice is saved.
19
+ const defaultVoices = {
20
+ "openai-tts": "alloy",
21
+ "google-tts": "Kore",
22
+ // ElevenLabs' premade "Rachel".
23
+ elevenlabs: "21m00Tcm4TlvDq8ikWAM",
24
+ };
25
+ function lowest(modes) {
26
+ if (modes === undefined || modes.length === 0)
27
+ return undefined;
28
+ return thinkingModes.find((mode) => modes.includes(mode));
29
+ }
30
+ export async function recipeFor(deps, target) {
31
+ const catalogue = deps.catalogue();
32
+ const { provider, model } = target;
33
+ if (target.family === "llm") {
34
+ let modes;
35
+ if (isLocalCliProvider(provider))
36
+ modes = (await deps.cliModels(provider, "llm").catch(() => [])).find((m) => m.id === model)?.thinkingModes;
37
+ else {
38
+ const row = catalogue.llm.find((m) => m.provider === provider && m.id === model);
39
+ modes = row?.llm.thinking === undefined ? undefined : Object.keys(row.llm.thinking);
40
+ }
41
+ const thinking = lowest(modes);
42
+ return {
43
+ kind: "call",
44
+ call: {
45
+ kind: "llm",
46
+ provider,
47
+ model,
48
+ prompt: checkPrompt,
49
+ ...(thinking === undefined ? {} : { thinking }),
50
+ },
51
+ };
52
+ }
53
+ if (target.family === "tts") {
54
+ if (provider === systemVoiceProvider)
55
+ return (await deps.systemVoiceReady())
56
+ ? { kind: "free-works" }
57
+ : { kind: "skip", reason: "No speech program was found on this computer." };
58
+ const voiceId = deps.voices().find((voice) => voice.provider === provider)?.voiceId ??
59
+ (Object.hasOwn(defaultVoices, provider) ? defaultVoices[provider] : undefined);
60
+ if (voiceId === undefined)
61
+ return {
62
+ kind: "skip",
63
+ reason: "Add a voice for this provider in Settings → Voices, then choose Check models.",
64
+ };
65
+ return { kind: "call", call: { kind: "tts", provider, model, voiceId, text: checkSpeech } };
66
+ }
67
+ if (isVideoTarget(catalogue, target))
68
+ return { kind: "skip", reason: "Image-to-video models are listed, never checked." };
69
+ const row = catalogue.image.find((m) => m.provider === provider && m.id === model);
70
+ const ratios = row?.image.aspectRatios ?? ["1:1"];
71
+ const aspect = ratios.includes("1:1") ? "1:1" : (ratios[0] ?? "1:1");
72
+ let thinking;
73
+ if (isLocalCliProvider(provider))
74
+ thinking = lowest((await deps.cliModels(provider, "image").catch(() => [])).find((m) => m.id === model)
75
+ ?.thinkingModes);
76
+ return {
77
+ kind: "call",
78
+ call: {
79
+ kind: "image",
80
+ provider,
81
+ model,
82
+ prompt: checkPicture,
83
+ aspect,
84
+ ...(thinking === undefined ? {} : { thinking }),
85
+ },
86
+ };
87
+ }
88
+ export function modelChecker(deps) {
89
+ return async (target, signal) => {
90
+ const recipe = await recipeFor(deps, target);
91
+ if (recipe.kind === "skip")
92
+ return { kind: "skipped", reason: recipe.reason };
93
+ if (recipe.kind === "free-works")
94
+ return { kind: "checked", verdict: "works", sentence: null, stopProvider: false, spent: 0 };
95
+ const answer = await checkModel(deps, recipe.call, signal);
96
+ return {
97
+ kind: "checked",
98
+ verdict: answer.verdict,
99
+ sentence: answer.sentence,
100
+ stopProvider: answer.stopProvider,
101
+ // A failure the provider may have billed is counted at the estimate the check showed.
102
+ spent: answer.verdict === "works"
103
+ ? spentOn(deps.catalogue(), target, answer.use)
104
+ : answer.mayHaveBilled
105
+ ? spentOn(deps.catalogue(), target, null)
106
+ : 0,
107
+ };
108
+ };
109
+ }
110
+ // The model-checks service as main.ts runs it: free listings from the providers' own model
111
+ // endpoints, and checks made through the recipes above.
112
+ export function wireModelChecks(deps) {
113
+ const { modelsFor } = modelSources(deps.registry);
114
+ const listing = createListing({
115
+ db: deps.db,
116
+ clock: deps.clock,
117
+ fetch: deps.fetch,
118
+ probes: keyProbes,
119
+ known: (provider, family) => deps
120
+ .catalogue()[family].filter((row) => row.provider === provider && row.enabled && !row.deprecated)
121
+ .map((row) => row.id),
122
+ cliModels: async (provider, family) => (await modelsFor(provider, family)).map((m) => m.id),
123
+ });
124
+ const checks = createModelChecks({
125
+ db: deps.db,
126
+ clock: deps.clock,
127
+ log: deps.log,
128
+ catalogue: deps.catalogue,
129
+ listing,
130
+ providerModels: modelsFor,
131
+ retiring: (model) => retirementOf(deps.lifecycle?.() ?? emptyLifecycle, deps.catalogue(), model),
132
+ check: modelChecker({
133
+ registry: deps.registry,
134
+ clock: deps.clock,
135
+ log: deps.log,
136
+ catalogue: deps.catalogue,
137
+ voices: () => listVoices(deps.db),
138
+ cliModels: modelsFor,
139
+ systemVoiceReady: async () => (await deps.statuses()).some((status) => status.id === systemVoiceProvider && readinessIsUsable(status.readiness)),
140
+ }),
141
+ });
142
+ return { checks, listing };
143
+ }
144
+ // A CLI that has become usable - installed and signed in - since the last look, or one that is
145
+ // usable and was never listed, is checked as if it had just been added.
146
+ export function cliWatcher(checks, statuses, known) {
147
+ const usable = new Map();
148
+ return async () => {
149
+ for (const status of await statuses()) {
150
+ if (status.readiness.kind !== "cli")
151
+ continue;
152
+ const now = readinessIsUsable(status.readiness);
153
+ const before = usable.get(status.id);
154
+ usable.set(status.id, now);
155
+ if (now && (before === false || (before === undefined && !known(status.id))))
156
+ await checks.automatic("cli-added", status.id);
157
+ }
158
+ };
159
+ }
160
+ // The hourly look. The weekly look goes first: it lists and checks every provider, a CLI
161
+ // among them, so a CLI it has just checked is known and isn't checked again as newly added.
162
+ export async function lookAtModels(checks, lookForClis) {
163
+ if (checks.weeklyDue())
164
+ await checks.automatic("weekly");
165
+ await lookForClis();
166
+ }
@@ -0,0 +1,51 @@
1
+ # Slopify 4.0.0
2
+
3
+ Released 18 October 2026.
4
+
5
+ ## Edit template
6
+
7
+ - **Set a template up once, with real samples.** Templates → **Edit template** shows a template section by section: Title and keywords, Article, Narration, Images, Video and style, Thumbnail, Shorts, PDF, Pauses and checks, YouTube description and posts, and Schedule. Each Save makes a short sample of the sections it changed with your own services. The sample is the opening of the article, about 30 seconds of narration, 4 images, a 30-second clip, a short, the PDF and the description, so you see and hear the result before a schedule uses it.
8
+ - Every paid Save shows its price on the button. A daily sample budget (Settings → Production defaults → Template samples, $2 by default) holds samples that would go over it. Claude Code and Codex plans are used only when you turn on "Let samples use my Claude Code or Codex plan".
9
+ - **Approve for schedules.** Once you approve a version in Edit template, schedules run the newest approved version and later edits wait until you approve them. Templates you never approve keep following their newest version, as before.
10
+ - **Compare models** makes one section's sample with 2–3 models side by side, with cost and time. **Say it as…** fixes a name the voice mispronounces. **Export as a file (.zip)** and **Import a template file (.zip)** share a template with its samples.
11
+ - Create opens on a template and a topic; **Make the video** starts it.
12
+
13
+ ## Posting to X, LinkedIn, Instagram, TikTok, Bluesky and Reddit
14
+
15
+ - **Copy for YouTube Studio** has a **Where** choice: YouTube plus each site the project posts to. Each post shows its text, its media in the site's shape, a live character count and plain warnings. Templates set the defaults in Edit template → YouTube description and posts.
16
+ - **Fill in <site>** opens the site and the Slopify Studio extension fills the post: text, media, the site's AI label, and its own scheduler where it has one (X, LinkedIn, TikTok). You press Post. On Instagram, Bluesky and Reddit, which have no scheduler, the extension fills the post at its release time and notifies you.
17
+ - The extension never presses Post, Share or Publish, and it only fills tabs Slopify opened. Allow each site in the extension's options with "Allow posting on …". Reddit has not been checked live yet.
18
+
19
+ ## Images and designed pieces
20
+
21
+ - **Edit a picture** you upload with an instruction, and keep editing the result. Every step is a version you can go back to.
22
+ - **Design posters and flyers.** The AI makes the artwork and Slopify sets the names, dates and prices in real fonts, so they are always spelled right. Download PNG or a print-ready PDF in A4, A3, A5 and social sizes. A design template with fields (event, date, venue…) makes a piece per row ahead of its date, or one at a time with Make a piece.
23
+
24
+ ## Keywords Slopify fills
25
+
26
+ - New built-in keywords such as {{Slopify_Title}}, {{Slopify_Summary}}, {{Slopify_Hook}}, {{Slopify_Chapters}}, {{Slopify_Setting}} and {{Slopify_Thumbnail_Text}}. The Insert bar above each prompt lists the ones that work there, with an example and what they cost. {{Scene}} and {{Appearance}} keep working; the editor offers to update them to {{Slopify_Scene}} and {{Slopify_Appearance}}.
27
+
28
+ ## Assistant, health and checks
29
+
30
+ - **Assistant.** A chat panel that runs on your Claude Code or Codex and can only use Slopify's own tools. It asks before anything that costs money, deletes or sends something, and shows what it will do. Its changes show as "by assistant".
31
+ - **Coming up on Home** says how many days of videos are ready, when a schedule's topics run out, and warns before something breaks: Claude Code or Codex signed out, a plan near its limit, disk filling, a model being retired. A weekly report can go to your notification URL (off by default).
32
+ - **Models that work for you.** Model pickers show which models your key or plan can actually run, with Check models and a weekly free check. Models that are being retired show their replacement.
33
+ - **Promise check.** An optional cheap review before narration: does the opening deliver what the title and thumbnail promise.
34
+ - **Topic ranking.** Schedules can rank new topics by what your library already covers, or also by public search interest (sends topic titles to Google, DuckDuckGo and Wikipedia; off by default).
35
+
36
+ ## Remote access and encoding
37
+
38
+ - **Open Slopify on your phone or laptop** through Tailscale (Settings → Remote access). Only devices on your own tailnet can open it, never the public internet. Keys, imports and updates can only be changed on this computer.
39
+ - **Encoding settings** (Settings → Production defaults → Encoding): video encoder (processor or NVIDIA graphics card), clip encoding speed and encoding priority.
40
+
41
+ ## Fixes
42
+
43
+ - A run's share of your Claude or Codex plan is now its own use only, never above 100%.
44
+ - Narration levelling now reaches the target loudness (−14 LUFS lands within 0.1 LU).
45
+ - The extension reads A/B test results again after it sets up A/B Testing.
46
+
47
+ ## Upgrading from 3.25.9
48
+
49
+ - Your projects, templates and schedules carry over unchanged; existing projects are not remade. Every template version you had keeps running, as before.
50
+ - The extension goes to 2.0.0. Posting needs its new optional permissions, granted in its options; YouTube works as before without them.
51
+ - `/mcp` now answers only on this computer: connect agents to `http://127.0.0.1:<port>/mcp`, not through a proxy.
@@ -0,0 +1,42 @@
1
+ # Slopify 4.1.0
2
+
3
+ Released 7 November 2026.
4
+
5
+ This release is about making Slopify easy to use without reading anything first: every button says what it does, each screen shows more and wastes less space, and the same thing has the same name everywhere.
6
+
7
+ ## Finding your way around
8
+
9
+ - **A new rail.** The left rail is narrow, with a word under every icon: Create, Home, Projects, Prompts, Templates, Calendar, Channels (once you have two or more) and Settings, then Search, Assistant, Help and Support Slopify at the foot. On a phone the bottom bar has Create in the middle.
10
+ - **Library is split in two.** **Prompts** holds your prompts and intros and outros, with every kind listed down the left. **Templates** holds video and poster templates. PDF looks are under Settings → Production defaults and Create's PDF choice, Pronunciation is under Settings → Voices, and What worked on YouTube is on the channel page. Old addresses still open the right page.
11
+ - The channel picker reads **Showing: All channels** in the header of Home, Projects and Calendar, and only appears with two or more channels.
12
+
13
+ ## Your first video
14
+
15
+ - The welcome is a checklist of what a short needs (Article, Narration, Images), each with its state and one button to fix it. The usage notice is a single line at the bottom of the window instead of a dialog, and start at login is asked once.
16
+ - **Create is one screen.** Pick what you're making, type the topic (the box has the cursor already) and press **Make the video**. Each part of the run is one sentence with Change, and anything missing is named once, with Fix. On a phone the Make button stays pinned within reach.
17
+ - **New prompt** opens beside Create and picks the prompt when you save, so you never leave the page. If you skipped the starter templates, Create offers them.
18
+ - **Everything this run will do** shows the whole run in plain sentences before you start.
19
+
20
+ ## A finished project
21
+
22
+ - The video, its downloads, the chapters, the shorts and every stage's status are on the first screen. Each section (Article, Narration, Images, Video, Shorts, YouTube, PDF, All files) leads with what it made and a named download.
23
+ - **Edit settings** uses Create's sections and names. **Versions** replaces History.
24
+ - Every action is a visible button: Mark uploaded, Rename, Save as template and Delete. Paid work says so on its button ("Make this image again").
25
+
26
+ ## Lists and settings
27
+
28
+ - **Home** shows your finished videos first, with Watch and Download, then what needs you and what's running, step by step.
29
+ - **Projects** rows show a picture, the length, what was made and when, with Open and Download.
30
+ - **Templates** are cards that say what each one makes, with **Make a video** and **Edit template**. Edit template's sections match Create's.
31
+ - **Prompts** searches every kind at once. The editor reads like text, **Insert a keyword** shows exactly what goes in, and every kind has examples to start from.
32
+ - **Settings** is one list of pages. **Keys & services** opens on three lines (who writes, who reads, who draws), each Ready or with a button to set it up. Trash has its own page, and Projects and Prompts show **Trash (n)** when something is in it.
33
+
34
+ ## One word per thing
35
+
36
+ - Captions (not subtitles), Narration, Voice, Images, Make … again (not Remake or Regenerate), Copy for YouTube Studio, Pauses and checks, PDF looks, and US spelling throughout.
37
+ - Info buttons are gone where a short line under the setting says it better. A status dot always has its word next to it, and each area has at most one lime button.
38
+
39
+ ## Fixes
40
+
41
+ - Typing the topic the moment Create opens no longer drops the starter template's writer and image service.
42
+ - Make the video is ready about a second after you stop typing, instead of three or four.
@@ -1,4 +1,16 @@
1
1
  [
2
+ {
3
+ "id": "4.1.0",
4
+ "title": "Slopify 4.1.0",
5
+ "version": "4.1.0",
6
+ "date": "2026-11-07"
7
+ },
8
+ {
9
+ "id": "4.0.0",
10
+ "title": "Slopify 4.0.0",
11
+ "version": "4.0.0",
12
+ "date": "2026-10-18"
13
+ },
2
14
  {
3
15
  "id": "3.25.9",
4
16
  "title": "Slopify 3.25.9",
@@ -1,4 +1,5 @@
1
1
  import { z } from "zod";
2
+ import { notTemplateSample } from "../template-studio/repo.js";
2
3
  import { bookSchema } from "../voices/model.js";
3
4
  import { formats } from "./model.js";
4
5
  import { liveProject } from "./repo.js";
@@ -33,7 +34,7 @@ const headSelect = `SELECT projects.id, projects.title, projects.format, project
33
34
  FROM projects LEFT JOIN project_controls ON project_controls.project_id = projects.id`;
34
35
  export function listProjectHeads(db) {
35
36
  return db
36
- .prepare(`${headSelect} WHERE ${liveProject()} ORDER BY created_at DESC, id DESC`)
37
+ .prepare(`${headSelect} WHERE ${liveProject()} AND ${notTemplateSample()} ORDER BY created_at DESC, id DESC`)
37
38
  .all()
38
39
  .map((raw) => {
39
40
  const row = headRow.parse(raw);
@@ -0,0 +1,95 @@
1
+ import { z } from "zod";
2
+ import { stageKinds } from "../../kernel/pipeline.js";
3
+ const outputRow = z.object({
4
+ project_id: z.string(),
5
+ role: z.string(),
6
+ count: z.number(),
7
+ duration_ms: z.number().nullable(),
8
+ });
9
+ const stageRow = z.object({
10
+ project_id: z.string(),
11
+ kind: z.enum(stageKinds),
12
+ state: z.string(),
13
+ finished_at: z.string().nullable(),
14
+ });
15
+ const outdatedRow = z.object({ project_id: z.string() });
16
+ // The roles a row names. A sound-only run's length comes from its export.
17
+ const namedRoles = [
18
+ "video",
19
+ "short_video",
20
+ "document_pdf",
21
+ "audio_mp3",
22
+ "audio_m4b",
23
+ "audio_export",
24
+ ];
25
+ const audioRoles = new Set(["audio_mp3", "audio_m4b", "audio_export"]);
26
+ export function listingFacts(db) {
27
+ const gathered = new Map();
28
+ const of = (projectId) => {
29
+ let one = gathered.get(projectId);
30
+ if (one === undefined) {
31
+ one = {
32
+ outputs: { video: false, shorts: 0, pdf: false, audio: false },
33
+ videoMs: null,
34
+ audioMs: null,
35
+ finishedAt: null,
36
+ failed: [],
37
+ };
38
+ gathered.set(projectId, one);
39
+ }
40
+ return one;
41
+ };
42
+ const roles = namedRoles.map(() => "?").join(",");
43
+ for (const row of db
44
+ .prepare(`SELECT project_id, role, COUNT(*) AS count, MAX(duration_ms) AS duration_ms FROM outputs WHERE role IN (${roles}) GROUP BY project_id, role`)
45
+ .all(...namedRoles)) {
46
+ const parsed = outputRow.parse(row);
47
+ const one = of(parsed.project_id);
48
+ if (parsed.role === "video") {
49
+ one.outputs.video = true;
50
+ one.videoMs = parsed.duration_ms;
51
+ }
52
+ else if (parsed.role === "short_video")
53
+ one.outputs.shorts = parsed.count;
54
+ else if (parsed.role === "document_pdf")
55
+ one.outputs.pdf = true;
56
+ else if (audioRoles.has(parsed.role)) {
57
+ one.outputs.audio = true;
58
+ if (parsed.duration_ms !== null)
59
+ one.audioMs = Math.max(one.audioMs ?? 0, parsed.duration_ms);
60
+ }
61
+ }
62
+ for (const row of db
63
+ .prepare("SELECT project_id, kind, state, finished_at FROM stages WHERE state IN ('done','failed','provided') ORDER BY rowid")
64
+ .all()) {
65
+ const parsed = stageRow.parse(row);
66
+ const one = of(parsed.project_id);
67
+ if (parsed.finished_at !== null &&
68
+ (one.finishedAt === null || parsed.finished_at > one.finishedAt))
69
+ one.finishedAt = parsed.finished_at;
70
+ if (parsed.state === "failed")
71
+ one.failed.push(parsed.kind);
72
+ }
73
+ const outdated = new Set(db
74
+ .prepare("SELECT DISTINCT revision_outputs.project_id FROM revision_outputs JOIN project_heads ON project_heads.project_id = revision_outputs.project_id AND project_heads.revision_id = revision_outputs.revision_id WHERE revision_outputs.selected = 1 AND revision_outputs.state = 'outdated'")
75
+ .all()
76
+ .map((row) => outdatedRow.parse(row).project_id));
77
+ const facts = new Map();
78
+ for (const [projectId, one] of gathered) {
79
+ const made = one.outputs;
80
+ const ms = one.videoMs ?? one.audioMs;
81
+ facts.set(projectId, {
82
+ ...(one.finishedAt === null ? {} : { finishedAt: one.finishedAt }),
83
+ ...(ms === null || ms <= 0 ? {} : { durationSeconds: Math.round(ms / 1000) }),
84
+ ...(made.video || made.shorts > 0 || made.pdf || made.audio
85
+ ? { outputs: { ...made } }
86
+ : {}),
87
+ ...(one.failed.length === 0 ? {} : { failedSteps: one.failed }),
88
+ ...(outdated.has(projectId) ? { outdated: true } : {}),
89
+ });
90
+ }
91
+ for (const projectId of outdated)
92
+ if (!facts.has(projectId))
93
+ facts.set(projectId, { outdated: true });
94
+ return facts;
95
+ }
@@ -1,5 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { failureId, stageKinds, stageStates } from "../../kernel/pipeline.js";
3
+ import { notTemplateSample } from "../template-studio/repo.js";
3
4
  import { admittedInItsState, parkedOnReview } from "./admitted-work.js";
4
5
  import { formats, stageSources } from "./model.js";
5
6
  import { runConfigSchema } from "./schema.js";
@@ -20,6 +21,7 @@ const standingRow = z.object({
20
21
  progress_current: z.number().nullable(),
21
22
  progress_total: z.number().nullable(),
22
23
  source: z.enum(stageSources),
24
+ retry_at: z.string().nullable(),
23
25
  admitted: z.number(),
24
26
  parked: z.number(),
25
27
  });
@@ -78,18 +80,19 @@ export function projectExists(db, id) {
78
80
  // Newest first.
79
81
  export function listProjects(db) {
80
82
  return db
81
- .prepare(`${projectSelect} WHERE ${liveProject()} ORDER BY created_at DESC, id DESC`)
83
+ .prepare(`${projectSelect} WHERE ${liveProject()} AND ${notTemplateSample()} ORDER BY created_at DESC, id DESC`)
82
84
  .all()
83
85
  .map((row) => toProject(projectRow.parse(row)));
84
86
  }
85
- // What 07 Projects needs of every project's stages and no more: the state each one is in
86
- // and how far through itself a running one is. One statement for the whole list rather
87
- // than `stagesOf` per row, and five columns rather than the whole stage table, because
88
- // the screen shows a status word and a meter and reads nothing else from a stage. One project's
89
- // alone when `projectId` is given.
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.
90
93
  export function stageStandingsByProject(db, projectId) {
91
94
  const grouped = new Map();
92
- 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`;
93
96
  const rows = projectId === undefined ? db.prepare(select).all() : db.prepare(select).all(projectId);
94
97
  for (const row of rows) {
95
98
  const parsed = standingRow.parse(row);
@@ -99,6 +102,7 @@ export function stageStandingsByProject(db, projectId) {
99
102
  progressCurrent: parsed.progress_current,
100
103
  progressTotal: parsed.progress_total,
101
104
  source: parsed.source,
105
+ ...(parsed.retry_at === null ? {} : { retryAt: parsed.retry_at }),
102
106
  ...(parsed.admitted === 1 ? { admitted: true } : {}),
103
107
  ...(parsed.parked === 1 ? { parked: true } : {}),
104
108
  };
@@ -1,9 +1,11 @@
1
1
  import { stageKinds } from "../../kernel/pipeline.js";
2
2
  import { imageScaleProblem } from "../images/scale.js";
3
+ import { placedProblems } from "../keywords/rules.js";
3
4
  import { loudnessFields } from "../loudness/model.js";
4
5
  import { pauseFields } from "../narration/pauses-model.js";
5
6
  import { reviewFields } from "../reviews/rules.js";
6
7
  import { shortsSettingsProblems } from "../shorts/model.js";
8
+ import { usesPostPrompt } from "../social/rules.js";
7
9
  import { ambientBedProblems, usesAmbientBed } from "../video/ambient-bed.js";
8
10
  import { usesAnimation, videoEditProblems } from "../video/edit-settings.js";
9
11
  import { usesVoices, voicesProblems } from "../voices/model.js";
@@ -75,6 +77,8 @@ export function admit(input) {
75
77
  else if (draft.title.length > titleMax) {
76
78
  fields.push({ field: "title", message: `Keep the title to ${titleMax} characters or fewer.` });
77
79
  }
80
+ // Slopify fills its keywords from the title, so the title can't use them.
81
+ fields.push(...placedProblems([{ field: "title", place: "title", body: draft.title }], draft.values));
78
82
  for (const kind of stageKinds) {
79
83
  if (!allowedSources[kind].includes(sourceOf(sources, kind))) {
80
84
  fields.push({
@@ -83,8 +87,8 @@ export function admit(input) {
83
87
  });
84
88
  }
85
89
  }
86
- if (needsLlmFor(draft) && !chosen(draft.llm)) {
87
- fields.push({ field: "llm", message: "Choose a text (LLM) provider and model." });
90
+ if (needsLlmFor(draft, input.keywordUses) && !chosen(draft.llm)) {
91
+ fields.push({ field: "llm", message: "Choose a Service and a Model under Written by." });
88
92
  }
89
93
  if (sources.article === "generate" && blank(draft.articlePrompt)) {
90
94
  fields.push({ field: "articlePrompt", message: "Pick an article prompt." });
@@ -94,7 +98,7 @@ export function admit(input) {
94
98
  fields.push(...voicesFields(draft));
95
99
  if (sources.audio === "generate") {
96
100
  if (voiced === undefined || !chosen(voiced)) {
97
- fields.push({ field: "audio", message: "Choose a narration provider and model." });
101
+ fields.push({ field: "audio", message: "Choose a Service and a Model under Read by." });
98
102
  }
99
103
  else if (voiced.voice.trim() === "") {
100
104
  fields.push({ field: "audio.voice", message: "Choose a voice for the narration." });
@@ -109,7 +113,7 @@ export function admit(input) {
109
113
  usesShorts(draft) ||
110
114
  usesAnimation(draft)) &&
111
115
  !chosen(draft.images)) {
112
- fields.push({ field: "images", message: "Choose an image provider and model." });
116
+ fields.push({ field: "images", message: "Choose a Service and a Model under Images by." });
113
117
  }
114
118
  if ((sources.thumbnail === "from_prompt" || sources.thumbnail === "prompt_by_llm") &&
115
119
  blank(draft.thumbnailPrompt)) {
@@ -118,7 +122,7 @@ export function admit(input) {
118
122
  if (sources.audio === "off" && draft.subtitles !== undefined && draft.subtitles.mode !== "off") {
119
123
  fields.push({
120
124
  field: "subtitles.mode",
121
- message: "Subtitles need narration. Turn narration on, or turn subtitles off.",
125
+ message: "Captions need narration. Turn narration on, or turn captions off.",
122
126
  });
123
127
  }
124
128
  fields.push(...youtubeDescriptionFields(draft));
@@ -132,7 +136,7 @@ export function admit(input) {
132
136
  fields.push(...reviewFields(draft));
133
137
  if (usesReference(draft) && draft.reference?.source === "provide")
134
138
  checkFile(input.staged, draft.provided.reference, "images", "provided.reference", "Upload the establishing image, or set Establishing image to Off in the Images section.", fields);
135
- checkProvided(draft, input.staged, fields);
139
+ checkProvided(draft, input.staged, fields, input.keywordUses);
136
140
  checkValues(draft, input.requiredSlots, fields);
137
141
  if (!Number.isFinite(draft.silenceGapSeconds) ||
138
142
  draft.silenceGapSeconds < 0 ||
@@ -219,7 +223,7 @@ function checkImagePrompts(draft, fields) {
219
223
  if (scaleProblem !== undefined)
220
224
  fields.push({ field: "imageScale", message: scaleProblem });
221
225
  }
222
- function checkProvided(draft, staged, fields) {
226
+ function checkProvided(draft, staged, fields, uses = {}) {
223
227
  const { sources, provided } = draft;
224
228
  if (sources.research === "provide" && blank(provided.research)) {
225
229
  fields.push({
@@ -230,7 +234,7 @@ function checkProvided(draft, staged, fields) {
230
234
  if (sources.article === "provide" && blank(provided.article)) {
231
235
  fields.push({ field: "provided.article", message: "Paste the article." });
232
236
  }
233
- fields.push(...articleOffFields(draft));
237
+ fields.push(...articleOffFields(draft, uses));
234
238
  if (sources.audio === "provide") {
235
239
  checkFile(staged, provided.audio, "audio", "provided.audio", "Pick an audio file.", fields);
236
240
  }
@@ -318,7 +322,7 @@ function checkValues(draft, requiredSlots, fields) {
318
322
  function blank(value) {
319
323
  return value === undefined || value.trim() === "";
320
324
  }
321
- export function llmUses(draft) {
325
+ export function llmUses(draft, keywords = {}) {
322
326
  const sources = draft.sources;
323
327
  const uses = [];
324
328
  if (sources.research === "generate")
@@ -341,10 +345,16 @@ export function llmUses(draft) {
341
345
  uses.push({ section: "outputs", label: "writing the YouTube description" });
342
346
  if (usesShorts(draft))
343
347
  uses.push({ section: "outputs", label: "picking the shorts" });
348
+ if (usesPostPrompt(draft))
349
+ uses.push({ section: "outputs", label: "writing the posts for other sites" });
350
+ if (keywords.scenes !== undefined)
351
+ uses.push({ section: "outputs", label: "writing image scenes" });
352
+ if (keywords.digest !== undefined)
353
+ uses.push({ section: "outputs", label: "writing the keyword digest" });
344
354
  return uses;
345
355
  }
346
- export function needsLlmFor(draft) {
347
- return llmUses(draft).length > 0;
356
+ export function needsLlmFor(draft, keywords = {}) {
357
+ return llmUses(draft, keywords).length > 0;
348
358
  }
349
359
  export function usesNarrationPreparation(draft) {
350
360
  return draft.sources.audio === "generate" && !blank(draft.narrationPrompt);
@@ -371,7 +381,7 @@ export function voicesFields(draft) {
371
381
  !draft.voices.speakers.some((speaker) => speaker.voice.provider === "inworld" && speaker.voice.model === "inworld-tts-2"))
372
382
  fields.push({
373
383
  field: "narrationPrompt",
374
- 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 clear Narration Preparation under Narration → Audio Advanced.",
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.",
375
385
  });
376
386
  return fields;
377
387
  }
@@ -479,8 +489,8 @@ export function ambientBedFields(draft, staged) {
479
489
  function chosen(choice) {
480
490
  return choice !== undefined && choice.provider.trim() !== "" && choice.model.trim() !== "";
481
491
  }
482
- // The aliases a run narrates with: its copied Library → Aliases while Use narration aliases is
483
- // 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.
484
494
  export function narrationAliasesOf(draft) {
485
495
  return draft.sources.audio === "generate" && draft.audio?.useNarrationAliases === true
486
496
  ? (draft.narrationAliases ?? [])
@@ -506,7 +516,7 @@ export function usesPronunciationGlossary(draft) {
506
516
  }
507
517
  // Article Off: a project of images or a thumbnail from prompts, with no text at all. What reads
508
518
  // the article can't be on with it.
509
- export function articleOffFields(draft) {
519
+ export function articleOffFields(draft, keywords = {}) {
510
520
  const { sources } = draft;
511
521
  if (sources.article !== "off")
512
522
  return [];
@@ -569,5 +579,30 @@ export function articleOffFields(draft) {
569
579
  },
570
580
  ]
571
581
  : []),
582
+ // The keywords Slopify writes from the article (`keywords/specs.ts`).
583
+ ...(keywords.digest === undefined
584
+ ? []
585
+ : [
586
+ {
587
+ field: keywords.digest,
588
+ message: `{{Slopify_Summary}}, {{Slopify_Hook}} and the other digest keywords are written from the article, and Article is Off. ${fix}, or remove them from this prompt.`,
589
+ },
590
+ ]),
591
+ ...(keywords.chapters === undefined
592
+ ? []
593
+ : [
594
+ {
595
+ field: keywords.chapters,
596
+ message: `{{Slopify_Chapters}} lists the article's chapters, and Article is Off. ${fix}, or remove it from this prompt.`,
597
+ },
598
+ ]),
599
+ ...(keywords.scenes === undefined
600
+ ? []
601
+ : [
602
+ {
603
+ field: keywords.scenes,
604
+ message: `{{Slopify_Scene}}, {{Slopify_Setting}} and {{Slopify_Mood}} are written from the article, and Article is Off. ${fix}, or remove them from this prompt.`,
605
+ },
606
+ ]),
572
607
  ];
573
608
  }
@@ -4,9 +4,11 @@ import { thinkingModes } from "../../kernel/ports/llm.js";
4
4
  import { castSnapshotSchema } from "../channels/schema.js";
5
5
  import { checkpointStageSchema } from "../checkpoints/schema.js";
6
6
  import { documentSettingsSchema } from "../document/theme-schema.js";
7
+ import { keywordFactsSchema } from "../keywords/schema.js";
7
8
  import { narrationAliasesSchema } from "../narration/aliases-schema.js";
8
9
  import { chunkModes } from "../narration/chunk.js";
9
10
  import { reviewModes, reviewStages } from "../reviews/model.js";
11
+ import { socialSettingsSchema } from "../social/schema.js";
10
12
  import { subtitleConfigSchema } from "../subtitles/model.js";
11
13
  import { ambientBedSchema } from "../video/ambient-bed-schema.js";
12
14
  import { animateModes, atmospheres, colorGrades, cutModes, lookLevels, transitionKinds, } from "../video/edit-settings.js";
@@ -156,6 +158,7 @@ export const runDraftSchema = z.object({
156
158
  .array(z.object({ title: z.string(), summary: z.string() }))
157
159
  .readonly()
158
160
  .optional(),
161
+ keywordFacts: keywordFactsSchema.optional(),
159
162
  titleStyle: z
160
163
  .object({
161
164
  fontId: z
@@ -193,6 +196,11 @@ export const runDraftSchema = z.object({
193
196
  levelSentences: z.boolean().optional(),
194
197
  // Absent is English (`kernel/ports/languages.ts`).
195
198
  language: languageSchema.optional(),
199
+ // Posting to other sites (`slices/social`); absent is posting nowhere.
200
+ social: socialSettingsSchema.optional(),
201
+ // A template studio sample (`slices/template-studio/scope.ts`): its steps make a short taste
202
+ // of the video, not all of it. Absent on every other project, whose steps it never changes.
203
+ sample: z.object({ fullScript: z.boolean() }).strict().optional(),
196
204
  });
197
205
  export const runConfigSchema = runDraftSchema.extend({
198
206
  rendered: z.record(z.string(), z.string()),
@@ -16,6 +16,3 @@ export function finishStage(db, stageId, state, failureReason, at) {
16
16
  export function resetStage(db, stageId) {
17
17
  db.prepare("UPDATE stages SET state = 'pending', failure_reason = NULL, failure_kind = NULL, retry_at = NULL, attempt_count = 0, progress_current = NULL, progress_total = NULL, started_at = NULL, finished_at = NULL WHERE id = ?").run(stageId);
18
18
  }
19
- export function setStageProgress(db, stageId, current, total) {
20
- db.prepare("UPDATE stages SET progress_current = ?, progress_total = ? WHERE id = ?").run(current, total, stageId);
21
- }